source: mainline/uspace/lib/fmtutil/fmtutil.c@ 1433ecda

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

Fix cstyle: make ccheck-fix and commit only files where all the changes are good.

  • Property mode set to 100644
File size: 6.2 KB
Line 
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>
32#include <stdlib.h>
33#include <str.h>
34
35typedef struct {
36 align_mode_t alignment;
37 bool newline_always;
38 size_t width;
39} printmode_t;
40
41errno_t print_wrapped_console(const char *str, align_mode_t alignment)
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;
49 errno_t rc = console_get_size(console, &con_cols, &con_rows);
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
63/** Line consumer that prints the lines aligned according to spec
64 *
65 **/
66static errno_t print_line(wchar_t *wstr, size_t chars, bool last, void *data)
67{
68 printmode_t *pm = (printmode_t *) data;
69 wchar_t old_char = wstr[chars];
70 wstr[chars] = 0;
71 errno_t rc = print_aligned_w(wstr, pm->width, last, pm->alignment);
72 wstr[chars] = old_char;
73 return rc;
74}
75
76errno_t print_wrapped(const char *str, size_t width, align_mode_t mode)
77{
78 printmode_t pm;
79 pm.alignment = mode;
80 pm.newline_always = false;
81 pm.width = width;
82 wchar_t *wstr = str_to_awstr(str);
83 if (wstr == NULL) {
84 return ENOMEM;
85 }
86 errno_t rc = wrap(wstr, width, print_line, &pm);
87 free(wstr);
88 return rc;
89}
90
91errno_t print_aligned_w(const wchar_t *wstr, size_t width, bool last,
92 align_mode_t mode)
93{
94 size_t i;
95 size_t len = wstr_length(wstr);
96 if (mode == ALIGN_LEFT || (mode == ALIGN_JUSTIFY && last)) {
97 for (i = 0; i < width; i++) {
98 if (i < len)
99 putchar(wstr[i]);
100 else
101 putchar(' ');
102 }
103 } else if (mode == ALIGN_RIGHT) {
104 for (i = 0; i < width; i++) {
105 if (i < width - len)
106 putchar(' ');
107 else
108 putchar(wstr[i - (width - len)]);
109 }
110 } else if (mode == ALIGN_CENTER) {
111 size_t padding = (width - len) / 2;
112 for (i = 0; i < width; i++) {
113 if ((i < padding) || ((i - padding) >= len))
114 putchar(' ');
115 else
116 putchar(wstr[i - padding]);
117 }
118 } else if (mode == ALIGN_JUSTIFY) {
119 size_t words = 0;
120 size_t word_chars = 0;
121 bool space = true;
122 for (i = 0; i < len; i++) {
123 if (space && wstr[i] != ' ') {
124 words++;
125 }
126 space = wstr[i] == ' ';
127 if (!space)
128 word_chars++;
129 }
130 size_t done_words = 0;
131 size_t done_chars = 0;
132 if (words == 0)
133 goto skip_words;
134 size_t excess_spaces = width - word_chars - (words - 1);
135 space = true;
136 i = 0;
137 size_t j;
138 while (i < len) {
139 /* Find a word */
140 while (i < len && wstr[i] == ' ')
141 i++;
142 if (i == len)
143 break;
144 if (done_words) {
145 size_t spaces = 1 + (((done_words *
146 excess_spaces) / (words - 1)) -
147 (((done_words - 1) * excess_spaces) /
148 (words - 1)));
149 for (j = 0; j < spaces; j++) {
150 putchar(' ');
151 }
152 done_chars += spaces;
153 }
154 while (i < len && wstr[i] != ' ') {
155 putchar(wstr[i++]);
156 done_chars++;
157 }
158 done_words++;
159 }
160 skip_words:
161 while (done_chars < width) {
162 putchar(' ');
163 done_chars++;
164 }
165 } else {
166 return EINVAL;
167 }
168
169 return EOK;
170}
171errno_t print_aligned(const char *str, size_t width, bool last, align_mode_t mode)
172{
173 wchar_t *wstr = str_to_awstr(str);
174 if (wstr == NULL) {
175 return ENOMEM;
176 }
177 errno_t rc = print_aligned_w(wstr, width, last, mode);
178 free(wstr);
179 return rc;
180}
181
182errno_t wrap(wchar_t *wstr, size_t width, line_consumer_fn consumer, void *data)
183{
184 size_t word_start = 0;
185 size_t last_word_end = 0;
186 size_t line_start = 0;
187 size_t line_len = 0;
188 size_t pos = 0;
189
190 /*
191 * Invariants:
192 * * line_len = last_word_end - line_start
193 * * line_start <= last_word_end <= word_start <= pos
194 */
195
196 while (wstr[pos] != 0) {
197 /* Skip spaces and process newlines */
198 while (wstr[pos] == ' ' || wstr[pos] == '\n') {
199 if (wstr[pos] == '\n') {
200 consumer(wstr + line_start, line_len, true,
201 data);
202 last_word_end = line_start = pos + 1;
203 line_len = 0;
204 }
205 pos++;
206 }
207 word_start = pos;
208 /* Find end of word */
209 while (wstr[pos] != 0 && wstr[pos] != ' ' &&
210 wstr[pos] != '\n')
211 pos++;
212 bool last = wstr[pos] == 0;
213 /* Check if the line still fits width */
214 if (pos - line_start > width) {
215 if (line_len > 0)
216 consumer(wstr + line_start, line_len, last,
217 data);
218 line_start = last_word_end = word_start;
219 line_len = 0;
220 }
221 /* Check if we need to force wrap of long word*/
222 if (pos - word_start > width) {
223 consumer(wstr + word_start, width, last, data);
224 pos = line_start = last_word_end = word_start + width;
225 line_len = 0;
226 }
227 last_word_end = pos;
228 line_len = last_word_end - line_start;
229 }
230 /* Here we have less than width chars starting from line_start.
231 * Moreover, the last portion does not contain spaces or newlines
232 */
233 if (pos - line_start > 0)
234 consumer(wstr + line_start, pos - line_start, true, data);
235
236 return EOK;
237}
238
Note: See TracBrowser for help on using the repository browser.