"Fossies" - the Fresh Open Source Software Archive

Member "ncc-2.8/nccnav/nccnav.C" (24 Jul 2008, 35640 Bytes) of package /linux/privat/old/ncc-2.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "nccnav.C" see the Fossies "Dox" file reference documentation.

    1 // sxanth@ceid.upatras.gr
    2 #include <stdio.h>
    3 #include <stdlib.h>
    4 #include <string.h>
    5 #include <ncurses.h>
    6 #include <ctype.h>
    7 #include <unistd.h>
    8 #include <sys/mman.h>
    9 #include <sys/types.h>
   10 #include <sys/stat.h>
   11 #include <signal.h>
   12 #include <fcntl.h>
   13 
   14 #include "dbstree.h"
   15 #include "inttree.h"
   16 
   17 // If you don't want an external viewer,
   18 // comment out the definitions of SOURCE_VIEWER
   19 #define SOURCE_VIEWER_INDENT "indent -st -kr | less"
   20 #define SOURCE_VIEWER "less"
   21 #define COLOR_VIEWER "vi -R"
   22 #define OUTFILE1 "nccnav.outs"
   23 
   24 static char *svr;
   25 static char CWD [1000];
   26 
   27 // "uti.mod"
   28 //
   29 // utilities
   30 //
   31 
   32 static char *strDup (char *s)
   33 {
   34     return strcpy (new char [strlen (s) + 1], s);
   35 }
   36 
   37 #define SHUT_UP_GCC(x) (void)x;
   38 
   39 static void progress ()
   40 {
   41 static  char pchars [] = "-\\|/", out [] = { '\r', '[', 0, ']' };
   42 static  int pi, ti;
   43     if (!(ti++ & 127)) {
   44         out [2] = pchars [pi = (pi + 1)%(sizeof pchars - 1)];
   45         write (fileno (stdout), out, sizeof out);
   46     }
   47 }
   48 
   49 static void aprogress ()
   50 {
   51 static  int ti;
   52     char out [] = { '\r', '[', 0, ']' };
   53     out [2] = '0' + ti++;
   54     write (fileno (stdout), out, sizeof out);
   55 }
   56 
   57 class foreach_intNode
   58 {
   59    protected:
   60 virtual void A (intNode*) = 0;
   61     void inorder (intNode*);
   62    public:
   63 };
   64 
   65 void foreach_intNode::inorder (intNode *i)
   66 {
   67     if (i->less) inorder (i->less);
   68     A (i);
   69     if (i->more) inorder (i->more);
   70 }
   71 
   72 
   73 class load_file
   74 {
   75     int fd;
   76    public:
   77     load_file (char*);
   78     int success;
   79     char *data;
   80     int len;
   81     ~load_file ();
   82 };
   83 
   84 #define ZC_OK 0
   85 #define ZC_NA 1
   86 #define ZC_AC 2
   87 #define ZC_FF 3
   88 
   89 #ifdef _POSIX_MAPPED_FILES
   90 
   91 load_file::load_file (char *f)
   92 {
   93     data = NULL;
   94     success = ZC_NA;
   95     fd = -1;
   96 
   97     struct stat statbuf;
   98     if (stat (f, &statbuf) == -1) return;
   99     len = statbuf.st_size;
  100     if (len == -1 || (fd = open (f, O_RDONLY)) == -1) return;
  101 
  102     success = ((data = (char*) mmap (0, len, PROT_READ, MAP_PRIVATE, fd, 0))
  103          != MAP_FAILED) ? ZC_OK : ZC_FF;
  104 }
  105 
  106 load_file::~load_file ()
  107 {
  108     if (data && data != MAP_FAILED) munmap (data, len);
  109     if (fd != -1) close (fd);
  110 }
  111 #else
  112 
  113 load_file::load_file (char *f)
  114 {
  115     data = NULL;
  116     success = ZC_NA;
  117     fd = -1;
  118 
  119     struct stat statbuf;
  120     if (stat (f, &statbuf) == -1) return;
  121     len = statbuf.st_size;
  122     if (len == -1 || (fd = open (f, O_RDONLY)) == -1) return;
  123 
  124     data = (char*) malloc (len);
  125     success = read (fd, data, len) == len ? ZC_OK : ZC_FF;
  126 }
  127 
  128 load_file::~load_file ()
  129 {
  130     if (data) free (data);
  131     if (fd != -1) close (fd);
  132 }
  133 
  134 #endif
  135 // "st1.mod"
  136 //
  137 // Symbol tree
  138 //
  139 
  140 class symNode : public dbsNodeStr
  141 {
  142    public:
  143     symNode *less, *more;
  144     unsigned int i;
  145     symNode ();
  146     ~symNode ();
  147 };
  148 
  149 static dbsTree<symNode> symTree;
  150 static unsigned int nsym = 1;
  151 
  152 symNode::symNode () : dbsNodeStr ()
  153 {
  154     symTree.addself (this);
  155     i = nsym++;
  156 }
  157 
  158 symNode::~symNode ()
  159 {
  160     if (less) delete less;
  161     if (more) delete more;
  162 }
  163 
  164 unsigned int enter_symbol (char *sy)
  165 {
  166     DBS_STRQUERY = sy;
  167     symNode *s = (symNode*) symTree.dbsFind ();
  168     if (!s) {
  169         DBS_STRQUERY = strDup (DBS_STRQUERY);
  170         s = new symNode;
  171         progress ();
  172     }
  173     return s->i;
  174 }
  175 //
  176 // Hyper nodes
  177 //
  178 
  179 class hyperNode : public intNode
  180 {
  181    public:
  182     void settle ();
  183     intTree itree;
  184     unsigned int *rel;
  185     hyperNode ();
  186     void relates (unsigned int);
  187     void rsettle ();
  188 };
  189 
  190 static intTree hyperTree;
  191 
  192 hyperNode::hyperNode () : intNode (&hyperTree)
  193 { }
  194 
  195 #define SOURCE_ID   0
  196 #define STRUCT_ID   1
  197 #define CALLER_ID   2
  198 #define GLOBAL_ID   3
  199 #define CALL_ID     4
  200 #define MEMBER_ID   5
  201 #define NFIELDS     6
  202 #define RECURS_BOOST    7   /* color */
  203 
  204 #define BASE        (1000*1000)
  205 #define SOURCE_BASE (SOURCE_ID * BASE)
  206 #define CALLER_BASE (CALLER_ID * BASE)
  207 #define GLOBAL_BASE (GLOBAL_ID * BASE)
  208 #define CALL_BASE   (CALL_ID * BASE)
  209 #define STRUCT_BASE (STRUCT_ID * BASE)
  210 #define MEMBER_BASE (MEMBER_ID * BASE)
  211 #define FIELD_BASE  (NFIELDS * BASE)
  212 #define RECURS_BASE (RECURS_BOOST * BASE)
  213 
  214 static unsigned int symbol_of (unsigned int i)
  215 {
  216     return i % BASE;
  217 }
  218 
  219 static unsigned int base_of (unsigned int i)
  220 {
  221     return i / BASE;
  222 }
  223 
  224 unsigned int counts [NFIELDS], dupes;
  225 
  226 void hyperNode::relates (unsigned int y)
  227 {
  228     if (!itree.intFind (y)) new intNode (&itree);
  229     else if (base_of (y) != STRUCT_ID && base_of (Key) != STRUCT_ID)
  230         dupes++;
  231 }
  232 
  233 static void relate (int x, int y)
  234 {
  235     hyperNode *h = (hyperNode*) hyperTree.intFind (x);
  236 
  237     if (!h) {
  238         h = new hyperNode;
  239         counts [base_of (x)]++;
  240     }
  241     h->relates (y);
  242 }
  243 
  244 static int nlinks = 0;
  245 
  246 static void relative (int x, int y)
  247 {
  248     ++nlinks;
  249     relate (base_of (x) == CALLER_ID ? x - CALLER_BASE + CALL_BASE : x, y);
  250     relate (base_of (y) == CALLER_ID ? y - CALLER_BASE + CALL_BASE : y, x);
  251 }
  252 // "repl.mod"
  253 //
  254 // macro replacements
  255 //
  256 
  257 static struct repl_s {
  258     unsigned int r, f;
  259 } * replarr;
  260 
  261 static unsigned int nreplarr, areplarr;
  262 
  263 static void stor_replacement (unsigned int r, unsigned int f)
  264 {
  265     if (nreplarr == areplarr)
  266         replarr = (repl_s*) realloc (replarr, sizeof (repl_s) * (areplarr += 64));
  267     replarr [nreplarr].r = r;
  268     replarr [nreplarr++].f = f;
  269 }
  270 
  271 static void repl_line (char *l)
  272 {
  273     char *d = strchr (l, ' ');
  274 
  275     if (d) {
  276         *d = 0;
  277         stor_replacement (enter_symbol (l) + CALL_BASE, enter_symbol (d + 1) + CALL_BASE);
  278     }
  279 }
  280 
  281 void do_replacements ()
  282 {
  283     unsigned int i, j, k, nu = 0, *un = (unsigned int*) alloca (sizeof * un * nreplarr);
  284     hyperNode **hns = (hyperNode**) alloca (sizeof * hns * nreplarr);
  285 
  286     for (i = 0; i < nreplarr; i++) {
  287         for (j = 0; j < nu; j++)
  288             if (un [j] == replarr [i].r) break;
  289         if (j < nu) continue;
  290         un [nu++] = replarr [i].r;
  291         hyperNode *h = hns [j] = (hyperNode*) hyperTree.intFind (replarr [i].r);
  292         if (!h) continue;
  293         h->settle ();
  294         for (j = 0; j < (unsigned int) h->itree.cnt; j++) {
  295             hyperNode *h2 = (hyperNode*) hyperTree.intFind (h->rel [j] - CALLER_BASE + CALL_BASE);
  296             intNode *n = h2->itree.intFind (replarr [i].r);
  297             if (n) {
  298                 n->intRemove (&h2->itree);
  299                 delete n;
  300             }
  301         }
  302         h->intRemove (&hyperTree);
  303     }
  304 
  305     for (i = 0; i < nreplarr; i++) {
  306         for (j = 0; j < nu; j++)
  307             if (un [j] == replarr [i].f) break;
  308         if (j < nu) {
  309             unsigned int l, m;
  310             k = replarr [i].f;
  311             for (j = 0; un [j] != replarr [i].r; j++);
  312             for (l = 0; l < nreplarr; l++)
  313                 if (replarr [l].r == k) {
  314                     for (m = 0; m < nu; m++)
  315                         if (un [m] == replarr [l].f) break;
  316                     if (m < nu) continue;
  317                     if (hns [j]) for (m = 0; (int) m < hns [j]->itree.cnt; m++)
  318                         relative (hns [j]->rel [m], replarr [l].f);
  319                 }
  320             continue;
  321         }
  322         for (j = 0; un [j] != replarr [i].r; j++);
  323         if (hns [j]) for (k = 0; (int) k < hns [j]->itree.cnt; k++)
  324             relative (hns [j]->rel [k], replarr [i].f);
  325     }
  326 }
  327 // "ln.mod"
  328 //
  329 // Line numbers
  330 //
  331 
  332 struct file_chunk {
  333     unsigned int start, end;
  334 } NoChunk = { ~0, ~0 };
  335 
  336 class lnnode : public intNode
  337 {
  338    public:
  339     file_chunk line;
  340     lnnode (unsigned int, unsigned int);
  341 };
  342 
  343 static intTree lnTree;
  344 
  345 lnnode::lnnode (unsigned int l, unsigned int e) : intNode (&lnTree)
  346 {
  347     line.start = l;
  348     line.end = e;
  349 }
  350 
  351 static void enter_line (unsigned int f, unsigned int l, unsigned int e)
  352 {
  353     if (!lnTree.intFind (f)) new lnnode (l, e);
  354 }
  355 
  356 file_chunk line_of (unsigned int f)
  357 {
  358     lnnode *l = (lnnode*) lnTree.intFind (f);
  359     return (l) ? l->line : NoChunk;
  360 }
  361 // "agr.mod"
  362 //
  363 // Make structure -> members link
  364 //
  365 
  366 void struct_fp_link (char *s)
  367 {
  368     char *dot, ss [100];
  369 
  370     if (!(dot = strchr (s, '.'))) return;
  371     *dot = 0; strcpy (ss, s+1); *dot = '.';
  372     relative (CALL_BASE + enter_symbol (s),
  373           STRUCT_BASE + enter_symbol (ss));
  374 }
  375 
  376 void struct_link (char *s)
  377 {
  378     char *dot, ss [100];
  379 
  380     if (!(dot = strchr (s, '.'))) return;
  381     *dot = 0; strcpy (ss, s); *dot = '.';
  382     relative (MEMBER_BASE + enter_symbol (s),
  383           STRUCT_BASE + enter_symbol (ss));
  384 }
  385 //
  386 // Structure line numbers
  387 //
  388 
  389 void struct_loc (char *s)
  390 {
  391     char *p;
  392 
  393     if (!(p = strchr (s, ' ')))
  394         return;
  395     *p++ = 0;
  396     enter_line (enter_symbol (s) + STRUCT_BASE, atoi (p), atoi (strchr (p, ' ')));
  397 }
  398 //
  399 // Symbol Table
  400 //
  401 
  402 static struct st_entry {
  403     char *name;
  404     int weight;
  405 } *symbol_table;
  406 
  407 static void totable (symNode *s)
  408 {
  409 static  int order = 0;
  410     symbol_table [s->i].name = s->Name;
  411     symbol_table [s->i].weight = order++;
  412 }
  413 
  414 void make_symbol_table ()
  415 {
  416     symbol_table = new st_entry [nsym];
  417     symTree.foreach (totable);
  418     delete symTree.root;
  419 }
  420 
  421 static int weight (unsigned int i)
  422 {
  423     return symbol_table [symbol_of (i)].weight;
  424 }
  425 
  426 static char *symbol_name (unsigned int i)
  427 {
  428     return symbol_table [symbol_of (i)].name;
  429 }
  430 // "hns.mod"
  431 //
  432 // Settle hypernodes
  433 //
  434 
  435 static unsigned int *tmp_table;
  436 
  437 class enter_intnodes : public foreach_intNode
  438 {
  439     void A (intNode *i) {
  440         *tmp_table++ = i->Key;
  441     }
  442    public:
  443     enter_intnodes (intTree *I) { if (I->root) inorder (I->root); }
  444 };
  445 
  446 void hyperNode::settle ()
  447 {
  448     if (!itree.root)
  449         return;
  450     tmp_table = rel = new unsigned int [itree.cnt];
  451     enter_intnodes E (&itree);
  452     SHUT_UP_GCC (E)
  453     delete itree.root;
  454 }
  455 
  456 class hyper_settle : public foreach_intNode
  457 {
  458    protected:
  459     void A (intNode *i) {
  460         ((hyperNode*)i)->settle ();
  461     }
  462    public:
  463     hyper_settle () { inorder (hyperTree.root); }
  464 };
  465 
  466 void settle_hyperNodes ()
  467 {
  468     hyper_settle H;
  469     SHUT_UP_GCC (H)
  470 }
  471 //
  472 // Sort symbol indexes
  473 //
  474 
  475 static void swap (unsigned int v[], int i, int j)
  476 {
  477     unsigned int swp = v [i];
  478     v [i] = v [j];
  479     v [j] = swp;
  480 }
  481 
  482 void qsort (unsigned int v[], int left, int right)
  483 {
  484     int i, last, wleft;
  485 
  486     if (left >= right)
  487         return;
  488     swap (v, left, (left+right)/2);
  489     wleft = weight (v [left]);
  490     last = left;
  491     for (i = left+1; i <= right; i++)
  492         if (weight (v [i]) < wleft)
  493             swap (v, i, ++last);
  494     swap (v, last, left);
  495     qsort (v, left, last-1);
  496     qsort (v, last+1, right);
  497 }
  498 
  499 void sort_fields (unsigned int v [], int n)
  500 {
  501     int i, j, k;
  502     struct {
  503         unsigned int *v;
  504         int n;
  505     } field [NFIELDS];
  506 
  507     for (i = 0; i < NFIELDS; i++) {
  508         field [i].v = (unsigned int*) alloca (n * sizeof (int));
  509         field [i].n = 0;
  510     }
  511 
  512     for (i = 0; i < n; i++)
  513         field [base_of (v [i])].v [field [base_of (v [i])].n++] = v [i];
  514 
  515     for (j = i = 0; i < NFIELDS; i++) {
  516         if (field [i].n > 1)
  517             qsort (field [i].v, 0, field [i].n - 1);
  518         for (k = 0; k < field [i].n; k++)
  519             v [j++] = field [i].v [k];
  520     }
  521 }
  522 // "ia.mod"
  523 //
  524 // Staring tables
  525 //
  526 
  527 class hyper_gets : public foreach_intNode
  528 {
  529     void A (intNode*);
  530    public:
  531     unsigned int nfiles, nfuncs;
  532     hyper_gets ();
  533 };
  534 
  535 unsigned int *Files, *funcs, *entries, nentries, *globals, nglobals;
  536 
  537 static bool has_callers (hyperNode *h)
  538 {
  539     int i;
  540     for (i = 0; i < h->itree.cnt; i++)
  541         if (base_of (h->rel [i]) == CALLER_ID
  542         // recursive callers of self, do not count
  543         && symbol_of (h->rel [i]) != symbol_of (h->Key))
  544             return true;
  545     return false;
  546 }
  547 
  548 void hyper_gets::A (intNode *i)
  549 {
  550     hyperNode *h = (hyperNode*) i;
  551 
  552     switch (base_of (h->Key)) {
  553         case SOURCE_ID: Files [nfiles++] = h->Key; break;
  554         case GLOBAL_ID: globals [nglobals++] = h->Key; break;
  555         case CALL_ID: funcs [nfuncs++] = h->Key;
  556             if (!has_callers (h)) nentries++; break;
  557     }
  558 }
  559 
  560 hyper_gets::hyper_gets ()
  561 {
  562     nglobals = nfiles = nfuncs = nentries = 0;
  563     inorder (hyperTree.root);
  564     counts [CALL_ID] = nfuncs;
  565 }
  566 
  567 void starting_tables ()
  568 {
  569     unsigned int i, j;
  570     Files = new unsigned int [counts [SOURCE_ID]];
  571     funcs = new unsigned int [counts [CALL_ID]];
  572     globals = new unsigned int [counts [GLOBAL_ID]];
  573     hyper_gets H;
  574     SHUT_UP_GCC (H);
  575     entries = new unsigned int [nentries];
  576     for (i = j = 0; i < counts [CALL_ID]; i++)
  577         if (!has_callers ((hyperNode*) hyperTree.intFind (funcs [i])))
  578             entries [j++] = funcs [i];
  579     qsort (Files, 0, counts [SOURCE_ID] - 1);
  580     qsort (funcs, 0, counts [CALL_ID] - 1);
  581     qsort (globals, 0, counts [GLOBAL_ID] - 1);
  582     qsort (entries, 0, nentries - 1);
  583 }
  584 // "pf.mod"
  585 //
  586 // Parse File
  587 //
  588 
  589 void linenumber (char *s)
  590 {
  591     char *f;
  592     if (!(f = strchr (s, ' ')))
  593         return;
  594     *f++ = 0;
  595     enter_line (enter_symbol (s) + CALL_BASE, atoi (f), atoi (strchr (f, ' ')));
  596 }
  597 
  598 #define FMT_CALLER  'D'
  599 #define FMT_CALL    'F'
  600 #define FMT_SOURCE  'P'
  601 #define FMT_GLOBAL  'g'
  602 #define FMT_GLOBALw 'G'
  603 #define FMT_STRUCT  's'
  604 #define FMT_STRUCTw 'S'
  605 #define FMT_LINE    'L'
  606 #define FMT_SLINE   'Y'
  607 #define FMT_REPL    'R'
  608 
  609 static bool wrt;
  610 
  611 unsigned int parse_line (char *l)
  612 {
  613     int base;
  614     char tmp [1000];
  615 
  616     wrt = false;
  617 
  618     switch (l [0]) {
  619         case FMT_LINE:   base = CALL_BASE;
  620                  linenumber (l+3);  break;
  621         case FMT_CALLER: base = CALLER_BASE;    break;
  622         case FMT_CALL:   base = CALL_BASE;
  623                  if (l[3] == '*')
  624                  struct_fp_link (l+3);  break;
  625         case FMT_SOURCE: base = SOURCE_BASE;
  626                  if (!strncmp (CWD, l + 3, strlen (CWD)))
  627                  strcpy (l + 3, strcpy (tmp, l + 3 + strlen (CWD)));
  628                             break;
  629         case FMT_GLOBALw: wrt = true;
  630         case FMT_GLOBAL: base = GLOBAL_BASE;    break;
  631         case FMT_STRUCTw: wrt = true;
  632         case FMT_STRUCT: base = MEMBER_BASE;
  633                  struct_link (l+3); break;
  634         case FMT_SLINE:  base = STRUCT_BASE;
  635                  struct_loc (l + 3);    break;
  636         case FMT_REPL:   repl_line (l + 3); return ~0;
  637         default: return ~0;
  638     }
  639 
  640     return base + enter_symbol (l + 3);
  641 }
  642 
  643 #define MLINE 512
  644 void parse_file (FILE *f)
  645 {
  646 static  int dfunc = 0;
  647     int h;
  648     char line [MLINE];
  649 
  650 
  651     while (fgets (line, MLINE, f)) {
  652         line [strlen (line) - 1] = 0;
  653         if ((h = parse_line (line)) == ~0) continue;
  654         if (base_of (h) == CALLER_ID || base_of (h) == SOURCE_ID)
  655             dfunc = h;
  656         else relative (wrt ? dfunc - CALLER_BASE + CALL_BASE : dfunc, h);
  657     }
  658 }
  659 
  660 void read_file (char *p)
  661 {
  662     FILE *f = fopen (p, "r");
  663 
  664     if (!f) {
  665         printf ("No such file [%s]\n", p);
  666         exit (1);
  667     }
  668     parse_file (f);
  669     fclose (f);
  670     if (!hyperTree.root) {
  671         printf ("File [%s] empty\n", p);
  672         exit (0);
  673     }
  674     aprogress ();
  675     make_symbol_table ();
  676     aprogress ();
  677     do_replacements ();
  678     aprogress ();
  679     settle_hyperNodes ();
  680     aprogress ();
  681     starting_tables ();
  682 }
  683 //
  684 // Get Relations of Link
  685 //
  686 
  687 struct linker {
  688     unsigned int tn, *t;
  689     linker (unsigned int, bool = true);
  690 };
  691 
  692 linker::linker (unsigned int i, bool dosort)
  693 {
  694     hyperNode *h = (hyperNode*) hyperTree.intFind (i);
  695     if (dosort) sort_fields (t = h->rel, tn = h->itree.cnt);
  696     else t = h->rel, tn = h->itree.cnt;
  697 }
  698 // "recur.mod"
  699 //
  700 // Recursion detection
  701 //
  702 
  703 class recursion_detector
  704 {
  705     unsigned int caller;
  706     bool check_in (unsigned int);
  707    public:
  708     recursion_detector (unsigned int, unsigned int);
  709     unsigned int *visited;
  710     bool indeed;
  711     ~recursion_detector ();
  712 };
  713 
  714 bool recursion_detector::check_in (unsigned int c)
  715 {
  716     hyperNode *h = (hyperNode*) hyperTree.intFind (c);
  717     unsigned int cs = symbol_of (c);
  718     unsigned int *t = h->rel;
  719     unsigned int tn = h->itree.cnt;
  720     unsigned int i;
  721 
  722     for (i = 0; i < tn; i++)
  723         if (base_of (t [i]) == CALL_ID) {
  724             unsigned int s = symbol_of (t [i]);
  725             if (s == caller) {
  726                 visited [caller] = cs;
  727                 return true;
  728             } else if (!visited [s]) {
  729                 visited [s] = cs;
  730                 if (check_in (t [i])) return true;
  731             }
  732         }
  733     return false;
  734 }
  735 
  736 recursion_detector::recursion_detector (unsigned int ca, unsigned ch)
  737 {
  738     visited = (unsigned int*) calloc (nsym, sizeof (int));
  739     caller = symbol_of (ca);
  740     visited [symbol_of (ch)] = caller;
  741 
  742     indeed = check_in (ch);
  743 }
  744 
  745 recursion_detector::~recursion_detector ()
  746 {
  747     free (visited);
  748 }
  749 
  750 bool is_recursive (unsigned int caller, unsigned int child)
  751 {
  752     recursion_detector RD (caller, child);
  753     return RD.indeed;
  754 }
  755 //
  756 // make recursion path
  757 //
  758 
  759 struct recursion_path
  760 {
  761     unsigned int *path;
  762     unsigned int n;
  763     recursion_path (unsigned int, unsigned int);
  764     ~recursion_path ();
  765 };
  766 
  767 recursion_path::recursion_path (unsigned int caller, unsigned int child)
  768 {
  769     recursion_detector RD (caller, child);
  770 
  771     if (RD.indeed) {
  772         unsigned int cs = symbol_of (caller);
  773         unsigned int i, cnt;
  774 
  775         for (cnt = 2, i = RD.visited [cs]; i != cs; i = RD.visited [i])
  776             ++cnt;
  777         n = cnt;
  778         path = (unsigned int*) malloc (sizeof (int) * cnt);
  779         path [n-1] = cs + CALL_BASE;
  780         for (cnt = 1, i = RD.visited [cs]; i != cs; i = RD.visited [i])
  781             path [n-1-cnt++] = i + CALL_BASE;
  782         path [n-1-cnt++] = i + CALLER_BASE;
  783         n = cnt;
  784     } else path = 0;
  785 }
  786 
  787 recursion_path::~recursion_path ()
  788 {
  789     if (path) free (path);
  790 }
  791 // "grf.mod"
  792 //
  793 // Graphics
  794 //
  795 
  796 unsigned int scr_x, scr_y;
  797 
  798 enum APP_COLOR {
  799     BLACK, HIGHLIGHT, C_UP1, C_UP2, C_UP3, NORMAL, C_DOWN1,
  800     C_DOWN2, C_DOWN3, C_DOWN4, OTHER
  801 };
  802 
  803 enum ecol {
  804     WHITE, BLUE, RED, GREEN, YELLOW, CYAN, MAGENTA
  805 };
  806 
  807 int Gcolor (APP_COLOR a)
  808 {
  809     switch (a) {
  810     case HIGHLIGHT: return COLOR_PAIR(WHITE)|A_BOLD;
  811     case C_UP1: return COLOR_PAIR (BLUE);
  812     case C_UP2: return COLOR_PAIR (BLUE)|A_BOLD;
  813     case C_UP3: return COLOR_PAIR (RED);
  814     case NORMAL:    return COLOR_PAIR(WHITE);
  815     case C_DOWN1:   return COLOR_PAIR(YELLOW)|A_DIM;
  816     case C_DOWN2:   return COLOR_PAIR(WHITE)|A_DIM;
  817     case C_DOWN3:   return COLOR_PAIR (CYAN);
  818     case C_DOWN4:   return COLOR_PAIR(WHITE)|A_DIM;
  819     default:
  820     case OTHER: return COLOR_PAIR(MAGENTA);
  821     }
  822 }
  823 
  824 void printstr (int x, int y, char *s, APP_COLOR a)
  825 {
  826     attrset (Gcolor (a));
  827     move (y, x);
  828     /* unfortunatelly, there's a bug in ncurses and
  829        addnstr (s, -1); counts tabs as 1 character
  830        with the result that long lines go past the end
  831        of the scr_x and appear on the next line
  832      */
  833     unsigned int i;
  834     char *p;
  835     for (i = x, p = s; i < scr_x && *p; p++)
  836         if (*p == '\t') i += 8;
  837         else i++;
  838     if (!*p) printw ("%s", s);
  839     else {
  840         char tmp [256];
  841         strncpy (tmp, s, p - s);
  842         tmp [p - s] = 0;
  843         printw ("%s", tmp);
  844     }
  845 }
  846 
  847 void cls ()
  848 {
  849     clear ();
  850 }
  851 
  852 int inkey ()
  853 {
  854     return getch ();
  855 }
  856 
  857 // Init modes
  858 
  859 void init_ncurses ()
  860 {
  861     initscr ();
  862     //leaveok (stdscr, true);
  863     start_color ();
  864     init_pair (BLUE, COLOR_BLUE, COLOR_BLACK);
  865     init_pair (RED, COLOR_RED, COLOR_BLACK);
  866     init_pair (GREEN, COLOR_GREEN, COLOR_BLACK);
  867     init_pair (YELLOW, COLOR_YELLOW, COLOR_BLACK);
  868     init_pair (CYAN, COLOR_CYAN, COLOR_BLACK);
  869     init_pair (MAGENTA, COLOR_MAGENTA, COLOR_BLACK);
  870     crmode ();
  871     keypad (stdscr, TRUE);
  872     noecho ();
  873     scr_x = COLS;
  874     scr_y = LINES-1;
  875 }
  876 
  877 void init_graphics ()
  878 {
  879     init_ncurses ();
  880 }
  881 
  882 void end_graphics ()
  883 {
  884     flash ();
  885     endwin ();
  886 }
  887 //
  888 // Text entry display
  889 //
  890 
  891 static bool has_calls (unsigned int i)
  892 {
  893     hyperNode *h = (hyperNode*) hyperTree.intFind (i);
  894     unsigned int *a = h->rel, j = h->itree.cnt;
  895 
  896     for (i = 0; i < j; i++)
  897         if (base_of (a [i]) == CALL_ID) return true;
  898     return false;
  899 }
  900 
  901 static bool has_file (unsigned int i)
  902 {
  903     hyperNode *h = (hyperNode*) hyperTree.intFind (i);
  904     unsigned int *a = h->rel, j = h->itree.cnt;
  905 
  906     for (i = 0; i < j; i++)
  907         if (base_of (a [i]) == SOURCE_ID) return true;
  908     return false;
  909 }
  910 
  911 APP_COLOR colors (unsigned int v)
  912 {
  913     switch (base_of (v)) {
  914     case SOURCE_ID: return C_UP1;
  915     case CALLER_ID: return C_UP2;
  916     case MEMBER_ID: return C_DOWN4;
  917     case GLOBAL_ID: return C_UP3;
  918     case NFIELDS:   return OTHER;
  919     case CALL_ID:   return !has_file (v) ? C_DOWN3 :
  920                    has_calls (v) ? C_DOWN1 : C_DOWN2;
  921     case RECURS_BOOST: return C_UP3;
  922     }
  923     return OTHER;
  924 }
  925 
  926 void printent (int x, int y, unsigned int e, unsigned int m, bool hi)
  927 {
  928     char trunc [180], *dot;
  929     char *s = symbol_name (e);
  930 
  931     if (strlen (s) > m)
  932         if (strchr (s, '/'))
  933             s = strcpy (trunc, strrchr (s, '/'));
  934         else
  935             s = strcpy (trunc, s + strlen (s) - m);
  936     printstr (x, y, s, hi ? HIGHLIGHT : colors (e));
  937     if ((dot = strchr (s, '.')))
  938         printstr (x + (dot - s), y, ".", NORMAL);
  939 }
  940 // "vscr.mod"
  941 //
  942 // a screenful
  943 //
  944 
  945 class nvscr {
  946    public:
  947 static  int jump_node;
  948     int ii;
  949     nvscr *next, *prev;
  950 virtual void vdraw () = 0;
  951 } *nvtop;
  952 
  953 int nvscr::jump_node;
  954 
  955 // "tdm.mod"
  956 //
  957 // Map with ncurses
  958 //
  959 
  960 struct coords {
  961     unsigned int x, y;
  962 };
  963 
  964 class TDmap : public nvscr {
  965     unsigned int epl, eps, e_spc;
  966     unsigned int *vmap, e_tot, e_cur, e_top, e_topp;
  967     coords locate (unsigned int);
  968     void add_to_list ();
  969    public:
  970     TDmap (unsigned int*, unsigned int, unsigned int, unsigned int=0);
  971     void move_arrow (int);
  972     void move_jump (unsigned int);
  973     void vdraw ()   { draw_map (); }
  974     void draw_map ();
  975     unsigned int enter ();
  976     unsigned int cursor ();
  977 virtual ~TDmap ();
  978 };
  979 
  980 void TDmap::add_to_list ()
  981 {
  982     if ((prev = nvtop)) {
  983         prev->next = this;
  984         ii = prev->ii + 1;
  985     } else ii = 0;
  986     next = 0;
  987     nvtop = this;
  988     jump_node = ii;
  989 }
  990 
  991 TDmap::~TDmap ()
  992 {
  993     if ((nvtop = prev))
  994         nvtop->next = 0;
  995 }
  996 
  997 unsigned int TDmap::enter ()
  998 {
  999     if (base_of (vmap [e_cur]) != RECURS_BOOST)
 1000         return vmap [e_cur];
 1001     return symbol_of (vmap [e_cur]) + CALL_BASE;
 1002 }
 1003 
 1004 unsigned int TDmap::cursor ()
 1005 {
 1006     return e_cur;
 1007 }
 1008 
 1009 void TDmap::move_arrow (int a)
 1010 {
 1011     unsigned int dir = 0, mov;
 1012     switch (a) {
 1013         case KEY_LEFT:  mov = 1, dir = 1; break;
 1014         case KEY_RIGHT: mov = 1; break;
 1015         case KEY_UP:    mov = epl, dir = 1; break;
 1016         case KEY_DOWN:  mov = epl; break;
 1017         case KEY_PPAGE: mov = eps, dir = 1; break;
 1018         case KEY_NPAGE: mov = eps; break;
 1019         default:    return;
 1020     }
 1021 
 1022     if (!dir) {
 1023         if (e_cur+mov < e_tot) e_cur += mov;
 1024         else if (mov == eps)
 1025             while (e_cur + epl < e_tot) e_cur += epl;
 1026         if (e_cur >= e_top + eps) e_top += eps;
 1027     } else {
 1028         e_cur = (e_cur >= mov) ? e_cur - mov : e_cur % epl;
 1029         if (e_cur < e_top) e_top = (e_top > eps) ? e_top - eps : 0;
 1030     }
 1031 }
 1032 
 1033 void TDmap::move_jump (unsigned int i)
 1034 {
 1035     e_cur = i;
 1036     e_top = (i/eps) * eps;
 1037 }
 1038 
 1039 coords TDmap::locate (unsigned int i)
 1040 {
 1041     coords r;
 1042     r.x = e_spc * (i % epl);
 1043     r.y = (i - e_top) / epl;
 1044     return r;
 1045 }
 1046 
 1047 void TDmap::draw_map ()
 1048 {
 1049     unsigned int i;
 1050     coords xy;
 1051 
 1052     if (e_topp != e_top) {
 1053         e_topp = e_top;
 1054         cls ();
 1055     }
 1056     for (i = e_top; i < e_top+eps && i < e_tot; i++) {
 1057         xy = locate (i);
 1058         printent (xy.x, xy.y, vmap [i], e_spc-1, false);
 1059     }
 1060     xy = locate (e_cur);
 1061     printent (xy.x, xy.y, vmap [e_cur], e_spc-1, true);
 1062 }
 1063 
 1064 unsigned int fieldlen (unsigned int *v, unsigned int n)
 1065 {
 1066     unsigned int i, ml;
 1067 
 1068     for (ml = i = 0; i < n; i++)
 1069         if (strlen (symbol_name (v [i])) > ml)
 1070             ml = strlen (symbol_name (v [i]));
 1071 
 1072     return (ml > scr_x/2) ? scr_x/2 : (ml < 15) ? 15 : ml+1;
 1073 }
 1074 
 1075 TDmap::TDmap (unsigned int *v, unsigned int n, unsigned int c, unsigned int ml)
 1076 {
 1077     if (!ml) ml = fieldlen (v, n);
 1078     e_spc = scr_x/(scr_x/ml);
 1079     vmap = v;
 1080     e_topp = e_tot = n;
 1081     epl = scr_x / e_spc;
 1082     eps = scr_y * epl;
 1083     move_jump (e_cur = c);
 1084     add_to_list ();
 1085 }
 1086 // "tv.mod"
 1087 //
 1088 // text Viewer
 1089 //
 1090 
 1091 #ifndef SOURCE_VIEWER
 1092 
 1093 class txtviewer
 1094 {
 1095     char **line;
 1096     unsigned int nlines, maxline, topline, tab;
 1097     void draw ();
 1098     void scrolll (int);
 1099     void main ();
 1100    public:
 1101     txtviewer (char*, char*, unsigned int);
 1102 };
 1103 
 1104 void txtviewer::draw ()
 1105 {
 1106     unsigned int i;
 1107     cls ();
 1108     for (i = topline; i < nlines && i < topline+scr_y; i++) {
 1109         if (strlen (line [i]) <= tab) continue;
 1110         printstr (0, i-topline, line [i]+tab, NORMAL);
 1111     }
 1112 }
 1113 
 1114 void txtviewer::scrolll (int key)
 1115 {
 1116     unsigned int tlp = topline, tbp = tab;
 1117     switch (key) {
 1118     case KEY_UP:
 1119         if (topline > 0) topline--;
 1120         break;
 1121     case KEY_DOWN:
 1122         if (topline + scr_y < nlines) topline++;
 1123         break;
 1124     case KEY_LEFT:
 1125         if (tab) tab--;
 1126         break;
 1127     case KEY_RIGHT:
 1128         if (maxline - tab > scr_x/2) tab++;
 1129         break;
 1130     case KEY_PPAGE:
 1131         if (topline) topline = (topline > scr_y) ? topline - scr_y : 0;
 1132         break;
 1133     case KEY_NPAGE:
 1134         if (topline + scr_y + 1 < nlines)
 1135             topline += scr_y;
 1136         break;
 1137     default:
 1138         return;
 1139     }
 1140     if (tlp != topline || tbp != tab) draw ();
 1141 }
 1142 
 1143 void txtviewer::main ()
 1144 {
 1145     int key;
 1146     while ((key = inkey ()) != '\n' && key != ' ')
 1147         scrolll (key);
 1148 }
 1149 
 1150 txtviewer::txtviewer (char *title, char *txt, unsigned int l)
 1151 {
 1152     nlines = l+1;
 1153     line = (char**) alloca (nlines * sizeof (char*));
 1154     maxline = l = 0;
 1155     line [l++] = title;
 1156     do {
 1157         line [l] = txt;
 1158         if ((txt = strchr (txt, '\n')))
 1159             *txt++ = 0;
 1160         if (strlen (line [l]) > maxline)
 1161             maxline = strlen (line [l]);
 1162     } while (++l < nlines);
 1163     topline = tab = 0;
 1164 
 1165     draw ();
 1166     main ();
 1167 }
 1168 
 1169 #else       /* SOURCE_VIEWER exists */
 1170 
 1171 void source_viewer_fatal ()
 1172 {
 1173     endwin ();
 1174     printf ("ALERT! Failed executing [%s] to display the text.\n"
 1175         " Please recompile nccnav with a different SOURCE_VIEWER value.\n", svr);
 1176     exit (1);
 1177 }
 1178 
 1179 void txtviewer (char *title, char *txt, unsigned int l, bool colored)
 1180 {
 1181     def_prog_mode();        /* Save the tty modes         */
 1182     endwin();           /* End curses mode temporarily    */
 1183     if (colored) {
 1184         unsigned int h = 0, *ip = (unsigned int*) title;
 1185         char *tmpc, cmd [100];
 1186         char tmpname [100];
 1187 
 1188         int i;
 1189         for (i = 0; i < strlen (title) / 4; i++)
 1190             h ^= *ip++;
 1191         sprintf (tmpname, "/tmp/nccnav-tmp%x.c", h);
 1192 
 1193         FILE *f = fopen (tmpc = tmpname, "w");
 1194         fputs (title, f); fputc ('\n', f);
 1195         fputs (txt, f);
 1196         fclose (f);
 1197         sprintf (cmd, COLOR_VIEWER" %s", tmpc);
 1198         system (cmd);
 1199         unlink (tmpc);
 1200     } else {
 1201         FILE *p = popen (svr, "w");
 1202         if (!p) source_viewer_fatal ();
 1203         fputs (title, p); fputc ('\n', p);
 1204         fputs (txt, p);
 1205         fflush (p);
 1206         pclose (p);
 1207     }
 1208     reset_prog_mode();      /* Return to the previous tty mode*/
 1209                     /* stored by def_prog_mode()      */
 1210     refresh();          /* Do refresh() to restore the    */
 1211                     /* Screen contents        */
 1212 }
 1213 
 1214 #endif
 1215 // "vf.mod"
 1216 //
 1217 // Extract text from file
 1218 //
 1219 
 1220 char *text_from (char *f, int l1, int l2)
 1221 {
 1222     load_file L (f);
 1223 
 1224     if (L.success != ZC_OK) return NULL;
 1225 
 1226     int i, cl;
 1227     char *r;
 1228 
 1229     for (i = 0, cl = 1; i <= L.len && cl < l1; i++)
 1230         if (L.data [i] == '\n') cl++;
 1231     if (cl < l1) return NULL;
 1232     l1 = i;
 1233     for (;i < L.len && cl <= l2; i++)
 1234         if (L.data [i] == '\n') cl++;
 1235     if (cl < l2) return NULL;
 1236     l2 = i;
 1237 
 1238     for (i = l1; i && !isspace (L.data [i]); --i);
 1239     l1 = 0;
 1240     for (; i; i--)
 1241         if (L.data [i] == '/' && L.data [i - 1] == '*')
 1242             for (i -= 2; i && (L.data [i] != '/' || L.data [i + 1] != '*'); --i);
 1243         else if (isspace (L.data [i])) continue;
 1244         else {
 1245             cl = i;
 1246             while (i && L.data [i] != '\n') --i;
 1247             for (i += !!i; isspace (L.data [i]); ++i);
 1248             if (L.data [i] != '/' || L.data [i + 1] != '/') {
 1249                 for (l1 = cl + 1; isspace (L.data [l1]); l1++);
 1250                 break;
 1251             }
 1252         }
 1253 
 1254     r = new char [1 + l2 - l1];
 1255     memcpy (r, L.data + l1, l2 - l1);
 1256     r [l2 - l1] = 0;
 1257     return r;
 1258 }
 1259 
 1260 void func_text (unsigned int f, bool color=false)
 1261 {
 1262     char *txt, *title, *fn;
 1263     file_chunk F = line_of (f);
 1264 
 1265     if (F.start == ~0U) return;
 1266     linker L (f);
 1267     fn = symbol_name (L.t [0]);
 1268     txt = text_from (fn, F.start, F.end);
 1269     if (txt) {
 1270         title = (char*) alloca (strlen (fn) + 20);
 1271         sprintf (title, "# %s %u", fn, F.start);
 1272         txtviewer (title, txt, F.end - F.start + 1, color);
 1273         delete [] txt;
 1274     }
 1275 }
 1276 // "file"
 1277 //
 1278 // view entire file
 1279 //
 1280 
 1281 void file_text (unsigned int i, bool color)
 1282 {
 1283 #ifdef SOURCE_VIEWER
 1284     def_prog_mode();        /* Save the tty modes         */
 1285     endwin();           /* End curses mode temporarily    */
 1286     if (color) {
 1287         char tmp [1024];
 1288         strcat (strcpy (tmp, COLOR_VIEWER" "), symbol_name (i));
 1289         system (tmp);
 1290     } else {
 1291         load_file L (symbol_name (i));
 1292 
 1293         if (L.success != ZC_OK) return;
 1294 
 1295         FILE *p = popen (svr, "w");
 1296         if (!p) source_viewer_fatal ();
 1297         fwrite (L.data, 1, L.len, p);
 1298         fflush (p);
 1299         pclose (p);
 1300     }
 1301     reset_prog_mode();      /* Return to the previous tty mode*/
 1302                     /* stored by def_prog_mode()      */
 1303     refresh();          /* Do refresh() to restore the    */
 1304                     /* Screen contents        */
 1305 #endif
 1306 }
 1307 // "pd.mod"
 1308 //
 1309 // pop ups
 1310 //
 1311 
 1312 void pastmode ();
 1313 void enter_othermode (unsigned int);
 1314 class FOO {};
 1315 
 1316 class popup : public nvscr {
 1317     popup *outer;
 1318     unsigned int *ent, nent;
 1319     WINDOW *w;
 1320     unsigned int top, cur, mx, my, dh, dw;
 1321     void add_to_list ();
 1322     void prefresh ();
 1323     void draw ();
 1324     void main ();
 1325    public:
 1326     popup (popup*, unsigned int, unsigned int, unsigned int);
 1327     void vdraw ();
 1328 virtual ~popup ();
 1329 };
 1330 
 1331 void popup::add_to_list ()
 1332 {
 1333     next = 0;
 1334     prev = (outer) ? outer->prev : nvtop;
 1335     prev->next = nvtop = this;
 1336     jump_node = ii = prev->ii + 1;
 1337 }
 1338 
 1339 void popup::prefresh ()
 1340 {
 1341     if (outer) outer->prefresh ();
 1342     else {
 1343         touchwin (stdscr);
 1344         wnoutrefresh (stdscr);
 1345     }
 1346     touchwin (w);
 1347     wnoutrefresh (w);
 1348 }
 1349 
 1350 #define CLEARBOX \
 1351     wclear (w);\
 1352     box (w, 0, 0);
 1353 
 1354 void popup::draw ()
 1355 {
 1356     unsigned int i;
 1357     for (i = 0; i < dh; i++) {
 1358         wattrset (w, Gcolor (i ? colors (ent [top + i]) : C_UP3));
 1359         mvwprintw (w, i, 1, "%s", symbol_name (ent [top + i]));
 1360     }
 1361     wmove (w, cur - top, 1);
 1362     wattrset (w, Gcolor (HIGHLIGHT));
 1363     wprintw (w, "%s", symbol_name (ent [cur]));
 1364     touchwin (w);
 1365     wrefresh (w);
 1366 }
 1367 
 1368 void popup::vdraw ()
 1369 {
 1370     prefresh ();
 1371     doupdate ();
 1372 }
 1373 
 1374 void popup::main ()
 1375 {
 1376     draw ();
 1377     prefresh ();
 1378     for (; ii <= jump_node; draw()) switch (inkey ()) {
 1379         case KEY_DOWN: if (cur < nent - 1)
 1380                 if (++cur == top + dh) {
 1381                     top++;
 1382                     CLEARBOX;
 1383                 }
 1384                 break;
 1385         case KEY_UP: if (cur > 0)
 1386                 if (--cur < top) {
 1387                     top--;
 1388                     CLEARBOX
 1389                 }
 1390                 break;
 1391         case KEY_PPAGE: cur = top = 0;
 1392                 CLEARBOX
 1393                 break;
 1394         case KEY_NPAGE: if (cur < nent - 1) {
 1395                 if ((cur += 6) >= nent) cur = nent - 1;
 1396                 if (cur >= top + dh) {
 1397                     top = cur - dh;
 1398                     CLEARBOX
 1399                 } }
 1400                 break;
 1401         case KEY_BACKSPACE: throw FOO ();
 1402         case KEY_LEFT:
 1403         case 'q': return;
 1404         case KEY_RIGHT: if (cur == 0) break;
 1405         case '\n': if (!cur) return;
 1406             { popup (this, ent [cur], mx + dw - 4, my + cur - top); }
 1407             vdraw ();
 1408             break;
 1409         case 'v':
 1410             func_text (ent [cur], true);
 1411             break;
 1412         case ' ':
 1413             func_text (ent [cur]);
 1414             cls ();
 1415             vdraw ();
 1416             break;
 1417         case '2': enter_othermode (ent [cur]);
 1418             cls ();
 1419             vdraw ();
 1420             break;
 1421         case '<':
 1422             pastmode ();
 1423             cls ();
 1424             vdraw ();
 1425     }
 1426 }
 1427 
 1428 popup::popup (popup *o, unsigned int f, unsigned int x, unsigned int y)
 1429 {
 1430     linker L (f);
 1431     unsigned int i, j;
 1432 
 1433     for (i = j = 0; i < L.tn; i++)
 1434         if (base_of (L.t [i]) == CALL_ID) j++;
 1435 
 1436     ent = 0;
 1437     if (!j) return;
 1438 
 1439     ent = (unsigned int*) malloc (sizeof (unsigned int) * (nent = j + 1));
 1440     ent [0] = f;
 1441     for (i = 0, j = 1; i < L.tn; i++)
 1442         if (base_of (L.t [i]) == CALL_ID)
 1443             ent [j++] = L.t [i];
 1444 
 1445     if (nent >= scr_y) {
 1446         dh = scr_y - 1;
 1447         my = 0;
 1448     } else {
 1449         dh = nent;
 1450         my = (y + dh >= scr_y) ? 0 : y;
 1451     }
 1452 
 1453     for (i = j = 0; i < nent; i++)
 1454         if ((f = strlen (symbol_name (ent [i]))) > j) j = f;
 1455     dw = j + 2;
 1456     mx = (x + dw >= scr_x) ? 0 : x;
 1457     top = cur = 0;
 1458 
 1459     outer = o;
 1460     w = newwin (dh + 1, dw, my, mx);
 1461     CLEARBOX;
 1462     add_to_list ();
 1463     main ();
 1464 }
 1465 
 1466 popup::~popup ()
 1467 {
 1468     if (ent) {
 1469         (nvtop = prev)->next = 0;
 1470         free (ent);
 1471         delwin (w);
 1472     }
 1473 }
 1474 // "mod.mod"
 1475 //
 1476 // modes
 1477 //
 1478 
 1479 void pastmode ()
 1480 {
 1481     char m [20];
 1482     nvscr *c = nvtop->prev;
 1483     for (;;) {
 1484         cls ();
 1485         sprintf (m, "%i/%i", c->ii, nvtop->ii);
 1486         printstr (0, scr_y, m, HIGHLIGHT);
 1487         c->vdraw ();
 1488         switch (inkey ()) {
 1489             case '<': if (c->prev) c = c->prev; break;
 1490             case '>': if (c->next) c = c->next; break;
 1491             case '\n': c->jump_node = c->ii; return;
 1492             default: nvtop->vdraw (); return;
 1493         }
 1494     }
 1495 }
 1496 
 1497 void othermode (unsigned int);
 1498 
 1499 void recursmode (recursion_path &RP)
 1500 {
 1501     int i;
 1502     TDmap M (RP.path, RP.n, 0, scr_x);
 1503 
 1504     M.draw_map ();
 1505     for (; M.ii <= M.jump_node; M.draw_map ()) {
 1506         printstr (0, scr_y, "Recursion unroll", C_UP2);
 1507         if ((i = inkey ()) == 'q')
 1508             break;
 1509         if (i == '\n') {
 1510             if (M.cursor () == 0) break;
 1511             othermode (M.enter ());
 1512             cls ();
 1513         } else M.move_arrow (i);
 1514     }
 1515 }
 1516 
 1517 void color_recursives (unsigned int caller, unsigned int *pa, int npa)
 1518 {
 1519     int i;
 1520     for (i = 0; i < npa; i++)
 1521         if (base_of (pa [i]) == CALL_ID && is_recursive (caller, pa [i]))
 1522             pa [i] = symbol_of (pa [i]) + RECURS_BASE;
 1523 }
 1524 
 1525 void othermode (unsigned int e)
 1526 {
 1527 static  bool rdetect = true;
 1528 
 1529     int key;
 1530     unsigned int i, j, c, *jarr;
 1531 
 1532     e = base_of (e) == CALLER_ID ? symbol_of (e) + CALL_BASE : e;
 1533     unsigned int tbase = base_of (e);
 1534     linker L (e);
 1535 
 1536     jarr = (unsigned int*) alloca ((L.tn + 1) * sizeof(int));
 1537     i = j = 0;
 1538     while (i < L.tn && base_of (L.t [i]) < CALL_ID)
 1539         jarr [j++] = L.t [i++];
 1540     jarr [c = j++] = e = symbol_of (e) + FIELD_BASE;
 1541     while (i < L.tn)
 1542         jarr [j++] = L.t [i++];
 1543 
 1544     if (rdetect && tbase == CALL_ID)
 1545         color_recursives (e, jarr + c + 1, i - c);
 1546 
 1547     TDmap M (jarr, j, c);
 1548 
 1549     M.draw_map ();
 1550     for (;M.ii <= M.jump_node; M.draw_map ()) {
 1551         if (tbase == CALL_ID && c >= 2 && base_of (jarr [1]) == SOURCE_ID) {
 1552             printstr (0, scr_y, "* FUNCTION IS       :MULTIPLE DEFINITIONS *", HIGHLIGHT);
 1553             printstr (13, scr_y,             " br0ken", C_UP2);
 1554         }
 1555         switch (key = inkey ()) {
 1556         case ' ':
 1557         case 'v':
 1558             j = base_of (M.enter ());
 1559             if (j == CALL_ID) func_text (M.enter (), key == 'v');
 1560             else if (j == CALLER_ID)
 1561                 func_text (symbol_of (M.enter ()) + CALL_BASE, key == 'v');
 1562             else if (j == NFIELDS && tbase == CALL_ID)
 1563                 func_text (symbol_of (M.enter ()) + CALL_BASE, key == 'v');
 1564             else if ((j == SOURCE_ID||(j == NFIELDS&&tbase == SOURCE_ID)))
 1565                 file_text (symbol_of (M.enter ()), key == 'v');
 1566             else if (j == STRUCT_ID || (j == NFIELDS && tbase == STRUCT_ID))
 1567                 func_text (symbol_of (M.enter ()) + STRUCT_BASE, key == 'v');
 1568             else break;
 1569             if (key != '1')
 1570                 cls ();
 1571             break;
 1572         case '\n':
 1573             if (M.enter () == e) return;
 1574             othermode (M.enter ());
 1575             cls ();
 1576             break;
 1577         case KEY_BACKSPACE:
 1578             cls ();
 1579             throw FOO();
 1580         case 'q':
 1581             cls ();
 1582             return;
 1583         case 'r':
 1584             if (base_of (M.enter ()) == CALL_ID) {
 1585                 recursion_path RP (e, M.enter ());
 1586                 if (RP.path) recursmode (RP);
 1587             }
 1588             cls ();
 1589             break;
 1590         case 'R':
 1591             if ((rdetect =! rdetect)) {
 1592                 printstr (0, scr_y, "Recursion Detector ENABLED.", OTHER);
 1593                 color_recursives (e, jarr + c + 1, i - c);
 1594             } else {
 1595                 printstr (0, scr_y, "Recursion Detector DISABLED", C_UP3);
 1596                 for (j = c; j < i+1; j++)
 1597                     if (base_of (jarr [j]) == RECURS_BOOST)
 1598                         jarr [j] -= RECURS_BASE - CALL_BASE;
 1599             }
 1600             break;
 1601         case 'm':
 1602             j = base_of (M.enter ());
 1603             if (j == CALL_ID || j == CALLER_ID || (j == NFIELDS && tbase == CALL_ID))
 1604                 try {
 1605                     j = j == CALL_ID ? M.enter () : symbol_of (M.enter ()) + CALL_BASE;
 1606                     cls ();
 1607                     popup P (0, j, 0, 0);
 1608                 } catch (FOO) { }
 1609             cls ();
 1610             break;
 1611         case '<':
 1612             pastmode ();
 1613             cls ();
 1614             break;
 1615         case 'C':
 1616             // end_graphics ();
 1617             def_prog_mode();        /* Save the tty modes         */
 1618             endwin();           /* End curses mode temporarily    */
 1619             system ("bash");
 1620             reset_prog_mode();      /* Return to the previous tty mode*/
 1621                             /* stored by def_prog_mode()      */
 1622             refresh();          /* Do refresh() to restore the    */
 1623                             /* Screen contents        */
 1624             // init_graphics ();
 1625             break;
 1626         default:
 1627             M.move_arrow (key);
 1628         }
 1629     }
 1630 }
 1631 
 1632 void enter_othermode (unsigned int e)
 1633 {
 1634     try {
 1635         othermode (e);
 1636     } catch (FOO) { }
 1637 }
 1638 
 1639 void globmode ()
 1640 {
 1641     unsigned int *t, tn;
 1642     t = globals, tn = counts [GLOBAL_ID];
 1643 
 1644     int key;
 1645     TDmap M (t, tn, 0);
 1646 
 1647     M.draw_map ();
 1648     for (;;M.draw_map ()) switch (key = inkey ()) {
 1649     case '\n':
 1650         enter_othermode (M.enter ());
 1651         cls ();
 1652         break;
 1653     case KEY_BACKSPACE:
 1654     case 'q':
 1655         return;
 1656     default:
 1657         if (key < 256 && isalpha (key)) {
 1658             unsigned int j = M.cursor ();
 1659             if (*symbol_name (t [j]) < key)
 1660                 while (j < tn
 1661                 && *symbol_name (t [j]) < key)
 1662                     j++;
 1663             else
 1664                 while (j > 0
 1665                 && *symbol_name (t [j]) > key)
 1666                     j--;
 1667             M.move_jump (j);
 1668         } else M.move_arrow (key);
 1669     }
 1670 }
 1671 
 1672 void funcmode (bool all)
 1673 {
 1674     unsigned int *t, tn;
 1675     if (all) t = funcs, tn = counts [CALL_ID];
 1676     else t = entries, tn = nentries;
 1677 
 1678     if (!tn) {
 1679         flash ();
 1680         return;
 1681     }
 1682 
 1683     int key;
 1684     TDmap M (t, tn, 0);
 1685 
 1686     M.draw_map ();
 1687     for (;;M.draw_map ()) switch (key = inkey ()) {
 1688     case '\n':
 1689         enter_othermode (M.enter ());
 1690         cls ();
 1691         break;
 1692     case KEY_BACKSPACE:
 1693     case 'q':
 1694         return;
 1695     case 'v':
 1696         func_text (M.enter (), true);
 1697         cls ();
 1698         break;
 1699     case ' ':
 1700         func_text (M.enter ());
 1701         cls ();
 1702         break;
 1703     default:
 1704         if (key < 256 && isalpha (key)) {
 1705             unsigned int j = M.cursor ();
 1706             if (*symbol_name (t [j]) < key)
 1707                 while (j < tn
 1708                 && *symbol_name (t [j]) < key)
 1709                     j++;
 1710             else
 1711                 while (j > 0
 1712                 && *symbol_name (t [j]) > key)
 1713                     j--;
 1714             M.move_jump (j);
 1715         } else M.move_arrow (key);
 1716     }
 1717 }
 1718 
 1719 void initialmode ()
 1720 {
 1721     int key;
 1722     TDmap M (Files, counts [SOURCE_ID], 0);
 1723 
 1724     M.draw_map ();
 1725     for (;;M.draw_map ()) switch (key = inkey ()) {
 1726         case '\n':
 1727             enter_othermode (M.enter ());
 1728             cls ();
 1729             break;
 1730         case KEY_BACKSPACE:
 1731         case 'q':
 1732             return;
 1733         case 'E':
 1734             funcmode (false);
 1735             cls ();
 1736             break;
 1737         case 'O':
 1738             funcmode (true);
 1739             cls ();
 1740             break;
 1741         case 'g':
 1742         case 'G':
 1743             globmode ();
 1744             cls ();
 1745             break;
 1746         default:
 1747             M.move_arrow (key);
 1748     }
 1749 }
 1750 // "main"
 1751 //
 1752 
 1753 int main (int argc, char **argv)
 1754 {
 1755     getcwd (CWD, sizeof CWD-1);
 1756     if (CWD [strlen (CWD) - 1] != '/')
 1757         strcat (CWD, "/");
 1758 #ifdef  SOURCE_VIEWER
 1759     svr = (char*) ((!strcmp (argv [0], "nccnav")) ? SOURCE_VIEWER : SOURCE_VIEWER_INDENT);
 1760 #endif
 1761     char *MapFile = (argc > 1) ? argv [1] : (char*)"Code.map";
 1762     read_file (MapFile);
 1763     signal (SIGPIPE, SIG_IGN);
 1764     init_graphics ();
 1765     initialmode ();
 1766     end_graphics ();
 1767     printf ("%i\tFilez \n%i\tfunctionz \n%i\tglobal variables \n"
 1768         "%i\tstructs\n%i\tmembers \n%i\tTotal links\n",
 1769         counts [SOURCE_ID], counts [CALL_ID], counts [GLOBAL_ID],
 1770         counts [STRUCT_ID], counts [MEMBER_ID], nlinks - dupes/2);
 1771 }