home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-11-28 | 32.5 KB | 1,394 lines |
- Newsgroups: comp.sources.unix
- From: panos@anchor.cs.colorado.edu (Panos Tsirigotis)
- Subject: v27i124: clc - C Libraries Collection, Part18/20
- References: <1.754527080.23891@gw.home.vix.com>
- Sender: unix-sources-moderator@gw.home.vix.com
- Approved: vixie@gw.home.vix.com
-
- Submitted-By: panos@anchor.cs.colorado.edu (Panos Tsirigotis)
- Posting-Number: Volume 27, Issue 124
- Archive-Name: clc/part18
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 18 (of 20)."
- # Contents: libs/src/dict/ht.c libs/src/sio/sio.c
- # Wrapped by panos@eclipse on Sun Nov 28 14:48:17 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'libs/src/dict/ht.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'libs/src/dict/ht.c'\"
- else
- echo shar: Extracting \"'libs/src/dict/ht.c'\" \(14487 characters\)
- sed "s/^X//" >'libs/src/dict/ht.c' <<'END_OF_FILE'
- X/*
- X * (c) Copyright 1993 by Panagiotis Tsirigotis
- X * All rights reserved. The file named COPYRIGHT specifies the terms
- X * and conditions for redistribution.
- X */
- X
- Xstatic char RCSid[] = "$Id: ht.c,v 3.2 93/09/28 21:08:12 panos Exp $" ;
- X
- X#include "htimpl.h"
- X
- Xenum lookup_type { EMPTY, FULL } ;
- X
- X
- X#define HASH( hp, func, arg ) \
- X ( &(hp)->table[ (*(func))( arg ) % (hp)->args.ht_table_entries ] )
- X
- X#define HASH_OBJECT( hp, obj ) HASH( hp, (hp)->args.ht_objvalue, obj )
- X#define HASH_KEY( hp, obj ) HASH( hp, (hp)->args.ht_keyvalue, key )
- X
- X
- X#define N_PRIMES ( sizeof( primes ) / sizeof( unsigned ) )
- X
- X
- X/*
- X * Used for the selection of a good array size
- X */
- Xstatic unsigned primes[] = { 3, 5, 7, 11, 13, 17, 23, 29 } ;
- X
- X
- X/*
- X * Pick a good number for hashing using the hint argument as a hint
- X * on the order of magnitude.
- X *
- X * Algorithm:
- X * 1. Find an odd number for testing numbers for primes. The starting
- X * point is 2**k-1 where k is selected such that
- X * 2**k-1 <= hint < 2**(k+1)-1
- X * 2. Check all odd numbers from the starting point on until you find
- X * one that is not a multiple of the selected primes.
- X */
- XPRIVATE unsigned find_good_size( hint )
- X register unsigned hint ;
- X{
- X register int k ;
- X unsigned starting_point ;
- X register unsigned size ;
- X
- X /*
- X * Don't bother with silly hints
- X */
- X if ( hint < DEFAULT_TABLE_ENTRIES )
- X return( DEFAULT_TABLE_ENTRIES ) ;
- X
- X /*
- X * Find starting point
- X *
- X * XXX: a hint that is too large ( 1 << ( WORD_SIZE - 1 ) ) will cause
- X * weird behavior
- X */
- X for ( k = 0 ; ; k++ )
- X if ( hint < ( 1 << k ) - 1 )
- X break ;
- X
- X starting_point = ( 1 << (k-1) ) - 1 ;
- X
- X /*
- X * XXX: This may be slow, especially on machines without division
- X * hardware (for example, SPARC V[78] implementations).
- X */
- X for ( size = starting_point ;; size += 2 )
- X {
- X register int j ;
- X
- X for ( j = 0 ; j < sizeof( primes ) / sizeof( unsigned ) ; j++ )
- X if ( size % primes[j] == 0 )
- X goto next ;
- X return( size ) ;
- Xnext: ;
- X }
- X}
- X
- X
- X/*
- X * Create a new hash table
- X */
- Xdict_h ht_create( oo_comp, ko_comp, flags, errnop, argsp )
- X dict_function oo_comp ;
- X dict_function ko_comp ;
- X int flags ;
- X int *errnop ;
- X struct ht_args *argsp ;
- X{
- X header_s *hp ;
- X int allocator_flags ;
- X unsigned table_size, bucket_size ;
- X char *id = "ht_create" ;
- X char *memset() ;
- X
- X if ( !__dict_args_ok( id, flags, errnop, oo_comp, ko_comp, DICT_UNORDERED ) )
- X return( NULL_HANDLE ) ;
- X
- X if ( argsp->ht_objvalue == NULL || argsp->ht_keyvalue == NULL )
- X return( __dict_create_error( id, flags, errnop, DICT_ENOHVFUNC ) ) ;
- X
- X hp = HHP( malloc( sizeof( header_s ) ) ) ;
- X if ( hp == NULL )
- X return( __dict_create_error( id, flags, errnop, DICT_ENOMEM ) ) ;
- X
- X /*
- X * Allocate the hash table
- X */
- X if ( argsp->ht_table_entries == 0 )
- X argsp->ht_table_entries = DEFAULT_TABLE_ENTRIES ;
- X else
- X argsp->ht_table_entries = find_good_size( argsp->ht_table_entries ) ;
- X
- X table_size = argsp->ht_table_entries * sizeof( tabent_s ) ;
- X hp->table = TEP( malloc( table_size ) ) ;
- X if ( hp->table == NULL )
- X {
- X free( (char *)hp ) ;
- X return( __dict_create_error( id, flags, errnop, DICT_ENOMEM ) ) ;
- X }
- X
- X /*
- X * Determine the bucket size and create an allocator
- X */
- X if ( argsp->ht_bucket_entries == 0 )
- X argsp->ht_bucket_entries = DEFAULT_BUCKET_ENTRIES ;
- X bucket_size = sizeof( bucket_s ) +
- X argsp->ht_bucket_entries * sizeof( dict_obj ) ;
- X
- X /*
- X * XXX: can't use fast allocator if we set FSM_ZERO_ALLOC
- X *
- X * XXX: should be able to give some indication to FSMA about the
- X * slots/chunk; currently we use the default.
- X */
- X allocator_flags = FSM_ZERO_ALLOC ;
- X if ( flags & DICT_RETURN_ERROR )
- X allocator_flags |= FSM_RETURN_ERROR ;
- X hp->alloc = fsm_create( bucket_size, 0, allocator_flags ) ;
- X if ( hp->alloc == NULL )
- X {
- X free( (char *)hp ) ;
- X free( (char *)hp->table ) ;
- X return( __dict_create_error( id, flags, errnop, DICT_ENOMEM ) ) ;
- X }
- X
- X __dict_init_header( DHP( hp ), oo_comp, ko_comp, flags, errnop ) ;
- X
- X /*
- X * Clear the table
- X */
- X (void) memset( (char *) hp->table, 0, (int) table_size ) ;
- X
- X hp->args = *argsp ;
- X return( (dict_h) hp ) ;
- X}
- X
- X
- X
- Xvoid ht_destroy( handle )
- X dict_h handle ;
- X{
- X header_s *hp = HHP( handle ) ;
- X
- X fsm_destroy( hp->alloc ) ;
- X free( (char *)hp->table ) ;
- X free( (char *)hp ) ;
- X}
- X
- X
- X/*
- X * Bucket chain reverse lookup:
- X * Return a pointer to the last dict_obj of the bucket chain that
- X * starts with bp (search up to the bucket 'stop' but *not* that bucket)
- X */
- XPRIVATE dict_obj *bc_reverse_lookup( bp, entries, stop )
- X bucket_s *bp ;
- X unsigned entries ;
- X bucket_s *stop ;
- X{
- X dict_obj *result ;
- X dict_obj *bucket_list ;
- X int j ;
- X
- X if ( bp == stop )
- X return( NULL ) ;
- X
- X result = bc_reverse_lookup( bp->next, entries, stop ) ;
- X if ( result )
- X return( result ) ;
- X
- X bucket_list = BUCKET_OBJECTS( bp ) ;
- X
- X for ( j = entries-1 ; j >= 0 ; j-- )
- X if ( bucket_list[ j ] != NULL )
- X return( &bucket_list[ j ] ) ;
- X return( NULL ) ;
- X}
- X
- X
- X/*
- X * Bucket chain lookup:
- X * Return a pointer to the first NULL (if type is EMPTY) or non-NULL
- X * (if type is FULL) dict_obj in the bucket chain.
- X */
- XPRIVATE dict_obj *bc_lookup( start, entries, type )
- X bucket_s *start ;
- X unsigned entries ;
- X enum lookup_type type ;
- X{
- X register bucket_s *bp ;
- X register int look_for_empty = ( type == EMPTY ) ;
- X
- X for ( bp = start ; bp != NULL ; bp = bp->next )
- X {
- X int j ;
- X dict_obj *bucket_list = BUCKET_OBJECTS( bp ) ;
- X
- X for ( j = 0 ; j < entries ; j++ )
- X if ( ( bucket_list[j] == NULL ) == look_for_empty )
- X return( &bucket_list[j] ) ;
- X }
- X return( NULL ) ;
- X}
- X
- X
- X
- X/*
- X * Search the bucket chain for the specified object
- X * Returns the pointer of the bucket where the object was found.
- X */
- XPRIVATE bucket_s *bc_search( chain, entries, object, index )
- X bucket_s *chain ;
- X unsigned entries ;
- X dict_obj object ;
- X int *index ;
- X{
- X bucket_s *bp ;
- X
- X for ( bp = chain ; bp ; bp = bp->next )
- X {
- X dict_obj *bucket_list = BUCKET_OBJECTS( bp ) ;
- X int i ;
- X
- X for ( i = 0 ; i < entries ; i++ )
- X if ( bucket_list[ i ] == object )
- X {
- X if ( index )
- X *index = i ;
- X return( bp ) ;
- X }
- X }
- X return( NULL ) ;
- X}
- X
- X
- X
- X/*
- X * Add a bucket to the chain of the specified table entry.
- X * Returns a pointer to the first slot of the new bucket or NULL on failure.
- X */
- XPRIVATE dict_obj *te_expand( tep, hp )
- X tabent_s *tep ;
- X header_s *hp ;
- X{
- X dheader_s *dhp = DHP( hp ) ;
- X bucket_s *bp ;
- X
- X bp = (bucket_s *) fsm_alloc( hp->alloc ) ;
- X if ( bp == NULL )
- X HANDLE_ERROR( dhp, "te_expand", DICT_ENOMEM, NULL ) ;
- X
- X /*
- X * Put the bucket at the head of this entry's chain
- X */
- X bp->next = tep->head_bucket ;
- X tep->head_bucket = bp ;
- X
- X /*
- X * Update entry info
- X */
- X tep->n_free += hp->args.ht_bucket_entries ;
- X return( BUCKET_OBJECTS( bp ) ) ;
- X}
- X
- X
- X/*
- X * Search a table entry for an object
- X */
- XPRIVATE dict_obj *te_search( tep, hp, type, arg )
- X tabent_s *tep ;
- X header_s *hp ;
- X search_e type ;
- X dict_h arg ;
- X{
- X dheader_s *dhp = DHP( hp ) ;
- X bucket_s *bp ;
- X
- X for ( bp = tep->head_bucket ; bp != NULL ; bp = bp->next )
- X {
- X int i ;
- X int result ;
- X dict_obj *bucket_list = BUCKET_OBJECTS( bp ) ;
- X
- X for ( i = 0 ; i < hp->args.ht_bucket_entries ; i++ )
- X if ( bucket_list[ i ] != NULL )
- X {
- X result = ( type == KEY_SEARCH )
- X ? (*dhp->ko_comp)( (dict_key)arg, bucket_list[ i ] )
- X : (*dhp->oo_comp)( (dict_obj)arg, bucket_list[ i ] ) ;
- X if ( result == 0 )
- X return( &bucket_list[ i ] ) ;
- X }
- X }
- X return( NULL ) ;
- X}
- X
- X
- XPRIVATE int ht_do_insert( hp, uniq, object, objectp )
- X header_s *hp ;
- X int uniq ;
- X register dict_obj object ;
- X dict_obj *objectp ;
- X{
- X dheader_s *dhp = DHP( hp ) ;
- X tabent_s *tep ;
- X dict_obj *object_slot ;
- X
- X if ( object == NULL )
- X HANDLE_ERROR( dhp, "ht_do_insert", DICT_ENULLOBJECT, DICT_ERR ) ;
- X
- X tep = HASH_OBJECT( hp, object ) ;
- X
- X /*
- X * We search the entry chain only if it exists and uniqueness is required.
- X */
- X if ( ENTRY_HAS_CHAIN( tep ) && uniq )
- X {
- X object_slot = te_search( tep, hp, OBJECT_SEARCH, (dict_h) object ) ;
- X if ( object_slot != NULL )
- X {
- X if ( objectp != NULL )
- X *objectp = *object_slot ;
- X ERRNO( dhp ) = DICT_EEXISTS ;
- X return( DICT_ERR ) ;
- X }
- X }
- X
- X /*
- X * If the entry chain is full, expand it
- X */
- X if ( ENTRY_IS_FULL( tep ) )
- X {
- X object_slot = te_expand( tep, hp ) ;
- X if ( object_slot == NULL )
- X return( DICT_ERR ) ;
- X }
- X else
- X object_slot = bc_lookup( tep->head_bucket,
- X hp->args.ht_bucket_entries, EMPTY ) ;
- X tep->n_free-- ;
- X
- X *object_slot = object ;
- X if ( objectp != NULL )
- X *objectp = *object_slot ;
- X return( DICT_OK ) ;
- X}
- X
- X
- X
- Xint ht_insert( handle, object )
- X dict_h handle ;
- X dict_obj object ;
- X{
- X header_s *hp = HHP( handle ) ;
- X
- X return( ht_do_insert( hp,
- X hp->dh.flags & DICT_UNIQUE_KEYS, object, (dict_obj *)NULL ) ) ;
- X}
- X
- X
- Xint ht_insert_uniq( handle, object, objectp )
- X dict_h handle ;
- X dict_obj object ;
- X dict_obj *objectp ;
- X{
- X header_s *hp = HHP( handle ) ;
- X dheader_s *dhp = DHP( hp ) ;
- X
- X if ( dhp->oo_comp == NULL_FUNC )
- X HANDLE_ERROR( dhp, "ht_insert_uniq", DICT_ENOOOCOMP, DICT_ERR ) ;
- X return( ht_do_insert( hp, TRUE, object, objectp ) ) ;
- X}
- X
- X
- Xint ht_delete( handle, object )
- X dict_h handle ;
- X dict_obj object ;
- X{
- X header_s *hp = HHP( handle ) ;
- X dheader_s *dhp = DHP( hp ) ;
- X tabent_s *tep ;
- X int bucket_index ;
- X bucket_s *bp ;
- X
- X if ( object == NULL )
- X HANDLE_ERROR( dhp, "ht_delete", DICT_ENULLOBJECT, DICT_ERR ) ;
- X
- X tep = HASH_OBJECT( hp, object ) ;
- X if ( ! ENTRY_HAS_CHAIN( tep ) )
- X {
- X ERRNO( dhp ) = DICT_ENOTFOUND ;
- X return( DICT_ERR ) ;
- X }
- X
- X bp = bc_search( tep->head_bucket,
- X hp->args.ht_bucket_entries, object, &bucket_index ) ;
- X if ( bp != NULL )
- X {
- X BUCKET_OBJECTS( bp )[ bucket_index ] = NULL ;
- X tep->n_free++ ;
- X return( DICT_OK ) ;
- X }
- X else
- X {
- X ERRNO( dhp ) = DICT_ENOTFOUND ;
- X return( DICT_ERR ) ;
- X }
- X}
- X
- X
- Xdict_obj ht_search( handle, key )
- X dict_h handle ;
- X dict_key key ;
- X{
- X header_s *hp = HHP( handle ) ;
- X tabent_s *tep = HASH_KEY( hp, key ) ;
- X dict_obj *objp = te_search( tep, hp, KEY_SEARCH, (dict_h) key ) ;
- X
- X return( ( objp == NULL ) ? NULL_OBJ : *objp ) ;
- X}
- X
- X
- X
- Xdict_obj ht_minimum( handle )
- X dict_h handle ;
- X{
- X header_s *hp = HHP( handle ) ;
- X unsigned bucket_entries = hp->args.ht_bucket_entries ;
- X int i ;
- X
- X for ( i = 0 ; i < hp->args.ht_table_entries ; i++ )
- X {
- X tabent_s *tep = &hp->table[i] ;
- X dict_obj *found ;
- X
- X if ( ! ENTRY_HAS_CHAIN( tep ) )
- X continue ;
- X found = bc_lookup( tep->head_bucket, bucket_entries, FULL ) ;
- X if ( found )
- X return( *found ) ;
- X }
- X return( NULL_OBJ ) ;
- X}
- X
- X
- Xdict_obj ht_maximum( handle )
- X dict_h handle ;
- X{
- X header_s *hp = HHP( handle ) ;
- X unsigned bucket_entries = hp->args.ht_bucket_entries ;
- X int i ;
- X
- X for ( i = hp->args.ht_table_entries-1 ; i >= 0 ; i-- )
- X {
- X tabent_s *tep = &hp->table[i] ;
- X dict_obj *found ;
- X
- X if ( ! ENTRY_HAS_CHAIN( tep ) )
- X continue ;
- X found = bc_reverse_lookup( tep->head_bucket,
- X bucket_entries, BUCKET_NULL ) ;
- X if ( found )
- X return( *found ) ;
- X }
- X return( NULL_OBJ ) ;
- X}
- X
- X
- Xdict_obj ht_successor( handle, object )
- X dict_h handle ;
- X dict_obj object ;
- X{
- X header_s *hp = HHP( handle ) ;
- X dheader_s *dhp = DHP( hp ) ;
- X tabent_s *table_end = &hp->table[ hp->args.ht_table_entries ] ;
- X unsigned bucket_entries = hp->args.ht_bucket_entries ;
- X tabent_s *tep ;
- X bucket_s *bp ;
- X int bucket_index ;
- X int i ;
- X char *id = "ht_successor" ;
- X
- X if ( object == NULL )
- X HANDLE_ERROR( dhp, id, DICT_ENULLOBJECT, NULL_OBJ ) ;
- X
- X tep = HASH_OBJECT( hp, object ) ;
- X if ( ! ENTRY_HAS_CHAIN( tep ) ||
- X ( bp = bc_search( tep->head_bucket,
- X bucket_entries, object, &bucket_index ) ) == NULL )
- X HANDLE_ERROR( dhp, id, DICT_EBADOBJECT, NULL_OBJ ) ;
- X
- X ERRNO( dhp ) = DICT_ENOERROR ;
- X
- X for ( i = bucket_index+1 ; i < bucket_entries ; i++ )
- X if ( BUCKET_OBJECTS( bp )[ i ] != NULL )
- X return( BUCKET_OBJECTS( bp )[ i ] ) ;
- X
- X for ( bp = bp->next ;; )
- X {
- X dict_obj *found = bc_lookup( bp, bucket_entries, FULL ) ;
- X
- X if ( found )
- X return( *found ) ;
- X tep++ ;
- X if ( tep >= table_end )
- X return( NULL_OBJ ) ;
- X bp = tep->head_bucket ;
- X }
- X}
- X
- X
- Xdict_obj ht_predecessor( handle, object )
- X dict_h handle ;
- X dict_obj object ;
- X{
- X header_s *hp = HHP( handle ) ;
- X dheader_s *dhp = DHP( hp ) ;
- X unsigned bucket_entries = hp->args.ht_bucket_entries ;
- X tabent_s *tep ;
- X bucket_s *stop ;
- X dict_obj *found ;
- X int bucket_index ;
- X int i ;
- X char *id = "ht_predecessor" ;
- X
- X if ( object == NULL )
- X HANDLE_ERROR( dhp, id, DICT_ENULLOBJECT, NULL_OBJ ) ;
- X
- X tep = HASH_OBJECT( hp, object ) ;
- X stop = bc_search( tep->head_bucket, bucket_entries, object, &bucket_index ) ;
- X if ( stop == NULL )
- X HANDLE_ERROR( dhp, id, DICT_EBADOBJECT, NULL_OBJ ) ;
- X
- X ERRNO( dhp ) = DICT_ENOERROR ;
- X
- X for ( i = bucket_index-1 ; i >= 0 ; i-- )
- X if ( BUCKET_OBJECTS( stop )[ i ] != NULL )
- X return( BUCKET_OBJECTS( stop )[ i ] ) ;
- X
- X for ( ;; )
- X {
- X found = bc_reverse_lookup( tep->head_bucket, bucket_entries, stop ) ;
- X if ( found )
- X return( *found ) ;
- X stop = NULL ;
- X tep-- ;
- X if ( tep < hp->table )
- X return( NULL_OBJ ) ;
- X }
- X}
- X
- X
- X
- X/*
- X * Sets the iterator to the beginning of the next used entry.
- X * The current table entry *is* included in the search.
- X */
- XPRIVATE void iter_next( hp )
- X header_s *hp ;
- X{
- X register int i ;
- X struct ht_iter *ip = &hp->iter ;
- X
- X for ( i = ip->current_table_entry ; i < hp->args.ht_table_entries ; i++ )
- X if ( ENTRY_HAS_CHAIN( &hp->table[i] ) )
- X {
- X ip->current_bucket = hp->table[i].head_bucket ;
- X ip->next_bucket_offset = 0 ;
- X break ;
- X }
- X ip->current_table_entry = i ;
- X}
- X
- X
- X/*
- X * We don't make any use of 'direction'
- X */
- Xvoid ht_iterate( handle, direction )
- X dict_h handle ;
- X enum dict_direction direction ;
- X{
- X header_s *hp = HHP( handle ) ;
- X
- X#ifdef lint
- X direction = direction ;
- X#endif
- X hp->iter.current_table_entry = 0 ;
- X iter_next( hp ) ;
- X}
- X
- X
- Xdict_obj ht_nextobj( handle )
- X dict_h handle ;
- X{
- X header_s *hp = HHP( handle ) ;
- X struct ht_iter *ip = &hp->iter ;
- X int i ;
- X
- X while ( ip->current_table_entry < hp->args.ht_table_entries )
- X {
- X do
- X {
- X for ( i = ip->next_bucket_offset ;
- X i < hp->args.ht_bucket_entries ; i++ )
- X {
- X dict_obj *bucket_list = BUCKET_OBJECTS( ip->current_bucket ) ;
- X
- X if ( bucket_list[i] != NULL )
- X {
- X ip->next_bucket_offset = i+1 ;
- X return( bucket_list[i] ) ;
- X }
- X }
- X ip->current_bucket = ip->current_bucket->next ;
- X }
- X while ( ip->current_bucket ) ;
- X
- X ip->current_table_entry++ ;
- X iter_next( hp ) ;
- X }
- X return( NULL_OBJ ) ;
- X}
- X
- END_OF_FILE
- if test 14487 -ne `wc -c <'libs/src/dict/ht.c'`; then
- echo shar: \"'libs/src/dict/ht.c'\" unpacked with wrong size!
- fi
- # end of 'libs/src/dict/ht.c'
- fi
- if test -f 'libs/src/sio/sio.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'libs/src/sio/sio.c'\"
- else
- echo shar: Extracting \"'libs/src/sio/sio.c'\" \(15212 characters\)
- sed "s/^X//" >'libs/src/sio/sio.c' <<'END_OF_FILE'
- X/*
- X * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis
- X * All rights reserved. The file named COPYRIGHT specifies the terms
- X * and conditions for redistribution.
- X */
- X
- Xstatic char RCSid[] = "$Id: sio.c,v 8.1 1993/03/13 01:15:55 panos Exp $" ;
- Xstatic char sio_version[] = VERSION ;
- X
- X#include <sys/types.h>
- X#include <sys/stat.h>
- X
- X#include "sio.h"
- X#include "impl.h"
- X
- X#ifdef EVENTS
- X#include "events.h"
- X#endif
- X
- X/*
- X * SIO WRITE FUNCTIONS: Swrite, Sputc
- X */
- X
- X/*
- X * Stream write call: arguments same as those of write(2)
- X */
- Xint Swrite( fd, addr, nbytes )
- X int fd ;
- X register char *addr ;
- X register int nbytes ;
- X{
- X register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
- X register __sio_od_t *odp = ODP( dp ) ;
- X register int b_transferred ;
- X register int b_avail ;
- X int total_b_transferred ;
- X int b_written ;
- X int b_in_buffer ;
- X
- X#ifdef EVENTS
- X EVENT( fd, EV_SWRITE ) ;
- X#endif
- X
- X IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ;
- X ASSERT( odp->start <= odp->nextb && odp->nextb <= odp->buf_end ) ;
- X
- X b_avail = odp->buf_end - odp->nextb ;
- X b_transferred = MIN( nbytes, b_avail ) ;
- X sio_memcopy( addr, odp->nextb, b_transferred ) ;
- X odp->nextb += b_transferred ;
- X
- X /*
- X * check if we are done
- X */
- X if ( b_transferred == nbytes )
- X return( b_transferred ) ;
- X
- X /*
- X * at this point we know that the buffer is full
- X */
- X b_in_buffer = odp->buf_end - odp->start ;
- X b_written = __sio_writef( odp, fd ) ;
- X if ( b_written != b_in_buffer )
- X return( (b_written >= nbytes) ? nbytes : b_written ) ;
- X
- X total_b_transferred = b_transferred ;
- X addr += b_transferred ;
- X nbytes -= b_transferred ;
- X
- X for ( ;; )
- X {
- X b_transferred = MIN( nbytes, odp->buffer_size ) ;
- X sio_memcopy( addr, odp->nextb, b_transferred ) ;
- X odp->nextb += b_transferred ;
- X nbytes -= b_transferred ;
- X if ( nbytes == 0 )
- X {
- X total_b_transferred += b_transferred ;
- X break ;
- X }
- X /*
- X * the buffer is full
- X */
- X b_written = __sio_writef( odp, fd ) ;
- X if ( b_written != odp->buffer_size )
- X {
- X if ( b_written != SIO_ERR )
- X {
- X total_b_transferred += b_written ;
- X odp->nextb += b_written ;
- X }
- X break ;
- X }
- X /*
- X * everything is ok
- X */
- X total_b_transferred += b_transferred ;
- X addr += b_transferred ;
- X }
- X return( total_b_transferred ) ;
- X}
- X
- X
- X/*
- X * Add a character to a file
- X */
- Xint Sputc( fd, c )
- X int fd ;
- X char c ;
- X{
- X register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
- X register __sio_od_t *odp = ODP( dp ) ;
- X
- X#ifdef EVENTS
- X EVENT( fd, EV_SPUTC ) ;
- X#endif
- X
- X IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ;
- X ASSERT( odp->start <= odp->nextb && odp->nextb <= odp->buf_end ) ;
- X
- X /*
- X * The following is a weak check since we should really be
- X * checking that nextb == buf_end (it would be an error for
- X * nextb to exceed buf_end; btw, the assertion above, when
- X * enabled makes sure this does not occur).
- X *
- X * NOTE: __sio_writef NEVER uses data beyond the end of buffer.
- X */
- X if ( odp->nextb >= odp->buf_end )
- X {
- X int b_in_buffer = odp->buf_end - odp->start ;
- X
- X /*
- X * There is nothing we can do if __sio_writef does not manage
- X * to write the whole buffer
- X */
- X if ( __sio_writef( odp, fd ) != b_in_buffer )
- X return( SIO_ERR ) ;
- X }
- X *odp->nextb++ = c ;
- X if ( __SIO_MUST_FLUSH( *odp, c ) && __sio_writef( odp, fd ) == SIO_ERR )
- X return( SIO_ERR ) ;
- X return ( c ) ;
- X}
- X
- X
- X
- X/*
- X * SIO READ FUNCTIONS
- X */
- X
- X/*
- X * Stream read call: arguments same as those of read(2)
- X */
- Xint Sread( fd, addr, nbytes )
- X int fd ;
- X char *addr ;
- X int nbytes ;
- X{
- X register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
- X register __sio_id_t *idp = IDP( dp ) ;
- X register int b_transferred ;
- X int b_read ;
- X int total_b_transferred ;
- X int b_left ;
- X
- X#ifdef EVENTS
- X EVENT( fd, EV_SREAD ) ;
- X#endif
- X
- X IO_SETUP( fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ;
- X ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
- X
- X b_left = idp->end - idp->nextb ;
- X b_transferred = MIN( b_left, nbytes ) ;
- X sio_memcopy( idp->nextb, addr, b_transferred ) ;
- X idp->nextb += b_transferred ;
- X if ( b_transferred == nbytes )
- X return( b_transferred ) ;
- X
- X nbytes -= b_transferred ;
- X total_b_transferred = b_transferred ;
- X addr += b_transferred ;
- X
- X do
- X {
- X b_read = __sio_readf( idp, fd ) ;
- X switch ( b_read )
- X {
- X case SIO_ERR:
- X if ( total_b_transferred == 0 )
- X return( SIO_ERR ) ;
- X /* FALL THROUGH */
- X
- X case 0:
- X return( total_b_transferred ) ;
- X }
- X
- X b_transferred = MIN( b_read, nbytes ) ;
- X sio_memcopy( idp->nextb, addr, b_transferred ) ;
- X addr += b_transferred ;
- X idp->nextb += b_transferred ;
- X total_b_transferred += b_transferred ;
- X nbytes -= b_transferred ;
- X }
- X while ( nbytes && b_read == idp->buffer_size ) ;
- X return( total_b_transferred ) ;
- X}
- X
- X
- X
- X/*
- X * Read a line from a file
- X * Returns a pointer to the beginning of the line or NULL
- X */
- Xchar *Srdline( fd )
- X int fd ;
- X{
- X register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
- X register __sio_id_t *idp = IDP( dp ) ;
- X register char *cp ;
- X register char *line_start ;
- X register int b_left ;
- X register int extension ;
- X
- X#ifdef EVENTS
- X EVENT( fd, EV_SRDLINE ) ;
- X#endif
- X
- X IO_SETUP( fd, dp, __SIO_INPUT_STREAM, NULL ) ;
- X ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
- X
- X#ifdef HAS_MMAP
- X if ( idp->memory_mapped && __sio_switch( idp, fd ) == FAILURE )
- X return( NULL ) ;
- X#endif
- X
- X b_left = idp->end - idp->nextb ;
- X /*
- X * Look for a '\n'. If the search fails, extend the buffer
- X * and search again (the extension is performed by copying the
- X * bytes that were searched to the auxiliary buffer and reading
- X * new input in the main buffer).
- X * If the new input still does not contain a '\n' and there is
- X * more space in the main buffer (this can happen with network
- X * connections), read more input until either the buffer is full
- X * or a '\n' is found.
- X * Finally, set cp to point to the '\n', and line_start to
- X * the beginning of the line
- X */
- X if ( b_left && ( cp = sio_memscan( idp->nextb, b_left, '\n' ) ) != NULL )
- X {
- X line_start = idp->nextb ;
- X idp->nextb = cp + 1 ;
- X }
- X else
- X {
- X extension = __sio_extend_buffer( idp, fd, b_left ) ;
- X if ( extension > 0 )
- X {
- X ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
- X
- X line_start = idp->start ;
- X cp = sio_memscan( idp->nextb, extension, '\n' ) ;
- X if ( cp != NULL )
- X idp->nextb = cp + 1 ;
- X else
- X for ( ;; )
- X {
- X idp->nextb = idp->end ;
- X extension = __sio_more( idp, fd ) ;
- X if ( extension > 0 )
- X {
- X cp = sio_memscan( idp->nextb, extension, '\n' ) ;
- X if ( cp == NULL )
- X continue ;
- X idp->nextb = cp + 1 ;
- X break ;
- X }
- X else
- X {
- X /*
- X * If there is spare room in the buffer avoid trashing
- X * the last character
- X */
- X if ( idp->end < &idp->buf[ idp->buffer_size ] )
- X cp = idp->end ;
- X else
- X cp = &idp->buf[ idp->buffer_size - 1 ] ;
- X break ;
- X }
- X }
- X }
- X else /* buffer could not be extended */
- X if ( b_left == 0 )
- X {
- X /*
- X * Set errno to 0 if EOF has been reached
- X */
- X if ( extension == 0 )
- X errno = 0 ;
- X return( NULL ) ;
- X }
- X else
- X {
- X line_start = idp->start ;
- X cp = idp->end ;
- X /*
- X * By setting idp->nextb to be equal to idp->end,
- X * subsequent calls to Srdline will return NULL because
- X * __sio_extend_buffer will be invoked and it will return 0.
- X */
- X idp->nextb = idp->end ;
- X }
- X }
- X *cp = NUL ;
- X idp->line_length = cp - line_start ;
- X return( line_start ) ;
- X}
- X
- X
- X/*
- X * Get a character from a file
- X */
- Xint Sgetc( fd )
- X int fd ;
- X{
- X register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
- X register __sio_id_t *idp = IDP( dp ) ;
- X
- X#ifdef EVENTS
- X EVENT( fd, EV_SGETC ) ;
- X#endif
- X
- X IO_SETUP( fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ;
- X ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
- X if ( idp->nextb >= idp->end )
- X {
- X register int b_read = __sio_readf( idp, fd ) ;
- X
- X if ( b_read == 0 )
- X return( SIO_EOF ) ;
- X else if ( b_read == SIO_ERR )
- X return( SIO_ERR ) ;
- X }
- X return( (int) *idp->nextb++ ) ;
- X}
- X
- X
- Xchar *Sfetch( fd, lenp )
- X int fd ;
- X long *lenp ;
- X{
- X register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
- X register __sio_id_t *idp = IDP( dp ) ;
- X register int b_read ;
- X register char *p ;
- X
- X#ifdef EVENTS
- X EVENT( fd, EV_SFETCH ) ;
- X#endif
- X
- X IO_SETUP( fd, dp, __SIO_INPUT_STREAM, NULL ) ;
- X ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
- X if ( idp->nextb >= idp->end )
- X {
- X b_read = __sio_readf( idp, fd ) ;
- X if ( b_read == SIO_ERR )
- X return( NULL ) ;
- X if ( b_read == 0 )
- X {
- X errno = 0 ;
- X return( NULL ) ;
- X }
- X }
- X *lenp = idp->end - idp->nextb ;
- X p = idp->nextb ;
- X idp->nextb = idp->end ;
- X return( p ) ;
- X}
- X
- X
- X
- X/*
- X * SIO CONTROL FUNCTIONS
- X */
- X
- X/*
- X * Undo the last Srdline or Sgetc
- X */
- Xint Sundo( fd, type )
- X int fd ;
- X int type ;
- X{
- X register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
- X register __sio_id_t *idp = IDP( dp ) ;
- X int retval = 0 ;
- X
- X#ifdef EVENTS
- X EVENT( fd, EV_SUNDO ) ;
- X#endif
- X
- X CONTROL_SETUP( dp, __SIO_INPUT_STREAM, SIO_ERR ) ;
- X
- X /*
- X * Undo works only for fd's used for input
- X */
- X if ( dp->stream_type != __SIO_INPUT_STREAM )
- X return( SIO_ERR ) ;
- X
- X /*
- X * Check if the operation makes sense; if so, do it, otherwise ignore it
- X */
- X switch ( type )
- X {
- X case SIO_UNDO_LINE:
- X if ( idp->nextb - idp->line_length > idp->start )
- X {
- X *--idp->nextb = '\n' ;
- X idp->nextb -= idp->line_length ;
- X }
- X ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
- X break ;
- X
- X case SIO_UNDO_CHAR:
- X if ( idp->nextb > idp->start )
- X idp->nextb-- ;
- X ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
- X break ;
- X
- X default:
- X retval = SIO_ERR ;
- X break ;
- X }
- X return( retval ) ;
- X}
- X
- X
- X/*
- X * Flush the buffer associated with the given file descriptor
- X * The special value, SIO_FLUSH_ALL flushes all buffers
- X *
- X * Return value:
- X * 0 : if fd is SIO_FLUSH_ALL or if the flush is successful
- X * SIO_ERR: if fd is not SIO_FLUSH_ALL and
- X * the flush is unsuccessful
- X * or the descriptor is not initialized or it is not
- X * an output descriptor
- X */
- Xint Sflush( fd )
- X int fd ;
- X{
- X register __sio_descriptor_t *dp ;
- X int b_in_buffer ;
- X
- X#ifdef EVENTS
- X EVENT( fd, EV_SFLUSH ) ;
- X#endif
- X
- X if ( fd == SIO_FLUSH_ALL )
- X {
- X for ( fd = 0, dp = __sio_descriptors ;
- X fd < N_SIO_DESCRIPTORS ;
- X dp++, fd++ )
- X if ( DESCRIPTOR_INITIALIZED( dp ) &&
- X dp->stream_type == __SIO_OUTPUT_STREAM )
- X (void) __sio_writef( ODP( dp ), fd ) ;
- X return( 0 ) ;
- X }
- X else
- X {
- X dp = &__sio_descriptors[ fd ] ;
- X
- X CONTROL_SETUP( dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ;
- X b_in_buffer = ODP( dp )->nextb - ODP( dp )->start ;
- X if ( __sio_writef( ODP( dp ), fd ) != b_in_buffer )
- X return( SIO_ERR ) ;
- X else
- X return( 0 ) ;
- X }
- X}
- X
- X
- X/*
- X * Close the file descriptor. This call is provided because
- X * a file descriptor may be closed and then reopened. There is
- X * no easy way for SIO to identify such a situation, so Sclose
- X * must be used.
- X *
- X * Sclose invokes Sdone which finalizes the buffer.
- X * There is no SIO_CLOSE_ALL value for fd because such a thing
- X * would imply that the program will exit very soon, therefore
- X * the closing of all file descriptors will be done in the kernel
- X * (and the finalization will be done by the finalization function
- X * NOTE: not true if the OS does not support a finalization function)
- X *
- X * There is no need to invoke SETUP; Sdone will do it.
- X */
- Xint Sclose( fd )
- X int fd ;
- X{
- X#ifdef EVENTS
- X EVENT( fd, EV_SCLOSE ) ;
- X#endif
- X
- X if ( __SIO_FD_INITIALIZED( fd ) )
- X if ( Sdone( fd ) == SIO_ERR )
- X return( SIO_ERR ) ;
- X return( close( fd ) ) ;
- X}
- X
- X
- X
- X/*
- X * Tie the file descriptor in_fd to the file descriptor out_fd
- X * This means that whenever a read(2) is done on in_fd, it is
- X * preceded by a write(2) on out_fd.
- X * Why this is nice to have:
- X * 1) When used in filters it maximizes concurrency
- X * 2) When the program prompts the user for something it forces
- X * the prompt string to be displayed even if it does not
- X * end with a '\n' (which would cause a flush).
- X * In this implementation, out_fd cannot be a regular file.
- X * This is done to avoid non-block-size write's.
- X * The file descriptors are initialized if that has not been done
- X * already. If any of them is initialized, it must be for the appropriate
- X * stream type (input or output).
- X *
- X * NOTE: the code handles correctly the case when in_fd == out_fd
- X */
- Xint Stie( in_fd, out_fd )
- X int in_fd, out_fd ;
- X{
- X struct stat st ;
- X register __sio_descriptor_t *dp ;
- X int was_initialized ;
- X boolean_e failed = NO ;
- X
- X#ifdef EVENTS
- X EVENT( in_fd, EV_STIE ) ;
- X#endif
- X
- X /*
- X * Check if the out_fd is open
- X */
- X if ( fstat( out_fd, &st ) == -1 )
- X return( SIO_ERR ) ;
- X
- X /*
- X * If the out_fd refers to a regular file, the request is silently ignored
- X */
- X if ( ( st.st_mode & S_IFMT ) == S_IFREG )
- X return( 0 ) ;
- X
- X dp = &__sio_descriptors[ in_fd ] ;
- X was_initialized = dp->initialized ; /* remember if it was initialized */
- X IO_SETUP( in_fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ;
- X
- X /*
- X * Perform manual initialization of out_fd to avoid leaving in_fd
- X * initialized if the initialization of out_fd fails.
- X * If out_fd is initialized, check if it is used for output.
- X * If it is not initialized, initialize it for output.
- X */
- X dp = &__sio_descriptors[ out_fd ] ;
- X if ( DESCRIPTOR_INITIALIZED( dp ) )
- X {
- X if ( dp->stream_type != __SIO_OUTPUT_STREAM )
- X {
- X failed = YES ;
- X errno = EBADF ;
- X }
- X }
- X else
- X if ( __sio_init( dp, out_fd, __SIO_OUTPUT_STREAM ) == SIO_ERR )
- X failed = YES ;
- X
- X if ( failed == NO )
- X {
- X __SIO_ID( in_fd ).tied_fd = out_fd ;
- X return( 0 ) ;
- X }
- X else
- X {
- X /*
- X * We failed. If we did any initialization, undo it
- X */
- X if ( ! was_initialized )
- X {
- X int save_errno = errno ;
- X
- X (void) Sdone( in_fd ) ;
- X errno = save_errno ;
- X }
- X return( SIO_ERR ) ;
- X }
- X}
- X
- X
- X/*
- X * Untie a file descriptor
- X */
- Xint Suntie( fd )
- X int fd ;
- X{
- X register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
- X
- X#ifdef EVENTS
- X EVENT( fd, EV_SUNTIE ) ;
- X#endif
- X
- X CONTROL_SETUP( dp, __SIO_INPUT_STREAM, SIO_ERR ) ;
- X
- X if ( IDP( dp )->tied_fd != SIO_NO_TIED_FD )
- X {
- X IDP( dp )->tied_fd = SIO_NO_TIED_FD ;
- X return( 0 ) ;
- X }
- X else
- X {
- X errno = EBADF ;
- X return( SIO_ERR ) ;
- X }
- X}
- X
- X
- X/*
- X * Changes the type of buffering on the specified descriptor.
- X * As a side-effect, it initializes the descriptor as an output stream.
- X */
- Xint Sbuftype( fd, type )
- X int fd, type ;
- X{
- X register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
- X
- X#ifdef EVENTS
- X EVENT( fd, EV_SBUFTYPE ) ;
- X#endif
- X
- X /*
- X * Check for a valid type
- X */
- X if ( type != SIO_LINEBUF && type != SIO_FULLBUF && type != SIO_NOBUF )
- X {
- X errno = EINVAL ;
- X return( SIO_ERR ) ;
- X }
- X
- X IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ;
- X ODP( dp )->buftype = type ;
- X return( 0 ) ;
- X}
- X
- X
- X#ifndef sio_memscan
- X
- XPRIVATE char *sio_memscan( from, how_many, ch )
- X char *from ;
- X int how_many ;
- X register char ch ;
- X{
- X register char *p ;
- X register char *last = from + how_many ;
- X
- X for ( p = from ; p < last ; p++ )
- X if ( *p == ch )
- X return( p ) ;
- X return( 0 ) ;
- X}
- X
- X#endif /* sio_memscan */
- X
- X
- X#ifdef NEED_MEMCOPY
- X
- Xvoid __sio_memcopy( from, to, nbytes )
- X register char *from, *to ;
- X register int nbytes ;
- X{
- X while ( nbytes-- )
- X *to++ = *from++ ;
- X}
- X
- X#endif /* NEED_MEMCOPY */
- X
- X
- END_OF_FILE
- if test 15212 -ne `wc -c <'libs/src/sio/sio.c'`; then
- echo shar: \"'libs/src/sio/sio.c'\" unpacked with wrong size!
- fi
- # end of 'libs/src/sio/sio.c'
- fi
- echo shar: End of archive 18 \(of 20\).
- cp /dev/null ark18isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 20 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
-