home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / ods2 / src / rms.c < prev    next >
C/C++ Source or Header  |  1998-09-11  |  37KB  |  1,050 lines

  1. /* Rms.c v1.2  RMS components */
  2.  
  3. /*
  4.         This is part of ODS2 written by Paul Nankervis,
  5.         email address:  Paulnank@au1.ibm.com
  6.  
  7.         ODS2 is distributed freely for all members of the
  8.         VMS community to use. However all derived works
  9.         must maintain comments in their source to acknowledge
  10.         the contibution of the original author.
  11. */
  12.  
  13. /*  Boy some cleanups are needed here - especially for
  14.     error handling and deallocation of memory after errors..
  15.     For now we have to settle for loosing memory left/right/center...
  16.  
  17.     This module implements file name parsing, file searches,
  18.     file opens, gets, etc...       */
  19.  
  20.  
  21. #define DEBUGx x
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <memory.h>
  26. #include <ctype.h>
  27. #include "descrip.h"
  28. #include "ssdef.h"
  29. #include "fibdef.h"
  30.  
  31. #define RMS_INITIALIZE doit     /* used by rms.h to create templates */
  32. #include "rms.h"
  33. #include "access.h"
  34. #include "direct.h"
  35.  
  36.  
  37. /* Table of file name component delimeters... */
  38.  
  39. char char_delim[] = {
  40. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  41. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0, 0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,
  42. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
  43. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0};
  44.  
  45.  
  46. /* Routine to find size of file name components */
  47.  
  48. unsigned name_delim(char *str,int len,int size[5])
  49. {
  50.     register unsigned ch;
  51.     register char *curptr = str;
  52.     register char *endptr = curptr + len;
  53.     register char *begptr = curptr;
  54.     while (curptr < endptr) {
  55.         ch = (*curptr++ & 127);
  56.         if (char_delim[ch]) break;
  57.     }
  58.     if (curptr > begptr && ch == ':') {
  59.         size[0] = (curptr - begptr);
  60.         begptr = curptr;
  61.         while (curptr < endptr) {
  62.             ch = (*curptr++ & 127);
  63.             if (char_delim[ch]) break;
  64.         }
  65.     } else {
  66.         size[0] = 0;
  67.     }
  68.     if (ch == '[' || ch == '<') {
  69.         if (curptr != begptr + 1) return RMS$_FNM;
  70.         while (curptr < endptr) {
  71.             ch = (*curptr++ & 127);
  72.                 if (char_delim[ch]) if (ch != '.') break;
  73.         }
  74.         if (curptr < begptr + 2 || (ch != ']' && ch != '>')) return RMS$_FNM;
  75.         size[1] = (curptr - begptr);
  76.         begptr = curptr;
  77.         while (curptr < endptr) {
  78.             ch = (*curptr++ & 127);
  79.             if (char_delim[ch]) break;
  80.         }
  81.     } else {
  82.         size[1] = 0;
  83.     }
  84.     if (curptr > begptr && char_delim[ch]) {
  85.         size[2] = (curptr - begptr) - 1;
  86.         begptr = curptr - 1;
  87.     } else {
  88.         size[2] = (curptr - begptr);
  89.         begptr = curptr;
  90.     }
  91.     if (curptr > begptr && ch == '.') {
  92.         while (curptr < endptr) {
  93.             ch = (*curptr++ & 127);
  94.             if (char_delim[ch]) break;
  95.         }
  96.         if (curptr > begptr && char_delim[ch]) {
  97.             size[3] = (curptr - begptr) - 1;
  98.             begptr = curptr - 1;
  99.         } else {
  100.             size[3] = (curptr - begptr);
  101.             begptr = curptr;
  102.         }
  103.     } else {
  104.         size[3] = 0;
  105.     }
  106.     if (curptr > begptr && (ch == ';' || ch == '.')) {
  107.         while (curptr < endptr) {
  108.             ch = (*curptr++ & 127);
  109.             if (char_delim[ch]) break;
  110.         }
  111.         size[4] = (curptr - begptr);
  112.     } else {
  113.         size[4] = 0;
  114.     }
  115. #ifdef DEBUG
  116.     printf("Name delim %d %d %d %d %d\n",size[0],size[1],size[2],size[3],size[4]);
  117. #endif
  118.     if (curptr >= endptr) {
  119.         return 1;
  120.     } else {
  121.         return RMS$_FNM;
  122.     }
  123. }
  124.  
  125.  
  126. /* Function to compare directory cache names - directory cache NOT IN USE */
  127.  
  128. int dircmp(unsigned keylen,void *key,void *node)
  129. {
  130.     register struct DIRCACHE *dirnode = (struct DIRCACHE *) node;
  131.     register int cmp = keylen - dirnode->dirlen;
  132.     if (cmp == 0) {
  133.         register unsigned len = keylen;
  134.         register char *keynam = (char *) key;
  135.         register char *dirnam = dirnode->dirnam;
  136.         while (len-- > 0) {
  137.             cmp = toupper(*keynam++) - toupper(*dirnam++);
  138.             if (cmp != 0) break;
  139.         }
  140.     }
  141.     return cmp;
  142. }
  143.  
  144.  
  145. /* Routine to find directory name in cache... NOT CURRENTLY IN USE!!! */
  146.  
  147. unsigned dircache(struct VCB *vcb,char *dirnam,int dirlen,struct fiddef *dirid)
  148. {
  149.     register struct DIRCACHE *dir;
  150.     if (dirlen < 1) {
  151.         dirid->fid$w_num = 4;
  152.         dirid->fid$w_seq = 4;
  153.         dirid->fid$b_rvn = 0;
  154.         dirid->fid$b_nmx = 0;
  155.         return 1;
  156.     } else {
  157.         unsigned create = 0;
  158.         dir = cachesearch((void *) &vcb->dircache,0,dirlen,dirnam,dircmp,&create);
  159.         if (dir != NULL) {
  160.             memcpy(dirid,&dir->dirid,sizeof(struct fiddef));
  161.             return 1;
  162.         }
  163.         return 0;
  164.     }
  165. }
  166.  
  167.  
  168. /*      For file context info we use WCCDIR and WCCFILE structures...
  169.         Each WCCFILE structure contains one WCCDIR structure for file
  170.         context. Each level of directory has an additional WCCDIR record.
  171.         For example DKA200:[PNANKERVIS.F11]RMS.C is loosley stored as:-
  172.                         next         next
  173.                 WCCFILE  -->  WCCDIR  -->  WCCDIR
  174.                 RMS.C;       F11.DIR;1    PNANKERVIS.DIR;1
  175.  
  176.         WCCFILE is pointed to by fab->fab$l_nam->nam$l_wcc and if a
  177.         file is open also by ifi_table[fab->fab$w_ifi]  (so that close
  178.         can easily locate it).
  179.  
  180.         Most importantly WCCFILE contains a resulting filename field
  181.         which stores the resulting file spec. Each WCCDIR has a prelen
  182.         length to indicate how many characters in the specification
  183.         exist before the bit contributed by this WCCDIR. (ie to store
  184.         the device name and any previous directory name entries.)  */
  185.  
  186.  
  187. #define STATUS_INIT 1
  188. #define STATUS_TMPDIR  2
  189. #define STATUS_WILDCARD 4
  190.  
  191. struct WCCDIR {
  192.     struct WCCDIR *wcd_next;
  193.     struct WCCDIR *wcd_prev;
  194.     int wcd_status;
  195.     int wcd_wcc;
  196.     int wcd_prelen;
  197.     unsigned short wcd_reslen;
  198.     struct dsc$descriptor wcd_serdsc;
  199.     struct fiddef wcd_dirid;
  200.     char wcd_sernam[1];         /* Must be last in structure */
  201. };                              /* Directory context */
  202.  
  203.  
  204. #define STATUS_RECURSE 8
  205. #define STATUS_TMPWCC  16
  206. #define MAX_FILELEN 1024
  207.  
  208. struct WCCFILE {
  209.     struct FAB *wcf_fab;
  210.     struct VCB *wcf_vcb;
  211.     struct FCB *wcf_fcb;
  212.     int wcf_status;
  213.     struct fiddef wcf_fid;
  214.     char wcf_result[MAX_FILELEN];
  215.     struct WCCDIR wcf_wcd;      /* Must be last..... (dynamic length). */
  216. };                              /* File context */
  217.  
  218.  
  219. /* Function to remove WCCFILE and WCCDIR structures when not required */
  220.  
  221. void cleanup_wcf(struct WCCFILE *wccfile)
  222. {
  223.     if (wccfile != NULL) {
  224.         struct WCCDIR *wcc = wccfile->wcf_wcd.wcd_next;
  225.         wccfile->wcf_wcd.wcd_next = NULL;
  226.         wccfile->wcf_wcd.wcd_prev = NULL;
  227.         /* should deaccess volume */
  228.         free(wccfile);
  229.         while (wcc != NULL) {
  230.             struct WCCDIR *next = wcc->wcd_next;
  231.             wcc->wcd_next = NULL;
  232.             wcc->wcd_prev = NULL;
  233.             free(wcc);
  234.             wcc = next;
  235.         }
  236.     }
  237. }
  238.  
  239.  
  240. /* Function to perform an RMS search... */
  241.  
  242. unsigned do_search(struct FAB *fab,struct WCCFILE *wccfile)
  243. {
  244.     int sts;
  245.     struct fibdef fibblk;
  246.     struct WCCDIR *wcc;
  247.     struct dsc$descriptor fibdsc,resdsc;
  248.     struct NAM *nam = fab->fab$l_nam;
  249.     wcc = &wccfile->wcf_wcd;
  250.     if (fab->fab$w_ifi != 0) return RMS$_IFI;
  251.  
  252.     /* if first time through position at top directory... WCCDIR */
  253.  
  254.     while ((wcc->wcd_status & STATUS_INIT) == 0 && wcc->wcd_next != NULL) {
  255.         wcc = wcc->wcd_next;
  256.     }
  257.     fibdsc.dsc$w_length = sizeof(struct fibdef);
  258.     fibdsc.dsc$a_pointer = (char *) &fibblk;
  259.     while (1) {
  260.         if ((wcc->wcd_status & STATUS_INIT) == 0 || wcc->wcd_wcc != 0) {
  261.             wcc->wcd_status |= STATUS_INIT;
  262.             resdsc.dsc$w_length = 256 - wcc->wcd_prelen;
  263.             resdsc.dsc$a_pointer = wccfile->wcf_result + wcc->wcd_prelen;
  264.             memcpy(&fibblk.fib$w_did_num,&wcc->wcd_dirid,sizeof(struct fiddef));
  265.             fibblk.fib$w_nmctl = 0;     /* FIB$M_WILD; */
  266.             fibblk.fib$l_acctl = 0;
  267.             fibblk.fib$w_fid_num = 0;
  268.             fibblk.fib$w_fid_seq = 0;
  269.             fibblk.fib$b_fid_rvn = 0;
  270.             fibblk.fib$b_fid_nmx = 0;
  271.             fibblk.fib$l_wcc = wcc->wcd_wcc;
  272. #ifdef DEBUG
  273.             wcc->wcd_sernam[wcc->wcd_serdsc.dsc$w_length] = '\0';
  274.             wccfile->wcf_result[wcc->wcd_prelen + wcc->wcd_reslen] = '\0';
  275.             printf("Ser: '%s' (%d,%d,%d) WCC: %d Prelen: %d '%s'\n",wcc->wcd_sernam,
  276.                    fibblk.fib$w_did_num | (fibblk.fib$b_did_nmx << 16),
  277.                    fibblk.fib$w_did_seq,fibblk.fib$b_did_rvn,
  278.                    wcc->wcd_wcc,wcc->wcd_prelen,wccfile->wcf_result + wcc->wcd_prelen);
  279. #endif
  280.             sts = direct(wccfile->wcf_vcb,&fibdsc,&wcc->wcd_serdsc,&wcc->wcd_reslen,&resdsc,0);
  281.         } else {
  282.             sts = SS$_NOMOREFILES;
  283.         }
  284.         if (sts & 1) {
  285. #ifdef DEBUG
  286.             wccfile->wcf_result[wcc->wcd_prelen + wcc->wcd_reslen] = '\0';
  287.             printf("Fnd: '%s'  (%d,%d,%d) WCC: %d\n",wccfile->wcf_result + wcc->wcd_prelen,
  288.                    fibblk.fib$w_fid_num | (fibblk.fib$b_fid_nmx << 16),
  289.                    fibblk.fib$w_fid_seq,fibblk.fib$b_fid_rvn,
  290.                    wcc->wcd_wcc);
  291. #endif
  292.             wcc->wcd_wcc = fibblk.fib$l_wcc;
  293.             if (wcc->wcd_prev) {/* go down directory */
  294.                 if (wcc->wcd_prev->wcd_next != wcc) printf("wcd_PREV corruption\n");
  295.                 if (fibblk.fib$w_fid_num != 4 || fibblk.fib$b_fid_nmx != 0 ||
  296.                     wcc == &wccfile->wcf_wcd ||
  297.                     memcmp(wcc->wcd_sernam,"000000.",7) == 0) {
  298.                     memcpy(&wcc->wcd_prev->wcd_dirid,&fibblk.fib$w_fid_num,sizeof(struct fiddef));
  299.                     if (wcc->wcd_next) wccfile->wcf_result[wcc->wcd_prelen - 1] = '.';
  300.                     wcc->wcd_prev->wcd_prelen = wcc->wcd_prelen + wcc->wcd_reslen - 5;
  301.                     wcc = wcc->wcd_prev;        /* go down one level */
  302.                     if (wcc->wcd_prev == NULL) wccfile->wcf_result[wcc->wcd_prelen - 1] = ']';
  303.                 }
  304.             } else {
  305.                 if (nam != NULL) {
  306.                     int fna_size[5];
  307.                     memcpy(&nam->nam$w_fid_num,&fibblk.fib$w_fid_num,sizeof(struct fiddef));
  308.                     nam->nam$b_rsl = wcc->wcd_prelen + wcc->wcd_reslen;
  309.                     name_delim(wccfile->wcf_result,nam->nam$b_rsl,fna_size);
  310.                     nam->nam$l_dev = nam->nam$l_rsa;
  311.                     nam->nam$b_dev = fna_size[0];
  312.                     nam->nam$l_dir = nam->nam$l_dev + fna_size[0];
  313.                     nam->nam$b_dir = fna_size[1];
  314.                     nam->nam$l_name = nam->nam$l_dir + fna_size[1];
  315.                     nam->nam$b_name = fna_size[2];
  316.                     nam->nam$l_type = nam->nam$l_name + fna_size[2];
  317.                     nam->nam$b_type = fna_size[3];
  318.                     nam->nam$l_ver = nam->nam$l_type + fna_size[3];
  319.                     nam->nam$b_ver = fna_size[4];
  320.                     if (nam->nam$b_rsl <= nam->nam$b_rss) {
  321.                         memcpy(nam->nam$l_rsa,wccfile->wcf_result,nam->nam$b_rsl);
  322.                     } else {
  323.                         return RMS$_RSS;
  324.                     }
  325.                 }
  326.                 memcpy(&wccfile->wcf_fid,&fibblk.fib$w_fid_num,sizeof(struct fiddef));
  327.  
  328.                 return 1;
  329.             }
  330.         } else {
  331. #ifdef DEBUG
  332.             printf("Err: %d\n",sts);
  333. #endif
  334.             if (sts == SS$_BADIRECTORY) {
  335.                 if (wcc->wcd_next != NULL) {
  336.                     if (wcc->wcd_next->wcd_status & STATUS_INIT) sts = SS$_NOMOREFILES;
  337.                 }
  338.             }
  339.             if (sts == SS$_NOMOREFILES) {
  340.                 wcc->wcd_status &= ~STATUS_INIT;
  341.                 wcc->wcd_wcc = 0;
  342.                 wcc->wcd_reslen = 0;
  343.                 if (wcc->wcd_status & STATUS_TMPDIR) {
  344.                     struct WCCDIR *savwcc = wcc;
  345.                     if (wcc->wcd_next != NULL) wcc->wcd_next->wcd_prev = wcc->wcd_prev;
  346.                     if (wcc->wcd_prev != NULL) wcc->wcd_prev->wcd_next = wcc->wcd_next;
  347.                     wcc = wcc->wcd_next;
  348.                     memcpy(wccfile->wcf_result + wcc->wcd_prelen + wcc->wcd_reslen - 6,".DIR;1",6);
  349.                     free(savwcc);
  350.                 } else {
  351.                     if ((wccfile->wcf_status & STATUS_RECURSE) && wcc->wcd_prev == NULL) {
  352.                         struct WCCDIR *newwcc;
  353.                         newwcc = (struct WCCDIR *) malloc(sizeof(struct WCCDIR) + 8);
  354.                         newwcc->wcd_next = wcc->wcd_next;
  355.                         newwcc->wcd_prev = wcc;
  356.                         newwcc->wcd_wcc = 0;
  357.                         newwcc->wcd_status = STATUS_TMPDIR;
  358.                         newwcc->wcd_reslen = 0;
  359.                         if (wcc->wcd_next != NULL) {
  360.                             wcc->wcd_next->wcd_prev = newwcc;
  361.                         }
  362.                         wcc->wcd_next = newwcc;
  363.                         memcpy(&newwcc->wcd_dirid,&wcc->wcd_dirid,sizeof(struct fiddef));
  364.                         newwcc->wcd_serdsc.dsc$w_length = 7;
  365.                         newwcc->wcd_serdsc.dsc$a_pointer = newwcc->wcd_sernam;
  366.                         memcpy(newwcc->wcd_sernam,"*.DIR;1",7);
  367.                         newwcc->wcd_prelen = wcc->wcd_prelen;
  368.                         wcc = newwcc;
  369.  
  370.                     } else {
  371.                         if (wcc->wcd_next != NULL) {
  372. #ifdef DEBUG
  373.                             if (wcc->wcd_next->wcd_prev != wcc) printf("wcd_NEXT corruption\n");
  374. #endif
  375.                             wcc = wcc->wcd_next;        /* backup one level */
  376.                             memcpy(wccfile->wcf_result + wcc->wcd_prelen + wcc->wcd_reslen - 6,".DIR;1",6);
  377.                         } else {
  378.                             sts = RMS$_NMF;
  379.                             break;      /* giveup */
  380.                         }
  381.                     }
  382.                 }
  383.             } else {
  384.                 if (sts == SS$_NOSUCHFILE) {
  385.                     if (wcc->wcd_prev) {
  386.                         sts = RMS$_DNF;
  387.                     } else {
  388.                         sts = RMS$_FNF;
  389.                     }
  390.                 }
  391.                 break;          /* error - abort! */
  392.             }
  393.         }
  394.     }
  395.     cleanup_wcf(wccfile);
  396.     if (nam != NULL) nam->nam$l_wcc = 0;
  397.     fab->fab$w_ifi = 0;         /* must dealloc memory blocks! */
  398.     return sts;
  399. }
  400.  
  401.  
  402. /* External entry for search function... */
  403.  
  404. unsigned sys_search(struct FAB *fab)
  405. {
  406.     struct NAM *nam = fab->fab$l_nam;
  407.     struct WCCFILE *wccfile;
  408.     if (nam == NULL) return RMS$_NAM;
  409.     wccfile = (struct WCCFILE *) nam->nam$l_wcc;
  410.     if (wccfile == NULL) return RMS$_WCC;
  411.     return do_search(fab,wccfile);
  412. }
  413.  
  414.  
  415.  
  416. #define DEFAULT_SIZE 120
  417. char default_buffer[DEFAULT_SIZE];
  418. char *default_name = "DKA200:[000000].;";
  419. int default_size[] = {7,8,0,1,1};
  420.  
  421.  
  422. /* Function to perform RMS parse.... */
  423.  
  424. unsigned do_parse(struct FAB *fab,struct WCCFILE **wccret)
  425. {
  426.     struct WCCFILE *wccfile;
  427.     char *fna = fab->fab$l_fna;
  428.     char *dna = fab->fab$l_dna;
  429.     struct NAM *nam = fab->fab$l_nam;
  430.     int sts;
  431.     int fna_size[5] = {0, 0, 0, 0, 0},dna_size[5] = {0, 0, 0, 0, 0};
  432.     if (fab->fab$w_ifi != 0) return RMS$_IFI;
  433.         if (nam != NULL) if (nam->nam$l_wcc == 0) {
  434.             cleanup_wcf((struct WCCFILE *) nam->nam$l_wcc);
  435.             nam->nam$l_wcc = 0;
  436.         }
  437.     /* Break up file specifications... */
  438.  
  439.     sts = name_delim(fna,fab->fab$b_fns,fna_size);
  440.     if ((sts & 1) == 0) return sts;
  441.     if (dna) {
  442.         sts = name_delim(dna,fab->fab$b_dns,dna_size);
  443.         if ((sts & 1) == 0) return sts;
  444.     }
  445.     /* Make WCCFILE entry for rest of processing */
  446.  
  447.     {
  448.         wccfile = (struct WCCFILE *) malloc(sizeof(struct WCCFILE) + 256);
  449.         if (wccfile == NULL) return SS$_INSFMEM;
  450.         wccfile->wcf_fab = fab;
  451.         wccfile->wcf_vcb = NULL;
  452.         wccfile->wcf_fcb = NULL;
  453.         wccfile->wcf_status = 0;
  454.         wccfile->wcf_wcd.wcd_status = 0;
  455.     }
  456.  
  457.     /* Combine file specifications */
  458.  
  459.     {
  460.         int field,ess = MAX_FILELEN;
  461.         char *esa,*def = default_name;
  462.         esa = wccfile->wcf_result;
  463.         for (field = 0; field < 5; field++) {
  464.             char *src;
  465.             int len = fna_size[field];
  466.             if (len > 0) {
  467.                 src = fna;
  468.             } else {
  469.                 len = dna_size[field];
  470.                 if (len > 0) {
  471.                     src = dna;
  472.                 } else {
  473.                     len = default_size[field];
  474.                     src = def;
  475.                 }
  476.             }
  477.             fna += fna_size[field];
  478.             if (field == 1) {
  479.                 int dirlen = len;
  480.                 if (len < 3) {
  481.                     dirlen = len = default_size[field];
  482.                     src = def;
  483.                 } else {
  484.                     char ch1 = *(src + 1);
  485.                     char ch2 = *(src + 2);
  486.                     if (ch1 == '.' || (ch1 == '-' &&
  487.                                        (ch2 == '-' || ch2 == '.' || ch2 == ']'))) {
  488.                         char *dir = def;
  489.                         int count = default_size[1] - 1;
  490.                         len--;
  491.                         src++;
  492.                         while (len >= 2 && *src == '-') {
  493.                             len--;
  494.                             src++;
  495.                             if (count < 2 || (count == 7 &&
  496.                                               memcmp(dir,"[000000",7) == 0)) return RMS$_DIR;
  497.                             while (count > 1) {
  498.                                 if (dir[--count] == '.') break;
  499.                             }
  500.                         }
  501.                         if (count < 2 && len < 2) {
  502.                             src = "[000000]";
  503.                             dirlen = len = 8;
  504.                         } else {
  505.                             if (*src != '.' && *src != ']') return RMS$_DIR;
  506.                             if (*src == '.' && count < 2) {
  507.                                 src++;
  508.                                 len--;
  509.                             }
  510.                             dirlen = len + count;
  511.                             if ((ess -= count) < 0) return RMS$_ESS;
  512.                             memcpy(esa,dir,count);
  513.                             esa += count;
  514.                         }
  515.                     }
  516.                 }
  517.                 fna_size[field] = dirlen;
  518.             } else {
  519.                 fna_size[field] = len;
  520.             }
  521.             dna += dna_size[field];
  522.             def += default_size[field];
  523.             if ((ess -= len) < 0) return RMS$_ESS;
  524.             while (len-- > 0) {
  525.                 register char ch;
  526.                 *esa++ = ch = *src++;
  527.                 if (ch == '*' || ch == '%')
  528.                     wccfile->wcf_status |= STATUS_WILDCARD;
  529.             }
  530.         }
  531.         /* Pass back results... */
  532.         if (nam) {
  533.             nam->nam$l_dev = nam->nam$l_esa;
  534.             nam->nam$b_dev = fna_size[0];
  535.             nam->nam$l_dir = nam->nam$l_dev + fna_size[0];
  536.             nam->nam$b_dir = fna_size[1];
  537.             nam->nam$l_name = nam->nam$l_dir + fna_size[1];
  538.             nam->nam$b_name = fna_size[2];
  539.             nam->nam$l_type = nam->nam$l_name + fna_size[2];
  540.             nam->nam$b_type = fna_size[3];
  541.             nam->nam$l_ver = nam->nam$l_type + fna_size[3];
  542.             nam->nam$b_ver = fna_size[4];
  543.             nam->nam$b_esl = esa - wccfile->wcf_result;
  544.             nam->nam$l_fnb = 0;
  545.             if (wccfile->wcf_status & STATUS_WILDCARD) nam->nam$l_fnb = NAM$M_WILDCARD;
  546.             if (nam->nam$b_esl <= nam->nam$b_ess) {
  547.                 memcpy(nam->nam$l_esa,wccfile->wcf_result,nam->nam$b_esl);
  548.             } else {
  549.                 return RMS$_ESS;
  550.             }
  551.         }
  552.     }
  553.     sts = 1;
  554.         if (nam != NULL) if (nam->nam$b_nop & NAM$M_SYNCHK) sts = 0;
  555.  
  556.     /* Now build up WCC structures as required */
  557.  
  558.     if (sts) {
  559.         int dirlen,dirsiz;
  560.         char *dirnam;
  561.         struct WCCDIR *wcc;
  562.         struct DEV *dev;
  563.         sts = device_lookup(fna_size[0],wccfile->wcf_result,0,&dev);
  564.         if ((sts & 1) == 0) return sts;
  565.         if ((wccfile->wcf_vcb = dev->vcb) == NULL) return SS$_DEVNOTMOUNT;
  566.         wcc = &wccfile->wcf_wcd;
  567.         wcc->wcd_prev = NULL;
  568.         wcc->wcd_next = NULL;
  569.  
  570.  
  571.  
  572.         /* find directory name - chop off ... if found */
  573.  
  574.         dirnam = wccfile->wcf_result + fna_size[0] + 1;
  575.         dirlen = fna_size[1] - 2;       /* Don't include [] */
  576.         if (dirlen >= 3) {
  577.             if (memcmp(dirnam + dirlen - 3,"...",3) == 0) {
  578.                 wccfile->wcf_status |= STATUS_RECURSE;
  579.                 dirlen -= 3;
  580.                 wccfile->wcf_status |= STATUS_WILDCARD;
  581.             }
  582.         }
  583.         /* see if we can find directory in cache... */
  584.  
  585.         dirsiz = dirlen;
  586.         do {
  587.             char *dirend = dirnam + dirsiz;
  588.             if (dircache(wccfile->wcf_vcb,dirnam,dirsiz,&wcc->wcd_dirid)) break;
  589.             while (dirsiz > 0) {
  590.                 dirsiz--;
  591.                 if (char_delim[*--dirend & 127]) break;
  592.             }
  593.         } while (1);
  594.  
  595.  
  596.         /* Create directory wcc blocks for what's left ... */
  597.  
  598.         while (dirsiz < dirlen) {
  599.             int seglen = 0;
  600.             char *dirptr = dirnam + dirsiz;
  601.             struct WCCDIR *wcd;
  602.             do {
  603.                 if (char_delim[*dirptr++ & 127]) break;
  604.                 seglen++;
  605.             } while (dirsiz + seglen < dirlen);
  606.             wcd = (struct WCCDIR *) malloc(sizeof(struct WCCDIR) + seglen + 8);
  607.             wcd->wcd_wcc = 0;
  608.             wcd->wcd_status = 0;
  609.             wcd->wcd_prelen = 0;
  610.             wcd->wcd_reslen = 0;
  611.             memcpy(wcd->wcd_sernam,dirnam + dirsiz,seglen);
  612.             memcpy(wcd->wcd_sernam + seglen,".DIR;1",7);
  613.             wcd->wcd_serdsc.dsc$w_length = seglen + 6;
  614.             wcd->wcd_serdsc.dsc$a_pointer = wcd->wcd_sernam;
  615.             wcd->wcd_prev = wcc;
  616.             wcd->wcd_next = wcc->wcd_next;
  617.             if (wcc->wcd_next != NULL) wcc->wcd_next->wcd_prev = wcd;
  618.             wcc->wcd_next = wcd;
  619.             wcd->wcd_prelen = fna_size[0] + dirsiz + 1; /* Include [. */
  620.             memcpy(&wcd->wcd_dirid,&wccfile->wcf_wcd.wcd_dirid,sizeof(struct fiddef));
  621.             dirsiz += seglen + 1;
  622.         }
  623.         wcc->wcd_wcc = 0;
  624.         wcc->wcd_status = 0;
  625.         wcc->wcd_reslen = 0;
  626.         wcc->wcd_serdsc.dsc$w_length = fna_size[2] + fna_size[3] + fna_size[4];
  627.         wcc->wcd_serdsc.dsc$a_pointer = wcc->wcd_sernam;
  628.         memcpy(wcc->wcd_sernam,wccfile->wcf_result + fna_size[0] + fna_size[1],
  629.                wcc->wcd_serdsc.dsc$w_length);
  630. #ifdef DEBUG
  631.         wcc->wcd_sernam[wcc->wcd_serdsc.dsc$w_length] = '\0';
  632.         printf("Parse spec is %s\n",wccfile->wcf_wcd.wcd_sernam);
  633.         for (dirsiz = 0; dirsiz < 5; dirsiz++) printf("  %d",fna_size[dirsiz]);
  634.         printf("\n");
  635. #endif
  636.     }
  637.     if (wccret != NULL) *wccret = wccfile;
  638.     if (nam != NULL) nam->nam$l_wcc = (int) wccfile;
  639.     return SS$_NORMAL;
  640. }
  641.  
  642.  
  643. /* External entry for parse function... */
  644.  
  645. unsigned sys_parse(struct FAB *fab)
  646. {
  647.     struct NAM *nam = fab->fab$l_nam;
  648.     if (nam == NULL) return RMS$_NAM;
  649.     return do_parse(fab,NULL);
  650. }
  651.  
  652.  
  653. /* Function to set default directory (heck we can sneak in the device...)  */
  654.  
  655. unsigned sys_setddir(struct dsc$descriptor *newdir,unsigned short *oldlen,
  656.                      struct dsc$descriptor *olddir)
  657. {
  658.     unsigned sts = 1;
  659.     if (oldlen != NULL) {
  660.         int retlen = default_size[0] + default_size[1];
  661.         if (retlen > olddir->dsc$w_length) retlen = olddir->dsc$w_length;
  662.         *oldlen = retlen;
  663.         memcpy(olddir->dsc$a_pointer,default_name,retlen);
  664.     }
  665.     if (newdir != NULL) {
  666.         struct FAB fab = cc$rms_fab;
  667.         struct NAM nam = cc$rms_nam;
  668.         fab.fab$l_nam = &nam;
  669.         nam.nam$b_nop |= NAM$M_SYNCHK;
  670.         nam.nam$b_ess = DEFAULT_SIZE;
  671.         nam.nam$l_esa = default_buffer;
  672.         fab.fab$b_fns = newdir->dsc$w_length;
  673.         fab.fab$l_fna = newdir->dsc$a_pointer;
  674.         sts = sys_parse(&fab);
  675.         if (sts & 1) {
  676.             if (nam.nam$b_name + nam.nam$b_type + nam.nam$b_ver > 2) return RMS$_DIR;
  677.             if (nam.nam$l_fnb & NAM$M_WILDCARD) return RMS$_WLD;
  678.             default_name = default_buffer;
  679.             default_size[0] = nam.nam$b_dev;
  680.             default_size[1] = nam.nam$b_dir;
  681.             memcpy(default_name + nam.nam$b_dev + nam.nam$b_dir,".;",3);
  682.         }
  683.     }
  684.     return sts;
  685. }
  686.  
  687.  
  688. /* This version of connect only resets record pointer */
  689.  
  690. unsigned sys_connect(struct RAB *rab)
  691. {
  692.     rab->rab$w_rfa[0] = 0;
  693.     rab->rab$w_rfa[1] = 0;
  694.     rab->rab$w_rfa[2] = 0;
  695.     rab->rab$w_rsz = 0;
  696.     if (rab->rab$l_fab->fab$b_org == FAB$C_SEQ) {
  697.         return 1;
  698.     } else {
  699.         return SS$_NOTINSTALL;
  700.     }
  701. }
  702.  
  703.  
  704. /* Disconnect is even more boring */
  705.  
  706. unsigned sys_disconnect(struct RAB *rab)
  707. {
  708.     return 1;
  709. }
  710.  
  711.  
  712.  
  713. #define IFI_MAX 10
  714. struct WCCFILE *ifi_table[] = {
  715.     NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
  716. };
  717.  
  718.  
  719. /* get for sequential files */
  720.  
  721. unsigned sys_get(struct RAB *rab)
  722. {
  723.     char delim,*buffer,*output;
  724.     unsigned cpylen,reclen,block,blocks,offset,eofblk;
  725.     unsigned endflg,rfm,sts;
  726.     struct VIOC *vioc;
  727.     struct FCB *fcb = ifi_table[rab->rab$l_fab->fab$w_ifi]->wcf_fcb;
  728.  
  729.     rfm = rab->rab$l_fab->fab$b_rfm;
  730.     if (rfm == FAB$C_STM || rfm == FAB$C_STMCR || rfm == FAB$C_STMLF) {
  731.         delim = 1;
  732.         if (rfm == FAB$C_STMLF) {
  733.             delim = '\n';
  734.         } else {
  735.             if (rfm == FAB$C_STMCR) delim = '\r';
  736.         }
  737.         reclen = rab->rab$w_usz;
  738.     } else {
  739.         delim = 0;
  740.         if (rfm == FAB$C_FIX) {
  741.             reclen = rab->rab$l_fab->fab$w_mrs;
  742.         }
  743.     }
  744.  
  745.     offset = rab->rab$w_rfa[2] + rab->rab$w_rsz;
  746.     block = (rab->rab$w_rfa[1] << 16) + rab->rab$w_rfa[0];
  747.     if (block == 0 && offset == 0) {
  748.         block = 1;
  749.     } else {
  750.         if (rab->rab$b_rac != RAB$C_RFA) {
  751.             if (delim) {
  752.                 offset++;
  753.             } else {
  754.                 if (rfm == FAB$C_VAR) {
  755.                     offset += 2;
  756.                 } else {
  757.                     if (rfm == FAB$C_VFC) offset += 2 + rab->rab$l_fab->fab$b_fsz;
  758.                 }
  759.                 if (offset & 1) offset++;
  760.                 if (rab->rab$l_fab->fab$b_rat & FAB$M_BLK) offset = (offset + 511) / 512 * 512;
  761.             }
  762.             block += offset / 512;
  763.         }
  764.     }
  765.     rab->rab$w_rfa[0] = block & 0xffff;
  766.     rab->rab$w_rfa[1] = block >> 16;
  767.     rab->rab$w_rfa[2] = offset = offset % 512;
  768.  
  769.  
  770.     eofblk = swapw(fcb->head->fh2$w_recattr.fat$l_efblk);
  771.     if (block > eofblk || (block == eofblk &&
  772.                            offset >= fcb->head->fh2$w_recattr.fat$w_ffbyte)) return RMS$_EOF;
  773.     sts = accesschunk(fcb,block,&vioc,&buffer,&blocks,0,NULL);
  774.     if ((sts & 1) == 0) return sts;
  775.  
  776.     if (rfm == FAB$C_VAR || rfm == FAB$C_VFC) {
  777.         unsigned short *lenptr = (unsigned short *) (buffer + offset);
  778.         reclen = *lenptr;
  779.         offset += 2;
  780.     }
  781. #ifdef DEBUG
  782.     printf("Block %d Offset %d Reclen %d Eofblk %d\n",block,offset,reclen,eofblk);
  783. #endif
  784.  
  785.     if (reclen > rab->rab$w_usz) {
  786.         sts = deaccesschunk(vioc,0,0);
  787.         return RMS$_RTB;
  788.     }
  789.     endflg = 0;
  790.     if (block + reclen / 512 >= eofblk) {
  791.         unsigned remaining = (eofblk - block) * 512 - offset +
  792.            fcb->head->fh2$w_recattr.fat$w_ffbyte;
  793.         if (remaining < reclen) {
  794.             reclen = remaining;
  795.             endflg = 1;
  796.         }
  797.     }
  798.     cpylen = 0;
  799.     output = rab->rab$l_ubf;
  800.     while (cpylen < reclen) {
  801.         unsigned seglen = blocks * 512 - offset;
  802.         if (seglen > reclen - cpylen) seglen = reclen - cpylen;
  803.         if (delim) {
  804.             char *inptr = buffer + offset;
  805.             if (delim != 1) {
  806.                 while (seglen-- > 0) {
  807.                     char ch = *inptr++;
  808.                     if (ch == delim) {
  809.                         reclen = cpylen;
  810.                         break;
  811.                     }
  812.                     if (cpylen++ < reclen) {
  813.                         *output++ = ch;
  814.                     } else {
  815.                         sts = RMS$_RTB;
  816.                         reclen = cpylen;
  817.                         break;
  818.                     }
  819.                 }
  820.             } else {
  821.                 while (seglen-- > 0) {
  822.                     char ch = *inptr++;
  823.                     if (ch != 0 || cpylen > 0) {
  824.                         if (ch == '\f' || ch == '\v' || ch == '\n' || ch == '\r') {
  825.                             reclen = cpylen;
  826.                         } else {
  827.                             if (cpylen++ < reclen) {
  828.                                 *output++ = ch;
  829.                             } else {
  830.                                 sts = RMS$_RTB;
  831.                                 reclen = cpylen;
  832.                                 break;
  833.                             }
  834.                         }
  835.                     }
  836.                 }
  837.             }
  838.             if (cpylen == reclen && endflg) break;
  839.         } else {
  840.             if (rfm == FAB$C_VFC) {
  841.                 unsigned fsz = rab->rab$l_fab->fab$b_fsz;
  842.                 if (fsz > seglen) fsz = seglen;
  843.                 if (cpylen < fsz) {
  844.                     fsz = fsz - cpylen;
  845.                     if (rab->rab$l_rhb) memcpy(rab->rab$l_rhb + cpylen,buffer + offset,fsz);
  846.                     cpylen += fsz;
  847.                     offset += fsz;
  848.                     seglen -= fsz;
  849.                 }
  850.             }
  851.             memcpy(output,buffer + offset,seglen);
  852.             output += seglen;
  853.             cpylen += seglen;
  854.         }
  855.         if (cpylen < reclen) {
  856.             sts = deaccesschunk(vioc,0,0);
  857.             block += blocks;
  858.             if (block > eofblk) return RMS$_EOF;
  859.             sts = accesschunk(fcb,block,&vioc,&buffer,&blocks,0,NULL);
  860.             if ((sts & 1) == 0) return sts;
  861.             offset = 0;
  862.         }
  863.     }
  864.     if (rfm == FAB$C_VFC) {
  865.         rab->rab$w_rsz = cpylen - rab->rab$l_fab->fab$b_fsz;;
  866.     } else {
  867.         rab->rab$w_rsz = cpylen;
  868.     }
  869.     deaccesschunk(vioc,0,1);
  870.     return sts;
  871. }
  872.  
  873.  
  874. /* display to fill fab & xabs with info from the file header... */
  875.  
  876. unsigned sys_display(struct FAB *fab)
  877. {
  878.     struct XABDAT *xab = fab->fab$l_xab;
  879.  
  880.     struct HEAD *head = ifi_table[fab->fab$w_ifi]->wcf_fcb->head;
  881.     unsigned short *pp = (unsigned short *) head;
  882.     struct IDENT *id = (struct IDENT *) (pp + head->fh2$b_idoffset);
  883.     int ifi_no = fab->fab$w_ifi;
  884.     if (ifi_no == 0 || ifi_no >= IFI_MAX) return RMS$_IFI;
  885.     fab->fab$l_alq = swapw(head->fh2$w_recattr.fat$l_hiblk);
  886.     fab->fab$b_bks = head->fh2$w_recattr.fat$b_bktsize;
  887.     fab->fab$w_deq = head->fh2$w_recattr.fat$w_defext;
  888.     fab->fab$b_fsz = head->fh2$w_recattr.fat$b_vfcsize;
  889.     fab->fab$w_gbc = head->fh2$w_recattr.fat$w_gbc;
  890.     fab->fab$w_mrs = head->fh2$w_recattr.fat$w_maxrec;
  891.     fab->fab$b_org = head->fh2$w_recattr.fat$b_rtype & 0xf0;
  892.     fab->fab$b_rfm = head->fh2$w_recattr.fat$b_rtype & 0x0f;
  893.     fab->fab$b_rat = head->fh2$w_recattr.fat$b_rattrib;
  894.     while (xab != NULL) {
  895.         switch (xab->xab$b_cod) {
  896.             case XAB$C_DAT:
  897.                 memcpy(&xab->xab$q_bdt,&id->fi2$q_bakdate,sizeof(struct TIME));
  898.                 memcpy(&xab->xab$q_cdt,&id->fi2$q_credate,sizeof(struct TIME));
  899.                 memcpy(&xab->xab$q_edt,&id->fi2$q_expdate,sizeof(struct TIME));
  900.                 memcpy(&xab->xab$q_rdt,&id->fi2$q_revdate,sizeof(struct TIME));
  901.                 xab->xab$w_rvn = id->fi2$w_revision;
  902.                 break;
  903.             case XAB$C_FHC:{
  904.                     struct XABFHC *fhc = (struct XABFHC *) xab;
  905.                     fhc->xab$b_atr = head->fh2$w_recattr.fat$b_rattrib;
  906.                     fhc->xab$b_bkz = head->fh2$w_recattr.fat$b_bktsize;
  907.                     fhc->xab$w_dxq = head->fh2$w_recattr.fat$w_defext;
  908.                     fhc->xab$l_ebk = swapw(head->fh2$w_recattr.fat$l_efblk);
  909.                     fhc->xab$w_ffb = head->fh2$w_recattr.fat$w_ffbyte;
  910.                     if (fhc->xab$l_ebk == 0) {
  911.                         fhc->xab$l_ebk = fab->fab$l_alq;
  912.                         if (fhc->xab$w_ffb == 0) fhc->xab$l_ebk++;
  913.                     }
  914.                     fhc->xab$w_gbc = head->fh2$w_recattr.fat$w_gbc;
  915.                     fhc->xab$l_hbk = swapw(head->fh2$w_recattr.fat$l_hiblk);
  916.                     fhc->xab$b_hsz = head->fh2$w_recattr.fat$b_vfcsize;
  917.                     fhc->xab$w_lrl = head->fh2$w_recattr.fat$w_maxrec;
  918.                     fhc->xab$w_verlimit = head->fh2$w_recattr.fat$w_versions;
  919.                 }
  920.                 break;
  921.             case XAB$C_PRO:{
  922.                     struct XABPRO *pro = (struct XABPRO *) xab;
  923.                     pro->xab$w_pro = head->fh2$w_fileprot;
  924.                     memcpy(&pro->xab$l_uic,&head->fh2$l_fileowner,4);
  925.                 }
  926.         }
  927.         xab = xab->xab$l_nxt;
  928.     }
  929.  
  930.     return 1;
  931. }
  932.  
  933.  
  934. /* close a file */
  935.  
  936. unsigned sys_close(struct FAB *fab)
  937. {
  938.     int sts;
  939.     int ifi_no = fab->fab$w_ifi;
  940.     if (ifi_no < 1 || ifi_no >= IFI_MAX) return RMS$_IFI;
  941.     sts = deaccessfile(ifi_table[ifi_no]->wcf_fcb);
  942.     if (sts & 1) {
  943.         ifi_table[ifi_no]->wcf_fcb = NULL;
  944.         if (ifi_table[ifi_no]->wcf_status & STATUS_TMPWCC) {
  945.             cleanup_wcf(ifi_table[ifi_no]);
  946.             if (fab->fab$l_nam != NULL) fab->fab$l_nam->nam$l_wcc = 0;
  947.         }
  948.         fab->fab$w_ifi = 0;
  949.         ifi_table[ifi_no] = NULL;
  950.     }
  951.     return sts;
  952. }
  953.  
  954.  
  955. /* open a file */
  956.  
  957. unsigned sys_open(struct FAB *fab)
  958. {
  959.     unsigned sts;
  960.     int ifi_no = 1;
  961.     int wcc_flag = 0;
  962.     struct WCCFILE *wccfile = NULL;
  963.     struct NAM *nam = fab->fab$l_nam;
  964.     if (fab->fab$w_ifi != 0) return RMS$_IFI;
  965.     while (ifi_table[ifi_no] != NULL && ifi_no < IFI_MAX) ifi_no++;
  966.     if (ifi_no >= IFI_MAX) return RMS$_IFI;
  967.     if (nam != NULL) {
  968.         wccfile = (struct WCCFILE *) nam->nam$l_wcc;
  969.     }
  970.     if (wccfile == NULL) {
  971.         sts = do_parse(fab,&wccfile);
  972.         if (sts & 1) {
  973.             wcc_flag = 1;
  974.             if (wccfile->wcf_status & STATUS_WILDCARD) {
  975.                 sts = RMS$_WLD;
  976.             } else {
  977.                 sts = do_search(fab,wccfile);
  978.             }
  979.             wccfile->wcf_status |= STATUS_TMPWCC;
  980.         }
  981.     } else {
  982.         sts = 1;
  983.     }
  984.     if (sts & 1) sts = accessfile(wccfile->wcf_vcb,&wccfile->wcf_fid,&wccfile->wcf_fcb,0);
  985.     if (sts & 1) {
  986.         ifi_table[ifi_no] = wccfile;
  987.         fab->fab$w_ifi = ifi_no;
  988.         sys_display(fab);
  989.     }
  990.     if (wcc_flag && ((sts & 1) == 0)) {
  991.         cleanup_wcf(wccfile);
  992.         if (nam != NULL) nam->nam$l_wcc = 0;
  993.     }
  994.     return sts;
  995. }
  996.  
  997.  
  998. /* blow away a file */
  999.  
  1000. unsigned sys_erase(struct FAB *fab)
  1001. {
  1002.     unsigned sts;
  1003.     int ifi_no = 1;
  1004.     int wcc_flag = 0;
  1005.     struct WCCFILE *wccfile = NULL;
  1006.     struct NAM *nam = fab->fab$l_nam;
  1007.     if (fab->fab$w_ifi != 0) return RMS$_IFI;
  1008.     while (ifi_table[ifi_no] != NULL && ifi_no < IFI_MAX) ifi_no++;
  1009.     if (ifi_no >= IFI_MAX) return RMS$_IFI;
  1010.     if (nam != NULL) {
  1011.         wccfile = (struct WCCFILE *) fab->fab$l_nam->nam$l_wcc;
  1012.     }
  1013.     if (wccfile == NULL) {
  1014.         sts = do_parse(fab,&wccfile);
  1015.         if (sts & 1) {
  1016.             wcc_flag = 1;
  1017.             if (wccfile->wcf_status & STATUS_WILDCARD) {
  1018.                 sts = RMS$_WLD;
  1019.             } else {
  1020.                 sts = do_search(fab,wccfile);
  1021.             }
  1022.         }
  1023.     } else {
  1024.         sts = 1;
  1025.     }
  1026.     if (sts & 1) {
  1027.         struct fibdef fibblk;
  1028.         struct dsc$descriptor fibdsc,serdsc;
  1029.         fibdsc.dsc$w_length = sizeof(struct fibdef);
  1030.         fibdsc.dsc$a_pointer = (char *) &fibblk;
  1031.         serdsc.dsc$w_length = wccfile->wcf_wcd.wcd_reslen;
  1032.         serdsc.dsc$a_pointer = wccfile->wcf_result + wccfile->wcf_wcd.wcd_prelen;
  1033.         memcpy(&fibblk.fib$w_did_num,&wccfile->wcf_wcd.wcd_dirid,sizeof(struct fiddef));
  1034.         fibblk.fib$w_nmctl = 0;
  1035.         fibblk.fib$l_acctl = 0;
  1036.         fibblk.fib$w_fid_num = 0;
  1037.         fibblk.fib$w_fid_seq = 0;
  1038.         fibblk.fib$b_fid_rvn = 0;
  1039.         fibblk.fib$b_fid_nmx = 0;
  1040.         fibblk.fib$l_wcc = 0;
  1041.         sts = direct(wccfile->wcf_vcb,&fibdsc,&serdsc,NULL,NULL,1);
  1042.         if (sts & 1) sts = accesserase(wccfile->wcf_vcb,&wccfile->wcf_fid);
  1043.     }
  1044.     if (wcc_flag) {
  1045.         cleanup_wcf(wccfile);
  1046.         if (nam != NULL) nam->nam$l_wcc = 0;
  1047.     }
  1048.     return sts;
  1049. }
  1050.