home *** CD-ROM | disk | FTP | other *** search
/ CD Shareware Magazine 1996 December / CD_shareware_12-96.iso / DOS / Programa / OXCC1434.ZIP / SRC / CFAR.C < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-15  |  44.8 KB  |  1,882 lines

  1. /* cfar.c */
  2. /* Import .o and .a (a.out format) files into a cff archive */
  3. /* Version 2 now incorporates FILE mode, absorbing 'cfin' and 'cfdel' */
  4. /* Copyright 1993, 1995 Norman D. Culver, All Rights Reserved */
  5.  
  6. /* compile: gcc -o -O2 -DSKELETON cfar.c */
  7.  
  8. typedef unsigned long size_t;
  9.  
  10. #include "oxbow.h"
  11.  
  12. extern void (*BUGPRINTF)(char *fmt, ...);
  13.  
  14. extern long atol(const char *);
  15. extern int strlen(const char *);
  16. extern void *strcpy(char *, const char *);
  17. extern int _strcpy(char *, char *);
  18. extern void memclr(char *, long);
  19. extern int strlwr(char *);
  20. extern void *strrchr(const char *, char);
  21. extern void *strstr(const char *, const char *);
  22. static void setup_origin(unsigned long, int);
  23. extern void oxlink_close_libs(void);
  24.  
  25. /* Program version */
  26. static Item prgversion = (Item)2;
  27. /* Archive version */
  28. static Item arversion;
  29.  
  30. /* Maximum library types */
  31. #define MAXLIBTYPE 16
  32.  
  33. typedef struct {
  34.     unsigned long sn;
  35.     unsigned long libnum : 12;    /* capacity for 4096 libraries per libtype */
  36.     unsigned long libtype : 4;    /* capacity for 16 library types */
  37.     unsigned long unused : 12;
  38.     unsigned long tag : 4;
  39. } SymItem;
  40.  
  41. typedef struct {
  42.     unsigned long filetime;
  43.     unsigned long sn : 28;
  44.     unsigned long tag : 4;
  45. } OrgItem;
  46.  
  47. /* Action bitmap */
  48. static int act;
  49. #define arADD (1)
  50. #define arREPLACE (2)
  51. #define arDELETE (4)
  52. #define arEXTRACT (8)
  53. #define arCHECK (16)
  54. #define arUPDATE (32)
  55.  
  56. static int verbose;            /* if 1, verbose mode */
  57. static long libtype;    /* 0 = modules, 1 = classes */
  58. static long oldlibtype = -1;
  59. static long libnum;        /* library number into which files are stored */
  60. static long oldlibnum = -1;
  61. static int map;            /* if 1, print archive map */
  62. static int map_bitmaps;    /* if 1, and map, print bitmaps */
  63. static int map_entries; /* if 1, and map, print entries */
  64. static int freshen;        /* if 1, freshen entries */
  65. static int shrink;        /* if 1, shrink archive */
  66. static int issymbol;    /* if 1, file names are really symbol names */
  67. static int batfile;        /* if 1, print a batchfile to remake archive */
  68. static void *archive;    /* handle of the open archive */
  69. static void *msyms;        /* handle of the master symbol table */
  70. static void *fipaths;    /* handle of the internal filemode path table */
  71. static void *ipaths;    /* handle of the internal path table */
  72. static void *qipaths;
  73. static void *origins;    /* handle of the origin path table */
  74. static void *qorigins;
  75. static void *lib;            /* handle of the current internal library */
  76. static void *plib;            /* handle of the library parent directory */
  77. static char curlib[1024];        /* internal path to the current library */
  78. static int curliblen;
  79. static char curobj[1024];    /* internal path to the current file */
  80. static int curobjlen;
  81. static char *cur_orgpath;    /* current origin path as given by cfpathtrn */
  82. static int cur_orgtype;        /* current origin type as given by cfpathtrn */
  83. static OrgItem cur_org;        /* current origin time and serial num */
  84. static char ltypes[MAXLIBTYPE];
  85. static char lnums[4096];
  86. static int delete;
  87. static int replace;
  88. static int add;
  89.  
  90. static unsigned long
  91. new_sn(char *name)
  92. {
  93. Item sn;
  94. int namlen = strlen(name);
  95.     if(cffind(archive, name, namlen, &sn) >= FOUND)
  96.     {
  97.         ++sn.a0;
  98.         cfreinsert(archive, name, namlen, &sn);
  99.         return sn.a0;
  100.     }
  101.     return 0;
  102. }
  103.  
  104. /* ++++++++++++++++++++++++++++ DLLMODE ++++++++++++++++++++++++++++++++ */
  105. static int dllmode;
  106.  
  107. static void
  108. proc_dllmode(char *dllpath)
  109. {
  110. char buf[256];
  111. char symbol[256];
  112. char dllname[256];
  113. char dlldef[256];
  114. int ordinal, argcnt, symlen, match, deflen;
  115. int filesize, filesize1;
  116. long dupnum;
  117. SymItem symval, saveval;
  118. char *filename;
  119. cfFILE *df;
  120. CFSTAT sbuf;
  121. void *xx, *xx1, *yy;
  122. int dlltype, dll_sn;
  123. char *cp;
  124.  
  125.     filename = strrchr(dllpath, '/');
  126.     if(filename)
  127.         ++filename;
  128.     else filename = dllpath;
  129.  
  130.     deflen = _strcpy(dlldef, filename);
  131.     if(strstr(dlldef, ".w32"))
  132.         dlltype = 1<<4;
  133.     else if(strstr(dlldef, ".os2"))
  134.         dlltype = 2<<4;
  135.     else if(strstr(dlldef, ".lnx"))
  136.         dlltype = 3<<4;
  137.     else if(strstr(dlldef, ".w16"))
  138.         dlltype = 4<<4;
  139.     else if(strstr(dlldef, ".os1"))
  140.         dlltype = 5<<4;
  141.     else
  142.         dlltype = 0;
  143.  
  144.     strcpy(curlib, "ltype3");
  145.     plib = cfsubopen(archive, curlib, F_RDWR|F_CREAT, NULL);
  146.     xx = cfsubopen(plib, dlldef, F_RDONLY, NULL);
  147.     if(!xx && delete)
  148.     {
  149.         cfprintf("cfar: %s does not exist\n", filename);
  150.         return;
  151.     }
  152.     if(xx && !(replace || delete))
  153.     {
  154.         cfclose(xx);
  155.         cfprintf("cfar: %s exists and replace not enabled\n", dlldef);
  156.         return;    
  157.     }
  158.     if(add || replace)
  159.     {
  160.         if(!(xx1 = cfopen(dllpath, F_RDONLY, NULL)))
  161.         {
  162.             cfclose(xx);
  163.             cfprintf("cfar: cannot open %s\n", dllpath);
  164.             return;
  165.         }
  166.         cfstat(xx1, &sbuf);
  167.         setup_origin(sbuf.st_mtime, 1);
  168.     }
  169.     symbol[0] = '_';    /* add leading underscore to symbols */
  170.     if(xx && (replace || delete))
  171.     {/* DELETE ALL OF THE OLD SYMBOLS */
  172.         saveval.sn = 0;
  173.  
  174.         /* get an in-memory uncompressed copy */
  175.         yy = cfsubopen(MEMTEMP, "", F_TEMPFILE, NULL);
  176.         filesize = cfunzip(yy,0,xx,0);
  177.         cfclose(xx);
  178.  
  179.         /* convert the memory file to a stream FILE */
  180.         cfseek(yy, 0, S_SET);
  181.         df = cffdopen(yy, "rt");
  182.         while(cffgets(buf, sizeof(buf)-1, df))
  183.         {
  184.           if( buf[0] == '#' || !isalnum(buf[0]) )
  185.             continue;
  186.           if(buf[0] == 'U' && strstr(buf, "UNHANDLED "))
  187.             break;
  188.           if(isdigit(buf[0]))
  189.           {
  190.             if(!strstr(buf, "ERROR:"))
  191.             {
  192.               /* the symbol is stored as oooo sssssssss cccc\n */
  193.               cfsscanf(buf, "%d %s %d", &ordinal, &symbol[1], &argcnt);
  194.  
  195.               /* Delete the symbol from msyms */
  196.               symlen = strlen(symbol);
  197.               dupnum = 0;
  198.               for(;;)
  199.               {
  200.               int    result = cffind_dupnum(msyms, symbol, symlen, &symval, &dupnum);
  201.  
  202.                 if(result >= FOUND)
  203.                 {
  204.                   symval.unused = 0;
  205.                   match = 0;
  206.                   if(saveval.sn)
  207.                   {
  208.                     if(symval.sn == saveval.sn && symval.libtype == 3)
  209.                     {
  210.                         match = 1;
  211.                     }
  212.                   }
  213.                   else
  214.                   {/* first */
  215.                     if(symval.libtype == 3)
  216.                     {/* check if the dll names match */
  217.                     int snum = symval.libnum;
  218.                        symval.libnum = 0;
  219.  
  220.                       if(cfget(qipaths, &symval, 8, buf, 256) >= FOUND)
  221.                       {
  222.                         if(!strcmp(buf, dllname))
  223.                         {
  224.                             symval.libnum = snum;
  225.                             saveval = symval;
  226.                             match = 1;
  227.                          }
  228.                        }
  229.                       }/* END: symval.libtype == 3 */
  230.                   }/* END: first */
  231.                   if(match)
  232.                   {
  233.                     if(cfdelete_dupnum(msyms, symbol, symlen, dupnum) != OK)
  234.                       cfprintf("cfar: ERROR can't delete %s dumpnum=%d\n",
  235.                             symbol, dupnum);
  236.                     break;
  237.                   }
  238.                   ++dupnum;
  239.                 }/* END: result >= FOUND */
  240.                 else break;
  241.               }/* END: for(;;) */
  242.             }/* END: !strstr(ERROR) */
  243.           }/* END: isdigit(buf[0]) */
  244.           else if((cp = strstr(buf, ".dll")))
  245.           {/* new dll encountered */
  246.             cp[4]=0;
  247.             if(saveval.sn)
  248.             {/* delete previous dll name from qipath */
  249.             int u = saveval.unused;
  250.             int n = saveval.libnum;
  251.                 saveval.unused = 0;
  252.                 saveval.libnum = 0;
  253.                 cfdelete(qipaths, &saveval, 8);
  254.                 saveval.unused = u;
  255.                 saveval.libnum = n;
  256.             }
  257.             strcpy(dllname, buf);
  258.             saveval.sn = 0;
  259.             if(verbose)
  260.                 cfprintf("delete %s\n", dllname);
  261.             continue;
  262.           }/* END: new dll encountered */            
  263.         }/* END: while(cffgets()) */
  264.  
  265.         /* delete last dllname from qipaths */
  266.         if(saveval.sn)
  267.         {
  268.             saveval.unused = 0;
  269.             saveval.libnum = 0;
  270.             cfdelete(qipaths, &saveval, 8);
  271.         }
  272.         cffclose(df); /* auto delete of tempfile yy */
  273.  
  274.         /* Delete the internal copy of dlldef */
  275.         cfdelete(plib, dlldef, deflen);
  276.         /* Delete the origin linkage */
  277.         strcat(dlldef, ".org");
  278.         cfdelete(plib, dlldef, deflen+4);
  279.         dlldef[deflen] = 0;
  280.     }/* END: DELETE OLD SYMBOLS */
  281.  
  282.     if(add || replace)
  283.     {/* INSERT NEW SYMBOLS */
  284.  
  285.         /* get the compressed file size */
  286.         filesize = cfzip(0,0,xx1,0);
  287.  
  288.         /* create a chunk to hold the compressed file */
  289.         xx = cfmake_chunk(plib, dlldef, deflen, filesize);
  290.         if(!xx)
  291.         {
  292.             cfprintf("cfar: cannot create internal file %s\n", filename);
  293.             cfclose(xx1);
  294.             return;
  295.         }
  296. #if 1
  297.         /* compress the external file into the internal chunk */
  298.         cfseek(xx1, 0, S_SET);
  299.         if((filesize1 = cfzip(xx,0,xx1,0)) != filesize)
  300.           cfprintf("cfar: ERROR ziperr fs1=%d fs=%d\n", filesize1, filesize);
  301. #else
  302.         /* copy the external file into the internal chunk */
  303.         cfseek(xx1, 0, S_SET);
  304.         if(cfcopy_file(xx, xx1) != sbuf.st_filesize)
  305.         {
  306.             cfprintf("cfar: ERROR copying %s\n", filename);
  307.             cfclose(xx);
  308.             cfclose(xx1);
  309.             return;
  310.         }
  311. #endif
  312.         cfclose(xx);    /* close the internal dlldef file chunk */
  313.  
  314.         /* Process the external dlldef file */
  315.         cfseek(xx1, 0, S_SET);
  316.         df = cffdopen(xx1, "rt");
  317.         while(cffgets(buf, sizeof(buf)-1, df))
  318.         {
  319.             if( buf[0] == '#' || !isalnum(buf[0]) )
  320.                 continue;
  321.             if((buf[0] == 'U') && strstr(buf, "UNHANDLED "))
  322.                 break;
  323.             if(isdigit(buf[0]))
  324.             {
  325.               if(!strstr(buf, "ERROR:"))
  326.               {
  327.                /* the symbol is stored as oooo sssssssss cccc\n */
  328.                cfsscanf(buf, "%d %s %d", &ordinal, &symbol[1], &argcnt);
  329.  
  330.                /* INSERT THE SYMBOL IN MSYMS, symval links to dllname */
  331.                symlen = strlen(symbol);
  332.                symval.sn = dll_sn;
  333.                symval.libtype = 3;
  334.                symval.unused = ordinal;
  335.                symval.libnum = (argcnt&15) | dlltype;
  336.                cfinsert_dupnum(msyms, symbol, symlen, &symval, NULL);
  337.                if(verbose)
  338.                    cfprintf("ord:%d argcnt:%d %s\n", ordinal, argcnt, symbol);
  339.              }
  340.             }
  341.             else if((cp = strstr(buf, ".dll")))
  342.             {/* new dll encountered */
  343.               cp[4]=0;
  344.               strcpy(dllname, buf);
  345.               /* insert in qipaths */
  346.               dll_sn = new_sn("SN0");
  347.               symval.sn = dll_sn;
  348.               symval.libtype = 3;
  349.               symval.unused = 0;
  350.               symval.libnum = 0;
  351.               symval.tag = STO_VALUE;
  352.               if(verbose)
  353.                   cfprintf("%s\n", dllname);
  354.               if(!cfput(qipaths, &symval, 8, dllname, strlen(dllname)+1,NULL))
  355.                 cfprintf("cfar: ERROR put dllname `%s' failed\n", dllname);
  356.             }            
  357.         }/* END: while(cffgets()) */
  358.  
  359.         cffclose(df);
  360.  
  361.         /* save the backlink to the origin */
  362.         strcat(dlldef, ".org");
  363.         cfinsert(plib, dlldef, deflen+4, &cur_org);
  364.  
  365.     }/* END: INSERT NEW SYMBOLS */
  366. }/* proc_dllmode() */
  367.  
  368. /* +++++++++++++++++++++++++++++ FILEMODE ++++++++++++++++++++++++++++++ */
  369. static int filemode;
  370. static int chunk;
  371. static int newname;
  372. static void *subdir;
  373. static char *midpart;
  374. static char *lastpart;
  375. static char basefile[256];
  376. static char midpath[1024];
  377. static char innerpath[1024];
  378.  
  379. static void
  380. proc_filemode(char *filepath)
  381. {
  382. void *fit;
  383. void *h = (subdir) ? subdir : archive;
  384. void *fd;
  385. char *filename;
  386. char *cfname;
  387. Item item;
  388. CFSTAT sbuf;
  389. int cfnamlen;
  390. int filesize;
  391. char *tag;
  392. int exists = 0;
  393.  
  394.     filename = strrchr(filepath, '/');
  395.     if(filename)
  396.         ++filename;
  397.     else filename = filepath;
  398.  
  399.     if(newname)
  400.         cfname = lastpart;
  401.     else
  402.         cfname = filename;
  403.  
  404.     cfnamlen = strlen(cfname);
  405.  
  406.     if((fit = cfopen(filepath, F_RDONLY, NULL)) != NULL)
  407.     {
  408.         /* check for existance of the archive item */
  409.         if(cfsubstat(h, cfname, &sbuf) == OK)
  410.         {
  411.           if(!replace)
  412.           {
  413.             cfclose(fit);
  414.             cfprintf("cfar: %s exists and replace not enabled\n", cfname);
  415.             return;
  416.           }
  417.           exists = 1;
  418.           cfunlink(h, cfname);
  419.         }
  420.         cfstat(fit, &sbuf);
  421.         filesize = sbuf.st_filesize;
  422.         setup_origin(sbuf.st_mtime, 1);
  423.  
  424.         if(verbose || act == arUPDATE)
  425.         {
  426.             if(act == arUPDATE)
  427.                  cfprintf("updating %s\n", cfname);
  428.             else cfprintf("%s\n", cfname);
  429.         }
  430.         if(chunk)
  431.         {
  432.             if(!(fd = cfmake_chunk(h, cfname, cfnamlen, filesize)))
  433.             {
  434.                 cfprintf("cfar: cannot make chunk for %s\n", cfname);
  435.                 cfclose(fit);
  436.                 return;
  437.             } 
  438.         }
  439.         else
  440.         {
  441.             if(!(fd = cfsubopen(h, cfname, F_RDWR|F_CREAT|F_FILEONLY, NULL)))
  442.             {
  443.                 cfprintf("cfar: could not create file %s\n", cfname);
  444.                 cfclose(fit);
  445.                 return;
  446.             }
  447.         }
  448.  
  449.         if(cfcopy_file(fd, fit) != filesize)
  450.             cfprintf("cfar: ERROR copying %s\n", cfname);
  451.  
  452.         cfclose(fd);
  453.         cfclose(fit);
  454.  
  455.         /* Store the backlink to the origin, time + origin serial number */
  456.         if(newname)
  457.             tag = "?";
  458.         else
  459.             tag = " ";
  460.         
  461.         curobjlen = cfsprintf(curobj, "%s/%s%s", innerpath, cfname, tag);
  462.         if(exists || act == arUPDATE)
  463.         {
  464.             cfreinsert(fipaths, curobj, curobjlen, &cur_org);
  465.         }
  466.         else
  467.         {
  468.             cfinsert(fipaths, curobj, curobjlen, &cur_org);
  469.         }
  470.     }
  471.     else
  472.     {
  473.         cfprintf("cfar: input file %s not found\n", filepath);
  474.     }
  475. }
  476. static void *
  477. create_middle(char *path, void *basehandle)
  478. {
  479. char *cp;
  480.  
  481.     cp = path;
  482.     while((cp = (char*)strchr(cp, '/')) != NULL)
  483.     {
  484.     void *subhandle;
  485.         *cp = '\0';        
  486.         subhandle = cfsubopen(basehandle, path, F_RDWR|F_CREAT, NULL);
  487.         cfclose(subhandle);
  488.         *cp = '/';
  489.         ++cp;
  490.     } 
  491.     return cfsubopen(basehandle, path, F_RDWR|F_CREAT, NULL);
  492. }
  493. static void *
  494. open_middle(void *basehandle)
  495. {
  496. void *subhandle = NULL;
  497.  
  498.     if(newname)
  499.     {
  500.       if(midpart)
  501.       {
  502.         subhandle = cfsubopen(basehandle, midpath, F_RDWR|F_CREAT, NULL);
  503.         if(subhandle == NULL)
  504.         {/* create the path in pieces */
  505.             subhandle = create_middle(midpath, basehandle);
  506.         }
  507.       }
  508.     }
  509.     else /* not newname */
  510.     {
  511.       if(innerpath[0])
  512.       {
  513.         subhandle = cfsubopen(basehandle, &innerpath[1], F_RDWR|F_CREAT, NULL);
  514.         if(subhandle == NULL)
  515.         {/* create the path in pieces */
  516.             subhandle = create_middle(&innerpath[1], basehandle);
  517.         }
  518.       }
  519.     }
  520. #if 0
  521.     if(subhandle)
  522.         cfsetverylazy(subhandle);
  523. #endif
  524.     return subhandle;
  525. }
  526. static void
  527. del_entry()
  528. {
  529. CFSTAT sbuf;
  530. char forgpath[1024];
  531.  
  532.     if(innerpath[0])
  533.     {
  534.         if(verbose)    
  535.             cfprintf("%s\n", lastpart);
  536.  
  537.         if(cfunlink(archive, innerpath) != OK)
  538.         {
  539.             cfprintf("cfar: delete failed for `%s'\n", innerpath);
  540.         }
  541.         else
  542.         {
  543.             cfsprintf(forgpath, "/fipaths%s ", innerpath);
  544.             if(cfunlink(archive, forgpath) != OK)
  545.             {
  546.                 cfsprintf(forgpath, "/fipath/%s?", innerpath);
  547.                 if(cfunlink(archive, forgpath) != OK)
  548.                     cfprintf("cfar: delerror, fipath:%s\n", forgpath);
  549.             }
  550.         }
  551.     }
  552.     else
  553.     {
  554.         cfprintf("cfar: delete, path missing\n");
  555.     }
  556. }
  557. static void
  558. out_entry()
  559. {
  560. void *in, *of;
  561.  
  562.     if(innerpath[0])
  563.     {
  564.       if((in = cfsubopen(archive, innerpath, F_RDONLY, NULL)) == NULL)
  565.       {
  566.         cfprintf("cfar: extract, `%s' does not exist\n", innerpath);
  567.         return;
  568.       }
  569.       if((of = cfopen(lastpart, F_RDWR|F_CREAT, NULL)) == NULL)
  570.       {
  571.           cfprintf("cfar: extract, cannot create output file `%s'\n", lastpart);
  572.         cfclose(in);
  573.       }
  574.       if(verbose)
  575.           cfprintf("%s\n", lastpart);
  576.       cfcopy_file(of, in);
  577.       cfclose(in);
  578.       cfclose(of);
  579.     }
  580.     else
  581.     {
  582.         cfprintf("cfar: extract, path missing\n");
  583.     }
  584. }
  585. /* ====================== END FILEMODE =================================== */
  586. static int
  587. open_curlib()
  588. {
  589.     if(lib)
  590.     {/* library is already open */
  591.         if(libtype == oldlibtype && libnum == oldlibnum)
  592.             return 1;
  593.  
  594.         cfclose(lib);
  595.         if(oldlibtype != libtype)
  596.         {
  597.             cfclose(plib);
  598.             cfsprintf(curlib, "ltype%d", libtype);
  599.             plib = cfsubopen(archive, curlib, F_RDWR|F_CREAT, NULL);
  600.         }
  601.         oldlibtype = libtype;
  602.         oldlibnum = libnum;
  603.     }
  604.     if(oldlibtype != libtype) {
  605.         cfsprintf(curlib, "ltype%d", libtype);
  606.         plib = cfsubopen(archive, curlib, F_RDWR|F_CREAT, NULL);
  607.     }
  608.     curliblen = cfsprintf(curlib, "ltype%d/lib%d", libtype, libnum);
  609.     lib = cfsubopen(archive, curlib, F_RDWR|F_CREAT|F_SORTED, NULL);
  610.     if(!lib)
  611.     {
  612.         cfprintf("cfar: can't open library %s\n", curlib);
  613.         return 0;
  614.     }
  615. #if 0
  616.     cfsetverylazy(lib);
  617.     cfsetverylazy(plib);
  618. #endif
  619.     return 1;
  620. }
  621. static void *
  622. make_scratch()
  623. {
  624.     return cfsubopen(MEMTEMP, "", F_TEMPFILE|F_BITMAP, NULL);
  625. }
  626. static void
  627. get_libtypes(char *name)
  628. {
  629. void *dirh;
  630. CFDIRENT *d;
  631.     memclr(ltypes, MAXLIBTYPE);
  632.     dirh = cfopendir(name);
  633.     while((d = cfreaddir(dirh)) != NULL) {
  634.         if(        d->d_name[0] == 'l'
  635.             &&    d->d_name[1] == 't')
  636.         {
  637.         long x = atol(&d->d_name[5]);
  638.             ltypes[x] = 1;
  639.         }
  640.     }
  641.     cfclosedir(dirh);
  642. }
  643. static void
  644. get_libnums(char *name)
  645. {
  646. void *dirh;
  647. CFDIRENT *d;
  648.     memclr(lnums, 4096);        
  649.     dirh = cfopendir(name);
  650.     while((d = cfreaddir(dirh)) != NULL)
  651.     {
  652.         if(        d->d_name[0] == 'l'
  653.             &&    d->d_name[1] == 'i')
  654.         {
  655.         long x = atol(&d->d_name[3]);
  656.             lnums[x] = 1;
  657.         }
  658.     }
  659.     cfclosedir(dirh);
  660. }
  661. static char *
  662. fileof(char *path)
  663. {
  664. int len = strlen(path);
  665. char *cp = &path[len-1];
  666. char *cp1;
  667.     while(cp != path)
  668.     {
  669.         if(*cp == '/' || *cp == '\\' || *cp == ':') {
  670.             ++cp;
  671.             break;
  672.         }
  673.         --cp;
  674.     }
  675.     len = strlen(cp);
  676.     cp1 = malloc(len+1);
  677.     strcpy(cp1, cp);
  678.     return cp1;
  679. }
  680. static char *
  681. objof(char *name)
  682. {
  683.     if(issymbol) {
  684.     long dupnum = 0;
  685.     SymItem symval;
  686.     int symlen = strlen(name);
  687.         for(;;)
  688.         {
  689.         int    result = cffind_dupnum(msyms, name, symlen, &symval, &dupnum);
  690.  
  691.             if(result >= FOUND)
  692.             {
  693.                 if(        (act == arCHECK)
  694.                     ||    (    symval.libtype == libtype
  695.                          &&    symval.libnum == libnum))
  696.                 {
  697.                 char curpath[256];
  698.                     if(cfget(qipaths, &symval, 8, curpath, 256) >= FOUND) {
  699.                       if(act == arCHECK)
  700.                         cfprintf("symbol %s is defined in %s\n", name, curpath);
  701.                       else return fileof(curpath);
  702.                     }
  703.                 }
  704.                 ++dupnum;
  705.             }
  706.             else return NULL;
  707.         }
  708.     }
  709.     else return fileof(name);
  710. }
  711. static void
  712. delete_file(char *name, int internal)
  713. {
  714. char *objname = objof(name);
  715. int objlen;
  716. Item packval;
  717. SymItem symval;
  718. char cpath[256];
  719. int cpathlen;
  720. Item objloc;
  721.  
  722.     if(!objname)
  723.         return;
  724.  
  725.     cpathlen = cfsprintf(cpath, "%s/%s", curlib, objname);
  726.  
  727.     /* Delete the data chunk */
  728.  
  729.     objlen = strlen(objname);
  730.     if(cffind(lib, objname, objlen, &objloc) < FOUND) {
  731.         if(!internal)
  732.             cfprintf("cfar: %s not found\n", cpath);
  733.         return;
  734.     }
  735.     if(verbose && !internal)
  736.         cfprintf("%s\n", objname);
  737.  
  738.     cfdelete(lib, objname, objlen);
  739.  
  740.     /* Read the quick access symbol pack and delete the symbols */
  741.     objname[objlen-1] = 'x';
  742.     if(cffind(lib, objname, objlen, &packval) >= FOUND)
  743.     {
  744.     char *cp, *sp, symlen;
  745.         cp = cflocalize(lib, &packval);
  746.         for(sp = cp; *sp ; sp += symlen+1)
  747.         {
  748.         long dupnum = 0;
  749.             symlen = strlen(sp);            
  750.             for(;;)
  751.             {
  752.             int    result = cffind_dupnum(msyms, sp, symlen, &symval, &dupnum);
  753.                 if(result >= FOUND)
  754.                 {
  755.                     if(        symval.libtype == libtype
  756.                         &&    symval.libnum == libnum)
  757.                     {
  758.                         cfdelete_dupnum(msyms, sp, symlen, dupnum);
  759.                         break;
  760.                     }
  761.                     ++dupnum;
  762.                 }
  763.                 else break;
  764.             }
  765.         }
  766.         cfrelease(cp, R_CLEAN);
  767.         /* Delete the symbol pack */
  768.         cfdelete(lib, objname, objlen);
  769.         /* Delete the origin linkage */
  770.         objname[objlen-1] = 't';
  771.         cfdelete(lib, objname, objlen);
  772.     }
  773.     /* Delete the path info */
  774.     cfdelete(ipaths, cpath, cpathlen);
  775.     cfdelete(qipaths, &symval, 8);
  776.     free(objname);
  777. }
  778. static void
  779. extract_file(char *name)
  780. {
  781. char *objname = objof(name);
  782. int objlen;
  783. Item objloc;
  784.  
  785.     if(!objname)
  786.         return;
  787.  
  788.     objlen = strlen(objname);
  789.     if(cffind(lib, objname, objlen, &objloc) == FOUND)
  790.     {
  791.     void *hobj;
  792.     void *fd;
  793.  
  794.         if((hobj = cfopen_chunk(lib, &objloc)) != NULL)
  795.         {
  796.             if((fd = cfopen(objname, F_RDWR|F_CREAT, NULL)) != NULL)
  797.             {
  798.                 cfcopy_file(fd, hobj);
  799.                 cfclose(fd);
  800.                 if(verbose)
  801.                     cfprintf("%s\n", objname);
  802.             }
  803.             cfclose(hobj);
  804.         }
  805.     }
  806.     free(objname);
  807. }
  808. static void
  809. setup_origin(unsigned long filetime, int flag)
  810. {
  811. int orglen;
  812. char *cp;
  813. Item orgsn;
  814.  
  815.     cur_org.filetime = filetime;
  816.     cur_org.tag = STO_VALUE;
  817.     cp = &cur_orgpath[strlen(cur_orgpath)-1];
  818.  
  819.     if(!flag && (*cp != 'a' || cp[-1] != '.'))
  820.     {/* origin is not a library */
  821.         cp = strrchr(cur_orgpath, '/');
  822.         *cp = 0;
  823.     }
  824.     if(flag && !newname)
  825.     {
  826.         cp = strrchr(cur_orgpath, '/');
  827.         *cp = 0;
  828.     }
  829.     /* Check if the origin is in the system */
  830.     orglen = strlen(cur_orgpath);
  831.     if(cffind(origins, cur_orgpath, orglen, &orgsn) >= FOUND)
  832.     {/* It is in the system, get the serial number */
  833.         cur_org.sn = orgsn.a0;
  834.     }
  835.     else
  836.     {/* Enter this origin into the system */
  837.         orgsn.item = new_sn("SN1");
  838.         orgsn.a2.type = STO_VALUE;
  839.         cur_org.sn = orgsn.a0;
  840.  
  841.         /* Store the origin, indexed both ways */
  842.         cfinsert(origins, cur_orgpath, orglen, &orgsn);
  843.         cfput(qorigins, &orgsn, 4, cur_orgpath, orglen+1, NULL);
  844.     }
  845.     if(*cp == 0) *cp = '/';
  846. }
  847. static void
  848. insert_file(char *path)
  849. {
  850. void *desc;
  851.  
  852.     /* Open the input file */
  853.     if((desc = cfopen(path, F_RDONLY, NULL)) != NULL)
  854.     {
  855.     int numobjs;
  856.     int i, j;
  857.     char *objname;
  858.     char *sympack;
  859.     int packx;
  860.     void *scratch;
  861.     CFSTAT s;
  862.  
  863.         cfstat(desc, &s);
  864.         setup_origin(s.st_mtime, 0);
  865.  
  866.         /* Create a scratch object in memory */
  867.         scratch = make_scratch();
  868.  
  869.         /* Take a look at the input file */
  870.         numobjs = oxlink_scan_file(desc, scratch);        
  871.  
  872.         /* oxlink_scan_file returns results in 'scratch' 
  873.             and on the 'scratch' stack */
  874.         for(i = 0; i < numobjs; ++i, free(objname), free(sympack))
  875.         {
  876.         unsigned long numsyms;
  877.         unsigned long symsize;
  878.         unsigned long objsize;
  879.         unsigned long objoffset;
  880.         unsigned long objnum;
  881.         unsigned long objnamlen;
  882.         SymItem objval;
  883.         int objexists = 0;
  884.         int clash = 0;
  885.  
  886.             cfpop_value(scratch, &symsize);
  887.             cfpop_value(scratch, &numsyms);
  888.             cfpop_value(scratch, &objnum);
  889.             cfpop_value(scratch, &objnamlen);
  890.             if(objnamlen > 0) {
  891.                 objname = malloc(objnamlen);
  892.                 cfpop_data(scratch, objname, objnamlen);
  893.             } else {
  894.                 objname = fileof(path);
  895.                 objnamlen = strlen(objname)+1;
  896.             }
  897.             cfpop_value(scratch, &objsize);
  898.             cfpop_value(scratch, &objoffset);
  899.  
  900.             /* Get space for a chunk of symbols */
  901.             sympack = malloc(symsize+1);
  902.             packx = 0;
  903.  
  904.             if((objnamlen + curliblen) > 255)
  905.             {
  906.                 cfprintf("%s -- name too long. CONTINUING\n", objname);
  907.                 continue;
  908.             }
  909.              /* Check the object file for current existence */
  910.             curobjlen = cfsprintf(curobj, "%s/%s", curlib, objname);
  911.             if(cffind(ipaths, curobj, curobjlen, &objval) >= FOUND)
  912.             {
  913.                 objexists = 1;
  914.                 if(!(act & (arREPLACE|arUPDATE))) {
  915.                     cfprintf("%s found in archive. CONTINUING\n", curobj);
  916.                     continue;
  917.                 }
  918.             }
  919.             /* Pass 1 over the symbols, check for clashes */ 
  920.             for(j = 0; j < numsyms; ++j)
  921.             {/* The global symbols for each .o file have been saved
  922.                     in 'sratch', keyed by (objnum<<18+symnum) */
  923.             Item symptr;
  924.             long key = (objnum<<18)+j;
  925.             SymItem symval;
  926.             int x;
  927.               if(cffind(scratch, &key, 4, &symptr) == FOUND)
  928.               {
  929.               char *cp = cflocalize(scratch, &symptr);
  930.                 if(cp)
  931.                 {
  932.                   /* Add to the quick access pack of symbols */
  933.                   x = _strcpy(&sympack[packx], cp)+1;
  934.                   if(!objexists)
  935.                   {/* Check for symbol clash with other .o files in lib */
  936.                     long dupnum = 0;
  937.                       for(;;)
  938.                       {/* Duplicate symbols are allowed, in separate libs */
  939.                       int result = cffind_dupnum(msyms,cp,x-1,&symval,&dupnum);
  940.                         if(result >= FOUND)
  941.                         {
  942.                             if(        symval.libtype == libtype
  943.                                 &&    symval.libnum == libnum)
  944.                             {
  945.                                 clash = 1;
  946.                             }
  947.                             if(!clash && result > FOUND)
  948.                             {/* Duplicate symbols exist */
  949.                                 ++dupnum;
  950.                                 continue;
  951.                             } else break;
  952.                         } else break;
  953.                       }
  954.                     }/* if(!objexists) */
  955.                     cfrelease(cp, R_CLEAN);
  956.                     if(clash)
  957.                     {
  958.                     char pathname[256];
  959.  
  960.                       pathname[0] = 0;
  961.                       cfget(qipaths, &symval, 8, pathname, 256);
  962.                       cfprintf("cfar: symbol `%s' in %s clashes with `%s' CONTINUING\n",
  963.                                 &sympack[packx], objname, pathname);
  964.                       break;
  965.                     }
  966.                     packx += x;
  967.                   }/* if(cp) */
  968.                 }/* if(cffind ) */
  969.             }/* END: for(j ) symbol pass 1 */
  970.             if(clash || !(act & (arADD|arREPLACE|arUPDATE)))
  971.                 continue;
  972.  
  973.             /* NOW add or replace the object file */
  974.             if(verbose || act == arUPDATE)
  975.             {
  976.                 if(act == arUPDATE)
  977.                      cfprintf("updating %s\n",objname);
  978.                 else cfprintf("%s\n", objname);
  979.             }
  980.             if(objexists) {
  981.                 delete_file(objname, 1);    
  982.             } else {/* Get a new serial number for the .o file */
  983.                 objval.sn = new_sn("SN0");                
  984.                 objval.libnum = libnum;
  985.                 objval.libtype = libtype;
  986.                 objval.unused = 0;
  987.                 objval.tag = STO_VALUE;
  988.             }
  989.  
  990.             /* Store the object file in a chunk */
  991. #if 1 /* the easy slow way, not much memory usage */
  992.             {
  993.             void *of;
  994.                 if((of = cfmake_chunk(lib, objname, objnamlen-1, objsize)))
  995.                 {
  996.                     if(cfcopy_file(of, desc) != objsize)
  997.                     {
  998.                         cfclose(of);
  999.                         cfprintf("cfar: ERROR copying %s\n", objname);
  1000.                         break;
  1001.                     }
  1002.                     cfclose(of);
  1003.                 }
  1004.                 else
  1005.                 {
  1006.                     cfprintf("cfar: ERROR can't make chunk for %s\n", objname);
  1007.                     break;
  1008.                 }
  1009.             }
  1010. #else /* the hard fast way, may use a LOT of memory */
  1011.             {
  1012.             Item space;
  1013.             char *loc;
  1014.                 if(cfgetspace(lib, objsize, &space) != NULL)
  1015.                 {/* ensure that there is enough space in the localizer bufs */
  1016.                 long curbufs, objbufs;
  1017.                     objbufs = (objsize / 1024)+1;
  1018.                     curbufs = cfcurbufs();
  1019.                     if(objbufs > curbufs)
  1020.                     {
  1021.                         cfmodbufs((objbufs-curbufs)+16);
  1022.                         objbufs = cfcurbufs();
  1023.                     }
  1024.                     if((loc = cflocalize(lib, &space)) != NULL) {
  1025.                         cfseek(desc, objoffset, S_SET);
  1026.                         cfread(desc, loc, objsize);
  1027.                         cfrelease(loc, R_DIRTY);
  1028.                         cfinsert(lib, objname, objnamlen-1, &space);
  1029.                     } else {
  1030.                         cfretspace(lib, &space);
  1031.                         cfprintf("cfar: ERROR can't localize space for %s\n", objname);
  1032.                         break;
  1033.                     }
  1034.                 }
  1035.                 else
  1036.                 {
  1037.                     cfprintf("cfar: ERROR can't allocate space for %s\n", objname);
  1038.                     break;
  1039.                 }
  1040.             }
  1041. #endif
  1042.             /* Store the quick access package of symbols */
  1043.             objname[objnamlen-2] = 'x';
  1044.             sympack[symsize] = 0;
  1045.             cfput(lib, objname, objnamlen-1, sympack, symsize+1, NULL); 
  1046.  
  1047.             /* Store the backlink to the origin, time + origin serial number */
  1048.             objname[objnamlen-2] = 't';
  1049.             cfinsert(lib, objname, objnamlen-1, &cur_org);
  1050.  
  1051.             /* Store the path, indexed both ways */
  1052.             cfinsert(ipaths, curobj, curobjlen, &objval);
  1053.             cfput(qipaths, &objval, 8, curobj, curobjlen+1, NULL);
  1054.  
  1055.             /* Store the symbols, symname is the key, objval is the item */
  1056.             /* Pass 2 over the symbols */ 
  1057.             for(j = 0; j < numsyms; ++j)
  1058.             {/* The global symbols for each .o file have been saved
  1059.                     in 'scratch', keyed by (objnum<<18+symnum) */
  1060.             Item symptr;
  1061.             long key = (objnum<<18)+j;
  1062.                 if(cffind(scratch, &key, 4, &symptr) == FOUND)
  1063.                 {
  1064.                 char *cp;
  1065.                     if((cp = cflocalize(scratch, &symptr)) != NULL) {
  1066.                         cfinsert_dupnum(msyms, cp, strlen(cp), &objval, NULL);
  1067.                         cfrelease(cp, R_CLEAN);
  1068.                     } else {
  1069.                         cfprintf("cfar: ERROR can't localize space for symbol %d\n", j);
  1070.                         break;
  1071.                     }
  1072.                 }
  1073.             }
  1074.         }/* END: for(numobjs) */
  1075.         cfclose(scratch);
  1076.         cfclose(desc);
  1077.     }/* END: if(desc) */
  1078.     else cfprintf("cfar: can't open file %s, CONTINUING\n", path);
  1079. }
  1080. static void
  1081. proc_objfile(char *path)
  1082. {
  1083.     if(issymbol && (act == arCHECK))
  1084.     {
  1085.         objof(path);
  1086.         return;
  1087.     }
  1088.     if(act & arEXTRACT)
  1089.         extract_file(path);
  1090.     if(act & arDELETE)
  1091.         delete_file(path, 0);
  1092.     if(act & (arADD|arREPLACE|arCHECK|arUPDATE))
  1093.         insert_file(path);
  1094. }
  1095. static void
  1096. print_map(char *arch)
  1097. {
  1098. char path[256];
  1099. void *dirh;
  1100. CFDIRENT *d;
  1101. int i, j;
  1102.  
  1103.     cfprintf("MAP of %s\n", arch);
  1104.     if(map_entries) {
  1105.         cfprintentries(arch);
  1106.         cfsprintf(path, "%s/ipaths", arch);
  1107.         cfprintentries(path);
  1108.         cfsprintf(path, "%s/qipaths", arch);
  1109.         cfprintentries(path);
  1110.         cfsprintf(path, "%s/origins", arch);
  1111.         cfprintentries(path);
  1112.         cfsprintf(path, "%s/qorigins", arch);
  1113.         cfprintentries(path);
  1114.         cfsprintf(path, "%s/msyms", arch);
  1115.         cfprintentries(path);
  1116.     }
  1117.     /* Print a list of origins */
  1118.     cfprintf("\n-------- OUTSIDE ORIGINS ----------\n\n");
  1119.     cfsprintf(path, "%s/origins", arch);
  1120.     if((origins = cfopen(path, F_STAT, NULL)) != NULL)
  1121.     {
  1122.     Item orgnum;
  1123.         if(cfhead(origins, &orgnum) == OK)
  1124.         {
  1125.             do {
  1126.                 memclr(path, 255);
  1127.                 cfkey(origins, path, 255);
  1128.                 cfprintf("oid:%u\t%s\n", orgnum.a0, path);            
  1129.             } while(cfnext(origins, &orgnum) == OK);
  1130.         }    
  1131.         cfclose(origins);
  1132.     }
  1133.     /* Print the various libraries and entries */
  1134.     cfprintf("\n-------- LIBRARIES ----------\n\n");
  1135.  
  1136.     get_libtypes(arch);
  1137.     for(i = 0; i < MAXLIBTYPE; ++i)
  1138.     {
  1139.         if(!ltypes[i])
  1140.             continue;
  1141.         cfsprintf(path, "%s/ltype%d", arch, i);
  1142.         cfprintf("\nLibrary type %d\n", i);
  1143.         get_libnums(path);
  1144.         if(map_entries) {
  1145.             cfprintf("------------ RAW ENTRIES -----------\n");
  1146.             cfprintentries(path);
  1147.         }
  1148.         if(i == 3)
  1149.         {/* dllmode library */
  1150.             cfprintf("DLL SYMBOL ENTRIES\n");
  1151.             continue;
  1152.         }
  1153.         for(j = 0; j < 4096; ++j)
  1154.         {
  1155.         void *clib;
  1156.             if(!lnums[j])
  1157.                 continue;
  1158.             cfsprintf(path, "%s/ltype%d/lib%d", arch, i, j);
  1159.             if((clib = cfopen(path, F_STAT, NULL)) != NULL) {
  1160.                 if(verbose)
  1161.                     cfprintf("------- lib%d  %d bytes -------\n",
  1162.                         j, cfbytesused(clib));
  1163.                 else
  1164.                     cfprintf("------- lib%d --------\n", j);
  1165.                 cfhead(clib, NULL);
  1166.                 do {
  1167.                 char key[256];
  1168.                 int keylen;
  1169.                     memclr(key,256);
  1170.                     cfkey(clib, key, 255);
  1171.                     keylen = strlen(key);
  1172.                     if(key[keylen-1] == 'o') {
  1173.                         if(verbose) {
  1174.                         int dlen;
  1175.                         OrgItem oi;
  1176.                             cfdatalen(clib, &dlen);
  1177.                             key[keylen-1] = 't';
  1178.                             cffind(clib, key, keylen, &oi);
  1179.                             key[keylen-1] = 'o';
  1180.                             cfprintf("    %s  bytes:%u oid:%u %s", 
  1181.                                 key, dlen, oi.sn, ctime(&oi.filetime));
  1182.                         }
  1183.                         else
  1184.                             cfprintf("     %s\n", key);
  1185.                         if(verbose) {
  1186.                         Item pakval;
  1187.                         char *cp, *sp;
  1188.                             key[keylen-1] = 'x';
  1189.                             cfmark(clib);
  1190.                             cffind(clib, key, keylen, &pakval);
  1191.                             cp = cflocalize(clib, &pakval);
  1192.                             for(sp=cp; *sp; sp += strlen(sp)+1)
  1193.                             {
  1194.                                 cfprintf("        %s\n", sp);
  1195.                             }
  1196.                             cfrelease(cp, R_CLEAN);
  1197.                             cffind_mark(clib, NULL);
  1198.                         }
  1199.                     }
  1200.                 } while (cfnext(clib, NULL) == OK);
  1201.                 if(map_entries) {
  1202.                     cfprintf("------------ RAW ENTRIES -----------\n");
  1203.                     cfprintentries(clib);
  1204.                 }
  1205.                 cfclose(clib);
  1206.             }
  1207.         }
  1208.     }
  1209.     /* Print the list of stored files */
  1210.     cfprintf("\n---------- STORED FILES ----------\n\n");
  1211.     cfsprintf(path, "%s/fipaths", arch);
  1212.     if((fipaths = cfopen(path, F_STAT, NULL)) != NULL)
  1213.     {
  1214.     OrgItem oi;
  1215.         if(cfhead(fipaths, &oi) == OK)
  1216.         {
  1217.             do {
  1218.                 memclr(path, 255);
  1219.                 cfkey(fipaths, path, 255);
  1220.                 cfprintf("%s\toid:%u  %s",
  1221.                     path, oi.sn, ctime(&oi.filetime));
  1222.             } while(cfnext(fipaths, &oi) == OK);
  1223.         }
  1224.         if(map_entries) {
  1225.             cfprintf("------------ RAW ENTRIES -----------\n");
  1226.             cfprintentries(fipaths);
  1227.         }
  1228.         cfclose(fipaths);
  1229.     }
  1230.     if(map_bitmaps) {
  1231.         cfprintf("\n------------ BITMAPS ---------------\n");
  1232.         cfprintbitmaps(arch);
  1233.     }
  1234. }
  1235. static void
  1236. Usage()
  1237. {
  1238. cfprintf("\
  1239. Usage: cfar [-acdflmrstvxCDFMNS] cfpath [file...]\n\
  1240.     Switch -- Meaning\n\
  1241.     a         Add file, do not overwrite\n\
  1242.     c         Check input files against library for clashes\n\
  1243.     d         Delete file\n\
  1244.     f         Freshen the archive (replace outdated files)\n\
  1245.     l#        Place file in libnum #, max:4095\n\
  1246.     m         Print archive map to stdout\n\
  1247.     r         Replace/Add file\n\
  1248.     s         'file' is a symbol name not a file name (for extract/delete)\n\
  1249.     t#        Set libtype # 0=module, 1=class, 2=subsystem, max:15\n\
  1250.     v         Verbose\n\
  1251.     x         Extract file\n\
  1252.     M         Print to stdout, commands which would recreate the archive\n\
  1253.     S         Shrink archive\n\
  1254.     D         Dll mode, deal with symbols stored in dlls\n\
  1255.     F         File mode, symbols not saved\n\
  1256.     C         If File mode, put file in a chunk\n\
  1257.     N         If File mode, give input file a new name (last part of cfpath)\n\
  1258. ");
  1259. }
  1260. static int
  1261. get_nameparts(char *name)
  1262. {
  1263. int namlen = strlen(name);
  1264. int i,j;
  1265.  
  1266.     basefile[0] = 0;
  1267.     midpath[0] = 0;
  1268.     innerpath[0] = 0;
  1269.     midpart = 0;
  1270.     if((lastpart = strrchr(name, '/')) != NULL)
  1271.         ++lastpart;
  1272.     if(newname && !lastpart)
  1273.     {
  1274.         cfprintf("cfar: new filename enabled but not supplied\n");
  1275.         Usage();
  1276.         return 1;
  1277.     }
  1278.     for(i = namlen-1; i >= 0; --i)
  1279.     {
  1280.         if(        name[i] == 'f'
  1281.             &&    name[i-1] == 'f'
  1282.             &&    name[i-2] == 'c'
  1283.             &&    name[i-3] == '.')
  1284.         {
  1285.             _strncpy(basefile, name, i+1);
  1286.  
  1287.             if(&name[i] > lastpart)
  1288.             {/* basefile is all there is */
  1289.                 lastpart = NULL;
  1290.             }
  1291.             else if(&name[i] != lastpart-2)
  1292.             {/* there is more than just a root directory mentioned */
  1293.                 midpart = &name[i]+2;
  1294.                 _strncpy(midpath, midpart, (int)(lastpart-midpart-1));
  1295.             }
  1296.             j = 0;
  1297.             if(midpart)
  1298.             {
  1299.                 innerpath[0] = '/';
  1300.                 j = _strcpy(&innerpath[1], midpath);
  1301.                 ++j;
  1302.             }
  1303.             if(lastpart && !newname)
  1304.             {
  1305.                 innerpath[j++] = '/';
  1306.                 strcpy(&innerpath[j], lastpart);
  1307.             }
  1308.         }
  1309.     }
  1310.     return 0;
  1311. }
  1312. static void
  1313. shrink_archive(char *name)
  1314. {
  1315. void *x;
  1316. void *y;
  1317.  
  1318.     cfprintf("cfar: shrink_archive %s\n", name);
  1319.     if(verbose)
  1320.         cfprintf("cfar: copy in\n");
  1321.     x = cfcopy("MEMORY/shrink", name);
  1322.     if(verbose)
  1323.         cfprintf("cfar: copy out\n");
  1324.     y = cfcopy(name, x);
  1325.     if(verbose)
  1326.         cfprintf("cfar: clean up\n");
  1327.     cfunlink(x, NULL);
  1328.     cfclose(y);
  1329. }
  1330. static void
  1331. stat_file(OrgItem *op, char *name, long namlen, long typ, long num, 
  1332.         char *arch, void *scratch)
  1333. {
  1334. Item orgtag;
  1335. char orgpath[1024];
  1336. char *in;
  1337. long orglen;
  1338. long sn = op->sn;
  1339.  
  1340.     cfget(qorigins, &sn, 4, &orgpath, 1023);
  1341.     orglen = strlen(orgpath);
  1342.  
  1343.     if(typ >= 0 && orgpath[orglen-1] == 'a' && orgpath[orglen-2] == '.')
  1344.     {/* This origin is a library */
  1345.         /* Mark this origin or return if it has been marked */
  1346.         orgtag.a2.size = op->sn;
  1347.         orgtag.a0 = typ<<4 + num;
  1348.         orgtag.a2.type = STO_VALUE;
  1349.         /* libraries are handled differently */
  1350.         if(cfinsert(scratch, &orgtag, 8, &orgtag) != OK)
  1351.             return;
  1352.     }
  1353.     else if(typ == -3 || typ >= 0)
  1354.     {/* This origin is a directory, with an embedded file */
  1355.         orgpath[orglen] = '/';
  1356.         ++orglen;
  1357.         orglen += _strcpy(&orgpath[orglen], name);
  1358.     }
  1359.     else if(typ == -1)
  1360.     {/* this origin is for a filemode entry */
  1361.         in = strrchr(name, '/');
  1362.         if(name[namlen-1] == '?')
  1363.             typ = -2;        /* the entry was made with newname */
  1364.         else
  1365.         {
  1366.             orglen += _strcpy(&orgpath[orglen], in);
  1367.             orgpath[orglen-1] = 0;    /* strip tag */
  1368.         }
  1369.     }
  1370.     /* The origin has not been examined, do it */
  1371.     if(freshen)
  1372.     {
  1373.     CFSTAT s;
  1374.         if(cfstat(orgpath, &s) == OK)
  1375.         {
  1376.             if(s.st_mtime > op->filetime)
  1377.             { /* REFRESH THIS ITEM */
  1378.                 ++orglen;
  1379.                 if(typ < 0 && typ != -3)
  1380.                 {
  1381.                     --namlen;    /* clip tag */
  1382.                     cfpush_data(scratch, name, namlen);
  1383.                     cfpush_value(scratch, &namlen);
  1384.                     ++namlen;
  1385.                 }
  1386.                 cfpush_data(scratch, orgpath, orglen);
  1387.                 cfpush_value(scratch, &orglen);
  1388.                 cfpush_value(scratch, &typ);
  1389.                 cfpush_value(scratch, &num);
  1390.             }
  1391.         }
  1392.         else
  1393.             cfprintf("cannot stat %s, CONTINUING\n", orgpath);
  1394.     }
  1395.     if(batfile)
  1396.     {
  1397.         if(typ == -3)
  1398.         {/* dllmode entry */
  1399.             cfprintf("cfar -Dr %s %s\n", arch, orgpath);
  1400.         }
  1401.         else if(typ < 0)
  1402.         {/* filemode entry */
  1403.         int c = (num == 1) ? 'C' : ' ';    /* chunk flag */
  1404.             if(typ == -2)
  1405.             {/* rename needed */
  1406.                 name[namlen-1] = 0;    /* clip off the tag */
  1407.                 cfprintf("cfar -FNr%c %s%s %s\n", c, arch, name, orgpath);
  1408.             }
  1409.             else
  1410.             {/* no rename, clip off the last part of name */
  1411.                 *in = 0;
  1412.                 cfprintf("cfar -Fr%c %s%s %s\n", c, arch, name, orgpath);
  1413.                 *in = '/';
  1414.             }
  1415.         }
  1416.         else
  1417.         {/* object file entry */
  1418.             cfprintf("cfar -rt%dl%d %s %s\n", typ, num, arch, orgpath);
  1419.         }
  1420.     }
  1421. }
  1422. static void
  1423. scan_archive(char *archname, void *scratch)
  1424. {
  1425. int i;
  1426. OrgItem oi;
  1427. void *clib;
  1428.  
  1429.     /* Check stored object files */
  1430.     get_libtypes(archname);
  1431.     for(i = 0; i < MAXLIBTYPE; ++i)
  1432.     {
  1433.     char path[256];
  1434.     int j;
  1435.         if(!ltypes[i])
  1436.             continue;
  1437.         cfsprintf(path, "%s/ltype%d", archname, i);
  1438.         get_libnums(path);
  1439.         if(i == 3)
  1440.         {/* dllmode libtype */
  1441.             if((clib = cfopen(path, F_RDONLY, NULL)))
  1442.             {
  1443.               if(cfhead(clib, &oi) == OK)
  1444.               {
  1445.                 do {
  1446.                 char key[256];
  1447.                 int keylen;
  1448.                 char *cp;
  1449.                     memclr(key,256);
  1450.                     cfkey(clib, key, 255);
  1451.                     keylen = strlen(key);
  1452.  
  1453.                     if((cp = strstr(key, ".org")))
  1454.                     {
  1455.                       *cp = 0;
  1456.                       stat_file(&oi, key, keylen-4, -3, 0, archname, scratch);
  1457.                     }
  1458.                 } while (cfnext(clib, &oi) == OK);
  1459.               }
  1460.               cfclose(clib);
  1461.             }
  1462.         }
  1463.         else
  1464.         { /* objmode libtype */
  1465.           for(j = 0; j < 4096; ++j)
  1466.           {
  1467.             if(!lnums[j])
  1468.                 continue;
  1469.             cfsprintf(path, "%s/ltype%d/lib%d", archname, i, j);
  1470.             if((clib = cfopen(path, F_RDONLY, NULL)))
  1471.             {
  1472.               if(cfhead(clib, &oi) == OK)
  1473.               {
  1474.                 do {
  1475.                 char key[256];
  1476.                 int keylen;
  1477.                     memclr(key,256);
  1478.                     cfkey(clib, key, 255);
  1479.                     keylen = strlen(key);
  1480.                     if(key[keylen-1] == 't') {
  1481.                         key[keylen-1] = 'o';
  1482.                         stat_file(&oi, key, keylen, i, j, archname, scratch);
  1483.                     }
  1484.                 } while (cfnext(clib, &oi) == OK);
  1485.               }
  1486.               cfclose(clib);
  1487.             }
  1488.           }
  1489.         }
  1490.     }
  1491.     /* Check stored FILEMODE files */
  1492.     if(cfhead(fipaths, &oi) == OK)
  1493.     {
  1494.       do {
  1495.       char key[1024];
  1496.       int keylen;
  1497.       char tag;
  1498.       int ischunk;
  1499.       CFSTAT sbuf;
  1500.         memclr(key,1024);
  1501.         cfkey(fipaths, key, 1023);
  1502.         keylen = strlen(key);
  1503.         tag = key[keylen-1];
  1504.         key[keylen-1] = 0;
  1505.         if(cfsubstat(archive, &key[1], &sbuf) != OK)
  1506.         {
  1507.             cfprintf("cfar: can't stat internal file %s\n", key);
  1508.             continue;
  1509.         }
  1510.         if(sbuf.st_mode & M_CHUNK)
  1511.             ischunk = 1;
  1512.         else
  1513.             ischunk = 0;
  1514.         key[keylen-1] = tag;
  1515.         stat_file(&oi, key, keylen, -1, ischunk, archname, scratch);
  1516.       } while (cfnext(fipaths, &oi) == OK);
  1517.     }
  1518. }
  1519. static void
  1520. setup_version(int flag, char *archname)
  1521. {
  1522. KeyItem snval = 0;
  1523.     cfinsert(archive, "ArVer", 5, &prgversion);
  1524.     cfinsert(archive, "SN0", 3, &snval);
  1525.     cfinsert(archive, "SN1", 3, &snval);
  1526.     cfinsert(archive, "SN2", 3, &snval);
  1527.     if(flag)
  1528.          cfprintf("cfar: add archive property to %s\n", archname);
  1529.     else cfprintf("cfar: create archive %s\n", archname);
  1530. }
  1531. static void
  1532. lose_backslashes(char *cp)
  1533. {
  1534.     while(*cp) {
  1535.         if(*cp == '\\')
  1536.             *cp = '/';
  1537.         ++cp;
  1538.     }
  1539. }
  1540. #ifdef SKELETON
  1541. int cfar(int argc, char **argv)
  1542. #else
  1543. int main(int argc, char **argv)
  1544. #endif
  1545. {
  1546. int err = 0;
  1547. int i, j;
  1548. long curbufs, newbufs;
  1549.  
  1550. #ifndef SKELETON
  1551.     cfinit("cfar", 400, NULL);
  1552.     if((err = oxlink_init(cf_find_file(argv[0], 0))) == 0)
  1553.     {
  1554. #endif
  1555.       /* Get the switches */
  1556.       for(i = 1; i < argc; ++i)
  1557.       {
  1558.       int trimsize = 1;
  1559.         lose_backslashes(argv[i]);
  1560.         if(argv[i][0] == '-')
  1561.         {
  1562.           for(j=1; argv[i][j]; ++j)
  1563.           {
  1564.             switch(argv[i][j])
  1565.             {
  1566.               case 'f':
  1567.                 freshen = 1;
  1568.                 break;
  1569.               case 'r':
  1570.                 act = arREPLACE;
  1571.                 replace = 1;
  1572.                 break;
  1573.               case 'a':
  1574.                 act = arADD;
  1575.                 add = 1;
  1576.                 replace = 0;
  1577.                 break;
  1578.               case 'x':
  1579.                 act |= arEXTRACT;
  1580.                 break;
  1581.               case 'd':
  1582.                 act |= arDELETE;
  1583.                 delete = 1;
  1584.                 break;
  1585.               case 'v':
  1586.                 verbose = 1;
  1587.                 break;
  1588.               case 'c':
  1589.                 act = arCHECK;
  1590.                 add = 0;
  1591.                 replace = 0;
  1592.                 break;
  1593.               case 'S':
  1594.                 shrink = 1;
  1595.                 break;
  1596.               case 'l':
  1597.                 libnum = atol(&argv[i][j+1]);
  1598.                 if(libnum < 0 || libnum > 4095)
  1599.                     err = 1;
  1600.                 break;
  1601.               case 't':
  1602.                 libtype = atol(&argv[i][j+1]);
  1603.                 if(libtype < 0 || libtype >= MAXLIBTYPE)
  1604.                     err = 1;
  1605.                 break;
  1606.               case 'm':
  1607.                 map = 1;
  1608.                 break;
  1609.               case 's':
  1610.                 issymbol = 1;
  1611.                 break;
  1612.               case 'B':
  1613.                 map_bitmaps = 1;
  1614.                 break;
  1615.               case 'C':
  1616.                 chunk = 1;
  1617.                 break;
  1618.               case 'F':
  1619.                 filemode = 1;
  1620.                 dllmode = 0;
  1621.                 break;
  1622.               case 'D':
  1623.                   dllmode = 1;
  1624.                   filemode = 0;
  1625.                   break;
  1626.               case 'N':
  1627.                 newname = 1;
  1628.                 break;
  1629.               case 'E':
  1630.                 map_entries = 1;
  1631.                 break;
  1632.               case 'M':
  1633.                 batfile = 1;
  1634.                 break;
  1635.               case '?':
  1636.                 err = 1;
  1637.                 break;
  1638.               default:
  1639.                 break;
  1640.             }
  1641.           }/* END: switch */
  1642. trim:
  1643.           /* Trim switch */
  1644.           for(j = i; j < argc-trimsize; ++j)
  1645.             argv[j] = argv[j+trimsize];
  1646.           argc -= trimsize;
  1647.           --i;
  1648.         }/* END: if('-') */
  1649.       }/* END: for(argc) (get switches) */
  1650.       if(verbose) {
  1651.         cfprintf("cff archiver Version:%u Copyright 1993, 1995 Norman D. Culver\n",
  1652.                 prgversion.a0);
  1653.       }
  1654.       if(err) Usage();
  1655.  
  1656.       if(argc > 1)
  1657.           err = get_nameparts(argv[1]);
  1658.  
  1659.       /* Get the archive */
  1660.       if(!err && (     (map|shrink|freshen|batfile)
  1661.                     || (act && argc > 2)
  1662.                     || (filemode && (act & (arDELETE|arEXTRACT)))
  1663.                  )
  1664.         )
  1665.       {
  1666.       int mode = F_RDWR;
  1667.       int new = 0;
  1668.  
  1669.         if(act & (arADD|arREPLACE))
  1670.             mode |= F_CREAT;
  1671.  
  1672.         curbufs = cfcurbufs(); /* current size of localizer space */
  1673.  
  1674. #ifdef SKELETON
  1675.         oxlink_close_libs();
  1676. #endif
  1677.         if((archive = cfopen(basefile, mode, NULL)) != NULL)
  1678.         {
  1679.           if(!(cfobtype(archive) & OB_XFILE))
  1680.           {
  1681. #if 0
  1682.             cfsetverylazy(archive);
  1683. #endif
  1684.             if(cfisnew(archive))
  1685.             {/* new file, set up version and serial numbers */
  1686.                 setup_version(0, basefile);
  1687.                 new = 1;
  1688.             }
  1689.             else
  1690.             {
  1691.                 if(cffind(archive, "ArVer", 5, &arversion) < FOUND) 
  1692.                 {/* old .cff file without archive property, enable it */
  1693.                     setup_version(1, basefile);
  1694.                     new = 1;
  1695.                 }
  1696.             }
  1697.             if(cffind(archive, "ArVer", 5, &arversion) >= FOUND)
  1698.             {
  1699.               if(arversion.a0 <= prgversion.a0)
  1700.               {
  1701.                 ipaths = cfsubopen(archive,"ipaths",F_RDWR|F_CREAT|F_SORTED,NULL);
  1702.                 qipaths = cfsubopen(archive,"qipaths",F_RDWR|F_CREAT, NULL);
  1703.                 origins = cfsubopen(archive,"origins",F_RDWR|F_CREAT|F_SORTED|F_BIGDIR, NULL);
  1704.                 qorigins = cfsubopen(archive,"qorigins",F_RDWR|F_CREAT, NULL);
  1705.                 msyms = cfsubopen(archive,"msyms",F_RDWR|F_CREAT|F_SORTED|F_HUGEDIR,NULL);
  1706.                 fipaths = cfsubopen(archive,"fipaths",F_RDWR|F_CREAT|F_SORTED,NULL); 
  1707.  
  1708.                 if(!ipaths) {
  1709.                     cfprintf("cfar: can't open subdir `ipaths'\n");
  1710.                     goto xt;
  1711.                 }
  1712.                 if(!qipaths) {
  1713.                     cfprintf("cfar: can't open subdir `ipaths'\n");
  1714.                     goto xt;
  1715.                 }
  1716.                 if(!origins) {
  1717.                     cfprintf("cfar: can't open subdir `origins'\n");
  1718.                     goto xt;
  1719.                 }
  1720.                 if(!qorigins) {
  1721.                     cfprintf("cfar: can't open subdir `qorigins'\n");
  1722.                     goto xt;
  1723.                 }
  1724.                 if(!msyms) {
  1725.                     cfprintf("cfar: can't open subdir `msyms'\n");
  1726.                     goto xt;
  1727.                 }
  1728.                 if(!fipaths) {
  1729.                     cfprintf("cfar: can't open subdir `fipaths'\n");
  1730.                     goto xt;
  1731.                 }
  1732. #if 0
  1733.                 cfsetverylazy(msyms);
  1734.                 cfsetverylazy(ipaths);
  1735.                 cfsetverylazy(qipaths);
  1736.                 cfsetverylazy(origins);
  1737.                 cfsetverylazy(qorigins);
  1738.                 cfsetverylazy(fipaths);
  1739. #endif
  1740.                 if(dllmode && argc >= 3 && (add || replace || delete))
  1741.                 {
  1742.                     libtype = 3;
  1743.                     libnum = 0;
  1744.                     for(i = 2; i < argc; ++i)
  1745.                     {
  1746.                         lose_backslashes(argv[i]);
  1747.                         strlwr(argv[i]);
  1748.                         cur_orgtype = cfpathtrn(argv[i], &cur_orgpath);
  1749.                         proc_dllmode(argv[i]);
  1750.                         free(cur_orgpath);
  1751.                     }
  1752.                 }
  1753.                 else if(filemode)
  1754.                 {/* PROCESS FILES STORED IN FILEMODE */
  1755.  
  1756.                     if(act & (arEXTRACT|arDELETE))
  1757.                     {
  1758.                         if(act & arEXTRACT)
  1759.                             out_entry();
  1760.                         else
  1761.                             del_entry();
  1762.                     }
  1763.                     else if(add || chunk || newname || replace)
  1764.                     {
  1765.                         subdir = open_middle(archive);
  1766.                         for(i = 2; i < argc; ++i)
  1767.                         {
  1768.                             lose_backslashes(argv[i]);
  1769.                             strlwr(argv[i]);
  1770.                             cur_orgtype = cfpathtrn(argv[i], &cur_orgpath);
  1771.                             proc_filemode(argv[i]);
  1772.                             free(cur_orgpath);
  1773.                         }
  1774.                         if(subdir)
  1775.                             cfclose(subdir);
  1776.                     }
  1777.                     else
  1778.                     {
  1779.                         cfprintf("cfar: incorrect filemode spec\n");
  1780.                     }
  1781.                 }
  1782.                 else if((argc < 3) && (freshen|batfile) && (!new))
  1783.                 {/* FRESHEN FILES IN ARCHIVE, OR PRINT BATCHFILE */
  1784.                 void *scratch = make_scratch();
  1785.  
  1786.                   /* check for files to freshen, print batfile if requested */
  1787.                   scan_archive(basefile, scratch);            
  1788.                   act = arUPDATE;
  1789.                   replace = 1;
  1790.  
  1791.                   /* files to freshen will be on the stack */
  1792.                   while(cfstackdepth(scratch) > 0)
  1793.                   {
  1794.                   long filelen;
  1795.                     cfpop_value(scratch, &libnum);
  1796.                     cfpop_value(scratch, &libtype);
  1797.                     cfpop_value(scratch, &filelen);
  1798.                     cur_orgpath = malloc(filelen);
  1799.                     cfpop_data(scratch, cur_orgpath, filelen);
  1800.  
  1801.                     if(libtype == -3)
  1802.                     {/* freshen a dllmode file */
  1803.                         libtype = 3;
  1804.                         libnum = 0;
  1805.                         proc_dllmode(cur_orgpath);
  1806.                     }
  1807.                     else if(libtype < 0)
  1808.                     {/* Freshen a filemode file */
  1809.                     long namlen, x;
  1810.                     char *cur_name;
  1811.                         cfpop_value(scratch, &namlen);
  1812.                         cur_name = calloc(1, namlen+strlen(basefile)+2);
  1813.                         x = _strcpy(cur_name, basefile);
  1814.                         cfpop_data(scratch, &cur_name[x], namlen);
  1815.                         chunk = (libnum == 1) ? 1 : 0;
  1816.                         newname = (libtype == -2) ? 1 : 0;
  1817.                         if(!newname) cur_name[x] = 0;
  1818.  
  1819.                         get_nameparts(cur_name);
  1820.                         subdir = open_middle(archive);
  1821.  
  1822.                         proc_filemode(cur_orgpath);
  1823.                         if(subdir)
  1824.                             cfclose(subdir);
  1825.                         free(cur_name);
  1826.                     }
  1827.                     else if(open_curlib())
  1828.                     {/* Freshen an object file */
  1829.                         proc_objfile(cur_orgpath);
  1830.                     }
  1831.                     free(cur_orgpath);
  1832.                   }/* END: freshen files on stack */
  1833.                   cfclose(scratch);
  1834.                 }
  1835.                 else if(argc > 2)
  1836.                 {/* PROCESS OBJECT FILES STORED WITH SYMBOL TABLES */
  1837.                   if(open_curlib())
  1838.                   {/* Process the input files */
  1839.                       for(i = 2; i < argc; ++i)
  1840.                       {
  1841.                         if(!issymbol)
  1842.                         {
  1843.                           lose_backslashes(argv[i]);
  1844.                           strlwr(argv[i]);
  1845.                         }
  1846.                         cur_orgtype = cfpathtrn(argv[i], &cur_orgpath);
  1847.                         proc_objfile(argv[i]);
  1848.                         free(cur_orgpath);
  1849.                       }        
  1850.                     }
  1851.                 }
  1852.                 cfclose(lib);
  1853.                 cfclose(plib);
  1854.                 cfclose(msyms);
  1855.                 cfclose(ipaths);
  1856.                 cfclose(qipaths);
  1857.                 cfclose(origins);
  1858.                 cfclose(qorigins);
  1859.                 cfclose(fipaths);
  1860.                 cfclose(archive);
  1861.  
  1862.                 if(shrink) shrink_archive(basefile);
  1863.                 if(map) print_map(basefile);
  1864.  
  1865.                 cfmodbufs(curbufs-cfcurbufs()); /* reset localizer space */
  1866.  
  1867.               } else cfprintf("cfar: a version %u archive cannot be processed by a version %u program\n", arversion.a0, prgversion.a0);
  1868.             } else cfprintf("cfar: %s is not an archive\n", basefile);
  1869.           } else cfprintf("cfar: %s is not a cff database\n", basefile);
  1870.         } else cfprintf("cfar: can't open archive %s\n", basefile);
  1871.       } else {cfprintf("cfar: insufficient args\n"); Usage();}
  1872. #ifndef SKELETON
  1873.     } else cfprintf("cfar: cannot find executable %s\n", argv[0]);
  1874. xt:
  1875.     cfexit();
  1876.     return 0;
  1877. #else
  1878. xt:
  1879.     return 0;
  1880. #endif
  1881. }
  1882.