583 lines
13 KiB
C
Executable File
583 lines
13 KiB
C
Executable File
/* 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 "@(#)entry.c 1.4 92/07/14 SMI" /* SVr4.0 1.10 */
|
|
#include <table.h>
|
|
#include <internal.h>
|
|
|
|
#define FPUTC( fid, c ) \
|
|
if( to == TLgenbuf + 2 * TL_MAXLINESZ ) { \
|
|
if( Write( tid, TLgenbuf, 2 * TL_MAXLINESZ ) != 2 * TL_MAXLINESZ ) \
|
|
return( TLFAILED ); \
|
|
to = TLgenbuf; \
|
|
} \
|
|
*to++ = c;
|
|
|
|
extern void TLf_free();
|
|
|
|
extern tbl_t TLtables[];
|
|
extern unsigned char TLinbuffer[];
|
|
extern unsigned char TLgenbuf[];
|
|
|
|
/* Grow an entry table - the table is always grown in E_GROWTH chunks */
|
|
static int
|
|
TLe_grow( tid )
|
|
int tid;
|
|
{
|
|
entryinfo_t *einfo = EINFO(tid);
|
|
|
|
if( !einfo->size ) {
|
|
if( !(ETAB(tid) = (entry_t **)Malloc( E_GROWTH * sizeof( entry_t * ) )))
|
|
return( TLNOMEMORY );
|
|
einfo->size = E_GROWTH;
|
|
} else {
|
|
if( !(ETAB(tid) = (entry_t **)Realloc( ETAB(tid),
|
|
(einfo->size + E_GROWTH) * sizeof( entry_t * ) ) ) )
|
|
return( TLNOMEMORY );
|
|
einfo->size += E_GROWTH;
|
|
}
|
|
return( TLOK );
|
|
}
|
|
|
|
entry_t *
|
|
TLe_malloc()
|
|
{
|
|
entry_t *entry;
|
|
if( entry = (entry_t *)Malloc( sizeof( entry_t ) ) ) {
|
|
Strncpy( entry, "", sizeof( entry_t ) );
|
|
return( entry );
|
|
} else return( NULL );
|
|
}
|
|
|
|
/* Free space associated with an entry */
|
|
void
|
|
TLe_free( entry )
|
|
entry_t *entry;
|
|
{
|
|
if( entry->status & IS_PARSED ) {
|
|
if( E_COMMENT(entry) ) {
|
|
Free( E_COMMENT(entry) );
|
|
E_COMMENT(entry) = NULL;
|
|
}
|
|
TLf_free( E_FIELDS(entry) );
|
|
}
|
|
entry->status = 0;
|
|
E_SEEKADDR(entry) = 0;
|
|
}
|
|
|
|
/*
|
|
Put a parsed entry structure in the table
|
|
*/
|
|
int
|
|
TLe_pput( tid, pstruct, entryno )
|
|
int tid;
|
|
parse_t *pstruct;
|
|
entryno_t entryno;
|
|
{
|
|
register entry_t *entry, **eptr;
|
|
|
|
if( !TLe_intable( tid, entryno ) ) return( TLINTERNAL );
|
|
|
|
eptr = ENTRYTAB( tid, entryno );
|
|
|
|
if( !(entry = *eptr ) ) return( TLINTERNAL );
|
|
if( entry->status & IS_PARSED )
|
|
TLe_free( entry );
|
|
|
|
entry->comment = pstruct->comment;
|
|
if( pstruct->type & PT_SPECIAL)
|
|
/* ignore ENTRY FORMAT comments here */
|
|
TLf_free( &(pstruct->fields) );
|
|
else entry->fields = pstruct->fields;
|
|
entry->status |= IS_PARSED;
|
|
return( TLOK );
|
|
}
|
|
|
|
/* Copy one entry to another */
|
|
TLe_copy( to, from )
|
|
entry_t *to, *from;
|
|
{
|
|
register rc = TLOK;
|
|
|
|
TLe_free( to );
|
|
to->status = from->status;
|
|
E_SEEKADDR(to) = E_SEEKADDR(from);
|
|
if( E_NFIELDS(from) > 0 )
|
|
rc = TLf_copy( E_FIELDS(to), E_FIELDS(from) );
|
|
if( (rc == TLOK ) && from->comment ) {
|
|
if( !(to->comment
|
|
= (unsigned char *)Malloc( Strlen( from->comment ) + 1 ) ) ) {
|
|
TLf_free( E_FIELDS(to) );
|
|
return( TLNOMEMORY );
|
|
}
|
|
Strcpy( to->comment, from->comment );
|
|
}
|
|
return( rc );
|
|
}
|
|
|
|
/* Write out an entry to a file, handle escapes in fields */
|
|
int
|
|
TLe_write( fid, tid, entry )
|
|
int fid, tid;
|
|
entry_t *entry;
|
|
{
|
|
register i, count, nfields;
|
|
tbl_t *tptr = TLtables + tid;
|
|
unsigned char **fptr;
|
|
register unsigned char *from, *to;
|
|
register unsigned char eoe, fs, comment;
|
|
|
|
eoe = tptr->description.td_eoe;
|
|
|
|
if( entry->status & IS_PARSED ) {
|
|
/*
|
|
If given an entry format, print out THAT many fields.
|
|
Unless, it is a COMMENT line.
|
|
*/
|
|
if( E_NFIELDS(entry ) )
|
|
nfields = ((tptr->status & GOT_FORMAT)? tptr->fieldnames.count:
|
|
E_NFIELDS(entry));
|
|
else nfields = 0;
|
|
|
|
fptr = E_GETFIELD( entry, 0 );
|
|
to = TLgenbuf;
|
|
from = *fptr;
|
|
|
|
fs = tptr->description.td_fs;
|
|
comment = tptr->description.td_comment;
|
|
|
|
if( nfields > 0 ) {
|
|
|
|
/* Print out 1st field */
|
|
while( *from ) {
|
|
if( *from == '\\' || *from == fs
|
|
|| *from == eoe || *from == '#' ) {
|
|
FPUTC( fid, '\\' );
|
|
}
|
|
|
|
FPUTC( fid, *from );
|
|
from++;
|
|
}
|
|
|
|
/* Write out <sep><fields> */
|
|
for( i = 1, fptr++, from = *fptr;
|
|
i < nfields;
|
|
i++, fptr++, from = *fptr ) {
|
|
|
|
FPUTC( fid, fs );
|
|
|
|
while( from && *from ) {
|
|
if( *from == '\\' || *from == fs
|
|
|| *from == eoe || *from == comment ) {
|
|
FPUTC( fid, '\\' );
|
|
}
|
|
|
|
FPUTC( fid, *from );
|
|
from++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Copy out Comment */
|
|
if( E_COMMENT(entry) ) {
|
|
FPUTC( fid, comment );
|
|
from = E_COMMENT(entry);
|
|
while( *from ) {
|
|
FPUTC( fid, *from );
|
|
from++;
|
|
}
|
|
}
|
|
|
|
/* Write out End of Entry char */
|
|
FPUTC( fid, eoe );
|
|
|
|
count = to - TLgenbuf;
|
|
|
|
if( count > 0 )
|
|
if( Write( fid, TLgenbuf, count ) != count )
|
|
return( TLFAILED );
|
|
|
|
} else {
|
|
/*
|
|
File entry. ASSERT: special characters in file entries
|
|
have already been escaped.
|
|
*/
|
|
/* Seek to correct place in the file */
|
|
if( Lseek( tptr->file.fid, E_SEEKADDR(entry), 0 ) != E_SEEKADDR(entry) )
|
|
return( TLFAILED );
|
|
if( (count = TLfl_getentry( tid, TLinbuffer, 2 * TL_MAXLINESZ )) < 0 )
|
|
return( count );
|
|
|
|
/* Count includes EOE char */
|
|
TLinbuffer[ count - 1 ] = eoe;
|
|
|
|
/* Write out whole entry and then an end of entry char. */
|
|
if( (count && Write( fid, TLinbuffer, count ) != count) )
|
|
return( TLFAILED );
|
|
}
|
|
return( count );
|
|
}
|
|
|
|
/*
|
|
Shift the entry table from entryno either up one (for delete)
|
|
(direction == -1 ) or down one (for add ) (direction == 1 );
|
|
If delete, the deleted entry is freed.
|
|
*/
|
|
static int
|
|
TLe_shift( tid, entryno, direction )
|
|
int tid, direction;
|
|
entryno_t entryno;
|
|
{
|
|
register entryinfo_t *einfo = EINFO(tid);
|
|
register entry_t **eptr;
|
|
register rc;
|
|
|
|
if( direction == 0 ) return( TLOK );
|
|
|
|
if( direction > 0 ) {
|
|
/* Make sure there is enough room to shift; NOTE: nentries + 1 is END */
|
|
if( einfo->nentries + 5 > einfo->size )
|
|
if( (rc = TLe_grow( tid )) != TLOK ) return( rc );
|
|
|
|
for( eptr = ENTRYTAB( tid, einfo->nentries + 1 );
|
|
eptr >= ENTRYTAB( tid, entryno ); eptr-- ) {
|
|
|
|
*(eptr + 1) = *eptr;
|
|
*eptr = NULL;
|
|
}
|
|
} else if( TLe_intable( tid, entryno ) ) {
|
|
/* Free 'deleted' entry */
|
|
eptr = ENTRYTAB( tid, entryno );
|
|
TLe_free( *eptr );
|
|
free( *eptr );
|
|
|
|
for( ; eptr <= ENTRYTAB( tid, einfo->nentries + 1 ); eptr++ ) {
|
|
*eptr = *(eptr + 1 );
|
|
}
|
|
}
|
|
return( TLOK );
|
|
}
|
|
|
|
/*
|
|
Initialize the Entry and Non-Comment Map tables.
|
|
*/
|
|
int
|
|
TLe_init( tid )
|
|
int tid;
|
|
{
|
|
register entryinfo_t *einfo = EINFO(tid);
|
|
register entry_t *begin, *end;
|
|
register rc;
|
|
|
|
/* Get memory for entry table and map */
|
|
if( ( rc = TLe_grow( tid )) != TLOK ) return( rc );
|
|
|
|
/* Put in BEGIN */
|
|
if( !(begin = (entry_t *)TLe_malloc()) )
|
|
return( TLNOMEMORY );
|
|
begin->status = IS_BEGIN;
|
|
*(ENTRYTAB(tid,0)) = begin;
|
|
|
|
/* Put in END */
|
|
if( !(end = (entry_t *)TLe_malloc() ) ) {
|
|
TLe_free( begin );
|
|
free( begin );
|
|
return( TLNOMEMORY );
|
|
}
|
|
end->status = IS_END;
|
|
*(ENTRYTAB(tid,1)) = end;
|
|
|
|
einfo->nentries = 0;
|
|
|
|
return( TLOK );
|
|
}
|
|
|
|
/*
|
|
Add entry into the table at Entryno.
|
|
*/
|
|
int
|
|
TLe_add( tid, entryno, entry )
|
|
int tid;
|
|
entryno_t entryno;
|
|
entry_t *entry;
|
|
{
|
|
register rc;
|
|
|
|
if( entryno != T_EEND(tid) && !TLe_intable( tid, entryno ) )
|
|
return( TLBADENTRY );
|
|
|
|
/* Make room in entry table for the new entry */
|
|
if( (rc = TLe_shift( tid, entryno, 1 )) != TLOK ) return( rc );
|
|
|
|
/* Put entry in table */
|
|
*(ENTRYTAB( tid, entryno )) = entry;
|
|
|
|
EINFO(tid)->nentries++;
|
|
|
|
return( TLOK );
|
|
}
|
|
|
|
/* Fill in Default Field names */
|
|
TLe_dfltformat( fields )
|
|
field_t *fields;
|
|
{
|
|
register i;
|
|
unsigned char *ptr;
|
|
fields->count = 0;
|
|
for( i = 0; i < TL_MAXFIELDS; i++, fields->count++ ) {
|
|
if( !(ptr = (unsigned char *)Malloc( 5 )) ) {
|
|
TLf_free( fields );
|
|
return( TLNOMEMORY );
|
|
}
|
|
(void)sprintf( (char *)ptr, "%d", i + 1 );
|
|
fields->values[i] = ptr;
|
|
}
|
|
return( TLOK );
|
|
}
|
|
|
|
/* find 1st Non-Commentary entry, looking for Special comments */
|
|
int
|
|
TLe_prolog( tid, descr )
|
|
int tid;
|
|
TLdesc_t *descr;
|
|
{
|
|
register tbl_t *tptr = TLtables + tid;
|
|
register count, done = FALSE, seekaddr = 0, rc = TLOK;
|
|
register trc, gotfs = FALSE, gotformat = FALSE;
|
|
register TLdesc_t *dptr = &(tptr->description);
|
|
parse_t pstruct;
|
|
register entry_t *entry;
|
|
field_t filefieldnames;
|
|
unsigned char filefs;
|
|
int size;
|
|
|
|
/* Set up Description */
|
|
dptr->td_fs = descr->td_fs? descr->td_fs: ':';
|
|
dptr->td_eoe = descr->td_eoe? descr->td_eoe: '\n';
|
|
dptr->td_comment = descr->td_comment? descr->td_comment: '#';
|
|
|
|
if( descr->td_format )
|
|
if( !TLp_fieldnames( tid, descr->td_format ) ) return( TLBADFORMAT );
|
|
|
|
count = 1;
|
|
if( tptr->file.fid ) {
|
|
if( Lseek( tptr->file.fid, 0L, 0 ) < 0 ) return( TLFAILED );
|
|
} else done = 1;
|
|
while( !done ) {
|
|
if( (rc = TLparse( tid, &pstruct, &size )) == TLEOF ) {
|
|
tptr->status |= FOUND_EOF;
|
|
rc = TLOK;
|
|
break;
|
|
}
|
|
if( rc != TLOK ) return( rc );
|
|
if( !(entry = (entry_t *)TLe_malloc() ) )
|
|
return( TLNOMEMORY );
|
|
if( pstruct.type & PT_SPECIAL ) {
|
|
if( pstruct.fields.count > 0 ) {
|
|
gotformat = TRUE;
|
|
filefieldnames = pstruct.fields;
|
|
}
|
|
if( pstruct.descr.td_fs ) {
|
|
gotfs = TRUE;
|
|
filefs = pstruct.descr.td_fs;
|
|
}
|
|
} else done = TRUE;
|
|
if( pstruct.fields.count != 0 ) {
|
|
/*
|
|
If this is not a comment line, delay the parsing of it
|
|
until AFTER any description info from the open has been
|
|
recorded.
|
|
*/
|
|
entry->status = IN_FILE;
|
|
} else {
|
|
entry->comment = pstruct.comment;
|
|
entry->status |= IS_PARSED;
|
|
}
|
|
E_SEEKADDR(entry) = seekaddr;
|
|
|
|
/* keep track of how far the file has been parsed */
|
|
if( seekaddr > tptr->hiwater )
|
|
tptr->hiwater = seekaddr;
|
|
|
|
if( (rc = TLe_add( tid, count, entry ) ) != TLOK ) {
|
|
TLe_free( entry );
|
|
Free( entry );
|
|
return( rc );
|
|
}
|
|
count++;
|
|
seekaddr += size;
|
|
}
|
|
if( rc != TLOK ) goto e_prolog_out;
|
|
|
|
if( gotfs ) {
|
|
dptr->td_fs = filefs;
|
|
if( descr->td_fs ) {
|
|
rc = TLBADFS;
|
|
goto e_prolog_out;
|
|
}
|
|
}
|
|
|
|
if( descr->td_format ) {
|
|
/* Note: descr->td_format is already parsed and in tptr */
|
|
if( gotformat && TLf_compare( &(tptr->fieldnames), &(filefieldnames) ) ) {
|
|
rc = TLDIFFFORMAT;
|
|
|
|
/* Use Format in file */
|
|
TLf_free( &(tptr->fieldnames) );
|
|
tptr->fieldnames = filefieldnames;
|
|
}
|
|
tptr->status |= GOT_FORMAT;
|
|
|
|
} else if( gotformat ) {
|
|
tptr->fieldnames = filefieldnames;
|
|
tptr->status |= GOT_FORMAT;
|
|
|
|
} else if( (trc = TLe_dfltformat( &(tptr->fieldnames) ) ) != TLOK )
|
|
rc = trc;
|
|
|
|
e_prolog_out:
|
|
return( rc );
|
|
}
|
|
|
|
/*
|
|
Delete an entry table entry at Entryno; Non-comment map is updated
|
|
*/
|
|
int
|
|
TLe_delete( tid, entryno )
|
|
int tid;
|
|
entryno_t entryno;
|
|
{
|
|
register rc;
|
|
|
|
if( !TLe_intable( tid, entryno ) ) return( TLBADENTRY );
|
|
|
|
/* Delete the entryno */
|
|
if( (rc = TLe_shift( tid, entryno, -1 )) != TLOK ) return( rc );
|
|
|
|
EINFO( tid )->nentries--;
|
|
|
|
return( TLOK );
|
|
}
|
|
|
|
/*
|
|
Parse an INFILE entry and put it in the table
|
|
*/
|
|
int
|
|
TLe_parse( tid, entry, entryno )
|
|
int tid;
|
|
entryno_t entryno;
|
|
entry_t *entry;
|
|
{
|
|
parse_t pstruct;
|
|
register tbl_t *tptr = TLtables + tid;
|
|
register rc;
|
|
int size;
|
|
|
|
if( entry->status & IS_PARSED ) return( TLOK );
|
|
if( Lseek( tptr->file.fid, E_SEEKADDR(entry), 0 ) == -1 )
|
|
return( TLFAILED );
|
|
if( (rc = TLparse( tid, &pstruct,&size )) == TLEOF )
|
|
return( TLBADENTRY );
|
|
if( rc == TLOK ) rc = TLe_pput( tid, &pstruct, entryno );
|
|
return( rc );
|
|
}
|
|
|
|
/* Return a pointer to the entry entry of an IN-TABLE entry */
|
|
int
|
|
TLe_getentry( tid, entryno, eptr )
|
|
int tid;
|
|
entryno_t entryno;
|
|
entry_t **eptr;
|
|
{
|
|
register rc;
|
|
if( !TLe_intable( tid, entryno ) && (rc = TLe_find( tid, entryno )) != TLOK )
|
|
return( rc );
|
|
|
|
*eptr = *(ENTRYTAB(tid, entryno));
|
|
|
|
if( !((*eptr)->status & IS_PARSED ) )
|
|
return( TLe_parse( tid, *eptr, entryno ) );
|
|
|
|
return( TLOK );
|
|
}
|
|
|
|
/*
|
|
Find non-TLBEGIN and non-TLEND entries. This routine makes sure
|
|
that if the entries exist, they end up parsed and in the table.
|
|
*/
|
|
int
|
|
TLe_find( tid, entryno )
|
|
int tid;
|
|
entryno_t entryno;
|
|
{
|
|
register tbl_t *tptr = TLtables + tid;
|
|
entry_t *entry, *newentry;
|
|
register nseekaddr, rc = TLOK, count, last, findeof = IS_FROM_END(entryno);
|
|
parse_t pstruct;
|
|
|
|
/* If in table, then all that is needed is to parse the entry */
|
|
if( !findeof && TLe_intable( tid, entryno ) )
|
|
return( TLe_getentry( tid, entryno, &entry ) );
|
|
|
|
/* else if whole table has been parsed, then no such entry */
|
|
if( tptr->status & FOUND_EOF ) return( (findeof? TLOK: TLBADENTRY) );
|
|
|
|
/* Find Last Entry that is known */
|
|
last = (T_EEND(tid) - 1);
|
|
count = (findeof? 1: (entryno - last));
|
|
|
|
/* Seek to where we have parsed in the file */
|
|
nseekaddr = tptr->hiwater;
|
|
if( Lseek( tptr->file.fid, nseekaddr, 0 ) == -1 )
|
|
return( TLFAILED );
|
|
|
|
/* Get entry to the position AFTER this entry */
|
|
if( (rc = TLfl_getentry( tid, TLinbuffer, 2 * TL_MAXLINESZ )) < 0 ) {
|
|
if( rc == TLEOF ) {
|
|
/* This 'shouldn't' happen - i.e. this entry should've been
|
|
gotten before, but just in case ... */
|
|
tptr->status |= FOUND_EOF;
|
|
rc = (findeof? TLOK: TLBADENTRY);
|
|
}
|
|
return( rc );
|
|
}
|
|
nseekaddr += rc;
|
|
|
|
/* Now, skip passed intervening entries in the file, until the
|
|
desired one if found */
|
|
while( count > 0 ) {
|
|
/* Get next entry from file */
|
|
if( (rc = TLfl_getentry( tid, TLinbuffer, 2 * TL_MAXLINESZ )) < 0
|
|
&& rc != TLEOF )
|
|
return( rc );
|
|
if( rc == 0 || rc == TLEOF ) {
|
|
/* No next entry to get */
|
|
tptr->status |= FOUND_EOF;
|
|
return( (findeof? TLOK: TLBADENTRY) );
|
|
}
|
|
if( !(newentry = (entry_t *)TLe_malloc() ) )
|
|
return( TLNOMEMORY );
|
|
E_SEEKADDR(newentry) = nseekaddr;
|
|
if( nseekaddr > tptr->hiwater )
|
|
tptr->hiwater = nseekaddr;
|
|
nseekaddr += rc;
|
|
newentry->status |= IN_FILE;
|
|
/* Put in table */
|
|
if( (rc = TLe_add( tid, last + 1, newentry ) ) != TLOK ) {
|
|
TLe_free( newentry );
|
|
Free( newentry );
|
|
return( rc );
|
|
}
|
|
if( !findeof ) count--;
|
|
last++;
|
|
}
|
|
/* Now it is in the table */
|
|
if( (rc = TLbparse( tid, &pstruct, TLinbuffer )) == TLOK )
|
|
rc = TLe_pput( tid, &pstruct, entryno );
|
|
return( rc );
|
|
}
|