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

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

Use proper formula to calculate number of spaces between words when using ALIGN_JUSITFY

  • Property mode set to 100644
File size: 6.0 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 size_t spaces = 1 + (((done_words *
148 excess_spaces) / (words - 1)) -
149 (((done_words - 1) * excess_spaces) /
150 (words - 1)));
151 for (j = 0; j < spaces; j++) {
152 putchar(' ');
153 }
154 done_chars += spaces;
155 }
156 while (i < len && wstr[i] != ' ') {
157 putchar(wstr[i++]);
158 done_chars++;
159 }
160 done_words++;
161 }
162 while (done_chars < width) {
163 putchar(' ');
164 done_chars++;
165 }
166 }
167 else {
168 return EINVAL;
169 }
170
171 return EOK;
172}
173int print_aligned(const char *str, size_t width, align_mode_t mode)
174{
175 wchar_t *wstr = str_to_awstr(str);
176 if (wstr == NULL) {
177 return ENOMEM;
178 }
179 int rc = print_aligned_w(wstr, width, mode);
180 free(wstr);
181 return rc;
182}
183
184/**
185 */
186int wrap(wchar_t *wstr, size_t width, line_consumer_fn consumer, void *data)
187{
188 size_t word_start = 0;
189 size_t last_word_end = 0;
190 size_t line_start = 0;
191 size_t line_len = 0;
192 size_t pos = 0;
193
194 /*
195 * Invariants:
196 * * line_len = last_word_end - line_start
197 * * line_start <= last_word_end <= word_start <= pos
198 */
199
200 while (wstr[pos] != 0) {
201 /* Skip spaces and process newlines */
202 while (wstr[pos] == ' ' || wstr[pos] == '\n') {
203 if (wstr[pos] == '\n') {
204 consumer(wstr + line_start, line_len, data);
205 last_word_end = line_start = pos + 1;
206 line_len = 0;
207 }
208 pos++;
209 }
210 word_start = pos;
211 /* Find end of word */
212 while (wstr[pos] != 0 && wstr[pos] != ' ' &&
213 wstr[pos] != '\n')
214 pos++;
215 /* Check if the line still fits width */
216 if (pos - line_start > width) {
217 if (line_len > 0)
218 consumer(wstr + line_start, line_len, data);
219 line_start = last_word_end = word_start;
220 line_len = 0;
221 }
222 /* Check if we need to force wrap of long word*/
223 if (pos - word_start > width) {
224 consumer(wstr + word_start, width, data);
225 pos = line_start = last_word_end = word_start + width;
226 line_len = 0;
227 }
228 last_word_end = pos;
229 line_len = last_word_end - line_start;
230 }
231 /* Here we have less than width chars starting from line_start.
232 * Moreover, the last portion does not contain spaces or newlines
233 */
234 if (pos - line_start > 0)
235 consumer(wstr + line_start, pos - line_start, data);
236
237 return EOK;
238}
239
Note: See TracBrowser for help on using the repository browser.