diff options
author | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
commit | 487ca4806cc046076293cf6cc5fbba0db282bac7 (patch) | |
tree | 847b412ab5158dd7bdd7ed7e5a4cc3fbca94be32 /Build/source/texk/kpathsea/expand.c | |
parent | a3d3111bfe26b8e5f5bc6049dfb2a4ca2edc7881 (diff) |
texk 1
git-svn-id: svn://tug.org/texlive/trunk@1485 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/kpathsea/expand.c')
-rw-r--r-- | Build/source/texk/kpathsea/expand.c | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/Build/source/texk/kpathsea/expand.c b/Build/source/texk/kpathsea/expand.c new file mode 100644 index 00000000000..78ea662f566 --- /dev/null +++ b/Build/source/texk/kpathsea/expand.c @@ -0,0 +1,359 @@ +/* expand.c: general expansion. + + Copyright 1993, 94, 95, 96, 97, 98, 05 Karl Berry & Olaf Weber. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include <kpathsea/config.h> + +#include <kpathsea/c-pathch.h> +#include <kpathsea/expand.h> +#include <kpathsea/pathsearch.h> +#include <kpathsea/tilde.h> +#include <kpathsea/variable.h> +#include <kpathsea/concatn.h> +#include <kpathsea/absolute.h> +#include <kpathsea/str-list.h> + +/* Do variable expansion first so ~${USER} works. (Besides, it's what the + shells do.) */ + +string +kpse_expand P1C(const_string, s) +{ + string var_expansion = kpse_var_expand (s); + string tilde_expansion = kpse_tilde_expand (var_expansion); + + /* `kpse_var_expand' always gives us new memory; `kpse_tilde_expand' + doesn't, necessarily. So be careful that we don't free what we are + about to return. */ + if (tilde_expansion != var_expansion) + free (var_expansion); + + return tilde_expansion; +} + + +/* Forward declarations of functions from the original expand.c */ +static str_list_type brace_expand P1H(const_string*); + +/* If $KPSE_DOT is defined in the environment, prepend it to any relative + path components. */ + +static string +kpse_expand_kpse_dot P1C(string, path) +{ + string ret, elt; + string kpse_dot = getenv("KPSE_DOT"); +#ifdef MSDOS + boolean malloced_kpse_dot = false; +#endif + + if (kpse_dot == NULL) + return path; + ret = (string)xmalloc(1); + *ret = 0; + +#ifdef MSDOS + /* Some setups of ported Bash force $KPSE_DOT to have the //d/foo/bar + form (when `pwd' is used), which is not understood by libc and the OS. + Convert them back to the usual d:/foo/bar form. */ + if (kpse_dot[0] == '/' && kpse_dot[1] == '/' + && kpse_dot[2] >= 'A' && kpse_dot[2] <= 'z' && kpse_dot[3] == '/') { + kpse_dot++; + kpse_dot = xstrdup (kpse_dot); + kpse_dot[0] = kpse_dot[1]; /* drive letter */ + kpse_dot[1] = ':'; + malloced_kpse_dot = true; + } +#endif + + for (elt = kpse_path_element (path); elt; elt = kpse_path_element (NULL)) { + string save_ret = ret; + /* We assume that the !! magic is only used on absolute components. + Single "." gets special treatment, as does "./" or its equivalent. */ + if (kpse_absolute_p (elt, false) || (elt[0] == '!' && elt[1] == '!')) { + ret = concat3(ret, elt, ENV_SEP_STRING); + } else if (elt[0] == '.' && elt[1] == 0) { + ret = concat3 (ret, kpse_dot, ENV_SEP_STRING); +#ifndef VMS + } else if (elt[0] == '.' && IS_DIR_SEP(elt[1])) { + ret = concatn (ret, kpse_dot, elt + 1, ENV_SEP_STRING, NULL); + } else { + ret = concatn (ret, kpse_dot, DIR_SEP_STRING, elt, ENV_SEP_STRING, NULL); +#endif + } + free (save_ret); + } + +#ifdef MSDOS + if (malloced_kpse_dot) free (kpse_dot); +#endif + + ret[strlen (ret) - 1] = 0; + return ret; +} + +/* Do brace expansion on ELT; then do variable and ~ expansion on each + element of the result; then do brace expansion again, in case a + variable definition contained braces (e.g., $TEXMF). Return a + string comprising all of the results separated by ENV_SEP_STRING. */ + +static string +kpse_brace_expand_element P1C(const_string, elt) +{ + unsigned i; + str_list_type expansions = brace_expand (&elt); + string ret = (string)xmalloc (1); + *ret = 0; + + for (i = 0; i != STR_LIST_LENGTH(expansions); i++) { + /* Do $ and ~ expansion on each element. */ + string x = kpse_expand (STR_LIST_ELT(expansions,i)); + string save_ret = ret; + if (!STREQ (x, STR_LIST_ELT(expansions,i))) { + /* If we did any expansions, do brace expansion again. Since + recursive variable definitions are not allowed, this recursion + must terminate. (In practice, it's unlikely there will ever be + more than one level of recursion.) */ + string save_x = x; + x = kpse_brace_expand_element (x); + free (save_x); + } + ret = concat3 (ret, x, ENV_SEP_STRING); + free (save_ret); + free (x); + } + for (i = 0; i != STR_LIST_LENGTH(expansions); ++i) { + free(STR_LIST_ELT(expansions,i)); + } + str_list_free(&expansions); + ret[strlen (ret) - 1] = 0; /* waste the trailing null */ + return ret; +} + +/* Be careful to not waste all the memory we allocate for each element. */ + +string +kpse_brace_expand P1C(const_string, path) +{ + string kpse_dot_expansion; + string elt; + unsigned len; + /* Must do variable expansion first because if we have + foo = .:~ + TEXINPUTS = $foo + we want to end up with TEXINPUTS = .:/home/karl. + Since kpse_path_element is not reentrant, we must get all + the path elements before we start the loop. */ + string xpath = kpse_var_expand (path); + string ret = (string)xmalloc (1); + *ret = 0; + + for (elt = kpse_path_element (xpath); elt; elt = kpse_path_element (NULL)) { + string save_ret = ret; + /* Do brace expansion first, so tilde expansion happens in {~ka,~kb}. */ + string expansion = kpse_brace_expand_element (elt); + ret = concat3 (ret, expansion, ENV_SEP_STRING); + free (expansion); + free (save_ret); + } + + /* Waste the last byte by overwriting the trailing env_sep with a null. */ + len = strlen (ret); + if (len != 0) + ret[len - 1] = 0; + free (xpath); + + kpse_dot_expansion = kpse_expand_kpse_dot (ret); + if (kpse_dot_expansion != ret) + free (ret); + + return kpse_dot_expansion; +} + +/* Expand all special constructs in a path, and include only the actually + existing directories in the result. */ +string +kpse_path_expand P1C(const_string, path) +{ + string ret; + string xpath; + string elt; + unsigned len; + + /* Initialise ret to the empty string. */ + ret = (string)xmalloc (1); + *ret = 0; + len = 0; + + /* Expand variables and braces first. */ + xpath = kpse_brace_expand (path); + + /* Now expand each of the path elements, printing the results */ + for (elt = kpse_path_element (xpath); elt; elt = kpse_path_element (NULL)) { + str_llist_type *dirs; + + /* Skip and ignore magic leading chars. */ + if (*elt == '!' && *(elt + 1) == '!') + elt += 2; + + /* Search the disk for all dirs in the component specified. + Be faster to check the database, but this is more reliable. */ + dirs = kpse_element_dirs (elt); + if (dirs && *dirs) { + str_llist_elt_type *dir; + + for (dir = *dirs; dir; dir = STR_LLIST_NEXT (*dir)) { + string thedir = STR_LLIST (*dir); + unsigned dirlen = strlen (thedir); + string save_ret = ret; + /* We need to retain trailing slash if that's the root directory. + * On unix, "/" is root dir, "" often taken to be current dir. + * On windows, "C:/" is root dir of drive C, and "C:" is current + * on drive C. There's no need to look at other cases, like UNC + * names. + */ + if (dirlen == 1 || (dirlen == 3 && NAME_BEGINS_WITH_DEVICE (thedir) + && IS_DIR_SEP (thedir[2]))) { + ret = concat3 (ret, thedir, ENV_SEP_STRING); + len += dirlen + 1; + ret[len - 1] = ENV_SEP; + } else { + ret = concat (ret, thedir); + len += dirlen; + ret [len - 1] = ENV_SEP; + } + free (save_ret); + } + } + } + /* Get rid of trailing ':', if any. */ + if (len != 0) + ret[len - 1] = 0; + return ret; +} + +/* ... */ +static void expand_append P3C(str_list_type*, partial, + const_string, text, const_string, p) +{ + string new_string; + unsigned len; + str_list_type tmp; + tmp = str_list_init(); + len = p - text; + new_string = (string)xmalloc(len+1); + strncpy(new_string, text, len); + new_string[len]=0; + str_list_add(&tmp, new_string); + str_list_concat_elements(partial, tmp); +} + + + +static str_list_type brace_expand P1C(const_string *, text) +{ + str_list_type result, partial, recurse; + const_string p; + result = str_list_init(); + partial = str_list_init(); + for (p = *text; *p && *p != '}'; ++p) { + /* FIXME: Should be IS_ENV_SEP(*p) */ + if (*p == ENV_SEP || *p == ',') { + expand_append(&partial, *text, p); + str_list_concat(&result, partial); + str_list_free(&partial); + *text = p+1; + partial = str_list_init(); + } else if (*p == '{') { + expand_append(&partial, *text, p); + ++p; + recurse = brace_expand(&p); + str_list_concat_elements(&partial, recurse); + str_list_free(&recurse); + /* Check for missing closing brace. */ + if (*p != '}') { + WARNING1 ("%s: Unmatched {", *text); + } + *text = p+1; + } else if (*p == '$') { + /* Skip ${VAR} */ + if (*(p+1) == '{') + for (p+=2; *p!='}';++p); + } + } + expand_append(&partial, *text, p); + str_list_concat(&result, partial); + str_list_free(&partial); + *text = p; + return result; +} + + + +#if defined (TEST) +#include <stdio.h> + +fatal_error (format, arg1, arg2) + char *format, *arg1, *arg2; +{ + report_error (format, arg1, arg2); + exit (1); +} + +report_error (format, arg1, arg2) + char *format, *arg1, *arg2; +{ + fprintf (stderr, format, arg1, arg2); + fprintf (stderr, "\n"); +} + +main () +{ + char example[256]; + + for (;;) + { + char **result; + int i; + + fprintf (stderr, "brace_expand> "); + + if ((!fgets (example, 256, stdin)) || + (strncmp (example, "quit", 4) == 0)) + break; + + if (strlen (example)) + example[strlen (example) - 1] = 0; + + result = brace_expand (example); + + for (i = 0; result[i]; i++) + printf ("%s\n", result[i]); + + free_array (result); + } +} + +/* + * Local variables: + * test-compile-command: "gcc -g -DTEST -I.. -I. -o brace_expand braces.c -L. -lkpathsea" + * end: + */ + +#endif /* TEST */ |