📄 char_io.c
字号:
break; case 2: /* C-b backward one character */ if (lpos > 0) cl_backward (1); break; case 21: /* C-u kill to beginning of line */ if (lpos == 0) break; /* Copy the string being deleted to KILL_BUF. */ grub_memmove (kill_buf, buf, lpos); kill_buf[lpos] = 0; { /* XXX: Not very clever. */ int count = lpos; cl_backward (lpos); cl_delete (count); } break; case 11: /* C-k kill to end of line */ if (lpos == llen) break; /* Copy the string being deleted to KILL_BUF. */ grub_memmove (kill_buf, buf + lpos, llen - lpos + 1); cl_delete (llen - lpos); break; case 25: /* C-y yank the kill buffer */ cl_insert (kill_buf); break; case 16: /* C-p fetch the previous command */ { char *p; if (history < 0) /* Save the working buffer. */ grub_strcpy (cmdline, buf); else if (grub_strcmp (get_history (history), buf) != 0) /* If BUF is modified, add it into the history list. */ add_history (buf, history); history++; p = get_history (history); if (! p) { history--; break; } grub_strcpy (buf, p); llen = grub_strlen (buf); lpos = llen; cl_refresh (1, 0); } break; case 14: /* C-n fetch the next command */ { char *p; if (history < 0) { break; } else if (grub_strcmp (get_history (history), buf) != 0) /* If BUF is modified, add it into the history list. */ add_history (buf, history); history--; p = get_history (history); if (! p) p = cmdline; grub_strcpy (buf, p); llen = grub_strlen (buf); lpos = llen; cl_refresh (1, 0); } break; } } /* ESC, C-d and C-h are always handled. Actually C-d is not functional if READLINE is zero, as the cursor cannot go backward, but that's ok. */ switch (c) { case 27: /* ESC immediately return 1 */ return 1; case 4: /* C-d delete character under cursor */ if (lpos == llen) break; cl_delete (1); break; case 8: /* C-h backspace */# ifdef GRUB_UTIL case 127: /* also backspace */# endif if (lpos > 0) { cl_backward (1); cl_delete (1); } break; default: /* insert printable character into line */ if (c >= ' ' && c <= '~') { char str[2]; str[0] = c; str[1] = 0; cl_insert (str); } } } grub_putchar ('\n'); /* If ECHO_CHAR is NUL, remove the leading spaces. */ lpos = 0; if (! echo_char) while (buf[lpos] == ' ') lpos++; /* Copy the working buffer to CMDLINE. */ grub_memmove (cmdline, buf + lpos, llen - lpos + 1); /* If the readline-like feature is turned on and CMDLINE is not empty, add it into the history list. */ if (readline && lpos < llen) add_history (cmdline, 0); return 0;}/* Don't use this with a MAXLEN greater than 1600 or so! The problem is that GET_CMDLINE depends on the everything fitting on the screen at once. So, the whole screen is about 2000 characters, minus the PROMPT, and space for error and status lines, etc. MAXLEN must be at least 1, and PROMPT and CMDLINE must be valid strings (not NULL or zero-length). If ECHO_CHAR is nonzero, echo it instead of the typed character. */intget_cmdline (char *prompt, char *cmdline, int maxlen, int echo_char, int readline){ int old_cursor; int ret; old_cursor = setcursor (1); /* Because it is hard to deal with different conditions simultaneously, less functional cases are handled here. Assume that TERM_NO_ECHO implies TERM_NO_EDIT. */ if (current_term->flags & (TERM_NO_ECHO | TERM_NO_EDIT)) { char *p = cmdline; int c; /* Make sure that MAXLEN is not too large. */ if (maxlen > MAX_CMDLINE) maxlen = MAX_CMDLINE; /* Print only the prompt. The contents of CMDLINE is simply discarded, even if it is not empty. */ grub_printf ("%s", prompt); /* Gather characters until a newline is gotten. */ while ((c = ASCII_CHAR (getkey ())) != '\n' && c != '\r') { /* Return immediately if ESC is pressed. */ if (c == 27) { setcursor (old_cursor); return 1; } /* Printable characters are added into CMDLINE. */ if (c >= ' ' && c <= '~') { if (! (current_term->flags & TERM_NO_ECHO)) grub_putchar (c); /* Preceding space characters must be ignored. */ if (c != ' ' || p != cmdline) *p++ = c; } } *p = 0; if (! (current_term->flags & TERM_NO_ECHO)) grub_putchar ('\n'); setcursor (old_cursor); return 0; } /* Complicated features are left to real_get_cmdline. */ ret = real_get_cmdline (prompt, cmdline, maxlen, echo_char, readline); setcursor (old_cursor); return ret;}intsafe_parse_maxint (char **str_ptr, int *myint_ptr){ char *ptr = *str_ptr; int myint = 0; int mult = 10, found = 0; /* * Is this a hex number? */ if (*ptr == '0' && tolower (*(ptr + 1)) == 'x') { ptr += 2; mult = 16; } while (1) { /* A bit tricky. This below makes use of the equivalence: (A >= B && A <= C) <=> ((A - B) <= (C - B)) when C > B and A is unsigned. */ unsigned int digit; digit = tolower (*ptr) - '0'; if (digit > 9) { digit -= 'a' - '0'; if (mult == 10 || digit > 5) break; digit += 10; } found = 1; if (myint > ((MAXINT - digit) / mult)) { errnum = ERR_NUMBER_OVERFLOW; return 0; } myint = (myint * mult) + digit; ptr++; } if (!found) { errnum = ERR_NUMBER_PARSING; return 0; } *str_ptr = ptr; *myint_ptr = myint; return 1;}#endif /* STAGE1_5 */#if !defined(STAGE1_5) || defined(FSYS_FAT)intgrub_tolower (int c){ if (c >= 'A' && c <= 'Z') return (c + ('a' - 'A')); return c;}#endif /* ! STAGE1_5 || FSYS_FAT */intgrub_isspace (int c){ switch (c) { case ' ': case '\t': case '\r': case '\n': return 1; default: break; } return 0;}#if !defined(STAGE1_5) || defined(FSYS_ISO9660)intgrub_memcmp (const char *s1, const char *s2, int n){ while (n) { if (*s1 < *s2) return -1; else if (*s1 > *s2) return 1; s1++; s2++; n--; } return 0;}#endif /* ! STAGE1_5 || FSYS_ISO9660 */#ifndef STAGE1_5intgrub_strncat (char *s1, const char *s2, int n){ int i = -1; while (++i < n && s1[i] != 0); while (i < n && (s1[i++] = *(s2++)) != 0); s1[n - 1] = 0; if (i >= n) return 0; s1[i] = 0; return 1;}#endif /* ! STAGE1_5 *//* XXX: This below is an evil hack. Certainly, we should change the strategy to determine what should be defined and what shouldn't be defined for each image. For example, it would be better to create a static library supporting minimal standard C functions and link each image with the library. Complicated things should be left to computer, definitely. -okuji */#if !defined(STAGE1_5) || defined(FSYS_VSTAFS)intgrub_strcmp (const char *s1, const char *s2){ while (*s1 || *s2) { if (*s1 < *s2) return -1; else if (*s1 > *s2) return 1; s1 ++; s2 ++; } return 0;}#endif /* ! STAGE1_5 || FSYS_VSTAFS */#ifndef STAGE1_5/* Wait for a keypress and return its code. */intgetkey (void){ return current_term->getkey ();}/* Check if a key code is available. */intcheckkey (void){ return current_term->checkkey ();}#endif /* ! STAGE1_5 *//* Display an ASCII character. */voidgrub_putchar (int c){ if (c == '\n') grub_putchar ('\r');#ifndef STAGE1_5 else if (c == '\t' && current_term->getxy) { int n; n = 8 - ((current_term->getxy () >> 8) & 3); while (n--) grub_putchar (' '); return; }#endif /* ! STAGE1_5 */ #ifdef STAGE1_5 /* In Stage 1.5, only the normal console is supported. */ console_putchar (c); #else /* ! STAGE1_5 */ if (c == '\n') { /* Internal `more'-like feature. */ if (count_lines >= 0) { count_lines++; if (count_lines >= max_lines - 2) { int tmp; /* It's important to disable the feature temporarily, because the following grub_printf call will print newlines. */ count_lines = -1; if (current_term->setcolorstate) current_term->setcolorstate (COLOR_STATE_HIGHLIGHT); grub_printf ("\n[Hit return to continue]"); if (current_term->setcolorstate) current_term->setcolorstate (COLOR_STATE_NORMAL); do { tmp = ASCII_CHAR (getkey ()); } while (tmp != '\n' && tmp != '\r'); grub_printf ("\r \r"); /* Restart to count lines. */ count_lines = 0; return; } } } current_term->putchar (c); #endif /* ! STAGE1_5 */}#ifndef STAGE1_5voidgotoxy (int x, int y){ current_term->gotoxy (x, y);}intgetxy (void){ return current_term->getxy ();}voidcls (void){ /* If the terminal is dumb, there is no way to clean the terminal. */ if (current_term->flags & TERM_DUMB) grub_putchar ('\n'); else current_term->cls ();}intsetcursor (int on){ if (current_term->setcursor) return current_term->setcursor (on); return 1;}#endif /* ! STAGE1_5 */intsubstring (const char *s1, const char *s2){ while (*s1 == *s2) { /* The strings match exactly. */ if (! *(s1++)) return 0; s2 ++; } /* S1 is a substring of S2. */ if (*s1 == 0) return -1; /* S1 isn't a substring. */ return 1;}#ifndef STAGE1_5/* Terminate the string STR with NUL. */intnul_terminate (char *str){ int ch; while (*str && ! grub_isspace (*str)) str++; ch = *str; *str = 0; return ch;}char *grub_strstr (const char *s1, const char *s2){ while (*s1) { const char *ptr, *tmp; ptr = s1; tmp = s2; while (*tmp && *ptr == *tmp) ptr++, tmp++; if (tmp > s2 && ! *tmp) return (char *) s1; s1++; } return 0;}intgrub_strlen (const char *str){ int len = 0; while (*str++) len++; return len;}#endif /* ! STAGE1_5 */intmemcheck (int addr, int len){#ifdef GRUB_UTIL static int start_addr (void) { int ret;# if defined(HAVE_START_SYMBOL) asm volatile ("movl $start, %0" : "=a" (ret));# elif defined(HAVE_USCORE_START_SYMBOL) asm volatile ("movl $_start, %0" : "=a" (ret));# endif return ret; } static int end_addr (void) { int ret;# if defined(HAVE_END_SYMBOL) asm volatile ("movl $end, %0" : "=a" (ret));# elif defined(HAVE_USCORE_END_SYMBOL) asm volatile ("movl $_end, %0" : "=a" (ret));# endif return ret; } if (start_addr () <= addr && end_addr () > addr + len) return ! errnum;#endif /* GRUB_UTIL */ if ((addr < RAW_ADDR (0x1000)) || (addr < RAW_ADDR (0x100000) && RAW_ADDR (mbi.mem_lower * 1024) < (addr + len)) || (addr >= RAW_ADDR (0x100000) && RAW_ADDR (mbi.mem_upper * 1024) < ((addr - 0x100000) + len))) errnum = ERR_WONT_FIT; return ! errnum;}void *grub_memmove (void *to, const void *from, int len){ if (memcheck ((int) to, len)) { /* This assembly code is stolen from linux-2.2.2/include/asm-i386/string.h. This is not very fast but compact. */ int d0, d1, d2; if (to < from) { asm volatile ("cld\n\t" "rep\n\t" "movsb" : "=&c" (d0), "=&S" (d1), "=&D" (d2) : "0" (len),"1" (from),"2" (to) : "memory"); } else { asm volatile ("std\n\t" "rep\n\t" "movsb\n\t" "cld" : "=&c" (d0), "=&S" (d1), "=&D" (d2) : "0" (len), "1" (len - 1 + (const char *) from), "2" (len - 1 + (char *) to) : "memory"); } } return errnum ? NULL : to;}void *grub_memset (void *start, int c, int len){ char *p = start; if (memcheck ((int) start, len)) { while (len -- > 0) *p ++ = c; } return errnum ? NULL : start;}#ifndef STAGE1_5char *grub_strcpy (char *dest, const char *src){ grub_memmove (dest, src, grub_strlen (src) + 1); return dest;}#endif /* ! STAGE1_5 */#ifndef GRUB_UTIL# undef memcpy/* GCC emits references to memcpy() for struct copies etc. */void *memcpy (void *dest, const void *src, int n) __attribute__ ((alias ("grub_memmove")));#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -