]>
diplodocus.org Git - nmh/blob - docs/historical/mh-6.8.5/sbr/fmtcompile.c
1 /* fmtcompile.c - "compile" format strings for fmtscan */
3 static char ident
[] = "@(#)$Id: fmtcompile.c,v 1.17 1993/08/19 21:05:42 jromine Exp shettich $";
7 #include "../h/addrsbr.h"
8 #include "../h/formatsbr.h"
9 #include "../zotnet/tws.h"
10 #include "../h/fmtcompile.h"
13 #include <sys/types.h>
16 static struct format
*formatvec
; /* array to hold formats */
17 static struct format
*next_fp
; /* next free format slot */
18 static struct format
*fp
; /* current format slot */
19 static struct comp
*cm
; /* most recent comp ref */
20 static struct ftable
*ftbl
; /* most recent func ref */
22 static int infunction
; /* function nesting cnt */
24 extern char *getusr();
25 extern struct mailname fmt_mnull
;
28 char *name
; /* function name */
29 char type
; /* argument type */
30 #define TF_COMP 0 /* component expected */
31 #define TF_NUM 1 /* number expected */
32 #define TF_STR 2 /* string expected */
33 #define TF_EXPR 3 /* component or func. expected */
34 #define TF_NONE 4 /* no argument */
35 #define TF_MYBOX 5 /* special - get current user's mbox */
36 #define TF_NOW 6 /* special - get current unix time */
37 #define TF_EXPR_SV 7 /* like expr but save current str reg */
38 #define TF_NOP 8 /* like expr but no result */
39 char f_type
; /* fmt type */
40 char extra
; /* arg. type dependent extra info */
42 #define TFL_PUTS 1 /* implicit putstr if top level */
43 #define TFL_PUTN 2 /* implicit putnum if top level */
46 static struct ftable functable
[] = {
47 "nonzero", TF_EXPR
, FT_V_NE
, FT_IF_V_NE
, 0,
48 "zero", TF_EXPR
, FT_V_EQ
, FT_IF_V_EQ
, 0,
49 "eq", TF_NUM
, FT_V_EQ
, FT_IF_V_EQ
, 0,
50 "ne", TF_NUM
, FT_V_NE
, FT_IF_V_NE
, 0,
51 "gt", TF_NUM
, FT_V_GT
, FT_IF_V_GT
, 0,
52 "null", TF_EXPR
, FT_S_NULL
, FT_IF_S_NULL
, 0,
53 "nonnull", TF_EXPR
, FT_S_NONNULL
, FT_IF_S
, 0,
54 "match", TF_STR
, FT_V_MATCH
, FT_IF_MATCH
, 0,
55 "amatch", TF_STR
, FT_V_AMATCH
, FT_IF_AMATCH
, 0,
57 "putstr", TF_EXPR
, FT_STR
, 0, 0,
58 "putstrf", TF_EXPR
, FT_STRF
, 0, 0,
59 "putnum", TF_EXPR
, FT_NUM
, 0, 0,
60 "putnumf", TF_EXPR
, FT_NUMF
, 0, 0,
61 "putaddr", TF_STR
, FT_PUTADDR
, 0, 0,
62 "void", TF_NOP
, 0, 0, 0,
64 "comp", TF_COMP
, FT_LS_COMP
, 0, TFL_PUTS
,
65 "lit", TF_STR
, FT_LS_LIT
, 0, TFL_PUTS
,
66 "getenv", TF_STR
, FT_LS_GETENV
, 0, TFL_PUTS
,
67 "profile", TF_STR
, FT_LS_MFIND
, 0, TFL_PUTS
,
68 "trim", TF_EXPR
, FT_LS_TRIM
, 0, 0,
69 "compval", TF_COMP
, FT_LV_COMP
, 0, TFL_PUTN
,
70 "compflag", TF_COMP
, FT_LV_COMPFLAG
, 0, TFL_PUTN
,
71 "num", TF_NUM
, FT_LV_LIT
, 0, TFL_PUTN
,
72 "msg", TF_NONE
, FT_LV_DAT
, 0, TFL_PUTN
,
73 "cur", TF_NONE
, FT_LV_DAT
, 1, TFL_PUTN
,
74 "size", TF_NONE
, FT_LV_DAT
, 2, TFL_PUTN
,
75 "width", TF_NONE
, FT_LV_DAT
, 3, TFL_PUTN
,
76 "unseen", TF_NONE
, FT_LV_DAT
, 4, TFL_PUTN
,
77 "dat", TF_NUM
, FT_LV_DAT
, 0, TFL_PUTN
,
78 "strlen", TF_NONE
, FT_LV_STRLEN
, 0, TFL_PUTN
,
79 "me", TF_MYBOX
, FT_LS_LIT
, 0, TFL_PUTS
,
80 "plus", TF_NUM
, FT_LV_PLUS_L
, 0, TFL_PUTN
,
81 "minus", TF_NUM
, FT_LV_MINUS_L
, 0, TFL_PUTN
,
82 "divide", TF_NUM
, FT_LV_DIVIDE_L
, 0, TFL_PUTN
,
83 "modulo", TF_NUM
, FT_LV_MODULO_L
, 0, TFL_PUTN
,
84 "charleft", TF_NONE
, FT_LV_CHAR_LEFT
, 0, TFL_PUTN
,
85 "timenow", TF_NOW
, FT_LV_LIT
, 0, TFL_PUTN
,
87 "month", TF_COMP
, FT_LS_MONTH
, FT_PARSEDATE
, TFL_PUTS
,
88 "lmonth", TF_COMP
, FT_LS_LMONTH
, FT_PARSEDATE
, TFL_PUTS
,
89 "tzone", TF_COMP
, FT_LS_ZONE
, FT_PARSEDATE
, TFL_PUTS
,
90 "day", TF_COMP
, FT_LS_DAY
, FT_PARSEDATE
, TFL_PUTS
,
91 "weekday", TF_COMP
, FT_LS_WEEKDAY
, FT_PARSEDATE
, TFL_PUTS
,
92 "tws", TF_COMP
, FT_LS_822DATE
, FT_PARSEDATE
, TFL_PUTS
,
93 "sec", TF_COMP
, FT_LV_SEC
, FT_PARSEDATE
, TFL_PUTN
,
94 "min", TF_COMP
, FT_LV_MIN
, FT_PARSEDATE
, TFL_PUTN
,
95 "hour", TF_COMP
, FT_LV_HOUR
, FT_PARSEDATE
, TFL_PUTN
,
96 "mday", TF_COMP
, FT_LV_MDAY
, FT_PARSEDATE
, TFL_PUTN
,
97 "mon", TF_COMP
, FT_LV_MON
, FT_PARSEDATE
, TFL_PUTN
,
98 "year", TF_COMP
, FT_LV_YEAR
, FT_PARSEDATE
, TFL_PUTN
,
99 "yday", TF_COMP
, FT_LV_YDAY
, FT_PARSEDATE
, TFL_PUTN
,
100 "wday", TF_COMP
, FT_LV_WDAY
, FT_PARSEDATE
, TFL_PUTN
,
101 "zone", TF_COMP
, FT_LV_ZONE
, FT_PARSEDATE
, TFL_PUTN
,
102 "clock", TF_COMP
, FT_LV_CLOCK
, FT_PARSEDATE
, TFL_PUTN
,
103 "rclock", TF_COMP
, FT_LV_RCLOCK
, FT_PARSEDATE
, TFL_PUTN
,
104 "sday", TF_COMP
, FT_LV_DAYF
, FT_PARSEDATE
, TFL_PUTN
,
105 "szone", TF_COMP
, FT_LV_ZONEF
, FT_PARSEDATE
, TFL_PUTN
,
106 "dst", TF_COMP
, FT_LV_DST
, FT_PARSEDATE
, TFL_PUTN
,
107 "pretty", TF_COMP
, FT_LS_PRETTY
, FT_PARSEDATE
, TFL_PUTS
,
108 "nodate", TF_COMP
, FT_LV_COMPFLAG
, FT_PARSEDATE
, TFL_PUTN
,
109 "date2local", TF_COMP
, FT_LOCALDATE
, FT_PARSEDATE
, 0,
110 "date2gmt", TF_COMP
, FT_GMTDATE
, FT_PARSEDATE
, 0,
112 "pers", TF_COMP
, FT_LS_PERS
, FT_PARSEADDR
, TFL_PUTS
,
113 "mbox", TF_COMP
, FT_LS_MBOX
, FT_PARSEADDR
, TFL_PUTS
,
114 "host", TF_COMP
, FT_LS_HOST
, FT_PARSEADDR
, TFL_PUTS
,
115 "path", TF_COMP
, FT_LS_PATH
, FT_PARSEADDR
, TFL_PUTS
,
116 "gname", TF_COMP
, FT_LS_GNAME
, FT_PARSEADDR
, TFL_PUTS
,
117 "note", TF_COMP
, FT_LS_NOTE
, FT_PARSEADDR
, TFL_PUTS
,
118 "addr", TF_COMP
, FT_LS_ADDR
, FT_PARSEADDR
, TFL_PUTS
,
119 "proper", TF_COMP
, FT_LS_822ADDR
, FT_PARSEADDR
, TFL_PUTS
,
120 "type", TF_COMP
, FT_LV_HOSTTYPE
, FT_PARSEADDR
, TFL_PUTN
,
121 "ingrp", TF_COMP
, FT_LV_INGRPF
, FT_PARSEADDR
, TFL_PUTN
,
122 "nohost", TF_COMP
, FT_LV_NOHOSTF
, FT_PARSEADDR
, TFL_PUTN
,
123 "formataddr", TF_EXPR_SV
, FT_FORMATADDR
, FT_FORMATADDR
, 0,
124 "friendly", TF_COMP
, FT_LS_FRIENDLY
, FT_PARSEADDR
, TFL_PUTS
,
126 "mymbox", TF_COMP
, FT_LV_COMPFLAG
, FT_MYMBOX
, TFL_PUTN
,
127 "addtoseq", TF_STR
, FT_ADDTOSEQ
, 0, 0,
129 (char *)0, 0, 0, 0, 0
135 static struct ftable
*lookup(name
)
138 register struct ftable
*t
= functable
;
140 register char c
= *name
;
142 while (nm
= t
->name
) {
143 if (*nm
== c
&& strcmp (nm
, name
) == 0)
148 return (struct ftable
*)0;
152 #define NEWCOMP(cm,name)\
153 cm = ((struct comp *)calloc(1, sizeof (struct comp)));\
154 cm->c_name = name; ncomp++;\
155 i = CHASH(name); cm->c_next = wantcomp[i]; wantcomp[i] = cm;
157 #define NEWFMT (next_fp++)
158 #define NEW(type,fill,wid)\
159 fp=NEWFMT; fp->f_type=(type); fp->f_fill=(fill); fp->f_width=(wid);
162 FINDCOMP( cm, name );\
168 #define LV( type, value ) NEW(type,0,0); fp->f_value = (value);
169 #define LS( type, str ) NEW(type,0,0); fp->f_text = (str);
170 #define PUTCOMP( comp ) NEW(FT_COMP,0,0); ADDC(comp);
171 #define PUTLIT( str ) NEW(FT_LIT,0,0); fp->f_text = (str);
172 #define PUTC( c ) NEW(FT_CHAR,0,0); fp->f_char = (c);
174 static char *compile();
175 static char *do_spec();
176 static char *do_name();
177 static char *do_func();
178 static char *do_expr();
179 static char *do_if();
180 static char *do_loop();
182 static char *format_string
;
183 static char *usr_fstring
; /* for CERROR */
185 #define CERROR(str) compile_error (str, cp)
188 compile_error(str
, cp
)
192 int errpos
= cp
- format_string
;
193 int errctx
= errpos
> 20 ? 20 : errpos
;
196 usr_fstring
[errpos
] = '\0';
197 for (i
= errpos
-errctx
; i
< errpos
; i
++)
199 if (iscntrl(usr_fstring
[i
]))
201 if (usr_fstring
[i
] < 32)
203 usr_fstring
[i
] = '_';
204 advise(NULLCP
, "\"%s\": format compile error - %s",
205 &usr_fstring
[errpos
-errctx
], str
);
206 adios (NULLCP
, "%*s", errctx
+1, "^");
210 * Compile format string "fstring" into format list "fmt".
211 * Return the number of header components found in the format
214 fmt_compile( fstring
, fmt
)
215 register char *fstring
;
222 (void) free (format_string
);
223 format_string
= getcpy (fstring
);
224 usr_fstring
= fstring
;
226 /* init the component hash table. */
227 for (i
= 0; i
< sizeof(wantcomp
)/sizeof(wantcomp
[0]); i
++)
230 bzero ((char *) &fmt_mnull
, sizeof fmt_mnull
);
232 /* it takes at least 4 char to generate one format so we
233 * allocate a worst-case format array using 1/4 the length
234 * of the format string. We actually need twice this much
235 * to handle both pre-processing (e.g., address parsing) and
238 i
= strlen(fstring
)/2 + 1;
239 next_fp
= formatvec
= (struct format
*)calloc ((unsigned) i
,
240 sizeof(struct format
));
242 adios (NULLCP
, "unable to allocate format storage");
247 cp
= compile(format_string
);
249 CERROR("extra '%>', '%|' or '%?'");
251 LV(FT_DONE
,0); /* really done */
257 static char *compile (sp
)
260 register char *cp
= sp
;
265 while ((c
= *cp
) && c
!= '%')
301 case ';': /* comment line */
303 while ((c
= *cp
++) && c
!= '\n')
315 static char *do_spec(sp
)
318 register char *cp
= sp
;
321 register int ljust
= 0;
322 #endif /* not lint */
323 register int wid
= 0;
324 register char fill
= ' ';
336 wid
= wid
*10 + (c
- '0');
342 fp
->f_type
= wid
? FT_COMPF
: FT_COMP
;
347 if (ftbl
->flags
& TFL_PUTS
) {
348 LV( wid
? FT_STRF
: FT_STR
, ftbl
->extra
);
350 else if (ftbl
->flags
& TFL_PUTN
) {
351 LV( wid
? FT_NUMF
: FT_NUM
, ftbl
->extra
);
356 CERROR("component or function name expected");
366 static char *do_name(sp
, preprocess
)
370 register char *cp
= sp
;
373 static int primed
= 0;
375 while (isalnum(c
= *cp
++) || c
== '-' || c
== '_')
378 CERROR("'}' expected");
382 switch (preprocess
) {
385 if (cm
->c_type
& CT_ADDR
) {
386 CERROR("component used as both date and address");
388 if (! (cm
->c_type
& CT_DATE
)) {
389 cm
->c_tws
= (struct tws
*)
390 calloc((unsigned) 1, sizeof *cm
-> c_tws
);
391 fp
->f_type
= preprocess
;
393 cm
->c_type
|= CT_DATE
;
399 (void) ismymbox ((struct mailname
*) 0);
402 cm
->c_type
|= CT_MYMBOX
;
405 if (cm
->c_type
& CT_DATE
) {
406 CERROR("component used as both date and address");
408 if (! (cm
->c_type
& CT_ADDRPARSE
)) {
409 cm
->c_mn
= &fmt_mnull
;
410 fp
->f_type
= preprocess
;
412 cm
->c_type
|= (CT_ADDR
| CT_ADDRPARSE
);
417 if (cm
->c_type
& CT_DATE
) {
418 CERROR("component used as both date and address");
420 cm
->c_type
|= CT_ADDR
;
426 static char *do_func(sp
)
429 register char *cp
= sp
;
431 register struct ftable
*t
;
433 int mflag
; /* minus sign in NUM */
437 while (isalnum(c
= *cp
++))
439 if (c
!= '(' && c
!= '{' && c
!= ' ' && c
!= ')') {
440 CERROR("'(', '{', ' ' or ')' expected");
443 if ((t
= lookup (sp
)) == 0) {
444 CERROR("unknown function");
453 CERROR("component name expected");
455 cp
= do_name(cp
, t
->extra
);
456 fp
->f_type
= t
->f_type
;
461 if (mflag
= (c
== '-'))
465 n
= n
*10 + (c
- '0');
475 while (c
&& c
!= ')')
482 LV(t
->f_type
,t
->extra
);
486 LS(t
->f_type
, getusr());
490 LV(t
->f_type
, time((time_t *) 0));
498 cp
= do_expr(cp
, t
->extra
);
506 cp
= do_expr(cp
, t
->extra
);
512 CERROR("')' expected");
518 static char *do_expr (sp
, preprocess
)
521 register char *cp
= sp
;
524 if ((c
= *cp
++) == '{') {
525 cp
= do_name (cp
, preprocess
);
526 fp
->f_type
= FT_LS_COMP
;
527 } else if (c
== '(') {
529 } else if (c
== ')') {
531 } else if (c
== '%' && *cp
== '<') {
534 CERROR ("'(', '{', '%<' or ')' expected");
539 static char *do_loop(sp
)
542 register char *cp
= sp
;
543 struct format
*floop
;
548 CERROR ("']' expected");
550 LV(FT_DONE
, 1); /* not yet done */
552 fp
->f_skip
= floop
- fp
; /* skip backwards */
557 static char *do_if(sp
)
560 register char *cp
= sp
;
561 register struct format
*fexpr
,
562 *fif
= (struct format
*)NULL
;
563 register int c
= '<';
566 if (c
== '<') { /* doing an IF */
567 if ((c
= *cp
++) == '{') /*}*/{
569 fp
->f_type
= FT_LS_COMP
;
574 /* see if we can merge the load and the "if" */
575 if (ftbl
->f_type
>= IF_FUNCS
)
576 fp
->f_type
= ftbl
->extra
;
582 CERROR("'(' or '{' expected"); /*}*/
586 fexpr
= fp
; /* loc of [ELS]IF */
587 cp
= compile (cp
); /* compile IF TRUE stmts */
589 fif
->f_skip
= next_fp
- fif
;
591 if ((c
= *cp
++) == '|') { /* the last ELSE */
593 fif
= fp
; /* loc of GOTO */
594 fexpr
->f_skip
= next_fp
- fexpr
;
596 fexpr
= (struct format
*)NULL
;/* no extra ENDIF */
598 cp
= compile (cp
); /* compile ELSE stmts */
599 fif
->f_skip
= next_fp
- fif
;
602 else if (c
== '?') { /* another ELSIF */
604 fif
= fp
; /* loc of GOTO */
605 fexpr
->f_skip
= next_fp
- fexpr
;
607 c
= '<'; /* impersonate an IF */
614 CERROR("'>' expected.");
617 if (fexpr
) /* IF ... [ELSIF ...] ENDIF */
618 fexpr
->f_skip
= next_fp
- fexpr
;