1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 #ifdef HAVE_CONFIG_H
30 #include "../config.h"
31 #endif
32
33 #include "tags.h"
34 #include "textBuf.h"
35 #include "text.h"
36 #include "nedit.h"
37 #include "window.h"
38 #include "file.h"
39 #include "preferences.h"
40 #include "search.h"
41 #include "selection.h"
42 #include "calltips.h"
43 #include "../util/DialogF.h"
44 #include "../util/fileUtils.h"
45 #include "../util/misc.h"
46 #include "../util/utils.h"
47 #include "../util/refString.h"
48 #include "../util/nedit_malloc.h"
49
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <ctype.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <unistd.h>
57 #include <sys/param.h>
58
59 #include <Xm/PrimitiveP.h>
60 #include <Xm/Xm.h>
61 #include <Xm/SelectioB.h>
62 #include <X11/Xatom.h>
63
64 #ifdef HAVE_DEBUG_H
65 #include "../debug.h"
66 #endif
67
68 #define MAXLINE 2048
69 #define MAX_TAG_LEN 256
70 #define MAXDUPTAGS 100
71 #define MAX_TAG_INCLUDE_RECURSION_LEVEL 5
72
73
74
75 #define TIP_DEFAULT_LINES 4
76
77 #define STRSAVE(a) (NEditStrdup(a!=
NULL?a:
""))
78
79 typedef struct _tag {
80 struct _tag *next;
81 const char *path;
82 const char *name;
83 const char *file;
84 const char *searchString;
85 int posInf;
86 short language;
87 short index;
88 } tag;
89
90
91
92
93
94
95
96
97 enum searchDirection {
FORWARD,
BACKWARD};
98
99 static int loadTagsFile(
const char *tagSpec,
int index,
int recLevel);
100 static void findDefCB(Widget widget, XtPointer closure, Atom *sel,
101 Atom *type, XtPointer value,
unsigned long *length,
int *format);
102 static void setTag(tag *t,
const char *name,
const char *file,
103 int language,
const char *searchString,
int posInf,
104 const char * tag);
105 static int fakeRegExSearch(WindowInfo *window,
char *buffer,
106 const char *searchString,
int *startPos,
int *endPos);
107 static void updateMenuItems(
void);
108 static int addTag(
const char *name,
const char *file,
int lang,
109 const char *search,
int posInf,
const char *path,
110 int index);
111 static int delTag(
const char *name,
const char *file,
int lang,
112 const char *search,
int posInf,
int index);
113 static tag *getTag(
const char *name,
int search_type);
114 static int findDef(WindowInfo *window,
const char *value,
int search_type);
115 static int findAllMatches(WindowInfo *window,
const char *string);
116 static void findAllCB(Widget parent, XtPointer client_data, XtPointer call_data);
117 static Widget createSelectMenu(Widget parent,
char *label,
int nArgs,
118 char *args[]);
119 static void editTaggedLocation( Widget parent,
int i );
120 static void showMatchingCalltip( Widget parent,
int i );
121
122 static int searchLine(
char *line,
const char *regex);
123 static void rstrip(
char *dst,
const char *src );
124 static int nextTFBlock(
FILE *fp,
char *header,
char **tiptext,
int *lineAt,
125 int *lineNo);
126 static int loadTipsFile(
const char *tipsFile,
int index,
int recLevel);
127
128
129
130 static tag **Tags =
NULL;
131 static unsigned DefTagHashSize = 100000u;
132
133 tagFile *TagsFileList =
NULL;
134
135
136 static tag **Tips =
NULL;
137 tagFile *TipsFileList =
NULL;
138
139
140
141
142 static int searchMode =
TAG;
143 static const char *tagName;
144 static char tagFiles[
MAXDUPTAGS][
MAXPATHLEN];
145 static char tagSearch[
MAXDUPTAGS][
MAXPATHLEN];
146 static int tagPosInf[
MAXDUPTAGS];
147 static Boolean globAnchored;
148 static int globPos;
149 static int globHAlign;
150 static int globVAlign;
151 static int globAlignMode;
152
153
154 static int tagsShowCalltip( WindowInfo *window,
char *text ) {
155 if (text)
156 return ShowCalltip( window, text, globAnchored, globPos, globHAlign,
157 globVAlign, globAlignMode);
158 else
159 return 0;
160 }
161
162
163 static tagFile *setFileListHead(tagFile *t,
int file_type )
164 {
165 if (file_type ==
TAG)
166 TagsFileList = t;
167 else
168 TipsFileList = t;
169 return t;
170 }
171
172
173 static tag *getTag(
const char *name,
int search_type)
174 {
175 static char lastName[
MAXLINE];
176 static tag *t =
NULL;
177 tag **table;
178
179 if (search_type ==
TIP)
180 table = Tips;
181 else
182 table = Tags;
183
184 if (table ==
NULL)
return NULL;
185
186 if (name) {
187 unsigned const addr = StringHashAddr(name) % DefTagHashSize;
188 t = table[addr];
189 strcpy(lastName,name);
190 }
191 else if (t) {
192 name = lastName;
193 t = t->next;
194 }
195 else return NULL;
196
197 for (;t; t = t->next)
198 if (!strcmp(name,t->name))
return t;
199 return NULL;
200 }
201
202
203
204
205 static tag* matchTagRec(tag
const* tpl, tag* bkt)
206 {
207
208
209 tag *t = bkt;
210 for (; t; t = t->next)
211 if ((tpl->language == t->language) && (tpl->posInf == t->posInf) &&
212 (tpl->name == t->name) && (tpl->searchString == t->searchString) &&
213 (tpl->file == t->file))
return t;
214
215 return NULL;
216 }
217
218
219
220
221
222
223
224 static int addTag(
const char *name,
const char *file,
int lang,
225 const char *search,
int posInf,
const char *path,
int index)
226 {
227 char newfile[
MAXPATHLEN];
228 tag **table;
229
230 if (searchMode ==
TIP) {
231 if (Tips ==
NULL)
232 Tips = (tag **)NEditCalloc(DefTagHashSize,
sizeof(tag*));
233 table = Tips;
234 }
else {
235 if (Tags ==
NULL)
236 Tags = (tag **)NEditCalloc(DefTagHashSize,
sizeof(tag*));
237 table = Tags;
238 }
239
240 if (*file ==
'/')
241 strncpy(newfile, file,
MAXPATHLEN);
242 else
243 snprintf(newfile,
MAXPATHLEN,
"%s%s", path, file);
244 newfile[
MAXPATHLEN -
1] =
'\0';
245
246 NormalizePathname(newfile);
247
248 {
249 tag tpl;
250 setTag(&tpl, name, newfile, lang, search, posInf, path);
251
252 {
253 unsigned const addr = StringHashAddr(tpl.name) % DefTagHashSize;
254
255 tag *t = matchTagRec(&tpl, table[addr]);
256 if (t)
257 return 0;
258
259 t = NEditNew(tag);
260 *t = tpl;
261 t->index = index;
262 t->next = table[addr];
263 table[addr] = t;
264 }
265 }
266
267 return 1;
268 }
269
270
271
272
273
274
275
276
277 static int delTag(
const char *name,
const char *file,
int lang,
278 const char *search,
int posInf,
int index)
279 {
280 tag *t, *last;
281 int start,finish,i,del=
0;
282 tag **table;
283
284 if (searchMode ==
TIP)
285 table = Tips;
286 else
287 table = Tags;
288
289 if (table ==
NULL)
return FALSE;
290 if (name)
291 start = finish = StringHashAddr(name) % DefTagHashSize;
292 else {
293 start =
0;
294 finish = DefTagHashSize;
295 }
296
297 for (i = start; i<finish; i++) {
298 for (last =
NULL, t = table[i]; t; last = t, t = t?t->next:table[i]) {
299 if (index && index != t->index)
continue;
300 if (posInf != t->posInf)
continue;
301 if (lang >=
PLAIN_LANGUAGE_MODE && lang != t->language)
continue;
302 if (name && strcmp(name,t->name))
continue;
303 if (file && strcmp(file,t->file))
continue;
304 if (search && strcmp(search,t->searchString))
continue;
305
306 if (last)
307 last->next = t->next;
308 else
309 table[i] = t->next;
310
311 RefStringFree(t->name);
312 RefStringFree(t->file);
313 RefStringFree(t->searchString);
314 RefStringFree(t->path);
315 NEditFree(t);
316 t =
NULL;
317 del++;
318 }
319 }
320 return del>
0;
321 }
322
323
324 static int tagFileIndex =
0;
325
326
327
328
329
330
331 int AddRelTagsFile(
const char *tagSpec,
const char *windowPath,
int file_type)
332 {
333 tagFile *t;
334 int added=
0;
335 struct stat statbuf;
336 char *filename;
337 char pathName[
MAXPATHLEN];
338 char *tmptagSpec;
339 tagFile *FileList;
340
341 searchMode = file_type;
342 if (searchMode ==
TAG)
343 FileList = TagsFileList;
344 else
345 FileList = TipsFileList;
346
347 tmptagSpec = NEditStrdup(tagSpec);
348 for (filename = strtok(tmptagSpec,
":"); filename; filename = strtok(
NULL,
":")){
349 if (*filename ==
'/' || *filename ==
'~')
350 continue;
351 if (windowPath && *windowPath) {
352 strcpy(pathName, windowPath);
353 }
else {
354 strcpy(pathName, GetCurrentDir());
355 }
356 strcat(pathName,
"/");
357 strcat(pathName, filename);
358 NormalizePathname(pathName);
359
360 for (t = FileList; t && strcmp(t->filename, pathName); t = t->next);
361 if (t) {
362 added=
1;
363 continue;
364 }
365 if (stat(pathName, &statbuf) !=
0)
366 continue;
367 t = (tagFile *) NEditMalloc(
sizeof(tagFile));
368 t->filename =
STRSAVE(pathName);
369 t->loaded =
0;
370 t->date = statbuf.st_mtime;
371 t->index = ++tagFileIndex;
372 t->next = FileList;
373 FileList = setFileListHead(t, file_type);
374 added=
1;
375 }
376 NEditFree(tmptagSpec);
377 updateMenuItems();
378 if (added)
379 return TRUE;
380 else
381 return FALSE;
382 }
383
384
385
386
387
388
389
390
391
392
393 int AddTagsFile(
const char *tagSpec,
int file_type)
394 {
395 tagFile *t;
396 int added=
1;
397 struct stat statbuf;
398 char *filename;
399 char pathName[
MAXPATHLEN];
400 char *tmptagSpec;
401 tagFile *FileList;
402
403
404 if (tagSpec ==
NULL) {
405 fprintf(stderr,
"xnedit: Internal Error!\n"
406 " Passed NULL pointer to AddTagsFile!\n");
407 return FALSE;
408 }
409
410 searchMode = file_type;
411 if (searchMode ==
TAG)
412 FileList = TagsFileList;
413 else
414 FileList = TipsFileList;
415
416 tmptagSpec = NEditStrdup(tagSpec);
417 for (filename = strtok(tmptagSpec,
":"); filename; filename = strtok(
NULL,
":")) {
418 if (*filename !=
'/') {
419 strcpy(pathName, GetCurrentDir());
420 strcat(pathName,
"/");
421 strcat(pathName,filename);
422 }
else {
423 strcpy(pathName,filename);
424 }
425 NormalizePathname(pathName);
426
427 for (t = FileList; t && strcmp(t->filename,pathName); t = t->next);
428 if (t) {
429
430
431
432 ++(t->refcount);
433 added=
1;
434 continue;
435 }
436 if (stat(pathName,&statbuf) !=
0) {
437
438 added =
0;
439 continue;
440 }
441 t = (tagFile *) NEditMalloc(
sizeof(tagFile));
442 t->filename =
STRSAVE(pathName);
443 t->loaded =
0;
444 t->date = statbuf.st_mtime;
445 t->index = ++tagFileIndex;
446 t->next = FileList;
447 t->refcount =
1;
448 FileList = setFileListHead(t, file_type );
449 }
450 NEditFree(tmptagSpec);
451 updateMenuItems();
452 if (added)
453 return TRUE;
454 else
455 return FALSE;
456 }
457
458
459
460
461
462
463
464
465 int DeleteTagsFile(
const char *tagSpec,
int file_type, Boolean force_unload)
466 {
467 tagFile *t, *last;
468 tagFile *FileList;
469 char pathName[
MAXPATHLEN], *tmptagSpec, *filename;
470 int removed;
471
472
473 if (tagSpec ==
NULL) {
474 fprintf(stderr,
"xnedit: Internal Error: Passed NULL pointer to DeleteTagsFile!\n");
475 return FALSE;
476 }
477
478 searchMode = file_type;
479 if (searchMode ==
TAG)
480 FileList = TagsFileList;
481 else
482 FileList = TipsFileList;
483
484 tmptagSpec = NEditStrdup(tagSpec);
485 removed=
1;
486 for (filename = strtok(tmptagSpec,
":"); filename;
487 filename = strtok(
NULL,
":")) {
488 if (*filename !=
'/') {
489 strcpy(pathName, GetCurrentDir());
490 strcat(pathName,
"/");
491 strcat(pathName,filename);
492 }
else {
493 strcpy(pathName,filename);
494 }
495 NormalizePathname(pathName);
496
497 for (last=
NULL,t = FileList; t; last = t,t = t->next) {
498 if (strcmp(t->filename, pathName))
499 continue;
500
501 if (searchMode ==
TIP && !force_unload && --t->refcount >
0) {
502 break;
503 }
504 if (t->loaded)
505 delTag(
NULL,
NULL,-
2,
NULL,-
2,t->index);
506 if (last) last->next = t->next;
507 else FileList = setFileListHead(t->next, file_type);
508 NEditFree(t->filename);
509 NEditFree(t);
510 updateMenuItems();
511 break;
512 }
513
514 if (!t)
515 removed =
0;
516 }
517 if (removed)
518 return TRUE;
519 else
520 return FALSE;
521 }
522
523
524
525
526
527 static void updateMenuItems(
void)
528 {
529 WindowInfo *w;
530 Boolean tipStat=
FALSE, tagStat=
FALSE;
531
532 if (TipsFileList) tipStat=
TRUE;
533 if (TagsFileList) tagStat=
TRUE;
534
535 for (w=WindowList; w!=
NULL; w=w->next) {
536 if (!IsTopDocument(w))
537 continue;
538 XtSetSensitive(w->showTipItem, tipStat || tagStat);
539 XtSetSensitive(w->unloadTipsMenuItem, tipStat);
540 XtSetSensitive(w->findDefItem, tagStat);
541 XtSetSensitive(w->unloadTagsMenuItem, tagStat);
542 }
543 }
544
545
546
547
548
549 static int scanCTagsLine(
char *line,
const char *tagPath,
int index)
550 {
551 char *name = line, *searchString =
NULL;
552 char *file =
NULL;
553 char *posTagREEnd =
NULL, *posTagRENull =
NULL;
554 int pos;
555
556
557 if ((*name !=
'!') && (file = strchr(name,
'\t')) !=
NULL)
558 {
559 *file++ =
'\0';
560 if ((searchString = strchr(file,
'\t')) !=
NULL)
561 *searchString++ =
'\0';
562 else return 0;
563 }
564 else return 0;
565
566
567
568
569
570 if(searchString[
0] ==
'/' || searchString[
0] ==
'?') {
571
572 pos=-
1;
573
574
575
576
577
578
579 posTagREEnd = strrchr(searchString,
';');
580 posTagRENull = strchr(searchString,
0);
581 if(!posTagREEnd || (posTagREEnd[
1] !=
'""') ||
582 (posTagRENull[-
1] == searchString[
0])) {
583
584 posTagREEnd = posTagRENull;
585 }
else {
586
587 *posTagREEnd =
0;
588 }
589
590
591
592
593
594
595
596 if(posTagREEnd > (searchString+
2)) {
597 posTagREEnd--;
598 if(searchString[
0] == *posTagREEnd)
599 *posTagREEnd=
0;
600 }
601 }
else {
602 pos=atoi(searchString);
603 *searchString=
0;
604 }
605
606 return addTag(name, file,
PLAIN_LANGUAGE_MODE, searchString, pos, tagPath,
607 index);
608 }
609
610
611
612
613
614
615
616 static int scanETagsLine(
const char *line,
const char * tagPath,
int index,
617 char * file,
int recLevel)
618 {
619 char name[
MAXLINE], searchString[
MAXLINE];
620 char incPath[
MAXPATHLEN];
621 int pos, len;
622 char *posDEL, *posSOH, *posCOM;
623
624
625 if(line[
0]==
12) {
626 *file=
0;
627 return 0;
628 }
629
630
631 posDEL=strchr(line,
'\177');
632 posSOH=strchr(line,
'\001');
633 posCOM=strrchr(line,
',');
634 if(*file && posDEL && (posSOH > posDEL) && (posCOM > posSOH)) {
635
636 len=Min(
MAXLINE-
1, posDEL - line);
637 strncpy(searchString, line, len);
638 searchString[len]=
0;
639 len=Min(
MAXLINE-
1, (posSOH - posDEL) -
1);
640 strncpy(name, posDEL +
1, len);
641 name[len]=
0;
642 pos=atoi(posCOM+
1);
643
644 return addTag(name, file,
PLAIN_LANGUAGE_MODE, searchString, pos,
645 tagPath, index);
646 }
647 if (*file && posDEL && (posCOM > posDEL)) {
648
649 len=Min(
MAXLINE-
1, posDEL - line);
650 strncpy(searchString, line, len);
651 searchString[len]=
0;
652
653 while(--len >=
0) {
654 if( isalnum((
unsigned char)searchString[len]) ||
655 (searchString[len] ==
'_'))
656 break;
657 }
658 if(len<
0)
659 return 0;
660 pos=len;
661 while (pos >=
0 && (isalnum((
unsigned char)searchString[pos]) ||
662 (searchString[pos] ==
'_')))
663 pos--;
664 strncpy(name, searchString + pos +
1, len - pos);
665 name[len - pos] =
0;
666 pos=atoi(posCOM+
1);
667 return addTag(name, file,
PLAIN_LANGUAGE_MODE, searchString, pos,
668 tagPath, index);
669 }
670
671 if(*line && posCOM) {
672 len=Min(
MAXPATHLEN-
1, posCOM - line);
673 strncpy(file, line, len);
674 file[len]=
0;
675
676 if(!(strncmp(posCOM+
1,
"include",
7))) {
677 if(*file !=
'/') {
678 if((strlen(tagPath) + strlen(file)) >=
MAXPATHLEN) {
679 fprintf(stderr,
"tags.c: MAXPATHLEN overflow\n");
680 *file=
0;
681 return 0;
682 }
683 strcpy(incPath, tagPath);
684 strcat(incPath, file);
685 CompressPathname(incPath);
686 return(loadTagsFile(incPath, index, recLevel+
1));
687 }
else {
688 return(loadTagsFile(file, index, recLevel+
1));
689 }
690 }
691 }
692 return 0;
693 }
694
695
696 typedef enum {
697 TFT_CHECK,
TFT_ETAGS,
TFT_CTAGS
698 }
TFT;
699
700
701
702
703
704 static int loadTagsFile(
const char *tagsFile,
int index,
int recLevel)
705 {
706 FILE *fp =
NULL;
707 char line[
MAXLINE];
708 char file[
MAXPATHLEN], tagPath[
MAXPATHLEN];
709 char resolvedTagsFile[
MAXPATHLEN+
1];
710 int nTagsAdded=
0;
711 int tagFileType =
TFT_CHECK;
712
713 if(recLevel >
MAX_TAG_INCLUDE_RECURSION_LEVEL) {
714 return 0;
715 }
716
717
718
719
720 if(!ResolvePath(tagsFile, resolvedTagsFile)) {
721 return 0;
722 }
723
724
725 if ((fp = fopen(resolvedTagsFile,
"r")) ==
NULL) {
726 return 0;
727 }
728
729 ParseFilename(resolvedTagsFile,
NULL, tagPath);
730
731
732 while (fgets(line,
MAXLINE, fp)) {
733
734
735
736
737
738 AllWindowsBusy(
"Loading tags file...");
739
740
741
742
743 if(tagFileType==
TFT_CHECK) {
744 if(line[
0]==
12)
745 tagFileType=
TFT_ETAGS;
746 else
747 tagFileType=
TFT_CTAGS;
748 }
749 if(tagFileType==
TFT_CTAGS) {
750 nTagsAdded += scanCTagsLine(line, tagPath, index);
751 }
else {
752 nTagsAdded += scanETagsLine(line, tagPath, index, file, recLevel);
753 }
754 }
755 fclose(fp);
756
757 AllWindowsUnbusy();
758 return nTagsAdded;
759 }
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774 #define TAG_STS_ERR_FMT "NEdit: Error getting status for tag file %s\n"
775 int LookupTag(
const char *name,
const char **file,
int *language,
776 const char **searchString,
int * pos,
const char **path,
777 int search_type)
778 {
779 tag *t;
780 tagFile *tf;
781 struct stat statbuf;
782 tagFile *FileList;
783 int load_status;
784
785 searchMode = search_type;
786 if (searchMode ==
TIP)
787 FileList = TipsFileList;
788 else
789 FileList = TagsFileList;
790
791
792
793
794
795
796
797
798
799
800
801 for (tf = FileList; tf && name; tf = tf->next) {
802 if (tf->loaded) {
803 if (stat(tf->filename,&statbuf) !=
0) {
804 fprintf(stderr,
TAG_STS_ERR_FMT, tf->filename);
805 }
else {
806 if (tf->date == statbuf.st_mtime) {
807
808 continue;
809 }
810 }
811
812 delTag(
NULL,
NULL,-
2,
NULL,-
2,tf->index);
813 }
814
815 if (FileList == TipsFileList)
816 load_status = loadTipsFile(tf->filename, tf->index,
0);
817 else
818 load_status = loadTagsFile(tf->filename, tf->index,
0);
819 if(load_status) {
820 if (stat(tf->filename,&statbuf) !=
0) {
821 if(!tf->loaded) {
822
823 fprintf(stderr,
TAG_STS_ERR_FMT, tf->filename);
824 }
825 }
else {
826 tf->date = statbuf.st_mtime;
827 }
828 tf->loaded =
1;
829 }
else {
830 tf->loaded =
0;
831 }
832 }
833
834 t = getTag(name, search_type);
835
836 if (!t) {
837 return FALSE;
838 }
else {
839 *file = t->file;
840 *language = t->language;
841 *searchString = t->searchString;
842 *pos = t->posInf;
843 *path = t->path;
844 return TRUE;
845 }
846 }
847
848
849
850
851
852 static int findDef(WindowInfo *window,
const char *value,
int search_type) {
853 static char tagText[
MAX_TAG_LEN +
1];
854 const char *p;
855 char message[
MAX_TAG_LEN+
40];
856 int l, ml, status =
0;
857
858 searchMode = search_type;
859 l = strlen(value);
860 if (l <=
MAX_TAG_LEN) {
861
862 for (p = value; *p && isascii(*p); p++) {
863 }
864 if (!(*p)) {
865 ml = ((l <
MAX_TAG_LEN) ? (l) : (
MAX_TAG_LEN));
866 strncpy(tagText, value, ml);
867 tagText[ml] =
'\0';
868
869 status = findAllMatches(window, tagText);
870
871
872 if (status ==
0 && search_type ==
TIP && TagsFileList !=
NULL) {
873 searchMode =
TIP_FROM_TAG;
874 status = findAllMatches(window, tagText);
875 }
876
877 if (status ==
0) {
878
879 if (searchMode ==
TIP_FROM_TAG || searchMode ==
TIP) {
880 sprintf(message,
"No match for \"%s\" in calltips or tags.",
881 tagName);
882 tagsShowCalltip( window, message );
883 }
else
884 {
885 DialogF(
DF_WARN, window->textArea,
1,
"Tags",
886 "\"%s\" not found in tags file%s",
"OK", tagName,
887 (TagsFileList && TagsFileList->next) ?
"s" :
"");
888 }
889 }
890 }
891 else {
892 fprintf(stderr,
"NEdit: Can''t handle non 8-bit text\n");
893 XBell(TheDisplay,
0);
894 }
895 }
896 else {
897 fprintf(stderr,
"NEdit: Tag Length too long.\n");
898 XBell(TheDisplay,
0);
899 }
900 return status;
901 }
902
903
904
905
906
907
908 static void findDefinitionHelper(WindowInfo *window, Time time,
const char *arg,
909 int search_type)
910 {
911 if(arg)
912 {
913 findDef(window, arg, search_type);
914 }
915 else
916 {
917 searchMode = search_type;
918 XtGetSelectionValue(window->textArea,
XA_PRIMARY,
XA_STRING,
919 findDefCB, window, time);
920 }
921 }
922
923
924
925
926 void FindDefinition(WindowInfo *window, Time time,
const char *arg)
927 {
928 findDefinitionHelper(window, time, arg,
TAG);
929 }
930
931
932
933
934 void FindDefCalltip(WindowInfo *window, Time time,
const char *arg)
935 {
936
937 globAnchored = False;
938 globPos = -
1;
939 globHAlign =
TIP_LEFT;
940 globVAlign =
TIP_BELOW;
941 globAlignMode =
TIP_SLOPPY;
942
943 findDefinitionHelper(window, time, arg,
TIP);
944 }
945
946
947 static void findDefCB(Widget widget, XtPointer closure, Atom *sel,
948 Atom *type, XtPointer v,
unsigned long *length,
int *format)
949 {
950 WindowInfo *window = closure;
951 char *value = v;
952
953
954 if (*type ==
XT_CONVERT_FAIL || value ==
NULL) {
955 XBell(TheDisplay,
0);
956 }
else {
957 findDef(window, value, searchMode);
958 }
959 NEditFree(value);
960 }
961
962
963
964
965
966
967
968
969 int ShowTipString(WindowInfo *window,
char *text, Boolean anchored,
970 int pos, Boolean lookup,
int search_type,
int hAlign,
int vAlign,
971 int alignMode) {
972
973 if (search_type ==
TAG)
return 0;
974
975
976 globAnchored = anchored;
977 globPos = pos;
978 globHAlign = hAlign;
979 globVAlign = vAlign;
980 globAlignMode = alignMode;
981
982
983 if (!lookup)
984 return tagsShowCalltip(window, text);
985 else
986 return findDef(window, text, search_type);
987 }
988
989
990 static void setTag(tag *t,
const char *name,
const char *file,
991 int language,
const char *searchString,
int posInf,
992 const char *path)
993 {
994 t->name = RefStringDup(name);
995 t->file = RefStringDup(file);
996 t->searchString = RefStringDup(searchString);
997 t->path = RefStringDup(path);
998 t->language = language;
999 t->posInf = posInf;
1000 }
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012 static int fakeRegExSearch(WindowInfo *window,
char *in_buffer,
1013 const char *searchString,
int *startPos,
int *endPos)
1014 {
1015 int found, searchStartPos, dir, ctagsMode;
1016 char searchSubs[
3*
MAXLINE+
3], *outPtr;
1017 const char *fileString, *inPtr;
1018
1019 if (in_buffer ==
NULL) {
1020
1021 fileString = BufAsString(window->buffer);
1022 }
else {
1023 fileString = in_buffer;
1024 }
1025
1026
1027 if (*startPos != -
1) {
1028 dir =
SEARCH_FORWARD;
1029 searchStartPos = *startPos;
1030 ctagsMode=
0;
1031 }
else if (searchString[
0] ==
'/') {
1032 dir =
SEARCH_FORWARD;
1033 searchStartPos =
0;
1034 ctagsMode=
1;
1035 }
else if (searchString[
0] ==
'?') {
1036 dir =
SEARCH_BACKWARD;
1037
1038 searchStartPos = strlen(fileString);
1039 ctagsMode=
1;
1040 }
else {
1041 fprintf(stderr,
"NEdit: Error parsing tag file search string");
1042 return FALSE;
1043 }
1044
1045
1046 outPtr=searchSubs;
1047 if(ctagsMode) {
1048 inPtr=searchString+
1;
1049 if(*inPtr ==
'^') {
1050
1051 *outPtr++ = *inPtr++;
1052 }
1053 }
else {
1054 inPtr=searchString;
1055 }
1056 while(*inPtr) {
1057 if( (*inPtr==
'\\' && inPtr[
1]==
'/') ||
1058 (*inPtr==
'\r' && inPtr[
1]==
'$' && !inPtr[
2])
1059 ) {
1060
1061
1062
1063
1064 inPtr++;
1065 }
else if(strchr(
"()-[]<>{}.|^*+?&\\", *inPtr)
1066 || (*inPtr ==
'$' && (inPtr[
1]||(!ctagsMode)))){
1067
1068
1069
1070
1071 *outPtr++ =
'\\';
1072 *outPtr++ = *inPtr++;
1073 }
else if (isspace((
unsigned char)*inPtr)) {
1074 *outPtr++ =
'\\';
1075 *outPtr++ =
's';
1076 *outPtr++ =
'+';
1077 do { inPtr++ ; }
while(isspace((
unsigned char)*inPtr));
1078 }
else {
1079 *outPtr++ = *inPtr++;
1080 }
1081 }
1082 *outPtr=
0;
1083
1084 found = SearchString(fileString, searchSubs, dir,
SEARCH_REGEX,
1085 False, searchStartPos, startPos, endPos,
NULL,
NULL,
NULL);
1086
1087 if(!found && !ctagsMode) {
1088
1089
1090
1091
1092 found = SearchString(fileString, searchSubs,
SEARCH_BACKWARD,
1093 SEARCH_REGEX, False, searchStartPos, startPos, endPos,
NULL,
1094 NULL,
NULL);
1095 }
1096
1097
1098 if (found) {
1099
1100 return TRUE;
1101 }
else {
1102
1103 XBell(TheDisplay,
0);
1104 return FALSE;
1105 }
1106 }
1107
1108
1109
1110
1111 static int findAllMatches(WindowInfo *window,
const char *string)
1112 {
1113 Widget dialogParent = window->textArea;
1114 char filename[
MAXPATHLEN], pathname[
MAXPATHLEN];
1115 char temp[
32+
2*
MAXPATHLEN+
MAXLINE];
1116 const char *fileToSearch, *searchString, *tagPath;
1117 char **dupTagsList;
1118 int startPos, i, pathMatch=
0, samePath=
0, langMode, nMatches=
0;
1119
1120
1121 if (*string ==
'\0' || strlen(string) >
MAX_TAG_LEN) {
1122 XBell(TheDisplay,
0);
1123 return -
1;
1124 }
1125 tagName=string;
1126
1127
1128 while (LookupTag(string, &fileToSearch, &langMode, &searchString, &startPos,
1129 &tagPath, searchMode)) {
1130
1131
1132
1133 if (window->languageMode !=
PLAIN_LANGUAGE_MODE &&
1134 GetPrefSmartTags() && langMode !=
PLAIN_LANGUAGE_MODE &&
1135 langMode != window->languageMode) {
1136 string=
NULL;
1137 continue;
1138 }
1139 if (*fileToSearch ==
'/')
1140 strcpy(tagFiles[nMatches], fileToSearch);
1141 else
1142 sprintf(tagFiles[nMatches],
"%s%s",tagPath,fileToSearch);
1143 strcpy(tagSearch[nMatches],searchString);
1144 tagPosInf[nMatches]=startPos;
1145 ParseFilename(tagFiles[nMatches], filename, pathname);
1146
1147 if (GetPrefSmartTags() && !strcmp(window->filename,filename)
1148 && !strcmp(window->path,pathname) ) {
1149 if (nMatches) {
1150 strcpy(tagFiles[
0],tagFiles[nMatches]);
1151 strcpy(tagSearch[
0],tagSearch[nMatches]);
1152 tagPosInf[
0]=tagPosInf[nMatches];
1153 }
1154 nMatches =
1;
1155 break;
1156 }
1157
1158 if (!strcmp(window->path,pathname)) {
1159 samePath++;
1160 pathMatch=nMatches;
1161 }
1162 if (++nMatches >=
MAXDUPTAGS) {
1163 DialogF(
DF_WARN, dialogParent,
1,
"Tags",
1164 "Too many duplicate tags, first %d shown",
"OK",
MAXDUPTAGS);
1165 break;
1166 }
1167
1168 string =
NULL;
1169 }
1170
1171
1172 if (!nMatches) {
1173 return 0;
1174 }
1175
1176
1177 if (GetPrefSmartTags() && samePath ==
1 && nMatches >
1) {
1178 strcpy(tagFiles[
0],tagFiles[pathMatch]);
1179 strcpy(tagSearch[
0],tagSearch[pathMatch]);
1180 tagPosInf[
0]=tagPosInf[pathMatch];
1181 nMatches =
1;
1182 }
1183
1184
1185
1186 if (GetPrefSmartTags()) {
1187 for (i=
1; i<nMatches; i++)
1188 if (strcmp(tagFiles[i],tagFiles[i-
1]))
1189 break;
1190 if (i==nMatches)
1191 nMatches =
1;
1192 }
1193
1194 if (nMatches>
1) {
1195 if (!(dupTagsList = (
char **) NEditMalloc(
sizeof(
char *) * nMatches))) {
1196 fprintf(stderr,
"xnedit: findAllMatches(): out of heap space!\n");
1197 XBell(TheDisplay,
0);
1198 return -
1;
1199 }
1200
1201 for (i=
0; i<nMatches; i++) {
1202 ParseFilename(tagFiles[i], filename, pathname);
1203 if ((i<nMatches-
1 && !strcmp(tagFiles[i],tagFiles[i+
1])) ||
1204 (i>
0 && !strcmp(tagFiles[i],tagFiles[i-
1]))) {
1205 if(*(tagSearch[i]) && (tagPosInf[i] != -
1)) {
1206 sprintf(temp,
"%2d. %s%s %8i %s", i+
1, pathname,
1207 filename, tagPosInf[i], tagSearch[i]);
1208 }
else if (*(tagSearch[i])) {
1209 sprintf(temp,
"%2d. %s%s %s", i+
1, pathname,
1210 filename, tagSearch[i]);
1211 }
else {
1212 sprintf(temp,
"%2d. %s%s %8i", i+
1, pathname, filename,
1213 tagPosInf[i]);
1214 }
1215 }
else {
1216 sprintf(temp,
"%2d. %s%s",i+
1,pathname,filename);
1217 }
1218
1219 if (
NULL == (dupTagsList[i] = (
char*) NEditMalloc(strlen(temp) +
1))) {
1220 int j;
1221 fprintf(stderr,
"xnedit: findAllMatches(): out of heap space!\n");
1222
1223
1224 for (j = i -
1; j > -
1; j--) {
1225 NEditFree(dupTagsList[j]);
1226 }
1227 NEditFree(dupTagsList);
1228
1229 XBell(TheDisplay,
0);
1230 return -
1;
1231 }
1232
1233 strcpy(dupTagsList[i],temp);
1234 }
1235 createSelectMenu(dialogParent,
"Duplicate Tags", nMatches, dupTagsList);
1236 for (i=
0; i<nMatches; i++)
1237 NEditFree(dupTagsList[i]);
1238 NEditFree(dupTagsList);
1239 return 1;
1240 }
1241
1242
1243
1244
1245
1246 if (searchMode ==
TAG)
1247 editTaggedLocation( dialogParent,
0 );
1248 else
1249 showMatchingCalltip( dialogParent,
0 );
1250 return 1;
1251 }
1252
1253
1254 static void findAllCB(Widget parent, XtPointer client_data, XtPointer call_data)
1255 {
1256 int i;
1257 char *eptr;
1258
1259 XmSelectionBoxCallbackStruct *cbs =
1260 (XmSelectionBoxCallbackStruct *) call_data;
1261 if (cbs->reason == XmCR_NO_MATCH)
1262 return;
1263 if (cbs->reason == XmCR_CANCEL) {
1264 XtDestroyWidget(XtParent(parent));
1265 return;
1266 }
1267
1268 XmStringGetLtoR(cbs->value,XmFONTLIST_DEFAULT_TAG,&eptr);
1269 if ((i = atoi(eptr)-
1) <
0) {
1270 XBell(TheDisplay,
0);
1271 return;
1272 }
1273
1274 if (searchMode ==
TAG)
1275 editTaggedLocation( parent, i );
1276 else
1277 showMatchingCalltip( parent, i );
1278
1279 if (cbs->reason == XmCR_OK)
1280 XtDestroyWidget(XtParent(parent));
1281 }
1282
1283
1284 static void findAllCloseCB(Widget parent, XtPointer client_data,
1285 XtPointer call_data)
1286 {
1287 XtDestroyWidget(parent);
1288 }
1289
1290
1291
1292
1293
1294
1295
1296 static int moveAheadNLines(
char *str,
int *pos,
int n ) {
1297 int i=n;
1298 while (str[*pos] !=
'\0' && n>
0) {
1299 if (str[*pos] ==
'\n')
1300 --n;
1301 ++(*pos);
1302 }
1303 if (n==
0)
1304 return -
1;
1305 else
1306 return i-n;
1307 }
1308
1309
1310
1311
1312
1313
1314 static void showMatchingCalltip( Widget parent,
int i )
1315 {
1316 int startPos=
0, fileLen, readLen, tipLen;
1317 int endPos=
0;
1318 char *fileString;
1319 FILE *fp;
1320 struct stat statbuf;
1321 char *message;
1322
1323
1324 NormalizePathname(tagFiles[i]);
1325 fp = fopen(tagFiles[i],
"r");
1326 if (fp ==
NULL) {
1327 DialogF(
DF_ERR, parent,
1,
"Error opening File",
"Error opening %s",
1328 "OK", tagFiles[i]);
1329 return;
1330 }
1331 if (fstat(fileno(fp), &statbuf) !=
0) {
1332 fclose(fp);
1333 DialogF(
DF_ERR, parent,
1,
"Error opening File",
"Error opening %s",
1334 "OK", tagFiles[i]);
1335 return;
1336 }
1337
1338
1339
1340 fileLen = statbuf.st_size;
1341 fileString = (
char*)NEditMalloc(fileLen+
1);
1342 if (fileString ==
NULL) {
1343 fclose(fp);
1344 DialogF(
DF_ERR, parent,
1,
"File too large",
1345 "File is too large to load",
"OK");
1346 return;
1347 }
1348
1349
1350 readLen = fread(fileString,
sizeof(
char), fileLen, fp);
1351 if (ferror(fp)) {
1352 fclose(fp);
1353 DialogF(
DF_ERR, parent,
1,
"Error reading File",
"Error reading %s",
1354 "OK", tagFiles[i]);
1355 NEditFree(fileString);
1356 return;
1357 }
1358 fileString[readLen] =
0;
1359
1360
1361 if (fclose(fp) !=
0) {
1362
1363 DialogF(
DF_WARN, parent,
1,
"Error closing File",
1364 "Unable to close file",
"OK");
1365
1366 }
1367
1368
1369 if (!*(tagSearch[i])) {
1370
1371 if ((moveAheadNLines( fileString, &startPos, tagPosInf[i]-
1 )) >=
0) {
1372 DialogF(
DF_ERR, parent,
1,
"Tags Error",
1373 "%s\n not long enough for definition to be on line %d",
1374 "OK", tagFiles[i], tagPosInf[i]);
1375 NEditFree(fileString);
1376 return;
1377 }
1378 }
else {
1379 startPos = tagPosInf[i];
1380 if(!fakeRegExSearch(WidgetToWindow(parent), fileString, tagSearch[i],
1381 &startPos, &endPos)){
1382 DialogF(
DF_WARN, parent,
1,
"Tag not found",
1383 "Definition for %s\nnot found in %s",
"OK", tagName,
1384 tagFiles[i]);
1385 NEditFree(fileString);
1386 return;
1387 }
1388 }
1389
1390 if (searchMode ==
TIP) {
1391 int dummy, found;
1392
1393
1394 endPos = startPos;
1395 found = SearchString(fileString,
"\\n\\s*\\n",
SEARCH_FORWARD,
1396 SEARCH_REGEX, False, startPos, &endPos, &dummy,
NULL,
1397 NULL,
NULL);
1398 if (!found) {
1399
1400 moveAheadNLines( fileString, &endPos,
TIP_DEFAULT_LINES );
1401 --endPos;
1402 }
1403 }
else {
1404
1405 endPos = startPos;
1406 moveAheadNLines( fileString, &endPos,
TIP_DEFAULT_LINES );
1407
1408 if (((
size_t) endPos) <= (strlen(fileString)-
5)) {
1409 sprintf( &fileString[endPos],
". . ." );
1410 endPos +=
5;
1411 }
1412 }
1413
1414 tipLen = endPos - startPos;
1415 message = (
char*)malloc(tipLen+
1);
1416 if (message ==
NULL)
1417 {
1418 DialogF(
DF_ERR, parent,
1,
"Out of Memory",
1419 "Can''t allocate memory for calltip message",
"OK");
1420 NEditFree(fileString);
1421 return;
1422 }
1423 strncpy( message, &fileString[startPos], tipLen );
1424 message[tipLen] =
0;
1425
1426
1427 tagsShowCalltip( WidgetToWindow(parent), message );
1428 NEditFree(message);
1429 NEditFree(fileString);
1430 }
1431
1432
1433
1434 static void editTaggedLocation( Widget parent,
int i )
1435 {
1436
1437
1438 int startPos, endPos, lineNum, rows;
1439 char filename[
MAXPATHLEN], pathname[
MAXPATHLEN];
1440 WindowInfo *windowToSearch;
1441 WindowInfo *parentWindow = WidgetToWindow(parent);
1442
1443 ParseFilename(tagFiles[i],filename,pathname);
1444
1445 EditExistingFile(parentWindow, filename, pathname,
NULL,
NULL,
0,
NULL,
1446 False,
NULL, GetPrefOpenInTab(), False);
1447 windowToSearch = FindWindowWithFile(filename, pathname);
1448 if (windowToSearch ==
NULL) {
1449 DialogF(
DF_WARN, parent,
1,
"File not found",
"File %s not found",
"OK",
1450 tagFiles[i]);
1451 return;
1452 }
1453
1454 startPos=tagPosInf[i];
1455
1456 if(!*(tagSearch[i])) {
1457
1458 SelectNumberedLine(windowToSearch, startPos);
1459 return;
1460 }
1461
1462
1463 if(!fakeRegExSearch(windowToSearch,
NULL, tagSearch[i], &startPos,
1464 &endPos)){
1465 DialogF(
DF_WARN, windowToSearch->shell,
1,
"Tag Error",
1466 "Definition for %s\nnot found in %s",
"OK", tagName,
1467 tagFiles[i]);
1468 return;
1469 }
1470
1471
1472 BufSelect(windowToSearch->buffer, startPos, endPos);
1473 RaiseFocusDocumentWindow(windowToSearch, True);
1474
1475
1476
1477 lineNum = BufCountLines(windowToSearch->buffer,
0, startPos);
1478 XtVaGetValues(windowToSearch->lastFocus, textNrows, &rows,
NULL);
1479 TextSetScroll(windowToSearch->lastFocus, lineNum - rows/
4,
0);
1480 TextSetCursorPos(windowToSearch->lastFocus, endPos);
1481 }
1482
1483
1484 static Widget createSelectMenu(Widget parent,
char *label,
int nArgs,
1485 char *args[])
1486 {
1487 int i;
1488 char tmpStr[
100];
1489 Widget menu;
1490 XmStringTable list;
1491 XmString popupTitle;
1492 int ac;
1493 Arg csdargs[
20];
1494
1495 list = (XmStringTable) NEditMalloc(nArgs *
sizeof(XmString *));
1496 for (i=
0; i<nArgs; i++)
1497 list[i] = XmStringCreateSimple(args[i]);
1498 sprintf(tmpStr,
"Select File With TAG: %s",tagName);
1499 popupTitle = XmStringCreateSimple(tmpStr);
1500 ac =
0;
1501 XtSetArg(csdargs[ac], XmNlistLabelString, popupTitle); ac++;
1502 XtSetArg(csdargs[ac], XmNlistItems, list); ac++;
1503 XtSetArg(csdargs[ac], XmNlistItemCount, nArgs); ac++;
1504 XtSetArg(csdargs[ac], XmNvisibleItemCount,
12); ac++;
1505 XtSetArg(csdargs[ac], XmNautoUnmanage, False); ac++;
1506 menu = CreateSelectionDialog(parent,label,csdargs,ac);
1507 XtUnmanageChild(XmSelectionBoxGetChild(menu, XmDIALOG_TEXT));
1508 XtUnmanageChild(XmSelectionBoxGetChild(menu, XmDIALOG_HELP_BUTTON));
1509 XtUnmanageChild(XmSelectionBoxGetChild(menu, XmDIALOG_SELECTION_LABEL));
1510 XtAddCallback(menu, XmNokCallback, (XtCallbackProc)findAllCB, menu);
1511 XtAddCallback(menu, XmNapplyCallback, (XtCallbackProc)findAllCB, menu);
1512 XtAddCallback(menu, XmNcancelCallback, (XtCallbackProc)findAllCB, menu);
1513 AddMotifCloseCallback(XtParent(menu), findAllCloseCB,
NULL);
1514 for (i=
0; i<nArgs; i++)
1515 XmStringFree(list[i]);
1516 NEditFree(list);
1517 XmStringFree(popupTitle);
1518 ManageDialogCenteredOnPointer(menu);
1519 return menu;
1520 }
1521
1522
1523
1524
1525
1526
1527
1528 enum tftoken_types {
TF_EOF,
TF_BLOCK,
TF_VERSION,
TF_INCLUDE,
TF_LANGUAGE,
1529 TF_ALIAS,
TF_ERROR,
TF_ERROR_EOF };
1530
1531
1532 static int searchLine(
char *line,
const char *regex) {
1533 int dummy1, dummy2;
1534 return SearchString(line, regex,
SEARCH_FORWARD,
SEARCH_REGEX,
1535 False,
0, &dummy1, &dummy2,
NULL,
NULL,
NULL);
1536 }
1537
1538
1539 static Boolean lineEmpty(
const char *line) {
1540 while (*line && *line !=
'\n') {
1541 if (*line !=
' ' && *line !=
'\t')
1542 return False;
1543 ++line;
1544 }
1545 return True;
1546 }
1547
1548
1549 static void rstrip(
char *dst,
const char *src ) {
1550 int wsStart, dummy2;
1551
1552 if(SearchString(src,
"\\s*\\n",
SEARCH_FORWARD,
SEARCH_REGEX,
1553 False,
0, &wsStart, &dummy2,
NULL,
NULL,
NULL)) {
1554 if(dst != src)
1555 memcpy(dst, src, wsStart);
1556 dst[wsStart] =
0;
1557 }
else
1558 if(dst != src)
1559 strcpy(dst, src);
1560 }
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574 static int nextTFBlock(
FILE *fp,
char *header,
char **body,
int *blkLine,
1575 int *currLine)
1576 {
1577
1578 const char *commenTF_regex =
"^\\s*\\* comment \\*\\s*$";
1579 const char *version_regex =
"^\\s*\\* version \\*\\s*$";
1580 const char *include_regex =
"^\\s*\\* include \\*\\s*$";
1581 const char *language_regex =
"^\\s*\\* language \\*\\s*$";
1582 const char *alias_regex =
"^\\s*\\* alias \\*\\s*$";
1583 char line[
MAXLINE], *status;
1584 int dummy1;
1585 int code;
1586
1587
1588 while(
1) {
1589
1590 while((status=fgets(line,
MAXLINE, fp))) {
1591 ++(*currLine);
1592 if(!lineEmpty( line ))
1593 break;
1594 }
1595
1596
1597 if(!status)
1598 return TF_EOF;
1599
1600
1601 if( !searchLine(line, commenTF_regex) )
1602 break;
1603
1604
1605 while((status=fgets(line,
MAXLINE, fp))) {
1606 ++(*currLine);
1607 if(lineEmpty( line ))
1608 break;
1609 }
1610
1611 if(!status)
1612 return TF_EOF;
1613 }
1614
1615
1616 dummy1 = searchLine(line, include_regex);
1617 if( dummy1 || searchLine(line, alias_regex) ) {
1618
1619 int incLen, incPos, i, incLines;
1620
1621
1622 if(dummy1)
1623 code =
TF_INCLUDE;
1624 else {
1625 code =
TF_ALIAS;
1626
1627 status=fgets(line,
MAXLINE, fp);
1628 ++(*currLine);
1629 if (!status)
1630 return TF_ERROR_EOF;
1631 if (lineEmpty( line )) {
1632 fprintf( stderr,
"xnedit: Warning: empty ''* alias *'' "
1633 "block in calltips file.\n" );
1634 return TF_ERROR;
1635 }
1636 rstrip(header, line);
1637 }
1638 incPos = ftell(fp);
1639 *blkLine = *currLine +
1;
1640 if (incPos <
0)
1641 return TF_ERROR;
1642
1643 while((status=fgets(line,
MAXLINE, fp)) || feof(fp)) {
1644 ++(*currLine);
1645 if(feof(fp) || lineEmpty( line ))
1646 break;
1647 }
1648 incLen = ftell(fp) - incPos;
1649 incLines = *currLine - *blkLine;
1650
1651 --(*currLine);
1652 if (incLines ==
0) {
1653 fprintf( stderr,
"xnedit: Warning: empty ''* include *'' or"
1654 " ''* alias *'' block in calltips file.\n" );
1655 return TF_ERROR;
1656 }
1657
1658 *body = (
char *)NEditMalloc(incLen+
1);
1659 if (!*body)
1660 return TF_ERROR;
1661 *body[
0]=
0;
1662 if (fseek(fp, incPos,
SEEK_SET) !=
0) {
1663 NEditFree(*body);
1664 return TF_ERROR;
1665 }
1666
1667
1668 for (i=
0; i<incLines; i++) {
1669 status = fgets(line,
MAXLINE, fp);
1670 if (!status) {
1671 NEditFree(*body);
1672 return TF_ERROR_EOF;
1673 }
1674 rstrip(line,line);
1675 if(i)
1676 strcat(*body,
":");
1677 strcat(*body, line);
1678 }
1679
1680 }
1681
1682 else if( searchLine(line, language_regex) ) {
1683
1684 status=fgets(line,
MAXLINE, fp);
1685 ++(*currLine);
1686 if (!status)
1687 return TF_ERROR_EOF;
1688 if (lineEmpty( line )) {
1689 fprintf( stderr,
"xnedit: Warning: empty ''* language *'' block in calltips file.\n" );
1690 return TF_ERROR;
1691 }
1692 *blkLine = *currLine;
1693 rstrip(header, line);
1694 code =
TF_LANGUAGE;
1695 }
1696
1697 else if( searchLine(line, version_regex) ) {
1698
1699 status=fgets(line,
MAXLINE, fp);
1700 ++(*currLine);
1701 if (!status)
1702 return TF_ERROR_EOF;
1703 if (lineEmpty( line )) {
1704 fprintf( stderr,
"xnedit: Warning: empty ''* version *'' block in calltips file.\n" );
1705 return TF_ERROR;
1706 }
1707 *blkLine = *currLine;
1708 rstrip(header, line);
1709 code =
TF_VERSION;
1710 }
1711
1712 else {
1713
1714
1715
1716 rstrip(header, line);
1717
1718 status=fgets(line,
MAXLINE, fp);
1719 ++(*currLine);
1720 if (!status)
1721 return TF_ERROR_EOF;
1722 if (lineEmpty( line )) {
1723 fprintf( stderr,
"xnedit: Warning: empty calltip block:\n"
1724 " \"%s\"\n", header);
1725 return TF_ERROR;
1726 }
1727 *blkLine = *currLine;
1728 *body = strdup(line);
1729 code =
TF_BLOCK;
1730 }
1731
1732
1733 dummy1 = *currLine;
1734 while(fgets(line,
MAXLINE, fp)) {
1735 ++(*currLine);
1736 if (lineEmpty( line ))
1737 break;
1738 }
1739
1740
1741 if (dummy1+
1 < *currLine && code !=
TF_BLOCK) {
1742 fprintf( stderr,
"xnedit: Warning: extra lines in language or version block ignored.\n" );
1743 }
1744
1745 return code;
1746 }
1747
1748
1749 typedef struct _alias {
1750 char *dest;
1751 char *sources;
1752 struct _alias *next;
1753 } tf_alias;
1754
1755
1756
1757
1758
1759 static tf_alias *new_alias(
const char *dest,
char *sources) {
1760 tf_alias *alias;
1761
1762
1763
1764 alias = (tf_alias *)NEditMalloc(
sizeof(tf_alias) );
1765 if(!alias)
1766 return NULL;
1767
1768
1769 alias->dest = (
char*)NEditMalloc( strlen(dest)+
1 );
1770 if(!(alias->dest))
1771 return NULL;
1772 strcpy( alias->dest, dest );
1773 alias->sources = sources;
1774 return alias;
1775 }
1776
1777
1778 static void free_alias_list(tf_alias *alias) {
1779 tf_alias *tmp_alias;
1780 while(alias) {
1781 tmp_alias = alias->next;
1782 NEditFree(alias->dest);
1783 NEditFree(alias->sources);
1784 NEditFree(alias);
1785 alias = tmp_alias;
1786 }
1787 }
1788
1789
1790
1791
1792
1793
1794
1795 static int loadTipsFile(
const char *tipsFile,
int index,
int recLevel)
1796 {
1797 FILE *fp =
NULL;
1798 char header[
MAXLINE];
1799 char *body, *tipIncFile;
1800 char tipPath[
MAXPATHLEN];
1801 char resolvedTipsFile[
MAXPATHLEN+
1];
1802 int nTipsAdded=
0, langMode =
PLAIN_LANGUAGE_MODE, oldLangMode;
1803 int currLine=
0, code, blkLine;
1804 tf_alias *aliases=
NULL, *tmp_alias;
1805
1806 if(recLevel >
MAX_TAG_INCLUDE_RECURSION_LEVEL) {
1807 fprintf(stderr,
"xnedit: Warning: Reached recursion limit before loading calltips file:\n\t%s\n", tipsFile);
1808 return 0;
1809 }
1810
1811
1812 #ifndef VMS
1813
1814 strncpy(tipPath, tipsFile,
MAXPATHLEN);
1815 tipPath[
MAXPATHLEN -
1] =
'\0';
1816 ExpandTilde(tipPath);
1817 if(!ResolvePath(tipPath, resolvedTipsFile))
1818 return 0;
1819 #else
1820 if(!ResolvePath(tipsFile, resolvedTipsFile))
1821 return 0;
1822 #endif
1823
1824
1825 ParseFilename(resolvedTipsFile,
NULL, tipPath);
1826
1827
1828 if ((fp = fopen(resolvedTipsFile,
"r")) ==
NULL)
1829 return 0;
1830
1831 while(
1 ) {
1832 code = nextTFBlock(fp, header, &body, &blkLine, &currLine);
1833 if( code ==
TF_ERROR_EOF ) {
1834 fprintf(stderr,
"xnedit: Warning: unexpected EOF in calltips file.\n");
1835 break;
1836 }
1837 if( code ==
TF_EOF )
1838 break;
1839
1840 switch (code) {
1841 case TF_BLOCK:
1842
1843
1844
1845
1846 nTipsAdded += addTag(header, resolvedTipsFile, langMode,
"",
1847 blkLine, tipPath, index);
1848 NEditFree( body );
1849 break;
1850 case TF_INCLUDE:
1851
1852
1853 for(tipIncFile=strtok(body,
":"); tipIncFile;
1854 tipIncFile=strtok(
NULL,
":")) {
1855
1856
1857
1858 nTipsAdded += loadTipsFile( tipIncFile, index, recLevel+
1);
1859 }
1860 NEditFree( body );
1861 break;
1862 case TF_LANGUAGE:
1863
1864
1865 oldLangMode = langMode;
1866 langMode = FindLanguageMode( header );
1867 if (langMode ==
PLAIN_LANGUAGE_MODE &&
1868 strcmp(header,
"Plain")) {
1869 fprintf(stderr,
1870 "xnedit: Error reading calltips file:\n\t%s\n"
1871 "Unknown language mode: \"%s\"\n",
1872 tipsFile, header);
1873 langMode = oldLangMode;
1874 }
1875 break;
1876 case TF_ERROR:
1877 fprintf(stderr,
"xnedit: Warning: Recoverable error while "
1878 "reading calltips file:\n \"%s\"\n",
1879 resolvedTipsFile);
1880 break;
1881 case TF_ALIAS:
1882
1883 tmp_alias = aliases;
1884 aliases = new_alias(header, body);
1885 if( !aliases ) {
1886 fprintf(stderr,
"xnedit: Can''t allocate memory for tipfile "
1887 "alias in calltips file:\n \"%s\"\n",
1888 resolvedTipsFile);
1889
1890 free_alias_list(tmp_alias);
1891 fclose(fp);
1892 return 0;
1893 }
1894
1895 aliases->next = tmp_alias;
1896 break;
1897 default:
1898 ;
1899 }
1900 }
1901
1902
1903 tmp_alias = aliases;
1904 while (tmp_alias) {
1905 tag *t;
1906 char *src;
1907 t = getTag(tmp_alias->dest,
TIP);
1908 if (!t) {
1909 fprintf(stderr,
"xnedit: Can''t find destination of alias \"%s\"\n"
1910 " in calltips file:\n \"%s\"\n",
1911 tmp_alias->dest, resolvedTipsFile);
1912 }
else {
1913 for(src=strtok(tmp_alias->sources,
":"); src; src=strtok(
NULL,
":"))
1914 addTag(src, resolvedTipsFile, t->language,
"", t->posInf,
1915 tipPath, index);
1916 }
1917 tmp_alias = tmp_alias->next;
1918 }
1919 free_alias_list(aliases);
1920 fclose(fp);
1921
1922 return nTipsAdded;
1923 }
1924