|
|
1.1 ! root 1: /* tilde.c -- Tilde expansion code (~/foo := $HOME/foo). */ ! 2: ! 3: /* Copyright (C) 1988,1989, 1991 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 ! 9: it under the terms of the GNU General Public License as published by ! 10: the Free Software Foundation; either version 2 of the License, or ! 11: (at your option) any later version. ! 12: ! 13: Readline is distributed in the hope that it will be useful, ! 14: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 16: GNU General Public License for more details. ! 17: ! 18: You should have received a copy of the GNU General Public License ! 19: along with this program; if not, write to the Free Software ! 20: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 21: ! 22: #include "sysdep.h" ! 23: ! 24: #ifndef __MSDOS__ ! 25: #include <pwd.h> ! 26: #endif ! 27: ! 28: #ifdef __GNUC__ ! 29: #undef alloca ! 30: #define alloca(x) __builtin_alloca(x) ! 31: #endif ! 32: ! 33: #ifndef savestring ! 34: #ifdef xmalloc ! 35: #define savestring(x) (char *)strcpy ((char *)malloc (1 + strlen (x)), (x)) ! 36: #else ! 37: #define savestring(x) (char *)strcpy (xmalloc (1 + strlen (x)), (x)) ! 38: #endif /* xmalloc */ ! 39: #endif ! 40: ! 41: typedef int Function (); ! 42: #if !defined (NULL) ! 43: # define NULL 0x0 ! 44: #endif ! 45: ! 46: #ifndef xmalloc ! 47: #if defined (TEST) ! 48: static char *xmalloc (), *xrealloc (); ! 49: #else ! 50: extern char *xmalloc (), *xrealloc (); ! 51: #endif /* TEST */ ! 52: #endif /* !xmalloc */ ! 53: ! 54: /* The default value of tilde_additional_prefixes. This is set to ! 55: whitespace preceding a tilde so that simple programs which do not ! 56: perform any word separation get desired behaviour. */ ! 57: static char *default_prefixes[] = ! 58: { " ~", "\t~", (char *)NULL }; ! 59: ! 60: /* The default value of tilde_additional_suffixes. This is set to ! 61: whitespace or newline so that simple programs which do not ! 62: perform any word separation get desired behaviour. */ ! 63: static char *default_suffixes[] = ! 64: { " ", "\n", (char *)NULL }; ! 65: ! 66: /* If non-null, this contains the address of a function to call if the ! 67: standard meaning for expanding a tilde fails. The function is called ! 68: with the text (sans tilde, as in "foo"), and returns a malloc()'ed string ! 69: which is the expansion, or a NULL pointer if there is no expansion. */ ! 70: Function *tilde_expansion_failure_hook = (Function *)NULL; ! 71: ! 72: /* When non-null, this is a NULL terminated array of strings which ! 73: are duplicates for a tilde prefix. Bash uses this to expand ! 74: `=~' and `:~'. */ ! 75: char **tilde_additional_prefixes = default_prefixes; ! 76: ! 77: /* When non-null, this is a NULL terminated array of strings which match ! 78: the end of a username, instead of just "/". Bash sets this to ! 79: `:' and `=~'. */ ! 80: char **tilde_additional_suffixes = default_suffixes; ! 81: ! 82: /* Find the start of a tilde expansion in STRING, and return the index of ! 83: the tilde which starts the expansion. Place the length of the text ! 84: which identified this tilde starter in LEN, excluding the tilde itself. */ ! 85: static int ! 86: tilde_find_prefix (string, len) ! 87: char *string; ! 88: int *len; ! 89: { ! 90: register int i, j, string_len; ! 91: register char **prefixes = tilde_additional_prefixes; ! 92: ! 93: string_len = strlen (string); ! 94: *len = 0; ! 95: ! 96: if (!*string || *string == '~') ! 97: return (0); ! 98: ! 99: if (prefixes) ! 100: { ! 101: for (i = 0; i < string_len; i++) ! 102: { ! 103: for (j = 0; prefixes[j]; j++) ! 104: { ! 105: if (strncmp (string + i, prefixes[j], strlen (prefixes[j])) == 0) ! 106: { ! 107: *len = strlen (prefixes[j]) - 1; ! 108: return (i + *len); ! 109: } ! 110: } ! 111: } ! 112: } ! 113: return (string_len); ! 114: } ! 115: ! 116: /* Find the end of a tilde expansion in STRING, and return the index of ! 117: the character which ends the tilde definition. */ ! 118: static int ! 119: tilde_find_suffix (string) ! 120: char *string; ! 121: { ! 122: register int i, j, string_len; ! 123: register char **suffixes = tilde_additional_suffixes; ! 124: ! 125: string_len = strlen (string); ! 126: ! 127: for (i = 0; i < string_len; i++) ! 128: { ! 129: if (string[i] == '/' || !string[i]) ! 130: break; ! 131: ! 132: for (j = 0; suffixes && suffixes[j]; j++) ! 133: { ! 134: if (strncmp (string + i, suffixes[j], strlen (suffixes[j])) == 0) ! 135: return (i); ! 136: } ! 137: } ! 138: return (i); ! 139: } ! 140: ! 141: /* Return a new string which is the result of tilde expanding FILENAME. */ ! 142: char * ! 143: tilde_expand (filename) ! 144: char *filename; ! 145: { ! 146: char *result, *tilde_expand_word (); ! 147: int result_size, result_index; ! 148: ! 149: result_size = result_index = 0; ! 150: result = (char *)NULL; ! 151: ! 152: /* Scan through FILENAME expanding tildes as we come to them. */ ! 153: while (1) ! 154: { ! 155: register int start, end; ! 156: char *tilde_word, *expansion; ! 157: int len; ! 158: ! 159: /* Make START point to the tilde which starts the expansion. */ ! 160: start = tilde_find_prefix (filename, &len); ! 161: ! 162: /* Copy the skipped text into the result. */ ! 163: /* This test is always true the first time, since result_index ! 164: is 0, result_size is 0, and start is >= 0. So we malloc here. */ ! 165: if ((result_index + start + 1) > result_size) { ! 166: result_size += (start + 20); ! 167: if (result == NULL) ! 168: result = (char *)xmalloc ( 1 + result_size); ! 169: else ! 170: result = (char *)xrealloc (result, 1 + result_size); ! 171: } ! 172: ! 173: strncpy (result + result_index, filename, start); ! 174: result_index += start; ! 175: ! 176: /* Advance FILENAME upto the starting tilde. */ ! 177: filename += start; ! 178: ! 179: /* Make END be the index of one after the last character of the ! 180: username. */ ! 181: end = tilde_find_suffix (filename); ! 182: ! 183: /* If both START and END are zero, we are all done. */ ! 184: if (!start && !end) ! 185: break; ! 186: ! 187: /* Expand the entire tilde word, and copy it into RESULT. */ ! 188: tilde_word = (char *)xmalloc (1 + end); ! 189: strncpy (tilde_word, filename, end); ! 190: tilde_word[end] = '\0'; ! 191: filename += end; ! 192: ! 193: expansion = tilde_expand_word (tilde_word); ! 194: free (tilde_word); ! 195: ! 196: len = strlen (expansion); ! 197: if ((result_index + len + 1) > result_size) ! 198: result = (char *)xrealloc (result, 1 + (result_size += (len + 20))); ! 199: ! 200: strcpy (result + result_index, expansion); ! 201: result_index += len; ! 202: free (expansion); ! 203: } ! 204: ! 205: result[result_index] = '\0'; ! 206: ! 207: return (result); ! 208: } ! 209: ! 210: /* Do the work of tilde expansion on FILENAME. FILENAME starts with a ! 211: tilde. If there is no expansion, call tilde_expansion_failure_hook. */ ! 212: char * ! 213: tilde_expand_word (filename) ! 214: char *filename; ! 215: { ! 216: char *dirname = filename ? savestring (filename) : (char *)NULL; ! 217: ! 218: if (dirname && *dirname == '~') ! 219: { ! 220: char *temp_name; ! 221: if (!dirname[1] || dirname[1] == '/') ! 222: { ! 223: /* Prepend $HOME to the rest of the string. */ ! 224: char *temp_home = (char *)getenv ("HOME"); ! 225: ! 226: temp_name = (char *)alloca (1 + strlen (&dirname[1]) ! 227: + (temp_home? strlen (temp_home) : 0)); ! 228: temp_name[0] = '\0'; ! 229: if (temp_home) ! 230: strcpy (temp_name, temp_home); ! 231: strcat (temp_name, &dirname[1]); ! 232: free (dirname); ! 233: dirname = savestring (temp_name); ! 234: } ! 235: else ! 236: { ! 237: #ifndef __MSDOS__ ! 238: struct passwd *getpwnam (), *user_entry; ! 239: #endif ! 240: char *username = (char *)alloca (257); ! 241: int i, c; ! 242: ! 243: for (i = 1; c = dirname[i]; i++) ! 244: { ! 245: if (c == '/') ! 246: break; ! 247: else ! 248: username[i - 1] = c; ! 249: } ! 250: username[i - 1] = '\0'; ! 251: ! 252: #ifndef __MSDOS__ ! 253: if (!(user_entry = getpwnam (username))) ! 254: { ! 255: /* If the calling program has a special syntax for ! 256: expanding tildes, and we couldn't find a standard ! 257: expansion, then let them try. */ ! 258: #endif ! 259: if (tilde_expansion_failure_hook) ! 260: { ! 261: char *expansion; ! 262: ! 263: expansion = ! 264: (char *)(*tilde_expansion_failure_hook) (username); ! 265: ! 266: if (expansion) ! 267: { ! 268: temp_name = (char *)alloca (1 + strlen (expansion) ! 269: + strlen (&dirname[i])); ! 270: strcpy (temp_name, expansion); ! 271: strcat (temp_name, &dirname[i]); ! 272: free (expansion); ! 273: goto return_name; ! 274: } ! 275: } ! 276: /* We shouldn't report errors. */ ! 277: #ifndef __MSDOS__ ! 278: } ! 279: else ! 280: { ! 281: temp_name = (char *)alloca (1 + strlen (user_entry->pw_dir) ! 282: + strlen (&dirname[i])); ! 283: strcpy (temp_name, user_entry->pw_dir); ! 284: strcat (temp_name, &dirname[i]); ! 285: #endif ! 286: return_name: ! 287: free (dirname); ! 288: dirname = savestring (temp_name); ! 289: #ifndef __MSDOS__ ! 290: } ! 291: endpwent (); ! 292: #endif ! 293: } ! 294: } ! 295: return (dirname); ! 296: } ! 297: ! 298: #if defined (TEST) ! 299: #undef NULL ! 300: #include <stdio.h> ! 301: ! 302: main (argc, argv) ! 303: int argc; ! 304: char **argv; ! 305: { ! 306: char *result, line[512]; ! 307: int done = 0; ! 308: ! 309: while (!done) ! 310: { ! 311: printf ("~expand: "); ! 312: fflush (stdout); ! 313: ! 314: if (!gets (line)) ! 315: strcpy (line, "done"); ! 316: ! 317: if ((strcmp (line, "done") == 0) || ! 318: (strcmp (line, "quit") == 0) || ! 319: (strcmp (line, "exit") == 0)) ! 320: { ! 321: done = 1; ! 322: break; ! 323: } ! 324: ! 325: result = tilde_expand (line); ! 326: printf (" --> %s\n", result); ! 327: free (result); ! 328: } ! 329: exit (0); ! 330: } ! 331: ! 332: static void memory_error_and_abort (); ! 333: ! 334: static char * ! 335: xmalloc (bytes) ! 336: int bytes; ! 337: { ! 338: char *temp = (char *)malloc (bytes); ! 339: ! 340: if (!temp) ! 341: memory_error_and_abort (); ! 342: return (temp); ! 343: } ! 344: ! 345: static char * ! 346: xrealloc (pointer, bytes) ! 347: char *pointer; ! 348: int bytes; ! 349: { ! 350: char *temp; ! 351: ! 352: if (!pointer) ! 353: temp = (char *)malloc (bytes); ! 354: else ! 355: temp = (char *)realloc (pointer, bytes); ! 356: ! 357: if (!temp) ! 358: memory_error_and_abort (); ! 359: ! 360: return (temp); ! 361: } ! 362: ! 363: static void ! 364: memory_error_and_abort () ! 365: { ! 366: fprintf (stderr, "readline: Out of virtual memory!\n"); ! 367: abort (); ! 368: } ! 369: ! 370: /* ! 371: * Local variables: ! 372: * compile-command: "gcc -g -DTEST -o tilde tilde.c" ! 373: * end: ! 374: */ ! 375: #endif /* TEST */ ! 376:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.