2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
23 /* $XConsortium: dtinfogen_worker.c /main/24 1996/11/26 12:35:07 cde-hal $
25 * (c) Copyright 1996 Digital Equipment Corporation.
26 * (c) Copyright 1996 Hewlett-Packard Company.
27 * (c) Copyright 1996 International Business Machines Corp.
28 * (c) Copyright 1996 Sun Microsystems, Inc.
29 * (c) Copyright 1996 Novell, Inc.
30 * (c) Copyright 1996 FUJITSU LIMITED.
31 * (c) Copyright 1996 Hitachi.
40 # include <libgen.h> /* for dirname() */
43 #if !defined(CSRG_BASED)
44 #include <sys/sysmacros.h>
46 #include <sys/param.h>
48 #include <X11/Intrinsic.h>
49 #include <Dt/Utility.h>
51 #include <lib/DtSvc/DtUtil2/LocaleXlate.h>
53 #define LANG_COMMON "C" /* default os language */
54 #define CLANG_COMMON "C.ISO-8859-1" /* default canonical language */
56 #define XtsNewString(str) \
57 ((str) != NULL ? (char *)(memcpy(XtMalloc((unsigned)strlen(str) + 1), \
58 str, (unsigned)strlen(str) + 1)) : NULL)
62 FSTAT_EXISTS = 1 << 0,
63 FSTAT_IS_FILE = 1 << 1,
64 FSTAT_IS_DIR = 1 << 2,
65 FSTAT_IS_READABLE = 1 << 3,
66 FSTAT_IS_WRITABLE = 1 << 4,
67 FSTAT_IS_EXECUTABLE = 1 << 5
75 COMPRESSED_STRING_CODE = 11,
76 SHORT_LIST_CODE = 105,
81 typedef struct _GlobalsStruct
84 char *ldLibraryPathEnv;
92 char *sgmlSearchPathEnv;
93 char *sgmlCatFilesEnv;
96 int sgmlCatFilesMaxLen;
101 char *lang; /* os-specific language (value of env) */
102 char *clang; /* canonical language */
103 int dtsridx; /* dtsearch: index into langtbl */
133 typedef struct _TOCEntry
139 typedef struct _TOCRecord
149 #define TOC_REC_COLS 6
151 static char *TOCElems[] =
162 static char *emptyString = "";
164 #define STR(s) ((s) ? (s) : emptyString)
166 #define EXEC_NAME "dtinfogen"
180 { "C.ISO-8859-1", 1, "eng.sfx", "eng.stp", NULL },
181 { "es_ES.ISO-8859-1", 2, "esp.sfx", "esp.stp", NULL },
182 { "fr_FR.ISO-8859-1", 3, "fra.sfx", "fra.stp", NULL },
183 { "it_IT.ISO-8859-1", 4, "ita.sfx", "ita.stp", NULL },
184 { "de_DE.ISO-8859-1", 5, "deu.sfx", "deu.stp", NULL },
185 { "ja_JP.EUC-JP", 7, NULL, NULL, "jpn.knj" },
186 { NULL, 0, NULL, NULL, NULL }
189 static char *usageMsg1 = "USAGE:\n\
191 " EXEC_NAME " admin\n\
192 " EXEC_NAME " build [-h] [-T <tmpdir>] [-m <catalog>] [-d <library description>]\n\
193 [-n <library short name>] -l <library> <bookcase-doc>...\n\
194 " EXEC_NAME " tocgen [-h] [-T <tmpdir>] [-m <catalog>] -f <tocfile> [-id <tocid>]\n\
195 [-title <toctitle>] <document>...\n\
196 " EXEC_NAME " update [-h] [-m <catalog>] -l <library> -b <bookcase> <stylesheet>\n\
197 " EXEC_NAME " validate [-h] [-T <tmpdir>] [-m <catalog>] <document>...\n"
201 static char *usageMsg2 = "\
202 -T <tmpdir> directory for intermediate processing files\n\
203 -h help: show usage\n\
204 -v verbose: more diagnostic output\n";
206 static GlobalsStruct *gStruct;
208 static void printUsage(char *preMsg, int exitCode);
209 static void dieRWD(int exitCode, char *format, ...);
210 static void die(int exitCode, char *format, ...);
211 static void sigHandler(int sig);
212 static void touchFile(char *fileName);
213 static Boolean checkStat(char *fileName, unsigned int flags);
214 static void checkDir(char *dirName);
215 static void checkExec(char *execName);
216 static char *makeTmpFile(void);
217 static char *makeWorkDir(void);
218 static void removeWorkDir(void);
219 static void runShellCmd(char *cmd);
220 static Boolean doAdmin(int argc, char *argv[]);
221 static Boolean doBuild(int argc, char *argv[]);
222 static Boolean doTocgen(int argc, char *argv[]);
223 static Boolean doUpdate(int argc, char *argv[]);
224 static Boolean doValidate(int argc, char *argv[]);
225 static Boolean doHelp(int argc, char *argv[]);
226 static void appendStr(char **str, int *curLen, int *maxLen, char *strToAppend);
227 static char *makeAbsPathEnv(char *var);
228 static char *makeAbsPathStr(char *str);
229 static char *addToEnv(char *var, char *addMe, Boolean prepend);
230 static char *buildPath(char *format, ...);
231 static char *buildSGML(void);
232 static char *buildDecl(void);
233 static char *buildStyleProlog(void);
234 static char *buildSpec(void);
235 static void defaultGlobals(void);
236 static void checkGlobals(void);
237 static int parseArgs(int argc, char *argv[]);
238 static char *parseDocument(Boolean runCmd, ...);
239 static void buildBookcase(char *cmdSrc, char *dirName);
240 static char *storeBookCase(char *cmdSrc, char *tocOpt, char *dbName,
242 static Boolean findBookCaseNameAndDesc(char *tmpFile, char *bookCaseName,
244 static void validateBookCaseName(char *bookCaseName);
245 static void validateBookCase(char *mapName, char *bookCaseName);
246 static void editMapFile(char *bookCaseName, char *bookCaseMap);
247 static void buildTOC(int argc, char *argv[]);
248 static char *tocBookcase(int argc, char *argv[]);
249 static void makeTOC(char *id, char *title);
250 static char *sgmlData(char *inData);
251 static char *replaceData(char *inData, char *replaceMe, char *replacement);
252 static void addTOCEntry(TOCEntry **tocEntries, int *curSize, int *maxSize,
254 static int compareTOCEntries(const void *entry1, const void *entry2);
255 static void sortTOCEntries(TOCEntry *tocEntries, int nTOCEntries);
256 static void freeTOCEntries(TOCEntry *tocEntries, int nTOCEntries);
257 static TOCRecord *getTOCRecord(FILE *fp);
258 static void freeTOCRecord(TOCRecord *);
259 static char *getTOCField(FILE *fp);
262 printUsage(char *preMsg, int exitCode)
265 fputs(preMsg, stderr);
267 fputs(usageMsg1, stderr);
268 fputs(usageMsg2, stderr);
274 dieRWD(int exitCode, char *format, ...)
278 va_start(ap, format);
279 vfprintf(stderr, format, ap);
282 if (!gStruct->keepWorkDir)
289 die(int exitCode, char *format, ...)
293 va_start(ap, format);
294 vfprintf(stderr, format, ap);
303 gStruct->keepWorkDir = False; /* Always clean up on signal. */
304 dieRWD(-1, "Received signal; exiting...\n");
308 touchFile(char *fileName)
312 if ((fp = fopen(fileName, "w")) == (FILE *)NULL)
313 dieRWD(-1, "%s: %s: %s\n",
314 EXEC_NAME, fileName, strerror(errno));
317 "$XConsortium: dtinfogen_worker.c /main/24 1996/11/26 12:35:07 cde-hal $");
323 checkStat(char *fileName, unsigned int flags)
326 Boolean userOwnsFile;
334 if (stat(fileName, &statBuf) != 0)
337 if ((flags & FSTAT_IS_FILE) &&
338 (!S_ISREG(statBuf.st_mode)))
344 if ((flags & FSTAT_IS_DIR) &&
345 (!S_ISDIR(statBuf.st_mode)))
351 userOwnsFile = (getuid() == statBuf.st_uid);
352 userInGroup = (getgid() == statBuf.st_gid);
355 if (flags & FSTAT_IS_READABLE)
359 if (!(statBuf.st_mode & S_IRUSR))
362 else if (userInGroup)
364 if (!(statBuf.st_mode & S_IRGRP))
367 else if (!(statBuf.st_mode & S_IROTH))
371 if (flags & FSTAT_IS_WRITABLE)
375 if (!(statBuf.st_mode & S_IWUSR))
378 else if (userInGroup)
380 if (!(statBuf.st_mode & S_IWGRP))
383 else if (!(statBuf.st_mode & S_IWOTH))
387 if (flags & FSTAT_IS_EXECUTABLE)
391 if (!(statBuf.st_mode & S_IXUSR))
394 else if (userInGroup)
396 if (!(statBuf.st_mode & S_IXGRP))
399 else if (!(statBuf.st_mode & S_IXOTH))
408 checkDir(char *dirName)
410 char cmdBuf[MAXPATHLEN + 10];
415 if (checkStat(dirName, FSTAT_IS_DIR))
417 if (checkStat(dirName, FSTAT_IS_WRITABLE))
420 dieRWD(-1, "%s: %s not writable\n", EXEC_NAME, dirName);
423 snprintf(cmdBuf, sizeof(cmdBuf), "mkdir -p %s", dirName);
428 testExec(char *execName, Boolean tellIt)
433 char execBuf[MAXPATHLEN + 1];
439 if ((path = getenv("PATH")) == (char *)NULL)
442 path = XtsNewString(path);
443 pathVector = _DtVectorizeInPlace(path, ':');
445 for (i = 0; pathVector[i] != (char *)NULL; i++)
447 snprintf(execBuf, sizeof(execBuf), "%s/%s", pathVector[i], execName);
448 if (checkStat(execBuf, FSTAT_IS_EXECUTABLE))
452 found = (pathVector[i] != (char *)NULL);
454 XtFree((char *)pathVector);
458 fprintf(stderr, "%s ==> %s\n", execName, execBuf);
464 checkExec(char *execName)
466 if (!testExec(execName, gStruct->verbose))
467 die(-1, "%s: %s not found\n", EXEC_NAME, execName);
477 workDir = makeWorkDir();
478 for (i = 1; i != 0; i++)
480 tmpFile = buildPath("%s/tmp.%d", workDir, i);
481 if (!checkStat(tmpFile, FSTAT_EXISTS))
487 dieRWD(-1, "%s: could not create tmp file.\n", EXEC_NAME);
493 /* The return from this function should NOT be freed. */
498 char cmdBuf[MAXPATHLEN + 10];
501 if (gStruct->workDir)
502 return gStruct->workDir;
504 if (!checkStat(gStruct->tmpDir, FSTAT_IS_DIR | FSTAT_IS_WRITABLE))
505 dieRWD(-1, "%s: %s: %s\n",
506 EXEC_NAME, gStruct->tmpDir, strerror(errno));
508 /* Start with suffix "1"; if we wrap to "0" */
509 /* (that's LOTS of directories), die. */
510 for (i = 1; i != 0; i++)
512 workDir = buildPath("%s/otk.%d", gStruct->tmpDir, i);
513 if (!checkStat(workDir, FSTAT_EXISTS))
515 snprintf(cmdBuf, sizeof(cmdBuf), "mkdir -p %s", workDir);
517 gStruct->workDir = workDir;
525 dieRWD(-1, "%s: could not create work directory.\n", EXEC_NAME);
535 char cmdBuf[MAXPATHLEN + 10];
537 if (gStruct->workDir)
539 snprintf(cmdBuf, sizeof(cmdBuf), "rm -rf %s", gStruct->workDir);
540 ret = system(cmdBuf);
541 if(ret != 0) die(-1, "system for rm failed; exiting...\n");
542 XtFree(gStruct->workDir);
543 gStruct->workDir = (char *)NULL;
548 runShellCmd(char *cmd)
550 if (gStruct->verbose)
551 fprintf(stdout, "%s\n", cmd);
553 if (system(cmd) != 0)
554 dieRWD(-1, "%s: command failed: %s\n", EXEC_NAME, cmd);
558 doAdmin(int argc, char *argv[])
560 if (strcmp(argv[1], "admin") == 0)
563 printUsage(EXEC_NAME ": too many arguments\n", -1);
565 runShellCmd("Librarian");
574 doBuild(int argc, char *argv[])
576 if (strcmp(argv[1], "build") == 0)
583 int argsProcessed = parseArgs(argc - 2, &(argv[2])) + 2;
585 if (!gStruct->library)
586 printUsage(EXEC_NAME ": -l required\n", -1);
587 if (argsProcessed >= argc)
588 printUsage(EXEC_NAME ": no bookcases given\n", -1);
590 checkDir(gStruct->library);
592 if (!gStruct->libDesc)
593 gStruct->libDesc = "Information Library";
597 if (argsProcessed >= argc)
598 printUsage(EXEC_NAME ": no bookcases given\n", -1);
600 signal(SIGINT, sigHandler);
601 signal(SIGTERM, sigHandler);
603 for ( ; argsProcessed < argc; argsProcessed++)
605 bookcase = argv[argsProcessed];
606 if (!checkStat(bookcase, FSTAT_IS_READABLE))
607 dieRWD(-1, "%s: %s: %s\n",
608 EXEC_NAME, bookcase, strerror(errno));
610 bcCopy = XtsNewString(bookcase);
611 if ((dirName = dirname(bcCopy)) == (char *)NULL)
613 dirName = XtsNewString(dirName);
616 if (gStruct->loadESIS)
618 cmdSrc = buildPath("cat %s", bookcase);
622 cmdSrc = parseDocument(False, bookcase, 0);
625 buildBookcase(cmdSrc, dirName);
631 if (!gStruct->libName)
632 gStruct->libName = "infolib";
633 fileToTouch = buildPath("%s/%s.oli",
634 gStruct->library, gStruct->libName);
635 touchFile(fileToTouch);
645 doTocgen(int argc, char *argv[])
647 if (strcmp(argv[1], "tocgen") == 0)
649 int argsProcessed = parseArgs(argc - 2, &(argv[2])) + 2;
652 gStruct->id = "TOC-NODE-ID";
654 gStruct->title = "Table of Contents";
658 if (argsProcessed >= argc)
659 printUsage(EXEC_NAME ": book document(s) required\n", -1);
660 if (!gStruct->outFile)
661 printUsage(EXEC_NAME ": -f required for tocgen\n", -1);
663 signal(SIGINT, sigHandler);
664 signal(SIGTERM, sigHandler);
666 buildTOC(argc - argsProcessed, &argv[argsProcessed]);
674 doUpdate(int argc, char *argv[])
676 if (strcmp(argv[1], "update") == 0)
678 char bookCaseBuf[MAXPATHLEN + 1];
682 int argsProcessed = parseArgs(argc - 2, &(argv[2])) + 2;
686 if (!gStruct->library)
687 printUsage(EXEC_NAME ": -l required for update\n", -1);
688 if (!checkStat(gStruct->library, FSTAT_IS_DIR))
689 die(-1, "%s: %s: %s\n", EXEC_NAME,
690 gStruct->library, strerror(errno));
692 if (!gStruct->bookCase)
693 printUsage(EXEC_NAME ": -b required\n", -1);
694 snprintf(bookCaseBuf, sizeof(bookCaseBuf), "%s/%s",
695 gStruct->library, gStruct->bookCase);
696 if (!checkStat(bookCaseBuf, FSTAT_IS_DIR))
697 die(-1, "%s: No such bookcase: %s\n", EXEC_NAME,
700 if (!checkStat(gStruct->styleProlog, FSTAT_IS_READABLE))
701 die(-1, "%s: faulty installation: %s\n", EXEC_NAME,
702 gStruct->styleProlog);
704 if (argsProcessed >= argc)
705 printUsage((char *)NULL, -1);
706 styleSheet = argv[argsProcessed++];
707 if (!checkStat(styleSheet, FSTAT_IS_READABLE))
708 die(-1, "%s: %s: %s\n", EXEC_NAME, styleSheet, strerror(errno));
710 cmdSrc = parseDocument(False,
711 gStruct->styleProlog, styleSheet, 0);
712 cmd = buildPath("%s | StyleUpdate %s %s",
713 cmdSrc, gStruct->library, gStruct->bookCase);
726 doValidate(int argc, char *argv[])
728 if (strcmp(argv[1], "validate") == 0)
733 int argsProcessed = parseArgs(argc - 2, &(argv[2])) + 2;
737 if (argsProcessed >= argc)
738 printUsage(EXEC_NAME ": no documents given\n", -1);
740 for ( ; argsProcessed < argc; argsProcessed++)
742 bookcase = argv[argsProcessed];
743 if (!checkStat(bookcase, FSTAT_IS_READABLE))
744 dieRWD(-1, "%s: %s: %s\n",
745 EXEC_NAME, bookcase, strerror(errno));
747 if (gStruct->saveESIS)
749 cmdSrc = parseDocument(False, bookcase, 0);
750 cmd = buildPath("%s > %s", cmdSrc, gStruct->saveESIS);
757 parseDocument(True, bookcase, 0);
768 doHelp(int argc, char *argv[])
770 if (strcmp(argv[1], "-h") == 0)
772 printUsage((char *)NULL, 0);
782 appendStr(char **str, int *curLen, int *maxLen, char *strToAppend)
789 len = strlen(strToAppend);
790 while (*curLen + len >= *maxLen)
792 newStr = XtRealloc(*str, (*maxLen + MAXPATHLEN) * sizeof(char));
797 *maxLen += MAXPATHLEN;
800 *((char *) memcpy (&((*str)[*curLen]), strToAppend, len) + len) = '\0';
805 makeAbsPathEnv(char *var)
807 char *oldPath, *newPath = NULL;
814 oldPath = getenv(var);
815 if (oldPath == (char *)NULL)
818 newPath = makeAbsPathStr(oldPath);
820 if (gStruct->verbose)
821 fprintf(stdout, "Expanding %s\n from %s\n to %s\n",
822 var, oldPath, newPath);
824 pathlen = strlen(var) + strlen(newPath) + 2;
825 newVar = XtMalloc(pathlen);
826 snprintf(newVar, pathlen, "%s=%s", var, newPath);
835 makeAbsPathStr(char *str)
837 char *newPath = (char *)NULL;
840 char cwd[MAXPATHLEN + 1];
847 if (str == (char *)NULL)
849 str = XtsNewString(str);
851 if (!getcwd(cwd, MAXPATHLEN))
854 /* Vectorize current dir, skipping over leading '/' */
855 cwdVector = _DtVectorizeInPlace(cwd + 1, '/');
856 for (cwdVectorLen = 0;
857 cwdVector[cwdVectorLen] != (char *)NULL;
862 /* Vectorize incoming path */
863 pathVector = _DtVectorizeInPlace(str, ':');
865 for (i = 0; pathVector[i] != (char *)NULL; i++)
868 appendStr(&newPath, &newPathLen, &maxPathLen, ":");
870 if ((pathVector[i][0] == '/') || /* Fully-specified pathname. */
871 ((pathVector[i][0] == '.') && /* Current dir. */
872 (pathVector[i][1] == '\0')))
874 appendStr(&newPath, &newPathLen, &maxPathLen, pathVector[i]);
878 dirVector = _DtVectorizeInPlace(pathVector[i], '/');
880 dirVector[j] != (char *)NULL && (strcmp(dirVector[j], "..") == 0);
885 if ((j >= cwdVectorLen) && (dirVector[j] == (char *)NULL))
887 appendStr(&newPath, &newPathLen, &maxPathLen, "/");
891 for (k = 0; k < cwdVectorLen - j; k++)
893 appendStr(&newPath, &newPathLen, &maxPathLen, "/");
894 appendStr(&newPath, &newPathLen, &maxPathLen, cwdVector[k]);
896 for ( ; dirVector[j] != (char *)NULL; j++)
898 appendStr(&newPath, &newPathLen, &maxPathLen, "/");
899 appendStr(&newPath, &newPathLen, &maxPathLen, dirVector[j]);
903 XtFree((char *)dirVector);
906 XtFree((char *)pathVector);
907 XtFree((char *)cwdVector);
914 addToEnv(char *var, char *addMe, Boolean prepend)
922 envStr = getenv(var);
925 return XtsNewString(envStr);
927 len = strlen(var) + strlen(STR(envStr)) + strlen(addMe) + 3;
928 ptrlen = len * sizeof(char);
930 if ((ptr = XtMalloc(ptrlen)) != (char *)NULL)
935 snprintf(ptr, ptrlen, "%s=%s:%s", var, addMe, envStr);
936 else snprintf(ptr, ptrlen, "%s=%s:%s", var, envStr, addMe);
938 else snprintf(ptr, ptrlen, "%s=%s", var, addMe);
944 return XtsNewString(envStr);
948 buildPath(char *format, ...)
950 char pathBuf[(2 * MAXPATHLEN) + 1];
953 va_start(ap, format);
954 vsnprintf(pathBuf, sizeof(pathBuf), format, ap);
957 return XtsNewString(pathBuf);
960 /* Assumes gStruct->install and gStruct->clang */
961 /* are set (may be NULL) */
966 buildPath("%s/infolib/%s/SGML",
967 STR(gStruct->install), STR(gStruct->clang));
969 if (!checkStat(sgmlPath, FSTAT_IS_DIR))
973 sgmlPath = buildPath("%s/infolib/%s/SGML",
974 STR(gStruct->install), LANG_COMMON);
976 if (!checkStat(sgmlPath, FSTAT_IS_DIR)) {
982 fprintf(stderr, "(DEBUG) buildSGML=\"%s\"\n", sgmlPath);
988 /* Assumes gStruct->sgml is set (may be NULL) */
992 return buildPath("%s/dtinfo.decl", STR(gStruct->sgml));
995 /* Assumes gStruct->sgml is set (may be NULL) */
997 buildStyleProlog(void)
999 return buildPath("%s/styprolog.sgml", STR(gStruct->sgml));
1002 /* Assumes gStruct->install is set (may be NULL) */
1006 return buildPath("%s/infolib/etc/mmdb.infolib.spec",
1007 STR(gStruct->install));
1011 defaultGlobals(void)
1013 memset((void *)gStruct, 0, sizeof(GlobalsStruct));
1015 gStruct->verbose = False;
1017 /* Clear out the ENV environment variable. */
1018 if (getenv("ENV") != (char *)NULL)
1021 gStruct->pathEnv = makeAbsPathEnv("PATH");
1022 gStruct->ldLibraryPathEnv = makeAbsPathEnv("LD_LIBRARY_PATH");
1023 gStruct->libPathEnv = makeAbsPathEnv("LIBPATH");
1024 gStruct->shlibPathEnv = makeAbsPathEnv("SHLIB_PATH");
1025 gStruct->lcxPathEnv = makeAbsPathEnv("DTLCXSEARCHPATH");
1026 gStruct->dtInfoHomeEnv = makeAbsPathEnv("DTINFO_HOME");
1027 gStruct->dtInfoBinEnv = makeAbsPathEnv("DTINFO_BIN");
1028 gStruct->tmpDirEnv = makeAbsPathEnv("TMPDIR");
1029 gStruct->sgmlPathEnv = makeAbsPathEnv("SGML_PATH");
1030 gStruct->sgmlSearchPathEnv = makeAbsPathEnv("SGML_SEARCH_PATH");
1031 gStruct->sgmlCatFilesEnv = makeAbsPathEnv("SGML_CATALOG_FILES");
1032 gStruct->sgmlCatFiles = NULL;
1033 gStruct->sgmlCatFilesLen = 0;
1034 gStruct->sgmlCatFilesMaxLen = 0;
1036 gStruct->install = getenv("DTINFO_HOME");
1037 gStruct->arch = getenv("ARCH");
1039 { /* resolve lang from env variable */
1041 if ((lang = getenv("LC_ALL")) == NULL)
1042 if ((lang = getenv("LC_CTYPE")) == NULL)
1043 if ((lang = getenv("LANG")) == NULL)
1046 gStruct->lang = strdup(lang);
1049 { /* resolve canonical lang using _DtLcx routines */
1050 _DtXlateDb db = NULL;
1051 char platform[_DtPLATFORM_MAX_LEN + 1];
1052 int execver, compver;
1054 gStruct->clang = NULL;
1056 if (_DtLcxOpenAllDbs(&db) == 0)
1058 if (_DtXlateGetXlateEnv(db, platform, &execver, &compver) == 0)
1060 /* _DtLcxXlateOpToStd allocates space for std lang using strdup */
1061 _DtLcxXlateOpToStd(db, platform, compver, DtLCX_OPER_SETLOCALE,
1062 gStruct->lang, &gStruct->clang, NULL, NULL, NULL);
1069 if (gStruct->clang == NULL)
1070 gStruct->clang = strdup(CLANG_COMMON);
1073 { /* resolve dtsearch language based on canonical lang */
1075 for (gStruct->dtsridx = 0, iter = langtbl; iter->name; iter++) {
1076 if (strcmp(iter->name, gStruct->clang) == 0) { /* found a match */
1077 gStruct->dtsridx = iter - langtbl;
1083 if ((gStruct->sgml = buildSGML()) == NULL) {
1084 die(-1, "%s: Cannot find SGML files\n", EXEC_NAME);
1087 gStruct->decl = buildDecl();
1088 gStruct->styleProlog = buildStyleProlog();
1090 if ((gStruct->tmpDir = getenv("TMPDIR")) == (char *)NULL)
1091 gStruct->tmpDir = "/usr/tmp";
1093 gStruct->spec = buildSpec();
1095 gStruct->dirMode = 0775;
1096 gStruct->searchEngine = "dtsearch";
1097 gStruct->parser = "nsgmls";
1098 if (!testExec(gStruct->parser, False))
1099 gStruct->parser = "sgmls";
1101 gStruct->keepWorkDir = False;
1102 gStruct->workDir = (char *)NULL;
1104 gStruct->tocElemIndex = 0;
1110 if ((!gStruct->install) || (!checkStat(gStruct->install, FSTAT_IS_DIR)))
1111 die(-1, "%s: Cannot find DtInfo Toolkit installation directory.\n"
1113 "The DTINFO_HOME variable must be set to the directory "
1114 "where the DtInfo\n"
1115 "toolkit is installed.\n"
1117 "You probably invoked this script in an unsupported manner.\n",
1121 die(-1, "%s: ARCH not set\n", EXEC_NAME);
1123 if (!checkStat(gStruct->sgml, FSTAT_IS_DIR))
1124 die(-1, "%s: Can't find DtInfo SGML directory (%s): %s\n",
1125 EXEC_NAME, STR(gStruct->sgml), strerror(errno));
1127 if (!checkStat(gStruct->decl, FSTAT_IS_READABLE))
1128 die(-1, "%s: faulty installation: %s: %s\n",
1129 EXEC_NAME, STR(gStruct->decl), strerror(errno));
1131 if (!checkStat(gStruct->spec, FSTAT_IS_READABLE))
1132 die(-1, "%s: faulty installation: %s: %s\n",
1133 EXEC_NAME, STR(gStruct->spec), strerror(errno));
1135 if (!checkStat(gStruct->tmpDir, FSTAT_IS_DIR | FSTAT_IS_WRITABLE))
1136 die(-1, "%s: %s: %s\n",
1137 EXEC_NAME, STR(gStruct->tmpDir), strerror(errno));
1140 checkExec("NCFGen");
1141 checkExec("MixedGen");
1142 checkExec("NodeParser");
1143 checkExec("StyleUpdate");
1144 checkExec("valBase");
1145 checkExec(gStruct->parser);
1146 if (strcmp(gStruct->searchEngine, "dtsearch") == 0)
1148 checkExec("dtsrcreate");
1149 checkExec("dtsrload");
1150 checkExec("dtsrindex");
1152 gStruct->dtsrlib = buildPath("%s/infolib/etc/%s/dtsr",
1154 STR(langtbl[gStruct->dtsridx].name));
1156 if (!checkStat(gStruct->dtsrlib, FSTAT_IS_DIR)) {
1157 XtFree(gStruct->dtsrlib);
1158 gStruct->dtsrlib = buildPath("%s/infolib/etc/%s/dtsr",
1159 gStruct->install, LANG_COMMON);
1162 fprintf(stderr, "(DEBUG) gStruct->dtsrlib=\"%s\"\n", gStruct->dtsrlib);
1164 gStruct->dbdfile = buildPath("%s/infolib/etc/dtsr/%s.dbd",
1166 gStruct->searchEngine);
1167 gStruct->keytypes = "Default Head Graphics Example Index Table";
1169 checkExec("validator");
1173 addCatFile(char *catalog, Bool needed)
1175 Boolean parserIsNSGMLS;
1176 char pathBuf[(2 * MAXPATHLEN) + 10];
1180 if (!checkStat(catalog, FSTAT_IS_READABLE)) {
1183 dieRWD(-1, "%s: %s: %s\n",
1184 EXEC_NAME, catalog, strerror(errno));
1186 parserIsNSGMLS = (strcmp(gStruct->parser, "nsgmls") == 0);
1189 ptr1 = makeAbsPathStr(catalog);
1190 snprintf(pathBuf, sizeof(pathBuf), "-c%s ", ptr1);
1191 appendStr(&gStruct->sgmlCatFiles, &gStruct->sgmlCatFilesLen,
1192 &gStruct->sgmlCatFilesMaxLen, pathBuf);
1197 ptr1 = strrchr(catalog, '/');
1198 catlen = strlen(catalog);
1200 catlen -= strlen(ptr1);
1201 snprintf(pathBuf, sizeof(pathBuf), "%.*s/%%P:%.*s/%%S",
1202 catlen, catalog, catlen, catalog);
1203 ptr1 = makeAbsPathStr(pathBuf);
1204 ptr2 = addToEnv("SGML_PATH", ptr1, False);
1205 if (gStruct->sgmlPathEnv)
1206 XtFree(gStruct->sgmlPathEnv);
1209 gStruct->sgmlPathEnv = ptr2;
1214 parseArgs(int argc, char *argv[])
1218 for (i = 0; (i < argc) && (argv[i][0] == '-'); i++)
1220 if (strcmp(argv[i], "-l") == 0)
1224 gStruct->library = argv[i];
1225 if (checkStat(gStruct->library, FSTAT_EXISTS) &&
1226 !checkStat(gStruct->library, FSTAT_IS_WRITABLE))
1227 dieRWD(-1, "%s: %s: %s\n",
1228 EXEC_NAME, gStruct->library, strerror(errno));
1231 else if (strcmp(argv[i], "-b") == 0)
1234 gStruct->bookCase = argv[i];
1236 else if (strcmp(argv[i], "-d") == 0)
1242 gStruct->libDesc = XtsNewString(argv[i]);
1244 /* Change TABs to SPACEs */
1245 for (j = 0; gStruct->libDesc[j] != '\0'; j++)
1247 if (gStruct->libDesc[j] == '\t')
1248 gStruct->libDesc[j] = ' ';
1252 else if (strcmp(argv[i], "-n") == 0)
1256 gStruct->libName = argv[i];
1257 if (strlen(gStruct->libName) > 8)
1258 dieRWD(-1, "%s: information library name must be \n"
1259 "less than or equal to eight characters.\n", EXEC_NAME);
1262 else if (strcmp(argv[i], "-f") == 0)
1266 gStruct->outFile = argv[i];
1267 if (checkStat(gStruct->outFile, FSTAT_EXISTS) &&
1268 !checkStat(gStruct->outFile, FSTAT_IS_WRITABLE))
1269 dieRWD(-1, "%s: %s already exists and not writable\n",
1270 EXEC_NAME, gStruct->outFile);
1273 else if (strcmp(argv[i], "-v") == 0)
1275 gStruct->verbose = True;
1277 else if (strcmp(argv[i], "-h") == 0)
1279 printUsage((char *)NULL, 0);
1281 else if (strcmp(argv[i], "-T") == 0)
1285 gStruct->tmpDir = argv[i];
1286 checkDir(gStruct->tmpDir);
1289 else if (strcmp(argv[i], "-m") == 0)
1292 addCatFile(argv[i], True);
1294 else if (strcmp(argv[i], "-s") == 0)
1297 gStruct->searchEngine = argv[i];
1299 else if (strcmp(argv[i], "--save-esis") == 0)
1302 gStruct->saveESIS = argv[i];
1304 else if (strcmp(argv[i], "--load-esis") == 0)
1307 gStruct->loadESIS = True;
1309 else if (strcmp(argv[i], "--bin") == 0)
1315 ptr1 = addToEnv("PATH", argv[i], True);
1316 ptr2 = makeAbsPathEnv("PATH");
1317 if (gStruct->pathEnv)
1318 XtFree(gStruct->pathEnv);
1321 gStruct->pathEnv = ptr2;
1324 else if (strcmp(argv[i], "--keep") == 0)
1326 gStruct->keepWorkDir = True;
1328 else if (strcmp(argv[i], "-chapter") == 0)
1330 gStruct->tocElemIndex++;
1332 else if (strcmp(argv[i], "-id") == 0)
1335 gStruct->id = argv[i];
1337 else if (strcmp(argv[i], "-title") == 0)
1340 gStruct->title = argv[i];
1342 else if (strcmp(argv[i], "-parser") == 0)
1345 gStruct->parser = argv[i];
1349 fprintf(stderr, "%s: unrecognized option %s ignored\n",
1350 EXEC_NAME, argv[i]);
1358 parseDocument(Boolean runCmd, ...)
1362 char *cmd = (char *)NULL;
1365 Boolean parserIsNSGMLS;
1367 parserIsNSGMLS = (strcmp(gStruct->parser, "nsgmls") == 0);
1369 if (!checkStat(gStruct->sgml, FSTAT_IS_DIR | FSTAT_IS_READABLE))
1370 dieRWD(-1, "%s: faulty installation: %s\n",
1371 EXEC_NAME, strerror(errno));
1373 addCatFile(buildPath("%s/infolib/%s/SGML/catalog",
1374 STR(gStruct->install), STR(gStruct->clang)), False);
1375 addCatFile(buildPath("%s/infolib/%s/SGML/catalog",
1376 STR(gStruct->install), LANG_COMMON), True);
1380 if (!gStruct->sgmlSearchPathEnv)
1381 gStruct->sgmlSearchPathEnv = addToEnv("SGML_SEARCH_PATH", ".", False);
1385 ptr = addToEnv("SGML_PATH", "%S", False);
1386 if (gStruct->sgmlPathEnv)
1387 XtFree(gStruct->sgmlPathEnv);
1388 gStruct->sgmlPathEnv = ptr;
1391 appendStr(&cmd, &cmdLen, &maxLen, gStruct->parser);
1393 if (parserIsNSGMLS) {
1394 appendStr(&cmd, &cmdLen, &maxLen, " -bidentity ");
1395 appendStr(&cmd, &cmdLen, &maxLen, gStruct->sgmlCatFiles);
1400 appendStr(&cmd, &cmdLen, &maxLen, " -sg ");
1402 if (! parserIsNSGMLS)
1403 appendStr(&cmd, &cmdLen, &maxLen, gStruct->decl);
1405 va_start(ap, runCmd);
1406 while ((ptr = va_arg(ap, char *)) != 0)
1408 appendStr(&cmd, &cmdLen, &maxLen, " ");
1409 appendStr(&cmd, &cmdLen, &maxLen, ptr);
1415 return (char *)NULL;
1419 appendStr(&cmd, &cmdLen, &maxLen, "-oline -wno-idref ");
1421 appendStr(&cmd, &cmdLen, &maxLen, " -l ");
1423 appendStr(&cmd, &cmdLen, &maxLen, gStruct->decl);
1424 va_start(ap, runCmd);
1425 while ((ptr = va_arg(ap, char *)) != 0)
1427 appendStr(&cmd, &cmdLen, &maxLen, " ");
1428 appendStr(&cmd, &cmdLen, &maxLen, ptr);
1436 buildBookcase(char *cmdSrc, char *dirName)
1442 char *newMmdbPathEnv;
1445 char cmd[MAXPATHLEN * 3];
1446 char bookCaseName[MAXPATHLEN + 1]; /* Not paths, just big buffers. */
1447 char bookCaseDesc[MAXPATHLEN + 1];
1449 dataBase = makeWorkDir();
1451 tmpFile = storeBookCase(cmdSrc, "all", dataBase, dirName);
1452 newMmdbPathEnv = buildPath("MMDB_PATH=%s", STR(gStruct->library));
1453 if (gStruct->mmdbPathEnv)
1454 XtFree(gStruct->mmdbPathEnv);
1455 gStruct->mmdbPathEnv = newMmdbPathEnv;
1456 putenv(newMmdbPathEnv);
1458 if (gStruct->verbose)
1459 fprintf(stderr, "%s\n", newMmdbPathEnv);
1461 if (!findBookCaseNameAndDesc(tmpFile, bookCaseName, bookCaseDesc))
1462 dieRWD(-1, "%s: Missing Bookcase name\n", EXEC_NAME);
1465 bookCaseDir = buildPath("%s/%s", STR(gStruct->library), bookCaseName);
1466 if (checkStat(bookCaseDir, FSTAT_IS_DIR))
1468 fprintf(stderr, "%s: deleting existing %s ...\n",
1469 EXEC_NAME, bookCaseDir);
1470 snprintf(cmd, sizeof(cmd), "rm -rf %s", bookCaseDir);
1473 if (checkStat(bookCaseDir, FSTAT_IS_DIR))
1474 dieRWD(-1, "%s: failed to delete %s\n",
1475 EXEC_NAME, bookCaseDir);
1478 snprintf(cmd, sizeof(cmd), "dbdrv define %s %s \"%s\"",
1479 gStruct->spec, bookCaseName, bookCaseDesc);
1482 bookCaseMap = buildPath("%s/bookcase.map", gStruct->library);
1483 editMapFile(bookCaseName, bookCaseMap);
1486 * changed not to use pipe for better error handling
1490 const char* style_file = makeTmpFile();
1492 snprintf(cmd, sizeof(cmd), "NCFGen -load-style %s %s > %s",
1493 bookCaseName, dataBase, style_file);
1497 snprintf(cmd, sizeof(cmd), "cat %s | dbdrv stdin_load %s %s.stylesheet",
1498 style_file, bookCaseName, bookCaseName);
1501 snprintf(cmd, sizeof(cmd), "rm -f %s", style_file);
1503 if(ret1 != 0) die(-1, "system for rm failed; exiting...\n");
1504 XtFree((char*)style_file);
1510 const char* compress_file = makeTmpFile();
1512 snprintf(cmd, sizeof(cmd), "NCFGen -compressed %s %s > %s",
1513 bookCaseName, dataBase, compress_file);
1517 snprintf(cmd, sizeof(cmd), "cat %s | dbdrv stdin_load %s %s.node",
1518 compress_file, bookCaseName, bookCaseName);
1521 snprintf(cmd, sizeof(cmd), "rm -f %s", compress_file);
1523 if(ret1 != 0) die(-1, "system for rm failed; exiting...\n");
1524 XtFree((char*)compress_file);
1529 const char* anonym_file = makeTmpFile();
1531 snprintf(cmd, sizeof(cmd), "MixedGen -compressed %s %s > %s",
1532 dataBase, bookCaseDir, anonym_file);
1536 snprintf(cmd, sizeof(cmd), "cat %s | dbdrv mixed_load %s",
1537 anonym_file, bookCaseName);
1541 snprintf(cmd, sizeof(cmd), "rm -f %s", anonym_file);
1543 if(ret1 != 0) die(-1, "system for rm failed; exiting...\n");
1544 XtFree((char*)anonym_file);
1547 validateBookCase(bookCaseMap, bookCaseName);
1548 XtFree(bookCaseMap);
1550 if (strcmp(gStruct->searchEngine, "dtsearch") == 0)
1552 char curDir[MAXPATHLEN + 1];
1553 char newDir[MAXPATHLEN + 1];
1554 const char *dtsr_stp, *dtsr_sfx, *dtsr_knj;
1556 snprintf(cmd, sizeof(cmd), "mkdir -p %s/%s",
1557 bookCaseDir, gStruct->searchEngine);
1560 snprintf(cmd, sizeof(cmd), "cp %s/%s/%s.fzk %s/%s",
1561 dataBase, gStruct->searchEngine, bookCaseName,
1562 bookCaseDir, gStruct->searchEngine);
1565 snprintf(cmd, sizeof(cmd), "cp %s %s/%s",
1566 gStruct->dbdfile, bookCaseDir, gStruct->searchEngine);
1569 if ((dtsr_stp = langtbl[gStruct->dtsridx].stp)) {
1570 snprintf(cmd, sizeof(cmd), "cp %s/%s %s/%s/%s.stp",
1571 gStruct->dtsrlib, dtsr_stp, bookCaseDir,
1572 gStruct->searchEngine, bookCaseName);
1576 if ((dtsr_sfx = langtbl[gStruct->dtsridx].sfx)) {
1577 snprintf(cmd, sizeof(cmd), "cp %s/%s %s/%s/%s.sfx",
1578 gStruct->dtsrlib, dtsr_sfx, bookCaseDir,
1579 gStruct->searchEngine, bookCaseName);
1583 if ((dtsr_knj = langtbl[gStruct->dtsridx].knj)) {
1584 snprintf(cmd, sizeof(cmd), "cp %s/%s %s/%s/%s.knj",
1585 gStruct->dtsrlib, dtsr_knj, bookCaseDir,
1586 gStruct->searchEngine, bookCaseName);
1591 ret2 = getcwd(curDir, MAXPATHLEN);
1592 if(ret2 == (char *)NULL) die(-1, "getcwd failed; exiting...\n");
1593 snprintf(newDir, sizeof(newDir), "%s/%s",
1594 bookCaseDir, gStruct->searchEngine);
1595 if (chdir(newDir) != 0)
1596 dieRWD(-1, "%s: Cannot find %s: %s\n",
1597 EXEC_NAME, newDir, strerror(errno));
1599 snprintf(cmd, sizeof(cmd), "dtsrcreate %s-o -a%d -l%d %s",
1600 (gStruct->verbose) ? "" : "-q ", 210,
1601 langtbl[gStruct->dtsridx].dtsrlang, bookCaseName);
1604 snprintf(cmd, sizeof(cmd), "dtsrload -d%s '-t\n' %s",
1605 bookCaseName, bookCaseName);
1608 snprintf(cmd, sizeof(cmd), "dtsrindex -d%s '-t\n' %s",
1609 bookCaseName, bookCaseName);
1612 snprintf(cmd, sizeof(cmd), "echo keytypes %s = %s > %s.ocf",
1613 bookCaseName, gStruct->keytypes, gStruct->searchEngine);
1616 snprintf(cmd, sizeof(cmd), "%s.fzk", bookCaseName);
1618 snprintf(cmd, sizeof(cmd), "%s.dbd", gStruct->searchEngine);
1621 if (chdir(curDir) != 0)
1622 dieRWD(-1, "%s: Cannot find %s: %s\n",
1623 EXEC_NAME, curDir, strerror(errno));
1625 XtFree(bookCaseDir);
1627 if (!gStruct->keepWorkDir)
1632 storeBookCase(char *cmdSrc, char *tocOpt, char *dbName,
1640 * changed not to use pipe for better error handling
1644 const char* nsgmls_file = makeTmpFile();
1646 cmd = buildPath("%s > %s;echo", cmdSrc, nsgmls_file);
1650 tmpFile = makeTmpFile();
1652 cmd = buildPath("cat %s | NodeParser %s %s %s > %s",
1653 nsgmls_file, tocOpt, dbName, dirName, tmpFile);
1656 cmd = buildPath("rm -f %s", nsgmls_file);
1658 if(ret != 0) die(-1, "system for rm failed; exiting...\n");
1659 XtFree((char*)nsgmls_file);
1668 findBookCaseNameAndDesc(char *tmpFile, char *bookCaseName,
1672 char lineBuf[MAXPATHLEN + 1];
1674 static char *patt1 = "BookCase name: `";
1675 static char *patt2 = "' desc: `";
1678 if ((fp = fopen(tmpFile, "r")) == (FILE *)NULL)
1679 dieRWD(-1, "%s: opening %s: %s\n",
1680 EXEC_NAME, tmpFile, strerror(errno));
1682 while (fgets(lineBuf, MAXPATHLEN, fp) != (char *)NULL)
1684 if ((p1 = strstr(lineBuf, patt1)) != (char *)NULL)
1686 p1 += strlen(patt1);
1687 if ((p2 = strstr(p1, patt2)) != (char *)NULL)
1690 *((char *) memcpy(bookCaseName, p1, len) + len) = '\0';
1691 validateBookCaseName(bookCaseName);
1692 p1 = p2 + strlen(patt2);
1693 if ((p2 = strchr(p1, '\'')) != (char *)NULL)
1696 *((char *) memcpy(bookCaseDesc, p1, len) + len) = '\0';
1710 validateBookCaseName(char *bookCaseName)
1712 Boolean isOk = False;
1714 if (strlen(bookCaseName) <= 8)
1718 for (i = 0; bookCaseName[i] != '\0'; i++)
1720 if (!isalnum((unsigned char) bookCaseName[i]))
1724 isOk = (bookCaseName[i] == '\0');
1728 dieRWD(-1, "%s: Bookcase name `%s' is not valid;\n"
1729 "only 8 alphanumeric characters are allowed\n",
1730 EXEC_NAME, bookCaseName);
1734 validateBookCase(char *mapFile, char *bookCaseName)
1738 char lineBuf[MAXPATHLEN + 1];
1739 char cmdBuf[MAXPATHLEN + 1];
1742 if ((fp = fopen(mapFile, "r")) == (FILE *)NULL)
1743 dieRWD(-1, "%s: cannot open bookcase.map: %s\n",
1744 EXEC_NAME, strerror(errno));
1746 ret = fgets(lineBuf, MAXPATHLEN, fp); /* Skip first line. */
1747 if(ret == (char *)NULL) die(-1, "fgets failed; exiting...\n");
1749 while (fgets(lineBuf, MAXPATHLEN, fp) != (char *)NULL)
1751 if ((bcName = strtok(lineBuf, "\t\n")) != (char *)NULL)
1753 if (strcmp(bcName, bookCaseName) != 0)
1755 snprintf(cmdBuf, sizeof(cmdBuf), "valBase %s %s",
1756 bookCaseName, bcName);
1758 /* Should this return an error code instead of */
1759 /* exiting so that we can cleanup the bookcase? */
1760 runShellCmd(cmdBuf);
1769 editMapFile(char *bookCaseName, char *bookCaseMap)
1772 struct stat statBuf;
1777 char *oldDesc, *libID;
1783 Boolean replaced = False;
1785 if ((stat(bookCaseMap, &statBuf) != 0) ||
1786 ((fp = fopen(bookCaseMap, "r")) == (FILE *)NULL))
1787 dieRWD(-1, "%s: %s: %s\n", EXEC_NAME, bookCaseMap,
1790 file = XtMalloc((statBuf.st_size + 1) * sizeof(char));
1791 ret = fread(file, statBuf.st_size, sizeof(char), fp);
1792 if(ret == 0) die(-1, "fread failed; exiting...\n");
1793 if (file[statBuf.st_size - 1] == '\n')
1794 file[statBuf.st_size - 1] = '\0';
1795 else file[statBuf.st_size] = '\0';
1798 fileVector = _DtVectorizeInPlace(file, '\n');
1800 firstLine = XtsNewString(fileVector[0]);
1801 lineVector = _DtVectorizeInPlace(firstLine, '\t');
1802 if ((oldDesc = lineVector[0]) != (char *)NULL)
1803 libID = lineVector[1];
1805 libID = (char *)NULL;
1806 XtFree((char *)lineVector);
1808 if ((libDesc = gStruct->libDesc) == (char *)NULL)
1811 for (i = 0, lastLine = (char *)NULL; fileVector[i] != (char *)NULL; i++)
1812 lastLine = fileVector[i];
1814 if ((fp = fopen(bookCaseMap, "w")) == (FILE *)NULL)
1815 dieRWD(-1, "%s: %s: %s\n", EXEC_NAME, bookCaseMap,
1818 bcNameLen = strlen(bookCaseName);
1820 fprintf(fp, "%s\t%s\n", STR(libDesc), STR(libID));
1823 for (i = 1; fileVector[i] != (char *)NULL; i++)
1825 if ((strncmp(fileVector[i], bookCaseName, bcNameLen) == 0) &&
1826 (!isalnum((unsigned char) fileVector[i][bcNameLen])) &&
1827 (fileVector[i][bcNameLen] != '_'))
1831 fprintf(fp, "%s\n", lastLine);
1837 fprintf(fp, "%s\n", fileVector[i]);
1842 fprintf(fp, "%s\n", lastLine);
1846 XtFree((char *)fileVector);
1851 buildTOC(int argc, char *argv[])
1854 char lineBuf[MAXPATHLEN + 1];
1855 char idBuf[MAXPATHLEN + 1];
1856 char titleBuf[MAXPATHLEN + 1];
1862 static char *patt1start = "<TOC id=\"";
1863 static char *patt1end = "\">";
1864 static char *patt2start = "<TITLE>";
1865 static char *patt2end = "</TITLE>";
1867 len = MIN(strlen(gStruct->id), MAXPATHLEN);
1868 *((char *) memcpy (idBuf, gStruct->id, len) + len) = '\0';
1869 len = MIN(strlen(gStruct->title), MAXPATHLEN);
1870 *((char *) memcpy (titleBuf, gStruct->title, len) + len) = '\0';
1872 if (checkStat(gStruct->outFile, FSTAT_IS_FILE))
1874 if ((fp = fopen(gStruct->outFile, "r")) == (FILE *)NULL)
1875 die(-1, "%s: %s: %s\n", EXEC_NAME, gStruct->outFile,
1878 idBuf[0] = titleBuf[0] = '\0';
1879 while (fgets(lineBuf, MAXPATHLEN, fp) != (char *)NULL)
1881 if ((p1 = strstr(lineBuf, patt1start)) != (char *)NULL)
1883 p1 += strlen(patt1start);
1884 if ((p2 = strstr(p1, patt1end)) != (char *)NULL)
1887 *((char *) memcpy(idBuf, p1, len) + len) = '\0';
1890 if ((p1 = strstr(lineBuf, patt2start)) != (char *)NULL)
1892 p1 += strlen(patt2start);
1893 if ((p2 = strstr(p1, patt2end)) != (char *)NULL)
1896 *((char *) memcpy(titleBuf, p1, len) + len) = '\0';
1902 if (idBuf[0] == '\0')
1903 die(-1, "%s: %s has no ID\n", EXEC_NAME, gStruct->outFile);
1904 if (titleBuf[0] == '\0')
1905 die(-1, "%s: %s has not TITLE\n", EXEC_NAME, gStruct->outFile);
1908 tocBC = tocBookcase(argc, argv);
1909 cmdSrc = parseDocument(False, tocBC, 0);
1910 if ((tocDir = dirname(tocBC)) == (char *)NULL)
1912 tocDir = XtsNewString(tocDir);
1913 p1 = storeBookCase(cmdSrc, "toc", makeWorkDir(), tocDir);
1919 makeTOC(idBuf, titleBuf);
1921 if (!gStruct->keepWorkDir)
1926 tocBookcase(int argc, char *argv[])
1932 tmpFile = makeTmpFile();
1933 if (gStruct->verbose)
1934 fprintf(stderr, "TOC Bookcase: %s\n", tmpFile);
1936 if ((fp = fopen(tmpFile, "w")) == (FILE *)NULL)
1937 dieRWD(-1, "%s: %s: %s\n", EXEC_NAME,
1938 tmpFile, strerror(errno));
1940 fputs("<!DOCTYPE Bookcase PUBLIC \n"
1941 "\"-//Common Desktop Environment//"
1942 "DTD DtInfo Bookcase Description//EN\" \n"
1944 " <!-- Books -->\n",
1947 for (i = 0; i < argc; i++)
1949 fprintf(fp, "\t<!ENTITY book%d SYSTEM '%s' SUBDOC>\n",
1954 "<BOOKCASE StyleSheet=dummySty>\n"
1955 " <BOOKCASENAME>TOCDummy</>\n"
1956 " <BOOKCASEDESC>Dummy Bookcase for TOC Generation</>\n"
1957 " <StyleSheet name=\"dummySty\"><path>*</>"
1958 "<online><linebreak after></></>\n"
1960 " <TITLE>Dummy Book for TOC Generation</>\n"
1964 for (i = 0; i < argc; i++)
1966 fprintf(fp, "\t<FILE>&book%d;</>\n", i + 1);
1979 makeTOC(char *id, char *title)
1987 TOCRecord *tocRecord;
1988 TOCEntry newTOCEntry;
1989 TOCEntry *tocEntries = (TOCEntry *)NULL;
1990 int nTOCEntries = 0;
1991 int maxTOCEntries = 0;
1996 tocTitle = sgmlData(title);
1997 for (i = 0; id[i] != '\0'; i++)
1999 if ((!isalnum((unsigned char) id[i])) &&
2000 (id[i] != '.') && (id[i] != '-'))
2001 die(-1, "bad ID: %s\n", id);
2004 fileIn = buildPath("%s/NodeMeta", makeWorkDir());
2005 if ((fpIn = fopen(fileIn, "r")) == (FILE *)NULL)
2006 dieRWD(-1, "%s: internal error: %s\n",
2007 EXEC_NAME, strerror(errno));
2009 if ((fpOut = fopen(gStruct->outFile, "w")) == (FILE *)NULL)
2010 dieRWD(-1, "%s: %s: %s\n",
2011 EXEC_NAME, gStruct->outFile, strerror(errno));
2013 while ((tocRecord = getTOCRecord(fpIn)))
2015 char lineBuf[MAXPATHLEN + 1];
2017 if (tocRecord->code != NODE_META)
2020 trTitle = sgmlData(STR(tocRecord->title));
2022 ptr1 = replaceData(STR(tocRecord->loc), "&", "&");
2023 ptr2 = replaceData(ptr1, "\"", """);
2026 snprintf(lineBuf, sizeof(lineBuf),
2027 "<TOCEntry LinkEnd=\"%s\">%s</> <!-- %s:%s -->\n",
2028 ptr2, trTitle, STR(tocRecord->file),
2029 STR(tocRecord->line));
2033 newTOCEntry.ord = STR(tocRecord->ord);
2034 newTOCEntry.entry = lineBuf;
2035 addTOCEntry(&tocEntries, &nTOCEntries, &maxTOCEntries,
2038 freeTOCRecord(tocRecord);
2043 fprintf(fpOut, "<!DOCTYPE TOC PUBLIC\n"
2044 " \"-//Common Desktop Environment//"
2045 "DTD DtInfo Table of Contents//EN\">\n"
2047 "<TITLE>%s</TITLE>\n",
2053 sortTOCEntries(tocEntries, nTOCEntries);
2054 for (i = 0; i < nTOCEntries; i++)
2057 * From the original PERL script (I don't understand the logic):
2058 * ## The magic no. 6 here is based on the no. of sections that
2059 * ## are allowed at one level. Currently , it is 99999, ie. only
2060 * ## five digits are allowed
2062 olvl = strlen(tocEntries[i].ord) / 6;
2064 while (olvl <= level)
2066 for (j = 0; j < level * 4; j++)
2068 fprintf(fpOut, "</%s>\n",
2069 TOCElems[level + gStruct->tocElemIndex]);
2073 while (olvl > level)
2077 for (j = 0; j < level * 4; j++)
2079 fprintf(fpOut, "<%s>\n",
2080 TOCElems[level + gStruct->tocElemIndex]);
2082 for (j = 0; j < level * 4; j++)
2084 fputs(tocEntries[i].entry, fpOut);
2086 freeTOCEntries(tocEntries, nTOCEntries);
2090 for (j = 0; j < level * 4; j++)
2092 fprintf(fpOut, "</%s>\n\n", TOCElems[level + gStruct->tocElemIndex]);
2096 fputs("</TOC>\n", fpOut);
2101 sgmlData(char *inData)
2106 p1 = replaceData(inData, "&", "&");
2107 p2 = replaceData(p1, "<", "<");
2108 outData = replaceData(p2, ">", ">");
2117 replaceData(char *inData, char *replaceMe, char *replacement)
2121 int replaceMeLen = strlen(replaceMe);
2127 while ((p = strstr(p, replaceMe)) != (char *)NULL)
2134 return XtsNewString(inData);
2136 newLen = strlen(inData) + (i * (strlen(replacement) - replaceMeLen));
2137 newData = XtMalloc((newLen + 1) * sizeof(char));
2140 while ((endP = strstr(p, replaceMe)) != (char *)NULL)
2142 slen = strlen(newData);
2144 *((char *) memcpy(newData + slen, p, len) + len) = '\0';
2146 slen = strlen(newData);
2147 len = MIN(strlen(replacement), (newLen - slen) * sizeof(char));
2148 *((char *) memcpy(newData + slen, replacement, len) + len) = '\0';
2149 p = endP + replaceMeLen;
2151 slen = strlen(newData);
2152 len = MIN(strlen(p), (newLen - slen) * sizeof(char));
2153 *((char *) memcpy(newData + slen, p, len) + len) = '\0';
2159 addTOCEntry(TOCEntry **tocEntries, int *nTOCEntries, int *maxEntries,
2162 if (*nTOCEntries >= *maxEntries)
2167 (TOCEntry *)XtRealloc((char *)*tocEntries,
2168 (*maxEntries + 10) * sizeof(TOCEntry));
2172 *tocEntries = newArray;
2176 (*tocEntries)[*nTOCEntries].ord = XtsNewString(newEntry->ord);
2177 (*tocEntries)[*nTOCEntries].entry = XtsNewString(newEntry->entry);
2182 compareTOCEntries(const void *entry1, const void *entry2)
2184 TOCEntry *tEntry1 = (TOCEntry *)entry1;
2185 TOCEntry *tEntry2 = (TOCEntry *)entry2;
2187 return strcmp(tEntry1->ord, tEntry2->ord);
2191 sortTOCEntries(TOCEntry *tocEntries, int nTOCEntries)
2193 qsort((void *)tocEntries, nTOCEntries, sizeof(TOCEntry),
2198 freeTOCEntries(TOCEntry *tocEntries, int nTOCEntries)
2202 for (i = 0; i < nTOCEntries; i++)
2204 XtFree(tocEntries[i].ord);
2205 XtFree(tocEntries[i].entry);
2208 XtFree((char *)tocEntries);
2212 getTOCRecord(FILE *fp)
2214 char lineBuf[MAXPATHLEN + 1];
2216 TOCRecord *tocRecord;
2219 tocRecord = (TOCRecord *)XtMalloc(sizeof(TOCRecord));
2221 if (fgets(lineBuf, MAXPATHLEN, fp) == (char *)NULL)
2223 XtFree((char *)tocRecord);
2224 return (TOCRecord *)NULL;
2227 tocRecord->code = atoi(lineBuf);
2229 if (fgets(lineBuf, MAXPATHLEN, fp) == (char *)NULL)
2231 XtFree((char *)tocRecord);
2232 return (TOCRecord *)NULL;
2234 cols = atoi(lineBuf);
2236 if (cols < TOC_REC_COLS)
2238 XtFree((char *)tocRecord);
2239 return (TOCRecord *)NULL;
2242 /* DISCARD first item (book). */
2243 ptr = getTOCField(fp);
2247 tocRecord->loc = getTOCField(fp);
2250 tocRecord->file = getTOCField(fp);
2253 tocRecord->line = getTOCField(fp);
2256 tocRecord->ord = getTOCField(fp);
2259 tocRecord->title = getTOCField(fp);
2264 ptr = getTOCField(fp);
2273 freeTOCRecord(TOCRecord *tocRecord)
2275 XtFree(tocRecord->loc);
2276 XtFree(tocRecord->file);
2277 XtFree(tocRecord->line);
2278 XtFree(tocRecord->ord);
2279 XtFree(tocRecord->title);
2281 XtFree((char *)tocRecord);
2285 getTOCField(FILE *fp)
2287 char lineBuf[MAXPATHLEN + 1];
2291 char *longField = (char *)NULL;
2295 if (fgets(lineBuf, MAXPATHLEN, fp) == (char *)NULL)
2296 return (char *)NULL;
2297 if (strcmp(lineBuf, "#\n") == 0)
2298 return (char *)NULL;
2300 lineType = atoi(lineBuf);
2304 case COMPRESSED_STRING_CODE:
2305 if (fgets(lineBuf, MAXPATHLEN, fp) == (char *)NULL)
2306 return (char *)NULL;
2311 if (fgets(lineBuf, MAXPATHLEN, fp) == (char *)NULL)
2312 return (char *)NULL;
2314 if ((ptr = strchr(lineBuf, '\t')) != (char *)NULL)
2321 if (fgets(lineBuf, MAXPATHLEN, fp) == (char *)NULL)
2322 return (char *)NULL;
2327 case SHORT_LIST_CODE:
2328 if (fgets(lineBuf, MAXPATHLEN, fp) == (char *)NULL)
2329 return (char *)NULL;
2331 if (strcmp(lineBuf, "#\n") != 0)
2334 while ((ptr = getTOCField(fp)) != (char *)NULL)
2336 if (longField != (char *)NULL)
2337 appendStr(&longField, &lfLen, &maxLen, "#");
2338 appendStr(&longField, &lfLen, &maxLen, ptr);
2347 if (fgets(lineBuf, MAXPATHLEN, fp) == (char *)NULL)
2348 return (char *)NULL;
2350 if (strcmp(lineBuf, "#\n") != 0)
2355 if (fgets(lineBuf, MAXPATHLEN, fp) == (char *)NULL)
2356 return (char *)NULL;
2359 ptrLen = strlen(lineBuf);
2360 if ((ptrLen > 0) && (lineBuf[ptrLen - 1] == '\n'))
2361 lineBuf[ptrLen - 1] = '\0';
2363 if (strcmp(lineBuf, "#") == 0)
2366 if (longField != (char *)NULL)
2367 appendStr(&longField, &lfLen, &maxLen, "#");
2368 appendStr(&longField, &lfLen, &maxLen, lineBuf);
2375 fprintf(stderr, "Unknown code: %d\n", lineType);
2380 if (ptr != (char *)NULL)
2382 ptrLen = strlen(ptr);
2383 if ((ptrLen > 0) && (ptr[ptrLen - 1] == '\n'))
2384 ptr[ptrLen - 1] = '\0';
2386 ptr = XtsNewString(ptr);
2388 if (longField != (char *)NULL)
2394 return (char *)NULL;
2398 main(int argc, char *argv[])
2400 GlobalsStruct globalsStruct;
2402 gStruct = &globalsStruct;
2405 printUsage((char *)NULL, -1);
2409 if (!doAdmin(argc, argv) &&
2410 !doBuild(argc, argv) &&
2411 !doTocgen(argc, argv) &&
2412 !doUpdate(argc, argv) &&
2413 !doValidate(argc, argv) &&
2414 !doHelp(argc, argv))
2415 printUsage(EXEC_NAME ": unrecognized subcommand `%s'\n", -1);