home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / unix_c / cpm / lar.c < prev    next >
C/C++ Source or Header  |  1989-03-21  |  14KB  |  656 lines

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