📄 tags.c
字号:
else Rcs[bucket] = newrcs; newstr = newrcs->string; } RcsStats.tbytes += len; return newstr;}/*** Decrease the reference count on a shared string. When the reference** count reaches zero, free the master string.*/static void rcs_free(const char *rcs_str){ int bucket; struct rcs *rp; struct rcs *prev = NULL; if (rcs_str == NULL) return; bucket = hashAddr(rcs_str) % RCS_SIZE; /* find it in hash */ for (rp = Rcs[bucket]; rp; rp = rp->next) { if (rcs_str == rp->string) break; prev = rp; } if (rp) /* It's a shared string, decrease ref count */ { rp->usage--; if (rp->usage < 0) /* D'OH! */ { fprintf(stderr, "NEdit: internal error deallocating shared string."); return; } if (rp->usage == 0) /* Last one- free the storage */ { free(rp->string); if (prev) prev->next = rp->next; else Rcs[bucket] = rp->next; free(rp); } } else /* Doesn't appear to be a shared string */ { fprintf(stderr, "NEdit: attempt to free a non-shared string."); return; }}/******************************************************************** * Functions for loading Calltips files * ********************************************************************/enum tftoken_types { TF_EOF, TF_BLOCK, TF_VERSION, TF_INCLUDE, TF_LANGUAGE, TF_ALIAS, TF_ERROR, TF_ERROR_EOF };/* A wrapper for SearchString */static int searchLine(char *line, const char *regex) { int dummy1, dummy2; return SearchString(line, regex, SEARCH_FORWARD, SEARCH_REGEX, False, 0, &dummy1, &dummy2, NULL, NULL, NULL);}/* Check if a line has non-ws characters */static Boolean lineEmpty(const char *line) { while (*line && *line != '\n') { if (*line != ' ' && *line != '\t') return False; ++line; } return True;}/* Remove trailing whitespace from a line */static void rstrip( char *dst, const char *src ) { int wsStart, dummy2; /* Strip trailing whitespace */ if(SearchString(src, "\\s*\\n", SEARCH_FORWARD, SEARCH_REGEX, False, 0, &wsStart, &dummy2, NULL, NULL, NULL)) { if(dst != src) memcpy(dst, src, wsStart); dst[wsStart] = 0; } else if(dst != src) strcpy(dst, src);}/* ** Get the next block from a tips file. A block is a \n\n+ delimited set of** lines in a calltips file. All of the parameters except <fp> are return** values, and most have different roles depending on the type of block** that is found. ** header: Depends on the block type** body: Depends on the block type. Used to return a new ** dynamically allocated string.** blkLine: Returns the line number of the first line of the block** after the "* xxxx *" line. ** currLine: Used to keep track of the current line in the file.*/static int nextTFBlock(FILE *fp, char *header, char **body, int *blkLine, int *currLine) { /* These are the different kinds of tokens */ const char *commenTF_regex = "^\\s*\\* comment \\*\\s*$"; const char *version_regex = "^\\s*\\* version \\*\\s*$"; const char *include_regex = "^\\s*\\* include \\*\\s*$"; const char *language_regex = "^\\s*\\* language \\*\\s*$"; const char *alias_regex = "^\\s*\\* alias \\*\\s*$"; char line[MAXLINE], *status; int dummy1; int code; /* Skip blank lines and comments */ while(1) { /* Skip blank lines */ while((status=fgets(line, MAXLINE, fp))) { ++(*currLine); if(!lineEmpty( line )) break; } /* Check for error or EOF */ if(!status) return TF_EOF; /* We've got a non-blank line -- is it a comment block? */ if( !searchLine(line, commenTF_regex) ) break; /* Skip the comment (non-blank lines) */ while((status=fgets(line, MAXLINE, fp))) { ++(*currLine); if(lineEmpty( line )) break; } if(!status) return TF_EOF; } /* Now we know it's a meaningful block */ dummy1 = searchLine(line, include_regex); if( dummy1 || searchLine(line, alias_regex) ) { /* INCLUDE or ALIAS block */ int incLen, incPos, i, incLines; /* fprintf(stderr, "Starting include/alias at line %i\n", *currLine); */ if(dummy1) code = TF_INCLUDE; else { code = TF_ALIAS; /* Need to read the header line for an alias */ status=fgets(line, MAXLINE, fp); ++(*currLine); if (!status) return TF_ERROR_EOF; if (lineEmpty( line )) { fprintf( stderr, "nedit: Warning: empty '* alias *' " "block in calltips file.\n" ); return TF_ERROR; } rstrip(header, line); } incPos = ftell(fp); *blkLine = *currLine + 1; /* Line of first actual filename/alias */ if (incPos < 0) return TF_ERROR; /* Figure out how long the block is */ while((status=fgets(line, MAXLINE, fp))) { ++(*currLine); if(lineEmpty( line )) break; } incLen = ftell(fp) - incPos; incLines = *currLine - *blkLine; /* Correct currLine for the empty line it read at the end */ --(*currLine); if (incLines == 0) { fprintf( stderr, "nedit: Warning: empty '* include *' or" " '* alias *' block in calltips file.\n" ); return TF_ERROR; } /* Make space for the filenames/alias sources */ *body = (char *)malloc(incLen+1); if (!*body) return TF_ERROR; *body[0]=0; if (fseek(fp, incPos, SEEK_SET) != 0) { free (*body); return TF_ERROR; } /* Read all the lines in the block */ /* fprintf(stderr, "Copying lines\n"); */ for (i=0; i<incLines; i++) { status = fgets(line, MAXLINE, fp); if (!status) { free (*body); return TF_ERROR_EOF; } rstrip(line,line); if(i) strcat(*body, ":"); strcat(*body, line); } /* fprintf(stderr, "Finished include/alias at line %i\n", *currLine); */ } else if( searchLine(line, language_regex) ) { /* LANGUAGE block */ status=fgets(line, MAXLINE, fp); ++(*currLine); if (!status) return TF_ERROR_EOF; if (lineEmpty( line )) { fprintf( stderr, "nedit: Warning: empty '* language *' block in calltips file.\n" ); return TF_ERROR; } *blkLine = *currLine; rstrip(header, line); code = TF_LANGUAGE; } else if( searchLine(line, version_regex) ) { /* VERSION block */ status=fgets(line, MAXLINE, fp); ++(*currLine); if (!status) return TF_ERROR_EOF; if (lineEmpty( line )) { fprintf( stderr, "nedit: Warning: empty '* version *' block in calltips file.\n" ); return TF_ERROR; } *blkLine = *currLine; rstrip(header, line); code = TF_VERSION; } else { /* Calltip block */ /* The first line is the key, the rest is the tip. Strip trailing whitespace. */ rstrip(header, line); status=fgets(line, MAXLINE, fp); ++(*currLine); if (!status) return TF_ERROR_EOF; if (lineEmpty( line )) { fprintf( stderr, "nedit: Warning: empty calltip block:\n" " \"%s\"\n", header); return TF_ERROR; } *blkLine = *currLine; *body = strdup(line); code = TF_BLOCK; } /* Skip the rest of the block */ dummy1 = *currLine; while(fgets(line, MAXLINE, fp)) { ++(*currLine); if (lineEmpty( line )) break; } /* Warn about any unneeded extra lines (which are ignored). */ if (dummy1+1 < *currLine && code != TF_BLOCK) { fprintf( stderr, "nedit: Warning: extra lines in language or version block ignored.\n" ); } return code;}/* A struct for describing a calltip alias */typedef struct _alias { char *dest; char *sources; struct _alias *next;} tf_alias;/*** Allocate a new alias, copying dest and stealing sources. This may** seem strange but that's the way it's called */static tf_alias *new_alias(const char *dest, char *sources) { tf_alias *alias; /* fprintf(stderr, "new_alias: %s <- %s\n", dest, sources); */ /* Allocate the alias */ alias = (tf_alias *)malloc( sizeof(tf_alias) ); if(!alias) return NULL; /* Fill it in */ alias->dest = (char*)malloc( strlen(dest)+1 ); if(!(alias->dest)) return NULL; strcpy( alias->dest, dest ); alias->sources = sources; return alias;}/* Deallocate a linked-list of aliases */static void free_alias_list(tf_alias *alias) { tf_alias *tmp_alias; while(alias) { tmp_alias = alias->next; free(alias->dest); free(alias->sources); free(alias); alias = tmp_alias; }}/*** Load a calltips file and insert all of the entries into the global tips** database. Each tip is essentially stored as its filename and the line** at which it appears--the exact same way ctags indexes source-code. That's** why calltips and tags share so much code.*/static int loadTipsFile(const char *tipsFile, int index, int recLevel){ FILE *fp = NULL; char header[MAXLINE]; char *body, *tipIncFile; char tipPath[MAXPATHLEN]; char resolvedTipsFile[MAXPATHLEN+1]; int nTipsAdded=0, langMode = PLAIN_LANGUAGE_MODE, oldLangMode; int currLine=0, code, blkLine; tf_alias *aliases=NULL, *tmp_alias; if(recLevel > MAX_TAG_INCLUDE_RECURSION_LEVEL) { fprintf(stderr, "nedit: Warning: Reached recursion limit before loading calltips file:\n\t%s\n", tipsFile); return 0; } /* find the tips file */#ifndef VMS /* Allow ~ in Unix filenames */ strncpy(tipPath, tipsFile, MAXPATHLEN); /* ExpandTilde is destructive */ ExpandTilde(tipPath); if(!ResolvePath(tipPath, resolvedTipsFile)) return 0;#else if(!ResolvePath(tipsFile, resolvedTipsFile)) return 0;#endif /* Get the path to the tips file */ ParseFilename(resolvedTipsFile, NULL, tipPath); /* Open the file */ if ((fp = fopen(resolvedTipsFile, "r")) == NULL) return 0; while( 1 ) { code = nextTFBlock(fp, header, &body, &blkLine, &currLine); if( code == TF_ERROR_EOF ) { fprintf(stderr,"nedit: Warning: unexpected EOF in calltips file.\n"); break; } if( code == TF_EOF ) break; switch (code) { case TF_BLOCK: /* Add the calltip to the global hash table. For the moment I'm just using line numbers because I don't want to have to deal with adding escape characters for regex metacharacters that might appear in the string */ nTipsAdded += addTag(header, resolvedTipsFile, langMode, "", blkLine, tipPath, index); free( body ); break; case TF_INCLUDE: /* nextTFBlock returns a colon-separated list of tips files in body */ for(tipIncFile=strtok(body,":"); tipIncFile; tipIncFile=strtok(NULL,":")) { /* fprintf(stderr, "nedit: DEBUG: including tips file '%s'\n", tipIncFile); */ nTipsAdded += loadTipsFile( tipIncFile, index, recLevel+1); } free( body );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -