1
0
Fork 0
mirror of git://git.code.sf.net/p/cdesktopenv/code synced 2025-03-09 15:50:02 +00:00
cde/cde/programs/dtcm/server/lexit.c
2015-01-13 14:22:25 +00:00

564 lines
12 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/* $TOG: lexit.c /main/5 1998/04/06 13:13:30 mgreess $ */
/*
* (c) Copyright 1993, 1994 Hewlett-Packard Company
* (c) Copyright 1993, 1994 International Business Machines Corp.
* (c) Copyright 1993, 1994 Novell, Inc.
* (c) Copyright 1993, 1994 Sun Microsystems, Inc.
*/
/*
* handcoded lexer to get rid of slow yylook routines
* produced by lex.
*/
#include <EUSCompat.h>
#include <ctype.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/stat.h>
#include "rtable4.h"
#include "parser.h"
#include "ansi_c.h"
extern char *pgname;
int yyylineno;
int externNumberVal;
char *externQuotedString;
Period_4 externPeriod;
Appt_Status_4 externApptStatus;
Tag_4 externTag;
Privacy_Level_4 externPrivacy;
static int hash_string P((register char *));
static char *strescapes P((char *));
static int len;
static caddr_t start_of_mmapped_area;
static caddr_t current_ptr;
static caddr_t end;
#define input_char() ((end == current_ptr)?0:(*(current_ptr++)))
#define unput_char() (((current_ptr>start_of_mmapped_area)?(current_ptr--):0))
#define ALPHA 1
#define DIGIT 2
#define IGNORE 3
#define SENDIT 4
#define EOFILE 5
#define QUOTE 6
#define COMMENT 7
#define NEWLINE 8
#define DASH 9
/*
the following token entry allows us to combine the
hash table, token id and action on token recog
together.
*/
typedef struct token_data {
const char * name; /* lexical token representation */
short first_token; /* index into tokens. points to
first token that hashes to this spot.
subsequent tokens may be found by following
next_token field IN first_token. */
short next_token;
void * info_to_change; /* ptr to 4 byte value to change when token
is found. Ignored if NULL */
int token_value; /* value to set above to. */
int return_value; /* value to return from yyylex when this token
is found */
} token_data_t;
static u_char parse_buffer[BUFSIZ*3];
static u_char initial_mask[255];
static u_int sendit_value[255];
/*
some macros to save my fingers
*/
#define PVAL(a,b) { #a,-1, -1, &externPeriod.period,b,PERIODVAL}
#define AVAL(a,b) { #a,-1, -1, &externApptStatus,b,APPTSTATUSVAL}
#define TVAL(a,b) { #a,-1, -1, &externTag.tag,b,TAGSVAL }
#define SVAL(a,b) { #a,-1, -1, &externPrivacy,b,PRIVACYVAL}
#define EMP(a,b) {#a,-1, -1, 0, 0,b}
token_data_t tokens[] = {
PVAL(single, single_4),
PVAL(daily, daily_4),
PVAL(weekly, weekly_4),
PVAL(biweekly, biweekly_4),
PVAL(monthly, monthly_4),
PVAL(yearly, yearly_4),
PVAL(nthWeekday, nthWeekday_4),
PVAL(everyNthDay, everyNthDay_4),
PVAL(everyNthWeek, everyNthWeek_4),
PVAL(everyNthMonth, everyNthMonth_4),
PVAL(monThruFri, monThruFri_4),
PVAL(monWedFri, monWedFri_4),
PVAL(tueThur, tueThur_4),
PVAL(daysOfWeek, daysOfWeek_4),
AVAL(active, active_4),
AVAL(pendingAdd, pendingAdd_4),
AVAL(pendingDelete, pendingDelete_4),
AVAL(committed, committed_4),
AVAL(cancelled, cancelled_4),
AVAL(completed, completed_4),
TVAL(appointment, appointment_4),
TVAL(reminder, reminder_4),
TVAL(otherTag, otherTag_4),
TVAL(holiday, holiday_4),
TVAL(toDo, toDo_4),
SVAL(public, public_4),
SVAL(private, private_4),
SVAL(semiprivate, semiprivate_4),
EMP(attributes,ATTRIBUTES_4),
EMP(attributelist,ATTRIBUTES_5),
EMP(author,AUTHOR),
EMP(Version, VERSION),
EMP(calendarattributes,CALATTRS),
EMP(duration,DURATION),
EMP(period,PERIOD),
EMP(nth,NTH),
EMP(enddate,ENDDATE),
EMP(ntimes,NTIMES),
EMP(what,WHAT),
EMP(details,DETAILS),
EMP(mailto,MAILTO),
EMP(exceptions,EXCEPTION),
EMP(key,KEY),
EMP(read,READ),
EMP(write,WRITE),
EMP(delete,DELETE),
EMP(exec,EXEC),
EMP(apptstat,APPTSTATUS),
EMP(tags,TAGS),
EMP(privacy,PRIVACY),
EMP(add,ADD),
EMP(remove,REMOVE),
EMP(access,ACCESS),
EMP(entrytable, TABLE),
EMP(hashedattributes, HASHEDATTRS),
EMP(deny,DENY)};
#define NUMTOKES (sizeof(tokens)/sizeof(tokens[0]))
/*
load parser masks & build
token hash tables...
we could make this staticly,
inititialized, but it would
be harder to maintain.
*/
/*
static u_char initial_mask[255];
static u_int sendit_value[255];
*/
static void
init()
{
int i;
for(i=0;i<255;i++)
if(isascii(i)) {
if(isalpha(i))
initial_mask[i] = ALPHA;
else if(isdigit(i))
initial_mask[i] = DIGIT;
else if(isspace(i))
initial_mask[i] = IGNORE;
else {
switch(i) {
case '-':
initial_mask[i] = DASH;
break;
case '*':
initial_mask[i] = COMMENT;
break;
case ' ':
initial_mask[i] = IGNORE;
break;
case '"':
initial_mask[i] = QUOTE;
break;
case '(':
initial_mask[i] = SENDIT;
sendit_value[i] = OPENPAREN;
break;
case ')':
initial_mask[i] = SENDIT;
sendit_value[i] = CLOSEPAREN;
break;
case ',':
initial_mask[i] = SENDIT;
sendit_value[i] = COMMA;
break;
case ':':
initial_mask[i] = SENDIT;
sendit_value[i] = COLON;
break;
}
}
}
else if(isspace(i))
initial_mask[i] = IGNORE;
initial_mask[0] = EOFILE;
initial_mask['\n'] = NEWLINE;
/*
build token hash table
*/
for(i=0;i<NUMTOKES;i++) {
int bucket = hash_string((char *) tokens[i].name);
if(tokens[bucket].first_token == -1)
tokens[bucket].first_token = i;
else {
int j = 0;
bucket = tokens[bucket].first_token;
while(tokens[bucket].next_token != -1)
j++, bucket = tokens[bucket].next_token;
tokens[bucket].next_token = i;
}
}
}
extern int
yyylex()
{
static int first_time=1;
if(first_time) {
init();
first_time = 0;
}
while(1) {
register u_char * ptr = parse_buffer;
register u_char c;
switch(initial_mask[ *ptr = input_char()]) {
case IGNORE:
continue;
case NEWLINE:
yyylineno++;
break;
case SENDIT:
*(ptr+1) = 0;
return(sendit_value[*ptr]);
case DASH:
/* make sure next input is a number */
if( initial_mask[*(++ptr)=input_char()] != DIGIT) {
fprintf(stderr, "%s: Unsupported char %c (ascii %d) found in callog file\n",
pgname, *ptr, *ptr);
return(0);
}
/* fall through */
case DIGIT:
while(initial_mask[*(++ptr)=input_char()] == DIGIT)
;
unput_char();
*ptr = '\0';
externNumberVal=atoi((char *)parse_buffer);
return(NUMBER);
case ALPHA:
{
register int bucket;
register token_data_t * t;
while(initial_mask[*(++ptr)=input_char()] == ALPHA)
;
unput_char();
*ptr = '\0';
if ((bucket = tokens[hash_string((char *) parse_buffer)].first_token)
== -1) {
fprintf(stderr, "%s: cannot lex %s in callog file\n",
pgname, parse_buffer);
return(0);
}
while(strcmp(tokens[bucket].name, (char*)parse_buffer) != 0)
if((bucket = tokens[bucket].next_token) == -1) /* end of chain */ {
fprintf(stderr, "%s: cannot lex %s in callog file\n",
pgname, parse_buffer);
return(0);
}
t = tokens + bucket;
if(t->info_to_change)
*((int *) t->info_to_change) = t->token_value;
return(t->return_value);
}
case QUOTE: /* note that code removes leading and trailing quotes
*/
while(1) {
switch(*ptr = input_char())
{
case '\\':
*++ptr = input_char(); /* load next char in any case */
ptr++;
break;
case '"':
*ptr = 0;
strescapes((char *) parse_buffer); /* process any escape sequences */
externQuotedString = (char *) strdup((char *)parse_buffer);
return(QUOTEDSTRING);
case EOFILE:
case '\n':
case '\r':
fprintf(stderr, "%s: missing matching \" in callog file\n", pgname);
return(0);
default:
ptr++;
}
}
case EOFILE:
return(0);
case COMMENT:
{
int i;
for(i=0;i<3;i++) /* look for 4 **** as comment lead-in */
if(initial_mask[*(++ptr)=input_char()]!= COMMENT) {
*(++ptr) = 0;
fprintf(stderr, "%s: cannot lex %s in callog file\n",
pgname, parse_buffer);
return(0);
}
while(input_char() != '\n') /* eat up rest of comment */
;
yyylineno++; /* since we eat the newline here.... */
continue;
}
default:
fprintf(stderr, "%s: Unsupported char %c (ascii %d) found in callog file\n",
pgname, *ptr, *ptr);
return(0);
}
}
}
extern int
yyywrap(FILE *f)
{
fclose (f);
munmap(start_of_mmapped_area, len);
return (1);
}
extern int
setinput (FILE* f)
{
struct stat buff;
if(fstat(fileno(f), & buff) < 0) {
perror("fstat");
return(-1);
}
if((start_of_mmapped_area =
mmap(NULL,
len = buff.st_size,
PROT_READ,
MAP_PRIVATE,
fileno(f),
0)) == (caddr_t) -1) { /* mmap failed??? */
perror("mmap");
return(-1);
}
#if !defined(USL) && !defined(__uxp__) && !defined(linux)
/* no madvise so we lose this optimization */
madvise(start_of_mmapped_area, len, MADV_SEQUENTIAL);
#endif
end = start_of_mmapped_area + len;
current_ptr = start_of_mmapped_area;
yyylineno = 1;
return(0);
}
static int
hash_string(register char *s)
{
register unsigned result = 0;
register int sum;
while(sum = *s++)
result = (result << 4) + sum;
return(result % NUMTOKES);
}
/*---------------------------------------------------------------------------
Strescapes performs escape character processing in a manner similar to the C
compiler. It processes a character string passed to it and performs the
following substitutions in place:
\\ -> \
\" -> "
\e -> 033
\t -> 011
\n -> newline
\0nn -> 0nn
\r -> cr
A single \ in front of other characters is ignored(&removed). As with
most string routines, strescapes returns it's argument. Note that
inserting a \0 will end the string at that location, but the remainder of
the string will be processed.
---------------------------------------------------------------------------*/
static char *
strescapes(char *s)
{
register char * in=s, * out=s;
while(*in)
{
if(*in == '\\')
switch(*(in+1))
{
case 'e': /* an escape character */
*out++ = '\033';
in += 2;
break;
case 't': /* a tab character */
*out++ = '\t';
in += 2;
break;
case 'n': /* a newline */
*out++ = '\n';
in += 2;
break;
case 'r': /* a carriage return */
*out++ = '\r';
in += 2;
break;
case '\\': /* a backslash */
*out++ = '\\';
in += 2;
break;
case '0': /* a octal constant */
{
register int i,result;
in++;
for(result=i=0; (i<=3) && (*in >='0') && (*in <= '7') ; )
{
result <<= 3;
result += (*in++) - '0';
}
*out++ = result & 0377;
break;
}
default: /* not used as escape.... make it disappear */
in++; /* this also handles nulls */
break;
}
else
*out++ = * in++;
}
*out='\0';
return(s);
}
#ifdef TEST
main(int argc, char ** argv)
{
FILE * f;
int d;
if(argc < 2) {
printf("usage: %s filename\n", argv[0]);
exit(1);
}
if((f = fopen(argv[1], "r")) == NULL) {
perror("fopen");
exit(2);
}
if(setinput(f) < 0) {
exit(3);
}
while(d=yyylex()) {
if(argc == 2)
printf("received %d, text <%s>\n", d, parse_buffer);
}
exit(0);
}
#endif