#include #include long stonum(); /* char compiler_name[80] = "Pablo Kleinman (4:900/101)"; /* who compiled this */ char compiler_name[80] = "Tomas Gradin (2:200/108)"; /* who compiled this */ */ char compiler_name[80] = "Fido Software (1:125/111)"; /* who compiled this */ /* Compiles a .LXT file, producing the .SLN file (SM+ and LM messages) and the .CLN file, containing the CM messages. */ struct _fido fido; struct _lang_hdr lang_hdr; _stack = 4000; #define SIZE 1000 /* max. strings per table */ unsigned *ptr; /* table of text offsets */ char *text; /* the text blob */ unsigned size; /* it's maximum size */ unsigned highest; /* highest index, per table */ unsigned amt; /* how much in there, per table */ unsigned totl_strings; /* total number of strings */ unsigned totl_size; /* total string size */ char fname[SS]; /* language filename */ int logfile; /* log shit here */ main(argc,argv) int argc; char **argv; { char buff[256],*cp,*op; char et; /* element type */ unsigned en; /* element number */ int in,out; /* file handles */ char phase; /* which pass: LM, SM, CM */ int i,n,f; unsigned totl_strings,totl_size; printf("Language Compiler (11 Jun 90) for "); copr(); printf("\r\nCompiled by: \"%s\"\r\n",compiler_name); printf("\r\nThis is a restricted use program. Not for distribution.\r\n\r\n"); allmem(); fastfile(2); size= sizmem(); if (size < 20000) { printf("Not enough memory to run!\r\n"); exit(1); } ptr= (unsigned *) getmem(size); /* get working storage */ size -= SIZE * 2; /* how much left */ text= (char *) &ptr[SIZE]; /* rest is text space */ if (--argc) /* get filename */ cpyarg(fname,*++argv); /* from command line */ else { printf("You have to specify a language filename\r\n"); exit(1); } n= open("fido.sys",0); /* load system stuff */ if (n == -1) { clprintf("The Fido system file \"FIDO.SYS\" is missing!\r\n"); exit(1); } read(n,&fido,sizeof(fido)); close(n); if ((fido.fido_version != FIDOVER) && (fido.file_version != FILEVER)) { clprintf("Wrong Fido/FidoNet version!\r\n"); exit(1); } /* Pre-process the filename so that we have a clean copy of the name portion around for making the full filename. Basically, lop off any extention and make upper case. */ for (cp= fname; *cp; cp++) { /* remove any extention */ if (*cp == '.') { /* from filename */ *cp= NUL; break; } } stoupper(fname); /* make all upper case */ strcpy(buff,fname); strcat(buff,".LXT"); /* input file name */ in= open(buff,0); if (in == -1) { printf("Can't find \"%s\" input file!\r\n",buff); exit(1); } strcpy(text,fname); strcat(text,".LOG"); logfile= creat(text,2); /* start logging */ clprintf("Log File: %s\r\n",text); clprintf("Input File: %s\r\n",buff); clprintf("Maximum String Size: %8,lu\r\n",0L + size); clprintf("Maximum Table Elements: %8,d\r\n",SIZE); /* Now compile the output file. */ newdelim(" ,\t"); /* the only delimiters */ phase= 'S'; /* from the top */ totl_strings= totl_size= 0; /* zero tally counters */ while (phase != 'X') { switch (phase) { case 'S': out= makeout(".SLN"); break; case 'C': out= makeout(".CLN"); break; } op= text; /* set output pointer */ amt= highest= 0; /* table index */ lseek(in,0L,0); /* start from the beginning */ for (i= 0; i < SIZE; i++) ptr[i]= 0; /* clear the table */ /* Lines have the format: XMnnn "string" Where X is the element type, and nnn is the element number. */ while (getline(in,buff,sizeof(buff))) { /* read a line */ cp= skip_delim(buff); et= toupper(*cp); /* get element type */ en= atoi(&cp[2]); /* element number */ if ((et == phase) || (et == 'N')) { /* if correct phase */ cp= next_arg(cp); /* skip keyword */ cpyscrarg(op,cp); /* copy, strip quotes */ scrmac(op,op); /* expand controls */ if (en >= SIZE) { clprintf("OOPS -- A numerator is out of range!\r\n"); clprintf("I give up!\r\n"); phase= 'X'; break; } ptr[en]= op - text; /* set it's place in the table */ if (en > highest) highest= en; ++totl_strings; /* count total defined */ /* Generally strings are null terminated. There is a special case where they end with \377, the marker for the ubiquituous CR/LF/NUL sequence; the 377 takes the place of the null. */ i= strlen(op) + 1; /* if \377 */ /* BREAKS FIDO -- "strcpy(buff,string(stringID))" fails if the string is not NUL terminated! (cpyarg, strcpy, strcat...) Too bad, cuz it saved 200 bytes/file immediately. (400 bytes more DS: space would be nice...) if (i > 1) if (op[i - 2] == '\377') --i; /* un-count NUL */ */ if (amt + i > size) { clprintf("OOPS -- Total size of text strings is too large!\r\n"); clprintf("I give up!\r\n"); phase= 'X'; break; } amt += i; /* total count */ op += i; /* advance pointer */ totl_size += i; /* total string size */ } } /* End of file -- write the table out. First we have to fixup all the offsets in the pointer table; the table is loaded with the text immediately following; the offsets should be relative to the start of the table. Note that the offset for xM0 will be zero, since it is the first thing in the buffer. */ n= highest * 2; /* table base offset */ n += 4; /* 0th plus marker */ f= -1; /* -1 == no msg yet */ for (i= 0; i <= highest; i++) { if (i && !ptr[i]) { /* report unused IDs */ if (f == -1) { clprintf("Unused stringIDs:\r\n"); f= 0; /* reuse as output counter */ } clprintf("%cM%-3d ",phase,i); if (++f >= 8) { /* 8 per line max */ clprintf("\r\n"); f= 0; } } ptr[i] += n; /* fixup offset */ } if (f > 0) clprintf("\r\n"); ptr[highest + 1]= -1; /* end-of-table marker */ write(out,(char *)&ptr[0],n); /* write table */ if (write(out,text,amt) != amt) { /* then text */ clprintf("OOPS -- Disk full!\r\n"); clprintf("I give up!\r\n"); phase= 'X'; } /* Switch to the next phase. */ switch (phase) { case 'S': /* this phase complete */ clprintf("SM Table String Size: %8,d\r\n",amt); clprintf("Highest Element: SM%03d\r\n",highest); closeout(out); phase= 'C'; break; case 'C': clprintf("CM Table String Size: %8,d\r\n",amt); clprintf("Highest Element: CM%03d\r\n",highest); closeout(out); phase= 'X'; break; } } clprintf("\r\n"); clprintf("Total String Size: %8,d\r\n",totl_size); clprintf("Total String Elements: %8,d\r\n",totl_strings); close(in); close(logfile); } /* Generate the CRC and close the file. */ closeout(f) int f; { int i; char c; i= crcfile(f); c= i >> 8; write(f,&c,1); /* MS byte first */ c= i; write(f,&c,1); /* then LS byte */ close(f); } /* CRC a file. */ crcfile(f) int f; { int i,n; lseek(f,0L,0); /* go over the file */ clrcrc(); while (n= read(f,text,size)) { /* generate the CRC */ for (i= 0; i < n; i++) updcrc(text[i]); } return(fincrc()); /* complete the CRC */ } /* Get a line from the file; return 0 if the file is empty. */ getline(f,buff,len) int f; char *buff; { char *cp; while (rline(f,buff,len)) { /* read a line of source, */ cp= skip_delim(buff); if (*cp == ';') continue; /* ignore comments */ if (! *cp) continue; /* and blank lines */ return(1); /* got one */ } return(0); /* file empty */ } /* Make an output file and basic header. */ makeout(ext) char *ext; { char *cp,buff[SS]; int out,i; strcpy(buff,fname); /* make full name */ strcat(buff,ext); clprintf("\r\n"); printf("Creating output file: \"%s\"\r\n",buff); out= creat(buff,2); if (out == -1) { printf("File creation error!\r\n"); exit(1); } for (cp= (char *) &lang_hdr, i= sizeof(struct _lang_hdr); i--;) *cp++= NUL; strcat(lang_hdr.junk,"This file is part of the Fido/FidoNet system by\r\n"); strcat(lang_hdr.junk,"Tom Jennings/Fido Software, Box 77731, San\r\n"); strcat(lang_hdr.junk,"Francisco CA 94107, USA. You may use this file with\r\n"); strcat(lang_hdr.junk,"Fido/FidoNet only. Do not modify this file.\r\n"); strcat(lang_hdr.junk,"\032"); /* Control-Z */ strcpy(lang_hdr.compiler,compiler_name); /* who dun it */ lang_hdr.version= LANGVER; /* set version, */ write(out,&lang_hdr,sizeof(struct _lang_hdr)); /* write out the header */ return(out); /* file handle */ } /* Copy a script arg; either a single word or a quoted string. */ cpyscrarg(dp,sp) char *dp,*sp; { char lastc,c,q; if (*sp == '"') q= *sp++; else q= NUL; /* optional quote stripping */ lastc= NUL; while (c= *sp) { ++sp; /* next ... */ if ((c == q) && (lastc != '\\')) /* if the quote char & not quoted */ break; /* end of argument */ if (!q && delim(c)) break; /* else stop if a delimiter */ *dp++= c; /* else part of same arg */ lastc= c; /* remember last char */ } *dp= NUL; } /* Convert C-like control characters. */ static scrmac(dp,sp) char *dp,*sp; { char *cp,c; int i; while (c= *sp++) { if (c == '\\') { /* if literal, */ c= *sp; /* get the next char */ if (c) ++sp; /* (dont skip the NUL!) */ switch (tolower(c)) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': /* octal! */ c= stonum(--sp,8); while (isdigit(*sp)) ++sp; break; case 'r': c= CR; break; case 'n': c= LF; break; case 'b': c= BS; break; case 't': c= TAB; break; default: break; /* else leave literal as-is */ } } if (c) *dp++= c; } *dp= NUL; } clprintf(f) char *f; { char buf[400],*p; _spr(buf,&f); p= buf; write (logfile,p,strlen(p)); while (*p) bdos(2,*p++); } /* Return true if the FBIT is set. */ fbit(bit) int bit; { return(fido.fbits[bit / sizeof(char)] & (1 << bit % sizeof(char))); }