home *** CD-ROM | disk | FTP | other *** search
- /* >c.makeALF */
-
- /* Utility for creating an ALF file from a number of AOF files
- *
- * makealf [-i inputfile] [-o outputfile] [object-file-list]
- *
- * Puts the object files given on the command line, and optionally
- * those named in <inputfile>, into a library file.
- *
- * If no <outputfile> is given, the output file is named "alf".
- *
- * Ambiguous filenames are not expanded.
- */
-
- /*------------------------------------------------------------------------*/
-
- #define VERSION_STRING "1.02 (31/3/1995)"
-
- #include <ctype.h>
- #include <signal.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
-
- #include "finfo.h"
- #include "lowfile.h"
-
- #define Chunk_file_ID 0xC3CBC6C5
- #define Max_n_objects 1024
- #define Object_name_size 16384 /* space for names of object files */
- #define Max_line_length 256 /* in input file */
- #define Output_buffer_size 32768
- #define String_table_unit 4096 /* granularity; must be power of 2 */
-
- /*------------------------------------------------------------------------*/
-
- typedef struct {
- char *name;
- int size;
- int time0; /* high word. (Weird.) */
- int time1; /* low word */
- } obj_info;
-
- /*------------------------------------------------------------------------*/
-
- static char *my_name;
- static FILE *input_file=NULL;
- static int output_file=0; /* RISC OS handle */
- static int object_file=0; /* RISC OS handle for current object file */
- static char *output_fname=NULL;
- static char *name_space; /* for names of object files */
- static int name_next=0; /* next free byte therein */
- static char **obj_name; /* array of names */
- static int n_objects=0;
- static int return_code=0;
- static char *output_buffer;
- static int output_buffer_next=0;
- static int output_buffer_start; /* file offset of start of buffer */
- static int symt_size; /* size of symbol-table chunk, in bytes */
- static char *string_table=NULL; /* for current object file */
- static int str_tab_size=0; /* this extends as necessary */
- static obj_info *object;
- static int chattyP=1; /* friendly progress reports? */
-
- /*------------------------------------------------------------------------*/
-
- static void close_files(void) {
- if (input_file) fclose(input_file);
- if (output_file) low_close(output_file);
- if (object_file) low_close(object_file);
- }
-
- /*------------------------------------------------------------------------*/
-
- static void warn(char *s) {
- fprintf(stderr,"! Warning (%s): %s.\n",my_name,s);
- return_code=4;
- }
-
- static void warn1(char *s, char *t) { /* s is format string */
- fprintf(stderr,"! Warning (%s): ",my_name);
- fprintf(stderr,s,t);
- fprintf(stderr,".\n");
- return_code=4;
- }
-
- static void err(char *s) {
- fprintf(stderr,"! Error (%s): %s.\n",my_name,s);
- close_files();
- exit(8);
- }
-
- static void err1(char *s, char *t) { /* s is format string */
- fprintf(stderr,"! Error (%s): ",my_name);
- fprintf(stderr,s,t);
- fprintf(stderr,".\n");
- close_files();
- exit(8);
- }
-
- /*------------------------------------------------------------------------*/
-
- static void *xmalloc(int size, char *s) {
- void *p;
- p=malloc(size);
- if (!p) err1("out of memory for %s",s);
- return p;
- }
-
- /*------------------------------------------------------------------------*/
-
- static void insert_obj_name(char *s) {
- int k;
- while(isspace(*s)) ++s;
- if (!*s || *s=='#') return;
- k=0; while (s[k] && !isspace(s[k])) ++k;
- if (name_next+k+1>=Object_name_size)
- err("out of memory for filenames");
- memcpy(name_space+name_next,s,k);
- name_space[name_next+k]=0;
- obj_name[n_objects++]=name_space+name_next;
- name_next+=k+1;
- }
-
- /*------------------------------------------------------------------------*/
-
- static void process_input_file(char *s) {
- char buf[Max_line_length];
- int l;
- input_file=fopen(s,"r");
- if (!input_file) {
- warn1("couldn't open input file %s",s);
- return; }
- while (fgets(buf,Max_line_length,input_file)) {
- l=strlen(buf);
- if (buf[l-1]!='\n') { warn1("over-long line in input file %s",s);
- printf("%d %s\n",buf[l-1],buf); }
- else buf[l-1]='\0';
- if (*buf=='#') continue; /* comment character */
- insert_obj_name(buf);
- }
- }
-
- /*------------------------------------------------------------------------*/
-
- static void flush_output(void) {
- low_setptr(output_file,output_buffer_start);
- low_write(output_file,output_buffer,output_buffer_next);
- output_buffer_start+=output_buffer_next;
- output_buffer_next=0;
- }
-
- static void put_word(unsigned int w) {
- if (output_buffer_next+4>=Output_buffer_size) flush_output();
- if (output_buffer_next&3) warn("ill-aligned put_word()");
- *((int *)(output_buffer+output_buffer_next))=w;
- output_buffer_next+=4;
- }
-
- static void put_string_padded(char *s, int l) {
- int i;
- i=(l+4)&~3;
- if (output_buffer_next+i>=Output_buffer_size) flush_output();
- if (i>Output_buffer_size) err("Excessively long string");
- memcpy(output_buffer+output_buffer_next,s,l);
- output_buffer_next+=l;
- do output_buffer[output_buffer_next++]='\0'; while (output_buffer_next&3);
- }
-
- static void put_eight(char *s) {
- if (output_buffer_next+8>=Output_buffer_size) flush_output();
- if (output_buffer_next&3) warn("ill-aligned put_eight()");
- *((int *)(output_buffer+output_buffer_next))=*((int *)s);
- *((int *)(output_buffer+output_buffer_next+4))=*((int *)(s+4));
- output_buffer_next+=8;
- }
-
- static void refresh_buffer(void) {
- low_setptr(output_file,output_buffer_start);
- output_buffer_next=low_read(output_file,output_buffer,Output_buffer_size);
- }
-
- static void put_word_at(int v, int p) {
- if (p&3) warn("ill-aligned put_word_at()");
- if (p<output_buffer_start || p>=output_buffer_start+output_buffer_next) {
- flush_output();
- low_setptr(output_file,p); output_buffer_start=p;
- refresh_buffer();
- }
- *(int *)(output_buffer+p-output_buffer_start)=v;
- if (p-output_buffer_start>output_buffer_next)
- output_buffer_next=p-output_buffer_start;
- }
-
- /*------------------------------------------------------------------------*/
-
- static void pad_output(void) {
- char z[4]="\0\0\0"; /* one more \0 added by compiler! */
- int i;
- i=(low_ptr(output_file)&3);
- if (i) low_write(output_file,z,4-i);
- }
-
- /*------------------------------------------------------------------------*/
-
- /* This assumes that a time_t counts seconds since midnight, 1/1/1970 */
- /* Also, it will stop working some time in 20xx */
- #define SEVENTY_YEARS (25567u*24u*60u*60u)
-
- static void set_cur_time(unsigned int *t0p, unsigned int *t1p) {
- time_t t;
- double d;
- time(&t);
- d=(t+(double)SEVENTY_YEARS)*100.;
- *t0p=(int)(d/65536.);
- *t1p=(int)(d-65536.*(*t0p))<<16;
- }
-
- /*------------------------------------------------------------------------*/
-
- /* The following breaks if the chunk file header doesn't fit into a
- * 4k buffer. This should not be a problem.
- */
-
- static void process_symbol_table(int num) {
- char wee_buf[4096];
- int *wb=(int *)wee_buf;
- int *sym_buf;
- int n_chunks;
- int n_symbols;
- int i,j;
- int str_ofs=0, sym_ofs=0, hdr_ofs=0;
- int str_siz,sym_siz,hdr_siz;
-
- low_read(object_file,wee_buf,4096);
- if (*wb!=0xC3CBC6C5)
- warn1("non-chunk-file ``object file'' %s",object[num].name);
- n_chunks=wb[2];
- for (i=0;i<n_chunks;++i) {
- if (wb[3+i*4]=='OBJ_' && wb[4+i*4]=='SYMT') {
- sym_ofs=wb[5+i*4]; sym_siz=wb[6+i*4]; }
- if (wb[3+i*4]=='OBJ_' && wb[4+i*4]=='STRT') {
- str_ofs=wb[5+i*4]; str_siz=wb[6+i*4]; }
- if (wb[3+i*4]=='OBJ_' && wb[4+i*4]=='HEAD') {
- hdr_ofs=wb[5+i*4]; hdr_siz=wb[6+i*4]; }
- }
- if (!hdr_ofs) {
- warn1("object file %s has no header chunk",object[num].name); return; }
- if (!str_ofs) {
- warn1("object file %s has no string table",object[num].name); return; }
- if (!sym_ofs) {
- warn1("object file %s has no symbol table",object[num].name); return; }
-
- low_setptr(object_file,hdr_ofs);
- low_read(object_file,wee_buf,4096);
- if (*wb!=0xC5E2D080) {
- warn1("non-AOF ``object'' file %s",object[num].name); return; }
- n_symbols=wb[3];
-
- if (str_siz>str_tab_size) {
- if (string_table) free(string_table);
- str_tab_size=(str_siz+(String_table_unit-1))&~(String_table_unit-1);
- string_table=xmalloc(str_tab_size,"string table");
- }
-
- low_setptr(object_file,str_ofs);
- low_read(object_file,string_table,str_siz);
-
- sym_buf=(int *)xmalloc(sym_siz,"symbol table");
- low_setptr(object_file,sym_ofs);
- low_read(object_file,sym_buf,sym_siz);
-
- for (i=0;i<n_symbols;++i) {
- if ((sym_buf[i*4+1]&3)==3) { /* if global & defined ... */
- put_word(num+3); /* ChunkIndex */
- j=strlen(string_table+sym_buf[i*4]);
- put_word(12+((j+4)&~3));
- put_word((j+4)&~3);
- put_string_padded(string_table+sym_buf[i*4],j);
- symt_size+=12+((j+4)&~3);
- }
- }
- free(sym_buf);
- }
-
- /*------------------------------------------------------------------------*/
-
- static char *sig_list[]={
- NULL,"SIGABRT","SIGFPE","SIGILL","SIGINT","SIGSEGV","SIGTERM","SIGSTAK"};
-
- static void handle_signal(int sig) {
- close_files();
- if (sig>0 && sig<8)
- fprintf(stderr,"!! %s caught signal %s -- exiting.\n",
- my_name,sig_list[sig]);
- else fprintf(stderr,"!! %s caught signal number %d -- exiting.\n",
- my_name,sig);
- exit(12);
- }
-
- /*------------------------------------------------------------------------*/
-
- int main(int argc, char *argv[]) {
- int i,j;
- fileinfo one_file; /* for finding stats of object files */
- char dbuf[256]; /* these two for splitting filenames */
- char lbuf[256]; /* ... */
- int ofs_TIME; /* offset to LIB_TIME chunk */
- int ofs_VRSN; /* offset to LIB_VRSN chunk */
- int ofs_DIRY; /* offset to LIB_DIRY chunk */
- unsigned int time0,time1; /* time now */
- int diry_size;
- int char_pos=0; /* for output formatting! */
-
- my_name=*argv; --argc; ++argv;
-
- if (argc==1 && !strcmp(*argv,"-v")) {
- fprintf(stderr,"This is makeALF, version " VERSION_STRING ".\n");
- return 0;
- }
-
- name_space=(char *)xmalloc(Object_name_size,"filenames");
- obj_name=(char **)xmalloc(Max_n_objects*sizeof(char *),"filenames");
- output_buffer=(char *)xmalloc(Output_buffer_size,"Output buffer");
-
- signal(SIGABRT,handle_signal);
- signal(SIGFPE,handle_signal);
- signal(SIGILL,handle_signal);
- signal(SIGINT,handle_signal);
- signal(SIGSEGV,handle_signal);
- signal(SIGTERM,handle_signal);
- signal(SIGSTAK,handle_signal);
-
- while (argc) {
- if (argv[0][0]=='-') {
- switch(tolower(argv[0][1])) {
- case 'i': if (argc<2) warn("`-i' must be followed by a filename");
- else { process_input_file(argv[1]); --argc; ++argv; }
- break;
- case 'o': if (argc<2) {
- warn("`-o' must be followed by a filename");
- break; }
- if (output_fname)
- warn("more than one `-o' given; I'm using the last");
- output_fname=argv[1]; --argc; ++argv;
- break;
- case 'q': chattyP=0;
- break;
- default: warn("unknown option. I understand -i, -o, -q.");
- break;
- }
- }
- else insert_obj_name(*argv);
- --argc; ++argv;
- }
-
- /* By this point we have the complete list of object filenames in
- * obj_name[] and name_space[].
- */
-
- if (!output_fname) output_fname="alf";
- output_file=low_open(output_fname,low_CREATE);
- if (!output_file) err1("couldn't open output file %s",output_fname);
-
- if (chattyP) printf("Reading sizes, datestamps etc...\n");
- object=xmalloc(n_objects*sizeof(obj_info),"object-file table");
- for (i=0;i<n_objects;++i) {
- if (chattyP) {
- int ll=strlen(obj_name[i]);
- if (ll+char_pos>=80) { printf("\n"); char_pos=0; }
- printf("%s ",obj_name[i]); fflush(stdout); char_pos+=ll+1;
- }
- fnsplit(obj_name[i],dbuf,lbuf);
- if (finfo(lbuf,dbuf,&one_file)) {
- warn1("couldn't find object file %s",obj_name[i]);
- object[i].name=NULL; }
- else {
- object[i].name=obj_name[i];
- object[i].size=one_file.length;
- object[i].time0=(one_file.time1<<16)+(one_file.time0>>16);
- object[i].time1=one_file.time0<<16;
- }
- }
- if (chattyP && char_pos) { printf("\n"); char_pos=0; }
-
- /* Now we have stats for object files, but there may be gaps
- * if files weren't found.
- * We shift things down as necessary to get rid of them.
- */
-
- i=0; j=0; /* moving object[i] into object[j] next, if it exists */
- while (i<n_objects) {
- if (object[i].name) {
- if (i!=j) object[j]=object[i];
- ++i; ++j; }
- else ++i;
- }
- n_objects=j;
-
- /* Write chunk file header... */
-
- put_word(Chunk_file_ID);
- put_word(5+n_objects); /* maxChunks */
- put_word(5+n_objects); /* numChunks */
-
- /* now one header entry for each chunk. First, LIB_TIME */
- put_eight("LIB_TIME");
- ofs_TIME=12+16*(5+n_objects);
- put_word(ofs_TIME);
- put_word(8); /* two words */
-
- /* Now LIB_VRSN */
- put_eight("LIB_VRSN");
- ofs_VRSN=ofs_TIME+8;
- put_word(ofs_VRSN);
- put_word(4); /* one word */
-
- /* Now LIB_DIRY */
- put_eight("LIB_DIRY");
- ofs_DIRY=ofs_VRSN+4;
- put_word(ofs_DIRY);
- put_word(0); /* size to be determined later */
-
- /* Now the LIB_DATA chunks */
- for (i=0;i<n_objects;++i) {
- put_eight("LIB_DATA");
- put_word(0); put_word(object[i].size); /* don't know the offsets yet */
- }
-
- /* And finally the two object-file-specific ones. */
- put_eight("OFL_SYMT");
- put_word(0); /* offset unknown */
- put_word(0); /* size unknown */
- put_eight("OFL_TIME");
- put_word(0); /* offset unknown */
- put_word(8);
-
- /* Now we need to write the chunks themselves. */
-
- set_cur_time(&time0,&time1);
- put_word(time0); /* LIB_TIME */
- put_word(time1);
-
- put_word(1); /* LIB_VRSN */
-
- /* While building the directory chunk, we mustn't forget to keep track
- * of how long it is.
- */
-
- diry_size=0;
- for (i=0;i<n_objects;++i) {
- put_word(3+i); /* ChunkIndex */
- j=strlen(object[i].name);
- put_word(20+((j+4)&~3)); /* EntryLength */
- put_word(8+((j+4)&~3)); /* DataLength */
- put_string_padded(object[i].name,j);
- put_word(object[i].time0);
- put_word(object[i].time1);
- diry_size+=20+((j+4)&~3);
- }
-
- /* Now copy the object files themselves. */
-
- if (chattyP) { printf("Copying object files"); fflush(stdout); }
- flush_output();
- { int n_in_buf=0,n_left;
- n_in_buf=0;
- for (i=0;i<n_objects;++i) {
- object_file=low_open(object[i].name,low_READ);
- if (!object_file) err1("couldn't open object file %s",object[i].name);
- n_left=low_extent(object_file);
- while (n_left>0) {
- j=low_read(object_file,output_buffer+n_in_buf,
- Output_buffer_size-n_in_buf);
- n_in_buf+=j; if (n_in_buf>=Output_buffer_size) {
- low_write(output_file,output_buffer,Output_buffer_size);
- n_in_buf=0;
- }
- n_left-=j;
- }
- low_close(object_file);
- pad_output();
- if (chattyP) { printf("."); fflush(stdout); }
- }
- if (n_in_buf) low_write(output_file,output_buffer,n_in_buf);
- }
- output_buffer_start=low_ptr(output_file); output_buffer_next=0;
-
- /* Now, the symbol table. This is a bit nasty, so we put most of the work
- * in another function. */
-
- if (chattyP){ printf("\nBuilding symbol table"); fflush(stdout); }
- symt_size=0; /* will accumulate */
- for (i=0;i<n_objects;++i) {
- object_file=low_open(object[i].name,low_READ);
- if (!object_file) err1("couldn't open object file %s",object[i].name);
- process_symbol_table(i);
- low_close(object_file);
- if (chattyP) { printf("."); fflush(stdout); }
- }
- object_file=0;
- if (chattyP) printf("\n");
-
- /* And the OFL_TIME chunk, which we give the same time as the LIB_TIME one. */
-
- put_word(time0);
- put_word(time1);
-
- /* Now we go back and fill in some stuff we left blank in the
- * header of this chunk file.
- */
-
- flush_output();
- output_buffer_start=-2*Output_buffer_size;
-
- put_word_at(diry_size,56);
- j=ofs_DIRY+diry_size;
- for (i=0;i<n_objects;++i) {
- put_word_at(j,68+16*i);
- j+=(object[i].size+3)&~3;
- }
- put_word_at(j,68+16*n_objects);
- put_word_at(symt_size,72+16*n_objects);
- put_word_at(j+(symt_size+3)&~3,84+16*n_objects);
-
- flush_output();
-
- /* That's all, folks! */
-
- close_files();
- return return_code;
- }
-