OpenCores
URL https://opencores.org/ocsvn/eco32/eco32/trunk

Subversion Repositories eco32

[/] [eco32/] [trunk/] [sim/] [getline/] [getline.c] - Blame information for rev 8

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 8 hellwig
#ifndef lint
2
static char     rcsid[] =
3
"$Id: getline.c,v 3.11 1993/12/02 15:54:31 thewalt Exp thewalt $";
4
static char    *copyright = "Copyright (C) 1991, 1992, 1993, Chris Thewalt";
5
#endif
6
 
7
/*
8
 * Copyright (C) 1991, 1992, 1993 by Chris Thewalt (thewalt@ce.berkeley.edu)
9
 *
10
 * Permission to use, copy, modify, and distribute this software
11
 * for any purpose and without fee is hereby granted, provided
12
 * that the above copyright notices appear in all copies and that both the
13
 * copyright notice and this permission notice appear in supporting
14
 * documentation.  This software is provided "as is" without express or
15
 * implied warranty.
16
 *
17
 * Thanks to the following people who have provided enhancements and fixes:
18
 *   Ron Ueberschaer, Christoph Keller, Scott Schwartz, Steven List,
19
 *   DaviD W. Sanderson, Goran Bostrom, Michael Gleason, Glenn Kasten,
20
 *   Edin Hodzic, Eric J Bivona, Kai Uwe Rommel, Danny Quah, Ulrich Betzler
21
 */
22
 
23
#include       "getline.h"
24
static int      gl_tab();  /* forward reference needed for gl_tab_hook */
25
 
26
/******************** imported interface *********************************/
27
 
28
#include <string.h>
29
#include <ctype.h>
30
#include <errno.h>
31
#include <signal.h>
32
 
33
extern int      isatty();
34
extern void    *malloc();
35
extern void     free();
36
 
37
/********************* exported interface ********************************/
38
 
39
char           *gl_getline();           /* read a line of input */
40
void            gl_setwidth();          /* specify width of screen */
41
void            gl_histadd();           /* adds entries to hist */
42
void            gl_strwidth();          /* to bind gl_strlen */
43
 
44
int             (*gl_in_hook)() = 0;
45
int             (*gl_out_hook)() = 0;
46
int             (*gl_tab_hook)() = gl_tab;
47
 
48
/******************** internal interface *********************************/
49
 
50
#define BUF_SIZE 1024
51
 
52
static int      gl_init_done = -1;      /* terminal mode flag  */
53
static int      gl_termw = 80;          /* actual terminal width */
54
static int      gl_scroll = 27;         /* width of EOL scrolling region */
55
static int      gl_width = 0;            /* net size available for input */
56
static int      gl_extent = 0;           /* how far to redraw, 0 means all */
57
static int      gl_overwrite = 0;        /* overwrite mode */
58
static int      gl_pos, gl_cnt = 0;     /* position and size of input */
59
static char     gl_buf[BUF_SIZE];       /* input buffer */
60
static char     gl_killbuf[BUF_SIZE]=""; /* killed text */
61
static char    *gl_prompt;              /* to save the prompt string */
62
static char     gl_intrc = 0;            /* keyboard SIGINT char */
63
static char     gl_quitc = 0;            /* keyboard SIGQUIT char */
64
static char     gl_suspc = 0;            /* keyboard SIGTSTP char */
65
static char     gl_dsuspc = 0;           /* delayed SIGTSTP char */
66
static int      gl_search_mode = 0;      /* search mode flag */
67
 
68
static void     gl_init();              /* prepare to edit a line */
69
static void     gl_cleanup();           /* to undo gl_init */
70
static void     gl_char_init();         /* get ready for no echo input */
71
static void     gl_char_cleanup();      /* undo gl_char_init */
72
static size_t   (*gl_strlen)() = (size_t(*)())strlen;
73
                                        /* returns printable prompt width */
74
 
75
static void     gl_addchar();           /* install specified char */
76
static void     gl_del();               /* del, either left (-1) or cur (0) */
77
static void     gl_error();             /* write error msg and die */
78
static void     gl_fixup();             /* fixup state variables and screen */
79
static int      gl_getc();              /* read one char from terminal */
80
static void     gl_kill();              /* delete to EOL */
81
static void     gl_newline();           /* handle \n or \r */
82
static void     gl_putc();              /* write one char to terminal */
83
static void     gl_puts();              /* write a line to terminal */
84
static void     gl_redraw();            /* issue \n and redraw all */
85
static void     gl_transpose();         /* transpose two chars */
86
static void     gl_yank();              /* yank killed text */
87
static void     gl_word();              /* move a word */
88
 
89
static void     hist_init();    /* initializes hist pointers */
90
static char    *hist_next();    /* return ptr to next item */
91
static char    *hist_prev();    /* return ptr to prev item */
92
static char    *hist_save();    /* makes copy of a string, without NL */
93
 
94
static void     search_addchar();       /* increment search string */
95
static void     search_term();          /* reset with current contents */
96
static void     search_back();          /* look back for current string */
97
static void     search_forw();          /* look forw for current string */
98
 
99
/************************ nonportable part *********************************/
100
 
101
extern int      write();
102
extern void     exit();
103
 
104
#ifdef unix
105
#ifndef __unix__
106
#define __unix__
107
#endif /* not __unix__ */
108
#endif /* unix */
109
 
110
#ifdef _IBMR2
111
#ifndef __unix__
112
#define __unix__
113
#endif
114
#endif
115
 
116
#ifdef __GO32__
117
#include <pc.h>
118
#undef MSDOS
119
#undef __unix__
120
#endif
121
 
122
#ifdef MSDOS
123
#include <bios.h>
124
#endif
125
 
126
#ifdef __unix__
127
#ifndef __convexc__
128
extern int      read();
129
extern int      kill();
130
extern int      ioctl();
131
#endif /* not __convexc__ */
132
#ifdef POSIX            /* use POSIX interface */
133
#include <termios.h>
134
struct termios  new_termios, old_termios;
135
#else /* not POSIX */
136
#include <sys/ioctl.h>
137
#ifdef M_XENIX  /* does not really use bsd terminal interface */
138
#undef TIOCSETN
139
#endif /* M_XENIX */
140
#ifdef TIOCSETN         /* use BSD interface */
141
#include <sgtty.h>
142
struct sgttyb   new_tty, old_tty;
143
struct tchars   tch;
144
struct ltchars  ltch;
145
#else                   /* use SYSV interface */
146
#include <termio.h>
147
struct termio   new_termio, old_termio;
148
#endif /* TIOCSETN */
149
#endif /* POSIX */
150
#endif  /* __unix__ */
151
 
152
#ifdef vms
153
#include <descrip.h>
154
#include <ttdef.h>
155
#include <iodef.h>
156
#include unixio
157
 
158
static int   setbuff[2];             /* buffer to set terminal attributes */
159
static short chan = -1;              /* channel to terminal */
160
struct dsc$descriptor_s descrip;     /* VMS descriptor */
161
#endif
162
 
163
static void
164
gl_char_init()                  /* turn off input echo */
165
{
166
#ifdef __unix__
167
#ifdef POSIX
168
    tcgetattr(0, &old_termios);
169
    gl_intrc = old_termios.c_cc[VINTR];
170
    gl_quitc = old_termios.c_cc[VQUIT];
171
#ifdef VSUSP
172
    gl_suspc = old_termios.c_cc[VSUSP];
173
#endif
174
#ifdef VDSUSP
175
    gl_dsuspc = old_termios.c_cc[VDSUSP];
176
#endif
177
    new_termios = old_termios;
178
    new_termios.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
179
    new_termios.c_iflag |= (IGNBRK|IGNPAR);
180
    new_termios.c_lflag &= ~(ICANON|ISIG|IEXTEN|ECHO);
181
    new_termios.c_cc[VMIN] = 1;
182
    new_termios.c_cc[VTIME] = 0;
183
    tcsetattr(0, TCSANOW, &new_termios);
184
#else                           /* not POSIX */
185
#ifdef TIOCSETN                 /* BSD */
186
    ioctl(0, TIOCGETC, &tch);
187
    ioctl(0, TIOCGLTC, &ltch);
188
    gl_intrc = tch.t_intrc;
189
    gl_quitc = tch.t_quitc;
190
    gl_suspc = ltch.t_suspc;
191
    gl_dsuspc = ltch.t_dsuspc;
192
    ioctl(0, TIOCGETP, &old_tty);
193
    new_tty = old_tty;
194
    new_tty.sg_flags |= RAW;
195
    new_tty.sg_flags &= ~ECHO;
196
    ioctl(0, TIOCSETN, &new_tty);
197
#else                           /* SYSV */
198
    ioctl(0, TCGETA, &old_termio);
199
    gl_intrc = old_termio.c_cc[VINTR];
200
    gl_quitc = old_termio.c_cc[VQUIT];
201
    new_termio = old_termio;
202
    new_termio.c_iflag &= ~(BRKINT|ISTRIP|IXON|IXOFF);
203
    new_termio.c_iflag |= (IGNBRK|IGNPAR);
204
    new_termio.c_lflag &= ~(ICANON|ISIG|ECHO);
205
    new_termio.c_cc[VMIN] = 1;
206
    new_termio.c_cc[VTIME] = 0;
207
    ioctl(0, TCSETA, &new_termio);
208
#endif /* TIOCSETN */
209
#endif /* POSIX */
210
#endif /* __unix__ */
211
 
212
#ifdef vms
213
    descrip.dsc$w_length  = strlen("tt:");
214
    descrip.dsc$b_dtype   = DSC$K_DTYPE_T;
215
    descrip.dsc$b_class   = DSC$K_CLASS_S;
216
    descrip.dsc$a_pointer = "tt:";
217
    (void)sys$assign(&descrip,&chan,0,0);
218
    (void)sys$qiow(0,chan,IO$_SENSEMODE,0,0,0,setbuff,8,0,0,0,0);
219
    setbuff[1] |= TT$M_NOECHO;
220
    (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);
221
#endif /* vms */
222
}
223
 
224
static void
225
gl_char_cleanup()               /* undo effects of gl_char_init */
226
{
227
#ifdef __unix__
228
#ifdef POSIX 
229
    tcsetattr(0, TCSANOW, &old_termios);
230
#else                   /* not POSIX */
231
#ifdef TIOCSETN         /* BSD */
232
    ioctl(0, TIOCSETN, &old_tty);
233
#else                   /* SYSV */
234
    ioctl(0, TCSETA, &old_termio);
235
#endif /* TIOCSETN */
236
#endif /* POSIX */
237
#endif /* __unix__ */
238
 
239
#ifdef vms
240
    setbuff[1] &= ~TT$M_NOECHO;
241
    (void)sys$qiow(0,chan,IO$_SETMODE,0,0,0,setbuff,8,0,0,0,0);
242
    sys$dassgn(chan);
243
    chan = -1;
244
#endif 
245
}
246
 
247
#if MSDOS || __EMX__ || __GO32__
248
int pc_keymap(c)
249
int c;
250
{
251
    switch (c) {
252
    case 72: c = 16;   /* up -> ^P */
253
        break;
254
    case 80: c = 14;   /* down -> ^N */
255
        break;
256
    case 75: c = 2;    /* left -> ^B */
257
        break;
258
    case 77: c = 6;    /* right -> ^F */
259
        break;
260
    default: c = 0;    /* make it garbage */
261
    }
262
    return c;
263
}
264
#endif /* MSDOS || __EMX__ || __GO32__ */
265
 
266
static int
267
gl_getc()
268
/* get a character without echoing it to screen */
269
{
270
    int             c;
271
#ifdef __unix__
272
    char            ch;
273
#endif
274
 
275
#ifdef __unix__
276
    while ((c = read(0, &ch, 1)) == -1) {
277
        if (errno != EINTR)
278
            break;
279
    }
280
    c = (ch <= 0)? -1 : ch;
281
#endif  /* __unix__ */
282
#ifdef MSDOS
283
    c = _bios_keybrd(_NKEYBRD_READ);
284
#endif  /* MSDOS */
285
#ifdef __GO32__
286
    c = getkey () ;
287
    if (c > 255) c = pc_keymap(c & 0377);
288
#endif /* __GO32__ */
289
#ifdef __TURBOC__
290
    while(!bioskey(1))
291
        ;
292
    c = bioskey(0);
293
#endif
294
#if MSDOS || __TURBOC__
295
    if ((c & 0377) == 224) {
296
        c = pc_keymap((c >> 8) & 0377);
297
    } else {
298
        c &= 0377;
299
    }
300
#endif /* MSDOS || __TURBOC__ */
301
#ifdef __EMX__
302
    c = _read_kbd(0, 1, 0);
303
    if (c == 224 || c == 0) {
304
        c = pc_keymap(_read_kbd(0, 1, 0));
305
    } else {
306
        c &= 0377;
307
    }
308
#endif
309
#ifdef vms
310
    if(chan < 0) {
311
       c='\0';
312
    }
313
    (void)sys$qiow(0,chan,IO$_TTYREADALL,0,0,0,&c,1,0,0,0,0);
314
    c &= 0177;                        /* get a char */
315
#endif
316
    return c;
317
}
318
 
319
static void
320
gl_putc(c)
321
int     c;
322
{
323
    char   ch = c;
324
 
325
    write(1, &ch, 1);
326
    if (ch == '\n') {
327
        ch = '\r';
328
        write(1, &ch, 1);       /* RAW mode needs '\r', does not hurt */
329
    }
330
}
331
 
332
/******************** fairly portable part *********************************/
333
 
334
static void
335
gl_puts(buf)
336
char *buf;
337
{
338
    int len;
339
 
340
    if (buf) {
341
        len = strlen(buf);
342
        write(1, buf, len);
343
    }
344
}
345
 
346
static void
347
gl_error(buf)
348
char *buf;
349
{
350
    int len = strlen(buf);
351
 
352
    gl_cleanup();
353
    write(2, buf, len);
354
    exit(1);
355
}
356
 
357
static void
358
gl_init()
359
/* set up variables and terminal */
360
{
361
    if (gl_init_done < 0) {              /* -1 only on startup */
362
        hist_init();
363
    }
364
    if (isatty(0) == 0 || isatty(1) == 0)
365
        gl_error("\n*** Error: getline(): not interactive, use stdio.\n");
366
    gl_char_init();
367
    gl_init_done = 1;
368
}
369
 
370
static void
371
gl_cleanup()
372
/* undo effects of gl_init, as necessary */
373
{
374
    if (gl_init_done > 0)
375
        gl_char_cleanup();
376
    gl_init_done = 0;
377
}
378
 
379
void
380
gl_setwidth(w)
381
int  w;
382
{
383
    if (w > 20) {
384
        gl_termw = w;
385
        gl_scroll = w / 3;
386
    } else {
387
        gl_error("\n*** Error: minimum screen width is 21\n");
388
    }
389
}
390
 
391
char *
392
gl_getline(prompt)
393
char *prompt;
394
{
395
    int             c, loc, tmp;
396
 
397
#ifdef __unix__
398
    int             sig;
399
#endif
400
 
401
    gl_init();
402
    gl_prompt = (prompt)? prompt : "";
403
    gl_buf[0] = 0;
404
    if (gl_in_hook)
405
        gl_in_hook(gl_buf);
406
    gl_fixup(gl_prompt, -2, BUF_SIZE);
407
    while ((c = gl_getc()) >= 0) {
408
        gl_extent = 0;   /* reset to full extent */
409
        if (isprint(c)) {
410
            if (gl_search_mode)
411
               search_addchar(c);
412
            else
413
               gl_addchar(c);
414
        } else {
415
            if (gl_search_mode) {
416
                if (c == '\033' || c == '\016' || c == '\020') {
417
                    search_term();
418
                    c = 0;               /* ignore the character */
419
                } else if (c == '\010' || c == '\177') {
420
                    search_addchar(-1); /* unwind search string */
421
                    c = 0;
422
                } else if (c != '\022' && c != '\023') {
423
                    search_term();      /* terminate and handle char */
424
                }
425
            }
426
            switch (c) {
427
              case '\n': case '\r':                     /* newline */
428
                gl_newline();
429
                gl_cleanup();
430
                return gl_buf;
431
                /*NOTREACHED*/
432
                break;
433
              case '\001': gl_fixup(gl_prompt, -1, 0);           /* ^A */
434
                break;
435
              case '\002': gl_fixup(gl_prompt, -1, gl_pos-1);   /* ^B */
436
                break;
437
              case '\004':                                      /* ^D */
438
                if (gl_cnt == 0) {
439
                    gl_buf[0] = 0;
440
                    gl_cleanup();
441
                    gl_putc('\n');
442
                    return gl_buf;
443
                } else {
444
                    gl_del(0);
445
                }
446
                break;
447
              case '\005': gl_fixup(gl_prompt, -1, gl_cnt);     /* ^E */
448
                break;
449
              case '\006': gl_fixup(gl_prompt, -1, gl_pos+1);   /* ^F */
450
                break;
451
              case '\010': case '\177': gl_del(-1);     /* ^H and DEL */
452
                break;
453
              case '\t':                                        /* TAB */
454
                if (gl_tab_hook) {
455
                    tmp = gl_pos;
456
                    loc = gl_tab_hook(gl_buf, gl_strlen(gl_prompt), &tmp);
457
                    if (loc >= 0 || tmp != gl_pos)
458
                        gl_fixup(gl_prompt, loc, tmp);
459
                }
460
                break;
461
              case '\013': gl_kill(gl_pos);                     /* ^K */
462
                break;
463
              case '\014': gl_redraw();                         /* ^L */
464
                break;
465
              case '\016':                                      /* ^N */
466
                strcpy(gl_buf, hist_next());
467
                if (gl_in_hook)
468
                    gl_in_hook(gl_buf);
469
                gl_fixup(gl_prompt, 0, BUF_SIZE);
470
                break;
471
              case '\017': gl_overwrite = !gl_overwrite;        /* ^O */
472
                break;
473
              case '\020':                                      /* ^P */
474
                strcpy(gl_buf, hist_prev());
475
                if (gl_in_hook)
476
                    gl_in_hook(gl_buf);
477
                gl_fixup(gl_prompt, 0, BUF_SIZE);
478
                break;
479
              case '\022': search_back(1);                      /* ^R */
480
                break;
481
              case '\023': search_forw(1);                      /* ^S */
482
                break;
483
              case '\024': gl_transpose();                      /* ^T */
484
                break;
485
              case '\025': gl_kill(0);                           /* ^U */
486
                break;
487
              case '\031': gl_yank();                           /* ^Y */
488
                break;
489
              case '\033':                              /* ansi arrow keys */
490
                c = gl_getc();
491
                if (c == '[') {
492
                    switch(c = gl_getc()) {
493
                      case 'A':                                 /* up */
494
                        strcpy(gl_buf, hist_prev());
495
                        if (gl_in_hook)
496
                            gl_in_hook(gl_buf);
497
                        gl_fixup(gl_prompt, 0, BUF_SIZE);
498
                        break;
499
                      case 'B':                                 /* down */
500
                        strcpy(gl_buf, hist_next());
501
                        if (gl_in_hook)
502
                            gl_in_hook(gl_buf);
503
                        gl_fixup(gl_prompt, 0, BUF_SIZE);
504
                        break;
505
                      case 'C': gl_fixup(gl_prompt, -1, gl_pos+1); /* right */
506
                        break;
507
                      case 'D': gl_fixup(gl_prompt, -1, gl_pos-1); /* left */
508
                        break;
509
                      default: gl_putc('\007');         /* who knows */
510
                        break;
511
                    }
512
                } else if (c == 'f' || c == 'F') {
513
                    gl_word(1);
514
                } else if (c == 'b' || c == 'B') {
515
                    gl_word(-1);
516
                } else
517
                    gl_putc('\007');
518
                break;
519
              default:          /* check for a terminal signal */
520
#ifdef __unix__
521
                if (c > 0) {     /* ignore 0 (reset above) */
522
                    sig = 0;
523
#ifdef SIGINT
524
                    if (c == gl_intrc)
525
                        sig = SIGINT;
526
#endif
527
#ifdef SIGQUIT
528
                    if (c == gl_quitc)
529
                        sig = SIGQUIT;
530
#endif
531
#ifdef SIGTSTP
532
                    if (c == gl_suspc || c == gl_dsuspc)
533
                        sig = SIGTSTP;
534
#endif
535
                    if (sig != 0) {
536
                        gl_cleanup();
537
                        kill(0, sig);
538
                        gl_init();
539
                        gl_redraw();
540
                        c = 0;
541
                    }
542
                }
543
#endif /* __unix__ */
544
                if (c > 0)
545
                    gl_putc('\007');
546
                break;
547
            }
548
        }
549
    }
550
    gl_cleanup();
551
    gl_buf[0] = 0;
552
    return gl_buf;
553
}
554
 
555
static void
556
gl_addchar(c)
557
int c;
558
/* adds the character c to the input buffer at current location */
559
{
560
    int  i;
561
 
562
    if (gl_cnt >= BUF_SIZE - 1)
563
        gl_error("\n*** Error: getline(): input buffer overflow\n");
564
    if (gl_overwrite == 0 || gl_pos == gl_cnt) {
565
        for (i=gl_cnt; i >= gl_pos; i--)
566
            gl_buf[i+1] = gl_buf[i];
567
        gl_buf[gl_pos] = c;
568
        gl_fixup(gl_prompt, gl_pos, gl_pos+1);
569
    } else {
570
        gl_buf[gl_pos] = c;
571
        gl_extent = 1;
572
        gl_fixup(gl_prompt, gl_pos, gl_pos+1);
573
    }
574
}
575
 
576
static void
577
gl_yank()
578
/* adds the kill buffer to the input buffer at current location */
579
{
580
    int  i, len;
581
 
582
    len = strlen(gl_killbuf);
583
    if (len > 0) {
584
        if (gl_overwrite == 0) {
585
            if (gl_cnt + len >= BUF_SIZE - 1)
586
                gl_error("\n*** Error: getline(): input buffer overflow\n");
587
            for (i=gl_cnt; i >= gl_pos; i--)
588
                gl_buf[i+len] = gl_buf[i];
589
            for (i=0; i < len; i++)
590
                gl_buf[gl_pos+i] = gl_killbuf[i];
591
            gl_fixup(gl_prompt, gl_pos, gl_pos+len);
592
        } else {
593
            if (gl_pos + len > gl_cnt) {
594
                if (gl_pos + len >= BUF_SIZE - 1)
595
                    gl_error("\n*** Error: getline(): input buffer overflow\n");
596
                gl_buf[gl_pos + len] = 0;
597
            }
598
            for (i=0; i < len; i++)
599
                gl_buf[gl_pos+i] = gl_killbuf[i];
600
            gl_extent = len;
601
            gl_fixup(gl_prompt, gl_pos, gl_pos+len);
602
        }
603
    } else
604
        gl_putc('\007');
605
}
606
 
607
static void
608
gl_transpose()
609
/* switch character under cursor and to left of cursor */
610
{
611
    int    c;
612
 
613
    if (gl_pos > 0 && gl_cnt > gl_pos) {
614
        c = gl_buf[gl_pos-1];
615
        gl_buf[gl_pos-1] = gl_buf[gl_pos];
616
        gl_buf[gl_pos] = c;
617
        gl_extent = 2;
618
        gl_fixup(gl_prompt, gl_pos-1, gl_pos);
619
    } else
620
        gl_putc('\007');
621
}
622
 
623
static void
624
gl_newline()
625
/*
626
 * Cleans up entire line before returning to caller. A \n is appended.
627
 * If line longer than screen, we redraw starting at beginning
628
 */
629
{
630
    int change = gl_cnt;
631
    int len = gl_cnt;
632
    int loc = gl_width - 5;     /* shifts line back to start position */
633
 
634
    if (gl_cnt >= BUF_SIZE - 1)
635
        gl_error("\n*** Error: getline(): input buffer overflow\n");
636
    if (gl_out_hook) {
637
        change = gl_out_hook(gl_buf);
638
        len = strlen(gl_buf);
639
    }
640
    if (loc > len)
641
        loc = len;
642
    gl_fixup(gl_prompt, change, loc);   /* must do this before appending \n */
643
    gl_buf[len] = '\n';
644
    gl_buf[len+1] = '\0';
645
    gl_putc('\n');
646
}
647
 
648
static void
649
gl_del(loc)
650
int loc;
651
/*
652
 * Delete a character.  The loc variable can be:
653
 *    -1 : delete character to left of cursor
654
 *     0 : delete character under cursor
655
 */
656
{
657
    int i;
658
 
659
    if ((loc == -1 && gl_pos > 0) || (loc == 0 && gl_pos < gl_cnt)) {
660
        for (i=gl_pos+loc; i < gl_cnt; i++)
661
            gl_buf[i] = gl_buf[i+1];
662
        gl_fixup(gl_prompt, gl_pos+loc, gl_pos+loc);
663
    } else
664
        gl_putc('\007');
665
}
666
 
667
static void
668
gl_kill(pos)
669
int pos;
670
/* delete from pos to the end of line */
671
{
672
    if (pos < gl_cnt) {
673
        strcpy(gl_killbuf, gl_buf + pos);
674
        gl_buf[pos] = '\0';
675
        gl_fixup(gl_prompt, pos, pos);
676
    } else
677
        gl_putc('\007');
678
}
679
 
680
static void
681
gl_word(direction)
682
int direction;
683
/* move forward or backword one word */
684
{
685
    int pos = gl_pos;
686
 
687
    if (direction > 0) {         /* forward */
688
        while (!isspace(gl_buf[pos]) && pos < gl_cnt)
689
            pos++;
690
        while (isspace(gl_buf[pos]) && pos < gl_cnt)
691
            pos++;
692
    } else {                            /* backword */
693
        if (pos > 0)
694
            pos--;
695
        while (isspace(gl_buf[pos]) && pos > 0)
696
            pos--;
697
        while (!isspace(gl_buf[pos]) && pos > 0)
698
            pos--;
699
        if (pos < gl_cnt && isspace(gl_buf[pos]))   /* move onto word */
700
            pos++;
701
    }
702
    gl_fixup(gl_prompt, -1, pos);
703
}
704
 
705
static void
706
gl_redraw()
707
/* emit a newline, reset and redraw prompt and current input line */
708
{
709
    if (gl_init_done > 0) {
710
        gl_putc('\n');
711
        gl_fixup(gl_prompt, -2, gl_pos);
712
    }
713
}
714
 
715
static void
716
gl_fixup(prompt, change, cursor)
717
char  *prompt;
718
int    change, cursor;
719
/*
720
 * This function is used both for redrawing when input changes or for
721
 * moving within the input line.  The parameters are:
722
 *   prompt:  compared to last_prompt[] for changes;
723
 *   change : the index of the start of changes in the input buffer,
724
 *            with -1 indicating no changes, -2 indicating we're on
725
 *            a new line, redraw everything.
726
 *   cursor : the desired location of the cursor after the call.
727
 *            A value of BUF_SIZE can be used  to indicate the cursor should
728
 *            move just past the end of the input line.
729
 */
730
{
731
    static int   gl_shift;      /* index of first on screen character */
732
    static int   off_right;     /* true if more text right of screen */
733
    static int   off_left;      /* true if more text left of screen */
734
    static char  last_prompt[80] = "";
735
    int          left = 0, right = -1;           /* bounds for redraw */
736
    int          pad;           /* how much to erase at end of line */
737
    int          backup;        /* how far to backup before fixing */
738
    int          new_shift;     /* value of shift based on cursor */
739
    int          extra;         /* adjusts when shift (scroll) happens */
740
    int          i;
741
    int          new_right = -1; /* alternate right bound, using gl_extent */
742
    int          l1, l2;
743
 
744
    if (change == -2) {   /* reset */
745
        gl_pos = gl_cnt = gl_shift = off_right = off_left = 0;
746
        gl_putc('\r');
747
        gl_puts(prompt);
748
        strcpy(last_prompt, prompt);
749
        change = 0;
750
        gl_width = gl_termw - gl_strlen(prompt);
751
    } else if (strcmp(prompt, last_prompt) != 0) {
752
        l1 = gl_strlen(last_prompt);
753
        l2 = gl_strlen(prompt);
754
        gl_cnt = gl_cnt + l1 - l2;
755
        strcpy(last_prompt, prompt);
756
        gl_putc('\r');
757
        gl_puts(prompt);
758
        gl_pos = gl_shift;
759
        gl_width = gl_termw - l2;
760
        change = 0;
761
    }
762
    pad = (off_right)? gl_width - 1 : gl_cnt - gl_shift;   /* old length */
763
    backup = gl_pos - gl_shift;
764
    if (change >= 0) {
765
        gl_cnt = strlen(gl_buf);
766
        if (change > gl_cnt)
767
            change = gl_cnt;
768
    }
769
    if (cursor > gl_cnt) {
770
        if (cursor != BUF_SIZE)         /* BUF_SIZE means end of line */
771
            gl_putc('\007');
772
        cursor = gl_cnt;
773
    }
774
    if (cursor < 0) {
775
        gl_putc('\007');
776
        cursor = 0;
777
    }
778
    if (off_right || (off_left && cursor < gl_shift + gl_width - gl_scroll / 2))
779
        extra = 2;                      /* shift the scrolling boundary */
780
    else
781
        extra = 0;
782
    new_shift = cursor + extra + gl_scroll - gl_width;
783
    if (new_shift > 0) {
784
        new_shift /= gl_scroll;
785
        new_shift *= gl_scroll;
786
    } else
787
        new_shift = 0;
788
    if (new_shift != gl_shift) {        /* scroll occurs */
789
        gl_shift = new_shift;
790
        off_left = (gl_shift)? 1 : 0;
791
        off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
792
        left = gl_shift;
793
        new_right = right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
794
    } else if (change >= 0) {            /* no scroll, but text changed */
795
        if (change < gl_shift + off_left) {
796
            left = gl_shift;
797
        } else {
798
            left = change;
799
            backup = gl_pos - change;
800
        }
801
        off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
802
        right = (off_right)? gl_shift + gl_width - 2 : gl_cnt;
803
        new_right = (gl_extent && (right > left + gl_extent))?
804
                     left + gl_extent : right;
805
    }
806
    pad -= (off_right)? gl_width - 1 : gl_cnt - gl_shift;
807
    pad = (pad < 0)? 0 : pad;
808
    if (left <= right) {                /* clean up screen */
809
        for (i=0; i < backup; i++)
810
            gl_putc('\b');
811
        if (left == gl_shift && off_left) {
812
            gl_putc('$');
813
            left++;
814
        }
815
        for (i=left; i < new_right; i++)
816
            gl_putc(gl_buf[i]);
817
        gl_pos = new_right;
818
        if (off_right && new_right == right) {
819
            gl_putc('$');
820
            gl_pos++;
821
        } else {
822
            for (i=0; i < pad; i++)      /* erase remains of prev line */
823
                gl_putc(' ');
824
            gl_pos += pad;
825
        }
826
    }
827
    i = gl_pos - cursor;                /* move to final cursor location */
828
    if (i > 0) {
829
        while (i--)
830
           gl_putc('\b');
831
    } else {
832
        for (i=gl_pos; i < cursor; i++)
833
            gl_putc(gl_buf[i]);
834
    }
835
    gl_pos = cursor;
836
}
837
 
838
static int
839
gl_tab(buf, offset, loc)
840
char  *buf;
841
int    offset;
842
int   *loc;
843
/* default tab handler, acts like tabstops every 8 cols */
844
{
845
    int i, count, len;
846
 
847
    len = strlen(buf);
848
    count = 8 - (offset + *loc) % 8;
849
    for (i=len; i >= *loc; i--)
850
        buf[i+count] = buf[i];
851
    for (i=0; i < count; i++)
852
        buf[*loc+i] = ' ';
853
    i = *loc;
854
    *loc = i + count;
855
    return i;
856
}
857
 
858
/******************* strlen stuff **************************************/
859
 
860
void gl_strwidth(func)
861
size_t (*func)();
862
{
863
    if (func != 0) {
864
        gl_strlen = func;
865
    }
866
}
867
 
868
/******************* History stuff **************************************/
869
 
870
#ifndef HIST_SIZE
871
#define HIST_SIZE 100
872
#endif
873
 
874
static int      hist_pos = 0, hist_last = 0;
875
static char    *hist_buf[HIST_SIZE];
876
 
877
static void
878
hist_init()
879
{
880
    int i;
881
 
882
    hist_buf[0] = "";
883
    for (i=1; i < HIST_SIZE; i++)
884
        hist_buf[i] = (char *)0;
885
}
886
 
887
void
888
gl_histadd(buf)
889
char *buf;
890
{
891
    static char *prev = 0;
892
    char *p = buf;
893
    int len;
894
 
895
    /* in case we call gl_histadd() before we call gl_getline() */
896
    if (gl_init_done < 0) {              /* -1 only on startup */
897
        hist_init();
898
        gl_init_done = 0;
899
    }
900
    while (*p == ' ' || *p == '\t' || *p == '\n')
901
        p++;
902
    if (*p) {
903
        len = strlen(buf);
904
        if (strchr(p, '\n'))    /* previously line already has NL stripped */
905
            len--;
906
        if (prev == 0 || strlen(prev) != len ||
907
                            strncmp(prev, buf, len) != 0) {
908
            hist_buf[hist_last] = hist_save(buf);
909
            prev = hist_buf[hist_last];
910
            hist_last = (hist_last + 1) % HIST_SIZE;
911
            if (hist_buf[hist_last] && *hist_buf[hist_last]) {
912
                free(hist_buf[hist_last]);
913
            }
914
            hist_buf[hist_last] = "";
915
        }
916
    }
917
    hist_pos = hist_last;
918
}
919
 
920
static char *
921
hist_prev()
922
/* loads previous hist entry into input buffer, sticks on first */
923
{
924
    char *p = 0;
925
    int   next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE;
926
 
927
    if (hist_buf[hist_pos] != 0 && next != hist_last) {
928
        hist_pos = next;
929
        p = hist_buf[hist_pos];
930
    }
931
    if (p == 0) {
932
        p = "";
933
        gl_putc('\007');
934
    }
935
    return p;
936
}
937
 
938
static char *
939
hist_next()
940
/* loads next hist entry into input buffer, clears on last */
941
{
942
    char *p = 0;
943
 
944
    if (hist_pos != hist_last) {
945
        hist_pos = (hist_pos+1) % HIST_SIZE;
946
        p = hist_buf[hist_pos];
947
    }
948
    if (p == 0) {
949
        p = "";
950
        gl_putc('\007');
951
    }
952
    return p;
953
}
954
 
955
static char *
956
hist_save(p)
957
char *p;
958
/* makes a copy of the string */
959
{
960
    char *s = 0;
961
    int   len = strlen(p);
962
    char *nl = strchr(p, '\n');
963
 
964
    if (nl) {
965
        if ((s = malloc(len)) != 0) {
966
            strncpy(s, p, len-1);
967
            s[len-1] = 0;
968
        }
969
    } else {
970
        if ((s = malloc(len+1)) != 0) {
971
            strcpy(s, p);
972
        }
973
    }
974
    if (s == 0)
975
        gl_error("\n*** Error: hist_save() failed on malloc\n");
976
    return s;
977
}
978
 
979
/******************* Search stuff **************************************/
980
 
981
static char  search_prompt[101];  /* prompt includes search string */
982
static char  search_string[100];
983
static int   search_pos = 0;      /* current location in search_string */
984
static int   search_forw_flg = 0; /* search direction flag */
985
static int   search_last = 0;      /* last match found */
986
 
987
static void
988
search_update(c)
989
int c;
990
{
991
    if (c == 0) {
992
        search_pos = 0;
993
        search_string[0] = 0;
994
        search_prompt[0] = '?';
995
        search_prompt[1] = ' ';
996
        search_prompt[2] = 0;
997
    } else if (c > 0) {
998
        search_string[search_pos] = c;
999
        search_string[search_pos+1] = 0;
1000
        search_prompt[search_pos] = c;
1001
        search_prompt[search_pos+1] = '?';
1002
        search_prompt[search_pos+2] = ' ';
1003
        search_prompt[search_pos+3] = 0;
1004
        search_pos++;
1005
    } else {
1006
        if (search_pos > 0) {
1007
            search_pos--;
1008
            search_string[search_pos] = 0;
1009
            search_prompt[search_pos] = '?';
1010
            search_prompt[search_pos+1] = ' ';
1011
            search_prompt[search_pos+2] = 0;
1012
        } else {
1013
            gl_putc('\007');
1014
            hist_pos = hist_last;
1015
        }
1016
    }
1017
}
1018
 
1019
static void
1020
search_addchar(c)
1021
int  c;
1022
{
1023
    char *loc;
1024
 
1025
    search_update(c);
1026
    if (c < 0) {
1027
        if (search_pos > 0) {
1028
            hist_pos = search_last;
1029
        } else {
1030
            gl_buf[0] = 0;
1031
            hist_pos = hist_last;
1032
        }
1033
        strcpy(gl_buf, hist_buf[hist_pos]);
1034
    }
1035
    if ((loc = strstr(gl_buf, search_string)) != 0) {
1036
        gl_fixup(search_prompt, 0, loc - gl_buf);
1037
    } else if (search_pos > 0) {
1038
        if (search_forw_flg) {
1039
            search_forw(0);
1040
        } else {
1041
            search_back(0);
1042
        }
1043
    } else {
1044
        gl_fixup(search_prompt, 0, 0);
1045
    }
1046
}
1047
 
1048
static void
1049
search_term()
1050
{
1051
    gl_search_mode = 0;
1052
    if (gl_buf[0] == 0)           /* not found, reset hist list */
1053
        hist_pos = hist_last;
1054
    if (gl_in_hook)
1055
        gl_in_hook(gl_buf);
1056
    gl_fixup(gl_prompt, 0, gl_pos);
1057
}
1058
 
1059
static void
1060
search_back(new_search)
1061
int new_search;
1062
{
1063
    int    found = 0;
1064
    char  *p, *loc;
1065
 
1066
    search_forw_flg = 0;
1067
    if (gl_search_mode == 0) {
1068
        search_last = hist_pos = hist_last;
1069
        search_update(0);
1070
        gl_search_mode = 1;
1071
        gl_buf[0] = 0;
1072
        gl_fixup(search_prompt, 0, 0);
1073
    } else if (search_pos > 0) {
1074
        while (!found) {
1075
            p = hist_prev();
1076
            if (*p == 0) {               /* not found, done looking */
1077
               gl_buf[0] = 0;
1078
               gl_fixup(search_prompt, 0, 0);
1079
               found = 1;
1080
            } else if ((loc = strstr(p, search_string)) != 0) {
1081
               strcpy(gl_buf, p);
1082
               gl_fixup(search_prompt, 0, loc - p);
1083
               if (new_search)
1084
                   search_last = hist_pos;
1085
               found = 1;
1086
            }
1087
        }
1088
    } else {
1089
        gl_putc('\007');
1090
    }
1091
}
1092
 
1093
static void
1094
search_forw(new_search)
1095
int new_search;
1096
{
1097
    int    found = 0;
1098
    char  *p, *loc;
1099
 
1100
    search_forw_flg = 1;
1101
    if (gl_search_mode == 0) {
1102
        search_last = hist_pos = hist_last;
1103
        search_update(0);
1104
        gl_search_mode = 1;
1105
        gl_buf[0] = 0;
1106
        gl_fixup(search_prompt, 0, 0);
1107
    } else if (search_pos > 0) {
1108
        while (!found) {
1109
            p = hist_next();
1110
            if (*p == 0) {               /* not found, done looking */
1111
               gl_buf[0] = 0;
1112
               gl_fixup(search_prompt, 0, 0);
1113
               found = 1;
1114
            } else if ((loc = strstr(p, search_string)) != 0) {
1115
               strcpy(gl_buf, p);
1116
               gl_fixup(search_prompt, 0, loc - p);
1117
               if (new_search)
1118
                   search_last = hist_pos;
1119
               found = 1;
1120
            }
1121
        }
1122
    } else {
1123
        gl_putc('\007');
1124
    }
1125
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.