source: trunk/athena/bin/discuss/client/trn_spec.c @ 12459

Revision 12459, 6.8 KB checked in by danw, 25 years ago (diff)
comment out text after #else and #endif
Line 
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
32static 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
51static 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};
72int n_trn_table = (sizeof(trn_table)/sizeof(struct trn_ent));
73       
74static struct swtch {
75        char *name;
76        int     set;
77} switches[] = {
78        { "-deleted",   TRSPEC_DEL },
79};
80
81int 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 */
91int
92parse_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}
144int
145process_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
180not_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
199int
200tg_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       
242add_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
257int 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}
Note: See TracBrowser for help on using the repository browser.