Newsgroups: comp.sources.unix From: panos@anchor.cs.colorado.edu (Panos Tsirigotis) Subject: v27i123: clc - C Libraries Collection, Part17/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 123 Archive-Name: clc/part17 #! /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 'libs/src/dict/bst.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: bst.c,v 3.3 93/09/28 21:06:50 panos Exp $" ; X X#include "bstimpl.h" X X X#define NODE_ALLOC( hp ) TNP( fsm_alloc( (hp)->alloc ) ) X#define NODE_FREE( hp, np ) fsm_free( (hp)->alloc, (char *)(np) ) X X X/* X * Find the minimum node of the subtree with root 'start' X */ X#define FIND_MINIMUM( hp, start, x ) \ X x = start ; \ X while ( LEFT( x ) != NIL( hp ) ) x = LEFT( x ) X X/* X * Find the maximum node of the subtree with root 'start' X */ X#define FIND_MAXIMUM( hp, start, x ) \ X x = start ; \ X while ( RIGHT( x ) != NIL( hp ) ) x = RIGHT( x ) X X X/* X * Returns a pointer to the node that contains the specified object X * or NIL( hp ) if the object is not found X */ XPRIVATE tnode_s *find_object( hp, object ) X header_s *hp ; X dict_obj object ; X{ X dheader_s *dhp = DHP( hp ) ; X register tnode_s *np = ROOT( hp ) ; X register tnode_s *null = NIL( hp ) ; X register int v ; X X while ( np != null ) X { X v = (*dhp->oo_comp)( object, OBJ( np ) ) ; X if ( v == 0 ) X if ( object == OBJ( np ) ) X break ; X else X v = -1 ; X np = ( v < 0 ) ? LEFT( np ) : RIGHT( np ) ; X } X return( np ) ; X} X X X X/* X * Create a tree (either simple or red-black) X */ Xdict_h bst_create( oo_comp, ko_comp, flags, errnop ) X dict_function oo_comp ; /* object-object comparator */ X dict_function ko_comp ; /* key-object comparator */ X int flags ; X int *errnop ; X{ X register header_s *hp ; X unsigned tnode_size ; X bool_int balanced_tree = flags & DICT_BALANCED_TREE ; X char *id = "bst_create" ; X X if ( ! __dict_args_ok( id, flags, errnop, oo_comp, ko_comp, DICT_ORDERED ) ) X return( NULL_HANDLE ) ; X X hp = THP( malloc( sizeof( header_s ) ) ) ; X if ( hp == NULL_HEADER ) X return( __dict_create_error( id, flags, errnop, DICT_ENOMEM ) ) ; X X /* X * Create an allocator X */ X tnode_size = sizeof( struct tree_node ) ; X if ( balanced_tree ) X tnode_size = sizeof( struct balanced_tree_node ) ; X X hp->alloc = fsm_create( tnode_size, 0, X ( flags & DICT_RETURN_ERROR ) ? FSM_RETURN_ERROR : FSM_NOFLAGS ) ; X if ( hp->alloc == NULL ) X { X free( (char *)hp ) ; X return( __dict_create_error( id, flags, errnop, DICT_ENOMEM ) ) ; X } X X LEFT( ANCHOR( hp ) ) = RIGHT( ANCHOR( hp ) ) = NIL( hp ) ; X OBJ( ANCHOR( hp ) ) = NULL_OBJ ; X OBJ( NIL( hp ) ) = NULL_OBJ ; X X if ( balanced_tree ) X { X COLOR( ANCHOR( hp ) ) = BLACK ; X COLOR( NIL( hp ) ) = BLACK ; X } X X /* X * Initialize dictionary header, hints X */ X __dict_init_header( DHP( hp ), oo_comp, ko_comp, flags, errnop ) ; X HINT_CLEAR( hp, last_search ) ; X HINT_CLEAR( hp, last_successor ) ; X HINT_CLEAR( hp, last_predecessor ) ; X X return( (dict_h) hp ) ; X} X X X/* X * Destroy a tree X */ Xvoid bst_destroy( handle ) X dict_h handle ; X{ X header_s *hp = THP( handle ) ; X X fsm_destroy( hp->alloc ) ; X free( (char *)hp ) ; X} X X X X/* X * Common code for tree insertions X */ XPRIVATE int tree_insert( hp, uniq, object, objectp ) X header_s *hp ; X register int uniq ; X dict_obj object ; X dict_obj *objectp ; X{ X dheader_s *dhp = DHP( hp ) ; X register tnode_s *x = ROOT( hp ) ; X register tnode_s *px = ANCHOR( hp ) ; X tnode_s *new ; X register int v ; X X if ( object == NULL_OBJ ) X HANDLE_ERROR( dhp, "tree_insert", DICT_ENULLOBJECT, DICT_ERR ) ; X X /* X * On exit from this loop, 'px' will point to a leaf node X * Furthermore, 'v' will hold the comparison value between the X * object stored at this node and the new 'object'. X * X * v must be initialized to -1 so that when we insert a node into an X * empty tree that node will be the *left* child of the anchor node X */ X v = -1 ; X while ( x != NIL( hp ) ) X { X v = (*dhp->oo_comp)( object, OBJ( x ) ) ; X X if ( v == 0 ) X if ( uniq ) X { X if ( objectp != NULL ) X *objectp = OBJ( x ) ; X ERRNO( dhp ) = DICT_EEXISTS ; X return( DICT_ERR ) ; X } X else X v = -1 ; /* i.e. LESS THAN */ X X px = x ; X x = ( v < 0 ) ? LEFT( x ) : RIGHT( x ) ; X } X X /* X * Allocate a new node and initialize all its fields X */ X new = NODE_ALLOC( hp ) ; X if ( new == NULL_NODE ) X { X ERRNO( dhp ) = DICT_ENOMEM ; X return( DICT_ERR ) ; X } X LEFT( new ) = RIGHT( new ) = NIL( hp ) ; X OBJ( new ) = object ; X PARENT( new ) = px ; X X if ( v < 0 ) X LEFT( px ) = new ; X else X RIGHT( px ) = new ; X X if ( dhp->flags & DICT_BALANCED_TREE ) X __dict_rbt_insfix( hp, new ) ; X X if ( objectp != NULL ) X *objectp = object ; X X return( DICT_OK ) ; X} X X X/* X * Insert the specified object in the tree X */ Xint bst_insert( handle, object ) X dict_h handle ; X dict_obj object ; X{ X header_s *hp = THP( handle ) ; X X return( tree_insert( hp, X hp->dh.flags & DICT_UNIQUE_KEYS, object, (dict_obj *)NULL ) ) ; X} X X X/* X * Insert the specified object in the tree only if it is unique X */ Xint bst_insert_uniq( handle, object, objectp ) X dict_h handle ; X dict_obj object ; X dict_obj *objectp ; X{ X return( tree_insert( THP( handle ), TRUE, object, objectp ) ) ; X} X X X/* X * Delete the specified object X */ Xint bst_delete( handle, object ) X dict_h handle ; X dict_obj object ; X{ X header_s *hp = THP( handle ) ; X dheader_s *dhp = DHP( hp ) ; X register tnode_s *null = NIL( hp ) ; X tnode_s *delnp ; X register tnode_s *y, *x ; X tnode_s *py ; X X if ( object == NULL_OBJ ) X HANDLE_ERROR( dhp, "bst_delete", DICT_ENULLOBJECT, DICT_ERR ) ; X X if ( HINT_MATCH( hp, last_search, object ) ) X delnp = HINT_GET( hp, last_search ) ; X else X { X delnp = find_object( hp, object ) ; X if ( delnp == null ) X { X ERRNO( dhp ) = DICT_ENOTFOUND ; X return( DICT_ERR ) ; X } X } X X HINT_CLEAR( hp, last_search ) ; X HINT_CLEAR( hp, last_successor ) ; X HINT_CLEAR( hp, last_predecessor ) ; X X /* X * y is the node actually being removed. It may be 'delnp' if X * 'delnp' has at most 1 child, otherwise it is 'delnp's successor X */ X if ( LEFT( delnp ) == null || RIGHT( delnp ) == null ) X y = delnp ; X else X { X /* X * We can use the FIND_MINIMUM macro since we are guaranteed X * there is a right child X */ X FIND_MINIMUM( hp, RIGHT( delnp ), y ) ; X OBJ( delnp ) = OBJ( y ) ; X } X X /* X * Set x to one of y's children: X * Case 1: y == delnp X * pick any child X * Case 2: y == successor( delnp ) X * y can only have a right child (if any), so pick that. X * Next, we link x to y's parent. X * X * The use of the NIL and ANCHOR nodes relieves us from checking X * boundary conditions: X * existence of x (when setting the PARENT field of x) X * y being the root of the tree X */ X x = ( LEFT( y ) != null ) ? LEFT( y ) : RIGHT( y ) ; X py = PARENT( y ) ; X PARENT( x ) = py ; X if ( y == LEFT( py ) ) X LEFT( py ) = x ; X else X RIGHT( py ) = x ; X X /* X * If this is a balanced tree and we unbalanced it, do the necessary repairs X */ X if ( ( dhp->flags & DICT_BALANCED_TREE ) && COLOR( y ) == BLACK ) X __dict_rbt_delfix( hp, x ) ; X X NODE_FREE( hp, y ) ; X X return( DICT_OK ) ; X} X X X/* X * Find an object with the specified key X */ Xdict_obj bst_search( handle, key ) X dict_h handle ; X dict_key key ; X{ X header_s *hp = THP( handle ) ; X dheader_s *dhp = DHP( hp ) ; X register tnode_s *np = ROOT( hp ) ; X register tnode_s *null = NIL( hp ) ; X register int v ; X X while ( np != null ) X { X v = (*dhp->ko_comp)( key, OBJ( np ) ) ; X if ( v == 0 ) X break ; X else X np = ( v < 0 ) ? LEFT( np ) : RIGHT( np ) ; X } X HINT_SET( hp, last_search, np ) ; /* update search hint */ X return( OBJ( np ) ) ; X} X X X/* X * Returns a pointer to the object with the smallest key value or X * NULL_OBJ if the tree is empty. X */ Xdict_obj bst_minimum( handle ) X dict_h handle ; X{ X register header_s *hp = THP( handle ) ; X register tnode_s *np ; X X if ( TREE_EMPTY( hp ) ) X return( NULL_OBJ ) ; X FIND_MINIMUM( hp, ROOT( hp ), np ) ; X HINT_SET( hp, last_successor, np ) ; X return( OBJ( np ) ) ; X} X X X/* X * Returns a pointer to the object with the greatest key value or X * NULL_OBJ if the tree is empty. X */ Xdict_obj bst_maximum( handle ) X dict_h handle ; X{ X register header_s *hp = THP( handle ) ; X register tnode_s *np ; X X if ( TREE_EMPTY( hp ) ) X return( NULL_OBJ ) ; X FIND_MAXIMUM( hp, ROOT( hp ), np ) ; X HINT_SET( hp, last_predecessor, np ) ; X return( OBJ( np ) ) ; X} X X X/* X * When there is no next node, this function returns ANCHOR( hp ) X */ XPRIVATE tnode_s *next_node( hp, x ) X register header_s *hp ; X register tnode_s *x ; X{ X register tnode_s *px ; X register tnode_s *next ; X X if ( RIGHT( x ) != NIL( hp ) ) X { X FIND_MINIMUM( hp, RIGHT( x ), next ) ; X } X else X { X px = PARENT( x ) ; X /* X * This loop will end at the root since the root is the *left* X * child of the anchor X */ X while ( x == RIGHT( px ) ) X { X x = px ; X px = PARENT( x ) ; X } X next = px ; X } X return( next ) ; X} X X X/* X * Returns a pointer to the object with the next >= key value or X * NULL_OBJ if the given object is the last one on the tree. X * It is an error to apply this function to an empty tree. X */ Xdict_obj bst_successor( handle, object ) X dict_h handle ; X dict_obj object ; X{ X register header_s *hp = THP( handle ) ; X dheader_s *dhp = DHP( hp ) ; X register tnode_s *x ; X register tnode_s *successor ; X char *id = "bst_successor" ; X X if ( object == NULL_OBJ ) X HANDLE_ERROR( dhp, id, DICT_ENULLOBJECT, NULL_OBJ ) ; X X if ( TREE_EMPTY( hp ) ) X HANDLE_ERROR( dhp, id, DICT_EBADOBJECT, NULL_OBJ ) ; X X if ( HINT_MATCH( hp, last_successor, object ) ) X x = HINT_GET( hp, last_successor ) ; X else X { X x = find_object( hp, object ) ; X if ( x == NIL( hp ) ) X HANDLE_ERROR( dhp, id, DICT_EBADOBJECT, NULL_OBJ ) ; X } X X successor = next_node( hp, x ) ; X X HINT_SET( hp, last_successor, successor ) ; X ERRNO( DHP( hp ) ) = DICT_ENOERROR ; /* in case we return NULL_OBJ */ X return( OBJ( successor ) ) ; X} X X X X/* X * When there is no next node, this function returns ANCHOR( hp ) X */ XPRIVATE tnode_s *previous_node( hp, x ) X register header_s *hp ; X register tnode_s *x ; X{ X register tnode_s *px ; X register tnode_s *previous ; X X if ( LEFT( x ) != NIL( hp ) ) X { X FIND_MAXIMUM( hp, LEFT( x ), previous ) ; X } X else X { X /* X * XXX: To avoid testing against the ANCHOR we can temporarily make the X * root of the tree the *right* child of the anchor X */ X px = PARENT( x ) ; X while ( px != ANCHOR( hp ) && x == LEFT( px ) ) X { X x = px ; X px = PARENT( x ) ; X } X previous = px ; X } X return( previous ) ; X} X X X X/* X * Returns a pointer to the object with the next <= key value or X * NULL if the given object is the first one on the tree. X * It is an error to apply this function to an empty tree. X */ Xdict_obj bst_predecessor( handle, object ) X dict_h handle ; X dict_obj object ; X{ X register header_s *hp = THP( handle ) ; X dheader_s *dhp = DHP( hp ) ; X tnode_s *predecessor ; X register tnode_s *x ; X char *id = "bst_predecessor" ; X X if ( object == NULL_OBJ ) X HANDLE_ERROR( dhp, id, DICT_ENULLOBJECT, NULL_OBJ ) ; X X if ( TREE_EMPTY( hp ) ) X HANDLE_ERROR( dhp, id, DICT_EBADOBJECT, NULL_OBJ ) ; X X if ( HINT_MATCH( hp, last_predecessor, object ) ) X x = HINT_GET( hp, last_predecessor ) ; X else X { X x = find_object( hp, object ) ; X if ( x == NIL( hp ) ) X HANDLE_ERROR( dhp, id, DICT_EBADOBJECT, NULL_OBJ ) ; X } X X predecessor = previous_node( hp, x ) ; X X HINT_SET( hp, last_predecessor, predecessor ) ; X ERRNO( DHP( hp ) ) = DICT_ENOERROR ; X return( OBJ( predecessor ) ) ; X} X X X Xvoid bst_iterate( handle, direction ) X dict_h handle ; X enum dict_direction direction ; X{ X register header_s *hp = THP( handle ) ; X struct tree_iterator *tip = &hp->iter ; X tnode_s *np ; X X tip->direction = direction ; X if ( TREE_EMPTY( hp ) ) X tip->next = NULL ; X else X { X if ( direction == DICT_FROM_START ) X { X FIND_MINIMUM( hp, ROOT( hp ), np ) ; X } X else X { X FIND_MAXIMUM( hp, ROOT( hp ), np ) ; X } X tip->next = np ; X } X} X X Xdict_obj bst_nextobj( handle ) X dict_h handle ; X{ X register header_s *hp = THP( handle ) ; X struct tree_iterator *tip = &hp->iter ; X tnode_s *current = tip->next ; X X if ( current == NULL ) X return( NULL_OBJ ) ; X X if ( tip->direction == DICT_FROM_START ) X tip->next = next_node( hp, current ) ; X else X tip->next = previous_node( hp, current ) ; X X if ( tip->next == ANCHOR( hp ) ) X tip->next = NULL ; X return( OBJ( current ) ) ; X} X X X#ifdef BST_DEBUG X X#include X X XPRIVATE void preorder( hp, np, action ) X header_s *hp ; X tnode_s *np ; X void (*action)() ; X{ X if ( np == NIL( hp ) ) X return ; X X (*action)( OBJ( np ) ) ; X preorder( hp, LEFT( np ), action ) ; X preorder( hp, RIGHT( np ), action ) ; X} X X XPRIVATE void inorder( hp, np, action ) X header_s *hp ; X tnode_s *np ; X void (*action)() ; X{ X if ( np == NIL( hp ) ) X return ; X X inorder( hp, LEFT( np ), action ) ; X (*action)( OBJ( np ) ) ; X inorder( hp, RIGHT( np ), action ) ; X} X X XPRIVATE void postorder( hp, np, action ) X header_s *hp ; X tnode_s *np ; X void (*action)() ; X{ X if ( np == NIL( hp ) ) X return ; X X postorder( hp, LEFT( np ), action ) ; X postorder( hp, RIGHT( np ), action ) ; X (*action)( OBJ( np ) ) ; X} X X Xvoid bst_traverse( handle, order, action ) X dict_h handle ; X bst_order_e order ; X void (*action)() ; X{ X header_s *hp = THP( handle ) ; X X switch ( order ) X { X case BST_INORDER: X inorder( hp, ROOT( hp ), action ) ; X break ; X X case BST_PREORDER: X preorder( hp, ROOT( hp ), action ) ; X break ; X X case BST_POSTORDER: X postorder( hp, ROOT( hp ), action ) ; X break ; X } X} X X X#ifdef MIN X#undef MIN X#endif X#define MIN( a, b ) ( a < b ? a : b ) X X#ifdef MAX X#undef MAX X#endif X#define MAX( a, b ) ( a > b ? a : b ) X Xvoid get_depth( hp, np, dp ) X header_s *hp ; X tnode_s *np ; X struct bst_depth *dp ; X{ X struct bst_depth ldep, rdep ; X X if ( np == NIL( hp ) ) X { X dp->depth_min = dp->depth_max = 0 ; X return ; X } X get_depth( hp, LEFT( np ), &ldep ) ; X get_depth( hp, RIGHT( np ), &rdep ) ; X dp->depth_min = MIN( ldep.depth_min, rdep.depth_min ) + 1 ; X dp->depth_max = MAX( ldep.depth_max, rdep.depth_max ) + 1 ; X if ( DHP( hp )->flags & DICT_BALANCED_TREE ) X { X if ( dp->depth_max > 2*dp->depth_min ) X (void) fprintf( stderr, "tree is not balanced\n" ) ; X } X} X Xvoid bst_getdepth( handle, dp ) X dict_h handle ; X struct bst_depth *dp ; X{ X header_s *hp = THP( handle ) ; X X get_depth( hp, ROOT( hp ), dp ) ; X} X X#endif /* BST_DEBUG */ X END_OF_FILE if test 14392 -ne `wc -c <'libs/src/dict/bst.c'`; then echo shar: \"'libs/src/dict/bst.c'\" unpacked with wrong size! fi # end of 'libs/src/dict/bst.c' fi if test -f 'libs/src/sio/sio.3' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'libs/src/sio/sio.3'\" else echo shar: Extracting \"'libs/src/sio/sio.3'\" \(13341 characters\) sed "s/^X//" >'libs/src/sio/sio.3' <<'END_OF_FILE' 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.\" $Id: sio.3,v 8.2 1993/11/22 19:00:24 panos Exp $ X.TH SIO 3X "29 May 1992" X.SH NAME XSread, Sgetc, Srdline, Sfetch, Swrite, Sputc, Sprint, Sprintv, Sdone, Sundo, Stie, Suntie, Sflush, Sclose, Sbuftype, Smorefds, Sgetchar, Sputchar, SIOLINELEN, SIOMAXLINELEN - fast stream I/O X.SH SYNOPSIS X.LP X.nf X.ft B X#include "sio.h" X.LP X.ft B Xint Sread( fd, buf, nbytes ) Xint fd ; Xchar *buf ; Xint nbytes ; X.LP X.ft B Xint Sgetc( fd ) Xint fd ; X.LP X.ft B Xchar *Srdline( fd ) Xint fd ; X.LP X.ft B Xchar *Sfetch( fd, length ) Xint fd ; Xlong *length ; X.LP X.ft B Xint Swrite( fd, buf, nbytes ) Xint fd ; Xchar *buf ; Xint nbytes ; X.LP X.ft B Xint Sputc( fd, c ) Xint fd ; Xchar c ; X.LP X.ft B Xint Sprint( fd, format [ , ... ] ) Xint fd ; Xchar *format ; X.LP X.ft B Xint Sprintv( fd, format, ap ) Xint fd ; Xchar *format ; Xva_list ap ; X.LP X.ft B Xint Sdone( fd ) Xint fd ; X.LP X.ft B Xint Sundo( fd, type ) Xint fd ; Xint type ; X.LP X.ft B Xint Stie( ifd, ofd ) Xint ifd, ofd ; X.LP X.ft B Xint Suntie( fd ) Xint fd ; X.LP X.ft B Xint Sbuftype( fd, type ) Xint fd, type ; X.LP X.ft B Xint Smorefds() X.LP X.ft B Xint Sflush( fd ) Xint fd ; X.LP X.ft B Xint Sclose( fd ) Xint fd ; X.LP X.ft B Xint Sgetchar( fd ) Xint fd ; X.LP X.ft B Xint Sputchar( fd, c ) Xint fd; Xchar c ; X.LP X.ft B Xint SIOLINELEN( fd ) Xint fd ; X.LP X.ft B Xint SIOMAXLINELEN( fd ) Xint fd ; X.SH DESCRIPTION XThe \fISIO\fR library provides support Xfor \fIstream\fR I/O on file descriptors. XThe first argument of every function Xor macro is a file descriptor. The file descriptor may be used either for Xinput or for output, but not both. Attempting to use a descriptor for Xboth input and output will cause the call for the latter use to fail. XWhen you are Xdone with using a file descriptor, you should inform \fISIO\fR Xby invoking \fBSdone()\fR (unless the program is about to Xcall \fIexit(3)\fR). XYou can also use \fBSdone()\fR if Xyou want to perform a different type of operation on the same Xfile descriptor (e.g. first you were reading data from the file Xdescriptor and then you want to write some data). XAnother possibility is to do stream I/O at different file offsets Xby using \fBSdone()\fR before using \fBlseek(2)\fR to move to a Xnew file offset. X.LP XI/O operations on different file descriptors do not interfere X(unless the file descriptors refer to the same file, in which case Xthe results are undefined). X.LP XFor disk files, I/O always starts at the current file offset. XIf that offset is not a multiple of the preferred block size for file Xsystem I/O, performance will not be optimal X(the preferred block size is determined from the X\fIst_blksize\fR field in \fIstruct stat\fR). XFor optimal performance, it is recommended that no I/O operations X(like \fIread(2)\fR or \fIwrite(2)\fR) Xare applied to the file descriptor if it is to be used by \fISIO\fR. X.LP XRead I/O is either buffered, or is done using memory mapping whenever Xthat is possible and appropriate. X.LP XThe library functions that do stream I/O resemble system calls X(for example \fBSread()\fR resembles \fIread(2)\fR) so that modifying Xa program that uses the system calls to use the \fISIO\fR functions Xis easy (e.g. just replace \fIread(2)\fR with \fBSread()\fR; the function Xsignatures as well as the return values are exactly the same; also make Xsure to replace calls to \fIclose(2)\fP with \fBSclose()\fP). X.LP X\fISIO\fR uses the underlying system calls \fIread(2)\fR and \fIwrite(2)\fR Xto do I/O (except when reading files using memory mapping). XThese calls may be interrupted (i.e. they may return -1 with X.I errno Xset to EINTR). Such interruptions are ignored by \fISIO\fR which Xsimply reissues the system call X(this means that a \fISIO\fP call will never fail because the Xunderlying I/O system call was interrupted). X.LP X.B Sread() Xreads \fInbytes\fR bytes from the stream associated with file Xdescriptor \fIfd\fR into the buffer pointed to by \fIbuf\fR. X.LP X.B Sgetc() Xreads a character from the stream Xassociated with file descriptor \fIfd\fR. XIt returns \fBSIO_EOF\fR if the end of file has been reached. X.LP X.B Sgetchar() X(a macro) performs exactly the same function as \fBSgetc()\fR but Xit is much faster. X.LP X.B Srdline() Xreads a line from the stream Xassociated with file descriptor \fIfd\fR. XThe newline at the end of the line is replaced by a NUL byte. Lines Xlonger than the maximum line length supported by \fISIO\fR will Xhave characters deleted. X.LP X.B SIOLINELEN() X(a macro) returns the length of Xthe line returned by the last call to \fBSrdline()\fR X(the value returned by \fBSIOLINELEN()\fR is valid only after X\fBSrdline()\fR and as long as no other X\fISIO\fR calls are performed on that file descriptor). X.LP X.B SIOMAXLINELEN() X(a macro) returns Xthe maximul line length supported by \fISIO\fR for the file Xdescriptor. As a side-effect it initializes \fIfd\fR for input. X.LP X.B Sfetch() Xreturns a pointer to data coming from the stream Xassociated with file Xdescriptor \fIfd\fR. The amount of data available is indicated Xby the \fIlength\fR argument. One possible use for this function Xis to copy files. X.LP X.B Swrite() Xwrites \fInbytes\fR bytes to the stream associated with file Xdescriptor \fIfd\fR from the buffer pointed to by \fIbuf\fR. X.LP X.B Sputc() Xwrites a single character to the stream Xassociated with file descriptor \fIfd\fR. X.LP X.B Sputchar() X(a macro) performs exactly the same function as \fBSputc()\fR Xbut it is much faster. X.LP X.B Sprint() Ximitates the behavior of printf(3) as defined in the XANSI C Standard. There are some limitations. Check the \fBSprint()\fR Xman page for more information. X.LP X.B Sprintv() Xis the same as \fBSprint()\fR except that it uses a X\fIvarargs\fR argument list. X.LP X.B Sundo() Xreturns the characters returned by the last call to X\fBSrdline()\fR, \fBSgetc()\fR or \fBSgetchar()\fR to the stream Xso that they can be reread. The \fItype\fR argument to \fBSundo()\fR Xcan be \fBSIO_UNDO_LINE\fR or \fBSIO_UNDO_CHAR\fR depending Xon whether the call whose effect needs to be undone was X\fBSrdline()\fR or \fBSgetc()\fR/\fBSgetchar()\fR respectively. XThere is no check on Xwhether the last function invoked on \fIfd\fR was one of the above Xand the results are undefined if there is no correspondence Xbetween the \fItype\fR and the last operation on \fIfd\fR. X(i.e. the result is undefined if you try \fBSIO_UNDO_CHAR\fR Xand the last operation was not \fBSgetchar()\fR or \fBSgetc()\fR). X.LP X.B Stie() Xties the file descriptor \fIifd\fR to the file descriptor \fIofd\fR. XThis means that whenever a \fIread(2)\fR is done on \fIifd\fR, it is Xpreceded by a \fIwrite(2)\fR on \fIofd\fR. XFor filters it is useful to do \fIStie( 0, 1 )\fR to maximize concurrency. XIt is also useful to do the same thing when you issue prompts to the Xuser and you want the user reply to appear on the same line with the Xprompt. X\fIifd\fR, \fIofd\fR will be initialized for input, output respectively X(if any of them is initialized, it must be for the appropriate Xstream type (input or output)). XIf \fIifd\fR was tied to another file descriptor, the old tie is broken. X.LP X.B Suntie() Xundoes the effect of \fBStie()\fR for the specified input file descriptor. X.LP X.B Sbuftype() Xdetermines the buffering type for the output stream associated with Xfile descriptor \fIfd\fR. XBy default output directed to terminals is line buffered, output Xdirected to file descriptor 2 (standard error) is unbuffered and Xeverything else is fully buffered. XPossible values for the \fItype\fR argument are X.RS X.TP 15 X.SB SIO_FULLBUF Xfor full buffering X.TP X.SB SIO_LINEBUF Xfor line buffering X.TP X.SB SIO_NOBUF Xfor no buffering X.RE X.LP X.B Smorefds() Xshould be used to inform \fBSIO\fR that the number of available file Xdescriptors has been increased. \fBSIO\fR uses an array of internal Xstream descriptors which are indexed by the file descriptor number. Some Xoperating systems (ex. SunOS 4.1[.x]) allow the number of available Xfile descriptors to vary. If that number is increased beyond its initial Xvalue \fBSIO\fR needs to know in order to allocate more stream descriptors. X.LP X.B Sdone() Xflushes any buffered output for \fIfd\fR Xand releases the \fISIO\fR resources used. \fBSdone()\fR Xis useful in case the program needs to reprocess the Xdata of a file descriptor (assuming the file descriptor corresponds Xto a file). The program can call \fBSdone()\fR, X\fIlseek(2)\fR to the beginning of the file Xand then proceed to reread the file. X.LP X.B Sflush() Xcauses any buffered stream output to be written to the Xfile descriptor. If its argument is the special value \fBSIO_FLUSH_ALL\fR Xthen all output streams will be flushed. X.LP X.B Sclose() Xcloses a file descriptor used for stream I/O, flushes Xany buffered output and releases the \fISIO\fR resources used. X.SH EXAMPLES X.LP XThe following code implements a (poor) substitute for the tee command X(it copies standard input to a file as well as to standard output). X.ne 10 X.RS X.nf X.ft B X#include "sio.h" X.sp .5 Xmain( argc, argv ) X int argc ; X char *argv[] ; X{ X char *file = (argc > 1) ? argv[ 1 ] : "tee.file" ; X int fd = creat( file, 0644 ) ; X long length ; X char *s ; X.sp .5 X while ( s = Sfetch( 0, &length ) ) X { X Swrite( 1, s, length ) ; X Swrite( fd, s, length ) ; X } X exit( 0 ) ; X} X.fi X.ft R X.RE X.SH RETURN VALUES X.LP X.B Sread() Xreturns the number of bytes read on success X(0 means end-of-file) Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B Sgetc() Xreturns the character read on success, XSIO_EOF when the end-of-file is reached, Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B Srdline() Xreturns a pointer to the next line on success. XOn failure or when the end-of-file is reached it returns X.SM NULL. XIf the end-of-file is reached \fIerrno\fR is set to 0, otherwise it indicates Xthe error. X.LP X.B Sfetch() Xreturns a pointer to file data on success. X(the \fIlength\fR argument indicates how many bytes Xare available). XOn failure or when the end-of-file is reached it returns X.SM NULL. XIf the end-of-file is reached \fIerrno\fR is set to 0, otherwise it indicates Xthe error. X.LP X.B Swrite() Xreturns the number of bytes written on success Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B Sputc() Xreturns the character it was given as an argument on success X.B Sprint() Xreturns the number of characters printed on success Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B Sdone() Xreturns \fB0\fR on success Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B Sundo() Xreturns \fB0\fR on success Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B Stie() Xreturns \fB0\fR on success Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B Suntie() Xreturns \fB0\fR on success Xor \fBSIO_ERR\fR on failure X(\fIerrno\fR is set to \fBEBADF\fR if there Xwas no tied file descriptor). X.LP X.B Sbuftype() Xreturns \fB0\fR on success Xor \fBSIO_ERR\fR on failure X(\fIerrno\fR is set to \fBEBADF\fR if this is not an output stream Xor to \fBEINVAL\fR if an unknown \fItype\fR is specified). X.LP X.B Smorefds() Xreturns \fB0\fR on success Xor \fBSIO_ERR\fR on failure (because of lack of memory). X.LP X.B Sflush() Xreturns \fB0\fR on success Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B Sclose() Xreturns \fB0\fR on success Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B Sgetchar() Xreturns the character read on success, XSIO_EOF when the end-of-file is reached, Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B Sputchar() Xreturns the character it was given as an argument on success Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP X.B SIOLINELEN() Xreturns the length of the last line read by \fBSrdline()\fR. X.LP X.B SIOMAXLINELEN() Xreturns the length of the longest line supported by \fISIO\fR on success Xor \fBSIO_ERR\fR on failure (\fIerrno\fR is set to indicate the error). X.LP XAttempting a read operation on a descriptor opened for writing or vice Xversa will cause the operation to fail with \fIerrno\fR set to \fBEBADF\fR. X.LP XThe first \fISIO\fR operation on a descriptor must be a read or write Xoperation. It cannot be a control operation (like \fBSflush()\fR). Such Xan operation will fail with \fIerrno\fR set to \fBEBADF\fR. X.LP X.IP "\fBNOTE 1:\fR" 15 X\fBStie()\fR is an input/output operation for the Xrespective file descriptors, not a control operation. \fBSuntie()\fR Xis a control operation. X.IP "\fBNOTE 2:\fR" X\fBSIO_ERR\fR is defined to be \fB-1\fR. X.SH "SEE ALSO" X.LP XSprint(3) X.SH BUGS X.LP XIf the operating system does not provide for invocation of a Xfinalization function upon exit, the program will have to Xexplicitly flush all output streams. XThe following operating systems provide such a facility: XSunOS 4.x, Ultrix 4.x, SunOS 5.x X.LP XSocket file descriptors can be used for input as well as output but X\fBSIO\fR does not support this. X.LP XThe current implementation will not try to use memory mapping to Xread a file if the file offset is not 0 (it will use buffered I/O instead). X.LP XPointers returned by \fBSfetch()\fR point to read-only memory. XAttempting to modify this memory will result in a segmentation Xviolation. END_OF_FILE if test 13341 -ne `wc -c <'libs/src/sio/sio.3'`; then echo shar: \"'libs/src/sio/sio.3'\" unpacked with wrong size! fi # end of 'libs/src/sio/sio.3' fi echo shar: End of archive 17 \(of 20\). cp /dev/null ark17isdone 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