📄 getline.c
字号:
"new_GetLine: Insufficient memory to allocate undo buffer.\n"); return del_GetLine(gl); }; gl->vi.undo.line[0] = '\0';/* * Allocate a freelist from which to allocate nodes for the list * of signals. */ gl->sig_mem = _new_FreeList("new_GetLine", sizeof(GlSignalNode), GLS_FREELIST_BLOCKING); if(!gl->sig_mem) return del_GetLine(gl);/* * Install dispositions for the default list of signals that gl_get_line() * traps. */ for(i=0; i<sizeof(gl_signal_list)/sizeof(gl_signal_list[0]); i++) { const struct GlDefSignal *sig = gl_signal_list + i; if(gl_trap_signal(gl, sig->signo, sig->flags, sig->after, sig->errno_value)) return del_GetLine(gl); };/* * Allocate an empty table of key bindings. */ gl->bindings = _new_KeyTab(); if(!gl->bindings) return del_GetLine(gl);/* * Define the available actions that can be bound to key sequences. */ for(i=0; i<sizeof(gl_actions)/sizeof(gl_actions[0]); i++) { if(_kt_set_action(gl->bindings, gl_actions[i].name, gl_actions[i].fn)) return del_GetLine(gl); };/* * Set up the default bindings. */ if(gl_change_editor(gl, gl->editor)) return del_GetLine(gl);/* * Allocate termcap buffers. */#ifdef USE_TERMCAP gl->tgetent_buf = (char *) malloc(TERMCAP_BUF_SIZE); gl->tgetstr_buf = (char *) malloc(TERMCAP_BUF_SIZE); if(!gl->tgetent_buf || !gl->tgetstr_buf) { fprintf(stderr, "new_GetLine: Insufficient memory for termcap buffers.\n"); return del_GetLine(gl); };#endif/* * Set up for I/O assuming stdin and stdout. */ if(gl_change_terminal(gl, stdin, stdout, getenv("TERM"))) return del_GetLine(gl);/* * Create a freelist for use in allocating GlFdNode list nodes. */#ifdef HAVE_SELECT gl->fd_node_mem = _new_FreeList("new_GetLine", sizeof(GlFdNode), GLFD_FREELIST_BLOCKING); if(!gl->fd_node_mem) return del_GetLine(gl);#endif/* * We are done for now. */ return gl;}/*....................................................................... * Delete a GetLine object. * * Input: * gl GetLine * The object to be deleted. * Output: * return GetLine * The deleted object (always NULL). */GetLine *del_GetLine(GetLine *gl){ if(gl) { gl->glh = _del_GlHistory(gl->glh); gl->cpl = del_WordCompletion(gl->cpl); gl->ef = del_ExpandFile(gl->ef); gl->capmem = _del_StringGroup(gl->capmem); if(gl->line) free(gl->line); if(gl->cutbuf) free(gl->cutbuf); if(gl->vi.undo.line) free(gl->vi.undo.line); gl->sig_mem = _del_FreeList(NULL, gl->sig_mem, 1); gl->sigs = NULL; /* Already freed by freeing sig_mem */ gl->bindings = _del_KeyTab(gl->bindings);#ifdef USE_TERMCAP if(gl->tgetent_buf) free(gl->tgetent_buf); if(gl->tgetstr_buf) free(gl->tgetstr_buf);#endif if(gl->file_fp) fclose(gl->file_fp); if(gl->term) free(gl->term);#ifdef HAVE_SELECT gl->fd_node_mem = _del_FreeList(NULL, gl->fd_node_mem, 1);#endif free(gl); }; return NULL;}/*....................................................................... * Bind a control or meta character to an action. * * Input: * gl GetLine * The resource object of this program. * binder KtBinder The source of the binding. * c char The control or meta character. * If this is '\0', the call is ignored. * action const char * The action name to bind the key to. * Output: * return int 0 - OK. * 1 - Error. */static int gl_bind_control_char(GetLine *gl, KtBinder binder, char c, const char *action){ char keyseq[2];/* * Quietly reject binding to the NUL control character, since this * is an ambiguous prefix of all bindings. */ if(c == '\0') return 0;/* * Making sure not to bind characters which aren't either control or * meta characters. */ if(IS_CTRL_CHAR(c) || IS_META_CHAR(c)) { keyseq[0] = c; keyseq[1] = '\0'; } else { return 0; };/* * Install the binding. */ return _kt_set_keybinding(gl->bindings, binder, keyseq, action);}/*....................................................................... * Read a line from the user. * * Input: * gl GetLine * A resource object returned by new_GetLine(). * prompt char * The prompt to prefix the line with. * start_line char * The initial contents of the input line, or NULL * if it should start out empty. * start_pos int If start_line isn't NULL, this specifies the * index of the character over which the cursor * should initially be positioned within the line. * If you just want it to follow the last character * of the line, send -1. * Output: * return char * An internal buffer containing the input line, or * NULL at the end of input. If the line fitted in * the buffer there will be a '\n' newline character * before the terminating '\0'. If it was truncated * there will be no newline character, and the remains * of the line should be retrieved via further calls * to this function. */char *gl_get_line(GetLine *gl, const char *prompt, const char *start_line, int start_pos){ int waserr = 0; /* True if an error occurs */ gl->is_net = 0; /* Reset the 'is_net' flag */ gl->net_may_block = 0; gl->net_read_attempt = 0; gl->user_event_value = 0;/* * Check the arguments. */ if(!gl || !prompt) { fprintf(stderr, "gl_get_line: NULL argument(s).\n"); return NULL; };/* * If this is the first call to this function since new_GetLine(), * complete any postponed configuration. */ if(!gl->configured) { (void) gl_configure_getline(gl, NULL, NULL, TECLA_CONFIG_FILE); gl->configured = 1; };/* * If input is temporarily being taken from a file, return lines * from the file until the file is exhausted, then revert to * the normal input stream. */ if(gl->file_fp) { if(fgets(gl->line, gl->linelen, gl->file_fp)) return gl->line; gl_revert_input(gl); };/* * Is input coming from a non-interactive source? */ if(!gl->is_term) return fgets(gl->line, gl->linelen, gl->input_fp);/* * Record the new prompt and its displayed width. */ gl_replace_prompt(gl, prompt);/* * Before installing our signal handler functions, record the fact * that there are no pending signals. */ gl_pending_signal = -1;/* * Temporarily override the signal handlers of the calling program, * so that we can intercept signals that would leave the terminal * in a bad state. */ waserr = gl_override_signal_handlers(gl);/* * After recording the current terminal settings, switch the terminal * into raw input mode. */ waserr = waserr || gl_raw_terminal_mode(gl);/* * Attempt to read the line. */ waserr = waserr || gl_get_input_line(gl, start_line, start_pos, -1);/* * Restore terminal settings. */ gl_restore_terminal_attributes(gl);/* * Restore the signal handlers. */ gl_restore_signal_handlers(gl);/* * Having restored the program terminal and signal environment, * re-submit any signals that were received. */ if(gl_pending_signal != -1) { raise(gl_pending_signal); waserr = 1; };/* * If gl_get_input_line() aborted input due to the user asking to * temporarily read lines from a file, read the first line from * this file. */ if(!waserr && gl->file_fp) return gl_get_line(gl, prompt, NULL, 0);/* * Return the new input line. */ return waserr ? NULL : gl->line;}/*....................................................................... * Record of the signal handlers of the calling program, so that they * can be restored later. * * Input: * gl GetLine * The resource object of this library. * Output: * return int 0 - OK. * 1 - Error. */static int gl_override_signal_handlers(GetLine *gl){#ifndef __MINGW32__ GlSignalNode *sig; /* A node in the list of signals to be caught *//* * Set up our signal handler. */ SigAction act; act.sa_handler = gl_signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0;/* * Get the process signal mask so that we can see which signals the * calling program currently has blocked, and so that we can restore this * mask before returning to the calling program. */ if(sigprocmask(SIG_SETMASK, NULL, &gl->old_signal_set) == -1) { fprintf(stderr, "gl_get_line(): sigprocmask error: %s\n", strerror(errno)); return 1; };/* * Form a new process signal mask from the list of signals that we have * been asked to trap. */ sigemptyset(&gl->new_signal_set); for(sig=gl->sigs; sig; sig=sig->next) {/* * Trap this signal? If it is blocked by the calling program and we * haven't been told to unblock it, don't arrange to trap this signal. */ if(sig->flags & GLS_UNBLOCK_SIG || !sigismember(&gl->old_signal_set, sig->signo)) { if(sigaddset(&gl->new_signal_set, sig->signo) == -1) { fprintf(stderr, "gl_get_line(): sigaddset error: %s\n", strerror(errno)); return 1; }; }; };/* * Before installing our signal handlers, block all of the signals * that we are going to be trapping. */ if(sigprocmask(SIG_BLOCK, &gl->new_signal_set, NULL) == -1) { fprintf(stderr, "gl_get_line(): sigprocmask error: %s\n", strerror(errno)); return 1; };/* * Override the actions of the signals that we are trapping. */ for(sig=gl->sigs; sig; sig=sig->next) { if(sigismember(&gl->new_signal_set, sig->signo) && sigaction(sig->signo, &act, &sig->original)) { fprintf(stderr, "gl_get_line(): sigaction error: %s\n", strerror(errno)); return 1; }; };/* * Just in case a SIGWINCH signal was sent to the process while our * SIGWINCH signal handler wasn't in place, check to see if the terminal * size needs updating. */#ifdef USE_SIGWINCH if (gl->is_term) { if(gl_resize_terminal(gl, 0)) return 1; }#endif#endif /* __MINGW32__ */ return 0;}/*....................................................................... * Restore the signal handlers of the calling program. * * Input: * gl GetLine * The resource object of this library. * Output: * return int 0 - OK. * 1 - Error. */static int gl_restore_signal_handlers(GetLine *gl){#ifndef __MINGW32__ GlSignalNode *sig; /* A node in the list of signals to be caught *//* * Restore application signal handlers that were overriden * by gl_override_signal_handlers(). */ for(sig=gl->sigs; sig; sig=sig->next) { if(sigismember(&gl->new_signal_set, sig->signo) && sigaction(sig->signo, &sig->original, NULL)) { fprintf(stderr, "gl_get_line(): sigaction error: %s\n", strerror(errno)); return 1; }; };/* * Restore the original signal mask. */ if(sigprocmask(SIG_SETMASK, &gl->old_signal_set, NULL) == -1) { fprintf(stderr, "gl_get_line(): sigprocmask error: %s\n", strerror(errno)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -