This is request.c in view mode; [Download] [Up]
/* Requester handling. Copyright (C) 1993 Sebastiano Vigna This file is part of ne, the nice editor. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve what you give them. Help stamp out software-hoarding! */ #include "ne.h" #include "termchar.h" #include <dirent.h> /* This is the expected max length of the current directory name. */ #define CUR_DIR_MAX_SIZE 4096 /* This is the name taken by unnamed documents in the document selector. */ #define UNNAMED_NAME "<unnamed>" /* These are the default allocation sizes for the entry array and for the name array when reading a directory. The allocation sizes start with these values, and they are doubled each time more space is needed. This ensures a reasonable number of retries. */ #define DEF_ENTRIES_ALLOC_SIZE 256 #define DEF_NAMES_ALLOC_SIZE (4*1024) /* This function prompts the user to choose one between several (num_entries) strings, contained in the entries array. The maximum string width is given as max_name_len. The strings are displayed as an array. More than one page will be available if there are many strings. The number of the selected string is returned, or -1 on escaping. We rely on a series of auxiliary functions. */ static int x, y, page, names_per_line, names_per_page, num_entries, max_name_len; static const char * const *entries; /* This is the printing function used by the requester. It prints the strings from the entries array existing in a certain page (a page contains (lines-1)*names_per_line items) with max_name_len maximum width. */ static void print_strings(void) { int i,j; for(i=0; i<lines-1; i++) { move_cursor(i, 0); clear_to_eol(); for(j=0; j<names_per_line; j++) { if ((i+page*(lines-1))*names_per_line+j<num_entries) { move_cursor(i, j*max_name_len); output_string(entries[(i+page*(lines-1))*names_per_line+j]); } } } } static void request_move_to_sof(void) { int i = page; x = y = page = 0; if (i != page) print_strings(); } static void request_move_to_eof(void) { int i = page; page = (num_entries-1)/names_per_page; y = ((num_entries-1) % names_per_page) / names_per_line; x = (num_entries-1) % names_per_line; if (i != page) print_strings(); } static void request_toggle_seof(void) { if (x+y+page == 0) request_move_to_eof(); else request_move_to_sof(); } static void request_prev_page(int force) { if (!force && y>0) y = 0; else if (page) { page--; print_strings(); } } static void request_next_page(int force) { if (!force && y<lines-2) y = lines-2; else if ((page+1)*names_per_page < num_entries) { page++; print_strings(); } if (page*names_per_page+y*names_per_line+x >= num_entries) request_move_to_eof(); } static void request_move_up(void) { if (y>0) y--; else if (page) { y = lines-2; request_prev_page(TRUE); } } static void request_move_down(void) { if (page*names_per_page+(y+1)*names_per_line+x >= num_entries) request_move_to_eof(); else if (y<lines-2) y++; else if (page < num_entries/names_per_page) { y = 0; request_next_page(TRUE); } } int request_strings(const char * const * const local_entries, int local_num_entries, int local_max_name_len) { action a; input_class ic; int c, i, n; assert(local_num_entries > 0); x = y = page = 0; entries = local_entries; num_entries = local_num_entries; max_name_len = local_max_name_len; if (!(names_per_line = columns / (++max_name_len))) names_per_line = 1; names_per_page = names_per_line*(lines-1); print_strings(); while(TRUE) { move_cursor(y, x*max_name_len); while((ic = char_class[c = get_key_code()]) == IGNORE); switch(ic) { case ALPHA: if ((n = page*names_per_page+y*names_per_line+x) >= num_entries) n = num_entries-1; c = up_case[(unsigned char)c]; for(i=1; i<num_entries; i++) if (up_case[(unsigned char)entries[(n+i) % num_entries][0]] == c) { n = (n+i) % num_entries; if (n/names_per_page != page) { page = n/names_per_page; print_strings(); } y = (n % names_per_page) / names_per_line; x = n % names_per_line; break; } break; case RETURN: n = page*names_per_page+y*names_per_line+x; if (n >= num_entries) return(-1); else return(n); case COMMAND: if ((a = parse_command_line(key_binding[c], NULL, NULL, FALSE))>=0) { switch(a) { case MOVE_RIGHT: if (page*names_per_page+y*names_per_line+x != num_entries-1) { if (++x == names_per_line) { x = 0; request_move_down(); } } break; case MOVE_LEFT: if (x+y+page != 0) { if (--x<0) { x = names_per_line-1; request_move_up(); } } break; case MOVE_TO_SOL: x = 0; break; case MOVE_TO_EOL: x = names_per_line-1; break; case TOGGLE_SOL_EOL: if (x != 0) x = 0; else x = names_per_line-1; break; case LINE_UP: if (page+y != 0) request_move_up(); break; case LINE_DOWN: if (page*(lines-1)+y < (num_entries+names_per_line-1)/names_per_line-1) request_move_down(); break; case PREV_PAGE: request_prev_page(FALSE); break; case NEXT_PAGE: request_next_page(FALSE); break; case MOVE_TO_SOF: request_move_to_sof(); break; case MOVE_TO_EOF: request_move_to_eof(); break; case TOGGLE_SOF_EOF: request_toggle_seof(); break; case ESCAPE: return(-1); } } break; default: break; } } } /* This is the file requester. It reads the directory in which the filename lives, builds an array of string and calls request_strings(). If a directory name is returned, it enters the directory. Returns NULL on error or escaping. */ char *request_files(const char *filename) { int i, num_entries, name_len, max_name_len, total_len, next_dir, is_directory, entries_alloc_size = DEF_ENTRIES_ALLOC_SIZE, names_alloc_size = DEF_NAMES_ALLOC_SIZE; char *dir_name, **entries = NULL, *names = NULL, *cur_dir_name, *result = NULL, *p; DIR *d; struct dirent *de; struct stat s; if (!(cur_dir_name = getcwd(NULL, CUR_DIR_MAX_SIZE))) return(NULL); if (dir_name = str_dup(filename)) { if ((p = (char *)file_part(dir_name)) != dir_name) { *p = 0; chdir(tilde_expand(dir_name)); } free(dir_name); } if (entries = malloc(sizeof(char *)*entries_alloc_size)) { if (names = malloc(sizeof(char)*names_alloc_size)) { do { next_dir = FALSE; if (d = opendir(CURDIR)) { num_entries = max_name_len = total_len = 0; #ifdef _AMIGA total_len = 2; num_entries++; strcpy(names, "/"); entries[0] = names; #endif stop = FALSE; while(!stop && (de = readdir(d))) { is_directory = !stat(de->d_name, &s) && S_ISDIR(s.st_mode); name_len = strlen(de->d_name) + is_directory + 1; if (name_len > max_name_len) max_name_len = name_len; if (total_len+name_len > names_alloc_size) { char *t; t = realloc(names, sizeof(char)*(names_alloc_size = names_alloc_size*2 + name_len)); if (!t) break; names = t; } if (num_entries >= entries_alloc_size) { char **t; t = realloc(entries, sizeof(char *)*(entries_alloc_size *= 2)); if (!t) break; entries = t; } strcpy(entries[num_entries] = names+total_len, de->d_name); if (is_directory) strcpy(names+total_len+name_len-2, "/"); total_len += name_len; num_entries++; } if (num_entries) { #ifdef _AMIGA if (num_entries-1) qsort(entries+1, num_entries-1, sizeof(char *), strcmpp); #else if (num_entries-2 >= 0) { if (!strcmp(entries[0], "./") && !strcmp(entries[1], "../")) { p = entries[0]; entries[0] = entries[1]; entries[1] = p; } if (num_entries-2 > 0 ) qsort(entries+2, num_entries-2, sizeof(char *), strcmpp); } #endif if ((i = request_strings((const char * const *)entries, num_entries, max_name_len)) >= 0) { p = entries[i]; if (p[strlen(p)-1] == '/') { #ifndef _AMIGA p[strlen(p)-1] = 0; #endif chdir(p); next_dir = TRUE; } else { result = getcwd(NULL, CUR_DIR_MAX_SIZE+strlen(p)); strcat(result, "/"); strcat(result, p); } } } closedir(d); } } while(next_dir); free(names); } free(entries); } chdir(cur_dir_name); free(cur_dir_name); return(result); } /* This function requests a file name. If no_file_req is FALSE, the file requester is firstly presented. If no_file_req is TRUE, or the file requester is escaped, a long input is performed with the given prompt and default_name. */ char *request_file(buffer *b, const char *prompt, const char *default_name) { char *p; if (!b->no_file_req) { p = request_files(default_name); reset_window(); if (p) return(p); } if (p = request_string(prompt, default_name, FALSE)) return(p); return(NULL); } /* This function presents to the user a list of the documents currently available. It returns the number of the document selected, or -1 on escape or error. */ int request_document(void) { int i = -1, num_entries, max_name_len, total_len; char **entries, *names, *p, unnamed_name[] = UNNAMED_NAME; buffer *b = (buffer *)buffers.head; num_entries = max_name_len = total_len = 0; while(b->b_node.next) { p = b->filename ? b->filename : unnamed_name; if (strlen(p)>max_name_len) max_name_len = strlen(p); total_len += strlen(p)+1; num_entries++; b = (buffer *)b->b_node.next; } max_name_len += 8; if (num_entries) { if (entries = malloc(sizeof(char *)*num_entries)) { if (names = malloc(sizeof(char)*total_len)) { p = names; b = (buffer *)buffers.head; for(i=0; i<num_entries; i++) { entries[i] = p; strcpy(p, b->filename ? b->filename : unnamed_name); p += strlen(p)+1; b = (buffer *)b->b_node.next; } i = request_strings((const char * const *)entries, num_entries, max_name_len); reset_window(); free(names); } free(entries); } } return(i); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.