/* * ChkTeX, operating system specific code for ChkTeX. * Copyright (C) 1995-96 Jens T. Berger Thielemann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Contact the author at: * Jens Berger * Spektrumvn. 4 * N-0666 Oslo * Norway * E-mail: * * */ /* * Some functions which have to be made different from OS to OS, * unfortunately...:\ * */ #include "ChkTeX.h" #include "OpSys.h" #include "Utility.h" #ifdef KPATHSEA #include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_STAT_H # include #endif #if HAVE_DIRENT_H # include # define NAMLEN(dirent) strlen((dirent)->d_name) #else # define dirent direct # define NAMLEN(dirent) (dirent)->d_namlen # if HAVE_SYS_NDIR_H # include # endif # if HAVE_SYS_DIR_H # include # endif # if HAVE_NDIR_H # include # endif #endif #if defined(HAVE_OPENDIR) && defined(HAVE_CLOSEDIR) && \ defined(HAVE_READDIR) && defined(HAVE_STAT) && \ defined(S_IFDIR) && defined(SLASH) # define USE_RECURSE 1 #else # define USE_RECURSE 0 #endif #if defined(HAVE_LIBTERMCAP) || defined(HAVE_LIBTERMLIB) # define USE_TERMCAP 1 #endif #ifdef USE_TERMCAP # ifdef HAVE_TERMCAP_H # include # elif HAVE_TERMLIB_H # include # else int tgetent(char *BUFFER, char *TERMTYPE); char *tgetstr(char *NAME, char **AREA); # endif static char term_buffer[2048]; #endif /* -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- */ /* * This is the name of the global resource file. */ #ifndef SYSCONFDIR # if defined(__unix__) # define SYSCONFDIR "/usr/local/lib/" # elif defined(__MSDOS__) # define SYSCONFDIR "\\emtex\\data\\" # else # define SYSCONFDIR # endif #endif #define RCBASENAME "chktexrc" #ifdef __MSDOS__ # define LOCALRCFILE RCBASENAME #elif defined(WIN32) # define LOCALRCFILE RCBASENAME #else # define LOCALRCFILE "." RCBASENAME #endif char ConfigFile[BUFFER_SIZE] = LOCALRCFILE; struct WordList ConfigFiles; const char *ReverseOn; const char *ReverseOff; static int HasFile(char *Dir, const char *Filename, const char *App); #if USE_RECURSE static int SearchFile(char *Dir, const char *Filename, const char *App); #endif /* USE_RECURSE */ /* -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- */ /* * Modify this one to suit your needs. In any case, it should fill * the ConfigFile (sized BUFLEN) buffer above with full name & path * for the configuration file. The macro RCFILE will give you the * filename part of the file, if you need that. * * Note: This routine will be called several times. Your mission will * be to look in each location, and see whether a .chktexrc file exist * there. * * If you choose to do nothing, only the current directory will be * searched. * */ enum LookIn { liMin, liSysDir, liUsrDir, liXdgDir, liEnvir, liCurDir, liNFound, liMax }; int SetupVars(void) { char *Env; #ifdef __MSDOS__ char *Ptr; #endif static enum LookIn i = liMin; static int FoundFile; while (++i < liMax) { switch (i) { case liCurDir: /* Current directory */ strcpy(ConfigFile, LOCALRCFILE); break; case liEnvir: /* Environment defined */ #ifdef __MSDOS__ if ((Env = getenv("CHKTEXRC")) || (Env = getenv("CHKTEX_HOME"))) #elif defined(TEX_LIVE) if ((Env = kpse_var_value("CHKTEXRC"))) #else if ((Env = getenv("CHKTEXRC"))) #endif { strcpy(ConfigFile, Env); tackon(ConfigFile, LOCALRCFILE); #ifdef TEX_LIVE free(Env); #endif } else #ifdef __MSDOS__ if ((Env = getenv("EMTEXDIR"))) { strcpy(ConfigFile, Env); tackon(ConfigFile, "data"); tackon(ConfigFile, LOCALRCFILE); } else #endif *ConfigFile = 0; break; case liXdgDir: /* Cross-desktop group dir for resource files */ /* XDG is really unix specific, but it shouldn't hurt to * support it on Windows, should someone set the variables. */ if ((Env = getenv("XDG_CONFIG_HOME")) && *Env) { strcpy(ConfigFile, Env); tackon(ConfigFile, RCBASENAME); } else if ((Env = getenv("HOME")) && *Env) { strcpy(ConfigFile, Env); tackon(ConfigFile, ".config"); tackon(ConfigFile, RCBASENAME); } else *ConfigFile = 0; break; case liUsrDir: /* User dir for resource files */ #if defined(__unix__) if ((Env = getenv("HOME")) || (Env = getenv("LOGDIR"))) { strcpy(ConfigFile, Env); tackon(ConfigFile, LOCALRCFILE); } else #elif defined(__MSDOS__) strcpy(ConfigFile, PrgName); if ((Ptr = strrchr(ConfigFile, '\\')) || (Ptr = strchr(ConfigFile, ':'))) strcpy(++Ptr, RCBASENAME); else #endif *ConfigFile = 0; break; case liSysDir: /* System dir for resource files */ #ifdef TEX_LIVE if ((Env = kpse_var_value("CHKTEX_CONFIG"))) { strcpy(ConfigFile, Env); free(Env); } else if ((Env = kpse_var_value("TEXMFMAIN"))) { strcpy(ConfigFile, Env); tackon(ConfigFile, "chktex"); tackon(ConfigFile, RCBASENAME); free(Env); } else *ConfigFile = 0; #else /* TEX_LIVE */ #if defined(__unix__) || defined(__MSDOS__) strcpy(ConfigFile, SYSCONFDIR); tackon(ConfigFile, RCBASENAME); #else *ConfigFile = 0; #endif #endif /* TEX_LIVE */ break; case liNFound: case liMin: case liMax: *ConfigFile = 0; if (!FoundFile) PrintPrgErr(pmNoRsrc); } if (*ConfigFile && fexists(ConfigFile)) break; } FoundFile |= *ConfigFile; return (*ConfigFile); } /* -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- */ /* * This function should initialize the global variables ReverseOn * and ReverseOff to magic cookies, which when printed, makes the * text in between stand out. */ void SetupTerm(void) { #ifdef USE_TERMCAP char *termtype = getenv("TERM"); int success; char *buffer; static char str_so[3] = "so", str_se[3] = "se"; if (termtype) { success = tgetent(term_buffer, termtype); if (success < 0) PrintPrgErr(pmNoTermData); if (success == 0) PrintPrgErr(pmNoTermDefd); buffer = (char *) malloc(sizeof(term_buffer)); ReverseOn = tgetstr(str_so, &buffer); ReverseOff = tgetstr(str_se, &buffer); if (ReverseOn && ReverseOff) return; } #endif ReverseOn = PRE_ERROR_STR; ReverseOff = POST_ERROR_STR; } /* -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- */ /* * Concatenates the `File' string to the `Dir' string, leaving the result * in the `Dir' buffer. Takes care of inserting `directory' characters; * if we've got the strings "/usr/foo" and "bar", we'll get * "/usr/foo/bar". * * Behaviour somewhat controlled by the macros SLASH and DIRCHARS in the * OpSys.h file. * */ void tackon(char *Dir, const char *File) { int EndC; unsigned long SLen; if (Dir && (SLen = strlen(Dir))) { EndC = Dir[SLen - 1]; if (!(strchr(DIRCHARS, EndC))) { Dir[SLen++] = SLASH; Dir[SLen] = 0L; } } strcat(Dir, File); } /* * This function should add the appendix App to the filename Name. * If the resulting filename gets too long due to this, it may * overwrite the old appendix. * * Name may be assumed to be a legal filename under your OS. * * The appendix should contain a leading dot. */ void AddAppendix(char *Name, const char *App) { #ifdef __MSDOS__ char *p; if ((p = strrchr(Name, '.'))) strcpy(p, App); else strcat(Name, App); #else /* * NOTE! This may fail if your system has a claustrophobic file * name length limit. */ strcat(Name, App); #endif } /* -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- -=><=- */ /* * Locates a file, given a wordlist containing paths. If a * dir ends in a double SLASH, we'll search it recursively. * * We assume that * a) a deeper level in the dir. tree. has a longer path than * one above. * b) adding a level doesn't change any of the previous levels. * * If this function returns TRUE, Dest is guaranteed to contain * path & name of the found file. * * FALSE indicates that the file was not found; Dest is then * unspecified. */ int LocateFile(const char *Filename, /* File to search for */ char *Dest, /* Where to put final file */ const char *App, /* Extra optional appendix */ struct WordList *wl) /* List of paths, entries * ending in // will be recursed */ { unsigned long i; #if USE_RECURSE unsigned long Len; #endif FORWL(i, *wl) { strcpy(Dest, wl->Stack.Data[i]); #if USE_RECURSE Len = strlen(Dest); if (Len && (Dest[Len - 1] == SLASH) && (Dest[Len - 2] == SLASH)) { Dest[Len - 1] = Dest[Len - 2] = 0; if (SearchFile(Dest, Filename, App)) return (TRUE); } else #endif /* USE_RECURSE */ { if (HasFile(Dest, Filename, App)) return (TRUE); } } return (FALSE); } static int HasFile(char *Dir, const char *Filename, const char *App) { int DirLen = strlen(Dir); tackon(Dir, Filename); if (fexists(Dir)) return (TRUE); if (App) { AddAppendix(Dir, App); if (fexists(Dir)) return (TRUE); } Dir[DirLen] = 0; return (FALSE); } /* * If Filename is contains a directory component, then add a fully qualified * directory to the TeXInputs WordList. * * I'm not sure how it will work with some Windows paths, * e.g. C:path\to\file.tex since it doesn't really understand the leading C: * But I'm not sure it would even work with a path like that, and I have no * way to test it. * * Behaviour somewhat controlled by the macros SLASH and DIRCHARS in the * OpSys.h file. * */ void AddDirectoryFromRelativeFile(const char * Filename, struct WordList *TeXInputs) { if ( ! Filename ) return; /* There are no path delimiters, so it's just a file, return null */ if ( ! strstr( Filename, DIRCHARS ) ) return; char buf[BUFFER_SIZE]; if ( strchr(DIRCHARS,Filename[0]) ) { strcpy(buf,Filename); } else { getcwd(buf, BUFFER_SIZE); tackon(buf,Filename); } /* Keep up to the final SLASH -- that will be the directory. */ char * end = strrchr(buf,SLASH); *end = '\0'; InsertWord(buf,TeXInputs); } #if USE_RECURSE static int SearchFile(char *Dir, const char *Filename, const char *App) { struct stat *statbuf; struct dirent *de; DIR *dh; int DirLen = strlen(Dir); int Found = FALSE; DEBUG(("Searching %s for %s\n", Dir, Filename)); if (HasFile(Dir, Filename, App)) return (TRUE); else { if ((statbuf = malloc(sizeof(struct stat)))) { if ((dh = opendir(Dir))) { while (!Found && (de = readdir(dh))) { Dir[DirLen] = 0; if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) { tackon(Dir, de->d_name); if (!stat(Dir, statbuf)) { if ((statbuf->st_mode & S_IFMT) == S_IFDIR) Found = SearchFile(Dir, Filename, App); } } } closedir(dh); } else PrintPrgErr(pmNoOpenDir, Dir); free(statbuf); } } return (Found); } #endif /* USE_RECURSE */ #if defined(HAVE_STAT) int IsRegFile(const char *Filename) { int Retval = FALSE; struct stat *statbuf; if ((statbuf = malloc(sizeof(struct stat)))) { if (!stat(Filename, statbuf)) { if ((statbuf->st_mode & S_IFMT) == S_IFREG) Retval = TRUE; } free(statbuf); } return Retval; } #else int IsRegFile(const char *Filename) { printf("WTF\n");return TRUE; } #endif