home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / flistfrontend / src / rmsio.c < prev    next >
C/C++ Source or Header  |  1995-10-28  |  16KB  |  385 lines

  1. #ifndef NO_IDENT
  2. static char *Id = "$Id: rmsio.c,v 1.11 1995/10/28 13:52:43 tom Exp $";
  3. #endif
  4.  
  5. /*
  6.  * Title:    rmsio.c
  7.  * Author:    T.E.Dickey
  8.  * Created:    11 Sep 1984
  9.  * Last update:
  10.  *        28 Oct 1995, set flags to allow shared-read/write.
  11.  *        05 Jun 1995, prototypes
  12.  *        28 Feb 1989, print status-code in 'rerror()' if room.
  13.  *        16 Jun 1985, broke out CC2.0/CC1.5 difference as 'rabrfa_???'
  14.  *        15 Jun 1985, typed 'calloc'.  CC2.0 declares RAB's rfa as
  15.  *                 short[3], rather than long,short.
  16.  *        10 Apr 1985, added 'rclear', augmented 'rerror' by piping to
  17.  *                 'warn', and making better message for file-not-
  18.  *                 found.
  19.  *        09 Apr 1985, broke 'ropen' into 'ropen2' to provide defaults.
  20.  *        18 Feb 1985, polished RFA-defs a bit, fixed error return in
  21.  *                 'rseek'.
  22.  *        13 Feb 1984, in 'erstat', use global error if nil-pointer
  23.  *        12 Feb 1985, added 'erstat' entry (cf: 'ferror') to provide
  24.  *                 some error-checking.
  25.  *        04 Feb 1985, added block-I/O (if uppercase open-mode).  Fixed
  26.  *                 return from 'rclose', also deal only in RFILE
  27.  *                 (instead of assuming RAB-argument).
  28.  *        10 Nov 1984, began coding for output-file (CR-format only)
  29.  *        23 Oct 1984, no longer need dummy newline on 'rgetr'
  30.  *        28 Sep 1984, latch-only status in file-close
  31.  *        17 Sep 1984
  32.  *
  33.  * Function:    This module is designed as a look-alike for the Unix procedures
  34.  *        'fopen', 'fgets', 'fclose', 'ftell' and 'fseek', but with the
  35.  *        special application of reading VAX/VMS RMS-managed files by
  36.  *        record.  (The existing Unix-support knows only about carriage-
  37.  *        control files.)  By supplying a new procedure 'getr' (instead
  38.  *        of 'gets'), we read records instead of strings.  The calling
  39.  *        syntax is designed to permit simple replacement.
  40.  *
  41.  *        The Unix FILE pointer is replaced by a pointer to RMS
  42.  *        structures.  The calling format is preserved, since we wish
  43.  *        to be able to take the calling code to other systems.  The
  44.  *        crucial difference between VAX/VMS and Unix is that
  45.  *
  46.  *            'ftell' on VMS returns the address of the last record
  47.  *                which has been read.
  48.  *            'ftell' on Unix returns the address of the next byte
  49.  *                which will be read.
  50.  *
  51.  *        'ungetc' does not work properly in this environment.
  52.  *
  53.  * Entry:    ropen:    (fopen)  Open an RMS-file, returning pointer to buffers
  54.  *        ropen2:    (?)     Open a file, providing default-specification.
  55.  *        rgetr:    (fgets)  Read a record from RMS-file
  56.  *        rputr:    (fputs)     Write a record to RMS-file
  57.  *        rtell:    (ftell)  Returns offset into file (record-address)
  58.  *        rseek:    (fseek)  Position to specified record-address
  59.  *        rclose:    (fclose) Close an RMS-file, releasing I/O buffers
  60.  *        erstat:    (?)     Format an error message, if severe
  61.  *        rerror:    (perror) Print message for last error
  62.  *        rsize:    (?)     Returns size of largest record of input.
  63.  */
  64.  
  65. #include    <starlet.h>
  66. #include    <stdlib.h>
  67. #include    <stdio.h>
  68. #include    <string.h>
  69.  
  70. #include    <rms.h>
  71. #include    <stsdef.h>
  72. #include    <descrip.h>
  73.  
  74. #include    <ctype.h>
  75.  
  76. #include    "bool.h"
  77. #include    "warning.h"
  78. #include    "rabrfa.h"
  79. #include    "rmsio.h"
  80. #include    "rmsinit.h"
  81. #include    "sysutils.h"
  82.  
  83. #define    DEFAULT_RSIZE    512
  84.  
  85. #define    latch        if (!rmsio$err) rmsio$err = status
  86. #define    save_st        rmsio$err = status;
  87.  
  88. #define    CHECK(f)    sys(f)    {save_st; goto failed;}
  89. #define    NONZERO(f)    sys(f)    {save_st; return(0);}
  90. #define    ZERO(f)        sys(f)    {save_st; return(status);}
  91.  
  92. #define    CHECK2(f)    sys(f)    {latch; goto failed;}
  93.  
  94. /*
  95.  * Module-level data:
  96.  */
  97. static    unsigned rmsio$err = 0;
  98. static    char    rmsio$nam[NAM$C_MAXRSS] = ""; /* Last filename used in parse */
  99.  
  100. #define    zFAB    z->fab
  101. #define    zNAM    z->nam
  102. #define    zRAB    z->rab
  103.  
  104. #define    BLOCKED    (blocked ? FAB$M_BRO : 0)
  105. #define    isBLOCK    (zFAB.fab$b_fac & FAB$M_BRO)
  106.  
  107. /* <ropen>:
  108.  * Open a file for record I/O:
  109.  *
  110.  * mode_:
  111.  *    "r" - read, record
  112.  *    "w" - write, record
  113.  *    "R" - read, block (512)
  114.  *    "W" - write, block
  115.  */
  116. RFILE    *ropen (char *name_, char *mode_)
  117. {
  118.     return (ropen2(name_, nullC, mode_));
  119. }
  120.  
  121. /* <ropen>:
  122.  * Open a file for record I/O, giving a default file specification.
  123.  *
  124.  *    name_    => filename
  125.  *    dft_    => default specification
  126.  *    mode_    => Unix-style (record/block) mode (see: 'ropen')
  127.  */
  128. RFILE    *ropen2 (char *name_, char *dft_, char *mode_)
  129. {
  130.     RFILE    *z = calloc(1, sizeof(RFILE));
  131.     unsigned status;
  132.     int    newfile    = (_tolower(*mode_) == 'w');
  133.     int    blocked    = (isupper(*mode_));
  134.     int    no_old    = FALSE;
  135.     int    recsize = DEFAULT_RSIZE;
  136.     int    len;
  137.  
  138.     rmsinit_fab (&zFAB, &zNAM, dft_, name_);
  139.     rmsinit_nam (&zNAM, z->rsa, z->esa);
  140.  
  141.     zFAB.fab$l_xab = (char *)&z->xabfhc;
  142.     z->xabfhc = cc$rms_xabfhc;
  143.  
  144.     zRAB = cc$rms_rab;
  145.     zRAB.rab$l_fab = &zFAB;
  146.  
  147.     /*
  148.      * Open the file.  We assume that if it is a new file, then no
  149.      * version number is given.  Exploit this to obtain the format
  150.      * of any previously-existing file of that name.
  151.      */
  152.     CHECK(sys$parse(&zFAB));
  153.     strncpy (rmsio$nam, z->esa, len = zNAM.nam$b_esl);
  154.     rmsio$nam[len] = EOS;
  155.  
  156.     if (newfile)
  157.     {
  158.         zFAB.fab$b_fac = FAB$M_GET | BLOCKED;
  159.         sys(sys$search(&zFAB))
  160.             no_old = TRUE;
  161.         else
  162.         {
  163.             sys(sys$open(&zFAB))
  164.                 no_old    = TRUE;
  165.             else
  166.                 sys$close(&zFAB);
  167.         }
  168.         if (no_old)
  169.         {
  170.             zFAB.fab$b_rfm = FAB$C_VAR;
  171.             zFAB.fab$b_rat |= FAB$M_CR;
  172.         }
  173.         zFAB.fab$b_fac = FAB$M_PUT | BLOCKED;
  174.         zFAB.fab$b_shr |= FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_SHRUPD ;
  175.         CHECK(sys$create(&zFAB));
  176.     }
  177.     else
  178.     {
  179.         zFAB.fab$b_fac |= FAB$M_GET | BLOCKED;
  180.         /* 1995/10/27 - I'd noticed that 'most' was able to read files
  181.          * that were locked, and investigated.  The shrget/shrupd flags
  182.          * are necessary for the cases that I looked at, and 'most'
  183.          * also uses the shrput flag, which doesn't seem to hurt.
  184.          */
  185.         zFAB.fab$b_shr |= FAB$M_SHRGET | FAB$M_SHRPUT | FAB$M_SHRUPD ;
  186.         CHECK(sys$search(&zFAB));
  187.         CHECK(sys$open(&zFAB));
  188.     }
  189.  
  190.     /*
  191.      * Allocate a buffer big enough for the biggest record:
  192.      */
  193.     if (!newfile)    recsize = rsize(z);
  194.     zRAB.rab$l_ubf = calloc (1, zRAB.rab$w_usz = recsize);
  195.  
  196.     /*
  197.      * Connect an I/O stream to the file:
  198.      */
  199.     CHECK(sys$connect(&zRAB));
  200.     return (z);
  201.  
  202. failed:    rclose (z);
  203.     return (0);
  204. }
  205.  
  206. /* <rgetr>:
  207.  * Read a record, returning the number of bytes read, and returning to the
  208.  * caller the file-address of the record.
  209.  */
  210. int    rgetr (
  211.     RFILE *    z,        /* file-descriptor pointer    */
  212.     char *    bfr,        /* buffer to load        */
  213.     int    maxbfr,        /* ...its size            */
  214.     unsigned *mark_)    /* file-address of buffer    */
  215. {
  216.     unsigned status;
  217.     int    len    = -1;
  218.  
  219.     zRAB.rab$b_rac = RAB$C_SEQ;
  220.     if (isBLOCK)            /* return zero if error or EOF    */
  221.     {
  222.         CHECK(sys$read(&zRAB));
  223.     }
  224.     else
  225.     {
  226.         CHECK(sys$get(&zRAB));
  227.     }
  228.  
  229.     maxbfr--;            /* Index of last permissible    */
  230.     len = zRAB.rab$w_rsz;        /* limit length of returned buffer */
  231.     if (len > maxbfr) len = maxbfr;    /* ...to caller's 'maxbfr' size    */
  232.     memcpy (bfr, zRAB.rab$l_rbf, len); /* ...and copy buffer    */
  233.  
  234. failed:
  235.     *mark_ = rtell(z);        /* update file-mark        */
  236.     return (len);
  237. }
  238.  
  239. /* <rputr>:
  240.  * Write a record, given the buffer address and number of characters to
  241.  * write.
  242.  */
  243. int    rputr (
  244.     RFILE    *z,        /* file-descriptor pointer    */
  245.     char    *bfr,        /* buffer to load        */
  246.     int    maxbfr)        /* ...its size            */
  247. {
  248.     unsigned status;
  249.  
  250.     zRAB.rab$b_rac = RAB$C_SEQ;
  251.  
  252.     zRAB.rab$w_rsz = maxbfr;    /* set length of buffer        */
  253.     zRAB.rab$l_rbf = bfr;        /* ...and copy buffer-pointer    */
  254.     if (isBLOCK)            /* return nonzero if error    */
  255.     {
  256.         CHECK2(sys$write(&zRAB));
  257.     }
  258.     else
  259.     {
  260.         CHECK2(sys$put(&zRAB));
  261.     }
  262.     status = 0;
  263. failed:
  264.     if (status)    rerror();
  265.     return (status);
  266. }
  267.  
  268. /* <rtell>:
  269.  * Return the record-file-address translated into an offset value,
  270.  * compatible with the 'ftell' usage.
  271.  */
  272. unsigned rtell (RFILE *z)
  273. {
  274.     return (rabrfa_get (&zRAB));
  275. }
  276.  
  277. /* <rseek>:
  278.  * Search for a specific record, by offset.  If this was the offset obtained
  279.  * from 'rtell', the seek should properly lock on a record.
  280.  *
  281.  * Patch: The 'direction' argument is not implemented.  We assume that it is
  282.  *    0, for absolute positioning.
  283.  */
  284. int    rseek (RFILE *z, int offset, int direction)
  285. {
  286.     unsigned status;
  287.  
  288.     zRAB.rab$b_rac = RAB$C_RFA;
  289.     rabrfa_put (&zRAB, offset);
  290.     ZERO(sys$find(&zRAB));    /* return zero if ok */
  291.     return (0);
  292. }
  293.  
  294. /* <rclose>:
  295.  * Close the file, returning nonzero status iff an error occurs.
  296.  */
  297. int    rclose (RFILE *z)
  298. {
  299.     unsigned status;
  300.     char    *ubf_    = zRAB.rab$l_ubf;
  301.  
  302.     CHECK2(sys$disconnect(&zRAB));
  303.     CHECK2(sys$close(&zFAB));
  304.     status = 0;
  305. failed:
  306.     cfree (z);
  307.     if (ubf_)    cfree (ubf_);
  308.     return (status);
  309. }
  310.  
  311. /* <erstat>:
  312.  * If the last record operation (put/get) failed, show its status-message.
  313.  * If the given RFILE-pointer is null, show any error condition (so we can
  314.  * use this on a failed-open, or in place of 'rerror').
  315.  */
  316. int    erstat (RFILE *z, char *msg, int msglen)
  317. {
  318.     unsigned status    = z ? zRAB.rab$l_sts : rmsio$err;
  319.  
  320.     if (($VMS_STATUS_SEVERITY(status) == STS$K_SEVERE)
  321.     ||  (!z && !$VMS_STATUS_SUCCESS(status)) )
  322.     {
  323.         sysgetmsg (status, msg, msglen);
  324.         return (TRUE);
  325.     }
  326.     else
  327.         return (FALSE);
  328. }
  329.  
  330. /* <rerror>:
  331.  * Display the cause of the last error condition, like 'perror'
  332.  */
  333. void    rerror (void)
  334. {
  335. #define    MAX_MSG    132
  336.     auto    char    msg[MAX_MSG+NAM$C_MAXRSS];
  337.     register int    len;
  338.  
  339.     sysgetmsg (rmsio$err, msg, sizeof(msg));
  340.     if (rmsio$err == RMS$_FNF) {
  341.         len = strlen(msg);
  342.         sprintf (msg+len, ":: %.*s", sizeof(msg) - len - 2, rmsio$nam);
  343.     }
  344.     if ((len = strlen(msg)) < (sizeof(msg) - 16))
  345.         sprintf(msg+strlen(msg), " (st=%#x)", rmsio$err);
  346.     warn ("%.*s", MAX_MSG, msg);
  347.     rmsio$err = 0;
  348. }
  349.  
  350. /* <rclear>:
  351.  * Reset the error-latch.  Note that because only one latch is saved for
  352.  * all files together, we must be careful to test the latch when we need it,
  353.  * and to reset it otherwise.
  354.  */
  355. void    rclear (void)
  356. {
  357.     rmsio$err = 0;
  358. }
  359.  
  360. /* <rsize>:
  361.  * Return the length of the longest record in (an input) file:
  362.  */
  363. int    rsize (RFILE *z)
  364. {
  365.     struct    XABFHC    *xab_;
  366.     int    size;
  367.  
  368.     if (isBLOCK)
  369.         return (512);
  370.  
  371.     if ((xab_ = (struct XABFHC *)(zFAB.fab$l_xab)) != 0)
  372.     {
  373.         while (xab_)
  374.         {
  375.             if (xab_->xab$b_cod == XAB$C_FHC)
  376.             {
  377.                 if (size = xab_->xab$w_lrl)
  378.                     return (size);
  379.             }
  380.             xab_ = (struct XABFHC *)(xab_->xab$l_nxt);
  381.         }
  382.     }
  383.     return (DEFAULT_RSIZE);
  384. }