/* * find_read_traverse: read path without GPATH. * * r) path */ char * find_read_traverse(void) { static char val[MAXPATHLEN]; char path[MAXPATHLEN]; struct stack_entry *curp = varray_assign(stack, current_entry, 1); for (;;) { while (curp->p < curp->end) { char type = *(curp->p); const char *unit = curp->p + 1; curp->p += strlen(curp->p) + 1; /* * Skip files described in the skip list. */ /* makepath() returns unsafe module local area. */ strlimcpy(path, makepath(dir, unit, NULL), sizeof(path)); if (type == 'd') strcat(path, "/"); if (skipthisfile(path)) continue; if (type == 'f') { /* * Skip the following: * o directory * o file which does not exist * o dead symbolic link */ if (!test("f", path)) { if (test("d", path)) warning("'%s' is a directory. (Ignored)", path); else warning("'%s' not found. (Ignored)", path); continue; } /* * GLOBAL cannot treat path which includes blanks. * It will be improved in the future. */ if (!allow_blank && locatestring(path, " ", MATCH_FIRST)) { warning("'%s' ignored, because it includes blank.", &path[2]); continue; } /* * A blank at the head of path means * other than source file. */ if (regexec(suff, path, 0, 0, 0) == 0) { /* source file */ strlimcpy(val, path, sizeof(val)); } else { /* other file like 'Makefile' */ val[0] = ' '; strlimcpy(&val[1], path, sizeof(val) - 1); } val[sizeof(val) - 1] = '\0'; return val; } if (type == 'd') { STRBUF *sb = strbuf_open(0); char *dirp = curp->dirp; strcat(dirp, unit); strcat(dirp, "/"); if (getdirs(dir, sb) < 0) { warning("cannot open directory '%s'. (Ignored)", dir); strbuf_close(sb); *(curp->dirp) = 0; continue; } /* * Push stack. */ curp = varray_assign(stack, ++current_entry, 1); curp->dirp = dirp + strlen(dirp); curp->sb = sb; curp->start = curp->p = strbuf_value(sb); curp->end = curp->start + strbuf_getlen(sb); } } strbuf_close(curp->sb); curp->sb = NULL; if (current_entry == 0) break; /* * Pop stack. */ curp = varray_assign(stack, --current_entry, 0); *(curp->dirp) = 0; } find_eof = 1; return NULL; }
/* * find_read_filelist: read path from file * * r) path */ static char * find_read_filelist(void) { STATIC_STRBUF(ib); static char buf[MAXPATHLEN + 1]; static char *path; strbuf_clear(ib); for (;;) { path = strbuf_fgets(ib, ip, STRBUF_NOCRLF); if (path == NULL) { /* EOF */ find_eof = 1; return NULL; } if (*path == '\0') { /* skip empty line. */ continue; } /* * Lines which start with ". " are considered to be comments. */ if (*path == '.' && *(path + 1) == ' ') continue; /* * Skip the following: * o directory * o file which does not exist * o dead symbolic link */ if (!test("f", path)) { if (test("d", path)) warning("'%s' is a directory. (Ignored)", path); else warning("'%s' not found. (Ignored)", path); continue; } /* * normalize path name. * * rootdir /a/b/ * buf /a/b/c/d.c -> c/d.c -> ./c/d.c */ if (normalize(path, rootdir, cwddir, buf, sizeof(buf)) == NULL) { warning("'%s' is out of source tree. (Ignored)", path); continue; } path = buf; /* * GLOBAL cannot treat path which includes blanks. * It will be improved in the future. */ if (!allow_blank && locatestring(path, " ", MATCH_LAST)) { warning("'%s' ignored, because it includes blank.", path + 2); continue; } if (skipthisfile(path)) continue; /* * A blank at the head of path means * other than source file. */ if (regexec(suff, path, 0, 0, 0) != 0) *--path = ' '; return path; } }
/** * incremental: incremental update * * @param[in] dbpath dbpath directory * @param[in] root root directory of source tree * @return 0: not updated, 1: updated */ int incremental(const char *dbpath, const char *root) { STATISTICS_TIME *tim; struct stat statp; time_t gtags_mtime; STRBUF *addlist = strbuf_open(0); STRBUF *deletelist = strbuf_open(0); STRBUF *addlist_other = strbuf_open(0); IDSET *deleteset, *findset; int updated = 0; const char *path; unsigned int id, limit; tim = statistics_time_start("Time of inspecting %s and %s.", dbname(GTAGS), dbname(GRTAGS)); if (vflag) { fprintf(stderr, " Tag found in '%s'.\n", dbpath); fprintf(stderr, " Incremental updating.\n"); } /* * get modified time of GTAGS. */ path = makepath(dbpath, dbname(GTAGS), NULL); if (stat(path, &statp) < 0) die("stat failed '%s'.", path); gtags_mtime = statp.st_mtime; if (gpath_open(dbpath, 2) < 0) die("GPATH not found."); /* * deleteset: * The list of the path name which should be deleted from GPATH. * findset: * The list of the path name which exists in the current project. * A project is limited by the --file option. */ deleteset = idset_open(gpath_nextkey()); findset = idset_open(gpath_nextkey()); total = 0; /* * Make add list and delete list for update. */ if (single_update) { int type; const char *fid; if (skipthisfile(single_update)) goto exit; if (test("b", single_update)) goto exit; fid = gpath_path2fid(single_update, &type); if (fid == NULL) { /* new file */ type = issourcefile(single_update) ? GPATH_SOURCE : GPATH_OTHER; if (type == GPATH_OTHER) strbuf_puts0(addlist_other, single_update); else { strbuf_puts0(addlist, single_update); total++; } } else { /* update file */ if (type == GPATH_OTHER) goto exit; idset_add(deleteset, atoi(fid)); strbuf_puts0(addlist, single_update); total++; } } else { if (file_list) find_open_filelist(file_list, root); else find_open(NULL); while ((path = find_read()) != NULL) { const char *fid; int n_fid = 0; int other = 0; /* a blank at the head of path means 'NOT SOURCE'. */ if (*path == ' ') { if (test("b", ++path)) continue; other = 1; } if (stat(path, &statp) < 0) die("stat failed '%s'.", path); fid = gpath_path2fid(path, NULL); if (fid) { n_fid = atoi(fid); idset_add(findset, n_fid); } if (other) { if (fid == NULL) strbuf_puts0(addlist_other, path); } else { if (fid == NULL) { strbuf_puts0(addlist, path); total++; } else if (gtags_mtime < statp.st_mtime) { strbuf_puts0(addlist, path); total++; idset_add(deleteset, n_fid); } } } find_close(); /* * make delete list. */ limit = gpath_nextkey(); for (id = 1; id < limit; id++) { char fid[MAXFIDLEN]; int type; snprintf(fid, sizeof(fid), "%d", id); /* * This is a hole of GPATH. The hole increases if the deletion * and the addition are repeated. */ if ((path = gpath_fid2path(fid, &type)) == NULL) continue; /* * The file which does not exist in the findset is treated * assuming that it does not exist in the file system. */ if (type == GPATH_OTHER) { if (!idset_contains(findset, id) || !test("f", path) || test("b", path)) strbuf_puts0(deletelist, path); } else { if (!idset_contains(findset, id) || !test("f", path)) { strbuf_puts0(deletelist, path); idset_add(deleteset, id); } } } } statistics_time_end(tim); /* * execute updating. */ if ((!idset_empty(deleteset) || strbuf_getlen(addlist) > 0) || (strbuf_getlen(deletelist) + strbuf_getlen(addlist_other) > 0)) { int db; updated = 1; tim = statistics_time_start("Time of updating %s and %s.", dbname(GTAGS), dbname(GRTAGS)); if (!idset_empty(deleteset) || strbuf_getlen(addlist) > 0) updatetags(dbpath, root, deleteset, addlist); if (strbuf_getlen(deletelist) + strbuf_getlen(addlist_other) > 0) { const char *start, *end, *p; if (vflag) fprintf(stderr, "[%s] Updating '%s'.\n", now(), dbname(GPATH)); /* gpath_open(dbpath, 2); */ if (strbuf_getlen(deletelist) > 0) { start = strbuf_value(deletelist); end = start + strbuf_getlen(deletelist); for (p = start; p < end; p += strlen(p) + 1) gpath_delete(p); } if (strbuf_getlen(addlist_other) > 0) { start = strbuf_value(addlist_other); end = start + strbuf_getlen(addlist_other); for (p = start; p < end; p += strlen(p) + 1) { gpath_put(p, GPATH_OTHER); } } /* gpath_close(); */ } /* * Update modification time of tag files * because they may have no definitions. */ for (db = GTAGS; db < GTAGLIM; db++) utime(makepath(dbpath, dbname(db), NULL), NULL); statistics_time_end(tim); } exit: if (vflag) { if (updated) fprintf(stderr, " Global databases have been modified.\n"); else fprintf(stderr, " Global databases are up to date.\n"); fprintf(stderr, "[%s] Done.\n", now()); } strbuf_close(addlist); strbuf_close(deletelist); strbuf_close(addlist_other); gpath_close(); idset_close(deleteset); idset_close(findset); return updated; }