"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 }