📄 tags.c
字号:
** Nedit.tags: <tagfile1>:<tagfile2>** Returns True if all files were found in the FileList or loaded successfully,** FALSE otherwise.*/int AddTagsFile(const char *tagSpec, int file_type){ tagFile *t; int added=1; struct stat statbuf; char *filename; char pathName[MAXPATHLEN]; char *tmptagSpec; tagFile *FileList; /* To prevent any possible segfault */ if (tagSpec == NULL) { fprintf(stderr, "nedit: Internal Error!\n" " Passed NULL pointer to AddTagsFile!\n"); return FALSE; } searchMode = file_type; if (searchMode == TAG) FileList = TagsFileList; else FileList = TipsFileList; tmptagSpec = (char *) malloc(strlen(tagSpec)+1); strcpy(tmptagSpec, tagSpec); for (filename = strtok(tmptagSpec,":"); filename; filename = strtok(NULL,":")) { if (*filename != '/') { strcpy(pathName, GetCurrentDir()); strcat(pathName,"/"); strcat(pathName,filename); } else { strcpy(pathName,filename); } NormalizePathname(pathName); CompressPathname(pathName); for (t = FileList; t && strcmp(t->filename,pathName); t = t->next); if (t) { added=1; continue; } if (stat(pathName,&statbuf) != 0) { /* Problem reading this tags file. Return FALSE */ added = 0; continue; } t = (tagFile *) malloc(sizeof(tagFile)); t->filename = STRSAVE(pathName); t->loaded = 0; t->date = statbuf.st_mtime; t->index = ++tagFileIndex; t->next = FileList; FileList = setFileListHead(t, file_type ); } free(tmptagSpec); updateMenuItems(); if (added) return TRUE; else return FALSE;}/* Un-manage a colon-delimited set of tags files * Return TRUE if all files were found in the FileList and unloaded, FALSE * if any file was not found in the FileList. */int DeleteTagsFile(const char *tagSpec, int file_type){ tagFile *t, *last; tagFile *FileList; char pathName[MAXPATHLEN], *tmptagSpec, *filename; int removed; /* To prevent any possible segfault */ if (tagSpec == NULL) { fprintf(stderr, "nedit: Internal Error!\n" " Passed NULL pointer to DeleteTagsFile!\n"); return FALSE; } searchMode = file_type; if (searchMode == TAG) FileList = TagsFileList; else FileList = TipsFileList; tmptagSpec = (char *) malloc(strlen(tagSpec)+1); strcpy(tmptagSpec, tagSpec); removed=1; for (filename = strtok(tmptagSpec,":"); filename; filename = strtok(NULL,":")) { if (*filename != '/') { strcpy(pathName, GetCurrentDir()); strcat(pathName,"/"); strcat(pathName,filename); } else { strcpy(pathName,filename); } NormalizePathname(pathName); CompressPathname(pathName); for (last=NULL,t = FileList; t; last = t,t = t->next) { if (strcmp(t->filename, pathName)) continue; if (t->loaded) delTag(NULL,NULL,-2,NULL,-2,t->index); if (last) last->next = t->next; else FileList = setFileListHead(t->next, file_type); free(t->filename); free(t); updateMenuItems(); break; } /* If any file can't be removed, return false */ if (!t) removed = 0; } if (removed) return TRUE; else return FALSE;}/* ** Update the "Find Definition", "Unload Tags File", "Show Calltip", ** and "Unload Calltips File" menu items in the existing windows. */static void updateMenuItems() { WindowInfo *w; Boolean tipStat=FALSE, tagStat=FALSE; if (TipsFileList) tipStat=TRUE; if (TagsFileList) tagStat=TRUE; for (w=WindowList; w!=NULL; w=w->next) { XtSetSensitive(w->showTipItem, tipStat || tagStat); XtSetSensitive(w->unloadTipsMenuItem, tipStat); XtSetSensitive(w->findDefItem, tagStat); XtSetSensitive(w->unloadTagsMenuItem, tagStat); }}/* ** Scans one <line> from a ctags tags file (<index>) in tagPath.** Return value: Number of tag specs added.*/static int scanCTagsLine(const char *line, const char *tagPath, int index) { char name[MAXLINE], searchString[MAXLINE]; char file[MAXPATHLEN]; char *posTagREEnd, *posTagRENull; int nRead, pos; nRead = sscanf(line, "%s\t%s\t%[^\n]", name, file, searchString); if (nRead != 3) return 0; if ( *name == '!' ) return 0; /* ** Guess the end of searchString: ** Try to handle original ctags and exuberant ctags format: */ if(searchString[0] == '/' || searchString[0] == '?') { pos=-1; /* "search expr without pos info" */ /* Situations: /<ANY expr>/\0 ** ?<ANY expr>?\0 --> original ctags ** /<ANY expr>/;" <flags> ** ?<ANY expr>?;" <flags> --> exuberant ctags */ posTagREEnd = strrchr(searchString, ';'); posTagRENull = strchr(searchString, 0); if(!posTagREEnd || (posTagREEnd[1] != '"') || (posTagRENull[-1] == searchString[0])) { /* -> original ctags format = exuberant ctags format 1 */ posTagREEnd = posTagRENull; } else { /* looks like exuberant ctags format 2 */ *posTagREEnd = 0; } /* ** Hide the last delimiter: ** /<expression>/ becomes /<expression> ** ?<expression>? becomes ?<expression> ** This will save a little work in fakeRegExSearch. */ if(posTagREEnd > (searchString+2)) { posTagREEnd--; if(searchString[0] == *posTagREEnd) *posTagREEnd=0; } } else { pos=atoi(searchString); *searchString=0; } /* No ability to read language mode right now */ return addTag(name, file, PLAIN_LANGUAGE_MODE, searchString, pos, tagPath, index);} /* * Scans one <line> from an etags (emacs) tags file (<index>) in tagPath. * recLevel = current recursion level for tags file including * file = destination definition file. possibly modified. len=MAXPATHLEN! * Return value: Number of tag specs added. */static int scanETagsLine(const char *line, const char * tagPath, int index, char * file, int recLevel) { char name[MAXLINE], searchString[MAXLINE]; char incPath[MAXPATHLEN]; int pos, len; char *posDEL, *posSOH, *posCOM; /* check for destination file separator */ if(line[0]==12) { /* <np> */ *file=0; return 0; } /* check for standard definition line */ posDEL=strchr(line, '\177'); posSOH=strchr(line, '\001'); posCOM=strrchr(line, ','); if(*file && posDEL && (posSOH > posDEL) && (posCOM > posSOH)) { /* exuberant ctags -e style */ len=Min(MAXLINE-1, posDEL - line); strncpy(searchString, line, len); searchString[len]=0; len=Min(MAXLINE-1, (posSOH - posDEL) - 1); strncpy(name, posDEL + 1, len); name[len]=0; pos=atoi(posCOM+1); /* No ability to set language mode for the moment */ return addTag(name, file, PLAIN_LANGUAGE_MODE, searchString, pos, tagPath, index); } if (*file && posDEL && (posCOM > posDEL)) { /* old etags style, part name<soh> is missing here! */ len=Min(MAXLINE-1, posDEL - line); strncpy(searchString, line, len); searchString[len]=0; /* guess name: take the last alnum (plus _) part of searchString */ while(--len >= 0) { if( isalnum((unsigned char)searchString[len]) || (searchString[len] == '_')) break; } if(len<0) return 0; pos=len; while (pos >= 0 && (isalnum((unsigned char)searchString[pos]) || (searchString[pos] == '_'))) pos--; strncpy(name, searchString + pos + 1, len - pos); name[len - pos] = 0; /* name ready */ pos=atoi(posCOM+1); return addTag(name, file, PLAIN_LANGUAGE_MODE, searchString, pos, tagPath, index); } /* check for destination file spec */ if(*line && posCOM) { len=Min(MAXPATHLEN-1, posCOM - line); strncpy(file, line, len); file[len]=0; /* check if that's an include file ... */ if(!(strncmp(posCOM+1, "include", 7))) { if(*file != '/') { if((strlen(tagPath) + strlen(file)) >= MAXPATHLEN) { fprintf(stderr, "tags.c: MAXPATHLEN overflow\n"); *file=0; /* invalidate */ return 0; } strcpy(incPath, tagPath); strcat(incPath, file); CompressPathname(incPath); return(loadTagsFile(incPath, index, recLevel+1)); } else { return(loadTagsFile(file, index, recLevel+1)); } } } return 0;}/* Tag File Type */typedef enum { TFT_CHECK, TFT_ETAGS, TFT_CTAGS} TFT;/* ** Loads tagsFile into the hash table. ** Returns the number of added tag specifications.*/static int loadTagsFile(const char *tagsFile, int index, int recLevel){ FILE *fp = NULL; char line[MAXLINE]; char file[MAXPATHLEN], tagPath[MAXPATHLEN]; char resolvedTagsFile[MAXPATHLEN+1]; int nTagsAdded=0; int tagFileType = TFT_CHECK; if(recLevel > MAX_TAG_INCLUDE_RECURSION_LEVEL) { return 0; } /* the path of the tags file must be resolved to find the right files: * definition source files are (in most cases) specified relatively inside * the tags file to the tags files directory. */ if(!ResolvePath(tagsFile, resolvedTagsFile)) { return 0; } /* Open the file */ if ((fp = fopen(resolvedTagsFile, "r")) == NULL) { return 0; } ParseFilename(resolvedTagsFile, NULL, tagPath); /* Read the file and store its contents */ while (fgets(line, MAXLINE, fp)) { /* This might take a while if you have a huge tags file (like I do).. keep the windows up to date and post a busy cursor so the user doesn't think we died. */ AllWindowsBusy("Loading tags file..."); /* the first character in the file decides if the file is treat as etags or ctags file. */ if(tagFileType==TFT_CHECK) { if(line[0]==12) /* <np> */ tagFileType=TFT_ETAGS; else tagFileType=TFT_CTAGS; } if(tagFileType==TFT_CTAGS) { nTagsAdded += scanCTagsLine(line, tagPath, index); } else { nTagsAdded += scanETagsLine(line, tagPath, index, file, recLevel); } } fclose(fp); AllWindowsUnbusy(); return nTagsAdded;}/*** Given a tag name, lookup the file and path of the definition** and the proper search string. Returned strings are pointers** to internal storage which are valid until the next loadTagsFile call.**** Invocation with name != NULL (containing the searched definition) ** --> returns first definition of name** Successive invocation with name == NULL** --> returns further definitions (resulting from multiple tags files)**** Return Value: TRUE: tag spec found** FALSE: no (more) definitions found.*/#define TAG_STS_ERR_FMT "NEdit: Error getting status for tag file %s\n"int LookupTag(const char *name, const char **file, int *language, const char **searchString, int * pos, const char **path, int search_type){ tag *t; tagFile *tf; struct stat statbuf; tagFile *FileList; int load_status; searchMode = search_type; if (searchMode == TIP) FileList = TipsFileList; else FileList = TagsFileList; /* ** Go through the list of all tags Files: ** - load them (if not already loaded) ** - check for update of the tags file and reload it in that case ** - save the modification date of the tags file ** ** Do this only as long as name != NULL, not for sucessive calls ** to find multiple tags specs. ** */ for (tf = FileList; tf && name; tf = tf->next) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -