helpgen.c 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586
  1. /*
  2. * CDE - Common Desktop Environment
  3. *
  4. * Copyright (c) 1993-2012, The Open Group. All rights reserved.
  5. *
  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)
  10. * any later version.
  11. *
  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
  16. * details.
  17. *
  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
  22. */
  23. /* $TOG: helpgen.c /main/8 1998/04/20 12:52:36 mgreess $ */
  24. #include <dirent.h>
  25. #include <errno.h>
  26. #include <locale.h>
  27. #include <Dt/MsgCatP.h>
  28. #include <signal.h>
  29. #include <stdlib.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32. #include <unistd.h>
  33. #include <sys/param.h>
  34. #include <sys/stat.h>
  35. #include <sys/types.h>
  36. #include <X11/Xlib.h>
  37. #include <X11/Xresource.h>
  38. #include <X11/Intrinsic.h>
  39. #include <Dt/Help.h>
  40. #include <Dt/EnvControlP.h>
  41. #include "Dt/HelpP.h" /* in DtHelp library */
  42. #include "GenUtilsP.h" /* in DtHelp library */
  43. #include "ObsoleteP.h" /* in DtHelp library */
  44. #include "DtI/bufioI.h" /* for AccessI.h */
  45. #include "DtI/Access.h" /* in DtHelp library */
  46. #include "DtI/AccessP.h" /* in DtHelp library */
  47. #include "DtI/AccessI.h" /* in DtHelp library */
  48. #include "AccessCCDFI.h" /* in DtHelp library */
  49. #include "StringFuncsI.h" /* in DtHelp library */
  50. #ifdef _AIX
  51. #include <LocaleXlate.h>
  52. #endif
  53. #ifndef NL_CAT_LOCALE
  54. static const int NL_CAT_LOCALE = 0;
  55. #endif
  56. #ifndef CDE_INSTALLATION_TOP
  57. #define CDE_INSTALLATION_TOP "/usr/dt"
  58. #endif
  59. #ifndef CDE_CONFIGURATION_TOP
  60. #define CDE_CONFIGURATION_TOP "/etc/dt"
  61. #endif
  62. #ifndef DtSYS_FILE_SEARCH_ENV
  63. #define DtSYS_FILE_SEARCH_ENV "DTHELPSEARCHPATH"
  64. #endif
  65. #ifndef DtUSER_FILE_SEARCH_ENV
  66. #define DtUSER_FILE_SEARCH_ENV "DTHELPUSERSEARCHPATH"
  67. #endif
  68. /*****************************************************************************
  69. * defines
  70. *****************************************************************************/
  71. #define VOLUME_EXT ".hv"
  72. #define FAMILY_EXT ".hf"
  73. /*****************************************************************************
  74. * static strings.
  75. *****************************************************************************/
  76. static const char *ShellCmd = "sh";
  77. static const char *UsageStr =
  78. "%s -dir <directory> [-generate] [-file <name>] [-lang <language>]\n";
  79. static const char *TopLocId = "_hometopic";
  80. static const char *SlashString = "/";
  81. static const char *C_String = "C";
  82. static const char *DefCharSet = "C.ISO-8859-1";
  83. static const char *Family_ext = FAMILY_EXT;
  84. static const char *Ext_Hv = ".hv";
  85. static const char *Ext_Sdl = ".sdl";
  86. static const char *SuperMsg =
  87. "%s: Access denied for directory %s\nTry running as super user?\n";
  88. static const char *GeneralAccess =
  89. "%s: Unable to access %s - error status number %d\n";
  90. static const char *NotDirectory = "%s: Element of %s is not a directory\n";
  91. static const char *WriteInvalid = "%s: Write to %s invalid\n";
  92. static const char *defaultTopic = "<TOPIC charset %s>\n";
  93. static const char *defaultTitle12 =
  94. "<TYPE serif><WEIGHT bold><SIZE 12><ANGLE italic>\n%s\n</ANGLE></SIZE></WEIGHT></TYPE>\n";
  95. static const char *defaultTitle14 =
  96. "<TITLE><TYPE serif><WEIGHT bold><SIZE 14>\n%s\n</SIZE></WEIGHT></TYPE></TITLE>\n";
  97. static const char *defaultTextBody =
  98. "<ABBREV>Welcome to the Help Manager</ABBREV> \n\
  99. <PARAGRAPH>Each of the titles listed below represents a <ANGLE italic> \n\
  100. product family</> that has installed and registered its online help. Each \n\
  101. title (and icon) is a hyperlink that lists the help within the family.</> \n\
  102. <PARAGRAPH after 0 first 1 left 3 label \"<CHAR C.DT-SYMBOL-1><0xB7></>\">To \n\
  103. display a list of the help available for a product family, choose its \n\
  104. title (underlined text) or icon.</PARAGRAPH> \n\
  105. <PARAGRAPH after 0 first 1 left 3 label \"<CHAR C.DT-SYMBOL-1><0xB7></>\">\n\
  106. Within a product \n\
  107. family, find the help you want to view, then choose its title.</PARAGRAPH> \n\
  108. <PARAGRAPH first 1 left 3 label \"<CHAR C.DT-SYMBOL-1><0xB7></>\"> \n\
  109. If you need help while using help windows, press F1.</PARAGRAPH>";
  110. static const char *defaultAlternate =
  111. "<ABBREV>Welcome to the Help Manager</ABBREV> \n\
  112. <LINK 0 \"Help4Help How-To-Register-Help\"> \n\
  113. <TYPE serif><WEIGHT bold><SIZE 12><ANGLE italic> \n\
  114. Note:\\ \\ \\ No Help Registered</SIZE></WEIGHT></TYPE></></LINK> \n\
  115. <PARAGRAPH leftindent 3 firstindent 3> \n\
  116. <WEIGHT bold>No product families have registered their online help \n\
  117. files for browsing.</> Help may be available for some applications by \n\
  118. choosing Help commands directly within the applications.</>";
  119. /*****************************************************************************
  120. * global variables.
  121. *****************************************************************************/
  122. char *myName;
  123. char *Lang = NULL;
  124. char *ParentName = "_HOMETOPIC";
  125. char **TopicList = NULL;
  126. /* The family search list */
  127. char **FUserList = NULL;
  128. char **FSysList = NULL;
  129. /* The volume search list */
  130. char **VUserList = NULL;
  131. char **VSysList = NULL;
  132. char **FamilyList = NULL; /* the names of the unique families */
  133. char **FullFamilyName = NULL; /* the fully qualified family names */
  134. char **VolumeList = NULL; /* the names (only) of volume */
  135. char **FullVolName = NULL; /* the fully qualified volume names */
  136. char TopicName [MAXPATHLEN + 2];
  137. int FamilyNum = 0;
  138. /* Global Message Catalog file names */
  139. /*****************************************************************************
  140. * Private Function Declarations
  141. *****************************************************************************/
  142. extern char *FindFile (char *filename);
  143. /*****************************************************************************
  144. * options and resources
  145. *****************************************************************************/
  146. typedef struct
  147. {
  148. char *dir;
  149. char *file;
  150. char *lang;
  151. } ApplicationArgs, *ApplicationArgsPtr;
  152. static ApplicationArgs App_args =
  153. {
  154. NULL,
  155. "browser",
  156. NULL,
  157. };
  158. /*****************************************************************************
  159. * void MyExit(exit_val, pid)
  160. *****************************************************************************/
  161. void
  162. MyExit (
  163. int exit_val,
  164. pid_t pid)
  165. {
  166. if (pid != ((pid_t) -1))
  167. (void) kill(pid, SIGKILL);
  168. exit (exit_val);
  169. }
  170. /*****************************************************************************
  171. * char *GetMessage(set, n, s)
  172. *****************************************************************************/
  173. char *
  174. GetMessage (
  175. int set,
  176. int n,
  177. char *s)
  178. {
  179. char *msg;
  180. char *lang;
  181. char *catFileName=NULL;
  182. static nl_catd nlmsg_fd;
  183. static int first = 1;
  184. if ( first )
  185. {
  186. /* Setup our default message catalog names if none have been set! */
  187. /* Setup the short and long versions */
  188. catFileName = "dthelpgen";
  189. first = 0;
  190. if (strcmp (Lang, "C") == 0)
  191. /*
  192. * If LANG is not set or if LANG=C, then there
  193. * is no need to open the message catalog - just
  194. * return the built-in string "s".
  195. */
  196. nlmsg_fd = (nl_catd) -1;
  197. else
  198. nlmsg_fd = CATOPEN(catFileName, NL_CAT_LOCALE);
  199. }
  200. msg=CATGETS(nlmsg_fd,set,n,s);
  201. return (msg);
  202. }
  203. /*****************************************************************************
  204. * Boolean *GetPath(filename)
  205. *****************************************************************************/
  206. Boolean
  207. GetPath (char *filename, short strip, char ***list )
  208. {
  209. char *ptr;
  210. char **next = *list;
  211. if (strip)
  212. {
  213. ptr = strrchr (filename, '/');
  214. if (ptr)
  215. *ptr = '\0';
  216. else
  217. filename = "./";
  218. }
  219. while (next != NULL && *next != NULL && strcmp (*next, filename))
  220. next++;
  221. if (next == NULL || *next == NULL)
  222. *list = (char **) _DtHelpCeAddPtrToArray ((void **) (*list),
  223. strdup(filename));
  224. return False;
  225. }
  226. /*****************************************************************************
  227. * char *GetExtension(filename)
  228. * char *filename - name of file to get the extension from.
  229. * return a pointer to the extension of the file name
  230. *****************************************************************************/
  231. char *
  232. GetExtension(char *filename )
  233. {
  234. char *ext;
  235. /*
  236. * WARNING...
  237. * need multi-byte functionality here
  238. */
  239. ext = strrchr(filename, '.');
  240. if (ext)
  241. return(ext); /* safe because ext not in middle of character */
  242. return(""); /* never returns NULL */
  243. }
  244. /*****************************************************************************
  245. * Function: CreateVolumeLink
  246. *
  247. * outTopic the output stream.
  248. * volume_name Searches for a volume by this name.
  249. *
  250. * Reads a volume database and creates a label paragraph entry.
  251. *
  252. *****************************************************************************/
  253. int
  254. CreateVolumeLink (
  255. CanvasHandle canvas,
  256. FILE *outTopic,
  257. char *volume_name )
  258. {
  259. int result = -1;
  260. char *title = NULL;
  261. char *charSet = (char *) DefCharSet;
  262. char *abstract = NULL;
  263. char *pathName = NULL;
  264. VolumeHandle volume = NULL;
  265. pathName = FindFile (volume_name);
  266. if (pathName != NULL && _DtHelpCeOpenVolume(canvas,pathName,&volume) == 0)
  267. {
  268. if (_DtHelpCeGetVolumeTitle (canvas, volume, &title) == 0)
  269. result = 0;
  270. else if (_DtHelpCeGetTopicTitle(canvas,volume,(char*)TopLocId,&title)
  271. == True)
  272. result = 0;
  273. if (result == 0)
  274. {
  275. if (_DtHelpCeGetAsciiVolumeAbstract(canvas,volume,&abstract) == -1)
  276. abstract = NULL;
  277. charSet = _DtHelpCeGetVolumeLocale(volume);
  278. if (charSet == NULL)
  279. charSet = (char *) DefCharSet;
  280. }
  281. _DtHelpCeCloseVolume (canvas, volume);
  282. }
  283. if (result == 0)
  284. {
  285. fprintf (outTopic, (GetMessage(3, 4, "<CHARACTERSET %s>\n")), charSet);
  286. fprintf (outTopic,"<LINK 0 \"%s %s\">\n", volume_name, (char*)TopLocId);
  287. fprintf (outTopic, (GetMessage(3, 5, (char*)defaultTitle12)), title);
  288. fprintf (outTopic, "</LINK>\n");
  289. /*
  290. * put the abstract information about this
  291. * family in the header file
  292. */
  293. fprintf (outTopic, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
  294. if (abstract != NULL)
  295. {
  296. fprintf (outTopic, (GetMessage (3, 4, "<CHARACTERSET %s>\n")),
  297. charSet);
  298. fprintf (outTopic, "%s\n", abstract);
  299. fprintf (outTopic, "</CHARACTERSET>\n");
  300. free (abstract);
  301. }
  302. fprintf (outTopic, "</P>\n</CHARACTERSET>\n");
  303. }
  304. if (charSet != DefCharSet)
  305. free(charSet);
  306. if (title)
  307. free ((void *) title);
  308. return result;
  309. }
  310. /*****************************************************************************
  311. * Function: CreateFamily
  312. *
  313. *****************************************************************************/
  314. int
  315. CreateFamily (
  316. CanvasHandle canvas,
  317. char *family_name,
  318. FILE *out_volume,
  319. FILE *out_header,
  320. FILE *out_topic )
  321. {
  322. int result = -1;
  323. int count = 0;
  324. long filepos;
  325. char *charSet = NULL;
  326. char *title = NULL;
  327. char *abstract = NULL;
  328. char *list = NULL;
  329. char *token = NULL;
  330. char *ptr;
  331. char *bitmap = NULL;
  332. char familyName [20]; /* FAMILY%d */
  333. char bitmapName [MAXPATHLEN + 2];
  334. char bitmapNameTemp [sizeof(bitmapName)];
  335. XrmDatabase db;
  336. char *resType;
  337. XrmValue resValue;
  338. db = XrmGetFileDatabase (family_name);
  339. if (db)
  340. {
  341. /*
  342. * get the title
  343. */
  344. if (XrmGetResource (db, "Family.Title", "family.title",
  345. &resType, &resValue))
  346. {
  347. title = (char *) resValue.addr;
  348. /*
  349. * get the abstract
  350. */
  351. if (XrmGetResource (db, "Family.Abstract", "family.abstract",
  352. &resType, &resValue))
  353. {
  354. abstract = (char *) resValue.addr;
  355. /*
  356. * get the volumes list
  357. */
  358. if (XrmGetResource (db, "Family.Volumes", "family.volumes",
  359. &resType, &resValue))
  360. {
  361. list = (char *) resValue.addr;
  362. /*
  363. * get the character set
  364. */
  365. if (XrmGetResource (db, "Family.CharSet", "family.charSet",
  366. &resType, &resValue))
  367. {
  368. charSet = (char *) resValue.addr;
  369. /*
  370. * get the bitmap (optional)
  371. */
  372. if (XrmGetResource (db,
  373. "Family.Bitmap", "family.bitmap",
  374. &resType, &resValue))
  375. bitmap = (char *) resValue.addr;
  376. }
  377. else
  378. {
  379. fprintf (stderr,
  380. (GetMessage (1, 14,
  381. "%s: character set resource missing\n")),
  382. family_name);
  383. return -1;
  384. }
  385. }
  386. else
  387. {
  388. fprintf (stderr,
  389. (GetMessage (1, 13,
  390. "%s: volumes resource missing\n")),
  391. family_name);
  392. return -1;
  393. }
  394. }
  395. else
  396. {
  397. fprintf (stderr,
  398. (GetMessage (1, 12, "%s: abstract resource missing\n")),
  399. family_name);
  400. return -1;
  401. }
  402. }
  403. else
  404. {
  405. fprintf (stderr,
  406. (GetMessage (1, 11, "%s: title resource missing\n")),
  407. family_name);
  408. return -1;
  409. }
  410. if (title && abstract && list && charSet)
  411. {
  412. /*
  413. * find out the position of the file pointer
  414. */
  415. filepos = ftell (out_topic);
  416. /*
  417. * write out the <TOPIC>
  418. */
  419. fprintf (out_topic, (GetMessage (3, 1, (char*)defaultTopic)),
  420. charSet, title);
  421. /*
  422. * write out the <TITLE>
  423. */
  424. fprintf (out_topic, (GetMessage (3, 2, (char*)defaultTitle14)),
  425. title);
  426. fprintf (out_topic, "%s", (GetMessage (3, 3, "<P before 1 first 1 left 1>\n")));
  427. fprintf (out_topic, "%s\n", abstract);
  428. fprintf (out_topic, "</P>\n");
  429. do
  430. {
  431. token = NULL;
  432. list = _DtHelpCeGetNxtToken(list, &token);
  433. if (token && *token != '\0' && *token != '\n' &&
  434. CreateVolumeLink (canvas,out_topic, token) == 0)
  435. count++;
  436. if (token)
  437. {
  438. free ((void *) token);
  439. token = NULL;
  440. }
  441. } while (list && *list != '\0');
  442. if (count)
  443. {
  444. result = 0;
  445. sprintf (familyName, "FAMILY%d", FamilyNum);
  446. fprintf (out_topic, "</PARAGRAPH>\n</TOPIC>\n");
  447. /*
  448. * Put the link information in the header file
  449. */
  450. fprintf (out_header,
  451. (GetMessage (3, 4, "<CHARACTERSET %s>\n")), charSet);
  452. fprintf (out_header, "<LINK 0 %s>\n", familyName);
  453. fprintf (out_header, (GetMessage (3, 5, (char*)defaultTitle12)),
  454. title);
  455. fprintf (out_header, "</LINK>\n");
  456. /*
  457. * put the abstract information about this
  458. * family in the header file
  459. */
  460. if (NULL != bitmap && *bitmap != '/')
  461. {
  462. snprintf(bitmapName, sizeof(bitmapName), "%s", family_name);
  463. ptr = strrchr (bitmapName, '/');
  464. if (ptr)
  465. {
  466. ptr++;
  467. *ptr = '\0';
  468. snprintf(bitmapNameTemp, sizeof(bitmapNameTemp), "%s%s", bitmapName, bitmap);
  469. strcpy(bitmapName, bitmapNameTemp);
  470. bitmap = bitmapName;
  471. }
  472. else
  473. bitmap = NULL;
  474. }
  475. if (NULL != bitmap)
  476. {
  477. fprintf (out_header,
  478. (GetMessage (3, 6,
  479. "<P before 1 first 1 left 1 graphic %s glink %s gtypelink 0>\n")),
  480. bitmap, familyName);
  481. }
  482. else
  483. fprintf (out_header, "%s", GetMessage (3, 3, "<P before 1 first 1 left 1>\n"));
  484. fprintf (out_header, "%s\n", abstract);
  485. fprintf (out_header, "</P></CHARACTERSET>\n");
  486. /*
  487. * put the information in the volume file.
  488. */
  489. fprintf (out_volume, "*.%s.filepos: %ld\n",
  490. familyName, filepos);
  491. fprintf (out_volume, "*.%s.filename: %s\n",
  492. familyName, TopicName);
  493. TopicList = (char **) _DtHelpCeAddPtrToArray (
  494. (void **) TopicList,
  495. strdup (familyName));
  496. }
  497. else
  498. {
  499. /*
  500. * rewind back to the original starting position
  501. */
  502. fseek (out_topic, filepos, 0);
  503. /*
  504. * didn't find any volumes for this family.
  505. */
  506. result = -2;
  507. }
  508. }
  509. XrmDestroyDatabase (db);
  510. }
  511. return result;
  512. }
  513. /*****************************************************************************
  514. * Function: CheckFamilyList (name)
  515. *
  516. * See if this family has been seen
  517. *
  518. *****************************************************************************/
  519. int
  520. CheckFamilyList (char *name )
  521. {
  522. char **listPtr = FamilyList;
  523. while (listPtr != NULL && *listPtr != NULL)
  524. {
  525. if (strcmp (*listPtr, name) == 0)
  526. return True;
  527. listPtr++;
  528. }
  529. return False;
  530. }
  531. /*****************************************************************************
  532. * Function: AddFamilyToList (name)
  533. *
  534. * add the name to the family list
  535. *
  536. *****************************************************************************/
  537. char **
  538. AddFamilyToList (char *name )
  539. {
  540. FamilyList = (char **) _DtHelpCeAddPtrToArray ((void **) FamilyList,
  541. strdup(name));
  542. return FamilyList;
  543. }
  544. /*****************************************************************************
  545. * Function: ScanDirectory
  546. *
  547. * scan a directory looking for family files.
  548. *
  549. *****************************************************************************/
  550. void
  551. ScanDirectory (
  552. char *directory,
  553. long *ret_time)
  554. {
  555. DIR *pDir;
  556. struct stat buf;
  557. char fullName [MAXPATHLEN + 2];
  558. char *ptr;
  559. char *ext;
  560. struct dirent *pDirent;
  561. *ret_time = 0;
  562. if (stat(directory, &buf) == -1)
  563. return;
  564. *ret_time = buf.st_mtime;
  565. pDir = opendir (directory);
  566. if (pDir == NULL)
  567. return;
  568. snprintf(fullName, sizeof(fullName), "%s%s", directory, SlashString);
  569. ptr = fullName + strlen (fullName);
  570. /*
  571. * skip over the "." and ".." entries.
  572. */
  573. (void) readdir (pDir);
  574. (void) readdir (pDir);
  575. pDirent = readdir (pDir);
  576. while (pDirent)
  577. {
  578. ext = GetExtension (pDirent->d_name);
  579. if (strcmp (ext, Family_ext) == 0)
  580. {
  581. if (CheckFamilyList (pDirent->d_name) == False)
  582. {
  583. AddFamilyToList (pDirent->d_name);
  584. strcpy (ptr, pDirent->d_name);
  585. FullFamilyName = (char **) _DtHelpCeAddPtrToArray(
  586. (void **)FullFamilyName,
  587. strdup(fullName));
  588. }
  589. }
  590. else if (strcmp(ext, Ext_Hv) == 0 || strcmp(ext, Ext_Sdl) == 0)
  591. {
  592. strcpy (ptr, pDirent->d_name);
  593. VolumeList = (char **) _DtHelpCeAddPtrToArray((void **)VolumeList,
  594. strdup(pDirent->d_name));
  595. FullVolName = (char **) _DtHelpCeAddPtrToArray((void **)FullVolName,
  596. strdup(fullName));
  597. }
  598. pDirent = readdir (pDir);
  599. }
  600. closedir(pDir);
  601. return;
  602. }
  603. /*****************************************************************************
  604. * Function: FindFile
  605. *
  606. * Resolves the environment variable for all possible paths.
  607. *
  608. *****************************************************************************/
  609. char *
  610. FindFile (
  611. char *filename)
  612. {
  613. int i;
  614. int trimExt = 0;
  615. int different;
  616. char *fileExt;
  617. char *ext;
  618. struct stat status;
  619. fileExt = GetExtension(filename);
  620. if (*fileExt == '\0')
  621. trimExt = 1;
  622. i = 0;
  623. while (VolumeList != NULL && VolumeList[i] != NULL)
  624. {
  625. if (trimExt)
  626. {
  627. ext = GetExtension(VolumeList[i]);
  628. *ext = '\0';
  629. }
  630. different = strcmp(filename, VolumeList[i]);
  631. if (trimExt)
  632. *ext = '.';
  633. if (!different && access(FullVolName[i], R_OK) == 0
  634. && stat(FullVolName[i], &status) == 0
  635. && S_ISDIR(status.st_mode) == 0)
  636. return (FullVolName[i]);
  637. i++;
  638. }
  639. return NULL;
  640. }
  641. /*****************************************************************************
  642. * Function: ExpandPaths
  643. *
  644. * Resolves the environment variable for all possible paths.
  645. *
  646. *****************************************************************************/
  647. void
  648. ExpandPaths (
  649. char *lang,
  650. char *type,
  651. char *env_var,
  652. char *default_str,
  653. char ***list)
  654. {
  655. short strip;
  656. char *ptr;
  657. char *hPtr;
  658. char *src;
  659. char *pathName;
  660. char *searchPath;
  661. searchPath = getenv (env_var);
  662. if (searchPath == NULL || *searchPath == '\0')
  663. {
  664. if (default_str == NULL)
  665. return;
  666. searchPath = default_str;
  667. }
  668. searchPath = strdup (searchPath);
  669. *list = NULL;
  670. src = searchPath;
  671. do
  672. {
  673. ptr = strchr (src, ':');
  674. if (ptr)
  675. *ptr = '\0';
  676. /*
  677. * check to see if %H is declared. If so, we're going
  678. * to have to trim it before saving as the directory path.
  679. */
  680. strip = False;
  681. hPtr = strrchr (src, '%');
  682. if (hPtr != NULL)
  683. {
  684. hPtr++;
  685. if (*hPtr == 'H')
  686. strip = True;
  687. }
  688. /*
  689. * check to see if the path needs expanding
  690. */
  691. if (NULL != strchr (src, '%'))
  692. pathName = _DtHelpCeExpandPathname (src, NULL, type, NULL, lang,
  693. (_DtSubstitutionRec *) NULL, 0);
  694. else
  695. pathName = strdup(src);
  696. if (pathName)
  697. {
  698. GetPath (pathName, strip, list);
  699. free (pathName);
  700. }
  701. if (ptr)
  702. {
  703. *ptr = ':';
  704. ptr++;
  705. }
  706. src = ptr;
  707. } while (src && *src);
  708. free(searchPath);
  709. }
  710. /*****************************************************************************
  711. * Function: CheckTimeStamps
  712. *
  713. * Check the time stamps on the volume dir to determine if
  714. * it needs regenerating.
  715. *
  716. *****************************************************************************/
  717. int
  718. CheckTimeStamps (
  719. XrmDatabase db,
  720. char **dir_list)
  721. {
  722. long timeVal;
  723. char *value;
  724. struct stat buf;
  725. while (*dir_list != NULL)
  726. {
  727. if (stat(*dir_list, &buf) == -1)
  728. buf.st_mtime = 0;
  729. value = _DtHelpCeGetResourceString(db, *dir_list,
  730. "TimeStamp", "timeStamp");
  731. timeVal = atol(value);
  732. if (timeVal != buf.st_mtime)
  733. return 1;
  734. dir_list++;
  735. }
  736. return 0;
  737. }
  738. /*****************************************************************************
  739. * Function: CheckInfo
  740. *
  741. * Check the information in the volume to determine if it needs regenerating.
  742. *
  743. *****************************************************************************/
  744. int
  745. CheckInfo (
  746. char *file)
  747. {
  748. int result = 1;
  749. char **list1, **list2;
  750. char **volDirList;
  751. XrmDatabase db;
  752. db = XrmGetFileDatabase (file);
  753. if (db != NULL)
  754. {
  755. volDirList = _DtHelpCeGetResourceStringArray(db, NULL,
  756. "DirList", "dirList");
  757. if (volDirList != NULL)
  758. {
  759. result = 0;
  760. list1 = volDirList;
  761. list2 = FUserList;
  762. while (result == 0 && *list1 != NULL
  763. && list2 != NULL && *list2 != NULL)
  764. {
  765. result = strcmp(*list1, *list2);
  766. list1++;
  767. list2++;
  768. }
  769. if (list2 != NULL && *list2 != NULL)
  770. result = 1;
  771. list2 = FSysList;
  772. while (result == 0 && *list1 != NULL
  773. && list2 != NULL && *list2 != NULL)
  774. {
  775. result = strcmp(*list1, *list2);
  776. list1++;
  777. list2++;
  778. }
  779. if (list2 != NULL && *list2 != NULL)
  780. result = 1;
  781. list2 = VUserList;
  782. while (result == 0 && *list1 != NULL
  783. && list2 != NULL && *list2 != NULL)
  784. {
  785. result = strcmp(*list1, *list2);
  786. list1++;
  787. list2++;
  788. }
  789. if (list2 != NULL && *list2 != NULL)
  790. result = 1;
  791. list2 = VSysList;
  792. while (result == 0 && *list1 != NULL
  793. && list2 != NULL && *list2 != NULL)
  794. {
  795. result = strcmp(*list1, *list2);
  796. list1++;
  797. list2++;
  798. }
  799. if (*list1 != NULL || (list2 != NULL && *list2 != NULL))
  800. result = 1;
  801. if (result == 0)
  802. result = CheckTimeStamps(db, volDirList);
  803. _DtHelpCeFreeStringArray(volDirList);
  804. }
  805. XrmDestroyDatabase(db);
  806. }
  807. return result;
  808. }
  809. /*****************************************************************************
  810. * Main routine
  811. *****************************************************************************/
  812. int
  813. main(
  814. int argc,
  815. char *argv[] )
  816. {
  817. int i;
  818. int result;
  819. int foundFamily;
  820. int foundVolumes;
  821. int usedUser = 0;
  822. int doGen = 0;
  823. char tmpVolume [MAXPATHLEN + 2];
  824. char tmpVolumeTemp[sizeof(tmpVolume)];
  825. char tmpVolume2 [MAXPATHLEN + 2];
  826. char tmpTopic [MAXPATHLEN + 2];
  827. char tmpHeader [MAXPATHLEN + 2];
  828. char headerName [MAXPATHLEN + 2];
  829. char baseName [MAXPATHLEN + 2];
  830. char baseNameTemp[sizeof(baseName)];
  831. char tempName [MAXPATHLEN + 2];
  832. char **next;
  833. char *charSet;
  834. char *topicTitle;
  835. char *ptr;
  836. char *endDir;
  837. long preamble;
  838. long modTime;
  839. FILE *outVolume;
  840. FILE *outTopic;
  841. FILE *outHeader;
  842. pid_t childPid = (pid_t) -1;
  843. CanvasHandle canvasHandle;
  844. myName = strrchr (argv[0], '/');
  845. if (myName)
  846. myName++;
  847. else
  848. myName = argv[0];
  849. /*
  850. * have to do a setlocale here, so that the usage message is in the
  851. * correct language.
  852. */
  853. Lang = getenv ("LANG");
  854. /*
  855. * use the default if no lang is specified.
  856. */
  857. if (Lang == NULL || *Lang == '\0')
  858. Lang = (char*)C_String;
  859. setlocale(LC_ALL, "");
  860. _DtEnvControl(DT_ENV_SET);
  861. /*
  862. * now process the arguments
  863. */
  864. for (i = 1; i < argc; i++)
  865. {
  866. if (argv[i][0] == '-')
  867. {
  868. if (argv[i][1] == 'd' && i + 1 < argc)
  869. App_args.dir = argv[++i];
  870. else if (argv[i][1] == 'f' && i + 1 < argc)
  871. App_args.file = argv[++i];
  872. else if (argv[i][1] == 'g')
  873. doGen = 1;
  874. else if (argv[i][1] == 'l' && i + 1 < argc)
  875. App_args.lang = argv[++i];
  876. else
  877. {
  878. fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
  879. exit (1);
  880. }
  881. }
  882. else
  883. {
  884. fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
  885. exit (1);
  886. }
  887. }
  888. /*
  889. * get the language we are working with.
  890. */
  891. if (App_args.lang != NULL)
  892. {
  893. /*
  894. * Set the locale! Since the user has specified a (likely)
  895. * different language to do the processing in, we need to
  896. * do a setlocale to work with the new language.
  897. */
  898. Lang = App_args.lang;
  899. if (setlocale(LC_ALL, Lang) == NULL)
  900. {
  901. fprintf (stderr, (GetMessage(1, 20,
  902. "%s: Invalid system language specified - %s\n")),
  903. myName, Lang);
  904. exit (1);
  905. }
  906. _DtEnvControl(DT_ENV_SET);
  907. }
  908. Lang = strdup(Lang);
  909. /*
  910. * get the directory to work in
  911. */
  912. if (NULL == App_args.dir)
  913. {
  914. fprintf (stderr, (GetMessage(1,1, ((char*)UsageStr))), myName);
  915. exit (1);
  916. }
  917. if (App_args.dir[0] != '/')
  918. {
  919. if (getcwd (baseName, MAXPATHLEN) == NULL)
  920. {
  921. fprintf (stderr, (GetMessage (1, 18,
  922. "%s: Unable to access current working directory - error status number %d\n")),
  923. myName, errno);
  924. exit (1);
  925. }
  926. snprintf(baseNameTemp, sizeof(baseNameTemp), "%s/%s", baseName, App_args.dir);
  927. strcpy(baseName, baseNameTemp);
  928. }
  929. else
  930. snprintf(baseName, sizeof(baseName), "%s", App_args.dir);
  931. /*
  932. * make sure the directory exists
  933. */
  934. ptr = _DtHelpCeExpandPathname (baseName, NULL, "help", NULL, Lang,
  935. (_DtSubstitutionRec *) NULL, 0);
  936. if (ptr == NULL || *ptr == '\0')
  937. {
  938. fprintf (stderr,
  939. (GetMessage (1, 15, "%s: Destination directory missing\n")),
  940. myName);
  941. exit (1);
  942. }
  943. snprintf(tmpVolume, sizeof(tmpVolume), "%s", ptr);
  944. if (tmpVolume[strlen (tmpVolume) - 1] != '/') {
  945. snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, SlashString);
  946. strcpy(tmpVolume, tmpVolumeTemp);
  947. }
  948. free (ptr);
  949. /*
  950. * march down the path, checking that
  951. * 1) it exists
  952. * 2) the caller has access permission.
  953. * 3) resolve all symbolic links
  954. */
  955. endDir = strchr (tmpVolume, '/');
  956. if (endDir != NULL)
  957. {
  958. endDir++;
  959. endDir = strchr (endDir, '/');
  960. }
  961. while (endDir && *endDir != '\0')
  962. {
  963. /*
  964. * remember the rest of the string (including the slash)
  965. * and strip the trailing slash from the directory path.
  966. */
  967. snprintf(tmpVolume2, sizeof(tmpVolume2), "%s", endDir);
  968. *endDir = '\0';
  969. /*
  970. * trace the path and copy the new string into the old buffer.
  971. */
  972. ptr = _DtHelpCeTracePathName(tmpVolume);
  973. if (ptr != NULL)
  974. {
  975. snprintf(tmpVolume, sizeof(tmpVolume), "%s", ptr);
  976. free (ptr);
  977. }
  978. if (access (tmpVolume, F_OK) == -1)
  979. {
  980. switch (errno)
  981. {
  982. case ENOTDIR:
  983. ptr = GetMessage (1, 2, (char*)NotDirectory);
  984. fprintf (stderr, ptr, myName, tmpVolume);
  985. exit (1);
  986. case EACCES:
  987. ptr = GetMessage (1, 3, (char*)SuperMsg);
  988. fprintf (stderr, ptr, myName, tmpVolume);
  989. exit (1);
  990. case ENOENT:
  991. if (mkdir(tmpVolume,
  992. (S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) == -1
  993. && errno != EEXIST && errno != EROFS)
  994. {
  995. switch (errno)
  996. {
  997. case ENOTDIR:
  998. ptr = GetMessage(1,2,
  999. (char*)NotDirectory);
  1000. break;
  1001. case EACCES:
  1002. ptr = GetMessage(1, 3,
  1003. (char*)SuperMsg);
  1004. break;
  1005. case ENOENT:
  1006. ptr = GetMessage(1, 4,
  1007. "%s: Element of %s does not exist\n");
  1008. break;
  1009. case ENOSPC:
  1010. ptr = GetMessage (1, 5,
  1011. "%s: File system containing %s is full\n");
  1012. break;
  1013. default:
  1014. ptr = GetMessage(1,6,
  1015. (char*)GeneralAccess);
  1016. break;
  1017. }
  1018. fprintf (stderr, ptr, myName, tmpVolume, errno);
  1019. exit (1);
  1020. }
  1021. break;
  1022. default:
  1023. ptr = GetMessage (1, 6, (char*)GeneralAccess);
  1024. fprintf (stderr, ptr, myName, tmpVolume, errno);
  1025. exit (1);
  1026. }
  1027. }
  1028. /*
  1029. * point to the end of the string (past where the slash will go)
  1030. */
  1031. endDir = tmpVolume + strlen(tmpVolume) + 2;
  1032. /*
  1033. * append the rest of the directory spec that hasn't been checked.
  1034. */
  1035. strcat (tmpVolume, tmpVolume2);
  1036. endDir = strchr (endDir, '/');
  1037. }
  1038. /*
  1039. * get temporary files for the volume and topic file.
  1040. */
  1041. snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, App_args.file);
  1042. strcpy(tmpVolume, tmpVolumeTemp);
  1043. (void) strcpy (tmpHeader, tmpVolume);
  1044. (void) strcpy (tmpTopic, tmpVolume);
  1045. snprintf(tmpVolumeTemp, sizeof(tmpVolumeTemp), "%s%s", tmpVolume, Ext_Hv);
  1046. strcpy(tmpVolume, tmpVolumeTemp);
  1047. (void) strcat (tmpHeader, "00.ht");
  1048. (void) strcat (tmpTopic , "01.ht");
  1049. result = access (tmpVolume, F_OK);
  1050. /*
  1051. * If it exists, make sure the invoker can write to it.
  1052. */
  1053. if (result == 0)
  1054. {
  1055. if (access (tmpVolume, W_OK) == -1)
  1056. {
  1057. if (errno == EROFS)
  1058. ptr = GetMessage (1, 7,
  1059. "%s: File system containing %s is read only\n");
  1060. else if (errno == EACCES)
  1061. ptr = GetMessage (1, 8,
  1062. "%s: Requires root permission to write to %s\n");
  1063. else
  1064. ptr = GetMessage (1, 9, (char*)WriteInvalid);
  1065. fprintf (stderr, ptr, myName, tmpVolume, errno);
  1066. exit (1);
  1067. }
  1068. }
  1069. else if (result == -1 && errno != ENOENT)
  1070. {
  1071. ptr = GetMessage (1, 6, (char*)GeneralAccess);
  1072. fprintf (stderr, ptr, myName, tmpVolume, errno);
  1073. exit (1);
  1074. }
  1075. else /* file does not exist */
  1076. doGen = 1;
  1077. /*
  1078. * Find out if we have any paths to check.
  1079. */
  1080. ExpandPaths(Lang, "families", DtUSER_FILE_SEARCH_ENV, NULL, &FUserList);
  1081. ExpandPaths(Lang, "volumes", DtUSER_FILE_SEARCH_ENV, NULL, &VUserList);
  1082. ExpandPaths(Lang, "families", DtSYS_FILE_SEARCH_ENV ,
  1083. DtDEFAULT_SYSTEM_PATH, &FSysList);
  1084. ExpandPaths(Lang, "volumes", DtSYS_FILE_SEARCH_ENV ,
  1085. DtDEFAULT_SYSTEM_PATH, &VSysList);
  1086. if (((FUserList == NULL || *FUserList == NULL) &&
  1087. (FSysList == NULL || *FSysList == NULL)) ||
  1088. ((VUserList == NULL || *VUserList == NULL) &&
  1089. (VSysList == NULL || *VSysList == NULL)))
  1090. {
  1091. ptr = GetMessage (1, 10, "%s: Search Path empty\n");
  1092. fprintf (stderr, ptr, myName);
  1093. exit (1);
  1094. }
  1095. /*
  1096. * If we already haven't determined that the volume needs (re)generating
  1097. * check the info squirreled away in the old volume.
  1098. */
  1099. if (doGen == 0)
  1100. doGen = CheckInfo(tmpVolume);
  1101. /*
  1102. * the volume doesn't need (re)generating.
  1103. * exit now.
  1104. */
  1105. if (doGen == 0)
  1106. exit(0);
  1107. /*
  1108. * create a canvas for the functions.
  1109. */
  1110. canvasHandle = _DtHelpCeCreateDefCanvas();
  1111. if (canvasHandle == NULL)
  1112. {
  1113. fprintf (stderr, GetMessage(1, 19,"%s: Unable to allocate memory\n"),
  1114. myName);
  1115. MyExit (1, -1);
  1116. }
  1117. /*
  1118. * open the individual files that will hold the browser information.
  1119. * <file>.hv
  1120. */
  1121. outVolume = fopen (tmpVolume, "w");
  1122. if (outVolume == NULL)
  1123. {
  1124. ptr = GetMessage (1, 9, (char*)WriteInvalid);
  1125. fprintf (stderr, ptr, myName, tmpVolume, errno);
  1126. _DtHelpCeDestroyCanvas(canvasHandle);
  1127. MyExit (1, -1);
  1128. }
  1129. /*
  1130. * <file>00.ht
  1131. */
  1132. outTopic = fopen (tmpTopic, "w");
  1133. if (outTopic == NULL)
  1134. {
  1135. ptr = GetMessage (1, 9, (char*)WriteInvalid);
  1136. fprintf (stderr, ptr, myName, tmpTopic, errno);
  1137. (void) unlink (tmpVolume);
  1138. _DtHelpCeDestroyCanvas(canvasHandle);
  1139. MyExit (1, -1);
  1140. }
  1141. /*
  1142. * <file>01.ht
  1143. */
  1144. outHeader = fopen (tmpHeader, "w");
  1145. if (outHeader == NULL)
  1146. {
  1147. ptr = GetMessage (1, 9, (char*)WriteInvalid);
  1148. fprintf (stderr, ptr, myName, tmpHeader, errno);
  1149. (void) unlink (tmpVolume);
  1150. (void) unlink (tmpTopic);
  1151. _DtHelpCeDestroyCanvas(canvasHandle);
  1152. MyExit (1, -1);
  1153. }
  1154. /*
  1155. * fork off the dtksh script that will put up a dialog
  1156. * telling the user that we're building help browser
  1157. * information.
  1158. */
  1159. childPid = fork();
  1160. /*
  1161. * if this is the child, exec the dthelpgen.ds script.
  1162. */
  1163. if (childPid == 0)
  1164. {
  1165. execlp("dthelpgen.ds", "dthelpgen.ds",
  1166. ((char *) 0), ((char *) 0), ((char *) 0));
  1167. _exit(1);
  1168. }
  1169. /*
  1170. * initialize the main topic
  1171. */
  1172. strcpy (TopicName, App_args.file);
  1173. strcat (TopicName, "01.ht");
  1174. strcpy (headerName, App_args.file);
  1175. strcat (headerName, "00.ht");
  1176. /*
  1177. * The original dthelpgen extracts the CDE Standard name from
  1178. * its message catalogue( set 2/msg 1 ).
  1179. * But on IBM ODE, this is a problem. For example,
  1180. * fr_FR's dthelpgen.cat has
  1181. * fr_FR.ISO-8859-1 in set 2/msg 1.
  1182. * Correct Fr_FR's message catalogue must have,
  1183. * fr_FR.IBM-850
  1184. * there. But current IBM ode's Makefile cannot do this. Instead put
  1185. * fr_FR.ISO-8859-1. ( That is "do nothing" ).
  1186. * To fix this, dthelpgen converts the current IBM LANG to CDE
  1187. * standard name with _DtLcx*() function provided by libDtHelp.a as
  1188. * internal API.
  1189. */
  1190. #ifdef _AIX
  1191. {
  1192. _DtXlateDb db = NULL;
  1193. int ret;
  1194. char plat[_DtPLATFORM_MAX_LEN];
  1195. int execver;
  1196. int compver;
  1197. char *ret_stdLocale;
  1198. char *ret_stdLangTerr;
  1199. char *ret_stdCodeset;
  1200. char *ret_stdModifier;
  1201. ret = _DtLcxOpenAllDbs( &db );
  1202. if ( !ret ) {
  1203. ret = _DtXlateGetXlateEnv( db, plat, &execver, &compver );
  1204. if ( !ret ) {
  1205. ret = _DtLcxXlateOpToStd( db, plat, execver,
  1206. DtLCX_OPER_SETLOCALE,
  1207. setlocale( LC_MESSAGES, NULL ),
  1208. &ret_stdLocale, &ret_stdLangTerr,
  1209. &ret_stdCodeset, &ret_stdModifier );
  1210. if ( !ret ) {
  1211. charSet = strdup( ret_stdLocale );
  1212. } else {
  1213. charSet = "C.ISO-8859-1";
  1214. }
  1215. } else {
  1216. charSet = "C.ISO-8859-1";
  1217. }
  1218. ret = _DtLcxCloseDb( &db );
  1219. } else {
  1220. charSet = "C.ISO-8859-1";
  1221. }
  1222. }
  1223. #else /* _AIX */
  1224. charSet = strdup (GetMessage (2, 1, "C.ISO-8859-1"));
  1225. #endif /* _AIX */
  1226. topicTitle = strdup (GetMessage (2, 2, "Welcome to Help Manager"));
  1227. fprintf (outHeader, (GetMessage (3, 1, (char*)defaultTopic)),
  1228. charSet, topicTitle);
  1229. fprintf (outHeader, (GetMessage (3, 2, (char*)defaultTitle14)), topicTitle);
  1230. free(topicTitle);
  1231. preamble = ftell (outHeader);
  1232. fprintf (outHeader, "%s\n", GetMessage (2, 3, (char*)defaultTextBody));
  1233. /*
  1234. * loop through the directories looking for all the unique families
  1235. * and -all- the volumes.
  1236. */
  1237. fprintf (outVolume, "!# Last modification time stamp per directory\n");
  1238. next = FUserList;
  1239. while (next != NULL && *next != NULL)
  1240. {
  1241. ScanDirectory(*next, &modTime);
  1242. fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
  1243. next++;
  1244. }
  1245. next = FSysList;
  1246. while (next != NULL && *next != NULL)
  1247. {
  1248. ScanDirectory(*next, &modTime);
  1249. fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
  1250. next++;
  1251. }
  1252. next = VUserList;
  1253. while (next != NULL && *next != NULL)
  1254. {
  1255. ScanDirectory(*next, &modTime);
  1256. fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
  1257. next++;
  1258. }
  1259. next = VSysList;
  1260. while (next != NULL && *next != NULL)
  1261. {
  1262. ScanDirectory(*next, &modTime);
  1263. fprintf (outVolume, "*.%s.timeStamp: %ld\n" , *next, modTime);
  1264. next++;
  1265. }
  1266. fprintf (outVolume, "*.charSet: %s\n", charSet);
  1267. free(charSet);
  1268. fprintf (outVolume, "\n!# Topic filenames and offsets\n");
  1269. /*
  1270. * Now create families.
  1271. */
  1272. foundVolumes = 0;
  1273. foundFamily = 0;
  1274. for (next = FullFamilyName; next != NULL && *next != NULL; next++)
  1275. {
  1276. result = CreateFamily(canvasHandle,*next,outVolume,outHeader,outTopic);
  1277. if (result == 0)
  1278. {
  1279. FamilyNum++;
  1280. foundVolumes = 1;
  1281. foundFamily = 1;
  1282. }
  1283. else if (result == -2)
  1284. foundFamily = 1;
  1285. }
  1286. if (foundFamily == 0)
  1287. fprintf(stderr,
  1288. GetMessage(1, 16, "%s: Zero Family files found\n"), myName);
  1289. else if (foundVolumes == 0)
  1290. fprintf (stderr,
  1291. GetMessage (1, 17, "%s: Zero Volume files found\n"), myName);
  1292. /*
  1293. * Clean up
  1294. */
  1295. if (FamilyList != NULL)
  1296. _DtHelpCeFreeStringArray(FamilyList);
  1297. if (FullFamilyName != NULL)
  1298. _DtHelpCeFreeStringArray(FullFamilyName);
  1299. if (VolumeList != NULL)
  1300. _DtHelpCeFreeStringArray(VolumeList);
  1301. if (FullVolName != NULL)
  1302. _DtHelpCeFreeStringArray(FullVolName);
  1303. /*
  1304. * If no family or volume files were found,
  1305. * write out the alternative preamble
  1306. */
  1307. if (foundFamily == 0 || foundVolumes == 0)
  1308. {
  1309. fseek (outHeader, preamble, 0);
  1310. fprintf (outHeader, "%s\n", GetMessage (2, 5, (char*)defaultAlternate));
  1311. }
  1312. /*
  1313. * write the ending message and finish the topic.
  1314. */
  1315. fprintf (outHeader, "</TOPIC>\n");
  1316. /*
  1317. * write out the volume resouces
  1318. */
  1319. fprintf (outVolume, "\n\n!# Top (or home) topic filename and offset\n");
  1320. fprintf (outVolume, "*.%s.filepos: 0\n" , ParentName);
  1321. fprintf (outVolume, "*.%s.filename: %s\n", ParentName, headerName);
  1322. fprintf (outVolume, "\n\n!# Volume Title\n");
  1323. fprintf (outVolume, "*.title: %s\n",
  1324. GetMessage (2, 4, "Help - Top Level"));
  1325. /*
  1326. * top topic
  1327. */
  1328. fprintf (outVolume, "\n\n!# Topic Home Location\n");
  1329. fprintf (outVolume, "*.topTopic: %s\n", ParentName);
  1330. /*
  1331. * topic hierarchy
  1332. */
  1333. fprintf (outVolume, "\n\n!# Topic Hierarchy\n");
  1334. fprintf (outVolume, "*.%s.parent: \n", ParentName);
  1335. for (next = TopicList; next && *next; next++)
  1336. fprintf (outVolume, "*.%s.parent: %s\n", *next, ParentName);
  1337. /*
  1338. * topic list
  1339. */
  1340. fprintf (outVolume, "\n\n!# Topic List\n");
  1341. fprintf (outVolume, "*.topicList: %s", ParentName);
  1342. next = TopicList;
  1343. while (next && *next)
  1344. {
  1345. fprintf (outVolume, " \\\n %s", *next);
  1346. next++;
  1347. }
  1348. fprintf (outVolume, "\n");
  1349. /*
  1350. * The paths used to create this information.
  1351. */
  1352. fprintf (outVolume, "\n\n!# Paths Searched\n");
  1353. fprintf (outVolume, "*.dirList: ");
  1354. next = FUserList;
  1355. while (next != NULL && *next != NULL)
  1356. {
  1357. fprintf (outVolume, " \\\n %s", *next);
  1358. next++;
  1359. }
  1360. next = FSysList;
  1361. while (next != NULL && *next != NULL)
  1362. {
  1363. fprintf (outVolume, " \\\n %s", *next);
  1364. next++;
  1365. }
  1366. next = VUserList;
  1367. while (next != NULL && *next != NULL)
  1368. {
  1369. fprintf (outVolume, " \\\n %s", *next);
  1370. next++;
  1371. }
  1372. next = VSysList;
  1373. while (next != NULL && *next != NULL)
  1374. {
  1375. fprintf (outVolume, " \\\n %s", *next);
  1376. next++;
  1377. }
  1378. fprintf (outVolume, "\n");
  1379. /*
  1380. * close the volumes.
  1381. */
  1382. fclose (outVolume);
  1383. fclose (outHeader);
  1384. fclose (outTopic);
  1385. if (TopicList != NULL)
  1386. _DtHelpCeFreeStringArray(TopicList);
  1387. if (FUserList != NULL)
  1388. _DtHelpCeFreeStringArray(FUserList);
  1389. if (FSysList != NULL)
  1390. _DtHelpCeFreeStringArray(FSysList);
  1391. if (VUserList != NULL)
  1392. _DtHelpCeFreeStringArray(VUserList);
  1393. if (VSysList != NULL)
  1394. _DtHelpCeFreeStringArray(VSysList);
  1395. _DtHelpCeDestroyCanvas(canvasHandle);
  1396. MyExit (0, childPid);
  1397. }