home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / cpgms.zip / LAR261.C < prev    next >
Text File  |  1985-08-05  |  27KB  |  1,121 lines

  1. /* 
  2.  * Lar - LU format library file maintainer 
  3.  *     by     Stephen C. Hemminger 
  4.  *         Bedford MA 
  5.  * 
  6.  *    DeSmet version T. Bonfield        Feb 84
  7.  *    DeSmet updates R. McVay            Mar 84
  8.  */
  9. #define VERSION        2
  10. #define REVISION    61
  11. #define LAST_MOD    "27 Oct 84"
  12. /* 
  13.  * DESCRIPTION 
  14.  *    Lar is a program to manipulate CP/M LU format libraries. 
  15.  *    The original CP/M library program LU is the product 
  16.  *    of Gary P. Novosielski. The primary use of lar is to combine several 
  17.  *    files together for upload/download to a personal computer. 
  18.  * 
  19.  * Usage: lar [-]key library [files] ...
  20.  * 
  21.  * Key functions are: 
  22.  * a - Add files to library    (also creates new libraries) 
  23.  * l - List directory of library
  24.  * e - Extract files from library 
  25.  * p - Print files in library 
  26.  * d - Delete files in library 
  27.  * r - Reorganize library 
  28.  * 
  29.  * EXAMPLES: 
  30.  * lar l foo.lbr        list all files in FOO.LBR 
  31.  * lar e foo.lbr 1.c 2.c    extract files 1.c, 2.c from FOO.LBR 
  32.  * lar p foo.lbr 1.c        display 1.c from FOO.LBR 
  33.  * lar a foo.lbr 1.c 2.c 3.c     add or replace files in FOO.LBR 
  34.  * 
  35.  * When creating a new library, you will be prompted for the maximum 
  36.  * number of entries it can contain. Assuming NEW.LBR doen't exist ... 
  37.  * lar a new.lbr        create an empty library 
  38.  * lar a new.lbr a.c,b.c,d.c    create NEW.LBR, add files. 
  39.  * 
  40.  * The Reorganize option causes <lbrfile>.tmp to be created, and 
  41.  * the contents of the old library to be copied into it. 
  42.  * 
  43.  * This program is public domain software, no warranty intended or 
  44.  * implied. 
  45.  * 
  46.  * 
  47.  * PORTABILITY 
  48.  *    The original version by Stephan C. Hemminger was set up for  
  49.  *    Version 7 UNIX, and was not useable as is. It has been hacked 
  50.  *    to fit the DeSmet C compiler for MSDOS. The basic 
  51.  *    problems were: fread() and fwrite() incompatibility, no  
  52.  *    text/binary differentiation problem in MSDOS. 
  53.  * 
  54.  *    Also, I have made random changes to the source merely to reflect 
  55.  *    my programming taste; he original code was quite good. I have also 
  56.  *    changed the wording of some errors, etc more in line with the current 
  57.  *    flavor of messages in the micro environment. The original Verbose 
  58.  *    flag option was removed, and made the default. No need to suppress 
  59.  *    what few messages and text there is. 
  60.  * 
  61.  *    As mentioned before, ther is no problem with text or binary files; 
  62.  *     they are treated identically. Control-Z characters are added to the 
  63.  *    end of all files to round it up to a multiple of 128 bytes. 
  64.  * 
  65.  *    Note that all files are kept as multiples of 128 bytes, to be  
  66.  *    compatible with the CP/M utility LU. This may present a problem 
  67.  *    with certain data files, but will be OK for text and .COM files 
  68.  *    anyways, and probably most other files. 
  69.  *                                             T. Bonfield
  70.  *
  71.  *  v1.1- added the exception handler for a "dashed" option and a default
  72.  *        library extension of .lbr. 
  73.  *      - fixed a bug that put the drive descriptor into the library file
  74.  *        entry.
  75.  *  v1.2- fixed a "member not found" bug by forcing all filenames to lower
  76.  *        case.
  77.  *      - changed the commands u->a and t->l to jive with LU better.
  78.  *  v1.3- fixed subtle "casting" bug in copyentry().
  79.  *      - copyentry() now uses acopy().
  80.  *      - rewrote fcopy() and acopy() to use 16K copy buffer to
  81.  *        eliminate disk thrashing on -a -e & -r.
  82.  *      - fixed "not enough room" bug in reorg().
  83.  *    v1.4- fixed bug in acopy() that crashed big member extractions.
  84.  *        - increased copy buffer size to 32K - 128.
  85.  *    v2.0-2.2- wildcards added by P.H. Mack based on v1.1
  86.  *    v2.3-2.4- ???
  87.  *    v2.5- wildcard references to members added to v1.4 (inspired by P.H. Mack)
  88.  *        - cleaned up acopy()'s handling of -p option
  89.  *        - generalized getname() & cvt_to_fcb a little
  90.  *    v2.6- wildcards for -a
  91.  *    v2.61-cleaned up a bit, sprinked in a few console status checks for
  92.  *          MultiLink users
  93.  *                                             R. McVay
  94.  * 
  95.  * * Unix is a trademark of Bell Labs. 
  96.  * ** CP/M is a trademark of Digital Research. 
  97.  */ 
  98.  
  99.  
  100. #include <stdio.h>
  101.  
  102. /* Library file status values: */ 
  103.  
  104. #define ACTIVE    0 
  105. #define UNUSED    0xff 
  106. #define    DELETED    0xfe 
  107. #define    CTRLZ    0x1a 
  108.  
  109. #define    MAXFILES 256
  110. #define    SECTOR     128 
  111. #define BIGBUFF 32640
  112. #define    DSIZE    (sizeof(struct ludir)) 
  113. #define    SLOTS_SEC (SECTOR/DSIZE) 
  114. #define    equal(s1, s2) (    strcmp(s1,s2) == 0 ) 
  115. #define FALSE    0 
  116. #define    TRUE    1 
  117. #define    BOOL    int 
  118.  
  119. /* Globals */ 
  120. char    *fname[MAXFILES]; 
  121. BOOL    ftouched[MAXFILES]; 
  122.  
  123. struct ludir {            /* internal dir. stucture, 32 bytes */ 
  124.     char    l_stat;        /* 12 byte filename: */ 
  125.     char    l_name[8];
  126.     char    l_ext[3];
  127.     int        l_off;            /* offset in library, */ 
  128.     int        l_len;            /* length of file, */ 
  129.     char    l_fill[16];        /* 16 byte filler, */ 
  130. } ldir[MAXFILES]; 
  131.  
  132. int        errcnt,
  133.         nfiles,
  134.         nslots; 
  135.  
  136. char    *getname(),
  137.         *strlower(),
  138.         *malloc(); 
  139.  
  140. long    lseek();
  141.  
  142. char    aname[20];        /* global library name reference */
  143.  
  144.  
  145. main(argc, argv) 
  146. int        argc; 
  147. char    *argv[]; 
  148.     char    *flagp,
  149.             *request; 
  150.  
  151.     if (argc < 3)
  152.         help(); 
  153.     if (*argv[1] == '-') /* strip the dash if present */
  154.         ++argv[1];
  155.     *argv[1] = tolower(*argv[1]);
  156.  
  157.     strcpy(aname, argv[2]);            /* name of LBR file, */ 
  158.     if ((index(aname, "*") > -1) || (index(aname, "?") > -1))
  159.             error("wildcards not allowed in library name");
  160.     if (index(aname, ".") == -1)    /* add default extension .lbr */
  161.         strcat(aname, ".lbr");
  162.     argv[2] = aname;
  163.  
  164.     filenames(argc, argv); 
  165.  
  166.     switch (*argv[1])
  167.     { 
  168.         case 'l':            /* list table of contents */
  169.             table(aname); 
  170.             break; 
  171.  
  172.         case 'a':            /* add */
  173.             update(aname); 
  174.             break; 
  175.  
  176.         case 'e':            /* extract members */
  177.             getfiles(aname, FALSE); 
  178.             break; 
  179.  
  180.         case 'p':            /* print members */
  181.             getfiles(aname, TRUE); 
  182.             break; 
  183.  
  184.         case 'd':            /* delete members */
  185.             delete(aname); 
  186.             break; 
  187.  
  188.         case 'r':            /* reorganize library */
  189.             reorg(aname); 
  190.             break; 
  191.  
  192.         default:            /* bad request */
  193.             printf("err: unrecognized function [%s]\n\n", argv[1]);
  194.             help(); 
  195.             break;
  196.     } 
  197.     exit(0); 
  198.  
  199.  
  200. /************************************************************************
  201. * Get file names, check for dups, and initialize                        * 
  202. * This is where we'll encounter and expand wildcards                    *
  203. ************************************************************************/
  204.  
  205. filenames(ac, av)
  206. int        ac;
  207. char    *av[]; 
  208.     int i,
  209.         j; 
  210.  
  211.     errcnt = 0; 
  212.     for (i = 3, j = 0; i < ac; i++, j++)
  213.     { 
  214.         fname[j] = calloc(15, 1);    /* we're going to copy all file args */
  215.         cvt_to_fcb(strlower(av[i]), fname[j]); 
  216.         ftouched[j] = FALSE; 
  217.         if (j >= MAXFILES) 
  218.             error("Too many file names."); /* we'll double check in wildexp() */
  219.         if (index(fname[j], "?") > -1)
  220.             j = wildexp(j, *av[1]);
  221.     } 
  222.     nfiles = j; 
  223.  
  224.     for (i = 0; i < nfiles; i++)     /* pack 'em back up */
  225.     {
  226.         j = index(fname[i], ":") + 1;
  227.         strcpy(fname[i]+j, getname(fname[i]+j));
  228.     }
  229.  
  230.     for (i = 0; i < nfiles; i++)
  231.     {
  232.         for (j = i + 1; j < nfiles; j++)
  233.         {
  234.             if (equal(fname[i], fname[j]))
  235.             { 
  236.                 printf("%s ", fname[i]); 
  237.                 error("duplicate file name"); 
  238.             }
  239.         }
  240.     } 
  241.  
  242.  
  243. /************************************************************************
  244. * Do wildcard expansion of ambiguous name at fname[j].                    *
  245. * Return the resulting "expanded" index to the last name in the fname    *
  246. * list.                                                                    *
  247. ************************************************************************/
  248.  
  249. wildexp(j, func)
  250. int        j;
  251. char    func;
  252. {
  253. #define    GETDTA    0x2F00
  254. #define    FIRST    0x1100
  255. #define    NEXT    0x1200
  256.     FILE    lfd;
  257.     char    pattern[15], libname[15];
  258.     int        i, k, mode, oj;
  259.     int        our_dta_oset, our_dta_seg;
  260.     extern    int    _rax, _rbx, _rdx, _rds, _res;
  261.  
  262.     struct fcb
  263.     {
  264.         char    drvnum,
  265.                 name[8],
  266.                 ext[3],
  267.                 misc[20];
  268.     } search_fcb;
  269.         
  270.  
  271.     strcpy(pattern, fname[j]);    /* this allows us to return an    */
  272.     free(fname[j]);                /* index to a valid name, even    */
  273.     oj = --j;                    /* if none is found here        */
  274.  
  275.     if (func == 'a')
  276.     {
  277.         /* Then expansion must be done on disk file names.    *
  278.          * Sorry, but this is very compiler dependent.    The    *
  279.          * following code uses DeSmet's _doint() and a pre-    *
  280.          * defined set of "register" variables.                */
  281.  
  282.         for (i = 0; i < 15; libname[i++] = '\0')
  283.             ;
  284.         cvt_to_fcb(aname, libname);
  285.  
  286.         _rax = GETDTA;
  287.         _doint(0x21);
  288.         our_dta_seg = _res;
  289.         our_dta_oset = _rbx;
  290.  
  291.         /* The first order of business is to set up the fcb    *
  292.          * the DOS will use as a pattern for the search.    */
  293.  
  294.         if (pattern[1] == ':')    /* set up drive number        */
  295.         {
  296.             search_fcb.drvnum = toupper(*pattern) - 'A' + 1;
  297.             strcpy(search_fcb.name, pattern + 2);
  298.         }
  299.         else
  300.         {
  301.             search_fcb.drvnum = '\0';
  302.             strcpy(search_fcb.name, pattern);
  303.         }
  304.  
  305.         /* Now we'll scan any matching filenames into         *
  306.          * fnames[] using an algorithm stolen shamelessly    *
  307.          * from sq18u.c.                                    */
  308.  
  309.         for (mode = FIRST;; mode = NEXT)
  310.         {
  311.             csts();        /* for MultiLink users */
  312.             _rdx = search_fcb;
  313.             _rds = -1;
  314.             _rax = mode;
  315.             _doint(0x21);
  316.             if ((_rax & 0xFF) == 0xFF)    /* no match found    */
  317.                 break;
  318.  
  319.             ++j;
  320.             if (j >= MAXFILES)
  321.                 error("(wildexp) too many files");
  322.             else
  323.                 fname[j] = calloc(15, 1);
  324.             if (!fname[j])
  325.                 error("(wildexp) out of memory");
  326.             else
  327.             {
  328.                 if (pattern[1] == ':')
  329.                 {
  330.                     fname[j][0] = *pattern;
  331.                     fname[j][1] = ':';
  332.                     i = 2;
  333.                 }
  334.                 else
  335.                     i = 0;
  336.                 _lmove(11, our_dta_oset + 1, our_dta_seg, &fname[j][i], _showds());
  337.                 fname[j][i + 11] = '\0';
  338.                 if (equal(libname, fname[j]))
  339.                 {
  340.                     free(fname[j]);
  341.                     --j;
  342.                 }
  343.             }
  344.         }
  345.     }
  346.     else
  347.     {
  348.         /* expansion is from names in library table of contents */
  349.         /* library name can't be ambiguous                        */
  350.         if ((lfd = open(aname, 2)) == -1)
  351.             cant(aname);
  352.         getdir(lfd);
  353.  
  354.         for (i = 1; i < nslots; i++)
  355.         {
  356.             csts();        /* for MultiLink users */
  357.             if (ldir[i].l_stat == ACTIVE)
  358.             {
  359.                 ldir[i].l_off = 0;    /* setting up end of string */
  360.                 if (amatch(pattern, ldir[i].l_name))
  361.                 {
  362.                     ++j;
  363.                     if (j >= MAXFILES)
  364.                         error("(wildexp) too many files");
  365.                     else
  366.                         fname[j] = calloc(15, 1);
  367.                     if (!fname[j])
  368.                         error("(wildexp) out of memory");
  369.                     else
  370.                         strcpy(fname[j], ldir[i].l_name);
  371.                 }
  372.             }
  373.         }
  374.     }
  375.     if (j == oj)
  376.         printf("wildexp: %s not matched\n", pattern);
  377.     return(j);
  378. }
  379.  
  380.  
  381. /************************************************************************
  382. * try to match a filename to an ambiguous pattern; lengths must match    *
  383. ************************************************************************/
  384.  
  385. amatch(pattern, fname)
  386. char    *pattern,
  387.         *fname;
  388. {
  389.     while (*pattern && *fname)
  390.     {
  391.         if ((*pattern != '?') && (*pattern != *fname))
  392.             return(FALSE);
  393.         ++pattern;
  394.         ++fname;
  395.     }
  396.     return(*pattern == *fname);
  397. }
  398.  
  399.  
  400. /************************************************************************
  401. * list the contents and statistics of the library                        *
  402. ************************************************************************/
  403.  
  404. table(lib) 
  405. char *lib; 
  406.     FILE    lfd; 
  407.     int        i,
  408.             total; 
  409.     int        active = 0, 
  410.             unused = 0, 
  411.             deleted = 0; 
  412.     char     *uname; 
  413.  
  414.     if ((lfd = open(lib,2)) == -1) 
  415.         cant(lib); 
  416.  
  417.     getdir(lfd); 
  418.     total =    ldir[0].l_len; 
  419.     printf("Name         Index    Length (128 byte blocks)\n"); 
  420.     printf("Directory    %4u    %6u\n", 0, total); 
  421.  
  422.     for (i = 1; i < nslots;    i++)
  423.     {
  424.         csts();        /* for MultiLink users */
  425.         switch(ldir[i].l_stat) 
  426.         { 
  427.             case ACTIVE: 
  428.                 active++; 
  429.                 uname = getname(&ldir[i].l_name); 
  430.                 total += ldir[i].l_len; 
  431.                 printf("%-12s %4u   %7u\n", uname,ldir[i].l_off,ldir[i].l_len); 
  432.                 break; 
  433.             case UNUSED: 
  434.                 unused++; 
  435.                 break; 
  436.             default: 
  437.                 deleted++; 
  438.                 break;
  439.         }
  440.     } 
  441.     printf("-----------------------------\n"); 
  442.     printf("Total blocks        %7u\n", total); 
  443.     printf("\nLibrary %s has %u slots, %u deleted, %u active, %u unused\n", 
  444.         lib, nslots, deleted, active, unused); 
  445.     close(lfd); 
  446.     not_found (); 
  447.  
  448.  
  449. /************************************************************************
  450. * add new members to a library; create the library if necessary            *
  451. ************************************************************************/
  452.  
  453. update(name) 
  454. char    *name; 
  455.     FILE    lfd; 
  456.     int        i; 
  457.      
  458.     if ((lfd = open(name,2)) == -1)
  459.     { 
  460.         if ((lfd = creat(name)) == -1) 
  461.             cant(name); 
  462.         initdir(lfd); 
  463.     }  
  464.     getdir(lfd);            /* read directory, */ 
  465.  
  466.     for (i = 0; (i < nfiles) && (errcnt == 0); i++) 
  467.         addfil(fname[i], lfd); 
  468.     if (errcnt != 0) 
  469.         printf("fatal errors - last file may be bad\n"); 
  470.     putdir(lfd); 
  471.     close(lfd); 
  472.  
  473.  
  474. /************************************************************************
  475. * extract (or print if pflag) a library member                            *
  476. ************************************************************************/
  477.  
  478. getfiles(name, pflag) 
  479. char    *name; 
  480. BOOL    pflag; 
  481.     FILE    lfd,
  482.             ofd; 
  483.     int        i; 
  484.     char    *unixname; 
  485.  
  486.     if ((lfd = open(name,2)) == -1) 
  487.         cant (name); 
  488.  
  489.     getdir(lfd); 
  490.  
  491.     for (i = 1; i < nslots;    i++) 
  492.     { 
  493.         if (ldir[i].l_stat == ACTIVE) 
  494.         {
  495.             unixname = getname(&ldir[i].l_name); 
  496.             if (filarg(unixname)) 
  497.             {
  498.                 printf("Extracting %s\n", unixname); 
  499.                 
  500.                 if (pflag) 
  501.                     ofd = STDOUT; 
  502.                 else 
  503.                     ofd = creat(unixname); 
  504.     
  505.                 if (ofd == -1) 
  506.                 { 
  507.                     printf("%s - can't create output file\n",unixname); 
  508.                     errcnt++; 
  509.                 } 
  510.                 else 
  511.                 { 
  512.                     lseek(lfd, (long) ldir[i].l_off * SECTOR,0); 
  513.                     acopy(lfd, ofd, ldir[i].l_len); 
  514.                     if (!pflag) 
  515.                         close(ofd); 
  516.                 } 
  517.             }
  518.         }
  519.     } 
  520.     close(lfd); 
  521.     not_found(); 
  522.  
  523.  
  524. /************************************************************************
  525. * mark a library directory entry as deleted                                *
  526. ************************************************************************/
  527.  
  528. delete(lname) 
  529. char    *lname; 
  530.     FILE    f; 
  531.     int        i; 
  532.  
  533.     if ((f = open(lname,2)) == -1) 
  534.         cant(lname); 
  535.  
  536.     if (nfiles <= 0) 
  537.         error("delete by name only"); 
  538.  
  539.     getdir(f); 
  540.     for (i = 0; i < nslots;    i++)
  541.     { 
  542.         if (filarg(getname(&ldir[i].l_name))) 
  543.             ldir[i].l_stat = DELETED; 
  544.     } 
  545.  
  546.     not_found(); 
  547.     if (errcnt > 0) 
  548.         printf("errors - library not updated\n"); 
  549.     else
  550.         putdir(f); 
  551.     close(f); 
  552.  
  553.  
  554. /************************************************************************
  555. * reorganize a library                                                    *
  556. ************************************************************************/
  557.  
  558. reorg(name) 
  559. char    *name; 
  560.     FILE    olib,
  561.             nlib; 
  562.     int        oldsize,
  563.             i,
  564.             j; 
  565.     struct    ludir    odir[MAXFILES]; 
  566.     char    tmpname[SECTOR]; 
  567.  
  568.     for (i = 0; (i < 8) && (name[i] != '.'); i++) /* copy filename, */ 
  569.         tmpname[i]= name[i];        /* strip off extention, */ 
  570.     tmpname[i]= '\0'; 
  571.     strcat(tmpname,".tmp");            /* make new name, */ 
  572.  
  573.     if ((olib = open(name,2)) == -1) 
  574.         cant(name); 
  575.  
  576.     if ((nlib = creat(tmpname)) == -1) 
  577.         cant(tmpname); 
  578.  
  579.     getdir(olib); 
  580.     printf("Old library has %d slots\n", oldsize = nslots); 
  581.     for (i = 0; i < nslots ; i++) 
  582.         copymem((char *)&odir[i], (char *)&ldir[i], sizeof(struct ludir)); 
  583.     initdir(nlib); 
  584.     errcnt = 0; 
  585.  
  586.     for (i = j = 1; (i < oldsize) && !errcnt; i++) 
  587.     {
  588.         if (odir[i].l_stat == ACTIVE)
  589.         { 
  590.             printf("Copying: %-8.8s.%3.3s\n", &odir[i].l_name, &odir[i].l_ext); 
  591.             copyentry(&odir[i], olib, &ldir[j], nlib); 
  592.             if (++j > nslots)
  593.             { 
  594.                 errcnt++; 
  595.                 printf("Not enough room in new library\n"); 
  596.             } 
  597.         }
  598.     } 
  599.  
  600.     close(olib); 
  601.     putdir(nlib); 
  602.     close(nlib); 
  603.  
  604.     if (errcnt)
  605.     { 
  606.         printf("Errors, library not updated\n"); 
  607.         unlink(tmpname); 
  608.     }
  609.     else
  610.     { 
  611.         unlink(name);            /* delete orig file, */ 
  612.         rename(tmpname,name);        /* rename it, */ 
  613.     } 
  614.  
  615.  
  616. /************************************************************************ 
  617. * print error message and exit                                            *
  618. ************************************************************************/
  619.  
  620. help()
  621.     printf("LAR v%d.%d - %s\n", VERSION, REVISION, LAST_MOD); 
  622.     printf("\nUsage: lar [-]<aledrp> library [files] ...\n"); 
  623.     printf("\nFunctions are:\n\ta - Add files to library (*)\n"); 
  624.     printf("\tl - List library directory\n"); 
  625.      printf("\te - Extract files from library (*)\n"); 
  626.     printf("\td - Delete files in library (*)\n"); 
  627.     printf("\tr - Reorganize library\n"); 
  628.     printf("\tp - Print files in library (*)\n"); 
  629.     printf("\nAssumed library extension is .LBR\n");
  630.     printf("\n(*) Wildcards allowed with these functions.\n");
  631.     exit(1); 
  632. }
  633.  
  634.  
  635. /************************************************************************ 
  636. * return index of t in s, -1 if none                                    *
  637. ************************************************************************/
  638.  
  639. index(s, t)
  640. char    *s,
  641.         *t;
  642. {
  643.     int        i,
  644.             j,
  645.             k;
  646.  
  647.     for (i = 0; s[i] != '\0'; i++)
  648.     {
  649.         for (j = i, k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++)
  650.             ;
  651.         if (t[k] == '\0')
  652.             return(i);
  653.     }
  654.     return(-1);
  655. }
  656.  
  657.  
  658. /************************************************************************ 
  659. * print an error message string and exit                                *
  660. ************************************************************************/
  661.  
  662. error(str) 
  663. char *str; 
  664.     printf("LAR: %s\n", str); 
  665.     exit(1); 
  666.  
  667.  
  668. /************************************************************************
  669. * can't perform function because of file error                            *
  670. ************************************************************************/
  671.  
  672. cant(name) 
  673. char *name; 
  674.  
  675.     printf("%s: File open error\n", name); 
  676.     exit(1); 
  677.  
  678.  
  679. /************************************************************************
  680. * read the directory of a library into the ludir structure                *
  681. ************************************************************************/
  682.  
  683. getdir(f) 
  684. FILE f; 
  685.     int cnt; 
  686.  
  687.     lseek(f,0L,0); 
  688.     if (read(f,&ldir[0],DSIZE) != DSIZE)    /* read 1st entry to find */ 
  689.         error("No directory\n");            /* number of slots, */ 
  690.  
  691.     nslots = ldir[0].l_len * SLOTS_SEC; 
  692.     cnt = DSIZE * (nslots - 1);                /* already read one slot, */ 
  693.  
  694.     if (read(f,&ldir[1],cnt) != cnt) 
  695.         error("Can't read directory - is it a library?"); 
  696.  
  697.  
  698. /************************************************************************
  699. * write the ludir structure to the beginning of the library file        *
  700. ************************************************************************/
  701.  
  702. putdir(f) 
  703. FILE f; 
  704.  
  705.     lseek(f,0L,0); 
  706.     if (write(f,&ldir,nslots * DSIZE) != (nslots * DSIZE)) 
  707.         error("Can't write directory - library may be botched"); 
  708.  
  709.  
  710. /************************************************************************
  711. * format a virgin library directory                                        *
  712. ************************************************************************/
  713.  
  714. initdir(f) 
  715. FILE f; 
  716.     int i; 
  717.     int numsecs; 
  718.     char line[80]; 
  719.  
  720.     do
  721.     { 
  722.         puts ("Number of slots to allocate: "); 
  723.         gets(line); 
  724.         putchar('\n'); 
  725.         nslots = atoi (line); 
  726.         if (nslots < 1)
  727.         {
  728.             nslots = 0;
  729.             printf("Must have at least one!\n");
  730.         }
  731.         else if (nslots > MAXFILES)
  732.         {
  733.             nslots = 0; 
  734.             printf("Too many slots\n"); 
  735.         }
  736.     }
  737.     while (nslots == 0); 
  738.  
  739.     numsecs    = nslots / SLOTS_SEC; 
  740.     if (nslots != numsecs * SLOTS_SEC)
  741.         ++numsecs;
  742.     nslots = numsecs * SLOTS_SEC; 
  743.  
  744.     for (i = 0; i < nslots;    i++)
  745.     { 
  746.         ldir[i].l_stat = UNUSED; 
  747.         blank_fill(&ldir[i].l_name,8); 
  748.         blank_fill(&ldir[i].l_ext,3); 
  749.     } 
  750.     ldir[0].l_stat = ACTIVE; 
  751.     ldir[0].l_len = numsecs; 
  752.  
  753.     putdir(f); 
  754.  
  755.  
  756. /************************************************************************
  757. * Fill a string with blanks, no trailing null                            *
  758. ************************************************************************/
  759.  
  760. blank_fill(s, n)
  761. char    *s; 
  762. int        n; 
  763.     while (n--) *s++= ' '; 
  764.  
  765.  
  766. /************************************************************************
  767. * convert nm.ex to a Unix style string                                    *
  768. ************************************************************************/
  769.  
  770. char *getname(nm)
  771. char    *nm; 
  772.     static char namebuf[14]; 
  773.     int        i,
  774.             j; 
  775.  
  776.     for (i = 0; (i < 8) && (nm[i] != ' '); i++) 
  777.         namebuf[i] = tolower(nm[i]); 
  778.     namebuf[i++] = '.';
  779.     j = i;
  780.  
  781.     for (i = 8; (i < 11) && (nm[i] != ' '); i++, j++) 
  782.         namebuf[j] = tolower(nm[i]); 
  783.     namebuf[j] = '\0'; 
  784.  
  785.     return namebuf; 
  786.  
  787.  
  788. /************************************************************************
  789. * check if name matches argument list                                    *
  790. ************************************************************************/
  791.  
  792. filarg(name)
  793. char    *name; 
  794.     register int i;
  795.  
  796.     if (nfiles <= 0) 
  797.         return 1; 
  798.  
  799.     for (i = 0; i < nfiles;    i++) 
  800.     if (equal(name, fname[i]))
  801.     { 
  802.         ftouched[i] = TRUE; 
  803.         return    1; 
  804.     } 
  805.  
  806.     return 0; 
  807.  
  808.  
  809. /************************************************************************
  810. * tolower() all characters in a string                                *
  811. ************************************************************************/
  812.  
  813. char *strlower(string)
  814. char *string;
  815. {
  816.     char *ptr;
  817.  
  818.     ptr = string;
  819.     while (*string)
  820.     {
  821.         *string = tolower(*string);
  822.         ++string;
  823.     }
  824.     return(ptr);
  825.  
  826.  
  827. /************************************************************************
  828. * print an error message for unmatched argument and bump errcnt            *
  829. ************************************************************************/
  830.  
  831. not_found() 
  832.     register int i; 
  833.  
  834.     for (i = 0; i < nfiles;    i++) 
  835.     if (!ftouched[i])
  836.     { 
  837.         printf("%s : not in library.\n", fname[i]); 
  838.         errcnt++; 
  839.     } 
  840.  
  841.  
  842. /************************************************************************
  843. * copy nsec*128 bytes from one file to another                            *
  844. ************************************************************************/
  845.  
  846. acopy(fdi, fdo, nsecs) 
  847. FILE    fdi,
  848.         fdo; 
  849. int        nsecs; 
  850.     char    *buf; 
  851.     int        n,
  852.             i;
  853.  
  854.     if ((buf = malloc(BIGBUFF)) == 0)
  855.         error("acopy: not enough memory for BIGBUFF");
  856.  
  857.      do
  858.      { 
  859.         csts();        /* for MultiLink users */
  860.         if ((n = read(fdi, buf, min(BIGBUFF/SECTOR, nsecs) * SECTOR)) == -1) 
  861.             error("acopy: read error");
  862.         if (fdo == STDOUT)
  863.         {
  864.             for (i = 0; (i < n) && (buf[i] != CTRLZ); i++)
  865.                 putchar(buf[i]);
  866.             if (buf[i] == CTRLZ)
  867.                 puts("\n\n");
  868.         }
  869.         else if (write(fdo, buf, n) != n) 
  870.             error("acopy: write error"); 
  871.         nsecs -= n/SECTOR;
  872.     }
  873.     while (nsecs);
  874.  
  875.     free(buf);
  876. }
  877.  
  878.  
  879. /************************************************************************
  880. * return the lesser of two numbers                                        *
  881. ************************************************************************/
  882.  
  883. min(num1, num2)
  884. int        num1,
  885.         num2;
  886. {
  887.     if (num1 < num2)
  888.         return(num1);
  889.     else
  890.         return(num2);
  891. }
  892.  
  893.  
  894. /************************************************************************
  895. * add a member to the library                                            *
  896. ************************************************************************/
  897.  
  898. addfil(name, lfd) 
  899. char    *name; 
  900. FILE    lfd; 
  901.     FILE    ifd; 
  902.     int        secoffs,
  903.             numsecs, 
  904.             i; 
  905.  
  906.     if ((ifd = open(name,2)) == -1)
  907.     { 
  908.         printf("--- can't find library %s\n",name); 
  909.         errcnt++; 
  910.         return; 
  911.     } 
  912.     for (i = 0; i < nslots;    i++)
  913.     { 
  914.         if (equal(getname(&ldir[i].l_name), name))
  915.         { 
  916.             printf("Updating existing file %s\n", name); 
  917.             break; 
  918.         } 
  919.         if (ldir[i].l_stat != ACTIVE)
  920.         { 
  921.             printf("Adding new file %s\n", name); 
  922.             break; 
  923.         } 
  924.     } 
  925.     if (i >= nslots)
  926.     { 
  927.         printf("Can't add %s, library is full\n", name); 
  928.         errcnt++; 
  929.         return; 
  930.     } 
  931.  
  932.     ldir[i].l_stat = ACTIVE; 
  933.     name += index(name, ":") + 1;    /* remove drive descriptor */
  934.     cvt_to_fcb(name, &ldir[i].l_name); 
  935.     /* append to end */ 
  936.     secoffs    = lseek(lfd, 0L, 2) / SECTOR; 
  937.  
  938.     ldir[i].l_off = secoffs; 
  939.     numsecs = fcopy(ifd, lfd); 
  940.     ldir[i].l_len = numsecs; 
  941.     close(ifd); 
  942.  
  943.  
  944. /************************************************************************
  945. * copy a complete file into the library                                    *
  946. ************************************************************************/
  947.  
  948. fcopy(ifd, ofd) 
  949. FILE    ifd,
  950.         ofd; 
  951.     int        total = 0; 
  952.     int        n; 
  953.     char    *sectorbuf; 
  954.  
  955.     if ((sectorbuf = malloc(BIGBUFF)) == 0)
  956.         error("fcopy: no buffer");
  957.  
  958.     do
  959.     { 
  960.         csts();        /* for MultiLink users */
  961.         if ((n = read(ifd, sectorbuf, BIGBUFF)) == -1)
  962.             error("fcopy: read error"); 
  963.         while (n % SECTOR)
  964.             sectorbuf[n++] = CTRLZ;
  965.         if (write(ofd, sectorbuf, n) != n) 
  966.             error("fcopy: write error"); 
  967.         total += n/SECTOR; 
  968.     }
  969.     while (n == BIGBUFF);
  970.  
  971.     free(sectorbuf); 
  972.     return total; 
  973.  
  974.  
  975. /************************************************************************
  976. * copy a directory entry from one ludir structure to another            *
  977. ************************************************************************/
  978.  
  979. copyentry(old, of, new, nf) 
  980. struct    ludir    *old,
  981.                 *new; 
  982. FILE    of,
  983.         nf; 
  984. {  
  985.     int        secoffs,
  986.             numsecs;
  987.  
  988.     new->l_stat = ACTIVE; 
  989.     copymem(&new->l_name, &old->l_name, 8); 
  990.     copymem(&new->l_ext, &old->l_ext, 3); 
  991.     lseek(of, (long)old->l_off * SECTOR, 0); /* home of subtle bug */
  992.     secoffs = lseek(nf, 0L, 2) / SECTOR; 
  993.  
  994.     new->l_off = secoffs; 
  995.     numsecs    = old->l_len; 
  996.     new->l_len = numsecs; 
  997.  
  998.     acopy(of, nf, numsecs);
  999.  
  1000.  
  1001. /************************************************************************
  1002. * memory move used by copyentry()                                        *
  1003. ************************************************************************/
  1004.  
  1005. copymem(dst, src, n) 
  1006. char    *dst,
  1007.         *src; 
  1008. unsigned n; 
  1009.     while(n--) 
  1010.         *dst++ = *src++; 
  1011.  
  1012.  
  1013. /************************************************************************
  1014. * Convert a normal asciiz string to MSDOS/CPM FCB format.                *
  1015. * Make the filename portion 8 characters, extention 3 maximum.             * 
  1016. * Expand *'s into ?'s.                                                    *
  1017. * NOTE: doesn't end outname[] with \0, doesn't strip drive descriptor    *
  1018. ************************************************************************/
  1019.  
  1020. cvt_to_fcb(inname, outname) 
  1021. char    *inname; 
  1022. char    outname[]; 
  1023.     char    c; 
  1024.     int        i,j; 
  1025.  
  1026.     for (i = 0; i <= index(inname, ":"); i++) /* do drive descriptor */
  1027.         outname[i] = inname[i];                  /* if present            */
  1028.     inname += i;
  1029.     outname += i;
  1030.  
  1031.     for (i = 0; i < 8; i++)        /* now expand the inname */
  1032.     { 
  1033.         switch (*inname)
  1034.         {
  1035.             case '\0':                /* if null or        */ 
  1036.             case '.':                /* if a dot            */
  1037.                 outname[i] = ' ';    /* pad with blanks, */ 
  1038.                 break;
  1039.  
  1040.             case '*':                /* if asterisk        */
  1041.                 outname[i] = '?';    /* pad with ?'s        */
  1042.                 break;
  1043.  
  1044.             default:
  1045.                 outname[i] = toupper(*inname); 
  1046.                 ++inname; 
  1047.         } 
  1048.     } 
  1049.  
  1050.     if (*inname == '*')        /* handle the *.ext case */
  1051.         ++inname;
  1052.     if (*inname == '.')
  1053.         ++inname;
  1054.  
  1055.     for (; i < 11; i++)        /* now expand the extension */
  1056.     { 
  1057.         switch (*inname)
  1058.         {
  1059.             case '\0':                /* if null or        */ 
  1060.                 outname[i] = ' ';    /* pad with blanks, */ 
  1061.                 break;
  1062.  
  1063.             case '*':                /* if asterisk        */
  1064.                 outname[i] = '?';        /* pad with ?'s        */
  1065.                 break;
  1066.  
  1067.             case '.':                /* if a dot, */ 
  1068.                 error("(cvt_to_fcb) invalid name");    /* error out */ 
  1069.                 break;
  1070.  
  1071.             default:
  1072.                 outname[i] = toupper(*inname); 
  1073.                 ++inname; 
  1074.         } 
  1075.     } 
  1076.     return;