1 | /* |
---|
2 | * $Id: trn_spec.c,v 1.6 1999-02-08 14:46:56 danw Exp $ |
---|
3 | * |
---|
4 | * Copyright (C) 1986 by the Massachusetts Institute of Technology |
---|
5 | * |
---|
6 | * Parse a command line containing transaction specifiers and |
---|
7 | * "standard" message selection control arguments. |
---|
8 | * |
---|
9 | * parse_trans_spec "compiles" the command line arguments into |
---|
10 | * a "generator" data structure. |
---|
11 | * |
---|
12 | * The generator strucuture contains things like a trn_info for each |
---|
13 | * generated transaction. |
---|
14 | * |
---|
15 | * It is indended that the application will call "tg_next_trn" repeatedly |
---|
16 | * until it returns a non-zero error code. "tg_next_trn" returns |
---|
17 | * DSC_NO_MORE when there are no more transactions in a series, and |
---|
18 | * silently swallows things like deleted transactions (unless the |
---|
19 | * -deleted option was given...) |
---|
20 | * |
---|
21 | * It is intended that this will be the place to do things like |
---|
22 | * matching subjects based on a regexp, implementing "-by_chain", etc, |
---|
23 | * although some significant rearrangement of the FSMs will be needed |
---|
24 | * to do that. |
---|
25 | * |
---|
26 | * If this were LISP, I would wind up turning tg_next_trn into something |
---|
27 | * which called eval.. but it isn't. Sorry. |
---|
28 | * |
---|
29 | */ |
---|
30 | |
---|
31 | #ifndef lint |
---|
32 | static char *rcsid_trn_spec_c = "$Id: trn_spec.c,v 1.6 1999-02-08 14:46:56 danw Exp $"; |
---|
33 | #endif /* lint */ |
---|
34 | |
---|
35 | #include "interface.h" |
---|
36 | #include "globals.h" |
---|
37 | #include "trn_spec.h" |
---|
38 | #include "discuss_err.h" |
---|
39 | #include "dsc_et.h" |
---|
40 | #include <stdio.h> |
---|
41 | #include <string.h> |
---|
42 | #include <ctype.h> |
---|
43 | |
---|
44 | #define max(a,b) ((a)<(b)?(b):(a)) |
---|
45 | |
---|
46 | /* |
---|
47 | * Table of legal transaction specs. Entries must be sorted in ASCII |
---|
48 | * order. |
---|
49 | */ |
---|
50 | |
---|
51 | static struct trn_ent { |
---|
52 | char *name; |
---|
53 | int first, second; |
---|
54 | } trn_table[] = { |
---|
55 | { ".", TRSPEC_CUR|TRSPEC_REM, 0 }, |
---|
56 | { "cur", TRSPEC_CUR|TRSPEC_REM, 0 }, |
---|
57 | { "n", TRSPEC_NEXT|TRSPEC_REM, 0 }, |
---|
58 | { "next", TRSPEC_NEXT|TRSPEC_REM, 0 }, |
---|
59 | { "nr", TRSPEC_NREF|TRSPEC_REM, 0 }, |
---|
60 | { "nref", TRSPEC_NREF|TRSPEC_REM, 0 }, |
---|
61 | { "p", TRSPEC_PREV|TRSPEC_REM, 0 }, |
---|
62 | { "pr", TRSPEC_PREF|TRSPEC_REM, 0 }, |
---|
63 | { "pref", TRSPEC_PREF|TRSPEC_REM, 0 }, |
---|
64 | { "prev", TRSPEC_PREV|TRSPEC_REM, 0 }, |
---|
65 | { "all", TRSPEC_FIRST|TRSPEC_REM, TRSPEC_NEXT }, |
---|
66 | { "aref", TRSPEC_FREF|TRSPEC_REM, TRSPEC_NREF }, |
---|
67 | { "first", TRSPEC_FIRST|TRSPEC_REM, 0 }, |
---|
68 | { "last", TRSPEC_LAST|TRSPEC_REM, 0}, |
---|
69 | { "$", TRSPEC_LAST|TRSPEC_REM, 0}, |
---|
70 | { "new", TRSPEC_FUNS|TRSPEC_REM, TRSPEC_NEXT }, |
---|
71 | }; |
---|
72 | int n_trn_table = (sizeof(trn_table)/sizeof(struct trn_ent)); |
---|
73 | |
---|
74 | static struct swtch { |
---|
75 | char *name; |
---|
76 | int set; |
---|
77 | } switches[] = { |
---|
78 | { "-deleted", TRSPEC_DEL }, |
---|
79 | }; |
---|
80 | |
---|
81 | int n_switches = (sizeof(switches)/sizeof(struct swtch)); |
---|
82 | |
---|
83 | /* |
---|
84 | * Parse a transaction specifier. |
---|
85 | * Returns a "generator" for the transactions specified. |
---|
86 | * Modifies (reallocs) argv to contain only the arguments it does |
---|
87 | * not understand. |
---|
88 | * |
---|
89 | * Returns a standard error code. |
---|
90 | */ |
---|
91 | int |
---|
92 | parse_trans_spec(argv_p, argc_p, environ, dfault, gen) |
---|
93 | char ***argv_p; /* Pointer to array of (char *) */ |
---|
94 | int *argc_p; /* Arg count (modified) */ |
---|
95 | struct _dsc_pub *environ; |
---|
96 | char *dfault; |
---|
97 | trans_gen **gen; /* Return */ |
---|
98 | { |
---|
99 | char **argv = *argv_p; |
---|
100 | char **nargv; |
---|
101 | int nargc = 0; |
---|
102 | int argc = *argc_p; |
---|
103 | register char **argp = argv; /* induction variable */ |
---|
104 | int code = 0; /* return error code */ |
---|
105 | trans_gen *tg; |
---|
106 | |
---|
107 | if (!environ->attending) |
---|
108 | return DISC_NO_MTG; |
---|
109 | |
---|
110 | nargv = (char **)malloc(0); |
---|
111 | tg = (trans_gen *)malloc(sizeof(*tg)); |
---|
112 | |
---|
113 | tg->flags = 0; |
---|
114 | tg->minfo = &environ->m_info; |
---|
115 | tg->nbp = &environ->nb; |
---|
116 | tg->te_last = tg->te = (trnspec_entry *)tg; |
---|
117 | tg->current = environ->current; |
---|
118 | tg->highest_seen = environ->highest_seen; |
---|
119 | |
---|
120 | --argc; |
---|
121 | ++argp; |
---|
122 | if (argc == 0) process_an_arg(tg, dfault); |
---|
123 | |
---|
124 | for ( ; argc; --argc, ++argp) { |
---|
125 | if(process_an_arg(tg, *argp)) { |
---|
126 | nargv = (char **) realloc(nargv, nargc + 1 * (sizeof(char *))); |
---|
127 | nargv[nargc] = *argp; |
---|
128 | nargc++; |
---|
129 | } else free(*argp); |
---|
130 | *argp = NULL; |
---|
131 | } |
---|
132 | free (*argv_p); |
---|
133 | |
---|
134 | *argv_p = nargv; |
---|
135 | *argc_p = nargc; |
---|
136 | *gen = tg; |
---|
137 | |
---|
138 | dsc_get_mtg_info(tg->nbp, tg->minfo, &code); |
---|
139 | if (code) return code; |
---|
140 | if (environ->current == 0) return 0; |
---|
141 | dsc_get_trn_info(tg->nbp, environ->current, &tg->tinfo, &code); |
---|
142 | return code; |
---|
143 | } |
---|
144 | int |
---|
145 | process_an_arg(tg, arg) |
---|
146 | trans_gen *tg; |
---|
147 | char *arg; |
---|
148 | { |
---|
149 | int i, val, retval; |
---|
150 | char *cp; |
---|
151 | |
---|
152 | if ((cp = strchr(arg, ',')) || |
---|
153 | (cp = strchr(arg, ':'))) { |
---|
154 | *cp = '\0'; |
---|
155 | retval = process_an_arg(tg, arg); |
---|
156 | if (!retval) { |
---|
157 | retval = process_an_arg(tg, cp+1); |
---|
158 | if (!retval) { |
---|
159 | tg->te_last->flags &= ~TRSPEC_REM; |
---|
160 | tg->te_last->flags |= TRSPEC_UNTIL; |
---|
161 | } |
---|
162 | } |
---|
163 | *cp = ','; |
---|
164 | return 0; |
---|
165 | } |
---|
166 | |
---|
167 | { |
---|
168 | register char c; |
---|
169 | int val = 0; |
---|
170 | trnspec_entry *new_te; |
---|
171 | for (cp = arg; c = *cp; cp++) { |
---|
172 | if (!isdigit(c)) goto not_number; |
---|
173 | val *= 10; |
---|
174 | val += (c - '0'); |
---|
175 | } |
---|
176 | add_new_te(tg, TRSPEC_NUM|TRSPEC_REM, val); |
---|
177 | return 0; |
---|
178 | } |
---|
179 | |
---|
180 | not_number: |
---|
181 | for (i = 0; i < n_trn_table; i++) { |
---|
182 | if(!strcmp(arg, trn_table[i].name)) { |
---|
183 | add_new_te(tg, trn_table[i].first, 0); |
---|
184 | if (trn_table[i].second) { |
---|
185 | add_new_te(tg, trn_table[i].second, 0); |
---|
186 | } |
---|
187 | return 0; |
---|
188 | } |
---|
189 | } |
---|
190 | for (i = 0; i < n_switches; i++) { |
---|
191 | if(!strcmp(arg, switches[i].name)) { |
---|
192 | tg->flags |= switches[i].set; |
---|
193 | return 0; |
---|
194 | } |
---|
195 | } |
---|
196 | return 1; |
---|
197 | } |
---|
198 | |
---|
199 | int |
---|
200 | tg_next_trn(tg) |
---|
201 | trans_gen *tg; |
---|
202 | { |
---|
203 | register trnspec_entry *te; |
---|
204 | int deleted, remove, until, flags, trn_num, unseen; |
---|
205 | int code = 0; |
---|
206 | |
---|
207 | /* Come up with next xcn number */ |
---|
208 | if(tg->te == (trnspec_entry *)tg) return DSC_NO_MORE; |
---|
209 | |
---|
210 | te=tg->te; |
---|
211 | |
---|
212 | trn_num = tg_next_trn_num(tg, te); |
---|
213 | |
---|
214 | if (trn_num == 0) return DSC_NO_MORE; |
---|
215 | |
---|
216 | if (trn_num != tg->current) |
---|
217 | dsc_get_trn_info(tg->nbp, trn_num, &tg->tinfo, &code); |
---|
218 | |
---|
219 | if (tg->flags&TRSPEC_DEL) { |
---|
220 | if (code != DELETED_TRN) { |
---|
221 | /* arg! */ |
---|
222 | deleted = -1; |
---|
223 | flags = TRSPEC_NEXT; |
---|
224 | goto again; |
---|
225 | /* end arg! */ |
---|
226 | } else code = 0; |
---|
227 | } |
---|
228 | |
---|
229 | if (code == 0) { |
---|
230 | tg->current = trn_num; |
---|
231 | } |
---|
232 | |
---|
233 | if(te->flags&TRSPEC_REM) { |
---|
234 | remque(te); |
---|
235 | te_free(te); |
---|
236 | } |
---|
237 | |
---|
238 | if (code) tg->current = 0; |
---|
239 | return code; |
---|
240 | } |
---|
241 | |
---|
242 | add_new_te(tg, flags, num) |
---|
243 | trans_gen *tg; |
---|
244 | int flags; |
---|
245 | int num; |
---|
246 | { |
---|
247 | trnspec_entry *new_te = (trnspec_entry *)malloc(sizeof(*new_te)); |
---|
248 | new_te->flags = flags; |
---|
249 | new_te->num = num; |
---|
250 | insque(new_te, tg->te_last); |
---|
251 | } |
---|
252 | |
---|
253 | /* |
---|
254 | * A Lisp programmer would call this function a special case of eval.. |
---|
255 | */ |
---|
256 | |
---|
257 | int tg_next_trn_num(tg, te) |
---|
258 | trans_gen *tg; |
---|
259 | trnspec_entry *te; |
---|
260 | { |
---|
261 | int trn_num; |
---|
262 | |
---|
263 | switch (te->flags&TRSPEC_KINDS) { |
---|
264 | case TRSPEC_UNTIL: |
---|
265 | trn_num = tg_next_trn_num(tg, te->down); |
---|
266 | if (trn_num >= tg->current) return 0; |
---|
267 | /* fall through into next... */ |
---|
268 | |
---|
269 | case TRSPEC_NEXT: |
---|
270 | if (tg->flags&TRSPEC_DEL) return tg->current + 1; |
---|
271 | else return tg->tinfo.next; |
---|
272 | |
---|
273 | case TRSPEC_PREV: |
---|
274 | if (tg->flags&TRSPEC_DEL) return tg->tinfo.current - 1; |
---|
275 | else return tg->tinfo.prev; |
---|
276 | |
---|
277 | case TRSPEC_NREF: |
---|
278 | return tg->tinfo.nref; |
---|
279 | |
---|
280 | case TRSPEC_PREF: |
---|
281 | return tg->tinfo.pref; |
---|
282 | |
---|
283 | case TRSPEC_FREF: |
---|
284 | return tg->tinfo.fref; |
---|
285 | |
---|
286 | case TRSPEC_LREF: |
---|
287 | return tg->tinfo.lref; |
---|
288 | |
---|
289 | case TRSPEC_FIRST: |
---|
290 | return tg->minfo->first; |
---|
291 | |
---|
292 | case TRSPEC_LAST: |
---|
293 | return tg->minfo->last; |
---|
294 | |
---|
295 | case TRSPEC_CUR: |
---|
296 | return te->tinfo.current; |
---|
297 | |
---|
298 | case TRSPEC_NUM: |
---|
299 | return te->num; |
---|
300 | |
---|
301 | case TRSPEC_FUNS: |
---|
302 | return tg->highest_seen + 1; |
---|
303 | |
---|
304 | default: |
---|
305 | abort(); |
---|
306 | } |
---|
307 | } |
---|