/[pupa]/pupa/normal/cmdline.c
ViewVC logotype

Diff of /pupa/normal/cmdline.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.2 by marco_g, Mon Nov 17 18:07:07 2003 UTC revision 1.3 by marco_g, Wed Dec 3 19:17:27 2003 UTC
# Line 2  Line 2 
2   *  PUPA  --  Preliminary Universal Programming Architecture for GRUB   *  PUPA  --  Preliminary Universal Programming Architecture for GRUB
3   *  Copyright (C) 1999,2000,2001,2002  Free Software Foundation, Inc.   *  Copyright (C) 1999,2000,2001,2002  Free Software Foundation, Inc.
4   *  Copyright (C) 2003  Yoshinori K. Okuji <okuji@enbug.org>   *  Copyright (C) 2003  Yoshinori K. Okuji <okuji@enbug.org>
5     *  Copyright (C) 2003 Marco Gerards <metgerards@student.han.nl>
6   *   *
7   *  This program is free software; you can redistribute it and/or modify   *  This program is free software; you can redistribute it and/or modify
8   *  it under the terms of the GNU General Public License as published by   *  it under the terms of the GNU General Public License as published by
# Line 24  Line 25 
25  #include <pupa/err.h>  #include <pupa/err.h>
26  #include <pupa/types.h>  #include <pupa/types.h>
27  #include <pupa/mm.h>  #include <pupa/mm.h>
28    #include <pupa/machine/partition.h>
29    #include <pupa/disk.h>
30    #include <pupa/file.h>
31    
32  static char *kill_buf;  static char *kill_buf;
33    
34    static int hist_size;
35    static char **hist_lines = 0;
36    static int hist_pos = 0;
37    static int hist_end = 0;
38    static int hist_used = 0;
39    
40    pupa_err_t
41    pupa_set_history (int newsize)
42    {
43      char **old_hist_lines = hist_lines;
44      hist_lines = pupa_malloc (sizeof (char *) * newsize);
45    
46      /* Copy the old lines into the new buffer.  */
47      if (old_hist_lines)
48        {
49          /* Remove the lines that don't fit in the new buffer.  */
50          if (newsize < hist_used)
51            {
52              int i;
53              int delsize = hist_used - newsize;
54              hist_used = newsize;
55    
56              for (i = 0; i < delsize; i++)
57                {
58                  int pos = hist_end - i;
59                  if (pos > hist_size)
60                    pos -= hist_size;
61                  pupa_free (old_hist_lines[pos]);
62                }
63    
64              hist_end -= delsize;
65              if (hist_end < 0)
66                hist_end = hist_size - hist_end;
67            }
68    
69          if (hist_pos < hist_end)
70            pupa_memmove (hist_lines, old_hist_lines + hist_pos,
71                          (hist_end - hist_pos) * sizeof (char *));
72          else
73            {
74              /* Copy the first part.  */
75              pupa_memmove (hist_lines, old_hist_lines,
76                            hist_pos * sizeof (char *));
77    
78    
79              /* Copy the last part.  */
80              pupa_memmove (hist_lines + hist_pos, old_hist_lines + hist_pos,
81                            (hist_size - hist_pos) * sizeof (char *));
82    
83            }
84        }
85    
86      pupa_free (old_hist_lines);
87    
88      hist_size = newsize;
89      hist_pos = 0;
90      hist_end = hist_used;
91      return 0;
92    }
93    
94    /* Get the entry POS from the history where `0' is the newest
95       entry.  */
96    static char *
97    pupa_history_get (int pos)
98    {
99      pos = (hist_pos + pos) % hist_size;
100      return hist_lines[pos];
101    }
102    
103    
104    /* Insert a new history line S on the top of the history.  */
105    static void
106    pupa_history_add (char *s)
107    {
108      /* Remove the oldest entry in the history to make room for a new
109         entry.  */
110      if (hist_used + 1 > hist_size)
111        {
112          hist_end--;
113          if (hist_end < 0)
114            hist_end = hist_size + hist_end;
115    
116          pupa_free (hist_lines[hist_end]);
117        }
118      else
119        hist_used++;
120    
121      /* Move to the next position.  */
122      hist_pos--;
123      if (hist_pos < 0)
124        hist_pos = hist_size + hist_pos;
125    
126      /* Insert into history.  */
127      hist_lines[hist_pos] = pupa_strdup (s);
128    }
129    
130    /* Replace the history entry on position POS with the string S.  */
131    static void
132    pupa_history_replace (int pos, char *s)
133    {
134      pos = (hist_pos + pos) % hist_size;
135      pupa_free (hist_lines[pos]);
136      hist_lines[pos] = pupa_strdup (s);
137    }
138    
139    /* Try to complete the string in BUF, return the characters that
140       should be added to the string.  This command outputs the possible
141       completions, in that case set RESTORE to 1 so the caller can
142       restore the prompt.  */
143    static char *
144    pupa_tab_complete (char *buf, int *restore)
145    {
146      char *pos = buf;
147      char *path;
148      
149      char *found = 0;
150      int begin;
151      int end;
152      int len;
153      int numfound = 0;
154    
155      /* The disk that is used for pupa_partition_iterate.  */
156      pupa_device_t partdev;
157                    
158      /* String that is added when matched.  */
159      char *matchstr;
160    
161      void print_simple_completion (char *comp)
162        {
163          pupa_printf (" %s", comp);
164        }
165    
166      void print_partition_completion (char *comp)
167        {
168          pupa_fs_t fs = 0;
169          pupa_device_t part;
170          char devname[20];
171          
172          pupa_sprintf (devname, "%s,%s", partdev->disk->name, comp);
173          part = pupa_device_open (devname);
174          if (!part)
175            pupa_printf ("\n\tPartition num:%s, Filesystem cannot be accessed",
176                         comp);
177          else
178            {
179              char *label;
180    
181              fs = pupa_fs_probe (part);
182              /* Ignore all errors.  */
183              pupa_errno = 0;
184    
185              pupa_printf ("\n\tPartition num:%s, Filesystem type %s",
186                           comp, fs ? fs->name : "Unknown");
187              
188              if (fs)
189                {
190                  (fs->label) (part, &label);
191                  if (pupa_errno == PUPA_ERR_NONE)
192                    {
193                      if (label && pupa_strlen (label))
194                        pupa_printf (", Label: %s", label);
195                      pupa_free (label);
196                    }
197                  pupa_errno = PUPA_ERR_NONE;
198                }
199              pupa_device_close (part);
200            }
201        }
202    
203      /* Add a string to the list of possible completions.  COMP is the
204         string that should be added.  If this string completely matches
205         add the string MATCH to the input after adding COMP.  The string
206         WHAT contains a discription of the kind of data that is added.
207         Use PRINT_COMPLETION to show the completions if there are
208         multiple matches.  XXX: Because of a bug in gcc it is required to
209         use __regparm__ in some cases.  */
210    
211      int NESTED_FUNC_ATTR
212        add_completion (const char *comp, const char *match, const char *what,
213                        void (*print_completion) (char *))
214        {
215          /* Bug in strncmp then len ==0.  */
216          if (!len || pupa_strncmp (pos, comp, len) == 0)
217            {
218              numfound++;
219            
220              if (numfound == 1)
221                {
222                  begin = len;
223                  found = pupa_strdup (comp);
224                  end = pupa_strlen (found);
225                  matchstr = (char *) match;
226                }
227              /* Multiple matches found, print the first instead of completing.  */
228              else if (numfound == 2)
229                {
230                  pupa_printf ("\nPossible %s are: ", what);
231                  print_completion (found);
232                }
233                
234              if (numfound > 1)
235                {
236                  char *s1 = found;
237                  const char *s2 = comp;
238                  int cnt = 0;
239                
240                  print_completion ((char *) comp);
241                                
242                  /* Find out how many characters match.  */
243                  while ((cnt < end) && *s1 && *s2 && (*s1 == *s2))
244                    {
245                      s1++;
246                      s2++;
247                      cnt++;
248                    }          
249                  end = cnt;
250                }
251            }
252    
253          return 0;
254        }
255    
256      int iterate_part (const pupa_partition_t p)
257        {
258          add_completion (pupa_partition_get_name (p), ")", "partitions",
259                          print_partition_completion);
260          return 0;
261        }
262    
263      int iterate_dir (const char *filename, int dir)
264        {
265          if (!dir)
266            add_completion (filename, " ", "files", print_simple_completion);
267          else
268            {
269              char fname[pupa_strlen (filename) + 2];
270              pupa_strcpy (fname, filename);
271              pupa_sprintf (fname, "%s/", filename);
272              add_completion (fname, "", "files", print_simple_completion);
273            }
274          return 0;
275        }
276    
277      int iterate_dev (const char *devname)
278        {
279          pupa_device_t dev;
280          
281          /* Complete the partition part.  */
282          dev = pupa_device_open (devname);
283          
284          if (dev)
285            {
286              if (dev->disk && dev->disk->has_partitions)
287                add_completion (devname, ",", "disks", print_simple_completion);
288              else
289                add_completion (devname, ")", "disks", print_simple_completion);
290            }
291    
292          return 0;
293        }
294    
295      int iterate_commands (pupa_command_t cmd)
296        {
297          if (cmd->flags & PUPA_COMMAND_FLAG_CMDLINE)
298            add_completion (cmd->name, " ", "commands", print_simple_completion);
299          return 0;
300        }
301      
302      /* Remove blank space on the beginning of the line.  */
303      while (*pos == ' ')
304        pos++;
305    
306      /* Check if the string is a command or path.  */
307      path = pupa_strchr (pos, ' ');
308          
309      if (!path)
310        {
311          /* Tab complete a command.  */
312          len = pupa_strlen (pos);
313                    
314          pupa_iterate_commands (iterate_commands);
315        }
316      else
317        {
318          pos = path;
319    
320          /* Remove blank space on the beginning of the line.  */
321          while (*pos == ' ')
322            pos++;
323            
324          /* Check if this is a completion for a device name.  */
325          if (*pos == '(' && !pupa_strchr (pos, ')'))
326            {
327              /* Check if this is a device or partition.  */
328              char *partition = pupa_strchr (++pos, ',');
329                            
330              if (!partition)
331                {
332                  /* Complete the disk part.  */
333                  len = pupa_strlen (pos);
334                  pupa_disk_dev_iterate (iterate_dev);
335                  if (pupa_errno)
336                    goto fail;
337                }
338              else
339                {
340                  *partition = '\0';
341    
342                  /* Complete the partition part.  */
343                  partdev = pupa_device_open (pos);
344                  *partition = ',';
345                  pupa_errno = PUPA_ERR_NONE;
346      
347                  if (partdev)
348                    {
349                      if (partdev->disk && partdev->disk->has_partitions)
350                        {
351                          pos = partition + 1;
352                          len = pupa_strlen (pos);
353                                        
354                          pupa_partition_iterate (partdev->disk, iterate_part);
355                          if (pupa_errno)
356                            pupa_errno = 0;
357                        }
358    
359                      pupa_device_close (partdev);
360                    }
361                  else
362                    goto fail;
363                }
364            }
365          else
366            {
367              char *device = pupa_file_get_device_name (pos);
368              pupa_device_t dev;
369              pupa_fs_t fs;
370    
371              dev = pupa_device_open (device);
372              if (!dev)
373                goto fail;
374                            
375              fs = pupa_fs_probe (dev);
376              if (pupa_errno)
377                goto fail;
378    
379              pos = pupa_strrchr (pos, '/');
380              if (pos)
381                {
382                  char *dir;
383                  char *dirfile;
384                  pos++;
385                  len = pupa_strlen (pos);
386    
387                  dir = pupa_strchr (path, '/');
388                  if (!dir)
389                    {
390                      *restore = 0;
391                      return 0;
392                    }
393    
394                  dir = pupa_strdup (dir);
395    
396                  /* Cut away the filename part.  */
397                  dirfile = pupa_strrchr (dir, '/');
398                  dirfile[1] = '\0';
399                  
400                  /* Tab complete a file.  */
401                  (fs->dir) (dev, dir, iterate_dir);
402                  if (dev)
403                    pupa_device_close (dev);
404    
405                  pupa_free (device);
406                  pupa_free (dir);
407    
408                  if (pupa_errno)
409                    goto fail;
410                }
411              else
412                {
413                  found = pupa_strdup ("/");
414                  matchstr = "";
415                  numfound = 1;
416                  begin = 0;
417                  end = 1;
418                }
419            }
420                        
421        }
422    
423      /* If more than one match is found those matches will be printed and
424         the prompt should be restored.  */
425      if (numfound > 1)
426        *restore = 1;
427      else
428        *restore = 0;
429    
430      /* Return the part that matches.  */
431      if (end && found)
432        {
433          char *insert;
434          insert = pupa_malloc (end - begin + 1 + sizeof (matchstr));
435          pupa_strncpy (insert, found + begin, end - begin);
436          insert[end - begin] = '\0';
437          if (numfound == 1)
438            pupa_strcat (insert, matchstr);
439          pupa_free (found);
440    
441          return insert;
442        }
443    
444     fail:
445      pupa_free (found);
446      pupa_errno = PUPA_ERR_NONE;
447    
448      return 0;
449    }
450    
451  void  void
452  pupa_cmdline_run (int nested)  pupa_cmdline_run (int nested)
453  {  {
# Line 82  pupa_cmdline_get (const char *prompt, ch Line 503  pupa_cmdline_get (const char *prompt, ch
503    pupa_size_t plen;    pupa_size_t plen;
504    char buf[max_len];    char buf[max_len];
505    int key;    int key;
506      int histpos = 0;
507    auto void cl_insert (const char *str);    auto void cl_insert (const char *str);
508    auto void cl_delete (unsigned len);    auto void cl_delete (unsigned len);
509    auto void cl_print (int pos, int c);    auto void cl_print (int pos, int c);
# Line 167  pupa_cmdline_get (const char *prompt, ch Line 589  pupa_cmdline_get (const char *prompt, ch
589        
590    cl_insert (cmdline);    cl_insert (cmdline);
591    
592      pupa_history_add (buf);
593    
594    while ((key = PUPA_TERM_ASCII_CHAR (pupa_getkey ())) != '\n' && key != '\r')    while ((key = PUPA_TERM_ASCII_CHAR (pupa_getkey ())) != '\n' && key != '\r')
595      {      {
596        if (readline)        if (readline)
# Line 200  pupa_cmdline_get (const char *prompt, ch Line 624  pupa_cmdline_get (const char *prompt, ch
624                break;                break;
625    
626              case 9:     /* Ctrl-i or TAB */              case 9:     /* Ctrl-i or TAB */
627                /* FIXME */                {
628                    char *insert;
629                    int restore;
630                    
631                    /* Backup the next character and make it 0 so it will
632                       be easy to use string functions.  */
633                    char backup = buf[lpos];
634                    buf[lpos] = '\0';
635                    
636    
637                    insert = pupa_tab_complete (buf, &restore);
638                    /* Restore the original string.  */
639                    buf[lpos] = backup;
640                    
641                    if (restore)
642                      {
643                        /* Restore the prompt.  */
644                        pupa_printf ("\n%s%s", prompt, buf);
645                        xpos = plen;
646                        ystart = ypos = (pupa_getxy () & 0xFF);
647                      }
648    
649                    if (insert)
650                      {
651                        cl_insert (insert);
652                        pupa_free (insert);
653                      }
654                  }
655                break;                break;
656    
657              case 11:    /* Ctrl-k */              case 11:    /* Ctrl-k */
# Line 217  pupa_cmdline_get (const char *prompt, ch Line 668  pupa_cmdline_get (const char *prompt, ch
668                break;                break;
669    
670              case 14:    /* Ctrl-n */              case 14:    /* Ctrl-n */
671                /* FIXME */                {
672                break;                  char *hist;
673    
674                    lpos = 0;
675    
676                    if (histpos > 0)
677                      histpos--;
678    
679                    cl_delete (llen);
680                    hist = pupa_history_get (histpos);
681                    cl_insert (hist);
682    
683                    break;
684                  }
685              case 16:    /* Ctrl-p */              case 16:    /* Ctrl-p */
686                /* FIXME */                {
687                    char *hist;
688    
689                    lpos = 0;
690    
691                    if (histpos < hist_used - 1)
692                      histpos++;
693    
694                    cl_delete (llen);
695                    hist = pupa_history_get (histpos);
696    
697                    cl_insert (hist);
698                  }
699                break;                break;
700    
701              case 21:    /* Ctrl-u */              case 21:    /* Ctrl-u */
# Line 282  pupa_cmdline_get (const char *prompt, ch Line 756  pupa_cmdline_get (const char *prompt, ch
756              }              }
757            break;            break;
758          }          }
759    
760          pupa_history_replace (histpos, buf);
761      }      }
762    
763    pupa_putchar ('\n');    pupa_putchar ('\n');

Legend:
Removed from v.1.2  
changed lines
  Added in v.1.3

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26