# HG changeset patch # User jwe # Date 1051154861 0 # Node ID de8c1d2ee7288a4badf148c7ed2d97d8bd6dd2af # Parent f1fcc371e5efa867a5a7daed60b506cb54853147 [project @ 2003-04-24 03:27:41 by jwe] diff -r f1fcc371e5ef -r de8c1d2ee728 liboctave/ChangeLog --- a/liboctave/ChangeLog Wed Apr 23 19:51:58 2003 +0000 +++ b/liboctave/ChangeLog Thu Apr 24 03:27:41 2003 +0000 @@ -1,5 +1,9 @@ 2003-04-23 John W. Eaton + * kpse.cc: Move most functions from kpse-xfns.c here and make + static. Include most of kpse-xfns.h directly, removing + unnecessary bits. + * dMatrix.cc (Matrix::pseudo_inverse): Now const. * CMatrix.cc (ComplexMatrix::pseudo_inverse): Likewise. diff -r f1fcc371e5ef -r de8c1d2ee728 liboctave/kpse-config.h --- a/liboctave/kpse-config.h Wed Apr 23 19:51:58 2003 +0000 +++ b/liboctave/kpse-config.h Thu Apr 24 03:27:41 2003 +0000 @@ -64,12 +64,6 @@ from c-auto.in). We use <...> instead of "..." so that the current cpp directory (i.e., kpathsea/) won't be searched. */ -#include "kpse-xfns.h" /* STREQ, etc. */ - -extern DIR *xopendir (char *dirname); - -extern void xclosedir (DIR *d); - /* If you want to find subdirectories in a directory with non-Unix semantics (specifically, if a directory with no subdirectories does not have exactly two links), define this. */ diff -r f1fcc371e5ef -r de8c1d2ee728 liboctave/kpse-xfns.c --- a/liboctave/kpse-xfns.c Wed Apr 23 19:51:58 2003 +0000 +++ b/liboctave/kpse-xfns.c Thu Apr 24 03:27:41 2003 +0000 @@ -22,313 +22,10 @@ #include #endif -#ifdef HAVE_UNISTD_H -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#include -#endif - -#include -#include +#include #include "kpse-xfns.h" -/* xfopen.c: fopen and fclose with error checking. */ - -/* These routines just check the return status from standard library - routines and abort if an error happens. */ - -FILE * -xfopen (const char *filename, const char *mode) -{ - FILE *f; - - assert (filename && mode); - - f = fopen (filename, mode); - if (f == NULL) - FATAL_PERROR (filename); - - return f; -} - -void -xfclose (FILE *f, const char *filename) -{ - assert (f); - - if (fclose (f) == EOF) - FATAL_PERROR (filename); -} - -/* xfseek.c: fseek with error checking. */ - -void -xfseek (FILE *f, long offset, int wherefrom, char *filename) -{ - if (fseek (f, offset, wherefrom) < 0) - FATAL_PERROR (filename); -} - -/* xftell.c: ftell with error checking. */ - -unsigned long -xftell (FILE *f, char *filename) -{ - long where = ftell (f); - - if (where < 0) - FATAL_PERROR (filename); - - return where; -} - -/* xopendir.c: opendir and closedir with error checking. */ - -#ifndef WIN32 -DIR * -xopendir (char *dirname) -{ - DIR *d = opendir (dirname); - - if (d == NULL) - FATAL_PERROR (dirname); - - return d; -} -#endif /* not WIN32 */ - -void -xclosedir (DIR *d) -{ -#ifdef CLOSEDIR_VOID - closedir (d); -#else - int ret = closedir (d); - - if (ret != 0) - FATAL ("closedir failed"); -#endif -} - -/* xstat.c: stat and (maybe) lstat with error checking. */ - -struct stat -xstat (const char *path) -{ - struct stat s; - - if (stat (path, &s) != 0) - FATAL_PERROR (path); - - return s; -} - -/* If we don't have symbolic links, lstat is the same as stat, and - a #define is made in the include file. */ - -#ifdef S_ISLNK -struct stat -xlstat (const char *path) -{ - struct stat s; - - if (lstat (path, &s) != 0) - FATAL_PERROR (path); - - return s; -} -#endif - -/* xgetcwd.c: a from-scratch version of getwd. Ideas from the tcsh 5.20 - source, apparently uncopyrighted. */ - -#if ! (defined (HAVE_GETCWD) || defined (HAVE_GETWD)) - -static void -xchdir (char *dirname) -{ - if (chdir (dirname) != 0) - FATAL_PERROR (dirname); -} - -#endif /* not HAVE_GETCWD && not HAVE_GETWD */ - -/* Return the pathname of the current directory, or give a fatal error. */ - -char * -xgetcwd (void) -{ - /* If the system provides getcwd, use it. If not, use getwd if - available. But provide a way not to use getcwd: on some systems - getcwd forks, which is expensive and may in fact be impossible for - large programs like tex. If your system needs this define and it - is not detected by configure, let me know. - -- Olaf Weber d_name); - - if (SAME_FILE_P (test_stat, cwd_stat)) - { - /* We've found it. Prepend the pathname. */ - char *temp = cwd_path; - cwd_path = concat3 ("/", e->d_name, cwd_path); - free (temp); - - /* Set up to test the next parent. */ - cwd_stat = xstat ("."); - - /* Stop reading this directory. */ - found = 1; - } - } - if (!found) - FATAL2 ("No inode %d/device %d in parent directory", - cwd_stat.st_ino, cwd_stat.st_dev); - - xclosedir (parent_dir); - } - - /* If the current directory is the root, cwd_path will be the empty - string, and we will have not gone through the loop. */ - if (*cwd_path == 0) - strcpy (cwd_path, "/"); - else - /* Go back to where we were. */ - xchdir (cwd_path); - -#ifdef DOSISH - /* Prepend the drive letter to CWD_PATH, since this technique - never tells us what the drive is. - - Note that on MS-DOS/MS-Windows, the branch that works around - missing `getwd' will probably only work for DJGPP (which does - have `getwd'), because only DJGPP reports meaningful - st_ino numbers. But someday, somebody might need this... */ - { - char drive[3]; - char *temp = cwd_path; - - /* Make the drive letter lower-case, unless it is beyond Z: (yes, - there ARE such drives, in case of Novell Netware on MS-DOS). */ - drive[0] = root_stat.st_dev + (root_stat.st_dev < 26 ? 'a' : 'A'); - drive[1] = ':'; - drive[2] = '\0'; - - cwd_path = concat (drive, cwd_path); - free (temp); - } -#endif - - return cwd_path; -#endif /* not HAVE_GETCWD && not HAVE_GETWD */ -} - -/* xmalloc.c: malloc with error checking. */ - -void * -xmalloc (unsigned size) -{ - void *new_mem = (void *) malloc (size); - - if (new_mem == NULL) - { - fprintf (stderr, "fatal: memory exhausted (xmalloc of %u bytes).\n", - size); - /* 1 means success on VMS, so pick a random number (ASCII `K'). */ - exit (75); - } - - return new_mem; -} - -/* xrealloc.c: realloc with error checking. */ - -extern void *xmalloc (unsigned); - -void * -xrealloc (void *old_ptr, unsigned size) -{ - void *new_mem; - - if (old_ptr == NULL) - new_mem = xmalloc (size); - else - { - new_mem = (void *) realloc (old_ptr, size); - if (new_mem == NULL) - { - /* We used to print OLD_PTR here using %x, and casting its - value to unsigned, but that lost on the Alpha, where - pointers and unsigned had different sizes. Since the info - is of little or no value anyway, just don't print it. */ - fprintf (stderr, "fatal: memory exhausted (realloc of %u bytes).\n", - size); - /* 1 means success on VMS, so pick a random number (ASCII `B'). */ - exit (66); - } - } - - return new_mem; -} - -/* xstrdup.c: strdup with error checking. */ - -/* Return a copy of S in new storage. */ - -char * -xstrdup (const char *s) -{ - char *new_string = (char *) xmalloc (strlen (s) + 1); - return strcpy (new_string, s); -} - /* basename.c: return the last element in a path. */ #ifndef HAVE_BASENAME @@ -337,7 +34,7 @@ pointer into NAME. For example, `basename ("/foo/bar.baz")' returns "bar.baz". */ -const char * +static const char * basename (const char *name) { const char *base = NULL; @@ -363,1261 +60,3 @@ { return (char *) basename (name); } - -/* file-p.c: file predicates. */ - -/* Test whether FILENAME1 and FILENAME2 are actually the same file. If - stat fails on either of the names, we return false, without error. */ - -int -same_file_p (const char *filename1, const char *filename2) -{ - struct stat sb1, sb2; - /* These are put in variables only so the results can be inspected - under gdb. */ - int r1 = stat (filename1, &sb1); - int r2 = stat (filename2, &sb2); - - return r1 == 0 && r2 == 0 ? SAME_FILE_P (sb1, sb2) : 0; -} - -/* dir.c: directory operations. */ - -/* Return true if FN is a directory or a symlink to a directory, - false if not. */ - -int -dir_p (const char *fn) -{ -#ifdef WIN32 - int fa = GetFileAttributes(fn); - return (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY)); -#else - struct stat stats; - return stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode); -#endif -} - -#ifndef WIN32 - -/* Return -1 if FN isn't a directory, else its number of links. - Duplicate the call to stat; no need to incur overhead of a function - call for that little bit of cleanliness. */ - -int -dir_links (const char *fn) -{ - static hash_table_type link_table; - char **hash_ret; - long ret; - - if (link_table.size == 0) - link_table = hash_create (457); - -#ifdef KPSE_DEBUG - /* This is annoying, but since we're storing integers as pointers, we - can't print them as strings. */ - if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) - kpse_debug_hash_lookup_int = 1; -#endif - - hash_ret = hash_lookup (link_table, fn); - -#ifdef KPSE_DEBUG - if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) - kpse_debug_hash_lookup_int = 0; -#endif - - /* Have to cast the int we need to/from the const_string that the hash - table stores for values. Let's hope an int fits in a pointer. */ - if (hash_ret) - ret = (long) *hash_ret; - else - { - struct stat stats; - ret = stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode) - ? stats.st_nlink : (unsigned) -1; - - /* It's up to us to copy the value. */ - hash_insert (&link_table, xstrdup (fn), (const char *) ret); - -#ifdef KPSE_DEBUG - if (KPSE_DEBUG_P (KPSE_DEBUG_STAT)) - DEBUGF2 ("dir_links(%s) => %ld\n", fn, ret); -#endif - } - - return ret; -} - -#endif /* !WIN32 */ - -/* hash.c: hash table operations. */ - -/* The hash function. We go for simplicity here. */ - -/* All our hash tables are related to filenames. */ -#ifdef MONOCASE_FILENAMES -#define TRANSFORM(x) toupper (x) -#else -#define TRANSFORM(x) (x) -#endif - -static unsigned -hash (hash_table_type table, const char *key) -{ - unsigned n = 0; - - /* Our keys aren't often anagrams of each other, so no point in - weighting the characters. */ - while (*key != 0) - n = (n + n + TRANSFORM (*key++)) % table.size; - - return n; -} - -hash_table_type -hash_create (unsigned size) -{ - /* hash_table_type ret; changed into "static ..." to work around gcc - optimizer bug for Alpha. */ - static hash_table_type ret; - unsigned b; - ret.buckets = XTALLOC (size, hash_element_type *); - ret.size = size; - - /* calloc's zeroes aren't necessarily NULL, so be safe. */ - for (b = 0; b key = key; - new_elt->value = value; - new_elt->next = NULL; - - /* Insert the new element at the end of the list. */ - if (!table->buckets[n]) - /* first element in bucket is a special case. */ - table->buckets[n] = new_elt; - else - { - hash_element_type *loc = table->buckets[n]; - while (loc->next) /* Find the last element. */ - loc = loc->next; - loc->next = new_elt; /* Insert the new one after. */ - } -} - -/* Remove a (KEY, VALUE) pair. */ - -void -hash_remove (hash_table_type *table, const char *key, const char *value) -{ - hash_element_type *p; - hash_element_type *q; - unsigned n = hash (*table, key); - - /* Find pair. */ - for (q = NULL, p = table->buckets[n]; p != NULL; q = p, p = p->next) - if (FILESTRCASEEQ (key, p->key) && STREQ (value, p->value)) - break; - if (p) { - /* We found something, remove it from the chain. */ - if (q) q->next = p->next; else table->buckets[n] = p->next; - /* We cannot dispose of the contents. */ - free (p); - } -} - -/* Look up STR in MAP. Return a (dynamically-allocated) list of the - corresponding strings or NULL if no match. */ - -#ifdef KPSE_DEBUG -/* Print the hash values as integers if this is nonzero. */ -int kpse_debug_hash_lookup_int = 0; -#endif - -char ** -hash_lookup (hash_table_type table, const char *key) -{ - hash_element_type *p; - str_list_type ret; - unsigned n = hash (table, key); - ret = str_list_init (); - - /* Look at everything in this bucket. */ - for (p = table.buckets[n]; p != NULL; p = p->next) - if (FILESTRCASEEQ (key, p->key)) - /* Cast because the general str_list_type shouldn't force const data. */ - str_list_add (&ret, (char *) p->value); - - /* If we found anything, mark end of list with null. */ - if (STR_LIST (ret)) - str_list_add (&ret, NULL); - -#ifdef KPSE_DEBUG - if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) - { - DEBUGF1 ("hash_lookup(%s) =>", key); - if (!STR_LIST (ret)) - fputs (" (nil)\n", stderr); - else - { - char **r; - for (r = STR_LIST (ret); *r; r++) - { - putc (' ', stderr); - if (kpse_debug_hash_lookup_int) - fprintf (stderr, "%ld", (long) *r); - else - fputs (*r, stderr); - } - putc ('\n', stderr); - } - fflush (stderr); - } -#endif - - return STR_LIST (ret); -} - -/* We only print nonempty buckets, to decrease output volume. */ - -void -hash_print (hash_table_type table, int summary_only) -{ - unsigned b; - unsigned total_elements = 0, total_buckets = 0; - - for (b = 0; b < table.size; b++) { - hash_element_type *bucket = table.buckets[b]; - - if (bucket) { - unsigned len = 1; - hash_element_type *tb; - - total_buckets++; - if (!summary_only) fprintf (stderr, "%4d ", b); - - for (tb = bucket->next; tb != NULL; tb = tb->next) - len++; - if (!summary_only) fprintf (stderr, ":%-5d", len); - total_elements += len; - - if (!summary_only) { - for (tb = bucket; tb != NULL; tb = tb->next) - fprintf (stderr, " %s=>%s", tb->key, tb->value); - putc ('\n', stderr); - } - } - } - - fprintf (stderr, - "%u buckets, %u nonempty (%u%%); %u entries, average chain %.1f.\n", - table.size, - total_buckets, - 100 * total_buckets / table.size, - total_elements, - total_buckets ? total_elements / (double) total_buckets : 0.0); -} - -/* concat.c: dynamic string concatenation. */ - -/* Return the concatenation of S1 and S2. See `concatn.c' for a - `concatn', which takes a variable number of arguments. */ - -char * -concat (const char *s1, const char *s2) -{ - char *answer = (char *) xmalloc (strlen (s1) + strlen (s2) + 1); - strcpy (answer, s1); - strcat (answer, s2); - - return answer; -} - -/* concat3.c: concatenate three strings. */ - -char * -concat3 (const char *s1, const char *s2, const char *s3) -{ - char *answer - = (char *) xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1); - strcpy (answer, s1); - strcat (answer, s2); - strcat (answer, s3); - - return answer; -} - -/* concatn.c: Concatenate an arbitrary number of strings. */ - -/* OK, it would be epsilon more efficient to compute the total length - and then do the copying ourselves, but I doubt it matters in reality. */ - -char * -concatn (const char *str1, ...) -{ - char *arg; - char *ret; - va_list ap; - - va_start (ap, str1); - - if (!str1) - return NULL; - - ret = xstrdup (str1); - - while ((arg = va_arg (ap, char *)) != NULL) - { - char *temp = concat (ret, arg); - free (ret); - ret = temp; - } - va_end (ap); - - return ret; -} - -/* debug.c: Help the user discover what's going on. */ - -#ifdef KPSE_DEBUG - -unsigned kpathsea_debug = 0; - -/* If the real definitions of fopen or fclose are macros, we lose -- the - #undef won't restore them. */ - -FILE * -fopen (const char *filename, const char *mode) -{ -#undef fopen - FILE *ret = fopen (filename, mode); - - if (KPSE_DEBUG_P (KPSE_DEBUG_FOPEN)) - DEBUGF3 ("fopen(%s, %s) => 0x%lx\n", filename, mode, (unsigned long) ret); - - return ret; -} - -int -fclose (FILE *f) -{ -#undef fclose - int ret = fclose (f); - - if (KPSE_DEBUG_P (KPSE_DEBUG_FOPEN)) - DEBUGF2 ("fclose(0x%lx) => %d\n", (unsigned long) f, ret); - - return ret; -} - -#endif - -/* libc replacement functions for win32. */ - -/* - This does make sense only under WIN32. - Functions: - - popen() rewritten - - pclose() rewritten - - stat() wrapper for _stat(), removing trailing slashes - */ - -#ifdef WIN32 - -#include - -/* The X library (among other things) defines `FALSE' and `TRUE', and so - we only want to define them if necessary, for use by application code. */ -#ifndef FALSE -#define FALSE 0 -#define TRUE 1 -#endif /* FALSE */ - -struct _popen_elt { - FILE *f; /* File stream returned */ - HANDLE hp; /* Handle of associated process */ - struct _popen_elt *next; /* Next list element */ -}; - -static struct _popen_elt _z = { NULL, 0, &_z }; -static struct _popen_elt *_popen_list = &_z; - -FILE *popen (const char *cmd, const char *mode) -{ - STARTUPINFO si; - PROCESS_INFORMATION pi; - SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; - FILE *f = NULL; - int fno, i; - HANDLE child_in, child_out; - HANDLE father_in, father_out; - HANDLE father_in_dup, father_out_dup; - HANDLE current_in, current_out; - HANDLE current_pid; - int binary_mode; - char *new_cmd, *app_name = NULL; - char *p, *q; - struct _popen_elt *new_process; - char pname[PATH_MAX], *fp; - char *suffixes[] = { ".bat", ".cmd", ".com", ".exe", NULL }; - char **s; - int go_on; - - /* We should look for the application name along the PATH, - and decide to prepend "%COMSPEC% /c " or not to the command line. - Do nothing for the moment. */ - - /* Another way to do that would be to try CreateProcess first without - invoking cmd, and look at the error code. If it fails because of - command not found, try to prepend "cmd /c" to the cmd line. - */ - - /* Look for the application name */ - for (p = cmd; *p && isspace(*p); p++); - if (*p == '"') { - q = ++p; - while(*p && *p != '"') p++; - if (*p != '\0') { - fprintf(stderr, "popen: malformed command (\" not terminated)\n"); - return NULL; - } - } - else - for (q = p; *p && !isspace(*p); p++); - /* q points to the beginning of appname, p to the last + 1 char */ - if ((app_name = malloc(p - q + 1)) == NULL) { - fprintf(stderr, "xpopen: malloc(app_name) failed.\n"); - return NULL; - } - strncpy(app_name, q, p - q ); - app_name[p - q] = '\0'; - pname[0] = '\0'; -#ifdef TRACE - fprintf(stderr, "popen: app_name = %s\n", app_name); -#endif - - /* Looking for appname on the path */ - for (s = suffixes, go_on = 1; go_on; *s++) { - if (SearchPath(NULL, /* Address of search path */ - app_name, /* Address of filename */ - *s, /* Address of extension */ - PATH_MAX, /* Size of destination buffer */ - pname, /* Address of destination buffer */ - &fp) /* File part of app_name */ - != 0) { -#ifdef TRACE - fprintf(stderr, "%s found with suffix %s\n", app_name, *s); -#endif - new_cmd = xstrdup(cmd); - free(app_name); - app_name = xstrdup(pname); - break; - } - go_on = (*s != NULL); - } - if (go_on == 0) { - /* the app_name was not found */ -#ifdef TRACE - fprintf(stderr, "%s not found, concatenating comspec\n", app_name); -#endif - new_cmd = concatn(getenv("COMSPEC"), " /c ", cmd, NULL); - free(app_name); - app_name = NULL; - } - else { - } -#ifdef TRACE - fprintf(stderr, "popen: app_name = %s\n", app_name); - fprintf(stderr, "popen: cmd_line = %s\n", new_cmd); -#endif - - current_in = GetStdHandle(STD_INPUT_HANDLE); - current_out = GetStdHandle(STD_OUTPUT_HANDLE); - current_pid = GetCurrentProcess(); - ZeroMemory( &si, sizeof(STARTUPINFO) ); - si.cb = sizeof(STARTUPINFO); - si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - - if (strchr(mode, 'b')) - binary_mode = _O_BINARY; - else - binary_mode = _O_TEXT; - - /* Opening the pipe for writing */ - if (strchr(mode, 'w')) { - binary_mode |= _O_WRONLY; - if (CreatePipe(&child_in, &father_out, &sa, 0) == FALSE) { - fprintf(stderr, "popen: error CreatePipe\n"); - return NULL; - } -#if 0 - if (SetStdHandle(STD_INPUT_HANDLE, child_in) == FALSE) { - fprintf(stderr, "popen: error SetStdHandle child_in\n"); - return NULL; - } -#endif - si.hStdInput = child_in; - si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - - if (DuplicateHandle(current_pid, father_out, - current_pid, &father_out_dup, - 0, FALSE, DUPLICATE_SAME_ACCESS) == FALSE) { - fprintf(stderr, "popen: error DuplicateHandle father_out\n"); - return NULL; - } - CloseHandle(father_out); - fno = _open_osfhandle((long)father_out_dup, binary_mode); - f = _fdopen(fno, mode); - i = setvbuf( f, NULL, _IONBF, 0 ); - } - /* Opening the pipe for reading */ - else if (strchr(mode, 'r')) { - binary_mode |= _O_RDONLY; - if (CreatePipe(&father_in, &child_out, &sa, 0) == FALSE) { - fprintf(stderr, "popen: error CreatePipe\n"); - return NULL; - } -#if 0 - if (SetStdHandle(STD_OUTPUT_HANDLE, child_out) == FALSE) { - fprintf(stderr, "popen: error SetStdHandle child_out\n"); - return NULL; - } -#endif - si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - si.hStdOutput = child_out; - si.hStdError = GetStdHandle(STD_ERROR_HANDLE); - if (DuplicateHandle(current_pid, father_in, - current_pid, &father_in_dup, - 0, FALSE, DUPLICATE_SAME_ACCESS) == FALSE) { - fprintf(stderr, "popen: error DuplicateHandle father_in\n"); - return NULL; - } - CloseHandle(father_in); - fno = _open_osfhandle((long)father_in_dup, binary_mode); - f = _fdopen(fno, mode); - i = setvbuf( f, NULL, _IONBF, 0 ); - } - else { - fprintf(stderr, "popen: invalid mode %s\n", mode); - return NULL; - } - - /* creating child process */ - if (CreateProcess(app_name, /* pointer to name of executable module */ - new_cmd, /* pointer to command line string */ - NULL, /* pointer to process security attributes */ - NULL, /* pointer to thread security attributes */ - TRUE, /* handle inheritance flag */ - CREATE_NEW_CONSOLE, /* creation flags */ - NULL, /* pointer to environment */ - NULL, /* pointer to current directory */ - &si, /* pointer to STARTUPINFO */ - &pi /* pointer to PROCESS_INFORMATION */ - ) == FALSE) { - fprintf(stderr, "popen: CreateProcess %x\n", GetLastError()); - return NULL; - } - -#if 0 - /* Restoring saved values for stdin/stdout */ - if (SetStdHandle(STD_INPUT_HANDLE, current_in) == FALSE) - fprintf(stderr, "popen: error re-redirecting Stdin\n"); - if (SetStdHandle(STD_OUTPUT_HANDLE, current_out) == FALSE) - fprintf(stderr, "popen: error re-redirecting Stdout\n"); -#endif - /* Only the process handle is needed */ - if (CloseHandle(pi.hThread) == FALSE) { - fprintf(stderr, "popen: error closing thread handle\n"); - return NULL; - } - - if (new_cmd) free(new_cmd); - if (app_name) free(app_name); - -#if 0 - /* This does not seem to make sense for console apps */ - while (1) { - i = WaitForInputIdle(pi.hProcess, 5); /* Wait 5ms */ - if (i == 0xFFFFFFFF) { - fprintf(stderr, "popen: process can't initialize\n"); - return NULL; - } - else if (i == WAIT_TIMEOUT) - fprintf(stderr, "popen: warning, process still not initialized\n"); - else - break; - } -#endif - - /* Add the pair (f, pi.hProcess) to the list */ - if ((new_process = malloc(sizeof(struct _popen_elt))) == NULL) { - fprintf (stderr, "popen: malloc(new_process) error\n"); - return NULL; - } - /* Saving the FILE * pointer, access key for retrieving the process - handle later on */ - new_process->f = f; - /* Closing the unnecessary part of the pipe */ - if (strchr(mode, 'r')) { - CloseHandle(child_out); - } - else if (strchr(mode, 'w')) { - CloseHandle(child_in); - } - /* Saving the process handle */ - new_process->hp = pi.hProcess; - /* Linking it to the list of popen() processes */ - new_process->next = _popen_list; - _popen_list = new_process; - - return f; - -} - -int pclose (FILE *f) -{ - struct _popen_elt *p, *q; - int exit_code; - - /* Look for f is the access key in the linked list */ - for (q = NULL, p = _popen_list; - p != &_z && p->f != f; - q = p, p = p->next); - - if (p == &_z) { - fprintf(stderr, "pclose: error, file not found."); - return -1; - } - - /* Closing the FILE pointer */ - fclose(f); - - /* Waiting for the process to terminate */ - if (WaitForSingleObject(p->hp, INFINITE) != WAIT_OBJECT_0) { - fprintf(stderr, "pclose: error, process still active\n"); - return -1; - } - - /* retrieving the exit code */ - if (GetExitCodeProcess(p->hp, &exit_code) == 0) { - fprintf(stderr, "pclose: can't get process exit code\n"); - return -1; - } - - /* Closing the process handle, this will cause the system to - remove the process from memory */ - if (CloseHandle(p->hp) == FALSE) { - fprintf(stderr, "pclose: error closing process handle\n"); - return -1; - } - - /* remove the elt from the list */ - if (q != NULL) - q->next = p->next; - else - _popen_list = p->next; - free(p); - - return exit_code; -} - -#endif - -/* find-suffix.c: return the stuff after a dot. */ - -/* Return pointer to first character after `.' in last directory element - of NAME. If the name is `foo' or `/foo.bar/baz', we have no extension. */ - -char * -find_suffix (const char *name) -{ - const char *slash_pos; - char *dot_pos = strrchr (name, '.'); - - if (dot_pos == NULL) - return NULL; - - for (slash_pos = name + strlen (name); - slash_pos > dot_pos && !IS_DIR_SEP (*slash_pos); - slash_pos--) - ; - - return slash_pos > dot_pos ? NULL : dot_pos + 1; -} - -/* rm-suffix.c: remove any suffix. */ - -/* Generic const warning -- see extend-fname.c. */ - -char * -remove_suffix (const char *s) -{ - char *ret; - const char *suffix = find_suffix (s); - - if (suffix) - { - /* Back up to before the dot. */ - suffix--; - ret = (char *) xmalloc (suffix - s + 1); - strncpy (ret, s, suffix - s); - ret[suffix - s] = 0; - } - else - ret = (char *) s; - - return ret; -} - -/* make-suffix.c: unconditionally add a filename suffix. */ - -/* Return a new string: S suffixed with SUFFIX, regardless of what it - was before. This returns a newly allocated string. */ - -char * -make_suffix (const char *s, const char *suffix) -{ - char *new_s; - const char *dot_pos = strrchr (s, '.'); - const char *slash_pos; - - for (slash_pos = s + strlen (s) - 1; slash_pos > dot_pos && slash_pos > s; - slash_pos--) { - if (IS_DIR_SEP (*slash_pos)) - break; - } - - if (dot_pos == NULL || slash_pos > dot_pos ) - new_s = concat3 (s, ".", suffix); - else - { - unsigned past_dot_index = dot_pos + 1 - s; - - new_s = (char *) xmalloc (past_dot_index + strlen (suffix) + 1); - strncpy (new_s, s, dot_pos + 1 - s); - strcpy (new_s + past_dot_index, suffix); - } - - return new_s; -} - -/* readable.c: check if a filename is a readable non-directory file. */ - -/* Truncate any too-long components in NAME, returning the result. It's - too bad this is necessary. See comments in readable.c for why. */ - -static char * -kpse_truncate_filename (const char *name) -{ - unsigned c_len = 0; /* Length of current component. */ - unsigned ret_len = 0; /* Length of constructed result. */ - - /* Allocate enough space. */ - char *ret = (char *) xmalloc (strlen (name) + 1); - - for (; *name; name++) - { - if (IS_DIR_SEP (*name) || IS_DEVICE_SEP (*name)) - { /* At a directory delimiter, reset component length. */ - c_len = 0; - } - else if (c_len > NAME_MAX) - { /* If past the max for a component, ignore this character. */ - continue; - } - - /* Copy this character. */ - ret[ret_len++] = *name; - c_len++; - } - ret[ret_len] = 0; - - return ret; -} - -/* If access can read FN, run stat (assigning to stat buffer ST) and - check that fn is not a directory. Don't check for just being a - regular file, as it is potentially useful to read fifo's or some - kinds of devices. */ - -#ifdef __DJGPP__ -/* `stat' is way too expensive for such a simple job. */ -#define READABLE(fn, st) \ - (access (fn, R_OK) == 0 && access (fn, D_OK) == -1) -#elif WIN32 -#define READABLE(fn, st) \ - (GetFileAttributes(fn) != 0xFFFFFFFF && \ - !(GetFileAttributes(fn) & FILE_ATTRIBUTE_DIRECTORY)) -#else -#define READABLE(fn, st) \ - (access (fn, R_OK) == 0 && stat (fn, &(st)) == 0 && !S_ISDIR (st.st_mode)) -#endif - -/* POSIX invented the brain-damage of not necessarily truncating - filename components; the system's behavior is defined by the value of - the symbol _POSIX_NO_TRUNC, but you can't change it dynamically! - - Generic const return warning. See extend-fname.c. */ - -char * -kpse_readable_file (const char *name) -{ - struct stat st; - char *ret; - - if (READABLE (name, st)) { - ret = (char *) name; - -#ifdef ENAMETOOLONG - } else if (errno == ENAMETOOLONG) { - ret = kpse_truncate_filename (name); - - /* Perhaps some other error will occur with the truncated name, so - let's call access again. */ - if (!READABLE (ret, st)) - { /* Failed. */ - if (ret != name) free (ret); - ret = NULL; - } -#endif /* ENAMETOOLONG */ - - } else { /* Some other error. */ - if (errno == EACCES) { /* Maybe warn them if permissions are bad. */ - perror (name); - } - ret = NULL; - } - - return ret; -} - -/* absolute.c: Test if a filename is absolute or explicitly relative. */ - -/* Sorry this is such a system-dependent mess, but I can't see any way - to usefully generalize. */ - -int -kpse_absolute_p (const char *filename, int relative_ok) -{ - int absolute = IS_DIR_SEP (*filename) -#ifdef DOSISH - /* Novell allows non-alphanumeric drive letters. */ - || (*filename && IS_DEVICE_SEP (filename[1])) -#endif /* DOSISH */ -#ifdef WIN32 - /* UNC names */ - || (*filename == '\\' && filename[1] == '\\') -#endif - ; - int explicit_relative - = relative_ok - && (*filename == '.' && (IS_DIR_SEP (filename[1]) - || (filename[1] == '.' && IS_DIR_SEP (filename[2])))); - - return absolute || explicit_relative; -} - -/* str-list.c: define routines for string lists. */ - -/* See the lib.h file for comments. */ - -str_list_type -str_list_init (void) -{ - str_list_type ret; - - STR_LIST_LENGTH (ret) = 0; - STR_LIST (ret) = NULL; - - return ret; -} - -void -str_list_add (str_list_type *l, char *s) -{ - STR_LIST_LENGTH (*l)++; - XRETALLOC (STR_LIST (*l), STR_LIST_LENGTH (*l), char *); - STR_LIST_LAST_ELT (*l) = s; -} - -/* May as well save some reallocations and do everything in a chunk - instead of calling str_list_add on each element. */ - -void -str_list_concat (str_list_type *target, str_list_type more) -{ - unsigned e; - unsigned prev_len = STR_LIST_LENGTH (*target); - - STR_LIST_LENGTH (*target) += STR_LIST_LENGTH (more); - XRETALLOC (STR_LIST (*target), STR_LIST_LENGTH (*target), char *); - - for (e = 0; e < STR_LIST_LENGTH (more); e++) - STR_LIST_ELT (*target, prev_len + e) = STR_LIST_ELT (more, e); -} - -/* Free the list (but not the elements within it). */ - -void -str_list_free (str_list_type *l) -{ - if (STR_LIST (*l)) - { - free (STR_LIST (*l)); - STR_LIST (*l) = NULL; - } -} - -/* str-llist.c: Implementation of a linked list of strings. */ - -/* Add the new string STR to the end of the list L. */ - -void -str_llist_add (str_llist_type *l, char *str) -{ - str_llist_elt_type *e; - str_llist_elt_type *new_elt = XTALLOC1 (str_llist_elt_type); - - /* The new element will be at the end of the list. */ - STR_LLIST (*new_elt) = str; - STR_LLIST_MOVED (*new_elt) = 0; - STR_LLIST_NEXT (*new_elt) = NULL; - - /* Find the current end of the list. */ - for (e = *l; e && STR_LLIST_NEXT (*e); e = STR_LLIST_NEXT (*e)) - ; - - if (!e) - *l = new_elt; - else - STR_LLIST_NEXT (*e) = new_elt; -} - -/* Move an element towards the top. The idea is that when a file is - found in a given directory, later files will likely be in that same - directory, and looking for the file in all the directories in between - is thus a waste. */ - -void -str_llist_float (str_llist_type *l, str_llist_elt_type *mover) -{ - str_llist_elt_type *last_moved, *unmoved; - - /* If we've already moved this element, never mind. */ - if (STR_LLIST_MOVED (*mover)) - return; - - /* Find the first unmoved element (to insert before). We're - guaranteed this will terminate, since MOVER itself is currently - unmoved, and it must be in L (by hypothesis). */ - for (last_moved = NULL, unmoved = *l; STR_LLIST_MOVED (*unmoved); - last_moved = unmoved, unmoved = STR_LLIST_NEXT (*unmoved)) - ; - - /* If we are the first unmoved element, nothing to relink. */ - if (unmoved != mover) - { /* Remember `mover's current successor, so we can relink `mover's - predecessor to it. */ - str_llist_elt_type *before_mover; - str_llist_elt_type *after_mover = STR_LLIST_NEXT (*mover); - - /* Find `mover's predecessor. */ - for (before_mover = unmoved; STR_LLIST_NEXT (*before_mover) != mover; - before_mover = STR_LLIST_NEXT (*before_mover)) - ; - - /* `before_mover' now links to `after_mover'. */ - STR_LLIST_NEXT (*before_mover) = after_mover; - - /* Insert `mover' before `unmoved' and after `last_moved' (or at - the head of the list). */ - STR_LLIST_NEXT (*mover) = unmoved; - if (!last_moved) - *l = mover; - else - STR_LLIST_NEXT (*last_moved) = mover; - } - - /* We've moved it. */ - STR_LLIST_MOVED (*mover) = 1; -} - -/* fn.c: arbitrarily long filenames (or just strings). */ - -/* /usr/local/lib/texmf/fonts/public/cm/pk/ljfour/cmr10.300pk is 58 - chars, so ASCII `K' seems a good choice. */ -#define CHUNK_SIZE 75 - -fn_type -fn_init (void) -{ - fn_type ret; - - FN_ALLOCATED (ret) = FN_LENGTH (ret) = 0; - FN_STRING (ret) = NULL; - - return ret; -} - -fn_type -fn_copy0 (const char *s, unsigned len) -{ - fn_type ret; - - FN_ALLOCATED (ret) = CHUNK_SIZE > len ? CHUNK_SIZE : len + 1; - FN_STRING (ret) = (char *) xmalloc (FN_ALLOCATED (ret)); - - strncpy (FN_STRING (ret), s, len); - FN_STRING (ret)[len] = 0; - FN_LENGTH (ret) = len + 1; - - return ret; -} - -/* Don't think we ever try to free something that might usefully be - empty, so give fatal error if nothing allocated. */ - -void -fn_free (fn_type *f) -{ - assert (FN_STRING (*f) != NULL); - free (FN_STRING (*f)); - FN_STRING (*f) = NULL; - FN_ALLOCATED (*f) = 0; - FN_LENGTH (*f) = 0; -} - -/* An arithmetic increase seems more reasonable than geometric. We - don't increase the length member since it may be more convenient for - the caller to add than subtract when appending the stuff that will - presumably follow. */ - -static void -grow (fn_type *f, unsigned len) -{ - while (FN_LENGTH (*f) + len > FN_ALLOCATED (*f)) - { - FN_ALLOCATED (*f) += CHUNK_SIZE; - XRETALLOC (FN_STRING (*f), FN_ALLOCATED (*f), char); - } -} - -void -fn_1grow (fn_type *f, char c) -{ - grow (f, 1); - FN_STRING (*f)[FN_LENGTH (*f)] = c; - FN_LENGTH (*f)++; -} - -void -fn_grow (fn_type *f, void *source, unsigned len) -{ - grow (f, len); - strncpy (FN_STRING (*f) + FN_LENGTH (*f), (char *) source, len); - FN_LENGTH (*f) += len; -} - -void -fn_str_grow (fn_type *f, const char *s) -{ - unsigned more_len = strlen (s); - grow (f, more_len); - strcat (FN_STRING (*f), s); - FN_LENGTH (*f) += more_len; -} - -void -fn_shrink_to (fn_type *f, unsigned loc) -{ - assert (FN_LENGTH (*f) > loc); - FN_STRING (*f)[loc] = 0; - FN_LENGTH (*f) = loc + 1; -} - -/* variable.c: variable expansion. */ - -/* Here's the simple one, when a program just wants a value. */ - -char * -kpse_var_value (const char *var) -{ - char *ret = getenv (var); - - if (ret) - ret = kpse_var_expand (ret); - -#ifdef KPSE_DEBUG - if (KPSE_DEBUG_P (KPSE_DEBUG_VARS)) - DEBUGF2("variable: %s = %s\n", var, ret ? ret : "(nil)"); -#endif - - return ret; -} - -/* We have to keep track of variables being expanded, otherwise - constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop. - (Or indirectly recursive variables, etc.) Our simple solution is to - add to a list each time an expansion is started, and check the list - before expanding. */ - -typedef struct { - const char *var; - int expanding; -} expansion_type; -static expansion_type *expansions; /* The sole variable of this type. */ -static unsigned expansion_len = 0; - -static void -expanding (const char *var, int xp) -{ - unsigned e; - for (e = 0; e < expansion_len; e++) { - if (STREQ (expansions[e].var, var)) { - expansions[e].expanding = xp; - return; - } - } - - /* New variable, add it to the list. */ - expansion_len++; - XRETALLOC (expansions, expansion_len, expansion_type); - expansions[expansion_len - 1].var = xstrdup (var); - expansions[expansion_len - 1].expanding = xp; -} - - -/* Return whether VAR is currently being expanding. */ - -static int -expanding_p (const char *var) -{ - unsigned e; - for (e = 0; e < expansion_len; e++) { - if (STREQ (expansions[e].var, var)) - return expansions[e].expanding; - } - - return 0; -} - -/* Append the result of value of `var' to EXPANSION, where `var' begins - at START and ends at END. If `var' is not set, do not complain. - This is a subroutine for the more complicated expansion function. */ - -static void -expand (fn_type *expansion, const char *start, const char *end) -{ - char *value; - unsigned len = end - start + 1; - char *var = (char *) xmalloc (len + 1); - strncpy (var, start, len); - var[len] = 0; - - if (expanding_p (var)) { - WARNING1 ("kpathsea: variable `%s' references itself (eventually)", var); - } else { - /* Check for an environment variable. */ - value = getenv (var); - - if (value) { - expanding (var, 1); - value = kpse_var_expand (value); - expanding (var, 0); - fn_grow (expansion, value, strlen (value)); - free (value); - } - - free (var); - } -} - -/* Can't think of when it would be useful to change these (and the - diagnostic messages assume them), but ... */ -#ifndef IS_VAR_START /* starts all variable references */ -#define IS_VAR_START(c) ((c) == '$') -#endif -#ifndef IS_VAR_CHAR /* variable name constituent */ -#define IS_VAR_CHAR(c) (ISALNUM (c) || (c) == '_') -#endif -#ifndef IS_VAR_BEGIN_DELIMITER /* start delimited variable name (after $) */ -#define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{') -#endif -#ifndef IS_VAR_END_DELIMITER -#define IS_VAR_END_DELIMITER(c) ((c) == '}') -#endif - - -/* Maybe we should support some or all of the various shell ${...} - constructs, especially ${var-value}. */ - -char * -kpse_var_expand (const char *src) -{ - const char *s; - char *ret; - fn_type expansion; - expansion = fn_init (); - - /* Copy everything but variable constructs. */ - for (s = src; *s; s++) { - if (IS_VAR_START (*s)) { - s++; - - /* Three cases: `$VAR', `${VAR}', `$'. */ - if (IS_VAR_CHAR (*s)) { - /* $V: collect name constituents, then expand. */ - const char *var_end = s; - - do { - var_end++; - } while (IS_VAR_CHAR (*var_end)); - - var_end--; /* had to go one past */ - expand (&expansion, s, var_end); - s = var_end; - - } else if (IS_VAR_BEGIN_DELIMITER (*s)) { - /* ${: scan ahead for matching delimiter, then expand. */ - const char *var_end = ++s; - - while (*var_end && !IS_VAR_END_DELIMITER (*var_end)) - var_end++; - - if (! *var_end) { - WARNING1 ("%s: No matching } for ${", src); - s = var_end - 1; /* will incr to null at top of loop */ - } else { - expand (&expansion, s, var_end - 1); - s = var_end; /* will incr past } at top of loop*/ - } - - } else { - /* $: error. */ - WARNING2 ("%s: Unrecognized variable construct `$%c'", src, *s); - /* Just ignore those chars and keep going. */ - } - } else - fn_1grow (&expansion, *s); - } - fn_1grow (&expansion, 0); - - ret = FN_STRING (expansion); - return ret; -} diff -r f1fcc371e5ef -r de8c1d2ee728 liboctave/kpse-xfns.h --- a/liboctave/kpse-xfns.h Wed Apr 23 19:51:58 2003 +0000 +++ b/liboctave/kpse-xfns.h Thu Apr 24 03:27:41 2003 +0000 @@ -18,209 +18,6 @@ License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#ifndef KPATHSEA_LIB_H -#define KPATHSEA_LIB_H - -#if defined (__cplusplus) -extern "C" { -#endif - -/* c-std.h: the first header files. */ - -/* Header files that essentially all of our sources need, and - that all implementations have. We include these first, to help with - NULL being defined multiple times. */ -#include -#include -#include - -#include - -#if HAVE_UNISTD_H -#include -#endif - -#include - -#ifdef WIN32 -#include -#endif /* not WIN32 */ - -#include -#include -#include - -/* c-dir.h: directory headers. */ - -#ifdef WIN32 - -#include - -#else /* not WIN32 */ - -/* Use struct dirent instead of struct direct. */ -#ifdef HAVE_DIRENT_H -#include -#define NAMLEN(dirent) strlen ((dirent)->d_name) -#else /* not DIRENT */ -#define dirent direct -#define NAMLEN(dirent) ((dirent)->d_namlen) - -#ifdef HAVE_SYS_NDIR_H -#include -#endif - -#ifdef HAVE_SYS_DIR_H -#include -#endif - -#ifdef HAVE_NDIR_H -#include -#endif - -#endif /* not DIRENT */ - -#endif /* not WIN32 */ - -/* c-fopen.h: how to open files with fopen. */ - -/* How to open a text file: */ -#ifndef FOPEN_A_MODE -#define FOPEN_A_MODE "a" -#endif - -#ifndef FOPEN_R_MODE -#define FOPEN_R_MODE "r" -#endif - -#ifndef FOPEN_W_MODE -#define FOPEN_W_MODE "w" -#endif - -/* How to open a binary file for reading: */ -#ifndef FOPEN_RBIN_MODE -#if defined(DOS) || defined (OS2) || defined (WIN32) || defined (__DJGPP__) || defined (__CYGWIN32__) -#define FOPEN_RBIN_MODE "rb" -#else -#define FOPEN_RBIN_MODE "r" -#endif /* not (DOS or OS2 or WIN32 or __DJGPP__ or __CYGWIN32__) */ -#endif /* not FOPEN_RBIN_MODE */ - -/* How to open a binary file for writing: */ -#ifndef FOPEN_WBIN_MODE -#if defined (DOS) || defined (OS2) || defined (WIN32) || defined (__DJGPP__) || defined (__CYGWIN32__) -#define FOPEN_WBIN_MODE "wb" -#else -#define FOPEN_WBIN_MODE "w" -#endif /* not (DOS or OS2 or WIN32 or DJGPP or CYGWIN32) */ -#endif /* not FOPEN_WBIN_MODE */ - -/* How to open a binary file for appending: */ -#ifndef FOPEN_ABIN_MODE -#if defined (DOS) || defined (OS2) || defined (WIN32) || defined (__DJGPP__) || defined (__CYGWIN32__) -#define FOPEN_ABIN_MODE "ab" -#else -#define FOPEN_ABIN_MODE "a" -#endif /* not (DOS or OS2 or WIN32 or DJGPP or CYGWIN32) */ -#endif /* not FOPEN_ABIN_MODE */ - -/* How to switch an already open file handle to binary mode. - Used on DOSISH systems when we need to switch a standard - stream, such as stdin or stdout, to binary mode. */ -#include -#ifdef DOSISH -#include -#ifndef O_BINARY -#ifdef _O_BINARY -#define O_BINARY _O_BINARY -#endif -#endif -#if defined (__DJGPP__) || defined (WIN32) || defined (__CYGWIN32__) -#define SET_BINARY(f) setmode((f), O_BINARY) -#endif -#else /* not DOSISH */ -#ifndef O_BINARY -#define O_BINARY 0 -#endif -#define SET_BINARY(f) 0 -#endif /* not DOSISH */ - -/* c-namemx.h: define NAME_MAX, the maximum length of a single - component in a filename. No such limit may exist, or may vary - depending on the filesystem. */ - -#include - -/* Most likely the system will truncate filenames if it is not POSIX, - and so we can use the BSD value here. */ -#ifndef _POSIX_NAME_MAX -#define _POSIX_NAME_MAX 255 -#endif - -#ifndef NAME_MAX -#define NAME_MAX _POSIX_NAME_MAX -#endif - -/* c-ctype.h: ASCII-safe versions of the macros. */ - -#include - -/* Be sure we have `isascii'. */ -#ifndef isascii -#define isascii(c) 1 -#endif - -#define ISALNUM(c) (isascii (c) && isalnum(c)) -#define ISALPHA(c) (isascii (c) && isalpha(c)) -#define ISASCII isascii -#define ISCNTRL(c) (isascii (c) && iscntrl(c)) -#define ISDIGIT(c) (isascii (c) && isdigit (c)) -#define ISGRAPH(c) (isascii (c) && isgraph(c)) -#define ISLOWER(c) (isascii (c) && islower(c)) -#define ISPRINT(c) (isascii (c) && isprint(c)) -#define ISPUNCT(c) (isascii (c) && ispunct(c)) -#define ISSPACE(c) (isascii (c) && isspace(c)) -#define ISUPPER(c) (isascii (c) && isupper(c)) -#define ISXDIGIT(c) (isascii (c) && isxdigit(c)) -#define TOASCII toascii -#define TOLOWER(c) (ISUPPER (c) ? tolower (c) : (c)) -#define TOUPPER(c) (ISLOWER (c) ? toupper (c) : (c)) - -/* This isn't part of the usual , but it's useful sometimes. */ -#ifndef isblank -#define isblank(c) ((c) == ' ' || (c) == '\t') -#endif - -/* Here's why this mess is necessary: - -From: meyering@cs.utexas.edu (Jim Meyering) -Date: Wed, 25 Nov 1992 09:52:33 -0600 -Subject: ss-921123: using isascii with macros - - Yesterday some cursory regression testing found that GNU od - (in an upcoming release of textutils) generated incorrect output - when run on an SGI indigo because isprint ('\377') returned true. - Of course, '\377' is not a printing character; the problem lay - in using isprint without first making sure its integer argument - corresponded to an ascii code. - - MORAL: always guard uses of ctype macros with isascii if it's available. - An obvious alternative is to avoid and define and use your - own versions of the ctype macros. - - A pretty clean approach to using and isascii was - suggested by David MacKenzie: - - #ifndef isascii - #define isascii(c) 1 - #endif - - #define ISDIGIT(c) (isascii (c) && isdigit (c)) - #define ISPRINT(c) (isascii (c) && isprint (c)) - ... - - then, use ISDIGIT, etc. instead of isdigit, etc. */ - /* c-pathch.h: define the characters which separate components of filenames and environment variable paths. */ @@ -250,625 +47,3 @@ #ifndef NAME_BEGINS_WITH_DEVICE #define NAME_BEGINS_WITH_DEVICE(name) 0 #endif - -/* What separates elements in environment variable path lists? */ -#ifndef ENV_SEP -#ifdef DOSISH -#define ENV_SEP ';' -#define ENV_SEP_STRING ";" -#else -#define ENV_SEP ':' -#define ENV_SEP_STRING ":" -#endif /* not DOS */ -#endif /* not ENV_SEP */ - -#ifndef IS_ENV_SEP -#define IS_ENV_SEP(ch) ((ch) == ENV_SEP) -#endif - -/* c-pathmx.h: define PATH_MAX, the maximum length of a filename. - Since no such limit may exist, it's preferable to dynamically grow - filenames as needed. */ - -#include - -/* Cheat and define this as a manifest constant no matter what, instead - of using pathconf. I forget why we want to do this. */ - -#ifndef _POSIX_PATH_MAX -#define _POSIX_PATH_MAX 255 -#endif - -#ifndef PATH_MAX -#ifdef MAXPATHLEN -#define PATH_MAX MAXPATHLEN -#else -#define PATH_MAX _POSIX_PATH_MAX -#endif -#endif /* not PATH_MAX */ - -/* c-proto.h: macros to include or discard prototypes. */ - -#if !defined(WIN32) -#define DllImport -#define __cdecl -#elif (defined(_DLL) && !defined(_IMPORT)) || !defined(_DLL) -#define DllImport -#else -#define DllImport __declspec(dllimport) -#endif - -/* debug.h: Runtime tracing. */ - -/* If NO_DEBUG is defined (not recommended), skip all this. */ -#ifndef NO_DEBUG - -#if defined(WIN32) -#if defined(_DEBUG) -/* This was needed at some time for catching errors in pdftex. */ -#include -#define SET_CRT_DEBUG_FIELD(a) \ - _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) -#define CLEAR_CRT_DEBUG_FIELD(a) \ - _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG)) -#define SETUP_CRTDBG \ - { _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); \ - _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT ); \ - _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE ); \ - _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT ); \ - _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE ); \ - _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );\ - } -#else /* ! _DEBUG */ -#define SET_CRT_DEBUG_FIELD(a) -#define CLEAR_CRT_DEBUG_FIELD(a) -#define SETUP_CRTDBG -#endif /* _DEBUG */ -#endif /* WIN32 */ - -/* OK, we'll have tracing support. */ -#define KPSE_DEBUG - -/* Bit vector defining what we should trace. */ -extern DllImport unsigned kpathsea_debug; - -/* Set a bit. */ -#define KPSE_DEBUG_SET(bit) kpathsea_debug |= 1 << (bit) - -/* Test if a bit is on. */ -#define KPSE_DEBUG_P(bit) (kpathsea_debug & (1 << (bit))) - -#define KPSE_DEBUG_STAT 0 /* stat calls */ -#define KPSE_DEBUG_HASH 1 /* hash lookups */ -#define KPSE_DEBUG_FOPEN 2 /* fopen/fclose calls */ -#define KPSE_DEBUG_PATHS 3 /* search path initializations */ -#define KPSE_DEBUG_EXPAND 4 /* path element expansion */ -#define KPSE_DEBUG_SEARCH 5 /* searches */ -#define KPSE_DEBUG_VARS 6 /* variable values */ -#define KPSE_LAST_DEBUG KPSE_DEBUG_VARS - -/* A printf for the debugging. */ -#define DEBUGF_START() do { fputs ("kdebug:", stderr) -#define DEBUGF_END() fflush (stderr); } while (0) - -#define DEBUGF(str) \ - DEBUGF_START (); fputs (str, stderr); DEBUGF_END () -#define DEBUGF1(str, e1) \ - DEBUGF_START (); fprintf (stderr, str, e1); DEBUGF_END () -#define DEBUGF2(str, e1, e2) \ - DEBUGF_START (); fprintf (stderr, str, e1, e2); DEBUGF_END () -#define DEBUGF3(str, e1, e2, e3) \ - DEBUGF_START (); fprintf (stderr, str, e1, e2, e3); DEBUGF_END () -#define DEBUGF4(str, e1, e2, e3, e4) \ - DEBUGF_START (); fprintf (stderr, str, e1, e2, e3, e4); DEBUGF_END () - -#undef fopen -#define fopen kpse_fopen_trace -extern FILE *fopen (const char *filename, const char *mode); -#undef fclose -#define fclose kpse_fclose_trace -extern int fclose (FILE *); - -#endif /* not NO_DEBUG */ - -/* c-stat.h: declarations for using stat(2). */ - -#include - -/* This is the symbol that X uses to determine if has been - read, so we define it. */ -#define __TYPES__ - -#include - -#if defined (WIN32) && !defined (__MINGW32__) - -/* System description file for Windows NT. */ - -/* - * Define symbols to identify the version of Unix this is. - * Define all the symbols that apply correctly. - */ - -#ifndef DOSISH -#define DOSISH -#endif - -#ifndef MAXPATHLEN -#define MAXPATHLEN _MAX_PATH -#endif - -#define HAVE_DUP2 1 -#define HAVE_RENAME 1 -#define HAVE_RMDIR 1 -#define HAVE_MKDIR 1 -#define HAVE_GETHOSTNAME 1 -#define HAVE_RANDOM 1 -#define USE_UTIME 1 -#define HAVE_MOUSE 1 -#define HAVE_TZNAME 1 - -/* These have to be defined because our compilers treat __STDC__ as being - defined (most of them anyway). */ - -#define access _access -#define alloca _alloca -#define chdir _chdir -#define chmod _chmod -#define close _close -#define creat _creat -#define dup _dup -#define dup2 _dup2 -#define execlp _execlp -#define execvp _execvp -#define fdopen _fdopen -#define fileno _fileno -#define getpid _getpid -#define getwd(dir) GetCurrentDirectory(MAXPATHLEN, dir) -#define index strchr -#define isatty _isatty -#define itoa _itoa -#define link _link -#define lseek _lseek -#define mkdir _mkdir -#define mktemp _mktemp -#define open _open -#define pipe _pipe -#if 0 -#define popen _popen -#define pclose _pclose -#endif -#define read _read -#define rmdir _rmdir -#define setmode _setmode -#define spawnlp _spawnlp -#define stat _stat -#define strcasecmp _stricmp -#define strdup _strdup -#define strncasecmp _strnicmp -#define unlink _unlink -#define umask _umask -#define utime _utime -#define write _write - -#define S_IFMT _S_IFMT -#define S_IFDIR _S_IFDIR -#define S_IFCHR _S_IFCHR -#define S_IFIFO _S_IFIFO -#define S_IFREG _S_IFREG -#define S_IREAD _S_IREAD -#define S_IWRITE _S_IWRITE -#define S_IEXEC _S_IEXEC -#define S_IXUSR _S_IEXEC -#define S_IXGRP _S_IEXEC -#define S_IXOTH _S_IEXEC -#define S_IRUSR _S_IREAD -#define S_IWUSR _S_IWRITE -#define O_RDWR _O_RDWR -#define O_CREAT _O_CREAT -#define O_TRUNC _O_TRUNC -#define O_RDONLY _O_RDONLY -#define O_WRONLY _O_WRONLY -#define O_APPEND _O_APPEND -#define O_TEXT _O_TEXT -#define O_BINARY _O_BINARY - -/* Define this so that winsock.h definitions don't get included when - windows.h is... For this to have proper effect, config.h must - always be included before windows.h. */ -#define _WINSOCKAPI_ 1 - -#include - -/* Defines size_t and alloca (). */ -#include - -/* For proper declaration of environ. */ -#include -#include -#include -#include -#include - -/* Web2C takes care of ensuring that these are defined. */ -#ifdef max -#undef max -#undef min -#endif - -/* Functions from win32lib.c */ -extern FILE *popen(const char *, const char *); -extern int pclose(FILE *); - -/* ============================================================ */ - -#endif /* WIN32 */ - -/* POSIX predicates for testing file attributes. */ - -#if !defined (S_ISBLK) && defined (S_IFBLK) -#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) -#endif -#if !defined (S_ISCHR) && defined (S_IFCHR) -#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) -#endif -#if !defined (S_ISDIR) && defined (S_IFDIR) -#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif -#if !defined (S_ISREG) && defined (S_IFREG) -#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) -#endif -#if !defined (S_ISFIFO) && defined (S_IFIFO) -#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) -#endif -#if !defined (S_ISLNK) && defined (S_IFLNK) -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif -#if !defined (S_ISSOCK) && defined (S_IFSOCK) -#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) -#endif -#if !defined (S_ISMPB) && defined (S_IFMPB) /* V7 */ -#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB) -#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC) -#endif -#if !defined (S_ISNWK) && defined (S_IFNWK) /* HP/UX */ -#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK) -#endif - -/* readable.h: Is a file readable? */ - -/* If NAME is readable and is a regular file, return it. If the error is - ENAMETOOLONG, truncate any too-long path components, and if the - result is a readable file, return that. Otherwise return NULL. */ - -extern char *kpse_readable_file (const char *name); - -/* absolute.h: Declare absolute filename predicate. */ - -extern int kpse_absolute_p (const char *filename, int relative_ok); - -/* hash.h: declarations for a hash table. */ - -/* A single (key,value) pair. */ -typedef struct hash_element_struct -{ - const char *key; - const char *value; - struct hash_element_struct *next; -} hash_element_type; - -/* The usual arrangement of buckets initialized to null. */ -typedef struct -{ - hash_element_type **buckets; - unsigned size; -} hash_table_type; - -#ifdef KPSE_DEBUG -/* How to print the hash results when debugging. */ -extern int kpse_debug_hash_lookup_int; -#endif - -/* Create a hash table of size SIZE. */ -extern hash_table_type hash_create (unsigned size); - -/* Insert the (KEY,VALUE) association into TABLE. KEY may have more - than one VALUE. Neither KEY nor VALUE is copied. */ -extern void hash_insert (hash_table_type *table, const char *key, - const char *value); - -/* Remove the (KEY,VALUE) association from TABLE. */ -extern void hash_remove (hash_table_type *table, const char *key, - const char *value); - -/* Look up KEY in MAP, and return NULL-terminated list of all matching - values (not copies), in insertion order. If none, return NULL. */ -extern char **hash_lookup (hash_table_type table, const char *key); - -/* Print TABLE to stderr. */ -extern void hash_print (hash_table_type table, int summary_only); - -/* str-list.h: Declarations for string lists. */ - -/* Lists of strings; used for, e.g., directory lists. */ - -typedef struct -{ - unsigned length; - char **list; -} str_list_type; - -#define STR_LIST_LENGTH(l) ((l).length) -#define STR_LIST(l) ((l).list) -#define STR_LIST_ELT(l, n) STR_LIST (l)[n] -#define STR_LIST_LAST_ELT(l) STR_LIST_ELT (l, STR_LIST_LENGTH (l) - 1) - -/* Return a new, empty, list. */ -extern str_list_type str_list_init (void); - -/* Append the string S to the list L. It's up to the caller to not - deallocate S; we don't copy it. Also up to the caller to terminate - the list with a null entry. */ -extern void str_list_add (str_list_type *l, char *s); - -/* Append all the elements from MORE to TARGET. */ -extern void str_list_concat (str_list_type * target, str_list_type more); - -/* Free the space for the list elements (but not the list elements - themselves). */ -extern void str_list_free (str_list_type *l); - -/* str-llist.h: A linked list of strings, - -It's pretty disgusting that both this and str-list exist; the reason is -that C cannot express iterators very well, and I don't want to change -all the for loops right now. */ - -/* It's a little bizarre to be using the same type for the list and the - elements of the list, but no reason not to in this case, I think -- - we never need a NULL string in the middle of the list, and an extra - NULL/NULL element always at the end is inconsequential. */ - -struct str_llist_elt -{ - char *str; - int moved; - struct str_llist_elt *next; -}; -typedef struct str_llist_elt str_llist_elt_type; -typedef struct str_llist_elt *str_llist_type; - -#define STR_LLIST(sl) ((sl).str) -#define STR_LLIST_MOVED(sl) ((sl).moved) -#define STR_LLIST_NEXT(sl) ((sl).next) - - -/* Add the new string E to the end of the list L. */ -extern void str_llist_add (str_llist_type *l, char *e); - -/* Reorganize L so that E is below only other elements that have already - been moved. Set `moved' member for E. */ -extern void str_llist_float (str_llist_type *l, str_llist_elt_type *e); - -/* xstat.h: stat with error checking. */ - -/* Two files are indistinguishable if they are on the same device - and have the same inode. This checks two stat buffers for that. Cf. - the `same_file_p' routine in file-p.c, declared in kpathlib.h. */ -#define SAME_FILE_P(s1, s2) \ - ((s1).st_ino == (s2).st_ino && (s1).st_dev == (s2).st_dev) - -/* Does stat(2) on PATH, and aborts if the stat fails. */ -extern struct stat xstat (const char *path); - -/* Ditto, for lstat(2) (except that lstat might not exist). */ -#ifdef S_ISLNK -extern struct stat xlstat (const char *path); -#else -#define xlstat xstat -#endif - -/* fn.h: arbitrarily long filenames (or just strings). */ - -/* Arbitrarily long filenames; it's inconvenient to use obstacks here, - because we want to maintain a null terminator. Also used for - dynamically growing strings even when the null byte isn't necessary, - e.g., in `variable.c', since I don't want to pass obstacks around - everywhere, and one can't free parts of an obstack arbitrarily. */ - -typedef struct -{ - char *str; - unsigned allocated; - unsigned length; /* includes the terminating null byte, if any */ -} fn_type; - -#define FN_STRING(fn) ((fn).str) -#define FN_ALLOCATED(fn) ((fn).allocated) -#define FN_LENGTH(fn) ((fn).length) - - -/* Create a new empty fn. */ -extern fn_type fn_init (void); - -/* Create a new fn from the first LEN characters from S and a null. */ -extern fn_type fn_copy0 (const char *s, unsigned len); - -/* Free what's been allocated. Can also just free the string if it's - been extracted out. Fatal error if nothing allocated in F. */ -extern void fn_free (fn_type *f); - -/* Append the character C to the fn F. Don't append trailing null. */ -extern void fn_1grow (fn_type *f, char c); - -/* Append LENGTH bytes from SOURCE to F. */ -extern void fn_grow (fn_type *f, void *source, unsigned length); - -/* Concatenate the component S to the fn F. Assumes string currently in - F is null terminated. */ -extern void fn_str_grow (fn_type *f, const char *s); - -/* Add a null to F's string at position LOC, and update its length. - Fatal error if LOC is past the end of the string. */ -extern void fn_shrink_to (fn_type *f, unsigned loc); - -/* variable.h: Declare variable expander. */ - -/* Return the (variable-expanded) environment variable value or config - file value, or NULL. */ -extern char *kpse_var_value (const char *var); - -/* Expand $VAR and ${VAR} references in SRC, returning the (always newly - dynamically-allocated) result. An unterminated ${ or any other - character following $ produce error messages, and that part of SRC is - ignored. In the $VAR form, the variable name consists of consecutive - letters, digits, and underscores. In the ${VAR} form, the variable - name consists of whatever is between the braces. - - In any case, ``expansion'' means calling `getenv'; if the variable is not - set, look in texmf.cnf files for a definition. If not set there, either, - the expansion is the empty string (no error). */ -extern char *kpse_var_expand (const char *src); - -/* lib.h: other stuff. */ - -/* Define common sorts of messages. */ - -/* This should be called only after a system call fails. Don't exit - with status `errno', because that might be 256, which would mean - success (exit statuses are truncated to eight bits). */ -#define FATAL_PERROR(str) do { \ - fputs ("pathsearch: ", stderr); \ - perror (str); exit (EXIT_FAILURE); } while (0) - -#define START_FATAL() do { \ - fputs ("pathsearch: fatal: ", stderr); -#define END_FATAL() fputs (".\n", stderr); exit (1); } while (0) - -#define FATAL(str) \ - START_FATAL (); fputs (str, stderr); END_FATAL () -#define FATAL1(str, e1) \ - START_FATAL (); fprintf (stderr, str, e1); END_FATAL () -#define FATAL2(str, e1, e2) \ - START_FATAL (); fprintf (stderr, str, e1, e2); END_FATAL () -#define FATAL3(str, e1, e2, e3) \ - START_FATAL (); fprintf (stderr, str, e1, e2, e3); END_FATAL () -#define FATAL4(str, e1, e2, e3, e4) \ - START_FATAL (); fprintf (stderr, str, e1, e2, e3, e4); END_FATAL () -#define FATAL5(str, e1, e2, e3, e4, e5) \ - START_FATAL (); fprintf (stderr, str, e1, e2, e3, e4, e5); END_FATAL () -#define FATAL6(str, e1, e2, e3, e4, e5, e6) \ - START_FATAL (); fprintf (stderr, str, e1, e2, e3, e4, e5, e6); END_FATAL () - - -#define START_WARNING() do { fputs ("warning: ", stderr) -#define END_WARNING() fputs (".\n", stderr); fflush (stderr); } while (0) - -#define WARNING(str) \ - START_WARNING (); fputs (str, stderr); END_WARNING () -#define WARNING1(str, e1) \ - START_WARNING (); fprintf (stderr, str, e1); END_WARNING () -#define WARNING2(str, e1, e2) \ - START_WARNING (); fprintf (stderr, str, e1, e2); END_WARNING () -#define WARNING3(str, e1, e2, e3) \ - START_WARNING (); fprintf (stderr, str, e1, e2, e3); END_WARNING () -#define WARNING4(str, e1, e2, e3, e4) \ - START_WARNING (); fprintf (stderr, str, e1, e2, e3, e4); END_WARNING () - - -/* I find this easier to read. */ -#define STREQ(s1, s2) (strcmp (s1, s2) == 0) -#define STRNEQ(s1, s2, n) (strncmp (s1, s2, n) == 0) - -/* Support for FAT/ISO-9660 filesystems. Theoretically this should be - done at runtime, per filesystem, but that's painful to program. */ -#ifdef MONOCASE_FILENAMES -#define FILESTRCASEEQ(s1, s2) (strcasecmp (s1, s2) == 0) -#define FILESTRNCASEEQ(s1, s2, l) (strncasecmp (s1, s2, l) == 0) -#define FILECHARCASEEQ(c1, c2) (toupper (c1) == toupper (c2)) -#else -#define FILESTRCASEEQ STREQ -#define FILESTRNCASEEQ STRNEQ -#define FILECHARCASEEQ(c1, c2) ((c1) == (c2)) -#endif - -/* This is the maximum number of numerals that result when a 64-bit - integer is converted to a string, plus one for a trailing null byte, - plus one for a sign. */ -#define MAX_INT_LENGTH 21 - -/* If the environment variable TEST is set, return it; otherwise, - DEFAULT. This is useful for paths that use more than one envvar. */ -#define ENVVAR(test, default) (getenv (test) ? (test) : (default)) - -/* Return a fresh copy of S1 followed by S2, et al. */ -extern DllImport char *concat (const char *s1, const char *s2); -extern DllImport char *concat3 (const char *, const char *, const char *); -extern DllImport char *concatn (const char *str1, ...); - -/* A fresh copy of just S. */ -extern DllImport char *xstrdup (const char *s); - -/* True if FILENAME1 and FILENAME2 are the same file. If stat fails on - either name, return false, no error message. - Cf. `SAME_FILE_P' in xstat.h. */ -extern DllImport int same_file_p (const char *filename1, - const char *filename2); - -#ifndef HAVE_BASENAME -/* Return NAME with any leading path stripped off. This returns a - pointer into NAME. */ -extern DllImport const char *basename (const char *name); -#endif /* not HAVE_BASENAME */ - -/* If NAME has a suffix, return a pointer to its first character (i.e., - the one after the `.'); otherwise, return NULL. */ -extern DllImport char *find_suffix (const char *name); - -/* Return NAME with any suffix removed. */ -extern DllImport char *remove_suffix (const char *name); - -/* Return S with the suffix SUFFIX, removing any suffix already present. - For example, `make_suffix ("/foo/bar.baz", "quux")' returns - `/foo/bar.quux'. Returns a string allocated with malloc. */ -extern DllImport char *make_suffix (const char *s, const char *suffix); - -/* Return NAME with STEM_PREFIX prepended to the stem. For example, - `make_prefix ("/foo/bar.baz", "x")' returns `/foo/xbar.baz'. - Returns a string allocated with malloc. */ -extern DllImport char *make_prefix (char *stem_prefix, char *name); - - -/* Return the current working directory. */ -extern DllImport char *xgetcwd (void); - -/* Returns true if FN is a directory or a symlink to a directory. */ -extern DllImport int dir_p (const char *fn); - -/* If FN is a readable directory, return the number of links it has. - Otherwise, return -1. */ -extern DllImport int dir_links (const char *fn); - -/* Like their stdio counterparts, but abort on error, after calling - perror(3) with FILENAME as its argument. */ -extern DllImport FILE *xfopen (const char *filename, const char *mode); -extern DllImport void xfclose (FILE *, const char *filename); - -/* These call the corresponding function in the standard library, and - abort if those routines fail. Also, `xrealloc' calls `xmalloc' if - OLD_ADDRESS is null. */ -extern DllImport void *xmalloc (unsigned size); -extern DllImport void *xrealloc (void *old_address, unsigned new_size); - -extern DllImport char *xbasename (const char *name); - -/* (Re)Allocate N items of type T using xmalloc/xrealloc. */ -#define XTALLOC(n, t) ((t *) xmalloc ((n) * sizeof (t))) -#define XTALLOC1(t) XTALLOC (1, t) -#define XRETALLOC(addr, n, t) ((addr) = (t *) xrealloc (addr, (n) * sizeof(t))) - -#if defined (__cplusplus) -} -#endif - -#endif /* not KPATHSEA_LIB_H */ diff -r f1fcc371e5ef -r de8c1d2ee728 liboctave/kpse.cc --- a/liboctave/kpse.cc Wed Apr 23 19:51:58 2003 +0000 +++ b/liboctave/kpse.cc Thu Apr 24 03:27:41 2003 +0000 @@ -1,7 +1,8 @@ /* pathsearch.c: look up a filename in a path. -Copyright (C) 1993, 94, 95, 96, 97 Karl Berry. +Copyright (C) 1993, 94, 95, 96, 97, 98 Karl Berry. Copyright (C) 1993, 94, 95, 96, 97 Karl Berry & O. Weber. +Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public @@ -25,12 +26,398 @@ #include "kpse-xfns.h" #include "kpse.h" -#include /* for `time' */ - -#ifdef __DJGPP__ -#include /* for stat bits */ +/* c-std.h: the first header files. */ + +/* Header files that essentially all of our sources need, and + that all implementations have. We include these first, to help with + NULL being defined multiple times. */ +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#include +#endif + +#ifdef WIN32 +#include +#endif /* not WIN32 */ + +#include "sysdir.h" +#include "statdefs.h" + +/* define NAME_MAX, the maximum length of a single + component in a filename. No such limit may exist, or may vary + depending on the filesystem. */ + +/* Most likely the system will truncate filenames if it is not POSIX, + and so we can use the BSD value here. */ +#ifndef _POSIX_NAME_MAX +#define _POSIX_NAME_MAX 255 +#endif + +#ifndef NAME_MAX +#define NAME_MAX _POSIX_NAME_MAX +#endif + +/* c-ctype.h: ASCII-safe versions of the macros. */ + +#include + +/* What separates elements in environment variable path lists? */ +#ifndef ENV_SEP +#ifdef DOSISH +#define ENV_SEP ';' +#define ENV_SEP_STRING ";" +#else +#define ENV_SEP ':' +#define ENV_SEP_STRING ":" +#endif /* not DOS */ +#endif /* not ENV_SEP */ + +#ifndef IS_ENV_SEP +#define IS_ENV_SEP(ch) ((ch) == ENV_SEP) +#endif + +/* c-pathmx.h: define PATH_MAX, the maximum length of a filename. + Since no such limit may exist, it's preferable to dynamically grow + filenames as needed. */ + +/* Cheat and define this as a manifest constant no matter what, instead + of using pathconf. I forget why we want to do this. */ + +#ifndef _POSIX_PATH_MAX +#define _POSIX_PATH_MAX 255 +#endif + +#ifndef PATH_MAX +#ifdef MAXPATHLEN +#define PATH_MAX MAXPATHLEN +#else +#define PATH_MAX _POSIX_PATH_MAX +#endif +#endif /* not PATH_MAX */ + +/* debug.h: Runtime tracing. */ + +/* If NO_DEBUG is defined (not recommended), skip all this. */ +#ifndef NO_DEBUG + +/* OK, we'll have tracing support. */ +#define KPSE_DEBUG + +/* Set a bit. */ +#define KPSE_DEBUG_SET(bit) kpathsea_debug |= 1 << (bit) + +/* Test if a bit is on. */ +#define KPSE_DEBUG_P(bit) (kpathsea_debug & (1 << (bit))) + +#define KPSE_DEBUG_STAT 0 /* stat calls */ +#define KPSE_DEBUG_HASH 1 /* hash lookups */ +#define KPSE_DEBUG_FOPEN 2 /* fopen/fclose calls */ +#define KPSE_DEBUG_PATHS 3 /* search path initializations */ +#define KPSE_DEBUG_EXPAND 4 /* path element expansion */ +#define KPSE_DEBUG_SEARCH 5 /* searches */ +#define KPSE_DEBUG_VARS 6 /* variable values */ +#define KPSE_LAST_DEBUG KPSE_DEBUG_VARS + +/* A printf for the debugging. */ +#define DEBUGF_START() do { fputs ("kdebug:", stderr) +#define DEBUGF_END() fflush (stderr); } while (0) + +#define DEBUGF(str) \ + DEBUGF_START (); fputs (str, stderr); DEBUGF_END () +#define DEBUGF1(str, e1) \ + DEBUGF_START (); fprintf (stderr, str, e1); DEBUGF_END () +#define DEBUGF2(str, e1, e2) \ + DEBUGF_START (); fprintf (stderr, str, e1, e2); DEBUGF_END () +#define DEBUGF3(str, e1, e2, e3) \ + DEBUGF_START (); fprintf (stderr, str, e1, e2, e3); DEBUGF_END () +#define DEBUGF4(str, e1, e2, e3, e4) \ + DEBUGF_START (); fprintf (stderr, str, e1, e2, e3, e4); DEBUGF_END () + +#undef fopen +#define fopen kpse_fopen_trace +extern FILE *fopen (const char *filename, const char *mode); +#undef fclose +#define fclose kpse_fclose_trace +extern int fclose (FILE *); + +#endif /* not NO_DEBUG */ + +#if defined (WIN32) && !defined (__MINGW32__) + +/* System description file for Windows NT. */ + +/* + * Define symbols to identify the version of Unix this is. + * Define all the symbols that apply correctly. + */ + +#ifndef DOSISH +#define DOSISH +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN _MAX_PATH #endif +#define HAVE_DUP2 1 +#define HAVE_RENAME 1 +#define HAVE_RMDIR 1 +#define HAVE_MKDIR 1 +#define HAVE_GETHOSTNAME 1 +#define HAVE_RANDOM 1 +#define USE_UTIME 1 +#define HAVE_MOUSE 1 +#define HAVE_TZNAME 1 + +/* These have to be defined because our compilers treat __STDC__ as being + defined (most of them anyway). */ + +#define access _access +#define stat _stat +#define strcasecmp _stricmp +#define strdup _strdup +#define strncasecmp _strnicmp + +#define S_IFMT _S_IFMT +#define S_IFDIR _S_IFDIR + +/* Define this so that winsock.h definitions don't get included when + windows.h is... For this to have proper effect, config.h must + always be included before windows.h. */ +#define _WINSOCKAPI_ 1 + +#include + +/* Defines size_t and alloca (). */ +#include + +/* For proper declaration of environ. */ +#include +#include +#include + +/* ============================================================ */ + +#endif /* WIN32 */ + +/* hash.h: declarations for a hash table. */ + +/* A single (key,value) pair. */ +typedef struct hash_element_struct +{ + const char *key; + const char *value; + struct hash_element_struct *next; +} hash_element_type; + +/* The usual arrangement of buckets initialized to null. */ +typedef struct +{ + hash_element_type **buckets; + unsigned size; +} hash_table_type; + +static hash_table_type hash_create (unsigned size); + + +#ifdef KPSE_DEBUG +/* How to print the hash results when debugging. */ +extern int kpse_debug_hash_lookup_int; +#endif + +/* fn.h: arbitrarily long filenames (or just strings). */ + +/* Arbitrarily long filenames; it's inconvenient to use obstacks here, + because we want to maintain a null terminator. Also used for + dynamically growing strings even when the null byte isn't necessary, + e.g., in `variable.c', since I don't want to pass obstacks around + everywhere, and one can't free parts of an obstack arbitrarily. */ + +typedef struct +{ + char *str; + unsigned allocated; + unsigned length; /* includes the terminating null byte, if any */ +} fn_type; + +#define FN_STRING(fn) ((fn).str) +#define FN_ALLOCATED(fn) ((fn).allocated) +#define FN_LENGTH(fn) ((fn).length) + +/* lib.h: other stuff. */ + +/* Define common sorts of messages. */ + +/* This should be called only after a system call fails. Don't exit + with status `errno', because that might be 256, which would mean + success (exit statuses are truncated to eight bits). */ +#define FATAL_PERROR(str) do { \ + fputs ("pathsearch: ", stderr); \ + perror (str); exit (EXIT_FAILURE); } while (0) + +#define START_FATAL() do { \ + fputs ("pathsearch: fatal: ", stderr); +#define END_FATAL() fputs (".\n", stderr); exit (1); } while (0) + +#define FATAL(str) \ + START_FATAL (); fputs (str, stderr); END_FATAL () +#define FATAL1(str, e1) \ + START_FATAL (); fprintf (stderr, str, e1); END_FATAL () +#define FATAL2(str, e1, e2) \ + START_FATAL (); fprintf (stderr, str, e1, e2); END_FATAL () +#define FATAL3(str, e1, e2, e3) \ + START_FATAL (); fprintf (stderr, str, e1, e2, e3); END_FATAL () +#define FATAL4(str, e1, e2, e3, e4) \ + START_FATAL (); fprintf (stderr, str, e1, e2, e3, e4); END_FATAL () +#define FATAL5(str, e1, e2, e3, e4, e5) \ + START_FATAL (); fprintf (stderr, str, e1, e2, e3, e4, e5); END_FATAL () +#define FATAL6(str, e1, e2, e3, e4, e5, e6) \ + START_FATAL (); fprintf (stderr, str, e1, e2, e3, e4, e5, e6); END_FATAL () + + +#define START_WARNING() do { fputs ("warning: ", stderr) +#define END_WARNING() fputs (".\n", stderr); fflush (stderr); } while (0) + +#define WARNING(str) \ + START_WARNING (); fputs (str, stderr); END_WARNING () +#define WARNING1(str, e1) \ + START_WARNING (); fprintf (stderr, str, e1); END_WARNING () +#define WARNING2(str, e1, e2) \ + START_WARNING (); fprintf (stderr, str, e1, e2); END_WARNING () +#define WARNING3(str, e1, e2, e3) \ + START_WARNING (); fprintf (stderr, str, e1, e2, e3); END_WARNING () +#define WARNING4(str, e1, e2, e3, e4) \ + START_WARNING (); fprintf (stderr, str, e1, e2, e3, e4); END_WARNING () + + +/* I find this easier to read. */ +#define STREQ(s1, s2) (strcmp (s1, s2) == 0) +#define STRNEQ(s1, s2, n) (strncmp (s1, s2, n) == 0) + +/* Support for FAT/ISO-9660 filesystems. Theoretically this should be + done at runtime, per filesystem, but that's painful to program. */ +#ifdef MONOCASE_FILENAMES +#define FILESTRCASEEQ(s1, s2) (strcasecmp (s1, s2) == 0) +#define FILESTRNCASEEQ(s1, s2, l) (strncasecmp (s1, s2, l) == 0) +#define FILECHARCASEEQ(c1, c2) (toupper (c1) == toupper (c2)) +#else +#define FILESTRCASEEQ STREQ +#define FILESTRNCASEEQ STRNEQ +#define FILECHARCASEEQ(c1, c2) ((c1) == (c2)) +#endif + +/* This is the maximum number of numerals that result when a 64-bit + integer is converted to a string, plus one for a trailing null byte, + plus one for a sign. */ +#define MAX_INT_LENGTH 21 + +/* If the environment variable TEST is set, return it; otherwise, + DEFAULT. This is useful for paths that use more than one envvar. */ +#define ENVVAR(test, default) (getenv (test) ? (test) : (default)) + + +/* (Re)Allocate N items of type T using xmalloc/xrealloc. */ +#define XTALLOC(n, t) ((t *) xmalloc ((n) * sizeof (t))) +#define XTALLOC1(t) XTALLOC (1, t) +#define XRETALLOC(addr, n, t) ((addr) = (t *) xrealloc (addr, (n) * sizeof(t))) + +extern "C" char *xbasename (const char *name); + +static FILE *xfopen (const char *filename, const char *mode); + +static void xfclose (FILE *f, const char *filename); + +unsigned long xftell (FILE *f, char *filename); + +static void xclosedir (DIR *d); + +static void *xmalloc (unsigned size); + +static void *xrealloc (void *old_ptr, unsigned size); + +static char *xstrdup (const char *s); + +extern char *xbasename (const char *name); + +static int dir_p (const char *fn); + +#ifndef WIN32 +int dir_links (const char *fn); +#endif + +static unsigned hash (hash_table_type table, const char *key); + +static void hash_insert (hash_table_type *table, const char *key, + const char *value); + +static char **hash_lookup (hash_table_type table, const char *key); + +static void hash_print (hash_table_type table, int summary_only); + +static char *concat (const char *s1, const char *s2); + +static char *concat3 (const char *s1, const char *s2, const char *s3); + +static char *concatn (const char *str1, ...); + +static char *find_suffix (const char *name); + +static char *kpse_truncate_filename (const char *name); + +static char *kpse_readable_file (const char *name); + +static int kpse_absolute_p (const char *filename, int relative_ok); + +static str_list_type str_list_init (void); + +static void str_list_add (str_list_type *l, char *s); + +static void str_list_concat (str_list_type *target, str_list_type more); + +static void str_list_free (str_list_type *l); + +static void str_llist_add (str_llist_type *l, char *str); + +static void str_llist_float (str_llist_type *l, str_llist_elt_type *mover); + +static fn_type fn_init (void); + +static fn_type fn_copy0 (const char *s, unsigned len); + +static void fn_free (fn_type *f); + +static void grow (fn_type *f, unsigned len); + +static void fn_1grow (fn_type *f, char c); + +static void fn_grow (fn_type *f, void *source, unsigned len); + +static void fn_str_grow (fn_type *f, const char *s); + +static void fn_shrink_to (fn_type *f, unsigned loc); + +static char *kpse_var_value (const char *var); + +static void expanding (const char *var, int xp); + +static int expanding_p (const char *var); + +static void expand (fn_type *expansion, const char *start, const char *end); + +static char *kpse_var_expand (const char *src); + +#include /* for `time' */ + /* The very first search is for texmf.cnf, called when someone tries to initialize the TFM path or whatever. init_path calls kpse_cnf_get which calls kpse_all_path_search to find all the texmf.cnf's. We @@ -56,7 +443,7 @@ char *log_name = kpse_var_value ("TEXMFLOG"); first_time = false; if (log_name) { - log_file = fopen (log_name, FOPEN_A_MODE); + log_file = xfopen (log_name, "a"); if (!log_file) perror (log_name); free (log_name); @@ -266,29 +653,6 @@ char *name; bool absolute_p; -#ifdef __DJGPP__ - /* We will use `stat' heavily, so let's request for - the fastest possible version of `stat', by telling - it what members of struct stat do we really need. - - We need to set this on each call because this is a - library function; the caller might need other options - from `stat'. Thus save the flags and restore them - before exit. - - This call tells `stat' that we do NOT need to recognize - executable files (neither by an extension nor by a magic - signature); that we do NOT need time stamp of root directories; - and that we do NOT need the write access bit in st_mode. - - Note that `kpse_set_progname' needs the EXEC bits, - but it was already called by the time we get here. */ - unsigned short save_djgpp_flags = _djstat_flags; - - _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT - | _STAT_ROOT_TIME | _STAT_WRITEBIT; -#endif - /* Make a leading ~ count as an absolute filename, and expand $FOO's. */ name = kpse_expand (original_name); @@ -324,11 +688,6 @@ putc ('\n', stderr); } -#ifdef __DJGPP__ - /* Undo any side effects. */ - _djstat_flags = save_djgpp_flags; -#endif - return STR_LIST (ret_list); } @@ -489,29 +848,6 @@ { str_list_type ret_list; -#ifdef __DJGPP__ - /* We will use `stat' heavily, so let's request for - the fastest possible version of `stat', by telling - it what members of struct stat do we really need. - - We need to set this on each call because this is a - library function; the caller might need other options - from `stat'. Thus save the flags and restore them - before exit. - - This call tells `stat' that we do NOT need to recognize - executable files (neither by an extension nor by a magic - signature); that we do NOT need time stamp of root directories; - and that we do NOT need the write access bit in st_mode. - - Note that `kpse_set_progname' needs the EXEC bits, - but it was already called by the time we get here. */ - unsigned short save_djgpp_flags = _djstat_flags; - - _djstat_flags = _STAT_EXEC_MAGIC | _STAT_EXEC_EXT - | _STAT_ROOT_TIME | _STAT_WRITEBIT; -#endif - if (KPSE_DEBUG_P (KPSE_DEBUG_SEARCH)) { const char **p; @@ -560,11 +896,6 @@ putc ('\n', stderr); } -#ifdef __DJGPP__ - /* Undo any side effects. */ - _djstat_flags = save_djgpp_flags; -#endif - return STR_LIST (ret_list); } @@ -1526,7 +1857,7 @@ unsigned len = strlen (db_filename) - sizeof (DB_NAME) + 1; /* Keep the /. */ char *top_dir = (char *) xmalloc (len + 1); char *cur_dir = NULL; /* First thing in ls-R might be a filename. */ - FILE *db_file = fopen (db_filename, FOPEN_R_MODE); + FILE *db_file = xfopen (db_filename, "r"); strncpy (top_dir, db_filename, len); top_dir[len] = 0; @@ -1723,7 +2054,7 @@ { char *line, *real, *alias; unsigned count = 0; - FILE *alias_file = fopen (alias_filename, FOPEN_R_MODE); + FILE *alias_file = xfopen (alias_filename, "r"); if (alias_file) { while ((line = read_line (alias_file)) != NULL) { @@ -1733,13 +2064,13 @@ } else { /* Each line should have two fields: realname aliasname. */ real = line; - while (*real && ISSPACE (*real)) + while (*real && isspace (*real)) real++; alias = real; - while (*alias && !ISSPACE (*alias)) + while (*alias && !isspace (*alias)) alias++; *alias++ = 0; - while (*alias && ISSPACE (*alias)) + while (*alias && isspace (*alias)) alias++; /* Is the check for errors strong enough? Should we warn the user for potential errors? */ @@ -2428,3 +2759,986 @@ return element (p, false); } +/* xfopen.c: fopen and fclose with error checking. */ + +/* These routines just check the return status from standard library + routines and abort if an error happens. */ + +FILE * +xfopen (const char *filename, const char *mode) +{ + FILE *f; + + assert (filename && mode); + + f = fopen (filename, mode); + if (f == NULL) + FATAL_PERROR (filename); + + return f; +} + +void +xfclose (FILE *f, const char *filename) +{ + assert (f); + + if (fclose (f) == EOF) + FATAL_PERROR (filename); +} + +/* xftell.c: ftell with error checking. */ + +unsigned long +xftell (FILE *f, char *filename) +{ + long where = ftell (f); + + if (where < 0) + FATAL_PERROR (filename); + + return where; +} + +void +xclosedir (DIR *d) +{ +#ifdef CLOSEDIR_VOID + closedir (d); +#else + int ret = closedir (d); + + if (ret != 0) + FATAL ("closedir failed"); +#endif +} + +/* xmalloc.c: malloc with error checking. */ + +void * +xmalloc (unsigned size) +{ + void *new_mem = (void *) malloc (size); + + if (new_mem == NULL) + { + fprintf (stderr, "fatal: memory exhausted (xmalloc of %u bytes).\n", + size); + /* 1 means success on VMS, so pick a random number (ASCII `K'). */ + exit (75); + } + + return new_mem; +} + +/* xrealloc.c: realloc with error checking. */ + +extern void *xmalloc (unsigned); + +void * +xrealloc (void *old_ptr, unsigned size) +{ + void *new_mem; + + if (old_ptr == NULL) + new_mem = xmalloc (size); + else + { + new_mem = (void *) realloc (old_ptr, size); + if (new_mem == NULL) + { + /* We used to print OLD_PTR here using %x, and casting its + value to unsigned, but that lost on the Alpha, where + pointers and unsigned had different sizes. Since the info + is of little or no value anyway, just don't print it. */ + fprintf (stderr, "fatal: memory exhausted (realloc of %u bytes).\n", + size); + /* 1 means success on VMS, so pick a random number (ASCII `B'). */ + exit (66); + } + } + + return new_mem; +} + +/* xstrdup.c: strdup with error checking. */ + +/* Return a copy of S in new storage. */ + +char * +xstrdup (const char *s) +{ + char *new_string = (char *) xmalloc (strlen (s) + 1); + return strcpy (new_string, s); +} + +/* dir.c: directory operations. */ + +/* Return true if FN is a directory or a symlink to a directory, + false if not. */ + +int +dir_p (const char *fn) +{ +#ifdef WIN32 + int fa = GetFileAttributes(fn); + return (fa != 0xFFFFFFFF && (fa & FILE_ATTRIBUTE_DIRECTORY)); +#else + struct stat stats; + return stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode); +#endif +} + +#ifndef WIN32 + +/* Return -1 if FN isn't a directory, else its number of links. + Duplicate the call to stat; no need to incur overhead of a function + call for that little bit of cleanliness. */ + +int +dir_links (const char *fn) +{ + static hash_table_type link_table; + char **hash_ret; + long ret; + + if (link_table.size == 0) + link_table = hash_create (457); + +#ifdef KPSE_DEBUG + /* This is annoying, but since we're storing integers as pointers, we + can't print them as strings. */ + if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) + kpse_debug_hash_lookup_int = 1; +#endif + + hash_ret = hash_lookup (link_table, fn); + +#ifdef KPSE_DEBUG + if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) + kpse_debug_hash_lookup_int = 0; +#endif + + /* Have to cast the int we need to/from the const_string that the hash + table stores for values. Let's hope an int fits in a pointer. */ + if (hash_ret) + ret = (long) *hash_ret; + else + { + struct stat stats; + ret = stat (fn, &stats) == 0 && S_ISDIR (stats.st_mode) + ? stats.st_nlink : (unsigned) -1; + + /* It's up to us to copy the value. */ + hash_insert (&link_table, xstrdup (fn), (const char *) ret); + +#ifdef KPSE_DEBUG + if (KPSE_DEBUG_P (KPSE_DEBUG_STAT)) + DEBUGF2 ("dir_links(%s) => %ld\n", fn, ret); +#endif + } + + return ret; +} + +#endif /* !WIN32 */ + +/* hash.c: hash table operations. */ + +/* The hash function. We go for simplicity here. */ + +/* All our hash tables are related to filenames. */ +#ifdef MONOCASE_FILENAMES +#define TRANSFORM(x) toupper (x) +#else +#define TRANSFORM(x) (x) +#endif + +static unsigned +hash (hash_table_type table, const char *key) +{ + unsigned n = 0; + + /* Our keys aren't often anagrams of each other, so no point in + weighting the characters. */ + while (*key != 0) + n = (n + n + TRANSFORM (*key++)) % table.size; + + return n; +} + +hash_table_type +hash_create (unsigned size) +{ + /* hash_table_type ret; changed into "static ..." to work around gcc + optimizer bug for Alpha. */ + static hash_table_type ret; + unsigned b; + ret.buckets = XTALLOC (size, hash_element_type *); + ret.size = size; + + /* calloc's zeroes aren't necessarily NULL, so be safe. */ + for (b = 0; b key = key; + new_elt->value = value; + new_elt->next = NULL; + + /* Insert the new element at the end of the list. */ + if (!table->buckets[n]) + /* first element in bucket is a special case. */ + table->buckets[n] = new_elt; + else + { + hash_element_type *loc = table->buckets[n]; + while (loc->next) /* Find the last element. */ + loc = loc->next; + loc->next = new_elt; /* Insert the new one after. */ + } +} + +/* Look up STR in MAP. Return a (dynamically-allocated) list of the + corresponding strings or NULL if no match. */ + +#ifdef KPSE_DEBUG +/* Print the hash values as integers if this is nonzero. */ +int kpse_debug_hash_lookup_int = 0; +#endif + +char ** +hash_lookup (hash_table_type table, const char *key) +{ + hash_element_type *p; + str_list_type ret; + unsigned n = hash (table, key); + ret = str_list_init (); + + /* Look at everything in this bucket. */ + for (p = table.buckets[n]; p != NULL; p = p->next) + if (FILESTRCASEEQ (key, p->key)) + /* Cast because the general str_list_type shouldn't force const data. */ + str_list_add (&ret, (char *) p->value); + + /* If we found anything, mark end of list with null. */ + if (STR_LIST (ret)) + str_list_add (&ret, NULL); + +#ifdef KPSE_DEBUG + if (KPSE_DEBUG_P (KPSE_DEBUG_HASH)) + { + DEBUGF1 ("hash_lookup(%s) =>", key); + if (!STR_LIST (ret)) + fputs (" (nil)\n", stderr); + else + { + char **r; + for (r = STR_LIST (ret); *r; r++) + { + putc (' ', stderr); + if (kpse_debug_hash_lookup_int) + fprintf (stderr, "%ld", (long) *r); + else + fputs (*r, stderr); + } + putc ('\n', stderr); + } + fflush (stderr); + } +#endif + + return STR_LIST (ret); +} + +/* We only print nonempty buckets, to decrease output volume. */ + +void +hash_print (hash_table_type table, int summary_only) +{ + unsigned b; + unsigned total_elements = 0, total_buckets = 0; + + for (b = 0; b < table.size; b++) { + hash_element_type *bucket = table.buckets[b]; + + if (bucket) { + unsigned len = 1; + hash_element_type *tb; + + total_buckets++; + if (!summary_only) fprintf (stderr, "%4d ", b); + + for (tb = bucket->next; tb != NULL; tb = tb->next) + len++; + if (!summary_only) fprintf (stderr, ":%-5d", len); + total_elements += len; + + if (!summary_only) { + for (tb = bucket; tb != NULL; tb = tb->next) + fprintf (stderr, " %s=>%s", tb->key, tb->value); + putc ('\n', stderr); + } + } + } + + fprintf (stderr, + "%u buckets, %u nonempty (%u%%); %u entries, average chain %.1f.\n", + table.size, + total_buckets, + 100 * total_buckets / table.size, + total_elements, + total_buckets ? total_elements / (double) total_buckets : 0.0); +} + +/* concat.c: dynamic string concatenation. */ + +/* Return the concatenation of S1 and S2. See `concatn.c' for a + `concatn', which takes a variable number of arguments. */ + +char * +concat (const char *s1, const char *s2) +{ + char *answer = (char *) xmalloc (strlen (s1) + strlen (s2) + 1); + strcpy (answer, s1); + strcat (answer, s2); + + return answer; +} + +/* concat3.c: concatenate three strings. */ + +char * +concat3 (const char *s1, const char *s2, const char *s3) +{ + char *answer + = (char *) xmalloc (strlen (s1) + strlen (s2) + strlen (s3) + 1); + strcpy (answer, s1); + strcat (answer, s2); + strcat (answer, s3); + + return answer; +} + +/* concatn.c: Concatenate an arbitrary number of strings. */ + +/* OK, it would be epsilon more efficient to compute the total length + and then do the copying ourselves, but I doubt it matters in reality. */ + +char * +concatn (const char *str1, ...) +{ + char *arg; + char *ret; + va_list ap; + + va_start (ap, str1); + + if (!str1) + return NULL; + + ret = xstrdup (str1); + + while ((arg = va_arg (ap, char *)) != NULL) + { + char *temp = concat (ret, arg); + free (ret); + ret = temp; + } + va_end (ap); + + return ret; +} + +/* debug.c: Help the user discover what's going on. */ + +#ifdef KPSE_DEBUG + +unsigned int kpathsea_debug = 0; + +/* If the real definitions of fopen or fclose are macros, we lose -- the + #undef won't restore them. */ + +FILE * +fopen (const char *filename, const char *mode) +{ +#undef fopen + FILE *ret = fopen (filename, mode); + + if (KPSE_DEBUG_P (KPSE_DEBUG_FOPEN)) + DEBUGF3 ("fopen(%s, %s) => 0x%lx\n", filename, mode, (unsigned long) ret); + + return ret; +} + +int +fclose (FILE *f) +{ +#undef fclose + int ret = fclose (f); + + if (KPSE_DEBUG_P (KPSE_DEBUG_FOPEN)) + DEBUGF2 ("fclose(0x%lx) => %d\n", (unsigned long) f, ret); + + return ret; +} + +#endif + +/* find-suffix.c: return the stuff after a dot. */ + +/* Return pointer to first character after `.' in last directory element + of NAME. If the name is `foo' or `/foo.bar/baz', we have no extension. */ + +char * +find_suffix (const char *name) +{ + const char *slash_pos; + char *dot_pos = strrchr (name, '.'); + + if (dot_pos == NULL) + return NULL; + + for (slash_pos = name + strlen (name); + slash_pos > dot_pos && !IS_DIR_SEP (*slash_pos); + slash_pos--) + ; + + return slash_pos > dot_pos ? NULL : dot_pos + 1; +} + +/* rm-suffix.c: remove any suffix. */ + +/* Generic const warning -- see extend-fname.c. */ + +char * +remove_suffix (const char *s) +{ + char *ret; + const char *suffix = find_suffix (s); + + if (suffix) + { + /* Back up to before the dot. */ + suffix--; + ret = (char *) xmalloc (suffix - s + 1); + strncpy (ret, s, suffix - s); + ret[suffix - s] = 0; + } + else + ret = (char *) s; + + return ret; +} + +/* readable.c: check if a filename is a readable non-directory file. */ + +/* Truncate any too-long components in NAME, returning the result. It's + too bad this is necessary. See comments in readable.c for why. */ + +static char * +kpse_truncate_filename (const char *name) +{ + unsigned c_len = 0; /* Length of current component. */ + unsigned ret_len = 0; /* Length of constructed result. */ + + /* Allocate enough space. */ + char *ret = (char *) xmalloc (strlen (name) + 1); + + for (; *name; name++) + { + if (IS_DIR_SEP (*name) || IS_DEVICE_SEP (*name)) + { /* At a directory delimiter, reset component length. */ + c_len = 0; + } + else if (c_len > NAME_MAX) + { /* If past the max for a component, ignore this character. */ + continue; + } + + /* Copy this character. */ + ret[ret_len++] = *name; + c_len++; + } + ret[ret_len] = 0; + + return ret; +} + +/* If access can read FN, run stat (assigning to stat buffer ST) and + check that fn is not a directory. Don't check for just being a + regular file, as it is potentially useful to read fifo's or some + kinds of devices. */ + +#ifdef WIN32 +#define READABLE(fn, st) \ + (GetFileAttributes(fn) != 0xFFFFFFFF && \ + !(GetFileAttributes(fn) & FILE_ATTRIBUTE_DIRECTORY)) +#else +#define READABLE(fn, st) \ + (access (fn, R_OK) == 0 && stat (fn, &(st)) == 0 && !S_ISDIR (st.st_mode)) +#endif + +/* POSIX invented the brain-damage of not necessarily truncating + filename components; the system's behavior is defined by the value of + the symbol _POSIX_NO_TRUNC, but you can't change it dynamically! + + Generic const return warning. See extend-fname.c. */ + +char * +kpse_readable_file (const char *name) +{ + struct stat st; + char *ret; + + if (READABLE (name, st)) { + ret = (char *) name; + +#ifdef ENAMETOOLONG + } else if (errno == ENAMETOOLONG) { + ret = kpse_truncate_filename (name); + + /* Perhaps some other error will occur with the truncated name, so + let's call access again. */ + if (!READABLE (ret, st)) + { /* Failed. */ + if (ret != name) free (ret); + ret = NULL; + } +#endif /* ENAMETOOLONG */ + + } else { /* Some other error. */ + if (errno == EACCES) { /* Maybe warn them if permissions are bad. */ + perror (name); + } + ret = NULL; + } + + return ret; +} + +/* absolute.c: Test if a filename is absolute or explicitly relative. */ + +/* Sorry this is such a system-dependent mess, but I can't see any way + to usefully generalize. */ + +int +kpse_absolute_p (const char *filename, int relative_ok) +{ + int absolute = IS_DIR_SEP (*filename) +#ifdef DOSISH + /* Novell allows non-alphanumeric drive letters. */ + || (*filename && IS_DEVICE_SEP (filename[1])) +#endif /* DOSISH */ +#ifdef WIN32 + /* UNC names */ + || (*filename == '\\' && filename[1] == '\\') +#endif + ; + int explicit_relative + = relative_ok + && (*filename == '.' && (IS_DIR_SEP (filename[1]) + || (filename[1] == '.' && IS_DIR_SEP (filename[2])))); + + return absolute || explicit_relative; +} + +/* str-list.c: define routines for string lists. */ + +/* See the lib.h file for comments. */ + +str_list_type +str_list_init (void) +{ + str_list_type ret; + + STR_LIST_LENGTH (ret) = 0; + STR_LIST (ret) = NULL; + + return ret; +} + +void +str_list_add (str_list_type *l, char *s) +{ + STR_LIST_LENGTH (*l)++; + XRETALLOC (STR_LIST (*l), STR_LIST_LENGTH (*l), char *); + STR_LIST_LAST_ELT (*l) = s; +} + +/* May as well save some reallocations and do everything in a chunk + instead of calling str_list_add on each element. */ + +void +str_list_concat (str_list_type *target, str_list_type more) +{ + unsigned e; + unsigned prev_len = STR_LIST_LENGTH (*target); + + STR_LIST_LENGTH (*target) += STR_LIST_LENGTH (more); + XRETALLOC (STR_LIST (*target), STR_LIST_LENGTH (*target), char *); + + for (e = 0; e < STR_LIST_LENGTH (more); e++) + STR_LIST_ELT (*target, prev_len + e) = STR_LIST_ELT (more, e); +} + +/* Free the list (but not the elements within it). */ + +void +str_list_free (str_list_type *l) +{ + if (STR_LIST (*l)) + { + free (STR_LIST (*l)); + STR_LIST (*l) = NULL; + } +} + +/* str-llist.c: Implementation of a linked list of strings. */ + +/* Add the new string STR to the end of the list L. */ + +void +str_llist_add (str_llist_type *l, char *str) +{ + str_llist_elt_type *e; + str_llist_elt_type *new_elt = XTALLOC1 (str_llist_elt_type); + + /* The new element will be at the end of the list. */ + STR_LLIST (*new_elt) = str; + STR_LLIST_MOVED (*new_elt) = 0; + STR_LLIST_NEXT (*new_elt) = NULL; + + /* Find the current end of the list. */ + for (e = *l; e && STR_LLIST_NEXT (*e); e = STR_LLIST_NEXT (*e)) + ; + + if (!e) + *l = new_elt; + else + STR_LLIST_NEXT (*e) = new_elt; +} + +/* Move an element towards the top. The idea is that when a file is + found in a given directory, later files will likely be in that same + directory, and looking for the file in all the directories in between + is thus a waste. */ + +void +str_llist_float (str_llist_type *l, str_llist_elt_type *mover) +{ + str_llist_elt_type *last_moved, *unmoved; + + /* If we've already moved this element, never mind. */ + if (STR_LLIST_MOVED (*mover)) + return; + + /* Find the first unmoved element (to insert before). We're + guaranteed this will terminate, since MOVER itself is currently + unmoved, and it must be in L (by hypothesis). */ + for (last_moved = NULL, unmoved = *l; STR_LLIST_MOVED (*unmoved); + last_moved = unmoved, unmoved = STR_LLIST_NEXT (*unmoved)) + ; + + /* If we are the first unmoved element, nothing to relink. */ + if (unmoved != mover) + { /* Remember `mover's current successor, so we can relink `mover's + predecessor to it. */ + str_llist_elt_type *before_mover; + str_llist_elt_type *after_mover = STR_LLIST_NEXT (*mover); + + /* Find `mover's predecessor. */ + for (before_mover = unmoved; STR_LLIST_NEXT (*before_mover) != mover; + before_mover = STR_LLIST_NEXT (*before_mover)) + ; + + /* `before_mover' now links to `after_mover'. */ + STR_LLIST_NEXT (*before_mover) = after_mover; + + /* Insert `mover' before `unmoved' and after `last_moved' (or at + the head of the list). */ + STR_LLIST_NEXT (*mover) = unmoved; + if (!last_moved) + *l = mover; + else + STR_LLIST_NEXT (*last_moved) = mover; + } + + /* We've moved it. */ + STR_LLIST_MOVED (*mover) = 1; +} + +/* fn.c: arbitrarily long filenames (or just strings). */ + +/* /usr/local/lib/texmf/fonts/public/cm/pk/ljfour/cmr10.300pk is 58 + chars, so ASCII `K' seems a good choice. */ +#define CHUNK_SIZE 75 + +fn_type +fn_init (void) +{ + fn_type ret; + + FN_ALLOCATED (ret) = FN_LENGTH (ret) = 0; + FN_STRING (ret) = NULL; + + return ret; +} + +fn_type +fn_copy0 (const char *s, unsigned len) +{ + fn_type ret; + + FN_ALLOCATED (ret) = CHUNK_SIZE > len ? CHUNK_SIZE : len + 1; + FN_STRING (ret) = (char *) xmalloc (FN_ALLOCATED (ret)); + + strncpy (FN_STRING (ret), s, len); + FN_STRING (ret)[len] = 0; + FN_LENGTH (ret) = len + 1; + + return ret; +} + +/* Don't think we ever try to free something that might usefully be + empty, so give fatal error if nothing allocated. */ + +void +fn_free (fn_type *f) +{ + assert (FN_STRING (*f) != NULL); + free (FN_STRING (*f)); + FN_STRING (*f) = NULL; + FN_ALLOCATED (*f) = 0; + FN_LENGTH (*f) = 0; +} + +/* An arithmetic increase seems more reasonable than geometric. We + don't increase the length member since it may be more convenient for + the caller to add than subtract when appending the stuff that will + presumably follow. */ + +static void +grow (fn_type *f, unsigned len) +{ + while (FN_LENGTH (*f) + len > FN_ALLOCATED (*f)) + { + FN_ALLOCATED (*f) += CHUNK_SIZE; + XRETALLOC (FN_STRING (*f), FN_ALLOCATED (*f), char); + } +} + +void +fn_1grow (fn_type *f, char c) +{ + grow (f, 1); + FN_STRING (*f)[FN_LENGTH (*f)] = c; + FN_LENGTH (*f)++; +} + +void +fn_grow (fn_type *f, void *source, unsigned len) +{ + grow (f, len); + strncpy (FN_STRING (*f) + FN_LENGTH (*f), (char *) source, len); + FN_LENGTH (*f) += len; +} + +void +fn_str_grow (fn_type *f, const char *s) +{ + unsigned more_len = strlen (s); + grow (f, more_len); + strcat (FN_STRING (*f), s); + FN_LENGTH (*f) += more_len; +} + +void +fn_shrink_to (fn_type *f, unsigned loc) +{ + assert (FN_LENGTH (*f) > loc); + FN_STRING (*f)[loc] = 0; + FN_LENGTH (*f) = loc + 1; +} + +/* variable.c: variable expansion. */ + +/* Here's the simple one, when a program just wants a value. */ + +char * +kpse_var_value (const char *var) +{ + char *ret = getenv (var); + + if (ret) + ret = kpse_var_expand (ret); + +#ifdef KPSE_DEBUG + if (KPSE_DEBUG_P (KPSE_DEBUG_VARS)) + DEBUGF2("variable: %s = %s\n", var, ret ? ret : "(nil)"); +#endif + + return ret; +} + +/* We have to keep track of variables being expanded, otherwise + constructs like TEXINPUTS = $TEXINPUTS result in an infinite loop. + (Or indirectly recursive variables, etc.) Our simple solution is to + add to a list each time an expansion is started, and check the list + before expanding. */ + +typedef struct { + const char *var; + int expanding; +} expansion_type; +static expansion_type *expansions; /* The sole variable of this type. */ +static unsigned expansion_len = 0; + +static void +expanding (const char *var, int xp) +{ + unsigned e; + for (e = 0; e < expansion_len; e++) { + if (STREQ (expansions[e].var, var)) { + expansions[e].expanding = xp; + return; + } + } + + /* New variable, add it to the list. */ + expansion_len++; + XRETALLOC (expansions, expansion_len, expansion_type); + expansions[expansion_len - 1].var = xstrdup (var); + expansions[expansion_len - 1].expanding = xp; +} + + +/* Return whether VAR is currently being expanding. */ + +static int +expanding_p (const char *var) +{ + unsigned e; + for (e = 0; e < expansion_len; e++) { + if (STREQ (expansions[e].var, var)) + return expansions[e].expanding; + } + + return 0; +} + +/* Append the result of value of `var' to EXPANSION, where `var' begins + at START and ends at END. If `var' is not set, do not complain. + This is a subroutine for the more complicated expansion function. */ + +static void +expand (fn_type *expansion, const char *start, const char *end) +{ + char *value; + unsigned len = end - start + 1; + char *var = (char *) xmalloc (len + 1); + strncpy (var, start, len); + var[len] = 0; + + if (expanding_p (var)) { + WARNING1 ("kpathsea: variable `%s' references itself (eventually)", var); + } else { + /* Check for an environment variable. */ + value = getenv (var); + + if (value) { + expanding (var, 1); + value = kpse_var_expand (value); + expanding (var, 0); + fn_grow (expansion, value, strlen (value)); + free (value); + } + + free (var); + } +} + +/* Can't think of when it would be useful to change these (and the + diagnostic messages assume them), but ... */ +#ifndef IS_VAR_START /* starts all variable references */ +#define IS_VAR_START(c) ((c) == '$') +#endif +#ifndef IS_VAR_CHAR /* variable name constituent */ +#define IS_VAR_CHAR(c) (isalnum (c) || (c) == '_') +#endif +#ifndef IS_VAR_BEGIN_DELIMITER /* start delimited variable name (after $) */ +#define IS_VAR_BEGIN_DELIMITER(c) ((c) == '{') +#endif +#ifndef IS_VAR_END_DELIMITER +#define IS_VAR_END_DELIMITER(c) ((c) == '}') +#endif + + +/* Maybe we should support some or all of the various shell ${...} + constructs, especially ${var-value}. */ + +char * +kpse_var_expand (const char *src) +{ + const char *s; + char *ret; + fn_type expansion; + expansion = fn_init (); + + /* Copy everything but variable constructs. */ + for (s = src; *s; s++) { + if (IS_VAR_START (*s)) { + s++; + + /* Three cases: `$VAR', `${VAR}', `$'. */ + if (IS_VAR_CHAR (*s)) { + /* $V: collect name constituents, then expand. */ + const char *var_end = s; + + do { + var_end++; + } while (IS_VAR_CHAR (*var_end)); + + var_end--; /* had to go one past */ + expand (&expansion, s, var_end); + s = var_end; + + } else if (IS_VAR_BEGIN_DELIMITER (*s)) { + /* ${: scan ahead for matching delimiter, then expand. */ + const char *var_end = ++s; + + while (*var_end && !IS_VAR_END_DELIMITER (*var_end)) + var_end++; + + if (! *var_end) { + WARNING1 ("%s: No matching } for ${", src); + s = var_end - 1; /* will incr to null at top of loop */ + } else { + expand (&expansion, s, var_end - 1); + s = var_end; /* will incr past } at top of loop*/ + } + + } else { + /* $: error. */ + WARNING2 ("%s: Unrecognized variable construct `$%c'", src, *s); + /* Just ignore those chars and keep going. */ + } + } else + fn_1grow (&expansion, *s); + } + fn_1grow (&expansion, 0); + + ret = FN_STRING (expansion); + return ret; +} diff -r f1fcc371e5ef -r de8c1d2ee728 liboctave/kpse.h --- a/liboctave/kpse.h Wed Apr 23 19:51:58 2003 +0000 +++ b/liboctave/kpse.h Thu Apr 24 03:27:41 2003 +0000 @@ -19,7 +19,36 @@ #ifndef KPATHSEA_PATHSEARCH_H #define KPATHSEA_PATHSEARCH_H -#include "kpse-xfns.h" +/* Lists of strings; used for, e.g., directory lists. */ + +typedef struct +{ + unsigned length; + char **list; +} str_list_type; + +#define STR_LIST_LENGTH(l) ((l).length) +#define STR_LIST(l) ((l).list) +#define STR_LIST_ELT(l, n) STR_LIST (l)[n] +#define STR_LIST_LAST_ELT(l) STR_LIST_ELT (l, STR_LIST_LENGTH (l) - 1) + +/* It's a little bizarre to be using the same type for the list and the + elements of the list, but no reason not to in this case, I think -- + we never need a NULL string in the middle of the list, and an extra + NULL/NULL element always at the end is inconsequential. */ + +struct str_llist_elt +{ + char *str; + int moved; + struct str_llist_elt *next; +}; +typedef struct str_llist_elt str_llist_elt_type; +typedef struct str_llist_elt *str_llist_type; + +#define STR_LLIST(sl) ((sl).str) +#define STR_LLIST_MOVED(sl) ((sl).moved) +#define STR_LLIST_NEXT(sl) ((sl).next) /* If PATH is non-null, return its first element (as defined by IS_ENV_SEP). If it's NULL, return the next element in the previous @@ -126,5 +155,7 @@ Called by mktexpk et al. */ extern void kpse_db_insert (const char *fname); +extern unsigned int kpathsea_debug; + #endif /* not KPATHSEA_PATHSEARCH_H */