home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume27 / clc / part18 < prev    next >
Encoding:
Text File  |  1993-11-28  |  32.5 KB  |  1,394 lines

  1. Newsgroups: comp.sources.unix
  2. From: panos@anchor.cs.colorado.edu (Panos Tsirigotis)
  3. Subject: v27i124: clc - C Libraries Collection, Part18/20
  4. References: <1.754527080.23891@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: panos@anchor.cs.colorado.edu (Panos Tsirigotis)
  9. Posting-Number: Volume 27, Issue 124
  10. Archive-Name: clc/part18
  11.  
  12. #! /bin/sh
  13. # This is a shell archive.  Remove anything before this line, then unpack
  14. # it by saving it into a file and typing "sh file".  To overwrite existing
  15. # files, type "sh file -c".  You can also feed this as standard input via
  16. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  17. # will see the following message at the end:
  18. #        "End of archive 18 (of 20)."
  19. # Contents:  libs/src/dict/ht.c libs/src/sio/sio.c
  20. # Wrapped by panos@eclipse on Sun Nov 28 14:48:17 1993
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'libs/src/dict/ht.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'libs/src/dict/ht.c'\"
  24. else
  25. echo shar: Extracting \"'libs/src/dict/ht.c'\" \(14487 characters\)
  26. sed "s/^X//" >'libs/src/dict/ht.c' <<'END_OF_FILE'
  27. X/*
  28. X * (c) Copyright 1993 by Panagiotis Tsirigotis
  29. X * All rights reserved.  The file named COPYRIGHT specifies the terms 
  30. X * and conditions for redistribution.
  31. X */
  32. X
  33. Xstatic char RCSid[] = "$Id: ht.c,v 3.2 93/09/28 21:08:12 panos Exp $" ;
  34. X
  35. X#include "htimpl.h"
  36. X
  37. Xenum lookup_type { EMPTY, FULL } ;
  38. X
  39. X
  40. X#define HASH( hp, func, arg )            \
  41. X                ( &(hp)->table[ (*(func))( arg ) % (hp)->args.ht_table_entries ] )
  42. X
  43. X#define HASH_OBJECT( hp, obj )      HASH( hp, (hp)->args.ht_objvalue, obj )
  44. X#define HASH_KEY( hp, obj )          HASH( hp, (hp)->args.ht_keyvalue, key )
  45. X
  46. X
  47. X#define N_PRIMES                            ( sizeof( primes ) / sizeof( unsigned ) )
  48. X
  49. X
  50. X/*
  51. X * Used for the selection of a good array size
  52. X */
  53. Xstatic unsigned primes[] = { 3, 5, 7, 11, 13, 17, 23, 29 } ;
  54. X
  55. X
  56. X/*
  57. X * Pick a good number for hashing using the hint argument as a hint
  58. X * on the order of magnitude.
  59. X *
  60. X * Algorithm:
  61. X *        1. Find an odd number for testing numbers for primes. The starting
  62. X *            point is 2**k-1 where k is selected such that
  63. X *                    2**k-1 <= hint < 2**(k+1)-1
  64. X *        2. Check all odd numbers from the starting point on until you find
  65. X *            one that is not a multiple of the selected primes.
  66. X */ 
  67. XPRIVATE unsigned find_good_size( hint )
  68. X    register unsigned        hint ;
  69. X{
  70. X    register int            k ;
  71. X    unsigned                    starting_point ;
  72. X    register unsigned        size ;
  73. X
  74. X    /*
  75. X     * Don't bother with silly hints
  76. X     */
  77. X    if ( hint < DEFAULT_TABLE_ENTRIES )
  78. X        return( DEFAULT_TABLE_ENTRIES ) ;
  79. X
  80. X    /*
  81. X     * Find starting point
  82. X     *
  83. X     * XXX:    a hint that is too large ( 1 << ( WORD_SIZE - 1 ) ) will cause
  84. X     *            weird behavior
  85. X     */
  86. X    for ( k = 0 ; ; k++ )
  87. X        if ( hint < ( 1 << k ) - 1 )
  88. X            break ;
  89. X    
  90. X    starting_point  = ( 1 << (k-1) ) - 1 ;
  91. X    
  92. X    /*
  93. X     * XXX:    This may be slow, especially on machines without division
  94. X     *            hardware (for example, SPARC V[78] implementations).
  95. X     */
  96. X    for ( size = starting_point ;; size += 2 )
  97. X    {
  98. X        register int j ;
  99. X
  100. X        for ( j = 0 ; j < sizeof( primes ) / sizeof( unsigned ) ; j++ )
  101. X            if ( size % primes[j] == 0 )
  102. X                goto next ;
  103. X        return( size ) ;
  104. Xnext: ;
  105. X    }
  106. X}
  107. X
  108. X
  109. X/*
  110. X * Create a new hash table
  111. X */
  112. Xdict_h ht_create( oo_comp, ko_comp, flags, errnop, argsp )
  113. X    dict_function    oo_comp ;
  114. X    dict_function    ko_comp ;
  115. X    int                flags ;
  116. X    int                *errnop ;
  117. X    struct ht_args *argsp ;
  118. X{
  119. X    header_s            *hp ;
  120. X    int                allocator_flags ;
  121. X    unsigned            table_size, bucket_size ;
  122. X    char                *id = "ht_create" ;
  123. X    char *memset() ;
  124. X
  125. X    if ( !__dict_args_ok( id, flags, errnop, oo_comp, ko_comp, DICT_UNORDERED ) )
  126. X        return( NULL_HANDLE ) ;
  127. X
  128. X   if ( argsp->ht_objvalue == NULL || argsp->ht_keyvalue == NULL )
  129. X        return( __dict_create_error( id, flags, errnop, DICT_ENOHVFUNC ) ) ;
  130. X
  131. X    hp = HHP( malloc( sizeof( header_s ) ) ) ;
  132. X    if ( hp == NULL )
  133. X        return( __dict_create_error( id, flags, errnop, DICT_ENOMEM ) ) ;
  134. X
  135. X   /*
  136. X    * Allocate the hash table
  137. X    */
  138. X    if ( argsp->ht_table_entries == 0 )
  139. X        argsp->ht_table_entries = DEFAULT_TABLE_ENTRIES ;
  140. X    else
  141. X        argsp->ht_table_entries = find_good_size( argsp->ht_table_entries ) ;
  142. X
  143. X   table_size = argsp->ht_table_entries * sizeof( tabent_s ) ;
  144. X   hp->table = TEP( malloc( table_size ) ) ;
  145. X   if ( hp->table == NULL )
  146. X   {
  147. X      free( (char *)hp ) ;
  148. X        return( __dict_create_error( id, flags, errnop, DICT_ENOMEM ) ) ;
  149. X   }
  150. X
  151. X   /*
  152. X    * Determine the bucket size and create an allocator
  153. X    */
  154. X    if ( argsp->ht_bucket_entries == 0 )
  155. X        argsp->ht_bucket_entries = DEFAULT_BUCKET_ENTRIES ;
  156. X   bucket_size = sizeof( bucket_s ) +
  157. X                                argsp->ht_bucket_entries * sizeof( dict_obj ) ;
  158. X    
  159. X    /*
  160. X     * XXX: can't use fast allocator if we set FSM_ZERO_ALLOC
  161. X     *
  162. X     * XXX: should be able to give some indication to FSMA about the
  163. X     *          slots/chunk; currently we use the default.
  164. X     */
  165. X    allocator_flags = FSM_ZERO_ALLOC ;
  166. X    if ( flags & DICT_RETURN_ERROR )
  167. X        allocator_flags |= FSM_RETURN_ERROR ;
  168. X   hp->alloc = fsm_create( bucket_size, 0, allocator_flags ) ;
  169. X   if ( hp->alloc == NULL )
  170. X   {
  171. X      free( (char *)hp ) ;
  172. X      free( (char *)hp->table ) ;
  173. X        return( __dict_create_error( id, flags, errnop, DICT_ENOMEM ) ) ;
  174. X   }
  175. X
  176. X    __dict_init_header( DHP( hp ), oo_comp, ko_comp, flags, errnop ) ;
  177. X
  178. X    /*
  179. X     * Clear the table
  180. X     */
  181. X    (void) memset( (char *) hp->table, 0, (int) table_size ) ;
  182. X
  183. X    hp->args = *argsp ;
  184. X   return( (dict_h) hp ) ;
  185. X}
  186. X
  187. X
  188. X
  189. Xvoid ht_destroy( handle )
  190. X   dict_h        handle ;
  191. X{
  192. X   header_s        *hp = HHP( handle ) ;
  193. X
  194. X   fsm_destroy( hp->alloc ) ;
  195. X   free( (char *)hp->table ) ;
  196. X   free( (char *)hp ) ;
  197. X}
  198. X
  199. X
  200. X/*
  201. X * Bucket chain reverse lookup:
  202. X *     Return a pointer to the last dict_obj of the bucket chain that
  203. X *     starts with bp (search up to the bucket 'stop' but *not* that bucket)
  204. X */
  205. XPRIVATE dict_obj *bc_reverse_lookup( bp, entries, stop )
  206. X    bucket_s        *bp ;
  207. X    unsigned        entries ;
  208. X    bucket_s        *stop ;
  209. X{
  210. X    dict_obj        *result ;
  211. X    dict_obj        *bucket_list ;
  212. X    int            j ;
  213. X
  214. X    if ( bp == stop )
  215. X        return( NULL ) ;
  216. X
  217. X    result = bc_reverse_lookup( bp->next, entries, stop ) ;
  218. X    if ( result )
  219. X        return( result ) ;
  220. X
  221. X    bucket_list = BUCKET_OBJECTS( bp ) ;
  222. X
  223. X    for ( j = entries-1 ; j >= 0 ; j-- )
  224. X        if ( bucket_list[ j ] != NULL )
  225. X            return( &bucket_list[ j ] ) ;
  226. X    return( NULL ) ;
  227. X}
  228. X
  229. X
  230. X/*
  231. X * Bucket chain lookup:
  232. X *        Return a pointer to the first NULL (if type is EMPTY) or non-NULL
  233. X *        (if type is FULL) dict_obj in the bucket chain.
  234. X */
  235. XPRIVATE dict_obj *bc_lookup( start, entries, type )
  236. X    bucket_s                *start ;
  237. X    unsigned                entries ;
  238. X    enum lookup_type    type ;
  239. X{
  240. X    register bucket_s    *bp ;
  241. X    register int        look_for_empty = ( type == EMPTY ) ;
  242. X
  243. X    for ( bp = start ; bp != NULL ; bp = bp->next )
  244. X    {
  245. X        int j ;
  246. X        dict_obj *bucket_list = BUCKET_OBJECTS( bp ) ;
  247. X
  248. X        for ( j = 0 ; j < entries ; j++ )
  249. X            if ( ( bucket_list[j] == NULL ) == look_for_empty )
  250. X                return( &bucket_list[j] ) ;
  251. X    }
  252. X    return( NULL ) ;
  253. X}
  254. X
  255. X
  256. X
  257. X/*
  258. X * Search the bucket chain for the specified object
  259. X * Returns the pointer of the bucket where the object was found.
  260. X */
  261. XPRIVATE bucket_s *bc_search( chain, entries, object, index )
  262. X    bucket_s        *chain ;
  263. X    unsigned        entries ;
  264. X    dict_obj        object ;
  265. X    int            *index ;
  266. X{
  267. X    bucket_s        *bp ;
  268. X
  269. X    for ( bp = chain ; bp ; bp = bp->next )
  270. X    {
  271. X        dict_obj *bucket_list = BUCKET_OBJECTS( bp ) ;
  272. X        int i ;
  273. X
  274. X        for ( i = 0 ; i < entries ; i++ )
  275. X            if ( bucket_list[ i ] == object )
  276. X            {
  277. X                if ( index )
  278. X                    *index = i ;
  279. X                return( bp ) ;
  280. X            }
  281. X    }
  282. X    return( NULL ) ;
  283. X}
  284. X
  285. X
  286. X
  287. X/*
  288. X * Add a bucket to the chain of the specified table entry.
  289. X * Returns a pointer to the first slot of the new bucket or NULL on failure.
  290. X */
  291. XPRIVATE dict_obj *te_expand( tep, hp )
  292. X    tabent_s        *tep ;
  293. X    header_s        *hp ;
  294. X{
  295. X    dheader_s    *dhp = DHP( hp ) ;
  296. X    bucket_s        *bp ;
  297. X
  298. X    bp = (bucket_s *) fsm_alloc( hp->alloc ) ;
  299. X    if ( bp == NULL )
  300. X        HANDLE_ERROR( dhp, "te_expand", DICT_ENOMEM, NULL ) ;
  301. X
  302. X    /*
  303. X     * Put the bucket at the head of this entry's chain
  304. X     */
  305. X    bp->next = tep->head_bucket ;
  306. X    tep->head_bucket = bp ;
  307. X
  308. X    /*
  309. X     * Update entry info
  310. X     */
  311. X    tep->n_free += hp->args.ht_bucket_entries ;
  312. X    return( BUCKET_OBJECTS( bp ) ) ;
  313. X}
  314. X
  315. X
  316. X/*
  317. X * Search a table entry for an object
  318. X */
  319. XPRIVATE dict_obj *te_search( tep, hp, type, arg )
  320. X    tabent_s        *tep ;
  321. X    header_s        *hp ;
  322. X    search_e        type ;
  323. X    dict_h        arg ;
  324. X{
  325. X    dheader_s    *dhp = DHP( hp ) ;
  326. X    bucket_s        *bp ;
  327. X
  328. X    for ( bp = tep->head_bucket ; bp != NULL ; bp = bp->next )
  329. X    {
  330. X        int i ;
  331. X        int result ;
  332. X        dict_obj *bucket_list = BUCKET_OBJECTS( bp ) ;
  333. X
  334. X        for ( i = 0 ; i < hp->args.ht_bucket_entries ; i++ )
  335. X            if ( bucket_list[ i ] != NULL )
  336. X            {
  337. X                result = ( type == KEY_SEARCH )
  338. X                    ? (*dhp->ko_comp)( (dict_key)arg, bucket_list[ i ] )
  339. X                    : (*dhp->oo_comp)( (dict_obj)arg, bucket_list[ i ] ) ;
  340. X                if ( result == 0 )
  341. X                    return( &bucket_list[ i ] ) ;
  342. X            }
  343. X    }
  344. X    return( NULL ) ;
  345. X}
  346. X
  347. X
  348. XPRIVATE int ht_do_insert( hp, uniq, object, objectp )
  349. X    header_s                *hp ;
  350. X    int                    uniq ;
  351. X    register dict_obj object ;
  352. X    dict_obj                *objectp ;
  353. X{
  354. X    dheader_s            *dhp = DHP( hp ) ;
  355. X    tabent_s                *tep ;
  356. X    dict_obj                *object_slot ;
  357. X
  358. X    if ( object == NULL )
  359. X        HANDLE_ERROR( dhp, "ht_do_insert", DICT_ENULLOBJECT, DICT_ERR ) ;
  360. X    
  361. X    tep = HASH_OBJECT( hp, object ) ;
  362. X
  363. X    /*
  364. X     * We search the entry chain only if it exists and uniqueness is required.
  365. X     */
  366. X    if ( ENTRY_HAS_CHAIN( tep ) && uniq )
  367. X    {
  368. X        object_slot = te_search( tep, hp, OBJECT_SEARCH, (dict_h) object ) ;
  369. X        if ( object_slot != NULL )
  370. X        {
  371. X            if ( objectp != NULL )
  372. X                *objectp = *object_slot ;
  373. X            ERRNO( dhp ) = DICT_EEXISTS ;
  374. X            return( DICT_ERR ) ;
  375. X        }
  376. X    }
  377. X
  378. X    /*
  379. X     * If the entry chain is full, expand it
  380. X     */
  381. X    if ( ENTRY_IS_FULL( tep ) )
  382. X    {
  383. X        object_slot = te_expand( tep, hp ) ;
  384. X        if ( object_slot == NULL )
  385. X            return( DICT_ERR ) ;
  386. X    }
  387. X    else
  388. X        object_slot = bc_lookup( tep->head_bucket,
  389. X                                                        hp->args.ht_bucket_entries, EMPTY ) ;
  390. X    tep->n_free-- ;
  391. X
  392. X    *object_slot = object ;
  393. X    if ( objectp != NULL )
  394. X        *objectp = *object_slot ;
  395. X    return( DICT_OK ) ;
  396. X}
  397. X
  398. X
  399. X
  400. Xint ht_insert( handle, object )
  401. X    dict_h        handle ;
  402. X    dict_obj        object ;
  403. X{
  404. X    header_s        *hp = HHP( handle ) ;
  405. X
  406. X    return( ht_do_insert( hp,
  407. X                    hp->dh.flags & DICT_UNIQUE_KEYS, object, (dict_obj *)NULL ) ) ;
  408. X}
  409. X
  410. X
  411. Xint ht_insert_uniq( handle, object, objectp )
  412. X    dict_h        handle ;
  413. X    dict_obj        object ;
  414. X    dict_obj        *objectp ;
  415. X{
  416. X    header_s    *hp = HHP( handle ) ;
  417. X    dheader_s    *dhp = DHP( hp ) ;
  418. X
  419. X    if ( dhp->oo_comp == NULL_FUNC )
  420. X        HANDLE_ERROR( dhp, "ht_insert_uniq", DICT_ENOOOCOMP, DICT_ERR ) ;
  421. X    return( ht_do_insert( hp, TRUE, object, objectp ) ) ;
  422. X}
  423. X
  424. X
  425. Xint ht_delete( handle, object )
  426. X    dict_h        handle ;
  427. X    dict_obj        object ;
  428. X{
  429. X    header_s        *hp = HHP( handle ) ;
  430. X    dheader_s    *dhp = DHP( hp ) ;
  431. X    tabent_s        *tep ;
  432. X    int            bucket_index ;
  433. X    bucket_s        *bp ;
  434. X
  435. X   if ( object == NULL )
  436. X      HANDLE_ERROR( dhp, "ht_delete", DICT_ENULLOBJECT, DICT_ERR ) ;
  437. X
  438. X    tep = HASH_OBJECT( hp, object ) ;
  439. X    if ( ! ENTRY_HAS_CHAIN( tep ) )
  440. X    {
  441. X        ERRNO( dhp ) = DICT_ENOTFOUND ;
  442. X        return( DICT_ERR ) ;
  443. X    }
  444. X
  445. X    bp = bc_search( tep->head_bucket,
  446. X                                hp->args.ht_bucket_entries, object, &bucket_index ) ;
  447. X   if ( bp != NULL )
  448. X   {
  449. X        BUCKET_OBJECTS( bp )[ bucket_index ] = NULL ;
  450. X        tep->n_free++ ;
  451. X      return( DICT_OK ) ;
  452. X   }
  453. X   else
  454. X   {
  455. X      ERRNO( dhp ) = DICT_ENOTFOUND ;
  456. X      return( DICT_ERR ) ;
  457. X   }
  458. X}
  459. X
  460. X
  461. Xdict_obj ht_search( handle, key )
  462. X    dict_h        handle ;
  463. X    dict_key        key ;
  464. X{
  465. X    header_s        *hp    = HHP( handle ) ;
  466. X    tabent_s        *tep    = HASH_KEY( hp, key ) ;
  467. X    dict_obj        *objp = te_search( tep, hp, KEY_SEARCH, (dict_h) key ) ;
  468. X
  469. X    return( ( objp == NULL ) ? NULL_OBJ : *objp ) ;
  470. X}
  471. X
  472. X
  473. X
  474. Xdict_obj ht_minimum( handle )
  475. X    dict_h        handle ;
  476. X{
  477. X    header_s        *hp                = HHP( handle ) ;
  478. X    unsigned        bucket_entries = hp->args.ht_bucket_entries ;
  479. X    int            i ;
  480. X
  481. X    for ( i = 0 ; i < hp->args.ht_table_entries ; i++ )
  482. X    {
  483. X        tabent_s *tep = &hp->table[i] ;
  484. X        dict_obj *found ;
  485. X
  486. X        if ( ! ENTRY_HAS_CHAIN( tep ) )
  487. X            continue ;
  488. X        found = bc_lookup( tep->head_bucket, bucket_entries, FULL ) ;
  489. X        if ( found )
  490. X            return( *found ) ;
  491. X    }
  492. X    return( NULL_OBJ ) ;
  493. X}
  494. X
  495. X
  496. Xdict_obj ht_maximum( handle )
  497. X    dict_h        handle ;
  498. X{
  499. X    header_s        *hp                = HHP( handle ) ;
  500. X    unsigned        bucket_entries = hp->args.ht_bucket_entries ;
  501. X    int i ;
  502. X
  503. X    for ( i = hp->args.ht_table_entries-1 ; i >= 0 ; i-- )
  504. X    {
  505. X        tabent_s *tep = &hp->table[i] ;
  506. X        dict_obj *found ;
  507. X
  508. X        if ( ! ENTRY_HAS_CHAIN( tep ) )
  509. X            continue ;
  510. X        found = bc_reverse_lookup( tep->head_bucket,
  511. X                                                            bucket_entries, BUCKET_NULL ) ;
  512. X        if ( found )
  513. X            return( *found ) ;
  514. X    }
  515. X    return( NULL_OBJ ) ;
  516. X}
  517. X
  518. X
  519. Xdict_obj ht_successor( handle, object )
  520. X    dict_h        handle ;
  521. X    dict_obj        object ;
  522. X{
  523. X    header_s        *hp                = HHP( handle ) ;
  524. X    dheader_s    *dhp                = DHP( hp ) ;
  525. X    tabent_s        *table_end        = &hp->table[ hp->args.ht_table_entries ] ;
  526. X    unsigned        bucket_entries    = hp->args.ht_bucket_entries ;
  527. X    tabent_s        *tep ;
  528. X    bucket_s        *bp ;
  529. X    int            bucket_index ;
  530. X    int            i ;
  531. X    char            *id = "ht_successor" ;
  532. X
  533. X    if ( object == NULL )
  534. X        HANDLE_ERROR( dhp, id, DICT_ENULLOBJECT, NULL_OBJ ) ;
  535. X
  536. X    tep = HASH_OBJECT( hp, object ) ;
  537. X    if ( ! ENTRY_HAS_CHAIN( tep ) ||
  538. X                 ( bp = bc_search( tep->head_bucket,
  539. X                                bucket_entries, object, &bucket_index ) ) == NULL )
  540. X        HANDLE_ERROR( dhp, id, DICT_EBADOBJECT, NULL_OBJ ) ;
  541. X
  542. X    ERRNO( dhp ) = DICT_ENOERROR ;
  543. X    
  544. X    for ( i = bucket_index+1 ; i < bucket_entries ; i++ )
  545. X        if ( BUCKET_OBJECTS( bp )[ i ] != NULL )
  546. X            return( BUCKET_OBJECTS( bp )[ i ] ) ;
  547. X    
  548. X    for ( bp = bp->next ;; )
  549. X    {
  550. X        dict_obj *found = bc_lookup( bp, bucket_entries, FULL ) ;
  551. X
  552. X        if ( found )
  553. X            return( *found ) ;
  554. X        tep++ ;
  555. X        if ( tep >= table_end )
  556. X            return( NULL_OBJ ) ;
  557. X        bp = tep->head_bucket ;
  558. X    }
  559. X}
  560. X
  561. X
  562. Xdict_obj ht_predecessor( handle, object )
  563. X    dict_h        handle ;
  564. X    dict_obj        object ;
  565. X{
  566. X    header_s        *hp                = HHP( handle ) ;
  567. X    dheader_s    *dhp                = DHP( hp ) ;
  568. X    unsigned        bucket_entries = hp->args.ht_bucket_entries ;
  569. X    tabent_s        *tep ;
  570. X    bucket_s        *stop ;
  571. X    dict_obj        *found ;
  572. X    int            bucket_index ;
  573. X    int            i ;
  574. X    char            *id = "ht_predecessor" ;
  575. X
  576. X    if ( object == NULL )
  577. X        HANDLE_ERROR( dhp, id, DICT_ENULLOBJECT, NULL_OBJ ) ;
  578. X
  579. X    tep = HASH_OBJECT( hp, object ) ;
  580. X    stop = bc_search( tep->head_bucket, bucket_entries, object, &bucket_index ) ;
  581. X    if ( stop == NULL )
  582. X        HANDLE_ERROR( dhp, id, DICT_EBADOBJECT, NULL_OBJ ) ;
  583. X    
  584. X    ERRNO( dhp ) = DICT_ENOERROR ;
  585. X
  586. X    for ( i = bucket_index-1 ; i >= 0 ; i-- )
  587. X        if ( BUCKET_OBJECTS( stop )[ i ] != NULL )
  588. X            return( BUCKET_OBJECTS( stop )[ i ] ) ;
  589. X    
  590. X    for ( ;; )
  591. X    {
  592. X        found = bc_reverse_lookup( tep->head_bucket, bucket_entries, stop ) ;
  593. X        if ( found )
  594. X            return( *found ) ;
  595. X        stop = NULL ;
  596. X        tep-- ;
  597. X        if ( tep < hp->table )
  598. X            return( NULL_OBJ ) ;
  599. X    }
  600. X}
  601. X
  602. X
  603. X
  604. X/*
  605. X * Sets the iterator to the beginning of the next used entry.
  606. X * The current table entry *is* included in the search.
  607. X */
  608. XPRIVATE void iter_next( hp )
  609. X    header_s            *hp ;
  610. X{
  611. X    register int    i ;
  612. X    struct ht_iter *ip = &hp->iter ;
  613. X
  614. X    for ( i = ip->current_table_entry ; i < hp->args.ht_table_entries ; i++ )
  615. X        if ( ENTRY_HAS_CHAIN( &hp->table[i] ) )
  616. X        {
  617. X            ip->current_bucket = hp->table[i].head_bucket ;
  618. X            ip->next_bucket_offset = 0 ;
  619. X            break ;
  620. X        }
  621. X    ip->current_table_entry = i ;
  622. X}
  623. X
  624. X
  625. X/*
  626. X * We don't make any use of 'direction'
  627. X */
  628. Xvoid ht_iterate( handle, direction )
  629. X    dict_h                    handle ;
  630. X    enum dict_direction    direction ;
  631. X{
  632. X    header_s                    *hp = HHP( handle ) ;
  633. X
  634. X#ifdef lint
  635. X    direction = direction ;
  636. X#endif
  637. X    hp->iter.current_table_entry = 0 ;
  638. X    iter_next( hp ) ;
  639. X}
  640. X
  641. X
  642. Xdict_obj ht_nextobj( handle )
  643. X    dict_h            handle ;
  644. X{
  645. X    header_s            *hp = HHP( handle ) ;
  646. X    struct ht_iter *ip = &hp->iter ;
  647. X    int                 i ;
  648. X
  649. X    while ( ip->current_table_entry < hp->args.ht_table_entries )
  650. X    {
  651. X        do
  652. X        {
  653. X            for ( i = ip->next_bucket_offset ;
  654. X                                        i < hp->args.ht_bucket_entries ; i++ )
  655. X            {
  656. X                dict_obj *bucket_list = BUCKET_OBJECTS( ip->current_bucket ) ;
  657. X
  658. X                if ( bucket_list[i] != NULL )
  659. X                {
  660. X                    ip->next_bucket_offset = i+1 ;
  661. X                    return( bucket_list[i] ) ;
  662. X                }
  663. X            }
  664. X            ip->current_bucket = ip->current_bucket->next ;
  665. X        }
  666. X        while ( ip->current_bucket ) ;
  667. X
  668. X        ip->current_table_entry++ ;
  669. X        iter_next( hp ) ;
  670. X    }
  671. X    return( NULL_OBJ ) ;
  672. X}
  673. X
  674. END_OF_FILE
  675. if test 14487 -ne `wc -c <'libs/src/dict/ht.c'`; then
  676.     echo shar: \"'libs/src/dict/ht.c'\" unpacked with wrong size!
  677. fi
  678. # end of 'libs/src/dict/ht.c'
  679. fi
  680. if test -f 'libs/src/sio/sio.c' -a "${1}" != "-c" ; then 
  681.   echo shar: Will not clobber existing file \"'libs/src/sio/sio.c'\"
  682. else
  683. echo shar: Extracting \"'libs/src/sio/sio.c'\" \(15212 characters\)
  684. sed "s/^X//" >'libs/src/sio/sio.c' <<'END_OF_FILE'
  685. X/*
  686. X * (c) Copyright 1992, 1993 by Panagiotis Tsirigotis
  687. X * All rights reserved.  The file named COPYRIGHT specifies the terms 
  688. X * and conditions for redistribution.
  689. X */
  690. X
  691. Xstatic char RCSid[] = "$Id: sio.c,v 8.1 1993/03/13 01:15:55 panos Exp $" ;
  692. Xstatic char sio_version[] = VERSION ;
  693. X
  694. X#include <sys/types.h>
  695. X#include <sys/stat.h>
  696. X
  697. X#include "sio.h"
  698. X#include "impl.h"
  699. X
  700. X#ifdef EVENTS
  701. X#include "events.h"
  702. X#endif
  703. X
  704. X/*
  705. X * SIO WRITE FUNCTIONS: Swrite, Sputc
  706. X */
  707. X
  708. X/*
  709. X * Stream write call: arguments same as those of write(2)
  710. X */
  711. Xint Swrite( fd, addr, nbytes )
  712. X    int fd ;
  713. X    register char *addr ;
  714. X    register int nbytes ;
  715. X{
  716. X    register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  717. X    register __sio_od_t *odp = ODP( dp ) ;
  718. X    register int b_transferred ;
  719. X    register int b_avail ;
  720. X    int total_b_transferred ;
  721. X    int b_written ;
  722. X    int b_in_buffer ;
  723. X
  724. X#ifdef EVENTS
  725. X    EVENT( fd, EV_SWRITE ) ;
  726. X#endif
  727. X
  728. X    IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ;
  729. X    ASSERT( odp->start <= odp->nextb && odp->nextb <= odp->buf_end ) ;
  730. X
  731. X    b_avail = odp->buf_end - odp->nextb ;
  732. X    b_transferred = MIN( nbytes, b_avail ) ;
  733. X    sio_memcopy( addr, odp->nextb, b_transferred ) ;
  734. X    odp->nextb += b_transferred ;
  735. X
  736. X    /*
  737. X     * check if we are done
  738. X     */
  739. X    if ( b_transferred == nbytes )
  740. X        return( b_transferred ) ;
  741. X
  742. X    /*
  743. X     * at this point we know that the buffer is full
  744. X     */
  745. X    b_in_buffer = odp->buf_end - odp->start ;
  746. X    b_written = __sio_writef( odp, fd ) ;
  747. X    if ( b_written != b_in_buffer )
  748. X        return( (b_written >= nbytes) ? nbytes : b_written ) ;
  749. X    
  750. X    total_b_transferred = b_transferred ;
  751. X    addr += b_transferred ;
  752. X    nbytes -= b_transferred ;
  753. X
  754. X    for ( ;; )
  755. X    {
  756. X        b_transferred = MIN( nbytes, odp->buffer_size ) ;
  757. X        sio_memcopy( addr, odp->nextb, b_transferred ) ;
  758. X        odp->nextb += b_transferred ;
  759. X        nbytes -= b_transferred ;
  760. X        if ( nbytes == 0 )
  761. X        {
  762. X            total_b_transferred += b_transferred ;
  763. X            break ;
  764. X        }
  765. X        /*
  766. X         * the buffer is full
  767. X         */
  768. X        b_written = __sio_writef( odp, fd ) ;
  769. X        if ( b_written != odp->buffer_size )
  770. X        {
  771. X            if ( b_written != SIO_ERR )
  772. X            {
  773. X                total_b_transferred += b_written ;
  774. X                odp->nextb += b_written ;
  775. X            }
  776. X            break ;
  777. X        }
  778. X        /*
  779. X         * everything is ok
  780. X         */
  781. X        total_b_transferred += b_transferred ;
  782. X        addr += b_transferred ;
  783. X    }
  784. X    return( total_b_transferred ) ;
  785. X}
  786. X
  787. X
  788. X/*
  789. X * Add a character to a file
  790. X */
  791. Xint Sputc( fd, c )
  792. X    int fd ;
  793. X    char c ;
  794. X{
  795. X    register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  796. X    register __sio_od_t *odp = ODP( dp ) ;
  797. X
  798. X#ifdef EVENTS
  799. X    EVENT( fd, EV_SPUTC ) ;
  800. X#endif
  801. X    
  802. X    IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ;
  803. X    ASSERT( odp->start <= odp->nextb && odp->nextb <= odp->buf_end ) ;
  804. X
  805. X    /*
  806. X     * The following is a weak check since we should really be
  807. X     * checking that nextb == buf_end (it would be an error for
  808. X     * nextb to exceed buf_end; btw, the assertion above, when
  809. X     * enabled makes sure this does not occur).
  810. X     *
  811. X     * NOTE: __sio_writef NEVER uses data beyond the end of buffer.
  812. X     */
  813. X    if ( odp->nextb >= odp->buf_end )
  814. X    {
  815. X        int b_in_buffer = odp->buf_end - odp->start ;
  816. X
  817. X        /*
  818. X         * There is nothing we can do if __sio_writef does not manage
  819. X         * to write the whole buffer
  820. X         */
  821. X        if ( __sio_writef( odp, fd ) != b_in_buffer )
  822. X            return( SIO_ERR ) ;
  823. X    }
  824. X    *odp->nextb++ = c ;
  825. X    if ( __SIO_MUST_FLUSH( *odp, c ) && __sio_writef( odp, fd ) == SIO_ERR )
  826. X        return( SIO_ERR ) ;
  827. X    return ( c ) ;
  828. X}
  829. X
  830. X
  831. X
  832. X/*
  833. X * SIO READ FUNCTIONS
  834. X */
  835. X
  836. X/*
  837. X * Stream read call: arguments same as those of read(2)
  838. X */
  839. Xint Sread( fd, addr, nbytes )
  840. X    int fd ;
  841. X    char *addr ;
  842. X    int nbytes ;
  843. X{
  844. X    register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  845. X    register __sio_id_t *idp = IDP( dp ) ;
  846. X    register int b_transferred ;
  847. X    int b_read ;
  848. X    int total_b_transferred ;
  849. X    int b_left ;
  850. X
  851. X#ifdef EVENTS
  852. X    EVENT( fd, EV_SREAD ) ;
  853. X#endif
  854. X
  855. X    IO_SETUP( fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ;
  856. X    ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
  857. X
  858. X    b_left = idp->end - idp->nextb ;
  859. X    b_transferred = MIN( b_left, nbytes ) ;
  860. X    sio_memcopy( idp->nextb, addr, b_transferred ) ;
  861. X    idp->nextb += b_transferred ;
  862. X    if ( b_transferred == nbytes )
  863. X        return( b_transferred ) ;
  864. X    
  865. X    nbytes -= b_transferred ;
  866. X    total_b_transferred = b_transferred ;
  867. X    addr += b_transferred ;
  868. X
  869. X    do
  870. X    {
  871. X        b_read = __sio_readf( idp, fd ) ;
  872. X        switch ( b_read )
  873. X        {
  874. X            case SIO_ERR:
  875. X                if ( total_b_transferred == 0 )
  876. X                    return( SIO_ERR ) ;
  877. X                /* FALL THROUGH */
  878. X            
  879. X            case 0:
  880. X                return( total_b_transferred ) ;
  881. X        }
  882. X            
  883. X        b_transferred = MIN( b_read, nbytes ) ;
  884. X        sio_memcopy( idp->nextb, addr, b_transferred ) ;
  885. X        addr += b_transferred ;
  886. X        idp->nextb += b_transferred ;
  887. X        total_b_transferred += b_transferred ;
  888. X        nbytes -= b_transferred ;
  889. X    }
  890. X    while ( nbytes && b_read == idp->buffer_size ) ;
  891. X    return( total_b_transferred ) ;
  892. X}
  893. X
  894. X
  895. X
  896. X/*
  897. X * Read a line from a file
  898. X * Returns a pointer to the beginning of the line or NULL
  899. X */
  900. Xchar *Srdline( fd )
  901. X    int fd ;
  902. X{
  903. X    register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  904. X    register __sio_id_t *idp = IDP( dp ) ;
  905. X    register char *cp ;
  906. X    register char *line_start ;
  907. X    register int b_left ;
  908. X    register int extension ;
  909. X
  910. X#ifdef EVENTS
  911. X    EVENT( fd, EV_SRDLINE ) ;
  912. X#endif
  913. X
  914. X    IO_SETUP( fd, dp, __SIO_INPUT_STREAM, NULL ) ;
  915. X    ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
  916. X
  917. X#ifdef HAS_MMAP
  918. X    if ( idp->memory_mapped && __sio_switch( idp, fd ) == FAILURE )
  919. X        return( NULL ) ;
  920. X#endif
  921. X
  922. X    b_left = idp->end - idp->nextb ;
  923. X    /*
  924. X     * Look for a '\n'. If the search fails, extend the buffer
  925. X     * and search again (the extension is performed by copying the
  926. X     * bytes that were searched to the auxiliary buffer and reading 
  927. X     * new input in the main buffer).
  928. X     * If the new input still does not contain a '\n' and there is
  929. X     * more space in the main buffer (this can happen with network
  930. X     * connections), read more input until either the buffer is full
  931. X     * or a '\n' is found.
  932. X     * Finally, set cp to point to the '\n', and line_start to
  933. X     * the beginning of the line
  934. X     */
  935. X    if ( b_left && ( cp = sio_memscan( idp->nextb, b_left, '\n' ) ) != NULL )
  936. X    {
  937. X        line_start = idp->nextb ;
  938. X        idp->nextb = cp + 1 ;
  939. X    }
  940. X    else
  941. X    {
  942. X        extension = __sio_extend_buffer( idp, fd, b_left ) ;
  943. X        if ( extension > 0 )
  944. X        {
  945. X            ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
  946. X
  947. X            line_start = idp->start ;
  948. X            cp = sio_memscan( idp->nextb, extension, '\n' ) ;
  949. X            if ( cp != NULL )
  950. X                idp->nextb = cp + 1 ;
  951. X            else
  952. X                for ( ;; )
  953. X                {
  954. X                    idp->nextb = idp->end ;
  955. X                    extension = __sio_more( idp, fd ) ;
  956. X                    if ( extension > 0 )
  957. X                    {
  958. X                        cp = sio_memscan( idp->nextb, extension, '\n' ) ;
  959. X                        if ( cp == NULL )
  960. X                            continue ;
  961. X                        idp->nextb = cp + 1 ;
  962. X                        break ;
  963. X                    }
  964. X                    else
  965. X                    {
  966. X                        /*
  967. X                         * If there is spare room in the buffer avoid trashing
  968. X                         * the last character
  969. X                         */
  970. X                        if ( idp->end < &idp->buf[ idp->buffer_size ] )
  971. X                            cp = idp->end ;
  972. X                        else
  973. X                            cp = &idp->buf[ idp->buffer_size - 1 ] ;
  974. X                        break ;
  975. X                    }
  976. X                }
  977. X        }
  978. X        else                    /* buffer could not be extended */
  979. X            if ( b_left == 0 )
  980. X            {
  981. X                /*
  982. X                 * Set errno to 0 if EOF has been reached
  983. X                 */
  984. X                if ( extension == 0 )
  985. X                    errno = 0 ;
  986. X                return( NULL ) ;
  987. X            }
  988. X            else
  989. X            {
  990. X                line_start = idp->start ;
  991. X                cp = idp->end ;
  992. X                /*
  993. X                 * By setting idp->nextb to be equal to idp->end,
  994. X                 * subsequent calls to Srdline will return NULL because
  995. X                 * __sio_extend_buffer will be invoked and it will return 0.
  996. X                 */
  997. X                idp->nextb = idp->end ;
  998. X            }
  999. X    }
  1000. X    *cp = NUL ;
  1001. X    idp->line_length = cp - line_start ;
  1002. X    return( line_start ) ;
  1003. X}
  1004. X
  1005. X
  1006. X/*
  1007. X * Get a character from a file
  1008. X */
  1009. Xint Sgetc( fd )
  1010. X    int fd ;
  1011. X{
  1012. X    register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  1013. X    register __sio_id_t *idp = IDP( dp ) ;
  1014. X
  1015. X#ifdef EVENTS
  1016. X    EVENT( fd, EV_SGETC ) ;
  1017. X#endif
  1018. X
  1019. X    IO_SETUP( fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ;
  1020. X    ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
  1021. X    if ( idp->nextb >= idp->end )
  1022. X    {
  1023. X        register int b_read = __sio_readf( idp, fd ) ;
  1024. X
  1025. X        if ( b_read == 0 )
  1026. X            return( SIO_EOF ) ;
  1027. X        else if ( b_read == SIO_ERR )
  1028. X            return( SIO_ERR ) ;
  1029. X    }
  1030. X    return( (int) *idp->nextb++ ) ;
  1031. X}
  1032. X
  1033. X
  1034. Xchar *Sfetch( fd, lenp )
  1035. X    int fd ;
  1036. X    long *lenp ;
  1037. X{
  1038. X    register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  1039. X    register __sio_id_t *idp = IDP( dp ) ;
  1040. X    register int b_read ;
  1041. X    register char *p ;
  1042. X
  1043. X#ifdef EVENTS
  1044. X    EVENT( fd, EV_SFETCH ) ;
  1045. X#endif
  1046. X
  1047. X    IO_SETUP( fd, dp, __SIO_INPUT_STREAM, NULL ) ;
  1048. X    ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
  1049. X    if ( idp->nextb >= idp->end )
  1050. X    {
  1051. X        b_read = __sio_readf( idp, fd ) ;
  1052. X        if ( b_read == SIO_ERR )
  1053. X            return( NULL ) ;
  1054. X        if ( b_read == 0 )
  1055. X        {
  1056. X            errno = 0 ;
  1057. X            return( NULL ) ;
  1058. X        }
  1059. X    }
  1060. X    *lenp = idp->end - idp->nextb ;
  1061. X    p = idp->nextb ;
  1062. X    idp->nextb = idp->end ;
  1063. X    return( p ) ;
  1064. X}
  1065. X
  1066. X
  1067. X
  1068. X/*
  1069. X * SIO CONTROL FUNCTIONS
  1070. X */
  1071. X
  1072. X/*
  1073. X * Undo the last Srdline or Sgetc
  1074. X */
  1075. Xint Sundo( fd, type )
  1076. X    int fd ;
  1077. X    int type ;
  1078. X{
  1079. X    register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ; 
  1080. X    register __sio_id_t *idp = IDP( dp ) ;
  1081. X    int retval = 0 ;
  1082. X
  1083. X#ifdef EVENTS
  1084. X    EVENT( fd, EV_SUNDO ) ;
  1085. X#endif
  1086. X
  1087. X    CONTROL_SETUP( dp, __SIO_INPUT_STREAM, SIO_ERR ) ;
  1088. X
  1089. X    /*
  1090. X     * Undo works only for fd's used for input
  1091. X     */
  1092. X    if ( dp->stream_type != __SIO_INPUT_STREAM )
  1093. X        return( SIO_ERR ) ;
  1094. X
  1095. X    /*
  1096. X     * Check if the operation makes sense; if so, do it, otherwise ignore it
  1097. X     */
  1098. X    switch ( type )
  1099. X    {
  1100. X        case SIO_UNDO_LINE:
  1101. X            if ( idp->nextb - idp->line_length > idp->start )
  1102. X            {
  1103. X                *--idp->nextb = '\n' ;
  1104. X                idp->nextb -= idp->line_length ;
  1105. X            }
  1106. X            ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
  1107. X            break ;
  1108. X        
  1109. X        case SIO_UNDO_CHAR:
  1110. X            if ( idp->nextb > idp->start )
  1111. X                idp->nextb-- ;
  1112. X            ASSERT( idp->start <= idp->nextb && idp->nextb <= idp->end ) ;
  1113. X            break ;
  1114. X        
  1115. X        default:
  1116. X            retval = SIO_ERR ;
  1117. X            break ;
  1118. X    }
  1119. X    return( retval ) ;
  1120. X}
  1121. X
  1122. X
  1123. X/*
  1124. X * Flush the buffer associated with the given file descriptor
  1125. X * The special value, SIO_FLUSH_ALL flushes all buffers
  1126. X *
  1127. X * Return value:
  1128. X *            0 :  if fd is SIO_FLUSH_ALL or if the flush is successful
  1129. X *        SIO_ERR: if fd is not SIO_FLUSH_ALL and
  1130. X *                                the flush is unsuccessful
  1131. X *                            or the descriptor is not initialized or it is not 
  1132. X *                                an output descriptor
  1133. X */
  1134. Xint Sflush( fd )
  1135. X    int fd ;
  1136. X{
  1137. X   register __sio_descriptor_t *dp ;
  1138. X   int b_in_buffer ;
  1139. X
  1140. X#ifdef EVENTS
  1141. X    EVENT( fd, EV_SFLUSH ) ;
  1142. X#endif
  1143. X
  1144. X   if ( fd == SIO_FLUSH_ALL )
  1145. X   {
  1146. X      for ( fd = 0, dp = __sio_descriptors ;
  1147. X                fd < N_SIO_DESCRIPTORS ;
  1148. X                dp++, fd++ )
  1149. X         if ( DESCRIPTOR_INITIALIZED( dp ) &&
  1150. X                            dp->stream_type == __SIO_OUTPUT_STREAM )
  1151. X            (void) __sio_writef( ODP( dp ), fd ) ;
  1152. X      return( 0 ) ;
  1153. X   }
  1154. X   else
  1155. X   {
  1156. X      dp = &__sio_descriptors[ fd ] ;
  1157. X
  1158. X        CONTROL_SETUP( dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ;
  1159. X      b_in_buffer = ODP( dp )->nextb - ODP( dp )->start ;
  1160. X      if ( __sio_writef( ODP( dp ), fd ) != b_in_buffer )
  1161. X         return( SIO_ERR ) ;
  1162. X      else
  1163. X         return( 0 ) ;
  1164. X   }
  1165. X}
  1166. X
  1167. X
  1168. X/*
  1169. X * Close the file descriptor. This call is provided because
  1170. X * a file descriptor may be closed and then reopened. There is
  1171. X * no easy way for SIO to identify such a situation, so Sclose
  1172. X * must be used.
  1173. X *
  1174. X * Sclose invokes Sdone which finalizes the buffer.
  1175. X * There is no SIO_CLOSE_ALL value for fd because such a thing
  1176. X * would imply that the program will exit very soon, therefore
  1177. X * the closing of all file descriptors will be done in the kernel
  1178. X * (and the finalization will be done by the finalization function
  1179. X * NOTE: not true if the OS does not support a finalization function)
  1180. X *
  1181. X * There is no need to invoke SETUP; Sdone will do it.
  1182. X */
  1183. Xint Sclose( fd )
  1184. X    int fd ;
  1185. X{
  1186. X#ifdef EVENTS
  1187. X    EVENT( fd, EV_SCLOSE ) ;
  1188. X#endif
  1189. X
  1190. X    if ( __SIO_FD_INITIALIZED( fd ) )
  1191. X        if ( Sdone( fd ) == SIO_ERR )
  1192. X            return( SIO_ERR ) ;
  1193. X    return( close( fd ) ) ;
  1194. X}
  1195. X
  1196. X
  1197. X
  1198. X/*
  1199. X * Tie the file descriptor in_fd to the file descriptor out_fd
  1200. X * This means that whenever a read(2) is done on in_fd, it is
  1201. X * preceded by a write(2) on out_fd.
  1202. X * Why this is nice to have:
  1203. X *     1) When used in filters it maximizes concurrency
  1204. X *        2) When the program prompts the user for something it forces
  1205. X *            the prompt string to be displayed even if it does not
  1206. X *            end with a '\n' (which would cause a flush).
  1207. X * In this implementation, out_fd cannot be a regular file.
  1208. X * This is done to avoid non-block-size write's.
  1209. X * The file descriptors are initialized if that has not been done
  1210. X * already. If any of them is initialized, it must be for the appropriate
  1211. X * stream type (input or output).
  1212. X *
  1213. X * NOTE: the code handles correctly the case when in_fd == out_fd
  1214. X */
  1215. Xint Stie( in_fd, out_fd )
  1216. X    int in_fd, out_fd ;
  1217. X{
  1218. X    struct stat st ;
  1219. X    register __sio_descriptor_t *dp ;
  1220. X    int was_initialized ;
  1221. X    boolean_e failed = NO ;
  1222. X
  1223. X#ifdef EVENTS
  1224. X    EVENT( in_fd, EV_STIE ) ;
  1225. X#endif
  1226. X
  1227. X    /*
  1228. X     * Check if the out_fd is open
  1229. X     */
  1230. X    if ( fstat( out_fd, &st ) == -1 )
  1231. X        return( SIO_ERR ) ;
  1232. X
  1233. X    /*
  1234. X     * If the out_fd refers to a regular file, the request is silently ignored
  1235. X     */
  1236. X    if ( ( st.st_mode & S_IFMT ) == S_IFREG )
  1237. X        return( 0 ) ;
  1238. X    
  1239. X    dp = &__sio_descriptors[ in_fd ] ;
  1240. X    was_initialized = dp->initialized ;        /* remember if it was initialized */
  1241. X    IO_SETUP( in_fd, dp, __SIO_INPUT_STREAM, SIO_ERR ) ;
  1242. X
  1243. X    /*
  1244. X     * Perform manual initialization of out_fd to avoid leaving in_fd
  1245. X     * initialized if the initialization of out_fd fails.
  1246. X     * If out_fd is initialized, check if it is used for output.
  1247. X     * If it is not initialized, initialize it for output.
  1248. X     */
  1249. X    dp = &__sio_descriptors[ out_fd ] ;
  1250. X    if ( DESCRIPTOR_INITIALIZED( dp ) )
  1251. X    {
  1252. X        if ( dp->stream_type != __SIO_OUTPUT_STREAM )
  1253. X        {
  1254. X            failed = YES ;
  1255. X            errno = EBADF ;
  1256. X        }
  1257. X    }
  1258. X    else
  1259. X        if ( __sio_init( dp, out_fd, __SIO_OUTPUT_STREAM ) == SIO_ERR )
  1260. X            failed = YES ;
  1261. X
  1262. X    if ( failed == NO )
  1263. X    {
  1264. X        __SIO_ID( in_fd ).tied_fd = out_fd ;
  1265. X        return( 0 ) ;
  1266. X    }
  1267. X    else
  1268. X    {
  1269. X        /*
  1270. X         * We failed. If we did any initialization, undo it
  1271. X         */
  1272. X        if ( ! was_initialized )
  1273. X        {
  1274. X            int save_errno = errno ;
  1275. X
  1276. X            (void) Sdone( in_fd ) ;
  1277. X            errno = save_errno ;
  1278. X        }
  1279. X        return( SIO_ERR ) ;
  1280. X    }
  1281. X}
  1282. X
  1283. X
  1284. X/*
  1285. X * Untie a file descriptor
  1286. X */
  1287. Xint Suntie( fd )
  1288. X    int fd ;
  1289. X{
  1290. X    register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  1291. X
  1292. X#ifdef EVENTS
  1293. X    EVENT( fd, EV_SUNTIE ) ;
  1294. X#endif
  1295. X
  1296. X    CONTROL_SETUP( dp, __SIO_INPUT_STREAM, SIO_ERR ) ;
  1297. X    
  1298. X    if ( IDP( dp )->tied_fd != SIO_NO_TIED_FD )
  1299. X    {
  1300. X        IDP( dp )->tied_fd = SIO_NO_TIED_FD ;
  1301. X        return( 0 ) ;
  1302. X    }
  1303. X    else
  1304. X    {
  1305. X        errno = EBADF ;
  1306. X        return( SIO_ERR ) ;
  1307. X    }
  1308. X}
  1309. X
  1310. X
  1311. X/*
  1312. X * Changes the type of buffering on the specified descriptor.
  1313. X * As a side-effect, it initializes the descriptor as an output stream.
  1314. X */
  1315. Xint Sbuftype( fd, type )
  1316. X    int fd, type ;
  1317. X{
  1318. X    register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  1319. X
  1320. X#ifdef EVENTS
  1321. X    EVENT( fd, EV_SBUFTYPE ) ;
  1322. X#endif
  1323. X
  1324. X    /*
  1325. X     * Check for a valid type
  1326. X     */
  1327. X    if ( type != SIO_LINEBUF && type != SIO_FULLBUF && type != SIO_NOBUF )
  1328. X    {
  1329. X        errno = EINVAL ;
  1330. X        return( SIO_ERR ) ;
  1331. X    }
  1332. X
  1333. X    IO_SETUP( fd, dp, __SIO_OUTPUT_STREAM, SIO_ERR ) ;
  1334. X    ODP( dp )->buftype = type ;
  1335. X    return( 0 ) ;
  1336. X}
  1337. X
  1338. X
  1339. X#ifndef sio_memscan
  1340. X
  1341. XPRIVATE char *sio_memscan( from, how_many, ch )
  1342. X   char *from ;
  1343. X   int how_many ;
  1344. X   register char ch ;
  1345. X{
  1346. X   register char *p ;
  1347. X   register char *last = from + how_many ;
  1348. X
  1349. X   for ( p = from ; p < last ; p++ )
  1350. X      if ( *p == ch )
  1351. X         return( p ) ;
  1352. X      return( 0 ) ;
  1353. X}
  1354. X
  1355. X#endif    /* sio_memscan */
  1356. X
  1357. X
  1358. X#ifdef NEED_MEMCOPY
  1359. X
  1360. Xvoid __sio_memcopy( from, to, nbytes )
  1361. X   register char *from, *to ;
  1362. X   register int nbytes ;
  1363. X{
  1364. X   while ( nbytes-- )
  1365. X      *to++ = *from++ ;
  1366. X}
  1367. X
  1368. X#endif /* NEED_MEMCOPY */
  1369. X
  1370. X
  1371. END_OF_FILE
  1372. if test 15212 -ne `wc -c <'libs/src/sio/sio.c'`; then
  1373.     echo shar: \"'libs/src/sio/sio.c'\" unpacked with wrong size!
  1374. fi
  1375. # end of 'libs/src/sio/sio.c'
  1376. fi
  1377. echo shar: End of archive 18 \(of 20\).
  1378. cp /dev/null ark18isdone
  1379. MISSING=""
  1380. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
  1381.     if test ! -f ark${I}isdone ; then
  1382.     MISSING="${MISSING} ${I}"
  1383.     fi
  1384. done
  1385. if test "${MISSING}" = "" ; then
  1386.     echo You have unpacked all 20 archives.
  1387.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1388. else
  1389.     echo You still need to unpack the following archives:
  1390.     echo "        " ${MISSING}
  1391. fi
  1392. ##  End of shell archive.
  1393. exit 0
  1394.