1 |
/* GNU Mailutils -- a suite of utilities for electronic mail |
/* GNU Mailutils -- a suite of utilities for electronic mail |
2 |
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc. |
Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. |
3 |
|
|
4 |
GNU Mailutils is free software; you can redistribute it and/or modify |
GNU Mailutils is free software; you can redistribute it and/or modify |
5 |
it under the terms of the GNU General Public License as published by |
it under the terms of the GNU General Public License as published by |
23 |
# include <strings.h> |
# include <strings.h> |
24 |
#endif |
#endif |
25 |
|
|
26 |
|
#define obstack_chunk_alloc malloc |
27 |
|
#define obstack_chunk_free free |
28 |
|
#include <obstack.h> |
29 |
|
|
30 |
typedef struct /* A string object type */ |
typedef struct /* A string object type */ |
31 |
{ |
{ |
32 |
int size; /* Allocated size or 0 for static storage */ |
int size; /* Allocated size or 0 for static storage */ |
46 |
mh_instr_t *prog; /* Program itself */ |
mh_instr_t *prog; /* Program itself */ |
47 |
int stop; /* Stop execution immediately */ |
int stop; /* Stop execution immediately */ |
48 |
|
|
49 |
char *outbuf; /* Output buffer */ |
struct obstack stk; /* Output buffer */ |
50 |
size_t width; /* Output buffer size */ |
size_t width; /* Output buffer width */ |
51 |
size_t ind; /* Output buffer index */ |
size_t ind; /* Output buffer index */ |
52 |
|
|
53 |
int fmtflags; /* Current formatting flags */ |
int fmtflags; /* Current formatting flags */ |
167 |
*size = p - (unsigned char*) str; |
*size = p - (unsigned char*) str; |
168 |
} |
} |
169 |
|
|
170 |
|
static void |
171 |
|
put_string (struct mh_machine *mach, char *str, int len) |
172 |
|
{ |
173 |
|
if (len == 0) |
174 |
|
len = strlen (str); |
175 |
|
obstack_grow (&mach->stk, str, len); |
176 |
|
mach->ind += len; |
177 |
|
} |
178 |
|
|
179 |
|
static void |
180 |
|
print_hdr_segment (struct mh_machine *mach, char *str, size_t len) |
181 |
|
{ |
182 |
|
if (!len) |
183 |
|
len = strlen (str); |
184 |
|
|
185 |
|
if (len < mach->width) |
186 |
|
put_string (mach, str, len); |
187 |
|
else |
188 |
|
{ |
189 |
|
char *endp = str + len; |
190 |
|
|
191 |
|
while (str < endp) |
192 |
|
{ |
193 |
|
size_t rest; |
194 |
|
char *p; |
195 |
|
size_t size; |
196 |
|
|
197 |
|
size = endp - str; |
198 |
|
rest = mach->width - mach->ind; |
199 |
|
if (size < rest) |
200 |
|
{ |
201 |
|
put_string (mach, str, size); |
202 |
|
break; |
203 |
|
} |
204 |
|
|
205 |
|
for (p = str + rest - 1; p > str && !isspace (*p); p--) |
206 |
|
; |
207 |
|
|
208 |
|
if (p > str) |
209 |
|
{ |
210 |
|
put_string (mach, str, p - str); |
211 |
|
put_string (mach, "\n\t", 0); |
212 |
|
mach->ind = 1; |
213 |
|
str = p; |
214 |
|
} |
215 |
|
else |
216 |
|
{ |
217 |
|
put_string (mach, str, size); |
218 |
|
str += len; |
219 |
|
} |
220 |
|
} |
221 |
|
} |
222 |
|
} |
223 |
|
|
224 |
/* Print len bytes from str into mach->outbuf */ |
/* Print len bytes from str into mach->outbuf */ |
225 |
static void |
static void |
226 |
print_string (struct mh_machine *mach, size_t width, char *str, size_t fmtlen) |
print_hdr_string (struct mh_machine *mach, char *str) |
227 |
{ |
{ |
228 |
size_t rest, len; |
char *p; |
229 |
|
|
230 |
if (!str) |
if (!str) |
231 |
str = ""; |
str = ""; |
232 |
|
|
233 |
|
p = strchr (str, '\n'); |
234 |
|
while (p) |
235 |
|
{ |
236 |
|
print_hdr_segment (mach, str, p - str + 1); |
237 |
|
mach->ind = 0; |
238 |
|
str = p + 1; |
239 |
|
p = strchr (str, '\n'); |
240 |
|
} |
241 |
|
|
242 |
|
if (str[0]) |
243 |
|
print_hdr_segment (mach, str, 0); |
244 |
|
} |
245 |
|
|
246 |
|
static void |
247 |
|
print_simple_segment (struct mh_machine *mach, size_t width, |
248 |
|
char *str, size_t len) |
249 |
|
{ |
250 |
|
size_t rest; |
251 |
|
|
252 |
|
if (!str) |
253 |
|
str = ""; |
254 |
|
|
255 |
|
if (!len) |
256 |
|
len = strlen (str); |
257 |
|
|
258 |
if (!width) |
if (!width) |
259 |
width = mach->width; |
width = mach->width; |
260 |
len = strlen (str); |
|
261 |
rest = width - mach->ind; |
rest = width - mach->ind; |
262 |
|
if (rest == 0) |
263 |
|
return; |
264 |
if (len > rest) |
if (len > rest) |
265 |
|
len = rest; |
266 |
|
|
267 |
|
put_string (mach, str, len); |
268 |
|
} |
269 |
|
|
270 |
|
static void |
271 |
|
print_string (struct mh_machine *mach, size_t width, char *str) |
272 |
|
{ |
273 |
|
char *p; |
274 |
|
|
275 |
|
if (!str) |
276 |
|
str = ""; |
277 |
|
|
278 |
|
if (!width) |
279 |
|
width = mach->width; |
280 |
|
|
281 |
|
p = strchr (str, '\n'); |
282 |
|
while (p) |
283 |
{ |
{ |
284 |
if (fmtlen >= len) |
print_simple_segment (mach, width, str, p - str + 1); |
285 |
fmtlen = rest; |
mach->ind = 0; |
286 |
len = rest; |
str = p + 1; |
287 |
|
p = strchr (str, '\n'); |
288 |
} |
} |
289 |
|
|
290 |
|
if (str[0]) |
291 |
|
print_simple_segment (mach, width, str, 0); |
292 |
|
} |
293 |
|
|
294 |
if (fmtlen < len) |
static void |
295 |
len = fmtlen; |
print_fmt_string (struct mh_machine *mach, size_t fmtwidth, char *str) |
296 |
|
{ |
297 |
memcpy (mach->outbuf + mach->ind, str, len); |
size_t len = strlen (str); |
298 |
mach->ind += len; |
if (len > fmtwidth) |
299 |
|
len = fmtwidth; |
300 |
|
put_string (mach, str, len); |
301 |
|
|
302 |
if (fmtlen > len) |
if (fmtwidth > len) |
303 |
{ |
{ |
304 |
fmtlen -= len; |
fmtwidth -= len; |
305 |
memset (mach->outbuf + mach->ind, ' ', fmtlen); |
mach->ind += fmtwidth; |
306 |
mach->ind += fmtlen; |
while (fmtwidth--) |
307 |
|
obstack_1grow (&mach->stk, ' '); |
308 |
} |
} |
309 |
} |
} |
310 |
|
|
311 |
|
/* FIXME: width? */ |
312 |
static void |
static void |
313 |
print_obj (struct mh_machine *mach, size_t width, strobj_t *obj) |
print_obj (struct mh_machine *mach, size_t width, strobj_t *obj) |
314 |
{ |
{ |
315 |
if (!strobj_is_null (obj)) |
if (!strobj_is_null (obj)) |
316 |
print_string (mach, 0, strobj_ptr (obj), strobj_len (obj)); |
print_string (mach, 0, strobj_ptr (obj)); |
317 |
} |
} |
318 |
|
|
319 |
static void |
static void |
322 |
mach->fmtflags = 0; |
mach->fmtflags = 0; |
323 |
} |
} |
324 |
|
|
325 |
|
static void |
326 |
|
format_num (struct mh_machine *mach, long num) |
327 |
|
{ |
328 |
|
int n; |
329 |
|
char buf[64]; |
330 |
|
char *ptr; |
331 |
|
int fmtwidth = mach->fmtflags & MH_WIDTH_MASK; |
332 |
|
int padchar = mach->fmtflags & MH_FMT_ZEROPAD ? '0' : ' '; |
333 |
|
|
334 |
|
n = snprintf (buf, sizeof buf, "%ld", num); |
335 |
|
|
336 |
|
if (fmtwidth) |
337 |
|
{ |
338 |
|
if (n > fmtwidth) |
339 |
|
{ |
340 |
|
ptr = buf + n - fmtwidth; |
341 |
|
*ptr = '?'; |
342 |
|
} |
343 |
|
else |
344 |
|
{ |
345 |
|
int i; |
346 |
|
ptr = buf; |
347 |
|
for (i = n; i < fmtwidth && mach->ind < mach->width; |
348 |
|
i++, mach->ind++) |
349 |
|
obstack_1grow (&mach->stk, padchar); |
350 |
|
} |
351 |
|
} |
352 |
|
else |
353 |
|
ptr = buf; |
354 |
|
|
355 |
|
print_string (mach, 0, ptr); |
356 |
|
reset_fmt_defaults (mach); |
357 |
|
} |
358 |
|
|
359 |
|
static void |
360 |
|
format_str (struct mh_machine *mach, char *str) |
361 |
|
{ |
362 |
|
if (!str) |
363 |
|
str = ""; |
364 |
|
if (mach->fmtflags) |
365 |
|
{ |
366 |
|
int len = strlen (str); |
367 |
|
int fmtwidth = mach->fmtflags & MH_WIDTH_MASK; |
368 |
|
int padchar = ' '; |
369 |
|
|
370 |
|
if (mach->fmtflags & MH_FMT_RALIGN) |
371 |
|
{ |
372 |
|
int i, n; |
373 |
|
|
374 |
|
n = fmtwidth - len; |
375 |
|
for (i = 0; i < n && mach->ind < mach->width; |
376 |
|
i++, mach->ind++, fmtwidth--) |
377 |
|
obstack_1grow (&mach->stk, padchar); |
378 |
|
} |
379 |
|
|
380 |
|
print_fmt_string (mach, fmtwidth, str); |
381 |
|
reset_fmt_defaults (mach); |
382 |
|
} |
383 |
|
else |
384 |
|
print_string (mach, 0, str); |
385 |
|
} |
386 |
|
|
387 |
/* Execute pre-compiled format on message msg with number msgno. |
/* Execute pre-compiled format on message msg with number msgno. |
388 |
buffer and bufsize specify output storage */ |
buffer and bufsize specify output storage */ |
389 |
int |
int |
390 |
mh_format (mh_format_t *fmt, message_t msg, size_t msgno, |
mh_format (mh_format_t *fmt, message_t msg, size_t msgno, |
391 |
char *buffer, size_t bufsize) |
size_t width, char **pret) |
392 |
{ |
{ |
393 |
struct mh_machine mach; |
struct mh_machine mach; |
394 |
char buf[64]; |
char buf[64]; |
400 |
mach.message = msg; |
mach.message = msg; |
401 |
mach.msgno = msgno; |
mach.msgno = msgno; |
402 |
|
|
403 |
mach.width = bufsize - 1; /* Allow for terminating NULL */ |
mach.width = width; |
|
mach.outbuf = buffer; |
|
404 |
mach.pc = 1; |
mach.pc = 1; |
405 |
|
obstack_init (&mach.stk); |
406 |
reset_fmt_defaults (&mach); |
reset_fmt_defaults (&mach); |
407 |
|
|
408 |
while (!mach.stop) |
while (!mach.stop) |
531 |
break; |
break; |
532 |
|
|
533 |
case mhop_num_print: |
case mhop_num_print: |
534 |
{ |
format_num (&mach, mach.reg_num); |
|
int n; |
|
|
char buf[64]; |
|
|
char *ptr; |
|
|
int fmtwidth = mach.fmtflags & MH_WIDTH_MASK; |
|
|
int padchar = mach.fmtflags & MH_FMT_ZEROPAD ? '0' : ' '; |
|
|
|
|
|
n = snprintf (buf, sizeof buf, "%d", mach.reg_num); |
|
|
|
|
|
if (fmtwidth) |
|
|
{ |
|
|
if (n > fmtwidth) |
|
|
{ |
|
|
ptr = buf + n - fmtwidth; |
|
|
*ptr = '?'; |
|
|
} |
|
|
else |
|
|
{ |
|
|
int i; |
|
|
ptr = buf; |
|
|
for (i = n; i < fmtwidth && mach.ind < mach.width; |
|
|
i++, mach.ind++) |
|
|
mach.outbuf[mach.ind] = padchar; |
|
|
} |
|
|
} |
|
|
else |
|
|
ptr = buf; |
|
|
|
|
|
print_string (&mach, 0, ptr, strlen (ptr)); |
|
|
reset_fmt_defaults (&mach); |
|
|
} |
|
535 |
break; |
break; |
536 |
|
|
537 |
case mhop_str_print: |
case mhop_str_print: |
538 |
if (mach.fmtflags) |
format_str (&mach, strobj_ptr (&mach.reg_str)); |
|
{ |
|
|
int len = strobj_len (&mach.reg_str); |
|
|
int fmtwidth = mach.fmtflags & MH_WIDTH_MASK; |
|
|
int padchar = ' '; |
|
|
|
|
|
if (mach.fmtflags & MH_FMT_RALIGN) |
|
|
{ |
|
|
int i, n; |
|
|
|
|
|
n = fmtwidth - len; |
|
|
for (i = 0; i < n && mach.ind < mach.width; |
|
|
i++, mach.ind++, fmtwidth--) |
|
|
mach.outbuf[mach.ind] = padchar; |
|
|
} |
|
|
|
|
|
print_string (&mach, 0, strobj_ptr (&mach.reg_str), fmtwidth); |
|
|
reset_fmt_defaults (&mach); |
|
|
} |
|
|
else |
|
|
print_obj (&mach, 0, &mach.reg_str); |
|
539 |
break; |
break; |
540 |
|
|
541 |
case mhop_fmtspec: |
case mhop_fmtspec: |
549 |
} |
} |
550 |
strobj_free (&mach.reg_str); |
strobj_free (&mach.reg_str); |
551 |
strobj_free (&mach.arg_str); |
strobj_free (&mach.arg_str); |
552 |
mach.outbuf[mach.ind] = 0; |
|
553 |
|
if (pret) |
554 |
|
{ |
555 |
|
obstack_1grow (&mach.stk, 0); |
556 |
|
*pret = strdup (obstack_finish (&mach.stk)); |
557 |
|
} |
558 |
|
obstack_free (&mach.stk, NULL); |
559 |
return mach.ind; |
return mach.ind; |
560 |
} |
} |
561 |
|
|
973 |
static void |
static void |
974 |
builtin_putstr (struct mh_machine *mach) |
builtin_putstr (struct mh_machine *mach) |
975 |
{ |
{ |
976 |
print_string (mach, 0, |
print_string (mach, 0, strobj_ptr (&mach->arg_str)); |
|
strobj_ptr (&mach->arg_str), strobj_len (&mach->arg_str)); |
|
977 |
} |
} |
978 |
|
|
979 |
/* putstrf expr print str in a fixed width*/ |
/* putstrf expr print str in a fixed width*/ |
980 |
static void |
static void |
981 |
builtin_putstrf (struct mh_machine *mach) |
builtin_putstrf (struct mh_machine *mach) |
982 |
{ |
{ |
983 |
print_string (mach, mach->reg_num, |
format_str (mach, strobj_ptr (&mach->arg_str)); |
|
strobj_ptr (&mach->arg_str), strobj_len (&mach->arg_str)); |
|
984 |
} |
} |
985 |
|
|
986 |
/* putnum expr print num*/ |
/* putnum expr print num*/ |
989 |
{ |
{ |
990 |
char *p; |
char *p; |
991 |
asprintf (&p, "%d", mach->arg_num); |
asprintf (&p, "%d", mach->arg_num); |
992 |
print_string (mach, 0, p, strlen (p)); |
print_string (mach, 0, p); |
993 |
free (p); |
free (p); |
994 |
} |
} |
995 |
|
|
997 |
static void |
static void |
998 |
builtin_putnumf (struct mh_machine *mach) |
builtin_putnumf (struct mh_machine *mach) |
999 |
{ |
{ |
1000 |
char *p; |
format_num (mach, mach->arg_num); |
|
asprintf (&p, "%d", mach->arg_num); |
|
|
print_string (mach, mach->reg_num, p, strlen (p)); |
|
|
free (p); |
|
1001 |
} |
} |
1002 |
|
|
1003 |
static int |
static int |
1783 |
} |
} |
1784 |
|
|
1785 |
static void |
static void |
1786 |
builtin_printstr (struct mh_machine *mach) |
builtin_printhdr (struct mh_machine *mach) |
1787 |
{ |
{ |
1788 |
print_obj (mach, mach->reg_num, &mach->arg_str); |
if (!strobj_is_null (&mach->arg_str)) |
1789 |
print_obj (mach, mach->reg_num, &mach->reg_str); |
print_hdr_string (mach, strobj_ptr (&mach->arg_str)); |
1790 |
|
if (!strobj_is_null (&mach->reg_str)) |
1791 |
|
print_hdr_string (mach, strobj_ptr (&mach->reg_str)); |
1792 |
} |
} |
1793 |
|
|
1794 |
static void |
static void |
1866 |
{ "comp", builtin_comp, mhtype_num, mhtype_str }, |
{ "comp", builtin_comp, mhtype_num, mhtype_str }, |
1867 |
{ "compval", builtin_compval, mhtype_num, mhtype_str }, |
{ "compval", builtin_compval, mhtype_num, mhtype_str }, |
1868 |
{ "trim", builtin_trim, mhtype_str, mhtype_str, 1 }, |
{ "trim", builtin_trim, mhtype_str, mhtype_str, 1 }, |
1869 |
{ "putstr", builtin_putstr, mhtype_str, mhtype_str, 1 }, |
{ "putstr", builtin_putstr, mhtype_none, mhtype_str, 1 }, |
1870 |
{ "putstrf", builtin_putstrf, mhtype_str, mhtype_str, 1 }, |
{ "putstrf", builtin_putstrf, mhtype_none, mhtype_str, 1 }, |
1871 |
{ "putnum", builtin_putnum, mhtype_str, mhtype_num, 1 }, |
{ "putnum", builtin_putnum, mhtype_none, mhtype_num, 1 }, |
1872 |
{ "putnumf", builtin_putnumf, mhtype_str, mhtype_num, 1 }, |
{ "putnumf", builtin_putnumf, mhtype_none, mhtype_num, 1 }, |
1873 |
{ "sec", builtin_sec, mhtype_num, mhtype_str }, |
{ "sec", builtin_sec, mhtype_num, mhtype_str }, |
1874 |
{ "min", builtin_min, mhtype_num, mhtype_str }, |
{ "min", builtin_min, mhtype_num, mhtype_str }, |
1875 |
{ "hour", builtin_hour, mhtype_num, mhtype_str }, |
{ "hour", builtin_hour, mhtype_num, mhtype_str }, |
1912 |
{ "unre", builtin_unre, mhtype_str, mhtype_str }, |
{ "unre", builtin_unre, mhtype_str, mhtype_str }, |
1913 |
{ "rcpt", builtin_rcpt, mhtype_num, mhtype_str }, |
{ "rcpt", builtin_rcpt, mhtype_num, mhtype_str }, |
1914 |
{ "concat", builtin_concat, mhtype_none, mhtype_str, 1 }, |
{ "concat", builtin_concat, mhtype_none, mhtype_str, 1 }, |
1915 |
{ "printstr", builtin_printstr, mhtype_none, mhtype_str }, |
{ "printhdr", builtin_printhdr, mhtype_none, mhtype_str }, |
1916 |
{ "in_reply_to", builtin_in_reply_to, mhtype_str, mhtype_none }, |
{ "in_reply_to", builtin_in_reply_to, mhtype_str, mhtype_none }, |
1917 |
{ "references", builtin_references, mhtype_str, mhtype_none }, |
{ "references", builtin_references, mhtype_str, mhtype_none }, |
1918 |
{ "package", builtin_package, mhtype_str, mhtype_none }, |
{ "package", builtin_package, mhtype_str, mhtype_none }, |