/* * Back-end misc module * See "diff.h" for the details of data structure. * This module should be independent from GUI frontend. * * Copyright INOUE Seiichiro , licensed under the GPL. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include "diff.h" /* NOTE: * Most of the routines doesn't modify DiffFiles argument. * However, I can't specify 'const' modifier, * because dfiles_get_fileinfo() requires 'non-const' argument. * Refer to "diffdata.c" about why dfiles_get_fileinfo() does so. */ /** * dfiles_get_status: * See "diff.h" about enum FilesStatus. * No need to check fi3. **/ FilesStatus dfiles_get_status(DiffFiles *dfiles) { const FileInfo *fi1 = dfiles_get_fileinfo(dfiles, FIRST_FILE, FALSE); const FileInfo *fi2 = dfiles_get_fileinfo(dfiles, SECOND_FILE, FALSE); /* Checking order does matter */ if (dfiles->binary) return BINARY_FILES; if (fi1->fname[0] == '\0') return ONLY_FILE2_EXISTS; if (fi2->fname[0] == '\0') return ONLY_FILE1_EXISTS; if (fi1->f_dir == TRUE) { /* double check */ if (fi2->f_dir == FALSE) { g_warning("something wrong in dfiles_get_status()\n"); } return DIRECTORIES; } if (dfiles->dlines_list == NULL) return IDENTICAL_FILES; return DIFFERENT_FILES; } /** * dfiles_has_file_modified: * Check the files have been modified. * If a file has been modified by the other process, * mmap'ed memory is also modified. * Some operations depend on mmap'ed memory, so this check is necessary. * Checking only mtime is insufficient, * because you can change mtime to arbitrary value, e.g. by 'touch' command. **/ FileModStatue dfiles_has_file_modified(DiffFiles *dfiles) { int n; /* This function doesn't matter unless they are comparable files. */ if (dfiles_get_status(dfiles) != DIFFERENT_FILES) return MOD_DONTCARE; for (n = 0; n < MAX_NUM_COMPARE_FILES; n++) { const FileInfo *fi = dfiles_get_fileinfo(dfiles, n, FALSE); struct stat sb; if (!fi->fname[0]) continue; if (stat(fi->fname, &sb) == -1) { g_warning("%s: stat in dfiles_is_file_modified()", fi->fname); return MOD_ERROR; } if (sb.st_mtime > fi->mtime || sb.st_ctime > fi->ctime) return MOD_MODIFIED; } return MOD_NOT_MODIFIED; } /** * dfiles_calc_total_nlines: * Calculate the tolal number of different lines, and return it. * Note: in diff3 case, the third dlines->nlines is zero. **/ int dfiles_calc_total_nlines(const DiffFiles *dfiles, WhichFile n) { GList *list;/* Doubly linked list of DiffLines */ int ret_nlines = 0; for (list = dfiles->dlines_list; list; list = list->next) { DiffLines *dlines = list->data; if (n == FIRST_FILE && (dlines->difftype & F2ONLY || dlines->difftype & F3ONLY || dlines->difftype & F23ADD)) continue; if (n == SECOND_FILE && (dlines->difftype & F1ONLY || dlines->difftype & F3ONLY || dlines->difftype & F31ADD)) continue; if (n == THIRD_FILE && (dlines->difftype & F1ONLY || dlines->difftype & F2ONLY || dlines->difftype & F12ADD)) continue; ret_nlines += dlines->between[n].end - dlines->between[n].begin + 1; } return ret_nlines; } /** * dfiles_get_max_nlines: * Compare the number of lines of thefiles, and return one of the bigger. * Input: * (const)DiffFiles *dfiles; * Output: * Return value; The number of lines of the bigger. **/ int dfiles_get_max_nlines(DiffFiles *dfiles) { const FileInfo *fi1 = dfiles_get_fileinfo(dfiles, FIRST_FILE, TRUE); const FileInfo *fi2 = dfiles_get_fileinfo(dfiles, SECOND_FILE, TRUE); const FileInfo *fi3 = dfiles_get_fileinfo(dfiles, THIRD_FILE, TRUE); int tmp; tmp = (fi1->nlines > fi2->nlines) ? fi1->nlines : fi2->nlines; return (tmp > fi3->nlines) ? tmp : fi3->nlines; } /* * DiffFindFunc functions: * Using the current difference, find a specified difference, * and return it. * The return value is an internal data, * so it shouldn't be modified by the caller. * Input: * const DiffFiles *dfiles; * const GList *cur_dlines_node; the current difference. * Output: * Return value; GList of DiffLines */ /** * dfiles_get_curl: * Return the current different lines. **/ const GList* dfiles_get_curl(const DiffFiles *dfiles, const GList *cur_dlines_node) { return cur_dlines_node; } /** * dfiles_get_firstl: * Return the first different lines. **/ const GList* dfiles_get_firstl(const DiffFiles *dfiles, const GList *cur_dlines_node) { if (cur_dlines_node) return g_list_first((GList*)cur_dlines_node); else return dfiles->dlines_list; } /** * dfiles_get_lastl: * Return the last different lines. **/ const GList* dfiles_get_lastl(const DiffFiles *dfiles, const GList *cur_dlines_node) { if (cur_dlines_node) return g_list_last((GList*)cur_dlines_node); else return g_list_last(dfiles->dlines_list); } /** * dfiles_find_nextl: * Return the next different lines. **/ const GList* dfiles_find_nextl(const DiffFiles *dfiles, const GList *cur_dlines_node) { if (cur_dlines_node) return g_list_next((GList*)cur_dlines_node); else return dfiles->dlines_list;/* first one */ } /** * dfiles_find_prevl: * Return the previous different lines. **/ const GList* dfiles_find_prevl(const DiffFiles *dfiles, const GList *cur_dlines_node) { if (cur_dlines_node) return g_list_previous((GList*)cur_dlines_node); else return g_list_last(dfiles->dlines_list); } /** * dfiles_find_rel_curl: * Return the _relative_ current different lines. **/ const GList* dfiles_find_rel_curl(const DiffFiles *dfiles, WhichFile n, int cur_line) { const GList *list;/* Doubly linked list of DiffLines */ for (list = dfiles->dlines_list; list; list = list->next) { const DiffLines *dlines = list->data; if (dlines->between[n].begin == cur_line) { return list; } } return NULL; } /** * dfiles_find_rel_nextl: * Return the _relative_ next different lines. **/ const GList* dfiles_find_rel_nextl(const DiffFiles *dfiles, WhichFile n, int cur_line) { const GList *list;/* Doubly linked list of DiffLines */ for (list = dfiles->dlines_list; list; list = list->next) { const DiffLines *dlines = list->data; if (dlines->between[n].begin > cur_line) { return list; } } return NULL; } /** * dfiles_find_rel_prevl: * Return the _relative_ previous different lines. **/ const GList* dfiles_find_rel_prevl(const DiffFiles *dfiles, WhichFile n, int cur_line) { const GList *list;/* Doubly linked list of DiffLines */ const GList *prev_list; for (list = prev_list = dfiles->dlines_list; list; list = list->next) { const DiffLines *dlines = list->data; if (dlines->between[n].end > cur_line) { return prev_list; } prev_list = list; } return NULL; } /** * dfiles_find_includel: * Return the different lines that includes @cur_line. **/ const GList* dfiles_find_includel(const DiffFiles *dfiles, WhichFile n, int cur_line) { const GList *list;/* Doubly linked list of DiffLines */ for (list = dfiles->dlines_list; list; list = list->next) { const DiffLines *dlines = list->data; if (dlines->between[n].begin <= cur_line && cur_line <= dlines->between[n].end) { return list; } } return NULL; }