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