home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / config / gtscc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  59.8 KB  |  2,731 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /* */
  19. /*
  20.  *--------------------------------------------------------------------------
  21.  *
  22.  *    
  23.  *
  24.  *--------------------------------------------------------------------------
  25.  *
  26.  *    gtscc - Global To Static C/C++ compiler driver.
  27.  *
  28.  *    Syntax:
  29.  *
  30.  *    gtscc [options] -c file.cpp ...
  31.  *    gtscc [options] file.o ... libxx.a ...
  32.  *
  33.  *    gtscc is a compiler and linker driver/wrapper for Irix only.
  34.  *    gtscc takes all compiler options and passes them onto the Irix
  35.  *    cc/CC compiler/linker.
  36.  *    Typically, gtscc is used in two phases. Phase one is during compilation.
  37.  *    gtscc, the compiler, converts all inline globals to statics, and records
  38.  *    the existance of other globals and how to compile the file in the gtscc
  39.  *    database file.
  40.  *    During linking, globals dependencies are analyzed, and a list of
  41.  *    "convertable" globals is determined. Globals that are not referenced
  42.  *    globally, but are referenced locally are considered convertable.
  43.  *    The linker then recompiles the files that those symbols are in, and
  44.  *    converts them to statics. It also calls the archiver to install
  45.  *    the converted objects into libraries.
  46.  *    Finally the linker is called.
  47.  *
  48.  *    Created: David Williams, djw@netscape.com, 13-Feb-1997
  49.  *
  50.  *--------------------------------------------------------------------------
  51.  */
  52. #include <stdio.h>
  53. #include <stdlib.h>
  54. #include <string.h>
  55. #include <sys/types.h>
  56. #include <sys/wait.h>
  57. #include <sys/param.h>
  58. #include <sys/types.h>
  59. #include <unistd.h>
  60. #include <ctype.h>
  61.  
  62. #if defined(LINUX) && defined(__GLIBC__)
  63. #include <libelf/libelf.h>
  64. #else
  65. #include <libelf.h>
  66. #endif
  67.  
  68. #include <sys/stat.h>
  69. #include <fcntl.h>
  70. #include <sys/time.h>
  71.  
  72. #define DEFAULT_MAX_GLOBALS 15500
  73.  
  74. #define ELFSYM_IS_DEFINED(x)   ((x).st_shndx != SHN_UNDEF)
  75. #define ELFSYM_IS_UNDEFINED(x) ((x).st_shndx == SHN_UNDEF)
  76.  
  77. #ifdef IRIX
  78. #define CC_COMMAND  "cc"
  79. #define CCC_COMMAND "CC"
  80. #define AS_COMMAND  "cc"
  81. #define LD_COMMAND  "CC"
  82. #define AR_COMMAND  "ar"
  83. #define AR_OPTIONS  "cr"
  84. #else
  85. #define HANDLES_DASHSO
  86. #define CC_COMMAND  "gcc"
  87. #define CCC_COMMAND "g++"
  88. #define AS_COMMAND  "gcc"
  89. #define LD_COMMAND  "g++"
  90. #define AR_COMMAND  "ar"
  91. #define AR_OPTIONS  "cr"
  92. #endif
  93.  
  94. #define EH_NEW(type) (type*)malloc(sizeof(type))
  95.  
  96. #define TRUE 1
  97. #define FALSE 0
  98.  
  99. #define EH_TAG_FILE   'F'
  100. #define EH_TAG_GLOBAL 'G'
  101. #define EH_TAG_ZAPPED 'Z'
  102. #define EH_TAG_INLINE 'I'
  103. #define EH_TAG_UNDEFINED 'U'
  104.  
  105. #define VERBOSITY_USER(x)  ((x) > 0)
  106. #define VERBOSITY_DEBUG(x) ((x) > 1)
  107. #define VERBOSITY_MAJOR(x) ((x) > 2)
  108.  
  109. static char eh_unnamed_object[] = "<name not known>";
  110.  
  111. typedef struct {
  112.     char*    name;       /* archive */
  113. } EhArchive;
  114.  
  115. typedef struct {
  116.     char*      name;     /* name of C/C++ file, relative to rootdir */
  117.     char*      directory;/* must compile in this directory */
  118.     char**     cc_args;  /* cc -I ..... */
  119.     char*      as_savefile;
  120.     time_t     compile_time;
  121.     char*      target_object;
  122. } EhSource;
  123.  
  124. typedef struct EhObject {
  125.     struct EhObject* _recompile; /* used for recompilation link list */
  126.     unsigned   _needs_unzap;
  127.     char*      name;     /* name of .o */
  128.     EhArchive* archive;  /* it is stored in */
  129.     EhSource*  source;
  130.     char*      pathname;
  131.     unsigned   nusers;
  132. } EhObject;
  133.  
  134. typedef enum {
  135.     EH_SYM_UNDEFINED,
  136.     EH_SYM_DEFINED,
  137.     EH_SYM_ZAPPED,
  138.     EH_SYM_INLINE /* are treated special - they belong to no file */
  139. } EhSymState;
  140.  
  141. typedef struct EhSym {
  142.     struct EhSym* _next; /* used for link list */
  143.     char*      name;     /* name of symbol */
  144.     EhObject*  object;   /* if symbol is undefined == NULL */
  145.     unsigned   ngusers;   /* number of global users */
  146.     unsigned   nlusers;   /* number of local file users */
  147.  
  148. #if 0
  149.     unsigned   section;  /* section in elf file */
  150.     unsigned   index;    /* index into symbol table */
  151.     unsigned char info;
  152.     unsigned   dirty;
  153. #endif
  154.     EhSymState state;
  155. } EhSym;
  156.  
  157. #define EHSYM_ISDEFINED(x)   ((x)->object!=NULL && (x)->state==EH_SYM_DEFINED)
  158. #define EHSYM_ISZAPPED(x)    ((x)->object!=NULL && (x)->state==EH_SYM_ZAPPED)
  159. #define EHSYM_ISUNDEFINED(x) ((x)->object == NULL)
  160. #define EHSYM_ISUSED(x)      ((x)->nusers != 0)
  161. #define EHSYM_ISINLINE(x)    ((x)->state == EH_SYM_INLINE)
  162.  
  163. #define EH_OBJECT_CANBUILD(x) \
  164. ((x)->source != NULL && (x)->name != eh_unnamed_object)
  165.  
  166. #define USE_HASHING
  167.  
  168. typedef struct {
  169. #ifdef USE_HASHING
  170.     EhSym** heads;
  171.     unsigned size;
  172. #else
  173.     EhSym* head;
  174. #endif
  175.     unsigned nentries;
  176. } EhSymTable;
  177.  
  178. static char*
  179. make_relative_pathname(char* buf, char* filename, char* rootdir)
  180. {
  181.     char  buf1[MAXPATHLEN];
  182.     char  buf2[MAXPATHLEN];
  183.     char* p;
  184.     char* q;
  185.  
  186.     if (rootdir == NULL) {
  187.         strcpy(buf, filename);
  188.         return filename;
  189.     }
  190.  
  191.     if (filename[0] != '/') {
  192.         if (getcwd(buf2, sizeof(buf2)) == NULL) {
  193.             fprintf(stderr, "cannot get pwd\n");
  194.             return NULL;
  195.         }
  196.  
  197.         strcat(buf2, "/");
  198.         strcat(buf2, filename);
  199.  
  200.         filename = buf2;
  201.     }
  202.  
  203.     if (realpath(filename, buf1) == NULL) {
  204.         fprintf(stderr, "realpath(%s,..) failed\n", filename);
  205.         return NULL;
  206.     }
  207.     
  208.     if (realpath(rootdir, buf2) == NULL) {
  209.         fprintf(stderr, "realpath(%s,..) failed\n", rootdir);
  210.         return NULL;
  211.     }
  212.  
  213.     strcat(buf2, "/");
  214.  
  215.     for (p = buf1, q = buf2; *p == *q; p++, q++)
  216.         ;
  217.  
  218.     strcpy(buf, p);
  219.  
  220.     return buf;
  221. }
  222.  
  223. static EhArchive*
  224. EhArchiveNew(char* name, char* rootdir)
  225. {
  226.     EhArchive* archive = EH_NEW(EhArchive);
  227.     char pathbuf[MAXPATHLEN];
  228.  
  229.     make_relative_pathname(pathbuf, name, rootdir);
  230.  
  231.     archive->name = strdup(pathbuf);
  232.  
  233.     return archive;
  234. }
  235.  
  236. #if 0
  237. /*
  238.  *    This is evil, we should never free anything, because it messes up
  239.  *    interning.
  240.  */
  241. static void
  242. EhSourceDelete(EhSource* source)
  243. {
  244.     unsigned n;
  245.     if (source->name != NULL)
  246.         free(source->name);
  247.     if (source->directory != NULL)
  248.         free(source->directory);
  249.     if (source->cc_args != NULL) {
  250.         for (n = 0; source->cc_args[n] != NULL; n++)
  251.             free(source->cc_args[n]);
  252.         free(source->cc_args);
  253.     }
  254.     if (source->as_savefile != NULL)
  255.         free(source->as_savefile);
  256. }
  257. #endif
  258.  
  259. static EhSource*
  260. EhSourceNew(char* name, char** cc_args, char* directory)
  261. {
  262.     EhSource* source = EH_NEW(EhSource);
  263.     unsigned n;
  264.     unsigned m;
  265.  
  266.     source->name = strdup(name);
  267.     source->directory = (directory != NULL)? strdup(directory): NULL;
  268.     source->as_savefile = NULL;
  269.     source->compile_time = 0;
  270.     source->target_object = NULL;
  271.     source->cc_args = NULL;
  272.  
  273.     if (cc_args != NULL) {
  274.  
  275.         for (n = 0; cc_args[n] != NULL; n++)
  276.             ;
  277.  
  278.         source->cc_args = (char**)malloc(sizeof(char*) * (n+1));
  279.  
  280.         for (m = 0, n = 0; cc_args[n] != NULL;) {
  281.             if (strcmp(cc_args[n], "-o") == 0 && cc_args[n+1] != NULL) {
  282.                 source->target_object = strdup(cc_args[n+1]);
  283.                 n += 2;
  284.             } else {
  285.                 source->cc_args[m++] =  strdup(cc_args[n++]);
  286.             }
  287.         }
  288.  
  289.         source->cc_args[m] = NULL;
  290.     }
  291.  
  292.     return source;
  293. }
  294.  
  295. static EhObject*
  296. EhObjectNewArchiveObject(EhArchive* archive, char* name)
  297. {
  298.     EhObject* object = EH_NEW(EhObject);
  299.  
  300.     if (name == eh_unnamed_object)
  301.         object->name = name;
  302.     else
  303.         object->name = strdup(name);
  304.     object->archive = archive;
  305.     object->source = NULL;
  306.     object->_recompile = NULL;
  307.     object->_needs_unzap = 0;
  308.     object->pathname = NULL;
  309.     object->nusers = 0;
  310.  
  311.     return object;
  312. }
  313.  
  314. static EhObject*
  315. EhObjectNew(char* name, char* rootdir)
  316. {
  317.     EhObject* object = EhObjectNewArchiveObject(NULL, name);
  318.     char pathname[MAXPATHLEN];
  319.  
  320.     make_relative_pathname(pathname, name, rootdir);
  321.     object->pathname = strdup(pathname);
  322.  
  323.     return object;
  324. }
  325.  
  326. static EhObject*
  327. EhObjectNewFromSource(EhSource* source)
  328. {
  329.     EhObject* object = EhObjectNewArchiveObject(NULL, eh_unnamed_object);
  330.  
  331.     object->source = source;
  332.  
  333.     return object;
  334. }
  335.  
  336. static char*
  337. EhObjectGetFilename(EhObject* object, char* buf)
  338. {
  339.     if (object->archive) {
  340.         strcpy(buf, object->archive->name);
  341.         strcat(buf, ":");
  342.         strcat(buf, object->name);
  343.         return buf;
  344.     } else {
  345.         return object->name;
  346.     }
  347. }
  348.  
  349. static EhSym*
  350. EhSymNewDefined(char* name, EhObject* object)
  351. {
  352.     EhSym* sym = EH_NEW(EhSym);
  353.  
  354.     sym->name = strdup(name);
  355.     sym->object = object;
  356.     sym->state = EH_SYM_DEFINED;
  357.     sym->ngusers = 0;
  358.     sym->nlusers = 0;
  359.  
  360.     return sym;
  361. }
  362.  
  363. static EhSym*
  364. EhSymNewInline(char* name)
  365. {
  366.     EhSym* sym = EhSymNewDefined(name, NULL);
  367.     sym->state = EH_SYM_INLINE;
  368.  
  369.     return sym;
  370. }
  371.  
  372. static EhSym*
  373. EhSymNewUndefined(char* name)
  374. {
  375.     EhSym* sym = EhSymNewDefined(name, NULL);
  376.     sym->state = EH_SYM_UNDEFINED;
  377.  
  378.     return sym;
  379. }
  380.  
  381. static EhSym*
  382. EhSymNewZapped(char* name, EhObject* object)
  383. {
  384.     EhSym* sym = EhSymNewDefined(name, object);
  385.     sym->state = EH_SYM_ZAPPED;
  386.  
  387.     return sym;
  388. }
  389.  
  390. static EhSym*
  391. EhSymNewRandomZap(char* name)
  392. {
  393.     EhSym* sym = EhSymNewZapped(name, NULL);
  394.  
  395.     return sym;
  396. }
  397.  
  398. EhSymTable*
  399. EhSymTableNew(unsigned p_size)
  400. {
  401.     EhSymTable* table = EH_NEW(EhSymTable);
  402.  
  403. #ifdef USE_HASHING
  404.     unsigned size;
  405.     for (size = 0x1; size < (16*1024); size <<= 1) {
  406.         if (size >= p_size)
  407.             break;
  408.     }
  409.     table->size = size;
  410.     table->heads = (EhSym**)calloc(size, sizeof(EhSym*));
  411. #else
  412.     table->head = NULL;
  413. #endif
  414.     table->nentries = 0;
  415.  
  416.     return table;
  417. }
  418.  
  419. EhSym*
  420. EhSymTableInsert(EhSymTable* table, EhSym* sym)
  421. {
  422. #ifdef USE_HASHING
  423.     unsigned long hash = elf_hash(sym->name);
  424.     unsigned long mask = table->size - 1;
  425.     unsigned index = (hash & mask);
  426.  
  427.     sym->_next = table->heads[index];
  428.     table->heads[index] = sym;
  429. #else
  430.     sym->_next = table->head;
  431.     table->head = sym;
  432. #endif
  433.     table->nentries++;
  434.  
  435.     return sym;
  436. }
  437.  
  438. EhSym*
  439. EhSymTableFind(EhSymTable* table, char* name)
  440. {
  441.     EhSym* sym;
  442.     EhSym* head;
  443.  
  444. #ifdef USE_HASHING
  445.     unsigned long hash = elf_hash(name);
  446.     unsigned long mask = table->size - 1;
  447.     unsigned index = (hash & mask);
  448.     head = table->heads[index];
  449. #else
  450.     head = table->head;
  451. #endif
  452.  
  453.     for (sym = head; sym != NULL; sym = sym->_next) {
  454.         if (strcmp(name, sym->name) == 0)
  455.             break;
  456.     }
  457.  
  458.     return sym;
  459. }
  460.  
  461. typedef int (*eh_dump_mappee_t)(EhSym* sym, void* arg);
  462.  
  463. static int
  464. EhSymTableMap(EhSymTable* table, eh_dump_mappee_t func, void* arg)
  465. {
  466.     EhSym* sym;
  467.     EhSym* head;
  468.  
  469. #ifdef USE_HASHING
  470.     unsigned n;
  471.     for (n = 0; n < table->size; n++) {
  472.         head = table->heads[n];
  473. #else
  474.         head = table->head; {
  475. #endif
  476.         for (sym = head; sym != NULL; sym = sym->_next) {
  477.             if ((func)(sym, arg) == -1)
  478.                 return -1;
  479.         }
  480.     }
  481.  
  482.     return 0;
  483. }
  484.  
  485. typedef struct {
  486.     EhObject* o_old;
  487.     EhObject* o_new;
  488. } fixup_info;
  489.  
  490. static int
  491. fixup_mappee(EhSym* sym, void* arg)
  492. {
  493.     fixup_info* info = (fixup_info*)arg;
  494.  
  495.     if (sym->object == info->o_old)
  496.         sym->object = info->o_new;
  497.  
  498.     return 0;
  499. }
  500.  
  501. static EhObject*
  502. EhSymTableObjectFixup(EhSymTable* table, EhObject* o_old, EhObject* o_new)
  503. {
  504.     fixup_info info;
  505.  
  506.     /*
  507.      *    Now visit every sym that pointed to tmp, and point it
  508.      *    at object.
  509.      */
  510.     info.o_old = o_old;
  511.     info.o_new = o_new;
  512.     EhSymTableMap(table, fixup_mappee, &info);
  513.     
  514.     return o_new;
  515. }
  516.  
  517.  
  518.  
  519. static char*
  520. safe_fgets(char* buf, unsigned size, FILE* fp)
  521. {
  522.     unsigned nread = 0;
  523.  
  524.     if (buf == NULL)
  525.         buf = (char*)malloc(size);
  526.  
  527.     for (;;) {
  528.  
  529.         if (fgets(&buf[nread], size - nread, fp) == NULL) {
  530.             free(buf);
  531.             return NULL;
  532.         }
  533.  
  534.         if (strchr(buf, '\n') != NULL)
  535.             return buf;
  536.  
  537.         /*
  538.          *    fgets returns n-1 characters and \0
  539.          */
  540.         nread += (size - nread) - 1;
  541.         size += 1024;
  542.         buf = (char*)realloc(buf, size);
  543.     }
  544. }
  545.  
  546. static int
  547. EhSymTableFpLoad(EhSymTable* table, FILE* fp)
  548. {
  549.     char* buf = NULL; /* I hope this is big enough */
  550.     char* p;
  551.     char* name;
  552.     char* state;
  553.     EhSym* sym;
  554.     EhSource* source = NULL;
  555.     EhObject* object = NULL;
  556.     char* cc_args[512];
  557.     unsigned n;
  558.     unsigned line_n = 0;
  559.     char* ctime = NULL;
  560.     char* directory;
  561.     char* savefile;
  562.  
  563.     while ((buf = safe_fgets(buf, 1024, fp)) != NULL) {
  564.  
  565.         if ((p = strchr(buf, '\n')) == NULL) {
  566.             fprintf(stderr, "line to long: %d\n", line_n);
  567.             return -1;
  568.         }
  569.         *p = '\0';
  570.  
  571.         line_n++;
  572.  
  573.         if (buf[0] == '!') /* comment */
  574.             continue;
  575.  
  576.         for (p = buf; isspace(*p); p++)
  577.             ;
  578.  
  579.         name = p;
  580.         for (; !isspace(*p); p++)
  581.             ;
  582.         *p++ = '\0';
  583.  
  584.         if (name[0] == '\0')
  585.             continue;
  586.         
  587.         for (; isspace(*p); p++)
  588.             ;
  589.  
  590.         state = p;
  591.         for (; !isspace(*p) && *p != '\0'; p++)
  592.             ;
  593.         *p++ = '\0';
  594.  
  595.         if (state[0] == EH_TAG_GLOBAL
  596.             ||
  597.             state[0] == EH_TAG_ZAPPED
  598.             ||
  599.             state[0] == EH_TAG_INLINE) {
  600.             sym = EhSymTableFind(table, name);
  601.             if (sym == NULL) { /* install a new one */
  602.                 
  603.                 if (source == NULL && state[0] != EH_TAG_INLINE) {
  604.                     fprintf(stderr,
  605.                             "[%d] found new style symbol (%s) but no source\n",
  606.                             line_n, name);
  607.                 }
  608.  
  609.                 if (state[0] == EH_TAG_GLOBAL)
  610.                     sym = EhSymNewDefined(name, object);
  611.                 else if (state[0] == EH_TAG_INLINE)
  612.                     sym = EhSymNewInline(name);
  613.                 else
  614.                     sym = EhSymNewZapped(name, object);
  615.                 
  616.                 EhSymTableInsert(table, sym);
  617.             } else {
  618.                 if (state[0] == EH_TAG_GLOBAL) {
  619.                     if (sym->state != EH_SYM_DEFINED) {
  620.                         fprintf(stderr,
  621.                                 "out of sync defined symbol: %s, fixing\n",
  622.                                 sym->name);
  623.                         sym->state = EH_SYM_DEFINED;
  624.                     }
  625.                 } else if (state[0] == EH_TAG_INLINE) {
  626.                     if (sym->state != EH_SYM_INLINE) {
  627.                         fprintf(stderr,
  628.                                 "out of sync inlined symbol: %s, fixing\n",
  629.                                 sym->name);
  630.                         sym->state = EH_SYM_INLINE;
  631.                     }
  632.                 } else {
  633.                     if (sym->state != EH_SYM_ZAPPED) {
  634.                         fprintf(stderr,
  635.                                 "out of sync zapped symbol: %s, fixing\n",
  636.                                 sym->name);
  637.                         sym->state = EH_SYM_ZAPPED;
  638.                     }
  639.                 }
  640.  
  641. #if 0
  642.                 /* these are probably "special" symbols like .div */
  643.                 if (sym->object != object) {
  644.                     fprintf(stderr,
  645.                             "out of sync object for symbol: %s, ignoring\n",
  646.                             sym->name);
  647.                 }
  648. #endif
  649.             }
  650.  
  651.             continue; /* no more fields we care about */
  652.         } else if (state[0] == EH_TAG_FILE) {
  653.  
  654.             directory = p;
  655.             for (; !isspace(*p) && *p != '\0'; p++)
  656.                 ;
  657.             *p++ = '\0';
  658.  
  659.             savefile = p;
  660.             for (; !isspace(*p) && *p != '\0'; p++)
  661.                 ;
  662.             *p++ = '\0';
  663.  
  664.             ctime = p;
  665.             for (; !isspace(*p) && *p != '\0'; p++)
  666.                 ;
  667.             *p++ = '\0';
  668.  
  669.             for (n = 0; *p != '\0';) {
  670.  
  671.                 for (; isspace(*p); p++)
  672.                     ;
  673.             
  674.                 cc_args[n++] = p++;
  675.                 
  676.                 for (; !isspace(*p) && *p != '\0'; p++)
  677.                     ;
  678.                 
  679.                 if (*p == '\0')
  680.                     break;
  681.  
  682.                 *p++ = '\0';
  683.             }
  684.             cc_args[n] = NULL;
  685.  
  686.             if (strcmp(directory, ".") == 0)
  687.                 directory = NULL;
  688.             source = EhSourceNew(name, cc_args, directory);
  689.             if (ctime != NULL)
  690.                 source->compile_time = (time_t)atoi(ctime);
  691.             object = EhObjectNewFromSource(source);
  692.  
  693.         } else { /* old style symbol list */
  694.             sym = EhSymTableFind(table, name);
  695.             if (sym != NULL) {
  696.                 if (sym->state != EH_SYM_ZAPPED) {
  697.                     fprintf(stderr,
  698.                             "out of sync random zapped symbol: %s, fixing\n",
  699.                             sym->name);
  700.                     sym->state = EH_SYM_ZAPPED;
  701.                 }
  702.             } else {
  703.                 sym = EhSymNewRandomZap(name);
  704.             }
  705.         }
  706.     }
  707.  
  708.     return line_n;
  709. }
  710.  
  711. typedef struct {
  712.     EhSym**  vector;
  713.     unsigned index;
  714. } flush_info;
  715.  
  716. static int
  717. flush_mappee(EhSym* sym, void* arg)
  718. {
  719.     flush_info* info = (flush_info*)arg;
  720.  
  721.     if (sym->state == EH_SYM_INLINE
  722.         ||
  723.         (sym->object != NULL && sym->state == EH_SYM_DEFINED)
  724.         ||
  725.         (sym->object != NULL && sym->state == EH_SYM_ZAPPED)) {
  726.         if (info->vector != NULL)
  727.             info->vector[info->index] = sym;
  728.         info->index++;
  729.     }
  730.  
  731.     return 0;
  732. }
  733.  
  734. static  int
  735. flush_compare(const void* ap, const void* bp)
  736. {
  737.     EhSym** ax = (EhSym**)ap;
  738.     EhSym** bx = (EhSym**)bp;
  739.     EhSym* a = *ax;
  740.     EhSym* b = *bx;
  741.     EhObject* oa = a->object;
  742.     EhObject* ob = b->object;
  743.     int foo;
  744.  
  745.     if (oa == NULL && ob != NULL)
  746.         return -1;
  747.     if (oa != NULL && ob == NULL)
  748.         return 1;
  749.     if (oa == NULL && ob == NULL) {
  750.         foo = strcmp(a->name, b->name);
  751.         if (foo < 0)
  752.             return -1;
  753.         else if (foo > 0)
  754.             return 1;
  755.         return 0;
  756.     }
  757.  
  758.     if (oa->source == NULL && ob->source != NULL)
  759.         return -1;
  760.     if (oa->source != NULL && ob->source == NULL)
  761.         return 1;
  762.     if (oa->source == ob->source)
  763.         return 0;
  764.     if (oa->source < ob->source)
  765.         return -1;
  766.     if (oa->source > ob->source)
  767.         return 1;
  768.     foo = strcmp(a->name, b->name);
  769.     if (foo < 0)
  770.         return -1;
  771.     else if (foo > 0)
  772.         return 1;
  773.     return 0;
  774. }
  775.  
  776. static void
  777. EhSourceFpWrite(EhSource* source, FILE* fp)
  778. {
  779.     unsigned n = 0;
  780.  
  781.     fputs(source->name, fp);
  782.     fputc(' ', fp);
  783.     fputc(EH_TAG_FILE, fp);
  784.  
  785.     fputc(' ', fp);
  786.     if (source->directory != NULL)
  787.         fprintf(fp, "%s", source->directory);
  788.     else
  789.         fputc('.', fp);
  790.     
  791.     fputc(' ', fp);
  792.     if (source->as_savefile != NULL)
  793.         fprintf(fp, "%s", source->as_savefile);
  794.     else
  795.         fputc('.', fp);
  796.     
  797.     fputc(' ', fp);
  798.     fprintf(fp, "%d", source->compile_time);
  799.  
  800.     if (source->target_object != NULL) {
  801.         fputs(" -o ", fp);
  802.         fputs(source->target_object, fp);
  803.     }
  804.     
  805.     if (source->cc_args != NULL) {
  806.         for (n = 0; source->cc_args[n] != NULL; n++) {
  807.             fputc(' ', fp);
  808.             fputs(source->cc_args[n], fp);
  809.         }
  810.     }
  811.  
  812.     if (n < 1)
  813.         fprintf(stderr, "WARNING: %s has no args\n", source->name);
  814.  
  815.     fputc('\n', fp);
  816. }
  817.  
  818. static int
  819. EhSymTableFpDump(EhSymTable* table, FILE* fp)
  820. {
  821.     flush_info info;
  822.     unsigned n;
  823.     EhObject* object = NULL;
  824.     EhSym**   syms;
  825.     EhSym*    sym;
  826.     unsigned size;
  827.  
  828.     info.index = 0;
  829.     info.vector = NULL;
  830.     EhSymTableMap(table, flush_mappee, (void*)&info);
  831.     size = info.index;
  832.  
  833.     syms = (EhSym**)malloc(sizeof(EhSym*) * size);
  834.     info.index = 0;
  835.     info.vector = syms;
  836.     EhSymTableMap(table, flush_mappee, (void*)&info);
  837.  
  838.     /* sort */
  839.     qsort(syms, size, sizeof(EhSym*), flush_compare);
  840.  
  841.     /* dump */
  842.     for (n = 0; n < size; n++) {
  843.         sym = syms[n];
  844.  
  845.         if (sym->object != object) {
  846.             object = sym->object;
  847.  
  848.             if (object->source != NULL) {
  849.                 EhSourceFpWrite(object->source, fp);
  850.             }
  851.         }
  852.  
  853.         if (sym->state == EH_SYM_INLINE) {
  854.             fprintf(fp, "%s %c\n", sym->name, EH_TAG_INLINE);
  855.         } else if (object->source != NULL && sym->state == EH_SYM_ZAPPED) {
  856.             fprintf(fp, "%s %c\n", sym->name, EH_TAG_ZAPPED);
  857.         } else if (object->source != NULL && sym->state == EH_SYM_DEFINED) {
  858.             fprintf(fp, "%s %c\n", sym->name, EH_TAG_GLOBAL);
  859.         }
  860.     }
  861.  
  862.     free(syms);
  863.  
  864.     return n;
  865. }
  866.  
  867. int djw_debug;
  868. char* djw_test_name;
  869.  
  870. int
  871. eh_process_object(Elf* elf, EhObject* object, EhSymTable* table)
  872. {
  873.     Elf32_Shdr *   shdr;
  874.     Elf32_Ehdr *   ehdr;
  875.     Elf_Scn * scn;
  876.     Elf_Data *     shstr_data;
  877.     Elf_Data*      sym_data = NULL;
  878.     Elf_Data*      str_data = NULL;
  879.     Elf_Data*      rel_data[4];
  880.     int            nrel_data = 0;
  881.     Elf32_Rel*     rel_entries;
  882.     Elf_Data*      rela_data[10];
  883.     int            nrela_data = 0;
  884.     Elf32_Rela*    rela_entries;
  885.     unsigned int   cnt;
  886.     Elf32_Sym* elf_sym;
  887.     int i;
  888.     int j;
  889.     int k;
  890.     char*  name;
  891.     EhSym* sym;
  892.     char buf[MAXPATHLEN];
  893.  
  894.     /* Obtain the .shstrtab data buffer */
  895.     if (((ehdr = elf32_getehdr(elf)) == NULL) ||
  896.         ((scn = elf_getscn(elf, ehdr->e_shstrndx)) == NULL) ||
  897.         ((shstr_data = elf_getdata(scn, NULL)) == NULL)) {
  898.         fprintf(stderr, "problems on %s\n", EhObjectGetFilename(object, buf));
  899.         return -1;
  900.     }
  901.  
  902.     /* get the string table */
  903.     for (cnt = 1, scn = NULL; (scn = elf_nextscn(elf, scn)); cnt++) {
  904.         if ((shdr = elf32_getshdr(scn)) == NULL) {
  905.             fprintf(stderr, "problems on %s, section %d\n",
  906.                     EhObjectGetFilename(object, buf), cnt);
  907.             return -1;
  908.         }
  909.  
  910. #if 0
  911.         fprintf(stderr, "%s: section %d type %d name %s\n",
  912.                 EhObjectGetFilename(object, buf),
  913.                 cnt,
  914.                 shdr->sh_type,
  915.                 (char*)shstr_data->d_buf + shdr->sh_name);
  916. #endif
  917.  
  918.         /*
  919.          *    Get the string table.
  920.          */
  921.         if (shdr->sh_type == SHT_STRTAB &&
  922. #ifdef sun
  923.             strcmp((char*)shstr_data->d_buf + shdr->sh_name, ".strtab") == 0 &&
  924. #endif
  925.             cnt != ehdr->e_shstrndx) {
  926.             if (str_data != NULL) {
  927.                 fprintf(stderr, "multiple string tables for %s - bailing\n",
  928.                         EhObjectGetFilename(object, buf));
  929.                 return -1;
  930.             }
  931.             str_data = elf_getdata(scn, NULL);
  932.         } else if (shdr->sh_type == SHT_SYMTAB) { /* look into sym table */
  933.             if (sym_data != NULL) {
  934.                 fprintf(stderr, "multiple symbol tables for %s - bailing\n",
  935.                         EhObjectGetFilename(object, buf));
  936.                 return -1;
  937.             }
  938.             sym_data = elf_getdata(scn, NULL);
  939.         } else if (shdr->sh_type == SHT_REL) { /* look into rel table */
  940.             if (nrel_data >= 4) {
  941.                 fprintf(stderr, "too many relocation tables for %s bailing\n",
  942.                         EhObjectGetFilename(object, buf));
  943.                 return -1;
  944.             }
  945.             rel_data[nrel_data++] = elf_getdata(scn, NULL);
  946.         } else if (shdr->sh_type == SHT_RELA) { /* look into rela table */
  947.             if (nrela_data >= 10) {
  948.                 fprintf(stderr, "too many RELA tables for %s bailing\n",
  949.                         EhObjectGetFilename(object, buf));
  950.                 return -1;
  951.             }
  952.             rela_data[nrela_data++] = elf_getdata(scn, NULL);
  953.         }
  954.     }
  955.  
  956.     if (sym_data == NULL) {
  957.         fprintf(stderr, "could not load sym table for %s\n",
  958.                 EhObjectGetFilename(object, buf));
  959.         return -1;
  960.     }
  961.  
  962.     if (str_data == NULL) {
  963.         fprintf(stderr, "could not load string table for %s\n",
  964.                 EhObjectGetFilename(object, buf));
  965.         return -1;
  966.     }
  967.  
  968.     elf_sym = (Elf32_Sym*)sym_data->d_buf;
  969.  
  970.     for (i = 0; i < (sym_data->d_size/sizeof(Elf32_Sym)); i++) {
  971.  
  972.         /*
  973.          *    We are only interested in globals.
  974.          */
  975.         if (ELF32_ST_BIND(elf_sym[i].st_info) != STB_GLOBAL)
  976.             continue;
  977.         
  978.         name = (char *)str_data->d_buf + elf_sym[i].st_name;
  979.         
  980.         if (djw_test_name != NULL
  981.             && strcmp(djw_test_name, name) == 0) {
  982.             printf("found %s\n", name);
  983.         }
  984.         
  985.         sym = EhSymTableFind(table, name);
  986.         
  987.         /*
  988.          *    Treat inlines as non-globals
  989.          */
  990.         if (sym != NULL && sym->state == EH_SYM_INLINE)
  991.             continue;
  992.         
  993. #if 0
  994.         printf("name = %s value = %d type = %d, info = %d,"
  995.                " other = %d, size = %d\n",
  996.                name,
  997.                elf_sym[i].st_value,
  998.                ELF32_ST_TYPE(elf_sym[i].st_info),
  999.                elf_sym[i].st_info,
  1000.                elf_sym[i].st_other,
  1001.                elf_sym[i].st_size);
  1002. #endif
  1003.         
  1004.         /* defined */
  1005.         if (ELFSYM_IS_DEFINED(elf_sym[i])) {
  1006.             
  1007.             if (sym != NULL) {
  1008.                 
  1009.                 if (sym->object == NULL) { /* object undefined */
  1010.                     sym->object = object;
  1011.                 } else if (sym->object->name==eh_unnamed_object) {
  1012.                     
  1013.                     if (object->source != NULL
  1014.                         &&
  1015.                         object->source != sym->object->source) {
  1016.                         
  1017.                         fprintf(stderr,
  1018.                                 "warning: symbol %s defined in more than one source file\n"
  1019.                                 "last time: %s\n"
  1020.                                 "this time: %s (ignored)\n",
  1021.                                 sym->name,
  1022.                                 object->source->name,
  1023.                                 sym->object->source->name);
  1024.                     } else {
  1025.                         object->source = sym->object->source;
  1026.                         /*
  1027.                          *    Do a global: sym->object = object;
  1028.                          */
  1029.                         EhSymTableObjectFixup(table,
  1030.                                               sym->object, /*old*/
  1031.                                               object); /*new*/
  1032.                         
  1033.                     }
  1034.                     
  1035.                 } else if (sym->object != object) {
  1036.                     fprintf(stderr,
  1037.                             "warning: symbol %s define in multiple object files\n"
  1038.                             "last time: %s\n"
  1039.                             "this time: %s (ignored)\n",
  1040.                             sym->name,
  1041.                             object->name,
  1042.                             sym->object->name);
  1043.                 }
  1044.                 
  1045.                 sym->state = EH_SYM_DEFINED;
  1046.  
  1047.             } else {
  1048.                 sym = EhSymNewDefined(name, object);
  1049.                 EhSymTableInsert(table, sym);
  1050.             }                
  1051.  
  1052.             for (k = 0; k < nrel_data; k++) {
  1053.                 int nentries = rel_data[k]->d_size/sizeof(Elf32_Rel);
  1054.  
  1055.                 rel_entries = (Elf32_Rel*)rel_data[k]->d_buf;
  1056.                 
  1057.                 for (j = 0; j < nentries; j++) {
  1058.                     if (ELF32_R_SYM(rel_entries[j].r_info) == i) {
  1059.                         /* locally referenced */
  1060.                         sym->nlusers++;
  1061.                     }
  1062.                 }
  1063.             }
  1064.             for (k = 0; k < nrela_data; k++) {
  1065.                 int nentries = rela_data[k]->d_size/sizeof(Elf32_Rela);
  1066.  
  1067.                 rela_entries = (Elf32_Rela*)rela_data[k]->d_buf;
  1068.                 
  1069.                 for (j = 0; j < nentries; j++) {
  1070.                     if (ELF32_R_SYM(rela_entries[j].r_info) == i) {
  1071.                         /* locally referenced */
  1072.                         sym->nlusers++;
  1073.                     }
  1074.                 }
  1075.             }
  1076.         }  
  1077.         
  1078.         /* Undefined. */
  1079.         else if (ELFSYM_IS_UNDEFINED(elf_sym[i])) {
  1080.             
  1081.             if (sym == NULL) {
  1082.                 sym = EhSymNewUndefined(name);
  1083.                 EhSymTableInsert(table, sym);
  1084.             }
  1085.             sym->ngusers++;
  1086.         } else {
  1087.             
  1088. #if 1
  1089.             printf("what is this: "
  1090.                    "name = %s value = %d type = %d, "
  1091.                    "info = %d, other = %d, size = %d\n",
  1092.                    name,
  1093.                    elf_sym[i].st_value,
  1094.                    ELF32_ST_TYPE(elf_sym[i].st_info),
  1095.                    elf_sym[i].st_info,
  1096.                    elf_sym[i].st_other,
  1097.                    elf_sym[i].st_size);
  1098. #endif
  1099.             ;
  1100.         }/* type ==... */
  1101.     } /* for each symbol */
  1102.  
  1103.     return 0;
  1104. }
  1105.  
  1106. int
  1107. eh_process_file(char* filename, EhSymTable* table, char* rootdir)
  1108. {
  1109.     Elf* elf;
  1110.     Elf* arf;
  1111.     int  fd;
  1112.     Elf_Cmd cmd;
  1113.     Elf_Kind e_kind;
  1114.     EhObject* object;
  1115.     EhArchive* archive;
  1116.     Elf_Arhdr* arhdr;
  1117.     char* name;
  1118.     int   rv = 0;
  1119.  
  1120.     if ((fd = open(filename, O_RDONLY)) == -1) {
  1121.         fprintf(stderr, "error opening %s\n", filename);
  1122.         return -1;
  1123.     }
  1124.  
  1125.     elf_version(EV_CURRENT);
  1126.     if ((arf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
  1127.         return -1;
  1128.     }
  1129.  
  1130.     e_kind = elf_kind(arf);
  1131.     if (e_kind == ELF_K_ELF) {
  1132.         object = EhObjectNew(filename, rootdir);
  1133.         rv = eh_process_object(arf, object, table);
  1134.         
  1135.     } else if (e_kind == ELF_K_AR) {
  1136.  
  1137.         archive = EhArchiveNew(filename, rootdir);
  1138.         cmd = ELF_C_READ;
  1139.  
  1140. #if 0
  1141.         arsyms = elf_getarsym(arf, &narsyms);
  1142.  
  1143.         for (i = 0; i < narsyms && arsyms[i].as_name != NULL; i++) {
  1144.             printf("%s - %d\n", arsyms[i].as_name, arsyms[i].as_off);
  1145.         }
  1146.  
  1147.         arhdr = elf_getarhdr(arf);
  1148.         for (i = 0; arhdr[i].ar_rawname != NULL; i++) {
  1149.  
  1150.             if (arhdr[i].ar_name != NULL)
  1151.                 printf("%s\n", arhdr[i].ar_name);
  1152.             else
  1153.                 printf("[%s]\n", arhdr[i].ar_rawname);
  1154.         }
  1155. #endif
  1156.  
  1157.         rv = 0;
  1158.  
  1159.         while ((elf = elf_begin(fd, cmd, arf)) != 0) {
  1160.  
  1161.             e_kind = elf_kind(elf);
  1162.  
  1163.             if (e_kind != ELF_K_ELF)
  1164.                 continue;
  1165.  
  1166.             arhdr = elf_getarhdr(elf);
  1167.  
  1168.             if (arhdr != NULL) {
  1169.                 if (arhdr->ar_name != NULL)
  1170.                     name = arhdr->ar_name;
  1171.                 else
  1172.                     name = arhdr->ar_rawname;
  1173.             } else {
  1174.                 name = eh_unnamed_object;
  1175.             }
  1176.  
  1177.             object = EhObjectNewArchiveObject(archive, name);
  1178.             rv = eh_process_object(elf, object, table);
  1179.  
  1180.             if (rv == -1)
  1181.                 break;
  1182.  
  1183.             cmd = elf_next(elf);
  1184.             elf_end(elf);
  1185.         }
  1186.     }
  1187.  
  1188.     elf_end(arf);
  1189.  
  1190.     close(fd);
  1191.  
  1192.     return rv;
  1193. }
  1194.  
  1195. static int
  1196. eh_dump_unused(EhSym* sym, void* arg)
  1197. {
  1198.     char buf[MAXPATHLEN];
  1199.  
  1200.     printf(/*"0x%x "*/ "%s %d %d ", /*sym,*/
  1201.            sym->name, sym->ngusers, sym->nlusers);
  1202.  
  1203.     if (EHSYM_ISINLINE(sym))
  1204.         printf("%c ", EH_TAG_INLINE);
  1205.     else if (EHSYM_ISZAPPED(sym))
  1206.         printf("%c ", EH_TAG_ZAPPED);
  1207.     else if (EHSYM_ISDEFINED(sym))
  1208.         printf("%c ", EH_TAG_GLOBAL);
  1209.     else
  1210.         printf("%c ", EH_TAG_UNDEFINED);
  1211.  
  1212.     if (sym->object != NULL) {
  1213.         printf("%s ", EhObjectGetFilename(sym->object, buf));
  1214.         if (sym->object->source != NULL) {
  1215.             printf("%s recompilable\n", sym->object->source->name);
  1216.         } else {
  1217.             printf("nosource notrecompilable\n");
  1218.         }
  1219.     } else {
  1220.         printf("noobject nosource notrecompilable\n");
  1221.     }
  1222.     
  1223.     return 0;
  1224. }
  1225.  
  1226. static void
  1227. print_dump(EhSymTable* table)
  1228. {
  1229.     printf("everything\n");
  1230.     EhSymTableMap(table, eh_dump_unused, NULL);
  1231. }
  1232.  
  1233. typedef struct {
  1234.     unsigned ndefined;
  1235.     unsigned nused; /* globally */
  1236.     unsigned nundefined;
  1237.     unsigned nzapped;
  1238.     unsigned nzapped_nowused;
  1239.     unsigned ninlined;
  1240.     unsigned nunlinked;
  1241.     unsigned ndeadcode;
  1242. } SummaryInfo;
  1243.  
  1244. static int
  1245. eh_summary_mappee(EhSym* sym, void* arg) {
  1246.     SummaryInfo* info = (SummaryInfo*)arg;
  1247.  
  1248.     if (EHSYM_ISDEFINED(sym)) {
  1249.         if (sym->ngusers != 0)
  1250.             info->nused++;
  1251.         else if (sym->object != NULL && sym->object->nusers == 0)
  1252.             info->nunlinked++;
  1253.         else if (sym->nlusers != 0)
  1254.             info->ndefined++;
  1255.         else
  1256.             info->ndeadcode++;
  1257.             
  1258.     } else if (EHSYM_ISZAPPED(sym)) { /* one of ours */
  1259.         if (sym->ngusers != 0)
  1260.             info->nzapped_nowused++;
  1261.         else
  1262.             info->nzapped++;
  1263.     } else if (EHSYM_ISINLINE(sym)) { /* one of ours */
  1264.         info->ninlined++;
  1265.     } else {
  1266.         info->nundefined++;
  1267.     }
  1268.  
  1269.     return 0;
  1270. }
  1271.  
  1272. static void
  1273. get_summary(EhSymTable* table, SummaryInfo* info)
  1274. {
  1275.     info->ndefined = 0;
  1276.     info->nused = 0;
  1277.     info->nundefined = 0;
  1278.     info->nzapped = 0;
  1279.     info->nzapped_nowused = 0;
  1280.     info->ninlined = 0;
  1281.     info->nunlinked = 0;
  1282.     info->ndeadcode = 0;
  1283.     
  1284.     EhSymTableMap(table, eh_summary_mappee, info);
  1285.  
  1286. static void
  1287. print_summary(EhSymTable* table)
  1288. {
  1289.     SummaryInfo info;
  1290.  
  1291.     get_summary(table, &info);
  1292.     
  1293.     printf("summary:\n"
  1294.            "defined and used:             %d\n"
  1295.            "defined but unused globally:  %d\n"
  1296.            "total globals in target:      %d\n"
  1297.            "--------------------------------\n"
  1298.            "global to statics *:          %d\n"
  1299.            "global to statics (now used): %d\n"
  1300.            "inlined to statics *:         %d\n"
  1301.            "defined in unlinked objects:  %d\n"
  1302.            "defined but unused (deadcode):%d\n"
  1303.            "undefined but used:           %d\n",
  1304.            info.nused,
  1305.            info.ndefined,
  1306.            (info.nused + info.ndefined),
  1307.            info.nzapped,
  1308.            info.nzapped_nowused,
  1309.            info.ninlined,
  1310.            info.nunlinked,               
  1311.            info.ndeadcode,               
  1312.            info.nundefined);
  1313. }
  1314.  
  1315. typedef struct EhDirMapEntree {
  1316.     char* dirname;
  1317.     struct EhDirMapEntree* _next;
  1318. } EhDirMapEntree;
  1319.  
  1320. typedef struct EhDirMap {
  1321.     EhDirMapEntree* head;
  1322. } EhDirMap;
  1323.  
  1324. static EhDirMap*
  1325. EhDirMapNew(void)
  1326. {
  1327.     EhDirMap* dm = EH_NEW(EhDirMap);
  1328.     dm->head = NULL;
  1329.     return dm;
  1330. }
  1331.  
  1332. static void
  1333. EhDirMapAddDirectory(EhDirMap* map, char* dirname)
  1334. {
  1335.     EhDirMapEntree* entree = EH_NEW(EhDirMapEntree);
  1336.     EhDirMapEntree* foo;
  1337.  
  1338.     entree->dirname = strdup(dirname);
  1339.     entree->_next = NULL;
  1340.  
  1341.     if (map->head == NULL) {
  1342.         map->head = entree;
  1343.     } else {
  1344.         for (foo = map->head; foo->_next != NULL; foo = foo->_next)
  1345.             ;
  1346.  
  1347.         foo->_next = entree;
  1348.     }
  1349. }
  1350.  
  1351. static char*
  1352. EhDirMapGetLibName(EhDirMap* map, char* name, char* libbuf)
  1353. {
  1354.     EhDirMapEntree* foo;
  1355.     struct stat     buf;
  1356.  
  1357.     for (foo = map->head; foo != NULL; foo = foo->_next) {
  1358.         sprintf(libbuf, "%s/lib%s.a", foo->dirname, name);
  1359.  
  1360.         if (stat(libbuf, &buf) != -1)
  1361.             return libbuf;
  1362.     }
  1363.  
  1364.     return NULL;
  1365. }
  1366.  
  1367. static char*
  1368. test_for_global(char* buf)
  1369. {
  1370. #ifdef IRIX
  1371.     if (strncmp(buf, "\t.globl\t", 8) == 0)
  1372.         return &buf[8];
  1373. #else
  1374.     if (strncmp(buf, "\t.global ", 9) == 0)
  1375.         return &buf[9];
  1376. #endif
  1377.     return NULL;
  1378. }
  1379.  
  1380. static char*
  1381. test_for_file(char* foo, char* buf)
  1382. {
  1383. #ifdef IRIX
  1384.     char* p;
  1385.     char* q;
  1386.     if (strncmp(buf, "\t.file\t", 6) == 0) {
  1387.         for (p = &buf[6]; *p != '"' && *p != '\0'; p++)
  1388.             ;
  1389.         if (*p == '\0')
  1390.             return NULL;
  1391.         p++; /* quote */
  1392.         q = strchr(p, '"');
  1393.         if (q == NULL)
  1394.             return NULL;
  1395.         memcpy(foo, p, q - p);
  1396.         foo[q - p] = '\0';
  1397.         return foo;
  1398.     }
  1399. #else
  1400.     printf("test_for_file() not implimented\n");
  1401. #endif
  1402.     return NULL;
  1403. }
  1404.  
  1405. static int
  1406. EhSourceZapFp(EhSource* source, EhSymTable* table, FILE* fpi, FILE* fpo,
  1407.               unsigned verbosity, unsigned cplusplus)
  1408. {
  1409.     char*     buf = NULL;
  1410.     char*     p;
  1411.     int       nzap = 0;
  1412.     char*     name;
  1413.     EhSym*    sym;
  1414.     int       i_zapped;
  1415.     EhObject* object = EhObjectNewFromSource(source);
  1416.     char*     filename = source->name;
  1417.     char*     tmp_name;
  1418.     char      foo[256];
  1419.     unsigned  line_n = 0;
  1420.  
  1421.     if (VERBOSITY_DEBUG(verbosity))
  1422.         fputs("gts: ", stderr);
  1423.  
  1424.     while ((buf = safe_fgets(buf, 4192, fpi)) != NULL) {
  1425.  
  1426.         i_zapped = 0;
  1427.         for (p = buf; *p != '\0' && *p != '\n'; p++)
  1428.             ;
  1429.         *p = '\0';
  1430.  
  1431.         if ((tmp_name = test_for_file(foo, buf)) != NULL) {
  1432.             if (strcmp(tmp_name, filename) != 0) /* not the same file */
  1433.                 filename = "non local file";
  1434.             else
  1435.                 filename = source->name;
  1436.         }
  1437.  
  1438.         else if ((name = test_for_global(buf)) != NULL) {
  1439.  
  1440.             sym = EhSymTableFind(table, name);
  1441.  
  1442.             /* an inline, we have to treat specially */
  1443.             if ((filename != source->name && cplusplus != 0) /* inline now */
  1444.                 ||
  1445.                 (sym != NULL && sym->state == EH_SYM_INLINE)) {/* was inline */
  1446.  
  1447.                 if (!sym) { 
  1448.  
  1449.                     sym = EhSymNewInline(name);
  1450.                     
  1451.                     EhSymTableInsert(table, sym);
  1452.                 }
  1453.                 sym->state = EH_SYM_INLINE; /* just make sure */
  1454.  
  1455.                 if (fpo != NULL) /* always zap inlines we see */
  1456.                     fputs(" # gts", fpo);
  1457.  
  1458.             } else { /* a real global */
  1459.  
  1460.                 if (fpo != NULL && sym != NULL && EHSYM_ISZAPPED(sym)) {
  1461.                     if (VERBOSITY_DEBUG(verbosity)) {
  1462.                         fprintf(stderr, "%s ", &buf[8]);
  1463.                     }
  1464.                     nzap++;
  1465.  
  1466.                     if (fpo != NULL)
  1467.                         fputs(" # gts", fpo);
  1468.                 }
  1469.  
  1470.                 if (sym != NULL) {
  1471.                     if (sym->object == NULL) {
  1472.                         sym->object = object;
  1473.                     } else if (sym->object != object) {
  1474.                         sym->object->source = source;
  1475.                         EhSymTableObjectFixup(table, object, sym->object);
  1476.                         object = sym->object;
  1477.                     }
  1478.                 } else { /* install a new one */
  1479.                     
  1480.                     sym = EhSymNewDefined(name, object);
  1481.                     
  1482.                     EhSymTableInsert(table, sym);
  1483.                 }
  1484.  
  1485.             }
  1486.         }
  1487.  
  1488.         if (fpo != NULL) {
  1489.             fputs(buf, fpo);
  1490.             fputc('\n', fpo);
  1491.         }
  1492.         line_n++;
  1493.     }
  1494.     
  1495.     if (VERBOSITY_DEBUG(verbosity))
  1496.         fputc('\n', stderr);
  1497.  
  1498.     return nzap;
  1499. }
  1500.  
  1501. static void
  1502. print_command(char* command, char** args, unsigned verbosity)
  1503. {
  1504.     int i;
  1505.     FILE* fp = stderr;
  1506.     if (!VERBOSITY_USER(verbosity))
  1507.         return;
  1508.  
  1509.     fprintf(fp, "%s: ", command);
  1510.     for (i = 0; args[i]; i++) {
  1511.         fprintf(fp, "%s ", args[i]);
  1512.     }
  1513.     fprintf(fp, "\n");
  1514. }
  1515.  
  1516. static int
  1517. do_command(char* label, char** args, unsigned verbosity)
  1518. {
  1519.     int status;
  1520.     pid_t child_pid;
  1521.     char* file = args[0];
  1522.  
  1523.     print_command(label, args, verbosity);
  1524.  
  1525.     if ((child_pid = fork()) == -1) {
  1526.         fprintf(stderr, "could not fork: ");
  1527.         perror(NULL);
  1528.         return -1;
  1529.     }
  1530.  
  1531.     if (child_pid == 0) { /* i am the child */
  1532.         if (execvp(file, args) == -1) {
  1533.             fprintf(stderr, "could not exec %s: ", file);
  1534.             perror(NULL);
  1535.             exit(3);
  1536.         }
  1537.         /*NOTREACHED*/
  1538.     }
  1539.  
  1540.     if (waitpid(child_pid, &status, 0) == -1) {
  1541.         fprintf(stderr, "wait on %s failed: ", file);
  1542.         perror(NULL);
  1543.         return -1;
  1544.     }
  1545.  
  1546.     return WEXITSTATUS(status);
  1547. }
  1548.  
  1549. static char*
  1550. suffix_name(char* s)
  1551. {
  1552.     char* p;
  1553.  
  1554.     if ((p = strrchr(s, '.')) != NULL)
  1555.         return p;
  1556.     else
  1557.         return "";
  1558. }
  1559.  
  1560. static char base_name_buf[MAXPATHLEN];
  1561.  
  1562. static char*
  1563. base_name(char* s)
  1564. {
  1565.     char* p;
  1566.  
  1567.     if ((p = strrchr(s, '.')) != NULL) {
  1568.         memcpy(base_name_buf, s, p - s);
  1569.         base_name_buf[p - s] = '\0';
  1570.         s = base_name_buf;
  1571.     }
  1572.     return s;
  1573. }
  1574.  
  1575. static char*
  1576. file_base_name(char *s)
  1577. {
  1578.     char* p;
  1579.  
  1580.     s = base_name(s);
  1581.  
  1582.     if ((p = strrchr(s, '/')) != NULL)
  1583.         s = &p[1];
  1584.     
  1585.     return s;
  1586. }
  1587. static int
  1588. EhSourceCompile(EhSource*   source,
  1589.                 EhSymTable* table,
  1590.                 unsigned    verbosity,
  1591.                 unsigned    do_compile,
  1592.                 unsigned    do_zap,
  1593.                 unsigned    do_assem)
  1594. {
  1595.     char* filename = source->name;
  1596.     char** opts = source->cc_args;
  1597.     char asname[MAXPATHLEN];
  1598.     char o_asname[MAXPATHLEN];
  1599.     char* cc_opts[256];
  1600.     unsigned i = 0;
  1601.     unsigned j = 0;
  1602.     FILE* in_fp;
  1603.     FILE* out_fp;
  1604.     int   status;
  1605.     int nzap = 0;
  1606.     char* save_prefix = NULL;
  1607.     unsigned do_dash_s = (do_zap != 0 || save_prefix != NULL);
  1608.     char* cc_command;
  1609.     char* use_savefile = NULL;
  1610.     struct timeval start_time;
  1611.     struct timeval end_time;
  1612. #ifdef DEBUG_djw
  1613.     char savebuf[1024];
  1614. #endif
  1615.     unsigned is_cplusplus = 0;
  1616.  
  1617. #ifdef LINUX
  1618.     gettimeofday(&start_time,NULL);
  1619. #else
  1620.     gettimeofday(&start_time);
  1621. #endif
  1622.  
  1623.     /* munge file */
  1624. #ifdef HANDLES_DASHSO
  1625.     if (source->target_object != NULL)
  1626.         strcpy(asname, base_name(source->target_object));
  1627.     else
  1628. #endif
  1629.         strcpy(asname, file_base_name(filename));
  1630.     strcat(asname, ".s");
  1631.  
  1632.     strcpy(o_asname, asname);
  1633.     strcat(o_asname, ".gts_tmp");
  1634.  
  1635.     if (strcmp(suffix_name(filename), ".cpp") == 0) {
  1636.         cc_command = CCC_COMMAND;
  1637.         is_cplusplus = 1;
  1638.     } else if (strcmp(suffix_name(filename), ".s") == 0) {
  1639.         do_compile = FALSE;
  1640.         cc_command = CC_COMMAND;
  1641.     } else {
  1642.         cc_command = CC_COMMAND;
  1643.     }
  1644.  
  1645.     if (do_compile) {
  1646.  
  1647.         j = 0;
  1648.         cc_opts[j++] = cc_command;
  1649.         cc_opts[j++] = "-c";
  1650.  
  1651.         if (do_dash_s) {
  1652.             cc_opts[j++] = "-S";
  1653. #ifdef HANDLES_DASHSO
  1654.             if (source->target_object != NULL) {
  1655.                 cc_opts[j++] = "-o";
  1656.                 cc_opts[j++] = asname;
  1657.             }
  1658. #endif
  1659.         } else if (source->target_object != NULL) {
  1660.             cc_opts[j++] = "-o";
  1661.             cc_opts[j++] = source->target_object;
  1662.         }
  1663.         
  1664.         i = 0;
  1665.         while (opts[i] != NULL)
  1666.             cc_opts[j++] = opts[i++];
  1667.         
  1668.         cc_opts[j++] = filename;
  1669.         cc_opts[j] = NULL;
  1670.         
  1671.         if ((status = do_command("compile", cc_opts, verbosity)) != 0) {
  1672.             fprintf(stderr, "compile failed (returned %d)\n", status);
  1673.             return -1;
  1674.         }
  1675.  
  1676.         if (!do_dash_s)
  1677.             return 0;
  1678.     }
  1679.  
  1680.     /*
  1681.      *    Now we have a foo.s file, what do we do with it?
  1682.      */
  1683.     if (do_zap > 1) {
  1684.  
  1685.         if (use_savefile == NULL)
  1686.             use_savefile = asname;
  1687.  
  1688.         if ((in_fp = fopen(use_savefile, "r")) == NULL) {
  1689.             fprintf(stderr, "could not open %s for reading\n", asname);
  1690.             return -1;
  1691.         }
  1692.     
  1693.         if ((out_fp = fopen(o_asname, "w")) == NULL) {
  1694.             fprintf(stderr, "could not open %s for writing\n", o_asname);
  1695.             return -1;
  1696.         }
  1697.     
  1698.         j = 0;
  1699.         cc_opts[j++] = "gts";
  1700.         cc_opts[j++] = asname;
  1701.         cc_opts[j++] = o_asname;
  1702.         cc_opts[j++] = NULL;
  1703.         print_command("gts", cc_opts, verbosity);
  1704.  
  1705.         nzap = EhSourceZapFp(source, table, in_fp, out_fp, verbosity, is_cplusplus);
  1706.  
  1707.         fclose(in_fp);
  1708.         fclose(out_fp);
  1709.  
  1710.         j = 0;
  1711.         cc_opts[j++] = "rename";
  1712.         cc_opts[j++] = o_asname;
  1713.         cc_opts[j++] = asname;
  1714.         cc_opts[j++] = NULL;
  1715.         print_command("rename", cc_opts, verbosity);
  1716.  
  1717. #ifdef DEBUG_djw
  1718.         strcpy(savebuf, "gts_pre_");
  1719.         strcat(savebuf, asname);
  1720.         rename(asname, savebuf);
  1721. #endif
  1722.  
  1723.         if (rename(o_asname, asname) == -1) {
  1724.             fprintf(stderr, "could not rename %s\n", o_asname);
  1725.             return -1;
  1726.         }
  1727.  
  1728.     } else if (do_zap > 0) { /* audit only */
  1729.  
  1730.         if ((in_fp = fopen(asname, "r")) == NULL) {
  1731.             fprintf(stderr, "could not open %s for reading\n", asname);
  1732.             return -1;
  1733.         }
  1734.     
  1735.         j = 0;
  1736.         cc_opts[j++] = "audit";
  1737.         cc_opts[j++] = asname;
  1738.         cc_opts[j++] = NULL;
  1739.         print_command("audit", cc_opts, verbosity);
  1740.  
  1741.         nzap = EhSourceZapFp(source, table, in_fp, NULL, verbosity, is_cplusplus);
  1742.  
  1743.         fclose(in_fp);
  1744.     }
  1745.  
  1746.     if (do_assem) {
  1747.         i = 0;
  1748.         j = 0;
  1749.         cc_opts[j++] = AS_COMMAND;
  1750.         cc_opts[j++] = "-c";
  1751.  
  1752.         if (source->target_object != NULL) {
  1753.             cc_opts[j++] = "-o";
  1754.             cc_opts[j++] = source->target_object;
  1755.         }
  1756.  
  1757.         while (opts[i] != NULL)
  1758.             cc_opts[j++] = opts[i++];
  1759.  
  1760.         cc_opts[j++] = asname;
  1761.         cc_opts[j] = NULL;
  1762.  
  1763.         if ((status = do_command("assemble", cc_opts, verbosity)) != 0) {
  1764.  
  1765.             unlink(asname);
  1766.  
  1767.             fprintf(stderr,
  1768.                 "gtscc of %s failed (exit status = %d), reverting to %s:\n",
  1769.                     filename,
  1770.                     status,
  1771.                     cc_command);
  1772.             
  1773.             i = 0;
  1774.             j = 0;
  1775.             cc_opts[j++] = cc_command;
  1776.             cc_opts[j++] = "-c";
  1777.  
  1778.             if (source->target_object != NULL) {
  1779.                 cc_opts[j++] = "-o";
  1780.                 cc_opts[j++] = source->target_object;
  1781.             }
  1782.  
  1783.             for (; opts[i]; i++, j++)
  1784.                 cc_opts[j] = opts[i];
  1785.             
  1786.             cc_opts[j++] = filename;
  1787.             cc_opts[j] = NULL;
  1788.             
  1789.             if ((status = do_command("fix-compile", cc_opts, verbosity)) != 0)
  1790.                 return -1;
  1791.  
  1792.             return 0;
  1793.         }
  1794.     }
  1795.  
  1796.     if (save_prefix != NULL && save_prefix[0] != '\0') {
  1797.  
  1798.         sprintf(o_asname, save_prefix, file_base_name(filename));
  1799.  
  1800.         j = 0;
  1801.         cc_opts[j++] = "rename";
  1802.         cc_opts[j++] = asname;
  1803.         cc_opts[j++] = o_asname;
  1804.         cc_opts[j++] = NULL;
  1805.         print_command("savefile", cc_opts, verbosity);
  1806.  
  1807.         if (rename(asname, o_asname) == -1) {
  1808.             fprintf(stderr, "could not rename %s to %s - sorry\n",
  1809.                     asname, o_asname);
  1810.             return -1;
  1811.         }
  1812.  
  1813.         if (source->as_savefile != NULL)
  1814.             free(source->as_savefile);
  1815.         source->as_savefile = strdup(o_asname);
  1816.     } else {
  1817.  
  1818.         j = 0;
  1819.         cc_opts[j++] = "unlink";
  1820.         cc_opts[j++] = asname;
  1821.         cc_opts[j++] = NULL;
  1822.         print_command("unlink", cc_opts, verbosity);
  1823.  
  1824. #ifdef DEBUG_djw
  1825.         strcpy(savebuf, "gts_post_");
  1826.         strcat(savebuf, asname);
  1827.         rename(asname, savebuf);
  1828. #else
  1829.         unlink(asname);
  1830. #endif
  1831.     }
  1832.  
  1833. #ifdef LINUX
  1834.     gettimeofday(&end_time,NULL);
  1835. #else
  1836.     gettimeofday(&end_time);
  1837. #endif
  1838.  
  1839.     source->compile_time = ((end_time.tv_sec - start_time.tv_sec) * 1000) +
  1840.                            ((end_time.tv_usec - start_time.tv_usec) / 1000);
  1841.  
  1842.     return nzap;
  1843. }
  1844.  
  1845. static char target_buf[MAXPATHLEN]; /* this will go away with rel source */
  1846.  
  1847. static char*
  1848. EhSourceGetTarget(EhSource* source)
  1849. {
  1850.     if (source->target_object != NULL)
  1851.         return source->target_object;
  1852.  
  1853.     strcpy(target_buf, base_name(source->name));
  1854.     strcat(target_buf, ".o");
  1855.  
  1856.     return target_buf;
  1857. }
  1858.  
  1859. static int
  1860. EhArchiveUpdate(EhArchive* archive, char* target, char* rootdir,
  1861.                 unsigned verbosity)
  1862. {
  1863.     char* args[8];
  1864.     unsigned nargs;
  1865.     int status;
  1866.     char pathname[MAXPATHLEN];
  1867.  
  1868.     pathname[0] = '\0';
  1869.     if (rootdir != NULL) {
  1870.         strcat(pathname, rootdir);
  1871.         strcat(pathname, "/");
  1872.     }
  1873.     strcat(pathname, archive->name);
  1874.  
  1875. #if 0
  1876.     nargs = 0;
  1877.     args[nargs++] = AR_COMMAND;
  1878.     args[nargs++] = "dc";
  1879.     args[nargs++] = pathname;
  1880.     args[nargs++] = target;
  1881.     args[nargs++] = NULL;
  1882.     
  1883.     if ((status = do_command("delete from archive", args, verbosity)) != 0) {
  1884.         fprintf(stderr, "archive: %s delete %s failed (status = %d)\n",
  1885.                 pathname,
  1886.                 target);
  1887.         return -1;
  1888.     }
  1889. #endif
  1890.  
  1891.     nargs = 0;
  1892.     args[nargs++] = AR_COMMAND;
  1893.     args[nargs++] = AR_OPTIONS;
  1894.     args[nargs++] = pathname;
  1895.     args[nargs++] = target;
  1896.     args[nargs++] = NULL;
  1897.     
  1898.     if ((status = do_command("archive", args, verbosity)) != 0) {
  1899.         fprintf(stderr, "archive: %s <- %s failed (status = %d)\n",
  1900.                 pathname,
  1901.                 target);
  1902.         return -1;
  1903.     }
  1904.  
  1905.     return 0;
  1906. }
  1907.  
  1908. static int
  1909. EhObjectRebuild(EhObject*   object,
  1910.                 EhSymTable* table,
  1911.                 unsigned    verbosity,
  1912.                 char*       rootdir)
  1913. {
  1914.     EhSource* source = object->source;
  1915.     char  cwd[MAXPATHLEN];
  1916.     char  fullpath[MAXPATHLEN];
  1917.     int   rv = 0;
  1918.     int   do_chdir = 0;
  1919.  
  1920.     if (!source) {
  1921.         fprintf(stderr,
  1922.                 "wanted to recompile %s, but I don't how\n",
  1923.                 object->name);
  1924.         return -1;
  1925.     }
  1926.     
  1927. #if 0
  1928.     if (VERBOSITY_USER(verbosity))
  1929. #endif
  1930.         fprintf(stderr, "recompiling %s\n", source->name);
  1931.     
  1932.     /*
  1933.      *    Check to see if we need to chdir
  1934.      */
  1935.     if (source->directory != NULL) {
  1936.         if (getcwd(cwd, sizeof(cwd)) == NULL) {
  1937.             fprintf(stderr, "cannot get pwd: cannot compile\n");
  1938.             return -1;
  1939.         }
  1940.         
  1941.         make_relative_pathname(fullpath, cwd, rootdir);
  1942.         
  1943.         if (strcmp(fullpath, source->directory) != 0) {
  1944.             fullpath[0] = '\0';
  1945.             if (rootdir != NULL) {
  1946.                 strcat(fullpath, rootdir);
  1947.                 strcat(fullpath, "/");
  1948.             }
  1949.             strcat(fullpath, source->directory);
  1950.  
  1951.             if (chdir(fullpath) == -1) {
  1952.                 fprintf(stderr, "cannot chdir - can't compile\n");
  1953.                 return -1;
  1954.             }
  1955.             do_chdir++;
  1956.         }
  1957.     }
  1958.  
  1959.     rv = EhSourceCompile(source,
  1960.                          table,
  1961.                          verbosity,
  1962.                          TRUE,  /* compile  */
  1963.                          2,     /* do zap   */
  1964.                          TRUE); /* do assem */
  1965.  
  1966.     if (do_chdir) {
  1967.         if (chdir(cwd) == -1) {
  1968.             fprintf(stderr, "cannot chdir - this will be very confused\n");
  1969.             return -1;
  1970.         }
  1971.     }
  1972.  
  1973.     if (rv == -1) {
  1974.         fprintf(stderr, "recompiling %s failed\n",  source->name);
  1975.         return -1;
  1976.     }
  1977.     
  1978.     /* do archive */
  1979.     fullpath[0] = '\0';
  1980.     if (rootdir != NULL) {
  1981.         strcat(fullpath, rootdir);
  1982.         strcat(fullpath, "/");
  1983.     }
  1984.  
  1985.     if (source->directory != NULL)
  1986.         strcat(fullpath, source->directory);
  1987.  
  1988.     strcat(fullpath, "/");
  1989.     strcat(fullpath, EhSourceGetTarget(source));
  1990.     
  1991.     if (object->archive != NULL) {
  1992.         if (EhArchiveUpdate(object->archive, fullpath, rootdir,
  1993.                             verbosity) == -1)
  1994.             return -1;
  1995.     }
  1996.  
  1997.     /* do install */
  1998. #if 0
  1999.     if (rv != -1) {
  2000.     }
  2001. #endif
  2002.  
  2003.     return rv;
  2004. }
  2005.  
  2006. static int
  2007. object_nusers_mappee(EhSym* sym, void* arg)
  2008. {
  2009.     if (sym->object != NULL)
  2010.         sym->object->nusers += sym->ngusers;
  2011.     return 0;
  2012. }
  2013.  
  2014. typedef struct {
  2015.     EhObject* recompile_list;
  2016.     unsigned  recompile_count;
  2017.     unsigned  recompile_wish_count;
  2018.     unsigned  unzap_count;
  2019.     unsigned  zap_count;
  2020. } RecompileInfo;
  2021.  
  2022. static int
  2023. recompile_init_mappee(EhSym* sym, void* arg)
  2024. {
  2025.     RecompileInfo* info = (RecompileInfo*)arg;
  2026.  
  2027.     if (EHSYM_ISZAPPED(sym) && sym->ngusers != 0) {
  2028.         if (EH_OBJECT_CANBUILD(sym->object)) {
  2029.             sym->state = EH_SYM_DEFINED;
  2030.             if (sym->object->_recompile == NULL) {
  2031.                 sym->object->_recompile = info->recompile_list;
  2032.                 info->recompile_list = sym->object;
  2033.                 info->recompile_count++;
  2034.             }
  2035.             info->unzap_count++;
  2036.             sym->object->_needs_unzap++;
  2037.         }
  2038.         info->recompile_wish_count++;
  2039.     }
  2040.     else if (EHSYM_ISDEFINED(sym) /* it's defined */
  2041.              && sym->ngusers == 0 /* there are no global users */
  2042.              && sym->nlusers != 0 /* BUT, ther are local users */
  2043.              && sym->object->nusers != 0) { /* object is linked */
  2044.  
  2045.         if (EH_OBJECT_CANBUILD(sym->object)) {
  2046.             sym->state = EH_SYM_ZAPPED;
  2047.             if (sym->object->_recompile == NULL) {
  2048.                 sym->object->_recompile = info->recompile_list;
  2049.                 info->recompile_list = sym->object;
  2050.                 info->recompile_count++;
  2051.             }
  2052.             info->zap_count++;
  2053.         }
  2054.         info->recompile_wish_count++;
  2055.     }
  2056.  
  2057.     return 0;
  2058. }
  2059.  
  2060. static char**    recompile_compare_prefs;
  2061. static char**    recompile_compare_unprefs;
  2062.  
  2063. static unsigned
  2064. match_prefs(char* candidate, char** prefs)
  2065. {
  2066.     unsigned n;
  2067.  
  2068.     for (n = 0; prefs[n] != NULL; n++) {
  2069.         char*    pref = prefs[n];
  2070.         unsigned len = strlen(pref);
  2071.         if (strncmp(pref, candidate, len) == 0)
  2072.             return n; /* cool */
  2073.     }
  2074.     return (unsigned)-1; /* big! */
  2075. }
  2076.  
  2077. static  int
  2078. recompile_compare(const void* ap, const void* bp)
  2079. {
  2080.     EhObject** ax = (EhObject**)ap;
  2081.     EhObject** bx = (EhObject**)bp;
  2082.     EhObject*  obj_a = *ax;
  2083.     EhObject*  obj_b = *bx;
  2084.     EhSource*  src_a = obj_a->source;
  2085.     EhSource*  src_b = obj_b->source;
  2086.     unsigned   matcha;
  2087.     unsigned   matchb;
  2088.     int        foo;
  2089.  
  2090.     if (obj_a->_needs_unzap == 0 && obj_b->_needs_unzap != 0)
  2091.         return -1;
  2092.     if (obj_a->_needs_unzap != 0 && obj_b->_needs_unzap == 0)
  2093.         return 1;
  2094.  
  2095.     if (src_a == NULL && src_b != NULL)
  2096.         return 1;
  2097.     if (src_a != NULL && src_b == NULL)
  2098.         return -1;
  2099.     if (src_a == src_b)
  2100.         return 0;
  2101.  
  2102.     if (recompile_compare_unprefs != NULL
  2103.         && src_a->directory != NULL && src_b->directory != NULL) {
  2104.  
  2105.         matcha = match_prefs(src_a->directory, recompile_compare_unprefs);
  2106.         matchb = match_prefs(src_b->directory, recompile_compare_unprefs);
  2107.  
  2108.         if (matcha > matchb) /* greater is good */
  2109.             return -1;
  2110.         if (matcha < matchb)
  2111.             return 1;
  2112.     }
  2113.  
  2114.     if (recompile_compare_prefs != NULL
  2115.         && src_a->directory != NULL && src_b->directory != NULL) {
  2116.  
  2117.         matcha = match_prefs(src_a->directory, recompile_compare_prefs);
  2118.         matchb = match_prefs(src_b->directory, recompile_compare_prefs);
  2119.  
  2120.         if (matcha > matchb) /* greater is bad */
  2121.             return 1;
  2122.         if (matcha < matchb)
  2123.             return -1;
  2124.     }
  2125.  
  2126.     /* else same directory probably */
  2127.     foo = strcmp(src_a->name, src_b->name);
  2128.  
  2129.     if (foo < 0)
  2130.         return -1;
  2131.     if (foo > 0)
  2132.         return 1;
  2133.  
  2134.     return 0;
  2135. }
  2136.  
  2137. static int
  2138. do_recompilation(EhSymTable* table, char* gts_file, unsigned max_globals,
  2139.                  char** prefs, char** unprefs,
  2140.                  char* rootdir, unsigned verbosity)
  2141. {
  2142.     SummaryInfo s_info;
  2143.     RecompileInfo info;
  2144.     unsigned    size;
  2145.     unsigned n;
  2146.     EhObject* object;
  2147.     EhObject** recompiles;
  2148.     unsigned delta;
  2149.     int rv;
  2150.     unsigned nzaps;
  2151.     EhObject dummy; /* just marks the end of the recomp list */
  2152.     time_t  eta;
  2153.  
  2154.     get_summary(table, &s_info);
  2155.  
  2156.     if ((s_info.nused + s_info.ndefined) <= max_globals) {
  2157.         if (VERBOSITY_USER(verbosity))
  2158.             fprintf(stderr,
  2159.             "number of globals <= requested max, skipping recompilation\n");
  2160.         return 0;
  2161.     }
  2162.  
  2163.     /* Init recompilation. */
  2164.     info.recompile_list = &dummy; /* cannot use NULL, because syms test that */
  2165.     info.recompile_count = 0;
  2166.     info.recompile_wish_count = 0;
  2167.     info.unzap_count = 0;
  2168.     info.zap_count = 0;
  2169.     EhSymTableMap(table, recompile_init_mappee, (void*)&info);
  2170.     size = info.recompile_count;
  2171.  
  2172.     recompiles = (EhObject**)malloc(sizeof(EhObject*) * size);
  2173.  
  2174.     /* install */
  2175.     n = 0;
  2176.     for (object = info.recompile_list;
  2177.          object != &dummy;
  2178.          object = object->_recompile) {
  2179.         recompiles[n++] = object;
  2180.     }
  2181.  
  2182.     /* sort */
  2183.     recompile_compare_prefs = prefs;
  2184.     recompile_compare_unprefs = unprefs;
  2185.     qsort(recompiles, size, sizeof(EhObject*), recompile_compare);
  2186.  
  2187.     /*
  2188.      *    sorted !
  2189.      *    less recompile the first n, n = ndefined - max
  2190.      */
  2191.     delta = (s_info.nused + s_info.ndefined) - max_globals;
  2192.  
  2193.     if (delta > info.zap_count) {
  2194.         fprintf(stderr,
  2195.                 "WARNING: there too many globals (%d/%d fixables).\n"
  2196.                 "         I don't think I can fix this, but I'll try.\n"
  2197.                 "         You might get lucky.\n",
  2198.                 info.zap_count,
  2199.                 delta);
  2200.     }
  2201.  
  2202.     if (VERBOSITY_USER(verbosity))
  2203.         fprintf(stderr, "scheduling recompilation targets:\n");
  2204.  
  2205.     eta = 0;
  2206.     for (n = 0; n < size; n++) {
  2207.         char* cname = "unknown";
  2208.         object = recompiles[n];
  2209.         if (object->source != NULL) {
  2210.             cname = object->source->name;
  2211.             eta += object->source->compile_time;
  2212.         }
  2213.         
  2214.         if (VERBOSITY_DEBUG(verbosity))
  2215.             fprintf(stderr, "object %s from source %s\n", object->name, cname);
  2216.     }
  2217.  
  2218. #if 0
  2219.     if (VERBOSITY_USER(verbosity))
  2220. #endif
  2221.         fprintf(stderr, "gts-ing %d symbols, eta = %d minutes\n", delta,
  2222.                 eta/(60*1000));
  2223.  
  2224.     if (gts_file != NULL) {
  2225.         FILE* zap_fp;
  2226.         if ((zap_fp = fopen(gts_file, "w")) == NULL) {
  2227.             perror(0);
  2228.             fprintf(stderr,
  2229.                     "WARNING: could not open the gtscc db file %s.\n"
  2230.                     "         I will continue with the recompilation, but\n"
  2231.                     "         if you recompile any of the files I touched\n"
  2232.                     "         I'll have to recompile them after you!\n",
  2233.                     gts_file);
  2234.         } else {
  2235.         
  2236.             EhSymTableFpDump(table, zap_fp);
  2237.             
  2238.             fclose(zap_fp);
  2239.         }
  2240.     }
  2241.  
  2242.     for (n = 0, nzaps = 0; n < size && nzaps < delta; n++) {
  2243.  
  2244.         object = recompiles[n];
  2245.         rv = EhObjectRebuild(object, table, verbosity, rootdir);
  2246.  
  2247.         if (rv == -1)
  2248.             return -1;
  2249.  
  2250.         nzaps += rv;
  2251.  
  2252.         object->_recompile = NULL; /* clean up now */
  2253.     }
  2254.  
  2255.     if (nzaps < delta) {
  2256.         fprintf(stderr,
  2257.                 "WARNING: I wanted to gts %d symbols, but only managed\n"
  2258.                 "         to get %d of them.\n"
  2259.                 "         Your link may fail with GOT errors.\n",
  2260.                 delta,
  2261.                 nzaps);
  2262.     }
  2263.     
  2264.     free(recompiles);
  2265.  
  2266.     return n;
  2267. }
  2268.  
  2269. typedef struct FileList
  2270. {
  2271.     char*            name;
  2272.     struct FileList* next;
  2273. } FileList;
  2274.  
  2275. static FileList*
  2276. fileListFind(FileList* list, char* name)
  2277. {
  2278.     FileList* foo;
  2279.  
  2280.     for (foo = list; foo != NULL; foo = foo->next) {
  2281.         if (strcmp(name, foo->name) == 0)
  2282.             return foo;
  2283.     }
  2284.     return NULL;
  2285. }
  2286.  
  2287. static FileList*
  2288. fileListAppend(FileList** list_a, char* name)
  2289. {
  2290.     FileList* list = *list_a;
  2291.     FileList* foo;
  2292.     FileList* last;
  2293.  
  2294.     for (foo = list, last = NULL; foo != NULL; last = foo, foo = foo->next)
  2295.         ;
  2296.  
  2297.     if (last == NULL) {
  2298.         foo = EH_NEW(FileList);
  2299.         foo->next = NULL;
  2300.         foo->name = strdup(name);
  2301.         *list_a = foo;
  2302.     } else {
  2303.         foo = EH_NEW(FileList);
  2304.         foo->next = NULL;
  2305.         foo->name = strdup(name);
  2306.         last->next = foo;
  2307.     }
  2308.  
  2309.     return *list_a;
  2310. }
  2311.  
  2312. #if 0
  2313. static FileList* c_list;
  2314. #endif
  2315. static FileList* o_list;
  2316.  
  2317. #if 0
  2318. static char*
  2319. EhSourceAdjustPathname(EhSource* source, char* rootdir)
  2320. {
  2321.     char buf[MAXPATHLEN];
  2322.     char buf2[MAXPATHLEN];
  2323.     char* p;
  2324.     char* q;
  2325.     char* filename = source->name;
  2326.  
  2327.     if (getcwd(buf, sizeof(buf)) == NULL) {
  2328.         fprintf(stderr, "cannot get pwd\n");
  2329.         return NULL;
  2330.     }
  2331.  
  2332.     strcat(buf, "/");
  2333.     strcat(buf, filename);
  2334.  
  2335.     if (rootdir == NULL) {
  2336.         filename = buf;
  2337.     } else {
  2338.         if (realpath(buf, buf2) == NULL) {
  2339.             fprintf(stderr, "realpath() failed: %s\n", buf2);
  2340.             return NULL;
  2341.         }
  2342.  
  2343.         if (realpath(rootdir, buf) == NULL) {
  2344.             fprintf(stderr, "realpath() failed: %s\n", buf);
  2345.             return NULL;
  2346.         }
  2347.         strcat(buf, "/"); 
  2348.         
  2349.         for (p = buf, q = buf2; *p == *q; p++, q++)
  2350.             ;
  2351.  
  2352.         filename = q;
  2353.     }
  2354.  
  2355.     free(source->name);
  2356.     source->name = strdup(filename);
  2357.  
  2358.     return source->name;
  2359. }
  2360. #endif
  2361.  
  2362. static unsigned
  2363. katoi(char *buf)
  2364. {
  2365.     unsigned base = 1;
  2366.     char* s;
  2367.     
  2368.     for (s = buf; isdigit(*s); s++)
  2369.         ;
  2370.  
  2371.     if (*s == 'k' || *s == 'K')
  2372.         base = 1024;
  2373.  
  2374.     *s = '\0';
  2375.  
  2376.     return base * atoi(buf);
  2377. }
  2378.  
  2379. static void
  2380. usage(void)
  2381. {
  2382.     fprintf(stderr,
  2383.             "Usage:\n"
  2384.             "as a compiler:\n"
  2385.             "gtscc [gtscc_options] [compiler_options] -c file.c file.cpp ...\n"
  2386.             "gtscc_options:\n"
  2387.             "-gtsfile <db.gts>       the gts database file (use this)\n"
  2388.             "-gtsrootdir <directory> the root for the tree (use this)\n"
  2389.             "-gtsverbose             be more verbose (3 levels)\n"
  2390.             "-gtsnozap               don't convert globals to statics\n"
  2391.             "-gtsnoupdate            don't update the database file\n"
  2392.             "as a linker:\n"
  2393.             "gtscc [gtscc_options] [linker_options] file.o ... libxx.a ...\n"
  2394.             "gtscc_options:\n"
  2395.             "-gtsfile <db.gts>       the gts database file (use this)\n"
  2396.             "-gtsrootdir <directory> the root for the tree (use this)\n"
  2397.             "-gtspref <directory>    please recompile these paths first\n"
  2398.             "-gtsunpref <directory>  please try to avoid recompiling these\n"
  2399.             "-gtsverbose             be more verbose (3 levels)\n"
  2400.             "-gtssummary             print a summary of global usage\n"
  2401.             "-gtsdump                print a detailed listing of all symbols\n"
  2402.             "-gtsmaxglobals <number>[k] maximum globals allowed in target\n"
  2403.             "-gtsnorecompile         don't do the normal recompilation\n"
  2404.             "-gtsnolink              don't call linker after recompilation\n"
  2405.             "-gtsnoupdate            don't update the database file\n"
  2406.             "-help                   print this\n"
  2407.     );
  2408. }
  2409.  
  2410. int
  2411. main(int argc, char** argv)
  2412. {
  2413.     EhSymTable* table = EhSymTableNew(1000);
  2414.     EhSym* sym;
  2415.     FILE* zap_fp;
  2416.     unsigned n = 0;
  2417.     unsigned verbosity = 0;
  2418.     char* arg_buf[256];
  2419.     unsigned nargs = 0;
  2420.     EhDirMap*   dmap = EhDirMapNew();
  2421.     unsigned do_dump = 0;
  2422.     unsigned do_summary = 0;
  2423.     unsigned do_link = 1;
  2424.     unsigned in_link = 1;
  2425.     unsigned do_audit = 1;
  2426.     unsigned do_zap = 1;
  2427.     unsigned do_assem = 1;
  2428.     unsigned do_recompile = 1;
  2429.     unsigned do_collect = 1;
  2430.     char* name;
  2431.     char* saveprefix = NULL;
  2432.     char* rootdir = NULL;
  2433.     int rv;
  2434.     EhSource* source = NULL;
  2435.     char* gts_file = NULL;
  2436.     char* path_prefs[32];
  2437.     unsigned npath_prefs = 0;
  2438.     char* path_un_prefs[32];
  2439.     unsigned npath_un_prefs = 0;
  2440.     char* suffix;
  2441.     unsigned max_globals = DEFAULT_MAX_GLOBALS;
  2442.     FileList* list;
  2443.  
  2444.     if (elf_version(EV_CURRENT) == EV_NONE) {
  2445.         fprintf(stderr, "something losing about your elf lib - sorry!\n");
  2446.         return 3;
  2447.         /* library out of date */
  2448.         /* recover from error */
  2449.     }
  2450.  
  2451.     arg_buf[nargs] = NULL;
  2452.  
  2453.     for (n = 1; n < argc; n++) {
  2454.  
  2455.         if (strcmp(argv[n], "-help") == 0) {
  2456.             usage();
  2457.             return 0;
  2458.         } else if (strcmp(argv[n], "-gtssummary") == 0) {
  2459.             do_summary = 1;
  2460.         } else if (strcmp(argv[n], "-gtsdump") == 0) {
  2461.             do_dump = 1;
  2462.         } else if (strcmp(argv[n], "-gtsnorecompile") == 0) {
  2463.             do_recompile = 0;
  2464.         } else if (strcmp(argv[n], "-gtsnolink") == 0) {
  2465.             do_link = 0;
  2466.         } else if (strcmp(argv[n], "-gtsverbose") == 0) {
  2467.             verbosity++;
  2468.         } else if (strcmp(argv[n], "-gtsnoupdate") == 0) {
  2469.             do_collect = 0;
  2470.         } else if (strcmp(argv[n], "-gtsnoaudit") == 0) {
  2471.             do_audit = 0;
  2472.         } else if (strcmp(argv[n], "-gtsnozap") == 0) {
  2473.             do_zap = 0;
  2474.         } else if (strcmp(argv[n], "-gtsrootdir") == 0) {
  2475.             if (argc < n+2) {
  2476.                 fprintf(stderr,    "-gtsrootdir requires an argument\n");
  2477.                 usage();
  2478.                 return 2;
  2479.             }
  2480.             rootdir = argv[n+1];
  2481.             n++;
  2482.         } else if (strcmp(argv[n], "-gtsdebugsym") == 0) {
  2483.             if (argc < n+2) {
  2484.                 fprintf(stderr,    "-gtsdebugsym requires an argument\n");
  2485.                 usage();
  2486.                 return 2;
  2487.             }
  2488.             djw_test_name = argv[n+1];
  2489.             n++;
  2490.         } else if (strcmp(argv[n], "-gtsmaxglobals") == 0) {
  2491.             if (argc < n+2) {
  2492.                 fprintf(stderr,    "-gtsmaxglobals requires an argument\n");
  2493.                 usage();
  2494.                 return 2;
  2495.             }
  2496.             max_globals = katoi(argv[n+1]);
  2497.             n++;
  2498.  
  2499.         } else if (strcmp(argv[n], "-gtspref") == 0) {
  2500.             if (argc < n+2) {
  2501.                 fprintf(stderr,    "-gtspref requires an argument\n");
  2502.                 usage();
  2503.                 return 2;
  2504.             }
  2505.             path_prefs[npath_prefs++] = argv[n+1];
  2506.             path_prefs[npath_prefs] = NULL;
  2507.             n++;
  2508.  
  2509.         } else if (strcmp(argv[n], "-gtsunpref") == 0) {
  2510.             if (argc < n+2) {
  2511.                 fprintf(stderr,    "-gtsunpref requires an argument\n");
  2512.                 usage();
  2513.                 return 2;
  2514.             }
  2515.             path_un_prefs[npath_un_prefs++] = argv[n+1];
  2516.             path_un_prefs[npath_un_prefs] = NULL;
  2517.             n++;
  2518.  
  2519.         } else if (strcmp(argv[n], "-gtssaveprefix") == 0) {
  2520.             if (argc < n+2) {
  2521.                 fprintf(stderr,    "-gtssaveprefix requires an argument\n");
  2522.                 usage();
  2523.                 return 2;
  2524.             }
  2525.             saveprefix = argv[n+1];
  2526.             n++;
  2527.  
  2528.         } else if (strcmp(argv[n], "-gtsfile") == 0) {
  2529.  
  2530.             struct stat sbuf;
  2531.  
  2532.             if (argc < n+2) {
  2533.                 fprintf(stderr,    "-gtsfile requires an argument\n");
  2534.                 usage();
  2535.                 return 2;
  2536.             }
  2537.  
  2538.             gts_file = argv[n+1];
  2539.                 
  2540.             if (stat(gts_file, &sbuf) == -1) {
  2541.                 fprintf(stderr,
  2542.                         "warning: %s does not exist, will be created\n",
  2543.                         gts_file);
  2544.             } else {
  2545.                 
  2546.                 if ((zap_fp = fopen(gts_file, "r")) == NULL) {
  2547.                     fprintf(stderr,    "you lose cannot open %s\n", gts_file);
  2548.                     usage();
  2549.                     return 2;
  2550.                 }
  2551.  
  2552.                 if (EhSymTableFpLoad(table, zap_fp) == -1) {
  2553.                     fprintf(stderr,
  2554.                             "error: failed reading symbols from gtsfile %s\n",
  2555.                             argv[n+1]);
  2556.                     usage();
  2557.                     return 2;
  2558.                 }
  2559.                 
  2560.                 fclose(zap_fp);
  2561.             }
  2562.  
  2563.             n++;
  2564.  
  2565.         } else if (strcmp(argv[n], "-gtsname") == 0) {
  2566.             if (argc < n+2) {
  2567.                 fprintf(stderr,    "-gtsname requires an argument\n");
  2568.                 usage();
  2569.                 return 2;
  2570.             }
  2571.  
  2572.             sym = EhSymTableFind(table, argv[n+1]);
  2573.             if (!sym)
  2574.                 sym = EhSymNewRandomZap(argv[n+1]);
  2575.             n++;
  2576.             do_audit = 1;
  2577.  
  2578.         } else if (strcmp(argv[n], "-c") == 0) { /* do not link */
  2579.             in_link = 0;
  2580.             do_link = 0;
  2581.         } else if (strcmp(argv[n], "-S") == 0) { /* do not assem */
  2582.             do_assem = 0;
  2583.         } else if (strcmp(argv[n], "-o") == 0) { /* parse through */
  2584.             arg_buf[nargs++] = argv[n++];
  2585.             arg_buf[nargs++] = argv[n];
  2586.             arg_buf[nargs] = NULL;
  2587.         } else if (strcmp((suffix = suffix_name(argv[n])), ".cpp") == 0
  2588.                    ||
  2589.                    strcmp(suffix, ".c") == 0
  2590.                    ||
  2591.                    strcmp(suffix, ".s") == 0) {
  2592.             char pathname[MAXPATHLEN];
  2593.  
  2594.             make_relative_pathname(pathname, ".", rootdir);
  2595.  
  2596.             source = EhSourceNew(argv[n], arg_buf, pathname);
  2597.  
  2598.             rv = EhSourceCompile(source,
  2599.                                  table,
  2600.                                  verbosity,
  2601.                                  TRUE, /* compile, .s files ignore anyway */
  2602.                                  (do_audit + do_zap),
  2603.                                  do_assem);
  2604.             if (rv == -1)
  2605.                 return 1;
  2606.  
  2607. #if 0
  2608.             EhSourceAdjustPathname(source, rootdir);
  2609. #endif
  2610.  
  2611.         } else if (strcmp(suffix, ".o") == 0 || strcmp(suffix, ".a") == 0) {
  2612.  
  2613.             if (fileListFind(o_list, argv[n]) == NULL) {
  2614.                 fileListAppend(&o_list, argv[n]);
  2615.             } else {
  2616.                 fprintf(stderr,
  2617.                         "%s repeated on command line - ignored\n",
  2618.                         argv[n]);
  2619.             }
  2620.             arg_buf[nargs++] = argv[n];
  2621.             arg_buf[nargs] = NULL;
  2622.  
  2623.         } else if (strncmp(argv[n], "-L", 2) == 0) {
  2624.             EhDirMapAddDirectory(dmap, &argv[n][2]);
  2625.         } else if (strncmp(argv[n], "-l", 2) == 0) {
  2626.             char pathbuf[MAXPATHLEN];
  2627.             name = EhDirMapGetLibName(dmap, &argv[n][2], pathbuf);
  2628.             if (name != NULL) {
  2629.                 if (fileListFind(o_list, name) == NULL) {
  2630.                     fileListAppend(&o_list, name);
  2631.                 } else {
  2632.                     fprintf(stderr,
  2633.                             "%s repeated on command line - ignored\n",
  2634.                             name);
  2635.                 }
  2636.             } else {
  2637.                 fprintf(stderr, 
  2638.                         "unable to resolve library reference %s - ignoring\n",
  2639.                         argv[n]);
  2640.             }
  2641.             arg_buf[nargs++] = argv[n];
  2642.             arg_buf[nargs] = NULL;
  2643.         } else {
  2644.             arg_buf[nargs++] = argv[n];
  2645.             arg_buf[nargs] = NULL;
  2646.         }
  2647.     }
  2648.  
  2649.     /*
  2650.      *    Analyse objects.
  2651.      */
  2652.     if (o_list != NULL) {
  2653.         for (list = o_list; list != NULL; list = list->next) {
  2654.  
  2655.             if (eh_process_file(list->name, table, rootdir)) {
  2656.                 fprintf(stderr, "oops we died around %s\n", list->name);
  2657.                 return 1;
  2658.             }
  2659.         }
  2660.         
  2661.         /* look for unused objects */
  2662.         EhSymTableMap(table, object_nusers_mappee, 0);
  2663.     }
  2664.  
  2665.     if (do_summary) {
  2666.         print_summary(table);
  2667.     }
  2668.  
  2669.     if (do_dump) {
  2670.         print_dump(table);
  2671.     }
  2672.  
  2673.     if (!in_link && gts_file != NULL) {
  2674.         FILE* zap_fp;
  2675.         if ((zap_fp = fopen(gts_file, "w")) == NULL) {
  2676.             perror(0);
  2677.             usage();
  2678.             return 2;
  2679.         }
  2680.  
  2681.         EhSymTableFpDump(table, zap_fp);
  2682.         fclose(zap_fp);
  2683.         return 0;
  2684.     }
  2685.  
  2686.     /*
  2687.      *    Now the fun really starts.
  2688.      */
  2689.     if (do_recompile) {
  2690.         char** pp = NULL;
  2691.         char** up = NULL;
  2692.         
  2693.         if (npath_prefs > 0)
  2694.             pp = path_prefs;
  2695.         
  2696.         if (npath_un_prefs > 0)
  2697.             up = path_un_prefs;
  2698.  
  2699.         if (!do_collect)
  2700.             gts_file = NULL;
  2701.         
  2702.         rv = do_recompilation(table, gts_file, max_globals, pp, up, rootdir,
  2703.                               verbosity);
  2704.         if (rv == -1)
  2705.             return 1;
  2706.     }
  2707.  
  2708.     /*
  2709.      *    Finally.
  2710.      */
  2711.     if (do_link) {
  2712.  
  2713.         int status;
  2714.  
  2715.         arg_buf[nargs+1] = NULL;
  2716.         for (n = nargs; n > 0; n--)
  2717.             arg_buf[n] = arg_buf[n-1];
  2718.         arg_buf[0] = LD_COMMAND;
  2719.         
  2720.         status = do_command("link", arg_buf, verbosity);
  2721.  
  2722.         if (status == -1)
  2723.             return 3;
  2724.         else
  2725.             return status;
  2726.     }
  2727.     
  2728.     return 0;
  2729. }
  2730.