home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / sigm / vol149 / unix-lu.lbr / LAR.C < prev   
Encoding:
C/C++ Source or Header  |  1985-02-10  |  14.6 KB  |  681 lines

  1. /*% /bin/env - /bin/ncc -O lar.c -o lar
  2. From linus!sch Tue Jul 26 08:07:37 1983
  3. Subject: CP/M Lu library maintainer
  4.  
  5. When transfering files to my personal computer, I often want to transfer
  6. several files at once using the Umodem program.  To do this I wrote
  7. the following small program to combine files for the CP/M LU program.
  8.  
  9. No special treatment necessary, just:
  10.     cc -O lar.c -o lar
  11. to make it.
  12.  
  13. -- 
  14. Stephen Hemminger,  Mitre Corp. Bedford MA 
  15.     {allegra,genrad,ihnp4, utzoo}!linus!sch    (UUCP)
  16.     linus!sch@mitre-bedford            (ARPA)
  17. ----------------- lar.c ----------------------
  18. */
  19.  
  20. /*
  21.  * Lar - LU format library file maintainer
  22.  * by Stephen C. Hemminger
  23.  *    linus!sch    or    sch@Mitre-Bedford
  24.  *
  25.  *  Usage: lar key library [files] ...
  26.  *
  27.  *  Key functions are:
  28.  *    u - Update, add files to library
  29.  *    t - Table of contents
  30.  *    e - Extract files from library
  31.  *    p - Print files in library
  32.  *    d - Delete files in library
  33.  *    r - Reorginize library
  34.  *  Other keys:
  35.  *    v - Verbose
  36.  *
  37.  *  This program is public domain software, no warranty intended or
  38.  *  implied.
  39.  *
  40.  *  DESCRPTION
  41.  *     Lar is a Unix program to manipulate CP/M LU format libraries.
  42.  *     The original CP/M library program LU is the product
  43.  *     of Gary P. Novosielski. The primary use of lar is to combine several
  44.  *     files together for upload/download to a personal computer.
  45.  *
  46.  *  PORTABILITY
  47.  *     The code is modeled after the Software tools archive program,
  48.  *     and is setup for Version 7 Unix.  It does not make any assumptions
  49.  *     about byte ordering, explict and's and shift's are used.
  50.  *     If you have a dumber C compiler, you may have to recode new features
  51.  *     like structure assignment, typedef's and enumerated types.
  52.  *
  53.  *  BUGS/MISFEATURES
  54.  *     The biggest problem is text files, the programs tries to detect
  55.  *     text files vs. binaries by checking for non-Ascii (8th bit set) chars.
  56.  *     If the file is text then it will throw away Control-Z chars which
  57.  *     CP/M puts on the end.  All files in library are padded with Control-Z
  58.  *     at the end to the CP/M sector size if necessary.
  59.  *
  60.  *     No effort is made to handle the difference between CP/M and Unix
  61.  *     end of line chars.  CP/M uses Cr/Lf and Unix just uses Lf.
  62.  *     The solution is just to use the Unix command sed when necessary.
  63.  *
  64.  *  * Unix is a trademark of Bell Labs.
  65.  *  ** CP/M is a trademark of Digital Research.
  66.  */
  67.  
  68. #include <stdio.h>
  69. #include <ctype.h>
  70.  
  71. #define ACTIVE    00
  72. #define UNUSED    0xff
  73. #define DELETED 0xfe
  74. #define CTRLZ    0x1a
  75.  
  76. #define MAXFILES 256
  77. #define SECTOR     128
  78. #define DSIZE    ( sizeof(struct ludir) )
  79. #define SLOTS_SEC (SECTOR/DSIZE)
  80. #define equal(s1, s2) ( strcmp(s1,s2) == 0 )
  81. /* if you don't have void type just define as blank */
  82. #define VOID    (void)
  83.  
  84. /* if no enum's then define false as 0 and true as 1 and bool as int */
  85. typedef enum {false=0, true=1} bool;
  86.  
  87. /* Globals */
  88. char   *fname[MAXFILES];
  89. bool ftouched[MAXFILES];
  90.  
  91. typedef struct {
  92.     unsigned char   lobyte;
  93.     unsigned char   hibyte;
  94. } word;
  95.  
  96. /* convert word to int */
  97. #define wtoi(w) ( (w.hibyte<<8) + w.lobyte)
  98. #define itow(dst,src)    dst.hibyte = (src & 0xff00) >> 8;\
  99.                 dst.lobyte = src & 0xff;
  100.  
  101. struct ludir {            /* Internal library ldir structure */
  102.     unsigned char   l_stat;    /*  status of file */
  103.     char    l_name[8];        /*  name */
  104.     char    l_ext[3];        /*  extension */
  105.     word    l_off;        /*  offset in library */
  106.     word    l_len;        /*  lengty of file */
  107.     char    l_fill[16];        /*  pad to 32 bytes */
  108. } ldir[MAXFILES];
  109.  
  110. int     errcnt, nfiles, nslots;
  111. bool    verbose = false;
  112. char    *cmdname;
  113.  
  114. char   *getname(), *sprintf();
  115. int    update(), reorg(), table(), extract(), print(), delete();
  116.  
  117. main (argc, argv)
  118. int    argc;
  119. char  **argv;
  120. {
  121.     register char *flagp;
  122.     char   *aname;            /* name of library file */
  123.     int       (*function)() = NULL;    /* function to do on library */
  124. /* set the function to be performed, but detect conflicts */
  125. #define setfunc(val)    if(function != NULL) conflict(); else function = val
  126.  
  127.     cmdname = argv[0];
  128.     if (argc < 3)
  129.     help ();
  130.  
  131.     aname = argv[2];
  132.     filenames (argc, argv);
  133.  
  134.     for(flagp = argv[1]; *flagp; flagp++)
  135.     switch (*flagp) {
  136.     case '-':
  137.         break;
  138.     case 'u': 
  139.         setfunc(update);
  140.         break;
  141.     case 't': 
  142.         setfunc(table);
  143.         break;
  144.     case 'e': 
  145.         setfunc(extract);
  146.         break;
  147.     case 'p': 
  148.         setfunc(print);
  149.         break;
  150.     case 'd': 
  151.         setfunc(delete);
  152.         break;
  153.     case 'r': 
  154.         setfunc(reorg);
  155.         break;
  156.     case 'v':
  157.         verbose = true;
  158.         break;
  159.     default: 
  160.         help ();
  161.     }
  162.  
  163.     if(function == NULL) {
  164.     fprintf(stderr,"No function key letter specified\n");
  165.     help();
  166.     }
  167.  
  168.     (*function)(aname);
  169. }
  170.  
  171. /* print error message and exit */
  172. help () {
  173.     fprintf (stderr, "Usage: %s {utepdr}[v] library [files] ...\n", cmdname);
  174.     fprintf (stderr, "Functions are:\n\tu - Update, add files to library\n");
  175.     fprintf (stderr, "\tt - Table of contents\n");
  176.     fprintf (stderr, "\te - Extract files from library\n");
  177.     fprintf (stderr, "\tp - Print files in library\n");
  178.     fprintf (stderr, "\td - Delete files in library\n");
  179.     fprintf (stderr, "\tr - Reorginize library\n");
  180.  
  181.     fprintf (stderr, "Flags are:\n\tv - Verbose\n");
  182.     exit (1);
  183. }
  184.  
  185. conflict() {
  186.    fprintf(stderr,"Conficting keys\n");
  187.    help();
  188. }
  189.  
  190. error (str)
  191. char   *str;
  192. {
  193.     fprintf (stderr, "%s: %s\n", cmdname, str);
  194.     exit (1);
  195. }
  196.  
  197. cant (name)
  198. char   *name;
  199. {
  200.     extern int  errno;
  201.     extern char *sys_errlist[];
  202.  
  203.     fprintf (stderr, "%s: %s\n", name, sys_errlist[errno]);
  204.     exit (1);
  205. }
  206.  
  207. /* Get file names, check for dups, and initialize */
  208. filenames (ac, av)
  209. char  **av;
  210. {
  211.     register int    i, j;
  212.  
  213.     errcnt = 0;
  214.     for (i = 0; i < ac - 3; i++) {
  215.     fname[i] = av[i + 3];
  216.     ftouched[i] = false;
  217.     if (i == MAXFILES)
  218.         error ("Too many file names.");
  219.     }
  220.     fname[i] = NULL;
  221.     nfiles = i;
  222.     for (i = 0; i < nfiles; i++)
  223.     for (j = i + 1; j < nfiles; j++)
  224.         if (equal (fname[i], fname[j])) {
  225.         fprintf (stderr, "%s", fname[i]);
  226.         error (": duplicate file name");
  227.         }
  228. }
  229.  
  230. table (lib)
  231. char   *lib;
  232. {
  233.     FILE   *lfd;
  234.     register int    i, total;
  235.     int active = 0, unused = 0, deleted = 0;
  236.     char *uname;
  237.  
  238.     if ((lfd = fopen (lib, "r")) == NULL)
  239.     cant (lib);
  240.  
  241.     getdir (lfd);
  242.     total = wtoi(ldir[0].l_len);
  243.     if(verbose) {
  244.      printf("Name          Index Length\n");
  245.     printf("Directory           %4d\n", total);
  246.     }
  247.  
  248.     for (i = 1; i < nslots; i++)
  249.     switch(ldir[i].l_stat) {
  250.     case ACTIVE:
  251.         active++;
  252.         uname = getname(ldir[i].l_name, ldir[i].l_ext);
  253.         if (filarg (uname))
  254.             if(verbose)
  255.             printf ("%-12s   %4d %4d\n", uname,
  256.                 wtoi (ldir[i].l_off), wtoi (ldir[i].l_len));
  257.             else
  258.             printf ("%s\n", uname);
  259.         total += wtoi(ldir[i].l_len);
  260.         break;
  261.     case UNUSED:
  262.         unused++;
  263.         break;
  264.     default:
  265.         deleted++;
  266.     }
  267.     if(verbose) {
  268.     printf("--------------------------\n");
  269.     printf("Total sectors       %4d\n", total);
  270.     printf("\nLibrary %s has %d slots, %d deleted %d active, %d unused\n",
  271.         lib, nslots, deleted, active, unused);
  272.     }
  273.  
  274.     VOID fclose (lfd);
  275.     not_found ();
  276. }
  277.  
  278. getdir (f)
  279. FILE *f;
  280. {
  281.  
  282.     rewind(f);
  283.  
  284.     if (fread ((char *) & ldir[0], DSIZE, 1, f) != 1)
  285.     error ("No directory\n");
  286.  
  287.     nslots = wtoi (ldir[0].l_len) * SLOTS_SEC;
  288.  
  289.     if (fread ((char *) & ldir[1], DSIZE, nslots, f) != nslots)
  290.     error ("Can't read directory - is it a library?");
  291. }
  292.  
  293. putdir (f)
  294. FILE *f;
  295. {
  296.  
  297.     rewind(f);
  298.     if (fwrite ((char *) ldir, DSIZE, nslots, f) != nslots)
  299.     error ("Can't write directory - library may be botched");
  300. }
  301.  
  302. initdir (f)
  303. FILE *f;
  304. {
  305.     register int    i;
  306.     int     numsecs;
  307.     char    line[80];
  308.     static struct ludir blankentry = {
  309.     UNUSED,
  310.     { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' },
  311.     { ' ', ' ', ' ' },
  312.     };
  313.  
  314.     for (;;) {
  315.     printf ("Number of slots to allocate: ");
  316.     if (fgets (line, 80, stdin) == NULL)
  317.         error ("Eof when reading input");
  318.     nslots = atoi (line);
  319.     if (nslots < 1)
  320.         printf ("Must have at least one!\n");
  321.     else if (nslots > MAXFILES)
  322.         printf ("Too many slots\n");
  323.     else
  324.         break;
  325.     }
  326.  
  327.     numsecs = nslots / SLOTS_SEC;
  328.     nslots = numsecs * SLOTS_SEC;
  329.  
  330.     for (i = 0; i < nslots; i++)
  331.     ldir[i] = blankentry;
  332.     ldir[0].l_stat = ACTIVE;
  333.     itow (ldir[0].l_len, numsecs);
  334.  
  335.     putdir (f);
  336. }
  337.  
  338. /* convert nm.ex to a Unix style string */
  339. char   *getname (nm, ex)
  340. char   *nm, *ex;
  341. {
  342.     static char namebuf[14];
  343.     register char  *cp, *dp;
  344.  
  345.     for (cp = namebuf, dp = nm; *dp != ' ' && dp != &nm[8];) {
  346.     *cp++ = isupper (*dp) ? tolower (*dp) : *dp;
  347.     ++dp;
  348.     }
  349.     *cp++ = '.';
  350.  
  351.     for (dp = ex; *dp != ' ' && dp != &ex[3];) {
  352.     *cp++ = isupper (*dp) ? tolower (*dp) : *dp;
  353.     ++dp;
  354.     }
  355.  
  356.     *cp = '\0';
  357.     return namebuf;
  358. }
  359.  
  360. putname (cpmname, unixname)
  361. char   *cpmname, *unixname;
  362. {
  363.     register char  *p1, *p2;
  364.  
  365.     for (p1 = unixname, p2 = cpmname; *p1; p1++, p2++) {
  366.     while (*p1 == '.') {
  367.         p2 = cpmname + 8;
  368.         p1++;
  369.     }
  370.     if (p2 - cpmname < 11)
  371.         *p2 = islower(*p1) ? toupper(*p1) : *p1;
  372.     else {
  373.         fprintf (stderr, "%s: name truncated\n", unixname);
  374.         break;
  375.     }
  376.     }
  377.     while (p2 - cpmname < 11)
  378.     *p2++ = ' ';
  379. }
  380.  
  381. /* filarg - check if name matches argument list */
  382. filarg (name)
  383. char   *name;
  384. {
  385.     register int    i;
  386.  
  387.     if (nfiles <= 0)
  388.     return 1;
  389.  
  390.     for (i = 0; i < nfiles; i++)
  391.     if (equal (name, fname[i])) {
  392.         ftouched[i] = true;
  393.         return 1;
  394.     }
  395.  
  396.     return 0;
  397. }
  398.  
  399. not_found () {
  400.     register int    i;
  401.  
  402.     for (i = 0; i < nfiles; i++)
  403.     if (!ftouched[i]) {
  404.         fprintf (stderr, "%s: not in library.\n", fname[i]);
  405.         errcnt++;
  406.     }
  407. }
  408.  
  409.  
  410. extract(name)
  411. char *name;
  412. {
  413.     getfiles(name, false);
  414. }
  415.  
  416. print(name)
  417. char *name;
  418. {
  419.     getfiles(name, true);
  420. }
  421.  
  422. getfiles (name, pflag)
  423. char   *name;
  424. bool    pflag;
  425. {
  426.     FILE *lfd, *ofd;
  427.     register int    i;
  428.     char   *unixname;
  429.  
  430.     if ((lfd = fopen (name, "r"))  == NULL)
  431.     cant (name);
  432.  
  433.     ofd = pflag ? stdout : NULL;
  434.     getdir (lfd);
  435.  
  436.     for (i = 1; i < nslots; i++) {
  437.     if(ldir[i].l_stat != ACTIVE)
  438.         continue;
  439.     unixname = getname (ldir[i].l_name, ldir[i].l_ext);
  440.     if (!filarg (unixname))
  441.         continue;
  442.     fprintf(stderr,"%s", unixname);
  443.     if (ofd != stdout)
  444.         ofd = fopen (unixname, "w");
  445.     if (ofd == NULL) {
  446.         fprintf (stderr, "  - can't create");
  447.         errcnt++;
  448.     }
  449.     else {
  450.         VOID fseek (lfd, (long) wtoi (ldir[i].l_off) * SECTOR, 0);
  451.         acopy (lfd, ofd, wtoi (ldir[i].l_len));
  452.         if (ofd != stdout)
  453.         VOID fclose (ofd);
  454.     }
  455.     putc('\n', stderr);
  456.     }
  457.     VOID fclose (lfd);
  458.     not_found ();
  459. }
  460.  
  461. acopy (fdi, fdo, nsecs)
  462. FILE *fdi, *fdo;
  463. register unsigned int nsecs;
  464. {
  465.     register int    i, c;
  466.     int        textfile = 1;
  467.  
  468.     while( nsecs-- != 0) 
  469.     for(i=0; i<SECTOR; i++) {
  470.         c = getc(fdi);
  471.         if( feof(fdi) ) 
  472.             error("Premature EOF\n");
  473.         if( ferror(fdi) )
  474.             error ("Can't read");
  475.         if( !isascii(c) )
  476.             textfile = 0;
  477.         if( nsecs != 0 || !textfile || c != CTRLZ) {
  478.             putc(c, fdo);
  479.             if ( ferror(fdo) )
  480.                 error ("write error");
  481.         }
  482.      }
  483. }
  484.  
  485. update (name)
  486. char   *name;
  487. {
  488.     FILE *lfd;
  489.     register int    i;
  490.  
  491.     if ((lfd = fopen (name, "r+")) == NULL) {
  492.     if ((lfd = fopen (name, "w+")) == NULL)
  493.         cant (name);
  494.     initdir (lfd);
  495.     }
  496.     else
  497.     getdir (lfd);        /* read old directory */
  498.  
  499.     if(verbose)
  500.         fprintf (stderr,"Updating files:\n");
  501.     for (i = 0; i < nfiles; i++)
  502.     addfil (fname[i], lfd);
  503.     if (errcnt == 0)
  504.     putdir (lfd);
  505.     else
  506.     fprintf (stderr, "fatal errors - library not changed\n");
  507.     VOID fclose (lfd);
  508. }
  509.  
  510. addfil (name, lfd)
  511. char   *name;
  512. FILE *lfd;
  513. {
  514.     FILE    *ifd;
  515.     register int secoffs, numsecs;
  516.     register int i;
  517.  
  518.     if ((ifd = fopen (name, "r")) == NULL) {
  519.     fprintf (stderr, "%s: can't find to add\n",name);
  520.     errcnt++;
  521.     return;
  522.     }
  523.     if(verbose)
  524.         fprintf(stderr, "%s\n", name);
  525.     for (i = 0; i < nslots; i++) {
  526.     if (equal( getname (ldir[i].l_name, ldir[i].l_ext), name) ) /* update */
  527.         break;
  528.     if (ldir[i].l_stat != ACTIVE)
  529.         break;
  530.     }
  531.     if (i >= nslots) {
  532.     fprintf (stderr, "%s: can't add library is full\n",name);
  533.     errcnt++;
  534.     return;
  535.     }
  536.  
  537.     ldir[i].l_stat = ACTIVE;
  538.     putname (ldir[i].l_name, name);
  539.     VOID fseek(lfd, 0L, 2);        /* append to end */
  540.     secoffs = ftell(lfd) / SECTOR;
  541.  
  542.     itow (ldir[i].l_off, secoffs);
  543.     numsecs = fcopy (ifd, lfd);
  544.     itow (ldir[i].l_len, numsecs);
  545.     VOID fclose (ifd);
  546. }
  547.  
  548. fcopy (ifd, ofd)
  549. FILE *ifd, *ofd;
  550. {
  551.     register int total = 0;
  552.     register int i, n;
  553.     char sectorbuf[SECTOR];
  554.  
  555.  
  556.     while ( (n = fread( sectorbuf, 1, SECTOR, ifd)) != 0) {
  557.     if (n != SECTOR)
  558.         for (i = n; i < SECTOR; i++)
  559.         sectorbuf[i] = CTRLZ;
  560.     if (fwrite( sectorbuf, 1, SECTOR, ofd ) != SECTOR)
  561.         error("write error");
  562.     ++total;
  563.     }
  564.     return total;
  565. }
  566.  
  567. delete (lname)
  568. char   *lname;
  569. {
  570.     FILE *f;
  571.     register int    i;
  572.  
  573.     if ((f = fopen (lname, "r+")) == NULL)
  574.     cant (lname);
  575.  
  576.     if (nfiles <= 0)
  577.     error("delete by name only");
  578.  
  579.     getdir (f);
  580.     for (i = 0; i < nslots; i++) {
  581.     if (!filarg ( getname (ldir[i].l_name, ldir[i].l_ext)))
  582.         continue;
  583.     ldir[i].l_stat = DELETED;
  584.     }
  585.  
  586.     not_found();
  587.     if (errcnt > 0)
  588.     fprintf (stderr, "errors - library not updated\n");
  589.     else
  590.     putdir (f);
  591.     VOID fclose (f);
  592. }
  593.  
  594. reorg (name)
  595. char  *name;
  596. {
  597.     FILE *olib, *nlib;
  598.     int oldsize;
  599.     register int i, j;
  600.     struct ludir odir[MAXFILES];
  601.     char tmpname[SECTOR];
  602.  
  603.     VOID sprintf(tmpname,"%-10.10s.TMP", name);
  604.  
  605.     if( (olib = fopen(name,"r")) == NULL)
  606.     cant(name);
  607.  
  608.     if( (nlib = fopen(tmpname, "w")) == NULL)
  609.     cant(tmpname);
  610.  
  611.     getdir(olib);
  612.     printf("Old library has %d slots\n", oldsize = nslots);
  613.     for(i = 0; i < nslots ; i++)
  614.         copymem( (char *) &odir[i], (char *) &ldir[i],
  615.             sizeof(struct ludir));
  616.     initdir(nlib);
  617.     errcnt = 0;
  618.  
  619.     for (i = j = 1; i < oldsize; i++)
  620.     if( odir[i].l_stat == ACTIVE ) {
  621.         if(verbose)
  622.         fprintf(stderr, "Copying: %-8.8s.%3.3s\n",
  623.             odir[i].l_name, odir[i].l_ext);
  624.         copyentry( &odir[i], olib,  &ldir[j], nlib);
  625.         if (++j >= nslots) {
  626.         errcnt++;
  627.         fprintf(stderr, "Not enough room in new library\n");
  628.         break;
  629.         }
  630.         }
  631.  
  632.     VOID fclose(olib);
  633.     putdir(nlib);
  634.     VOID fclose (nlib);
  635.  
  636.     if(errcnt == 0) {
  637.     if ( unlink(name) < 0 || link(tmpname, name) < 0) {
  638.         VOID unlink(tmpname);
  639.         cant(name);
  640.         }
  641.     }
  642.     else
  643.     fprintf(stderr,"Errors, library not updated\n");
  644.     VOID unlink(tmpname);
  645.  
  646. }
  647.  
  648. copyentry( old, of, new, nf )
  649. struct ludir *old, *new;
  650. FILE *of, *nf;
  651. {
  652.     register int secoffs, numsecs;
  653.     char buf[SECTOR];
  654.  
  655.     new->l_stat = ACTIVE;
  656.     copymem(new->l_name, old->l_name, 8);
  657.     copymem(new->l_ext, old->l_ext, 3);
  658.     VOID fseek(of, (long) wtoi(old->l_off)*SECTOR, 0);
  659.     VOID fseek(nf, 0L, 2);
  660.     secoffs = ftell(nf) / SECTOR;
  661.  
  662.     itow (new->l_off, secoffs);
  663.     numsecs = wtoi(old->l_len);
  664.     itow (new->l_len, numsecs);
  665.  
  666.     while(numsecs-- != 0) {
  667.     if( fread( buf, 1, SECTOR, of) != SECTOR)
  668.         error("read error");
  669.     if( fwrite( buf, 1, SECTOR, nf) != SECTOR)
  670.         error("write error");
  671.     }
  672. }
  673.  
  674. copymem(dst, src, n)
  675. register char *dst, *src;
  676. register unsigned int n;
  677. {
  678.     while(n-- != 0)
  679.         *dst++ = *src++;
  680. }
  681.