示例#1
0
文件: search.c 项目: StarchLinux/mg
/*
 * Incremental Search.
 *	dir is used as the initial direction to search.
 *	^S	switch direction to forward
 *	^R	switch direction to reverse
 *	^Q	quote next character (allows searching for ^N etc.)
 *	<ESC>	exit from Isearch
 *	<DEL>	undoes last character typed. (tricky job to do this correctly).
 *	other ^ exit search, don't set mark
 *	else	accumulate into search string
 */
static int
isearch(int dir)
{
	struct line	*clp;		/* Saved line pointer */
	int		 c;
	int		 cbo;		/* Saved offset */
	int		 success;
	int		 pptr;
	int		 firstc;
	int		 xcase;
	int		 i;
	char		 opat[NPAT];
	int		 cdotline;	/* Saved line number */

#ifndef NO_MACRO
	if (macrodef) {
		ewprintf("Can't isearch in macro");
		return (FALSE);
	}
#endif /* !NO_MACRO */
	for (cip = 0; cip < NSRCH; cip++)
		cmds[cip].s_code = SRCH_NOPR;

	(void)strlcpy(opat, pat, sizeof(opat));
	cip = 0;
	pptr = -1;
	clp = curwp->w_dotp;
	cbo = curwp->w_doto;
	cdotline = curwp->w_dotline;
	is_lpush();
	is_cpush(SRCH_BEGIN);
	success = TRUE;
	is_prompt(dir, TRUE, success);

	for (;;) {
		update();

		switch (c = getkey(FALSE)) {
		case CCHR('['):
			/*
			 * If new characters come in the next 300 msec,
			 * we can assume that they belong to a longer
			 * escaped sequence so we should ungetkey the
			 * ESC to avoid writing out garbage.
			 */
			if (ttwait(300) == FALSE)
				ungetkey(c);
			srch_lastdir = dir;
			curwp->w_markp = clp;
			curwp->w_marko = cbo;
			curwp->w_markline = cdotline;
			ewprintf("Mark set");
			return (TRUE);
		case CCHR('G'):
			if (success != TRUE) {
				while (is_peek() == SRCH_ACCM)
					is_undo(&pptr, &dir);
				success = TRUE;
				is_prompt(dir, pptr < 0, success);
				break;
			}
			curwp->w_dotp = clp;
			curwp->w_doto = cbo;
			curwp->w_dotline = cdotline;
			curwp->w_rflag |= WFMOVE;
			srch_lastdir = dir;
			(void)ctrlg(FFRAND, 0);
			(void)strlcpy(pat, opat, sizeof(pat));
			return (ABORT);
		case CCHR('S'):
			if (dir == SRCH_BACK) {
				dir = SRCH_FORW;
				is_lpush();
				is_cpush(SRCH_FORW);
				success = TRUE;
			}
			if (success == FALSE && dir == SRCH_FORW) {
				/* wrap the search to beginning */
				curwp->w_dotp = bfirstlp(curbp);
				curwp->w_doto = 0;
				curwp->w_dotline = 1;
				if (is_find(dir) != FALSE) {
					is_cpush(SRCH_MARK);
					success = TRUE;
				}
				ewprintf("Overwrapped I-search: %s", pat);
				break;
			}

			is_lpush();
			pptr = strlen(pat);
			(void)forwchar(FFRAND, 1);
			if (is_find(SRCH_FORW) != FALSE)
				is_cpush(SRCH_MARK);
			else {
				(void)backchar(FFRAND, 1);
				ttbeep();
				success = FALSE;
				ewprintf("Failed I-search: %s", pat);
			}
			is_prompt(dir, pptr < 0, success);
			break;
		case CCHR('R'):
			if (dir == SRCH_FORW) {
				dir = SRCH_BACK;
				is_lpush();
				is_cpush(SRCH_BACK);
				success = TRUE;
			}
			if (success == FALSE && dir == SRCH_BACK) {
				/* wrap the search to end */
				curwp->w_dotp = blastlp(curbp);
				curwp->w_doto = llength(curwp->w_dotp);
				curwp->w_dotline = curwp->w_bufp->b_lines;
				if (is_find(dir) != FALSE) {
					is_cpush(SRCH_MARK);
					success = TRUE;
				}
				ewprintf("Overwrapped I-search: %s", pat);
				break;
			}
			is_lpush();
			pptr = strlen(pat);
			(void)backchar(FFRAND, 1);
			if (is_find(SRCH_BACK) != FALSE)
				is_cpush(SRCH_MARK);
			else {
				(void)forwchar(FFRAND, 1);
				ttbeep();
				success = FALSE;
			}
			is_prompt(dir, pptr < 0, success);
			break;
		case CCHR('W'):
			/* add the rest of the current word to the pattern */
			clp = curwp->w_dotp;
			cbo = curwp->w_doto;
			firstc = 1;
			if (pptr == -1)
				pptr = 0;
			if (dir == SRCH_BACK) {
				/* when isearching backwards, cbo is the start of the pattern */
				cbo += pptr;
			}

			/* if the search is case insensitive, add to pattern using lowercase */
			xcase = 0;
			for (i = 0; pat[i]; i++)
				if (ISUPPER(CHARMASK(pat[i])))
					xcase = 1;

			while (cbo < llength(clp)) {
				c = lgetc(clp, cbo++);
				if ((!firstc && !isalnum(c)))
					break;

				if (pptr == NPAT - 1) {
					ttbeep();
					break;
				}
				firstc = 0;
				if (!xcase && ISUPPER(c))
					c = TOLOWER(c);

				pat[pptr++] = c;
				pat[pptr] = '\0';
				/* cursor only moves when isearching forwards */
				if (dir == SRCH_FORW) {
					curwp->w_doto = cbo;
					curwp->w_rflag |= WFMOVE;
					update();
				}
			}
			is_prompt(dir, pptr < 0, success);
			break;
		case CCHR('H'):
		case CCHR('?'):
			is_undo(&pptr, &dir);
			if (is_peek() != SRCH_ACCM)
				success = TRUE;
			is_prompt(dir, pptr < 0, success);
			break;
		case CCHR('\\'):
		case CCHR('Q'):
			c = (char)getkey(FALSE);
			goto addchar;
		case CCHR('M'):
			c = CCHR('J');
			goto addchar;
		default:
			if (ISCTRL(c)) {
				ungetkey(c);
				curwp->w_markp = clp;
				curwp->w_marko = cbo;
				curwp->w_markline = cdotline;
				ewprintf("Mark set");
				curwp->w_rflag |= WFMOVE;
				return (TRUE);
			}
			/* FALLTHRU */
		case CCHR('I'):
		case CCHR('J'):
	addchar:
			if (pptr == -1)
				pptr = 0;
			if (pptr == 0)
				success = TRUE;
			if (pptr == NPAT - 1)
				ttbeep();
			else {
				pat[pptr++] = c;
				pat[pptr] = '\0';
			}
			is_lpush();
			if (success != FALSE) {
				if (is_find(dir) != FALSE)
					is_cpush(c);
				else {
					success = FALSE;
					ttbeep();
					is_cpush(SRCH_ACCM);
				}
			} else
				is_cpush(SRCH_ACCM);
			is_prompt(dir, FALSE, success);
		}
	}
	/* NOTREACHED */
}
示例#2
0
/* parses: async-record | stream-record | result-record
 * note: post-value data is ignored.
 * 
 * FIXME: that's NOT exactly what the GDB docs call an output, and that's not
 *        exactly what a line could be.  The GDB docs state that a line can
 *        contain more than one stream-record, as it's not terminated by a
 *        newline, and as it defines:
 * 
 *        output ==> 
 *            ( out-of-band-record )* [ result-record ] "(gdb)" nl
 *        out-of-band-record ==>
 *            async-record | stream-record
 *        stream-record ==>
 *            console-stream-output | target-stream-output | log-stream-output
 *        console-stream-output ==>
 *            "~" c-string
 *        target-stream-output ==>
 *            "@" c-string
 *        log-stream-output ==>
 *            "&" c-string
 * 
 *        so as none of the stream-outputs are terminated by a newline, and the
 *        parser here only extracts the first record it will fail with combined
 *        records in one line.
 */
struct gdb_mi_record *gdb_mi_record_parse(const gchar *line)
{
	struct gdb_mi_record *record = g_malloc0(sizeof *record);

	/* FIXME: prompt detection should not really be useful, especially not as a
	 * special case, as the prompt should always follow an (optional) record */
	if (is_prompt(line))
		record->type = GDB_MI_TYPE_PROMPT;
	else
	{
		/* extract token */
		const gchar *token_end = line;
		for (token_end = line; g_ascii_isdigit(*token_end); token_end++)
			;
		if (token_end > line)
		{
			record->token = g_strndup(line, (gsize)(token_end - line));
			line = token_end;
			while (g_ascii_isspace(*line)) line++;
		}

		/* extract record */
		record->type = *line;
		if (*line) ++line;
		while (g_ascii_isspace(*line)) line++;
		switch (record->type)
		{
			case '~':
			case '@':
			case '&':
				/* FIXME: although the syntax description in the docs are clear,
				 * the "GDB/MI Stream Records" section does not agree with it,
				 * widening the input to:
				 * 
				 * > [string-output] is either raw text (with an implicit new
				 * > line) or a quoted C string (which does not contain an
				 * > implicit newline).
				 * 
				 * This adds "raw text" to "c-string"... so? */
				record->klass = parse_cstring(&line);
				break;
			case '^':
			case '*':
			case '+':
			case '=':
			{
				struct gdb_mi_result *prev = NULL;
				record->klass = parse_string(&line);
				while (*line)
				{
					while (g_ascii_isspace(*line)) line++;
					if (*line != ',')
						break;
					else
					{
						struct gdb_mi_result *res = g_malloc0(sizeof *res);
						line++;
						while (g_ascii_isspace(*line)) line++;
						if (!parse_result(res, &line))
						{
							g_warning("failed to parse result");
							gdb_mi_result_free(res, TRUE);
							break;
						}
						if (prev)
							prev->next = res;
						else
							record->first = res;
						prev = res;
					}
				}
				break;
			}
			default:
				/* FIXME: what to do with invalid prefix? */
				record->type = GDB_MI_TYPE_PROMPT;
		}
	}

	return record;
}