]> mj.ucw.cz Git - umpf.git/blob - lex.c
allow comments behind #
[umpf.git] / lex.c
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <string.h>
4 #include <stdlib.h>
5 #include <stdarg.h>
6
7 #include "cond.tab.h"
8 #include "umpf.h"
9 #define KLEN 10 
10
11 struct keys {
12         char* keywords;
13         enum yytokentype keytoks;
14 };
15
16 static struct keys kwds[] = 
17         {       {"copy", KW_COPY},
18                 {"else", KW_ELSE},
19                 {"if", KW_IF}, 
20                 {"mail", KW_MAIL}, 
21                 {"pipe", KW_PIPE},
22                 {"discard", KW_DISCARD},
23                 {"filter", KW_FILTER}
24         };
25
26 void
27 read_conf(char* filename)
28 {
29         conf = fopen(filename, "r");
30
31         if (! conf) {
32                 fprintf(stderr, "Error reading config file: %m\nSaving to default mailbox %s\n", default_mailbox);
33                 longjmp(env, 1); 
34         }
35 }
36
37 void __attribute__ ((noreturn)) 
38 die(char* msg, ...)
39 {
40         va_list args;
41
42         va_start(args, msg);
43         vfprintf(stderr, msg, args);
44         fputc('\n', stderr);
45         va_end(args);
46         exit(1);
47 }
48
49 void*
50 xmalloc(size_t size)
51 {
52         void* ret;
53
54         if (!(ret = malloc(size)))
55                 die("Low memory");
56
57         return ret;
58 }
59
60 void*
61 xrealloc(void* buf, size_t size)
62 {
63         buf = realloc(buf, size);
64         
65         if (!buf)
66                 die("Low memory");
67
68         return buf;
69 }
70
71 static void __attribute__ ((noreturn)) 
72 parse_err(char* msg, ...)
73 {
74         va_list args;
75
76         va_start(args, msg);
77         fprintf(stderr, "Line %d: ", line);
78         vfprintf(stderr, msg, args);
79         fputc('\n', stderr);
80         fprintf(stderr, "Saving the email to default mailbox %s\n",
81                 default_mailbox);
82         va_end(args);
83         longjmp(env, 1); 
84 }
85
86 char*
87 xstrdup(const char* s)
88 {
89         void* ret;
90
91         if (!(ret = strdup(s)))
92                 die("Low memory");
93
94         return ret;
95 }
96
97 static char*
98 get_string_out(int delim)
99 {
100         int last = delim; 
101         int i = 0;
102         int c;
103         char buf[BUFSIZE];
104
105         while ((c = getc(conf)) != delim || last == '\\'){
106                 if (last=='\\' && c != delim)
107                         buf[i-1] = c;
108                 else {          
109                         buf[i] = c;
110                         i++;
111                 }
112                 last = c;
113                 if (i >= BUFSIZE-1)
114                         parse_err("Too long string, max allowed length is %d",BUFSIZE-1);       
115         }       
116         buf[i] = '\0';
117
118         return xstrdup(buf);
119 }
120
121 static int
122 is_var_id(int c)
123 {
124         return  (c >= '0' && c <= '9' ) ||
125                 (c >= 'a' && c <= 'z') ||
126                 (c >= 'A' && c <= 'Z') ||
127                 c == '_' ||
128                 c == '-'; 
129 }
130
131 static int
132 is_alpha(int c)
133 {
134         return (c >= 'a' && c <= 'z') ||
135                 (c >= 'A' && c <= 'Z');
136 }
137
138 static int
139 get_token_start(void)
140 {
141         int c;
142         int want_newline = 0;
143
144         for(;;) {
145                 c = getc(conf);
146                 if (c == EOF)
147                         return c;
148                 if (c == '#') {
149                         want_newline = 1;
150                         continue;
151                 }
152                 if (c == '\n') {
153                         line++;
154                         want_newline = 0;
155                         continue;
156                 }
157                 if (c != '\n' && want_newline)
158                         continue;
159                 if (c != ' ' && c != '\t')
160                         return c;
161         }
162 }
163
164 int
165 yylex(void)
166 {
167         int c;
168         
169         c = get_token_start();
170         if (c == EOF)
171                 return 0;
172         
173         int d = getc(conf);
174         if (d >= 0) {
175                 switch (CC(c,d)) {
176                 case CC('!','='): yylval.n = CC('!','='); return NEQ;
177                 case CC('!','~'): yylval.n = CC('!','='); return NRE;
178                 case CC('<','='): yylval.n = CC('<','='); return LE;
179                 case CC('>','='): yylval.n = CC('>','='); return GE;
180                 case CC('=','='): yylval.n = CC('=','='); return EQ;
181                 case CC('~','~'): yylval.n = CC('~','~'); return RE;
182                 case CC('-','>'): yylval.n = CC('-','>'); return ARROW;
183                 }
184                 ungetc(d,conf);
185         }
186
187         switch (c) {
188                 case '!':
189                 case '(':
190                 case ')':
191                 case '-':
192                 case '+':
193                 case '*':
194                 case '/':
195                 case '{':
196                 case '}':
197                 case '<':
198                 case '>':
199                 case '=':
200                 case ';':
201                 case '.':
202                 case '|':
203                 case '&':
204                 case '^':
205                         yylval.n = c;
206                         return c;
207                 
208                 case '"':
209                 case '\'':
210                         yylval.str = get_string_out(c);
211                         return CONST;   
212         }
213
214         if (c >= '0' && c <= '9'){
215                 ungetc(c,conf);
216                 int i = 0;
217                 char buf[BUFSIZE];
218         
219                 while ((c = getc(conf))>= '0' && c<= '9'){
220                         buf[i] = c;
221                         i++;
222                         if (i >= BUFSIZE-1)
223                                 parse_err("Too long number");   
224                 }
225                 ungetc(c,conf);
226                 buf[i] = 0;
227                 yylval.str = xstrdup(buf);
228
229                 return CONST;
230         }
231
232         if (c == '$'){
233                 int i = 0;
234                 char buf[BUFSIZE];
235         
236                 while (is_var_id(c = getc(conf))){
237                         buf[i]=c;
238                         i++;
239                         if (i >= BUFSIZE-1)
240                                 parse_err("Too long identifier, max allowed length is %d",BUFSIZE-1);   
241                 }
242                 ungetc(c,conf);
243                 buf[i] = 0;
244                 yylval.str = xstrdup(buf);
245
246                 return VAR;
247         }
248
249         if (is_alpha(c)){
250                 char buf[KLEN]; 
251                 int n, i = 0;
252
253                 ungetc(c,conf);
254                 while (is_alpha(c = getc(conf))){
255                         buf[i++] = c;
256                         if (i >= KLEN)
257                                 parse_err("Keyword too long");
258                 }
259                 buf[i] = 0;
260                 ungetc(c,conf);
261
262                 n = (sizeof(kwds)/sizeof(struct keys));
263                 for (i = 0; i < n; i++){
264                         if (!strcmp(buf,kwds[i].keywords))
265                                 return kwds[i].keytoks;
266                 }
267
268                 parse_err("Unknown keyword %s", buf);
269         }
270
271         parse_err("Unknown character %c", c);
272 }