/** returns the position where text was found in the start buffer * or 0 if not found */ static const char * search_string (const char *start, const char *text) { const char *result = NULL; char *local_text = g_strdup (text); char *d = local_text; const char *e = start; /* fmt sometimes replaces a space with a newline in the help file */ /* Replace the newlines in the link name with spaces to correct the situation */ while (*d != '\0') { if (*d == '\n') *d = ' '; str_next_char (&d); } /* Do search */ for (d = local_text; *e; e++) { if (*d == *e) d++; else d = local_text; if (*d == '\0') { result = e + 1; break; } } g_free (local_text); return result; }
/** Check if directory completion is needed */ static gboolean check_is_cd (const char *text, int lc_start, input_complete_t flags) { char *p, *q; SHOW_C_CTX ("check_is_cd"); if ((flags & INPUT_COMPLETE_CD) == 0) return FALSE; /* Skip initial spaces */ p = (char *) text; q = (char *) text + lc_start; while (p < q && p[0] != '\0' && str_isspace (p)) str_next_char (&p); /* Check if the command is "cd" and the cursor is after it */ return (p[0] == 'c' && p[1] == 'd' && str_isspace (p + 2) && p + 2 < q); }
static void fetch_hosts (const char *filename) { FILE *file = fopen (filename, "r"); char buffer[256], *name; char *lc_start; char *bi; if (!file) return; while (fgets (buffer, 255, file) != NULL) { /* Skip to first character. */ for (bi = buffer; bi[0] != '\0' && str_isspace (bi); str_next_char (&bi)); /* Ignore comments... */ if (bi[0] == '#') continue; /* Handle $include. */ if (!strncmp (bi, "$include ", 9)) { char *includefile = bi + 9; char *t; /* Find start of filename. */ while (*includefile && whitespace (*includefile)) includefile++; t = includefile; /* Find end of filename. */ while (t[0] != '\0' && !str_isspace (t)) str_next_char (&t); *t = '\0'; fetch_hosts (includefile); continue; } /* Skip IP #s. */ while (bi[0] != '\0' && !str_isspace (bi)) str_next_char (&bi); /* Get the host names separated by white space. */ while (bi[0] != '\0' && bi[0] != '#') { while (bi[0] != '\0' && str_isspace (bi)) str_next_char (&bi); if (bi[0] == '#') continue; for (lc_start = bi; bi[0] != '\0' && !str_isspace (bi); str_next_char (&bi)); if (bi - lc_start == 0) continue; name = g_strndup (lc_start, bi - lc_start); { char **host_p; if (hosts_p - hosts >= hosts_alloclen) { int j; j = hosts_p - hosts; hosts_alloclen += 30; hosts = g_renew (char *, hosts, hosts_alloclen + 1); hosts_p = hosts + j; } for (host_p = hosts; host_p < hosts_p; host_p++) if (!strcmp (name, *host_p)) break; /* We do not want any duplicates */ if (host_p == hosts_p) { *(hosts_p++) = name; *hosts_p = NULL; } else g_free (name); } } }
static int complete_engine (WInput * in, int what_to_do) { if (in->completions != NULL && str_offset_to_pos (in->buffer, in->point) != end) input_free_completions (in); if (in->completions == NULL) { char *s; end = str_offset_to_pos (in->buffer, in->point); s = in->buffer; if (in->point != 0) { /* get symbol before in->point */ size_t i; for (i = in->point - 1; i > 0; i--) str_next_char (&s); } for (; s >= in->buffer; str_prev_char (&s)) { start = s - in->buffer; if (strchr (" \t;|<>", *s) != NULL) break; } if (start < end) { str_next_char (&s); start = s - in->buffer; } in->completions = try_complete (in->buffer, &start, &end, in->completion_flags); } if (in->completions != NULL) { if (what_to_do & DO_INSERTION || ((what_to_do & DO_QUERY) && !in->completions[1])) { char *lc_complete = in->completions[0]; if (insert_text (in, lc_complete, strlen (lc_complete))) { if (in->completions[1]) tty_beep (); else input_free_completions (in); } else tty_beep (); } if ((what_to_do & DO_QUERY) && in->completions && in->completions[1]) { int maxlen = 0, i, count = 0; int x, y, w, h; int start_x, start_y; char **p, *q; Dlg_head *query_dlg; WListbox *query_list; for (p = in->completions + 1; *p != NULL; count++, p++) { i = str_term_width1 (*p); if (i > maxlen) maxlen = i; } start_x = in->widget.x; start_y = in->widget.y; if (start_y - 2 >= count) { y = start_y - 2 - count; h = 2 + count; } else { if (start_y >= LINES - start_y - 1) { y = 0; h = start_y; } else { y = start_y + 1; h = LINES - start_y - 1; } } x = start - in->term_first_shown - 2 + start_x; w = maxlen + 4; if (x + w > COLS) x = COLS - w; if (x < 0) x = 0; if (x + w > COLS) w = COLS; input = in; min_end = end; query_height = h; query_width = w; query_dlg = create_dlg (TRUE, y, x, query_height, query_width, dialog_colors, query_callback, NULL, "[Completion]", NULL, DLG_COMPACT); query_list = listbox_new (1, 1, h - 2, w - 2, FALSE, NULL); add_widget (query_dlg, query_list); for (p = in->completions + 1; *p; p++) listbox_add_item (query_list, LISTBOX_APPEND_AT_END, 0, *p, NULL); run_dlg (query_dlg); q = NULL; if (query_dlg->ret_value == B_ENTER) { listbox_get_current (query_list, &q, NULL); if (q) insert_text (in, q, strlen (q)); } if (q || end != min_end) input_free_completions (in); i = query_dlg->ret_value; /* B_USER if user wants to start over again */ destroy_dlg (query_dlg); if (i == B_USER) return 1; } } else tty_beep (); return 0; }
static cb_ret_t query_callback (Dlg_head * h, Widget * sender, dlg_msg_t msg, int parm, void *data) { static char buff[MB_LEN_MAX] = ""; static int bl = 0; switch (msg) { case DLG_KEY: switch (parm) { case KEY_LEFT: case KEY_RIGHT: bl = 0; h->ret_value = 0; dlg_stop (h); return MSG_HANDLED; case KEY_BACKSPACE: bl = 0; /* exit from completion list if input line is empty */ if (end == 0) { h->ret_value = 0; dlg_stop (h); } /* Refill the list box and start again */ else if (end == min_end) { end = str_get_prev_char (&input->buffer[end]) - input->buffer; input_handle_char (input, parm); h->ret_value = B_USER; dlg_stop (h); return MSG_HANDLED; } else { int new_end; int i; GList *e; new_end = str_get_prev_char (&input->buffer[end]) - input->buffer; for (i = 0, e = ((WListbox *) h->current->data)->list; e != NULL; i++, e = g_list_next (e)) { WLEntry *le = (WLEntry *) e->data; if (strncmp (input->buffer + start, le->text, new_end - start) == 0) { listbox_select_entry ((WListbox *) h->current->data, i); end = new_end; input_handle_char (input, parm); send_message ((Widget *) h->current->data, WIDGET_DRAW, 0); break; } } } return MSG_HANDLED; default: if (parm < 32 || parm > 255) { bl = 0; if (input_key_is_in_map (input, parm) != 2) return MSG_NOT_HANDLED; if (end == min_end) return MSG_HANDLED; /* This means we want to refill the list box and start again */ h->ret_value = B_USER; dlg_stop (h); return MSG_HANDLED; } else { GList *e; int i; int need_redraw = 0; int low = 4096; char *last_text = NULL; buff[bl++] = (char) parm; buff[bl] = '\0'; switch (str_is_valid_char (buff, bl)) { case -1: bl = 0; /* fallthrough */ case -2: return MSG_HANDLED; } for (i = 0, e = ((WListbox *) h->current->data)->list; e != NULL; i++, e = g_list_next (e)) { WLEntry *le = (WLEntry *) e->data; if (strncmp (input->buffer + start, le->text, end - start) == 0 && strncmp (&le->text[end - start], buff, bl) == 0) { if (need_redraw == 0) { need_redraw = 1; listbox_select_entry ((WListbox *) h->current->data, i); last_text = le->text; } else { char *si, *sl; int si_num = 0; int sl_num = 0; /* count symbols between start and end */ for (si = le->text + start; si < le->text + end; str_next_char (&si), si_num++) ; for (sl = last_text + start; sl < last_text + end; str_next_char (&sl), sl_num++) ; /* pointers to next symbols */ si = &le->text[str_offset_to_pos (le->text, ++si_num)]; sl = &last_text[str_offset_to_pos (last_text, ++sl_num)]; while (si[0] != '\0' && sl[0] != '\0') { char *nexti, *nextl; nexti = str_get_next_char (si); nextl = str_get_next_char (sl); if (nexti - si != nextl - sl || strncmp (si, sl, nexti - si) != 0) break; si = nexti; sl = nextl; si_num++; } last_text = le->text; si = &last_text[str_offset_to_pos (last_text, si_num)]; if (low > si - last_text) low = si - last_text; need_redraw = 2; } } } if (need_redraw == 2) { insert_text (input, last_text, low); send_message ((Widget *) h->current->data, WIDGET_DRAW, 0); } else if (need_redraw == 1) { h->ret_value = B_ENTER; dlg_stop (h); } bl = 0; } return MSG_HANDLED; } break; default: return default_dlg_callback (h, sender, msg, parm, data); } }
gboolean user_menu_cmd (struct WEdit * edit_widget, const char *menu_file, int selected_entry) { char *p; char *data, **entries; int max_cols, menu_lines, menu_limit; int col, i, accept_entry = 1; int selected, old_patterns; gboolean res = FALSE; gboolean interactive = TRUE; if (!vfs_current_is_local ()) { message (D_ERROR, MSG_ERROR, "%s", _("Cannot execute commands on non-local filesystems")); return FALSE; } if (menu_file != NULL) menu = g_strdup (menu_file); else menu = g_strdup (edit_widget ? EDIT_LOCAL_MENU : MC_LOCAL_MENU); if (!exist_file (menu) || !menu_file_own (menu)) { if (menu_file != NULL) { message (D_ERROR, MSG_ERROR, _("Cannot open file %s\n%s"), menu, unix_error_string (errno)); MC_PTR_FREE (menu); return FALSE; } g_free (menu); if (edit_widget) menu = mc_config_get_full_path (EDIT_HOME_MENU); else menu = mc_config_get_full_path (MC_USERMENU_FILE); if (!exist_file (menu)) { g_free (menu); menu = mc_build_filename (mc_config_get_home_dir (), edit_widget ? EDIT_GLOBAL_MENU : MC_GLOBAL_MENU, NULL); if (!exist_file (menu)) { g_free (menu); menu = mc_build_filename (mc_global.sysconfig_dir, edit_widget ? EDIT_GLOBAL_MENU : MC_GLOBAL_MENU, NULL); if (!exist_file (menu)) { g_free (menu); menu = mc_build_filename (mc_global.share_data_dir, edit_widget ? EDIT_GLOBAL_MENU : MC_GLOBAL_MENU, NULL); } } } } if (!g_file_get_contents (menu, &data, NULL, NULL)) { message (D_ERROR, MSG_ERROR, _("Cannot open file%s\n%s"), menu, unix_error_string (errno)); MC_PTR_FREE (menu); return FALSE; } max_cols = 0; selected = 0; menu_limit = 0; entries = 0; /* Parse the menu file */ old_patterns = easy_patterns; p = check_patterns (data); for (menu_lines = col = 0; *p; str_next_char (&p)) { if (menu_lines >= menu_limit) { char **new_entries; menu_limit += MAX_ENTRIES; new_entries = g_try_realloc (entries, sizeof (new_entries[0]) * menu_limit); if (new_entries == NULL) break; entries = new_entries; new_entries += menu_limit; while (--new_entries >= &entries[menu_lines]) *new_entries = NULL; } if (col == 0 && !entries[menu_lines]) { if (*p == '#') { /* show prompt if first line of external script is #interactive */ if (selected_entry >= 0 && strncmp (p, "#silent", 7) == 0) interactive = FALSE; /* A commented menu entry */ accept_entry = 1; } else if (*p == '+') { if (*(p + 1) == '=') { /* Combined adding and default */ p = test_line (edit_widget, p + 1, &accept_entry); if (selected == 0 && accept_entry) selected = menu_lines; } else { /* A condition for adding the entry */ p = test_line (edit_widget, p, &accept_entry); } } else if (*p == '=') { if (*(p + 1) == '+') { /* Combined adding and default */ p = test_line (edit_widget, p + 1, &accept_entry); if (selected == 0 && accept_entry) selected = menu_lines; } else { /* A condition for making the entry default */ i = 1; p = test_line (edit_widget, p, &i); if (selected == 0 && i) selected = menu_lines; } } else if (*p != ' ' && *p != '\t' && str_isprint (p)) { /* A menu entry title line */ if (accept_entry) entries[menu_lines] = p; else accept_entry = 1; } } if (*p == '\n') { if (entries[menu_lines]) { menu_lines++; accept_entry = 1; } max_cols = max (max_cols, col); col = 0; } else { if (*p == '\t') *p = ' '; col++; } } if (menu_lines == 0) { message (D_ERROR, MSG_ERROR, _("No suitable entries found in %s"), menu); res = FALSE; } else { if (selected_entry >= 0) selected = selected_entry; else { Listbox *listbox; max_cols = min (max (max_cols, col), MAX_ENTRY_LEN); /* Create listbox */ listbox = create_listbox_window (menu_lines, max_cols + 2, _("User menu"), "[Menu File Edit]"); /* insert all the items found */ for (i = 0; i < menu_lines; i++) { p = entries[i]; LISTBOX_APPEND_TEXT (listbox, (unsigned char) p[0], extract_line (p, p + MAX_ENTRY_LEN), p); } /* Select the default entry */ listbox_select_entry (listbox->list, selected); selected = run_listbox (listbox); } if (selected >= 0) { execute_menu_command (edit_widget, entries[selected], interactive); res = TRUE; } do_refresh (); } easy_patterns = old_patterns; MC_PTR_FREE (menu); g_free (entries); g_free (data); return res; }