/* editgets.c - line input w/editing */ /* this code is released to the public domain */ /* written by Jon Burchmore */ /* modifications & enhancements by Bob Stout */ /* This is as close to ANSI compliant C that I could come, but it was made */ /* on an IBM compatable computer, so I designed it for that platform. */ /* If you're porting it to another computer type, please note how the IBM */ /* passes enhanced keys. First, it sends an ASCIIZ (character 0), then a */ /* standard character. Anyway, what the switch() statement does is check */ /* to see if there WAS a zero sent, and if there wasn't, it just "falls" */ /* through to the default, which handles normal characters. */ /* The conio header file provides the getch() function, which returns a */ /* single character from the KEYBOARD, not stdin, and waits if it must. */ /* It is be possible to re-write this function for a computer besides an */ /* IBM PC. */ /* It would be possible to check the variable insert, and if it's on, make */ /* the cursor large, and if it's off, make the cursor small, but my primary */ /* goal is portability, not fancy add-ons */ /* Pardon the lack of comments. I'm a coder, not an author. Besides, if */ /* you can't understand this, DON'T USE IT! (Words to live by) */ #include #include #include #include #undef min #define min(x,y) (((x) <= (y)) ? (x) : (y)) #define NUL 0x00 #define ESC 0x1B #define LEFT 0x4B #define RIGHT 0x4D #define HOME 0x47 #define END 0x4F #define INSERT 0x52 #define DELETE 0x53 #define BACKSPC 0x08 #define ENTER 0x0D #define CTLEND 0x75 #define CTLHOME 0x77 #define CTLRT 0x74 #define CTLLFT 0x73 /* ** Password mode - '*' is echoed for all characters, only ESC, ENTER, ** BACKSPC, and CTLHOME are active. */ int password_mode = 0; /* ** Aruments: 1) Buffer to receive string ** 2) Size of buffer ** 3) Default string */ int jgets(char *s, int maxlen, char *string) { char temp[500]; int insert = 1, done = 0, pos, len, i, j, c, zeroflag; if (NULL == string) string = ""; if (0 != (pos = len = strlen(string))) strncpy(temp, string, min(len, maxlen)); for (i = 0; i < maxlen; ++i) { if (NUL == *string) putchar('_'); else putchar(*string++); } for (i = 0; i < (maxlen - len); ++i) putchar(BACKSPC); while (!done) { zeroflag = 0; if ((c = getch()) == 0) { zeroflag = 1; c = getch(); } switch (c) { case ESC : if (len == 0) break; if (pos != len) { for (i = pos; i < len; i++) putch('_'); for (i = len; i >= 0; i--) { putch(BACKSPC); putch('_'); putch(BACKSPC); } pos = len = 0; break; } case LEFT : if (zeroflag) { if (password_mode) break; if (pos == 0) break; pos--; putch(BACKSPC); break; } case RIGHT : if (zeroflag) { if (password_mode) break; if (pos == len) break; if (pos != maxlen) { putch(temp[pos]); pos++; } break; } case HOME : if (zeroflag) { if (password_mode) break; while (pos-- > 0) putch(BACKSPC); pos = 0; break; } case END : if (zeroflag) { if (password_mode) break; while (pos < len) putch(temp[pos++]); break; } case INSERT : if (zeroflag) { if (password_mode) break; insert = (!(insert)); break; } case DELETE : if (zeroflag) { if (password_mode) break; if (pos == len) break; for (i = pos; i < len; i++) temp[i] = temp[i + 1]; len--; for (i = pos; i < len; i++) putch(temp[i]); putch('_'); for (i = len + 1; i > pos; i--) putch(BACKSPC); break; } case BACKSPC : if (c == BACKSPC) { if (pos == 0) break; if (pos != len) { for (i = pos - 1; i < len; i++) temp[i] = temp[i + 1]; pos--; len--; putch(BACKSPC); for (i = pos; i < len; i++) putch(temp[i]); putch('_'); for (i = len; i >= pos; i--) putch(BACKSPC); } else { putch(BACKSPC); putch('_'); putch(BACKSPC); pos = --len; } break; } case ENTER : if (c == ENTER) { done = 1; break; } case CTLEND : if (zeroflag) { if (password_mode) break; for (i = pos; i < len; ++i) putch('_'); for (i = pos; i < len; ++i) putch(BACKSPC); len = pos; break; } case CTLHOME : if (zeroflag) { if (pos == 0) break; if (pos != len) { while (0 != pos) { for (i = pos - 1; i < len; i++) temp[i] = temp[i + 1]; pos--; len--; putch(BACKSPC); for (i = pos; i < len; i++) putch(temp[i]); putch('_'); for (i = len; i >= pos; i--) putch(BACKSPC); } } else { while (0 != pos) { putch(BACKSPC); putch('_'); putch(BACKSPC); pos = --len; } } break; } case CTLRT : if (zeroflag) { if (password_mode) break; do { if (pos == len) break; if (pos != maxlen) { putch(temp[pos]); pos++; } } while (isspace(temp[pos])); do { if (pos == len) break; if (pos != maxlen) { putch(temp[pos]); pos++; } } while (!isspace(temp[pos])); break; } case CTLLFT : if (zeroflag) { if (password_mode) break; do { if (pos == 0) break; pos--; putch(BACKSPC); } while (isspace(temp[pos])); do { if (pos == 0) break; pos--; putch(BACKSPC); } while (!isspace(temp[pos])); break; } default : if (zeroflag) break; if (c == 0 || pos == maxlen) break; if ((!(insert)) || pos == len) { temp[pos++] = (char)c; if (pos > len) len++; if (password_mode) putch('*'); else putch(c); } else { if (len == maxlen) break; for (i = len++; i >= pos; i--) temp[i + 1] = temp[i]; temp[pos++] = (char)c; if (password_mode) putch('*'); else putch(c); for (i = pos; i < len; i++) putch(temp[i]); for (i = len; i > pos; i--) putch(BACKSPC); } } } temp[len] = '\0'; strcpy(s, temp); return len; } #ifdef TEST void main(void) { char mystring[60]; memset(mystring, 0, 60); fputs("Enter any string: ", stdout); jgets(mystring, 60, "This is a test"); puts(""); printf("editgets() returned:\n%s\n", mystring); password_mode = 1; memset(mystring, 0, 60); fputs("Enter any password: ", stdout); jgets(mystring, 50, NULL); puts(""); printf("editgets() returned:\n%s\n", mystring); } #endif