|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982 Regents of the University of California ! 3: */ ! 4: #ifndef lint ! 5: static char sccsid[] = "@(#)asmain.c 4.13 6/30/83"; ! 6: #endif not lint ! 7: ! 8: #include <stdio.h> ! 9: #include <ctype.h> ! 10: #include <signal.h> ! 11: ! 12: #include "as.h" ! 13: #include "assyms.h" ! 14: #include "asscan.h" ! 15: #include "asexpr.h" ! 16: ! 17: #define unix_lang_name "VAX/UNIX Assembler V6/30/83 4.13" ! 18: /* ! 19: * variables to manage reading the assembly source files ! 20: */ ! 21: char *dotsname; /*the current file name; managed by the parser*/ ! 22: int lineno; /*current line number; managed by the parser*/ ! 23: char **innames; /*names of the files being assembled*/ ! 24: int ninfiles; /*how many interesting files there are*/ ! 25: FILE *source; /*current source file (for listing) */ ! 26: char layout[400]; /*layout bytes */ ! 27: char *layoutpos = layout; /*layout position in listfile */ ! 28: int ind = 0; /*innames in-index: 0..minfiles */ ! 29: int endofsource = 0; ! 30: long sourcepos; ! 31: /* ! 32: * Flags settable from the argv process argument list ! 33: */ ! 34: int silent = 0; /*don't complain about any errors*/ ! 35: int savelabels = 0; /*write the labels to the a.out file*/ ! 36: int d124 = 4; /*default allocate 4 bytes for unknown pointers*/ ! 37: int anyerrs = 0; /*no errors yet*/ ! 38: int anywarnings=0; /*no warnings yet*/ ! 39: int orgwarn = 0; /*Bad origins*/ ! 40: int passno = 1; /* current pass*/ ! 41: int jxxxJUMP = 0; /* in jxxxes that branch too far, use jmp instead of brw */ ! 42: int readonlydata = 0; /* initialzed data -> text space */ ! 43: int liston = 0; /* don't produce listing */ ! 44: ! 45: ! 46: #ifdef DEBUG ! 47: int debug = 0; ! 48: int toktrace = 0; ! 49: #endif ! 50: ! 51: int useVM = 0; ! 52: ! 53: char *endcore; /*where to get more symbol space*/ ! 54: ! 55: /* ! 56: * Managers of the a.out file. ! 57: */ ! 58: struct exec hdr; ! 59: #define MAGIC 0407 ! 60: u_long tsize; /* total text size */ ! 61: u_long dsize; /* total data size */ ! 62: u_long datbase; /* base of the data segment */ ! 63: u_long trsize; /* total text relocation size */ ! 64: u_long drsize; /* total data relocation size */ ! 65: ! 66: /* ! 67: * Information about the current segment is accumulated in ! 68: * usedot; the most important information stored is the ! 69: * accumulated size of each of the text and data segments ! 70: * ! 71: * dotp points to the correct usedot expression for the current segment ! 72: */ ! 73: struct exp usedot[NLOC+NLOC]; /* info about all segments */ ! 74: struct exp *dotp; /* data/text location pointer */ ! 75: /* ! 76: * The inter pass temporary token file is opened and closed by stdio, but ! 77: * is written to using direct read/write, as the temporary file ! 78: * is composed of buffers exactly BUFSIZ long. ! 79: */ ! 80: FILE *tokfile; /* interpass communication file */ ! 81: char tokfilename[TNAMESIZE]; ! 82: /* ! 83: * The string file is the string table ! 84: * cat'ed to the end of the built up a.out file ! 85: */ ! 86: FILE *strfile; /* interpass string file */ ! 87: char strfilename[TNAMESIZE]; ! 88: int strfilepos = 0; /* position within the string file */ ! 89: /* ! 90: * a.out is created during the second pass. ! 91: * It is opened by stdio, but is filled with the parallel ! 92: * block I/O library ! 93: */ ! 94: char *outfile = "a.out"; ! 95: FILE *a_out_file; ! 96: off_t a_out_off; /* cumulative offsets for segments */ ! 97: /* ! 98: * The logical files containing the assembled data for each of ! 99: * the text and data segments are ! 100: * managed by the parallel block I/O library. ! 101: * a.out is logically opened in many places at once to ! 102: * receive the assembled data from the various segments as ! 103: * it all trickles in, but is physically opened only once ! 104: * to minimize file overhead. ! 105: */ ! 106: BFILE *usefile[NLOC+NLOC]; /* text/data files */ ! 107: BFILE *txtfil; /* current text/data file */ ! 108: /* ! 109: * Relocation information is accumulated seperately for each ! 110: * segment. This is required by the old loader (from BTL), ! 111: * but not by the new loader (Bill Joy). ! 112: * ! 113: * However, the size of the relocation information can not be computed ! 114: * during or after the 1st pass because the ''absoluteness' of values ! 115: * is unknown until all locally declared symbols have been seen. ! 116: * Thus, the size of the relocation information is only ! 117: * known after the second pass is finished. ! 118: * This obviates the use of the block I/O ! 119: * library, which requires knowing the exact offsets in a.out. ! 120: * ! 121: * So, we save the relocation information internally (we don't ! 122: * go to internal files to minimize overhead). ! 123: * ! 124: * Empirically, we studied 259 files composing the system, ! 125: * two compilers and a compiler generator: (all of which have ! 126: * fairly large source files) ! 127: * ! 128: * Number of files = 259 ! 129: * Number of non zero text reloc files: 233 ! 130: * Number of non zero data reloc files: 53 ! 131: * Average text relocation = 889 ! 132: * Average data relocation = 346 ! 133: * Number of files > BUFSIZ text relocation = 71 ! 134: * Number of files > BUFSIZ data relocation = 6 ! 135: * ! 136: * For compiled C code, there is usually one text segment and two ! 137: * data segments; we see that allocating our own buffers and ! 138: * doing our internal handling of relocation information will, ! 139: * on the average, not use more memory than taken up by the buffers ! 140: * allocated for doing file I/O in parallel to a number of file. ! 141: * ! 142: * If we are assembling with the -V option, we ! 143: * use the left over token buffers from the 2nd pass, ! 144: * otherwise, we create our own. ! 145: * ! 146: * When the 2nd pass is complete, closeoutrel flushes the token ! 147: * buffers out to a BFILE. ! 148: * ! 149: * The internals to relbufdesc are known only in assyms.c ! 150: * ! 151: * outrel constructs the relocation information. ! 152: * closeoutrel flushes the relocation information to relfil. ! 153: */ ! 154: struct relbufdesc *rusefile[NLOC+NLOC]; ! 155: struct relbufdesc *relfil; /* un concatnated relocation info */ ! 156: BFILE *relocfile; /* concatnated relocation info */ ! 157: /* ! 158: * Once the relocation information has been written, ! 159: * we can write out the symbol table using the Block I/O ! 160: * mechanisms, as we once again know the offsets into ! 161: * the a.out file. ! 162: * ! 163: * We use relfil to output the symbol table information. ! 164: */ ! 165: char *tmpdirprefix = "/tmp/"; ! 166: int delexit(); ! 167: ! 168: main(argc, argv) ! 169: int argc; ! 170: char **argv; ! 171: { ! 172: char *sbrk(); ! 173: ! 174: tokfilename[0] = 0; ! 175: strfilename[0] = 0; ! 176: endcore = sbrk(0); ! 177: ! 178: argprocess(argc, argv); /* process argument lists */ ! 179: if (anyerrs) exit(1); ! 180: ! 181: initialize(); ! 182: zeroorigins(); /* set origins to zero */ ! 183: zerolocals(); /* fix local label counters */ ! 184: ! 185: i_pass1(); /* open temp files, etc */ ! 186: pass1(); /* first pass through .s files */ ! 187: testlocals(); /* check for undefined locals */ ! 188: if (anyerrs) delexit(); ! 189: ! 190: pass1_5(); /* resolve jxxx */ ! 191: if (anyerrs) delexit(); ! 192: ! 193: open_a_out(); /* open a.out */ ! 194: roundsegments(); /* round segments to FW */ ! 195: build_hdr(); /* build initial header, and output */ ! 196: ! 197: i_pass2(); /* reopen temporary file, etc */ ! 198: pass2(); /* second pass through the virtual .s */ ! 199: if (anyerrs) delexit(); ! 200: ! 201: fillsegments(); /* fill segments with 0 to FW */ ! 202: reloc_syms(); /* dump relocation and symbol table */ ! 203: ! 204: delete(); /* remove tmp file */ ! 205: bflush(); /* close off block I/O view of a.out */ ! 206: fix_a_out(); /* add in text and data reloc counts */ ! 207: ! 208: if (anyerrs == 0 && orgwarn) ! 209: yyerror("Caution: absolute origins.\n"); ! 210: ! 211: exit(anyerrs != 0); ! 212: } ! 213: ! 214: argprocess(argc, argv) ! 215: int argc; ! 216: char *argv[]; ! 217: { ! 218: register char *cp; ! 219: ! 220: ninfiles = 0; ! 221: silent = 0; ! 222: #ifdef DEBUG ! 223: debug = 0; ! 224: #endif ! 225: innames = (char **)ClearCalloc(argc+1, sizeof (innames[0])); ! 226: dotsname = "<argv error>"; ! 227: while (argc > 1) { ! 228: if (argv[1][0] != '-') ! 229: innames[ninfiles++] = argv[1]; ! 230: else { ! 231: cp = argv[1] + 1; ! 232: /* ! 233: * We can throw away single minus signs, so ! 234: * that make scripts for the PDP 11 assembler work ! 235: * on this assembler too ! 236: */ ! 237: while (*cp){ ! 238: switch(*cp++){ ! 239: default: ! 240: yyerror("Unknown flag: %c", *--cp); ! 241: cp++; ! 242: break; ! 243: case 'v': ! 244: selfwhat(stdout); ! 245: exit(1); ! 246: case 'd': ! 247: d124 = *cp++ - '0'; ! 248: if ( (d124 != 1) && (d124 != 2) && ! 249: (d124 != 4)){ ! 250: yyerror("-d[124] only"); ! 251: exit(1); ! 252: } ! 253: break; ! 254: case 'P': ! 255: liston = 1; ! 256: listfile = stdout; ! 257: break; ! 258: case 'o': ! 259: if (argc < 3){ ! 260: yyerror("-o what???"); ! 261: exit(1); ! 262: } ! 263: outfile = argv[2]; ! 264: bumpone: ! 265: argc -= 2; ! 266: argv += 2; ! 267: goto nextarg; ! 268: ! 269: case 't': ! 270: if (argc < 3){ ! 271: yyerror("-t what???"); ! 272: exit(1); ! 273: } ! 274: tmpdirprefix = argv[2]; ! 275: goto bumpone; ! 276: ! 277: case 'V': ! 278: useVM = 1; ! 279: break; ! 280: case 'W': ! 281: silent = 1; ! 282: break; ! 283: case 'L': ! 284: savelabels = 1; ! 285: break; ! 286: case 'J': ! 287: jxxxJUMP = 1; ! 288: break; ! 289: #ifdef DEBUG ! 290: case 'D': ! 291: debug = 1; ! 292: break; ! 293: case 'T': ! 294: toktrace = 1; ! 295: break; ! 296: #endif ! 297: case 'R': ! 298: readonlydata = 1; ! 299: break; ! 300: } /*end of the switch*/ ! 301: } /*end of pulling out all arguments*/ ! 302: } /*end of a flag argument*/ ! 303: --argc; ++argv; ! 304: nextarg:; ! 305: } ! 306: /* innames[ninfiles] = 0; */ ! 307: } ! 308: /* ! 309: * poke through the data space and find all sccs identifiers. ! 310: * We assume: ! 311: * a) that extern char **environ; is the first thing in the bss ! 312: * segment (true, if one is using the new version of cmgt.crt0.c) ! 313: * b) that the sccsid's have not been put into text space. ! 314: */ ! 315: selfwhat(place) ! 316: FILE *place; ! 317: { ! 318: extern char **environ; ! 319: register char *ub; ! 320: register char *cp; ! 321: char *sbrk(); ! 322: ! 323: for (cp = (char *)&environ, ub = sbrk(0); cp < ub; cp++){ ! 324: if (cp[0] != '@') continue; ! 325: if (cp[1] != '(') continue; ! 326: if (cp[2] != '#') continue; ! 327: if (cp[3] != ')') continue; ! 328: fputc('\t', place); ! 329: for (cp += 4; cp < ub; cp++){ ! 330: if (*cp == 0) break; ! 331: if (*cp == '>') break; ! 332: if (*cp == '\n') break; ! 333: fputc(*cp, place); ! 334: } ! 335: fputc('\n', place); ! 336: } ! 337: } ! 338: ! 339: initialize() ! 340: { ! 341: if (signal(SIGINT, SIG_IGN) != SIG_IGN) ! 342: signal(SIGINT, delexit); ! 343: /* ! 344: * Install symbols in the table ! 345: */ ! 346: symtabinit(); ! 347: syminstall(); ! 348: /* ! 349: * Build the expression parser accelerator token sets ! 350: */ ! 351: buildtokensets(); ! 352: } ! 353: ! 354: zeroorigins() ! 355: { ! 356: register int locindex; ! 357: /* ! 358: * Mark usedot: the first NLOC slots are for named text segments, ! 359: * the next for named data segments. ! 360: */ ! 361: for (locindex = 0; locindex < NLOC; locindex++){ ! 362: usedot[locindex].e_xtype = XTEXT; ! 363: usedot[NLOC + locindex].e_xtype = XDATA; ! 364: usedot[locindex].e_xvalue = 0; ! 365: usedot[NLOC + locindex].e_xvalue = 0; ! 366: } ! 367: } ! 368: ! 369: zerolocals() ! 370: { ! 371: register int i; ! 372: ! 373: for (i = 0; i <= 9; i++) { ! 374: lgensym[i] = 1; ! 375: genref[i] = 0; ! 376: } ! 377: } ! 378: ! 379: i_pass1() ! 380: { ! 381: FILE *tempopen(); ! 382: if (useVM == 0) ! 383: tokfile = tempopen(tokfilename, "T"); ! 384: strfile = tempopen(strfilename, "S"); ! 385: /* ! 386: * write out the string length. ! 387: * This will be overwritten when the ! 388: * strings are tacked onto the growing a.out file ! 389: */ ! 390: strfilepos = sizeof(int); ! 391: fwrite(&strfilepos, sizeof(int), 1, strfile); ! 392: ! 393: inittokfile(); ! 394: initijxxx(); ! 395: } ! 396: ! 397: FILE *tempopen(tname, part) ! 398: char *tname; ! 399: char *part; ! 400: { ! 401: FILE *file; ! 402: (void)sprintf(tname, "%s%sas%s%05d", ! 403: tmpdirprefix, ! 404: (tmpdirprefix[strlen(tmpdirprefix)-1] != '/') ? "/" : 0, ! 405: part, ! 406: getpid()); ! 407: file = fopen(tname, "w"); ! 408: if (file == NULL) { ! 409: yyerror("Bad pass 1 temporary file for writing %s", tname); ! 410: delexit(); ! 411: } ! 412: return(file); ! 413: } ! 414: ! 415: pass1() ! 416: { ! 417: register int i; ! 418: ! 419: passno = 1; ! 420: dotp = &usedot[0]; ! 421: txtfil = (BFILE *)0; ! 422: relfil = (struct relbufdesc *)0; ! 423: ! 424: if (ninfiles == 0){ /*take the input from stdin directly*/ ! 425: lineno = 1; ! 426: dotsname = "<stdin>"; ! 427: ! 428: yyparse(); ! 429: } else { /*we have the names tanked*/ ! 430: for (i = 0; i < ninfiles; i++){ ! 431: new_dot_s(innames[i]); ! 432: if (freopen(innames[i], "r", stdin) == NULL) { ! 433: yyerror( "Can't open source file %s\n", ! 434: innames[i]); ! 435: exit(2); ! 436: } ! 437: /* stdio is NOT used to read the input characters */ ! 438: /* we use read directly, into our own buffers */ ! 439: yyparse(); ! 440: } ! 441: } ! 442: ! 443: closetokfile(); /*kick out the last buffered intermediate text*/ ! 444: } ! 445: ! 446: testlocals() ! 447: { ! 448: register int i; ! 449: for (i = 0; i <= 9; i++) { ! 450: if (genref[i]) ! 451: yyerror("Reference to undefined local label %df", i); ! 452: lgensym[i] = 1; ! 453: genref[i] = 0; ! 454: } ! 455: } ! 456: ! 457: pass1_5() ! 458: { ! 459: sortsymtab(); ! 460: #ifdef DEBUG ! 461: if (debug) dumpsymtab(); ! 462: #endif ! 463: jxxxfix(); ! 464: #ifdef DEBUG ! 465: if (debug) dumpsymtab(); ! 466: #endif ! 467: } ! 468: ! 469: open_a_out() ! 470: { ! 471: /* ! 472: * Open up the a.out file now, and get set to build ! 473: * up offsets into it for all of the various text,data ! 474: * text relocation and data relocation segments. ! 475: */ ! 476: a_out_file = fopen(outfile, "w"); ! 477: if (a_out_file == NULL) { ! 478: yyerror("Cannot create %s", outfile); ! 479: delexit(); ! 480: } ! 481: biofd = a_out_file->_file; ! 482: a_out_off = 0; ! 483: } ! 484: ! 485: roundsegments() ! 486: { ! 487: register int locindex; ! 488: register long v; ! 489: /* ! 490: * round and assign text segment origins ! 491: * the exec header always goes in usefile[0] ! 492: */ ! 493: tsize = 0; ! 494: for (locindex=0; locindex<NLOC; locindex++) { ! 495: v = round(usedot[locindex].e_xvalue, FW); ! 496: usedot[locindex].e_xvalue = tsize; ! 497: if ((locindex == 0) || (v != 0) ){ ! 498: usefile[locindex] = (BFILE *)Calloc(1, sizeof(BFILE)); ! 499: bopen(usefile[locindex], a_out_off); ! 500: if (locindex == 0) ! 501: a_out_off = sizeof (struct exec); ! 502: } else { ! 503: usefile[locindex] = (BFILE *)-1; ! 504: } ! 505: tsize += v; ! 506: a_out_off += v; ! 507: } ! 508: /* ! 509: * Round and assign data segment origins. ! 510: */ ! 511: datbase = round(tsize, FW); ! 512: for (locindex=0; locindex<NLOC; locindex++) { ! 513: v = round(usedot[NLOC+locindex].e_xvalue, FW); ! 514: usedot[NLOC+locindex].e_xvalue = datbase + dsize; ! 515: if (v != 0){ ! 516: usefile[NLOC + locindex] = (BFILE *)Calloc(1,sizeof(BFILE)); ! 517: bopen(usefile[NLOC + locindex], a_out_off); ! 518: } else { ! 519: usefile[NLOC + locindex] = (BFILE *)-1; ! 520: } ! 521: dsize += v; ! 522: a_out_off += v; ! 523: } ! 524: /* ! 525: * Assign final values to symbols ! 526: */ ! 527: hdr.a_bss = dsize; ! 528: freezesymtab(); /* this touches hdr.a_bss */ ! 529: stabfix(); ! 530: /* ! 531: * Set up the relocation information "files" to ! 532: * be zero; outrel takes care of the rest ! 533: */ ! 534: for (locindex = 0; locindex < NLOC + NLOC; locindex++){ ! 535: rusefile[locindex] = (struct relbufdesc *)0; ! 536: } ! 537: } ! 538: ! 539: build_hdr() ! 540: { ! 541: /* ! 542: * Except for the text and data relocation sizes, ! 543: * calculate the final values for the header ! 544: * ! 545: * Write out the initial copy; we to come ! 546: * back later and patch up a_trsize and a_drsize, ! 547: * and overwrite this first version of the header. ! 548: */ ! 549: hdr.a_magic = MAGIC; ! 550: hdr.a_text = tsize; ! 551: hdr.a_data = dsize; ! 552: hdr.a_bss -= dsize; ! 553: hdr.a_syms = sizesymtab(); /* Does not include string pool length */ ! 554: hdr.a_entry = 0; ! 555: hdr.a_trsize = 0; ! 556: hdr.a_drsize = 0; ! 557: ! 558: bwrite((char *)&hdr, sizeof(hdr), usefile[0]); ! 559: } ! 560: ! 561: i_pass2() ! 562: { ! 563: if (useVM == 0) { ! 564: fclose(tokfile); ! 565: tokfile = fopen(tokfilename, "r"); ! 566: if (tokfile==NULL) { ! 567: yyerror("Bad pass 2 temporary file for reading %s", tokfilename); ! 568: delexit(); ! 569: } ! 570: } ! 571: fclose(strfile); ! 572: strfile = fopen(strfilename, "r"); ! 573: } ! 574: ! 575: pass2() ! 576: { ! 577: #ifdef DEBUG ! 578: if (debug) ! 579: printf("\n\n\n\t\tPASS 2\n\n\n\n"); ! 580: #endif DEBUG ! 581: passno = 2; ! 582: lineno = 1; ! 583: if (liston && ninfiles != 0) ! 584: { ! 585: char ch; ! 586: source = fopen (innames[ind++], "r"); ! 587: (void)sprintf (layoutpos, "%4ld 00000000 ", lineno); ! 588: layoutpos += LHEAD; ! 589: ch = getc (source); ! 590: if (ch == EOF) ! 591: { ! 592: if (ind == ninfiles) ! 593: endofsource = 1; ! 594: else ! 595: source = fopen (innames[ind++], "r"); ! 596: } ! 597: else ! 598: ungetc (ch, source); ! 599: } ! 600: else ! 601: endofsource = 1; ! 602: dotp = &usedot[0]; ! 603: txtfil = usefile[0]; /* already opened (always!) */ ! 604: relfil = 0; /* outrel takes care of the rest */ ! 605: initoutrel(); ! 606: ! 607: inittokfile(); ! 608: ! 609: yyparse(); ! 610: ! 611: closetokfile(); ! 612: } ! 613: ! 614: fillsegments() ! 615: { ! 616: int locindex; ! 617: /* ! 618: * Round text and data segments to FW by appending zeros ! 619: */ ! 620: for (locindex = 0; locindex < NLOC + NLOC; locindex++) { ! 621: if (usefile[locindex]) { ! 622: txtfil = usefile[locindex]; ! 623: dotp = &usedot[locindex]; ! 624: while (usedot[locindex].e_xvalue & FW) ! 625: outb(0); ! 626: } ! 627: } ! 628: } ! 629: ! 630: reloc_syms() ! 631: { ! 632: u_long closerelfil(); ! 633: /* ! 634: * Move the relocation information to a.out ! 635: * a_out_off is the offset so far: ! 636: * exec + text segments + data segments ! 637: */ ! 638: relocfile = (BFILE *)Calloc(1,sizeof(BFILE)); ! 639: bopen(relocfile, a_out_off); ! 640: a_out_off += closeoutrel(relocfile); ! 641: ! 642: hdr.a_trsize = trsize; ! 643: hdr.a_drsize = drsize; ! 644: if (readonlydata) { ! 645: hdr.a_text += hdr.a_data; ! 646: hdr.a_data = 0; ! 647: hdr.a_trsize += hdr.a_drsize; ! 648: hdr.a_drsize = 0; ! 649: } ! 650: /* ! 651: * Output the symbol table and the string pool ! 652: * ! 653: * We must first rewind the string pool file to its beginning, ! 654: * in case it was seek'ed into for fetching ascii and asciz ! 655: * strings. ! 656: */ ! 657: fseek(strfile, 0, 0); ! 658: symwrite(relocfile); ! 659: } ! 660: ! 661: fix_a_out() ! 662: { ! 663: if (lseek(a_out_file->_file, 0L, 0) < 0L) ! 664: yyerror("Reposition for header rewrite fails"); ! 665: if (write(a_out_file->_file, (char *)&hdr, sizeof (struct exec)) < 0) ! 666: yyerror("Rewrite of header fails"); ! 667: } ! 668: ! 669: delexit() ! 670: { ! 671: delete(); ! 672: if (passno == 2){ ! 673: unlink(outfile); ! 674: } ! 675: exit(1); ! 676: } ! 677: ! 678: delete() ! 679: { ! 680: if (useVM == 0 || tokfilename[0]) ! 681: unlink(tokfilename); ! 682: if (strfilename[0]) ! 683: unlink(strfilename); ! 684: } ! 685: ! 686: sawabort() ! 687: { ! 688: char *fillinbuffer(); ! 689: while (fillinbuffer() != (char *)0) ! 690: continue; ! 691: delete(); ! 692: exit(1); /*although the previous pass will also exit non zero*/ ! 693: } ! 694: ! 695: panic(fmt, a1, a2, a3, a4) ! 696: char *fmt; ! 697: /*VARARGS 1*/ ! 698: { ! 699: yyerror("Assembler panic: bad internal data structure."); ! 700: yyerror(fmt, a1, a2, a3, a4); ! 701: delete(); ! 702: abort(); ! 703: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.