📄 gtkfilesel.c
字号:
struct stat ent_sbuf; char path_buf[MAXPATHLEN*2]; gint path_buf_len; sent = g_new(CompletionDirSent, 1); sent->mtime = sbuf->st_mtime; sent->inode = sbuf->st_ino; sent->device = sbuf->st_dev; path_buf_len = strlen(dir_name); if (path_buf_len > MAXPATHLEN) { cmpl_errno = CMPL_ERRNO_TOO_LONG; return NULL; } strcpy(path_buf, dir_name); directory = opendir(dir_name); if(!directory) { cmpl_errno = errno; return NULL; } while((dirent_ptr = readdir(directory)) != NULL) { int entry_len = strlen(dirent_ptr->d_name); buffer_size += entry_len + 1; entry_count += 1; if(path_buf_len + entry_len + 2 >= MAXPATHLEN) { cmpl_errno = CMPL_ERRNO_TOO_LONG; closedir(directory); return NULL; } } sent->name_buffer = g_new(gchar, buffer_size); sent->entries = g_new(CompletionDirEntry, entry_count); sent->entry_count = entry_count; buffer_ptr = sent->name_buffer; rewinddir(directory); for(i = 0; i < entry_count; i += 1) { dirent_ptr = readdir(directory); if(!dirent_ptr) { cmpl_errno = errno; closedir(directory); return NULL; } strcpy(buffer_ptr, dirent_ptr->d_name); sent->entries[i].entry_name = buffer_ptr; buffer_ptr += strlen(dirent_ptr->d_name); *buffer_ptr = 0; buffer_ptr += 1; path_buf[path_buf_len] = '/'; strcpy(path_buf + path_buf_len + 1, dirent_ptr->d_name); if (stat_subdirs) { if(stat(path_buf, &ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) sent->entries[i].is_dir = 1; else /* stat may fail, and we don't mind, since it could be a * dangling symlink. */ sent->entries[i].is_dir = 0; } else sent->entries[i].is_dir = 1; } qsort(sent->entries, sent->entry_count, sizeof(CompletionDirEntry), compare_cmpl_dir); closedir(directory); return sent;}static gbooleancheck_dir(gchar *dir_name, struct stat *result, gboolean *stat_subdirs){ /* A list of directories that we know only contain other directories. * Trying to stat every file in these directories would be very * expensive. */ static struct { gchar *name; gboolean present; struct stat statbuf; } no_stat_dirs[] = { { "/afs", FALSE, { 0 } }, { "/net", FALSE, { 0 } } }; static const gint n_no_stat_dirs = sizeof(no_stat_dirs) / sizeof(no_stat_dirs[0]); static gboolean initialized = FALSE; gint i; if (!initialized) { initialized = TRUE; for (i = 0; i < n_no_stat_dirs; i++) { if (stat (no_stat_dirs[i].name, &no_stat_dirs[i].statbuf) == 0) no_stat_dirs[i].present = TRUE; } } if(stat(dir_name, result) < 0) { cmpl_errno = errno; return FALSE; } *stat_subdirs = TRUE; for (i=0; i<n_no_stat_dirs; i++) { if (no_stat_dirs[i].present && (no_stat_dirs[i].statbuf.st_dev == result->st_dev) && (no_stat_dirs[i].statbuf.st_ino == result->st_ino)) { *stat_subdirs = FALSE; break; } } return TRUE;}/* open a directory by absolute pathname */static CompletionDir*open_dir(gchar* dir_name, CompletionState* cmpl_state){ struct stat sbuf; gboolean stat_subdirs; CompletionDirSent *sent; GList* cdsl; if (!check_dir (dir_name, &sbuf, &stat_subdirs)) return NULL; cdsl = cmpl_state->directory_sent_storage; while (cdsl) { sent = cdsl->data; if(sent->inode == sbuf.st_ino && sent->mtime == sbuf.st_mtime && sent->device == sbuf.st_dev) return attach_dir(sent, dir_name, cmpl_state); cdsl = cdsl->next; } sent = open_new_dir(dir_name, &sbuf, stat_subdirs); if (sent) { cmpl_state->directory_sent_storage = g_list_prepend(cmpl_state->directory_sent_storage, sent); return attach_dir(sent, dir_name, cmpl_state); } return NULL;}static CompletionDir*attach_dir(CompletionDirSent* sent, gchar* dir_name, CompletionState *cmpl_state){ CompletionDir* new_dir; new_dir = g_new(CompletionDir, 1); cmpl_state->directory_storage = g_list_prepend(cmpl_state->directory_storage, new_dir); new_dir->sent = sent; new_dir->fullname = g_strdup(dir_name); new_dir->fullname_len = strlen(dir_name); return new_dir;}static gintcorrect_dir_fullname(CompletionDir* cmpl_dir){ gint length = strlen(cmpl_dir->fullname); struct stat sbuf; if (strcmp(cmpl_dir->fullname + length - 2, "/.") == 0) { if (length == 2) { strcpy(cmpl_dir->fullname, "/"); cmpl_dir->fullname_len = 1; return TRUE; } else { cmpl_dir->fullname[length - 2] = 0; } } else if (strcmp(cmpl_dir->fullname + length - 3, "/./") == 0) cmpl_dir->fullname[length - 2] = 0; else if (strcmp(cmpl_dir->fullname + length - 3, "/..") == 0) { if(length == 3) { strcpy(cmpl_dir->fullname, "/"); cmpl_dir->fullname_len = 1; return TRUE; } if(stat(cmpl_dir->fullname, &sbuf) < 0) { cmpl_errno = errno; return FALSE; } cmpl_dir->fullname[length - 2] = 0; if(!correct_parent(cmpl_dir, &sbuf)) return FALSE; } else if (strcmp(cmpl_dir->fullname + length - 4, "/../") == 0) { if(length == 4) { strcpy(cmpl_dir->fullname, "/"); cmpl_dir->fullname_len = 1; return TRUE; } if(stat(cmpl_dir->fullname, &sbuf) < 0) { cmpl_errno = errno; return FALSE; } cmpl_dir->fullname[length - 3] = 0; if(!correct_parent(cmpl_dir, &sbuf)) return FALSE; } cmpl_dir->fullname_len = strlen(cmpl_dir->fullname); return TRUE;}static gintcorrect_parent(CompletionDir* cmpl_dir, struct stat *sbuf){ struct stat parbuf; gchar *last_slash; gchar *new_name; gchar c = 0; last_slash = strrchr(cmpl_dir->fullname, '/'); g_assert(last_slash); if(last_slash != cmpl_dir->fullname) { /* last_slash[0] = 0; */ } else { c = last_slash[1]; last_slash[1] = 0; } if (stat(cmpl_dir->fullname, &parbuf) < 0) { cmpl_errno = errno; return FALSE; } if (parbuf.st_ino == sbuf->st_ino && parbuf.st_dev == sbuf->st_dev) /* it wasn't a link */ return TRUE; if(c) last_slash[1] = c; /* else last_slash[0] = '/'; */ /* it was a link, have to figure it out the hard way */ new_name = find_parent_dir_fullname(cmpl_dir->fullname); if (!new_name) return FALSE; g_free(cmpl_dir->fullname); cmpl_dir->fullname = new_name; return TRUE;}static gchar*find_parent_dir_fullname(gchar* dirname){ gchar buffer[MAXPATHLEN]; gchar buffer2[MAXPATHLEN];#if defined(sun) && !defined(__SVR4) if(!getwd(buffer))#else if(!getcwd(buffer, MAXPATHLEN))#endif { cmpl_errno = errno; return NULL; } if(chdir(dirname) != 0 || chdir("..") != 0) { cmpl_errno = errno; return NULL; }#if defined(sun) && !defined(__SVR4) if(!getwd(buffer2))#else if(!getcwd(buffer2, MAXPATHLEN))#endif { chdir(buffer); cmpl_errno = errno; return NULL; } if(chdir(buffer) != 0) { cmpl_errno = errno; return NULL; } return g_strdup(buffer2);}/**********************************************************************//* Completion Operations *//**********************************************************************/static PossibleCompletion*attempt_homedir_completion(gchar* text_to_complete, CompletionState *cmpl_state){ gint index, length; if (!cmpl_state->user_dir_name_buffer && !get_pwdb(cmpl_state)) return NULL; length = strlen(text_to_complete) - 1; cmpl_state->user_completion_index += 1; while(cmpl_state->user_completion_index < cmpl_state->user_directories_len) { index = first_diff_index(text_to_complete + 1, cmpl_state->user_directories [cmpl_state->user_completion_index].login); switch(index) { case PATTERN_MATCH: break; default: if(cmpl_state->last_valid_char < (index + 1)) cmpl_state->last_valid_char = index + 1; cmpl_state->user_completion_index += 1; continue; } cmpl_state->the_completion.is_a_completion = 1; cmpl_state->the_completion.is_directory = 1; append_completion_text("~", cmpl_state); append_completion_text(cmpl_state-> user_directories[cmpl_state->user_completion_index].login, cmpl_state); return append_completion_text("/", cmpl_state); } if(text_to_complete[1] || cmpl_state->user_completion_index > cmpl_state->user_directories_len) { cmpl_state->user_completion_index = -1; return NULL; } else { cmpl_state->user_completion_index += 1; cmpl_state->the_completion.is_a_completion = 1; cmpl_state->the_completion.is_directory = 1; return append_completion_text("~/", cmpl_state); }}/* returns the index (>= 0) of the first differing character, * PATTERN_MATCH if the completion matches */static gintfirst_diff_index(gchar* pat, gchar* text){ gint diff = 0; while(*pat && *text && *text == *pat) { pat += 1; text += 1; diff += 1; } if(*pat) return diff; return PATTERN_MATCH;}static PossibleCompletion*append_completion_text(gchar* text, CompletionState* cmpl_state){ gint len, i = 1; if(!cmpl_state->the_completion.text) return NULL; len = strlen(text) + strlen(cmpl_state->the_completion.text) + 1; if(cmpl_state->the_completion.text_alloc > len) { strcat(cmpl_state->the_completion.text, text); return &cmpl_state->the_completion; } while(i < len) { i <<= 1; } cmpl_state->the_completion.text_alloc = i; cmpl_state->the_completion.text = (gchar*)g_realloc(cmpl_state->the_completion.text, i); if(!cmpl_state->the_completion.text) return NULL; else { strcat(cmpl_state->the_completion.text, text); return &cmpl_state->the_completion; }}static CompletionDir*find_completion_dir(gchar* text_to_complete, gchar** remaining_text, CompletionState* cmpl_state){ gchar* first_slash = strchr(text_to_complete, '/'); CompletionDir* dir = cmpl_state->reference_dir; CompletionDir* next; *remaining_text = text_to_complete; while(first_slash) { gint le
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -