source: mainline/uspace/lib/fmtutil/fmtutil.c@ 02246b8

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

fputc, putchar vs. fputwc, putwchar.

  • 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 */
64static errno_t print_line(wchar_t *wstr, size_t chars, bool last, void *data)
65{
66 printmode_t *pm = (printmode_t *) data;
67 wchar_t old_char = wstr[chars];
68 wstr[chars] = 0;
69 errno_t rc = print_aligned_w(wstr, pm->width, last, pm->alignment);
70 wstr[chars] = old_char;
71 return rc;
72}
73
74errno_t print_wrapped(const char *str, size_t width, align_mode_t mode)
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 }
84 errno_t rc = wrap(wstr, width, print_line, &pm);
85 free(wstr);
86 return rc;
87}
88
89errno_t print_aligned_w(const wchar_t *wstr, size_t width, bool last,
90 align_mode_t mode)
91{
92 size_t i;
93 size_t len = wstr_length(wstr);
94 if (mode == ALIGN_LEFT || (mode == ALIGN_JUSTIFY && last)) {
95 for (i = 0; i < width; i++) {
96 if (i < len)
97 putwchar(wstr[i]);
98 else
99 putwchar(' ');
100 }
101 } else if (mode == ALIGN_RIGHT) {
102 for (i = 0; i < width; i++) {
103 if (i < width - len)
104 putwchar(' ');
105 else
106 putwchar(wstr[i - (width - len)]);
107 }
108 } else if (mode == ALIGN_CENTER) {
109 size_t padding = (width - len) / 2;
110 for (i = 0; i < width; i++) {
111 if ((i < padding) || ((i - padding) >= len))
112 putwchar(' ');
113 else
114 putwchar(wstr[i - padding]);
115 }
116 } else if (mode == ALIGN_JUSTIFY) {
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] == ' ';
125 if (!space)
126 word_chars++;
127 }
128 size_t done_words = 0;
129 size_t done_chars = 0;
130 if (words == 0)
131 goto skip_words;
132 size_t excess_spaces = width - word_chars - (words - 1);
133 space = true;
134 i = 0;
135 size_t j;
136 while (i < len) {
137 /* Find a word */
138 while (i < len && wstr[i] == ' ')
139 i++;
140 if (i == len)
141 break;
142 if (done_words) {
143 size_t spaces = 1 + (((done_words *
144 excess_spaces) / (words - 1)) -
145 (((done_words - 1) * excess_spaces) /
146 (words - 1)));
147 for (j = 0; j < spaces; j++) {
148 putwchar(' ');
149 }
150 done_chars += spaces;
151 }
152 while (i < len && wstr[i] != ' ') {
153 putwchar(wstr[i++]);
154 done_chars++;
155 }
156 done_words++;
157 }
158 skip_words:
159 while (done_chars < width) {
160 putwchar(' ');
161 done_chars++;
162 }
163 } else {
164 return EINVAL;
165 }
166
167 return EOK;
168}
169errno_t print_aligned(const char *str, size_t width, bool last, align_mode_t mode)
170{
171 wchar_t *wstr = str_to_awstr(str);
172 if (wstr == NULL) {
173 return ENOMEM;
174 }
175 errno_t rc = print_aligned_w(wstr, width, last, mode);
176 free(wstr);
177 return rc;
178}
179
180errno_t wrap(wchar_t *wstr, size_t width, line_consumer_fn consumer, void *data)
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;
187
188 /*
189 * Invariants:
190 * * line_len = last_word_end - line_start
191 * * line_start <= last_word_end <= word_start <= pos
192 */
193
194 while (wstr[pos] != 0) {
195 /* Skip spaces and process newlines */
196 while (wstr[pos] == ' ' || wstr[pos] == '\n') {
197 if (wstr[pos] == '\n') {
198 consumer(wstr + line_start, line_len, true,
199 data);
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++;
210 bool last = wstr[pos] == 0;
211 /* Check if the line still fits width */
212 if (pos - line_start > width) {
213 if (line_len > 0)
214 consumer(wstr + line_start, line_len, last,
215 data);
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) {
221 consumer(wstr + word_start, width, last, data);
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 }
228 /*
229 * Here we have less than width chars starting from line_start.
230 * Moreover, the last portion does not contain spaces or newlines
231 */
232 if (pos - line_start > 0)
233 consumer(wstr + line_start, pos - line_start, true, data);
234
235 return EOK;
236}
237
Note: See TracBrowser for help on using the repository browser.