static int lua_kpathsea_readable_file(lua_State * L) { kpathsea *kp = (kpathsea *) luaL_checkudata(L, 1, KPATHSEA_METATABLE); char *name = xstrdup(luaL_checkstring(L, 2)); lua_pushstring(L, kpathsea_readable_file(*kp, name)); free(name); return 1; }
static string maketex (kpathsea kpse, kpse_file_format_type format, string* args) { /* New implementation, use fork/exec pair instead of popen, since * the latter is virtually impossible to make safe. */ unsigned len; string *s; string ret = NULL; string fn; #if defined(WIN32) char fullbin[256], *wrp; wrp = kpathsea_var_value(kpse, "SELFAUTOLOC"); if(wrp == NULL) { fprintf(stderr, "I cannot get SELFAUTOLOC\n"); exit(100); } strcpy(fullbin, wrp); free(wrp); for(wrp=fullbin; *wrp; wrp++) { if(*wrp == '/') *wrp = '\\'; } strcat(fullbin, "\\"); strcat(fullbin, args[0]); #endif if (!kpse->make_tex_discard_errors) { fprintf (stderr, "\nkpathsea: Running"); for (s = &args[0]; *s != NULL; s++) fprintf (stderr, " %s", *s); fputc('\n', stderr); } #if defined (AMIGA) /* Amiga has a different interface. */ { string cmd; string newcmd; cmd = xstrdup(args[0]); for (s = &args[1]; *s != NULL; s++) { newcmd = concat(cmd, *s); free (cmd); cmd = newcmd; } ret = system(cmd) == 0 ? getenv ("LAST_FONT_CREATED"): NULL; free (cmd); } #elif defined (MSDOS) && !defined(__DJGPP__) #error Implement new MSDOS mktex call interface here #else /* WIN32 or Unix */ { #if defined (WIN32) /* spawnvp(_P_NOWAIT, ...) and pipe --ak 2002/12/15 */ unsigned long nexitcode = STILL_ACTIVE; HANDLE hchild; int hstdout, childpipe[2]; int hstderr = -1; FILE *Hnul = NULL; fn = NULL; if(_pipe(childpipe, 1024, O_TEXT | _O_NOINHERIT) == -1) { perror("kpathsea: pipe()"); goto labeldone; } hstdout = _dup(fileno(stdout)); if(_dup2(childpipe[1], fileno(stdout)) != 0) { close(hstdout); close(childpipe[0]); close(childpipe[1]); goto labeldone; } close(childpipe[1]); if(kpse->make_tex_discard_errors) { Hnul = fopen("nul", "w"); if(!Hnul) { perror("kpathsea: fopen(\"nul\")"); } else { hstderr = _dup(fileno(stderr)); _dup2(fileno(Hnul), fileno(stderr)); } } fprintf(stderr, "\nThe command name is %s\n", fullbin); hchild = (HANDLE)_spawnvp(_P_NOWAIT, fullbin, (const char * const *) args); _dup2(hstdout, fileno(stdout)); close(hstdout); if(hchild == (HANDLE)(-1)) { close(childpipe[0]); goto labeldone; } if(hchild) { char buf[1024+1]; int num; fn = xstrdup(""); while(nexitcode == STILL_ACTIVE) { num = read(childpipe[0], buf, sizeof(buf)-1); if(num) { string newfn; buf[num] = '\0'; newfn = concat(fn, buf); free(fn); fn = newfn; } if(!GetExitCodeProcess(hchild, &nexitcode)) { fn = NULL; close(childpipe[0]); goto labeldone; } } close(childpipe[0]); } labeldone: if(kpse->make_tex_discard_errors && Hnul) { _dup2(hstderr, fileno(stderr)); close(hstderr); fclose(Hnul); } #else /* !WIN32 */ /* Standard input for the child. Set to /dev/null */ int childin; /* Standard output for the child, what we're interested in. */ int childout[2]; /* Standard error for the child, same as parent or /dev/null */ int childerr; /* Child pid. */ pid_t childpid; /* Open the channels that the child will use. */ /* A fairly horrible uses of gotos for here for the error case. */ if ((childin = open("/dev/null", O_RDONLY)) < 0) { perror("kpathsea: open(\"/dev/null\", O_RDONLY)"); goto error_childin; } if (pipe(childout) < 0) { perror("kpathsea: pipe()"); goto error_childout; } if ((childerr = open("/dev/null", O_WRONLY)) < 0) { perror("kpathsea: open(\"/dev/null\", O_WRONLY)"); goto error_childerr; } if ((childpid = fork()) < 0) { perror("kpathsea: fork()"); close(childerr); error_childerr: close(childout[0]); close(childout[1]); error_childout: close(childin); error_childin: fn = NULL; } else if (childpid == 0) { /* Child * * We can use vfork, provided we're careful about what we * do here: do not return from this function, do not modify * variables, call _exit if there is a problem. * * Complete setting up the file descriptors. * We use dup(2) so the order in which we do this matters. */ close(childout[0]); /* stdin -- the child will not receive input from this */ if (childin != 0) { close(0); if (dup(childin) != 0) { perror("kpathsea: dup(2) failed for stdin"); close(childin); _exit(1); } close(childin); } /* stdout -- the output of the child's action */ if (childout[1] != 1) { close(1); if (dup(childout[1]) != 1) { perror("kpathsea: dup(2) failed for stdout"); close(childout[1]); _exit(1); } close(childout[1]); } /* stderr -- use /dev/null if we discard errors */ if (childerr != 2) { if (kpse->make_tex_discard_errors) { close(2); if (dup(childerr) != 2) { perror("kpathsea: dup(2) failed for stderr"); close(childerr); _exit(1); } } close(childerr); } /* FIXME: We could/should close all other file descriptors as well. */ /* exec -- on failure a call of _exit(2) it is the only option */ if (execvp(args[0], args)) perror(args[0]); _exit(1); } else { /* Parent */ char buf[1024+1]; int num; /* Clean up child file descriptors that we won't use anyway. */ close(childin); close(childout[1]); close(childerr); /* Get stdout of child from the pipe. */ fn = xstrdup(""); while ((num = read(childout[0],buf,sizeof(buf)-1)) != 0) { if (num == -1) { if (errno != EINTR) { perror("kpathsea: read()"); break; } } else { string newfn; buf[num] = '\0'; newfn = concat(fn, buf); free(fn); fn = newfn; } } /* End of file on pipe, child should have exited at this point. */ close(childout[0]); /* We don't really care about the exit status at this point. */ wait(NULL); } #endif /* !WIN32 */ if (fn) { len = strlen(fn); /* Remove trailing newlines and returns. */ while (len && (fn[len - 1] == '\n' || fn[len - 1] == '\r')) { fn[len - 1] = '\0'; len--; } ret = len == 0 ? NULL : kpathsea_readable_file (kpse, fn); if (!ret && len > 1) { WARNING2 ("kpathsea: %s output `%s' instead of a filename", args[0], fn); } /* Free the name if we're not returning it. */ if (fn != ret) free (fn); } } #endif /* WIN32 or Unix */ if (ret == NULL) misstex (kpse, format, args); else kpathsea_db_insert (kpse, ret); return ret; }
str_list_type * kpathsea_db_search_list (kpathsea kpse, string* names, const_string path_elt, boolean all) { const_string *db_dirs, *orig_dirs; const_string last_slash, name, path; string temp_str = NULL; boolean done; unsigned e; const_string *aliases, *r; int n; str_list_type *ret = NULL; boolean relevant = false; /* If we failed to build the database (or if this is the recursive call to build the db path), quit. */ if (kpse->db.buckets == NULL) return NULL; /* Don't bother doing any lookups if this `path_elt' isn't covered by any of database directories. We do this not so much because the extra couple of hash lookups matter -- they don't -- but rather because we want to return NULL in this case, so path_search can know to do a disk search. */ for (e = 0; !relevant && e < STR_LIST_LENGTH (kpse->db_dir_list); e++) { relevant = elt_in_db (STR_LIST_ELT (kpse->db_dir_list, e), path_elt); } if (!relevant) return NULL; done = false; ret = XTALLOC1 (str_list_type); *ret = str_list_init (); /* Handle each name. */ for (n = 0; !done && names[n]; n++) { name = names[n]; /* Absolute names should have been caught in our caller. */ if (kpathsea_absolute_p(kpse, name, true)) continue; /* When tex-glyph.c calls us looking for, e.g., dpi600/cmr10.pk, we won't find it unless we change NAME to just `cmr10.pk' and append `/dpi600' to PATH_ELT. We are justified in using a literal `/' here, since that's what tex-glyph.c unconditionally uses in DPI_BITMAP_SPEC. But don't do anything if the / begins NAME; that should never happen. */ last_slash = strrchr (name, '/'); if (last_slash && last_slash != name) { unsigned len = last_slash - name + 1; string dir_part = (string)xmalloc (len); strncpy (dir_part, name, len - 1); dir_part[len - 1] = 0; path = temp_str = concat3 (path_elt, "/", dir_part); name = last_slash + 1; free (dir_part); } else { path = path_elt; } /* If we have aliases for this name, use them. */ if (kpse->alias_db.buckets) aliases = hash_lookup (kpse->alias_db, name); else aliases = NULL; if (!aliases) { aliases = XTALLOC1 (const_string); aliases[0] = NULL; } { /* Push aliases up by one and insert the original name at front. */ unsigned i; unsigned len = 1; /* Have NULL element already allocated. */ for (r = aliases; *r; r++) len++; aliases = (const_string *) xrealloc ((void *) aliases, (len + 1) * sizeof(const_string)); for (i = len; i > 0; i--) { aliases[i] = aliases[i - 1]; } aliases[0] = name; } for (r = aliases; !done && *r; r++) { const_string ctry = *r; /* We have an ls-R db. Look up `try'. */ orig_dirs = db_dirs = hash_lookup (kpse->db, ctry); /* For each filename found, see if it matches the path element. For example, if we have .../cx/cmr10.300pk and .../ricoh/cmr10.300pk, and the path looks like .../cx, we don't want the ricoh file. */ while (!done && db_dirs && *db_dirs) { string db_file = concat (*db_dirs, ctry); boolean matched = match (db_file, path); #ifdef KPSE_DEBUG if (KPATHSEA_DEBUG_P (KPSE_DEBUG_SEARCH)) DEBUGF3 ("db:match(%s,%s) = %d\n", db_file, path, matched); #endif /* We got a hit in the database. Now see if the file actually exists, possibly under an alias. */ if (matched) { string found = NULL; if (kpathsea_readable_file (kpse, db_file)) { found = db_file; } else { const_string *a; free (db_file); /* `db_file' wasn't on disk. */ /* The hit in the DB doesn't exist in disk. Now try all its aliases. For example, suppose we have a hierarchy on CD, thus `mf.bas', but ls-R contains `mf.base'. Find it anyway. Could probably work around this with aliases, but this is pretty easy and shouldn't hurt. The upshot is that if one of the aliases actually exists, we use that. */ for (a = aliases + 1; *a && !found; a++) { string atry = concat (*db_dirs, *a); if (kpathsea_readable_file (kpse, atry)) found = atry; else free (atry); } } /* If we have a real file, add it to the list, maybe done. */ if (found) { str_list_add (ret, found); if (!all && found) done = true; } } else { /* no match in the db */ free (db_file); } /* On to the next directory, if any. */ db_dirs++; } /* This is just the space for the pointers, not the strings. */ if (orig_dirs && *orig_dirs) free (orig_dirs); } free ((void *) aliases); if (temp_str) free (temp_str); } return ret; }