source: mainline/uspace/lib/fmtutil/fmtutil.c@ 0b63dc2

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0b63dc2 was 09ab0a9a, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Fix vertical spacing with new Ccheck revision.

  • Property mode set to 100644
File size: 6.2 KB
RevLine 
[22cf42d9]1/*
2 * Copyright (c) 2011 Martin Sucha
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <io/console.h>
30#include <errno.h>
31#include <fmtutil.h>
[38d150e]32#include <stdlib.h>
[1d6dd2a]33#include <str.h>
[22cf42d9]34
35typedef struct {
36 align_mode_t alignment;
37 bool newline_always;
38 size_t width;
39} printmode_t;
40
[b7fd2a0]41errno_t print_wrapped_console(const char *str, align_mode_t alignment)
[22cf42d9]42{
43 console_ctrl_t *console = console_init(stdin, stdout);
44 if (console == NULL) {
45 printf("%s", str);
46 return EOK;
47 }
48 sysarg_t con_rows, con_cols, con_col, con_row;
[b7fd2a0]49 errno_t rc = console_get_size(console, &con_cols, &con_rows);
[22cf42d9]50 if (rc != EOK) {
51 return rc;
52 }
53 rc = console_get_pos(console, &con_col, &con_row);
54 if (rc != EOK) {
55 return rc;
56 }
57 if (con_col != 0) {
58 printf("\n");
59 }
60 return print_wrapped(str, con_cols, alignment);
61}
62
[7c3fb9b]63/** Line consumer that prints the lines aligned according to spec */
[b7fd2a0]64static errno_t print_line(wchar_t *wstr, size_t chars, bool last, void *data)
[22cf42d9]65{
66 printmode_t *pm = (printmode_t *) data;
[6045ecf]67 wchar_t old_char = wstr[chars];
[22cf42d9]68 wstr[chars] = 0;
[b7fd2a0]69 errno_t rc = print_aligned_w(wstr, pm->width, last, pm->alignment);
[6045ecf]70 wstr[chars] = old_char;
71 return rc;
[22cf42d9]72}
73
[b7fd2a0]74errno_t print_wrapped(const char *str, size_t width, align_mode_t mode)
[22cf42d9]75{
76 printmode_t pm;
77 pm.alignment = mode;
78 pm.newline_always = false;
79 pm.width = width;
80 wchar_t *wstr = str_to_awstr(str);
81 if (wstr == NULL) {
82 return ENOMEM;
83 }
[b7fd2a0]84 errno_t rc = wrap(wstr, width, print_line, &pm);
[22cf42d9]85 free(wstr);
86 return rc;
87}
88
[b7fd2a0]89errno_t print_aligned_w(const wchar_t *wstr, size_t width, bool last,
[6045ecf]90 align_mode_t mode)
[22cf42d9]91{
92 size_t i;
93 size_t len = wstr_length(wstr);
[6045ecf]94 if (mode == ALIGN_LEFT || (mode == ALIGN_JUSTIFY && last)) {
[22cf42d9]95 for (i = 0; i < width; i++) {
96 if (i < len)
[ed88c8e]97 putwchar(wstr[i]);
[22cf42d9]98 else
[ed88c8e]99 putwchar(' ');
[22cf42d9]100 }
[1433ecda]101 } else if (mode == ALIGN_RIGHT) {
[22cf42d9]102 for (i = 0; i < width; i++) {
103 if (i < width - len)
[ed88c8e]104 putwchar(' ');
[22cf42d9]105 else
[ed88c8e]106 putwchar(wstr[i - (width - len)]);
[22cf42d9]107 }
[1433ecda]108 } else if (mode == ALIGN_CENTER) {
[22cf42d9]109 size_t padding = (width - len) / 2;
110 for (i = 0; i < width; i++) {
111 if ((i < padding) || ((i - padding) >= len))
[ed88c8e]112 putwchar(' ');
[22cf42d9]113 else
[ed88c8e]114 putwchar(wstr[i - padding]);
[22cf42d9]115 }
[1433ecda]116 } else if (mode == ALIGN_JUSTIFY) {
[22cf42d9]117 size_t words = 0;
118 size_t word_chars = 0;
119 bool space = true;
120 for (i = 0; i < len; i++) {
121 if (space && wstr[i] != ' ') {
122 words++;
123 }
124 space = wstr[i] == ' ';
[1433ecda]125 if (!space)
126 word_chars++;
[22cf42d9]127 }
[19d007e]128 size_t done_words = 0;
129 size_t done_chars = 0;
130 if (words == 0)
131 goto skip_words;
[1433ecda]132 size_t excess_spaces = width - word_chars - (words - 1);
[22cf42d9]133 space = true;
134 i = 0;
135 size_t j;
136 while (i < len) {
137 /* Find a word */
[1433ecda]138 while (i < len && wstr[i] == ' ')
139 i++;
140 if (i == len)
141 break;
[22cf42d9]142 if (done_words) {
[fcfac250]143 size_t spaces = 1 + (((done_words *
144 excess_spaces) / (words - 1)) -
145 (((done_words - 1) * excess_spaces) /
146 (words - 1)));
[22cf42d9]147 for (j = 0; j < spaces; j++) {
[ed88c8e]148 putwchar(' ');
[22cf42d9]149 }
150 done_chars += spaces;
151 }
152 while (i < len && wstr[i] != ' ') {
[ed88c8e]153 putwchar(wstr[i++]);
[22cf42d9]154 done_chars++;
155 }
156 done_words++;
157 }
[1433ecda]158 skip_words:
[22cf42d9]159 while (done_chars < width) {
[ed88c8e]160 putwchar(' ');
[22cf42d9]161 done_chars++;
162 }
[1433ecda]163 } else {
[e406736]164 return EINVAL;
165 }
[a35b458]166
[22cf42d9]167 return EOK;
168}
[b7fd2a0]169errno_t print_aligned(const char *str, size_t width, bool last, align_mode_t mode)
[22cf42d9]170{
171 wchar_t *wstr = str_to_awstr(str);
172 if (wstr == NULL) {
173 return ENOMEM;
174 }
[b7fd2a0]175 errno_t rc = print_aligned_w(wstr, width, last, mode);
[22cf42d9]176 free(wstr);
177 return rc;
178}
179
[b7fd2a0]180errno_t wrap(wchar_t *wstr, size_t width, line_consumer_fn consumer, void *data)
[22cf42d9]181{
182 size_t word_start = 0;
183 size_t last_word_end = 0;
184 size_t line_start = 0;
185 size_t line_len = 0;
186 size_t pos = 0;
[a35b458]187
[22cf42d9]188 /*
189 * Invariants:
190 * * line_len = last_word_end - line_start
191 * * line_start <= last_word_end <= word_start <= pos
192 */
[a35b458]193
[22cf42d9]194 while (wstr[pos] != 0) {
195 /* Skip spaces and process newlines */
196 while (wstr[pos] == ' ' || wstr[pos] == '\n') {
197 if (wstr[pos] == '\n') {
[6045ecf]198 consumer(wstr + line_start, line_len, true,
199 data);
[22cf42d9]200 last_word_end = line_start = pos + 1;
201 line_len = 0;
202 }
203 pos++;
204 }
205 word_start = pos;
206 /* Find end of word */
207 while (wstr[pos] != 0 && wstr[pos] != ' ' &&
208 wstr[pos] != '\n')
209 pos++;
[6045ecf]210 bool last = wstr[pos] == 0;
[22cf42d9]211 /* Check if the line still fits width */
212 if (pos - line_start > width) {
213 if (line_len > 0)
[6045ecf]214 consumer(wstr + line_start, line_len, last,
215 data);
[22cf42d9]216 line_start = last_word_end = word_start;
217 line_len = 0;
218 }
219 /* Check if we need to force wrap of long word*/
220 if (pos - word_start > width) {
[6045ecf]221 consumer(wstr + word_start, width, last, data);
[22cf42d9]222 pos = line_start = last_word_end = word_start + width;
223 line_len = 0;
224 }
225 last_word_end = pos;
226 line_len = last_word_end - line_start;
227 }
[7c3fb9b]228 /*
229 * Here we have less than width chars starting from line_start.
[1b20da0]230 * Moreover, the last portion does not contain spaces or newlines
[22cf42d9]231 */
232 if (pos - line_start > 0)
[6045ecf]233 consumer(wstr + line_start, pos - line_start, true, data);
[22cf42d9]234
235 return EOK;
236}
Note: See TracBrowser for help on using the repository browser.