~darkmuggle-deactivatedaccount/ubuntu/quantal/grub2/fix-872244

« back to all changes in this revision

Viewing changes to normal/cmdline.c

  • Committer: Bazaar Package Importer
  • Author(s): Otavio Salvador
  • Date: 2006-01-05 15:20:40 UTC
  • mto: (17.3.1 squeeze) (1.9.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20060105152040-b72i5pq1a82z22yi
Tags: upstream-1.92
ImportĀ upstreamĀ versionĀ 1.92

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  GRUB  --  GRand Unified Bootloader
 
3
 *  Copyright (C) 1999,2000,2001,2002,2003,2004,2005  Free Software Foundation, Inc.
 
4
 *
 
5
 *  This program is free software; you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation; either version 2 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
18
 */
 
19
 
 
20
#include <grub/normal.h>
 
21
#include <grub/misc.h>
 
22
#include <grub/term.h>
 
23
#include <grub/err.h>
 
24
#include <grub/types.h>
 
25
#include <grub/mm.h>
 
26
#include <grub/partition.h>
 
27
#include <grub/disk.h>
 
28
#include <grub/file.h>
 
29
#include <grub/env.h>
 
30
 
 
31
static char *kill_buf;
 
32
 
 
33
static int hist_size;
 
34
static char **hist_lines = 0;
 
35
static int hist_pos = 0;
 
36
static int hist_end = 0;
 
37
static int hist_used = 0;
 
38
 
 
39
grub_err_t
 
40
grub_set_history (int newsize)
 
41
{
 
42
  char **old_hist_lines = hist_lines;
 
43
  hist_lines = grub_malloc (sizeof (char *) * newsize);
 
44
 
 
45
  /* Copy the old lines into the new buffer.  */
 
46
  if (old_hist_lines)
 
47
    {
 
48
      /* Remove the lines that don't fit in the new buffer.  */
 
49
      if (newsize < hist_used)
 
50
        {
 
51
          int i;
 
52
          int delsize = hist_used - newsize;
 
53
          hist_used = newsize;
 
54
 
 
55
          for (i = 1; i <= delsize; i++)
 
56
            {
 
57
              int pos = hist_end - i;
 
58
              if (pos < 0)
 
59
                pos += hist_size;
 
60
              grub_free (old_hist_lines[pos]);
 
61
            }
 
62
 
 
63
          hist_end -= delsize;
 
64
          if (hist_end < 0)
 
65
            hist_end += hist_size;
 
66
        }
 
67
 
 
68
      if (hist_pos < hist_end)
 
69
        grub_memmove (hist_lines, old_hist_lines + hist_pos,
 
70
                      (hist_end - hist_pos) * sizeof (char *));
 
71
      else if (hist_used)
 
72
        {
 
73
          /* Copy the older part.  */
 
74
          grub_memmove (hist_lines, old_hist_lines + hist_pos,
 
75
                        (hist_size - hist_pos) * sizeof (char *));
 
76
          
 
77
          /* Copy the newer part. */
 
78
          grub_memmove (hist_lines + hist_size - hist_pos, old_hist_lines,
 
79
                        hist_end * sizeof (char *));
 
80
        }
 
81
    }
 
82
 
 
83
  grub_free (old_hist_lines);
 
84
 
 
85
  hist_size = newsize;
 
86
  hist_pos = 0;
 
87
  hist_end = hist_used;
 
88
  return 0;
 
89
}
 
90
 
 
91
/* Get the entry POS from the history where `0' is the newest
 
92
   entry.  */
 
93
static char *
 
94
grub_history_get (int pos)
 
95
{
 
96
  pos = (hist_pos + pos) % hist_size;
 
97
  return hist_lines[pos];
 
98
}
 
99
 
 
100
 
 
101
/* Insert a new history line S on the top of the history.  */
 
102
static void
 
103
grub_history_add (char *s)
 
104
{
 
105
  /* Remove the oldest entry in the history to make room for a new
 
106
     entry.  */
 
107
  if (hist_used + 1 > hist_size)
 
108
    {
 
109
      hist_end--;
 
110
      if (hist_end < 0)
 
111
        hist_end = hist_size + hist_end;
 
112
 
 
113
      grub_free (hist_lines[hist_end]);
 
114
    }
 
115
  else
 
116
    hist_used++;
 
117
 
 
118
  /* Move to the next position.  */
 
119
  hist_pos--;
 
120
  if (hist_pos < 0)
 
121
    hist_pos = hist_size + hist_pos;
 
122
 
 
123
  /* Insert into history.  */
 
124
  hist_lines[hist_pos] = grub_strdup (s);
 
125
}
 
126
 
 
127
/* Replace the history entry on position POS with the string S.  */
 
128
static void
 
129
grub_history_replace (int pos, char *s)
 
130
{
 
131
  pos = (hist_pos + pos) % hist_size;
 
132
  grub_free (hist_lines[pos]);
 
133
  hist_lines[pos] = grub_strdup (s);
 
134
}
 
135
 
 
136
void
 
137
grub_cmdline_run (int nested)
 
138
{
 
139
  grub_normal_init_page ();
 
140
  grub_setcursor (1);
 
141
  
 
142
  grub_printf ("\
 
143
 [ Minimal BASH-like line editing is supported. For the first word, TAB\n\
 
144
   lists possible command completions. Anywhere else TAB lists possible\n\
 
145
   device/file completions.%s ]\n\n",
 
146
               nested ? " ESC at any time exits." : "");
 
147
  
 
148
  while (1)
 
149
    {
 
150
      static char cmdline[GRUB_MAX_CMDLINE];
 
151
 
 
152
      grub_print_error ();
 
153
      grub_errno = GRUB_ERR_NONE;
 
154
      cmdline[0] = '\0';
 
155
      
 
156
      if (! grub_cmdline_get ("grub> ", cmdline, sizeof (cmdline), 0, 1)
 
157
          && nested)
 
158
        return;
 
159
 
 
160
      if (! *cmdline)
 
161
        continue;
 
162
 
 
163
      grub_command_execute (cmdline, 1);
 
164
    }
 
165
}
 
166
 
 
167
/* A completion hook to print items.  */
 
168
static void
 
169
print_completion (const char *item, grub_completion_type_t type, int count)
 
170
{
 
171
  if (count == 0)
 
172
    {
 
173
      /* If this is the first time, print a label.  */
 
174
      const char *what;
 
175
 
 
176
      switch (type)
 
177
        {
 
178
        case GRUB_COMPLETION_TYPE_COMMAND:
 
179
          what = "commands";
 
180
          break;
 
181
        case GRUB_COMPLETION_TYPE_DEVICE:
 
182
          what = "devices";
 
183
          break;
 
184
        case GRUB_COMPLETION_TYPE_FILE:
 
185
          what = "files";
 
186
          break;
 
187
        case GRUB_COMPLETION_TYPE_PARTITION:
 
188
          what = "partitions";
 
189
          break;
 
190
        case GRUB_COMPLETION_TYPE_ARGUMENT:
 
191
          what = "arguments";
 
192
          break;
 
193
        default:
 
194
          what = "things";
 
195
          break;
 
196
        }
 
197
            
 
198
      grub_printf ("\nPossible %s are:\n", what);
 
199
    }
 
200
 
 
201
  if (type == GRUB_COMPLETION_TYPE_PARTITION)
 
202
    {
 
203
      grub_normal_print_device_info (item);
 
204
      grub_errno = GRUB_ERR_NONE;
 
205
    }
 
206
  else
 
207
    grub_printf (" %s", item);
 
208
}
 
209
 
 
210
/* Get a command-line. If ECHO_CHAR is not zero, echo it instead of input
 
211
   characters. If READLINE is non-zero, readline-like key bindings are
 
212
   available. If ESC is pushed, return zero, otherwise return non-zero.  */
 
213
/* FIXME: The dumb interface is not supported yet.  */
 
214
int
 
215
grub_cmdline_get (const char *prompt, char cmdline[], unsigned max_len,
 
216
                  int echo_char, int readline)
 
217
{
 
218
  unsigned xpos, ypos, ystart;
 
219
  grub_size_t lpos, llen;
 
220
  grub_size_t plen;
 
221
  char buf[max_len];
 
222
  int key;
 
223
  int histpos = 0;
 
224
  auto void cl_insert (const char *str);
 
225
  auto void cl_delete (unsigned len);
 
226
  auto void cl_print (int pos, int c);
 
227
  auto void cl_set_pos (void);
 
228
 
 
229
  void cl_set_pos (void)
 
230
    {
 
231
      xpos = (plen + lpos) % 79;
 
232
      ypos = ystart + (plen + lpos) / 79;
 
233
      grub_gotoxy (xpos, ypos);
 
234
    }
 
235
  
 
236
  void cl_print (int pos, int c)
 
237
    {
 
238
      char *p;
 
239
 
 
240
      for (p = buf + pos; *p; p++)
 
241
        {
 
242
          if (xpos++ > 78)
 
243
            {
 
244
              grub_putchar ('\n');
 
245
              
 
246
              xpos = 1;
 
247
              if (ypos == (unsigned) (grub_getxy () & 0xFF))
 
248
                ystart--;
 
249
              else
 
250
                ypos++;
 
251
            }
 
252
 
 
253
          if (c)
 
254
            grub_putchar (c);
 
255
          else
 
256
            grub_putchar (*p);
 
257
        }
 
258
    }
 
259
  
 
260
  void cl_insert (const char *str)
 
261
    {
 
262
      grub_size_t len = grub_strlen (str);
 
263
 
 
264
      if (len + llen < max_len)
 
265
        {
 
266
          grub_memmove (buf + lpos + len, buf + lpos, llen - lpos + 1);
 
267
          grub_memmove (buf + lpos, str, len);
 
268
 
 
269
          llen += len;
 
270
          lpos += len;
 
271
          cl_print (lpos - len, echo_char);
 
272
          cl_set_pos ();
 
273
        }
 
274
    }
 
275
 
 
276
  void cl_delete (unsigned len)
 
277
    {
 
278
      if (lpos + len <= llen)
 
279
        {
 
280
          grub_size_t saved_lpos = lpos;
 
281
 
 
282
          lpos = llen - len;
 
283
          cl_set_pos ();
 
284
          cl_print (lpos, ' ');
 
285
          lpos = saved_lpos;
 
286
          cl_set_pos ();
 
287
          
 
288
          grub_memmove (buf + lpos, buf + lpos + len, llen - lpos + 1);
 
289
          llen -= len;
 
290
          cl_print (lpos, echo_char);
 
291
          cl_set_pos ();
 
292
        }
 
293
    }
 
294
  
 
295
  plen = grub_strlen (prompt);
 
296
  lpos = llen = 0;
 
297
  buf[0] = '\0';
 
298
 
 
299
  if ((grub_getxy () >> 8) != 0)
 
300
    grub_putchar ('\n');
 
301
  
 
302
  grub_printf (prompt);
 
303
  
 
304
  xpos = plen;
 
305
  ystart = ypos = (grub_getxy () & 0xFF);
 
306
  
 
307
  cl_insert (cmdline);
 
308
 
 
309
  if (hist_used == 0)
 
310
    grub_history_add (buf);
 
311
 
 
312
  while ((key = GRUB_TERM_ASCII_CHAR (grub_getkey ())) != '\n' && key != '\r')
 
313
    {
 
314
      if (readline)
 
315
        {
 
316
          switch (key)
 
317
            {
 
318
            case 1:     /* Ctrl-a */
 
319
              lpos = 0;
 
320
              cl_set_pos ();
 
321
              break;
 
322
 
 
323
            case 2:     /* Ctrl-b */
 
324
              if (lpos > 0)
 
325
                {
 
326
                  lpos--;
 
327
                  cl_set_pos ();
 
328
                }
 
329
              break;
 
330
 
 
331
            case 5:     /* Ctrl-e */
 
332
              lpos = llen;
 
333
              cl_set_pos ();
 
334
              break;
 
335
 
 
336
            case 6:     /* Ctrl-f */
 
337
              if (lpos < llen)
 
338
                {
 
339
                  lpos++;
 
340
                  cl_set_pos ();
 
341
                }
 
342
              break;
 
343
 
 
344
            case 9:     /* Ctrl-i or TAB */
 
345
              {
 
346
                char *insert;
 
347
                int restore;
 
348
                
 
349
                /* Backup the next character and make it 0 so it will
 
350
                   be easy to use string functions.  */
 
351
                char backup = buf[lpos];
 
352
                buf[lpos] = '\0';
 
353
                
 
354
 
 
355
                insert = grub_normal_do_completion (buf, &restore,
 
356
                                                    print_completion);
 
357
                /* Restore the original string.  */
 
358
                buf[lpos] = backup;
 
359
                
 
360
                if (restore)
 
361
                  {
 
362
                    /* Restore the prompt.  */
 
363
                    grub_printf ("\n%s%s", prompt, buf);
 
364
                    xpos = plen;
 
365
                    ystart = ypos = (grub_getxy () & 0xFF);
 
366
                  }
 
367
 
 
368
                if (insert)
 
369
                  {
 
370
                    cl_insert (insert);
 
371
                    grub_free (insert);
 
372
                  }
 
373
              }
 
374
              break;
 
375
 
 
376
            case 11:    /* Ctrl-k */
 
377
              if (lpos < llen)
 
378
                {
 
379
                  if (kill_buf)
 
380
                    grub_free (kill_buf);
 
381
 
 
382
                  kill_buf = grub_strdup (buf + lpos);
 
383
                  grub_errno = GRUB_ERR_NONE;
 
384
 
 
385
                  cl_delete (llen - lpos);
 
386
                }
 
387
              break;
 
388
 
 
389
            case 14:    /* Ctrl-n */
 
390
              {
 
391
                char *hist;
 
392
 
 
393
                lpos = 0;
 
394
 
 
395
                if (histpos > 0)
 
396
                  {
 
397
                    grub_history_replace (histpos, buf);
 
398
                    histpos--;
 
399
                  }
 
400
 
 
401
                cl_delete (llen);
 
402
                hist = grub_history_get (histpos);
 
403
                cl_insert (hist);
 
404
 
 
405
                break;
 
406
              }
 
407
            case 16:    /* Ctrl-p */
 
408
              {
 
409
                char *hist;
 
410
 
 
411
                lpos = 0;
 
412
 
 
413
                if (histpos < hist_used - 1)
 
414
                  {
 
415
                    grub_history_replace (histpos, buf);
 
416
                    histpos++;
 
417
                  }
 
418
 
 
419
                cl_delete (llen);
 
420
                hist = grub_history_get (histpos);
 
421
 
 
422
                cl_insert (hist);
 
423
              }
 
424
              break;
 
425
 
 
426
            case 21:    /* Ctrl-u */
 
427
              if (lpos > 0)
 
428
                {
 
429
                  grub_size_t n = lpos;
 
430
                  
 
431
                  if (kill_buf)
 
432
                    grub_free (kill_buf);
 
433
 
 
434
                  kill_buf = grub_malloc (n + 1);
 
435
                  grub_errno = GRUB_ERR_NONE;
 
436
                  if (kill_buf)
 
437
                    {
 
438
                      grub_memcpy (kill_buf, buf, n);
 
439
                      kill_buf[n] = '\0';
 
440
                    }
 
441
 
 
442
                  lpos = 0;
 
443
                  cl_set_pos ();
 
444
                  cl_delete (n);
 
445
                }
 
446
              break;
 
447
 
 
448
            case 25:    /* Ctrl-y */
 
449
              if (kill_buf)
 
450
                cl_insert (kill_buf);
 
451
              break;
 
452
            }
 
453
        }
 
454
 
 
455
      switch (key)
 
456
        {
 
457
        case '\e':
 
458
          return 0;
 
459
 
 
460
        case '\b':
 
461
          if (lpos > 0)
 
462
            {
 
463
              lpos--;
 
464
              cl_set_pos ();
 
465
            }
 
466
          else
 
467
            break;
 
468
          /* fall through */
 
469
          
 
470
        case 4: /* Ctrl-d */
 
471
          if (lpos < llen)
 
472
            cl_delete (1);
 
473
          break;
 
474
 
 
475
        default:
 
476
          if (grub_isprint (key))
 
477
            {
 
478
              char str[2];
 
479
 
 
480
              str[0] = key;
 
481
              str[1] = '\0';
 
482
              cl_insert (str);
 
483
            }
 
484
          break;
 
485
        }
 
486
    }
 
487
 
 
488
  grub_putchar ('\n');
 
489
  grub_refresh ();
 
490
 
 
491
  /* If ECHO_CHAR is NUL, remove leading spaces.  */
 
492
  lpos = 0;
 
493
  if (! echo_char)
 
494
    while (buf[lpos] == ' ')
 
495
      lpos++;
 
496
 
 
497
  histpos = 0;
 
498
  if (grub_strlen (buf) > 0)
 
499
    {
 
500
      grub_history_replace (histpos, buf);
 
501
      grub_history_add ("");
 
502
    }
 
503
  
 
504
  grub_memcpy (cmdline, buf + lpos, llen - lpos + 1);
 
505
 
 
506
  return 1;
 
507
}