dtcm: Resolve CID 87822
[oweals/cde.git] / cde / programs / dtcm / server / lexit.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $TOG: lexit.c /main/5 1998/04/06 13:13:30 mgreess $ */
24 /*
25  *  (c) Copyright 1993, 1994 Hewlett-Packard Company
26  *  (c) Copyright 1993, 1994 International Business Machines Corp.
27  *  (c) Copyright 1993, 1994 Novell, Inc.
28  *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
29  */
30
31 /*
32  * handcoded lexer to get rid of slow yylook routines
33  * produced by lex.
34  */
35
36
37 #include <EUSCompat.h>
38 #include <ctype.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/mman.h>
44 #include <sys/param.h>
45 #include <sys/stat.h>
46
47 #include "rtable4.h"
48 #include "parser.h"
49 #include "ansi_c.h"
50
51 extern char *pgname;
52 int yyylineno;
53
54 int externNumberVal;
55 char *externQuotedString;
56 Period_4 externPeriod;
57 Appt_Status_4 externApptStatus;
58 Tag_4 externTag;
59 Privacy_Level_4 externPrivacy;
60
61 static int      hash_string     P((register char *));
62 static char     *strescapes     P((char *));
63
64 static int len;
65 static caddr_t start_of_mmapped_area;
66 static caddr_t current_ptr;
67 static caddr_t end;
68
69 #define input_char()    ((end == current_ptr)?0:(*(current_ptr++)))
70 #define unput_char()    (((current_ptr>start_of_mmapped_area)?(current_ptr--):0))
71                           
72 #define ALPHA   1
73 #define DIGIT   2
74 #define IGNORE  3
75 #define SENDIT  4
76 #define EOFILE  5
77 #define QUOTE   6
78 #define COMMENT 7
79 #define NEWLINE 8
80 #define DASH    9
81
82 /* 
83   the following token entry allows us to combine the
84   hash table, token id and action on token recog 
85   together.
86   */
87
88 typedef struct token_data {
89   const char * name;            /* lexical token representation */
90   short first_token;            /* index into tokens.  points to
91                                    first token that hashes to this spot.
92                                    subsequent tokens may be found by following
93                                    next_token field IN first_token. */
94   short  next_token;
95   void * info_to_change;        /* ptr to 4 byte value to change when token 
96                                    is found.  Ignored if NULL */
97   int token_value;              /* value to set above to.  */
98   int return_value;             /* value to return from yyylex when this token
99                                    is found */
100 } token_data_t;
101
102 static u_char parse_buffer[BUFSIZ*3];
103 static u_char initial_mask[255];
104 static u_int  sendit_value[255];
105
106 /*
107   some macros to save my fingers
108  */
109
110 #define PVAL(a,b) { #a,-1, -1, &externPeriod.period,b,PERIODVAL}
111 #define AVAL(a,b) { #a,-1, -1, &externApptStatus,b,APPTSTATUSVAL}
112 #define TVAL(a,b) { #a,-1, -1, &externTag.tag,b,TAGSVAL }
113 #define SVAL(a,b) { #a,-1, -1, &externPrivacy,b,PRIVACYVAL}
114
115 #define EMP(a,b) {#a,-1, -1, 0, 0,b}
116
117 token_data_t tokens[] = {
118   PVAL(single, single_4),
119   PVAL(daily, daily_4),
120   PVAL(weekly, weekly_4),
121   PVAL(biweekly, biweekly_4),
122   PVAL(monthly, monthly_4),
123   PVAL(yearly, yearly_4),
124   PVAL(nthWeekday, nthWeekday_4),
125   PVAL(everyNthDay, everyNthDay_4),
126   PVAL(everyNthWeek, everyNthWeek_4),
127   PVAL(everyNthMonth, everyNthMonth_4),
128   PVAL(monThruFri, monThruFri_4),
129   PVAL(monWedFri, monWedFri_4),
130   PVAL(tueThur, tueThur_4),
131   PVAL(daysOfWeek, daysOfWeek_4),
132
133   AVAL(active, active_4),
134   AVAL(pendingAdd, pendingAdd_4),
135   AVAL(pendingDelete, pendingDelete_4),
136   AVAL(committed, committed_4),
137   AVAL(cancelled, cancelled_4),
138   AVAL(completed, completed_4),
139
140   TVAL(appointment, appointment_4),
141   TVAL(reminder, reminder_4),
142   TVAL(otherTag, otherTag_4),
143   TVAL(holiday, holiday_4),
144   TVAL(toDo, toDo_4),
145
146   SVAL(public, public_4),
147   SVAL(private, private_4),
148   SVAL(semiprivate, semiprivate_4),
149
150   EMP(attributes,ATTRIBUTES_4),
151   EMP(attributelist,ATTRIBUTES_5),
152   EMP(author,AUTHOR),
153   EMP(Version, VERSION),
154   EMP(calendarattributes,CALATTRS),
155   EMP(duration,DURATION),
156   EMP(period,PERIOD),
157   EMP(nth,NTH),
158   EMP(enddate,ENDDATE),
159   EMP(ntimes,NTIMES),
160   EMP(what,WHAT),
161   EMP(details,DETAILS),
162   EMP(mailto,MAILTO),
163   EMP(exceptions,EXCEPTION),
164   EMP(key,KEY),
165   EMP(read,READ),
166   EMP(write,WRITE),
167   EMP(delete,DELETE),
168   EMP(exec,EXEC),
169   EMP(apptstat,APPTSTATUS),
170   EMP(tags,TAGS),
171   EMP(privacy,PRIVACY),
172   EMP(add,ADD),
173   EMP(remove,REMOVE),
174   EMP(access,ACCESS),
175   EMP(entrytable, TABLE),
176   EMP(hashedattributes, HASHEDATTRS),
177   EMP(deny,DENY)};
178
179
180 #define NUMTOKES (sizeof(tokens)/sizeof(tokens[0]))
181
182 /*
183   load parser masks & build
184   token hash tables...
185   we could make this staticly,
186   inititialized, but it would
187   be harder to maintain.
188   */
189
190 /*
191 static u_char initial_mask[255];
192 static u_int  sendit_value[255];
193 */
194
195 static void
196 init()
197 {
198   int i;
199
200   for(i=0;i<255;i++)
201     if(isascii(i)) {
202       if(isalpha(i))
203         initial_mask[i] = ALPHA;
204       else if(isdigit(i))
205         initial_mask[i] = DIGIT;
206       else if(isspace(i))
207         initial_mask[i] = IGNORE;
208       else {
209         switch(i) {
210         case '-':
211           initial_mask[i] = DASH;
212           break;
213         case '*':
214           initial_mask[i] = COMMENT;
215           break;
216         case ' ':
217           initial_mask[i] = IGNORE;
218           break;
219         case '"':
220           initial_mask[i] = QUOTE;
221           break;
222         case '(':
223           initial_mask[i] = SENDIT;
224           sendit_value[i] = OPENPAREN;
225           break;
226         case ')':
227           initial_mask[i] = SENDIT;
228           sendit_value[i] = CLOSEPAREN;
229           break;
230         case ',':
231           initial_mask[i] = SENDIT;
232           sendit_value[i] = COMMA;
233           break;
234         case ':':
235           initial_mask[i] = SENDIT;
236           sendit_value[i] = COLON;
237           break;
238         }
239       }
240     }
241     else if(isspace(i))
242       initial_mask[i] = IGNORE;
243
244   initial_mask[0] = EOFILE;
245   initial_mask['\n'] = NEWLINE;
246
247   /*
248     build token hash table
249     */
250
251   for(i=0;i<NUMTOKES;i++) {
252     int bucket = hash_string((char *) tokens[i].name);
253     
254     if(tokens[bucket].first_token == -1)
255       tokens[bucket].first_token = i;
256     else {
257       int j = 0;
258       bucket = tokens[bucket].first_token;
259       while(tokens[bucket].next_token != -1)
260         j++, bucket = tokens[bucket].next_token;
261       tokens[bucket].next_token = i;
262     }
263   }
264 }
265
266 extern int
267 yyylex()
268 {
269   static int first_time=1;
270
271   if(first_time) {
272     init();
273     first_time = 0;
274   }
275
276   while(1) {
277     register u_char * ptr = parse_buffer;
278     register u_char c;
279
280     switch(initial_mask[ *ptr = input_char()]) {
281
282     case IGNORE:
283       continue;
284
285     case NEWLINE:
286       yyylineno++;
287       break;
288
289     case SENDIT:
290       *(ptr+1) = 0;
291       return(sendit_value[*ptr]);
292
293     case DASH:
294       /* make sure next input is a number */
295       if( initial_mask[*(++ptr)=input_char()] != DIGIT) {
296          fprintf(stderr, "%s: Unsupported char %c (ascii %d) found in callog file\n",
297               pgname, *ptr, *ptr);
298          return(0);
299       }
300       /* fall through */
301
302     case DIGIT:
303       while(initial_mask[*(++ptr)=input_char()] == DIGIT)
304         ;
305
306       unput_char();
307
308       *ptr = '\0';
309
310       externNumberVal=atoi((char *)parse_buffer); 
311       return(NUMBER);
312
313     case ALPHA:
314       {
315         register int bucket;
316         register token_data_t * t;
317
318         while(initial_mask[*(++ptr)=input_char()] == ALPHA)
319           ;
320
321         unput_char();
322
323         *ptr = '\0';
324
325         if ((bucket = tokens[hash_string((char *) parse_buffer)].first_token)
326             == -1) {
327                 fprintf(stderr, "%s: cannot lex %s in callog file\n",
328                         pgname, parse_buffer);
329                 return(0);
330         }
331
332         while(strcmp(tokens[bucket].name, (char*)parse_buffer) != 0)
333           if((bucket = tokens[bucket].next_token) == -1) /* end of chain */ {
334             fprintf(stderr, "%s: cannot lex %s in callog file\n", 
335                     pgname, parse_buffer);
336             return(0);
337           }
338         t = tokens + bucket;
339
340         if(t->info_to_change)
341           *((int *) t->info_to_change) = t->token_value;
342         return(t->return_value);
343       }
344
345     case QUOTE:       /* note that code removes leading and trailing quotes
346                                                 */
347       while(1) {
348         switch(*ptr = input_char())
349           {
350           case '\\':
351             *++ptr = input_char(); /* load next char in any case */
352                 ptr++; 
353             break;
354           case '"':
355             *ptr = 0;
356             strescapes((char *) parse_buffer); /* process any escape sequences */
357             externQuotedString = (char *) strdup((char *)parse_buffer);
358             return(QUOTEDSTRING);
359           case EOFILE:
360           case '\n':
361           case '\r':
362             fprintf(stderr, "%s: missing matching \" in callog file\n", pgname);
363             return(0);
364           default:
365             ptr++;
366           }
367       }
368       
369       
370       
371     case EOFILE:
372       return(0);
373
374     case COMMENT:
375       {
376         int i;
377         for(i=0;i<3;i++) /* look for 4 **** as comment lead-in */
378           if(initial_mask[*(++ptr)=input_char()]!= COMMENT) {
379             *(++ptr) = 0;
380             fprintf(stderr, "%s: cannot lex %s in callog file\n",
381                     pgname, parse_buffer);
382             return(0);
383           }
384
385         while(input_char() != '\n') /* eat up rest of comment */
386           ;
387         yyylineno++; /* since we eat the newline here.... */
388
389         continue;
390       }
391
392
393     default:
394       fprintf(stderr, "%s: Unsupported char %c (ascii %d) found in callog file\n",
395               pgname, *ptr, *ptr);
396       return(0);
397     }
398   }
399 }
400
401   
402 extern int
403 yyywrap(FILE *f)
404 {
405   fclose (f);
406   munmap(start_of_mmapped_area, len);
407   return (1);
408 }
409
410 extern int
411 setinput (FILE* f)
412 {
413   struct stat buff;
414
415   if(fstat(fileno(f), & buff) < 0) {
416     perror("fstat");
417     return(-1);
418   }
419   
420   if((start_of_mmapped_area = 
421       mmap(NULL,  
422            len = buff.st_size,
423            PROT_READ,
424            MAP_PRIVATE,
425            fileno(f),
426            0)) == (caddr_t) -1) { /* mmap failed??? */
427         perror("mmap");
428         return(-1);
429       }
430
431 #if !defined(USL) && !defined(__uxp__) && !defined(linux)
432   /* no madvise so we lose this optimization */
433   madvise(start_of_mmapped_area, len, MADV_SEQUENTIAL);
434 #endif
435
436   end = start_of_mmapped_area + len;
437   current_ptr = start_of_mmapped_area;
438   yyylineno = 1;        
439   
440   return(0);
441 }
442
443
444
445 static int 
446 hash_string(register char *s)
447 {
448   register unsigned result = 0;
449   register int sum;
450   
451   while(sum = *s++)
452     result = (result << 4) + sum;
453   
454   return(result % NUMTOKES);
455 }
456
457 /*---------------------------------------------------------------------------
458   Strescapes performs escape character processing in a manner similar to the C
459   compiler.  It processes a character string passed to it and performs the
460   following substitutions in place:
461   
462   \\    ->   \
463   \"    ->   "
464   \e    ->   033
465   \t    ->   011
466   \n    ->   newline
467   \0nn  ->   0nn
468   \r    ->   cr
469   
470   A single \ in front of other characters is ignored(&removed).  As with
471   most string routines, strescapes returns it's argument.  Note that
472   inserting a \0 will end the string at that location, but the remainder of
473   the string will be processed.
474   
475   ---------------------------------------------------------------------------*/
476
477
478 static char * 
479 strescapes(char *s)
480 {
481   register char * in=s, * out=s;
482   
483   while(*in)
484     {
485       if(*in == '\\')
486         switch(*(in+1))
487           {
488           case 'e':  /* an escape character */
489             *out++ = '\033';
490             in += 2;
491             break;
492             
493           case 't':  /* a tab character */
494             *out++ = '\t';
495             in += 2;
496             break;
497             
498           case 'n':  /* a newline */
499             *out++ = '\n';
500             in += 2;
501             break;
502           case 'r':  /* a carriage return */
503             *out++ = '\r';
504             in += 2;
505             break;
506           case '\\': /* a backslash */
507             *out++ = '\\';
508             in += 2;
509             break;
510           case '0':  /* a octal constant */
511             {
512               register int i,result;
513               in++;
514               for(result=i=0; (i<=3) && (*in >='0') && (*in <= '7') ; )
515                 {
516                   result <<= 3;
517                   result += (*in++) - '0';
518                 }
519               *out++ = result & 0377;
520               break;
521             }
522             
523           default:  /* not used as escape.... make it disappear */
524             in++;   /* this also handles nulls */
525             break;
526           }
527       else
528         *out++ = * in++;
529     }
530   *out='\0';
531   return(s);
532 }
533
534
535 #ifdef TEST
536
537 main(int argc, char ** argv)
538 {
539   FILE * f;
540   int d;
541
542   if(argc < 2) {
543     printf("usage: %s filename\n", argv[0]);
544     exit(1);
545   }
546
547   if((f = fopen(argv[1], "r")) == NULL) {
548     perror("fopen");
549     exit(2);
550   }
551
552   if(setinput(f) < 0) {
553     exit(3);
554   }
555
556   while(d=yyylex()) {
557     if(argc == 2)
558       printf("received %d, text <%s>\n", d, parse_buffer);
559   }
560
561   exit(0);
562 }
563     
564 #endif