/*! * @brief structを登録する */ int register_struct_tree(char *label, char *argument) { STRUCT_TREE *now_struct_tree = NULL; STRUCT_TREE *old_struct_tree = NULL; now_struct_tree = struct_tree_top; while(now_struct_tree != NULL){ old_struct_tree = now_struct_tree; now_struct_tree = now_struct_tree->next_ptr; } now_struct_tree = (STRUCT_TREE *)calloc(sizeof(STRUCT_TREE),1); now_struct_tree->prev_ptr = old_struct_tree; now_struct_tree->next_ptr = NULL; if(struct_tree_top == NULL){ struct_tree_top = now_struct_tree; }else{ old_struct_tree->next_ptr = now_struct_tree; } now_struct_tree->label = charalloc(label); now_struct_tree->argument = charalloc(argument); return 0; }
/* This function is equivalent to strncasecmp() for multibyte * strings. */ int mbstrncasecmp(const char *s1, const char *s2, size_t n) { #ifdef ENABLE_UTF8 if (use_utf8) { char *s1_mb, *s2_mb; wchar_t ws1, ws2; if (s1 == s2) return 0; assert(s1 != NULL && s2 != NULL); s1_mb = charalloc(MB_CUR_MAX); s2_mb = charalloc(MB_CUR_MAX); for (; *s1 != '\0' && *s2 != '\0' && n > 0; s1 += move_mbright(s1, 0), s2 += move_mbright(s2, 0), n--) { bool bad_s1_mb = FALSE, bad_s2_mb = FALSE; int s1_mb_len, s2_mb_len; s1_mb_len = parse_mbchar(s1, s1_mb, NULL); if (mbtowc(&ws1, s1_mb, s1_mb_len) < 0) { mbtowc_reset(); ws1 = (unsigned char)*s1_mb; bad_s1_mb = TRUE; } s2_mb_len = parse_mbchar(s2, s2_mb, NULL); if (mbtowc(&ws2, s2_mb, s2_mb_len) < 0) { mbtowc_reset(); ws2 = (unsigned char)*s2_mb; bad_s2_mb = TRUE; } if (bad_s1_mb != bad_s2_mb || towlower(ws1) != towlower(ws2)) break; } free(s1_mb); free(s2_mb); return (n > 0) ? towlower(ws1) - towlower(ws2) : 0; } else #endif return strncasecmp(s1, s2, n); }
/* Fix the regex if we're on platforms which require an adjustment * from GNU-style to BSD-style word boundaries. */ const char *fixbounds(const char *r) { #ifndef GNU_WORDBOUNDS int i, j = 0; char *r2 = charalloc(strlen(r) * 5); char *r3; #ifdef DEBUG fprintf(stderr, "fixbounds(): Start string = \"%s\"\n", r); #endif for (i = 0; i < strlen(r); i++) { if (r[i] != '\0' && r[i] == '\\' && (r[i + 1] == '>' || r[i + 1] == '<')) { strcpy(&r2[j], "[[:"); r2[j + 3] = r[i + 1]; strcpy(&r2[j + 4], ":]]"); i++; j += 6; } else r2[j] = r[i]; j++; } r2[j] = '\0'; r3 = mallocstrcpy(NULL, r2); free(r2); #ifdef DEBUG fprintf(stderr, "fixbounds(): Ending string = \"%s\"\n", r3); #endif return (const char *) r3; #endif /* !GNU_WORDBOUNDS */ return r; }
/* Return TRUE if the multibyte string s contains one or more blank * multibyte characters, and FALSE otherwise. */ bool has_blank_mbchars(const char *s) { assert(s != NULL); #ifdef ENABLE_UTF8 if (use_utf8) { bool retval = FALSE; char *chr_mb = charalloc(MB_CUR_MAX); for (; *s != '\0'; s += move_mbright(s, 0)) { parse_mbchar(s, chr_mb, NULL); if (is_blank_mbchar(chr_mb)) { retval = TRUE; break; } } free(chr_mb); return retval; } else #endif return has_blank_chars(s); }
/* Convert the Unicode value in chr to a multibyte character with the * same wide character value as chr, if possible. If the conversion * succeeds, return the (dynamically allocated) multibyte character and * its length. Otherwise, return an undefined (dynamically allocated) * multibyte character and a length of zero. */ char *make_mbchar(long chr, int *chr_mb_len) { char *chr_mb; assert(chr_mb_len != NULL); #ifdef ENABLE_UTF8 if (use_utf8) { chr_mb = charalloc(MB_CUR_MAX); *chr_mb_len = wctomb(chr_mb, (wchar_t)chr); /* Reject invalid Unicode characters. */ if (*chr_mb_len < 0 || !is_valid_unicode((wchar_t)chr)) { wctomb_reset(); *chr_mb_len = 0; } } else { #endif *chr_mb_len = 1; chr_mb = mallocstrncpy(NULL, (char *)&chr, 1); #ifdef ENABLE_UTF8 } #endif return chr_mb; }
/* Compile the regular expression regexp to see if it's valid. Return * TRUE if it is, or FALSE otherwise. */ bool regexp_init(const char *regexp) { int rc; assert(!regexp_compiled); rc = regcomp(&search_regexp, regexp, REG_EXTENDED #ifndef NANO_TINY | (ISSET(CASE_SENSITIVE) ? 0 : REG_ICASE) #endif ); if (rc != 0) { size_t len = regerror(rc, &search_regexp, NULL, 0); char *str = charalloc(len); regerror(rc, &search_regexp, str, len); statusbar(_("Bad regex \"%s\": %s"), regexp, str); free(str); return FALSE; } regexp_compiled = TRUE; return TRUE; }
/* Display a message on the statusbar, and set disable_cursorpos to * true, so that the message won't be immediately overwritten if * constant cursor position display is on. */ void statusbar(const char *msg, ...) { va_list ap; char *bar, *foo; size_t start_x; bool old_whitespace; va_start(ap, msg); /* Curses mode is turned off. If we use wmove() now, it will muck * up the terminal settings. So we just use vfprintf(). */ if (isendwin()) { vfprintf(stderr, msg, ap); va_end(ap); return; } blank_statusbar(); old_whitespace = ISSET(WHITESPACE_DISPLAY); UNSET(WHITESPACE_DISPLAY); bar = charalloc(mb_cur_max() * (COLS - 3)); vsnprintf(bar, mb_cur_max() * (COLS - 3), msg, ap); va_end(ap); foo = display_string(bar, 0, COLS - 4, false); free(bar); if (old_whitespace) { SET(WHITESPACE_DISPLAY); } start_x = (COLS - strlenpt(foo) - 4) / 2; wmove(bottomwin, 0, start_x); set_color(bottomwin, interface_colors[STATUS_BAR]); waddstr(bottomwin, "[ "); waddstr(bottomwin, foo); free(foo); waddstr(bottomwin, " ]"); clear_color(bottomwin, interface_colors[STATUS_BAR]); wnoutrefresh(bottomwin); reset_cursor(); wnoutrefresh(edit); /* Leave the cursor at its position in the edit window, not in * the statusbar. */ disable_cursorpos = true; /* If we're doing quick statusbar blanking, and constant cursor * position display is off, blank the statusbar after only one * keystroke. Otherwise, blank it after twenty-six keystrokes, as * Pico does. */ statusblank = ISSET(QUICK_BLANK) && !ISSET(CONST_UPDATE) ? 1 : 26; }
/* Copy the first n characters of one malloc()ed string to another * pointer. Should be used as: "dest = mallocstrncpy(dest, src, * n);". */ char *mallocstrncpy(char *dest, const char *src, size_t n) { if (src == NULL) src = ""; if (src != dest) free(dest); dest = charalloc(n); strncpy(dest, src, n); return dest; }
/* The file browser front end. We check to see if inpath has a * directory in it. If it does, we start do_browser() from there. * Otherwise, we start do_browser() from the current directory. */ char *do_browse_from(const char *inpath) { struct stat st; char *path; /* This holds the tilde-expanded version of inpath. */ DIR *dir = NULL; assert(inpath != NULL); path = real_dir_from_tilde(inpath); /* Perhaps path is a directory. If so, we'll pass it to * do_browser(). Or perhaps path is a directory / a file. If so, * we'll try stripping off the last path element and passing it to * do_browser(). Or perhaps path doesn't have a directory portion * at all. If so, we'll just pass the current directory to * do_browser(). */ if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) { path = mallocstrassn(path, striponedir(path)); if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) { free(path); path = charalloc(PATH_MAX + 1); path = getcwd(path, PATH_MAX + 1); if (path != NULL) align(&path); } } #ifndef DISABLE_OPERATINGDIR /* If the resulting path isn't in the operating directory, use * the operating directory instead. */ if (check_operating_dir(path, FALSE)) path = mallocstrcpy(path, operating_dir); #endif if (path != NULL) dir = opendir(path); /* If we can't open the path, get out. */ if (dir == NULL) { free(path); beep(); return NULL; } return do_browser(path, dir); }
/* Is the word starting at position pos in buf a whole word? */ bool is_whole_word(size_t pos, const char *buf, const char *word) { char *p = charalloc(mb_cur_max()), *r = charalloc(mb_cur_max()); size_t word_end = pos + strlen(word); bool retval; assert(buf != NULL && pos <= strlen(buf) && word != NULL); parse_mbchar(buf + move_mbleft(buf, pos), p, NULL); parse_mbchar(buf + word_end, r, NULL); /* If we're at the beginning of the line or the character before the * word isn't a non-punctuation "word" character, and if we're at * the end of the line or the character after the word isn't a * non-punctuation "word" character, we have a whole word. */ retval = (pos == 0 || !is_word_mbchar(p, FALSE)) && (word_end == strlen(buf) || !is_word_mbchar(r, FALSE)); free(p); free(r); return retval; }
/* This function is equivalent to getdelim(). */ ssize_t ngetdelim(char **lineptr, size_t *n, int delim, FILE *stream) { size_t indx = 0; int c; /* Sanity checks. */ if (lineptr == NULL || n == NULL || stream == NULL || fileno(stream) == -1) { errno = EINVAL; return -1; } /* Allocate the line the first time. */ if (*lineptr == NULL) { *n = MAX_BUF_SIZE; *lineptr = charalloc(*n); } while ((c = getc(stream)) != EOF) { /* Check if more memory is needed. */ if (indx >= *n) { *n += MAX_BUF_SIZE; *lineptr = charealloc(*lineptr, *n); } /* Put the result in the line. */ (*lineptr)[indx++] = (char)c; /* Bail out. */ if (c == delim) break; } /* Make room for the null character. */ if (indx >= *n) { *n += MAX_BUF_SIZE; *lineptr = charealloc(*lineptr, *n); } /* Null-terminate the buffer. */ null_at(lineptr, indx++); *n = indx; /* The last line may not have the delimiter. We have to return what * we got, and the error will be seen on the next iteration. */ return (c == EOF && (indx - 1) == 0) ? -1 : indx - 1; }
/* Compile the regular expression regex to see if it's valid. Return * TRUE if it is, or FALSE otherwise. */ bool nregcomp(const char *regex, int eflags) { regex_t preg; const char *r = fixbounds(regex); int rc = regcomp(&preg, r, REG_EXTENDED | eflags); if (rc != 0) { size_t len = regerror(rc, &preg, NULL, 0); char *str = charalloc(len); regerror(rc, &preg, str, len); rcfile_error(N_("Bad regex \"%s\": %s"), r, str); free(str); } regfree(&preg); return (rc == 0); }
/* This function is equivalent to strchr() for multibyte strings. */ char *mbstrchr(const char *s, const char *c) { assert(s != NULL && c != NULL); #ifdef ENABLE_UTF8 if (use_utf8) { bool bad_s_mb = FALSE, bad_c_mb = FALSE; char *s_mb = charalloc(MB_CUR_MAX); const char *q = s; wchar_t ws, wc; int c_mb_len = mbtowc(&wc, c, MB_CUR_MAX); if (c_mb_len < 0) { mbtowc_reset(); wc = (unsigned char)*c; bad_c_mb = TRUE; } while (*s != '\0') { int s_mb_len = parse_mbchar(s, s_mb, NULL); if (mbtowc(&ws, s_mb, s_mb_len) < 0) { mbtowc_reset(); ws = (unsigned char)*s; bad_s_mb = TRUE; } if (bad_s_mb == bad_c_mb && ws == wc) break; s += s_mb_len; q += s_mb_len; } free(s_mb); if (*s == '\0') q = NULL; return (char *)q; } else #endif return strchr(s, *c); }
char *replace_line(const char *needle) { char *copy; size_t new_line_size, search_match_count; /* Calculate the size of the new line. */ #ifdef HAVE_REGEX_H if (ISSET(USE_REGEXP)) { search_match_count = regmatches[0].rm_eo - regmatches[0].rm_so; new_line_size = replace_regexp(NULL, FALSE); } else { #endif search_match_count = strlen(needle); new_line_size = strlen(openfile->current->data) - search_match_count + strlen(answer) + 1; #ifdef HAVE_REGEX_H } #endif /* Create the buffer. */ copy = charalloc(new_line_size); /* The head of the original line. */ strncpy(copy, openfile->current->data, openfile->current_x); /* The replacement text. */ #ifdef HAVE_REGEX_H if (ISSET(USE_REGEXP)) replace_regexp(copy + openfile->current_x, TRUE); else #endif strcpy(copy + openfile->current_x, answer); /* The tail of the original line. */ assert(openfile->current_x + search_match_count <= strlen(openfile->current->data)); strcat(copy, openfile->current->data + openfile->current_x + search_match_count); return copy; }
/*! * @brief 信号のVerilog HDL生成 */ int create_verilog_signal() { SIGNAL_TREE *now_signal_tree; char *buf; char *str; buf = calloc(STR_MAX, 1); now_signal_tree = signal_tree_top; while(now_signal_tree != NULL){ strcpy(buf ,""); if( (now_signal_tree->flag == SIGNAL_FLAG_REG) || (now_signal_tree->flag == SIGNAL_FLAG_WIRE) ){ switch(now_signal_tree->flag){ case SIGNAL_FLAG_REG: sprintf(buf, "reg "); break; case SIGNAL_FLAG_WIRE: sprintf(buf, "wire "); break; default: break; } if(now_signal_tree->width > 0){ sprintf(buf, "%s[%d:0] ", buf, now_signal_tree->width-1); } str = regalloc(now_signal_tree->label); sprintf(buf, "%s%s;", buf, str); free(str); now_signal_tree->verilog = charalloc(buf); } now_signal_tree = now_signal_tree->next_ptr; } free(buf); return 0; }
/* Get verbatim input. Set got_enter to TRUE if we got the Enter key as * part of the verbatim input. */ void do_statusbar_verbatim_input(bool *got_enter) { int *kbinput; size_t kbinput_len, i; char *output; *got_enter = FALSE; /* Read in all the verbatim characters. */ kbinput = get_verbatim_kbinput(bottomwin, &kbinput_len); /* Display all the verbatim characters at once, not filtering out * control characters. */ output = charalloc(kbinput_len + 1); for (i = 0; i < kbinput_len; i++) output[i] = (char)kbinput[i]; output[i] = '\0'; do_statusbar_output(output, kbinput_len, got_enter, TRUE); free(output); }
/* Convert the Unicode value in chr to a multibyte character, if possible. * If the conversion succeeds, return the (dynamically allocated) multibyte * character and its length. Otherwise, return an undefined (dynamically * allocated) multibyte character and a length of zero. */ char *make_mbchar(long chr, int *chr_mb_len) { char *chr_mb; #ifdef ENABLE_UTF8 if (use_utf8) { chr_mb = charalloc(MB_CUR_MAX); *chr_mb_len = wctomb(chr_mb, (wchar_t)chr); /* Reject invalid Unicode characters. */ if (*chr_mb_len < 0 || !is_valid_unicode((wchar_t)chr)) { IGNORE_CALL_RESULT(wctomb(NULL, 0)); *chr_mb_len = 0; } } else #endif { *chr_mb_len = 1; chr_mb = mallocstrncpy(NULL, (char *)&chr, 1); } return chr_mb; }
/* Save the recorded cursor positions for files that were edited. */ void save_poshistory(void) { poshiststruct *posptr; FILE *hisfile = fopen(poshistname, "wb"); if (hisfile == NULL) fprintf(stderr, _("Error writing %s: %s\n"), poshistname, strerror(errno)); else { /* Don't allow others to read or write the history file. */ chmod(poshistname, S_IRUSR | S_IWUSR); for (posptr = position_history; posptr != NULL; posptr = posptr->next) { char *path_and_place; size_t length; /* Assume 20 decimal positions each for line and column number, * plus two spaces, plus the line feed, plus the null byte. */ path_and_place = charalloc(strlen(posptr->filename) + 44); sprintf(path_and_place, "%s %zd %zd\n", posptr->filename, posptr->lineno, posptr->xno); length = strlen(path_and_place); /* Encode newlines in filenames as nulls. */ sunder(path_and_place); /* Restore the terminating newline. */ path_and_place[length - 1] = '\n'; if (fwrite(path_and_place, sizeof(char), length, hisfile) < length) fprintf(stderr, _("Error writing %s: %s\n"), poshistname, strerror(errno)); free(path_and_place); } fclose(hisfile); stat(poshistname, &stat_of_positions_file); } }
/* Ask a question on the statusbar. The prompt will be stored in the * static prompt, which should be NULL initially, and the answer will be * stored in the answer global. Returns -1 on aborted enter, -2 on a * blank string, and 0 otherwise, the valid shortcut key caught. * curranswer is any editable text that we want to put up by default, * and refresh_func is the function we want to call to refresh the edit * window. * * The allow_tabs parameter indicates whether we should allow tabs to be * interpreted. The allow_files parameter indicates whether we should * allow all files (as opposed to just directories) to be tab * completed. */ int do_prompt(bool allow_tabs, #ifndef DISABLE_TABCOMP bool allow_files, #endif int menu, const char *curranswer, #ifndef DISABLE_HISTORIES linestruct **history_list, #endif void (*refresh_func)(void), const char *msg, ...) { va_list ap; int retval; functionptrtype func; #ifndef DISABLE_TABCOMP bool list = FALSE; #endif /* prompt has been freed and set to NULL unless the user resized * while at the statusbar prompt. */ free(prompt); prompt = charalloc(((COLS - 4) * mb_cur_max()) + 1); bottombars(menu); va_start(ap, msg); vsnprintf(prompt, (COLS - 4) * mb_cur_max(), msg, ap); va_end(ap); null_at(&prompt, actual_x(prompt, COLS - 4)); func = get_prompt_string(&retval, allow_tabs, #ifndef DISABLE_TABCOMP allow_files, &list, #endif curranswer, #ifndef DISABLE_HISTORIES history_list, #endif refresh_func); free(prompt); prompt = NULL; /* We're done with the prompt, so save the statusbar cursor * position. */ old_statusbar_x = statusbar_x; old_pww = statusbar_pww; /* If we left the prompt via Cancel or Enter, set the return value * properly. */ if (func == do_cancel) retval = -1; else if (func == do_enter_void) retval = (*answer == '\0') ? -2 : 0; blank_statusbar(); wnoutrefresh(bottomwin); #ifdef DEBUG fprintf(stderr, "answer = \"%s\"\n", answer); #endif #ifndef DISABLE_TABCOMP /* If we've done tab completion, there might be a list of filename * matches on the edit window at this point. Make sure that they're * cleared off. */ if (list) refresh_func(); #endif return retval; }
/* Read in a character, interpret it as a shortcut or toggle if * necessary, and return it. * Set ran_func to TRUE if we ran a function associated with a * shortcut key, and set finished to TRUE if we're done after running * or trying to run a function associated with a shortcut key. * refresh_func is the function we will call to refresh the edit window. */ int do_statusbar_input(bool *ran_func, bool *finished, void (*refresh_func)(void)) { int input; /* The character we read in. */ static int *kbinput = NULL; /* The input buffer. */ static size_t kbinput_len = 0; /* The length of the input buffer. */ const sc *s; bool have_shortcut = FALSE; const subnfunc *f; *ran_func = FALSE; *finished = FALSE; /* Read in a character. */ input = get_kbinput(bottomwin); #ifndef NANO_TINY if (input == KEY_WINCH) return KEY_WINCH; #endif #ifndef DISABLE_MOUSE /* If we got a mouse click and it was on a shortcut, read in the * shortcut character. */ if (func_key && input == KEY_MOUSE) { if (do_statusbar_mouse() == 1) input = get_kbinput(bottomwin); else { meta_key = FALSE; func_key = FALSE; input = ERR; } } #endif /* Check for a shortcut in the current list. */ s = get_shortcut(&input); /* If we got a shortcut from the current list, or a "universal" * statusbar prompt shortcut, set have_shortcut to TRUE. */ have_shortcut = (s != NULL); /* If we got a non-high-bit control key, a meta key sequence, or a * function key, and it's not a shortcut or toggle, throw it out. */ if (!have_shortcut) { if (is_ascii_cntrl_char(input) || meta_key || func_key) { beep(); meta_key = FALSE; func_key = FALSE; input = ERR; } } /* If we got a character, and it isn't a shortcut or toggle, * it's a normal text character. Display the warning if we're * in view mode, or add the character to the input buffer if * we're not. */ if (input != ERR && !have_shortcut) { /* If we're using restricted mode, the filename isn't blank, * and we're at the "Write File" prompt, disable text input. */ if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) { kbinput_len++; kbinput = (int *)nrealloc(kbinput, kbinput_len * sizeof(int)); kbinput[kbinput_len - 1] = input; } } /* If we got a shortcut, or if there aren't any other characters * waiting after the one we read in, we need to display all the * characters in the input buffer if it isn't empty. */ if (have_shortcut || get_key_buffer_len() == 0) { if (kbinput != NULL) { /* Display all the characters in the input buffer at * once, filtering out control characters. */ char *output = charalloc(kbinput_len + 1); size_t i; bool got_enter; /* Whether we got the Enter key. */ for (i = 0; i < kbinput_len; i++) output[i] = (char)kbinput[i]; output[i] = '\0'; do_statusbar_output(output, kbinput_len, &got_enter, FALSE); free(output); /* Empty the input buffer. */ kbinput_len = 0; free(kbinput); kbinput = NULL; } if (have_shortcut) { if (s->scfunc == do_tab || s->scfunc == do_enter_void) ; else if (s->scfunc == total_refresh) total_statusbar_refresh(refresh_func); else if (s->scfunc == do_cut_text_void) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable Cut. */ if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) do_statusbar_cut_text(); } else if (s->scfunc == do_left) do_statusbar_left(); else if (s->scfunc == do_right) do_statusbar_right(); #ifndef NANO_TINY else if (s->scfunc == do_prev_word_void) do_statusbar_prev_word(FALSE); else if (s->scfunc == do_next_word_void) do_statusbar_next_word(FALSE); #endif else if (s->scfunc == do_home) do_statusbar_home(); else if (s->scfunc == do_end) do_statusbar_end(); else if (s->scfunc == do_verbatim_input) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable verbatim input. */ if (!ISSET(RESTRICTED) || currmenu != MWRITEFILE || openfile->filename[0] == '\0') { bool got_enter; /* Whether we got the Enter key. */ do_statusbar_verbatim_input(&got_enter); /* If we got the Enter key, remove it from the input * buffer, set input to the key value for Enter, and * set finished to TRUE to indicate that we're done. */ if (got_enter) { get_input(NULL, 1); input = sc_seq_or(do_enter_void, 0); *finished = TRUE; } } } else if (s->scfunc == do_delete) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable Delete. */ if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) do_statusbar_delete(); } else if (s->scfunc == do_backspace) { /* If we're using restricted mode, the filename * isn't blank, and we're at the "Write File" * prompt, disable Backspace. */ if (!ISSET(RESTRICTED) || openfile->filename[0] == '\0' || currmenu != MWRITEFILE) do_statusbar_backspace(); } else { /* Handle any other shortcut in the current menu, setting * ran_func to TRUE if we try to run their associated * functions and setting finished to TRUE to indicate * that we're done after running or trying to run their * associated functions. */ f = sctofunc((sc *) s); if (s->scfunc != NULL) { *ran_func = TRUE; if (f && (!ISSET(VIEW_MODE) || f->viewok) && f->scfunc != do_gotolinecolumn_void) f->scfunc(); } *finished = TRUE; } } } return input; }
/* Move to the previous word in the prompt text. If allow_punct is * TRUE, treat punctuation as part of a word. Return TRUE if we started * on a word, and FALSE otherwise. */ bool do_statusbar_prev_word(bool allow_punct) { size_t pww_save = statusbar_pww; char *char_mb; int char_mb_len; bool begin_line = FALSE, started_on_word = FALSE; assert(answer != NULL); char_mb = charalloc(mb_cur_max()); /* Move backward until we find the character before the first letter * of the current word. */ while (!begin_line) { char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); /* If we've found it, stop moving backward through the current * line. */ if (!is_word_mbchar(char_mb, allow_punct)) break; /* If we haven't found it, then we've started on a word, so set * started_on_word to TRUE. */ started_on_word = TRUE; if (statusbar_x == 0) begin_line = TRUE; else statusbar_x = move_mbleft(answer, statusbar_x); } /* Move backward until we find the last letter of the previous * word. */ if (statusbar_x == 0) begin_line = TRUE; else statusbar_x = move_mbleft(answer, statusbar_x); while (!begin_line) { char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); /* If we've found it, stop moving backward through the current * line. */ if (is_word_mbchar(char_mb, allow_punct)) break; if (statusbar_x == 0) begin_line = TRUE; else statusbar_x = move_mbleft(answer, statusbar_x); } /* If we've found it, move backward until we find the character * before the first letter of the previous word. */ if (!begin_line) { if (statusbar_x == 0) begin_line = TRUE; else statusbar_x = move_mbleft(answer, statusbar_x); while (!begin_line) { char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); /* If we've found it, stop moving backward through the * current line. */ if (!is_word_mbchar(char_mb, allow_punct)) break; if (statusbar_x == 0) begin_line = TRUE; else statusbar_x = move_mbleft(answer, statusbar_x); } /* If we've found it, move forward to the first letter of the * previous word. */ if (!begin_line) statusbar_x += char_mb_len; } free(char_mb); statusbar_pww = statusbar_xplustabs(); if (need_statusbar_update(pww_save)) update_statusbar_line(answer, statusbar_x); /* Return whether we started on a word. */ return started_on_word; }
/* Move to the next word in the prompt text. If allow_punct is TRUE, * treat punctuation as part of a word. Return TRUE if we started on a * word, and FALSE otherwise. */ bool do_statusbar_next_word(bool allow_punct) { size_t pww_save = statusbar_pww; char *char_mb; int char_mb_len; bool end_line = FALSE, started_on_word = FALSE; assert(answer != NULL); char_mb = charalloc(mb_cur_max()); /* Move forward until we find the character after the last letter of * the current word. */ while (!end_line) { char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); /* If we've found it, stop moving forward through the current * line. */ if (!is_word_mbchar(char_mb, allow_punct)) break; /* If we haven't found it, then we've started on a word, so set * started_on_word to TRUE. */ started_on_word = TRUE; if (answer[statusbar_x] == '\0') end_line = TRUE; else statusbar_x += char_mb_len; } /* Move forward until we find the first letter of the next word. */ if (answer[statusbar_x] == '\0') end_line = TRUE; else statusbar_x += char_mb_len; while (!end_line) { char_mb_len = parse_mbchar(answer + statusbar_x, char_mb, NULL); /* If we've found it, stop moving forward through the current * line. */ if (is_word_mbchar(char_mb, allow_punct)) break; if (answer[statusbar_x] == '\0') end_line = TRUE; else statusbar_x += char_mb_len; } free(char_mb); statusbar_pww = statusbar_xplustabs(); if (need_statusbar_update(pww_save)) update_statusbar_line(answer, statusbar_x); /* Return whether we started on a word. */ return started_on_word; }
/* The user typed output_len multibyte characters. Add them to the * statusbar prompt, setting got_enter to TRUE if we get a newline, and * filtering out all ASCII control characters if allow_cntrls is * TRUE. */ void do_statusbar_output(char *output, size_t output_len, bool *got_enter, bool allow_cntrls) { size_t answer_len, i = 0; char *char_buf = charalloc(mb_cur_max()); int char_buf_len; assert(answer != NULL); answer_len = strlen(answer); *got_enter = FALSE; while (i < output_len) { /* If allow_cntrls is TRUE, convert nulls and newlines * properly. */ if (allow_cntrls) { /* Null to newline, if needed. */ if (output[i] == '\0') output[i] = '\n'; /* Newline to Enter, if needed. */ else if (output[i] == '\n') { /* Set got_enter to TRUE to indicate that we got the * Enter key, put back the rest of the characters in * output so that they can be parsed and output again, * and get out. */ *got_enter = TRUE; unparse_kbinput(output + i, output_len - i); return; } } /* Interpret the next multibyte character. */ char_buf_len = parse_mbchar(output + i, char_buf, NULL); i += char_buf_len; /* If allow_cntrls is FALSE, filter out an ASCII control * character. */ if (!allow_cntrls && is_ascii_cntrl_char(*(output + i - char_buf_len))) continue; /* More dangerousness fun. =) */ answer = charealloc(answer, answer_len + (char_buf_len * 2)); assert(statusbar_x <= answer_len); charmove(answer + statusbar_x + char_buf_len, answer + statusbar_x, answer_len - statusbar_x + char_buf_len); strncpy(answer + statusbar_x, char_buf, char_buf_len); answer_len += char_buf_len; statusbar_x += char_buf_len; } free(char_buf); statusbar_pww = statusbar_xplustabs(); update_statusbar_line(answer, statusbar_x); }
/* Move to the previous word in the file. If allow_punct is TRUE, treat * punctuation as part of a word. If allow_update is TRUE, update the * screen afterwards. Return TRUE if we started on a word, and FALSE * otherwise. */ bool do_prev_word(bool allow_punct, bool allow_update) { size_t pww_save = openfile->placewewant; filestruct *current_save = openfile->current; char *char_mb; int char_mb_len; bool begin_line = FALSE, started_on_word = FALSE; assert(openfile->current != NULL && openfile->current->data != NULL); char_mb = charalloc(mb_cur_max()); /* Move backward until we find the character before the first letter * of the current word. */ while (!begin_line) { char_mb_len = parse_mbchar(openfile->current->data + openfile->current_x, char_mb, NULL); /* If we've found it, stop moving backward through the current * line. */ if (!is_word_mbchar(char_mb, allow_punct)) break; /* If we haven't found it, then we've started on a word, so set * started_on_word to TRUE. */ started_on_word = TRUE; if (openfile->current_x == 0) begin_line = TRUE; else openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); } /* Move backward until we find the last letter of the previous * word. */ if (openfile->current_x == 0) begin_line = TRUE; else openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); for (; openfile->current != NULL; openfile->current = openfile->current->prev) { while (!begin_line) { char_mb_len = parse_mbchar(openfile->current->data + openfile->current_x, char_mb, NULL); /* If we've found it, stop moving backward through the * current line. */ if (is_word_mbchar(char_mb, allow_punct)) break; if (openfile->current_x == 0) begin_line = TRUE; else openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); } /* If we've found it, stop moving backward to the ends of * previous lines. */ if (!begin_line) break; if (openfile->current != openfile->fileage) { begin_line = FALSE; openfile->current_x = strlen(openfile->current->prev->data); } } /* If we haven't found it, move to the beginning of the file. */ if (openfile->current == NULL) openfile->current = openfile->fileage; /* If we've found it, move backward until we find the character * before the first letter of the previous word. */ else if (!begin_line) { if (openfile->current_x == 0) begin_line = TRUE; else openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); while (!begin_line) { char_mb_len = parse_mbchar(openfile->current->data + openfile->current_x, char_mb, NULL); /* If we've found it, stop moving backward through the * current line. */ if (!is_word_mbchar(char_mb, allow_punct)) break; if (openfile->current_x == 0) begin_line = TRUE; else openfile->current_x = move_mbleft(openfile->current->data, openfile->current_x); } /* If we've found it, move forward to the first letter of the * previous word. */ if (!begin_line) openfile->current_x += char_mb_len; } free(char_mb); openfile->placewewant = xplustabs(); /* If allow_update is TRUE, update the screen. */ if (allow_update) edit_redraw(current_save, pww_save); /* Return whether we started on a word. */ return started_on_word; }
/* Move to the next word in the file. If allow_punct is TRUE, treat * punctuation as part of a word. If allow_update is TRUE, update the * screen afterwards. Return TRUE if we started on a word, and FALSE * otherwise. */ bool do_next_word(bool allow_punct, bool allow_update) { size_t pww_save = openfile->placewewant; filestruct *current_save = openfile->current; char *char_mb; int char_mb_len; bool end_line = FALSE, started_on_word = FALSE; assert(openfile->current != NULL && openfile->current->data != NULL); char_mb = charalloc(mb_cur_max()); /* Move forward until we find the character after the last letter of * the current word. */ while (!end_line) { char_mb_len = parse_mbchar(openfile->current->data + openfile->current_x, char_mb, NULL); /* If we've found it, stop moving forward through the current * line. */ if (!is_word_mbchar(char_mb, allow_punct)) break; /* If we haven't found it, then we've started on a word, so set * started_on_word to TRUE. */ started_on_word = TRUE; if (openfile->current->data[openfile->current_x] == '\0') end_line = TRUE; else openfile->current_x += char_mb_len; } /* Move forward until we find the first letter of the next word. */ if (openfile->current->data[openfile->current_x] == '\0') end_line = TRUE; else openfile->current_x += char_mb_len; for (; openfile->current != NULL; openfile->current = openfile->current->next) { while (!end_line) { char_mb_len = parse_mbchar(openfile->current->data + openfile->current_x, char_mb, NULL); /* If we've found it, stop moving forward through the * current line. */ if (is_word_mbchar(char_mb, allow_punct)) break; if (openfile->current->data[openfile->current_x] == '\0') end_line = TRUE; else openfile->current_x += char_mb_len; } /* If we've found it, stop moving forward to the beginnings of * subsequent lines. */ if (!end_line) break; if (openfile->current != openfile->filebot) { end_line = FALSE; openfile->current_x = 0; } } free(char_mb); /* If we haven't found it, move to the end of the file. */ if (openfile->current == NULL) openfile->current = openfile->filebot; openfile->placewewant = xplustabs(); /* If allow_update is TRUE, update the screen. */ if (allow_update) edit_redraw(current_save, pww_save); /* Return whether we started on a word. */ return started_on_word; }
/* Set up the system variables for a search or replace. If use_answer * is TRUE, only set backupstring to answer. Return -2 to run the * opposite program (search -> replace, replace -> search), return -1 if * the search should be canceled (due to Cancel, a blank search string, * Go to Line, or a failed regcomp()), return 0 on success, and return 1 * on rerun calling program. * * replacing is TRUE if we call from do_replace(), and FALSE if called * from do_search(). */ int search_init(bool replacing, bool use_answer) { int i = 0; char *buf; static char *backupstring = NULL; /* The search string we'll be using. */ /* If backupstring doesn't exist, initialize it to "". */ if (backupstring == NULL) backupstring = mallocstrcpy(NULL, ""); /* If use_answer is TRUE, set backupstring to answer and get out. */ if (use_answer) { backupstring = mallocstrcpy(backupstring, answer); return 0; } /* We display the search prompt below. If the user types a partial * search string and then Replace or a toggle, we will return to * do_search() or do_replace() and be called again. In that case, * we should put the same search string back up. */ focusing = TRUE; if (last_search[0] != '\0') { char *disp = display_string(last_search, 0, COLS / 3, FALSE); buf = charalloc(strlen(disp) + 7); /* We use (COLS / 3) here because we need to see more on the line. */ sprintf(buf, " [%s%s]", disp, (strlenpt(last_search) > COLS / 3) ? "..." : ""); free(disp); } else buf = mallocstrcpy(NULL, ""); /* This is now one simple call. It just does a lot. */ i = do_prompt(FALSE, #ifndef DISABLE_TABCOMP TRUE, #endif replacing ? MREPLACE : MWHEREIS, backupstring, #ifndef DISABLE_HISTORIES &search_history, #endif /* TRANSLATORS: This is the main search prompt. */ edit_refresh, "%s%s%s%s%s%s", _("Search"), #ifndef NANO_TINY /* TRANSLATORS: The next three strings are modifiers of the search prompt. */ ISSET(CASE_SENSITIVE) ? _(" [Case Sensitive]") : #endif "", #ifdef HAVE_REGEX_H ISSET(USE_REGEXP) ? _(" [Regexp]") : #endif "", #ifndef NANO_TINY ISSET(BACKWARDS_SEARCH) ? _(" [Backwards]") : #endif "", replacing ? #ifndef NANO_TINY /* TRANSLATORS: The next two strings are modifiers of the search prompt. */ openfile->mark_set ? _(" (to replace) in selection") : #endif _(" (to replace)") : "", buf); fflush(stderr); /* Release buf now that we don't need it anymore. */ free(buf); free(backupstring); backupstring = NULL; /* Cancel any search, or just return with no previous search. */ if (i == -1 || (i < 0 && *last_search == '\0') || (!replacing && i == 0 && *answer == '\0')) { statusbar(_("Cancelled")); return -1; } else { functionptrtype func = func_from_key(&i); if (i == -2 || i == 0 ) { #ifdef HAVE_REGEX_H /* Use last_search if answer is an empty string, or * answer if it isn't. */ if (ISSET(USE_REGEXP) && !regexp_init((i == -2) ? last_search : answer)) return -1; #endif ; #ifndef NANO_TINY } else if (func == case_sens_void) { TOGGLE(CASE_SENSITIVE); backupstring = mallocstrcpy(backupstring, answer); return 1; } else if (func == backwards_void) { TOGGLE(BACKWARDS_SEARCH); backupstring = mallocstrcpy(backupstring, answer); return 1; #endif #ifdef HAVE_REGEX_H } else if (func == regexp_void) { TOGGLE(USE_REGEXP); backupstring = mallocstrcpy(backupstring, answer); return 1; #endif } else if (func == do_replace || func == flip_replace_void) { backupstring = mallocstrcpy(backupstring, answer); return -2; /* Call the opposite search function. */ } else if (func == do_gotolinecolumn_void) { do_gotolinecolumn(openfile->current->lineno, openfile->placewewant + 1, TRUE, TRUE); /* Put answer up on the statusbar and * fall through. */ return 3; } else { return -1; } } return 0; }
/* Set width to the number of files that we can display per line, if * necessary, and display the list of files. */ void browser_refresh(void) { size_t i; int line = 0, col = 0; /* The current line and column while the list is getting displayed. */ char *foo; /* The additional information that we'll display about a file. */ /* Perhaps window dimensions have changed; reinitialize the browser. */ browser_init(path_save, opendir(path_save)); qsort(filelist, filelist_len, sizeof(char *), diralphasort); /* Make sure the selected file is within range. */ if (selected >= filelist_len) selected = filelist_len - 1; titlebar(path_save); blank_edit(); wmove(edit, 0, 0); i = width * editwinrows * ((selected / width) / editwinrows); for (; i < filelist_len && line < editwinrows; i++) { struct stat st; const char *filetail = tail(filelist[i]); /* The filename we display, minus the path. */ size_t filetaillen = strlenpt(filetail); /* The length of the filename in columns. */ size_t foolen; /* The length of the file information in columns. */ int foomaxlen = 7; /* The maximum length of the file information in * columns: seven for "--", "(dir)", or the file size, * and 12 for "(parent dir)". */ bool dots = (COLS >= 15 && filetaillen >= longest - foomaxlen); /* Do we put an ellipsis before the filename? Don't set * this to TRUE if we have fewer than 15 columns (i.e. * one column for padding, plus seven columns for a * filename other than ".."). */ char *disp = display_string(filetail, dots ? filetaillen - longest + foomaxlen + 4 : 0, longest, FALSE); /* If we put an ellipsis before the filename, reserve * one column for padding, plus seven columns for "--", * "(dir)", or the file size, plus three columns for the * ellipsis. */ /* Start highlighting the currently selected file or directory. */ if (i == selected) wattron(edit, hilite_attribute); blank_line(edit, line, col, longest); /* If dots is TRUE, we will display something like "...ename". */ if (dots) mvwaddstr(edit, line, col, "..."); mvwaddstr(edit, line, dots ? col + 3 : col, disp); free(disp); col += longest; /* Show information about the file. We don't want to report * file sizes for links, so we use lstat(). */ if (lstat(filelist[i], &st) == -1 || S_ISLNK(st.st_mode)) { /* If the file doesn't exist (i.e. it's been deleted while * the file browser is open), or it's a symlink that doesn't * point to a directory, display "--". */ if (stat(filelist[i], &st) == -1 || !S_ISDIR(st.st_mode)) foo = mallocstrcpy(NULL, "--"); /* If the file is a symlink that points to a directory, * display it as a directory. */ else /* TRANSLATORS: Try to keep this at most 7 characters. */ foo = mallocstrcpy(NULL, _("(dir)")); } else if (S_ISDIR(st.st_mode)) { /* If the file is a directory, display it as such. */ if (strcmp(filetail, "..") == 0) { /* TRANSLATORS: Try to keep this at most 12 characters. */ foo = mallocstrcpy(NULL, _("(parent dir)")); foomaxlen = 12; } else foo = mallocstrcpy(NULL, _("(dir)")); } else { unsigned long result = st.st_size; char modifier; foo = charalloc(foomaxlen + 1); if (st.st_size < (1 << 10)) modifier = ' '; /* bytes */ else if (st.st_size < (1 << 20)) { result >>= 10; modifier = 'K'; /* kilobytes */ } else if (st.st_size < (1 << 30)) { result >>= 20; modifier = 'M'; /* megabytes */ } else {
/* Set filelist to the list of files contained in the directory path, * set filelist_len to the number of files in that list, set longest to * the width in columns of the longest filename in that list (between 15 * and COLS), and set width to the number of files that we can display * per line. longest needs to be at least 15 columns in order to * display ".. (parent dir)", as Pico does. Assume path exists and is a * directory. */ void browser_init(const char *path, DIR *dir) { const struct dirent *nextdir; size_t i = 0, path_len = strlen(path); int col = 0; /* The maximum number of columns that the filenames will take * up. */ int line = 0; /* The maximum number of lines that the filenames will take * up. */ int filesperline = 0; /* The number of files that we can display per line. */ assert(path != NULL && path[strlen(path) - 1] == '/' && dir != NULL); /* Set longest to zero, just before we initialize it. */ longest = 0; while ((nextdir = readdir(dir)) != NULL) { size_t d_len; /* Don't show the "." entry. */ if (strcmp(nextdir->d_name, ".") == 0) continue; d_len = strlenpt(nextdir->d_name); if (d_len > longest) longest = (d_len > COLS) ? COLS : d_len; i++; } rewinddir(dir); /* Put 10 columns' worth of blank space between columns of filenames * in the list whenever possible, as Pico does. */ longest += 10; if (filelist != NULL) free_chararray(filelist, filelist_len); filelist_len = i; filelist = (char **)nmalloc(filelist_len * sizeof(char *)); i = 0; while ((nextdir = readdir(dir)) != NULL && i < filelist_len) { /* Don't show the "." entry. */ if (strcmp(nextdir->d_name, ".") == 0) continue; filelist[i] = charalloc(path_len + strlen(nextdir->d_name) + 1); sprintf(filelist[i], "%s%s", path, nextdir->d_name); i++; } /* Maybe the number of files in the directory changed between the * first time we scanned and the second. i is the actual length of * filelist, so record it. */ filelist_len = i; closedir(dir); /* Make sure longest is between 15 and COLS. */ if (longest < 15) longest = 15; if (longest > COLS) longest = COLS; /* Set width to zero, just before we initialize it. */ width = 0; for (i = 0; i < filelist_len && line < editwinrows; i++) { /* Calculate the number of columns one filename will take up. */ col += longest; filesperline++; /* Add some space between the columns. */ col += 2; /* If the next entry isn't going to fit on the current line, * move to the next line. */ if (col > COLS - longest) { line++; col = 0; /* If width isn't initialized yet, and we've taken up more * than one line, it means that width is equal to * filesperline. */ if (width == 0) width = filesperline; } } /* If width isn't initialized yet, and we've taken up only one line, * it means that width is equal to longest. */ if (width == 0) width = longest; }
/* Allocate space for the help text for the current menu, and concatenate * the different pieces of text into it. */ void help_init(void) { size_t allocsize = 0; /* Space needed for help_text. */ const char *htx[3]; /* Untranslated help introduction. We break it up into three chunks * in case the full string is too long for the compiler to handle. */ char *ptr; const subnfunc *f; const sc *s; #ifndef NANO_TINY bool old_whitespace = ISSET(WHITESPACE_DISPLAY); UNSET(WHITESPACE_DISPLAY); #endif /* First, set up the initial help text for the current function. */ if (currmenu == MWHEREIS || currmenu == MREPLACE || currmenu == MREPLACEWITH) { htx[0] = N_("Search Command Help Text\n\n " "Enter the words or characters you would like to " "search for, and then press Enter. If there is a " "match for the text you entered, the screen will be " "updated to the location of the nearest match for the " "search string.\n\n The previous search string will be " "shown in brackets after the search prompt. Hitting " "Enter without entering any text will perform the " "previous search. "); htx[1] = N_("If you have selected text with the mark and then " "search to replace, only matches in the selected text " "will be replaced.\n\n The following function keys are " "available in Search mode:\n\n"); htx[2] = NULL; } else if (currmenu == MGOTOLINE) { htx[0] = N_("Go To Line Help Text\n\n " "Enter the line number that you wish to go to and hit " "Enter. If there are fewer lines of text than the " "number you entered, you will be brought to the last " "line of the file.\n\n The following function keys are " "available in Go To Line mode:\n\n"); htx[1] = NULL; htx[2] = NULL; } else if (currmenu == MINSERTFILE) { htx[0] = N_("Insert File Help Text\n\n " "Type in the name of a file to be inserted into the " "current file buffer at the current cursor " "location.\n\n If you have compiled nano with multiple " "file buffer support, and enable multiple file buffers " "with the -F or --multibuffer command line flags, the " "Meta-F toggle, or a nanorc file, inserting a file " "will cause it to be loaded into a separate buffer " "(use Meta-< and > to switch between file buffers). "); htx[1] = N_("If you need another blank buffer, do not enter " "any filename, or type in a nonexistent filename at " "the prompt and press Enter.\n\n The following " "function keys are available in Insert File mode:\n\n"); htx[2] = NULL; } else if (currmenu == MWRITEFILE) { htx[0] = N_("Write File Help Text\n\n " "Type the name that you wish to save the current file " "as and press Enter to save the file.\n\n If you have " "selected text with the mark, you will be prompted to " "save only the selected portion to a separate file. To " "reduce the chance of overwriting the current file with " "just a portion of it, the current filename is not the " "default in this mode.\n\n The following function keys " "are available in Write File mode:\n\n"); htx[1] = NULL; htx[2] = NULL; } #ifndef DISABLE_BROWSER else if (currmenu == MBROWSER) { htx[0] = N_("File Browser Help Text\n\n " "The file browser is used to visually browse the " "directory structure to select a file for reading " "or writing. You may use the arrow keys or Page Up/" "Down to browse through the files, and S or Enter to " "choose the selected file or enter the selected " "directory. To move up one level, select the " "directory called \"..\" at the top of the file " "list.\n\n The following function keys are available " "in the file browser:\n\n"); htx[1] = NULL; htx[2] = NULL; } else if (currmenu == MWHEREISFILE) { htx[0] = N_("Browser Search Command Help Text\n\n " "Enter the words or characters you would like to " "search for, and then press Enter. If there is a " "match for the text you entered, the screen will be " "updated to the location of the nearest match for the " "search string.\n\n The previous search string will be " "shown in brackets after the search prompt. Hitting " "Enter without entering any text will perform the " "previous search.\n\n"); htx[1] = N_(" The following function keys are available in " "Browser Search mode:\n\n"); htx[2] = NULL; } else if (currmenu == MGOTODIR) { htx[0] = N_("Browser Go To Directory Help Text\n\n " "Enter the name of the directory you would like to " "browse to.\n\n If tab completion has not been " "disabled, you can use the Tab key to (attempt to) " "automatically complete the directory name.\n\n The " "following function keys are available in Browser Go " "To Directory mode:\n\n"); htx[1] = NULL; htx[2] = NULL; } #endif /* !DISABLE_BROWSER */ #ifndef DISABLE_SPELLER else if (currmenu == MSPELL) { htx[0] = N_("Spell Check Help Text\n\n " "The spell checker checks the spelling of all text in " "the current file. When an unknown word is " "encountered, it is highlighted and a replacement can " "be edited. It will then prompt to replace every " "instance of the given misspelled word in the current " "file, or, if you have selected text with the mark, in " "the selected text.\n\n The following function keys " "are available in Spell Check mode:\n\n"); htx[1] = NULL; htx[2] = NULL; } #endif /* !DISABLE_SPELLER */ #ifndef NANO_TINY else if (currmenu == MEXTCMD) { htx[0] = N_("Execute Command Help Text\n\n " "This mode allows you to insert the output of a " "command run by the shell into the current buffer (or " "a new buffer in multiple file buffer mode). If you " "need another blank buffer, do not enter any " "command.\n\n The following function keys are " "available in Execute Command mode:\n\n"); htx[1] = NULL; htx[2] = NULL; } #endif /* !NANO_TINY */ else { /* Default to the main help list. */ htx[0] = N_("Main nano help text\n\n " "The nano editor is designed to emulate the " "functionality and ease-of-use of the UW Pico text " "editor. There are four main sections of the editor. " "The top line shows the program version, the current " "filename being edited, and whether or not the file " "has been modified. Next is the main editor window " "showing the file being edited. The status line is " "the third line from the bottom and shows important " "messages. "); htx[1] = N_("The bottom two lines show the most commonly used " "shortcuts in the editor.\n\n Shortcuts are written as " "follows: Control-key sequences are notated with a '^' " "and can be entered either by using the Ctrl key or " "pressing the Esc key twice. Meta-key sequences are " "notated with 'M-' and can be entered using either the " "Alt, Cmd, or Esc key, depending on your keyboard setup. "); htx[2] = N_("Also, pressing Esc twice and then typing a " "three-digit decimal number from 000 to 255 will enter " "the character with the corresponding value. The " "following keystrokes are available in the main editor " "window. Alternative keys are shown in " "parentheses:\n\n"); } htx[0] = _(htx[0]); if (htx[1] != NULL) htx[1] = _(htx[1]); if (htx[2] != NULL) htx[2] = _(htx[2]); allocsize += strlen(htx[0]); if (htx[1] != NULL) allocsize += strlen(htx[1]); if (htx[2] != NULL) allocsize += strlen(htx[2]); /* Calculate the length of the shortcut help text. Each entry has * one or two keys, which fill 16 columns, plus translated text, * plus one or two \n's. */ for (f = allfuncs; f != NULL; f = f->next) if (f->menus & currmenu) allocsize += (16 * mb_cur_max()) + strlen(f->help) + 2; #ifndef NANO_TINY /* If we're on the main list, we also count the toggle help text. * Each entry has "M-%c\t\t", five chars which fill 16 columns, * plus a space, plus translated text, plus one or two '\n's. */ if (currmenu == MMAIN) { size_t endis_len = strlen(_("enable/disable")); for (s = sclist; s != NULL; s = s->next) if (s->scfunc == do_toggle_void) allocsize += strlen(_(flagtostr(s->toggle))) + endis_len + 8; } #endif /* Allocate space for the help text. */ help_text = charalloc(allocsize + 1); /* Now add the text we want. */ strcpy(help_text, htx[0]); if (htx[1] != NULL) strcat(help_text, htx[1]); if (htx[2] != NULL) strcat(help_text, htx[2]); ptr = help_text + strlen(help_text); /* Remember this end-of-introduction, start-of-shortcuts. */ end_of_intro = ptr; /* Now add our shortcut info. */ for (f = allfuncs; f != NULL; f = f->next) { int scsfound = 0; if ((f->menus & currmenu) == 0) continue; /* Let's simply show the first two shortcuts from the list. */ for (s = sclist; s != NULL; s = s->next) { if ((s->menus & currmenu) == 0) continue; if (s->scfunc == f->scfunc) { scsfound++; /* Make the first column narrower (6) than the second (10), * but allow it to spill into the second, for "M-Space". */ if (scsfound == 1) { sprintf(ptr, "%s ", s->keystr); /* Unicode arrows take three bytes instead of one. */ if (s->keystr[1] == '\xE2') ptr += 8; else ptr += 6; } else { ptr += sprintf(ptr, "(%s)\t", s->keystr); break; } } } if (scsfound == 0) ptr += sprintf(ptr, "\t\t"); else if (scsfound == 1) ptr += 10; /* The shortcut's help text. */ ptr += sprintf(ptr, "%s\n", _(f->help)); if (f->blank_after) ptr += sprintf(ptr, "\n"); } #ifndef NANO_TINY /* And the toggles... */ if (currmenu == MMAIN) { int maximum = 0, counter = 0; /* First see how many toggles there are. */ for (s = sclist; s != NULL; s = s->next) maximum = (s->toggle && s->ordinal > maximum) ? s->ordinal : maximum; /* Now show them in the original order. */ while (counter < maximum) { counter++; for (s = sclist; s != NULL; s = s->next) if (s->toggle && s->ordinal == counter) { ptr += sprintf(ptr, "%s\t\t%s %s\n", (s->menus == MMAIN ? s->keystr : ""), _(flagtostr(s->toggle)), _("enable/disable")); if (s->toggle == NO_COLOR_SYNTAX || s->toggle == TABS_TO_SPACES) ptr += sprintf(ptr, "\n"); break; } } } if (old_whitespace) SET(WHITESPACE_DISPLAY); #endif /* !NANO_TINY */ /* If all went well, we didn't overwrite the allocated space. */ assert(strlen(help_text) <= allocsize + 1); }
/* Search for a match to the bracket at the current cursor position, if * there is one. */ void do_find_bracket(void) { linestruct *current_save; size_t current_x_save, pww_save; const char *ch; /* The location in matchbrackets of the bracket at the current * cursor position. */ int ch_len; /* The length of ch in bytes. */ const char *wanted_ch; /* The location in matchbrackets of the bracket complementing * the bracket at the current cursor position. */ int wanted_ch_len; /* The length of wanted_ch in bytes. */ char *bracket_set; /* The pair of characters in ch and wanted_ch. */ size_t i; /* Generic loop variable. */ size_t matchhalf; /* The number of single-byte characters in one half of * matchbrackets. */ size_t mbmatchhalf; /* The number of multibyte characters in one half of * matchbrackets. */ size_t count = 1; /* The initial bracket count. */ bool reverse; /* The direction we search. */ char *found_ch; /* The character we find. */ assert(mbstrlen(matchbrackets) % 2 == 0); ch = openfile->current->data + openfile->current_x; if (ch == '\0' || (ch = mbstrchr(matchbrackets, ch)) == NULL) { statusbar(_("Not a bracket")); return; } /* Save where we are. */ current_save = openfile->current; current_x_save = openfile->current_x; pww_save = openfile->placewewant; /* If we're on an opening bracket, which must be in the first half * of matchbrackets, we want to search forwards for a closing * bracket. If we're on a closing bracket, which must be in the * second half of matchbrackets, we want to search backwards for an * opening bracket. */ matchhalf = 0; mbmatchhalf = mbstrlen(matchbrackets) / 2; for (i = 0; i < mbmatchhalf; i++) matchhalf += parse_mbchar(matchbrackets + matchhalf, NULL, NULL); reverse = ((ch - matchbrackets) >= matchhalf); /* If we're on an opening bracket, set wanted_ch to the character * that's matchhalf characters after ch. If we're on a closing * bracket, set wanted_ch to the character that's matchhalf * characters before ch. */ wanted_ch = ch; while (mbmatchhalf > 0) { if (reverse) wanted_ch = matchbrackets + move_mbleft(matchbrackets, wanted_ch - matchbrackets); else wanted_ch += move_mbright(wanted_ch, 0); mbmatchhalf--; } ch_len = parse_mbchar(ch, NULL, NULL); wanted_ch_len = parse_mbchar(wanted_ch, NULL, NULL); /* Fill bracket_set in with the values of ch and wanted_ch. */ bracket_set = charalloc((mb_cur_max() * 2) + 1); strncpy(bracket_set, ch, ch_len); strncpy(bracket_set + ch_len, wanted_ch, wanted_ch_len); null_at(&bracket_set, ch_len + wanted_ch_len); found_ch = charalloc(mb_cur_max() + 1); while (TRUE) { if (find_bracket_match(reverse, bracket_set)) { /* If we found an identical bracket, increment count. If we * found a complementary bracket, decrement it. */ parse_mbchar(openfile->current->data + openfile->current_x, found_ch, NULL); count += (strncmp(found_ch, ch, ch_len) == 0) ? 1 : -1; /* If count is zero, we've found a matching bracket. Update * the screen and get out. */ if (count == 0) { edit_redraw(current_save, pww_save); break; } } else { /* We didn't find either an opening or closing bracket. * Indicate this, restore where we were, and get out. */ statusbar(_("No matching bracket")); openfile->current = current_save; openfile->current_x = current_x_save; openfile->placewewant = pww_save; break; } } /* Clean up. */ free(bracket_set); free(found_ch); }