#include #include #include #include #include #include #include "common.h" #define max_bytes 50000L #define max_modules 1000 #define max_idents 5000 #define max_sections 4000 #define hash_size 353 #define buf_size 100 #define longest_name 1000 #define long_buf_size (buf_size+longest_name) #define local static #define array_size(a)((int)(sizeof(a)/sizeof(a[0]))) #define false (boolean)0 #define true (boolean)1 #define ctangle 0 #define cweave 1 #define and_and 04 #define lt_lt 020 #define gt_gt 021 #define plus_plus 013 #define minus_minus 01 #define minus_gt 031 #define not_eq 032 #define lt_eq 034 #define gt_eq 035 #define eq_eq 036 #define or_or 037 #define find_char()(loc<=limit||get_line()) #define id_index(p)((sixteen_bits)((p)-id_table)) #define id_at(i)(&id_table[i]) #define mod_index(p)((sixteen_bits)((p)-mod_table)) #define mod_at(i)(&mod_table[i]) #define name_begin(p)((p)->byte_start) #define length(p)((int)(strlen(name_begin(p)))) #define name_end(p)(name_begin(p)+length(p)) #define complete_name(p)((p)->byte_start[-1]=='\0') #define print_mod(p) \ printf(": <%s%s>",name_begin(p),complete_name(p)?"":"...") #define spotless 0 #define harmless_message 1 #define error_message 2 #define fatal_message 3 #define mark_harmless() \ if(history==spotless)history=harmless_message;else #define mark_error()(history=error_message) #define overflow(t)fatal("\n! Sorry, %s capacity exceeded",t) #define confusion(s)fatal("\n! This can't happen: %s",s) #define show_banner flags['b'] #define show_happiness flags['h'] #define show_progress flags['p'] #define show_stats flags['s'] #define C_plus_plus flags['+'] #define compatibility_mode flags['c'] #define update_terminal()fflush(stdout) #define new_line()putchar('\n') #define term_write(string,leng)printf("%.*s",(int)(leng),string) #define buffer_end (&buffer[buf_size-2]) #define max_include_depth 10 #define max_include_paths 8 #define max_path_length 80 #define lines_match() \ (change_limit-change_buffer==limit-buffer \ &&strncmp(buffer,change_buffer,limit-buffer)==0) #define byte_mem_end (&byte_mem[max_bytes]) #define id_table_end (&id_table[max_idents]) #define mod_table_end (&mod_table[max_modules]) #define copy_char(c)if(id_loc0);}/*:60*//*66:*/ #line 1000 "common.w" *byte_ptr++='\0';/*:66*//*83:*/ #line 1307 "common.w" mod_text[0]=' ';/*:83*//*102:*/ #line 1649 "common.w" show_banner=show_happiness=show_progress=true;/*:102*/ #line 119 "common.w" scan_args(argc,argv); }/*:19*//*22:*/ #line 162 "common.w" local boolean input_ln(FILE*f) {register int c; register char*k=limit=buffer; while((c=getc(f))!='\n'&&c!=EOF) if(k<=buffer_end){*k++=c;if(!isspace(c))limit=k;} if(k>buffer_end) {loc= &buffer[0]; err_print("! Input line too long"); if(limit>buffer_end)limit=buffer_end; } if(buffer[0]=='@'&&limit> &buffer[1]&&strchr("IXYZ",buffer[1])!=NULL) buffer[1]=tolower(buffer[1]); return c!=EOF||limit>buffer; }/*:22*//*25:*/ #line 261 "common.w" boolean push_input_file(boolean header,boolean suspend) {boolean success=false; char delim=' '; while(loc',++loc; if(loc>=limit)err_print("! Include file name not given"); else if(++include_depth>=max_include_depth) {--include_depth; err_print("! Too many nested includes"); } else {/*26:*/ #line 298 "common.w" {char*k=cur_file_name; while(loc &buffer[1]&&buffer[0]=='@'&&buffer[1]=='i') {loc= &buffer[2];print_where=true;push_input_file(false,false);} else return true; else if(include_depth==0) {input_has_ended=true;web_file_open=false;return false;} else {fclose(cur_file);print_where=true; if(include_depth-- ==saved_include_depth) {changing=saved_changing;change_limit=saved_change_limit; saved_include_depth=0;including_header_file=false; if(changing)return false; } } while(true); }/*:31*//*33:*/ #line 464 "common.w" local void prime_the_change_buffer(void) {change_limit=change_buffer;/*34:*/ #line 477 "common.w" do {if(++change_line,!input_ln(change_file))return; if(limit> &buffer[1]&&buffer[0]=='@') if(buffer[1]=='x')break; else if(buffer[1]=='y'||buffer[1]=='z') {loc= &buffer[2]; err_print("! Where is the matching @x?"); } else/*35:*/ #line 497 "common.w" {if(buffer[1]=='i'&&!compatibility_mode) {loc= &buffer[2];err_print("! No includes allowed in change file");} }/*:35*/ #line 486 "common.w" }while(true);/*:34*//*36:*/ #line 506 "common.w" do if(++change_line,!input_ln(change_file)) {loc= &buffer[0];err_print("! Change file ended after @x");return;} while(limit==buffer);/*:36*//*37:*/ #line 512 "common.w" {int n=(int)(limit-buffer);change_limit=change_buffer+n; strncpy(change_buffer,buffer,n); }/*:37*/ #line 470 "common.w" }/*:33*//*38:*/ #line 529 "common.w" local void check_change(void) {int n=0; if(!lines_match())return; print_where=true; do {changing=true;/*39:*/ #line 560 "common.w" {if(++change_line,!input_ln(change_file)) {loc= &buffer[0];err_print("! Change file ended before @y"); change_limit=change_buffer;changing=false;return; } if(limit> &buffer[1]&&buffer[0]=='@') if(buffer[1]=='y')break; else if(buffer[1]=='x'||buffer[1]=='z') {loc= &buffer[2];err_print("! Where is the matching @y?");} else/*35:*/ #line 497 "common.w" {if(buffer[1]=='i'&&!compatibility_mode) {loc= &buffer[2];err_print("! No includes allowed in change file");} }/*:35*//*37:*/ #line 512 "common.w" {int n=(int)(limit-buffer);change_limit=change_buffer+n; strncpy(change_buffer,buffer,n); }/*:37*/ #line 572 "common.w" }/*:39*/ #line 538 "common.w" changing=false; if(!get_web_line()) {loc= &buffer[0]; err_print("! CWEB file ended during a change");return; } if(!lines_match())++n; }while(true); if(n>0) {loc= &buffer[2]; print("\n! Hmm... %d of the preceding lines failed to match",n); err_print(""); } }/*:38*//*41:*/ #line 585 "common.w" void reset_input(void) {boolean use_change_file=change_file_name[0]!='\0';/*42:*/ #line 601 "common.w" {if((web_file=fopen(web_file_name,"r"))!=NULL) strcpy(file[0].name,web_file_name); else if((web_file=fopen(alt_web_file_name,"r"))!=NULL) strcpy(file[0].name,alt_web_file_name); else fatal("! Cannot open \"%s\" as input file",web_file_name); web_file_open=true; if(use_change_file) if((change_file=fopen(change_file_name,"r"))!=NULL) strcpy(change.name,change_file_name); else if(!change_file_explicit) use_change_file=false; else fatal("! Cannot open \"%s\" as change file",change_file_name); }/*:42*/ #line 588 "common.w" cur_line=0;change_line=0;include_depth=0; if(use_change_file){changing=true;prime_the_change_buffer();} else change_limit=change_buffer; limit=buffer;loc= &buffer[1]; changing=false;input_has_ended=false; }/*:41*//*45:*/ #line 660 "common.w" boolean get_line(void) { restart: if(changing)mark_section_as_changed(section_count); else/*47:*/ #line 715 "common.w" {if(get_web_line() &&change_limit>change_buffer &&limit-buffer==change_limit-change_buffer &&buffer[0]==change_buffer[0] )check_change(); }/*:47*/ #line 665 "common.w" if(changing) {/*48:*/ #line 728 "common.w" {if(++change_line,!input_ln(change_file)) {err_print("! Change file ended without @z"); buffer[0]='@';buffer[1]='z';limit= &buffer[2]; } if(limit> &buffer[1]&&buffer[0]=='@') if(buffer[1]=='z') {prime_the_change_buffer();changing=false;print_where=true;} else if(buffer[1]=='x'||buffer[1]=='y') {loc= &buffer[2];err_print("! Where is the matching @z?");} else/*35:*/ #line 497 "common.w" {if(buffer[1]=='i'&&!compatibility_mode) {loc= &buffer[2];err_print("! No includes allowed in change file");} }/*:35*/ #line 739 "common.w" }/*:48*/ #line 667 "common.w" if(!changing) {mark_section_as_changed(section_count);goto restart;} } loc= &buffer[0];*limit=' '; if(compatibility_mode&&buffer[0]=='@'&&buffer[1]=='i') {loc+=2;print_where=true;push_input_file(false,changing); goto restart; } if(limit-buffer>5 &&strncmp(buffer,"#line",5)==0&&isspace((eight_bits)buffer[5]))/*46:*/ #line 686 "common.w" {sixteen_bits line=0; print_where=true; loc= &buffer[6];while(locline=line-1; strncpy(cur_f->name,loc,i);cur_f->name[i]='\0'; goto restart; } } } err_print("! Improper #line directive");goto restart; }/*:46*/ #line 679 "common.w" return!input_has_ended; }/*:45*//*50:*/ #line 755 "common.w" void check_complete(void) {if(change_limit!=change_buffer) {int l=(int)(change_limit-change_buffer); strncpy(buffer,change_buffer,l);limit= &buffer[l]; changing=true;loc=buffer;web_file_open=true; err_print("! Change file entry did not match"); } }/*:50*//*54:*/ #line 823 "common.w" char*store_string(char*s,int l) {char*dest=byte_ptr; if(byte_mem_end-byte_ptr<=l)overflow("byte memory"); byte_ptr+=l;*byte_ptr++='\0';return strncpy(dest,s,l); }/*:54*//*61:*/ #line 914 "common.w" id_pointer id_lookup(char*first,char*last,int ilk) {int l,h; if(last==NULL)last=first+(l=(int)strlen(first)); else l=(int)(last-first);/*62:*/ #line 932 "common.w" {char*p=first; h= *p;while(++phash_link; if(p==NULL)/*64:*/ #line 955 "common.w" {p=id_ptr; if(id_ptr++ >=id_table_end)overflow("identifier"); name_begin(p)=store_string(first,l); if(program==cweave)init_id_name(p,ilk); p->hash_link=hash[h];hash[h]=p; }/*:64*/ #line 947 "common.w" return p; }/*:63*/ #line 922 "common.w" }/*:61*//*70:*/ #line 1036 "common.w" local enum mod_comparison mod_name_cmp (char*p,int l1,char*q,int l2) {int l=l1=0)if(*p++ != *q++)return* --p< * --q?less:greater; return l1l2?extension:equal; }/*:70*//*71:*/ #line 1051 "common.w" local mod_pointer make_mod_node(char*name) {mod_pointer node=mod_ptr; if(mod_ptr++ >=mod_table_end)overflow("module name"); name_begin(node)=name; node->llink=NULL;node->rlink=NULL; init_module_name(node); return node; }/*:71*//*72:*/ #line 1067 "common.w" local mod_pointer mod_name_lookup(char*name,int l) {mod_pointer p; mod_pointer*loc= &root; while((p= *loc)!=NULL) {int l0=p->key_length;char*key=name_begin(p); switch(mod_name_cmp(name,l,key,l0)) {case less:loc= &p->llink;break; case greater:loc= &p->rlink;break; case equal:case extension:/*74:*/ #line 1109 "common.w" {enum mod_comparison cmp= mod_name_cmp(name+l0,l-l0,key+l0,(int)strlen(key+l0)); switch(cmp) {case less:case greater: err_print("! Incompatible module name"); print("\nName inconsistently extends <%.*s...>.\n",l0,key); return NULL; case extension:case equal: if(complete_name(p)) if(cmp==equal)return p; else {err_print("! Incompatible module name"); print("\nPrefix exists: <%s>.\n",key);return NULL; } name_begin(p)=store_string(name,l);/*77:*/ #line 1200 "common.w" free(key-1);/*:77*/ #line 1128 "common.w" return p; } }/*:74*/ #line 1081 "common.w" case prefix: err_print("! Incompatible module name"); print("\nName is a prefix of <%s%s>.\n" ,key,complete_name(p)?"":"..."); return NULL; } }/*73:*/ #line 1098 "common.w" {(p=make_mod_node(store_string(name,l)))->key_length=l; return*loc=p; }/*:73*/ #line 1090 "common.w" }/*:72*//*75:*/ #line 1152 "common.w" local mod_pointer prefix_lookup(char*name,int l) {mod_pointer p=root,*loc= &root; mod_pointer match=NULL; mod_pointer saved=NULL; while(p!=NULL) {int l0=p->key_length;char*key=name_begin(p); switch(mod_name_cmp(name,l,key,l0)) {case less:p= *(loc= &p->llink);break; case greater:p= *(loc= &p->rlink);break; case equal:return p; case extension:/*78:*/ #line 1209 "common.w" {enum mod_comparison cmp= mod_name_cmp(name+l0,l-l0,key+l0,(int)strlen(key+l0)); switch(cmp) {case less:case greater: err_print("! Incompatible module name"); print("\nName inconsistently extends <%.*s...>.\n",l0,key); return NULL; case prefix:case equal:return p; case extension: if(complete_name(p)) {err_print("! Incompatible module name"); print("\nPrefix exists: <%s>.\n",key);return NULL; }/*79:*/ #line 1236 "common.w" {/*77:*/ #line 1200 "common.w" free(key-1);/*:77*/ #line 1237 "common.w" if((key=(char*)malloc(l+2))==NULL)fatal("Out of dynamic memory!"); *key++='\1'; strncpy(key,name,l);key[l]='\0'; name_begin(p)=key; }/*:79*/ #line 1224 "common.w" return p; } }/*:78*/ #line 1167 "common.w" case prefix: if(match!=NULL) {err_print("! Ambiguous prefix");return NULL;} match=p;saved=p->rlink;p=p->llink; } if(p==NULL&&match!=NULL) p=saved,saved=NULL; } if(match==NULL)/*76:*/ #line 1190 "common.w" {char*key=(char*)malloc(l+2); if(key==NULL)fatal("Out of dynamic memory!"); *key++='\1'; strncpy(key,name,l);key[l]='\0'; (p=make_mod_node(key))->key_length=l; return*loc=p; }/*:76*/ #line 1179 "common.w" match->key_length=l; return match; }/*:75*//*82:*/ #line 1291 "common.w" mod_pointer get_module_name(void) {/*84:*/ #line 1315 "common.w" {eight_bits c;char*k=mod_text; do {if(!find_char()) {err_print("! Input ended in module name");break;} c= *loc++;/*85:*/ #line 1342 "common.w" if(c=='@') {if((c= *loc++)=='>')break; if(isspace(c)||c=='*'||c=='~') {err_print("! Module name didn't end");loc-=2;break;} if(k=mod_text_end-1) {print("\n! Module name too long: "); term_write(id_first,25);err_print(".."); } id_loc= *k==' '&&k>mod_text?k:k+1; }/*:84*/ #line 1294 "common.w" {int l=(int)(id_loc-id_first); return l>=3&&strncmp(id_loc-3,"...",3)==0 ?prefix_lookup(id_first,l-3):mod_name_lookup(id_first,l); } }/*:82*//*86:*/ #line 1360 "common.w" boolean get_control_text(void) {char c,*k=id_first= &mod_text[1]; do if((*k++= *loc++)=='@') if((c= *loc++)!='@') {if(c!='>') err_print("! Control codes are forbidden in control text"); return(id_loc=k-1)==id_first; } while(loc<=limit); err_print("! Control text didn't end"); return(id_loc=k)==id_first; }/*:86*//*87:*/ #line 1386 "common.w" void get_string(void) {char c,delim=loc[-1]; id_loc=id_first= &mod_text[1];copy_char(delim); if(delim=='L') *id_loc++=delim= *loc++; else if(delim=='<')delim='>'; do {if(loc>=limit) {err_print("! String didn't end");loc=limit;break;} copy_char(c= *loc++); if(c=='\\') if(loc=mod_text_end) {print("\n! String too long: "); term_write(mod_text+1,25);err_print(".."); } }/*:87*//*90:*/ #line 1449 "common.w" void err_print(char*s) {print(*s=='!'?"\n%s.":"%s.",s); if(web_file_open)/*91:*/ #line 1462 "common.w" {char*k,*l=(locbuffer) {for(k=buffer;k0)print("\n(%s)\n",mess[history]); }/*:93*/ #line 1489 "common.w" exit(history>harmless_message); }/*:92*//*94:*/ #line 1510 "common.w" void fatal(char*s,...) {va_list p;va_start(p,s); vprintf(s,p);va_end(p);err_print(""); history=fatal_message;wrap_up(); }/*:94*//*98:*/ #line 1563 "common.w" local void scan_args(int argc,char* *argv) {char*dot_pos; int files_found=0,paths_found=at_h_path[0].name==NULL?0:1; while(--argc>0) if(((* ++argv)[0]=='+'||(*argv)[0]=='-')&&(*argv)[1]!='\0')/*103:*/ #line 1656 "common.w" {boolean flag_change=(* *argv=='+'); char*p= &(*argv)[1];unsigned char c; while((c= *p++)!='\0') if((c=tolower(c))!='i')flags[c]=flag_change; else/*104:*/ #line 1668 "common.w" {size_t l=strlen(p); if(l==0)err_print("! Empty include path"); else if(l>max_path_length)err_print("! Include path too long"); else if(paths_found>=max_include_paths) err_print("! Too many include paths"); else {at_h_path[paths_found].length=(int)l; at_h_path[paths_found++].name=strcpy(byte_ptr,p); byte_ptr+=l+1; } break; }/*:104*/ #line 1661 "common.w" }/*:103*/ #line 1569 "common.w" else {if(strlen(*argv)+5>max_file_name_length) fatal("! Filename too long:\n%s",*argv); dot_pos=strrchr(*argv,'.'); switch(++files_found) {case 1:/*99:*/ #line 1597 "common.w" #ifndef CPPEXT #define CPPEXT "C" #endif {if(dot_pos==NULL)sprintf(web_file_name,"%s.w",*argv); else {sprintf(web_file_name,"%s",*argv); *dot_pos='\0'; } sprintf(alt_web_file_name,"%s.web",*argv); sprintf(change_file_name,"%s.ch",*argv); if(program==ctangle) sprintf(C_file_name,"%s.%s",*argv,C_plus_plus?CPPEXT:"c"); else {sprintf(tex_file_name,"%s.tex",*argv); sprintf(idx_file_name,"%s.idx",*argv); sprintf(scn_file_name,"%s.scn",*argv); } }/*:99*/ #line 1577 "common.w" break;case 2:/*100:*/ #line 1624 "common.w" if((*argv)[0]=='-')change_file_name[0]='\0'; else if((*argv)[0]!='+') {change_file_explicit=true; sprintf(change_file_name,dot_pos==NULL?"%s.ch":"%s",*argv); }/*:100*/ #line 1578 "common.w" break;case 3:/*101:*/ #line 1634 "common.w" if(program==ctangle) if(dot_pos!=NULL)sprintf(C_file_name,"%s",*argv); else sprintf(C_file_name,"%s.%s",*argv,C_plus_plus?CPPEXT:"c"); else {if(dot_pos!=NULL) {sprintf(tex_file_name,"%s",*argv);*dot_pos='\0';} else sprintf(tex_file_name,"%s.tex",*argv); sprintf(idx_file_name,"%s.idx",*argv); sprintf(scn_file_name,"%s.scn",*argv); }/*:101*/ #line 1579 "common.w" break;default:/*105:*/ #line 1688 "common.w" fatal("! Usage:\n" "c%se [(+|-)options] cwebfile[.w] [(changefile[.ch]|+|-) [outputfile[.%s]]]" ,program==ctangle?"tangl":"weav" ,program==ctangle?"c":"tex");/*:105*/ #line 1581 "common.w" } } if(files_found==0)/*105:*/ #line 1688 "common.w" fatal("! Usage:\n" "c%se [(+|-)options] cwebfile[.w] [(changefile[.ch]|+|-) [outputfile[.%s]]]" ,program==ctangle?"tangl":"weav" ,program==ctangle?"c":"tex");/*:105*/ #line 1584 "common.w" if(paths_found