Newsgroups: comp.sources.unix
From: panos@anchor.cs.colorado.edu (Panos Tsirigotis)
Subject: v27i117: clc - C Libraries Collection, Part11/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 117
Archive-Name: clc/part11

#! /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 11 (of 20)."
# Contents:  libs/src/pq/hpq.c libs/src/pset/pset.3
#   libs/src/sio/Sprint.3 libs/src/sio/impl.h libs/src/timer/timer.c
# Wrapped by panos@eclipse on Sun Nov 28 14:48:16 1993
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'libs/src/pq/hpq.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libs/src/pq/hpq.c'\"
else
echo shar: Extracting \"'libs/src/pq/hpq.c'\" \(5510 characters\)
sed "s/^X//" >'libs/src/pq/hpq.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: hpq.c,v 1.3 1993/04/01 02:15:46 panos Exp $" ;
Xstatic char version[] = VERSION ;
X
X#include "pq.h"
X#include "hpqimpl.h"
X
X#define PRIVATE			static
X
X#ifndef NULL
X#define NULL 0
X#endif
X
X#define PARENT( i )		( i >> 1 )
X#define LEFT( i )			( i << 1 )
X#define RIGHT( i )		( LEFT( i ) + 1 )
X
Xint pq_errno ;
X
X#define INITIAL_ARRAY_SIZE				100				/* entries */
X
X
Xpq_h __hpq_create( func, flags, errnop )
X	int (*func)() ;
X	int flags ;
X	int *errnop ;
X{
X	register header_s *hp ;
X	int *errp = ( errnop == NULL ) ? &pq_errno : errnop ;
X	char *malloc() ;
X
X	/*
X	 * Check if the user has provided the necessary comparison functions
X	 */
X	if ( func == NULL )
X		HANDLE_ERROR( flags, NULL, errp, PQ_ENOFUNC,
X				"HPQ __hpq_create: missing object-object comparator\n" ) ;
X
X	hp = HHP( malloc( sizeof( header_s ) ) ) ;
X	if ( hp == NULL )
X		HANDLE_ERROR( flags, NULL, errp, PQ_ENOMEM,
X												"HPQ __hpq_create: malloc failed\n" ) ;
X	
X	/*
X	 * Allocate object array
X	 */
X	hp->objects = (pq_obj *) malloc( INITIAL_ARRAY_SIZE * sizeof( pq_obj ) ) ;
X	if ( hp->objects == NULL )
X	{
X		free( (char *)hp ) ;
X		HANDLE_ERROR( flags, NULL, errp, PQ_ENOMEM, 
X												"HPQ __hpq_create: malloc failed\n" ) ;
X	}
X
X	/*
X	 * Initialize the header
X	 */
X	hp->is_better = func ;
X	hp->errnop = errp ;
X	hp->flags = flags ;
X	hp->max_size = INITIAL_ARRAY_SIZE ;
X	hp->cur_size = 0 ;
X	return( (pq_h) hp ) ;
X}
X
X
Xvoid __hpq_destroy( handle )
X	pq_h handle ;
X{
X	header_s *hp = HHP( handle ) ;
X
X	free( (char *) hp->objects ) ;
X	free( (char *)hp ) ;
X}
X
X
Xint __hpq_insert( handle, object )
X	pq_h handle ;
X	pq_obj object ;
X{
X	register header_s *hp = HHP( handle ) ;
X	register unsigned i, parent ;
X
X	if ( object == NULL )
X		HANDLE_ERROR( hp->flags, PQ_ERR, hp->errnop, PQ_ENULLOBJECT,
X											"HPQ __hpq_insert: NULL object\n" ) ;
X
X	/*
X	 * Make sure there is room to store the object
X	 */
X	if ( hp->cur_size >= hp->max_size && grow( hp ) == PQ_ERR )
X		return( PQ_ERR ) ;
X
X	i = hp->cur_size++ ;
X	parent = PARENT( i ) ;
X	while ( i > 0 && (*hp->is_better)( object, hp->objects[ parent ] ) )
X	{
X		hp->objects[ i ] = hp->objects[ parent ] ;
X		i = parent ;
X		parent = PARENT( i ) ;
X	}
X	hp->objects[ i ] = object ;
X	return( PQ_OK ) ;
X}
X
X
X#define CUTOFF								(INITIAL_ARRAY_SIZE * 128)
X#define INCREMENT							CUTOFF
X
X/*
X * Grow the table.
X * Algorithm:
X *			while the table_size is less than CUTOFF, double the size.
X * 		if it grows greater than CUTOFF, increase the size by INCREMENT
X *			(these number are in entries, not bytes)
X */
XPRIVATE int grow( hp )
X	header_s *hp ;
X{
X	unsigned new_size ;
X	char *new_objects ;
X	char *realloc() ;
X
X	if ( hp->max_size < CUTOFF )
X		new_size = hp->max_size * 2 ;
X	else
X		new_size = hp->max_size + INCREMENT ;
X
X	new_objects = realloc( (char *)hp->objects, new_size * sizeof( pq_obj ) ) ;
X	if ( new_objects == NULL )
X		HANDLE_ERROR( hp->flags, PQ_ERR, hp->errnop, PQ_ENOMEM,
X										"HPQ grow: out of memory\n" ) ;
X	
X	hp->max_size = new_size ;
X	hp->objects = (pq_obj *) new_objects ;
X	return( PQ_OK ) ;
X}
X
X
Xpq_obj __hpq_extract_head( handle )
X	pq_h handle ;
X{
X	register header_s *hp = HHP( handle ) ;
X	pq_obj object ;
X	void restore_heap() ;
X
X	if ( hp->cur_size == 0 )
X		return( NULL ) ;
X	
X	object = hp->objects[ 0 ] ;
X	hp->objects[ 0 ] = hp->objects[ --hp->cur_size ] ;
X	restore_heap( hp, 0 ) ;
X	return( object ) ;
X}
X
X
X#define EXISTS( hp, i )				( i < hp->cur_size )
X#define IS_BETTER( hp, i, j )		\
X			( (*hp->is_better)( hp->objects[ i ], hp->objects[ j ] ) )
X#define SWAP( hp, i, j )								\
X		{														\
X			pq_obj t = hp->objects[ i ] ;				\
X			hp->objects[ i ] = hp->objects[ j ] ;	\
X			hp->objects[ j ] = t ;						\
X		}
X
XPRIVATE void restore_heap( hp, start )
X	register header_s *hp ;
X	unsigned start ;
X{
X	register unsigned current = start ;
X	register unsigned better = current ;
X
X	for ( ;; )
X	{
X		register unsigned left = LEFT( current ) ;
X		register unsigned right = RIGHT( current ) ;
X
X		/*
X		 * Meaning of variables:
X		 *
X		 *		current:		the current tree node
X		 *		left:			its left child
X		 *		right:		its right child
X		 *		better: 		the best of current,left,right
X		 *
X		 * We start the loop with better == current
X		 *
X		 * The code takes advantage of the fact that the existence of
X		 * the right child implies the existence of the left child.
X		 * It works by finding the better of the two children (and puts
X		 * that in better) and comparing that against current.
X		 */
X		if ( EXISTS( hp, right ) )
X			better = IS_BETTER( hp, left, right ) ? left : right ;
X		else if ( EXISTS( hp, left ) )
X			better = left ;
X
X		if ( better == current || IS_BETTER( hp, current, better ) )
X			break ;
X		else 
X		{
X			SWAP( hp, current, better ) ;
X			current = better ;
X		}
X	}
X}
X
X
Xint __hpq_delete( handle, object )
X	pq_h handle ;
X	register pq_obj object ;
X{
X	register header_s *hp = HHP( handle ) ;
X	register unsigned i ;
X
X	if ( object == NULL )
X		HANDLE_ERROR( hp->flags, PQ_ERR, hp->errnop, PQ_ENULLOBJECT,
X											"HPQ __hpq_delete: NULL object\n" ) ;
X
X	/*
X	 * First find it
X	 */
X	for ( i = 0 ;; i++ )
X	{
X		if ( i < hp->cur_size )
X			if ( object == hp->objects[ i ] )
X				break ;
X			else
X				continue ;
X		else
X			HANDLE_ERROR( hp->flags, PQ_ERR, hp->errnop, PQ_ENOTFOUND,
X					"HPQ __hpq_delete: object not found\n" ) ;
X	}
X
X	hp->objects[ i ] = hp->objects[ --hp->cur_size ] ;
X	restore_heap( hp, i ) ;
X	return( PQ_OK ) ;
X}
X
END_OF_FILE
if test 5510 -ne `wc -c <'libs/src/pq/hpq.c'`; then
    echo shar: \"'libs/src/pq/hpq.c'\" unpacked with wrong size!
fi
# end of 'libs/src/pq/hpq.c'
fi
if test -f 'libs/src/pset/pset.3' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libs/src/pset/pset.3'\"
else
echo shar: Extracting \"'libs/src/pset/pset.3'\" \(5592 characters\)
sed "s/^X//" >'libs/src/pset/pset.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: pset.3,v 3.5 93/11/23 19:46:44 panos Exp $
X.TH PSET 3X "23 April 1993"
X.SH NAME
Xpset_create, pset_destroy, pset_add, pset_insert, pset_remove, pset_delete, pset_remove_index, pset_clear, pset_count, pset_pointer, pset_compact, pset_sort, pset_apply - routines that handle pointer sets
X.SH SYNOPSIS
X.LP
X.nf
X.ft B
X#include "pset.h"
X.LP
X.ft B
Xpset_h pset_create( alloc_start, alloc_step )
Xunsigned alloc_start, alloc_step ;
X.LP
X.ft B
Xvoid pset_destroy( pset )
Xpset_h pset ;
X.LP
X.ft B
XANY_TYPE *pset_add( pset, ptr )
Xpset_h pset ;
XANY_TYPE *ptr ;
X.LP
X.ft B
Xvoid *pset_insert( pset, ptr )
Xpset_h pset ;
Xvoid *ptr ;
X.LP
X.ft B
Xvoid pset_remove( pset, ptr )
Xpset_h pset ;
XANY_TYPE *ptr ;
X.LP
X.ft B
Xvoid pset_delete( pset, ptr )
Xpset_h pset ;
Xvoid *ptr ;
X.LP
X.ft B
Xvoid pset_remove_index( pset, index )
Xpset_h pset ;
Xunsigned index ;
X.LP
X.ft B
Xvoid pset_clear( pset )
Xpset_h pset ;
X.LP
X.ft B
Xunsigned pset_count( pset )
Xpset_h pset ;
X.LP
X.ft B
Xvoid *pset_pointer( pset, index )
Xpset_h pset ;
Xunsigned index ;
X.LP
X.ft B
Xvoid pset_compact( pset )
Xpset_h pset ;
X.LP
X.ft B
Xvoid pset_sort( pset, compfunc )
Xpset_h pset ;
Xint (*compfunc)() ;
X.LP
X.ft B
Xvoid pset_apply( pset, func, arg )
Xpset_h pset ;
Xvoid (*func)() ;
Xvoid *arg ;
X.SH DESCRIPTION
XThis library provides functions that handle sets of pointers. Pointers
Xcan be inserted and deleted from sets and the sets can be enumerated.
XPointers are inserted in sets in no particular order. However it is 
Xguaranteed
Xthat a sequence of insertions will result in a set which if enumerated
Xwill provide the pointers in the same order in which they were inserted
X(assuming no intervening deletions).
X.LP
X.B pset_create()
Xcreates a pointer set.
XIt will allocate space for
X.I alloc_start
Xpointers before returning.
X.I alloc_step
Xdetermines the amount by which the set size is increased in case of
Xoverflow. If any of these parameters is 0, a default value is used.
X.LP
X.B pset_destroy()
Xdestroys the specified pointer set.
X.LP
X.B pset_add()
Xis a macro that adds a pointer to the specified set.
XThe pointer can be of any type.
X.LP
X.B pset_insert()
Xinserts a pointer to the specified set.
XThis is the same operation as
X.B pset_add().
X.LP
X.B pset_remove()
Xremoves a pointer from the specified set.
X.LP
X.B pset_delete()
Xdeletes a pointer from the specified set.
XThis is the same operation as
X.B pset_remove().
X.LP
X.B pset_remove_index()
Xremoves the pointer that is at position
X.I index
Xin the set.
X.I index
Xshould be in the range [0, \fBpset_count(pset)\fP) (but there is no
Xcheck to enforce this).
XAfter this operation, the
X.I index
Xposition will be occupied by another pointer (unless it was the last one).
XNote that this call is a macro, and it may evaluate the
X.I index
Xargument more than once.
X.LP
X.B pset_clear()
Xremoves all pointers from the specified set.
X.LP
X.B pset_count()
Xreturns the number of pointers in the specified set.
X.LP
X.B pset_pointer()
Xreturns the pointer at position
X.I index
Xin the specified set.
X.I index
Xmust be between 0 and
X.B "pset_count(pset)."
X.B pset_pointer()
Xis a macro and it can also be used in the left-hand side of assignments.
X.LP
X.B pset_compact()
Xremoves all NULL pointers from
X.I pset.
X.LP
X.B pset_sort()
Xsorts the pointers in
X.I pset
Xusing the specified function.
X.I compfunc
Xis invoked with 2 arguments that are pointers pointing to pointers stored in 
X.I pset.
XFor example, if the pset holds pointers to objects of type T, then
Xthe function F whose address is in
X.I compfunc
Xshould be defined as:
XF( T **p1, T **p2 ).
X.br
X.I compfunc 
Xshould return a negative, zero or positive value 
Xif its first argument is less than, equal to, or greater than its
Xsecond argument.
X.LP
X.B pset_apply()
Xapplies
X.I func
Xto all pointers in
X.I pset.
XIf 
X.I arg
Xis not
X.SM NULL
Xthe function is invoked as:
X.RS
X(*func)( arg, p )
X.RE
Xwhere
X.I p
Xis a pset pointer.  If 
X.I arg
Xis
X.SM NULL
Xthe function is invoked as:
X.RS
X(*func)( p )
X.RE
X.SH EXAMPLE
XThe following code fragment reads lines from standard input
Xand places them in a pset. Then it sorts the pset, prints the
Xsorted contents to standard output and then it eliminates duplicate
Xlines (which it also prints to standard output).
X.RS
X.sp 1
X.ft B
X.nf
Xpset_h ph ;
Xchar buf[ 80 ] ;
Xunsigned u ;
Xint compstr() ;
Xvoid printstr() ;
X.sp 1
Xph = pset_create( 0, 0 ) ;
Xwhile ( gets( buf ) )
X.RS
Xpset_add( strcpy( malloc( strlen( buf ) + 1 ), buf ) ) ;
X.RE
Xpset_sort( ph, compstr ) ;
Xfor ( u = 0 ; u < pset_count( ph ) ; u++ )
X.RS
Xprintf( "%s\\n", (char *) pset_pointer( ph, u ) ) ;
X.RE
X.RE
X.fi
X.ft R
X.LP
XThe function
X.I compstr()
Xfollows:
X.sp 1
X.RS
X.ft B
X.nf
Xint compstr( p1, p2 )
X.RS
Xchar **p1, **p2 ;
X.RE
X{
X.RS
Xreturn( strcmp( *p1, *p2 ) ) ;
X.RE
X}
X.RE
X.SH "RETURN VALUES"
X.LP
X.I pset_h
Xis a pointer type. Functions that return
X.I pset_h
Xwill return
X.SM NULL
Xto indicate an error.
X.LP
X.B pset_create()
Xreturns a pointer set handle or
X.SM NULL
Xif it fails.
X.LP
X.B pset_add()
Xreturns its second argument if successful or
X.SM NULL
Xif it fails.
X.LP
X.B pset_insert()
Xreturns its second argument if successful or
X.SM NULL
Xif it fails.
X.LP
X.B pset_count()
Xalways returns the number of pointers in the set.
X.LP
X.B pset_pointer()
Xalways returns a pointer. There is no check if the specified index is within
Xrange.
X.SH BUGS
X.LP
X.B pset_add(),
X.B pset_remove(),
X.B pset_remove_index(),
X.B pset_count(),
X.B pset_clear(),
X.B pset_pointer()
Xand 
X.B pset_sort()
Xare macros, therefore the \fI&\fR operator cannot be applied to them.
END_OF_FILE
if test 5592 -ne `wc -c <'libs/src/pset/pset.3'`; then
    echo shar: \"'libs/src/pset/pset.3'\" unpacked with wrong size!
fi
# end of 'libs/src/pset/pset.3'
fi
if test -f 'libs/src/sio/Sprint.3' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libs/src/sio/Sprint.3'\"
else
echo shar: Extracting \"'libs/src/sio/Sprint.3'\" \(5277 characters\)
sed "s/^X//" >'libs/src/sio/Sprint.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: Sprint.3,v 8.1 1993/03/13 01:15:34 panos Exp $
X.TH Sprint 3X "29 May 1992"
X.SH NAME
XSprint -- formatted stream output
X.SH SYNOPSIS
X.LP
X.nf
X.ft B
Xint Sprint( fd, format [ , ... ] )
Xint fd ;
Xchar *format ;
X.SH DESCRIPTION
X\fBSprint()\fR provides formatted output conversion. The formatting is
Xcontrolled by the \fIformat\fR argument. All characters in
X\fIformat\fR that do not specify a conversion are printed. A conversion
Xis specified by a '%' followed by a string that ends with a
Xconversion type character. The string may contain flags, a field width,
Xa precision, and a modifier.
X.LP
XPossible flags (more that one can be specified and they can be in any order)
Xinclude:
X.TP 10
X.B \'-'
Xspecifies left adjustment of the converted argument. The default
Xis right adjustment. This flag is meaningful only if a field width
Xis specified.
X.TP
X.B \'+'
Xspecifies that a number will always have a sign as a prefix (this
Xforces a '+' sign to appear if the number is positive).
X.TP
X.B \' '
Xprefixes a \fIspace\fR to the number if the number has not a sign
X(therefore the '+' flag overrides this flag).
X.TP
X.B \'#'
XThe meaning of '#' depends on the conversion type character: for \fBo\fR 
Xconversions the first digit will be 0; for \fBx\fR or \fBX\fR conversions
X\fB0x\fR or \fB0X\fR respectively will be prefixed to the number (if it
Xis not zero); for \fBe\fR, \fBE\fR, \fBf\fR, \fBg\fR, and \fBG\fR conversions
Xthe number will always have a decimal point.
X.TP
X.B \'0'
Xspecifies padding with zeros instead of spaces.
X.LP
XThe field width is specified by a number. This number indicates the
X\fIminimum\fR width for the field. A '*' may be used instead of the number.
XIn that case the width is the value of the next argument which should
Xbe an \fBint\fR. 
XA negative width value specifies left adjustment with a width equal
Xto the absolute width value.
X.LP
XA precision is specified by a '.' followed by a number. The meaning of
Xthe precision depends on the type conversion character. For a string
Xconversion, precision determines how many characters are printed from
Xthe string. For integer conversions, precision determines the 
Xnumber of digits used to print the number (zero padding is done if
Xthe precision exceeds the length of the number). For floating point
Xconversions, precision determines the number of digits after the
Xdecimal point (\fBe\fR, \fBE\fR, \fBf\fR) or the number of
Xsignificant digits (\fBg\fR, \fBG\fR).
XA '*' may be used instead of a number to specify the precision. In that
Xcase the precision is the value of the next argument which should
Xbe an \fBint\fR.
XThe behavior of \fBSprint()\fR is undefined if the precision is negative.
X.LP
XThe length modifier is \fBl\fR and indicates that the argument is
Xa \fBlong\fR integer.
X.LP
XThe type conversion characters are:
X\fBd, i, o, x, X, u, c, s, f, e, E, g, G, p, n, %\fR.
XFor floating point conversions the argument should be of type \fIdouble\fR.
X.TP 10
X.B d,i
Xspecify signed decimal conversion.
X.TP
X.B u
Xspecifies unsigned decimal conversion.
X.TP
X.B o
Xspecifies octal conversion.
X.TP
X.B x,X
Xspecify hexadecimal conversion. For 
X.B x
Xthe hex digits used are 0123456789abcdef. For
X.B X
Xthe hex digits used are 0123456789ABCDEF.
XThere is no leading
X.B 0x
Xor
X.B 0X
X(use the '#' flag for that).
X.TP
X.B c
Xspecifies character conversion; the argument should be of type
X\fIchar\fR.
X.TP
X.B s
Xspecifies string conversion; the argument should be of type
X\fIchar *\fR.
X.TP
X.B f
Xspecifies conversion to the form [-]ddd.dddd. The number
Xof digits after the decimal point depends on precision; the default is 6.
XIf the precision is 0, the decimal point is not printed (this can
Xbe overriden with the '#' flag).
X.B e,E
Xspecify conversion to the form [-]ddd.dddd[eE][+-]ddd.
XThe number of digits after the decimal point depends on precision;
Xthe default is 6. If the precision is 0, the decimal point is not printed
X(this can be overriden with the '#' flag).
XThe exponent is at least 2 digit wide.
X.TP
X.B g,G
Xspecify a conversion using the
X.B e,E
Xformat respectively if the
Xexponent is less than -4 or greater than or equal to the precision;
Xotherwise the 
X.B f
Xformat is used.
X.TP
X.B p
Xis used to print pointers (type \fIvoid *\fR,
Xor \fIchar *\fR if the compiler does not support the former).
X.TP
X.B n
Xexpects a \fIint *\fR argument and puts in that integer 
Xthe number of characters already printed by this call.
X.TP
X.B %
Xis used to print a \fI%\fR.
X.LP
XIf an unknown conversion character is specified, the percent sign
Xfollowed by that character will be printed.
X.SH RETURN VALUE
X.LP
XIf no error occured, \fBSprint()\fR returns the number of characters
Xprinted. In case of error, it returns \fBSIO_ERR\fR.
X.SH BUGS
X.LP
XThis is a list of differences between \fBSprint()\fR and the ANSI C Standard
X\fBprintf()\fR:
X.LP
X\fBSprint()\fR does not support non-removal of trailing zeroes for
X\fBg\fR and \fBG\fR conversions when the '#' flag is used.
X.LP
X\fBSprint()\fR does not support the h and L modifiers.
X.LP
XThe current implementation assumes that \fIsizeof(int)==sizeof(long)\fR.
X.LP
X\fBSprint()\fR supports "%p" only if \fIsizeof(pointer)<=sizeof(int)\fR.
END_OF_FILE
if test 5277 -ne `wc -c <'libs/src/sio/Sprint.3'`; then
    echo shar: \"'libs/src/sio/Sprint.3'\" unpacked with wrong size!
fi
# end of 'libs/src/sio/Sprint.3'
fi
if test -f 'libs/src/sio/impl.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libs/src/sio/impl.h'\"
else
echo shar: Extracting \"'libs/src/sio/impl.h'\" \(5528 characters\)
sed "s/^X//" >'libs/src/sio/impl.h' <<'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
X/*
X * $Id: impl.h,v 8.1 1993/03/13 01:15:06 panos Exp $
X */
X
X#ifndef SIO_BUFFER_SIZE
X
X#include "sioconf.h"
X
X#ifdef HAS_MMAP
X#include <sys/types.h>
X
X
X/*
X * A struct map_unit describes a memory mapped area of a file.
X *
X * addr is the address where the file is mapped. If addr is NULL
X * the other fields are meaningless.
X * valid_bytes indicates how many bytes are _valid_ in that unit
X * mapped_bytes of a unit is how many bytes are mapped in that
X * unit ( valid <= mapped ).
X * Normally mapped_bytes will be equal to valid_bytes until
X * we reach the end of the file. Then if the file size is not a multiple
X * of the unit size, only the rest of the file will be mapped at the
X * unit, leaving part of what was mapped at the unit before still
X * visible (this happens because I chose not to unmap a unit before
X * remapping it). In that case valid_bytes shows the size of the "new"
X * mapping and mapped_bytes shows how many bytes are really mapped.
X * mapped_bytes is used in Sdone() to unmap the units.
X */
Xstruct map_unit
X{
X	caddr_t addr ;
X	size_t valid_bytes ;
X	size_t mapped_bytes ;
X} ;
X
X
X/*
X * Meaning of fields used when memory mapping:
X *
X *    file_offset:      it is the offset in the file where the next
X *                      mapping should be done
X *
X *    file_size:        size of the file (obtained from stat(2))
X */
Xstruct mmap_descriptor
X{
X   off_t file_offset ;
X   off_t file_size ;
X	struct map_unit first_unit ;
X	struct map_unit second_unit ;
X} ;
X
Xtypedef struct mmap_descriptor mapd_s ;
X
X#endif /* HAS_MMAP */
X
Xtypedef enum { FAILURE, SUCCESS } status_e ;
X
X/*
X * Descriptor management: convert a descriptor pointer to an input or
X * output descriptor pointer
X */
X#define IDP( dp )						(&(dp)->descriptor.input_descriptor)
X#define ODP( dp )						(&(dp)->descriptor.output_descriptor)
X
X#define DESCRIPTOR_INITIALIZED( dp )	((dp)->initialized)
X
X/*
X * Internal constants
X */
X#define SIO_BUFFER_SIZE       	8192
X#define SIO_NO_TIED_FD				(-1)
X
Xtypedef enum { NO = 0, YES = 1 } boolean_e ;
X
X#ifndef FALSE
X#define FALSE			0
X#define TRUE			1
X#endif
X
X#ifndef NULL
X#define NULL			0
X#endif
X
X#ifdef MIN
X#undef MIN
X#endif
X#define MIN( a, b )					( (a) < (b) ? (a) : (b) )
X
X#define NUL								'\0'
X
X#define PRIVATE						static
X
X#ifdef DEBUG
X
Xstatic char *itoa( num )
X	unsigned num ;
X{
X#define NUMBUF_SIZE		15
X	static char numbuf[ NUMBUF_SIZE ] ;
X	register char *p = &numbuf[ NUMBUF_SIZE ] ;
X
X	*--p = '\0' ;
X	do
X	{
X		*--p = num % 10 + '0' ;
X		num /= 10 ;
X	}
X	while ( num ) ;
X	return( p ) ;
X}
X
X#	define ASSERT( expr )														\
X		if ( ! (expr) )															\
X		{																				\
X			char *s1 = "SIO assertion << expr >> failed: File: " ;	\
X			char *s2 = __FILE__ ;												\
X			char *s3 = ", line: " ;												\
X			char *s4 = itoa( __LINE__ ) ;										\
X			char *s5 = "\n" ;														\
X			(void) write( 2, s1, strlen( s1 ) ) ;							\
X			(void) write( 2, s2, strlen( s2 ) ) ;							\
X			(void) write( 2, s3, strlen( s3 ) ) ;							\
X			(void) write( 2, s4, strlen( s4 ) ) ;							\
X			(void) write( 2, s5, strlen( s5 ) ) ;							\
X			exit ( 1 ) ;															\
X		}
X#else
X#	define ASSERT( expr )
X#endif
X
X
X#include <errno.h>
Xextern int errno ;
X
X/*
X * IO_SETUP initializes a descriptor if it is not already initialized.
X * It checks if the stream is of the right type (input or output).
X * CONTROL_SETUP checks if the descriptor is initialized and if the
X * stream is of the right type (input or output). 
X *
X * 	fd: file descriptor
X * 	dp: descriptor pointer
X * 	op: operation
X * 	ev: error value (if __sio_init fails; __sio_init should set errno) 
X *
X * IO_SETUP will call __sio_init if the descriptor is not initialized.
X * Possible errors:
X *		1. Using CONTROL_SETUP on an uninitialized descriptor.
X *		2. The operation is not appropriate for the descriptor (e.g.
X *			a read operation on an descriptor used for writing). 
X * Both errors set errno to EBADF.
X */
X#define CONTROL_SETUP( dp, type, ev )														\
X			{																							\
X				if ( ! DESCRIPTOR_INITIALIZED( dp ) || dp->stream_type != type )	\
X				{																						\
X					errno = EBADF ;																\
X					return( ev ) ;																	\
X				}																						\
X			}
X
X
X#define IO_SETUP( fd, dp, type, ev )														\
X			{																							\
X				if ( DESCRIPTOR_INITIALIZED( dp ) ) 										\
X				{																						\
X					if ( dp->stream_type != type )											\
X					{																					\
X						errno = EBADF ;															\
X						return( ev ) ;																\
X					}																					\
X				}																						\
X				else if ( __sio_init( dp, fd, type ) == SIO_ERR )						\
X					return( ev ) ;																	\
X			}
X
X
X/*
X * Internal functions that are visible
X */
Xint __sio_readf(), __sio_writef(), __sio_pwritef() ;
Xint __sio_extend_buffer(), __sio_init(), __sio_converter(), __sio_more() ;
Xstatus_e __sio_switch() ;
X
X
X#ifdef HAS_MEMOPS
X#include <memory.h>
X#define sio_memcopy( from, to, nbytes )   	(void) memcpy( to, from, nbytes )
X#define sio_memscan( from, nbytes, ch )      memchr( from, ch, nbytes )
X#endif
X
X#ifdef HAS_BCOPY
X#define sio_memcopy( from, to, nbytes )      (void) bcopy( from, to, nbytes )
X#endif
X
X#ifndef sio_memcopy
X#define sio_memcopy		__sio_memcopy
X#define NEED_MEMCOPY
Xvoid __sio_memcopy() ;
X#endif
X
X#ifndef sio_memscan
Xchar *sio_memscan() ;
X#endif
X
X#endif /* SIO_BUFFER_SIZE */
X
END_OF_FILE
if test 5528 -ne `wc -c <'libs/src/sio/impl.h'`; then
    echo shar: \"'libs/src/sio/impl.h'\" unpacked with wrong size!
fi
# end of 'libs/src/sio/impl.h'
fi
if test -f 'libs/src/timer/timer.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'libs/src/timer/timer.c'\"
else
echo shar: Extracting \"'libs/src/timer/timer.c'\" \(5559 characters\)
sed "s/^X//" >'libs/src/timer/timer.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: timer.c,v 5.1 93/11/26 12:16:33 panos Exp $" ;
Xstatic char *version = VERSION ;
X
X#include "timemacros.h"
X#include "impl.h"
X#include "defs.h"
X
X#define TIMER_H_NULL					((timer_h)NULL)
X
X
Xint timer_errno ;
X
X
X
X/*
X * Create a timer of the specified type.
X * Returns a timer handle
X */
Xtimer_h timer_create( type, flags, errnop )
X	enum timer_types	type ;
X	int					flags ;
X	int					*errnop ;
X{
X	int		*errp = ( errnop != NULL ) ? errnop : &timer_errno ;
X	timer_s	*tp ;
X
X	if ( type != TIMER_REAL && type != TIMER_VIRTUAL && type != TIMER_PROF )
X			HANDLE_ERROR( flags, TIMER_H_NULL, errp, TIMER_EBADTYPE,
X							"TIMER timer_create: bad timer type\n" ) ;
X			
X	tp = TIMER_ALLOC() ;
X	if ( tp == NULL )
X	{
X		*errp = TIMER_ENOMEM ;
X		return( TIMER_H_NULL ) ;
X	}
X	
X	tp->t_state = INACTIVE ;
X	tp->t_act = IDLE ;
X	tp->t_blocked = FALSE ;
X
X	tp->t_errnop = errp ;
X	tp->t_flags = flags & TIMER_CREATE_FLAGS ;
X	tp->t_action.ta_func = NULL ;
X	tp->t_action.ta_arg = NULL ;
X	tp->t_action.ta_flags = TIMER_NOFLAGS ;
X	if ( __ostimer_newtimer( tp, type ) == TIMER_ERR )
X	{
X		TIMER_FREE( tp ) ;
X		return( TIMER_H_NULL ) ;
X	}
X	return( (timer_h) tp ) ;
X}
X
X
Xvoid timer_destroy( handle )
X	timer_h	handle ;
X{
X	timer_s	*tp = TP( handle ) ;
X
X	__ostimer_blockall() ;
X
X	if ( tp->t_state == TICKING )
X	{
X		__ostimer_remove( tp->t_ostimer, tp ) ;
X		tp->t_state = DESTROYED ;
X	}
X	
X	if ( tp->t_act == IDLE || tp->t_act == PENDING )
X		TIMER_FREE( tp ) ;
X
X	__ostimer_unblockall() ;
X}
X
X
Xint timer_start( handle, itvp, time_type, ap )
X	timer_h					handle ;
X	struct itimerval		*itvp ;
X	enum timer_timetypes time_type ;
X	struct timer_action	*ap ;
X{
X	int					result ;
X	int					ok_to_start ;
X	timer_s				*tp	= TP( handle ) ;
X	struct os_timer	*otp	= tp->t_ostimer ;
X
X	__ostimer_blockall() ;
X
X	/*
X	 * We allow invoking timer_start from within the user-specified action
X	 * after the timer has expired. However, we do not allow this for
X	 * timers that have a t_interval (these timers stay at the TICKING state).
X	 */
X	ok_to_start = tp->t_state == INACTIVE &&
X							( tp->t_act == IDLE || tp->t_act == INVOKED ) ;
X
X	if ( ! ok_to_start )
X	{
X		__ostimer_unblockall() ;
X		HANDLE_ERROR( tp->t_flags, TIMER_ERR, tp->t_errnop, TIMER_EBADSTATE,
X			"TIMER timer_start: timer state does not allow this operation\n" ) ;
X	}
X
X	if ( itvp->it_value.tv_sec < 0 || itvp->it_value.tv_usec < 0 )
X	{
X		__ostimer_unblockall() ;
X		HANDLE_ERROR( tp->t_flags, TIMER_ERR, tp->t_errnop, TIMER_EBADTIME,
X			"TIMER timer_start: neg time value)\n" ) ;
X	}
X
X	tp->t_action = *ap ;
X	tp->t_action.ta_flags &= TIMER_START_FLAGS ;
X
X	result = __ostimer_add( otp, tp, itvp, time_type ) ;
X	__ostimer_unblockall() ;
X	return( result ) ;
X}
X
X
Xvoid timer_stop( handle )
X	timer_h handle ;
X{
X	timer_s *tp = TP( handle ) ;
X
X	__ostimer_blockall() ;
X
X	if ( tp->t_state == TICKING )
X	{
X		__ostimer_remove( tp->t_ostimer, tp ) ;
X		tp->t_state = INACTIVE ;
X	}
X
X	if ( tp->t_act == SCHEDULED )
X		tp->t_act = INVOKED ;		/* to avoid the invocation */
X	else if ( tp->t_act == PENDING )
X		tp->t_act = IDLE ;
X
X	tp->t_blocked = FALSE ;
X	
X	__ostimer_unblockall() ;
X}
X
X
Xvoid timer_block( handle )
X	timer_h handle ;
X{
X	timer_s *tp = TP( handle ) ;
X
X	__ostimer_blockall() ;
X
X	if ( tp->t_state == TICKING || 
X			tp->t_state == INACTIVE && 
X				( tp->t_act == PENDING || tp->t_act == SCHEDULED ) )
X		tp->t_blocked = TRUE ;
X
X	__ostimer_unblockall() ;
X}
X
X
Xvoid timer_unblock( handle )
X	timer_h handle ;
X{
X	timer_s *tp = TP( handle ) ;
X
X	__ostimer_blockall() ;
X
X	if ( tp->t_blocked )
X	{
X		tp->t_blocked = FALSE ;
X		if ( tp->t_act == PENDING )
X		{
X			tp->t_act = SCHEDULED ;
X			(void) __timer_invoke( tp ) ;
X		}
X	}
X	
X	__ostimer_unblockall() ;
X}
X
X
Xunsigned timer_expirations( handle )
X	timer_h handle ;
X{
X	return( TP( handle )->t_count ) ;
X}
X
X
X
X/*
X * Invoke the action of the specified timer
X * All timer interrupts should be blocked when this function is invoked
X * Returns TRUE if 
X */
Xenum timer_state __timer_invoke( tp )
X	register timer_s *tp ;
X{
X	enum timer_state state ;
X
X	/*
X	 * The reason for the infinite loop is that the timer may reexpire
X	 * while its function is being invoked.
X	 */
X	for ( ;; )
X	{
X		/*
X		 * This is the INVOKE part
X		 */
X		if ( tp->t_blocked )
X			tp->t_act = PENDING ;
X		else
X		{
X			if ( tp->t_state != DESTROYED && tp->t_act == SCHEDULED )
X			{
X				void	(*func)()	= tp->t_action.ta_func ;
X				void	*arg			= tp->t_action.ta_arg ;
X				int	flags 		= tp->t_action.ta_flags ;
X
X				tp->t_act = INVOKED ;
X				tp->t_expirations = tp->t_count ;
X				tp->t_count = 0 ;
X				if ( func != NULL )
X				{
X					int unblock_all_intrs = ! ( flags & TIMER_BLOCK_ALL ) ;
X					int unblock_all_but_same_intr = ! ( flags & TIMER_BLOCK_SAME ) ;
X					
X					if ( unblock_all_intrs )
X						__ostimer_unblockall() ;
X					else if ( unblock_all_but_same_intr )
X						__ostimer_unblockall_except( tp->t_ostimer ) ;
X
X					(*func)( tp, arg ) ;
X
X					if ( unblock_all_intrs || unblock_all_but_same_intr )
X						__ostimer_blockall() ;
X				}
X				else if ( arg != NULL )
X				{
X					int *ip = (int *) arg ;
X
X					if ( flags & TIMER_INC_VAR )
X						*ip += tp->t_expirations ;
X					else
X						*ip = 1 ;
X				}
X			}
X		}
X
X		state = tp->t_state ;
X
X		/*
X		 * This is the RETURN part
X		 */
X		if ( tp->t_state == DESTROYED )
X			TIMER_FREE( tp ) ;
X		else
X		{
X			if ( tp->t_act == INVOKED )
X				tp->t_act = IDLE ;
X			else if ( tp->t_act == SCHEDULED )
X				continue ;
X		}
X		break ;
X	}
X	return( state ) ;
X}
X
END_OF_FILE
if test 5559 -ne `wc -c <'libs/src/timer/timer.c'`; then
    echo shar: \"'libs/src/timer/timer.c'\" unpacked with wrong size!
fi
# end of 'libs/src/timer/timer.c'
fi
echo shar: End of archive 11 \(of 20\).
cp /dev/null ark11isdone
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
