~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to cmd-line-utils/readline/tilde.c

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */
 
2
 
 
3
/* Copyright (C) 1988,1989 Free Software Foundation, Inc.
 
4
 
 
5
   This file is part of GNU Readline, a library for reading lines
 
6
   of text with interactive input and history editing.
 
7
 
 
8
   Readline is free software; you can redistribute it and/or modify it
 
9
   under the terms of the GNU General Public License as published by the
 
10
   Free Software Foundation; either version 2, or (at your option) any
 
11
   later version.
 
12
 
 
13
   Readline is distributed in the hope that it will be useful, but
 
14
   WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
   General Public License for more details.
 
17
 
 
18
   You should have received a copy of the GNU General Public License
 
19
   along with Readline; see the file COPYING.  If not, write to the Free
 
20
   Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
 
21
 
 
22
#if defined (HAVE_CONFIG_H)
 
23
#  include "config_readline.h"
 
24
#endif
 
25
 
 
26
#if defined (HAVE_UNISTD_H)
 
27
#  ifdef _MINIX
 
28
#    include <sys/types.h>
 
29
#  endif
 
30
#  include <unistd.h>
 
31
#endif
 
32
 
 
33
#if defined (HAVE_STRING_H)
 
34
#  include <string.h>
 
35
#else /* !HAVE_STRING_H */
 
36
#  include <strings.h>
 
37
#endif /* !HAVE_STRING_H */  
 
38
 
 
39
#if defined (HAVE_STDLIB_H)
 
40
#  include <stdlib.h>
 
41
#else
 
42
#  include "ansi_stdlib.h"
 
43
#endif /* HAVE_STDLIB_H */
 
44
 
 
45
#include <sys/types.h>
 
46
#if defined (HAVE_PWD_H)
 
47
#include <pwd.h>
 
48
#endif
 
49
 
 
50
#include "tilde.h"
 
51
 
 
52
#if defined (TEST) || defined (STATIC_MALLOC)
 
53
static void *xmalloc (), *xrealloc ();
 
54
#else
 
55
#  include "xmalloc.h"
 
56
#endif /* TEST || STATIC_MALLOC */
 
57
 
 
58
#if !defined (HAVE_GETPW_DECLS)
 
59
#  if defined (HAVE_GETPWUID)
 
60
extern struct passwd *getpwuid PARAMS((uid_t));
 
61
#  endif
 
62
#  if defined (HAVE_GETPWNAM)
 
63
extern struct passwd *getpwnam PARAMS((const char *));
 
64
#  endif
 
65
#endif /* !HAVE_GETPW_DECLS */
 
66
 
 
67
#if !defined (savestring)
 
68
#define savestring(x) strcpy ((char *)xmalloc (1 + strlen (x)), (x))
 
69
#endif /* !savestring */
 
70
 
 
71
#if !defined (NULL)
 
72
#  if defined (__STDC__)
 
73
#    define NULL ((void *) 0)
 
74
#  else
 
75
#    define NULL 0x0
 
76
#  endif /* !__STDC__ */
 
77
#endif /* !NULL */
 
78
 
 
79
/* If being compiled as part of bash, these will be satisfied from
 
80
   variables.o.  If being compiled as part of readline, they will
 
81
   be satisfied from shell.o. */
 
82
extern char *sh_get_home_dir PARAMS((void));
 
83
extern char *sh_get_env_value PARAMS((const char *));
 
84
 
 
85
/* The default value of tilde_additional_prefixes.  This is set to
 
86
   whitespace preceding a tilde so that simple programs which do not
 
87
   perform any word separation get desired behaviour. */
 
88
static const char *default_prefixes[] =
 
89
  { " ~", "\t~", (const char *)NULL };
 
90
 
 
91
/* The default value of tilde_additional_suffixes.  This is set to
 
92
   whitespace or newline so that simple programs which do not
 
93
   perform any word separation get desired behaviour. */
 
94
static const char *default_suffixes[] =
 
95
  { " ", "\n", (const char *)NULL };
 
96
 
 
97
/* If non-null, this contains the address of a function that the application
 
98
   wants called before trying the standard tilde expansions.  The function
 
99
   is called with the text sans tilde, and returns a malloc()'ed string
 
100
   which is the expansion, or a NULL pointer if the expansion fails. */
 
101
tilde_hook_func_t *tilde_expansion_preexpansion_hook = (tilde_hook_func_t *)NULL;
 
102
 
 
103
/* If non-null, this contains the address of a function to call if the
 
104
   standard meaning for expanding a tilde fails.  The function is called
 
105
   with the text (sans tilde, as in "foo"), and returns a malloc()'ed string
 
106
   which is the expansion, or a NULL pointer if there is no expansion. */
 
107
tilde_hook_func_t *tilde_expansion_failure_hook = (tilde_hook_func_t *)NULL;
 
108
 
 
109
/* When non-null, this is a NULL terminated array of strings which
 
110
   are duplicates for a tilde prefix.  Bash uses this to expand
 
111
   `=~' and `:~'. */
 
112
char **tilde_additional_prefixes = (char **)default_prefixes;
 
113
 
 
114
/* When non-null, this is a NULL terminated array of strings which match
 
115
   the end of a username, instead of just "/".  Bash sets this to
 
116
   `:' and `=~'. */
 
117
char **tilde_additional_suffixes = (char **)default_suffixes;
 
118
 
 
119
static int tilde_find_prefix PARAMS((const char *, int *));
 
120
static int tilde_find_suffix PARAMS((const char *));
 
121
static char *isolate_tilde_prefix PARAMS((const char *, int *));
 
122
static char *glue_prefix_and_suffix PARAMS((char *, const char *, int));
 
123
 
 
124
/* Find the start of a tilde expansion in STRING, and return the index of
 
125
   the tilde which starts the expansion.  Place the length of the text
 
126
   which identified this tilde starter in LEN, excluding the tilde itself. */
 
127
static int
 
128
tilde_find_prefix (string, len)
 
129
     const char *string;
 
130
     int *len;
 
131
{
 
132
  register int i, j, string_len;
 
133
  register char **prefixes;
 
134
 
 
135
  prefixes = tilde_additional_prefixes;
 
136
 
 
137
  string_len = strlen (string);
 
138
  *len = 0;
 
139
 
 
140
  if (*string == '\0' || *string == '~')
 
141
    return (0);
 
142
 
 
143
  if (prefixes)
 
144
    {
 
145
      for (i = 0; i < string_len; i++)
 
146
        {
 
147
          for (j = 0; prefixes[j]; j++)
 
148
            {
 
149
              if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0)
 
150
                {
 
151
                  *len = strlen (prefixes[j]) - 1;
 
152
                  return (i + *len);
 
153
                }
 
154
            }
 
155
        }
 
156
    }
 
157
  return (string_len);
 
158
}
 
159
 
 
160
/* Find the end of a tilde expansion in STRING, and return the index of
 
161
   the character which ends the tilde definition.  */
 
162
static int
 
163
tilde_find_suffix (string)
 
164
     const char *string;
 
165
{
 
166
  register int i, j, string_len;
 
167
  register char **suffixes;
 
168
 
 
169
  suffixes = tilde_additional_suffixes;
 
170
  string_len = strlen (string);
 
171
 
 
172
  for (i = 0; i < string_len; i++)
 
173
    {
 
174
#if defined (__MSDOS__)
 
175
      if (string[i] == '/' || string[i] == '\\' /* || !string[i] */)
 
176
#else
 
177
      if (string[i] == '/' /* || !string[i] */)
 
178
#endif
 
179
        break;
 
180
 
 
181
      for (j = 0; suffixes && suffixes[j]; j++)
 
182
        {
 
183
          if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0)
 
184
            return (i);
 
185
        }
 
186
    }
 
187
  return (i);
 
188
}
 
189
 
 
190
/* Return a new string which is the result of tilde expanding STRING. */
 
191
char *
 
192
tilde_expand (string)
 
193
     const char *string;
 
194
{
 
195
  char *result;
 
196
  int result_size, result_index;
 
197
 
 
198
  result_index = result_size = 0;
 
199
  if ((result = strchr (string, '~')))
 
200
    result = (char *)xmalloc (result_size = (strlen (string) + 16));
 
201
  else
 
202
    result = (char *)xmalloc (result_size = (strlen (string) + 1));
 
203
 
 
204
  /* Scan through STRING expanding tildes as we come to them. */
 
205
  while (1)
 
206
    {
 
207
      register int start, end;
 
208
      char *tilde_word, *expansion;
 
209
      int len;
 
210
 
 
211
      /* Make START point to the tilde which starts the expansion. */
 
212
      start = tilde_find_prefix (string, &len);
 
213
 
 
214
      /* Copy the skipped text into the result. */
 
215
      if ((result_index + start + 1) > result_size)
 
216
        result = (char *)xrealloc (result, 1 + (result_size += (start + 20)));
 
217
 
 
218
      strncpy (result + result_index, string, start);
 
219
      result_index += start;
 
220
 
 
221
      /* Advance STRING to the starting tilde. */
 
222
      string += start;
 
223
 
 
224
      /* Make END be the index of one after the last character of the
 
225
         username. */
 
226
      end = tilde_find_suffix (string);
 
227
 
 
228
      /* If both START and END are zero, we are all done. */
 
229
      if (!start && !end)
 
230
        break;
 
231
 
 
232
      /* Expand the entire tilde word, and copy it into RESULT. */
 
233
      tilde_word = (char *)xmalloc (1 + end);
 
234
      strncpy (tilde_word, string, end);
 
235
      tilde_word[end] = '\0';
 
236
      string += end;
 
237
 
 
238
      expansion = tilde_expand_word (tilde_word);
 
239
      free (tilde_word);
 
240
 
 
241
      len = strlen (expansion);
 
242
#ifdef __CYGWIN__
 
243
      /* Fix for Cygwin to prevent ~user/xxx from expanding to //xxx when
 
244
         $HOME for `user' is /.  On cygwin, // denotes a network drive. */
 
245
      if (len > 1 || *expansion != '/' || *string != '/')
 
246
#endif
 
247
        {
 
248
          if ((result_index + len + 1) > result_size)
 
249
            result = (char *)xrealloc (result, 1 + (result_size += (len + 20)));
 
250
 
 
251
          strcpy (result + result_index, expansion);
 
252
          result_index += len;
 
253
        }
 
254
      free (expansion);
 
255
    }
 
256
 
 
257
  result[result_index] = '\0';
 
258
 
 
259
  return (result);
 
260
}
 
261
 
 
262
/* Take FNAME and return the tilde prefix we want expanded.  If LENP is
 
263
   non-null, the index of the end of the prefix into FNAME is returned in
 
264
   the location it points to. */
 
265
static char *
 
266
isolate_tilde_prefix (fname, lenp)
 
267
     const char *fname;
 
268
     int *lenp;
 
269
{
 
270
  char *ret;
 
271
  int i;
 
272
 
 
273
  ret = (char *)xmalloc (strlen (fname));
 
274
#if defined (__MSDOS__)
 
275
  for (i = 1; fname[i] && fname[i] != '/' && fname[i] != '\\'; i++)
 
276
#else
 
277
  for (i = 1; fname[i] && fname[i] != '/'; i++)
 
278
#endif
 
279
    ret[i - 1] = fname[i];
 
280
  ret[i - 1] = '\0';
 
281
  if (lenp)
 
282
    *lenp = i;
 
283
  return ret;
 
284
}
 
285
 
 
286
#if 0
 
287
/* Public function to scan a string (FNAME) beginning with a tilde and find
 
288
   the portion of the string that should be passed to the tilde expansion
 
289
   function.  Right now, it just calls tilde_find_suffix and allocates new
 
290
   memory, but it can be expanded to do different things later. */
 
291
char *
 
292
tilde_find_word (fname, flags, lenp)
 
293
     const char *fname;
 
294
     int flags, *lenp;
 
295
{
 
296
  int x;
 
297
  char *r;
 
298
 
 
299
  x = tilde_find_suffix (fname);
 
300
  if (x == 0)
 
301
    {
 
302
      r = savestring (fname);
 
303
      if (lenp)
 
304
        *lenp = 0;
 
305
    }
 
306
  else
 
307
    {
 
308
      r = (char *)xmalloc (1 + x);
 
309
      strncpy (r, fname, x);
 
310
      r[x] = '\0';
 
311
      if (lenp)
 
312
        *lenp = x;
 
313
    }
 
314
 
 
315
  return r;
 
316
}
 
317
#endif
 
318
 
 
319
/* Return a string that is PREFIX concatenated with SUFFIX starting at
 
320
   SUFFIND. */
 
321
static char *
 
322
glue_prefix_and_suffix (prefix, suffix, suffind)
 
323
     char *prefix;
 
324
     const char *suffix;
 
325
     int suffind;
 
326
{
 
327
  char *ret;
 
328
  int plen, slen;
 
329
 
 
330
  plen = (prefix && *prefix) ? strlen (prefix) : 0;
 
331
  slen = strlen (suffix + suffind);
 
332
  ret = (char *)xmalloc (plen + slen + 1);
 
333
  if (plen)
 
334
    strcpy (ret, prefix);
 
335
  strcpy (ret + plen, suffix + suffind);
 
336
  return ret;
 
337
}
 
338
 
 
339
/* Do the work of tilde expansion on FILENAME.  FILENAME starts with a
 
340
   tilde.  If there is no expansion, call tilde_expansion_failure_hook.
 
341
   This always returns a newly-allocated string, never static storage. */
 
342
char *
 
343
tilde_expand_word (filename)
 
344
     const char *filename;
 
345
{
 
346
  char *dirname, *expansion, *username;
 
347
  int user_len;
 
348
  struct passwd *user_entry;
 
349
 
 
350
  if (filename == 0)
 
351
    return ((char *)NULL);
 
352
 
 
353
  if (*filename != '~')
 
354
    return (savestring (filename));
 
355
 
 
356
  /* A leading `~/' or a bare `~' is *always* translated to the value of
 
357
     $HOME or the home directory of the current user, regardless of any
 
358
     preexpansion hook. */
 
359
  if (filename[1] == '\0' || filename[1] == '/')
 
360
    {
 
361
      /* Prefix $HOME to the rest of the string. */
 
362
      expansion = sh_get_env_value ("HOME");
 
363
 
 
364
      /* If there is no HOME variable, look up the directory in
 
365
         the password database. */
 
366
      if (expansion == 0)
 
367
        expansion = sh_get_home_dir ();
 
368
 
 
369
      return (glue_prefix_and_suffix (expansion, filename, 1));
 
370
    }
 
371
 
 
372
  username = isolate_tilde_prefix (filename, &user_len);
 
373
 
 
374
  if (tilde_expansion_preexpansion_hook)
 
375
    {
 
376
      expansion = (*tilde_expansion_preexpansion_hook) (username);
 
377
      if (expansion)
 
378
        {
 
379
          dirname = glue_prefix_and_suffix (expansion, filename, user_len);
 
380
          free (username);
 
381
          free (expansion);
 
382
          return (dirname);
 
383
        }
 
384
    }
 
385
 
 
386
  /* No preexpansion hook, or the preexpansion hook failed.  Look in the
 
387
     password database. */
 
388
  dirname = (char *)NULL;
 
389
#if defined (HAVE_GETPWNAM)
 
390
  user_entry = getpwnam (username);
 
391
#else
 
392
  user_entry = 0;
 
393
#endif
 
394
  if (user_entry == 0)
 
395
    {
 
396
      /* If the calling program has a special syntax for expanding tildes,
 
397
         and we couldn't find a standard expansion, then let them try. */
 
398
      if (tilde_expansion_failure_hook)
 
399
        {
 
400
          expansion = (*tilde_expansion_failure_hook) (username);
 
401
          if (expansion)
 
402
            {
 
403
              dirname = glue_prefix_and_suffix (expansion, filename, user_len);
 
404
              free (expansion);
 
405
            }
 
406
        }
 
407
      /* If we don't have a failure hook, or if the failure hook did not
 
408
         expand the tilde, return a copy of what we were passed. */
 
409
      if (dirname == 0)
 
410
        dirname = savestring (filename);
 
411
    }
 
412
#if defined (HAVE_GETPWENT)
 
413
  else
 
414
    dirname = glue_prefix_and_suffix (user_entry->pw_dir, filename, user_len);
 
415
#endif
 
416
 
 
417
  free (username);
 
418
#if defined (HAVE_GETPWENT)
 
419
  endpwent ();
 
420
#endif
 
421
  return (dirname);
 
422
}
 
423
 
 
424
 
 
425
#if defined (TEST)
 
426
#undef NULL
 
427
#include <stdio.h>
 
428
 
 
429
main (argc, argv)
 
430
     int argc;
 
431
     char **argv;
 
432
{
 
433
  char *result, line[512];
 
434
  int done = 0;
 
435
 
 
436
  while (!done)
 
437
    {
 
438
      printf ("~expand: ");
 
439
      fflush (stdout);
 
440
 
 
441
      if (!gets (line))
 
442
        strcpy (line, "done");
 
443
 
 
444
      if ((strcmp (line, "done") == 0) ||
 
445
          (strcmp (line, "quit") == 0) ||
 
446
          (strcmp (line, "exit") == 0))
 
447
        {
 
448
          done = 1;
 
449
          break;
 
450
        }
 
451
 
 
452
      result = tilde_expand (line);
 
453
      printf ("  --> %s\n", result);
 
454
      free (result);
 
455
    }
 
456
  exit (0);
 
457
}
 
458
 
 
459
static void memory_error_and_abort ();
 
460
 
 
461
static void *
 
462
xmalloc (bytes)
 
463
     size_t bytes;
 
464
{
 
465
  void *temp = (char *)malloc (bytes);
 
466
 
 
467
  if (!temp)
 
468
    memory_error_and_abort ();
 
469
  return (temp);
 
470
}
 
471
 
 
472
static void *
 
473
xrealloc (pointer, bytes)
 
474
     void *pointer;
 
475
     int bytes;
 
476
{
 
477
  void *temp;
 
478
 
 
479
  if (!pointer)
 
480
    temp = malloc (bytes);
 
481
  else
 
482
    temp = realloc (pointer, bytes);
 
483
 
 
484
  if (!temp)
 
485
    memory_error_and_abort ();
 
486
 
 
487
  return (temp);
 
488
}
 
489
 
 
490
static void
 
491
memory_error_and_abort ()
 
492
{
 
493
  fprintf (stderr, "readline: out of virtual memory\n");
 
494
  abort ();
 
495
}
 
496
 
 
497
/*
 
498
 * Local variables:
 
499
 * compile-command: "gcc -g -DTEST -o tilde tilde.c"
 
500
 * end:
 
501
 */
 
502
#endif /* TEST */