source: mainline/uspace/lib/fmtutil/fmtutil.c@ 22cf42d9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 22cf42d9 was 22cf42d9, checked in by Martin Sucha <sucha14@…>, 14 years ago

Add formatting library and display help message wrapped

  • Property mode set to 100644
File size: 5.9 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 <malloc.h>
32#include <fmtutil.h>
33
34typedef struct {
35 align_mode_t alignment;
36 bool newline_always;
37 size_t width;
38} printmode_t;
39
40int print_wrapped_console(const char *str, align_mode_t alignment)
41{
42 console_ctrl_t *console = console_init(stdin, stdout);
43 if (console == NULL) {
44 printf("%s", str);
45 return EOK;
46 }
47 sysarg_t con_rows, con_cols, con_col, con_row;
48 int rc = console_get_size(console, &con_cols, &con_rows);
49 if (rc != EOK) {
50 return rc;
51 }
52 rc = console_get_pos(console, &con_col, &con_row);
53 if (rc != EOK) {
54 return rc;
55 }
56 if (con_col != 0) {
57 printf("\n");
58 }
59 return print_wrapped(str, con_cols, alignment);
60}
61
62static int print_line(wchar_t *wstr, size_t chars, void *data)
63{
64 //char *line = wstr_to_astr(wstr);
65 printmode_t *pm = (printmode_t *) data;
66 //if (line == NULL) {
67 // return ENOMEM;
68 //}
69 wstr[chars] = 0;
70 return print_aligned_w(wstr, pm->width, pm->alignment);
71 //printf("%s", line);
72 //if (pm->newline_always || chars < pm->width)
73 // printf("\n");
74 //free(line);
75 //return EOK;
76}
77
78int print_wrapped(const char *str, size_t width, align_mode_t mode)
79{
80 printmode_t pm;
81 pm.alignment = mode;
82 pm.newline_always = false;
83 pm.width = width;
84 wchar_t *wstr = str_to_awstr(str);
85 if (wstr == NULL) {
86 return ENOMEM;
87 }
88 int rc = wrap(wstr, width, print_line, &pm);
89 free(wstr);
90 return rc;
91}
92
93int print_aligned_w(const wchar_t *wstr, size_t width, align_mode_t mode)
94{
95 size_t i;
96 size_t len = wstr_length(wstr);
97 if (mode == ALIGN_LEFT) {
98 for (i = 0; i < width; i++) {
99 if (i < len)
100 putchar(wstr[i]);
101 else
102 putchar(' ');
103 }
104 }
105 else if (mode == ALIGN_RIGHT) {
106 for (i = 0; i < width; i++) {
107 if (i < width - len)
108 putchar(' ');
109 else
110 putchar(wstr[i- (width - len)]);
111 }
112 }
113 else if (mode == ALIGN_CENTER) {
114 size_t padding = (width - len) / 2;
115 for (i = 0; i < width; i++) {
116 if ((i < padding) || ((i - padding) >= len))
117 putchar(' ');
118 else
119 putchar(wstr[i-padding]);
120 }
121 }
122 else if (mode == ALIGN_JUSTIFY) {
123 size_t words = 0;
124 size_t word_chars = 0;
125 bool space = true;
126 for (i = 0; i < len; i++) {
127 if (space && wstr[i] != ' ') {
128 words++;
129 }
130 space = wstr[i] == ' ';
131 if (!space) word_chars++;
132 }
133 if (words == 0) {
134 return EOK;
135 }
136 size_t excess_spaces = width - word_chars - (words-1);
137 space = true;
138 i = 0;
139 size_t done_words = 0;
140 size_t done_chars = 0;
141 size_t j;
142 while (i < len) {
143 /* Find a word */
144 while (i < len && wstr[i] == ' ') i++;
145 if (i == len) break;
146 if (done_words) {
147 // TODO: use better formula
148 size_t spaces = 1 + (excess_spaces /
149 (words - 1));
150 for (j = 0; j < spaces; j++) {
151 putchar(' ');
152 }
153 done_chars += spaces;
154 }
155 while (i < len && wstr[i] != ' ') {
156 putchar(wstr[i++]);
157 done_chars++;
158 }
159 done_words++;
160 }
161 while (done_chars < width) {
162 putchar(' ');
163 done_chars++;
164 }
165 }
166
167 return EOK;
168}
169int print_aligned(const char *str, size_t width, align_mode_t mode)
170{
171 wchar_t *wstr = str_to_awstr(str);
172 if (wstr == NULL) {
173 return ENOMEM;
174 }
175 int rc = print_aligned_w(wstr, width, mode);
176 free(wstr);
177 return rc;
178}
179
180/**
181 */
182int 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, data);
201 last_word_end = line_start = pos + 1;
202 line_len = 0;
203 }
204 pos++;
205 }
206 word_start = pos;
207 /* Find end of word */
208 while (wstr[pos] != 0 && wstr[pos] != ' ' &&
209 wstr[pos] != '\n')
210 pos++;
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, data);
215 line_start = last_word_end = word_start;
216 line_len = 0;
217 }
218 /* Check if we need to force wrap of long word*/
219 if (pos - word_start > width) {
220 consumer(wstr + word_start, width, data);
221 pos = line_start = last_word_end = word_start + width;
222 line_len = 0;
223 }
224 last_word_end = pos;
225 line_len = last_word_end - line_start;
226 }
227 /* Here we have less than width chars starting from line_start.
228 * Moreover, the last portion does not contain spaces or newlines
229 */
230 if (pos - line_start > 0)
231 consumer(wstr + line_start, pos - line_start, data);
232
233 return EOK;
234}
235
Note: See TracBrowser for help on using the repository browser.