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

  1. Newsgroups: comp.sources.unix
  2. From: panos@anchor.cs.colorado.edu (Panos Tsirigotis)
  3. Subject: v27i126: clc - C Libraries Collection, Part20/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 126
  10. Archive-Name: clc/part20
  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 20 (of 20)."
  19. # Contents:  libs/src/sio/siosup.c
  20. # Wrapped by panos@eclipse on Sun Nov 28 14:48:18 1993
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'libs/src/sio/siosup.c' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'libs/src/sio/siosup.c'\"
  24. else
  25. echo shar: Extracting \"'libs/src/sio/siosup.c'\" \(24088 characters\)
  26. sed "s/^X//" >'libs/src/sio/siosup.c' <<'END_OF_FILE'
  27. X/*
  28. X * (c) Copyright 1992, 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: siosup.c,v 8.4 1993/03/17 07:35:24 panos Exp $" ;
  34. X
  35. X#include <sys/types.h>
  36. X#include <sys/stat.h>
  37. X#include <fcntl.h>
  38. X
  39. X#include "impl.h"
  40. X#include "sio.h"
  41. X
  42. X#ifdef EVENTS
  43. X#include "events.h"
  44. X#endif
  45. X
  46. Xchar *malloc() ;
  47. Xchar *realloc() ;
  48. X
  49. X
  50. Xstatic __sio_descriptor_t static_descriptor_array[ N_SIO_DESCRIPTORS ] ;
  51. Xstatic int n_descriptors = N_SIO_DESCRIPTORS ;
  52. X__sio_descriptor_t *__sio_descriptors = static_descriptor_array ;
  53. X
  54. X#ifdef EVENTS
  55. Xstatic events_s static___sio_events[ N_SIO_DESCRIPTORS ] ;
  56. Xevents_s *__sio_events = static___sio_events ;
  57. X#endif
  58. X
  59. X
  60. X/*
  61. X * Code for finalization
  62. X */
  63. X#ifdef HAS_FINALIZATION_FUNCTION
  64. Xstatic int finalizer_installed ;
  65. X
  66. XSIO_DEFINE_FIN( sio_cleanup )
  67. X{
  68. X   (void) Sflush( SIO_FLUSH_ALL ) ;
  69. X}
  70. X#endif /* HAS_FINALIZATION_FUNCTION */
  71. X
  72. X
  73. X
  74. X#ifdef HAS_MMAP
  75. X
  76. X#define CHAR_NULL                ((char *)0)
  77. X
  78. X/*
  79. X * PAGES_MAPPED gives the size of each map unit in pages
  80. X */
  81. X#define PAGES_MAPPED                2
  82. X
  83. Xstatic size_t map_unit_size = 0 ;            /* bytes */
  84. Xstatic size_t page_size = 0 ;                    /* bytes */
  85. X
  86. Xstatic mapd_s static_mapd_array[ N_SIO_DESCRIPTORS ] ;
  87. Xstatic mapd_s *mmap_descriptors = static_mapd_array ;
  88. X
  89. X#define MDP( fd )                ( mmap_descriptors + (fd) )
  90. X
  91. X
  92. X/*
  93. X * NOTES ON MEMORY MAPPING:
  94. X *
  95. X *     1. Memory mapping works only for file descriptors opened for input
  96. X *        2. Mapping an object to a part of the address space where another
  97. X *            object is mapped will cause the old mapping to disappear (i.e. mmap
  98. X *            will not fail)
  99. X *
  100. X * Memory mapping interface:
  101. X *        SIO_MMAP : maps a file into a portion of the address space.
  102. X *        SIO_MUNMAP: unmap a portion of the address space
  103. X *        SIO_MNEED: indicate to the OS that we will need a portion of
  104. X *                         our address space.
  105. X *
  106. X * The map_unit_size variable defines how much of the file is mapped at
  107. X * a time. It is a multiple of the operating system page size. It is
  108. X * not less than SIO_BUFFER_SIZE unless SIO_BUFFER_SIZE is not a
  109. X * multiple of the page size (so the SIO_BUFFER_SIZE overrides
  110. X * PAGES_MAPPED).
  111. X *
  112. X * NOTE: All memory mapping code is in this file only
  113. X */
  114. X
  115. X
  116. X/*
  117. X * Macros used by the memory mapping code
  118. X */
  119. X#define FIRST_TIME( dp )                    ( dp->buf == NULL )
  120. X#define FATAL_ERROR( msg )                    perror( msg ), exit( 1 )
  121. X
  122. X/*
  123. X * Functions to support memory mapping:
  124. X *
  125. X *            try_memory_mapping
  126. X *            buffer_setup
  127. X *            __sio_switch
  128. X *            initial_map
  129. X *            map_unit
  130. X */
  131. X
  132. X/*
  133. X * try_memory_mapping attempts to setup the specified descriptor
  134. X * for memory mapping. 
  135. X * It returns FAILURE if it fails and SUCCESS if it is successful.
  136. X * If HAS_MMAP is not defined, the function is defined to be FAILURE.
  137. X *
  138. X * Sets fields:
  139. X *        memory_mapped:             TRUE or FALSE
  140. X *        
  141. X * Also sets the following fields if memory_mapped is TRUE:
  142. X *    file_offset, file_size, buffer_size
  143. X *
  144. X */
  145. XPRIVATE status_e try_memory_mapping( fd, idp, stp )
  146. X    int fd ;
  147. X    register __sio_id_t *idp ;
  148. X    struct stat *stp ;
  149. X{
  150. X    int access ;
  151. X
  152. X#ifdef EVENTS
  153. X    EVENT( fd, EV_TRY_MEMORY_MAPPING ) ;
  154. X#endif
  155. X
  156. X    /*
  157. X     * Do not try memory mapping if:
  158. X     *        1) The file is not a regular file
  159. X     *        2) The file is a regular file but has zero-length
  160. X     *        3) The file pointer is not positioned at the beginning of the file
  161. X     *        4) The fcntl to obtain the file descriptor flags fails
  162. X     *        5) The access mode is not O_RDONLY or O_RDWR
  163. X     *
  164. X     * The operations are done in this order to avoid the system calls
  165. X     * if possible.
  166. X     */
  167. X    if ( ( ( stp->st_mode & S_IFMT ) != S_IFREG ) ||
  168. X          ( stp->st_size == 0 ) ||
  169. X          ( lseek( fd, (long)0, 1 ) != 0 ) ||
  170. X          ( ( access = fcntl( fd, F_GETFL, 0 ) ) == -1 ) ||
  171. X          ( ( access &= 0x3 ) != O_RDONLY && access != O_RDWR ) )
  172. X    {
  173. X        idp->memory_mapped = FALSE ;
  174. X        return( FAILURE ) ;
  175. X    }
  176. X
  177. X    /*
  178. X     * Determine page_size and map_unit_size.
  179. X     * Note that the code works even if PAGES_MAPPED is 0.
  180. X     */
  181. X    if ( page_size == 0 )
  182. X    {
  183. X        page_size = getpagesize() ;
  184. X        map_unit_size = page_size * PAGES_MAPPED ;
  185. X        if ( map_unit_size < SIO_BUFFER_SIZE )
  186. X            if ( map_unit_size > 0 && SIO_BUFFER_SIZE % map_unit_size == 0 )
  187. X                map_unit_size = SIO_BUFFER_SIZE ;
  188. X            else
  189. X                map_unit_size = page_size ;
  190. X    }
  191. X    
  192. X    MDP(fd)->file_offset = 0 ;
  193. X    MDP(fd)->file_size = stp->st_size ;
  194. X    idp->buffer_size = map_unit_size ;
  195. X    idp->buf = CHAR_NULL ;
  196. X    idp->memory_mapped = TRUE ;
  197. X
  198. X    return( SUCCESS ) ;
  199. X}
  200. X
  201. X
  202. X/*
  203. X * Copy the current_unit to the primary buffer
  204. X *
  205. X * Sets fields: start, end, nextb
  206. X * Also sets the file pointer
  207. X */
  208. XPRIVATE void buffer_setup( idp, fd, mu_cur, mu_next )
  209. X    __sio_id_t *idp ;
  210. X    int fd ;
  211. X    struct map_unit *mu_cur ;
  212. X    struct map_unit *mu_next ;
  213. X{
  214. X    off_t new_offset ;
  215. X
  216. X    sio_memcopy( mu_cur->addr, idp->buf, mu_cur->valid_bytes ) ;
  217. X    idp->start = idp->buf ;
  218. X    idp->end = idp->buf + mu_cur->valid_bytes ;
  219. X    idp->nextb = idp->buf + ( idp->nextb - mu_cur->addr ) ;
  220. X
  221. X    if ( mu_next->addr != CHAR_NULL )
  222. X        new_offset = MDP(fd)->file_offset - mu_next->valid_bytes ;
  223. X    else
  224. X        new_offset = MDP(fd)->file_offset ;
  225. X    (void) lseek( fd, new_offset, 0 ) ;
  226. X}
  227. X
  228. X
  229. X/*
  230. X * Switch from memory mapping to buffered I/O
  231. X * If any mapping has occured, then the current unit is
  232. X * copied into the buffer that is allocated.
  233. X * Any data in the next unit is ignored.
  234. X * We rely on idp->buf to identify the current unit (so it
  235. X * better be equal to the address of one of the units).
  236. X *
  237. X * Sets fields:
  238. X *            start, end, nextb
  239. X */
  240. Xstatus_e __sio_switch( idp, fd )
  241. X    register __sio_id_t *idp ;
  242. X    int fd ;
  243. X{
  244. X    register mapd_s *mdp = MDP( fd ) ;
  245. X    struct map_unit *mu_cur, *mu_next ;
  246. X    unsigned buffer_size = idp->buffer_size ;
  247. X    char *buf_addr = idp->buf ;
  248. X    int first_time = FIRST_TIME( idp ) ;
  249. X    void buffer_setup() ;
  250. X    status_e setup_read_buffer() ;
  251. X
  252. X#ifdef EVENTS
  253. X    EVENT( fd, EV_SIO_SWITCH ) ;
  254. X#endif
  255. X
  256. X    /*
  257. X     * Initialize stream for buffering
  258. X     */
  259. X    if ( setup_read_buffer( idp, buffer_size ) == FAILURE )
  260. X        return( FAILURE ) ;
  261. X
  262. X    if ( ! first_time )
  263. X    {
  264. X        /*
  265. X         * Find current, next unit
  266. X         */
  267. X        if ( buf_addr == mdp->first_unit.addr )
  268. X        {
  269. X            mu_cur = &mdp->first_unit ;
  270. X            mu_next = &mdp->second_unit ;
  271. X        }
  272. X        else
  273. X        {
  274. X            mu_cur = &mdp->second_unit ;
  275. X            mu_next = &mdp->first_unit ;
  276. X        }
  277. X
  278. X        buffer_setup( idp, fd, mu_cur, mu_next ) ;
  279. X        /*
  280. X         * Destroy all mappings
  281. X         */
  282. X        (void) SIO_MUNMAP( mu_cur->addr, mu_cur->mapped_bytes ) ;
  283. X        if ( mu_next->addr != NULL )
  284. X            (void) SIO_MUNMAP( mu_next->addr, mu_next->mapped_bytes ) ;
  285. X    }
  286. X    else
  287. X        idp->start = idp->end = idp->nextb = idp->buf ;
  288. X
  289. X    idp->memory_mapped = FALSE ;
  290. X    return( SUCCESS ) ;
  291. X}
  292. X
  293. X
  294. X/*
  295. X * initial_map does the first memory map on the file descriptor.
  296. X * It attempts to map both units.
  297. X * The mapping always starts at file offset 0.
  298. X *
  299. X * SETS FIELDS:
  300. X *            first_unit.*, second_unit.*
  301. X *            file_offset
  302. X *
  303. X * Returns: 
  304. X *            number of bytes mapped in first_unit
  305. X *    or
  306. X *            0 to indicate that mmap failed.
  307. X */
  308. XPRIVATE int initial_map( mdp, fd )
  309. X    register mapd_s *mdp ;
  310. X    int fd ;
  311. X{
  312. X    register caddr_t addr ;
  313. X    register size_t requested_length = 2 * map_unit_size ;
  314. X    register size_t mapped_length = MIN( mdp->file_size, requested_length ) ;
  315. X    size_t bytes_left ;
  316. X    register size_t bytes_in_unit ;
  317. X
  318. X#ifdef EVENTS
  319. X    EVENT( fd, EV_INITIAL_MAP ) ;
  320. X#endif
  321. X
  322. X    addr = SIO_MMAP( CHAR_NULL, mapped_length, fd, 0 ) ;
  323. X    if ( (int) addr == -1 )
  324. X        return( 0 ) ;
  325. X
  326. X    SIO_MNEED( addr, mapped_length ) ;
  327. X
  328. X    /*
  329. X     * Map as much as possible in the first unit
  330. X     */
  331. X    bytes_in_unit = MIN( mapped_length, map_unit_size ) ;
  332. X    mdp->first_unit.addr             = addr ;
  333. X    mdp->first_unit.mapped_bytes     = bytes_in_unit ;
  334. X    mdp->first_unit.valid_bytes     = bytes_in_unit ;
  335. X
  336. X    /*
  337. X     * If there is more, map it in the second unit.
  338. X     */
  339. X    bytes_left = mapped_length - bytes_in_unit ;
  340. X    if ( bytes_left > 0 )
  341. X    {
  342. X        mdp->second_unit.addr             = addr + bytes_in_unit ;
  343. X        mdp->second_unit.mapped_bytes = bytes_left ;
  344. X        mdp->second_unit.valid_bytes     = bytes_left ;
  345. X    }
  346. X    else
  347. X        mdp->second_unit.addr             = CHAR_NULL ;
  348. X
  349. X    mdp->file_offset = mapped_length ;
  350. X
  351. X    return( mdp->first_unit.valid_bytes ) ;
  352. X}
  353. X
  354. X
  355. X/*
  356. X * ALGORITHM:
  357. X *
  358. X *        if ( there are more bytes in the file )
  359. X *        {
  360. X *            map them at the given unit
  361. X *            update offset
  362. X *            issue SIO_MNEED()
  363. X *        }
  364. X *        else
  365. X *            unmap the unit
  366. X */
  367. XPRIVATE status_e map_unit( mdp, fd, mup )
  368. X    register mapd_s *mdp ;
  369. X    int fd ;
  370. X    register struct map_unit *mup ;
  371. X{
  372. X    register size_t bytes_left = mdp->file_size - mdp->file_offset ;
  373. X    register size_t bytes_to_map = MIN( bytes_left, map_unit_size ) ;
  374. X
  375. X#ifdef EVENTS
  376. X    EVENT( fd, EV_MAP_UNIT ) ;
  377. X#endif
  378. X
  379. X    if ( bytes_to_map > 0 )
  380. X    {
  381. X        if ( (int) SIO_MMAP( mup->addr, bytes_to_map,
  382. X                                                            fd, mdp->file_offset ) == -1 )
  383. X            return( FAILURE ) ;            /* XXX: need to do more ? */
  384. X        
  385. X        mup->valid_bytes = bytes_to_map ;
  386. X        ASSERT( mup->valid_bytes <= mup->mapped_bytes ) ;
  387. X        mdp->file_offset += bytes_to_map ;
  388. X        SIO_MNEED( mup->addr, mup->valid_bytes ) ;
  389. X    }
  390. X    else
  391. X    {
  392. X        (void) SIO_MUNMAP( mup->addr, mup->mapped_bytes ) ;
  393. X        mup->addr = CHAR_NULL ;
  394. X    }
  395. X    return( SUCCESS ) ;
  396. X}
  397. X
  398. X#else
  399. X
  400. X#define try_memory_mapping( x, y, z )                FAILURE
  401. X
  402. X#endif /* HAS_MMAP */
  403. X
  404. X
  405. XPRIVATE status_e setup_read_buffer( idp, buf_size )
  406. X    register __sio_id_t *idp ;
  407. X    unsigned buf_size ;
  408. X{
  409. X    register char *buf ;
  410. X
  411. X    /*
  412. X     * First allocate space for 2 buffers: primary and auxiliary
  413. X     */
  414. X    buf = malloc( buf_size * 2 ) ;
  415. X    if ( buf == NULL )
  416. X        return( FAILURE ) ;
  417. X
  418. X    /*
  419. X     * The descriptor buf field should point to the start of the main buffer
  420. X     */
  421. X    idp->buf = buf + buf_size ;
  422. X    idp->buffer_size = buf_size ;
  423. X    return( SUCCESS ) ;
  424. X}
  425. X
  426. X
  427. XPRIVATE status_e init_input_stream( idp, fd, stp )
  428. X    register __sio_id_t *idp ;
  429. X    int fd ;
  430. X    struct stat *stp ;
  431. X{
  432. X#ifdef EVENTS
  433. X    EVENT( fd, EV_INIT_INPUT_STREAM ) ;
  434. X#endif
  435. X
  436. X    /*
  437. X     * First initialize the fields relevant to buffering: buf, buffer_size
  438. X     */
  439. X    if ( try_memory_mapping( fd, idp, stp ) == FAILURE )
  440. X    {
  441. X        /*
  442. X         * Try to use normal buffering
  443. X         */
  444. X        unsigned buf_size = (unsigned)
  445. X                            ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ;
  446. X        
  447. X        if ( setup_read_buffer( idp, buf_size ) == FAILURE )
  448. X            return( FAILURE ) ;
  449. X    }
  450. X
  451. X     /*
  452. X     * Initialize remaining descriptor fields
  453. X     */
  454. X    idp->max_line_length = 2 * idp->buffer_size - 1 ;
  455. X    idp->start = idp->end = idp->nextb = idp->buf ;
  456. X    idp->tied_fd = SIO_NO_TIED_FD ;
  457. X
  458. X    return( SUCCESS ) ;
  459. X}
  460. X
  461. X
  462. XPRIVATE status_e init_output_stream( odp, fd, stp )
  463. X    register __sio_od_t *odp ;
  464. X    int fd ;
  465. X    struct stat *stp ;
  466. X{
  467. X    register unsigned buf_size ;
  468. X    register char *buf ;
  469. X
  470. X#ifdef EVENTS
  471. X    EVENT( fd, EV_INIT_OUTPUT_STREAM ) ;
  472. X#endif
  473. X
  474. X    buf_size = (unsigned)
  475. X                        ( stp->st_blksize ? stp->st_blksize : SIO_BUFFER_SIZE ) ;
  476. X    buf = malloc( buf_size ) ;
  477. X    if ( buf == NULL )
  478. X        return( FAILURE ) ;
  479. X    
  480. X    /*
  481. X     * Initialize buffering fields
  482. X     */
  483. X    odp->buf = buf ;
  484. X    odp->buffer_size = buf_size ;
  485. X    odp->buf_end = odp->buf + buf_size ;
  486. X
  487. X    /*
  488. X     * Initialize remaining fields
  489. X     */
  490. X    odp->start = odp->nextb = odp->buf ;
  491. X    if ( isatty( fd ) )
  492. X        odp->buftype = SIO_LINEBUF ;
  493. X
  494. X    if ( fd == 2 )
  495. X        odp->buftype = SIO_NOBUF ;
  496. X
  497. X    return( SUCCESS ) ;
  498. X}
  499. X
  500. X
  501. X#ifndef HAS_ISATTY
  502. X
  503. X#ifdef HAS_SYSVTTY
  504. X
  505. X#include <termio.h>
  506. X
  507. XPRIVATE int isatty( fd )
  508. X    int fd ;
  509. X{
  510. X    struct termio t ;
  511. X
  512. X    if ( ioctl( fd, TCGETA, &t ) == -1 && errno == ENOTTY )
  513. X        return( FALSE ) ;
  514. X    else
  515. X        return( TRUE ) ;
  516. X}
  517. X#endif    /* HAS_SYSVTTY */
  518. X
  519. X#ifdef HAS_BSDTTY
  520. X
  521. X#include <sgtty.h>
  522. X
  523. XPRIVATE int isatty( fd )
  524. X    int fd ;
  525. X{
  526. X    struct sgttyb s ;
  527. X
  528. X    if ( ioctl( fd, TIOCGETP, &s ) == -1 && errno == ENOTTY )
  529. X        return( FALSE ) ;
  530. X    else
  531. X        return( TRUE ) ;
  532. X}
  533. X#endif    /* HAS_BSDTTY */
  534. X
  535. X#endif    /* ! HAS_ISATTY */
  536. X
  537. X
  538. X/*
  539. X * Initialize stream I/O for a file descriptor.
  540. X *
  541. X * Arguments:
  542. X *        fd:                file descriptor
  543. X *        dp:                descriptor pointer
  544. X *        stream_type:     either __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM
  545. X *
  546. X * Returns
  547. X *        0             if successful
  548. X *      SIO_ERR    if the file descriptor is not valid (sets errno)
  549. X *   exits        if stream_type is not __SIO_INPUT_STREAM or __SIO_OUTPUT_STREAM
  550. X */
  551. Xint __sio_init( dp, fd, stream_type )
  552. X    register __sio_descriptor_t *dp ;
  553. X    int fd ;
  554. X    enum __sio_stream stream_type ;
  555. X{
  556. X    struct stat st ;
  557. X    void terminate() ;
  558. X
  559. X#ifdef EVENTS
  560. X    EVENT( fd, EV_SIO_INIT ) ;
  561. X#endif
  562. X
  563. X    if ( fstat( fd, &st ) == -1 )
  564. X        return( SIO_ERR ) ;
  565. X
  566. X    switch ( stream_type )
  567. X    {
  568. X        case __SIO_INPUT_STREAM:
  569. X            if ( init_input_stream( IDP( dp ), fd, &st ) == FAILURE )
  570. X                return( SIO_ERR ) ;
  571. X            break ;
  572. X
  573. X        case __SIO_OUTPUT_STREAM:
  574. X            if ( init_output_stream( ODP( dp ), fd, &st ) == FAILURE )
  575. X                return( SIO_ERR ) ;
  576. X            break ;
  577. X            
  578. X        default:
  579. X            terminate( "SIO __sio_init: bad stream type (internal error).\n" ) ;
  580. X            /* NOTREACHED */
  581. X    }
  582. X    dp->stream_type = stream_type ;
  583. X    dp->initialized = TRUE ;
  584. X
  585. X#ifdef HAS_FINALIZATION_FUNCTION
  586. X    if ( ! finalizer_installed )
  587. X    {
  588. X        if ( ! SIO_FINALIZE( sio_cleanup ) )
  589. X        {
  590. X            char *s = "SIO __sio_init: finalizer installation failed\n" ;
  591. X
  592. X            (void) write( 2, s, strlen( s ) ) ;
  593. X        }
  594. X        else
  595. X            finalizer_installed = TRUE ;
  596. X    }
  597. X#endif /* HAS_FINALIZATION_FUNCTION */
  598. X
  599. X    return( 0 ) ;
  600. X}
  601. X
  602. X
  603. X/*
  604. X * __sio_writef writes the data in the buffer to the file descriptor.
  605. X *
  606. X * It tries to write as much data as possible until either all data
  607. X * are written or an error occurs. EINTR is the only error that is
  608. X * ignored.
  609. X * In case an error occurs but some data were written, that number
  610. X * is returned instead of SIO_ERR.
  611. X *
  612. X * Fields modified:
  613. X *        When successful: start, nextb
  614. X *        When not successful: start
  615. X *
  616. X * Return value:
  617. X *        Number of bytes written
  618. X *        SIO_ERR, if write(2) fails and no data were written
  619. X */ 
  620. Xint __sio_writef( odp, fd )
  621. X    register __sio_od_t *odp ;
  622. X    int fd ;
  623. X{
  624. X    register int b_in_buffer ;
  625. X    register int cc_total = 0 ;
  626. X
  627. X#ifdef EVENTS
  628. X    EVENT( fd, EV_SIO_WRITEF ) ;
  629. X#endif
  630. X
  631. X    /*
  632. X     * Make sure we don't exceed the buffer limits
  633. X     *    Maybe we should log this ?            XXX
  634. X     */
  635. X    if ( odp->nextb > odp->buf_end )
  636. X        odp->nextb = odp->buf_end ;
  637. X
  638. X    b_in_buffer = odp->nextb - odp->start ;
  639. X
  640. X    if ( b_in_buffer == 0 )
  641. X        return( 0 ) ;
  642. X    
  643. X    for ( ;; )
  644. X    {
  645. X        register int cc ;
  646. X
  647. X        cc = write( fd, odp->start, b_in_buffer ) ;
  648. X        if ( cc == b_in_buffer )
  649. X        {
  650. X            odp->start = odp->nextb = odp->buf ;
  651. X            cc_total += cc ;
  652. X            break ;
  653. X        }
  654. X        else if ( cc == -1 )
  655. X        {
  656. X            if ( errno == EINTR )
  657. X                continue ;
  658. X            else
  659. X                /*
  660. X                 * If some bytes were written, return that number, otherwise
  661. X                 * return SIO_ERR
  662. X                 */
  663. X                return( ( cc_total != 0 ) ? cc_total : SIO_ERR ) ;
  664. X        }
  665. X        else            /* some bytes were written */
  666. X        {
  667. X            odp->start += cc ;            /* advance start of buffer */
  668. X            b_in_buffer -= cc ;            /* decrease number bytes left in buffer */
  669. X            cc_total += cc ;                /* count the bytes that were written */
  670. X        }
  671. X    }
  672. X    return( cc_total ) ;
  673. X}
  674. X
  675. X
  676. X/*
  677. X * __sio_readf reads data from the file descriptor into the buffer.
  678. X * Unlike __sio_writef it does NOT try to read as much data as will fit
  679. X * in the buffer. It ignores EINTR.
  680. X *
  681. X * Returns: # of bytes read or SIO_ERR
  682. X *
  683. X * Fields set:
  684. X *         If it does not return SIO_ERR, it sets start, nextb, end
  685. X *            If it returns SIO_ERR, it does not change anything
  686. X */
  687. Xint __sio_readf( idp, fd )
  688. X    register __sio_id_t *idp ;
  689. X    int fd ;
  690. X{
  691. X    register int cc ;
  692. X
  693. X#ifdef EVENTS
  694. X    EVENT( fd, EV_SIO_READF ) ;
  695. X#endif
  696. X
  697. X    /*
  698. X     * First check for a tied fd and flush the stream if necessary
  699. X     *
  700. X     *         XXX    the return value of __sio_writef is not checked.
  701. X     *                    Is that right ?
  702. X     */
  703. X    if ( idp->tied_fd != SIO_NO_TIED_FD )
  704. X        (void) __sio_writef( &__SIO_OD( idp->tied_fd ), idp->tied_fd ) ;
  705. X
  706. X#ifdef HAS_MMAP
  707. X    if ( idp->memory_mapped )
  708. X    {
  709. X        register mapd_s *mdp = MDP( fd ) ;
  710. X
  711. X        /*
  712. X         * The functions initial_map and map_unit may fail.
  713. X         * In either case, we switch to buffered I/O.
  714. X         * If initial_map fails, we have read no data, so we
  715. X         * should perform a read(2).
  716. X         * If map_unit fails (for the next unit), we still have
  717. X         * the data in the current unit, so we can return.
  718. X         */
  719. X        if ( FIRST_TIME( idp ) )
  720. X        {
  721. X            cc = initial_map( mdp, fd ) ;
  722. X            if ( cc > 0 )
  723. X                idp->buf = mdp->first_unit.addr ;
  724. X            else
  725. X            {
  726. X                if ( __sio_switch( idp, fd ) == FAILURE )
  727. X                    return( SIO_ERR ) ;
  728. X                cc = -1 ;
  729. X            }
  730. X        }
  731. X        else
  732. X        {
  733. X            register struct map_unit *mu_cur, *mu_next ;
  734. X
  735. X            if ( idp->buf == mdp->first_unit.addr )
  736. X            {
  737. X                mu_cur = &mdp->first_unit ;
  738. X                mu_next = &mdp->second_unit ;
  739. X            }
  740. X            else
  741. X            {
  742. X                mu_cur = &mdp->second_unit ;
  743. X                mu_next = &mdp->first_unit ;
  744. X            }
  745. X
  746. X            if ( mu_next->addr != NULL )
  747. X            {
  748. X                idp->buf = mu_next->addr ;
  749. X                cc = mu_next->valid_bytes ;
  750. X                /*
  751. X                 * XXX:  Here we may return SIO_ERR even though there
  752. X                 *           are data in the current unit because the switch
  753. X                 *           fails (possibly because malloc failed).
  754. X                 */
  755. X                if ( map_unit( mdp, fd, mu_cur ) == FAILURE &&
  756. X                                        __sio_switch( idp, fd ) == FAILURE )
  757. X                    return( SIO_ERR ) ;
  758. X            }
  759. X            else
  760. X                cc = 0 ;
  761. X        }
  762. X        if ( cc >= 0 )
  763. X        {
  764. X            idp->end = idp->buf + cc ;
  765. X            idp->start = idp->nextb = idp->buf ;
  766. X            return( cc ) ;
  767. X        }
  768. X    }
  769. X#endif /* HAS_MMAP */
  770. X
  771. X    for ( ;; )
  772. X    {
  773. X        cc = read( fd, idp->buf, (int) idp->buffer_size ) ;
  774. X        if ( cc == -1 )
  775. X            if ( errno == EINTR )
  776. X                continue ;
  777. X            else
  778. X                return( SIO_ERR ) ;
  779. X        else
  780. X            break ;
  781. X    }
  782. X
  783. X    idp->end = idp->buf + cc ;
  784. X    idp->start = idp->nextb = idp->buf ;
  785. X    return( cc ) ;
  786. X}
  787. X
  788. X
  789. X/*
  790. X * __sio_extend_buffer is used by Srdline to extend the buffer
  791. X * If successful, it returns the number of bytes that have been read.
  792. X * If it fails (because of end-of-file or I/O error), it returns 0 or -1.
  793. X *
  794. X * Fields modified:
  795. X *     idp->start points to the start of the buffer area (which is in the
  796. X *     auxiliary buffer)
  797. X *        Also, if successful, idp->nextb is set to idp->buf, idp->end is modified.
  798. X */
  799. Xint __sio_extend_buffer( idp, fd, b_left )
  800. X    register __sio_id_t *idp ;
  801. X    int fd ;
  802. X    register int b_left ;
  803. X{
  804. X    register int b_read ;
  805. X
  806. X#ifdef EVENTS
  807. X    EVENT( fd, EV_SIO_EXTEND_BUFFER ) ;
  808. X#endif
  809. X
  810. X    /*
  811. X     * copy to auxiliary buffer
  812. X     */
  813. X    if ( b_left )
  814. X        sio_memcopy( idp->nextb, idp->buf - b_left, b_left ) ;
  815. X    b_read = __sio_readf( idp, fd ) ;
  816. X    idp->start = idp->buf - b_left ;
  817. X    return( b_read ) ;
  818. X}
  819. X
  820. X
  821. X/*
  822. X * __sio_more tries to read more data from the given file descriptor iff
  823. X * there is free space in the buffer.
  824. X * __sio_more is used only by Srdline and only AFTER __sio_extend_buffer
  825. X * has been called. This implies that 
  826. X *        a) this is not a memory mapped file
  827. X *        b) __sio_readf has been called (so we don't need to check for tied fd's
  828. X *
  829. X * Fields modified (only if successful):
  830. X *            idp->end
  831. X *
  832. X * Return value: the number of bytes read.
  833. X */
  834. Xint __sio_more( idp, fd )
  835. X    register __sio_id_t *idp ;
  836. X    int fd ;
  837. X{
  838. X    register int b_left = &idp->buf[ idp->buffer_size ] - idp->end ;
  839. X    register int cc ;
  840. X
  841. X#ifdef EVENTS
  842. X    EVENT( fd, EV_SIO_MORE ) ;
  843. X#endif
  844. X
  845. X    if ( b_left <= 0 )
  846. X        return( 0 ) ;
  847. X    
  848. X    for ( ;; )
  849. X    {
  850. X        cc = read( fd, idp->end, b_left ) ;
  851. X        if ( cc >= 0 )
  852. X        {
  853. X            idp->end += cc ;
  854. X            return( cc ) ;
  855. X        }
  856. X        else
  857. X            if ( errno == EINTR )
  858. X                continue ;
  859. X            else
  860. X                return( SIO_ERR ) ;
  861. X    }
  862. X}
  863. X
  864. X
  865. X/*
  866. X * Finalize a buffer by unmapping the file or freeing the malloc'ed memory
  867. X */
  868. Xint Sdone( fd )
  869. X    int fd ;
  870. X{
  871. X    register __sio_descriptor_t *dp = &__sio_descriptors[ fd ] ;
  872. X
  873. X#ifdef EVENTS
  874. X    EVENT( fd, EV_SDONE ) ;
  875. X#endif
  876. X
  877. X    if ( ! DESCRIPTOR_INITIALIZED( dp ) )
  878. X    {
  879. X        errno = EBADF ;
  880. X        return( SIO_ERR ) ;
  881. X    }
  882. X
  883. X    switch ( dp->stream_type )
  884. X    {
  885. X        case __SIO_INPUT_STREAM:
  886. X            {
  887. X                register __sio_id_t *idp = IDP( dp ) ;
  888. X
  889. X#ifdef HAS_MMAP
  890. X                if ( idp->memory_mapped )
  891. X                {
  892. X                    register mapd_s *mdp = MDP( fd ) ;
  893. X
  894. X                    if ( mdp->first_unit.addr != CHAR_NULL )
  895. X                        (void) SIO_MUNMAP( mdp->first_unit.addr,
  896. X                                                        mdp->first_unit.mapped_bytes ) ;
  897. X                    if ( mdp->second_unit.addr != CHAR_NULL )
  898. X                        (void) SIO_MUNMAP( mdp->second_unit.addr,
  899. X                                                        mdp->second_unit.mapped_bytes ) ;
  900. X                    idp->memory_mapped = FALSE ;
  901. X                }
  902. X                else
  903. X#endif    /* HAS_MMAP */
  904. X                    free( idp->buf - idp->buffer_size ) ;
  905. X                    idp->nextb = idp->end = NULL ;
  906. X            }
  907. X            break ;
  908. X        
  909. X        case __SIO_OUTPUT_STREAM:
  910. X            {
  911. X                register __sio_od_t *odp = ODP( dp ) ;
  912. X
  913. X                if ( Sflush( fd ) == SIO_ERR )
  914. X                    return( SIO_ERR ) ;
  915. X                free( odp->buf ) ;
  916. X                odp->nextb = odp->buf_end = NULL ;
  917. X            }
  918. X            break ;
  919. X        
  920. X        default:
  921. X            terminate( "SIO Sdone: bad stream type\n" ) ;
  922. X    }
  923. X
  924. X    dp->initialized = FALSE ;
  925. X    return( 0 ) ;
  926. X}
  927. X
  928. X
  929. XPRIVATE char *expand( area, old_size, new_size, is_static )
  930. X    char *area ;
  931. X    unsigned old_size, new_size ;
  932. X    int is_static ;
  933. X{
  934. X    char *new_area ;
  935. X
  936. X    if ( is_static )
  937. X    {
  938. X        if ( ( new_area = malloc( new_size ) ) == NULL )
  939. X            return( NULL ) ;
  940. X        sio_memcopy( area, new_area, old_size ) ;
  941. X    }
  942. X    else
  943. X        if ( ( new_area = realloc( area, new_size ) ) == NULL )
  944. X            return( NULL ) ;
  945. X    return( new_area ) ;
  946. X}
  947. X
  948. X
  949. X#include <sys/time.h>
  950. X#include <sys/resource.h>
  951. X
  952. XPRIVATE int get_fd_limit()
  953. X{
  954. X#ifdef RLIMIT_NOFILE
  955. X
  956. X    struct rlimit rl ;
  957. X
  958. X    (void) getrlimit( RLIMIT_NOFILE, &rl ) ;
  959. X    return( rl.rlim_cur ) ;
  960. X
  961. X#else
  962. X
  963. X    return( N_SIO_DESCRIPTORS ) ;
  964. X
  965. X#endif
  966. X}
  967. X
  968. X/*
  969. X * Expand the descriptor array (and if we use memory mapping the
  970. X * memory mapping descriptors). We first expand the memory mapping
  971. X * descriptors.
  972. X * There is no problem if the expansion of the SIO descriptors fails
  973. X * (i.e. there is no need to undo anything).
  974. X */
  975. Xint Smorefds()
  976. X{
  977. X    char *p ;
  978. X    int is_static ;
  979. X    unsigned new_size, old_size ;
  980. X    int n_fds = get_fd_limit() ;
  981. X
  982. X    if ( n_fds <= n_descriptors )
  983. X        return( 0 ) ;
  984. X
  985. X#ifdef EVENTS
  986. X    old_size = n_descriptors * sizeof( events_s ) ;
  987. X    new_size = n_fds * sizeof( events_s ) ;
  988. X    is_static = ( __sio_events == static___sio_events ) ;
  989. X    p = expand( (char *)__sio_events, old_size, new_size, is_static ) ;
  990. X    if ( p == NULL )
  991. X        return( SIO_ERR ) ;
  992. X    __sio_events = (events_s *) p ;
  993. X
  994. X    /*
  995. X     * Clear the codes field of the extra events structs.
  996. X     * We have to do this because a non-null codes field implies that
  997. X     * events recording is on for that fd
  998. X     */
  999. X    {
  1000. X        int i ;
  1001. X
  1002. X        for ( i = n_descriptors ; i < n_fds ; i++ )
  1003. X            __sio_events[i].codes = NULL ;
  1004. X    }
  1005. X#endif    /* EVENTS */
  1006. X
  1007. X#ifdef HAS_MMAP
  1008. X    old_size = n_descriptors * sizeof( mapd_s ) ;
  1009. X    new_size = n_fds * sizeof( mapd_s ) ;
  1010. X    is_static = ( mmap_descriptors == static_mapd_array ) ;
  1011. X    p = expand( (char *)mmap_descriptors, old_size, new_size, is_static ) ;
  1012. X    if ( p == NULL )
  1013. X        return( SIO_ERR ) ;
  1014. X    mmap_descriptors = (mapd_s *) p ;
  1015. X#endif    /* HAS_MMAP */
  1016. X    
  1017. X    old_size = n_descriptors * sizeof( __sio_descriptor_t ) ;
  1018. X    new_size = n_fds * sizeof( __sio_descriptor_t ) ;
  1019. X    is_static =  ( __sio_descriptors == static_descriptor_array ) ;
  1020. X    p = expand( (char *)__sio_descriptors, old_size, new_size, is_static ) ;
  1021. X    if ( p == NULL )
  1022. X        return( SIO_ERR ) ;
  1023. X    __sio_descriptors = (__sio_descriptor_t *) p ;
  1024. X
  1025. X    n_descriptors = n_fds ;
  1026. X    return( 0 ) ;
  1027. X}
  1028. X
  1029. X
  1030. X#ifdef EVENTS
  1031. X
  1032. X/*
  1033. X * Enable recording of events for the specified file descriptor
  1034. X */
  1035. Xint __sio_enable_events( fd )
  1036. X    int fd ;
  1037. X{
  1038. X    char *p = malloc( EVENT_ENTRIES * sizeof( short ) ) ;
  1039. X
  1040. X    if ( p == NULL )
  1041. X        return( SIO_ERR ) ;
  1042. X
  1043. X    __sio_events[ fd ].codes = (short *) p ;
  1044. X    return( 0 ) ;
  1045. X}
  1046. X
  1047. X
  1048. X/*
  1049. X * Disable recording of events for the specified file descriptor
  1050. X */
  1051. Xvoid __sio_disable_events( fd )
  1052. X    int fd ;
  1053. X{
  1054. X    if ( __sio_events[ fd ].codes != NULL )
  1055. X    {
  1056. X        free( (char *) __sio_events[ fd ].codes ) ;
  1057. X        __sio_events[ fd ].codes = NULL ;
  1058. X    }
  1059. X}
  1060. X
  1061. X
  1062. X/*
  1063. X * Move stored events to buf
  1064. X */
  1065. Xint __sio_get_events( fd, buf, size )
  1066. X    int fd ;
  1067. X    char *buf ;
  1068. X    int size ;
  1069. X{
  1070. X    events_s *evp = &__sio_events[ fd ] ;
  1071. X    int bufentries ;
  1072. X    int range1, range2 ;
  1073. X    int diff ;
  1074. X    char *p ;
  1075. X    int cc ;
  1076. X    int cc_total ;
  1077. X    int move_entries ;
  1078. X
  1079. X    if ( evp->codes == NULL )
  1080. X        return( 0 ) ;
  1081. X    
  1082. X    diff = evp->next - evp->start ;
  1083. X    if ( diff == 0 )
  1084. X        return( 0 ) ;
  1085. X
  1086. X    if ( diff > 0 )
  1087. X    {
  1088. X        range1 = diff ;
  1089. X        range2 = 0 ;
  1090. X    }
  1091. X    else
  1092. X    {
  1093. X        range1 = EVENT_ENTRIES - evp->start ;
  1094. X        range2 = evp->next ;
  1095. X    }
  1096. X
  1097. X    bufentries = size / sizeof( short ) ;
  1098. X    p = buf ;
  1099. X    cc_total = 0 ;
  1100. X
  1101. X    move_entries = MIN( range1, bufentries ) ;
  1102. X    cc = move_entries * sizeof( short ) ;
  1103. X    sio_memcopy( (char *) &evp->codes[ evp->start ], p, cc ) ;
  1104. X    cc_total += cc ;
  1105. X    p += cc ;
  1106. X    bufentries -= range1 ;
  1107. X    ADD( evp->start, move_entries ) ;
  1108. X
  1109. X    if ( bufentries == 0 || range2 == 0 )
  1110. X        return( cc_total ) ;
  1111. X
  1112. X    move_entries = MIN( range2, bufentries ) ;
  1113. X    cc = move_entries * sizeof( short ) ;
  1114. X    sio_memcopy(  (char *) &evp->codes[ evp->start ], p, cc ) ;
  1115. X    cc_total += cc ;
  1116. X    ADD( evp->start, move_entries ) ;
  1117. X
  1118. X    return( cc_total ) ;
  1119. X}
  1120. X
  1121. X#endif     /* EVENTS */
  1122. X
  1123. X
  1124. X/*
  1125. X * Simple function that prints the string s at stderr and then calls
  1126. X * exit
  1127. X */
  1128. XPRIVATE void terminate( s )
  1129. X    char *s ;
  1130. X{
  1131. X    (void) write( 2, s, strlen( s ) ) ;
  1132. X    (void) abort() ;
  1133. X    exit( 1 ) ;                /* in case abort fails */
  1134. X}
  1135. X
  1136. END_OF_FILE
  1137. if test 24088 -ne `wc -c <'libs/src/sio/siosup.c'`; then
  1138.     echo shar: \"'libs/src/sio/siosup.c'\" unpacked with wrong size!
  1139. fi
  1140. # end of 'libs/src/sio/siosup.c'
  1141. fi
  1142. echo shar: End of archive 20 \(of 20\).
  1143. cp /dev/null ark20isdone
  1144. MISSING=""
  1145. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 ; do
  1146.     if test ! -f ark${I}isdone ; then
  1147.     MISSING="${MISSING} ${I}"
  1148.     fi
  1149. done
  1150. if test "${MISSING}" = "" ; then
  1151.     echo You have unpacked all 20 archives.
  1152.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1153. else
  1154.     echo You still need to unpack the following archives:
  1155.     echo "        " ${MISSING}
  1156. fi
  1157. ##  End of shell archive.
  1158. exit 0
  1159.