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 + -
显示快捷键?