getline.c

来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 2,474 行 · 第 1/4 页

C
2,474
字号
	gl_putc('\r');
	gl_puts(prompt);
	gl_pos = gl_shift;
        gl_width = gl_termw - l2;
	change = 0;
    }
    pad = (off_right)? gl_width - 1 : gl_cnt - gl_shift;   /* old length */
    backup = gl_pos - gl_shift;
    if (change >= 0) {
        gl_cnt = (int) strlen(gl_buf);
        if (change > gl_cnt)
	    change = gl_cnt;
    }
    if (cursor > gl_cnt) {
	if (cursor != GL_BUF_SIZE) {		/* GL_BUF_SIZE means end of line */
	    if (gl_ellipses_during_completion == 0) {
	        gl_beep();
	    }
	}
	cursor = gl_cnt;
    }
    if (cursor < 0) {
	gl_beep();
	cursor = 0;
    }
    if (off_right || (off_left && cursor < gl_shift + gl_width - gl_scroll / 2))
	extra = 2;			/* shift the scrolling boundary */
    else
	extra = 0;
    new_shift = cursor + extra + gl_scroll - gl_width;
    if (new_shift > 0) {
	new_shift /= gl_scroll;
	new_shift *= gl_scroll;
    } else
	new_shift = 0;
    if (new_shift != gl_shift) {	/* scroll occurs */
	gl_shift = new_shift;
	off_left = (gl_shift)? 1 : 0;
	off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
        left = gl_shift;
	new_right = right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
    } else if (change >= 0) {		/* no scroll, but text changed */
	if (change < gl_shift + off_left) {
	    left = gl_shift;
	} else {
	    left = change;
	    backup = gl_pos - change;
	}
	off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
	right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
	new_right = (gl_extent && (right > left + gl_extent))?
	             left + gl_extent : right;
    }
    pad -= (off_right)? gl_width - 1 : gl_cnt - gl_shift;
    pad = (pad < 0)? 0 : pad;
    if (left <= right) {		/* clean up screen */
	for (i=0; i < backup; i++)
	    gl_putc('\b');
	if (left == gl_shift && off_left) {
	    gl_putc('$');
	    left++;
        }
	for (i=left; i < new_right; i++)
	    gl_putc(gl_buf[i]);
	gl_pos = new_right;
	if (off_right && new_right == right) {
	    gl_putc('$');
	    gl_pos++;
	} else {
	    for (i=0; i < pad; i++)	/* erase remains of prev line */
		gl_putc(' ');
	    gl_pos += pad;
	}
    }
    i = gl_pos - cursor;		/* move to final cursor location */
    if (i > 0) {
	while (i--)
	   gl_putc('\b');
    } else {
	for (i=gl_pos; i < cursor; i++)
	    gl_putc(gl_buf[i]);
    }
    gl_pos = cursor;
}

static int
gl_tab(char *buf, int offset, int *loc, size_t bufsize)
/* default tab handler, acts like tabstops every 8 cols */
{
    int i, count, len;

    len = (int) strlen(buf);
    count = 8 - (offset + *loc) % 8;
    for (i=len; i >= *loc; i--)
    	if (i+count < (int) bufsize)
		buf[i+count] = buf[i];
    for (i=0; i < count; i++)
    	if (*loc+i < (int) bufsize)
		buf[*loc+i] = ' ';
    i = *loc;
    *loc = i + count;
    return i;
}

/******************* History stuff **************************************/

#ifndef HIST_SIZE
#define HIST_SIZE 100
#endif

static int      hist_pos = 0, hist_last = 0;
static char    *hist_buf[HIST_SIZE];
static char     hist_empty_elem[2] = "";

static void
hist_init(void)
{
    int i;

    hist_buf[0] = hist_empty_elem;
    for (i=1; i < HIST_SIZE; i++)
	hist_buf[i] = (char *)0;
}

void
gl_histadd(char *buf)
{
    static char *prev = 0;
    char *p = buf;
    int len;

    /* in case we call gl_histadd() before we call getline() */
    if (gl_init_done < 0) {		/* -1 only on startup */
        hist_init();
        gl_init_done = 0;
    }
    while (*p == ' ' || *p == '\t' || *p == '\n')
	p++;
    if (*p) {
	len = (int) strlen(buf);
	if (strchr(p, '\n')) 	/* previously line already has NL stripped */
	    len--;
	if ((prev == 0) || ((int) strlen(prev) != len) ||
			    strncmp(prev, buf, (size_t) len) != 0) {
            hist_buf[hist_last] = hist_save(buf);
	    prev = hist_buf[hist_last];
            hist_last = (hist_last + 1) % HIST_SIZE;
            if (hist_buf[hist_last] && *hist_buf[hist_last]) {
	        free(hist_buf[hist_last]);
            }
	    hist_buf[hist_last] = hist_empty_elem;
	}
    }
    hist_pos = hist_last;
}

static char *
hist_prev(void)
/* loads previous hist entry into input buffer, sticks on first */
{
    char *p = 0;
    int   next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE;

    if (hist_buf[hist_pos] != 0 && next != hist_last) {
        hist_pos = next;
        p = hist_buf[hist_pos];
    }
    if (p == 0) {
	p = hist_empty_elem;
	gl_beep();
    }
    return p;
}

static char *
hist_next(void)
/* loads next hist entry into input buffer, clears on last */
{
    char *p = 0;

    if (hist_pos != hist_last) {
        hist_pos = (hist_pos+1) % HIST_SIZE;
	p = hist_buf[hist_pos];
    }
    if (p == 0) {
	p = hist_empty_elem;
	gl_beep();
    }
    return p;
}

static char *
hist_save(char *p)

/* makes a copy of the string */
{
    char *s = 0;
    size_t len = strlen(p);
    char *nl = strpbrk(p, "\n\r");

    if (nl) {
        if ((s = (char *) malloc(len)) != 0) {
            strncpy(s, p, len-1);
	    s[len-1] = 0;
	}
    } else {
        if ((s = (char *) malloc(len+1)) != 0) {
            strcpy(s, p);
        }
    }
    if (s == 0)
	gl_error("\n*** Error: hist_save() failed on malloc\n");
    return s;
}




void
gl_histsavefile(const char *const path)
{
	FILE *fp;
	const char *p;
	int i, j;

	fp = fopen(path,
#if defined(__windows__) || defined(MSDOS)
		"wt"
#else
		"w"
#endif
	);
	if (fp != NULL) {
		for (i=2; i<HIST_SIZE; i++) {
        		j = (hist_pos+i) % HIST_SIZE;
			p = hist_buf[j];
			if ((p == NULL) || (*p == '\0'))
				continue;
			fprintf(fp, "%s\n", p);
		}
		fclose(fp);
	}
}	/* gl_histsavefile */




void
gl_histloadfile(const char *const path)
{
	FILE *fp;
	char line[256];

	fp = fopen(path,
#if defined(__windows__) || defined(MSDOS)
		"rt"
#else
		"r"
#endif
	);
	if (fp != NULL) {
		memset(line, 0, sizeof(line));
		while (fgets(line, sizeof(line) - 2, fp) != NULL) {
			gl_histadd(line);
		}
		fclose(fp);
	}
}	/* gl_histloadfile */




/******************* Search stuff **************************************/

static char  search_prompt[101];  /* prompt includes search string */
static char  search_string[100];
static int   search_pos = 0;      /* current location in search_string */
static int   search_forw_flg = 0; /* search direction flag */
static int   search_last = 0;	  /* last match found */

static void
search_update(int c)
{
    if (c == 0) {
	search_pos = 0;
        search_string[0] = 0;
        search_prompt[0] = '?';
        search_prompt[1] = ' ';
        search_prompt[2] = 0;
    } else if (c > 0) {
        search_string[search_pos] = (char) c;
        search_string[search_pos+1] = (char) 0;
        search_prompt[search_pos] = (char) c;
        search_prompt[search_pos+1] = (char) '?';
        search_prompt[search_pos+2] = (char) ' ';
        search_prompt[search_pos+3] = (char) 0;
	search_pos++;
    } else {
	if (search_pos > 0) {
	    search_pos--;
            search_string[search_pos] = (char) 0;
            search_prompt[search_pos] = (char) '?';
            search_prompt[search_pos+1] = (char) ' ';
            search_prompt[search_pos+2] = (char) 0;
	} else {
	    gl_beep();
	    hist_pos = hist_last;
	}
    }
}

static void
search_addchar(int c)
{
    char *loc;

    search_update(c);
    if (c < 0) {
	if (search_pos > 0) {
	    hist_pos = search_last;
	} else {
	    gl_buf[0] = 0;
	    hist_pos = hist_last;
	}
	strcpy(gl_buf, hist_buf[hist_pos]);
    }
    if ((loc = strstr(gl_buf, search_string)) != 0) {
	gl_fixup(search_prompt, 0, (int) (loc - gl_buf));
    } else if (search_pos > 0) {
        if (search_forw_flg) {
	    search_forw(0);
        } else {
	    search_back(0);
        }
    } else {
	gl_fixup(search_prompt, 0, 0);
    }
}

static void
search_term(void)
{
    gl_search_mode = 0;
    if (gl_buf[0] == 0)		/* not found, reset hist list */
        hist_pos = hist_last;
    if (gl_in_hook)
	gl_in_hook(gl_buf);
    gl_fixup(gl_prompt, 0, gl_pos);
}

static void
search_back(int new_search)
{
    int    found = 0;
    char  *p, *loc;

    search_forw_flg = 0;
    if (gl_search_mode == 0) {
	search_last = hist_pos = hist_last;
	search_update(0);
	gl_search_mode = 1;
        gl_buf[0] = 0;
	gl_fixup(search_prompt, 0, 0);
    } else if (search_pos > 0) {
	while (!found) {
	    p = hist_prev();
	    if (*p == 0) {		/* not found, done looking */
	       gl_buf[0] = 0;
	       gl_fixup(search_prompt, 0, 0);
	       found = 1;
	    } else if ((loc = strstr(p, search_string)) != 0) {
	       strcpy(gl_buf, p);
	       gl_fixup(search_prompt, 0, (int) (loc - p));
	       if (new_search)
		   search_last = hist_pos;
	       found = 1;
	    }
	}

    } else {
        gl_beep();
    }
}

static void
search_forw(int new_search)
{
    int    found = 0;
    char  *p, *loc;

    search_forw_flg = 1;
    if (gl_search_mode == 0) {
	search_last = hist_pos = hist_last;
	search_update(0);
	gl_search_mode = 1;
        gl_buf[0] = 0;
	gl_fixup(search_prompt, 0, 0);
    } else if (search_pos > 0) {
	while (!found) {
	    p = hist_next();
	    if (*p == 0) {		/* not found, done looking */
	       gl_buf[0] = 0;
	       gl_fixup(search_prompt, 0, 0);
	       found = 1;
	    } else if ((loc = strstr(p, search_string)) != 0) {
	       strcpy(gl_buf, p);
	       gl_fixup(search_prompt, 0, (int) (loc - p));
	       if (new_search)
		   search_last = hist_pos;
	       found = 1;
	    }
	}
    } else {
        gl_beep();
    }
}


static void
gl_beep(void)
{
#ifdef __windows__
	MessageBeep(MB_OK);
#else
	gl_putc('\007');
#endif
}	/* gl_beep */



static int
gl_display_matches_sort_proc(const void *a, const void *b)
{
	return (strcasecmp(
		* ((const char **) a),
		* ((const char **) b)
	));
}	/* gl_display_matches_sort_proc */



static void
gl_display_matches(int nused)
{
	char buf[256];
	char buf2[256];
	size_t ilen, imaxlen;
	int i, j, k, l;
	int glen, allmatch;
	int nmax, ncol, colw, nrow;
	char *cp1, *cp2, *lim, *itemp;

	gl_putc('\n');
	if (nused == 0) {
		gl_beep();
		gl_puts("    (no matches)");
		gl_putc('\n');
	} else {
		qsort(gl_matchlist, (size_t) nused, sizeof(char *), gl_display_matches_sort_proc);

		/* Find the greatest amount that matches. */
		for (glen = 0; ; glen++) {
			allmatch = 1;
			for (i=1; i<nused; i++) {
				if (gl_matchlist[0][glen] != gl_matchlist[i][glen]) {
					allmatch = 0;
					break;
				}
			}
			if (allmatch == 0)
				break;
		}

		while (glen > 0) {
			if (!isalnum(gl_matchlist[0][glen - 1]))
				break;
			--glen;
		}

		nmax = nused;
		imaxlen = strlen(gl_matchlist[0]);
		for (i=1; i<nused; i++) {
			ilen = strlen(gl_matchlist[i]);
			if (ilen > imaxlen)
				imaxlen = ilen;
		}

		/* Subtract amount we'll skip for each item. */
		imaxlen -= glen;

		ncol = (gl_termw - 8) / ((int) imaxlen + 2);
		if (ncol < 1)
			ncol = 1;

		colw = (gl_termw - 8) / ncol;
		nrow = nmax / ncol;
		if ((nused % ncol) != 0)
			nrow++;

		if (nrow > (gl_termh - 4)) {
			nrow = gl_termh - 4;
			nmax = ncol * nrow;
		}

		for (i=0; i<(int) sizeof(buf2); i++)
			buf2[i] = ' ';

		for (j=0; j<nrow; j++) {
			(void) memcpy(buf, buf2, sizeof(buf));
			for (i=0, k=j, l=4; i<ncol; i++, k += nrow, l += colw) {
				if (k >= nmax)
					continue;
				itemp = gl_matchlist[k] + glen;
				cp1 = buf + l;
				lim = cp1 + (int) strlen(itemp);
				if (lim > (buf + sizeof(buf) - 1))
					continue;
				cp2 = itemp;
				while (cp1 < lim)
					*cp1++ = *cp2++;
			}
			for (cp1 = buf + sizeof(buf); *--cp1 == ' '; )
				;
			++cp1;
			*cp1 = '\0';
			gl_puts(buf);
			gl_putc('\n');
		}

		if (nused > nmax) {
			(void) sprintf(buf, "    ... %d others omitted ...", (nused - nmax));
			gl_puts(buf);
			gl_putc('\n');
		}
	}
	gl_fixup(gl_prompt, -2, GL_BUF_SIZE);
}	/* gl_display_matches */




static int
gl_do_tab_completion(char *buf, int *loc, size_t bufsize, int tabtab)
{
	char *startp;
	size_t startoff, amt;
	int c;
	int qmode;
	char *qstart;
	char *lastspacestart;
	char *cp;
	int ntoalloc, nused, nprocused, nalloced, i;
	char **newgl_matchlist;
	char *strtoadd, *strtoadd1;
	int addquotes;
	size_t llen, mlen, glen;
	int allmatch;
	char *curposp;
	size_t lenaftercursor;
	char *matchpfx;
	int wasateol;
	char ellipsessave[4];

	/* Zero out the rest of the buffer, so we can move stuff around
	 * and know we'll still be NUL-terminated.
	 */
	llen = strlen(buf);
	memset(buf + llen, 0, bufsize - llen);
	bufsize -= 4;	/* leave room for a NUL, space, and two quotes. */
	curposp = buf + *loc;
	wasateol = (*curposp == '\0');
	lenaftercursor = llen - (curposp - buf);
	if (gl_ellipses_during_completion != 0) {
		memcpy(ellipsessave, curposp, (size_t) 4);
		memcpy(curposp, "... ", (size_t) 4);
		gl_fixup(gl_prompt, gl_pos, gl_pos + 3);
		memcpy(curposp, ellipsessave, (size_t) 4);
	}

	qmode = 0;
	qstart = NULL;
	lastspacestart = NULL;
	matchpfx = NULL;

	cp = buf;
	while (cp < curposp) {
		c = (int) *cp++;
		if (c == '\0')
			break;
		if ((c == '"') || (c == '\'')) {
			if (qmode == c) {
				/* closing quote; end it. */
				qstart = NULL;
				qmode = 0;
			} else if (qmode != 0) {
				/* just treat it as a regular char. */
			} else {
				/* start new quote group. */
				qmode = c;
				qstart = cp - 1;
			}
		} else if ((isspace(c)) && (qmode == 0)) {
			/* found a non-quoted space. */
			lastspacestart = cp - 1;
		} else {
			/* regular char */
		}
	}

	if (qstart != NULL)
		startp = qstart + 1;
	else if (lastspacestart != NULL)
		startp = lastspacestart + 1;
	else
		startp = buf;

	cp = startp;
	mlen = (curposp - cp);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?