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 librararies 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: Volumegen.c /main/4 1995/11/08 11:48:17 rswiston $ */
24 /************************************<+>*************************************
25 ****************************************************************************
29 * Project: Cache Creek (Rivers) Project
30 * Description: Source for the 'volumegen' portion of HelpTAG.
32 * Modifications by Mike Wilson
33 * Modifications to support non-topic IDs added by Dex Smith
36 * (C) Copyright 1992, Hewlett-Packard, all rights reserved.
38 ****************************************************************************
39 ************************************<+>*************************************/
44 #include <sys/types.h>
58 /* extern int errno; */
59 /* extern char *sys_errlist[]; */
60 /* extern int sys_nerr; */
62 static void GenTopicList (
66 static void GenTopicHeir(
70 static void GenTopicLoc(
74 static void GenHomeLocation(
77 static void GenKeyWordList(
81 static void MergeMetaInfo(
85 static char *GetNextToken(
87 Boolean delimIsSpace);
91 /* Volumegen Input file suffixes */
93 #define HEIR_FILE_SUFFIX ".tpc" /* The input filename suffix used for topic */
94 /* heirarchy files. */
95 #define TLOC_FILE_SUFFIX ".idt" /* The input filename suffix used for topic */
98 #define IKEY_FILE_SUFFIX ".idx" /* The input filename suffix used for sorted*/
100 #define IMETA_FILE_SUFFIX ".hmi" /* The input filename suffix used for meta */
101 /* information file. */
105 /* Volumegen Output file suffixes */
108 #define VOL_FILE_SUFFIX ".hv" /* The filename suffix used for volume */
109 /* file generated by volumegen. */
111 #define KEY_FILE_SUFFIX ".hvk" /* The filename suffix used for keyword */
112 /* file generated by volumegen. */
116 /*****************************************************************************
117 * Function: void main();
120 * Purpose: Program Main line body
122 *****************************************************************************/
128 FILE *tlocFile, *heirFile, *keyFile, *metaFile;
129 FILE *volFile, *keyWordFile;
131 setlocale(LC_ALL, "");
133 /* Make sure that an argument naming the volume was supplied. */
135 fprintf (stderr, "usage: %s <volume-name>\n", *argv);
139 /* Construct the name of the heirarchy file and open it. */
140 fName = malloc (strlen (*(argv+1)) + strlen (HEIR_FILE_SUFFIX) + 1);
141 strcpy (fName, *(argv+1));
142 strcat (fName, HEIR_FILE_SUFFIX);
143 if ((heirFile = fopen (fName, "r")) == NULL) {
145 "%s: error opening heirarchy file %s for reading\n",
151 /* Construct the name of the topic location file and open it. */
152 fName = malloc (strlen (*(argv+1)) + strlen (TLOC_FILE_SUFFIX) + 1);
153 strcpy (fName, *(argv+1));
154 strcat (fName, TLOC_FILE_SUFFIX);
155 if ((tlocFile = fopen (fName, "r")) == NULL) {
157 "%s: error opening topic location file %s for reading\n",
163 /* Construct the name of the keyword file and open it. */
164 fName = malloc (strlen (*(argv+1)) + strlen (IKEY_FILE_SUFFIX) + 1);
165 strcpy (fName, *(argv+1));
166 strcat (fName, IKEY_FILE_SUFFIX);
167 if ((keyFile = fopen (fName, "r")) == NULL) {
169 "%s: error opening keyword file %s for reading\n",
176 /* Construct the name of the meta information file and open it. */
177 fName = malloc (strlen (*(argv+1)) + strlen (IMETA_FILE_SUFFIX) + 1);
178 strcpy (fName, *(argv+1));
179 strcat (fName, IMETA_FILE_SUFFIX);
180 if ((metaFile = fopen(fName, "r")) == NULL) {
182 "%s: error opening meta file %s for reading\n",
189 /* Construct the name of the volume file (the one we are creating)
191 fName = malloc (strlen (*(argv+1)) + strlen (VOL_FILE_SUFFIX) + 1);
192 strcpy (fName, *(argv+1));
193 strcat (fName, VOL_FILE_SUFFIX);
194 if ((volFile = fopen (fName, "w")) == NULL) {
195 fprintf (stderr, "%s: error opening Volume file %s for writing\n",
201 /* Construct the name of the keyword file (the one we are creating)
203 fName = malloc (strlen (*(argv+1)) + strlen (KEY_FILE_SUFFIX) + 1);
204 strcpy (fName, *(argv+1));
205 strcat (fName, KEY_FILE_SUFFIX);
206 if ((keyWordFile = fopen (fName, "w")) == NULL) {
207 fprintf (stderr, "%s: error opening Keyword file %s for writing\n",
214 /* Generate topic list and heirarchy */
215 GenTopicList (heirFile, volFile);
216 GenTopicHeir (heirFile, volFile);
218 /* Generate topic location table. */
219 GenTopicLoc(tlocFile, volFile);
222 /* Generate the keyword information */
223 GenKeyWordList(keyFile, keyWordFile);
226 /* Merge the Meta information */
227 MergeMetaInfo(metaFile, volFile);
229 /* Generate the Home Topic entry */
230 GenHomeLocation(volFile);
236 /*****************************************************************************
237 * Function: static void GenTopicList(
244 * Return Value: Void.
246 * Purpose: Generates the topic list in the <class>.hv file.
248 *****************************************************************************/
249 static void GenTopicList (
255 fseek (infile, 0, SEEK_SET);
257 fprintf (outfile, "# Topic List\n");
259 /* The output formatting is kind of tricky as we want to end every
260 line with a "\", except for the last line. Therefore each time
261 through the loop we print the "\\\n" for the previous line and
262 the body of the current line. */
263 fprintf (outfile, "*.topicList: ");
264 while ((token = GetNextToken (infile, TRUE)) != NULL) {
266 if ((strcmp (token, "{") != 0) && (strcmp (token, "}") != 0))
267 fprintf (outfile, "\\\n\t%s ", token);
272 fprintf (outfile, "\n\n");
277 /*****************************************************************************
278 * Function: static void GenTopicHeir(
285 * Return Value: Void.
287 * Purpose: Generates the topic hierarchy in the <class>.hv file.
289 *****************************************************************************/
290 static void GenTopicHeir(
294 char *token, *prevToken, *tempS;
298 topicStack = PStackCreate();
299 fseek (infile, 0, SEEK_SET);
301 fprintf (outfile, "# Topic Heirarchy\n");
303 while ((token = GetNextToken (infile, TRUE)) != NULL) {
305 if (strcmp (token, "{") == 0)
306 PStackPush (topicStack, prevToken);
308 else if (strcmp (token, "}") == 0) {
309 if (prevToken != NULL)
312 free (PStackPop (topicStack));
316 tempS = (char *) PStackPeek (topicStack);
320 fprintf (outfile, "*.%s.parent:\t%s\n", token, tempS);
322 if (prevToken != NULL)
328 PStackDestroy (topicStack);
329 fprintf (outfile, "\n");
334 /*****************************************************************************
335 * Function: static void GenTopicLoc(
342 * Return Value: Void.
344 * Purpose: Generates the topic Location section in the
347 *****************************************************************************/
348 static void GenTopicLoc(
352 char *topic, *topicFile, *topicPos;
354 char *trueTopicID = NULL;
355 char *locationIdNew = NULL;
358 fseek (infile, 0, SEEK_SET);
361 "# Topic Locations (file names, file positions, and non-topic IDs)\n");
363 /* Topic location files have a strict syntax where each line contains
364 either three tokens (the topic ID, the file containing the topic,
365 and the byte offset to the start of the topic), or two tokens (the
366 topic ID and a non-topic ID that occurs within the topic). The
367 first style (three tokens) is identified by the trailing ":" on the
368 topic ID. Similarly, the second style (two tokens) is identified by
369 the trailing ">" on the topic ID. If the file deviates from these
370 two variations of the syntax, the file is considered corrupt. */
373 if ((topic = GetNextToken (infile, TRUE)) == NULL)
376 /* If the topic ID ends with ":", then we've found a primary entry. */
377 if (*(topic + strlen (topic) - 1) == ':')
379 /* Strip the ":" at the end of the topic ID */
380 *(topic + strlen (topic) - 1) = '\0';
382 /* if there was a previous trueTopicID, print it out */
383 if (trueTopicID != (char *)NULL && idList != (char *)NULL)
385 fprintf(outfile, "*.%s.locationIDs:\t%s\n",
386 trueTopicID, idList);
389 idList = (char *)NULL;
392 /* Save the new true topic. */
393 trueTopicID = malloc(strlen(topic) + 1);
394 strcpy(trueTopicID, topic);
396 if ((topicFile = GetNextToken (infile, TRUE)) == NULL)
399 if ((topicPos = GetNextToken (infile, TRUE)) == NULL)
402 fprintf (outfile, "*.%s.filename:\t%s\n", topic, topicFile);
403 fprintf (outfile, "*.%s.filepos:\t%s\n", topic, topicPos);
408 /* Else, if the id ends with ">", we've found a non-topic entry. */
409 else if (*(topic + strlen (topic) - 1) == '>')
411 /* Get the next token, its the non-topic ID. */
412 if ((locationIdNew = GetNextToken (infile, TRUE)) == NULL)
415 /* If the ID list hasn't been started for this topic, start it. */
416 if (idList == (char *)NULL)
418 idList = malloc(strlen(locationIdNew) + 1);
419 strcpy(idList, locationIdNew);
421 /* Else, add the ID we've just found to the list. */
424 /* append the non-topic location ID to the list */
426 realloc(idList, strlen(idList) + strlen(locationIdNew) +2);
429 strcat(idList, locationIdNew);
434 /* If the token does not end with ":" or ">", we have a problem. */
435 printf("The <volume>%s file is corrupt!\n", TLOC_FILE_SUFFIX);
440 if (trueTopicID != (char *)NULL && idList != (char *)NULL)
442 fprintf(outfile, "*.%s.locationIDs:\t%s\n",
443 trueTopicID, idList);
448 fprintf (outfile, "\n\n");
456 /*****************************************************************************
457 * Function: static void GenKeyWordList(
464 * Return Value: Void.
466 * Purpose: Generates the keyword list using the <class>.idx file and
467 * writes the results to <class>.hv file.
469 *****************************************************************************/
470 static void GenKeyWordList(
476 char *keyWordNew=NULL;
477 char *locationIdNew=NULL;
478 char *keyWordLast=NULL;
479 char *locationIdLast=NULL;
482 static char empty[] = "";
484 fseek (infile, 0, SEEK_SET);
486 fprintf (outfile, "# Keyword Index\n");
488 /* idx files (e.g. keyword) have a strict syntax where each line contains
489 * three tokens (the sort key, the keyword, and the locationID of the
490 * topic in which the keyword resides). Therefore it is an error if the
491 * number of tokens in the file is not an integral multiple of 3.
495 fprintf (outfile, "*Keywords:\t\\\n");
499 /* We get the sortKey, but we don't use it */
500 if ((sortKey = GetNextToken (infile, FALSE)) == NULL)
503 if ((keyWordNew = GetNextToken (infile, FALSE)) == NULL)
506 if ((locationIdNew = GetNextToken (infile, FALSE)) == NULL)
511 /* Check to see if we have the same keyword as before? */
512 if (keyWordLast && (strcmp (keyWordNew, keyWordLast) == 0))
515 /* We have a duplicate so add it to our previous keyword list */
517 realloc(idList, strlen(idList) + strlen(locationIdNew) + 2);
519 /* Add the new locationId to our current list */
521 strcat(idList, locationIdNew);
525 if (keyWordLast != NULL)
527 /* Write out the lastList keyword list */
528 fprintf (outfile, "%s<\\\\>%s\\n\\\n", keyWordLast, idList);
530 /* Clean up our old values */
534 /* We have a new keyword, so create a new keyword list */
535 idList = malloc(strlen(locationIdNew) + 1);
536 strcpy(idList, locationIdNew);
537 keyWordLast = malloc(strlen(keyWordNew) + 1);
538 strcpy(keyWordLast, keyWordNew);
543 /* This is the first time in so we special case it */
544 /* Create our initial keyword list */
545 idList = malloc(strlen(locationIdNew) + 1);
546 strcpy(idList, locationIdNew);
547 keyWordLast = malloc(strlen(keyWordNew) + 1);
548 strcpy(keyWordLast, keyWordNew);
555 free (locationIdNew);
559 /* Write out the last keyword and idList */
564 fprintf (outfile, "%s<\\\\>%s\\n\n", keyWordLast, idList);
566 /* Clean up our old values */
567 if (keyWordLast != empty)
572 fprintf (outfile, "\n\n");
580 /*****************************************************************************
581 * Function: static char *GetAChar(FILE *file)
583 * Parameters: file from which to read a (possibly multibyte) character
586 * Return Value: pointer to (possibly multibyte) character
588 * Purpose: Read a (possibly multibyte) character from the file.
589 * Put the character byte(s) into local static storage,
590 * terminating the character with a null byte.
592 *****************************************************************************/
593 static char *GetAChar(FILE *ifile)
596 static char mbyte[32]; /* bigger than any possible multibyte char */
600 if (((c = getc(ifile)) == EOF) || (c == '\0'))
609 mbyte[length] = '\0';
610 if (mblen(mbyte,length) != -1) return mbyte; /* hurray! */
611 if (length == MB_CUR_MAX)
612 { /* reached max without a hit */
613 printf("An invalid multi-byte character was found in the input");
618 if ((c = getc(ifile)) == EOF)
620 printf("End-of-file found within a multi-byte character");
631 /*****************************************************************************
632 * Function: static void MergeMetaInfo(
639 * Return Value: Void.
641 * Purpose: Merges the <class>.hmi meta information into the
642 * runtime volume file <class>.hv file.
644 *****************************************************************************/
645 static void MergeMetaInfo(FILE *infile, FILE *outfile)
650 char *writeC, *token;
652 fprintf (outfile, "# Meta Information\n");
653 fseek (infile, 0, SEEK_SET);
655 /* Clear out any initial white space that may be present */
656 while ((*(nextC = GetAChar(infile)) != '\0') &&
657 (mblen(nextC, MB_CUR_MAX) == 1) &&
661 /* place that initial nextC value */
662 fputs(nextC, outfile);
664 while (*(nextC = GetAChar(infile)))
665 fputs(nextC, outfile);
667 fputs("\n\n", outfile);
672 /*****************************************************************************
673 * Function: static void GenHomeLocation(
680 * Return Value: Void.
682 * Purpose: Generates the topic Location section in the
685 *****************************************************************************/
686 static void GenHomeLocation(
689 char *topic, *topicFile, *topicPos;
691 fprintf (outfile, "# Topic Home Locations\n");
692 fprintf (outfile, "*topTopic: _HOMETOPIC\n");
693 fprintf (outfile, "\n\n");
704 /*****************************************************************************
705 * Function: static char *GetNextToken(FILE *file)
707 * Parameters: WidgetClass
710 * Return Value: Void.
712 * Purpose: This function will return a token from the input streem.
713 * A boolean flag is passed in which instructs the function to
714 * use one of two token delimiters: " " or '\0'.
715 * (e.g. space or null char).
716 *****************************************************************************/
717 static char *GetNextToken(FILE *file, Boolean delimIsSpace)
721 char *writeC, *token;
724 while ((*(nextC = GetAChar(file)) != '\0') &&
725 ((length = mblen(nextC, MB_CUR_MAX)) == 1) &&
737 if (writeC < (buff + BUFSIZ - length - 1))
739 strcpy(writeC, nextC);
742 nextC = GetAChar(file);
743 length = mblen(nextC, MB_CUR_MAX);
745 while ((length > 1) || ((*nextC != '\0') && !isspace(*nextC)));
750 if (writeC < (buff + BUFSIZ - length - 1))
752 strcpy(writeC, nextC);
755 nextC = GetAChar(file);
756 length = mblen(nextC, MB_CUR_MAX);
757 if ((length == 1) && (*nextC == '\036'))
760 while ((length > 1) || (*nextC != '\0'));
763 token = strdup(buff);