MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
el.c
1 /* $NetBSD: el.c,v 1.68 2011/07/29 15:16:33 christos Exp $ */
2 
3 /*-
4  * Copyright (c) 1992, 1993
5  * The Regents of the University of California. All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Christos Zoulas of Cornell University.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in the
17  * documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  * may be used to endorse or promote products derived from this software
20  * without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include "config.h"
36 #if !defined(lint) && !defined(SCCSID)
37 #if 0
38 static char sccsid[] = "@(#)el.c 8.2 (Berkeley) 1/3/94";
39 #else
40 #endif
41 #endif /* not lint && not SCCSID */
42 
43 /*
44  * el.c: EditLine interface functions
45  */
46 #include <sys/types.h>
47 #include <sys/param.h>
48 #include <string.h>
49 #include <stdlib.h>
50 #include <stdarg.h>
51 #include <ctype.h>
52 #include <locale.h>
53 #include <langinfo.h>
54 #include "el.h"
55 
56 /* el_init():
57  * Initialize editline and set default parameters.
58  */
59 public EditLine *
60 el_init(const char *prog, FILE *fin, FILE *fout, FILE *ferr)
61 {
62  EditLine *el = el_malloc(sizeof(*el));
63 
64  if (el == NULL)
65  return NULL;
66 
67  memset(el, 0, sizeof(EditLine));
68 
69  el->el_infile = fin;
70  el->el_outfile = fout;
71  el->el_errfile = ferr;
72 
73  el->el_infd = fileno(fin);
74  el->el_outfd = fileno(fout);
75  el->el_errfd = fileno(ferr);
76 
77  el->el_prog = Strdup(ct_decode_string(prog, &el->el_scratch));
78  if (el->el_prog == NULL) {
79  el_free(el);
80  return NULL;
81  }
82 
83  /*
84  * Initialize all the modules. Order is important!!!
85  */
86  el->el_flags = 0;
87 #ifdef WIDECHAR
88  setlocale(LC_CTYPE, NULL);
89  if (MB_CUR_MAX > 1)
90  el->el_flags |= CHARSET_IS_MULTIBYTE;
91 #endif
92 
93  if (terminal_init(el) == -1) {
94  el_free(el->el_prog);
95  el_free(el);
96  return NULL;
97  }
98  (void) keymacro_init(el);
99  (void) map_init(el);
100  if (tty_init(el) == -1)
101  el->el_flags |= NO_TTY;
102  (void) ch_init(el);
103  (void) search_init(el);
104  (void) hist_init(el);
105  (void) prompt_init(el);
106  (void) sig_init(el);
107  (void) read_init(el);
108 
109  return el;
110 }
111 
112 
113 /* el_end():
114  * Clean up.
115  */
116 public void
117 el_end(EditLine *el)
118 {
119 
120  if (el == NULL)
121  return;
122 
123  el_reset(el);
124 
125  terminal_end(el);
126  keymacro_end(el);
127  map_end(el);
128  tty_end(el);
129  ch_end(el);
130  search_end(el);
131  hist_end(el);
132  prompt_end(el);
133  sig_end(el);
134 
135  el_free(el->el_prog);
136 #ifdef WIDECHAR
137  el_free(el->el_scratch.cbuff);
138  el_free(el->el_scratch.wbuff);
139  el_free(el->el_lgcyconv.cbuff);
140  el_free(el->el_lgcyconv.wbuff);
141 #endif
142  el_free(el);
143 }
144 
145 
146 /* el_reset():
147  * Reset the tty and the parser
148  */
149 public void
150 el_reset(EditLine *el)
151 {
152 
153  tty_cookedmode(el);
154  ch_reset(el, 0); /* XXX: Do we want that? */
155 }
156 
157 
158 /* el_set():
159  * set the editline parameters
160  */
161 public int
162 FUN(el,set)(EditLine *el, int op, ...)
163 {
164  va_list ap;
165  int rv = 0;
166 
167  if (el == NULL)
168  return -1;
169  va_start(ap, op);
170 
171  switch (op) {
172  case EL_PROMPT:
173  case EL_RPROMPT: {
174  el_pfunc_t p = va_arg(ap, el_pfunc_t);
175 
176  rv = prompt_set(el, p, 0, op, 1);
177  break;
178  }
179 
180  case EL_RESIZE: {
181  el_zfunc_t p = va_arg(ap, el_zfunc_t);
182  void *arg = va_arg(ap, void *);
183  rv = ch_resizefun(el, p, arg);
184  break;
185  }
186 
187  case EL_PROMPT_ESC:
188  case EL_RPROMPT_ESC: {
189  el_pfunc_t p = va_arg(ap, el_pfunc_t);
190  int c = va_arg(ap, int);
191 
192  rv = prompt_set(el, p, c, op, 1);
193  break;
194  }
195 
196  case EL_TERMINAL:
197  rv = terminal_set(el, va_arg(ap, char *));
198  break;
199 
200  case EL_EDITOR:
201  rv = map_set_editor(el, va_arg(ap, Char *));
202  break;
203 
204  case EL_SIGNAL:
205  if (va_arg(ap, int))
206  el->el_flags |= HANDLE_SIGNALS;
207  else
208  el->el_flags &= ~HANDLE_SIGNALS;
209  break;
210 
211  case EL_BIND:
212  case EL_TELLTC:
213  case EL_SETTC:
214  case EL_ECHOTC:
215  case EL_SETTY:
216  {
217  const Char *argv[20];
218  int i;
219 
220  for (i = 1; i < 20; i++)
221  if ((argv[i] = va_arg(ap, Char *)) == NULL)
222  break;
223 
224  switch (op) {
225  case EL_BIND:
226  argv[0] = STR("bind");
227  rv = map_bind(el, i, argv);
228  break;
229 
230  case EL_TELLTC:
231  argv[0] = STR("telltc");
232  rv = terminal_telltc(el, i, argv);
233  break;
234 
235  case EL_SETTC:
236  argv[0] = STR("settc");
237  rv = terminal_settc(el, i, argv);
238  break;
239 
240  case EL_ECHOTC:
241  argv[0] = STR("echotc");
242  rv = terminal_echotc(el, i, argv);
243  break;
244 
245  case EL_SETTY:
246  argv[0] = STR("setty");
247  rv = tty_stty(el, i, argv);
248  break;
249 
250  default:
251  rv = -1;
252  EL_ABORT((el->el_errfile, "Bad op %d\n", op));
253  break;
254  }
255  break;
256  }
257 
258  case EL_ADDFN:
259  {
260  Char *name = va_arg(ap, Char *);
261  Char *help = va_arg(ap, Char *);
262  el_func_t func = va_arg(ap, el_func_t);
263 
264  rv = map_addfunc(el, name, help, func);
265  break;
266  }
267 
268  case EL_HIST:
269  {
270  hist_fun_t func = va_arg(ap, hist_fun_t);
271  void *ptr = va_arg(ap, void *);
272 
273  rv = hist_set(el, func, ptr);
274  if (!(el->el_flags & CHARSET_IS_MULTIBYTE))
275  el->el_flags &= ~NARROW_HISTORY;
276  break;
277  }
278 
279  case EL_EDITMODE:
280  if (va_arg(ap, int))
281  el->el_flags &= ~EDIT_DISABLED;
282  else
283  el->el_flags |= EDIT_DISABLED;
284  rv = 0;
285  break;
286 
287  case EL_GETCFN:
288  {
289  el_rfunc_t rc = va_arg(ap, el_rfunc_t);
290  rv = el_read_setfn(el, rc);
291  el->el_flags &= ~NARROW_READ;
292  break;
293  }
294 
295  case EL_CLIENTDATA:
296  el->el_data = va_arg(ap, void *);
297  break;
298 
299  case EL_UNBUFFERED:
300  rv = va_arg(ap, int);
301  if (rv && !(el->el_flags & UNBUFFERED)) {
302  el->el_flags |= UNBUFFERED;
303  read_prepare(el);
304  } else if (!rv && (el->el_flags & UNBUFFERED)) {
305  el->el_flags &= ~UNBUFFERED;
306  read_finish(el);
307  }
308  rv = 0;
309  break;
310 
311  case EL_PREP_TERM:
312  rv = va_arg(ap, int);
313  if (rv)
314  (void) tty_rawmode(el);
315  else
316  (void) tty_cookedmode(el);
317  rv = 0;
318  break;
319 
320  case EL_SETFP:
321  {
322  FILE *fp;
323  int what;
324 
325  what = va_arg(ap, int);
326  fp = va_arg(ap, FILE *);
327 
328  rv = 0;
329  switch (what) {
330  case 0:
331  el->el_infile = fp;
332  el->el_infd = fileno(fp);
333  break;
334  case 1:
335  el->el_outfile = fp;
336  el->el_outfd = fileno(fp);
337  break;
338  case 2:
339  el->el_errfile = fp;
340  el->el_errfd = fileno(fp);
341  break;
342  default:
343  rv = -1;
344  break;
345  }
346  break;
347  }
348 
349  case EL_REFRESH:
350  re_clear_display(el);
351  re_refresh(el);
352  terminal__flush(el);
353  break;
354 
355  default:
356  rv = -1;
357  break;
358  }
359 
360  va_end(ap);
361  return rv;
362 }
363 
364 
365 /* el_get():
366  * retrieve the editline parameters
367  */
368 public int
369 FUN(el,get)(EditLine *el, int op, ...)
370 {
371  va_list ap;
372  int rv;
373 
374  if (el == NULL)
375  return -1;
376 
377  va_start(ap, op);
378 
379  switch (op) {
380  case EL_PROMPT:
381  case EL_RPROMPT: {
382  el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
383  rv = prompt_get(el, p, 0, op);
384  break;
385  }
386  case EL_PROMPT_ESC:
387  case EL_RPROMPT_ESC: {
388  el_pfunc_t *p = va_arg(ap, el_pfunc_t *);
389  Char *c = va_arg(ap, Char *);
390 
391  rv = prompt_get(el, p, c, op);
392  break;
393  }
394 
395  case EL_EDITOR:
396  rv = map_get_editor(el, va_arg(ap, const Char **));
397  break;
398 
399  case EL_SIGNAL:
400  *va_arg(ap, int *) = (el->el_flags & HANDLE_SIGNALS);
401  rv = 0;
402  break;
403 
404  case EL_EDITMODE:
405  *va_arg(ap, int *) = !(el->el_flags & EDIT_DISABLED);
406  rv = 0;
407  break;
408 
409  case EL_TERMINAL:
410  terminal_get(el, va_arg(ap, const char **));
411  rv = 0;
412  break;
413 
414  case EL_GETTC:
415  {
416  static char name[] = "gettc";
417  char *argv[20];
418  int i;
419 
420  for (i = 1; i < (int)(sizeof(argv) / sizeof(argv[0])); i++)
421  if ((argv[i] = va_arg(ap, char *)) == NULL)
422  break;
423 
424  switch (op) {
425  case EL_GETTC:
426  argv[0] = name;
427  rv = terminal_gettc(el, i, argv);
428  break;
429 
430  default:
431  rv = -1;
432  EL_ABORT((el->el_errfile, "Bad op %d\n", op));
433  break;
434  }
435  break;
436  }
437 
438  case EL_GETCFN:
439  *va_arg(ap, el_rfunc_t *) = el_read_getfn(el);
440  rv = 0;
441  break;
442 
443  case EL_CLIENTDATA:
444  *va_arg(ap, void **) = el->el_data;
445  rv = 0;
446  break;
447 
448  case EL_UNBUFFERED:
449  *va_arg(ap, int *) = (!(el->el_flags & UNBUFFERED));
450  rv = 0;
451  break;
452 
453  case EL_GETFP:
454  {
455  int what;
456  FILE **fpp;
457 
458  what = va_arg(ap, int);
459  fpp = va_arg(ap, FILE **);
460  rv = 0;
461  switch (what) {
462  case 0:
463  *fpp = el->el_infile;
464  break;
465  case 1:
466  *fpp = el->el_outfile;
467  break;
468  case 2:
469  *fpp = el->el_errfile;
470  break;
471  default:
472  rv = -1;
473  break;
474  }
475  break;
476  }
477  default:
478  rv = -1;
479  break;
480  }
481  va_end(ap);
482 
483  return rv;
484 }
485 
486 
487 /* el_line():
488  * Return editing info
489  */
490 public const TYPE(LineInfo) *
491 FUN(el,line)(EditLine *el)
492 {
493 
494  return (const TYPE(LineInfo) *)(void *)&el->el_line;
495 }
496 
497 
498 /* el_source():
499  * Source a file
500  */
501 public int
502 el_source(EditLine *el, const char *fname)
503 {
504  FILE *fp;
505  size_t len;
506  char *ptr;
507  char *path = NULL;
508  const Char *dptr;
509  int error = 0;
510 
511  fp = NULL;
512  if (fname == NULL) {
513 /* XXXMYSQL: Bug#49967 */
514 #if defined(HAVE_GETUID) && defined(HAVE_GETEUID) && \
515  defined(HAVE_GETGID) && defined(HAVE_GETEGID)
516 #define HAVE_IDENTITY_FUNCS 1
517 #endif
518 
519 #if (defined(HAVE_ISSETUGID) || defined(HAVE_IDENTITY_FUNCS))
520  static const char elpath[] = "/.editrc";
521  size_t plen = sizeof(elpath);
522 /* XXXMYSQL: Portability fix (for which platforms?) */
523 #ifdef HAVE_ISSETUGID
524  if (issetugid())
525  return -1;
526 #elif defined(HAVE_IDENTITY_FUNCS)
527  if (getuid() != geteuid() || getgid() != getegid())
528  return (-1);
529 #endif
530  if ((ptr = getenv("HOME")) == NULL)
531  return -1;
532  plen += strlen(ptr);
533  if ((path = el_malloc(plen * sizeof(*path))) == NULL)
534  return -1;
535  (void)snprintf(path, plen, "%s%s", ptr, elpath);
536  fname = path;
537 #else
538  /*
539  * If issetugid() or the above mentioned get[e][u|g]id()
540  * functions are missing, always return an error, in order
541  * to keep from inadvertently opening up the user to a
542  * security hole.
543  */
544  return -1;
545 #endif
546  }
547  if (fp == NULL)
548  fp = fopen(fname, "r");
549  if (fp == NULL) {
550  el_free(path);
551  return -1;
552  }
553 
554  while ((ptr = fgetln(fp, &len)) != NULL) {
555  if (*ptr == '\n')
556  continue; /* Empty line. */
557  dptr = ct_decode_string(ptr, &el->el_scratch);
558  if (!dptr)
559  continue;
560  if (len > 0 && dptr[len - 1] == '\n')
561  --len;
562 
563  /* loop until first non-space char or EOL */
564  while (*dptr != '\0' && Isspace(*dptr))
565  dptr++;
566  if (*dptr == '#')
567  continue; /* ignore, this is a comment line */
568  if ((error = parse_line(el, dptr)) == -1)
569  break;
570  }
571 
572  el_free(path);
573  (void) fclose(fp);
574  return error;
575 }
576 
577 
578 /* el_resize():
579  * Called from program when terminal is resized
580  */
581 public void
582 el_resize(EditLine *el)
583 {
584  int lins, cols;
585  sigset_t oset, nset;
586 
587  (void) sigemptyset(&nset);
588  (void) sigaddset(&nset, SIGWINCH);
589  (void) sigprocmask(SIG_BLOCK, &nset, &oset);
590 
591  /* get the correct window size */
592  if (terminal_get_size(el, &lins, &cols))
593  terminal_change_size(el, lins, cols);
594 
595  (void) sigprocmask(SIG_SETMASK, &oset, NULL);
596 }
597 
598 
599 /* el_beep():
600  * Called from the program to beep
601  */
602 public void
603 el_beep(EditLine *el)
604 {
605 
606  terminal_beep(el);
607 }
608 
609 
610 /* el_editmode()
611  * Set the state of EDIT_DISABLED from the `edit' command.
612  */
613 protected int
614 /*ARGSUSED*/
615 el_editmode(EditLine *el, int argc, const Char **argv)
616 {
617  const Char *how;
618 
619  if (argv == NULL || argc != 2 || argv[1] == NULL)
620  return -1;
621 
622  how = argv[1];
623  if (Strcmp(how, STR("on")) == 0) {
624  el->el_flags &= ~EDIT_DISABLED;
625  tty_rawmode(el);
626  } else if (Strcmp(how, STR("off")) == 0) {
627  tty_cookedmode(el);
628  el->el_flags |= EDIT_DISABLED;
629  }
630  else {
631  (void) fprintf(el->el_errfile, "edit: Bad value `" FSTR "'.\n",
632  how);
633  return -1;
634  }
635  return 0;
636 }