|
|
1.1 root 1: /* formatsbr.c - format string interpretation */
2:
3: #include "../h/mh.h"
4: #include "../h/addrsbr.h"
5: #include "../h/formatsbr.h"
6: #include "../zotnet/tws.h"
7: #include "../h/fmtcompile.h"
8: #include <ctype.h>
9: #include <stdio.h>
10: #include <sys/types.h>
11: #include <sys/stat.h>
12:
13: /* */
14:
15:
16: #define NFMTS MAXARGS
17: #define QUOTE '\\'
18:
19: static char *formats = 0;
20: extern char *formataddr (); /* hook for custom address formatting */
21:
22: int fmt_norm = AD_NAME;
23: struct mailname fmt_mnull;
24:
25: /* */
26:
27: /* MAJOR HACK: See MHCHANGES for discussion */
28:
29: char *new_fs (form, format, def)
30: register char *form,
31: *format,
32: *def;
33: {
34: struct stat st;
35: register FILE *fp;
36:
37: if (formats)
38: free (formats);
39:
40: if (form) {
41: if ((fp = fopen (libpath (form), "r")) == NULL)
42: adios (form, "unable to open format file");
43:
44: if (fstat (fileno (fp), &st) == NOTOK)
45: adios (form, "unable to stat format file");
46:
47: if ((formats = malloc ((unsigned) st.st_size)) == NULLCP)
48: adios (form, "unable to allocate space for format");
49:
50: if (read (fileno(fp), formats, st.st_size) != st.st_size)
51: adios (form, "error reading format file");
52:
53: (void) fclose (fp);
54: }
55: else {
56: formats = getcpy (format ? format : def);
57: }
58:
59: normalize (formats);
60:
61: return formats;
62: }
63:
64: /* */
65:
66: static normalize (cp)
67: register char *cp;
68: {
69: register char *dp;
70:
71: for (dp = cp; *cp; cp++)
72: if (*cp != QUOTE)
73: *dp++ = *cp;
74: else
75: switch (*++cp) {
76: #define grot(x) case 'x': *dp++ = '\x'; break;
77: grot (b);
78: grot (f);
79: grot (n);
80: grot (r);
81: grot (t);
82:
83: case '\n':
84: break;
85:
86: case NULL:
87: cp--; /* fall */
88: default:
89: *dp++ = *cp;
90: break;
91: }
92:
93: *dp = NULL;
94: }
95:
96: /* */
97: /*
98: * test if string "sub" appears anywhere in string "str"
99: * (case insensitive).
100: */
101:
102: static int match (str, sub)
103: register char *str,
104: *sub;
105: {
106: register int c1;
107: register int c2;
108: register char *s1;
109: register char *s2;
110:
111: while (c1 = *sub) {
112: while ((c2 = *str++) && (c1 | 040) != (c2 | 040))
113: ;
114: if (! c2)
115: return 0;
116: s1 = sub + 1; s2 = str;
117: while ((c1 = *s1++) && (c1 | 040) == (*s2++ | 040))
118: ;
119: if (! c1)
120: return 1;
121: }
122: return 1;
123: }
124: /* */
125:
126: /* macros to format data */
127:
128: #define PUTDF(cp, num, wid, fill) if (cp + wid < ep){\
129: if((i = (num))<0) i = -(num);\
130: sp = cp + wid;\
131: do {\
132: *--sp = (i % 10) + '0';\
133: i /= 10;\
134: } while (i > 0 && sp > cp);\
135: if (i > 0)\
136: *sp = '?';\
137: else if ((num) < 0 && sp > cp)\
138: *--sp = '-';\
139: while (sp > cp)\
140: *--sp = fill;\
141: cp += wid;\
142: }
143: #define PUTD(cp, num) if (cp < ep){\
144: if((i = (num))==0) *cp++ = '0';\
145: else {\
146: if((i = (num))<0) \
147: *cp++ = '-', i = -(num);\
148: c = 10;\
149: while (c <= i) \
150: c *= 10;\
151: while (cp < ep && c > 1) {\
152: c /= 10;\
153: *cp++ = (i / c) + '0';\
154: i %= c;\
155: }\
156: }\
157: }
158: #define PUTSF(cp, str, wid, fill) {\
159: i = (wid);\
160: if (sp = (str)) {\
161: while ((c = *sp) && c <= 32)\
162: sp++;\
163: while( (c = *sp++) && --i >= 0 && cp < ep)\
164: if ( c > 32 ) \
165: *cp++ = c;\
166: else {\
167: while ( (c = *sp) && c <= 32 )\
168: sp++;\
169: *cp++ = ' ';\
170: }\
171: }\
172: while( --i >= 0 && cp < ep)\
173: *cp++ = fill;\
174: }
175: #define PUTS(cp, str) {\
176: if (sp = (str)) {\
177: while ((c = *sp) && c <= 32)\
178: sp++;\
179: while( (c = *sp++) && cp < ep)\
180: if ( c > 32 ) \
181: *cp++ = c;\
182: else {\
183: while ( (c = *sp) && c <= 32 )\
184: sp++;\
185: *cp++ = ' ';\
186: }\
187: }\
188: }
189:
190:
191: static char *lmonth[] = { "January", "February","March", "April",
192: "May", "June", "July", "August",
193: "September","October", "November","December" };
194:
195:
196: fmtscan (format, scanl, width, dat)
197: struct format *format;
198: char *scanl;
199: int width;
200: int dat[];
201: {
202: register char *cp = scanl;
203: register char *ep = scanl + width - 1;
204: register struct format *fmt = format;
205: register char *str = NULLCP;
206: register int value = 0;
207: register char *sp;
208: register int i;
209: register int c;
210: register struct comp *comp;
211: register struct tws *tws;
212: register struct mailname *mn;
213: char *savestr;
214: char buffer[BUFSIZ];
215:
216: while (cp < ep) {
217: switch (fmt->f_type) {
218:
219: case FT_COMP:
220: PUTS (cp, fmt->f_comp->c_text);
221: break;
222: case FT_COMPF:
223: PUTSF (cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill);
224: break;
225:
226: case FT_LIT:
227: sp = fmt->f_text;
228: while( (c = *sp++) && cp < ep)
229: *cp++ = c;
230: break;
231: case FT_LITF:
232: sp = fmt->f_text; i = fmt->f_width;
233: while( (c = *sp++) && --i >= 0 && cp < ep)
234: *cp++ = c;
235: while( --i >= 0 && cp < ep)
236: *cp++ = fmt->f_fill;
237: break;
238:
239: case FT_STR:
240: PUTS (cp, str);
241: break;
242: case FT_STRF:
243: PUTSF (cp, str, fmt->f_width, fmt->f_fill);
244: break;
245: case FT_STRFW:
246: adios (NULLCP, "internal error (FT_STRFW)");
247:
248: case FT_NUM:
249: PUTD (cp, value);
250: break;
251: case FT_NUMF:
252: PUTDF (cp, value, fmt->f_width, fmt->f_fill);
253: break;
254:
255: case FT_CHAR:
256: *cp++ = fmt->f_char;
257: break;
258:
259: case FT_DONE:
260: goto finished;
261:
262: case FT_IF_S:
263: if (str == NULLCP || *str == NULL) {
264: fmt += fmt->f_skip;
265: continue;
266: }
267: break;
268:
269: case FT_IF_S_NULL:
270: if (str != NULLCP && *str != NULL) {
271: fmt += fmt->f_skip;
272: continue;
273: }
274: break;
275:
276: case FT_IF_V_EQ:
277: if (value != fmt->f_value) {
278: fmt += fmt->f_skip;
279: continue;
280: }
281: break;
282:
283: case FT_IF_V_NE:
284: if (value == fmt->f_value) {
285: fmt += fmt->f_skip;
286: continue;
287: }
288: break;
289:
290: case FT_IF_V_GT:
291: if (value <= fmt->f_value) {
292: fmt += fmt->f_skip;
293: continue;
294: }
295: break;
296:
297: case FT_IF_MATCH:
298: if (! match (str, fmt->f_text)) {
299: fmt += fmt->f_skip;
300: continue;
301: }
302: break;
303:
304: case FT_V_MATCH:
305: value = match (str, fmt->f_text);
306: break;
307:
308: case FT_IF_AMATCH:
309: if (! uprf (str, fmt->f_text)) {
310: fmt += fmt->f_skip;
311: continue;
312: }
313: break;
314:
315: case FT_V_AMATCH:
316: value = uprf (str, fmt->f_text);
317: break;
318:
319: case FT_S_NONNULL:
320: value = (str != NULLCP && *str != NULL);
321: break;
322:
323: case FT_S_NULL:
324: value = (str == NULLCP || *str == NULL);
325: break;
326:
327: case FT_V_EQ:
328: value = (fmt->f_value == value);
329: break;
330:
331: case FT_V_NE:
332: value = (fmt->f_value != value);
333: break;
334:
335: case FT_V_GT:
336: value = (fmt->f_value > value);
337: break;
338:
339: case FT_GOTO:
340: fmt += fmt->f_skip;
341: continue;
342:
343: case FT_NOP:
344: break;
345:
346: case FT_LS_COMP:
347: str = fmt->f_comp->c_text;
348: break;
349: case FT_LS_LIT:
350: str = fmt->f_text;
351: break;
352:
353: case FT_LV_COMPFLAG:
354: value = fmt->f_comp->c_flags;
355: break;
356: case FT_LV_COMP:
357: value = (comp = fmt->f_comp)->c_text ? atoi(comp->c_text) : 0;
358: break;
359: case FT_LV_LIT:
360: value = fmt->f_value;
361: break;
362: case FT_LV_DAT:
363: value = dat[fmt->f_value];
364: break;
365: case FT_LV_STRLEN:
366: value = strlen(str);
367: break;
368: case FT_LV_CHAR_LEFT:
369: value = width - (cp - scanl);
370: break;
371: case FT_LV_PLUS_L:
372: value += fmt->f_value;
373: break;
374: case FT_LV_MINUS_L:
375: value = fmt->f_value - value;
376: break;
377: case FT_SAVESTR:
378: savestr = str;
379: break;
380:
381: case FT_LV_SEC:
382: value = fmt->f_comp->c_tws->tw_sec;
383: break;
384: case FT_LV_MIN:
385: value = fmt->f_comp->c_tws->tw_min;
386: break;
387: case FT_LV_HOUR:
388: value = fmt->f_comp->c_tws->tw_hour;
389: break;
390: case FT_LV_MDAY:
391: value = fmt->f_comp->c_tws->tw_mday;
392: break;
393: case FT_LV_MON:
394: value = fmt->f_comp->c_tws->tw_mon + 1;
395: break;
396: case FT_LS_MONTH:
397: str = tw_moty[fmt->f_comp->c_tws->tw_mon];
398: break;
399: case FT_LS_LMONTH:
400: str = lmonth[fmt->f_comp->c_tws->tw_mon];
401: break;
402: case FT_LS_ZONE:
403: str = dtwszone (fmt->f_comp->c_tws);
404: break;
405: case FT_LV_YEAR:
406: value = fmt->f_comp->c_tws->tw_year;
407: break;
408: case FT_LV_WDAY:
409: if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
410: set_dotw (tws);
411: value = tws->tw_wday;
412: break;
413: case FT_LS_DAY:
414: if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
415: set_dotw (tws);
416: str = tw_dotw[tws->tw_wday];
417: break;
418: case FT_LS_WEEKDAY:
419: if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
420: set_dotw (tws);
421: str = tw_ldotw[tws->tw_wday];
422: break;
423: case FT_LV_YDAY:
424: value = fmt->f_comp->c_tws->tw_yday;
425: break;
426: case FT_LV_ZONE:
427: value = fmt->f_comp->c_tws->tw_zone;
428: break;
429: case FT_LV_CLOCK:
430: if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
431: value = twclock(fmt->f_comp->c_tws);
432: break;
433: case FT_LV_RCLOCK:
434: if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
435: value = twclock(fmt->f_comp->c_tws);
436: value = time((long *) 0) - value;
437: break;
438: case FT_LV_DAYF:
439: if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
440: set_dotw (tws);
441: switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) {
442: case TW_SEXP:
443: value = 1; break;
444: case TW_SIMP:
445: value = 0; break;
446: default:
447: value = -1; break;
448: }
449: break;
450: case FT_LV_TZONEF:
451: value = fmt->f_comp->c_tws->tw_flags & TW_DST;
452: break;
453: case FT_LS_822DATE:
454: str = dasctime ( fmt->f_comp->c_tws , TW_ZONE);
455: break;
456: case FT_LS_PRETTY:
457: str = dasctime ( fmt->f_comp->c_tws, TW_NULL);
458: break;
459:
460: case FT_LS_PERS:
461: str = fmt->f_comp->c_mn->m_pers;
462: break;
463: case FT_LS_MBOX:
464: str = fmt->f_comp->c_mn->m_mbox;
465: break;
466: case FT_LS_HOST:
467: str = fmt->f_comp->c_mn->m_host;
468: break;
469: case FT_LS_PATH:
470: str = fmt->f_comp->c_mn->m_path;
471: break;
472: case FT_LS_GNAME:
473: str = fmt->f_comp->c_mn->m_gname;
474: break;
475: case FT_LS_NOTE:
476: str = fmt->f_comp->c_mn->m_note;
477: break;
478: case FT_LS_822ADDR:
479: str = adrformat( fmt->f_comp->c_mn );
480: break;
481: case FT_LV_HOSTTYPE:
482: value = fmt->f_comp->c_mn->m_type;
483: break;
484: case FT_LV_INGRPF:
485: value = fmt->f_comp->c_mn->m_ingrp;
486: break;
487: case FT_LV_NOHOSTF:
488: value = fmt->f_comp->c_mn->m_nohost;
489: break;
490: case FT_LS_FRIENDLY:
491: #ifdef BERK
492: str = fmt->f_comp->c_mn->m_mbox;
493: #else not BERK
494: mn = fmt -> f_comp -> c_mn;
495: if ((str = mn -> m_pers) == NULL)
496: switch (mn -> m_type) {
497: case LOCALHOST:
498: str = mn -> m_mbox;
499: break;
500: case UUCPHOST:
501: (void) sprintf (buffer, "%s!%s",
502: mn -> m_host, mn -> m_mbox);
503: str = buffer;
504: break;
505: default:
506: if (mn -> m_mbox) {
507: (void) sprintf (buffer, "%s@%s",
508: mn -> m_mbox, mn -> m_host);
509: str= buffer;
510: }
511: else
512: str = mn -> m_text;
513: break;
514: }
515: #endif BERK
516: break;
517:
518: case FT_PARSEDATE:
519: comp = fmt->f_comp;
520: if ((sp = comp->c_text) && (tws = dparsetime(sp))) {
521: *comp->c_tws = *tws;
522: comp->c_flags = 0;
523: } else if (comp->c_flags >= 0) {
524: bzero ((char *) comp -> c_tws, sizeof *comp -> c_tws);
525: comp->c_flags = 1;
526: }
527: break;
528:
529: case FT_FORMATADDR:
530: /* hook for custom address list formatting (see replsbr.c) */
531: str = formataddr (savestr, str);
532: break;
533:
534: case FT_PUTADDR:
535: /* output the str register as an address component,
536: * splitting it into multiple lines if necessary. The
537: * value reg. contains the max line length. The lit.
538: * field may contain a string to prepend to the result
539: * (e.g., "To: ")
540: */
541: {
542: register char *lp = str;
543: register int indent;
544: register int wid = value;
545: register int len = strlen (str);
546: register char *lastb;
547:
548: sp = fmt->f_text;
549: indent = strlen (sp);
550: wid -= indent;
551: while( (c = *sp++) && cp < ep)
552: *cp++ = c;
553: while (len > wid) {
554: /* try to break at a comma; failing that, break at a
555: * space, failing that, just split the line.
556: */
557: lastb = 0; sp = lp + wid;
558: while (sp > lp && (c = *--sp) != ',') {
559: if (! lastb && isspace(c))
560: lastb = sp - 1;
561: }
562: if (sp == lp)
563: if (! (sp = lastb))
564: sp = lp + wid - 1;
565: len -= sp - lp + 1;
566: while (cp < ep && lp <= sp)
567: *cp++ = *lp++;
568: *cp++ = '\n';
569: for (i=indent; cp < ep && i > 0; i--)
570: *cp++ = ' ';
571: while (isspace(*lp))
572: lp++, len--;
573: }
574: PUTS (cp, lp);
575: }
576: break;
577:
578: case FT_PARSEADDR:
579: comp = fmt->f_comp;
580: if (comp->c_mn != &fmt_mnull)
581: mnfree (comp->c_mn);
582: if ((sp = comp->c_text) && (sp = getname(sp)) &&
583: (mn = getm (sp, NULLCP, 0, fmt_norm, NULLCP))) {
584: comp->c_mn = mn;
585: while (getname(""))
586: ;
587: } else
588: comp->c_mn = &fmt_mnull;
589: break;
590:
591: case FT_MYMBOX:
592: /*
593: * if there's no component, we say true. Otherwise we
594: * say "true" only if we can parse the address and it
595: * matches one of our addresses.
596: */
597: comp = fmt->f_comp;
598: if (comp->c_mn != &fmt_mnull)
599: mnfree (comp->c_mn);
600: if ((sp = comp->c_text) && (sp = getname(sp)) &&
601: (mn = getm (sp, NULLCP, 0, AD_NAME, NULLCP))) {
602: comp->c_mn = mn;
603: comp->c_flags = ismymbox(mn);
604: while (getname(""))
605: ;
606: } else {
607: comp->c_flags = (comp->c_text == 0);
608: comp->c_mn = &fmt_mnull;
609: }
610: break;
611: }
612: fmt++;
613: }
614: finished:;
615: if (cp[-1] != '\n')
616: *cp++ = '\n';
617: *cp = NULL;
618: return (value);
619: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.