ReactOS  0.4.13-dev-551-gf37fb1f
getline.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1991, 1992, 1993 by Chris Thewalt (thewalt@ce.berkeley.edu)
3  *
4  * Permission to use, copy, modify, and distribute this software
5  * for any purpose and without fee is hereby granted, provided
6  * that the above copyright notices appear in all copies and that both the
7  * copyright notice and this permission notice appear in supporting
8  * documentation. This software is provided "as is" without express or
9  * implied warranty.
10  *
11  * Thanks to the following people who have provided enhancements and fixes:
12  * Ron Ueberschaer, Christoph Keller, Scott Schwartz, Steven List,
13  * DaviD W. Sanderson, Goran Bostrom, Michael Gleason, Glenn Kasten,
14  * Edin Hodzic, Eric J Bivona, Kai Uwe Rommel, Danny Quah, Ulrich Betzler
15  */
16 
17 /*
18  * Note: This version has been updated by Mike Gleason <mgleason@ncftp.com>
19  */
20 
21 static const char copyright[] = "getline: Copyright (C) 1991, 1992, 1993, Chris Thewalt";
22 
23 # include <windows.h>
24 # include <sys/types.h>
25 # include <sys/stat.h>
26 # include <errno.h>
27 # include <conio.h>
28 # include <io.h>
29 # include <fcntl.h>
30 // # define strcasecmp stricmp
31 // # define strncasecmp strnicmp
32 # define sleep(a) Sleep(a * 1000)
33 # ifndef S_ISREG
34 # define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
35 # define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
36 # endif
37 # ifndef open
38 # define open _open
39 # define write _write
40 # define read _read
41 # define close _close
42 # define lseek _lseek
43 # define stat _stat
44 # define lstat _stat
45 # define fstat _fstat
46 # define dup _dup
47 # define utime _utime
48 # define utimbuf _utimbuf
49 # endif
50 # ifndef unlink
51 # define unlink remove
52 # endif
53 # define NO_SIGNALS 1
54 # define LOCAL_PATH_DELIM '\\'
55 # define LOCAL_PATH_DELIM_STR "\\"
56 # define LOCAL_PATH_ALTDELIM '/'
57 # define IsLocalPathDelim(c) ((c == LOCAL_PATH_DELIM) || (c == LOCAL_PATH_ALTDELIM))
58 # define UNC_PATH_PREFIX "\\\\"
59 # define IsUNCPrefixed(s) (IsLocalPathDelim(s[0]) && IsLocalPathDelim(s[1]))
60 # define __windows__ 1
61 
62 /********************* C library headers ********************************/
63 
64 #include <stdio.h>
65 #include <string.h>
66 #ifdef HAVE_STRINGS_H
67 # include <strings.h>
68 #endif
69 #include <stdlib.h>
70 #include <ctype.h>
71 #include <signal.h>
72 
73 #define _getline_c_ 1
74 #include "getline.h"
75 
76 static int gl_tab(char *buf, int offset, int *loc, size_t bufsize);
77 
78 /******************** external interface *********************************/
79 
83 size_t gl_strlen(const char *s) { return strlen(s); }
85 int gl_filename_quoting_desired = -1; /* default to unspecified */
86 const char *gl_filename_quote_characters = " \t*?<>|;&()[]$`";
89 char gl_buf[GL_BUF_SIZE]; /* input buffer */
90 
91 /******************** internal interface *********************************/
92 
93 
94 static int gl_init_done = -1; /* terminal mode flag */
95 static int gl_termw = 80; /* actual terminal width */
96 static int gl_termh = 24; /* actual terminal height */
97 static int gl_scroll = 27; /* width of EOL scrolling region */
98 static int gl_width = 0; /* net size available for input */
99 static int gl_extent = 0; /* how far to redraw, 0 means all */
100 static int gl_overwrite = 0; /* overwrite mode */
101 static int gl_pos = 0, gl_cnt = 0; /* position and size of input */
102 static char gl_killbuf[GL_BUF_SIZE]=""; /* killed text */
103 static const char *gl_prompt; /* to save the prompt string */
104 static char gl_intrc = 0; /* keyboard SIGINT char */
105 static char gl_quitc = 0; /* keyboard SIGQUIT char */
106 // static char gl_suspc = 0; /* keyboard SIGTSTP char */
107 // static char gl_dsuspc = 0; /* delayed SIGTSTP char */
108 static int gl_search_mode = 0; /* search mode flag */
109 static char **gl_matchlist = 0;
110 static char *gl_home_dir = NULL;
111 static int gl_vi_preferred = -1;
112 static int gl_vi_mode = 0;
113 static int gl_result = GL_OK;
114 
115 static void gl_init(void); /* prepare to edit a line */
116 static void gl_cleanup(void); /* to undo gl_init */
117 static void gl_char_init(void); /* get ready for no echo input */
118 static void gl_char_cleanup(void); /* undo gl_char_init */
119  /* returns printable prompt width */
120 
121 static void gl_addchar(int c); /* install specified char */
122 static void gl_del(int loc, int); /* del, either left (-1) or cur (0) */
123 static void gl_error(const char *const buf); /* write error msg and die */
124 static void gl_fixup(const char *prompt, int change, int cursor); /* fixup state variables and screen */
125 static int gl_getc(void); /* read one char from terminal */
126 static int gl_getcx(int); /* read one char from terminal, if available before timeout */
127 static void gl_kill(int pos); /* delete to EOL */
128 static void gl_newline(void); /* handle \n or \r */
129 static void gl_putc(int c); /* write one char to terminal */
130 static void gl_puts(const char *const buf); /* write a line to terminal */
131 static void gl_redraw(void); /* issue \n and redraw all */
132 static void gl_transpose(void); /* transpose two chars */
133 static void gl_yank(void); /* yank killed text */
134 static void gl_word(int direction); /* move a word */
135 static void gl_killword(int direction);
136 
137 static void hist_init(void); /* initializes hist pointers */
138 static char *hist_next(void); /* return ptr to next item */
139 static char *hist_prev(void); /* return ptr to prev item */
140 static char *hist_save(char *p); /* makes copy of a string, without NL */
141 
142 static void search_addchar(int c); /* increment search string */
143 static void search_term(void); /* reset with current contents */
144 static void search_back(int new_search); /* look back for current string */
145 static void search_forw(int new_search); /* look forw for current string */
146 static void gl_beep(void); /* try to play a system beep sound */
147 
148 static int gl_do_tab_completion(char *buf, int *loc, size_t bufsize, int tabtab);
149 
150 /************************ nonportable part *********************************/
151 
152 #ifdef MSDOS
153 #include <bios.h>
154 #endif
155 
156 static void
157 gl_char_init(void) /* turn off input echo */
158 {
159 #ifdef __unix__
160 # ifdef HAVE_TERMIOS_H /* Use POSIX */
161  if (tcgetattr(0, &old_termios) == 0) {
162  gl_intrc = old_termios.c_cc[VINTR];
163  gl_quitc = old_termios.c_cc[VQUIT];
164 # ifdef VSUSP
165  gl_suspc = old_termios.c_cc[VSUSP];
166 # endif
167 # ifdef VDSUSP
168  gl_dsuspc = old_termios.c_cc[VDSUSP];
169 # endif
170  }
171  new_termios = old_termios;
172  new_termios.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
173  new_termios.c_iflag |= (IGNBRK|IGNPAR);
174  new_termios.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
175  new_termios.c_cc[VMIN] = 1;
176  new_termios.c_cc[VTIME] = 0;
177  tcsetattr(0, TCSANOW, &new_termios);
178 # elif defined(TIOCSETN) /* BSD */
179  if (ioctl(0, TIOCGETC, &tch) == 0) {
180  gl_intrc = tch.t_intrc;
181  gl_quitc = tch.t_quitc;
182  }
183  ioctl(0, TIOCGLTC, &ltch);
184  gl_suspc = ltch.t_suspc;
185  gl_dsuspc = ltch.t_dsuspc;
186  ioctl(0, TIOCGETP, &old_tty);
187  new_tty = old_tty;
188  new_tty.sg_flags |= RAW;
189  new_tty.sg_flags &= ~ECHO;
190  ioctl(0, TIOCSETN, &new_tty);
191 # else /* SYSV */
192  if (ioctl(0, TCGETA, &old_termio) == 0) {
193  gl_intrc = old_termio.c_cc[VINTR];
194  gl_quitc = old_termio.c_cc[VQUIT];
195  }
196  new_termio = old_termio;
197  new_termio.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
198  new_termio.c_iflag |= (IGNBRK|IGNPAR);
199  new_termio.c_lflag &= ~(ICANON|ISIG|ECHO);
200  new_termio.c_cc[VMIN] = 1;
201  new_termio.c_cc[VTIME] = 0;
202  ioctl(0, TCSETA, &new_termio);
203 # endif
204 #endif /* __unix__ */
205 }
206 
207 static void
208 gl_char_cleanup(void) /* undo effects of gl_char_init */
209 {
210 #ifdef __unix__
211 # ifdef HAVE_TERMIOS_H
212  tcsetattr(0, TCSANOW, &old_termios);
213 # elif defined(TIOCSETN) /* BSD */
214  ioctl(0, TIOCSETN, &old_tty);
215 # else /* SYSV */
216  ioctl(0, TCSETA, &old_termio);
217 # endif
218 #endif /* __unix__ */
219 }
220 
221 
222 
223 int
225 {
226  return (gl_result);
227 } /* gl_get_result */
228 
229 
230 
231 
232 #if defined(MSDOS) || defined(__windows__)
233 
234 #define K_UP 0x48
235 #define K_DOWN 0x50
236 #define K_LEFT 0x4B
237 #define K_RIGHT 0x4D
238 #define K_DELETE 0x53
239 #define K_INSERT 0x52
240 #define K_HOME 0x47
241 #define K_END 0x4F
242 #define K_PGUP 0x49
243 #define K_PGDN 0x51
244 
245 int pc_keymap(int c)
246 {
247  switch (c) {
248  case K_UP:
249  case K_PGUP:
250  c = 16; /* up -> ^P */
251  break;
252  case K_DOWN:
253  case K_PGDN:
254  c = 14; /* down -> ^N */
255  break;
256  case K_LEFT:
257  c = 2; /* left -> ^B */
258  break;
259  case K_RIGHT:
260  c = 6; /* right -> ^F */
261  break;
262  case K_END:
263  c = 5; /* end -> ^E */
264  break;
265  case K_HOME:
266  c = 1; /* home -> ^A */
267  break;
268  case K_INSERT:
269  c = 15; /* insert -> ^O */
270  break;
271  case K_DELETE:
272  c = 4; /* del -> ^D */
273  break;
274  default:
275  c = 0; /* make it garbage */
276  }
277  return c;
278 }
279 #endif /* defined(MSDOS) || defined(__windows__) */
280 
281 static int
282 gl_getc(void)
283 /* get a character without echoing it to screen */
284 {
285  int c;
286 #ifdef __unix__
287  char ch;
288 #endif
289 
290 #ifdef __unix__
291  ch = '\0';
292  while ((c = (int) read(0, &ch, 1)) == -1) {
293  if (errno != EINTR)
294  break;
295  }
296  if (c != (-1))
297  c = (int) ch;
298 #endif /* __unix__ */
299 #ifdef MSDOS
300  c = _bios_keybrd(_NKEYBRD_READ);
301  if ((c & 0377) == 224) {
302  c = pc_keymap((c >> 8) & 0377);
303  } else {
304  c &= 0377;
305  }
306 #endif /* MSDOS */
307 #ifdef __windows__
308  c = (int) _getch();
309  if ((c == 0) || (c == 0xE0)) {
310  /* Read key code */
311  c = (int) _getch();
312  c = pc_keymap(c);
313  } else if (c == '\r') {
314  /* Note: we only get \r from the console,
315  * and not a matching \n.
316  */
317  c = '\n';
318  }
319 #endif
320  return c;
321 }
322 
323 
324 
325 #ifdef __unix__
326 
327 static int
328 gl_getcx(int tlen)
329 /* Get a character without echoing it to screen, timing out
330  * after tlen tenths of a second.
331  */
332 {
333  int c, result;
334  char ch;
335  fd_set ss;
336  struct timeval tv;
337 
338  for (errno = 0;;) {
339  FD_ZERO(&ss);
340  FD_SET(0, &ss); /* set STDIN_FILENO */
341  tv.tv_sec = tlen / 10;
342  tv.tv_usec = (tlen % 10) * 100000L;
343  result = select(1, &ss, NULL, NULL, &tv);
344  if (result == 1) {
345  /* ready */
346  break;
347  } else if (result == 0) {
348  errno = ETIMEDOUT;
349  return (-2);
350  } else if (errno != EINTR) {
351  return (-1);
352  }
353  }
354 
355  for (errno = 0;;) {
356  c = (int) read(0, &ch, 1);
357  if (c == 1)
358  return ((int) ch);
359  if (errno != EINTR)
360  break;
361  }
362 
363  return (-1);
364 } /* gl_getcx */
365 
366 #endif /* __unix__ */
367 
368 
369 
370 
371 #ifdef __windows__
372 
373 static int
374 gl_getcx(int tlen)
375 {
376  int i, c;
377 
378  c = (-2);
379  tlen -= 2; /* Adjust for 200ms overhead */
380  if (tlen < 1)
381  tlen = 1;
382  for (i=0; i<tlen; i++) {
383  if (_kbhit()) {
384  c = (int) _getch();
385  if ((c == 0) || (c == 0xE0)) {
386  /* Read key code */
387  c = (int) _getch();
388  c = pc_keymap(c);
389  break;
390  }
391  }
392  (void) SleepEx((DWORD) (tlen * 100), FALSE);
393  }
394  return (c);
395 } /* gl_getcx */
396 
397 #endif /* __windows__ */
398 
399 
400 
401 
402 static void
403 gl_putc(int c)
404 {
405  char ch = (char) (unsigned char) c;
406 
407  write(1, &ch, 1);
408  if (ch == '\n') {
409  ch = '\r';
410  write(1, &ch, 1); /* RAW mode needs '\r', does not hurt */
411  }
412 }
413 
414 /******************** fairly portable part *********************************/
415 
416 static void
417 gl_puts(const char *const buf)
418 {
419  int len;
420 
421  if (buf) {
422  len = (int) strlen(buf);
423  write(1, buf, len);
424  }
425 }
426 
427 static void
428 gl_error(const char *const buf)
429 {
430  int len = (int) strlen(buf);
431 
432  gl_cleanup();
433  write(2, buf, len);
434  exit(1);
435 }
436 
437 static void
438 gl_init(void)
439 /* set up variables and terminal */
440 {
441  const char *cp;
442  int w;
443 
444  if (gl_init_done < 0) { /* -1 only on startup */
445  cp = (const char *) getenv("COLUMNS");
446  if (cp != NULL) {
447  w = atoi(cp);
448  if (w > 20)
449  gl_setwidth(w);
450  }
451  cp = (const char *) getenv("ROWS");
452  if (cp != NULL) {
453  w = atoi(cp);
454  if (w > 10)
455  gl_setheight(w);
456  }
457  hist_init();
458  }
459  if (_isatty(0) == 0 || _isatty(1) == 0)
460  gl_error("\n*** Error: getline(): not interactive, use stdio.\n");
461  gl_char_init();
462  gl_init_done = 1;
463 }
464 
465 static void
467 /* undo effects of gl_init, as necessary */
468 {
469  if (gl_init_done > 0)
470  gl_char_cleanup();
471  gl_init_done = 0;
472 #ifdef __windows__
473  Sleep(40);
475 #endif
476 }
477 
478 
479 static void
481 {
482  FILE *fp;
483  char path[256];
484 
485  /* If the user has a ~/.inputrc file,
486  * check it to see if it has a line like
487  * "set editing-mode vi". If it does,
488  * we know that the user wants vi
489  * emulation rather than emacs. If the
490  * file doesn't exist, it's no big
491  * deal since we can also check the
492  * $EDITOR environment variable.
493  */
495  if (gl_home_dir == NULL)
496  return;
497 
498 #ifdef HAVE_SNPRINTF
499  snprintf(path, sizeof(path), "%s/%s", gl_home_dir, ".inputrc");
500 #else
501  if (sizeof(path) >= (strlen(gl_home_dir) + strlen("/.inputrc")))
502  return;
503 
504  sprintf(path, "%s%s", gl_home_dir, "/.inputrc");
505 #endif
506 
507  fp = fopen(
508  path,
509 #if defined(__windows__) || defined(MSDOS)
510  "rt"
511 #else
512  "r"
513 #endif
514  );
515 
516  if (fp == NULL)
517  return;
518 
519  while (fgets(path, sizeof(path) - 1, fp) != NULL) {
520  if ((strstr(path, "editing-mode") != NULL) && (strstr(path, "vi") != NULL)) {
521  gl_vi_preferred = 1;
522  break;
523  }
524  }
525 
526  (void) fclose(fp);
527 } /* gl_check_inputrc_for_vi */
528 
529 
530 
531 void
533 {
534  if (w > 250)
535  w = 250;
536  if (w > 20) {
537  gl_termw = w;
538  gl_scroll = w / 3;
539  } else {
540  gl_error("\n*** Error: minimum screen width is 21\n");
541  }
542 } /* gl_setwidth */
543 
544 
545 
546 void
548 {
549  if (w > 10) {
550  gl_termh = w;
551  } else {
552  gl_error("\n*** Error: minimum screen height is 10\n");
553  }
554 } /* gl_setheight */
555 
556 
557 
558 
559 char *
560 getline(char *prompt)
561 {
562  int c, loc, tmp, lastch;
563  int vi_count, count;
564  int vi_delete;
565  char vi_countbuf[32];
566  char *cp;
567 
568 #ifdef __unix__
569  int sig;
570 #endif
571 
572  /* We'll change the result code only if something happens later. */
573  gl_result = GL_OK;
574 
575  /* Even if it appears that "vi" is preferred, we
576  * don't start in gl_vi_mode. They need to hit
577  * ESC to go into vi command mode.
578  */
579  gl_vi_mode = 0;
580  vi_count = 0;
581  vi_delete = 0;
582  if (gl_vi_preferred < 0) {
583  gl_vi_preferred = 0;
584  cp = (char *) getenv("EDITOR");
585  if (cp != NULL)
586  gl_vi_preferred = (strstr(cp, "vi") != NULL);
587  if (gl_vi_preferred == 0)
589  }
590 
591  gl_init();
592  gl_prompt = (prompt)? prompt : "";
593  gl_buf[0] = 0;
594  if (gl_in_hook)
597  lastch = 0;
598 
599 #ifdef __windows__
601 #endif
602 
603  while ((c = gl_getc()) != (-1)) {
604  gl_extent = 0; /* reset to full extent */
605  /* Note: \n may or may not be considered printable */
606  if ((c != '\t') && ((isprint(c) != 0) || ((c & 0x80) != 0))) {
607  if (gl_vi_mode > 0) {
608  /* "vi" emulation -- far from perfect,
609  * but reasonably functional.
610  */
611 vi:
612  for (count = 0; ; ) {
613  if (isdigit(c)) {
614  if (vi_countbuf[sizeof(vi_countbuf) - 2] == '\0')
615  vi_countbuf[strlen(vi_countbuf)] = (char) c;
616  } else if (vi_countbuf[0] != '\0') {
617  vi_count = atoi(vi_countbuf);
618  memset(vi_countbuf, 0, sizeof(vi_countbuf));
619  }
620  switch (c) {
621  case 'b':
622  gl_word(-1);
623  break;
624  case 'w':
625  if (vi_delete) {
626  gl_killword(1);
627  } else {
628  gl_word(1);
629  }
630  break;
631  case 'h': /* left */
632  if (vi_delete) {
633  if (gl_pos > 0) {
634  gl_fixup(gl_prompt, -1, gl_pos-1);
635  gl_del(0, 1);
636  }
637  } else {
638  gl_fixup(gl_prompt, -1, gl_pos-1);
639  }
640  break;
641  case ' ':
642  case 'l': /* right */
643  if (vi_delete) {
644  gl_del(0, 1);
645  } else {
646  gl_fixup(gl_prompt, -1, gl_pos+1);
647  }
648  break;
649  case 'k': /* up */
650  strcpy(gl_buf, hist_prev());
651  if (gl_in_hook)
654  break;
655  case 'j': /* down */
656  strcpy(gl_buf, hist_next());
657  if (gl_in_hook)
660  break;
661  case 'd':
662  if (vi_delete == 1) {
663  gl_kill(0);
664  vi_count = 1;
665  vi_delete = 0;
666  gl_vi_mode = 0;
667  goto vi_break;
668  }
669  vi_delete = 1;
670  goto vi_break;
671  case '^': /* start of line */
672  if (vi_delete) {
673  vi_count = gl_pos;
674  gl_fixup(gl_prompt, -1, 0);
675  for (c = 0; c < vi_count; c++) {
676  if (gl_cnt > 0)
677  gl_del(0, 0);
678  }
679  vi_count = 1;
680  vi_delete = 0;
681  } else {
682  gl_fixup(gl_prompt, -1, 0);
683  }
684  break;
685  case '$': /* end of line */
686  if (vi_delete) {
687  gl_kill(gl_pos);
688  } else {
689  loc = (int) strlen(gl_buf);
690  if (loc > 1)
691  loc--;
692  gl_fixup(gl_prompt, -1, loc);
693  }
694  break;
695  case 'p': /* paste after */
696  gl_fixup(gl_prompt, -1, gl_pos+1);
697  gl_yank();
698  break;
699  case 'P': /* paste before */
700  gl_yank();
701  break;
702  case 'r': /* replace character */
703  gl_buf[gl_pos] = (char) gl_getc();
705  vi_count = 1;
706  break;
707  case 'R':
708  gl_overwrite = 1;
709  gl_vi_mode = 0;
710  break;
711  case 'i':
712  case 'I':
713  gl_overwrite = 0;
714  gl_vi_mode = 0;
715  break;
716  case 'o':
717  case 'O':
718  case 'a':
719  case 'A':
720  gl_overwrite = 0;
721  gl_fixup(gl_prompt, -1, gl_pos+1);
722  gl_vi_mode = 0;
723  break;
724  }
725  count++;
726  if (count >= vi_count)
727  break;
728  }
729  vi_count = 1;
730  vi_delete = 0;
731 vi_break:
732  continue;
733  } else if (gl_search_mode) {
734  search_addchar(c);
735  } else {
736  gl_addchar(c);
737  }
738  } else {
739  if (gl_search_mode) {
740  if (c == '\033' || c == '\016' || c == '\020') {
741  search_term();
742  c = 0; /* ignore the character */
743  } else if (c == '\010' || c == '\177') {
744  search_addchar(-1); /* unwind search string */
745  c = 0;
746  } else if (c != '\022' && c != '\023') {
747  search_term(); /* terminate and handle char */
748  }
749  }
750  switch (c) {
751  case '\n': case '\r': /* newline */
752  gl_newline();
753  gl_cleanup();
754  return gl_buf;
755  case '\001': gl_fixup(gl_prompt, -1, 0); /* ^A */
756  break;
757  case '\002': gl_fixup(gl_prompt, -1, gl_pos-1); /* ^B */
758  break;
759  case '\004': /* ^D */
760  if (gl_cnt == 0) {
761  gl_buf[0] = 0;
762  gl_cleanup();
763  gl_putc('\n');
764  gl_result = GL_EOF;
765  return gl_buf;
766  } else {
767  gl_del(0, 1);
768  }
769  break;
770  case '\005': gl_fixup(gl_prompt, -1, gl_cnt); /* ^E */
771  break;
772  case '\006': gl_fixup(gl_prompt, -1, gl_pos+1); /* ^F */
773  break;
774  case '\010': case '\177': gl_del(-1, 0); /* ^H and DEL */
775  break;
776  case '\t': /* TAB */
777  if (gl_completion_proc) {
778  tmp = gl_pos;
779  gl_buf[sizeof(gl_buf) - 1] = '\0';
780  loc = gl_do_tab_completion(gl_buf, &tmp, sizeof(gl_buf), (lastch == '\t'));
781  gl_buf[sizeof(gl_buf) - 1] = '\0';
782  if (loc >= 0 || tmp != gl_pos)
783  gl_fixup(gl_prompt, /* loc */ -2, tmp);
784  if (lastch == '\t') {
785  c = 0;
786  lastch = 0;
787  }
788  } else if (gl_tab_hook) {
789  tmp = gl_pos;
790  gl_buf[sizeof(gl_buf) - 1] = '\0';
791  loc = gl_tab_hook(gl_buf, (int) gl_strlen(gl_prompt), &tmp, sizeof(gl_buf));
792  gl_buf[sizeof(gl_buf) - 1] = '\0';
793  if (loc >= 0 || tmp != gl_pos)
794  gl_fixup(gl_prompt, loc, tmp);
795  }
796  break;
797  case '\013': gl_kill(gl_pos); /* ^K */
798  break;
799  case '\014': gl_redraw(); /* ^L */
800  break;
801  case '\016': /* ^N */
802  strcpy(gl_buf, hist_next());
803  if (gl_in_hook)
806  break;
807  case '\017': gl_overwrite = !gl_overwrite; /* ^O */
808  break;
809  case '\020': /* ^P */
810  strcpy(gl_buf, hist_prev());
811  if (gl_in_hook)
814  break;
815  case '\022': search_back(1); /* ^R */
816  break;
817  case '\023': search_forw(1); /* ^S */
818  break;
819  case '\024': gl_transpose(); /* ^T */
820  break;
821  case '\025': gl_kill(0); /* ^U */
822  break;
823  case '\027': gl_killword(-1); /* ^W */
824  break;
825  case '\031': gl_yank(); /* ^Y */
826  break;
827  case '\033': /* ansi arrow keys */
828  c = gl_getcx(3);
829  if ((c == '[') || (c == 'O')) {
830 ansi:
831  switch(c = gl_getc()) {
832  case 'A': /* up */
833  strcpy(gl_buf, hist_prev());
834  if (gl_in_hook)
837  break;
838  case 'B': /* down */
839  strcpy(gl_buf, hist_next());
840  if (gl_in_hook)
843  break;
844  case 'C':
845  gl_fixup(gl_prompt, -1, gl_pos+1); /* right */
846  break;
847  case 'D':
848  gl_fixup(gl_prompt, -1, gl_pos-1); /* left */
849  break;
850  case '0':
851  case '1':
852  goto ansi;
853  default: gl_beep(); /* who knows */
854  break;
855  }
856  } else if ((gl_vi_preferred == 0) && ((c == 'f') || (c == 'F'))) {
857  gl_word(1);
858  } else if ((gl_vi_preferred == 0) && ((c == 'b') || (c == 'B'))) {
859  gl_word(-1);
860  } else if (c != (-1)) {
861  /* enter vi command mode */
862 #if defined(__windows__) || defined(MSDOS)
863  if (gl_vi_preferred == 0) {
864  /* On Windows, ESC acts like a line kill,
865  * so don't use vi mode unless they prefer
866  * vi mode.
867  */
868  gl_kill(0);
869  } else
870 #endif
871  if (gl_vi_mode == 0) {
872  gl_vi_mode = 1;
873  vi_count = 1;
874  vi_delete = 0;
875  memset(vi_countbuf, 0, sizeof(vi_countbuf));
876  if (gl_pos > 0)
877  gl_fixup(gl_prompt, -2, gl_pos-1); /* left 1 char */
878  /* Don't bother if the line is empty and we don't
879  * know for sure if the user wants vi mode.
880  */
881  if ((gl_cnt > 0) || (gl_vi_preferred == 1)) {
882  /* We still have to use the char read! */
883  goto vi;
884  }
885  gl_vi_mode = 0;
886  } else {
887  gl_beep();
888  }
889  }
890  break;
891  default: /* check for a terminal signal */
892  if (c > 0) { /* ignore 0 (reset above) */
893  if (c == gl_intrc) {
895  gl_buf[0] = 0;
896  gl_cleanup();
897 #ifdef SIGINT
898  raise(SIGINT);
899  gl_init();
900  gl_redraw();
901 #endif
902  return gl_buf;
903  }
904 
905  if (c == gl_quitc) {
907  gl_buf[0] = 0;
908  gl_cleanup();
909 #ifdef SIGQUIT
910  raise(SIGQUIT);
911  gl_init();
912  gl_redraw();
913 #endif
914  return gl_buf;
915  }
916 
917 #ifdef __unix__
918  if (c == gl_suspc || c == gl_dsuspc) {
919 #ifdef SIGTSTP
921  gl_buf[0] = 0;
922  gl_cleanup();
923  sig = SIGTSTP;
924  kill(0, sig);
925  gl_init();
926  gl_redraw();
927  return gl_buf;
928 #endif
929  }
930 #endif /* __unix__ */
931  }
932  if (c > 0)
933  gl_beep();
934  break;
935  }
936  }
937  if (c > 0)
938  lastch = c;
939  }
940  gl_buf[0] = 0;
941  gl_cleanup();
942  return gl_buf;
943 }
944 
945 static void
947 
948 /* adds the character c to the input buffer at current location */
949 {
950  int i;
951 
952  if (gl_cnt >= GL_BUF_SIZE - 1)
953  gl_error("\n*** Error: getline(): input buffer overflow\n");
954  if (gl_overwrite == 0 || gl_pos == gl_cnt) {
955  for (i=gl_cnt; i >= gl_pos; i--)
956  gl_buf[i+1] = gl_buf[i];
957  gl_buf[gl_pos] = (char) c;
959  } else {
960  gl_buf[gl_pos] = (char) c;
961  gl_extent = 1;
963  }
964 }
965 
966 static void
967 gl_yank(void)
968 /* adds the kill buffer to the input buffer at current location */
969 {
970  int i, len;
971 
972  len = (int) strlen(gl_killbuf);
973  if (len > 0) {
974  if (gl_overwrite == 0) {
975  if (gl_cnt + len >= GL_BUF_SIZE - 1)
976  gl_error("\n*** Error: getline(): input buffer overflow\n");
977  for (i=gl_cnt; i >= gl_pos; i--)
978  gl_buf[i+len] = gl_buf[i];
979  for (i=0; i < len; i++)
980  gl_buf[gl_pos+i] = gl_killbuf[i];
982  } else {
983  if (gl_pos + len > gl_cnt) {
984  if (gl_pos + len >= GL_BUF_SIZE - 1)
985  gl_error("\n*** Error: getline(): input buffer overflow\n");
986  gl_buf[gl_pos + len] = 0;
987  }
988  for (i=0; i < len; i++)
989  gl_buf[gl_pos+i] = gl_killbuf[i];
990  gl_extent = len;
992  }
993  } else
994  gl_beep();
995 }
996 
997 static void
999 /* switch character under cursor and to left of cursor */
1000 {
1001  int c;
1002 
1003  if (gl_pos > 0 && gl_cnt > gl_pos) {
1004  c = gl_buf[gl_pos-1];
1005  gl_buf[gl_pos-1] = gl_buf[gl_pos];
1006  gl_buf[gl_pos] = (char) c;
1007  gl_extent = 2;
1009  } else
1010  gl_beep();
1011 }
1012 
1013 static void
1015 /*
1016  * Cleans up entire line before returning to caller. A \n is appended.
1017  * If line longer than screen, we redraw starting at beginning
1018  */
1019 {
1020  int change = gl_cnt;
1021  int len = gl_cnt;
1022  int loc = gl_width - 5; /* shifts line back to start position */
1023 
1024  if (gl_cnt >= GL_BUF_SIZE - 1)
1025  gl_error("\n*** Error: getline(): input buffer overflow\n");
1026  if (gl_out_hook) {
1027  change = gl_out_hook(gl_buf);
1028  len = (int) strlen(gl_buf);
1029  }
1030  if (loc > len)
1031  loc = len;
1032  gl_fixup(gl_prompt, change, loc); /* must do this before appending \n */
1033  gl_buf[len] = '\n';
1034  gl_buf[len+1] = '\0';
1035  gl_putc('\n');
1036 }
1037 
1038 static void
1039 gl_del(int loc, int killsave)
1040 
1041 /*
1042  * Delete a character. The loc variable can be:
1043  * -1 : delete character to left of cursor
1044  * 0 : delete character under cursor
1045  */
1046 {
1047  int i, j;
1048 
1049  if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) {
1050  for (j=0, i=gl_pos+loc; i < gl_cnt; i++) {
1051  if ((j == 0) && (killsave != 0) && (gl_vi_mode != 0)) {
1052  gl_killbuf[0] = gl_buf[i];
1053  gl_killbuf[1] = '\0';
1054  j = 1;
1055  }
1056  gl_buf[i] = gl_buf[i+1];
1057  }
1058  gl_fixup(gl_prompt, gl_pos+loc, gl_pos+loc);
1059  } else
1060  gl_beep();
1061 }
1062 
1063 static void
1065 
1066 /* delete from pos to the end of line */
1067 {
1068  if (pos < gl_cnt) {
1070  gl_buf[pos] = '\0';
1072  } else
1073  gl_beep();
1074 }
1075 
1076 static void
1077 gl_killword(int direction)
1078 {
1079  int pos = gl_pos;
1080  int startpos = gl_pos;
1081  int tmp;
1082  int i;
1083 
1084  if (direction > 0) { /* forward */
1085  while (!isspace(gl_buf[pos]) && pos < gl_cnt)
1086  pos++;
1087  while (isspace(gl_buf[pos]) && pos < gl_cnt)
1088  pos++;
1089  } else { /* backward */
1090  if (pos > 0)
1091  pos--;
1092  while (isspace(gl_buf[pos]) && pos > 0)
1093  pos--;
1094  while (!isspace(gl_buf[pos]) && pos > 0)
1095  pos--;
1096  if (pos < gl_cnt && isspace(gl_buf[pos])) /* move onto word */
1097  pos++;
1098  }
1099  if (pos < startpos) {
1100  tmp = pos;
1101  pos = startpos;
1102  startpos = tmp;
1103  }
1104  memcpy(gl_killbuf, gl_buf + startpos, (size_t) (pos - startpos));
1105  gl_killbuf[pos - startpos] = '\0';
1106  if (isspace(gl_killbuf[pos - startpos - 1]))
1107  gl_killbuf[pos - startpos - 1] = '\0';
1108  gl_fixup(gl_prompt, -1, startpos);
1109  for (i=0, tmp=pos - startpos; i<tmp; i++)
1110  gl_del(0, 0);
1111 } /* gl_killword */
1112 
1113 static void
1114 gl_word(int direction)
1115 
1116 /* move forward or backword one word */
1117 {
1118  int pos = gl_pos;
1119 
1120  if (direction > 0) { /* forward */
1121  while (!isspace(gl_buf[pos]) && pos < gl_cnt)
1122  pos++;
1123  while (isspace(gl_buf[pos]) && pos < gl_cnt)
1124  pos++;
1125  } else { /* backword */
1126  if (pos > 0)
1127  pos--;
1128  while (isspace(gl_buf[pos]) && pos > 0)
1129  pos--;
1130  while (!isspace(gl_buf[pos]) && pos > 0)
1131  pos--;
1132  if (pos < gl_cnt && isspace(gl_buf[pos])) /* move onto word */
1133  pos++;
1134  }
1135  gl_fixup(gl_prompt, -1, pos);
1136 }
1137 
1138 static void
1140 /* emit a newline, reset and redraw prompt and current input line */
1141 {
1142  if (gl_init_done > 0) {
1143  gl_putc('\n');
1144  gl_fixup(gl_prompt, -2, gl_pos);
1145  }
1146 }
1147 
1148 static void
1149 gl_fixup(const char *prompt, int change, int cursor)
1150 
1151 
1152 /*
1153  * This function is used both for redrawing when input changes or for
1154  * moving within the input line. The parameters are:
1155  * prompt: compared to last_prompt[] for changes;
1156  * change : the index of the start of changes in the input buffer,
1157  * with -1 indicating no changes, -2 indicating we're on
1158  * a new line, redraw everything.
1159  * cursor : the desired location of the cursor after the call.
1160  * A value of GL_BUF_SIZE can be used to indicate the cursor should
1161  * move just past the end of the input line.
1162  */
1163 {
1164  static int gl_shift; /* index of first on screen character */
1165  static int off_right; /* true if more text right of screen */
1166  static int off_left; /* true if more text left of screen */
1167  static char last_prompt[80] = "";
1168  int left = 0, right = -1; /* bounds for redraw */
1169  int pad; /* how much to erase at end of line */
1170  int backup; /* how far to backup before fixing */
1171  int new_shift; /* value of shift based on cursor */
1172  int extra; /* adjusts when shift (scroll) happens */
1173  int i;
1174  int new_right = -1; /* alternate right bound, using gl_extent */
1175  int l1, l2;
1176 
1177  if (change == -2) { /* reset */
1178  gl_pos = gl_cnt = gl_shift = off_right = off_left = 0;
1179  gl_putc('\r');
1180  gl_puts(prompt);
1181  strcpy(last_prompt, prompt);
1182  change = 0;
1183  gl_width = gl_termw - (int) gl_strlen(prompt);
1184  } else if (strcmp(prompt, last_prompt) != 0) {
1185  l1 = (int) gl_strlen(last_prompt);
1186  l2 = (int) gl_strlen(prompt);
1187  gl_cnt = gl_cnt + l1 - l2;
1188  strcpy(last_prompt, prompt);
1189  gl_putc('\r');
1190  gl_puts(prompt);
1191  gl_pos = gl_shift;
1192  gl_width = gl_termw - l2;
1193  change = 0;
1194  }
1195  pad = (off_right)? gl_width - 1 : gl_cnt - gl_shift; /* old length */
1196  backup = gl_pos - gl_shift;
1197  if (change >= 0) {
1198  gl_cnt = (int) strlen(gl_buf);
1199  if (change > gl_cnt)
1200  change = gl_cnt;
1201  }
1202  if (cursor > gl_cnt) {
1203  if (cursor != GL_BUF_SIZE) { /* GL_BUF_SIZE means end of line */
1204  if (gl_ellipses_during_completion == 0) {
1205  gl_beep();
1206  }
1207  }
1208  cursor = gl_cnt;
1209  }
1210  if (cursor < 0) {
1211  gl_beep();
1212  cursor = 0;
1213  }
1214  if (off_right || (off_left && cursor < gl_shift + gl_width - gl_scroll / 2))
1215  extra = 2; /* shift the scrolling boundary */
1216  else
1217  extra = 0;
1218  new_shift = cursor + extra + gl_scroll - gl_width;
1219  if (new_shift > 0) {
1220  new_shift /= gl_scroll;
1221  new_shift *= gl_scroll;
1222  } else
1223  new_shift = 0;
1224  if (new_shift != gl_shift) { /* scroll occurs */
1225  gl_shift = new_shift;
1226  off_left = (gl_shift)? 1 : 0;
1227  off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
1228  left = gl_shift;
1229  new_right = right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
1230  } else if (change >= 0) { /* no scroll, but text changed */
1231  if (change < gl_shift + off_left) {
1232  left = gl_shift;
1233  } else {
1234  left = change;
1235  backup = gl_pos - change;
1236  }
1237  off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
1238  right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
1239  new_right = (gl_extent && (right > left + gl_extent))?
1240  left + gl_extent : right;
1241  }
1242  pad -= (off_right)? gl_width - 1 : gl_cnt - gl_shift;
1243  pad = (pad < 0)? 0 : pad;
1244  if (left <= right) { /* clean up screen */
1245  for (i=0; i < backup; i++)
1246  gl_putc('\b');
1247  if (left == gl_shift && off_left) {
1248  gl_putc('$');
1249  left++;
1250  }
1251  for (i=left; i < new_right; i++)
1252  gl_putc(gl_buf[i]);
1253  gl_pos = new_right;
1254  if (off_right && new_right == right) {
1255  gl_putc('$');
1256  gl_pos++;
1257  } else {
1258  for (i=0; i < pad; i++) /* erase remains of prev line */
1259  gl_putc(' ');
1260  gl_pos += pad;
1261  }
1262  }
1263  i = gl_pos - cursor; /* move to final cursor location */
1264  if (i > 0) {
1265  while (i--)
1266  gl_putc('\b');
1267  } else {
1268  for (i=gl_pos; i < cursor; i++)
1269  gl_putc(gl_buf[i]);
1270  }
1271  gl_pos = cursor;
1272 }
1273 
1274 static int
1275 gl_tab(char *buf, int offset, int *loc, size_t bufsize)
1276 /* default tab handler, acts like tabstops every 8 cols */
1277 {
1278  int i, count, len;
1279 
1280  len = (int) strlen(buf);
1281  count = 8 - (offset + *loc) % 8;
1282  for (i=len; i >= *loc; i--)
1283  if (i+count < (int) bufsize)
1284  buf[i+count] = buf[i];
1285  for (i=0; i < count; i++)
1286  if (*loc+i < (int) bufsize)
1287  buf[*loc+i] = ' ';
1288  i = *loc;
1289  *loc = i + count;
1290  return i;
1291 }
1292 
1293 /******************* History stuff **************************************/
1294 
1295 #ifndef HIST_SIZE
1296 #define HIST_SIZE 100
1297 #endif
1298 
1299 static int hist_pos = 0, hist_last = 0;
1300 static char *hist_buf[HIST_SIZE];
1301 static char hist_empty_elem[2] = "";
1302 
1303 static void
1305 {
1306  int i;
1307 
1309  for (i=1; i < HIST_SIZE; i++)
1310  hist_buf[i] = (char *)0;
1311 }
1312 
1313 void
1315 {
1316  static char *prev = 0;
1317  char *p = buf;
1318  int len;
1319 
1320  /* in case we call gl_histadd() before we call getline() */
1321  if (gl_init_done < 0) { /* -1 only on startup */
1322  hist_init();
1323  gl_init_done = 0;
1324  }
1325  while (*p == ' ' || *p == '\t' || *p == '\n')
1326  p++;
1327  if (*p) {
1328  len = (int) strlen(buf);
1329  if (strchr(p, '\n')) /* previously line already has NL stripped */
1330  len--;
1331  if ((prev == 0) || ((int) strlen(prev) != len) ||
1332  strncmp(prev, buf, (size_t) len) != 0) {
1334  prev = hist_buf[hist_last];
1335  hist_last = (hist_last + 1) % HIST_SIZE;
1336  if (hist_buf[hist_last] && *hist_buf[hist_last]) {
1338  }
1340  }
1341  }
1342  hist_pos = hist_last;
1343 }
1344 
1345 static char *
1347 /* loads previous hist entry into input buffer, sticks on first */
1348 {
1349  char *p = 0;
1350  int next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE;
1351 
1352  if (hist_buf[hist_pos] != 0 && next != hist_last) {
1353  hist_pos = next;
1354  p = hist_buf[hist_pos];
1355  }
1356  if (p == 0) {
1357  p = hist_empty_elem;
1358  gl_beep();
1359  }
1360  return p;
1361 }
1362 
1363 static char *
1365 /* loads next hist entry into input buffer, clears on last */
1366 {
1367  char *p = 0;
1368 
1369  if (hist_pos != hist_last) {
1370  hist_pos = (hist_pos+1) % HIST_SIZE;
1371  p = hist_buf[hist_pos];
1372  }
1373  if (p == 0) {
1374  p = hist_empty_elem;
1375  gl_beep();
1376  }
1377  return p;
1378 }
1379 
1380 static char *
1381 hist_save(char *p)
1382 
1383 /* makes a copy of the string */
1384 {
1385  char *s = 0;
1386  size_t len = strlen(p);
1387  char *nl = strpbrk(p, "\n\r");
1388 
1389  if (nl) {
1390  if ((s = (char *) malloc(len)) != 0) {
1391  strncpy(s, p, len-1);
1392  s[len-1] = 0;
1393  }
1394  } else {
1395  if ((s = (char *) malloc(len+1)) != 0) {
1396  strcpy(s, p);
1397  }
1398  }
1399  if (s == 0)
1400  gl_error("\n*** Error: hist_save() failed on malloc\n");
1401  return s;
1402 }
1403 
1404 
1405 
1406 
1407 void
1408 gl_histsavefile(const char *const path)
1409 {
1410  FILE *fp;
1411  const char *p;
1412  int i, j;
1413 
1414  fp = fopen(path,
1415 #if defined(__windows__) || defined(MSDOS)
1416  "wt"
1417 #else
1418  "w"
1419 #endif
1420  );
1421  if (fp != NULL) {
1422  for (i=2; i<HIST_SIZE; i++) {
1423  j = (hist_pos+i) % HIST_SIZE;
1424  p = hist_buf[j];
1425  if ((p == NULL) || (*p == '\0'))
1426  continue;
1427  fprintf(fp, "%s\n", p);
1428  }
1429  fclose(fp);
1430  }
1431 } /* gl_histsavefile */
1432 
1433 
1434 
1435 
1436 void
1437 gl_histloadfile(const char *const path)
1438 {
1439  FILE *fp;
1440  char line[256];
1441 
1442  fp = fopen(path,
1443 #if defined(__windows__) || defined(MSDOS)
1444  "rt"
1445 #else
1446  "r"
1447 #endif
1448  );
1449  if (fp != NULL) {
1450  memset(line, 0, sizeof(line));
1451  while (fgets(line, sizeof(line) - 2, fp) != NULL) {
1452  gl_histadd(line);
1453  }
1454  fclose(fp);
1455  }
1456 } /* gl_histloadfile */
1457 
1458 
1459 
1460 
1461 /******************* Search stuff **************************************/
1462 
1463 static char search_prompt[101]; /* prompt includes search string */
1464 static char search_string[100];
1465 static int search_pos = 0; /* current location in search_string */
1466 static int search_forw_flg = 0; /* search direction flag */
1467 static int search_last = 0; /* last match found */
1468 
1469 static void
1471 {
1472  if (c == 0) {
1473  search_pos = 0;
1474  search_string[0] = 0;
1475  search_prompt[0] = '?';
1476  search_prompt[1] = ' ';
1477  search_prompt[2] = 0;
1478  } else if (c > 0) {
1480  search_string[search_pos+1] = (char) 0;
1482  search_prompt[search_pos+1] = (char) '?';
1483  search_prompt[search_pos+2] = (char) ' ';
1484  search_prompt[search_pos+3] = (char) 0;
1485  search_pos++;
1486  } else {
1487  if (search_pos > 0) {
1488  search_pos--;
1489  search_string[search_pos] = (char) 0;
1490  search_prompt[search_pos] = (char) '?';
1491  search_prompt[search_pos+1] = (char) ' ';
1492  search_prompt[search_pos+2] = (char) 0;
1493  } else {
1494  gl_beep();
1495  hist_pos = hist_last;
1496  }
1497  }
1498 }
1499 
1500 static void
1502 {
1503  char *loc;
1504 
1505  search_update(c);
1506  if (c < 0) {
1507  if (search_pos > 0) {
1509  } else {
1510  gl_buf[0] = 0;
1511  hist_pos = hist_last;
1512  }
1514  }
1515  if ((loc = strstr(gl_buf, search_string)) != 0) {
1516  gl_fixup(search_prompt, 0, (int) (loc - gl_buf));
1517  } else if (search_pos > 0) {
1518  if (search_forw_flg) {
1519  search_forw(0);
1520  } else {
1521  search_back(0);
1522  }
1523  } else {
1524  gl_fixup(search_prompt, 0, 0);
1525  }
1526 }
1527 
1528 static void
1530 {
1531  gl_search_mode = 0;
1532  if (gl_buf[0] == 0) /* not found, reset hist list */
1533  hist_pos = hist_last;
1534  if (gl_in_hook)
1535  gl_in_hook(gl_buf);
1536  gl_fixup(gl_prompt, 0, gl_pos);
1537 }
1538 
1539 static void
1540 search_back(int new_search)
1541 {
1542  int found = 0;
1543  char *p, *loc;
1544 
1545  search_forw_flg = 0;
1546  if (gl_search_mode == 0) {
1548  search_update(0);
1549  gl_search_mode = 1;
1550  gl_buf[0] = 0;
1551  gl_fixup(search_prompt, 0, 0);
1552  } else if (search_pos > 0) {
1553  while (!found) {
1554  p = hist_prev();
1555  if (*p == 0) { /* not found, done looking */
1556  gl_buf[0] = 0;
1557  gl_fixup(search_prompt, 0, 0);
1558  found = 1;
1559  } else if ((loc = strstr(p, search_string)) != 0) {
1560  strcpy(gl_buf, p);
1561  gl_fixup(search_prompt, 0, (int) (loc - p));
1562  if (new_search)
1564  found = 1;
1565  }
1566  }
1567 
1568  } else {
1569  gl_beep();
1570  }
1571 }
1572 
1573 static void
1574 search_forw(int new_search)
1575 {
1576  int found = 0;
1577  char *p, *loc;
1578 
1579  search_forw_flg = 1;
1580  if (gl_search_mode == 0) {
1582  search_update(0);
1583  gl_search_mode = 1;
1584  gl_buf[0] = 0;
1585  gl_fixup(search_prompt, 0, 0);
1586  } else if (search_pos > 0) {
1587  while (!found) {
1588  p = hist_next();
1589  if (*p == 0) { /* not found, done looking */
1590  gl_buf[0] = 0;
1591  gl_fixup(search_prompt, 0, 0);
1592  found = 1;
1593  } else if ((loc = strstr(p, search_string)) != 0) {
1594  strcpy(gl_buf, p);
1595  gl_fixup(search_prompt, 0, (int) (loc - p));
1596  if (new_search)
1598  found = 1;
1599  }
1600  }
1601  } else {
1602  gl_beep();
1603  }
1604 }
1605 
1606 
1607 static void
1608 gl_beep(void)
1609 {
1610 #ifdef __windows__
1611  MessageBeep(MB_OK);
1612 #else
1613  gl_putc('\007');
1614 #endif
1615 } /* gl_beep */
1616 
1617 
1618 
1619 static int
1620 gl_display_matches_sort_proc(const void *a, const void *b)
1621 {
1622  return (strcasecmp(
1623  * ((const char **) a),
1624  * ((const char **) b)
1625  ));
1626 } /* gl_display_matches_sort_proc */
1627 
1628 
1629 
1630 static void
1632 {
1633  char buf[256];
1634  char buf2[256];
1635  size_t ilen, imaxlen;
1636  int i, j, k, l;
1637  int glen, allmatch;
1638  int nmax, ncol, colw, nrow;
1639  char *cp1, *cp2, *lim, *itemp;
1640 
1641  gl_putc('\n');
1642  if (nused == 0) {
1643  gl_beep();
1644  gl_puts(" (no matches)");
1645  gl_putc('\n');
1646  } else {
1647  qsort(gl_matchlist, (size_t) nused, sizeof(char *), gl_display_matches_sort_proc);
1648 
1649  /* Find the greatest amount that matches. */
1650  for (glen = 0; ; glen++) {
1651  allmatch = 1;
1652  for (i=1; i<nused; i++) {
1653  if (gl_matchlist[0][glen] != gl_matchlist[i][glen]) {
1654  allmatch = 0;
1655  break;
1656  }
1657  }
1658  if (allmatch == 0)
1659  break;
1660  }
1661 
1662  while (glen > 0) {
1663  if (!isalnum(gl_matchlist[0][glen - 1]))
1664  break;
1665  --glen;
1666  }
1667 
1668  nmax = nused;
1669  imaxlen = strlen(gl_matchlist[0]);
1670  for (i=1; i<nused; i++) {
1671  ilen = strlen(gl_matchlist[i]);
1672  if (ilen > imaxlen)
1673  imaxlen = ilen;
1674  }
1675 
1676  /* Subtract amount we'll skip for each item. */
1677  imaxlen -= glen;
1678 
1679  ncol = (gl_termw - 8) / ((int) imaxlen + 2);
1680  if (ncol < 1)
1681  ncol = 1;
1682 
1683  colw = (gl_termw - 8) / ncol;
1684  nrow = nmax / ncol;
1685  if ((nused % ncol) != 0)
1686  nrow++;
1687 
1688  if (nrow > (gl_termh - 4)) {
1689  nrow = gl_termh - 4;
1690  nmax = ncol * nrow;
1691  }
1692 
1693  for (i=0; i<(int) sizeof(buf2); i++)
1694  buf2[i] = ' ';
1695 
1696  for (j=0; j<nrow; j++) {
1697  (void) memcpy(buf, buf2, sizeof(buf));
1698  for (i=0, k=j, l=4; i<ncol; i++, k += nrow, l += colw) {
1699  if (k >= nmax)
1700  continue;
1701  itemp = gl_matchlist[k] + glen;
1702  cp1 = buf + l;
1703  lim = cp1 + (int) strlen(itemp);
1704  if (lim > (buf + sizeof(buf) - 1))
1705  continue;
1706  cp2 = itemp;
1707  while (cp1 < lim)
1708  *cp1++ = *cp2++;
1709  }
1710  for (cp1 = buf + sizeof(buf); *--cp1 == ' '; )
1711  ;
1712  ++cp1;
1713  *cp1 = '\0';
1714  gl_puts(buf);
1715  gl_putc('\n');
1716  }
1717 
1718  if (nused > nmax) {
1719  (void) sprintf(buf, " ... %d others omitted ...", (nused - nmax));
1720  gl_puts(buf);
1721  gl_putc('\n');
1722  }
1723  }
1725 } /* gl_display_matches */
1726 
1727 
1728 
1729 
1730 static int
1731 gl_do_tab_completion(char *buf, int *loc, size_t bufsize, int tabtab)
1732 {
1733  char *startp;
1734  size_t startoff, amt;
1735  int c;
1736  int qmode;
1737  char *qstart;
1738  char *lastspacestart;
1739  char *cp;
1740  int ntoalloc, nused, nprocused, nalloced, i;
1741  char **newgl_matchlist;
1742  char *strtoadd, *strtoadd1;
1743  int addquotes;
1744  size_t llen, mlen, glen;
1745  int allmatch;
1746  char *curposp;
1747  size_t lenaftercursor;
1748  char *matchpfx;
1749  int wasateol;
1750  char ellipsessave[4];
1751 
1752  /* Zero out the rest of the buffer, so we can move stuff around
1753  * and know we'll still be NUL-terminated.
1754  */
1755  llen = strlen(buf);
1756  memset(buf + llen, 0, bufsize - llen);
1757  bufsize -= 4; /* leave room for a NUL, space, and two quotes. */
1758  curposp = buf + *loc;
1759  wasateol = (*curposp == '\0');
1760  lenaftercursor = llen - (curposp - buf);
1761  if (gl_ellipses_during_completion != 0) {
1762  memcpy(ellipsessave, curposp, (size_t) 4);
1763  memcpy(curposp, "... ", (size_t) 4);
1765  memcpy(curposp, ellipsessave, (size_t) 4);
1766  }
1767 
1768  qmode = 0;
1769  qstart = NULL;
1770  lastspacestart = NULL;
1771  matchpfx = NULL;
1772 
1773  cp = buf;
1774  while (cp < curposp) {
1775  c = (int) *cp++;
1776  if (c == '\0')
1777  break;
1778  if ((c == '"') || (c == '\'')) {
1779  if (qmode == c) {
1780  /* closing quote; end it. */
1781  qstart = NULL;
1782  qmode = 0;
1783  } else if (qmode != 0) {
1784  /* just treat it as a regular char. */
1785  } else {
1786  /* start new quote group. */
1787  qmode = c;
1788  qstart = cp - 1;
1789  }
1790  } else if ((isspace(c)) && (qmode == 0)) {
1791  /* found a non-quoted space. */
1792  lastspacestart = cp - 1;
1793  } else {
1794  /* regular char */
1795  }
1796  }
1797 
1798  if (qstart != NULL)
1799  startp = qstart + 1;
1800  else if (lastspacestart != NULL)
1801  startp = lastspacestart + 1;
1802  else
1803  startp = buf;
1804 
1805  cp = startp;
1806  mlen = (curposp - cp);
1807 
1808  matchpfx = (char *) malloc(mlen + 1);
1809  memcpy(matchpfx, cp, mlen);
1810  matchpfx[mlen] = '\0';
1811 
1812 #define GL_COMPLETE_VECTOR_BLOCK_SIZE 64
1813 
1814  nused = 0;
1815  ntoalloc = GL_COMPLETE_VECTOR_BLOCK_SIZE;
1816  newgl_matchlist = (char **) malloc((size_t) (sizeof(char *) * (ntoalloc + 1)));
1817  if (newgl_matchlist == NULL) {
1818  free(matchpfx);
1819  gl_beep();
1820  return 0;
1821  }
1822  gl_matchlist = newgl_matchlist;
1823  nalloced = ntoalloc;
1824  for (i=nused; i<=nalloced; i++)
1825  gl_matchlist[i] = NULL;
1826 
1828  for (nprocused = 0;; nprocused++) {
1829  if (nused == nalloced) {
1830  ntoalloc += GL_COMPLETE_VECTOR_BLOCK_SIZE;
1831  newgl_matchlist = (char **) realloc((char *) gl_matchlist, (size_t) (sizeof(char *) * (ntoalloc + 1)));
1832  if (newgl_matchlist == NULL) {
1833  /* not enough memory to expand list -- abort */
1834  for (i=0; i<nused; i++)
1835  free(gl_matchlist[i]);
1836  free(gl_matchlist);
1837  gl_matchlist = NULL;
1838  gl_beep();
1839  free(matchpfx);
1840  return 0;
1841  }
1842  gl_matchlist = newgl_matchlist;
1843  nalloced = ntoalloc;
1844  for (i=nused; i<=nalloced; i++)
1845  gl_matchlist[i] = NULL;
1846  }
1847  cp = gl_completion_proc(matchpfx, nprocused);
1848  if (cp == NULL)
1849  break;
1850  if ((cp[0] == '.') && ((cp[1] == '\0') || ((cp[1] == '.') && (cp[2] == '\0'))))
1851  continue; /* Skip . and .. */
1852  gl_matchlist[nused++] = cp;
1853  }
1854 
1855  if (gl_ellipses_during_completion != 0) {
1857  gl_puts(" ");
1858  }
1859 
1860  /* We now have an array strings, whose last element is NULL. */
1861  strtoadd = NULL;
1862  strtoadd1 = NULL;
1863  amt = 0;
1864 
1866 
1867  if (nused == 1) {
1868  /* Exactly one match. */
1869  strtoadd = gl_matchlist[0];
1870  } else if (tabtab != 0) {
1871  /* TAB-TAB: print all matches */
1872  gl_display_matches(nused);
1873  } else if ((nused > 1) && (mlen > 0)) {
1874  /* Find the greatest amount that matches. */
1875  for (glen = strlen(matchpfx); ; glen++) {
1876  allmatch = 1;
1877  for (i=1; i<nused; i++) {
1878  if (gl_matchlist[0][glen] != gl_matchlist[i][glen]) {
1879  allmatch = 0;
1880  break;
1881  }
1882  }
1883  if (allmatch == 0)
1884  break;
1885  }
1886  strtoadd1 = (char *) malloc(glen + 1);
1887  if (strtoadd1 != NULL) {
1888  memcpy(strtoadd1, gl_matchlist[0], glen);
1889  strtoadd1[glen] = '\0';
1890  strtoadd = strtoadd1;
1891  }
1892  }
1893 
1894  if (strtoadd != NULL) {
1895  if ((qmode == 0) && (addquotes != 0)) {
1896  if (strpbrk(strtoadd, gl_filename_quote_characters) != NULL) {
1897  qmode = (strchr(strtoadd, '"') == NULL) ? '"' : '\'';
1898  memmove(curposp + 1, curposp, lenaftercursor + 1 /* NUL */);
1899  curposp++;
1900  *startp++ = (char) qmode;
1901  }
1902  }
1903  startoff = (size_t) (startp - buf);
1904  amt = strlen(strtoadd);
1905  if ((amt + startoff + lenaftercursor) >= bufsize)
1906  amt = bufsize - (amt + startoff + lenaftercursor);
1907  memmove(curposp + amt - mlen, curposp, lenaftercursor + 1 /* NUL */);
1908  curposp += amt - mlen;
1909  memcpy(startp, strtoadd, amt);
1910  if (nused == 1) {
1911  /* Exact match. */
1912  if (qmode != 0) {
1913  /* Finish the quoting. */
1914  memmove(curposp + 1, curposp, lenaftercursor + 1 /* NUL */);
1915  curposp++;
1916  buf[amt + startoff] = (char) qmode;
1917  amt++;
1918  }
1919  memmove(curposp + 1, curposp, lenaftercursor + 1 /* NUL */);
1920  curposp++;
1921  buf[amt + startoff] = (char) gl_completion_exact_match_extra_char;
1922  amt++;
1923  } else if ((!wasateol) && (!isspace(*curposp))) {
1924  /* Not a full match, but insert a
1925  * space for better readability.
1926  */
1927  memmove(curposp + 1, curposp, lenaftercursor + 1 /* NUL */);
1928  curposp++;
1929  buf[amt + startoff] = ' ';
1930  }
1931  *loc = (int) (startoff + amt);
1932 
1933  if (strtoadd1 != NULL)
1934  free(strtoadd1);
1935  }
1936 
1937  /* Don't need this any more. */
1938  for (i=0; i<nused; i++)
1939  free(gl_matchlist[i]);
1940  free(gl_matchlist);
1941  gl_matchlist = NULL;
1942  free(matchpfx);
1943 
1944  return 0;
1945 } /* gl_do_tab_completion */
1946 
1947 
1948 
1949 
1950 void
1952 {
1953  if (proc == NULL)
1954  proc = gl_local_filename_completion_proc; /* default proc */
1956 } /* gl_tab_completion */
1957 
1958 
1959 
1960 
1961 #ifndef _StrFindLocalPathDelim
1962 static char *
1963 _StrRFindLocalPathDelim(const char *src) /* TODO: optimize */
1964 {
1965  const char *last;
1966  int c;
1967 
1968  last = NULL;
1969  for (;;) {
1970  c = *src++;
1971  if (c == '\0')
1972  break;
1973  if (IsLocalPathDelim(c))
1974  last = src - 1;
1975  }
1976 
1977  return ((char *) last);
1978 } /* StrRFindLocalPathDelim */
1979 #endif /* Windows */
1980 
1981 
1982 
1983 
1984 void
1985 gl_set_home_dir(const char *homedir)
1986 {
1987  size_t len;
1988 #ifdef __windows__
1989  const char *homedrive, *homepath;
1990  char wdir[64];
1991 #else
1992  struct passwd *pw;
1993  char *cp;
1994 #endif
1995 
1996  if (gl_home_dir != NULL) {
1997  free(gl_home_dir);
1998  gl_home_dir = NULL;
1999  }
2000 
2001  if (homedir == NULL) {
2002 #ifdef __windows__
2003  homedrive = getenv("HOMEDRIVE");
2004  homepath = getenv("HOMEPATH");
2005  if ((homedrive != NULL) && (homepath != NULL)) {
2006  len = strlen(homedrive) + strlen(homepath) + 1;
2007  gl_home_dir = (char *) malloc(len);
2008  if (gl_home_dir != NULL) {
2009  strcpy(gl_home_dir, homedrive);
2010  strcat(gl_home_dir, homepath);
2011  return;
2012  }
2013  }
2014 
2015  wdir[0] = '\0';
2016  if (GetWindowsDirectory(wdir, sizeof(wdir) - 1) < 1)
2017  (void) strncpy(wdir, ".", sizeof(wdir));
2018  else if (wdir[1] == ':') {
2019  wdir[2] = '\\';
2020  wdir[3] = '\0';
2021  }
2022  homedir = wdir;
2023 #else
2024  cp = (char *) getlogin();
2025  if (cp == NULL) {
2026  cp = (char *) getenv("LOGNAME");
2027  if (cp == NULL)
2028  cp = (char *) getenv("USER");
2029  }
2030  pw = NULL;
2031  if (cp != NULL)
2032  pw = getpwnam(cp);
2033  if (pw == NULL)
2034  pw = getpwuid(getuid());
2035  if (pw == NULL)
2036  return; /* hell with it */
2037  homedir = pw->pw_dir;
2038 #endif
2039  }
2040 
2041  len = strlen(homedir) + /* NUL */ 1;
2042  gl_home_dir = (char *) malloc(len);
2043  if (gl_home_dir != NULL) {
2044  memcpy(gl_home_dir, homedir, len);
2045  }
2046 } /* gl_set_home_dir */
2047 
2048 
2049 
2050 
2051 char *gl_getpass(const char *const prompt, char *const pass, int dsize)
2052 {
2053 #ifdef __unix__
2054  char *cp;
2055  int c;
2056 
2057  memset(pass, 0, (size_t) sizeof(dsize));
2058  dsize--;
2059  gl_init();
2060 
2061  /* Display the prompt first. */
2062  if ((prompt != NULL) && (prompt[0] != '\0'))
2063  gl_puts(prompt);
2064 
2065  cp = pass;
2066  while ((c = gl_getc()) != (-1)) {
2067  if ((c == '\r') || (c == '\n'))
2068  break;
2069  if ((c == '\010') || (c == '\177')) {
2070  /* ^H and DEL */
2071  if (cp > pass) {
2072  *--cp = '\0';
2073  gl_putc('\010');
2074  gl_putc(' ');
2075  gl_putc('\010');
2076  }
2077  } else if (cp < (pass + dsize)) {
2078  gl_putc('*');
2079  *cp++ = c;
2080  }
2081  }
2082  *cp = '\0';
2083  gl_putc('\n');
2084  gl_cleanup();
2085  return (pass);
2086 #else
2087 #ifdef __windows__
2088  char *cp;
2089  int c;
2090 
2092  ZeroMemory(pass, (DWORD) sizeof(dsize));
2093  dsize--;
2094 
2095  if ((prompt != NULL) && (prompt[0] != '\0'))
2096  _cputs(prompt);
2097 
2098  for (cp = pass;;) {
2099  c = (int) _getch();
2100  if ((c == '\r') || (c == '\n'))
2101  break;
2102  if ((c == '\010') || (c == '\177')) {
2103  /* ^H and DEL */
2104  if (cp > pass) {
2105  *--cp = '\0';
2106  _putch('\010');
2107  _putch(' ');
2108  _putch('\010');
2109  }
2110  } else if (cp < (pass + dsize)) {
2111  _putch('*');
2112  *cp++ = c;
2113  }
2114  }
2115  _putch('\r');
2116  _putch('\n');
2117  Sleep(40);
2119 
2120  *cp = '\0';
2121  return (pass);
2122 #endif /* __windows__ */
2123 #endif /* ! __unix__ */
2124 } /* gl_getpass */
2125 
2126 
2127 
2128 
2129 #ifdef __unix__
2130 
2131 char *
2133 {
2134  static DIR *dir = NULL;
2135  static int filepfxoffset;
2136  static size_t filepfxlen;
2137 
2138  const char *filepfx;
2139  struct dirent *dent;
2140  char *cp;
2141  const char *dirtoopen, *name;
2142  char *dirtoopen1;
2143  size_t len, len2;
2144  struct stat st;
2145 
2146  if (idx == 0) {
2147  if (dir != NULL) {
2148  /* shouldn't get here! */
2149  closedir(dir);
2150  dir = NULL;
2151  }
2152  }
2153 
2154  if (dir == NULL) {
2155  dirtoopen1 = NULL;
2157  if (cp == start) {
2158  dirtoopen = LOCAL_PATH_DELIM_STR; /* root dir */
2159  filepfxoffset = 1;
2160  } else if (cp == NULL) {
2161  dirtoopen = ".";
2162  filepfxoffset = 0;
2163  } else {
2164  len = strlen(start) + 1;
2165  dirtoopen1 = (char *) malloc(len);
2166  if (dirtoopen1 == NULL)
2167  return NULL;
2168  memcpy(dirtoopen1, start, len);
2169  len = (cp - start);
2170  dirtoopen1[len] = '\0';
2171  dirtoopen = dirtoopen1;
2172  filepfxoffset = (int) ((cp + 1) - start);
2173  }
2174 
2175  if (strcmp(dirtoopen, "~") == 0) {
2176  if (gl_home_dir == NULL)
2178  if (gl_home_dir == NULL)
2179  return (NULL);
2180  dirtoopen = gl_home_dir;
2181  }
2182 
2183  dir = opendir(dirtoopen);
2184  if (dirtoopen1 != NULL)
2185  free(dirtoopen1);
2186 
2187  filepfx = start + filepfxoffset;
2188  filepfxlen = strlen(filepfx);
2189  }
2190 
2191  if (dir != NULL) {
2192  /* assumes "start" is same for each iteration. */
2193  filepfx = start + filepfxoffset;
2194 
2195  for (;;) {
2196  dent = readdir(dir);
2197  if (dent == NULL) {
2198  /* no more items */
2199  closedir(dir);
2200  dir = NULL;
2201 
2202  if (idx == 1) {
2203  /* There was exactly one match.
2204  * In this special case, we
2205  * want to append a / instead
2206  * of a space.
2207  */
2208  cp = gl_matchlist[0];
2209  if ((cp[0] == '~') && ((cp[1] == '\0') || (IsLocalPathDelim(cp[1])))) {
2210  len = strlen(cp + 1) + /* NUL */ 1;
2211  len2 = strlen(gl_home_dir);
2212  if (IsLocalPathDelim(gl_home_dir[len2 - 1]))
2213  len2--;
2214  cp = (char *) realloc(gl_matchlist[0], len + len2);
2215  if (cp == NULL) {
2216  cp = gl_matchlist[0];
2217  } else {
2218  memmove(cp + len2, cp + 1, len);
2219  memcpy(cp, gl_home_dir, len2);
2220  gl_matchlist[0] = cp;
2221  }
2222  }
2223  if ((lstat(cp, &st) == 0) && (S_ISDIR(st.st_mode)))
2225  }
2226  return NULL;
2227  }
2228 
2229  name = dent->d_name;
2230  if ((name[0] == '.') && ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0'))))
2231  continue; /* Skip . and .. */
2232 
2233  if ((filepfxlen == 0) || (strncmp(name, filepfx, filepfxlen) == 0)) {
2234  /* match */
2235  len = strlen(name);
2236  cp = (char *) malloc(filepfxoffset + len + 1 /* spare */ + 1 /* NUL */);
2237  *cp = '\0';
2238  if (filepfxoffset > 0)
2239  memcpy(cp, start, (size_t) filepfxoffset);
2240  memcpy(cp + filepfxoffset, name, len + 1);
2241  return (cp);
2242  }
2243  }
2244  }
2245 
2246  return NULL;
2247 } /* gl_local_filename_completion_proc */
2248 
2249 #endif /* __unix__ */
2250 
2251 
2252 
2253 
2254 
2255 #ifdef __windows__
2256 
2257 char *
2259 {
2260  static HANDLE searchHandle = NULL;
2261  static int filepfxoffset;
2262  static size_t filepfxlen;
2263 
2264  WIN32_FIND_DATA ffd;
2265  DWORD dwErr;
2266  char *cp, *c2, ch;
2267  const char *filepfx;
2268  const char *dirtoopen, *name;
2269  char *dirtoopen1, *dirtoopen2;
2270  size_t len, len2;
2271 
2272  if (idx == 0) {
2273  if (searchHandle != NULL) {
2274  /* shouldn't get here! */
2275  FindClose(searchHandle);
2276  searchHandle = NULL;
2277  }
2278  }
2279 
2280 
2281  if (searchHandle == NULL) {
2282  dirtoopen1 = NULL;
2283  dirtoopen2 = NULL;
2285  if (cp == start) {
2286  dirtoopen = LOCAL_PATH_DELIM_STR; /* root dir */
2287  filepfxoffset = 1;
2288  } else if (cp == NULL) {
2289  dirtoopen = ".";
2290  filepfxoffset = 0;
2291  } else {
2292  len = strlen(start) + 1;
2293  dirtoopen1 = (char *) malloc(len);
2294  if (dirtoopen1 == NULL)
2295  return NULL;
2296  memcpy(dirtoopen1, start, len);
2297  len = (cp - start);
2298  dirtoopen1[len] = '\0';
2299  dirtoopen = dirtoopen1;
2300  filepfxoffset = (int) ((cp + 1) - start);
2301  }
2302 
2303  if (strcmp(dirtoopen, "~") == 0) {
2304  if (gl_home_dir == NULL)
2306  if (gl_home_dir == NULL)
2307  return (NULL);
2308  dirtoopen = gl_home_dir;
2309  }
2310 
2311  len = strlen(dirtoopen);
2312  dirtoopen2 = (char *) malloc(len + 8);
2313  if (dirtoopen2 == NULL) {
2314  if (dirtoopen1 != NULL)
2315  free(dirtoopen1);
2316  return NULL;
2317  }
2318 
2319  memcpy(dirtoopen2, dirtoopen, len + 1);
2320  if (dirtoopen2[len - 1] == LOCAL_PATH_DELIM)
2321  memcpy(dirtoopen2 + len, "*.*", (size_t) 4);
2322  else
2323  memcpy(dirtoopen2 + len, "\\*.*", (size_t) 5);
2324 
2325  /* "Open" the directory. */
2326  memset(&ffd, 0, sizeof(ffd));
2327  searchHandle = FindFirstFile(dirtoopen2, &ffd);
2328 
2329  free(dirtoopen2);
2330  if (dirtoopen1 != NULL)
2331  free(dirtoopen1);
2332 
2333  if (searchHandle == INVALID_HANDLE_VALUE) {
2334  return NULL;
2335  }
2336 
2337  filepfx = start + filepfxoffset;
2338  filepfxlen = strlen(filepfx);
2339  } else {
2340  /* assumes "start" is same for each iteration. */
2341  filepfx = start + filepfxoffset;
2342  goto next;
2343  }
2344 
2345  for (;;) {
2346 
2347  name = ffd.cFileName;
2348  if ((name[0] == '.') && ((name[1] == '\0') || ((name[1] == '.') && (name[2] == '\0'))))
2349  goto next; /* Skip . and .. */
2350 
2351  if ((filepfxlen == 0) || (_strnicmp(name, filepfx, filepfxlen) == 0)) {
2352  /* match */
2353  len = strlen(name);
2354  cp = (char *) malloc(filepfxoffset + len + 4 /* spare */ + 1 /* NUL */);
2355  *cp = '\0';
2356  if (filepfxoffset > 0)
2357  memcpy(cp, start, filepfxoffset);
2358  memcpy(cp + filepfxoffset, name, len + 1);
2359  if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
2360  /* Embed file type with name. */
2361  c2 = cp + filepfxoffset + len + 1;
2362  *c2++ = '\0';
2363  *c2++ = 'd';
2364  *c2 = '\0';
2365  } else {
2366  c2 = cp + filepfxoffset + len + 1;
2367  *c2++ = '\0';
2368  *c2++ = '-';
2369  *c2 = '\0';
2370  }
2371  return (cp);
2372  }
2373 
2374 next:
2375  if (!FindNextFile(searchHandle, &ffd)) {
2376  dwErr = GetLastError();
2377  if (dwErr != ERROR_NO_MORE_FILES) {
2378  FindClose(searchHandle);
2379  searchHandle = NULL;
2380  return NULL;
2381  }
2382 
2383  /* no more items */
2384  FindClose(searchHandle);
2385  searchHandle = NULL;
2386 
2387  if (idx == 1) {
2388  /* There was exactly one match.
2389  * In this special case, we
2390  * want to append a \ instead
2391  * of a space.
2392  */
2393  cp = gl_matchlist[0];
2394  ch = (char) cp[strlen(cp) + 2];
2395  if (ch == (char) 'd')
2397 
2398  if ((cp[0] == '~') && ((cp[1] == '\0') || (IsLocalPathDelim(cp[1])))) {
2399  len = strlen(cp + 1) + /* NUL */ 1;
2400  len2 = strlen(gl_home_dir);
2401  if (IsLocalPathDelim(gl_home_dir[len2 - 1]))
2402  len2--;
2403  cp = (char *) realloc(gl_matchlist[0], len + len2 + 4);
2404  if (cp == NULL) {
2405  cp = gl_matchlist[0];
2406  } else {
2407  memmove(cp + len2, cp + 1, len);
2408  memcpy(cp, gl_home_dir, len2);
2409  c2 = cp + len + len2;
2410  *c2++ = '\0';
2411  *c2++ = ch;
2412  *c2 = '\0';
2413  gl_matchlist[0] = cp;
2414  }
2415  }
2416  }
2417  break;
2418  }
2419  }
2420  return (NULL);
2421 } /* gl_local_filename_completion_proc */
2422 
2423 #endif /* __windows__ */
#define realloc
Definition: debug_ros.c:6
Definition: winsock.h:66
static int gl_termw
Definition: getline.c:95
#define GL_BUF_SIZE
Definition: getline.h:8
int pc_keymap(int c)
Definition: getline.c:245
static int gl_overwrite
Definition: getline.c:100
#define isspace(c)
Definition: acclib.h:69
#define memmove(s1, s2, n)
Definition: mkisofs.h:881
static long backup()
Definition: maze.c:403
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:736
GLubyte GLubyte GLubyte GLubyte w
Definition: glext.h:6102
struct png_info_def **typedef void(__cdecl typeof(png_destroy_read_struct))(struct png_struct_def **
Definition: typeof.h:49
void gl_setwidth(int w)
Definition: getline.c:532
static int gl_vi_mode
Definition: getline.c:112
char * gl_local_filename_completion_proc(const char *start, int idx)
Definition: getline.c:2258
static void gl_beep(void)
Definition: getline.c:1608
void gl_histadd(char *buf)
Definition: getline.c:1314
char * strcat(char *DstString, const char *SrcString)
Definition: utclib.c:568
#define strcasecmp
Definition: fake.h:9
static void gl_transpose(void)
Definition: getline.c:998
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
char * strpbrk(const char *String, const char *Delimiters)
Definition: utclib.c:302
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
POINT last
Definition: font.c:46
#define __windows__
Definition: getline.c:60
char * strstr(char *String1, char *String2)
Definition: utclib.c:653
#define GL_INTERRUPT
Definition: getline.h:13
gl_tab_hook_proc gl_tab_hook
Definition: getline.c:82
GLuint GLuint GLsizei count
Definition: gl.h:1545
char * strncpy(char *DstString, const char *SrcString, ACPI_SIZE Count)
Definition: utclib.c:427
static void search_back(int new_search)
Definition: getline.c:1540
#define free
Definition: debug_ros.c:5
#define IsLocalPathDelim(c)
Definition: getline.c:57
#define EINTR
Definition: acclib.h:80
static void gl_kill(int pos)
Definition: getline.c:1064
static void gl_del(int loc, int)
Definition: getline.c:1039
GLintptr offset
Definition: glext.h:5920
#define K_HOME
Definition: getline.c:240
static void gl_word(int direction)
Definition: getline.c:1114
static int gl_display_matches_sort_proc(const void *a, const void *b)
Definition: getline.c:1620
#define snprintf
Definition: wintirpc.h:48
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
BOOL WINAPI FlushConsoleInputBuffer(IN HANDLE hConsoleInput)
Definition: console.c:169
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
#define ZeroMemory
Definition: winbase.h:1635
static const char copyright[]
Definition: getline.c:21
static void gl_cleanup(void)
Definition: getline.c:466
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:152
_Check_return_ _CRTIMP int __cdecl _isatty(_In_ int _FileHandle)
char *(* gl_tab_completion_proc)(const char *, int)
Definition: getline.h:20
struct msdos_volume_info vi
Definition: mkdosfs.c:435
#define SIGQUIT
Definition: signal.h:24
#define lstat
Definition: getline.c:44
int gl_completion_exact_match_extra_char
Definition: getline.c:88
static char ** gl_matchlist
Definition: getline.c:109
static HANDLE proc()
Definition: pdb.c:32
#define SIGINT
Definition: signal.h:23
int errno
#define FD_ZERO(set)
Definition: winsock.h:96
GLenum GLuint GLsizei bufsize
Definition: glext.h:7473
_Check_return_ _CRTIMP int __cdecl isalnum(_In_ int _C)
void gl_setheight(int w)
Definition: getline.c:547
gl_out_hook_proc gl_out_hook
Definition: getline.c:81
#define FD_SET(fd, set)
Definition: winsock.h:89
static int gl_pos
Definition: getline.c:101
static int search_pos
Definition: getline.c:1465
Definition: fatfs.h:198
#define GL_EOF
Definition: getline.h:12
static const char * gl_prompt
Definition: getline.c:103
#define sprintf(buf, format,...)
Definition: sprintf.c:55
DIR *__cdecl opendir(const char *)
pass
Definition: typegen.h:24
void gl_tab_completion(gl_tab_completion_proc proc)
Definition: getline.c:1951
#define read
Definition: getline.c:40
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static int search_last
Definition: getline.c:1467
static int gl_tab(char *buf, int offset, int *loc, size_t bufsize)
Definition: getline.c:1275
_CRTIMP int __cdecl _kbhit(void)
Definition: kbhit.c:21
#define K_INSERT
Definition: getline.c:239
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
INT WSAAPI select(IN INT s, IN OUT LPFD_SET readfds, IN OUT LPFD_SET writefds, IN OUT LPFD_SET exceptfds, IN CONST struct timeval *timeout)
Definition: select.c:41
#define ioctl
Definition: wintirpc.h:60
void __cdecl qsort(_Inout_updates_bytes_(_NumOfElements *_SizeOfElements) void *_Base, _In_ size_t _NumOfElements, _In_ size_t _SizeOfElements, _In_ int(__cdecl *_PtFuncCompare)(const void *, const void *))
static int gl_termh
Definition: getline.c:96
static char search_prompt[101]
Definition: getline.c:1463
_Check_return_ _CRTIMP int __cdecl _strnicmp(_In_reads_or_z_(_MaxCount) const char *_Str1, _In_reads_or_z_(_MaxCount) const char *_Str2, _In_ size_t _MaxCount)
unsigned int idx
Definition: utils.c:41
char * gl_getpass(const char *const prompt, char *const pass, int dsize)
Definition: getline.c:2051
static void gl_putc(int c)
Definition: getline.c:403
Definition: dirent.h:39
static char gl_intrc
Definition: getline.c:104
smooth NULL
Definition: ftsmooth.c:416
unsigned char
Definition: typeof.h:29
static char * hist_save(char *p)
Definition: getline.c:1381
char gl_buf[GL_BUF_SIZE]
Definition: getline.c:89
static void gl_error(const char *const buf)
Definition: getline.c:428
Definition: parser.c:48
#define HIST_SIZE
Definition: getline.c:1296
int __cdecl _cputs(const char *)
Definition: cputs.c:8
unsigned int dir
Definition: maze.c:112
static void hist_init(void)
Definition: getline.c:1304
#define FindFirstFile
Definition: winbase.h:3596
#define STD_INPUT_HANDLE
Definition: winbase.h:264
#define isdigit(c)
Definition: acclib.h:68
static void gl_display_matches(int nused)
Definition: getline.c:1631
#define ERROR_NO_MORE_FILES
Definition: winerror.h:121
#define write
Definition: getline.c:39
static void search_forw(int new_search)
Definition: getline.c:1574
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint GLint GLint j
Definition: glfuncs.h:250
#define FILE_ATTRIBUTE_DIRECTORY
Definition: nt_native.h:705
size_t gl_strlen(const char *s)
Definition: getline.c:83
r l[0]
Definition: byte_order.h:167
char * d_name
Definition: dirent.h:29
DWORD dwErr
Definition: service.c:36
int(* gl_tab_hook_proc)(char *, int, int *, size_t)
Definition: getline.h:18
__kernel_size_t size_t
Definition: linux.h:237
static int search_forw_flg
Definition: getline.c:1466
static void pad(Char *s)
Definition: bzip2.c:908
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
DWORD WINAPI SleepEx(IN DWORD dwMilliseconds, IN BOOL bAlertable)
Definition: synch.c:748
static char * _StrRFindLocalPathDelim(const char *src)
Definition: getline.c:1963
#define S_ISDIR(m)
Definition: getline.c:35
Definition: id3.c:18
static int gl_do_tab_completion(char *buf, int *loc, size_t bufsize, int tabtab)
Definition: getline.c:1731
#define FindNextFile
Definition: winbase.h:3602
static void gl_fixup(const char *prompt, int change, int cursor)
Definition: getline.c:1149
const GLubyte * c
Definition: glext.h:8905
static int hist_pos
Definition: getline.c:1299
int strncmp(const char *String1, const char *String2, ACPI_SIZE Count)
Definition: utclib.c:534
gl_in_hook_proc gl_in_hook
Definition: getline.c:80
static void gl_redraw(void)
Definition: getline.c:1139
unsigned long DWORD
Definition: ntddk_ex.h:95
GLint left
Definition: glext.h:7726
static char * hist_prev(void)
Definition: getline.c:1346
char * getline(char *prompt)
Definition: getline.c:560
static int gl_cnt
Definition: getline.c:101
#define GL_OK
Definition: getline.h:11
GLdouble GLdouble right
Definition: glext.h:10859
#define LOCAL_PATH_DELIM_STR
Definition: getline.c:55
static void search_term(void)
Definition: getline.c:1529
char * getlogin(void)
static char gl_killbuf[GL_BUF_SIZE]
Definition: getline.c:102
static int hist_last
Definition: getline.c:1299
#define K_LEFT
Definition: getline.c:236
#define ECHO
Definition: macro.lex.yy.c:616
int(* gl_out_hook_proc)(char *)
Definition: getline.h:17
static char search_string[100]
Definition: getline.c:1464
static const WCHAR L[]
Definition: oid.c:1250
static int gl_vi_preferred
Definition: getline.c:111
int gl_get_result(void)
Definition: getline.c:224
static int gl_getc(void)
Definition: getline.c:282
Definition: stat.h:55
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
#define K_RIGHT
Definition: getline.c:237
GLenum GLsizei len
Definition: glext.h:6722
GLdouble s
Definition: gl.h:2039
static void gl_puts(const char *const buf)
Definition: getline.c:417
#define K_DELETE
Definition: getline.c:238
_Check_return_opt_ _CRTIMP int __cdecl fclose(_Inout_ FILE *_File)
_Check_return_ _CRTIMP FILE *__cdecl fopen(_In_z_ const char *_Filename, _In_z_ const char *_Mode)
GLenum src
Definition: glext.h:6340
static int gl_search_mode
Definition: getline.c:108
int __cdecl closedir(DIR *)
int gl_filename_quoting_desired
Definition: getline.c:85
struct dirent *__cdecl readdir(DIR *)
static int gl_width
Definition: getline.c:98
static int gl_getcx(int)
Definition: getline.c:374
BOOL WINAPI MessageBeep(_In_ UINT)
static void gl_char_cleanup(void)
Definition: getline.c:208
_Check_return_opt_ _CRTIMP char *__cdecl fgets(_Out_writes_z_(_MaxCount) char *_Buf, _In_ int _MaxCount, _Inout_ FILE *_File)
_CRTIMP int __cdecl _putch(_In_ int _Ch)
static void search_addchar(int c)
Definition: getline.c:1501
#define K_DOWN
Definition: getline.c:235
static void gl_init(void)
Definition: getline.c:438
static int gl_init_done
Definition: getline.c:94
static unsigned __int64 next
Definition: rand_nt.c:6
_Check_return_ char *__cdecl getenv(_In_z_ const char *_VarName)
const char cursor[]
Definition: icontest.c:13
GLuint start
Definition: gl.h:1545
static void gl_newline(void)
Definition: getline.c:1014
static void gl_yank(void)
Definition: getline.c:967
Definition: services.c:325
#define LOCAL_PATH_DELIM
Definition: getline.c:54
#define K_UP
Definition: getline.c:234
static char * hist_next(void)
Definition: getline.c:1364
#define GL_COMPLETE_VECTOR_BLOCK_SIZE
uid_t getuid()
Definition: uid.c:27
#define MB_OK
Definition: winuser.h:784
static void gl_check_inputrc_for_vi(void)
Definition: getline.c:480
char * strchr(const char *String, int ch)
Definition: utclib.c:501
static void gl_addchar(int c)
Definition: getline.c:946
void gl_set_home_dir(const char *homedir)
Definition: getline.c:1985
#define isprint(c)
Definition: acclib.h:73
static char hist_empty_elem[2]
Definition: getline.c:1301
_Check_return_ int __cdecl atoi(_In_z_ const char *_Str)
int gl_ellipses_during_completion
Definition: getline.c:87
POINT cp
Definition: magnifier.c:59
Definition: name.c:36
char * strcpy(char *DstString, const char *SrcString)
Definition: utclib.c:388
#define c
Definition: ke_i.h:80
static char * hist_buf[HIST_SIZE]
Definition: getline.c:1300
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
static char gl_quitc
Definition: getline.c:105
#define ETIMEDOUT
Definition: errno.h:121
#define malloc
Definition: debug_ros.c:4
#define K_END
Definition: getline.c:241
void gl_histloadfile(const char *const path)
Definition: getline.c:1437
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
void exit(int exitcode)
Definition: _exit.c:33
GLfloat GLfloat p
Definition: glext.h:8902
static int gl_result
Definition: getline.c:113
#define ss
Definition: i386-dis.c:432
int _getch()
Definition: getch.c:16
const char * gl_filename_quote_characters
Definition: getline.c:86
static void gl_char_init(void)
Definition: getline.c:157
GLuint64EXT * result
Definition: glext.h:11304
#define memset(x, y, z)
Definition: compat.h:39
static int gl_scroll
Definition: getline.c:97
#define GetWindowsDirectory
Definition: winbase.h:3671
static int gl_extent
Definition: getline.c:99
#define RAW(x)
Definition: genincdata.c:42
int k
Definition: mpi.c:3369
static char * gl_home_dir
Definition: getline.c:110
#define K_PGUP
Definition: getline.c:242
gl_tab_completion_proc gl_completion_proc
Definition: getline.c:84
void gl_histsavefile(const char *const path)
Definition: getline.c:1408
int(* gl_in_hook_proc)(char *)
Definition: getline.h:16
static void gl_killword(int direction)
Definition: getline.c:1077
#define K_PGDN
Definition: getline.c:243
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
BOOL WINAPI FindClose(HANDLE hFindFile)
Definition: find.c:502
static void search_update(int c)
Definition: getline.c:1470
GLuint const GLchar * name
Definition: glext.h:6031