home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / unix-utils / lar.c next >
C/C++ Source or Header  |  2000-06-09  |  15KB  |  655 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();
  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.  
  181.     fprintf (stderr, "%s: %s\n", name, sys_errlist[errno]);
  182.     exit (1);
  183. }
  184.  
  185. /* Get file names, check for dups, and initialize */
  186. filenames (ac, av)
  187. char  **av;
  188. {
  189.     register int    i, j;
  190.  
  191.     errcnt = 0;
  192.     for (i = 0; i < ac - 3; i++) {
  193.     fname[i] = av[i + 3];
  194.     ftouched[i] = false;
  195.     if (i == MAXFILES)
  196.         error ("Too many file names.");
  197.     }
  198.     fname[i] = NULL;
  199.     nfiles = i;
  200.     for (i = 0; i < nfiles; i++)
  201.     for (j = i + 1; j < nfiles; j++)
  202.         if (equal (fname[i], fname[j])) {
  203.         fprintf (stderr, "%s", fname[i]);
  204.         error (": duplicate file name");
  205.         }
  206. }
  207.  
  208. table (lib)
  209. char   *lib;
  210. {
  211.     FILE   *lfd;
  212.     register int    i, total;
  213.     int active = 0, unused = 0, deleted = 0;
  214.     char *uname;
  215.  
  216.     if ((lfd = fopen (lib, "r")) == NULL)
  217.     cant (lib);
  218.  
  219.     getdir (lfd);
  220.     total = wtoi(ldir[0].l_len);
  221.     if(verbose) {
  222.      printf("Name          Index Length\n");
  223.     printf("Directory           %4d\n", total);
  224.     }
  225.  
  226.     for (i = 1; i < nslots; i++)
  227.     switch(ldir[i].l_stat) {
  228.     case ACTIVE:
  229.         active++;
  230.         uname = getname(ldir[i].l_name, ldir[i].l_ext);
  231.         if (filarg (uname))
  232.             if(verbose)
  233.             printf ("%-12s   %4d %4d\n", uname,
  234.                 wtoi (ldir[i].l_off), wtoi (ldir[i].l_len));
  235.             else
  236.             printf ("%s\n", uname);
  237.         total += wtoi(ldir[i].l_len);
  238.         break;
  239.     case UNUSED:
  240.         unused++;
  241.         break;
  242.     default:
  243.         deleted++;
  244.     }
  245.     if(verbose) {
  246.     printf("--------------------------\n");
  247.     printf("Total sectors       %4d\n", total);
  248.     printf("\nLibrary %s has %d slots, %d deleted %d active, %d unused\n",
  249.         lib, nslots, deleted, active, unused);
  250.     }
  251.  
  252.     VOID fclose (lfd);
  253.     not_found ();
  254. }
  255.  
  256. getdir (f)
  257. FILE *f;
  258. {
  259.  
  260.     rewind(f);
  261.  
  262.     if (fread ((char *) & ldir[0], DSIZE, 1, f) != 1)
  263.     error ("No directory\n");
  264.  
  265.     nslots = wtoi (ldir[0].l_len) * SLOTS_SEC;
  266.  
  267.     if (fread ((char *) & ldir[1], DSIZE, nslots, f) != nslots)
  268.     error ("Can't read directory - is it a library?");
  269. }
  270.  
  271. putdir (f)
  272. FILE *f;
  273. {
  274.  
  275.     rewind(f);
  276.     if (fwrite ((char *) ldir, DSIZE, nslots, f) != nslots)
  277.     error ("Can't write directory - library may be botched");
  278. }
  279.  
  280. initdir (f)
  281. FILE *f;
  282. {
  283.     register int    i;
  284.     int     numsecs;
  285.     char    line[80];
  286.     static struct ludir blankentry = {
  287.     UNUSED,
  288.     { ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' },
  289.     { ' ', ' ', ' ' },
  290.     };
  291.  
  292.     for (;;) {
  293.     printf ("Number of slots to allocate: ");
  294.     if (fgets (line, 80, stdin) == NULL)
  295.         error ("Eof when reading input");
  296.     nslots = atoi (line);
  297.     if (nslots < 1)
  298.         printf ("Must have at least one!\n");
  299.     else if (nslots > MAXFILES)
  300.         printf ("Too many slots\n");
  301.     else
  302.         break;
  303.     }
  304.  
  305.     numsecs = nslots / SLOTS_SEC;
  306.     nslots = numsecs * SLOTS_SEC;
  307.  
  308.     for (i = 0; i < nslots; i++)
  309.     ldir[i] = blankentry;
  310.     ldir[0].l_stat = ACTIVE;
  311.     itow (ldir[0].l_len, numsecs);
  312.  
  313.     putdir (f);
  314. }
  315.  
  316. /* convert nm.ex to a Unix style string */
  317. char   *getname (nm, ex)
  318. char   *nm, *ex;
  319. {
  320.     static char namebuf[14];
  321.     register char  *cp, *dp;
  322.  
  323.     for (cp = namebuf, dp = nm; *dp != ' ' && dp != &nm[8];)
  324.     *cp++ = isupper (*dp) ? tolower (*dp++) : *dp++;
  325.     *cp++ = '.';
  326.  
  327.     for (dp = ex; *dp != ' ' && dp != &ex[3];)
  328.     *cp++ = isupper (*dp) ? tolower (*dp++) : *dp++;
  329.  
  330.     *cp = '\0';
  331.     return namebuf;
  332. }
  333.  
  334. putname (cpmname, unixname)
  335. char   *cpmname, *unixname;
  336. {
  337.     register char  *p1, *p2;
  338.  
  339.     for (p1 = unixname, p2 = cpmname; *p1; p1++, p2++) {
  340.     while (*p1 == '.') {
  341.         p2 = cpmname + 8;
  342.         p1++;
  343.     }
  344.     if (p2 - cpmname < 11)
  345.         *p2 = islower(*p1) ? toupper(*p1) : *p1;
  346.     else {
  347.         fprintf (stderr, "%s: name truncated\n", unixname);
  348.         break;
  349.     }
  350.     }
  351.     while (p2 - cpmname < 11)
  352.     *p2++ = ' ';
  353. }
  354.  
  355. /* filarg - check if name matches argument list */
  356. filarg (name)
  357. char   *name;
  358. {
  359.     register int    i;
  360.  
  361.     if (nfiles <= 0)
  362.     return 1;
  363.  
  364.     for (i = 0; i < nfiles; i++)
  365.     if (equal (name, fname[i])) {
  366.         ftouched[i] = true;
  367.         return 1;
  368.     }
  369.  
  370.     return 0;
  371. }
  372.  
  373. not_found () {
  374.     register int    i;
  375.  
  376.     for (i = 0; i < nfiles; i++)
  377.     if (!ftouched[i]) {
  378.         fprintf (stderr, "%s: not in library.\n", fname[i]);
  379.         errcnt++;
  380.     }
  381. }
  382.  
  383.  
  384. extract(name)
  385. char *name;
  386. {
  387.     getfiles(name, false);
  388. }
  389.  
  390. print(name)
  391. char *name;
  392. {
  393.     getfiles(name, true);
  394. }
  395.  
  396. getfiles (name, pflag)
  397. char   *name;
  398. bool    pflag;
  399. {
  400.     FILE *lfd, *ofd;
  401.     register int    i;
  402.     char   *unixname;
  403.  
  404.     if ((lfd = fopen (name, "r"))  == NULL)
  405.     cant (name);
  406.  
  407.     ofd = pflag ? stdout : NULL;
  408.     getdir (lfd);
  409.  
  410.     for (i = 1; i < nslots; i++) {
  411.     if(ldir[i].l_stat != ACTIVE)
  412.         continue;
  413.     unixname = getname (ldir[i].l_name, ldir[i].l_ext);
  414.     if (!filarg (unixname))
  415.         continue;
  416.     fprintf(stderr,"%s", unixname);
  417.     if (ofd != stdout)
  418.         ofd = fopen (unixname, "w");
  419.     if (ofd == NULL) {
  420.         fprintf (stderr, "  - can't create");
  421.         errcnt++;
  422.     }
  423.     else {
  424.         VOID fseek (lfd, (long) wtoi (ldir[i].l_off) * SECTOR, 0);
  425.         acopy (lfd, ofd, wtoi (ldir[i].l_len));
  426.         if (ofd != stdout)
  427.         VOID fclose (ofd);
  428.     }
  429.     putc('\n', stderr);
  430.     }
  431.     VOID fclose (lfd);
  432.     not_found ();
  433. }
  434.  
  435. acopy (fdi, fdo, nsecs)
  436. FILE *fdi, *fdo;
  437. register unsigned int nsecs;
  438. {
  439.     register int    i, c;
  440.     int        textfile = 1;
  441.  
  442.     while( nsecs-- != 0) 
  443.     for(i=0; i<SECTOR; i++) {
  444.         c = getc(fdi);
  445.         if( feof(fdi) ) 
  446.             error("Premature EOF\n");
  447.         if( ferror(fdi) )
  448.             error ("Can't read");
  449.         if( !isascii(c) )
  450.             textfile = 0;
  451.         if( nsecs != 0 || !textfile || c != CTRLZ) {
  452.             putc(c, fdo);
  453.             if ( ferror(fdo) )
  454.                 error ("write error");
  455.         }
  456.      }
  457. }
  458.  
  459. update (name)
  460. char   *name;
  461. {
  462.     FILE *lfd;
  463.     register int    i;
  464.  
  465.     if ((lfd = fopen (name, "r+")) == NULL) {
  466.     if ((lfd = fopen (name, "w+")) == NULL)
  467.         cant (name);
  468.     initdir (lfd);
  469.     }
  470.     else
  471.     getdir (lfd);        /* read old directory */
  472.  
  473.     if(verbose)
  474.         fprintf (stderr,"Updating files:\n");
  475.     for (i = 0; i < nfiles; i++)
  476.     addfil (fname[i], lfd);
  477.     if (errcnt == 0)
  478.     putdir (lfd);
  479.     else
  480.     fprintf (stderr, "fatal errors - library not changed\n");
  481.     VOID fclose (lfd);
  482. }
  483.  
  484. addfil (name, lfd)
  485. char   *name;
  486. FILE *lfd;
  487. {
  488.     FILE    *ifd;
  489.     register int secoffs, numsecs;
  490.     register int i;
  491.  
  492.     if ((ifd = fopen (name, "r")) == NULL) {
  493.     fprintf (stderr, "%s: can't find to add\n",name);
  494.     errcnt++;
  495.     return;
  496.     }
  497.     if(verbose)
  498.         fprintf(stderr, "%s\n", name);
  499.     for (i = 0; i < nslots; i++) {
  500.     if (equal( getname (ldir[i].l_name, ldir[i].l_ext), name) ) /* update */
  501.         break;
  502.     if (ldir[i].l_stat != ACTIVE)
  503.         break;
  504.     }
  505.     if (i >= nslots) {
  506.     fprintf (stderr, "%s: can't add library is full\n",name);
  507.     errcnt++;
  508.     return;
  509.     }
  510.  
  511.     ldir[i].l_stat = ACTIVE;
  512.     putname (ldir[i].l_name, name);
  513.     VOID fseek(lfd, 0L, 2);        /* append to end */
  514.     secoffs = ftell(lfd) / SECTOR;
  515.  
  516.     itow (ldir[i].l_off, secoffs);
  517.     numsecs = fcopy (ifd, lfd);
  518.     itow (ldir[i].l_len, numsecs);
  519.     VOID fclose (ifd);
  520. }
  521.  
  522. fcopy (ifd, ofd)
  523. FILE *ifd, *ofd;
  524. {
  525.     register int total = 0;
  526.     register int i, n;
  527.     char sectorbuf[SECTOR];
  528.  
  529.  
  530.     while ( (n = fread( sectorbuf, 1, SECTOR, ifd)) != 0) {
  531.     if (n != SECTOR)
  532.         for (i = n; i < SECTOR; i++)
  533.         sectorbuf[i] = CTRLZ;
  534.     if (fwrite( sectorbuf, 1, SECTOR, ofd ) != SECTOR)
  535.         error("write error");
  536.     ++total;
  537.     }
  538.     return total;
  539. }
  540.  
  541. delete (lname)
  542. char   *lname;
  543. {
  544.     FILE *f;
  545.     register int    i;
  546.  
  547.     if ((f = fopen (lname, "r+")) == NULL)
  548.     cant (lname);
  549.  
  550.     if (nfiles <= 0)
  551.     error("delete by name only");
  552.  
  553.     getdir (f);
  554.     for (i = 0; i < nslots; i++) {
  555.     if (!filarg ( getname (ldir[i].l_name, ldir[i].l_ext)))
  556.         continue;
  557.     ldir[i].l_stat = DELETED;
  558.     }
  559.  
  560.     not_found();
  561.     if (errcnt > 0)
  562.     fprintf (stderr, "errors - library not updated\n");
  563.     else
  564.     putdir (f);
  565.     VOID fclose (f);
  566. }
  567.  
  568. reorg (name)
  569. char  *name;
  570. {
  571.     FILE *olib, *nlib;
  572.     int oldsize;
  573.     register int i, j;
  574.     struct ludir odir[MAXFILES];
  575.     char tmpname[SECTOR];
  576.  
  577.     VOID sprintf(tmpname,"%-10.10s.TMP", name);
  578.  
  579.     if( (olib = fopen(name,"r")) == NULL)
  580.     cant(name);
  581.  
  582.     if( (nlib = fopen(tmpname, "w")) == NULL)
  583.     cant(tmpname);
  584.  
  585.     getdir(olib);
  586.     printf("Old library has %d slots\n", oldsize = nslots);
  587.     for(i = 0; i < nslots ; i++)
  588.         copymem( (char *) &odir[i], (char *) &ldir[i],
  589.             sizeof(struct ludir));
  590.     initdir(nlib);
  591.     errcnt = 0;
  592.  
  593.     for (i = j = 1; i < oldsize; i++)
  594.     if( odir[i].l_stat == ACTIVE ) {
  595.         if(verbose)
  596.         fprintf(stderr, "Copying: %-8.8s.%3.3s\n",
  597.             odir[i].l_name, odir[i].l_ext);
  598.         copyentry( &odir[i], olib,  &ldir[j], nlib);
  599.         if (++j >= nslots) {
  600.         errcnt++;
  601.         fprintf(stderr, "Not enough room in new library\n");
  602.         break;
  603.         }
  604.         }
  605.  
  606.     VOID fclose(olib);
  607.     putdir(nlib);
  608.     VOID fclose (nlib);
  609.  
  610.     if(errcnt == 0) {
  611.     if ( unlink(name) < 0 || link(tmpname, name) < 0) {
  612.         VOID unlink(tmpname);
  613.         cant(name);
  614.         }
  615.     }
  616.     else
  617.     fprintf(stderr,"Errors, library not updated\n");
  618.     VOID unlink(tmpname);
  619.  
  620. }
  621.  
  622. copyentry( old, of, new, nf )
  623. struct ludir *old, *new;
  624. FILE *of, *nf;
  625. {
  626.     register int secoffs, numsecs;
  627.     char buf[SECTOR];
  628.  
  629.     new->l_stat = ACTIVE;
  630.     copymem(new->l_name, old->l_name, 8);
  631.     copymem(new->l_ext, old->l_ext, 3);
  632.     VOID fseek(of, (long) wtoi(old->l_off)*SECTOR, 0);
  633.     VOID fseek(nf, 0L, 2);
  634.     secoffs = ftell(nf) / SECTOR;
  635.  
  636.     itow (new->l_off, secoffs);
  637.     numsecs = wtoi(old->l_len);
  638.     itow (new->l_len, numsecs);
  639.  
  640.     while(numsecs-- != 0) {
  641.     if( fread( buf, 1, SECTOR, of) != SECTOR)
  642.         error("read error");
  643.     if( fwrite( buf, 1, SECTOR, nf) != SECTOR)
  644.         error("write error");
  645.     }
  646. }
  647.  
  648. copymem(dst, src, n)
  649. register char *dst, *src;
  650. register unsigned int n;
  651. {
  652.     while(n-- != 0)
  653.         *dst++ = *src++;
  654. }
  655.