home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / utilities / utilsm / makealf / Source / c / makeALF
Encoding:
Text File  |  1995-03-31  |  15.8 KB  |  534 lines

  1. /* >c.makeALF */
  2.  
  3. /* Utility for creating an ALF file from a number of AOF files
  4.  *
  5.  *    makealf [-i inputfile] [-o outputfile] [object-file-list]
  6.  *
  7.  * Puts the object files given on the command line, and optionally
  8.  * those named in <inputfile>, into a library file.
  9.  *
  10.  * If no <outputfile> is given, the output file is named "alf".
  11.  *
  12.  * Ambiguous filenames are not expanded.
  13.  */
  14.  
  15. /*------------------------------------------------------------------------*/
  16.  
  17. #define VERSION_STRING "1.02 (31/3/1995)"
  18.  
  19. #include <ctype.h>
  20. #include <signal.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <time.h>
  25.  
  26. #include "finfo.h"
  27. #include "lowfile.h"
  28.  
  29. #define Chunk_file_ID      0xC3CBC6C5
  30. #define Max_n_objects      1024
  31. #define Object_name_size   16384 /* space for names of object files */
  32. #define Max_line_length    256   /* in input file */
  33. #define Output_buffer_size 32768
  34. #define String_table_unit  4096  /* granularity; must be power of 2 */
  35.  
  36. /*------------------------------------------------------------------------*/
  37.  
  38. typedef struct {
  39.   char *name;
  40.   int size;
  41.   int time0; /* high word. (Weird.) */
  42.   int time1; /* low word */
  43. } obj_info;
  44.  
  45. /*------------------------------------------------------------------------*/
  46.  
  47. static char *my_name;
  48. static FILE *input_file=NULL;
  49. static int output_file=0;    /* RISC OS handle */
  50. static int object_file=0;    /* RISC OS handle for current object file */
  51. static char *output_fname=NULL;
  52. static char *name_space;    /* for names of object files */
  53. static int name_next=0;        /* next free byte therein */
  54. static char **obj_name;        /* array of names */
  55. static int n_objects=0;
  56. static int return_code=0;
  57. static char *output_buffer;
  58. static int output_buffer_next=0;
  59. static int output_buffer_start;    /* file offset of start of buffer */
  60. static int symt_size;        /* size of symbol-table chunk, in bytes */
  61. static char *string_table=NULL;    /* for current object file */
  62. static int str_tab_size=0;    /* this extends as necessary */
  63. static obj_info *object;
  64. static int chattyP=1;        /* friendly progress reports? */
  65.  
  66. /*------------------------------------------------------------------------*/
  67.  
  68. static void close_files(void) {
  69.   if (input_file) fclose(input_file);
  70.   if (output_file) low_close(output_file);
  71.   if (object_file) low_close(object_file);
  72. }
  73.  
  74. /*------------------------------------------------------------------------*/
  75.  
  76. static void warn(char *s) {
  77.   fprintf(stderr,"! Warning (%s): %s.\n",my_name,s);
  78.   return_code=4;
  79. }
  80.  
  81. static void warn1(char *s, char *t) {         /* s is format string */
  82.   fprintf(stderr,"! Warning (%s): ",my_name);
  83.   fprintf(stderr,s,t);
  84.   fprintf(stderr,".\n");
  85.   return_code=4;
  86. }
  87.  
  88. static void err(char *s) {
  89.   fprintf(stderr,"! Error (%s): %s.\n",my_name,s);
  90.   close_files();
  91.   exit(8);
  92. }
  93.  
  94. static void err1(char *s, char *t) {          /* s is format string */
  95.   fprintf(stderr,"! Error (%s): ",my_name);
  96.   fprintf(stderr,s,t);
  97.   fprintf(stderr,".\n");
  98.   close_files();
  99.   exit(8);
  100. }
  101.  
  102. /*------------------------------------------------------------------------*/
  103.  
  104. static void *xmalloc(int size, char *s) {
  105.   void *p;
  106.   p=malloc(size);
  107.   if (!p) err1("out of memory for %s",s);
  108.   return p;
  109. }
  110.  
  111. /*------------------------------------------------------------------------*/
  112.  
  113. static void insert_obj_name(char *s) {
  114.   int k;
  115.   while(isspace(*s)) ++s;
  116.   if (!*s || *s=='#') return;
  117.   k=0; while (s[k] && !isspace(s[k])) ++k;
  118.   if (name_next+k+1>=Object_name_size)
  119.     err("out of memory for filenames");
  120.   memcpy(name_space+name_next,s,k);
  121.   name_space[name_next+k]=0;
  122.   obj_name[n_objects++]=name_space+name_next;
  123.   name_next+=k+1;
  124. }
  125.  
  126. /*------------------------------------------------------------------------*/
  127.  
  128. static void process_input_file(char *s) {
  129.   char buf[Max_line_length];
  130.   int l;
  131.   input_file=fopen(s,"r");
  132.   if (!input_file) {
  133.     warn1("couldn't open input file %s",s);
  134.     return; }
  135.   while (fgets(buf,Max_line_length,input_file)) {
  136.     l=strlen(buf);
  137.     if (buf[l-1]!='\n') { warn1("over-long line in input file %s",s);
  138.                           printf("%d %s\n",buf[l-1],buf); }
  139.     else buf[l-1]='\0';
  140.     if (*buf=='#') continue; /* comment character */
  141.     insert_obj_name(buf);
  142.   }
  143. }
  144.  
  145. /*------------------------------------------------------------------------*/
  146.  
  147. static void flush_output(void) {
  148.   low_setptr(output_file,output_buffer_start);
  149.   low_write(output_file,output_buffer,output_buffer_next);
  150.   output_buffer_start+=output_buffer_next;
  151.   output_buffer_next=0;
  152. }
  153.  
  154. static void put_word(unsigned int w) {
  155.   if (output_buffer_next+4>=Output_buffer_size) flush_output();
  156.   if (output_buffer_next&3) warn("ill-aligned put_word()");
  157.   *((int *)(output_buffer+output_buffer_next))=w;
  158.   output_buffer_next+=4;
  159. }
  160.  
  161. static void put_string_padded(char *s, int l) {
  162.   int i;
  163.   i=(l+4)&~3;
  164.   if (output_buffer_next+i>=Output_buffer_size) flush_output();
  165.   if (i>Output_buffer_size) err("Excessively long string");
  166.   memcpy(output_buffer+output_buffer_next,s,l);
  167.   output_buffer_next+=l;
  168.   do output_buffer[output_buffer_next++]='\0'; while (output_buffer_next&3);
  169. }
  170.  
  171. static void put_eight(char *s) {
  172.   if (output_buffer_next+8>=Output_buffer_size) flush_output();
  173.   if (output_buffer_next&3) warn("ill-aligned put_eight()");
  174.   *((int *)(output_buffer+output_buffer_next))=*((int *)s);
  175.   *((int *)(output_buffer+output_buffer_next+4))=*((int *)(s+4));
  176.   output_buffer_next+=8;
  177. }
  178.  
  179. static void refresh_buffer(void) {
  180.   low_setptr(output_file,output_buffer_start);
  181.   output_buffer_next=low_read(output_file,output_buffer,Output_buffer_size);
  182. }
  183.  
  184. static void put_word_at(int v, int p) {
  185.   if (p&3) warn("ill-aligned put_word_at()");
  186.   if (p<output_buffer_start || p>=output_buffer_start+output_buffer_next) {
  187.     flush_output();
  188.     low_setptr(output_file,p); output_buffer_start=p;
  189.     refresh_buffer();
  190.   }
  191.   *(int *)(output_buffer+p-output_buffer_start)=v;
  192.   if (p-output_buffer_start>output_buffer_next)
  193.     output_buffer_next=p-output_buffer_start;
  194. }
  195.  
  196. /*------------------------------------------------------------------------*/
  197.  
  198. static void pad_output(void) {
  199.   char z[4]="\0\0\0"; /* one more \0 added by compiler! */
  200.   int i;
  201.   i=(low_ptr(output_file)&3);
  202.   if (i) low_write(output_file,z,4-i);
  203. }
  204.  
  205. /*------------------------------------------------------------------------*/
  206.  
  207. /* This assumes that a time_t counts seconds since midnight, 1/1/1970 */
  208. /* Also, it will stop working some time in 20xx */
  209. #define SEVENTY_YEARS (25567u*24u*60u*60u)
  210.  
  211. static void set_cur_time(unsigned int *t0p, unsigned int *t1p) {
  212.   time_t t;
  213.   double d;
  214.   time(&t);
  215.   d=(t+(double)SEVENTY_YEARS)*100.;
  216.   *t0p=(int)(d/65536.);
  217.   *t1p=(int)(d-65536.*(*t0p))<<16;
  218. }
  219.  
  220. /*------------------------------------------------------------------------*/
  221.  
  222. /* The following breaks if the chunk file header doesn't fit into a
  223.  * 4k buffer. This should not be a problem.
  224.  */
  225.  
  226. static void process_symbol_table(int num) {
  227.   char wee_buf[4096];
  228.   int *wb=(int *)wee_buf;
  229.   int *sym_buf;
  230.   int n_chunks;
  231.   int n_symbols;
  232.   int i,j;
  233.   int str_ofs=0, sym_ofs=0, hdr_ofs=0;
  234.   int str_siz,sym_siz,hdr_siz;
  235.  
  236.   low_read(object_file,wee_buf,4096);
  237.   if (*wb!=0xC3CBC6C5)
  238.     warn1("non-chunk-file ``object file'' %s",object[num].name);
  239.   n_chunks=wb[2];
  240.   for (i=0;i<n_chunks;++i) {
  241.     if (wb[3+i*4]=='OBJ_' && wb[4+i*4]=='SYMT') {
  242.       sym_ofs=wb[5+i*4]; sym_siz=wb[6+i*4]; }
  243.     if (wb[3+i*4]=='OBJ_' && wb[4+i*4]=='STRT') {
  244.       str_ofs=wb[5+i*4]; str_siz=wb[6+i*4]; }
  245.     if (wb[3+i*4]=='OBJ_' && wb[4+i*4]=='HEAD') {
  246.       hdr_ofs=wb[5+i*4]; hdr_siz=wb[6+i*4]; }
  247.   }
  248.   if (!hdr_ofs) {
  249.     warn1("object file %s has no header chunk",object[num].name); return; }
  250.   if (!str_ofs) {
  251.     warn1("object file %s has no string table",object[num].name); return; }
  252.   if (!sym_ofs) {
  253.     warn1("object file %s has no symbol table",object[num].name); return; }
  254.  
  255.   low_setptr(object_file,hdr_ofs);
  256.   low_read(object_file,wee_buf,4096);
  257.   if (*wb!=0xC5E2D080) {
  258.     warn1("non-AOF ``object'' file %s",object[num].name); return; }
  259.   n_symbols=wb[3];
  260.  
  261.   if (str_siz>str_tab_size) {
  262.     if (string_table) free(string_table);
  263.     str_tab_size=(str_siz+(String_table_unit-1))&~(String_table_unit-1);
  264.     string_table=xmalloc(str_tab_size,"string table");
  265.   }
  266.  
  267.   low_setptr(object_file,str_ofs);
  268.   low_read(object_file,string_table,str_siz);
  269.  
  270.   sym_buf=(int *)xmalloc(sym_siz,"symbol table");
  271.   low_setptr(object_file,sym_ofs);
  272.   low_read(object_file,sym_buf,sym_siz);
  273.  
  274.   for (i=0;i<n_symbols;++i) {
  275.     if ((sym_buf[i*4+1]&3)==3) {               /* if global & defined ... */
  276.       put_word(num+3); /* ChunkIndex */
  277.       j=strlen(string_table+sym_buf[i*4]);
  278.       put_word(12+((j+4)&~3));
  279.       put_word((j+4)&~3);
  280.       put_string_padded(string_table+sym_buf[i*4],j);
  281.       symt_size+=12+((j+4)&~3);
  282.     }
  283.   }
  284.   free(sym_buf);
  285. }
  286.  
  287. /*------------------------------------------------------------------------*/
  288.  
  289. static char *sig_list[]={
  290. NULL,"SIGABRT","SIGFPE","SIGILL","SIGINT","SIGSEGV","SIGTERM","SIGSTAK"};
  291.  
  292. static void handle_signal(int sig) {
  293.   close_files();
  294.   if (sig>0 && sig<8)
  295.     fprintf(stderr,"!! %s caught signal %s -- exiting.\n",
  296.             my_name,sig_list[sig]);
  297.   else fprintf(stderr,"!! %s caught signal number %d -- exiting.\n",
  298.                my_name,sig);
  299.   exit(12);
  300. }
  301.  
  302. /*------------------------------------------------------------------------*/
  303.  
  304. int main(int argc, char *argv[]) {
  305.   int i,j;
  306.   fileinfo one_file; /* for finding stats of object files */
  307.   char dbuf[256]; /* these two for splitting filenames */
  308.   char lbuf[256]; /* ... */
  309.   int ofs_TIME; /* offset to LIB_TIME chunk */
  310.   int ofs_VRSN; /* offset to LIB_VRSN chunk */
  311.   int ofs_DIRY; /* offset to LIB_DIRY chunk */
  312.   unsigned int time0,time1; /* time now */
  313.   int diry_size;
  314.   int char_pos=0; /* for output formatting! */
  315.  
  316.   my_name=*argv; --argc; ++argv;
  317.  
  318.   if (argc==1 && !strcmp(*argv,"-v")) {
  319.     fprintf(stderr,"This is makeALF, version " VERSION_STRING ".\n");
  320.     return 0;
  321.   }
  322.  
  323.   name_space=(char *)xmalloc(Object_name_size,"filenames");
  324.   obj_name=(char **)xmalloc(Max_n_objects*sizeof(char *),"filenames");
  325.   output_buffer=(char *)xmalloc(Output_buffer_size,"Output buffer");
  326.  
  327.   signal(SIGABRT,handle_signal);
  328.   signal(SIGFPE,handle_signal);
  329.   signal(SIGILL,handle_signal);
  330.   signal(SIGINT,handle_signal);
  331.   signal(SIGSEGV,handle_signal);
  332.   signal(SIGTERM,handle_signal);
  333.   signal(SIGSTAK,handle_signal);
  334.  
  335.   while (argc) {
  336.     if (argv[0][0]=='-') {
  337.       switch(tolower(argv[0][1])) {
  338.         case 'i': if (argc<2) warn("`-i' must be followed by a filename");
  339.                   else { process_input_file(argv[1]); --argc; ++argv; }
  340.                   break;
  341.         case 'o': if (argc<2) {
  342.                     warn("`-o' must be followed by a filename");
  343.                     break; }
  344.                   if (output_fname)
  345.                     warn("more than one `-o' given; I'm using the last");
  346.                   output_fname=argv[1]; --argc; ++argv;
  347.                   break;
  348.         case 'q': chattyP=0;
  349.                   break;
  350.         default: warn("unknown option. I understand -i, -o, -q.");
  351.                  break;
  352.       }
  353.     }
  354.     else insert_obj_name(*argv);
  355.     --argc; ++argv;
  356.   }
  357.  
  358. /* By this point we have the complete list of object filenames in
  359.  * obj_name[] and name_space[].
  360.  */
  361.  
  362.   if (!output_fname) output_fname="alf";
  363.   output_file=low_open(output_fname,low_CREATE);
  364.   if (!output_file) err1("couldn't open output file %s",output_fname);
  365.  
  366.   if (chattyP) printf("Reading sizes, datestamps etc...\n");
  367.   object=xmalloc(n_objects*sizeof(obj_info),"object-file table");
  368.   for (i=0;i<n_objects;++i) {
  369.     if (chattyP) {
  370.       int ll=strlen(obj_name[i]);
  371.       if (ll+char_pos>=80) { printf("\n"); char_pos=0; }
  372.       printf("%s ",obj_name[i]); fflush(stdout); char_pos+=ll+1;
  373.     }
  374.     fnsplit(obj_name[i],dbuf,lbuf);
  375.     if (finfo(lbuf,dbuf,&one_file)) {
  376.       warn1("couldn't find object file %s",obj_name[i]);
  377.       object[i].name=NULL; }
  378.     else {
  379.       object[i].name=obj_name[i];
  380.       object[i].size=one_file.length;
  381.       object[i].time0=(one_file.time1<<16)+(one_file.time0>>16);
  382.       object[i].time1=one_file.time0<<16;
  383.     }
  384.   }
  385.   if (chattyP && char_pos) { printf("\n"); char_pos=0; }
  386.  
  387. /* Now we have stats for object files, but there may be gaps
  388.  * if files weren't found.
  389.  * We shift things down as necessary to get rid of them.
  390.  */
  391.  
  392.   i=0; j=0; /* moving object[i] into object[j] next, if it exists */
  393.   while (i<n_objects) {
  394.     if (object[i].name) {
  395.       if (i!=j) object[j]=object[i];
  396.       ++i; ++j; }
  397.     else ++i;
  398.   }
  399.   n_objects=j;
  400.  
  401. /* Write chunk file header... */
  402.  
  403.   put_word(Chunk_file_ID);
  404.   put_word(5+n_objects); /* maxChunks */
  405.   put_word(5+n_objects); /* numChunks */
  406.  
  407. /* now one header entry for each chunk. First, LIB_TIME */
  408.   put_eight("LIB_TIME");
  409.   ofs_TIME=12+16*(5+n_objects);
  410.   put_word(ofs_TIME);
  411.   put_word(8); /* two words */
  412.  
  413. /* Now LIB_VRSN */
  414.   put_eight("LIB_VRSN");
  415.   ofs_VRSN=ofs_TIME+8;
  416.   put_word(ofs_VRSN);
  417.   put_word(4); /* one word */
  418.  
  419. /* Now LIB_DIRY */
  420.   put_eight("LIB_DIRY");
  421.   ofs_DIRY=ofs_VRSN+4;
  422.   put_word(ofs_DIRY);
  423.   put_word(0); /* size to be determined later */
  424.  
  425. /* Now the LIB_DATA chunks */
  426.   for (i=0;i<n_objects;++i) {
  427.     put_eight("LIB_DATA");
  428.     put_word(0); put_word(object[i].size); /* don't know the offsets yet */
  429.   }
  430.  
  431. /* And finally the two object-file-specific ones. */
  432.   put_eight("OFL_SYMT");
  433.   put_word(0); /* offset unknown */
  434.   put_word(0); /* size unknown   */
  435.   put_eight("OFL_TIME");
  436.   put_word(0); /* offset unknown */
  437.   put_word(8);
  438.  
  439. /* Now we need to write the chunks themselves. */
  440.  
  441.   set_cur_time(&time0,&time1);
  442.   put_word(time0); /* LIB_TIME */
  443.   put_word(time1);
  444.  
  445.   put_word(1); /* LIB_VRSN */
  446.  
  447. /* While building the directory chunk, we mustn't forget to keep track
  448.  * of how long it is.
  449.  */
  450.  
  451.   diry_size=0;
  452.   for (i=0;i<n_objects;++i) {
  453.     put_word(3+i);           /* ChunkIndex */
  454.     j=strlen(object[i].name);
  455.     put_word(20+((j+4)&~3)); /* EntryLength */
  456.     put_word(8+((j+4)&~3));  /* DataLength */
  457.     put_string_padded(object[i].name,j);
  458.     put_word(object[i].time0);
  459.     put_word(object[i].time1);
  460.     diry_size+=20+((j+4)&~3);
  461.   }
  462.  
  463. /* Now copy the object files themselves. */
  464.  
  465.   if (chattyP) { printf("Copying object files"); fflush(stdout); }
  466.   flush_output();
  467.   { int n_in_buf=0,n_left;
  468.     n_in_buf=0;
  469.     for (i=0;i<n_objects;++i) {
  470.       object_file=low_open(object[i].name,low_READ);
  471.       if (!object_file) err1("couldn't open object file %s",object[i].name);
  472.       n_left=low_extent(object_file);
  473.       while (n_left>0) {
  474.         j=low_read(object_file,output_buffer+n_in_buf,
  475.                    Output_buffer_size-n_in_buf);
  476.         n_in_buf+=j; if (n_in_buf>=Output_buffer_size) {
  477.           low_write(output_file,output_buffer,Output_buffer_size);
  478.           n_in_buf=0;
  479.         }
  480.         n_left-=j;
  481.       }
  482.       low_close(object_file);
  483.       pad_output();
  484.       if (chattyP) { printf("."); fflush(stdout); }
  485.     }
  486.     if (n_in_buf) low_write(output_file,output_buffer,n_in_buf);
  487.   }
  488.   output_buffer_start=low_ptr(output_file); output_buffer_next=0;
  489.  
  490. /* Now, the symbol table. This is a bit nasty, so we put most of the work
  491.  * in another function. */
  492.  
  493.   if (chattyP){ printf("\nBuilding symbol table"); fflush(stdout); }
  494.   symt_size=0; /* will accumulate */
  495.   for (i=0;i<n_objects;++i) {
  496.     object_file=low_open(object[i].name,low_READ);
  497.     if (!object_file) err1("couldn't open object file %s",object[i].name);
  498.     process_symbol_table(i);
  499.     low_close(object_file);
  500.     if (chattyP) { printf("."); fflush(stdout); }
  501.   }
  502.   object_file=0;
  503.   if (chattyP) printf("\n");
  504.  
  505. /* And the OFL_TIME chunk, which we give the same time as the LIB_TIME one. */
  506.  
  507.   put_word(time0);
  508.   put_word(time1);
  509.  
  510. /* Now we go back and fill in some stuff we left blank in the
  511.  * header of this chunk file.
  512.  */
  513.  
  514.   flush_output();
  515.   output_buffer_start=-2*Output_buffer_size;
  516.  
  517.   put_word_at(diry_size,56);
  518.   j=ofs_DIRY+diry_size;
  519.   for (i=0;i<n_objects;++i) {
  520.     put_word_at(j,68+16*i);
  521.     j+=(object[i].size+3)&~3;
  522.   }
  523.   put_word_at(j,68+16*n_objects);
  524.   put_word_at(symt_size,72+16*n_objects);
  525.   put_word_at(j+(symt_size+3)&~3,84+16*n_objects);
  526.  
  527.   flush_output();
  528.  
  529. /* That's all, folks! */
  530.  
  531.   close_files();
  532.   return return_code;
  533. }
  534.