|
|
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: #define NFMTS MAXARGS
14: #define QUOTE '\\'
15:
16: static char *formats = 0;
17: extern char *formataddr(); /* hook for custom address formatting */
18: struct msgs *fmt_current_folder;/* current folder (set by main program) */
19:
20: int fmt_norm = AD_NAME;
21: struct mailname fmt_mnull;
22:
23:
24: static
25: normalize(cp)
26: register char *cp;
27: {
28: register char *dp;
29:
30: for (dp = cp; *cp; cp++)
31: if (*cp != QUOTE)
32: *dp++ = *cp;
33: else
34: switch (*++cp) {
35:
36: case 'b':
37: *dp++ = '\b';
38: break;
39: case 'f':
40: *dp++ = '\f';
41: break;
42: case 'n':
43: *dp++ = '\n';
44: break;
45: case 'r':
46: *dp++ = '\r';
47: break;
48: case 't':
49: *dp++ = '\t';
50: break;
51:
52: case '\n':
53: break;
54:
55: case NULL:
56: cp--;
57: /* fall through */
58: default:
59: *dp++ = *cp;
60: break;
61: }
62:
63: *dp = NULL;
64: }
65:
66: char *
67: new_fs(form, format, def)
68: register char *form, *format, *def;
69: {
70: struct stat st;
71: register FILE *fp;
72:
73: if (formats)
74: free(formats);
75:
76: if (form) {
77: if ((fp = fopen(libpath(form), "r")) == NULL)
78: adios(form, "unable to open format file");
79:
80: if (fstat(fileno(fp), &st) == NOTOK)
81: adios(form, "unable to stat format file");
82:
83: if ((formats = malloc((unsigned) st.st_size + 1)) == NULLCP)
84: adios(form, "unable to allocate space for format");
85:
86: if (read(fileno(fp), formats, st.st_size) != st.st_size)
87: adios(form, "error reading format file");
88:
89: formats[st.st_size] = '\0';
90: (void) fclose(fp);
91: } else {
92: formats = getcpy(format ? format : def);
93: }
94:
95: normalize(formats);
96:
97: return formats;
98: }
99:
100: /*
101: * test if string "sub" appears anywhere in string "str"
102: * (case insensitive).
103: */
104: static int
105: match(str, sub)
106: register char *str, *sub;
107: {
108: register int c1;
109: register int c2;
110: register char *s1;
111: register char *s2;
112:
113: while (c1 = *sub) {
114: while ((c2 = *str++) && (c1 | 040) != (c2 | 040))
115: ;
116: if (!c2)
117: return 0;
118: s1 = sub + 1;
119: s2 = str;
120: while ((c1 = *s1++) && (c1 | 040) == (*s2++ | 040))
121: ;
122: if (!c1)
123: return 1;
124: }
125: return 1;
126: }
127:
128: /* macros to format data */
129:
130: #define PUTDF(cp, num, wid, fill) {\
131: if (cp + wid < ep) {\
132: if ((i = (num)) < 0)\
133: i = -(num);\
134: if ((c = (wid)) < 0)\
135: c = -c;\
136: sp = cp + c;\
137: do {\
138: *--sp = (i % 10) + '0';\
139: i /= 10;\
140: } while (i > 0 && sp > cp);\
141: if (i > 0)\
142: *sp = '?';\
143: else if ((num) < 0 && sp > cp)\
144: *--sp = '-';\
145: while (sp > cp)\
146: *--sp = fill;\
147: cp += c;\
148: }}
149: #define PUTD(cp, num) {\
150: if (cp < ep) {\
151: if ((i = (num)) == 0)\
152: *cp++ = '0';\
153: else {\
154: if ((i = (num)) < 0) \
155: *cp++ = '-', i = -(num);\
156: c = 10;\
157: while (c <= i) \
158: c *= 10;\
159: while (cp < ep && c > 1) {\
160: c /= 10;\
161: *cp++ = (i / c) + '0';\
162: i %= c;\
163: }\
164: }\
165: }}
166: #define PUTSF(cp, str, wid, fill) {\
167: rjust = 0;\
168: if ((i = (wid)) < 0) {\
169: i = -i;\
170: rjust++;\
171: }\
172: if (sp = (str)) {\
173: if (rjust) {\
174: c = strlen(sp);\
175: if (c > i)\
176: sp += c - i;\
177: else {\
178: while (--i >= c && cp < ep)\
179: *cp++ = fill;\
180: i++;\
181: }\
182: } else {\
183: while ((c = *sp) && c <= 32)\
184: sp++;\
185: }\
186: while ((c = *sp++) && --i >= 0 && cp < ep)\
187: if (c > 32) \
188: *cp++ = c;\
189: else {\
190: while ((c = *sp) && c <= 32)\
191: sp++;\
192: *cp++ = ' ';\
193: }\
194: }\
195: if (!rjust)\
196: while (--i >= 0 && cp < ep)\
197: *cp++ = fill;\
198: }
199:
200: #define PUTS(cp, str) {\
201: if (sp = (str)) {\
202: while ((c = *sp) && c <= 32)\
203: sp++;\
204: while ((c = *sp++) && cp < ep)\
205: if (c > 32) \
206: *cp++ = c;\
207: else {\
208: while ((c = *sp) && c <= 32)\
209: sp++;\
210: *cp++ = ' ';\
211: }\
212: }}
213:
214: static char *lmonth[] = {
215: "January", "February", "March", "April", "May", "June",
216: "July", "August", "September", "October", "November", "December"
217: };
218:
219:
220: fmtscan(format, scanl, width, dat)
221: struct format *format;
222: char *scanl;
223: int width;
224: int dat[];
225: {
226: register char *cp = scanl;
227: register char *ep = scanl + width - 1;
228: register struct format *fmt = format;
229: register char *str = NULLCP;
230: register int value = 0;
231: register char *sp;
232: register int i;
233: register int c;
234: register struct comp *comp;
235: register struct tws *tws;
236: register struct mailname *mn;
237: register int j;
238: int rjust;
239: long l;
240: char *savestr;
241: char buffer[BUFSIZ];
242:
243: for (;;) {
244: switch (fmt->f_type) {
245:
246: case FT_COMP:
247: PUTS(cp, fmt->f_comp->c_text);
248: break;
249: case FT_COMPF:
250: PUTSF(cp, fmt->f_comp->c_text, fmt->f_width,
251: fmt->f_fill);
252: break;
253:
254: case FT_LIT_FORCE:
255: sp = fmt->f_text;
256: i = strlen(sp);
257: ep += i; /* forced lits are `invisible' */
258:
259: while (c = *sp++)
260: *cp++ = c;
261: break;
262: case FT_LIT:
263: sp = fmt->f_text;
264: while ((c = *sp++) && cp < ep)
265: *cp++ = c;
266: break;
267: case FT_LITF:
268: sp = fmt->f_text;
269:
270: /* By default we left justify */
271: rjust = 0;
272: if ((i = fmt->f_width) < 0) {
273: i = -i;
274: rjust++;
275: }
276:
277: if (rjust) {
278: j = strlen(sp);
279: if (j > i)
280: sp += j - i;
281: else while (j < i && cp < ep) {
282: *cp++ = fmt->f_fill;
283: ++j;
284: }
285: }
286:
287: while ((c = *sp++) && --i >= 0 && cp < ep)
288: *cp++ = c;
289:
290: while (--i >= 0 && cp < ep)
291: *cp++ = fmt->f_fill;
292: break;
293:
294: case FT_STR:
295: PUTS(cp, str);
296: break;
297: case FT_STRF:
298: PUTSF(cp, str, fmt->f_width, fmt->f_fill);
299: break;
300: case FT_STRFW:
301: adios(NULLCP, "internal error (FT_STRFW)");
302:
303: case FT_NUM:
304: PUTD(cp, value);
305: break;
306: case FT_NUMF:
307: PUTDF(cp, value, fmt->f_width, fmt->f_fill);
308: break;
309:
310: case FT_CHAR:
311: *cp++ = fmt->f_char;
312: break;
313: case FT_DONE:
314: goto finished;
315:
316: case FT_IF_S:
317: if (str == NULLCP || *str == NULL) {
318: fmt += fmt->f_skip;
319: continue;
320: }
321: break;
322:
323: case FT_IF_S_NULL:
324: if (str != NULLCP && *str != NULL) {
325: fmt += fmt->f_skip;
326: continue;
327: }
328: break;
329:
330: case FT_IF_V_EQ:
331: if (value != fmt->f_value) {
332: fmt += fmt->f_skip;
333: continue;
334: }
335: break;
336:
337: case FT_IF_V_NE:
338: if (value == fmt->f_value) {
339: fmt += fmt->f_skip;
340: continue;
341: }
342: break;
343:
344: case FT_IF_V_GT:
345: if (value <= fmt->f_value) {
346: fmt += fmt->f_skip;
347: continue;
348: }
349: break;
350:
351: case FT_IF_MATCH:
352: if (!str || !match(str, fmt->f_text)) {
353: fmt += fmt->f_skip;
354: continue;
355: }
356: break;
357:
358: case FT_V_MATCH:
359: if (str)
360: value = match(str, fmt->f_text);
361: else
362: value = 0;
363: break;
364:
365: case FT_IF_AMATCH:
366: if (!str || !uprf(str, fmt->f_text)) {
367: fmt += fmt->f_skip;
368: continue;
369: }
370: break;
371:
372: case FT_V_AMATCH:
373: if (str)
374: value = uprf(str, fmt->f_text);
375: else
376: value = 0;
377: break;
378:
379: case FT_S_NONNULL:
380: value = (str != NULLCP && *str != NULL);
381: break;
382:
383: case FT_S_NULL:
384: value = (str == NULLCP || *str == NULL);
385: break;
386:
387: case FT_V_EQ:
388: value = (fmt->f_value == value);
389: break;
390:
391: case FT_V_NE:
392: value = (fmt->f_value != value);
393: break;
394:
395: case FT_V_GT:
396: value = (fmt->f_value > value);
397: break;
398:
399: case FT_GOTO:
400: fmt += fmt->f_skip;
401: continue;
402:
403: case FT_NOP:
404: break;
405:
406: case FT_LS_COMP:
407: str = fmt->f_comp->c_text;
408: break;
409: case FT_LS_LIT:
410: str = fmt->f_text;
411: break;
412: case FT_LS_TRIM:
413: if (str) {
414: register char *xp;
415:
416: /* Be careful since str can point into buffer */
417: bcopy(str, buffer, strlen(str) + 1);
418: str = buffer;
419:
420: /* Eat leading whitespace */
421: while (isspace(*str))
422: str++;
423:
424: /* Trim trailing whitespace */
425: xp = str + strlen(str) - 1;
426: while (xp > str && isspace(*xp))
427: *xp-- = '\0';
428:
429: /* By default we left justify */
430: rjust = 0;
431: if ((i = fmt->f_width) < 0) {
432: i = -i;
433: rjust++;
434: }
435:
436: /* If necessary, limit width and/or justify */
437: if (i > 0 && (j = strlen(str)) > i) {
438: if (!rjust)
439: str[i] = '\0';
440: else
441: str += j - i;
442: }
443: }
444: break;
445:
446: case FT_LV_COMPFLAG:
447: value = fmt->f_comp->c_flags;
448: break;
449: case FT_LV_COMP:
450: value = (comp = fmt->f_comp)->c_text ?
451: atoi(comp->c_text) : 0;
452: break;
453: case FT_LV_LIT:
454: value = fmt->f_value;
455: break;
456: case FT_LV_DAT:
457: value = dat[fmt->f_value];
458: break;
459: case FT_LV_STRLEN:
460: value = strlen(str);
461: break;
462: case FT_LV_CHAR_LEFT:
463: value = width - (cp - scanl);
464: break;
465: case FT_LV_PLUS_L:
466: value += fmt->f_value;
467: break;
468: case FT_LV_MINUS_L:
469: value = fmt->f_value - value;
470: break;
471: case FT_LV_DIVIDE_L:
472: if (fmt->f_value)
473: value = value / fmt->f_value;
474: else
475: value = 0;
476: break;
477: case FT_SAVESTR:
478: savestr = str;
479: break;
480:
481: case FT_LV_SEC:
482: value = fmt->f_comp->c_tws->tw_sec;
483: break;
484: case FT_LV_MIN:
485: value = fmt->f_comp->c_tws->tw_min;
486: break;
487: case FT_LV_HOUR:
488: value = fmt->f_comp->c_tws->tw_hour;
489: break;
490: case FT_LV_MDAY:
491: value = fmt->f_comp->c_tws->tw_mday;
492: break;
493: case FT_LV_MON:
494: value = fmt->f_comp->c_tws->tw_mon + 1;
495: break;
496: case FT_LS_MONTH:
497: str = tw_moty[fmt->f_comp->c_tws->tw_mon];
498: break;
499: case FT_LS_LMONTH:
500: str = lmonth[fmt->f_comp->c_tws->tw_mon];
501: break;
502: case FT_LS_ZONE:
503: str = dtwszone(fmt->f_comp->c_tws);
504: break;
505: case FT_LV_YEAR:
506: value = fmt->f_comp->c_tws->tw_year;
507: break;
508: case FT_LV_WDAY:
509: if (!(((tws = fmt->f_comp->c_tws)->tw_flags) &
510: (TW_SEXP | TW_SIMP)))
511: set_dotw(tws);
512: value = tws->tw_wday;
513: break;
514: case FT_LS_DAY:
515: if (!(((tws = fmt->f_comp->c_tws)->tw_flags) &
516: (TW_SEXP | TW_SIMP)))
517: set_dotw(tws);
518: str = tw_dotw[tws->tw_wday];
519: break;
520: case FT_LS_WEEKDAY:
521: if (!(((tws = fmt->f_comp->c_tws)->tw_flags) &
522: (TW_SEXP | TW_SIMP)))
523: set_dotw(tws);
524: str = tw_ldotw[tws->tw_wday];
525: break;
526: case FT_LV_YDAY:
527: value = fmt->f_comp->c_tws->tw_yday;
528: break;
529: case FT_LV_ZONE:
530: value = fmt->f_comp->c_tws->tw_zone;
531: break;
532: case FT_LV_CLOCK:
533: if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
534: value = twclock(fmt->f_comp->c_tws);
535: break;
536: case FT_LV_RCLOCK:
537: if ((value = fmt->f_comp->c_tws->tw_clock) == 0)
538: value = twclock(fmt->f_comp->c_tws);
539: value = time((long *) 0) - value;
540: break;
541: case FT_LV_DAYF:
542: if (!(((tws = fmt->f_comp->c_tws)->tw_flags) &
543: (TW_SEXP | TW_SIMP)))
544: set_dotw(tws);
545: switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) {
546: case TW_SEXP:
547: value = 1;
548: break;
549: case TW_SIMP:
550: value = 0;
551: break;
552: default:
553: value = -1;
554: break;
555: }
556: case FT_LV_ZONEF:
557: if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) ==
558: TW_SZEXP)
559: value = 1;
560: else
561: value = -1;
562: break;
563: case FT_LV_DST:
564: value = fmt->f_comp->c_tws->tw_flags & TW_DST;
565: break;
566: case FT_LS_822DATE:
567: str = dasctime(fmt->f_comp->c_tws, TW_ZONE);
568: break;
569: case FT_LS_PRETTY:
570: str = dasctime(fmt->f_comp->c_tws, TW_NULL);
571: break;
572:
573: case FT_LS_PERS:
574: str = fmt->f_comp->c_mn->m_pers;
575: break;
576: case FT_LS_MBOX:
577: str = fmt->f_comp->c_mn->m_mbox;
578: break;
579: case FT_LS_HOST:
580: str = fmt->f_comp->c_mn->m_host;
581: break;
582: case FT_LS_PATH:
583: str = fmt->f_comp->c_mn->m_path;
584: break;
585: case FT_LS_GNAME:
586: str = fmt->f_comp->c_mn->m_gname;
587: break;
588: case FT_LS_NOTE:
589: str = fmt->f_comp->c_mn->m_note;
590: break;
591: case FT_LS_822ADDR:
592: str = adrformat(fmt->f_comp->c_mn);
593: break;
594: case FT_LV_HOSTTYPE:
595: value = fmt->f_comp->c_mn->m_type;
596: break;
597: case FT_LV_INGRPF:
598: value = fmt->f_comp->c_mn->m_ingrp;
599: break;
600: case FT_LV_NOHOSTF:
601: value = fmt->f_comp->c_mn->m_nohost;
602: break;
603: case FT_LS_FRIENDLY:
604: #ifdef BERK
605: str = fmt->f_comp->c_mn->m_mbox;
606: #else
607: mn = fmt->f_comp->c_mn;
608: if ((str = mn->m_pers) == NULL)
609: switch (mn->m_type) {
610:
611: case LOCALHOST:
612: str = mn->m_mbox;
613: break;
614: case UUCPHOST:
615: (void) sprintf(buffer, "%s!%s",
616: mn->m_host, mn->m_mbox);
617: str = buffer;
618: break;
619: default:
620: if (mn->m_mbox) {
621: (void) sprintf(buffer, "%s@%s",
622: mn->m_mbox, mn->m_host);
623: str = buffer;
624: } else
625: str = mn->m_text;
626: break;
627: }
628: #endif BERK
629: break;
630:
631: case FT_LOCALDATE:
632: comp = fmt->f_comp;
633: if ((l = comp->c_tws->tw_clock) == 0)
634: l = twclock(comp->c_tws);
635: tws = dlocaltime(&l);
636: *comp->c_tws = *tws;
637: break;
638:
639: case FT_GMTDATE:
640: comp = fmt->f_comp;
641: if ((l = comp->c_tws->tw_clock) == 0)
642: l = twclock(comp->c_tws);
643: tws = dgmtime(&l);
644: *comp->c_tws = *tws;
645: break;
646:
647: case FT_PARSEDATE:
648: comp = fmt->f_comp;
649: if ((sp = comp->c_text) && (tws = dparsetime(sp))) {
650: *comp->c_tws = *tws;
651: comp->c_flags = 0;
652: } else if (comp->c_flags >= 0) {
653: bzero((char *)comp->c_tws,
654: sizeof(*comp->c_tws));
655: comp->c_flags = 1;
656: }
657: break;
658:
659: case FT_FORMATADDR:
660: /* custom address list formatting hook */
661: str = formataddr(savestr, str);
662: break;
663:
664: case FT_PUTADDR:
665: /*
666: * Output the str register as an address component,
667: * splitting it into multiple lines if necessary.
668: * The value reg. contains the max line length. The
669: * lit. field may contain a string to prepend to the
670: * result (e.g., "To: ")
671: */
672: {
673: register char *lp = str;
674: register int indent;
675: register int wid = value;
676: register int len = strlen(str);
677: register char *lastb;
678:
679: sp = fmt->f_text;
680: indent = strlen(sp);
681: wid -= indent;
682: while ((c = *sp++) && cp < ep)
683: *cp++ = c;
684: while (len > wid) {
685: /*
686: * Try to break at a comma; failing
687: * that, break at a space, failing
688: * that, just split the line.
689: */
690: lastb = 0;
691: sp = lp + wid;
692: while (sp > lp && (c = *--sp) != ',') {
693: if (!lastb && isspace(c))
694: lastb = sp - 1;
695: }
696: if (sp == lp)
697: if (!(sp = lastb))
698: sp = lp + wid - 1;
699: len -= sp - lp + 1;
700: while (cp < ep && lp <= sp)
701: *cp++ = *lp++;
702: *cp++ = '\n';
703: for (i = indent; cp < ep && i > 0; i--)
704: *cp++ = ' ';
705: while (isspace(*lp))
706: lp++, len--;
707: }
708: PUTS(cp, lp);
709: }
710: break;
711:
712: case FT_PARSEADDR:
713: comp = fmt->f_comp;
714: if (comp->c_mn != &fmt_mnull)
715: mnfree(comp->c_mn);
716: if ((sp = comp->c_text) && (sp = getname(sp)) &&
717: (mn = getm(sp, NULLCP, 0, fmt_norm, NULLCP))) {
718: comp->c_mn = mn;
719: while (getname(""))
720: ;
721: } else
722: comp->c_mn = &fmt_mnull;
723: break;
724:
725: case FT_MYMBOX:
726: /*
727: * If there's no component, we say true. Otherwise
728: * we say "true" only if we can parse the address and
729: * it matches one of our addresses.
730: */
731: comp = fmt->f_comp;
732: if (comp->c_mn != &fmt_mnull)
733: mnfree(comp->c_mn);
734: if ((sp = comp->c_text) && (sp = getname(sp)) &&
735: (mn = getm(sp, NULLCP, 0, AD_NAME, NULLCP))) {
736: comp->c_mn = mn;
737: comp->c_flags = ismymbox(mn);
738: while (sp = getname(sp))
739: if (comp->c_flags == 0 &&
740: (mn = getm(sp, NULLCP, 0,
741: AD_NAME, NULLCP)))
742: comp->c_flags |= ismymbox(mn);
743: } else {
744: comp->c_flags = (comp->c_text == 0);
745: comp->c_mn = &fmt_mnull;
746: }
747: break;
748:
749: case FT_ADDTOSEQ:
750: /*
751: * If we're working on a folder (as opposed to a
752: * file), add the current msg to sequence given in
753: * literal field. Don't disturb string or value
754: * registers.
755: */
756: if (fmt_current_folder)
757: (void) m_seqadd(fmt_current_folder,
758: fmt->f_text, dat[0], -1);
759: break;
760: }
761: fmt++;
762: }
763: finished:
764: if (cp[-1] != '\n')
765: *cp++ = '\n';
766: *cp = NULL;
767: return (value);
768: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.