source: mainline/uspace/lib/fmtutil/fmtutil.c@ e7ed26be

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

Enhance justify aligment mode and align bdsh help to the left

  • Property mode set to 100644
File size: 6.1 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
62/** Line consumer that prints the lines aligned according to spec
63 *
64 **/
65static int print_line(wchar_t *wstr, size_t chars, bool last, void *data)
66{
67 printmode_t *pm = (printmode_t *) data;
68 wchar_t old_char = wstr[chars];
69 wstr[chars] = 0;
70 int rc = print_aligned_w(wstr, pm->width, last, pm->alignment);
71 wstr[chars] = old_char;
72 return rc;
73}
74
75int print_wrapped(const char *str, size_t width, align_mode_t mode)
76{
77 printmode_t pm;
78 pm.alignment = mode;
79 pm.newline_always = false;
80 pm.width = width;
81 wchar_t *wstr = str_to_awstr(str);
82 if (wstr == NULL) {
83 return ENOMEM;
84 }
85 int rc = wrap(wstr, width, print_line, &pm);
86 free(wstr);
87 return rc;
88}
89
90int print_aligned_w(const wchar_t *wstr, size_t width, bool last,
91 align_mode_t mode)
92{
93 size_t i;
94 size_t len = wstr_length(wstr);
95 if (mode == ALIGN_LEFT || (mode == ALIGN_JUSTIFY && last)) {
96 for (i = 0; i < width; i++) {
97 if (i < len)
98 putchar(wstr[i]);
99 else
100 putchar(' ');
101 }
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 }
111 else if (mode == ALIGN_CENTER) {
112 size_t padding = (width - len) / 2;
113 for (i = 0; i < width; i++) {
114 if ((i < padding) || ((i - padding) >= len))
115 putchar(' ');
116 else
117 putchar(wstr[i-padding]);
118 }
119 }
120 else if (mode == ALIGN_JUSTIFY) {
121 size_t words = 0;
122 size_t word_chars = 0;
123 bool space = true;
124 for (i = 0; i < len; i++) {
125 if (space && wstr[i] != ' ') {
126 words++;
127 }
128 space = wstr[i] == ' ';
129 if (!space) word_chars++;
130 }
131 size_t done_words = 0;
132 size_t done_chars = 0;
133 if (words == 0)
134 goto skip_words;
135 size_t excess_spaces = width - word_chars - (words-1);
136 space = true;
137 i = 0;
138 size_t j;
139 while (i < len) {
140 /* Find a word */
141 while (i < len && wstr[i] == ' ') i++;
142 if (i == len) break;
143 if (done_words) {
144 size_t spaces = 1 + (((done_words *
145 excess_spaces) / (words - 1)) -
146 (((done_words - 1) * excess_spaces) /
147 (words - 1)));
148 for (j = 0; j < spaces; j++) {
149 putchar(' ');
150 }
151 done_chars += spaces;
152 }
153 while (i < len && wstr[i] != ' ') {
154 putchar(wstr[i++]);
155 done_chars++;
156 }
157 done_words++;
158 }
159skip_words:
160 while (done_chars < width) {
161 putchar(' ');
162 done_chars++;
163 }
164 }
165 else {
166 return EINVAL;
167 }
168
169 return EOK;
170}
171int 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 int rc = print_aligned_w(wstr, width, last, mode);
178 free(wstr);
179 return rc;
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, 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.