示例#1
0
文件: search.c 项目: ris21/yoda
/* Update a history list.  h should be the current position in the
 * list. */
void update_history(linestruct **h, const char *s)
{
    linestruct **hage = NULL, **hbot = NULL, *p;

    assert(h != NULL && s != NULL);

    if (*h == search_history) {
	hage = &searchage;
	hbot = &searchbot;
    } else if (*h == replace_history) {
	hage = &replaceage;
	hbot = &replacebot;
    }

    assert(hage != NULL && hbot != NULL);

    /* If this string is already in the history, delete it. */
    p = find_history(*hage, *hbot, s, strlen(s));

    if (p != NULL) {
	linestruct *foo, *bar;

	/* If the string is at the beginning, move the beginning down to
	 * the next string. */
	if (p == *hage)
	    *hage = (*hage)->next;

	/* Delete the string. */
	foo = p;
	bar = p->next;
	unlink_node(foo);
	delete_node(foo);
	renumber(bar);
    }

    /* If the history is full, delete the beginning entry to make room
     * for the new entry at the end.  We assume that MAX_SEARCH_HISTORY
     * is greater than zero. */
    if ((*hbot)->lineno == MAX_SEARCH_HISTORY + 1) {
	linestruct *foo = *hage;

	*hage = (*hage)->next;
	unlink_node(foo);
	delete_node(foo);
	renumber(*hage);
    }

    /* Add the new entry to the end. */
    (*hbot)->data = mallocstrcpy((*hbot)->data, s);
    splice_node(*hbot, make_new_node(*hbot), (*hbot)->next);
    *hbot = (*hbot)->next;
    (*hbot)->data = mallocstrcpy(NULL, "");

    /* Indicate that the history's been changed. */
    history_changed = TRUE;

    /* Set the current position in the list to the bottom. */
    *h = *hbot;
}
示例#2
0
文件: search.c 项目: ris21/yoda
/* Search for a string. */
void do_search(void)
{
    linestruct *fileptr = openfile->current;
    size_t fileptr_x = openfile->current_x;
    size_t pww_save = openfile->placewewant;
    int i;
    bool didfind;

    i = search_init(FALSE, FALSE);

    if (i == -1)
	/* Cancel, Go to Line, blank search string, or regcomp() failed. */
	search_replace_abort();
    else if (i == -2)
	/* Replace. */
	do_replace();
#if !defined(NANO_TINY) || defined(HAVE_REGEX_H)
    else if (i == 1)
	/* Case Sensitive, Backwards, or Regexp search toggle. */
	do_search();
#endif

    if (i != 0)
	return;

    /* If answer is now "", copy last_search into answer. */
    if (*answer == '\0')
	answer = mallocstrcpy(answer, last_search);
    else
	last_search = mallocstrcpy(last_search, answer);

#ifndef DISABLE_HISTORIES
    /* If answer is not "", add this search string to the search history
     * list. */
    if (answer[0] != '\0')
	update_history(&search_history, answer);
#endif

    findnextstr_wrap_reset();
    didfind = findnextstr(
#ifndef DISABLE_SPELLER
	FALSE,
#endif
	openfile->current, openfile->current_x, answer, NULL);

    /* If we found something, and we're back at the exact same spot where
     * we started searching, then this is the only occurrence. */
    if (fileptr == openfile->current && fileptr_x ==
	openfile->current_x && didfind) {
	    statusbar(_("This is the only occurrence"));
    }

    openfile->placewewant = xplustabs();
    edit_redraw(fileptr, pww_save);
    search_replace_abort();
}
示例#3
0
文件: search.c 项目: ris21/yoda
/* Initialize the search and replace history lists. */
void history_init(void)
{
    search_history = make_new_node(NULL);
    search_history->data = mallocstrcpy(NULL, "");
    searchage = search_history;
    searchbot = search_history;

    replace_history = make_new_node(NULL);
    replace_history->data = mallocstrcpy(NULL, "");
    replaceage = replace_history;
    replacebot = replace_history;
}
示例#4
0
/* Update a history list (the one in which item is the current position)
 * with a fresh string text.  That is: add text, or move it to the end. */
void update_history(linestruct **item, const char *text)
{
	linestruct **htop = NULL, **hbot = NULL, *thesame;

	if (*item == search_history) {
		htop = &searchtop;
		hbot = &searchbot;
	} else if (*item == replace_history) {
		htop = &replacetop;
		hbot = &replacebot;
	} else if (*item == execute_history) {
		htop = &executetop;
		hbot = &executebot;
	}

	/* See if the string is already in the history. */
	thesame = find_history(*hbot, *htop, text, HIGHEST_POSITIVE);

	/* If an identical string was found, delete that item. */
	if (thesame != NULL) {
		linestruct *after = thesame->next;

		/* If the string is at the head of the list, move the head. */
		if (thesame == *htop)
			*htop = after;

		unlink_node(thesame);
		renumber_from(after);
	}

	/* If the history is full, delete the oldest item (the one at the
	 * head of the list), to make room for a new item at the end. */
	if ((*hbot)->lineno == MAX_SEARCH_HISTORY + 1) {
		linestruct *oldest = *htop;

		*htop = (*htop)->next;
		unlink_node(oldest);
		renumber_from(*htop);
	}

	/* Store the fresh string in the last item, then create a new item. */
	(*hbot)->data = mallocstrcpy((*hbot)->data, text);
	splice_node(*hbot, make_new_node(*hbot));
	*hbot = (*hbot)->next;
	(*hbot)->data = mallocstrcpy(NULL, "");

	/* Indicate that the history needs to be saved on exit. */
	history_changed = TRUE;

	/* Set the current position in the list to the bottom. */
	*item = *hbot;
}
示例#5
0
void f()
{
        if (buf[0] == '~' && strchr(tmp, '/') == NULL)
        {
                buf = mallocstrcpy(buf, tmp);
                matches = username_tab_completion(tmp, &num_matches);
        }
        /* If we're in the middle of the original line, copy the string
           only up to the cursor position into buf, so tab completion
           will result in buf's containing only the tab-completed
           path/filename. */
        else if (strlen(buf) > strlen(tmp))
                buf = mallocstrcpy(buf, tmp);
}
示例#6
0
文件: utils.c 项目: sria91/nano
/* 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;
}
示例#7
0
/* Initialize the lists of historical search and replace strings
 * and the list of historical executed commands. */
void history_init(void)
{
	search_history = make_new_node(NULL);
	search_history->data = mallocstrcpy(NULL, "");
	searchtop = search_history;
	searchbot = search_history;

	replace_history = make_new_node(NULL);
	replace_history->data = mallocstrcpy(NULL, "");
	replacetop = replace_history;
	replacebot = replace_history;

	execute_history = make_new_node(NULL);
	execute_history->data = mallocstrcpy(NULL, "");
	executetop = execute_history;
	executebot = execute_history;
}
示例#8
0
/* Move h to the next string that's a tab completion of the string s,
 * looking at only the first len characters of s, and return that
 * string.  If there isn't one, or if len is 0, don't move h and return
 * s. */
char *get_history_completion(linestruct **h, char *s, size_t len)
{
	if (len > 0) {
		linestruct *htop = NULL, *hbot = NULL, *p;

		if (*h == search_history) {
			htop = searchtop;
			hbot = searchbot;
		} else if (*h == replace_history) {
			htop = replacetop;
			hbot = replacebot;
		} else if (*h == execute_history) {
			htop = executetop;
			hbot = executebot;
		}

		/* Search the history list from the current position to the top
		 * for a match of len characters.  Skip over an exact match. */
		p = find_history((*h)->prev, htop, s, len);

		while (p != NULL && strcmp(p->data, s) == 0)
			p = find_history(p->prev, htop, s, len);

		if (p != NULL) {
			*h = p;
			return mallocstrcpy(s, (*h)->data);
		}

		/* Search the history list from the bottom to the current position
		 * for a match of len characters.  Skip over an exact match. */
		p = find_history(hbot, *h, s, len);

		while (p != NULL && strcmp(p->data, s) == 0)
			p = find_history(p->prev, *h, s, len);

		if (p != NULL) {
			*h = p;
			return mallocstrcpy(s, (*h)->data);
		}
	}

	/* If we're here, we didn't find a match, we didn't find an inexact
	 * match, or len is 0.  Return s. */
	return (char *)s;
}
示例#9
0
/* Parse and store the name given after a linter/formatter command. */
void pick_up_name(const char *kind, char *ptr, char **storage)
{
    assert(ptr != NULL);

    if (!opensyntax) {
	rcfile_error(
		N_("A '%s' command requires a preceding 'syntax' command"), kind);
	return;
    }

    if (*ptr == '\0') {
	rcfile_error(N_("Missing command after '%s'"), kind);
	return;
    }

    free(*storage);

    /* Allow unsetting the command by using an empty string. */
    if (!strcmp(ptr, "\"\""))
	*storage = NULL;
    else if (*ptr == '"') {
	*storage = mallocstrcpy(NULL, ++ptr);
	char* q = *storage;
	char* p = *storage;
	/* Snip out the backslashes of escaped characters. */
	while (*p != '"') {
	    if (*p == '\0') {
		rcfile_error(N_("Argument of '%s' lacks closing \""), kind);
		free(*storage);
		*storage = NULL;
		return;
	    } else if (*p == '\\' && *(p + 1) != '\0') {
		p++;
	    }
	    *q++ = *p++;
	}
	*q = '\0';
    }
    else
	*storage = mallocstrcpy(NULL, ptr);
}
示例#10
0
int execvp(const std::string& file, const std::vector<std::string>& argv, char ***buf)
{
	*buf = (char **)malloc((argv.size() + 1) * sizeof(char *));
	char **args = *buf;
	size_t pos = 0;
	for (auto arg : argv) {
		args[pos++] = mallocstrcpy(NULL, arg.c_str());
	}
	args[pos] = NULL;

	return execvp(file.c_str(), args);
}
示例#11
0
文件: rcfile.c 项目: ris21/yoda
/* Parse the header-line regexes that may influence the choice of syntax. */
void parse_header_exp(char *ptr)
{
    regexlisttype *endheader = NULL;

    assert(ptr != NULL);

    if (syntaxes == NULL) {
	rcfile_error(
		N_("Cannot add a header regex without a syntax command"));
	return;
    }

    if (*ptr == '\0') {
	rcfile_error(N_("Missing regex string"));
	return;
    }

    while (*ptr != '\0') {
	const char *regexstring;
	regexlisttype *newheader;

	if (*ptr != '"') {
	    rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
	    ptr = parse_next_regex(ptr);
	    continue;
	}

	ptr++;

	regexstring = ptr;
	ptr = parse_next_regex(ptr);
	if (ptr == NULL)
	    break;

	newheader = (regexlisttype *)nmalloc(sizeof(regexlisttype));

	/* Save the regex string if it's valid. */
	if (nregcomp(regexstring, 0)) {
	    newheader->ext_regex = mallocstrcpy(NULL, regexstring);
	    newheader->ext = NULL;

	    if (endheader == NULL)
		endsyntax->headers = newheader;
	    else
		endheader->next = newheader;
	    endheader = newheader;
	    endheader->next = NULL;
	} else
	    free(newheader);
    }
}
示例#12
0
文件: utils.c 项目: sria91/nano
/* Append a new magicline to filebot. */
void new_magicline(void)
{
    openfile->filebot->next = (filestruct *)nmalloc(sizeof(filestruct));
    openfile->filebot->next->data = mallocstrcpy(NULL, "");
    openfile->filebot->next->prev = openfile->filebot;
    openfile->filebot->next->next = NULL;
    openfile->filebot->next->lineno = openfile->filebot->lineno + 1;
#ifndef DISABLE_COLOR
    openfile->filebot->next->multidata = NULL;
#endif
    openfile->filebot = openfile->filebot->next;
    openfile->totsize++;
}
示例#13
0
文件: browser.c 项目: ris21/yoda
/* 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);
}
示例#14
0
文件: utils.c 项目: rofl0r/nano
/* Return the user's home directory.  We use $HOME, and if that fails,
 * we fall back on the home directory of the effective user ID. */
void get_homedir(void)
{
    if (homedir == NULL) {
	const char *homenv = getenv("HOME");

	if (homenv == NULL) {
	    const struct passwd *userage = getpwuid(geteuid());

	    if (userage != NULL)
		homenv = userage->pw_dir;
	}
	homedir = mallocstrcpy(NULL, homenv);
    }
}
示例#15
0
文件: utils.c 项目: sria91/nano
/* Return the user's home directory.  We use $HOME, and if that fails,
 * we fall back on the home directory of the effective user ID. */
void get_homedir(void)
{
    if (homedir == NULL) {
	const char *homenv = getenv("HOME");

	if (homenv == NULL) {
	    const struct passwd *userage = getpwuid(geteuid());

	    if (userage != NULL)
		homenv = userage->pw_dir;
	}

	/* Only set homedir if some home directory could be determined,
	 * otherwise keep homedir NULL. */
	if (homenv != NULL && strcmp(homenv, "") != 0)
	    homedir = mallocstrcpy(NULL, homenv);
    }
}
示例#16
0
文件: search.c 项目: ris21/yoda
/* Search for the last string without prompting. */
void do_research(void)
{
    linestruct *fileptr = openfile->current;
    size_t fileptr_x = openfile->current_x;
    size_t pww_save = openfile->placewewant;
    bool didfind;

    focusing = TRUE;

#ifndef DISABLE_HISTORIES
    /* If nothing was searched for yet during this run of nano, but
     * there is a search history, take the most recent item. */
    if (last_search[0] == '\0' && searchbot->prev != NULL)
	last_search = mallocstrcpy(last_search, searchbot->prev->data);
#endif

    if (last_search[0] != '\0') {
#ifdef HAVE_REGEX_H
	/* Since answer is "", use last_search! */
	if (ISSET(USE_REGEXP) && !regexp_init(last_search))
	    return;
#endif

	findnextstr_wrap_reset();
	didfind = findnextstr(
#ifndef DISABLE_SPELLER
		FALSE,
#endif
		openfile->current, openfile->current_x, last_search, NULL);

	/* If we found something, and we're back at the exact same spot
	 * where we started searching, then this is the only occurrence. */
	if (fileptr == openfile->current && fileptr_x ==
		openfile->current_x && didfind) {
		statusbar(_("This is the only occurrence"));
	}
    } else
	statusbar(_("No current search pattern"));

    openfile->placewewant = xplustabs();
    edit_redraw(fileptr, pww_save);
    search_replace_abort();
}
示例#17
0
文件: rcfile.c 项目: ris21/yoda
/* Parse the linter requested for this syntax. */
void parse_linter(char *ptr)
{
    assert(ptr != NULL);

    if (syntaxes == NULL) {
	rcfile_error(
		N_("Cannot add a linter without a syntax command"));
	return;
    }

    if (*ptr == '\0') {
	rcfile_error(N_("Missing linter command"));
	return;
    }

    free(endsyntax->linter);

    /* Let them unset the linter by using "". */
    if (!strcmp(ptr, "\"\""))
	endsyntax->linter = NULL;
    else
	endsyntax->linter = mallocstrcpy(NULL, ptr);
}
示例#18
0
文件: prompt.c 项目: ris21/yoda
/* Get a string of input at the statusbar prompt.  This should only be
 * called from do_prompt(). */
functionptrtype get_prompt_string(int *actual, bool allow_tabs,
#ifndef DISABLE_TABCOMP
	bool allow_files,
	bool *list,
#endif
	const char *curranswer,
#ifndef DISABLE_HISTORIES
	linestruct **history_list,
#endif
	void (*refresh_func)(void))
{
    int kbinput = ERR;
    bool ran_func, finished;
    size_t curranswer_len;
    functionptrtype func;
#ifndef DISABLE_TABCOMP
    bool tabbed = FALSE;
	/* Whether we've pressed Tab. */
#endif
#ifndef DISABLE_HISTORIES
    char *history = NULL;
	/* The current history string. */
    char *magichistory = NULL;
	/* The temporary string typed at the bottom of the history, if
	 * any. */
#ifndef DISABLE_TABCOMP
    int last_kbinput = ERR;
	/* The key we pressed before the current key. */
    size_t complete_len = 0;
	/* The length of the original string that we're trying to
	 * tab complete, if any. */
#endif
#endif /* !DISABLE_HISTORIES */

    answer = mallocstrcpy(answer, curranswer);
    curranswer_len = strlen(answer);

    /* If reset_statusbar_x is TRUE, restore statusbar_x and
     * statusbar_pww to what they were before this prompt.  Then, if
     * statusbar_x is uninitialized or past the end of curranswer, put
     * statusbar_x at the end of the string and update statusbar_pww
     * based on it.  We do these things so that the cursor position
     * stays at the right place if a prompt-changing toggle is pressed,
     * or if this prompt was started from another prompt and we cancel
     * out of it. */
    if (reset_statusbar_x) {
	statusbar_x = old_statusbar_x;
	statusbar_pww = old_pww;
    }

    if (statusbar_x == (size_t)-1 || statusbar_x > curranswer_len) {
	statusbar_x = curranswer_len;
	statusbar_pww = statusbar_xplustabs();
    }

#ifdef DEBUG
    fprintf(stderr, "get_prompt_string: answer = \"%s\", statusbar_x = %lu\n", answer, (unsigned long) statusbar_x);
#endif

    update_statusbar_line(answer, statusbar_x);

    /* Refresh the edit window and the statusbar before getting
     * input. */
    wnoutrefresh(edit);
    wnoutrefresh(bottomwin);

    /* If we're using restricted mode, we aren't allowed to change the
     * name of the current file once it has one, because that would
     * allow writing to files not specified on the command line.  In
     * this case, disable all keys that would change the text if the
     * filename isn't blank and we're at the "Write File" prompt. */
    while (TRUE) {
	kbinput = do_statusbar_input(&ran_func, &finished, refresh_func);
	assert(statusbar_x <= strlen(answer));

#ifndef NANO_TINY
    if (kbinput == KEY_WINCH) {
	refresh_func();
	update_statusbar_line(answer, statusbar_x);
	continue;
    }
#endif

	func = func_from_key(&kbinput);

	if (func == do_cancel || func == do_enter_void)
	    break;

#ifndef DISABLE_TABCOMP
	if (func != do_tab)
	    tabbed = FALSE;

	if (func == do_tab) {
#ifndef DISABLE_HISTORIES
	    if (history_list != NULL) {
		if (last_kbinput != sc_seq_or(do_tab, NANO_CONTROL_I))
		    complete_len = strlen(answer);

		if (complete_len > 0) {
		    answer = mallocstrcpy(answer,
				get_history_completion(history_list,
					answer, complete_len));
		    statusbar_x = strlen(answer);
		}
	    } else
#endif
	    if (allow_tabs)
		answer = input_tab(answer, allow_files, &statusbar_x,
				   &tabbed, refresh_func, list);

	    update_statusbar_line(answer, statusbar_x);
	} else
#endif /* !DISABLE_TABCOMP */
#ifndef DISABLE_HISTORIES
	if (func == get_history_older_void) {
	    if (history_list != NULL) {
		/* If we're scrolling up at the bottom of the history list
		 * and answer isn't blank, save answer in magichistory. */
		if ((*history_list)->next == NULL && answer[0] != '\0')
		    magichistory = mallocstrcpy(magichistory, answer);

		/* Get the older search from the history list and save it in
		 * answer.  If there is no older search, don't do anything. */
		if ((history = get_history_older(history_list)) != NULL) {
		    answer = mallocstrcpy(answer, history);
		    statusbar_x = strlen(answer);
		}

		update_statusbar_line(answer, statusbar_x);

		/* This key has a shortcut-list entry when it's used to
		 * move to an older search, which means that finished has
		 * been set to TRUE.  Set it back to FALSE here, so that
		 * we aren't kicked out of the statusbar prompt. */
		finished = FALSE;
	    }
	} else if (func == get_history_newer_void) {
	    if (history_list != NULL) {
		/* Get the newer search from the history list and save it in
		 * answer.  If there is no newer search, don't do anything. */
		if ((history = get_history_newer(history_list)) != NULL) {
		    answer = mallocstrcpy(answer, history);
		    statusbar_x = strlen(answer);
		}

		/* If, after scrolling down, we're at the bottom of the
		 * history list, answer is blank, and magichistory is set,
		 * save magichistory in answer. */
		if ((*history_list)->next == NULL &&
		    *answer == '\0' && magichistory != NULL) {
			answer = mallocstrcpy(answer, magichistory);
			statusbar_x = strlen(answer);
		    }

		update_statusbar_line(answer, statusbar_x);

		/* This key has a shortcut-list entry when it's used to
		 * move to a newer search, which means that finished has
		 * been set to TRUE.  Set it back to FALSE here, so that
		 * we aren't kicked out of the statusbar prompt. */
		finished = FALSE;
	    }
	} else
#endif /* !DISABLE_HISTORIES */
	if (func == do_help_void) {
	    update_statusbar_line(answer, statusbar_x);

	    /* This key has a shortcut-list entry when it's used to go to
	     * the help browser or display a message indicating that help
	     * is disabled, which means that finished has been set to TRUE.
	     * Set it back to FALSE here, so that we aren't kicked out of
	     * the statusbar prompt. */
	    finished = FALSE;
	}

	/* If we have a shortcut with an associated function, break out if
	 * we're finished after running or trying to run the function. */
	if (finished)
	    break;

#if !defined(DISABLE_HISTORIES) && !defined(DISABLE_TABCOMP)
	last_kbinput = kbinput;
#endif

	reset_statusbar_cursor();
	wnoutrefresh(bottomwin);
    }

#ifndef DISABLE_HISTORIES
    /* Set the current position in the history list to the bottom,
     * and free magichistory if we need to. */
    if (history_list != NULL) {
	history_reset(*history_list);

	free(magichistory);
    }
#endif

    /* We've finished putting in an answer or run a normal shortcut's
     * associated function, so reset statusbar_x and statusbar_pww.  If
     * we've finished putting in an answer, reset the statusbar cursor
     * position too. */
    if (func) {
	if (func == do_cancel || func == do_enter_void || ran_func) {
	    statusbar_x = old_statusbar_x;
	    statusbar_pww = old_pww;

	    if (!ran_func)
		reset_statusbar_x = TRUE;
    /* Otherwise, we're still putting in an answer or a shortcut with
     * an associated function, so leave the statusbar cursor position
     * alone. */
	} else
	    reset_statusbar_x = FALSE;
    }

    *actual = kbinput;

    return func;
}
示例#19
0
文件: search.c 项目: mahyarap/nano
/* 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;
}
示例#20
0
/* Parse the headers (1st line) of the file which may influence the regex used. */
void parse_headers(char *ptr)
{
    char *regstr;

    assert(ptr != NULL);

    if (syntaxes == NULL) {
	rcfile_error(
		N_("Cannot add a header regex without a syntax command"));
	return;
    }

    if (*ptr == '\0') {
	rcfile_error(N_("Missing regex string"));
	return;
    }

    /* Now for the fun part.  Start adding regexes to individual strings
     * in the colorstrings array, woo! */
    while (ptr != NULL && *ptr != '\0') {
	exttype *newheader;
	    /* The new color structure. */

	if (*ptr != '"') {
	    rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
	    ptr = parse_next_regex(ptr);
	    continue;
	}

	ptr++;

	regstr = ptr;
	ptr = parse_next_regex(ptr);
	if (ptr == NULL)
	    break;

	newheader = (exttype *)nmalloc(sizeof(exttype));

	/* Save the regex string if it's valid */
	if (nregcomp(regstr, 0)) {
	    newheader->ext_regex = mallocstrcpy(NULL, regstr);
	    newheader->ext = NULL;
	    newheader->next = NULL;

#ifdef DEBUG
	     fprintf(stderr, "Starting a new header entry: %s\n", newheader->ext_regex);
#endif

	    if (endheader == NULL) {
		endsyntax->headers = newheader;
	    } else {
		endheader->next = newheader;
	    }

	    endheader = newheader;
	} else
	    free(newheader);

    }
}
示例#21
0
/* Parse the rcfile, once it has been opened successfully at rcstream,
 * and close it afterwards.  If syntax_only is TRUE, only allow the file
 * to contain color syntax commands: syntax, color, and icolor. */
void parse_rcfile(FILE *rcstream
#ifdef ENABLE_COLOR
	, bool syntax_only
#endif
	)
{
    char *buf = NULL;
    ssize_t len;
    size_t n;

    while ((len = getline(&buf, &n, rcstream)) > 0) {
	char *ptr, *keyword, *option;
	int set = 0;
	size_t i;

	/* Ignore the newline. */
	if (buf[len - 1] == '\n')
	    buf[len - 1] = '\0';

	lineno++;
	ptr = buf;
	while (isblank(*ptr))
	    ptr++;

	/* If we have a blank line or a comment, skip to the next
	 * line. */
	if (*ptr == '\0' || *ptr == '#')
	    continue;

	/* Otherwise, skip to the next space. */
	keyword = ptr;
	ptr = parse_next_word(ptr);

	/* Try to parse the keyword. */
	if (strcasecmp(keyword, "set") == 0) {
#ifdef ENABLE_COLOR
	    if (syntax_only)
		rcfile_error(
			N_("Command \"%s\" not allowed in included file"),
			keyword);
	    else
#endif
		set = 1;
	} else if (strcasecmp(keyword, "unset") == 0) {
#ifdef ENABLE_COLOR
	    if (syntax_only)
		rcfile_error(
			N_("Command \"%s\" not allowed in included file"),
			keyword);
	    else
#endif
		set = -1;
	}
#ifdef ENABLE_COLOR
	else if (strcasecmp(keyword, "include") == 0) {
	    if (syntax_only)
		rcfile_error(
			N_("Command \"%s\" not allowed in included file"),
			keyword);
	    else
		parse_include(ptr);
	} else if (strcasecmp(keyword, "syntax") == 0) {
	    if (endsyntax != NULL && endcolor == NULL)
		rcfile_error(N_("Syntax \"%s\" has no color commands"),
			endsyntax->desc);
	    parse_syntax(ptr);
	} else if (strcasecmp(keyword, "header") == 0)
	    parse_headers(ptr);
	else if (strcasecmp(keyword, "color") == 0)
	    parse_colors(ptr, FALSE);
	else if (strcasecmp(keyword, "icolor") == 0)
	    parse_colors(ptr, TRUE);
	else if (strcasecmp(keyword, "bind") == 0)
	    parse_keybinding(ptr);
#endif /* ENABLE_COLOR */
	else
	    rcfile_error(N_("Command \"%s\" not understood"), keyword);

	if (set == 0)
	    continue;

	if (*ptr == '\0') {
	    rcfile_error(N_("Missing flag"));
	    continue;
	}

	option = ptr;
	ptr = parse_next_word(ptr);

	for (i = 0; rcopts[i].name != NULL; i++) {
	    if (strcasecmp(option, rcopts[i].name) == 0) {
#ifdef DEBUG
		fprintf(stderr, "parse_rcfile(): name = \"%s\"\n", rcopts[i].name);
#endif
		if (set == 1) {
		    if (rcopts[i].flag != 0)
			/* This option has a flag, so it doesn't take an
			 * argument. */
			SET(rcopts[i].flag);
		    else {
			/* This option doesn't have a flag, so it takes
			 * an argument. */
			if (*ptr == '\0') {
			    rcfile_error(
				N_("Option \"%s\" requires an argument"),
				rcopts[i].name);
			    break;
			}
			option = ptr;
			if (*option == '"')
			    option++;
			ptr = parse_argument(ptr);

			option = mallocstrcpy(NULL, option);
#ifdef DEBUG
			fprintf(stderr, "option = \"%s\"\n", option);
#endif

			/* Make sure option is a valid multibyte
			 * string. */
			if (!is_valid_mbstring(option)) {
			    rcfile_error(
				N_("Option is not a valid multibyte string"));
			    break;
			}

#ifndef DISABLE_OPERATINGDIR
			if (strcasecmp(rcopts[i].name, "operatingdir") == 0)
			    operating_dir = option;
			else
#endif
#ifndef DISABLE_WRAPJUSTIFY
			if (strcasecmp(rcopts[i].name, "fill") == 0) {
			    if (!parse_num(option, &wrap_at)) {
				rcfile_error(
					N_("Requested fill size \"%s\" is invalid"),
					option);
				wrap_at = -CHARS_FROM_EOL;
			    } else
				free(option);
			} else
#endif
#ifndef NANO_TINY
			if (strcasecmp(rcopts[i].name,
				"matchbrackets") == 0) {
			    matchbrackets = option;
			    if (has_blank_mbchars(matchbrackets)) {
				rcfile_error(
					N_("Non-blank characters required"));
				free(matchbrackets);
				matchbrackets = NULL;
			    }
			} else if (strcasecmp(rcopts[i].name,
				"whitespace") == 0) {
			    whitespace = option;
			    if (mbstrlen(whitespace) != 2 ||
				strlenpt(whitespace) != 2) {
				rcfile_error(
					N_("Two single-column characters required"));
				free(whitespace);
				whitespace = NULL;
			    } else {
				whitespace_len[0] =
					parse_mbchar(whitespace, NULL,
					NULL);
				whitespace_len[1] =
					parse_mbchar(whitespace +
					whitespace_len[0], NULL, NULL);
			    }
			} else
#endif
#ifndef DISABLE_JUSTIFY
			if (strcasecmp(rcopts[i].name, "punct") == 0) {
			    punct = option;
			    if (has_blank_mbchars(punct)) {
				rcfile_error(
					N_("Non-blank characters required"));
				free(punct);
				punct = NULL;
			    }
			} else if (strcasecmp(rcopts[i].name,
				"brackets") == 0) {
			    brackets = option;
			    if (has_blank_mbchars(brackets)) {
				rcfile_error(
					N_("Non-blank characters required"));
				free(brackets);
				brackets = NULL;
			    }
			} else if (strcasecmp(rcopts[i].name,
				"quotestr") == 0)
			    quotestr = option;
			else
#endif
#ifndef NANO_TINY
			if (strcasecmp(rcopts[i].name,
				"backupdir") == 0)
			    backup_dir = option;
			else
#endif
#ifndef DISABLE_SPELLER
			if (strcasecmp(rcopts[i].name, "speller") == 0)
			    alt_speller = option;
			else
#endif
			if (strcasecmp(rcopts[i].name,
				"tabsize") == 0) {
			    if (!parse_num(option, &tabsize) ||
				tabsize <= 0) {
				rcfile_error(
					N_("Requested tab size \"%s\" is invalid"),
					option);
				tabsize = -1;
			    } else
				free(option);
			} else
			    assert(FALSE);
		    }
#ifdef DEBUG
		    fprintf(stderr, "flag = %ld\n", rcopts[i].flag);
#endif
		} else if (rcopts[i].flag != 0)
		    UNSET(rcopts[i].flag);
		else
		    rcfile_error(N_("Cannot unset flag \"%s\""),
			rcopts[i].name);
		break;
	    }
	}
	if (rcopts[i].name == NULL)
	    rcfile_error(N_("Unknown flag \"%s\""), option);
    }

#ifdef ENABLE_COLOR
    if (endsyntax != NULL && endcolor == NULL)
	rcfile_error(N_("Syntax \"%s\" has no color commands"),
		endsyntax->desc);
#endif

    free(buf);
    fclose(rcstream);
    lineno = 0;

    check_vitals_mapped();
    return;
}
示例#22
0
void parse_keybinding(char *ptr)
{
    char *keyptr = NULL, *keycopy = NULL, *funcptr = NULL, *menuptr = NULL;
    sc *s, *newsc;
    int i, menu;

    assert(ptr != NULL);

    if (*ptr == '\0') {
	rcfile_error(N_("Missing key name"));
	return;
    }

    keyptr = ptr;
    ptr = parse_next_word(ptr);
    keycopy = mallocstrcpy(NULL, keyptr);
    for (i = 0; i < strlen(keycopy); i++)
	keycopy[i] = toupper(keycopy[i]);

    if (keycopy[0] != 'M' && keycopy[0] != '^' && keycopy[0] != 'F' && keycopy[0] != 'K') {
	rcfile_error(
		N_("keybindings must begin with \"^\", \"M\", or \"F\""));
	return;
    }

    funcptr = ptr;
    ptr = parse_next_word(ptr);

    if (!strcmp(funcptr, "")) {
	rcfile_error(
		N_("Must specify function to bind key to"));
	return;
    }

    menuptr = ptr;
    ptr = parse_next_word(ptr);

    if (!strcmp(menuptr, "")) {
	rcfile_error(
		/* Note to translators, do not translate the word "all"
		   in the sentence below, everything else is fine */
		N_("Must specify menu to bind key to (or \"all\")"));
	return;
    }

    newsc = strtosc(menu, funcptr);
    if (newsc == NULL) {
	rcfile_error(
		N_("Could not map name \"%s\" to a function"), funcptr);
	return;
    }

    menu = strtomenu(menuptr);
    if (menu < 1) {
	rcfile_error(
		N_("Could not map name \"%s\" to a menu"), menuptr);
	return;
    }


#ifdef DEBUG
    fprintf(stderr, "newsc now address %d, menu func assigned = %d, menu = %d\n",
	&newsc, newsc->scfunc, menu);
#endif


    newsc->keystr = keycopy;
    newsc->menu = menu;
    newsc->type = strtokeytype(newsc->keystr);
    assign_keyinfo(newsc);
#ifdef DEBUG
    fprintf(stderr, "s->keystr = \"%s\"\n", newsc->keystr);
    fprintf(stderr, "s->seq = \"%d\"\n", newsc->seq);
#endif

    if (check_bad_binding(newsc)) {
	rcfile_error(
		N_("Sorry, keystr \"%s\" is an illegal binding"), newsc->keystr);
	return;
    }


    /* now let's have some fun.  Try and delete the other entries
       we found for the same menu, then make this new new
       beginning */
    for (s = sclist; s != NULL; s = s->next) {
        if (((s->menu & newsc->menu)) && s->seq == newsc->seq) {
	    s->menu &= ~newsc->menu;
#ifdef DEBUG
	    fprintf(stderr, "replaced menu entry %d\n", s->menu);
#endif
	}
    }
    newsc->next = sclist;
    sclist = newsc;
}
示例#23
0
/* Parse the color string in the line at ptr, and add it to the current
 * file's associated colors.  If icase is TRUE, treat the color string
 * as case insensitive. */
void parse_colors(char *ptr, bool icase)
{
    short fg, bg;
    bool bright = FALSE, no_fgcolor = FALSE;
    char *fgstr;

    assert(ptr != NULL);

    if (syntaxes == NULL) {
	rcfile_error(
		N_("Cannot add a color command without a syntax command"));
	return;
    }

    if (*ptr == '\0') {
	rcfile_error(N_("Missing color name"));
	return;
    }

    fgstr = ptr;
    ptr = parse_next_word(ptr);

    if (strchr(fgstr, ',') != NULL) {
	char *bgcolorname;

	strtok(fgstr, ",");
	bgcolorname = strtok(NULL, ",");
	if (bgcolorname == NULL) {
	    /* If we have a background color without a foreground color,
	     * parse it properly. */
	    bgcolorname = fgstr + 1;
	    no_fgcolor = TRUE;
	}
	if (strncasecmp(bgcolorname, "bright", 6) == 0) {
	    rcfile_error(
		N_("Background color \"%s\" cannot be bright"),
		bgcolorname);
	    return;
	}
	bg = color_to_short(bgcolorname, &bright);
    } else
	bg = -1;

    if (!no_fgcolor) {
	fg = color_to_short(fgstr, &bright);

	/* Don't try to parse screwed-up foreground colors. */
	if (fg == -1)
	    return;
    } else
	fg = -1;

    if (*ptr == '\0') {
	rcfile_error(N_("Missing regex string"));
	return;
    }

    /* Now for the fun part.  Start adding regexes to individual strings
     * in the colorstrings array, woo! */
    while (ptr != NULL && *ptr != '\0') {
	colortype *newcolor;
	    /* The new color structure. */
	bool cancelled = FALSE;
	    /* The start expression was bad. */
	bool expectend = FALSE;
	    /* Do we expect an end= line? */

	if (strncasecmp(ptr, "start=", 6) == 0) {
	    ptr += 6;
	    expectend = TRUE;
	}

	if (*ptr != '"') {
	    rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
	    ptr = parse_next_regex(ptr);
	    continue;
	}

	ptr++;

	fgstr = ptr;
	ptr = parse_next_regex(ptr);
	if (ptr == NULL)
	    break;

	newcolor = (colortype *)nmalloc(sizeof(colortype));

	/* Save the starting regex string if it's valid, and set up the
	 * color information. */
	if (nregcomp(fgstr, icase ? REG_ICASE : 0)) {
	    newcolor->fg = fg;
	    newcolor->bg = bg;
	    newcolor->bright = bright;
	    newcolor->icase = icase;

	    newcolor->start_regex = mallocstrcpy(NULL, fgstr);
	    newcolor->start = NULL;

	    newcolor->end_regex = NULL;
	    newcolor->end = NULL;

	    newcolor->next = NULL;

	    if (endcolor == NULL) {
		endsyntax->color = newcolor;
#ifdef DEBUG
		fprintf(stderr, "Starting a new colorstring for fg %hd, bg %hd\n", fg, bg);
#endif
	    } else {
#ifdef DEBUG
		fprintf(stderr, "Adding new entry for fg %hd, bg %hd\n", fg, bg);
#endif
		endcolor->next = newcolor;
	    }

	    endcolor = newcolor;
	} else {
	    free(newcolor);
	    cancelled = TRUE;
	}

	if (expectend) {
	    if (ptr == NULL || strncasecmp(ptr, "end=", 4) != 0) {
		rcfile_error(
			N_("\"start=\" requires a corresponding \"end=\""));
		return;
	    }
	    ptr += 4;
	    if (*ptr != '"') {
		rcfile_error(
			N_("Regex strings must begin and end with a \" character"));
		continue;
	    }

	    ptr++;

	    fgstr = ptr;
	    ptr = parse_next_regex(ptr);
	    if (ptr == NULL)
		break;

	    /* If the start regex was invalid, skip past the end regex to
	     * stay in sync. */
	    if (cancelled)
		continue;

	    /* Save the ending regex string if it's valid. */
	    newcolor->end_regex = (nregcomp(fgstr, icase ? REG_ICASE :
		0)) ? mallocstrcpy(NULL, fgstr) : NULL;

	    /* Lame way to skip another static counter */
            newcolor->id = endsyntax->nmultis;
            endsyntax->nmultis++;
	}
    }
}
示例#24
0
/* The main rcfile function.  It tries to open the system-wide rcfile,
 * followed by the current user's rcfile. */
void do_rcfile(void)
{
    struct stat rcinfo;
    FILE *rcstream;

    nanorc = mallocstrcpy(nanorc, SYSCONFDIR "/nanorc");

    /* Don't open directories, character files, or block files. */
    if (stat(nanorc, &rcinfo) != -1) {
	if (S_ISDIR(rcinfo.st_mode) || S_ISCHR(rcinfo.st_mode) ||
		S_ISBLK(rcinfo.st_mode))
	    rcfile_error(S_ISDIR(rcinfo.st_mode) ?
		_("\"%s\" is a directory") :
		_("\"%s\" is a device file"), nanorc);
    }

#ifdef DEBUG
    fprintf(stderr, "Parsing file \"%s\"\n", nanorc);
#endif

    /* Try to open the system-wide nanorc. */
    rcstream = fopen(nanorc, "rb");
    if (rcstream != NULL)
	parse_rcfile(rcstream
#ifdef ENABLE_COLOR
		, FALSE
#endif
		);

#ifdef DISABLE_ROOTWRAPPING
    /* We've already read SYSCONFDIR/nanorc, if it's there.  If we're
     * root, and --disable-wrapping-as-root is used, turn wrapping off
     * now. */
    if (geteuid() == NANO_ROOT_UID)
	SET(NO_WRAP);
#endif

    get_homedir();

    if (homedir == NULL)
	rcfile_error(N_("I can't find my home directory!  Wah!"));
    else {
#ifndef RCFILE_NAME
#define RCFILE_NAME ".nanorc"
#endif
	nanorc = charealloc(nanorc, strlen(homedir) + strlen(RCFILE_NAME) + 2);
	sprintf(nanorc, "%s/%s", homedir, RCFILE_NAME);

	/* Don't open directories, character files, or block files. */
	if (stat(nanorc, &rcinfo) != -1) {
	    if (S_ISDIR(rcinfo.st_mode) || S_ISCHR(rcinfo.st_mode) ||
		S_ISBLK(rcinfo.st_mode))
		rcfile_error(S_ISDIR(rcinfo.st_mode) ?
			_("\"%s\" is a directory") :
			_("\"%s\" is a device file"), nanorc);
	}

	/* Try to open the current user's nanorc. */
	rcstream = fopen(nanorc, "rb");
	if (rcstream == NULL) {
	    /* Don't complain about the file's not existing. */
	    if (errno != ENOENT)
		rcfile_error(N_("Error reading %s: %s"), nanorc,
			strerror(errno));
	} else
	    parse_rcfile(rcstream
#ifdef ENABLE_COLOR
		, FALSE
#endif
		);
    }

    free(nanorc);
    nanorc = NULL;

    if (errors && !ISSET(QUIET)) {
	errors = FALSE;
	fprintf(stderr,
		_("\nPress Enter to continue starting nano.\n"));
	while (getchar() != '\n')
	    ;
    }

#ifdef ENABLE_COLOR
    set_colorpairs();
#endif
}
示例#25
0
/* Parse the next syntax string from the line at ptr, and add it to the
 * global list of color syntaxes. */
void parse_syntax(char *ptr)
{
    const char *fileregptr = NULL, *nameptr = NULL;
    syntaxtype *tmpsyntax;
    exttype *endext = NULL;
	/* The end of the extensions list for this syntax. */

    assert(ptr != NULL);

    if (*ptr == '\0') {
	rcfile_error(N_("Missing syntax name"));
	return;
    }

    if (*ptr != '"') {
	rcfile_error(
		N_("Regex strings must begin and end with a \" character"));
	return;
    }

    ptr++;

    nameptr = ptr;
    ptr = parse_next_regex(ptr);

    if (ptr == NULL)
	return;

    /* Search for a duplicate syntax name.  If we find one, free it, so
     * that we always use the last syntax with a given name. */
    for (tmpsyntax = syntaxes; tmpsyntax != NULL;
	tmpsyntax = tmpsyntax->next) {
	if (strcmp(nameptr, tmpsyntax->desc) == 0) {
	    syntaxtype *prev_syntax = tmpsyntax;

	    tmpsyntax = tmpsyntax->next;
	    free(prev_syntax);
	    break;
	}
    }

    if (syntaxes == NULL) {
	syntaxes = (syntaxtype *)nmalloc(sizeof(syntaxtype));
	endsyntax = syntaxes;
    } else {
	endsyntax->next = (syntaxtype *)nmalloc(sizeof(syntaxtype));
	endsyntax = endsyntax->next;
#ifdef DEBUG
	fprintf(stderr, "Adding new syntax after first one\n");
#endif
    }

    endsyntax->desc = mallocstrcpy(NULL, nameptr);
    endsyntax->color = NULL;
    endcolor = NULL;
    endheader = NULL;
    endsyntax->extensions = NULL;
    endsyntax->headers = NULL;
    endsyntax->next = NULL;
    endsyntax->nmultis = 0;

#ifdef DEBUG
    fprintf(stderr, "Starting a new syntax type: \"%s\"\n", nameptr);
#endif

    /* The "none" syntax is the same as not having a syntax at all, so
     * we can't assign any extensions or colors to it. */
    if (strcmp(endsyntax->desc, "none") == 0) {
	rcfile_error(N_("The \"none\" syntax is reserved"));
	return;
    }

    /* The default syntax should have no associated extensions. */
    if (strcmp(endsyntax->desc, "default") == 0 && *ptr != '\0') {
	rcfile_error(
		N_("The \"default\" syntax must take no extensions"));
	return;
    }

    /* Now load the extensions into their part of the struct. */
    while (*ptr != '\0') {
	exttype *newext;
	    /* The new extension structure. */

	while (*ptr != '"' && *ptr != '\0')
	    ptr++;

	if (*ptr == '\0')
	    return;

	ptr++;

	fileregptr = ptr;
	ptr = parse_next_regex(ptr);
	if (ptr == NULL)
	    break;

	newext = (exttype *)nmalloc(sizeof(exttype));

	/* Save the extension regex if it's valid. */
	if (nregcomp(fileregptr, REG_NOSUB)) {
	    newext->ext_regex = mallocstrcpy(NULL, fileregptr);
	    newext->ext = NULL;

	    if (endext == NULL)
		endsyntax->extensions = newext;
	    else
		endext->next = newext;
	    endext = newext;
	    endext->next = NULL;
	} else
	    free(newext);
    }
}
示例#26
0
文件: browser.c 项目: ris21/yoda
/* 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 {
示例#27
0
文件: browser.c 项目: ris21/yoda
/* Our main file browser function.  path is the tilde-expanded path we
 * start browsing from. */
char *do_browser(char *path, DIR *dir)
{
    char *retval = NULL;
    int kbinput;
    bool old_const_update = ISSET(CONST_UPDATE);
    char *prev_dir = NULL;
	/* The directory we were in before backing up to "..". */
    char *ans = NULL;
	/* The last answer the user typed at the statusbar prompt. */
    size_t old_selected;
	/* The selected file we had before the current selected file. */
    functionptrtype func;
	/* The function of the key the user typed in. */

    curs_set(0);
    blank_statusbar();
    bottombars(MBROWSER);
    wnoutrefresh(bottomwin);

    UNSET(CONST_UPDATE);

    ans = mallocstrcpy(NULL, "");

  change_browser_directory:
	/* We go here after we select a new directory. */

    /* Start with no key pressed. */
    kbinput = ERR;

    path = mallocstrassn(path, get_full_path(path));

    /* Save the current path in order to be used later. */
    path_save = path;

    assert(path != NULL && path[strlen(path) - 1] == '/');

    /* Get the file list, and set longest and width in the process. */
    browser_init(path, dir);

    assert(filelist != NULL);

    /* Sort the file list. */
    qsort(filelist, filelist_len, sizeof(char *), diralphasort);

    /* If prev_dir isn't NULL, select the directory saved in it, and
     * then blow it away. */
    if (prev_dir != NULL) {
	browser_select_dirname(prev_dir);

	free(prev_dir);
	prev_dir = NULL;
    /* Otherwise, select the first file or directory in the list. */
    } else
	selected = 0;

    old_selected = (size_t)-1;

    titlebar(path);

    while (TRUE) {
	struct stat st;
	int i;
	size_t fileline = selected / width;
		/* The line number the selected file is on. */
	char *new_path;
		/* The path we switch to at the "Go to Directory"
		 * prompt. */

	/* Display the file list if we don't have a key, or if the
	 * selected file has changed, and set width in the process. */
	if (kbinput == ERR || old_selected != selected)
	    browser_refresh();

	old_selected = selected;

	kbinput = get_kbinput(edit);

#ifndef NANO_TINY
	if (kbinput == KEY_WINCH) {
	    kbinput = ERR;
	    curs_set(0);
	    continue;
	}
#endif

#ifndef DISABLE_MOUSE
	if (kbinput == KEY_MOUSE) {
	    int mouse_x, mouse_y;

	    /* We can click on the edit window to select a
	     * filename. */
	    if (get_mouseinput(&mouse_x, &mouse_y, TRUE) == 0 &&
		wmouse_trafo(edit, &mouse_y, &mouse_x, FALSE)) {
		/* longest is the width of each column.  There
		 * are two spaces between each column. */
		selected = (fileline / editwinrows) *
				(editwinrows * width) + (mouse_y *
				width) + (mouse_x / (longest + 2));

		/* If they clicked beyond the end of a row,
		 * select the last filename in that row. */
		if (mouse_x > width * (longest + 2))
		    selected--;

		/* If we're off the screen, select the last filename. */
		if (selected > filelist_len - 1)
		    selected = filelist_len - 1;

		/* If we selected the same filename as last time,
		 * put back the Enter key so that it's read in. */
		if (old_selected == selected)
		    unget_kbinput(sc_seq_or(do_enter_void, 0), FALSE, FALSE);
	    }
	}
#endif /* !DISABLE_MOUSE */

	func = parse_browser_input(&kbinput);

	if (func == total_refresh) {
	    total_redraw();
	} else if (func == do_help_void) {
#ifndef DISABLE_HELP
	    do_help_void();
	    /* Perhaps the window dimensions have changed. */
	    browser_refresh();
	    curs_set(0);
#else
	    nano_disabled_msg();
#endif
	} else if (func == do_search) {
	    /* Search for a filename. */
	    curs_set(1);
	    do_filesearch();
	    curs_set(0);
	} else if (func == do_research) {
	    /* Search for another filename. */
	    do_fileresearch();
	} else if (func == do_page_up) {
	    if (selected >= (editwinrows + fileline % editwinrows) * width)
		selected -= (editwinrows + fileline % editwinrows) * width;
	    else
		selected = 0;
	} else if (func == do_page_down) {
	    selected += (editwinrows - fileline % editwinrows) * width;
	    if (selected > filelist_len - 1)
		selected = filelist_len - 1;
	} else if (func == do_first_file) {
	    selected = 0;
	} else if (func == do_last_file) {
	    selected = filelist_len - 1;
	} else if (func == goto_dir_void) {
	    /* Go to a specific directory. */
	    curs_set(1);
	    i = do_prompt(TRUE,
#ifndef DISABLE_TABCOMP
			FALSE,
#endif
			MGOTODIR, ans,
#ifndef DISABLE_HISTORIES
			NULL,
#endif
			/* TRANSLATORS: This is a prompt. */
			browser_refresh, _("Go To Directory"));

	    curs_set(0);
	    bottombars(MBROWSER);

	    /* If the directory begins with a newline (i.e. an
	     * encoded null), treat it as though it's blank. */
	    if (i < 0 || *answer == '\n') {
		/* We canceled.  Indicate that on the statusbar, and
		* blank out ans, since we're done with it. */
		statusbar(_("Cancelled"));
		ans = mallocstrcpy(ans, "");
		continue;
	    } else if (i != 0) {
		/* Put back the "Go to Directory" key and save
		 * answer in ans, so that the file list is displayed
		 * again, the prompt is displayed again, and what we
		 * typed before at the prompt is displayed again. */
		unget_kbinput(sc_seq_or(do_gotolinecolumn_void, 0), FALSE, FALSE);
		ans = mallocstrcpy(ans, answer);
		continue;
	    }

	    /* We have a directory.  Blank out ans, since we're done
	     * with it. */
	    ans = mallocstrcpy(ans, "");

	    /* Convert newlines to nulls, just before we go to the
	     * directory. */
	    sunder(answer);
	    align(&answer);

	    new_path = real_dir_from_tilde(answer);

	    if (new_path[0] != '/') {
		new_path = charealloc(new_path, strlen(path) +
				strlen(answer) + 1);
		sprintf(new_path, "%s%s", path, answer);
	    }

#ifndef DISABLE_OPERATINGDIR
	    if (check_operating_dir(new_path, FALSE)) {
		statusbar(_("Can't go outside of %s in restricted mode"),
				operating_dir);
		free(new_path);
		continue;
	    }
#endif

	    dir = opendir(new_path);
	    if (dir == NULL) {
		/* We can't open this directory for some reason.
		* Complain. */
		statusbar(_("Error reading %s: %s"), answer,
				strerror(errno));
		beep();
		free(new_path);
		continue;
	    }

	    /* Start over again with the new path value. */
	    free(path);
	    path = new_path;
	    goto change_browser_directory;
	} else if (func == do_up_void) {
	    if (selected >= width)
		selected -= width;
	} else if (func == do_down_void) {
	    if (selected + width <= filelist_len - 1)
		selected += width;
	} else if (func == do_left) {
	    if (selected > 0)
		selected--;
	} else if (func == do_right) {
	    if (selected < filelist_len - 1)
		selected++;
	} else if (func == do_enter_void) {
	    /* We can't move up from "/". */
	    if (strcmp(filelist[selected], "/..") == 0) {
		statusbar(_("Can't move up a directory"));
		beep();
		continue;
	    }

#ifndef DISABLE_OPERATINGDIR
	    /* Note: The selected file can be outside the operating
	     * directory if it's ".." or if it's a symlink to a
	     * directory outside the operating directory. */
	    if (check_operating_dir(filelist[selected], FALSE)) {
		statusbar(_("Can't go outside of %s in restricted mode"),
				operating_dir);
		beep();
		continue;
	    }
#endif

	    if (stat(filelist[selected], &st) == -1) {
		/* We can't open this file for some reason.
		 * Complain. */
		 statusbar(_("Error reading %s: %s"),
				filelist[selected], strerror(errno));
		 beep();
		 continue;
	    }

	    if (!S_ISDIR(st.st_mode)) {
		/* We've successfully opened a file, we're done, so
		 * get out. */
		retval = mallocstrcpy(NULL, filelist[selected]);
		break;
	    } else if (strcmp(tail(filelist[selected]), "..") == 0)
		/* We've successfully opened the parent directory,
		 * save the current directory in prev_dir, so that
		 * we can easily return to it by hitting Enter. */
		prev_dir = mallocstrcpy(NULL, striponedir(filelist[selected]));

	    dir = opendir(filelist[selected]);
	    if (dir == NULL) {
		/* We can't open this directory for some reason.
		 * Complain. */
		statusbar(_("Error reading %s: %s"),
				filelist[selected], strerror(errno));
		beep();
		continue;
	    }

	    path = mallocstrcpy(path, filelist[selected]);

	    /* Start over again with the new path value. */
	    goto change_browser_directory;
	} else if (func == do_exit) {
	    /* Exit from the file browser. */
	    break;
	}
    }
    titlebar(NULL);
    edit_refresh();
    curs_set(1);
    if (old_const_update)
	SET(CONST_UPDATE);

    free(path);
    free(ans);

    free_chararray(filelist, filelist_len);
    filelist = NULL;
    filelist_len = 0;

    return retval;
}
示例#28
0
文件: rcfile.c 项目: rofl0r/nano
/* Let user unbind a sequence from a given (or all) menus */
void parse_unbinding(char *ptr)
{
    char *keyptr = NULL, *keycopy = NULL, *menuptr = NULL;
    sc *s;
    int i, menu;

    assert(ptr != NULL);

    if (*ptr == '\0') {
	rcfile_error(N_("Missing key name"));
	return;
    }

    keyptr = ptr;
    ptr = parse_next_word(ptr);
    keycopy = mallocstrcpy(NULL, keyptr);
    for (i = 0; i < strlen(keycopy); i++)
	keycopy[i] = toupper(keycopy[i]);

#ifdef DEBUG
    fprintf(stderr, "Starting unbinding code");
#endif

    if (keycopy[0] != 'M' && keycopy[0] != '^' && keycopy[0] != 'F' && keycopy[0] != 'K') {
	rcfile_error(
		N_("keybindings must begin with \"^\", \"M\", or \"F\""));
	return;
    }

    menuptr = ptr;
    ptr = parse_next_word(ptr);

    if (!strcmp(menuptr, "")) {
	rcfile_error(
		/* Note to translators, do not translate the word "all"
		   in the sentence below, everything else is fine */
		N_("Must specify menu to bind key to (or \"all\")"));
	return;
    }

    menu = strtomenu(menuptr);
    if (menu < 1) {
	rcfile_error(
		N_("Could not map name \"%s\" to a menu"), menuptr);
	return;
    }


#ifdef DEBUG
    fprintf(stderr, "unbinding \"%s\" from menu = %d\n", keycopy, menu);
#endif

    /* Now find the apropriate entries in the menu to delete */
    for (s = sclist; s != NULL; s = s->next) {
        if (((s->menu & menu)) && !strcmp(s->keystr,keycopy)) {
	    s->menu &= ~menu;
#ifdef DEBUG
	    fprintf(stderr, "deleted menu entry %d\n", s->menu);
#endif
	}
    }
}
示例#29
0
文件: search.c 项目: ris21/yoda
/* Go to the specified line and column, or ask for them if interactive
 * is TRUE.  Save the x-coordinate and y-coordinate if save_pos is TRUE.
 * Update the screen afterwards if allow_update is TRUE.  Note that both
 * the line and column numbers should be one-based. */
void do_gotolinecolumn(ssize_t line, ssize_t column, bool use_answer,
	bool interactive, bool save_pos, bool allow_update)
{
    if (interactive) {
	char *ans = mallocstrcpy(NULL, answer);
	functionptrtype func;

	/* Ask for the line and column. */
	int i = do_prompt(FALSE,
#ifndef DISABLE_TABCOMP
		TRUE,
#endif
		MGOTOLINE, use_answer ? ans : "",
#ifndef DISABLE_HISTORIES
		NULL,
#endif
		/* TRANSLATORS: This is a prompt. */
		edit_refresh, _("Enter line number, column number"));

	free(ans);

	/* Cancel, or Enter with blank string. */
	if (i < 0) {
	    statusbar(_("Cancelled"));
	    display_main_list();
	    return;
	}

	func = func_from_key(&i);

	if (func == gototext_void) {
	    /* Keep answer up on the statusbar. */
	    search_init(TRUE, TRUE);

	    do_search();
	    return;
	}

	/* Do a bounds check.  Display a warning on an out-of-bounds
	 * line or column number only if we hit Enter at the statusbar
	 * prompt. */
	if (!parse_line_column(answer, &line, &column) || line < 1 ||
		column < 1) {
	    if (i == 0)
		statusbar(_("Invalid line or column number"));
	    display_main_list();
	    return;
	}
    } else {
	if (line < 1)
	    line = openfile->current->lineno;

	if (column < 1)
	    column = openfile->placewewant + 1;
    }

    for (openfile->current = openfile->fileage;
	openfile->current != openfile->filebot && line > 1; line--)
	openfile->current = openfile->current->next;

    openfile->current_x = actual_x(openfile->current->data, column - 1);
    openfile->placewewant = column - 1;

    /* Put the top line of the edit window in range of the current line.
     * If save_pos is TRUE, don't change the cursor position when doing
     * it. */
    edit_update(save_pos ? NONE : CENTER);

    /* If allow_update is TRUE, update the screen. */
    if (allow_update) {
	edit_refresh();
	display_main_list();
    }
}
示例#30
0
文件: search.c 项目: ris21/yoda
/* Replace a string. */
void do_replace(void)
{
    linestruct *edittop_save, *begin;
    size_t begin_x, pww_save;
    ssize_t numreplaced;
    int i;

    if (ISSET(VIEW_MODE)) {
	print_view_warning();
	search_replace_abort();
	return;
    }

    i = search_init(TRUE, FALSE);
    if (i == -1) {
	/* Cancel, Go to Line, blank search string, or regcomp() failed. */
	search_replace_abort();
	return;
    } else if (i == -2) {
	/* No Replace. */
	do_search();
	return;
    } else if (i == 1)
	/* Case Sensitive, Backwards, or Regexp search toggle. */
	do_replace();

    if (i != 0)
	return;

    /* If answer is not "", add answer to the search history list and
     * copy answer into last_search. */
    if (answer[0] != '\0') {
#ifndef DISABLE_HISTORIES
	update_history(&search_history, answer);
#endif
	last_search = mallocstrcpy(last_search, answer);
    }

    last_replace = mallocstrcpy(last_replace, "");

    i = do_prompt(FALSE,
#ifndef DISABLE_TABCOMP
	TRUE,
#endif
	MREPLACEWITH, last_replace,
#ifndef DISABLE_HISTORIES
	&replace_history,
#endif
	/* TRANSLATORS: This is a prompt. */
	edit_refresh, _("Replace with"));

#ifndef DISABLE_HISTORIES
    /* If the replace string is not "", add it to the replace history list. */
    if (i == 0)
	update_history(&replace_history, answer);
#endif

    if (i != 0 && i != -2) {
	if (i == -1) {		/* Cancel. */
	    if (last_replace[0] != '\0')
		answer = mallocstrcpy(answer, last_replace);
	    statusbar(_("Cancelled"));
	}
	search_replace_abort();
	return;
    }

    last_replace = mallocstrcpy(last_replace, answer);

    /* Save where we are. */
    edittop_save = openfile->edittop;
    begin = openfile->current;
    begin_x = openfile->current_x;
    pww_save = openfile->placewewant;

    numreplaced = do_replace_loop(
#ifndef DISABLE_SPELLER
	FALSE,
#endif
	NULL, begin, &begin_x, last_search);

    /* Restore where we were. */
    openfile->edittop = edittop_save;
    openfile->current = begin;
    openfile->current_x = begin_x;
    openfile->placewewant = pww_save;

    edit_refresh();

    if (numreplaced >= 0)
	statusbar(P_("Replaced %lu occurrence",
		"Replaced %lu occurrences", (unsigned long)numreplaced),
		(unsigned long)numreplaced);

    search_replace_abort();
}