diff options
Diffstat (limited to 'dviware/crudetype/version3/w2c-ext.c')
-rw-r--r-- | dviware/crudetype/version3/w2c-ext.c | 628 |
1 files changed, 628 insertions, 0 deletions
diff --git a/dviware/crudetype/version3/w2c-ext.c b/dviware/crudetype/version3/w2c-ext.c new file mode 100644 index 0000000000..1936da74ad --- /dev/null +++ b/dviware/crudetype/version3/w2c-ext.c @@ -0,0 +1,628 @@ +/* External procedures for these programs. */ + +/* This includes <stdio.h> and "site.h". */ +#include "w2c-ext.h" + +extern unsigned char xord[], xchr[]; + +/* These help to deal with Pascal vs. C strings. */ +void make_c_string (), make_pascal_string (); +void end_with_null (), end_with_space (); + + +/* Round R to the nearest whole number. */ +integer zround (r) + double r; +{ + return r >= 0.0 ? (r + 0.5) : (r - 0.5); +} + + +/* Memory operations: variants of malloc(3) and realloc(3) that just + give up the ghost when they fail. It is a very bad practice to call + system procs & not check for errors. +*/ + +extern char *malloc (), *realloc (); + +char *xmalloc (size) + unsigned size; +{ + char *mem = malloc (size); + + if (mem == NULL) + { + fprintf (stderr, "! Cannot allocate %u bytes.\n", size); + exit (10); + } + + return mem; +} + + +char * xrealloc (ptr, size) + char *ptr; + unsigned size; +{ + char *mem = realloc (ptr, size); + + if (mem == NULL) + { + fprintf (stderr, "! Cannot reallocate %u bytes at %x.\n", size, ptr); + exit (10); + } + + return mem; +} + + +/* String operations. */ + +/* Deal with C and Pascal strings. */ + +/* Change the Pascal string P_STRING into a C string; i.e., make it + start after the leading character Pascal puts in, and terminate it + with a null. We also have to convert from the internal character set + (ASCII) to the external character set, if we're running on a + non-ASCII system. +*/ +void make_c_string (p_string) + char **p_string; +{ + (*p_string)++; + end_with_null (*p_string); +} + + +/* Replace the first space we come to with a null. +*/ +void end_with_null (s) + char *s; +{ + for ( ; *s != ' '; s++) +#ifdef NONASCII + *s = xchr[*s] +#endif + ; + *s = '\0'; +} + + +/* Change the C string C_STRING into a Pascal string; i.e., make it + start one character before it does now (so C_STRING had better have + been a Pascal string originally), and terminate with a space. We + also convert back from the external character set to the internal + character set (ASCII), if we're running on a non-ASCII system. +*/ +void make_pascal_string (c_string) + char **c_string; +{ + end_with_space (*c_string); + (*c_string)--; +} + +/* Replace the first null we come to with a space. +*/ +void end_with_space (s) + char *s; +{ + for ( ; *s != '\0' ; s++) +#ifdef NONASCII + *s = xchr[*s] +#endif + ; + + *s = ' '; +} + + +/* Change the suffix of BASE (a Pascal string) to be SUFFIX (another + Pascal string). We have to change them to C strings to do the work, + then convert them back to Pascal strings. +*/ +void makesuffix (base, suffix) + char *base; + char *suffix; +{ + char *last_dot, *last_slash; + make_c_string (&base); + + last_dot = rindex (base, '.'); + last_slash = rindex (base, '/'); + + if (last_dot == NULL || last_dot < last_slash) /* Add the suffix? */ + { + make_c_string (&suffix); + strcat (base, suffix); + make_pascal_string (&suffix); + } + + make_pascal_string (&base); +} + + +/* Insert the string INSERTION into TARGET before the index WHERE. We + assume that TARGET is large enough to hold the result. +*/ +static void insert_string (target, where, insertion) + char target[]; + int where; + char *insertion; +{ + int i; + unsigned insertion_length = strlen (insertion); + unsigned target_length = strlen (target); + + for (i = target_length; i >= where; i--) + target[i + insertion_length] = target[i]; + + strncpy (target + where, insertion, insertion_length); +} + + + +/* Path searching. */ + +#define NUMBER_OF_PATHS 11 + +static char *path[NUMBER_OF_PATHS]; +static char *env_var_names[NUMBER_OF_PATHS] + = { "BIBINPUTS", "GFFONTS", "MFBASES", "MFINPUTS", "MFPOOL", + "PKFONTS", "TEXFORMATS", "TEXINPUTS", "TEXPOOL", + "TEXFONTS", "VFFONTS" + }; + +#define READ_ACCESS 4 /* Used in access(2) call. */ + +/* What separates elements of the path variables. */ +#ifdef MS_DOS +#define PATH_DELIMITER ';' +#else +#define PATH_DELIMITER ':' +#endif + +/* We will need some system include files to deal with directories. */ +#ifdef SEARCH_SUBDIRECTORIES +#include <sys/types.h> +#include <sys/stat.h> +#ifdef SYSV +#include <dirent.h> +typedef struct dirent *directory_entry_type; +#else +#include <sys/dir.h> +typedef struct direct *directory_entry_type; +#endif /* not SYSV */ + +/* Declare getcwd(3). */ +extern char *getcwd (); +extern int errno; +#endif /* SEARCH_SUBDIRECTORIES */ + + +/* Subroutines. */ +static void next_component (); +int is_dir (); + +/* Says where NAME is ok to open for reading. */ +#define READABLE_FILE(name) access (name, READ_ACCESS) == 0 && !is_dir (name) + + +/* This routine initializes `path[PATH_INDEX]'. If the environment + variable `env_var_names[PATH_INDEX]' is not set, we simply use + DEFAULT_VALUE. Otherwise, we use the value of the environment + variable, and then replace any ``extra'' colons with DEFAULT_VALUE. + + For example, if DEFAULT_VALUE is `foo', and the environment variable + value is `:bar::baz:', the final result will be + `foo:bar:foo:baz:foo'. (Of course, it is pointless to have more than + one extra `:' in practice, but the point is that it can be anywhere.) + + If subdirectory searching has been compiled (by defining + SEARCH_SUBDIRECTORIES), and SUBDIR_FLAG so indicates, we look at each + directory in the path and add all subdirectories we find to the end + of the path. This is somewhat less efficient when we are looking for + only one file, and the file would be found early in the path, but is + far more efficient when we look up many files using the same path. */ + +/* Values for SUBDIR_FLAG. */ +#define SUBDIR_NO_CHECK 0 +#define SUBDIR_ALWAYS_CHECK 1 +#define SUBDIR_CHECK_IF_NOT_DEFAULT 2 + +static void +do_path (path_index, default_value, subdir_flag) + unsigned path_index; + char *default_value; + int subdir_flag; +{ + char *temp; + char *the_path; + + temp = getenv (env_var_names[path_index]); + if (temp == NULL) + /* This doesn't actually assign into the array, but it doesn't + matter. */ + the_path = default_value; + else + { /* Replace extra `:'s with the system default. */ + the_path = xmalloc (strlen (temp) + 1); + strcpy (the_path, temp); + + if (*the_path == PATH_DELIMITER) + { + the_path = xrealloc (the_path, strlen (the_path) + + strlen (default_value) + 1); + insert_string (the_path, 0, default_value); + } + if (*(the_path + strlen (the_path) - 1) == PATH_DELIMITER) + { + the_path = xrealloc (the_path, strlen (the_path) + + strlen (default_value) + 1); + strcat (the_path, default_value); + } + while ((temp = index (temp, PATH_DELIMITER)) != NULL) + { + temp++; + if (*temp == PATH_DELIMITER) + { + the_path = xrealloc (the_path, strlen (the_path) + + strlen (default_value) + 1); + insert_string (the_path, temp - the_path, default_value); + temp++; + } + } + } + + /* Assign to the final resting place. */ + path[path_index] = xmalloc (strlen (the_path) + 1); + strcpy (path[path_index], the_path); + +#ifdef SEARCH_SUBDIRECTORIES + /* At this point, `path[path_index]' is the colon-separated list of + directories to search. We want to add all the subdirectories + directly below each of those directories. */ + if (subdir_flag == SUBDIR_ALWAYS_CHECK + || (subdir_flag == SUBDIR_CHECK_IF_NOT_DEFAULT + && the_path != default_value)) + { + DIR *dir; + directory_entry_type e; + char dirname[FILENAMESIZE]; + + /* Unfortunately, we can't look in the environment for the current + directory, because if we are running under a program (let's say + Emacs), the PWD variable might have been set by Emacs' parent + to the current directory at the time Emacs was invoked. This + is not necessarily the same directory the user expects to be + in. So, we must always call getcwd(3), even though it is slow + and prone to hang in networked installations. */ + char *cwd = getcwd (NULL, FILENAMESIZE + 2); + if (cwd == NULL) + { + perror ("getcwd"); + exit (errno); + } + + temp = xmalloc (strlen (path[path_index]) + 1); + strcpy (temp, path[path_index]); + + do + { + next_component (dirname, &temp); + + /* All the `::'s should be gone by now, but we may as well make + sure `opendir' doesn't crash. */ + if (*dirname == 0) continue; + + /* By changing directories, we save a bunch of string + concatenations (and make the pathnames the kernel looks up + shorter). */ + if (chdir (dirname) != 0) continue; + + dir = opendir ("."); + if (dir == NULL) continue; + + while ((e = readdir (dir)) != NULL) + { + if (is_dir (e->d_name) && strcmp (e->d_name, ".") != 0 + && strcmp (e->d_name, "..") != 0) + { + unsigned len = strlen (path[path_index]); + char potential[FILENAMESIZE]; + strcpy (potential, dirname); + strcat (potential, "/"); + strcat (potential, e->d_name); + + path[path_index] = xrealloc (path[path_index], + len + strlen (potential) + 2); + + len = strlen (path[path_index]); + *(path[path_index] + len) = PATH_DELIMITER; + *(path[path_index] + len + 1) = 0; + strcat (path[path_index], potential); + } + } + closedir (dir); + + /* Change back to the current directory, in case the path + contains relative directory names. */ + if (chdir (cwd) != 0) + { + perror (cwd); + exit (errno); + } + } + while (*temp != 0); + } +#endif +} + + +/* This sets up the paths, by either copying from an environment variable + or using the default path, which is defined as a preprocessor symbol + (with the same name as the environment variable) in `site.h'. The + parameter PATH_BITS is a logical or of the paths we need to set. +*/ +extern void +setpaths (path_bits) + int path_bits; +{ + /* We must assign to the TFM file path before doing any of the other + font paths, since it is used as a default. */ + if (path_bits + & (TFMFILEPATHBIT | GFFILEPATHBIT | PKFILEPATHBIT | VFFILEPATHBIT)) + do_path (TFMFILEPATH, TEXFONTS, SUBDIR_ALWAYS_CHECK); + + if (path_bits & BIBINPUTPATHBIT) + do_path (BIBINPUTPATH, BIBINPUTS, SUBDIR_NO_CHECK); + + if (path_bits & GFFILEPATHBIT) + do_path (GFFILEPATH, path[TFMFILEPATH], SUBDIR_CHECK_IF_NOT_DEFAULT); + + if (path_bits & MFBASEPATHBIT) + do_path (MFBASEPATH, MFBASES, SUBDIR_NO_CHECK); + + if (path_bits & MFINPUTPATHBIT) + do_path (MFINPUTPATH, MFINPUTS, SUBDIR_ALWAYS_CHECK); + + if (path_bits & MFPOOLPATHBIT) + do_path (MFPOOLPATH, MFPOOL, SUBDIR_NO_CHECK); + + if (path_bits & PKFILEPATHBIT) + do_path (PKFILEPATH, path[TFMFILEPATH], SUBDIR_CHECK_IF_NOT_DEFAULT); + + if (path_bits & TEXFORMATPATHBIT) + do_path (TEXFORMATPATH, TEXFORMATS, SUBDIR_NO_CHECK); + + if (path_bits & TEXINPUTPATHBIT) + do_path (TEXINPUTPATH, TEXINPUTS, SUBDIR_ALWAYS_CHECK); + + if (path_bits & TEXPOOLPATHBIT) + do_path (TEXPOOLPATH, TEXPOOL, SUBDIR_NO_CHECK); + + if (path_bits & VFFILEPATHBIT) + do_path (VFFILEPATH, path[TFMFILEPATH], SUBDIR_CHECK_IF_NOT_DEFAULT); +} + + +/* Look for NAME, a Pascal string, in a colon-separated list of + directories. The path to use is given (indirectly) by PATH_INDEX. + If the search is successful, leave the full pathname in NAME (which + therefore must have enough room for such a pathname), padded with + blanks. Otherwise, or if NAME is an absolute or relative pathname, + just leave it alone. +*/ +boolean +testreadaccess (name, path_index) + char *name; + int path_index; +{ + char potential[FILENAMESIZE]; + int ok = 0; + char *the_path = path[path_index]; + char *saved_path = the_path; + + make_c_string (&name); + + if (*name == '/' || *name == '~' + || (*name == '.' && *(name + 1) == '/') + || (*name == '.' && *(name + 1) == '.' && *(name + 2) == '/')) + ok = READABLE_FILE (name); + else + { + do + { + next_component (potential, &the_path); + + if (*potential != 0) + { + strcat (potential, "/"); + strcat (potential, name); + ok = READABLE_FILE (potential); + } + } + while (!ok && *the_path != 0); + + /* If we found it, leave the answer in NAME. */ + if (ok) + strcpy (name, potential); + } + + make_pascal_string (&name); + + return ok; +} + + +/* Return, in NAME, the next component of PATH, i.e., the characters up + to the next PATH_DELIMITER. +*/ +static void next_component (name, path) + char name[]; + char **path; +{ + unsigned count = 0; + + while (**path != 0 && **path != PATH_DELIMITER) + { + name[count++] = **path; + (*path)++; /* Move further along, even between calls. */ + } + + name[count] = 0; + if (**path == PATH_DELIMITER) + (*path)++; /* Move past the delimiter. */ +} + + + +/* Return true if FN is a directory or a symlink to a directory, + false if not. +*/ +int +is_dir (fn) + char *fn; +{ + struct stat stats; + + return stat (fn, &stats) == 0 && (stats.st_mode & S_IFMT) == S_IFDIR; +} + + + +/* File operations. */ + +/* Open a file; don't return if any error occurs. NAME is a Pascal + string, but is changed to a C string and not changed back. + RMD: I do want it changed back +*/ +FILE * checked_fopen (name, mode) + char *name; + char *mode; +{ + FILE *result; + char *cp; + + make_c_string (&name); + + result = fopen (name, mode); + if (result != NULL) { + make_pascal_string (&name); + return result;} + + perror (name); + exit (1); + /*NOTREACHED*/ +} + + +/* Return true if we're at the end of FILE, else false. This implements + Pascal's `eof' builtin. +*/ +boolean test_eof (file) + text file; +{ + register int c; + FILE *ff ; + /* Maybe we're already at the end? */ + ff = *file ; + if (feof( ff)) + return true; + + if ((c = getc (*file)) == EOF) + return true; + + /* Whoops, we weren't at the end. Back up. */ + (void) ungetc (c, *file); + + return false; +} + + +/* Return true on end-of-line in FILE or at the end of FILE, else false. +*/ + +boolean eoln (file) + text file; +{ + register int c; + + if (feof (*file)) + return true; + + c = getc (*file); + + if (c != EOF) + (void) ungetc (c, *file); + + return c == '\n' || c == EOF; +} + + +/* Print real number R in the Pascal format N:M on the file F. +RMD: these procs not used; I made web2c generate proper write statements. +*/ +void fprintreal (f, r, n, m) + text f; + double r; + int n, m; +{ + char fmt[50]; /* Surely enough, since N and M won't be more than 25 + digits each! */ + + (void) sprintf (fmt, "%%%d.%dlf", n, m); + (void) fprintf (*f, fmt, r); +} + + +/* Print S, a Pascal string, on the file F. It starts at index 1 and is + terminated by a space. +*/ +static void fprint_pascal_string (s, f) + char *s; + FILE *f; +{ + s++; + while (*s != ' ') putc (*s++, f); +} + +/* Print S, a Pascal string, on stdout. +*/ +void printpascalstring (s) + char *s; +{ + fprint_pascal_string (s, stdout); +} + +/* Ditto, for stderr. +*/ +void errprintpascalstring (s) + char *s; +{ + fprint_pascal_string (s, stderr); +} + +/* Read an integer from the file F, reading past the subsequent end of + line. +*/ +integer inputint (f) + text f; +{ + char buffer[50]; /* Long enough for anything reasonable. */ + + return + fgets (buffer, sizeof (buffer), *f) + ? atoi (buffer) + : 0; +} + +/* Read three integers from stdin. +*/ +void zinput3ints (a,b,c) + integer *a, *b, *c; +{ + while (scanf ("%ld %ld %ld\n", a, b, c) != 3) + (void) fprintf (stderr, "Please enter three integers.\n"); +} + + |