Specify pattern rules in addition to suffix rules
[openafs.git] / src / config / mc.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #define MAXLINELEN      1024
11 #define MAXTOKLEN       100
12 #include <sys/param.h>
13 #include <sys/types.h>
14 #include <sys/file.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17
18 #include "afsconfig.h"
19 #include <string.h>
20
21 #define TOK_DONTUSE 1           /* Don't copy if match and this flag is set. */
22 struct token {
23     struct token *next;
24     char *key;
25     int flags;
26 };
27
28 /* free token list returned by parseLine */
29 static int
30 FreeTokens(struct token *alist)
31 {
32     struct token *nlist;
33     for (; alist; alist = nlist) {
34         nlist = alist->next;
35         free(alist->key);
36         free(alist);
37     }
38     return 0;
39 }
40
41 #define space(x)    ((x) == ' ' || (x) == '\t' || (x) == '<' || (x) == '>')
42 static int
43 ParseLine(char *aline, struct token **alist)
44 {
45     char tbuffer[MAXTOKLEN + 1];
46     char *tptr = NULL;
47     int inToken;
48     struct token *first, *last;
49     struct token *ttok;
50     int tc;
51     int dontUse = 0;
52
53     inToken = 0;                /* not copying token chars at start */
54     first = NULL;
55     last = NULL;
56     while (1) {
57         tc = *aline++;
58         if (tc == 0 || space(tc)) {     /* terminating null gets us in here, too */
59             if (inToken) {
60                 inToken = 0;    /* end of this token */
61                 if (!tptr)
62                     return -1;  /* should never get here */
63                 else
64                     *tptr++ = 0;
65                 ttok = (struct token *)malloc(sizeof(struct token));
66                 ttok->next = NULL;
67                 if (dontUse) {
68                     ttok->key = (char *)malloc(strlen(tbuffer));
69                     strcpy(ttok->key, tbuffer + 1);
70                     ttok->flags = TOK_DONTUSE;
71                     dontUse = 0;
72                 } else {
73                     ttok->key = (char *)malloc(strlen(tbuffer) + 1);
74                     strcpy(ttok->key, tbuffer);
75                     ttok->flags = 0;
76                 }
77                 if (last) {
78                     last->next = ttok;
79                     last = ttok;
80                 } else
81                     last = ttok;
82                 if (!first)
83                     first = ttok;
84             }
85         } else {
86             /* an alpha character */
87             if (!inToken) {
88                 if (tc == '-') {
89                     dontUse = 1;
90                 }
91                 tptr = tbuffer;
92                 inToken = 1;
93             }
94             if (tptr - tbuffer >= MAXTOKLEN)
95                 return -1;      /* token too long */
96             *tptr++ = tc;
97         }
98         if (tc == 0) {
99             /* last token flushed 'cause space(0) --> true */
100             if (last)
101                 last->next = NULL;
102             *alist = first;
103             return 0;
104         }
105     }
106 }
107
108 /* read a line into a buffer, putting in null termination and stopping on appropriate
109     end of line char.  Returns 0 at eof, > 0 at normal line end, and < 0 on error */
110 static int
111 GetLine(FILE * afile, char *abuffer, int amax)
112 {
113     int tc;
114     int first;
115
116     first = 1;
117     while (1) {
118         tc = getc(afile);
119         if (first && tc < 0)
120             return 0;
121         first = 0;
122         if (tc <= 0 || tc == '\012') {
123             if (amax > 0)
124                 *abuffer++ = 0;
125             return (amax > 0 ? 1 : -1);
126         }
127         if (amax > 0) {
128             /* keep reading to end of line so next one isn't bogus */
129             *abuffer++ = tc;
130             amax--;
131         }
132     }
133 }
134
135 int
136 mc_copy(FILE * ain, FILE * aout, char *alist[])
137 {
138     char tbuffer[MAXLINELEN];
139     struct token *tokens;
140     char **tp;
141     struct token *tt;
142     int code;
143     int copying;
144     int done;
145
146     copying = 1;                /* start off copying data */
147     while (1) {
148         /* copy lines, handling modes appropriately */
149         code = GetLine(ain, tbuffer, MAXLINELEN);
150         if (code <= 0)
151             break;
152         /* otherwise process the line */
153         if (tbuffer[0] == '<') {
154             /* interpret the line as a set of options, any one of which will cause us
155              * to start copying the data again. */
156             code = ParseLine(tbuffer, &tokens);
157             if (code != 0)
158                 return -1;
159             copying = 0;
160             done = 0;
161             for (tp = alist; (!done) && (*tp != NULL); tp++) {
162                 for (tt = tokens; tt; tt = tt->next) {
163                     if (!strcmp(*tp, tt->key)) {
164                         /* Need to search all tokens in case a dont use
165                          * flag is set. But we can stop on the first
166                          * don't use.
167                          */
168                         if (tt->flags & TOK_DONTUSE) {
169                             copying = 0;
170                             done = 1;
171                             break;
172                         } else {
173                             copying = 1;
174                         }
175                     }
176                 }
177             }
178             FreeTokens(tokens);
179         } else {
180             /* just copy the line */
181             if (copying) {
182                 fwrite(tbuffer, 1, strlen(tbuffer), aout);
183                 putc('\n', aout);
184             }
185         }
186     }
187     return 0;
188 }