/* lex.c -- lexers for command line script installer * Tim Martin * $Id: lex.c,v 1.5 2005/03/05 00:37:10 dasenbro Exp $ */ /* * Copyright (c) 1998-2003 Carnegie Mellon University. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The name "Carnegie Mellon University" must not be used to * endorse or promote products derived from this software without * prior written permission. For permission or any other legal * details, please contact * Office of Technology Transfer * Carnegie Mellon University * 5000 Forbes Avenue * Pittsburgh, PA 15213-3890 * (412) 268-4387, fax: (412) 268-7395 * tech-transfer@andrew.cmu.edu * * 4. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by Computing Services * at Carnegie Mellon University (http://www.cmu.edu/computing/)." * * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include "prot.h" #include "lex.h" #include "codes.h" /* current state the lexer is in */ int lexer_state = LEXER_STATE_NORMAL; #define ACAP_MAX_QSTR_LEN 4096 #define ERR() { \ lexer_state=LEXER_STATE_RECOVER; \ return SIEVE_FAIL; \ /* (result == DAEMON_ERR_EOF ? EOF : ERROR);*/ \ } #define ERR_PUSHBACK() { \ prot_ungetc(ch, stream); \ ERR(); \ } int token_lookup(char *str, int len) { if (strcmp(str,"ok")==0) return TOKEN_OK; if (strcmp(str,"no")==0) return TOKEN_NO; if (strcmp(str,"active")==0) return TOKEN_ACTIVE; return -1; } int yylex(lexstate_t * lvalp, void * client) { int ch; char buffer[ACAP_MAX_QSTR_LEN]; /* big enough for everything */ char *buff_ptr = buffer; /* ptr into the buffer */ char *buff_end = buffer + ACAP_MAX_QSTR_LEN -1; unsigned long count=0; int result = SIEVE_OK; int synchronizing; /* wheather we are in the process of reading a synchronizing string or not */ struct protstream *stream=(struct protstream *) client; while (1) { /* get a character this may block on a read if there is nothing in the buffer */ ch = prot_getc(stream); if (ch == -1) { return SIEVE_FAIL; } switch (lexer_state) { case LEXER_STATE_RECOVER: if (ch == '\r') lexer_state=LEXER_STATE_RECOVER_CR; break; case LEXER_STATE_RECOVER_CR: if (ch == '\n') lexer_state=LEXER_STATE_NORMAL; return EOL; case LEXER_STATE_CR: if (ch == '\n') { lexer_state=LEXER_STATE_NORMAL; return EOL; } /* otherwise, life is bad */ ERR_PUSHBACK(); case LEXER_STATE_QSTR: if (ch == '\"') { /* End of the string */ lvalp->str = NULL; /* if (! client->recovering) { */ result = string_allocate(buff_ptr - buffer, buffer, &lvalp->str); if (result != SIEVE_OK) ERR_PUSHBACK(); /*} */ lexer_state=LEXER_STATE_NORMAL; return STRING; } if (ch == '\0' || 0x7F < ((unsigned char)ch)) ERR_PUSHBACK(); /* Otherwise, we're appending a character */ if (buff_end <= buff_ptr) ERR_PUSHBACK(); /* too long! */ if (ch == '\\') { ch=prot_getc(stream); if (result != SIEVE_OK) ERR(); if (ch != '\"' && ch != '\\') ERR_PUSHBACK(); } *buff_ptr++ = ch; break; case LEXER_STATE_LITERAL: if (('0' <= ch) && (ch <= '9')) { unsigned long newcount = count * 10 + (ch - '0'); if (newcount < count) ERR_PUSHBACK(); /* overflow */ /* * XXX This should be fatal if non-synchronizing. */ count = newcount; break; } synchronizing = FALSE; if (ch != '}') ERR_PUSHBACK(); ch=prot_getc(stream); if (ch < 0) ERR(); if (ch != '\r') ERR_PUSHBACK(); ch=prot_getc(stream); if (ch < 0) ERR(); if (ch != '\n') ERR_PUSHBACK(); if (synchronizing) { /* static const char sync_reply[] = "+ \"Ready for data\"\r\n";*/ /* xxx if (client->recovering) return EOL;*/ /* pthread_mutex_lock(client_OUTPUT_MUTEX(client)); conn_write(client_CONN(client), sync_reply, sizeof(sync_reply) - 1); conn_flush(client_CONN(client)); pthread_mutex_unlock(client_OUTPUT_MUTEX(client));*/ } lvalp->str = NULL; result = string_allocate(count, NULL, &lvalp->str); if (result != SIEVE_OK) ERR_PUSHBACK(); /* there is a literal string on the wire. let's read it */ { char *it = string_DATAPTR(lvalp->str), *end = it + count; while (it < end) { *it=prot_getc(stream); it++; } } lexer_state=LEXER_STATE_NORMAL; return STRING; case LEXER_STATE_NUMBER: if (('0' <= ch) && (ch <= '9')) { unsigned long newcount = count * 10 + (ch - '0'); if (newcount < count) ERR_PUSHBACK(); /* overflow */ count = newcount; } else { lvalp->number = count; lexer_state=LEXER_STATE_NORMAL; prot_ungetc(ch, stream); return NUMBER; } break; case LEXER_STATE_NORMAL: if (isalpha((unsigned char) ch)) { lexer_state=LEXER_STATE_ATOM; *buff_ptr++ = tolower(ch); break; } switch (ch) { case '(': return '('; case ')': return ')'; case ' ': return ' '; case '\"': lexer_state=LEXER_STATE_QSTR; break; case '*': return '*'; case '0': /* fall through all numbers */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': count = ch - '0'; lexer_state=LEXER_STATE_NUMBER; break; case '{': count = 0; synchronizing = TRUE; lexer_state=LEXER_STATE_LITERAL; break; case '\r': lexer_state=LEXER_STATE_CR; break; case '\n': lexer_state=LEXER_STATE_NORMAL; return EOL; break; default: ERR_PUSHBACK(); } break; case LEXER_STATE_ATOM: if (!isalpha((unsigned char) ch)) { int token; buffer[ buff_ptr - buffer] = '\0'; /* We've got the atom. */ token = token_lookup((char *) buffer, (int) (buff_ptr - buffer)); if (token!=-1) { lexer_state=LEXER_STATE_NORMAL; prot_ungetc(ch, stream); return token; } else ERR_PUSHBACK(); } if (buff_end <= buff_ptr) ERR_PUSHBACK(); /* atom too long */ *buff_ptr++ = tolower(ch); break; } } /* while (1) */ return 0; }