2 * Copyright 2004-2005 Timo Hirvonen
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 #include <format_print.h>
29 static int numlen(int num
)
43 static int stack_print(char *buf
, char *stack
, int stack_len
, int width
, int align_left
, char pad
)
49 while (i
< width
&& stack_len
)
50 buf
[i
++] = stack
[--stack_len
];
56 if (stack_len
> width
)
58 pad_len
= width
- stack_len
;
62 buf
[i
++] = stack
[--stack_len
];
66 buf
[i
++] = stack
[--stack_len
];
71 static int print_num(char *buf
, int num
, int width
, int align_left
, char pad
)
79 for (i
= 0; i
< width
; i
++)
85 stack
[p
++] = num
% 10 + '0';
89 return stack_print(buf
, stack
, p
, width
, align_left
, pad
);
92 /* print '{,-}{h:,}mm:ss' */
93 static int print_time(char *buf
, int t
, int width
, int align_left
, char pad
)
109 /* put all chars to stack in reverse order ;) */
110 stack
[p
++] = s
% 10 + '0';
111 stack
[p
++] = s
/ 10 + '0';
113 stack
[p
++] = m
% 10 + '0';
114 stack
[p
++] = m
/ 10 + '0';
118 stack
[p
++] = h
% 10 + '0';
125 return stack_print(buf
, stack
, p
, width
, align_left
, pad
);
136 * field width. 0 if not set
138 * 1 => aling left. 0 => align right
140 static void print_str(char *buf
, int *idx
, const char *str
, int width
, int align_left
)
150 d
+= u_copy_chars(buf
+ d
, str
, &i
);
153 memset(buf
+ d
, ' ', ws_len
);
158 ws_len
= width
- u_str_width(str
);
161 memset(buf
+ d
, ' ', ws_len
);
171 u_get_char(str
, &s
, &u
);
176 /* gaah, skipped too much */
177 if (u_char_width(u
) == 2) {
183 buf
[d
++] = hex_tab
[(u
>> 4) & 0xf];
185 buf
[d
++] = hex_tab
[u
& 0xf];
194 d
+= u_copy_chars(buf
+ d
, str
+ s
, &w
);
202 u_get_char(str
, &s
, &u
);
205 u_set_char(buf
, &d
, u
);
211 static void print(char *str
, const char *format
, const struct format_option
*fopts
)
213 /* format and str indices */
218 int nlen
, align_left
, pad
, j
;
220 u_get_char(format
, &s
, &u
);
222 u_set_char(str
, &d
, u
);
225 u_get_char(format
, &s
, &u
);
227 u_set_char(str
, &d
, u
);
238 u_get_char(format
, &s
, &u
);
243 u_get_char(format
, &s
, &u
);
249 u_get_char(format
, &s
, &u
);
251 for (j
= 0; fopts
[j
].ch
; j
++) {
252 if (fopts
[j
].ch
!= u
)
255 if (fopts
[j
].empty
) {
256 memset(str
+ d
, ' ', nlen
);
258 } else if (fopts
[j
].type
== FO_STR
) {
259 print_str(str
, &d
, fopts
[j
].fo_str
, nlen
, align_left
);
260 } else if (fopts
[j
].type
== FO_INT
) {
261 d
+= print_num(str
+ d
, fopts
[j
].fo_int
, nlen
, align_left
, pad
);
262 } else if (fopts
[j
].type
== FO_TIME
) {
263 d
+= print_time(str
+ d
, fopts
[j
].fo_time
, nlen
, align_left
, pad
);
271 static char *l_str
= NULL
;
272 static char *r_str
= NULL
;
273 /* sizes in bytes. not counting the terminating 0! */
274 static int l_str_size
= -1;
275 static int r_str_size
= -1;
277 int format_print(char *str
, int width
, const char *format
, const struct format_option
*fopts
)
279 /* lengths of left and right aligned texts */
292 u_get_char(format
, &s
, &u
);
294 (*len
) += u_char_width(u
);
297 u_get_char(format
, &s
, &u
);
303 /* right aligned text starts */
309 u_get_char(format
, &s
, &u
);
312 /* minimum length of this field */
315 u_get_char(format
, &s
, &u
);
319 BUG_ON(fopts
[j
].ch
== 0);
320 if (fopts
[j
].ch
== u
) {
323 if (fopts
[j
].empty
) {
325 } else if (fopts
[j
].type
== FO_STR
) {
326 l
= u_str_width(fopts
[j
].fo_str
);
327 } else if (fopts
[j
].type
== FO_INT
) {
328 l
= numlen(fopts
[j
].fo_int
);
329 } else if (fopts
[j
].type
== FO_TIME
) {
330 int t
= fopts
[j
].fo_time
;
337 l
+= numlen(t
/ 3600) + 6;
342 BUG("invalid format option\n");
355 /* max utf-8 char len is 4 */
359 if (l_str_size
< lsize
) {
362 l_str
= xnew(char, l_str_size
+ 1);
363 l_str
[l_str_size
] = 0;
365 if (r_str_size
< rsize
) {
368 r_str
= xnew(char, r_str_size
+ 1);
369 r_str
[r_str_size
] = 0;
375 print(l_str
, format
, fopts
);
378 int ul
= u_str_width(l_str
);
380 d_print("L %d != %d: size=%d '%s'\n", ul
, llen
, lsize
, l_str
);
385 print(r_str
, format
+ eq_pos
+ 1, fopts
);
388 int ul
= u_str_width(r_str
);
390 d_print("R %d != %d: size=%d '%s'\n", ul
, rlen
, rsize
, r_str
);
395 /* NOTE: any invalid UTF-8 bytes have already been converted to <xx>
396 * (ASCII) where x is hex digit
399 if (llen
+ rlen
<= width
) {
401 int ws_len
= width
- llen
- rlen
;
404 /* I would use strcpy if it returned anything useful */
406 str
[pos
] = l_str
[pos
];
409 memset(str
+ pos
, ' ', ws_len
);
410 strcpy(str
+ pos
+ ws_len
, r_str
);
412 int l_space
= width
- rlen
;
417 pos
= u_copy_chars(str
, l_str
, &l_space
);
421 idx
= u_skip_chars(r_str
, &w
);
425 strcpy(str
+ pos
, r_str
+ idx
);
430 /* FIXME: compare with struct format_option[] */
431 int format_valid(const char *format
)
439 u_get_char(format
, &s
, &u
);
443 u_get_char(format
, &s
, &u
);
444 if (u
== '%' || u
== '=')
447 u_get_char(format
, &s
, &u
);
450 u_get_char(format
, &s
, &u
);
453 u_get_char(format
, &s
, &u
);