/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */ /* The copyright notice above does not evidence any */ /* actual or intended publication of such source code. */ #ident "@(#)parse.c 1.4 92/07/14 SMI" /* SVr4.0 1.8 */ #include #include #include #ifdef WHITESP /* I don't think WHITESPACE should be skipped */ #define SKIPWS(p,d) \ while( p && *p \ && *p != e->td_eoe && *p != e->td_comment && *p != td_fs \ && (*p == ' ' || *p == '\t') ) \ p++ #else #define SKIPWS(p,d) #endif #define FSMSG "FIELD SEPARATOR=" #define ENTMSG "ENTRY FORMAT=" #define isoctal(c) (isdigit((int)c) && c != '8' && c != '9') #define ISWSPACE(c) (c == ' ' || c == '\t') #define FOUND 1 #define NOT_FOUND 0 #define P_ERROR -1 static unsigned char *inptr; static int p_errno; extern tbl_t TLtables[]; extern unsigned char TLinbuffer[]; char *strpbrk(); /* Find either \\octal number or a char */ static TLp_char() { register tmp = 0, i; if( *inptr == '\\' ) { inptr++; if( isoctal( *inptr ) ) { for( i = 0; i < 3; i++ ) if( *inptr && isoctal( *inptr ) ) { tmp = tmp * 8 + (int)*inptr; inptr++; } else break; } else return( *inptr++ ); } else tmp = *inptr++; return( (char) tmp ); } /* Like strpbrk(3C) but also returns ptr to NULL */ unsigned char * TLstrpbrk( s1, s2 ) unsigned char *s1, *s2; { register unsigned char *ptr; if( ptr = (unsigned char *)strpbrk( (char *)s1, (char *)s2 ) ) return( ptr ); return( s1 + Strlen(s1) ); } /* get the next field, handling escapes. Return ptr to spot after field. */ static unsigned char * getfield( ptr, size, terminators ) unsigned char *ptr, *terminators; int *size; { register unsigned char *to = ptr, *t; register sz = 0, nescapes = 0; while( *ptr ) { /* skip escapes except for */ if( *ptr == '\\' && *(++ptr) ) { /* Found an escape - skip it */ nescapes++; } else for( t = terminators; *t; t++ ) { if( *t == *ptr ) /* Found a terminator */ goto gf_done; } /* If some escapes have been found, then squeeze the effective field string together. */ if( nescapes > 0 ) *to = *ptr; ptr++; to++; sz++; } gf_done: *size = sz; return( ptr ); } /* Parse: [ ]* */ static TLp_fields( tptr, pstruct, count_wspace ) tbl_t *tptr; parse_t *pstruct; int count_wspace; { register unsigned char *tsave = inptr, *ptr; register field_t *fieldp = &(pstruct->fields); unsigned char terminators[ 10 ]; int size, saw_fs = FALSE; fieldp->count = 0; (void)sprintf( (char *)terminators, "%c%c%s", tptr->description.td_fs, tptr->description.td_comment, (count_wspace? " \t": "") ); while( TRUE ) { /* Look for next field - field is terminated by one of the terminator characters. Handle escapes. */ ptr = (unsigned char *)getfield( inptr, &size, terminators ); if( size || saw_fs || *ptr == tptr->description.td_fs ) { /* Found a field */ if( fieldp->count == TL_MAXFIELDS ) { /* Too many fields */ p_errno = TLBADFORMAT; return( P_ERROR ); } /* Found a field - get a buffer for it */ if( !(fieldp->values[ fieldp->count ] = (unsigned char *)Malloc( size + 1 ) ) ) { inptr = tsave; p_errno = TLNOMEMORY; return( P_ERROR ); } Strncpy( fieldp->values[ fieldp->count ], inptr, size ); fieldp->values[ fieldp->count ][size] = '\0'; fieldp->count++; } if( !*ptr || *ptr == tptr->description.td_comment || isspace((int)*ptr) && !count_wspace ) { /* Field was not terminated by a field separator; ergo we're done */ if( !fieldp->count ) { inptr = tsave; return( NOT_FOUND ); } inptr = ptr; return( FOUND ); } /* Skip the separator */ if( *ptr == tptr->description.td_fs ) { saw_fs = TRUE; ptr++; } inptr = ptr; } } /* parse "FIELD SEPARATOR=x" where: x is some character, or \\octal number */ /*ARGSUSED*/ static TLp_fs( tptr, pstruct ) tbl_t *tptr; parse_t *pstruct; { register unsigned char *tsave = inptr; if( !Strncmp( inptr, FSMSG, Strlen( FSMSG ) ) ) { inptr += Strlen( FSMSG ); if( pstruct->descr.td_fs = TLp_char() ) { pstruct->type |= (PT_COMMENT|PT_SPECIAL); return( FOUND ); } } inptr = tsave; return( NOT_FOUND ); } /* Parse "ENTRY FORMAT=[[^]+]+ */ static TLp_format( tptr, pstruct ) tbl_t *tptr; parse_t *pstruct; { register unsigned char *tsave = inptr; register rc = NOT_FOUND, countwspace; if( !Strncmp( inptr, ENTMSG, Strlen( ENTMSG ) ) ) { inptr += Strlen( ENTMSG ); countwspace = ISWSPACE(tptr->description.td_fs) || ISWSPACE(tptr->description.td_comment); switch( rc = TLp_fields( tptr, pstruct, countwspace ) ) { case FOUND: if( pstruct->fields.count == 0 ) { /* Disallow empty ENTRY FORMATs */ inptr = tsave; p_errno = TLBADFORMAT; rc = P_ERROR; } else { pstruct->type |= (PT_COMMENT|PT_SPECIAL); rc = FOUND; } break; default: inptr = tsave; } } return( rc ); } /* Parse a Special Self-describing comment. */ static TLp_special( tptr, pstruct ) tbl_t *tptr; parse_t *pstruct; { register unsigned char *tsave = inptr; if( *inptr != tptr->description.td_comment ) return( NOT_FOUND ); inptr++; /* Two types of special comments: > Field separator setting, > Entry format */ while( TLp_fs( tptr, pstruct ) || TLp_format( tptr, pstruct ) ) SKIPWS( inptr, tptr ); if( !(pstruct->type & PT_SPECIAL) ) { /* This was not a SPECIAL comment */ inptr = tsave; return( NOT_FOUND ); } else return( FOUND ); } /* Parse a Comment */ static TLp_comment( tptr, pstruct ) tbl_t *tptr; parse_t *pstruct; { register unsigned char *tsave = inptr; register size; if( *inptr != tptr->description.td_comment ) return( NOT_FOUND ); if( TLp_special( tptr, pstruct ) == NOT_FOUND ) pstruct->type |= PT_COMMENT; /* Regardless of whether or not it is a SPECIAL comment, it is a comment, so record it. */ inptr = tsave + 1; while( *inptr && *inptr != tptr->description.td_eoe ) inptr++; if( inptr != tsave + 1 ) { size = inptr - tsave + 1; if( !(pstruct->comment = (unsigned char *)Malloc( size + 5 ))) { /* Extra character malloc'd for strncpy's null */ inptr = tsave; p_errno = TLNOMEMORY; return( P_ERROR ); } Strncpy( pstruct->comment, tsave + 1, size ); pstruct->comment[ size + 1 ] = '\0'; } else pstruct->comment = 0; return( FOUND ); } /* Parse an entry - this is some (possibly zero) number of fields followed by an optional comment; */ static TLp_entry( tptr, pstruct ) tbl_t *tptr; parse_t *pstruct; { if( TLp_fields( tptr, pstruct, FALSE ) == P_ERROR ) return( P_ERROR ); if( TLp_comment( tptr, pstruct ) == P_ERROR ) return( P_ERROR ); return( FOUND ); } /* TLbparse() - parse an entry that is currently in a buffer. */ int TLbparse( tid, pstruct, buffer ) int tid; parse_t *pstruct; unsigned char *buffer; { register tbl_t *tptr = TLtables + tid; Strncpy( pstruct, "", sizeof( parse_t ) ); /* Assume buffer is null-terminated */ inptr = buffer; SKIPWS( inptr, &(tptr->description) ); if( TLp_entry( tptr, pstruct ) == P_ERROR ) return( p_errno ); return( TLOK ); } /* TLparse() starts at where ever the file id currently points, gets an entry, and parses it. The parse results are placed in pstruct; */ int TLparse( tid, pstruct, size ) int tid, *size; parse_t *pstruct; { register rc; /* Read next entry into max-sized buffer */ if( (rc = TLfl_getentry( tid, TLinbuffer, 2 * TL_MAXLINESZ )) > 0 ) { *size = rc; return( TLbparse( tid, pstruct, TLinbuffer ) ); } if( rc < 0 ) return( rc ); return( TLOK ); } int TLp_iscomment( tid, ptr ) int tid; unsigned char *ptr; { register tbl_t *tptr = TLtables + tid; SKIPWS(ptr, &(tptr->description) ); return( *ptr == tptr->description.td_comment ); } /* Parse and fill in field names */ int TLp_fieldnames( tid, buffer ) int tid; unsigned char *buffer; { register tbl_t *tptr = TLtables + tid; parse_t pstruct; inptr = buffer; if( TLp_fields( tptr, &pstruct, FALSE ) != FOUND ) return( FALSE ); tptr->fieldnames = pstruct.fields; return( TRUE ); }