home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / software / unix / saoimage / sao1_07.tar / ctrldisk.c < prev    next >
C/C++ Source or Header  |  1990-06-10  |  14KB  |  491 lines

  1. #ifndef lint
  2. static char SccsId[] = "%W%  %G%";
  3. #endif
  4.  
  5. /* Module:    ctrldisk.c (Control Disk Access)
  6.  * Purpose:    Open, close, read, and write disk files and streams.
  7.  *        Centralized to facilitate selecting system specific code.
  8.  * Subroutine:    open_disk()        returns: int
  9.  * Subroutine:    fcntl_disk()        returns: void
  10.  * Subroutine:    flush_disk()        returns: void
  11.  * Subroutine:    lseek_disk()        returns: int
  12.  * Subroutine:    read_disk()        returns: int
  13.  * Subroutine:    write_disk()        returns: int
  14.  * Subroutine:    close_disk()        returns: void
  15.  * UNIX calls:    open(), fcntl(), lseek(), read(), write(), close()
  16.  * Copyright:    1989 Smithsonian Astrophysical Observatory
  17.  *        You may do anything you like with this file except remove
  18.  *        this copyright.  The Smithsonian Astrophysical Observatory
  19.  *        makes no representations about the suitability of this
  20.  *        software for any purpose.  It is provided "as is" without
  21.  *        express or implied warranty.
  22.  * Modified:    {0} Michael VanHilst    initial version          6 Oct 1989
  23.  *        {1} Jay Travisano (STScI)  VMS changes           10 Nov 1989
  24.  *        {n} <who> -- <does what> -- <when>
  25.  */
  26.  
  27. #ifndef VMS
  28.  
  29. #include <stdio.h>        /* define stderr, FILE, NULL, etc */
  30. #include <sys/file.h>        /* define open */
  31. #include <fcntl.h>        /* define fcntl */
  32.  
  33. /*
  34.  * Subroutine:    open_disk
  35.  * Returns:    File descriptor of open file (suitable for read())
  36.  */
  37. int open_disk ( filename, write_flag, no_block )
  38.      char *filename;
  39.      int write_flag;    /* i: 1=WriteOnly, 0=ReadWrite, -1=ReadOnly */
  40.      int no_block;    /* i: flag to set non-blocking flag */
  41. {
  42.   int flags;
  43.   int fd;
  44.  
  45.   if( write_flag > 0 ) {
  46.     flags = O_WRONLY;
  47.     if( write_flag > 1 )
  48.       /* create file if it doesn't exist, else condition causes error */
  49.       flags |= O_CREAT;
  50.   } else {
  51.     if( write_flag < 0 )
  52.       flags = O_RDONLY;
  53.     else
  54.       flags = O_RDWR;
  55.   }
  56.   if( no_block )
  57.     flags |= O_NDELAY;
  58.   if( (fd = open(filename, flags, 0)) == -1 ) {
  59.     perror("open error");
  60.     (void)fprintf(stderr, "ERROR: unable to open %s\n", filename);
  61.     (void)fflush(stderr);
  62.   }
  63.   return( fd );
  64. }
  65.  
  66. /*
  67.  * Subroutine:    fcntl_disk
  68.  * Purpose:    Change an open file's flags, check for errors
  69.  */
  70. void fcntl_disk ( fd, write_flag, no_block, filename )
  71.      int fd;        /* i: already open file descriptor */
  72.      int write_flag;    /* i: 1=WriteOnly, 0=ReadWrite, -1=ReadOnly */
  73.      int no_block;    /* i: include non-blocking flag */
  74.      char *filename;    /* [i]: name of file being accessed */
  75. {
  76.   int flags;
  77.  
  78.   if( write_flag > 0 ) {
  79.     flags = O_WRONLY;
  80.   } else {
  81.     if( write_flag < 0 )
  82.       flags = O_RDWR;
  83.     else
  84.       flags = O_RDONLY;
  85.   }
  86.   if( no_block )
  87.     flags |= O_NDELAY;
  88.   if( fcntl(fd, F_SETFL, flags) == -1) {
  89.     perror("fcntl error");
  90.     if( filename != NULL ) {
  91.       (void)fprintf(stderr, "Error changing flags on %s\n", filename);
  92.       (void)fflush(stderr);
  93.     }
  94.   }
  95. }
  96.  
  97. /*
  98.  * Subroutine:    flush_disk
  99.  * Purpose:    Read to functional end of file (useful with dynamic IO)
  100.  */
  101. void flush_disk ( fd, filename )
  102.      int fd;
  103.      char *filename;
  104. {
  105.   int flags, tflags;
  106.   int blocking;
  107.   int bytes, total;
  108.   char buf[4096];
  109.  
  110.   /* get status of device */
  111.   if( (flags = fcntl(fd, F_GETFL, 0)) == -1 ) {
  112.     (void)fprintf(stderr, "Error determining flag status on: %s\n", filename);
  113.     perror("fcntl error");
  114.   }
  115.   /* clear blocking if device would block on read */
  116.   if( (flags & O_NDELAY) == 0 ) {
  117.     blocking = 1;
  118.     tflags = flags & (~O_NDELAY);
  119.     if( fcntl(fd, F_SETFL, tflags) == -1) {
  120.       (void)fprintf(stderr,
  121.             "Error attempting to clear blocking on %s\n", filename);
  122.       perror("fcntl error");
  123.       return;
  124.     }
  125.   }
  126.   total = 0;
  127.   while( (bytes = read(fd, buf, 4096)) > 0 )
  128.     total += bytes;
  129. #ifdef DEBUG
  130.   if( bytes < 0 ) {
  131.     /* though non-blocking, some OS return "Operation would block" error */
  132.     (void)fprintf(stderr, "Error attempting to flush %s\n", filename);
  133.     perror("read error");
  134.   }
  135.   if( total > 0 )
  136.     (void)fprintf(stderr, "Flushed %d bytes from pipe\n", total);
  137. #endif
  138.   /* restore device to oriiginal status if needed */
  139.   if( blocking ) {
  140.     if( fcntl(fd, F_SETFL, flags) == -1 ) {
  141.       (void)fprintf(stderr,
  142.             "Error attempting to restore blocking on %s\n", filename);
  143.       perror("fcntl");
  144.       return;
  145.     }
  146.   }
  147. }
  148.  
  149. /*
  150.  * Subroutine:    lseek_disk
  151.  * Purpose:    Skip into a disk file before reading, check for errors
  152.  */
  153. int lseek_disk ( fd, nbytes, filename )
  154.      int fd;
  155.      int nbytes;
  156.      char *filename;        /* [i]: name of file being accessed */
  157. {
  158.   long lseek();            /* type not declared in <sys/file.h> */
  159.  
  160.   if( lseek(fd, (long)nbytes, L_SET) < 0 ) {
  161.     perror("lseek");
  162.     (void)fprintf(stderr, "Can't lseek %d bytes", nbytes);
  163.     if( filename != NULL )
  164.       (void)fprintf(stderr, "into file %s\n", filename);
  165.     else
  166.       (void)fprintf(stderr, "\n");
  167.     (void)fflush(stderr);
  168.     return( -1 );
  169.   }
  170.   return( 0 );
  171. }
  172.  
  173. /*
  174.  * Subroutine:    read_disk
  175.  * Purpose:    Read bytes from a disk file, check for errors
  176.  * Returns:    Number of bytes read, or error flag (-1)
  177.  * Note:    If report_error is 0, reading fewer than nbytes
  178.  *        is not treated as an error.
  179.  * Note:    BSD4.3 interrupts reads on any signal.  Thus reads may
  180.  *        be broken into (hopefully consecutive) pieces.
  181.  */
  182. int read_disk ( fd, buf, nbytes, report_error, filename, detail )
  183.      int fd;
  184.      char *buf;            /* i: buffer to receive read data */
  185.      int nbytes;        /* i: number of bytes expected */
  186.      int report_error;        /* i: report under-count read */
  187.      char *filename;        /* [i]: name of file being read */
  188.      char *detail;        /* [i]: "data", "header", etc */
  189. {
  190.   int got_this_read, got_so_far, left_to_get;
  191.   int zero = 0;    /* Count of times with 0 bytes */
  192.  
  193.   for( got_so_far = 0; got_so_far < nbytes; got_so_far += got_this_read ) {
  194.     left_to_get = nbytes - got_so_far;
  195.     if( (got_this_read = read(fd, &(buf[got_so_far]), left_to_get) )
  196.         != left_to_get ) {
  197.       if( (got_this_read <= 0) &&
  198.       ((got_this_read < 0) || (++zero > 3)) ) {
  199.     /* Unfortunately, we can't distinguish between a non-blocking ..  *
  200.      *  connection, and a read that was interrupted at the start. ... *
  201.      *  We assume the former is more likely and dangerous.          *
  202.      * Lest we fall into an endless loop, allow only 3 0-byte reads.  */
  203.     if( got_this_read < 0 )
  204.       perror("read error");
  205.     if( report_error ) {
  206.       (void)fprintf(stderr, "Error in reading");
  207.       if( detail != NULL )
  208.         (void)fprintf(stderr, " %s", detail);
  209.       if( filename != NULL )
  210.         (void)fprintf(stderr, " from %s", filename);
  211.       (void)fprintf(stderr, "\n");
  212.       (void)fflush(stderr);
  213.       if( report_error && (got_so_far >= 0) ) {
  214.         (void)fprintf(stderr, "Expected %d bytes, read %d\n",
  215.               nbytes, got_so_far);
  216.         (void)fflush(stderr);
  217.       }
  218.     }
  219.     return got_so_far;
  220.       }
  221.     }
  222.   }
  223.   return got_so_far;
  224. }
  225.  
  226. /*
  227.  * Subroutine:    write_disk
  228.  * Purpose:    Write data to the open disk file or stream
  229.  */
  230. int write_disk ( fd, buf, nbytes, filename )
  231.      int fd;
  232.      char *buf;
  233.      int nbytes;
  234.      char *filename;
  235. {
  236.   int gave;
  237.  
  238.   if( (gave = write(fd, buf, nbytes)) < nbytes ) {
  239.     /* if interrupted (or non-blocking reader), try the rest again */
  240.     if( gave > 0 ) {
  241.       /* I haven't tested this way of handling the situation with IRAF */
  242.       nbytes -= gave;
  243.       buf += gave;
  244.       if( (gave = write(fd, buf, nbytes)) == nbytes )
  245.     return( 0 );
  246.     }
  247.     perror(filename);
  248.     return( -1 );
  249.   }
  250.   return( 0 );
  251. }
  252.     
  253. /*
  254.  * Subroutine:    close_disk
  255.  * Purpose:    Close a disk file
  256.  */
  257. void close_disk ( fd, filename )
  258.      int fd;
  259.      char *filename;
  260. {
  261. #ifdef DEBUG
  262.   if( close(fd) == -1 ) {
  263.     perror("close error");
  264.     if( filename != NULL ) {
  265.       (void)fprintf(stderr, "Error closing %s\n", filename);
  266.       (void)fflush(stderr);
  267.     }
  268.   }
  269. #else
  270.   (void)close(fd);
  271. #endif
  272. }
  273.  
  274.  
  275. #else
  276.  
  277.  
  278. /*
  279.  * VMS versions of disk functions.  This implementation of these functions
  280.  * for VMS uses the standard C library calls, just as on Unix.  Although
  281.  * this is the easiest approach for now, there are some problems:
  282.  *
  283.  *    Performance    The VAX/VMS C library functions dealing with
  284.  *            file i/o have never been very efficient.  Better
  285.  *            performance (with some loss of generality, of
  286.  *            course) can be gained by using RMS system routines.
  287.  *            The VMS_OPEN_OPTIONS below should help, though.
  288.  *
  289.  *    VMS Files    VMS supports a number of different file types,
  290.  *            which are sometimes handled differently by the
  291.  *            the C library functions.  For example, a read()
  292.  *            operation on a file with a record size of 512
  293.  *            bytes will return a maximum of 512 bytes, regardless
  294.  *            of the number requested in the call.  Thus, for
  295.  *            these functions, we must loop around until all the
  296.  *            i/o requested has been performed.
  297.  *
  298.  *    Seeking        Depending on the type of file being accessed, the
  299.  *            operation of seeking to a byte offset in a file
  300.  *            is somewhat unpredictable.  For stream files, it
  301.  *            is usually okay, but for record files, only byte
  302.  *            offsets that are on a record boundary are allowed.
  303.  *            (As a result of this behavior, the -skip and -header
  304.  *            command line options may not always perform as
  305.  *            expected on VMS.)
  306.  *
  307.  * Note:  perror(NULL) will not work on VMS; some character string must
  308.  *    be specified, even if just "".
  309.  */
  310.  
  311. #define VMS_OPEN_OPTIONS "mbc=32","mbf=4","rop=RAH"
  312.  
  313. #include <stdio.h>        /* define stderr, FILE, NULL, etc */
  314. #include <sys/file.h>        /* define open */
  315.  
  316. /*
  317.  * Subroutine:    open_disk
  318.  * Returns:    File descriptor of open file (suitable for read())
  319.  */
  320. int open_disk ( filename, write_flag, no_block )
  321.      char *filename;
  322.      int write_flag;    /* i: 1=WriteOnly, 0=ReadWrite, -1=ReadOnly */
  323.      int no_block;    /* i: flag to set non-blocking flag */
  324. {
  325.   int flags;
  326.   int fd;
  327.  
  328.   if( write_flag > 0 ) {
  329.     flags = O_WRONLY;
  330.     if( write_flag > 1 )
  331.       /* create file if it doesn't exist, else condition causes error */
  332.       flags |= O_CREAT;
  333.   } else {
  334.     if( write_flag < 0 )
  335.       flags = O_RDONLY;
  336.     else
  337.       flags = O_RDWR;
  338.   }
  339.   if( no_block )
  340.     flags |= O_NDELAY;
  341.   if( (fd = open(filename, flags, 0, VMS_OPEN_OPTIONS)) == -1 ) {
  342.     (void)fprintf(stderr, "ERROR: unable to open %s\n", filename);
  343.     fflush(stderr);
  344.     perror("open error");
  345.   }
  346.   return( fd );
  347. }
  348.  
  349. /*
  350.  * Subroutine:    fcntl_disk
  351.  * Purpose:    Change an open file's flags, check for errors
  352.  */
  353. void fcntl_disk ( fd, write_flag, no_block, filename )
  354.      int fd;            /* i: already open file descriptor */
  355.      int write_flag;        /* i: 0=read, else write */
  356.      int no_block;        /* i: include non-blocking flag */
  357.      char *filename;        /* [i]: name of file being accessed */
  358. {
  359.     /* fcntl() not supported on VMS */
  360. }
  361.  
  362. /*
  363.  * Subroutine:    lseek_disk
  364.  * Purpose:    Skip into a disk file before reading, check for errors
  365.  */
  366. int lseek_disk ( fd, nbytes, filename )
  367.      int fd;
  368.      int nbytes;
  369.      char *filename;        /* [i]: name of file being accessed */
  370. {
  371.   long lseek();            /* type not declared in <sys/file.h> */
  372.  
  373.   if( lseek(fd, (long)nbytes, SEEK_SET) < 0 ) {
  374.     (void)fprintf(stderr, "Can't lseek %d bytes", nbytes);
  375.     if( filename != NULL )
  376.       (void)fprintf(stderr, "into file %s\n", filename);
  377.     else
  378.       (void)fprintf(stderr, "\n");
  379.     fflush(stderr);
  380.     perror("lseek error");
  381.     return( -1 );
  382.   }
  383.   return( 0 );
  384. }
  385.  
  386. /*
  387.  * Subroutine:    read_disk
  388.  * Purpose:    Read bytes from a disk file, check for errors
  389.  * Returns:    Number of bytes read, or error flag (-1)
  390.  * Note:    If report_error is 0, reading fewer than nbytes
  391.  *        is not treated as an error.
  392.  */
  393. int read_disk ( fd, buf, nbytes, report_error, filename, detail )
  394.      int fd;
  395.      char *buf;            /* i: buffer to receive read data */
  396.      int nbytes;        /* i: number of bytes expected */
  397.      int report_error;        /* i: report under-count read */
  398.      char *filename;        /* [i]: name of file being read */
  399.      char *detail;        /* [i]: "data", "header", etc */
  400. {
  401.     /* Note: On VMS, read() will return the number of bytes requested
  402.      * or the logical record size, whichever is less.  Loop around
  403.      * until we get everything we want.
  404.      */
  405.   int got, count=0;
  406.  
  407.   while (count < nbytes) {
  408.     got = read(fd, (buf+count), (nbytes-count));
  409.     if( got < 0 ) {
  410.       (void)fprintf(stderr, "Error in reading");
  411.       if( detail != NULL )
  412.     (void)fprintf(stderr, " %s", detail);
  413.       if( filename != NULL )
  414.     (void)fprintf(stderr, " from %s", filename);
  415.       (void)fprintf(stderr, "\n");
  416.       fflush(stderr);
  417.       perror("read error");
  418.       return( got );
  419.     } else if( got == 0 ) {            /* reached EOF ? */
  420.       if( count < nbytes && report_error ) {
  421.         (void)fprintf(stderr, "Expected %d bytes, read %d\n", nbytes, count);
  422.         fflush(stderr);
  423.       }
  424.       break;
  425.     } else {
  426.       count += got;
  427.     }
  428.   }
  429.   return( count );
  430. }
  431.  
  432. /*
  433.  * Subroutine:    write_disk
  434.  * Purpose:    Write data to the open disk file or stream
  435.  */
  436. void write_disk ( fd, buf, nbytes, filename )
  437.      int fd;
  438.      char *buf;
  439.      int nbytes;
  440.      char *filename;
  441. {
  442.     /* Note: On VMS, write() may write the number of bytes requested
  443.      * or the logical record size, whichever is less.  Loop around
  444.      * until we write everything we want.
  445.      */
  446.   int gave, count=0;
  447.  
  448.   while (count < nbytes) {
  449.     gave = write(fd, (buf+count), (nbytes-count));
  450.     if( gave < 0 ) {
  451.       perror (filename);
  452.       break;
  453.     } else {
  454.       count += gave;
  455.     }
  456.   }
  457. }
  458.     
  459. /*
  460.  * Subroutine:    close_disk
  461.  * Purpose:    Close a disk file
  462.  */
  463. void close_disk ( fd, filename )
  464.      int fd;
  465.      char *filename;
  466. {
  467.   int close();
  468.  
  469.   if( close(fd) == -1 ) {
  470.     if( filename != NULL ) {
  471.       (void)fprintf(stderr,"Error closing %s\n", filename);
  472.       fflush(stderr);
  473.     }
  474.     perror("close error");
  475.   }
  476. }
  477.  
  478. #endif
  479.  
  480.                                      
  481.                                                                
  482.                                                                
  483.                                                                
  484.                                                               
  485.  
  486.                                                                
  487.                                                                
  488.                                                                
  489.                                                                
  490.              
  491.