PrintTopics.c 88 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888
  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. #if DOC
  24. /*===================================================================
  25. $FILEBEG$: PrintTopics.c
  26. $COMPONENT$: dthelpprint
  27. $PROJECT$: Cde1
  28. $SYSTEM$: HPUX 9.0; AIX 3.2; SunOS 5.3
  29. $REVISION$: $TOG: PrintTopics.c /main/12 1998/04/01 17:26:51 mgreess $
  30. $COPYRIGHT$:
  31. (c) Copyright 1996 Digital Equipment Corporation.
  32. (c) Copyright 1993,1994,1996 Hewlett-Packard Company.
  33. (c) Copyright 1993,1994,1996 International Business Machines Corp.
  34. (c) Copyright 1993,1994,1996 Sun Microsystems, Inc.
  35. (c) Copyright 1993,1994,1996 Novell, Inc.
  36. (c) Copyright 1996 FUJITSU LIMITED.
  37. (c) Copyright 1996 Hitachi.
  38. ==$END$==============================================================*/
  39. #endif
  40. #ifndef _XOPEN_SOURCE
  41. # define _XOPEN_SOURCE 600
  42. #endif
  43. #ifdef HAVE_CONFIG_H
  44. #include <cde_config.h>
  45. #endif
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include <strings.h>
  50. #include <unistd.h>
  51. #include <sys/stat.h> /* for stat() */
  52. #if defined(sun)
  53. #include <widec.h>
  54. #else
  55. #include <wchar.h>
  56. #endif
  57. #include <locale.h>
  58. #if !defined(sun)
  59. #include <langinfo.h>
  60. #endif
  61. #include <iconv.h>
  62. #include <errno.h>
  63. #include <time.h>
  64. #include "HelpPrintI.h" /* helpprint */
  65. #include "DtI/HelpTermP.h" /* from libDtHelp */
  66. #include "Dt/CanvasP.h" /* from libDtHelp */
  67. #include "StringFuncsI.h" /* from libDtHelp */
  68. #include "DtI/bufioI.h" /* from libDtHelp; required for AccessI.h */
  69. #include "DtI/FileUtilsI.h" /* from libDtHelp */
  70. #include "DtI/Access.h" /* from libDtHelp */
  71. #include "DtI/AccessI.h" /* from libDtHelp */
  72. #include "GenUtilsP.h" /* from libDtHelp */
  73. #include "HelpXlate.h" /* from libDtHelp */
  74. #include "ObsoleteP.h" /* from libDtHelp */
  75. // lib/DtHelp/FormatTerm.c
  76. int _DtHelpTermCreateCanvas(int maxColumns, _DtCvHandle *ret_canvas);
  77. int _DtHelpTermGetTopicData(_DtCvHandle canvasHandle,
  78. _DtHelpVolumeHdl volHandle,
  79. char *locationId,
  80. char ***helpList,
  81. DtHelpHyperLines **hyperList);
  82. extern char * _DtHelpCeGetVolumeLocale(VolumeHandle helpVolumeHandle);
  83. extern const char * _DtHelpCeGetVolumeCharSet(VolumeHandle helpVolumeHandle);
  84. /*======== platform adjustments ==============*/
  85. #ifdef sun
  86. #define wcswidth(s,n) wscol(s)
  87. #define wcslen(s) wslen(s)
  88. #endif
  89. /*======== boundary values ==============*/
  90. #define MAXSECTS 50 /* max number of section nesting */
  91. #define MAXVOLTITLEWIDTH 50
  92. #define MAXTOPICTITLEWIDTH 50
  93. #define MAXPAGENUMWIDTH 3
  94. #define MAXSECTNUMWIDTH 8
  95. /*======== helper values ===============*/
  96. #define EOS '\0'
  97. #define EMPTY_STR s_EmptyStr
  98. #define PTSET 3 /* message set */
  99. /*======== helper variables ===============*/
  100. static char s_EmptyStr[1] = { EOS };
  101. /* To do:
  102. * check roman 8/Latin 1
  103. * check PAGER env variable
  104. * do character wrap
  105. */
  106. /*======== data structs ==============*/
  107. /* These data structs manage the table of contents (Toc)
  108. of a help volume. The Toc uses two organizational mechanisms:
  109. a linear table of entries, which gives sequential order
  110. and is used to generate the TOC; and a binary tree of entries
  111. that is sorted alphabetically by location id, and is used to
  112. speed lookup of the page number of a locationId for use in
  113. generating the index. */
  114. #if DOC
  115. ===================================================================
  116. $PTYPEBEG$: TocEntry
  117. $1LINER$: All data for a single toc entry
  118. $DESCRIPT$:
  119. $ARGS$:
  120. ========================================================$SKIP$=====*/
  121. #endif /*DOC*/
  122. /*$DEF$*/
  123. typedef struct TocEntry
  124. {
  125. struct TocEntry * nextEntry; /* next entry in the linear list */
  126. struct TocEntry * leftLoc; /* left location of sorted binary tree */
  127. struct TocEntry * rightLoc; /* right location of sorted binary tree */
  128. char * locationId; /* locationId of the topic */
  129. int pageNumber; /* page the topic located on */
  130. int level; /* nesting level */
  131. int sectNums[MAXSECTS]; /* section numbers */
  132. char * sectStr; /* alternate section string */
  133. } TocEntry;
  134. /*$END$*/
  135. #if DOC
  136. ===================================================================
  137. $PTYPEBEG$: Toc
  138. $1LINER$: Manages the toc entries in a volume
  139. $DESCRIPT$:
  140. $ARGS$:
  141. ========================================================$SKIP$=====*/
  142. #endif /*DOC*/
  143. /*$DEF$*/
  144. typedef struct Toc
  145. {
  146. TocEntry * linearEntries; /* ptr to head of linear list of entries */
  147. TocEntry * lastLinearEntry; /* ptr to tail of linear list of entries */
  148. TocEntry * sortedEntries; /* ptr to top of sorted btree of entries */
  149. } Toc;
  150. /*$END$*/
  151. #if DOC
  152. ===================================================================
  153. $PTYPEBEG$: HeadFootFormat
  154. $1LINER$: All data related to the header/footer formatting
  155. $DESCRIPT$:
  156. $ARGS$:
  157. ========================================================$SKIP$=====*/
  158. #endif /*DOC*/
  159. /*$DEF$*/
  160. typedef struct HeadFootFormat
  161. {
  162. char * formattedEvenHeader; /* formatted even-page header when printing volume */
  163. char * formattedOddHeader; /* formatted odd-page header when printing volume */
  164. char * formattedEvenFooter; /* formatted even-page footer when printing volume */
  165. char * formattedOddFooter; /* formatted odd-page footer when printing volume */
  166. int evenHeaderLineCnt; /* num lines in even-page header when printing volume */
  167. int oddHeaderLineCnt; /* num lines in odd-page header when printing volume */
  168. int evenFooterLineCnt; /* num lines in even-page footer when printing volume */
  169. int oddFooterLineCnt; /* num lines in odd-page footer when printing volume */
  170. } HeadFootFormat;
  171. /*$END$*/
  172. #if DOC
  173. ===================================================================
  174. $PTYPEBEG$: HeadFootFormatArgs
  175. $1LINER$: Arguments used in head/foot formatting
  176. $DESCRIPT$:
  177. $ARGS$:
  178. ========================================================$SKIP$=====*/
  179. #endif /*DOC*/
  180. /*$DEF$*/
  181. typedef struct HeadFootFormatArgs
  182. {
  183. char * volumeTitle;
  184. int volumeTitleColsWidth;
  185. char * topicTitle;
  186. int topicTitleColsWidth;
  187. char * volumeDate;
  188. int volumeDateColsWidth;
  189. char * todaysDate;
  190. int todaysDateColsWidth;
  191. int sectNumColsWidth;
  192. int pageNumColsWidth;
  193. }
  194. HeadFootFormatArgs;
  195. /*$END$*/
  196. #if DOC
  197. ===================================================================
  198. $PTYPEBEG$: PrintState
  199. $1LINER$: All data related to the on-going printing operation
  200. $DESCRIPT$:
  201. $ARGS$:
  202. ========================================================$SKIP$=====*/
  203. #endif /*DOC*/
  204. /*$DEF$*/
  205. typedef struct PrintState
  206. {
  207. char * currentLocId; /* current loc Id in volume */
  208. char * outputFromLocId; /* start output at this location */
  209. HeadFootFormatArgs hffArgs; /* arguments used in head/foot formatting */
  210. HeadFootFormat tocHFF; /* HF formatting info for TOC */
  211. HeadFootFormat bodyHFF; /* HF formatting info for body */
  212. HeadFootFormat indexHFF; /* HF formatting info for index */
  213. Boolean inhibitOutput; /* inhibit output */
  214. int curPageNumber; /* page number of current output */
  215. int curLineNumber; /* line number of current page of output */
  216. VolumeHandle volHandle; /* volume handle of volume being printed */
  217. CanvasHandle canvasHandle; /*canvas handle of terminal format canvas*/
  218. int sectNums[MAXSECTS]; /* current section number */
  219. char * sectStr; /* current section string value */
  220. int level; /* level of section nesting */
  221. } PrintState;
  222. /*$END$*/
  223. /*======== static variables ===============*/
  224. #if DOC
  225. ===================================================================
  226. $PTYPEBEG$: SymValue
  227. $1LINER$: Maps a symbolic string to a printf-format string.
  228. $DESCRIPT$:
  229. $ARGS$:
  230. ========================================================$SKIP$=====*/
  231. #endif /*DOC*/
  232. /*$DEF$*/
  233. typedef struct SymValue
  234. {
  235. char * symbol;
  236. char * argref;
  237. } SymValue;
  238. /* List of symbols that can be used in header/footer strings
  239. and the printf args that are used to access the data. */
  240. /* NOTE: ***IT IS CRITICAL THAT THE SYMBOL STRING HAVE THE
  241. SAME OR LONGER LENGTH THAN THE ARGUMENT STRING. ***/
  242. /* NOTE: ***ALWAYS UPDATE THE UNUSED_ARGREF AND THE sprintf() CALL
  243. IN PrintHeadFootStr() WHEN ADDING NEW SYMBOLS***/
  244. /* NOTE: The replacement values use a trick to get around the limitations
  245. of printf(), which only allows args numbered 1 to 9. The strategy
  246. is to do two printfs, and to use the %% construct in the first string
  247. to generate a % construct in the second string. */
  248. SymValue g_HeadFootSymsList[] =
  249. {
  250. { "$VOLUMEFILL", "%%2$*1$c" }, /* filler for fixed sized volume name */
  251. { "$TOPICFILL", "%%4$*3$c" }, /* filler for fixed sized current topic title */
  252. { "$PAGENUMFILL", "%%6$*5$c" }, /* filler for fixed sized page number */
  253. { "$SECTNUMFILL", "%%8$*7$c" }, /* filler for fixed sized section number or name */
  254. { "$TODAY", "%1$s" }, /* today's date */
  255. { "$VOLUME", "%2$s" }, /* volume name */
  256. { "$TOPIC", "%3$s" }, /* current topic title */
  257. { "$PAGENUM", "%4$d" }, /* page number */
  258. { "$VOLDATE", "%5$s" }, /* date on the help volume file */
  259. { "$SECTNUM", "%6$s" }, /* section number or name */
  260. { "$LMARGIN", "%8$*7$c" }, /* left margin blanks; args 7 & 8 */
  261. { NULL, NULL }
  262. };
  263. #define UNUSED_ARGREF "%%9$n" /* arg to hold the num of unused args */
  264. /*$END$*/
  265. /*======== functions ==============*/
  266. #if DOC
  267. ===================================================================
  268. $PFUNBEG$: TocNextEntry()
  269. $1LINER$: Get next entry in the toc
  270. $DESCRIPT$:
  271. $ARGS$:
  272. $RETURNS$:
  273. != NULL: next entry
  274. NULL: no more entires
  275. ========================================================$SKIP$=====*/
  276. #endif /*DOC*/
  277. static
  278. TocEntry * TocNextEntry(
  279. Toc * toc,
  280. TocEntry * entry)
  281. { /*$CODE$*/
  282. if (NULL == entry) return toc->linearEntries;
  283. return entry->nextEntry;
  284. } /*$END$*/
  285. #if DOC
  286. ===================================================================
  287. $PFUNBEG$: TocFindSortedEntry()
  288. $1LINER$: Finds an entry using the sorted btree of entries
  289. $DESCRIPT$:
  290. $RETURNS$:
  291. $ARGS$:
  292. 0: ok
  293. -1: entry not found
  294. ========================================================$SKIP$=====*/
  295. #endif /*DOC*/
  296. static
  297. int TocFindSortedEntry(
  298. Toc * toc,
  299. char * locationId,
  300. TocEntry * * ret_parent,
  301. TocEntry * * ret_entry)
  302. { /*$CODE$*/
  303. TocEntry * prev;
  304. TocEntry * cur;
  305. TocEntry * tmp;
  306. if (NULL == ret_parent) ret_parent = &tmp;
  307. if (NULL == ret_entry) ret_entry = &tmp;
  308. *ret_parent = NULL;
  309. *ret_entry = NULL;
  310. prev = toc->sortedEntries;
  311. cur = prev;
  312. while ( NULL != cur )
  313. {
  314. int cmp;
  315. cmp = _DtHelpCeStrCaseCmp(locationId,cur->locationId);
  316. if ( cmp < 0 )
  317. prev = cur, cur = cur->leftLoc;
  318. else if ( cmp > 0 )
  319. prev = cur, cur = cur->rightLoc;
  320. else
  321. {
  322. *ret_parent = prev, *ret_entry = cur;
  323. return 0; /* RETURN: found */
  324. }
  325. }
  326. *ret_parent = prev;
  327. return -1; /* RETURN: not found */
  328. } /*$END$*/
  329. #if DOC
  330. ===================================================================
  331. $PFUNBEG$: TocNewEntry()
  332. $1LINER$: Add a Toc entry to the Toc
  333. $DESCRIPT$:
  334. $RETURNS$:
  335. $ARGS$:
  336. 0: ok
  337. -1: memory allocation error
  338. ========================================================$SKIP$=====*/
  339. #endif /*DOC*/
  340. static
  341. int TocNewEntry(
  342. Toc * toc,
  343. char * locationId,
  344. int pageNumber,
  345. int level,
  346. int * sectNums,
  347. char * sectStr)
  348. { /*$CODE$*/
  349. TocEntry * new;
  350. new = calloc(1,sizeof(TocEntry));
  351. if (NULL == new) return -1; /* RETURN: mem alloc err */
  352. /* init contents */
  353. new->locationId = strdup(locationId);
  354. new->pageNumber = pageNumber;
  355. new->level = level;
  356. new->sectStr = sectStr;
  357. memcpy(new->sectNums, sectNums, sizeof(new->sectNums));
  358. if (NULL == new->locationId)
  359. { free(new); return -1; } /* RETURN: mem alloc err */
  360. /*** insert into toc ***/
  361. /* if first in list */
  362. if (NULL == toc->linearEntries)
  363. {
  364. toc->linearEntries = new;
  365. toc->lastLinearEntry = new;
  366. toc->sortedEntries = new;
  367. }
  368. else /* not first in list */
  369. {
  370. TocEntry * parent, * entry;
  371. if ( TocFindSortedEntry(toc,locationId,&parent,&entry) == 0 )
  372. return -2; /* RETURN: duplicate entry */
  373. /* insert into the btree (not balanced) */
  374. if( _DtHelpCeStrCaseCmp(locationId,parent->locationId) < 0 )
  375. parent->leftLoc = new;
  376. else
  377. parent->rightLoc = new;
  378. /* insert into the linear list */
  379. toc->lastLinearEntry->nextEntry = new;
  380. toc->lastLinearEntry = new;
  381. }
  382. return 0; /* RETURN: ok */
  383. } /*$END$*/
  384. #if DOC
  385. ===================================================================
  386. $PFUNBEG$: IconvFile()
  387. $1LINER$: Compares cur env and volume and iconv file if necessary
  388. $DESCRIPT$:
  389. $RETURNS$:
  390. 0: no conversion needed or not possible to determine if needed
  391. 1: conversion needed & successful
  392. -1: conversion needed and failed
  393. $ARGS$:
  394. ========================================================$SKIP$=====*/
  395. #endif /*DOC*/
  396. static
  397. int IconvFile(
  398. _DtHPrOptions * options,
  399. VolumeHandle helpVolumeHandle,
  400. char * * srcFile)
  401. { /*$CODE$*/
  402. #define CUR_LOCALE 0
  403. #define CUR_CODESET 1
  404. #define VOL_LOCALE 2
  405. #define VOL_CODESET 3
  406. #define FROM_CODESET 4
  407. #define TO_CODESET 5
  408. #define NUMSTRS 6
  409. int ret;
  410. int i;
  411. char * loc[NUMSTRS];
  412. char * destFile = NULL;
  413. char * codeset;
  414. char buf[1000];
  415. for (i=0; i<NUMSTRS; i++) loc[i] = NULL;
  416. /* get the normalized current codeset */
  417. _DtHelpCeGetLcCtype(&loc[CUR_LOCALE], NULL, &loc[CUR_CODESET]);
  418. /* get the normalized volume codeset */
  419. loc[VOL_LOCALE] = _DtHelpCeGetVolumeLocale(helpVolumeHandle);
  420. /* codeset begins after the '.'; find it */
  421. codeset = NULL;
  422. if ( loc[VOL_LOCALE]
  423. && _DtHelpCeStrchr(loc[VOL_LOCALE], ".", 1, &codeset) == 0)
  424. {
  425. codeset++;
  426. }
  427. loc[VOL_CODESET] = (NULL != codeset ? strdup(codeset) : NULL);
  428. /* if either locale is NULL or if they are the same string
  429. then don't iconv the file */
  430. if ( NULL == loc[CUR_CODESET]
  431. || NULL == loc[VOL_CODESET]
  432. || strcmp(loc[CUR_CODESET],loc[VOL_CODESET]) == 0 )
  433. {
  434. ret = 0; /* RETURN: no iconv needed/possible */
  435. goto cleanup;
  436. }
  437. /* get the source codeset */
  438. loc[FROM_CODESET] = strdup(loc[VOL_LOCALE]);
  439. /* get the target codeset */
  440. loc[TO_CODESET] = strdup(loc[CUR_LOCALE]);
  441. /* construct the command line */
  442. destFile = _DtHPrCreateTmpFile(TMPFILE_PREFIX,TMPFILE_SUFFIX);
  443. if (NULL == destFile)
  444. {
  445. ret = -1; /* error */
  446. goto cleanup;
  447. }
  448. sprintf(buf,options->iconvCmdAndArgs,
  449. loc[FROM_CODESET],loc[TO_CODESET],*srcFile, destFile);
  450. /* do the conversion */
  451. if(options->debugHelpPrint) printf("%s\n",buf);
  452. ret = system(buf);
  453. ret = (ret == 0 ? 1 : -1); /* 1: success; -1: failure */
  454. /* if successful conversion, change the src file */
  455. if (ret >= 0)
  456. {
  457. unlink(*srcFile);
  458. free(*srcFile);
  459. *srcFile = destFile;
  460. }
  461. else
  462. {
  463. unlink(destFile);
  464. }
  465. cleanup:
  466. /* free memory */
  467. for (i=0; i<NUMSTRS; i++) if (loc[i]) free(loc[i]);
  468. return ret;
  469. } /* count lines */
  470. #define ICONV_INBUF_TYPE ICONV_CONST char **
  471. #define WORKSIZE 1024*10 /* 10k */
  472. /*
  473. * _i18nwork1[] is used to convert the passed string with CD iconv.
  474. * in _converter_().
  475. *
  476. */
  477. static void *_i18nwork1 = NULL;
  478. static unsigned long _i18nsize1 = 0;
  479. static int shouldAlloc1 = ~0;
  480. static void _converter_( iconv_t CD,
  481. void *from, unsigned long from_len,
  482. void **to )
  483. {
  484. char *InBuf;
  485. size_t InBytesLeft;
  486. char *OutBuf = NULL;
  487. size_t OutBytesLeft = 0;
  488. size_t _OutBytesLeft = 0;
  489. size_t iconv_ret;
  490. size_t converted_num = 0;
  491. unsigned long to_len;
  492. *to = NULL;
  493. to_len = 0;
  494. if ( shouldAlloc1 ) {
  495. /* Obtain work area */
  496. _i18nwork1 = (size_t *)malloc( WORKSIZE );
  497. if ( !_i18nwork1 ) {
  498. _i18nwork1 = NULL;
  499. return;
  500. }
  501. _i18nsize1 = WORKSIZE;
  502. shouldAlloc1 = 0;
  503. }
  504. InBuf = (char *)from;
  505. InBytesLeft = from_len;
  506. OutBytesLeft = _i18nsize1;
  507. OutBuf = (char *)_i18nwork1;
  508. /*
  509. * Need to place iconv state to the initial one by
  510. * setting inbuf to NULL of iconv().
  511. */
  512. iconv( CD, (ICONV_INBUF_TYPE)NULL, 0, NULL, 0 );
  513. while( 1 ) {
  514. /*
  515. * InBuf
  516. * v
  517. * +----------------------------+
  518. * | | | |
  519. * +----------------------------+
  520. * <-------------------------->
  521. * InBytesLeft
  522. *
  523. * |
  524. * | iconv()
  525. * V
  526. * (_i18nwork1)
  527. * OutBuf
  528. * v
  529. * +----------------------------+
  530. * | | | |
  531. * +----------------------------+
  532. * <-------------------------->
  533. * InBytesLeft
  534. */
  535. iconv_ret = iconv( CD, (ICONV_INBUF_TYPE)&InBuf, &InBytesLeft,
  536. &OutBuf, &OutBytesLeft );
  537. if ( iconv_ret == 0 ) {
  538. /* iconv done
  539. * InBuf
  540. * v
  541. * +----------------------------+
  542. * |XXXXXXXXXXXXXXXXXXXXXXXXXXXX|
  543. * +----------------------------+
  544. *
  545. * InBytesLeft=0
  546. *
  547. * (_i18nwork1)
  548. * | OutBuf
  549. * V v
  550. * +----------------------------+
  551. * |XXXXXXXXXXXXXXXXX| | | |
  552. * +----------------------------+
  553. * <---------------> <-------->
  554. * converted_num OutBytesLeft
  555. */
  556. converted_num = (unsigned long)((char *)OutBuf-(char *)_i18nwork1);
  557. *to = (void *)_i18nwork1;
  558. to_len = (unsigned long)converted_num;
  559. break;
  560. } else {
  561. if ( errno == E2BIG ) {
  562. /* Overflow. still data is left.
  563. * InBuf
  564. * v
  565. * +----------------------------+
  566. * |XXXXXXXXXXXXXX| | | |
  567. * +----------------------------+
  568. * <----------->
  569. * InBytesLeft
  570. *
  571. * (_i18nwork1)
  572. * | OutBuf
  573. * V v
  574. * +----------------------------+
  575. * |XXXXXXXXXXXXXXXXXXXXXXXXXXX |
  576. * +----------------------------+
  577. * <------------------------->
  578. * converted_num OutBytesLeft=?
  579. */
  580. void *_p;
  581. /* Check how many converted already. */
  582. converted_num =
  583. (unsigned long)((char *)OutBuf - (char *)_i18nwork1);
  584. _i18nsize1 += WORKSIZE;
  585. _p = realloc( _i18nwork1, _i18nsize1 );
  586. if ( !_p ) {
  587. *to = NULL;
  588. to_len = 0;
  589. free( _i18nwork1 );
  590. _i18nwork1 = NULL;
  591. _i18nsize1 = 0;
  592. shouldAlloc1 = ~0;
  593. break;
  594. } else {
  595. _i18nwork1 = _p;
  596. OutBuf = (char *)((char*)_i18nwork1 + converted_num);
  597. OutBytesLeft += WORKSIZE;
  598. }
  599. } else {
  600. *to = NULL;
  601. to_len = 0;
  602. break;
  603. }
  604. }
  605. }
  606. /*
  607. * Null terminate
  608. */
  609. if ( *to != NULL ) {
  610. if ( _i18nsize1 >= to_len + 1 ) {
  611. ((char *)_i18nwork1)[to_len] = '\0';
  612. } else {
  613. void *_p;
  614. _i18nsize1++;
  615. _p = realloc( _i18nwork1, _i18nsize1 );
  616. if ( !_p ) {
  617. *to = NULL;
  618. to_len = 0;
  619. free( _i18nwork1 );
  620. _i18nwork1 = NULL;
  621. _i18nsize1 = 0;
  622. shouldAlloc1 = ~0;
  623. } else {
  624. _i18nwork1 = _p;
  625. ((char *)_i18nwork1)[to_len] = '\0';
  626. }
  627. }
  628. }
  629. }
  630. /*
  631. * Iconv for buffer
  632. */
  633. static
  634. int IconvBuffer(
  635. VolumeHandle helpVolumeHandle,
  636. char *src,
  637. char **dest )
  638. { /*$CODE$*/
  639. #define CUR_LOCALE 0
  640. #define CUR_CODESET 1
  641. #define VOL_LOCALE 2
  642. #define VOL_CODESET 3
  643. #define FROM_CODESET 4
  644. #define TO_CODESET 5
  645. #define NUMSTRS 6
  646. int ret;
  647. int i;
  648. char * loc[NUMSTRS];
  649. char * codeset;
  650. char buf[1000];
  651. static int isFirst = ~0;
  652. static iconv_t CD = (iconv_t)-1;
  653. for (i=0; i<NUMSTRS; i++) loc[i] = NULL;
  654. /* get the normalized current codeset */
  655. _DtHelpCeGetLcCtype(&loc[CUR_LOCALE], NULL, &loc[CUR_CODESET]);
  656. /* get the normalized volume codeset */
  657. loc[VOL_LOCALE] = _DtHelpCeGetVolumeLocale(helpVolumeHandle);
  658. /* codeset begins after the '.'; find it */
  659. codeset = NULL;
  660. if ( loc[VOL_LOCALE]
  661. && _DtHelpCeStrchr(loc[VOL_LOCALE], ".", 1, &codeset) == 0)
  662. {
  663. codeset++;
  664. }
  665. loc[VOL_CODESET] = (NULL != codeset ? strdup(codeset) : NULL);
  666. /* if either locale is NULL or if they are the same string
  667. then don't iconv the file */
  668. if ( NULL == loc[CUR_CODESET]
  669. || NULL == loc[VOL_CODESET]
  670. || strcmp(loc[CUR_CODESET],loc[VOL_CODESET]) == 0 )
  671. {
  672. ret = 0; /* RETURN: no iconv needed/possible */
  673. goto cleanup;
  674. }
  675. /* get the source codeset */
  676. loc[FROM_CODESET] = strdup(loc[VOL_LOCALE]);
  677. /* get the target codeset */
  678. loc[TO_CODESET] = strdup(loc[CUR_LOCALE]);
  679. if ( isFirst ) {
  680. CD = iconv_open( loc[TO_CODESET], loc[FROM_CODESET] );
  681. isFirst = 0;
  682. }
  683. if ( CD == (iconv_t)-1 ) {
  684. ret = 0;
  685. } else {
  686. ret = 1;
  687. _converter_( CD, (void *)src, (unsigned long)strlen( src ),
  688. (void **)dest );
  689. if ( *dest == NULL )
  690. ret = 0;
  691. }
  692. cleanup:
  693. /* free memory */
  694. for (i=0; i<NUMSTRS; i++) if (loc[i]) free(loc[i]);
  695. return ret;
  696. } /* count lines */
  697. #if DOC
  698. ===================================================================
  699. $PFUNBEG$: OpenTmpFile()
  700. $1LINER$: Opens temporary file
  701. $DESCRIPT$:
  702. opens a temporary file
  703. $RETURNS$:
  704. $ARGS$:
  705. ========================================================$SKIP$=====*/
  706. #endif /*DOC*/
  707. static
  708. FILE * OpenTmpFile(
  709. _DtHPrOptions * options,
  710. char * * ret_tmpFile)
  711. { /*$CODE$*/
  712. FILE * fp;
  713. /* Put in $HOME/.dt/tmp so that if the printer operation is running
  714. of a remote system, it can get to the (local) temp file.
  715. This would not be possible if the file were put in /tmp */
  716. *ret_tmpFile = _DtHPrCreateTmpFile(TMPFILE_PREFIX,TMPFILE_SUFFIX);
  717. if (NULL == *ret_tmpFile) return NULL; /* RETURN: error */
  718. fp = fopen(*ret_tmpFile,"w");
  719. if (NULL == fp)
  720. {
  721. fprintf(stderr,_DTGETMESSAGE(PTSET,6,
  722. "%s Error: unable to open temporary file %s\n"),
  723. options->programName, *ret_tmpFile);
  724. }
  725. return fp;
  726. } /* open tmp file */
  727. #if DOC
  728. ===================================================================
  729. $PFUNBEG$: CountLines()
  730. $1LINER$: counters number of CRs in a string
  731. $DESCRIPT$:
  732. counters number of CRs in a string
  733. $RETURNS$:
  734. $ARGS$:
  735. ========================================================$SKIP$=====*/
  736. #endif /*DOC*/
  737. static
  738. int CountLines(
  739. char * str)
  740. { /*$CODE$*/
  741. char * substr;
  742. int lineCount = 0;
  743. static char * newLine = "\n";
  744. substr = str;
  745. while( _DtHelpCeStrchr(substr,newLine,MB_CUR_MAX,&substr) == 0 )
  746. {
  747. lineCount++;
  748. substr++;
  749. }
  750. /* return line count to caller */
  751. return lineCount;
  752. } /* count lines */
  753. #if DOC
  754. ===================================================================
  755. $PFUNBEG$: AvailContentLines()
  756. $1LINER$: count number of lines available between top of page & footer
  757. $DESCRIPT$:
  758. Count number of lines available between top of page & footer
  759. $RETURNS$:
  760. $ARGS$:
  761. ========================================================$SKIP$=====*/
  762. #endif /*DOC*/
  763. int AvailContentLines(
  764. _DtHPrOptions * options,
  765. PrintState * state,
  766. HeadFootFormat * hff)
  767. { /*$DEF$*/
  768. return options->rowsTextHeight -
  769. ( (state->curPageNumber % 2) == 0
  770. ? hff->evenFooterLineCnt
  771. : hff->oddFooterLineCnt);
  772. } /*$END$*/
  773. #if DOC
  774. ===================================================================
  775. $PFUNBEG$: SectNumStr()
  776. $1LINER$: generates string ver of section number
  777. $DESCRIPT$:
  778. generates string ver of section number
  779. $RETURNS$:
  780. $ARGS$:
  781. buf: must be at least 4 * MAXSECTS chars long
  782. ========================================================$SKIP$=====*/
  783. #endif /*DOC*/
  784. static
  785. char * SectNumStr(
  786. int * sectNums,
  787. char * sectStr,
  788. char * buf)
  789. { /*$CODE$*/
  790. char partial[5];
  791. /* recall: if sectNums[0] == 0, then no section number is defined
  792. and none should be printed; try sectStr as alternate. */
  793. /* generate the section number */
  794. buf[0] = EOS;
  795. if (sectNums && sectNums[0] != 0 )
  796. {
  797. int sect;
  798. for ( sect = 1; sectNums[sect] != 0; sect++ )
  799. {
  800. sprintf(partial, "%d.", sectNums[sect]);
  801. strcat(buf,partial);
  802. }
  803. }
  804. else /* if no section number, take the section string, if avail */
  805. {
  806. if (sectStr) strcpy(buf,sectStr);
  807. else buf[0] = EOS;
  808. }
  809. return buf;
  810. } /*$END$*/
  811. #if DOC
  812. ===================================================================
  813. $PFUNBEG$: OutputBlankSpaces()
  814. $1LINER$: Outputs blank Spaces
  815. $DESCRIPT$:
  816. Outputs blank Spaces
  817. $RETURNS$:
  818. $ARGS$:
  819. topicsFP: pointer to output stream. If NULL, do nothing
  820. ========================================================$SKIP$=====*/
  821. #endif /*DOC*/
  822. static
  823. void OutputBlankSpaces(
  824. FILE * topicsFP,
  825. int spaceCount)
  826. { /*$CODE$*/
  827. if (NULL == topicsFP || spaceCount < 0) return;
  828. while (spaceCount--) fprintf(topicsFP," ");
  829. } /* $END$ */
  830. #if DOC
  831. ===================================================================
  832. $PFUNBEG$: OutputBlankLines()
  833. $1LINER$: Outputs blank lines
  834. $DESCRIPT$:
  835. Outputs blank lines
  836. $RETURNS$:
  837. $ARGS$:
  838. topicsFP: pointer to output stream. If NULL, do nothing
  839. ========================================================$SKIP$=====*/
  840. #endif /*DOC*/
  841. static
  842. void OutputBlankLines(
  843. FILE * topicsFP,
  844. PrintState * state,
  845. int lineCount)
  846. { /*$CODE$*/
  847. if (lineCount < 0) return; /* RETURN */
  848. state->curLineNumber += lineCount;
  849. if (NULL == topicsFP) return; /* RETURN */
  850. while (lineCount--) fprintf(topicsFP,"\n");
  851. } /* $END$ */
  852. #if DOC
  853. ===================================================================
  854. $PFUNBEG$: DoStrColsWidth()
  855. $1LINER$: Calculates number of cols used by a string; truncate if needed
  856. $DESCRIPT$:
  857. Calculates the number of cols used by the string and truncates
  858. the string to the specified maxWidth if this is exceeded.
  859. $NOTE$:
  860. $RETURNS$:
  861. The number of columns this string requires for printing.
  862. $ARGS$:
  863. ========================================================$SKIP$=====*/
  864. #endif /*DOC*/
  865. static
  866. int DoStrColsWidth(
  867. char * str,
  868. int maxWidth,
  869. Boolean truncateStr)
  870. { /*$CODE$*/
  871. int len;
  872. wchar_t * wcstr;
  873. int wclen;
  874. int width;
  875. /* alloc memory for the wchar_t string */
  876. len = strlen(str);
  877. wcstr = malloc(sizeof(wchar_t) * (len+1));
  878. /* convert str to wchar_t and get width in chars */
  879. mbstowcs(wcstr,str,len+1);
  880. wclen = wcslen(wcstr);
  881. /* get col width of the string and truncate if necessary */
  882. while ( (width = wcswidth(wcstr,wclen+1)) > maxWidth
  883. && truncateStr == True)
  884. wcstr[--wclen] = EOS;
  885. wcstombs(str,wcstr,len+1);
  886. free(wcstr);
  887. return wclen;
  888. } /*$END$*/
  889. #if DOC
  890. ===================================================================
  891. $PFUNBEG$: GenHeadFootFormatArgs()
  892. $1LINER$: Generates args used by a header/footer format string
  893. $DESCRIPT$:
  894. Generates args used by a header/footer format string
  895. $NOTE$:
  896. $RETURNS$:
  897. $ARGS$:
  898. ========================================================$SKIP$=====*/
  899. #endif /*DOC*/
  900. static
  901. void GenHeadFootFormatArgs(
  902. _DtHPrOptions * options,
  903. PrintState * state,
  904. Boolean updateTopicTitle,
  905. char * sectNumStr,
  906. Boolean updatePageNum)
  907. { /*$CODE$*/
  908. char * str;
  909. int width;
  910. time_t date = 0;
  911. struct tm * pTm;
  912. char buf[100];
  913. /* get the volume title and its size */
  914. if (NULL == state->hffArgs.volumeTitle)
  915. {
  916. /* get the volume title */
  917. str = NULL;
  918. _DtHelpCeGetVolumeTitle(state->canvasHandle,state->volHandle,&str);
  919. if (NULL == str) str = strdup("");
  920. width = DoStrColsWidth(str,MAXVOLTITLEWIDTH,True);
  921. /* put into state data */
  922. state->hffArgs.volumeTitle = str;
  923. state->hffArgs.volumeTitleColsWidth = width;
  924. }
  925. /* get the volume's date */
  926. if (NULL == state->hffArgs.volumeDate)
  927. {
  928. char * locDocId = NULL;
  929. char * locDateStamp = NULL;
  930. long long_date = 0;
  931. /* locDocId & locDateStamp will point to private memory; do not modify */
  932. _DtHelpCeGetDocStamp(state->volHandle,&locDocId, &locDateStamp);
  933. if ( NULL != locDateStamp
  934. && sscanf(locDateStamp, "%ld", &long_date) != 1 )
  935. locDateStamp = NULL; /* make invalid */
  936. else
  937. date = (time_t)long_date;
  938. /* if no vol date, try getting from the help volume file */
  939. if ( NULL == locDateStamp )
  940. {
  941. struct stat stats;
  942. date = 0;
  943. if ( stat(options->helpVolume,&stats) == 0 )
  944. date = stats.st_mtime;
  945. }
  946. /* convert the int into a string */
  947. pTm = localtime(&date);
  948. strftime(buf,sizeof(buf),"%x",pTm);
  949. width = DoStrColsWidth(buf,0,False);
  950. /* put into state data */
  951. state->hffArgs.volumeDate = strdup(buf);
  952. state->hffArgs.volumeDateColsWidth = width;
  953. free(locDocId);
  954. free(locDateStamp);
  955. }
  956. /* get today's date */
  957. if (NULL == state->hffArgs.todaysDate)
  958. {
  959. /* convert the int into a string */
  960. date = time(NULL);
  961. pTm = localtime(&date);
  962. strftime(buf,sizeof(buf),"%x",pTm);
  963. width = DoStrColsWidth(buf,0,False);
  964. /* put into state data */
  965. state->hffArgs.todaysDate = strdup(buf);
  966. state->hffArgs.todaysDateColsWidth = width;
  967. }
  968. /* get the topic title and its size */
  969. if (updateTopicTitle)
  970. {
  971. /* get the topic title */
  972. str = NULL;
  973. _DtHelpCeGetTopicTitle(state->canvasHandle, state->volHandle,
  974. state->currentLocId, &str);
  975. if (NULL == str) str = strdup("");
  976. width = DoStrColsWidth(str,MAXTOPICTITLEWIDTH,True);
  977. /* put into state data */
  978. if (state->hffArgs.topicTitle) free(state->hffArgs.topicTitle);
  979. state->hffArgs.topicTitle = str;
  980. state->hffArgs.topicTitleColsWidth = width;
  981. }
  982. /* get the size of the section number */
  983. if (sectNumStr)
  984. {
  985. width = DoStrColsWidth(sectNumStr,0,False);
  986. state->hffArgs.sectNumColsWidth = width;
  987. }
  988. /* get the size of the page number */
  989. if (updatePageNum)
  990. {
  991. int num;
  992. for ( width = 1, num = state->curPageNumber;
  993. (num >= 0) && ((num / 10) > 0);
  994. num /= 10, width++ )
  995. { /* do nothing */ }
  996. state->hffArgs.pageNumColsWidth = width;
  997. }
  998. } /*$END$*/
  999. #if DOC
  1000. ===================================================================
  1001. $PFUNBEG$: GenHeadFootFormatStr()
  1002. $1LINER$: Generates a printf-ready format string for the header/footer
  1003. $DESCRIPT$:
  1004. Generates a printf-ready format string for the header/footer
  1005. $NOTE$:
  1006. This function generates a string that uses the "%n$" prefix
  1007. supported by printf(3S) to allow a footer/header string to
  1008. ref any argument out of order. This functionality requires
  1009. that a ref to *every* argument be part of the format string.
  1010. Because not all args may be part of the user-specified format
  1011. string, this function appends the unused strings to the end
  1012. of the format string for purposes of sprintf(), then truncates
  1013. the unused portion before output.
  1014. $RETURNS$:
  1015. $ARGS$:
  1016. ========================================================$SKIP$=====*/
  1017. #endif /*DOC*/
  1018. static
  1019. void GenHeadFootFormatStr(
  1020. char * specStr,
  1021. char * * io_formattedStr,
  1022. int * io_lineCnt)
  1023. { /*$CODE$*/
  1024. char * lowLevelFormatStr;
  1025. SymValue * sym;
  1026. char * substr;
  1027. char unusedSyms[60];
  1028. if (NULL == specStr)
  1029. {
  1030. *io_formattedStr = NULL;
  1031. *io_lineCnt = 0;
  1032. return; /* RETURN */
  1033. }
  1034. /*** create the formatted string ***/
  1035. /* Make a working copy of the string; I assume that the
  1036. values of 'argref' string always be shorter than 'symbol'. */
  1037. lowLevelFormatStr = malloc(strlen(specStr) + sizeof(unusedSyms) + 10);
  1038. if (NULL == lowLevelFormatStr) return;
  1039. strcpy(lowLevelFormatStr,specStr);
  1040. /* replace the symbolic names with printf argument refs */
  1041. strcpy(unusedSyms,UNUSED_ARGREF);
  1042. for ( sym = g_HeadFootSymsList; sym->symbol != NULL; sym++ )
  1043. {
  1044. Boolean unused = True;
  1045. /* look for the symbol string */
  1046. while ( (substr = strstr(lowLevelFormatStr,sym->symbol)) != NULL )
  1047. { /* and replace it with the argref */
  1048. unused = False;
  1049. strcpy(substr, sym->argref);
  1050. strcpy(substr + strlen(sym->argref), substr + strlen(sym->symbol));
  1051. }
  1052. /* if unused, add to unused list */
  1053. if (unused) strcat(unusedSyms,sym->argref);
  1054. }
  1055. /* append unused syms to end of format str */
  1056. strcat(lowLevelFormatStr,unusedSyms);
  1057. /* store in caller's location */
  1058. *io_formattedStr = lowLevelFormatStr;
  1059. *io_lineCnt = CountLines(lowLevelFormatStr);
  1060. } /*$END$*/
  1061. #if DOC
  1062. ===================================================================
  1063. $PFUNBEG$: GenAllHeadFootFormatStrs()
  1064. $1LINER$: Generates printf-ready format strings for all headers/footers
  1065. $DESCRIPT$:
  1066. Generates printf-ready format strings for all headers/footers
  1067. $NOTE$:
  1068. $RETURNS$:
  1069. $ARGS$:
  1070. ========================================================$SKIP$=====*/
  1071. #endif /*DOC*/
  1072. static
  1073. void GenAllHeadFootFormatStrs(
  1074. _DtHPrOptions * options,
  1075. PrintState * state)
  1076. { /*$CODE$*/
  1077. /* Toc */
  1078. GenHeadFootFormatStr(options->tocHF.evenHeader,
  1079. &state->tocHFF.formattedEvenHeader, &state->tocHFF.evenHeaderLineCnt);
  1080. GenHeadFootFormatStr(options->tocHF.oddHeader,
  1081. &state->tocHFF.formattedOddHeader, &state->tocHFF.oddHeaderLineCnt);
  1082. GenHeadFootFormatStr(options->tocHF.evenFooter,
  1083. &state->tocHFF.formattedEvenFooter, &state->tocHFF.evenFooterLineCnt);
  1084. GenHeadFootFormatStr(options->tocHF.oddFooter,
  1085. &state->tocHFF.formattedOddFooter, &state->tocHFF.oddFooterLineCnt);
  1086. /* Body */
  1087. GenHeadFootFormatStr(options->bodyHF.evenHeader,
  1088. &state->bodyHFF.formattedEvenHeader, &state->bodyHFF.evenHeaderLineCnt);
  1089. GenHeadFootFormatStr(options->bodyHF.oddHeader,
  1090. &state->bodyHFF.formattedOddHeader, &state->bodyHFF.oddHeaderLineCnt);
  1091. GenHeadFootFormatStr(options->bodyHF.evenFooter,
  1092. &state->bodyHFF.formattedEvenFooter, &state->bodyHFF.evenFooterLineCnt);
  1093. GenHeadFootFormatStr(options->bodyHF.oddFooter,
  1094. &state->bodyHFF.formattedOddFooter, &state->bodyHFF.oddFooterLineCnt);
  1095. /* Index */
  1096. GenHeadFootFormatStr(options->indexHF.evenHeader,
  1097. &state->indexHFF.formattedEvenHeader, &state->indexHFF.evenHeaderLineCnt);
  1098. GenHeadFootFormatStr(options->indexHF.oddHeader,
  1099. &state->indexHFF.formattedOddHeader, &state->indexHFF.oddHeaderLineCnt);
  1100. GenHeadFootFormatStr(options->indexHF.evenFooter,
  1101. &state->indexHFF.formattedEvenFooter, &state->indexHFF.evenFooterLineCnt);
  1102. GenHeadFootFormatStr(options->indexHF.oddFooter,
  1103. &state->indexHFF.formattedOddFooter, &state->indexHFF.oddFooterLineCnt);
  1104. } /*$END$*/
  1105. #if DOC
  1106. ===================================================================
  1107. $PFUNBEG$: PrintHeadFootStr()
  1108. $1LINER$: Formats and prints the header/footer string
  1109. $DESCRIPT$:
  1110. Takes a format string, replaces the place holders with actual values,
  1111. and prints the output to topicsFP.
  1112. $NOTE$:
  1113. This function uses the "%n$" prefix supported by printf(3S)
  1114. to allow a footer/header string to ref any argument out of
  1115. order. This functionality requires that a ref to *every*
  1116. argument be part of the format string. Because not all args
  1117. may be part of the user-specified format string, this function
  1118. appends the unused strings to the end of the format string
  1119. for purposes of sprintf(), then truncates the unused portion
  1120. before output.
  1121. $RETURNS$:
  1122. number of lines in the header or footer
  1123. $ARGS$:
  1124. topicsFP: pointer to output stream. If NULL, increment
  1125. page and reset line number), but do not output;
  1126. If not NULL, request new page as well
  1127. ========================================================$SKIP$=====*/
  1128. #endif /*DOC*/
  1129. static
  1130. int PrintHeadFootStr(
  1131. _DtHPrOptions * options,
  1132. FILE * topicsFP,
  1133. PrintState * state,
  1134. char * formattedStr,
  1135. int lineCnt)
  1136. { /*$CODE$*/
  1137. char * newLine = "\n";
  1138. int lastValid = 0;
  1139. char sectNumStr[MAXSECTS * 4 + 5]; /* $SECTNUM */
  1140. char buf[3000];
  1141. if (NULL == formattedStr) return 0; /* RETURN */
  1142. if (NULL == topicsFP) return lineCnt; /* RETURN */
  1143. /*** generate dynamic data ***/
  1144. /* get the section number */
  1145. SectNumStr(state->sectNums,state->sectStr,sectNumStr);
  1146. /* update args; FIX: impove efficiency by processing topic title only when needed */
  1147. GenHeadFootFormatArgs(options,state,True,sectNumStr,True);
  1148. /* guidelines on string size and construction:
  1149. The objective is to allow one set of headers & footers to apply
  1150. to many different volumes and topics. This is made possible by
  1151. allowing for fixed length strings. To get fixed length strings,
  1152. the header/footer spec should include not only the string but
  1153. also the fill for that string.
  1154. The fill size is calculated based on the following widths:
  1155. volTitle : 50 printing chars e.g. "title "
  1156. topicTitle : 50 printing chars e.g. "title "
  1157. sectNumStr : 8 printing chars e.g. " 3.10.4"
  1158. pageNum : 3 printing chars e.g. " 3"
  1159. volDate : constant by locale--no fill needed e.g. "Mon, Jul 4, 1988"
  1160. dateStr : constant by locale--no fill needed e.g. "Mon, Jul 4, 1988"
  1161. */
  1162. /*** generate the str ***/
  1163. /* IMPT: the order of these arguments MUST match the argument numbers
  1164. given in the definition of the g_HeadFootSymsList variable. */
  1165. /* print the first set */
  1166. sprintf(buf, formattedStr,
  1167. state->hffArgs.todaysDate,state->hffArgs.volumeTitle,
  1168. state->hffArgs.topicTitle, (int) state->curPageNumber,
  1169. state->hffArgs.volumeDate, sectNumStr,
  1170. (int) options->colsAdjLeftMargin,(int) ' ' );
  1171. /* move the format string for the second set into new memory */
  1172. formattedStr = strdup(buf);
  1173. if(NULL == formattedStr) return 0; /* RETURN */
  1174. /* print the second set */
  1175. sprintf(buf, formattedStr,
  1176. MAXVOLTITLEWIDTH - state->hffArgs.volumeTitleColsWidth, (int) ' ',
  1177. MAXTOPICTITLEWIDTH - state->hffArgs.topicTitleColsWidth, (int) ' ',
  1178. MAXPAGENUMWIDTH - state->hffArgs.pageNumColsWidth, (int) ' ',
  1179. MAXSECTNUMWIDTH - state->hffArgs.sectNumColsWidth, (int) ' ',
  1180. &lastValid);
  1181. buf[lastValid] = EOS; /* truncate unused args */
  1182. free(formattedStr);
  1183. /*** output the str ***/
  1184. fprintf(topicsFP, "%s", buf);
  1185. return lineCnt;
  1186. } /*$END$*/
  1187. #if DOC
  1188. ===================================================================
  1189. $PFUNBEG$: PrintFooter()
  1190. $1LINER$: Print footer and use right form for odd/even pages
  1191. $DESCRIPT$:
  1192. Print footer and use right form for odd/even pages
  1193. $RETURNS$:
  1194. $ARGS$:
  1195. topicsFP: pointer to output stream. If NULL, increment
  1196. lines), but do not output;
  1197. ========================================================$SKIP$=====*/
  1198. #endif /*DOC*/
  1199. static
  1200. void PrintFooter(
  1201. _DtHPrOptions * options,
  1202. FILE * topicsFP,
  1203. PrintState * state,
  1204. _DtHPrHeadFoot * headFootInfo,
  1205. HeadFootFormat * headFootFormatting)
  1206. { /*$CODE$*/
  1207. /* fill to bottom of page */
  1208. OutputBlankLines(topicsFP,state,
  1209. (options->rowsTextHeight - state->curLineNumber) -
  1210. ( (state->curPageNumber % 2) == 0
  1211. ? headFootFormatting->evenFooterLineCnt
  1212. : headFootFormatting->oddFooterLineCnt));
  1213. if ( (state->curPageNumber % 2) == 0) /* Even page */
  1214. state->curLineNumber += PrintHeadFootStr(options,topicsFP,state,
  1215. headFootFormatting->formattedEvenFooter,
  1216. headFootFormatting->evenFooterLineCnt);
  1217. else /* odd page */
  1218. state->curLineNumber += PrintHeadFootStr(options,topicsFP,state,
  1219. headFootFormatting->formattedOddFooter,
  1220. headFootFormatting->oddFooterLineCnt);
  1221. } /*$END$*/
  1222. #if DOC
  1223. ===================================================================
  1224. $PFUNBEG$: PrintHeader()
  1225. $1LINER$: Print footer and use right form for odd/even pages
  1226. $DESCRIPT$:
  1227. Print footer and use right form for odd/even pages
  1228. $RETURNS$:
  1229. $ARGS$:
  1230. topicsFP: pointer to output stream. If NULL, increment
  1231. lines), but do not output;
  1232. ========================================================$SKIP$=====*/
  1233. #endif /*DOC*/
  1234. static
  1235. void PrintHeader(
  1236. _DtHPrOptions * options,
  1237. FILE * topicsFP,
  1238. PrintState * state,
  1239. _DtHPrHeadFoot * headFootInfo,
  1240. HeadFootFormat * headFootFormatting)
  1241. { /*$CODE$*/
  1242. if ( (state->curPageNumber % 2) == 0) /* Even page */
  1243. state->curLineNumber += PrintHeadFootStr(options,topicsFP,state,
  1244. headFootFormatting->formattedEvenHeader,
  1245. headFootFormatting->evenHeaderLineCnt);
  1246. else
  1247. state->curLineNumber += PrintHeadFootStr(options,topicsFP,state,
  1248. headFootFormatting->formattedOddHeader,
  1249. headFootFormatting->oddHeaderLineCnt);
  1250. } /*$END$*/
  1251. #if DOC
  1252. ===================================================================
  1253. $PFUNBEG$: NewPage()
  1254. $1LINER$: Outputs paper form feed, increments page count, resets line cnt
  1255. $DESCRIPT$:
  1256. Outputs paper form feed, increments page count, resets line cnt
  1257. $RETURNS$:
  1258. $ARGS$:
  1259. topicsFP: pointer to output stream. If NULL, increment
  1260. page and reset line number), but do not output;
  1261. If not NULL, request new page as well
  1262. ========================================================$SKIP$=====*/
  1263. #endif /*DOC*/
  1264. static
  1265. void NewPage(
  1266. _DtHPrOptions * options,
  1267. FILE * topicsFP,
  1268. PrintState * state,
  1269. Boolean advancePage)
  1270. { /*$CODE$*/
  1271. /* start new page: form feed */
  1272. if (topicsFP)
  1273. {
  1274. if (advancePage) fprintf(topicsFP," \n");
  1275. /* print top margin but don't add it to line count because the rowsTextHeight
  1276. value is calculated post-topMargin */
  1277. OutputBlankLines(topicsFP,state,options->rowsAdjTopMargin);
  1278. }
  1279. /* adjust page and line numbers */
  1280. if (advancePage) state->curPageNumber++;
  1281. state->curLineNumber = 1;
  1282. } /*$END$*/
  1283. #if DOC
  1284. ===================================================================
  1285. $PFUNBEG$: ProcessOneTopic()
  1286. $1LINER$: Recovers and formats help text for one topic
  1287. $DESCRIPT$:
  1288. Recovers and formats help text for one topic
  1289. $RETURNS$:
  1290. 0: The number of lines output.
  1291. -2: could not get topic information
  1292. $ARGS$:
  1293. topicsFP: pointer to output stream. If NULL, process topic
  1294. (e.g. count lines and inc page numbers), but do not output;
  1295. If not NULL, output lines and page headers
  1296. ========================================================$SKIP$=====*/
  1297. #endif /*DOC*/
  1298. static
  1299. int ProcessOneTopic(
  1300. _DtHPrOptions * options,
  1301. FILE * topicsFP,
  1302. PrintState * state,
  1303. Boolean printHeaderFooter)
  1304. { /*$CODE$*/
  1305. char * * helpList = NULL;
  1306. char * * ptrToLst;
  1307. int lineCount;
  1308. int availLines;
  1309. char sectNumStr[MAXSECTS * 4 + 5];
  1310. /* retrieve the text (but not the hyperlinks) from the volume */
  1311. if ( _DtHelpTermGetTopicData(state->canvasHandle, state->volHandle,
  1312. state->currentLocId, &helpList, NULL) != 0 )
  1313. {
  1314. fprintf(stderr,_DTGETMESSAGE(PTSET,5,
  1315. "%s Error: unable to get topic information:\n"
  1316. "volume %s, locationId %s\n"),
  1317. options->programName, options->helpVolume, options->locationId);
  1318. return -2; /* RETURN error */
  1319. }
  1320. /* output topic section number */
  1321. /* this operates on the assumption that topic title is first line */
  1322. ptrToLst = helpList;
  1323. SectNumStr(state->sectNums,state->sectStr,sectNumStr);
  1324. if (sectNumStr[0] != EOS)
  1325. {
  1326. /* NOTE: if allow the sect num string to be resource-defined,
  1327. then count the number of \n chars in it; don't assume how many. */
  1328. if (topicsFP) fprintf(topicsFP,"\n");
  1329. OutputBlankSpaces(topicsFP,options->colsAdjLeftMargin);
  1330. if (topicsFP) fprintf(topicsFP,"%s ", sectNumStr);
  1331. state->curLineNumber++;
  1332. /* and put the title (must be on first two lines) on the same line */
  1333. if ( (*helpList && (*helpList)[0] != EOS)
  1334. || (*(++helpList) && (*helpList)[0] != EOS) )
  1335. {
  1336. if (topicsFP) {
  1337. char *_p;
  1338. int ret;
  1339. ret = IconvBuffer( state->volHandle, *helpList, &_p );
  1340. if ( ret ) {
  1341. fprintf(topicsFP,"%s\n", _p); /* output title */
  1342. } else {
  1343. fprintf(topicsFP,"%s\n", *helpList); /* output title */
  1344. }
  1345. }
  1346. state->curLineNumber += CountLines(*helpList) + 1; /* 1=the known \n */
  1347. helpList++;
  1348. }
  1349. }
  1350. /* calc number of available lines from top of page to footer */
  1351. availLines = AvailContentLines(options,state,&state->bodyHFF);
  1352. /* cycle through the lines; add new pages where necessary */
  1353. for ( ; *helpList != NULL; helpList++ )
  1354. {
  1355. /* NOTE: it's impt to calc the final line before outputting it,
  1356. as the line may contain embedded newlines */
  1357. int linesCnt = CountLines(*helpList) + 1; /* 1=the known \n */
  1358. /* calc what line that will leave us on */
  1359. state->curLineNumber += linesCnt;
  1360. /* if at the end of a page, print footer, eject, and print header */
  1361. if (state->curLineNumber >= availLines)
  1362. {
  1363. /* output any filler blank lines */
  1364. OutputBlankLines(topicsFP,state,
  1365. availLines - (state->curLineNumber - linesCnt) );
  1366. if (printHeaderFooter)
  1367. PrintFooter(options,topicsFP,state,&options->bodyHF,&state->bodyHFF);
  1368. NewPage(options,topicsFP,state,True);
  1369. if (printHeaderFooter)
  1370. PrintHeader(options,topicsFP,state,&options->bodyHF,&state->bodyHFF);
  1371. /* recalc the line we're on */
  1372. state->curLineNumber += linesCnt;
  1373. /* calc number of available lines from top of page to footer */
  1374. availLines = AvailContentLines(options,state,&state->bodyHFF);
  1375. }
  1376. /* output the lines */
  1377. if (topicsFP)
  1378. {
  1379. OutputBlankSpaces(topicsFP,options->colsAdjLeftMargin);
  1380. {
  1381. char *_p;
  1382. int ret;
  1383. ret = IconvBuffer( state->volHandle, *helpList, &_p );
  1384. if ( ret ) {
  1385. fprintf(topicsFP,"%s\n", _p );
  1386. } else {
  1387. fprintf(topicsFP,"%s\n",*helpList);
  1388. }
  1389. }
  1390. }
  1391. }
  1392. /* free the memory of helpList */
  1393. _DtHelpFreeTopicData(ptrToLst,NULL);
  1394. return 0;
  1395. } /*$END$*/
  1396. #if DOC
  1397. ===================================================================
  1398. $PFUNBEG$: ProcessSubTopics()
  1399. $1LINER$: Recovers and formats help text for current & sub topics
  1400. $DESCRIPT$:
  1401. ond none should be printed. */
  1402. Subsections are numbered according to the legal method (e.g. 1.5.4.3)
  1403. Recovers and formats help text for current & sub topics
  1404. $RETURNS$:
  1405. 0: success
  1406. -1: could not create or open a temp file
  1407. -2: could not get help topic info
  1408. INHIBIT_OUTPUT: stop outputting children; we printed all we need to
  1409. $ARGS$:
  1410. level: may range from 1 to (MAXSECTS-1)
  1411. ========================================================$SKIP$=====*/
  1412. #endif /*DOC*/
  1413. static
  1414. int ProcessSubTopics(
  1415. _DtHPrOptions * options,
  1416. FILE * topicsFP,
  1417. Toc * toc,
  1418. int level,
  1419. PrintState * state)
  1420. { /*$CODE$*/
  1421. char * * children = NULL;
  1422. int ret = 0;
  1423. int firstSubSectNum;
  1424. int subSectNumIndex;
  1425. FILE * curFP;
  1426. #define INHIBIT_OUTPUT (-3)
  1427. /* remember, don't turn inhibitOutput on if there's no match */
  1428. if ( _DtHelpCeStrCaseCmp(state->outputFromLocId,state->currentLocId) == 0 )
  1429. {
  1430. int curPos;
  1431. /* toggle the flag and set ret value */
  1432. state->inhibitOutput = False;
  1433. ret = INHIBIT_OUTPUT; /* stop printing after this topic & its children */
  1434. curPos = state->curLineNumber; /* save off the current line position */
  1435. /* start new page but don't eject; output header;
  1436. output right number of blank lines to get to where topic starts */
  1437. NewPage(options,topicsFP,state,False);
  1438. PrintHeader(options,topicsFP,state,&options->bodyHF,&state->bodyHFF);
  1439. OutputBlankLines(topicsFP,state,curPos - state->curLineNumber);
  1440. }
  1441. /* init file ptr */
  1442. curFP = (state->inhibitOutput ? (FILE *) NULL : topicsFP);
  1443. /* init according to level */
  1444. if(level == 0) /* the top topic? */
  1445. { /* put top topic at same level as children */
  1446. firstSubSectNum = 2;
  1447. subSectNumIndex = 1;
  1448. state->level = 1;
  1449. /* no prior instance of ProcessSubTopics() set this */
  1450. state->sectNums[subSectNumIndex] = 1;
  1451. }
  1452. else /* not the top topic */
  1453. {
  1454. firstSubSectNum = 1;
  1455. subSectNumIndex = level;
  1456. state->level = level;
  1457. }
  1458. /* add this topic to the toc */
  1459. TocNewEntry(toc,state->currentLocId,state->curPageNumber,
  1460. state->level,state->sectNums,state->sectStr);
  1461. /* retrieve and possibly output the current topic */
  1462. ProcessOneTopic(options,curFP,state,True);
  1463. /* output the sub topics */
  1464. if (_DtHelpCeGetTopicChildren(state->volHandle,
  1465. state->currentLocId,&children) > 0)
  1466. {
  1467. char * * topic;
  1468. Boolean initSubSect = True;
  1469. /* cycle through the topics and output each one */
  1470. for (topic = children; *topic != NULL && (*topic)[0]; topic++ )
  1471. {
  1472. /* start level 0 & 1 topics on a new page */
  1473. if ( subSectNumIndex < 2 )
  1474. {
  1475. PrintFooter(options,curFP,state,&options->bodyHF,&state->bodyHFF);
  1476. NewPage(options,curFP,state,True);
  1477. PrintHeader(options,curFP,state,&options->bodyHF,&state->bodyHFF);
  1478. }
  1479. /* avoid orphans (i.e. require more than 4 lines left on page) */
  1480. if ( (AvailContentLines(options,state,&state->bodyHFF)
  1481. - state->curLineNumber) < 4 )
  1482. {
  1483. PrintFooter(options,curFP,state,&options->bodyHF,&state->bodyHFF);
  1484. NewPage(options,curFP,state,True);
  1485. PrintHeader(options,curFP,state,&options->bodyHF,&state->bodyHFF);
  1486. }
  1487. /* init new sub sect, if haven't yet done so */
  1488. if (initSubSect)
  1489. {
  1490. /* start new subsection; -1: make up for ++ later */
  1491. state->sectNums[subSectNumIndex] = firstSubSectNum - 1;
  1492. initSubSect = False;
  1493. }
  1494. /* make this the current topic */
  1495. state->currentLocId = *topic;
  1496. /* use subSectNumIndex, not level, so that the top topic and its
  1497. immediate children are at the same level */
  1498. /* inc the sect num before the call so that the
  1499. sect used below in the INHIBIT_OUTPUT wrapup is correct. */
  1500. /* pass in topicsFP, not curFP */
  1501. state->sectNums[subSectNumIndex]++; /* next subsection */
  1502. /* even though ProcessSubTopics() can return 'INHIBIT_OUTPUT',
  1503. don't stop processing, as this would cause the Toc to
  1504. be incomplete. */
  1505. ProcessSubTopics(options,topicsFP,toc, subSectNumIndex+1,state);
  1506. /* ProcessSubTopics(options,topicsFP,toc, state->level+1,state); */
  1507. }
  1508. }
  1509. /* if this is the last topic to be output, then finish up */
  1510. if (ret == INHIBIT_OUTPUT)
  1511. {
  1512. /* save off line num */
  1513. int curLine = state->curLineNumber;
  1514. /* output footer */
  1515. PrintFooter(options,curFP,state,&options->bodyHF,&state->bodyHFF);
  1516. state->inhibitOutput = True; /* inhibit again */
  1517. /* restore line num */
  1518. state->curLineNumber = curLine;
  1519. }
  1520. /* if processing subtopics, reset subsection number */
  1521. if(subSectNumIndex > 1) state->sectNums[subSectNumIndex] = 0;
  1522. state->level = level; /* state->level was modified by the FOR loop */
  1523. free(children);
  1524. return ret;
  1525. }
  1526. #if DOC
  1527. ===================================================================
  1528. $PFUNBEG$: ProcessFrontMatter()
  1529. $1LINER$: Process the help volume to generate a file of front matter
  1530. $DESCRIPT$:
  1531. Process the help volume to generate a file of front matter
  1532. $RETURNS$:
  1533. 0: success
  1534. -1: could not create or open a temp file
  1535. -2: could not get help topic info
  1536. $ARGS$:
  1537. ========================================================$SKIP$=====*/
  1538. #endif /*DOC*/
  1539. static
  1540. int ProcessFrontMatter(
  1541. _DtHPrOptions * options,
  1542. char * * ret_resultsFile,
  1543. PrintState * state)
  1544. { /*$CODE$*/
  1545. FILE * fp;
  1546. int ret;
  1547. /* open file */
  1548. fp = OpenTmpFile(options,ret_resultsFile);
  1549. if (NULL == fp) return -1; /* RETURN: error */
  1550. /*** process text ***/
  1551. /* setup the state */
  1552. state->inhibitOutput = False;
  1553. state->curPageNumber = 1;
  1554. state->curLineNumber = 1;
  1555. state->sectNums[0] = 0; /* inhibit section num printing */
  1556. state->sectStr = NULL; /* inhibit section string printing */
  1557. OutputBlankLines(fp,state, options->rowsTextHeight / 3);
  1558. /* NOTE: the code below causes the memory allocated for currentLocId
  1559. to be lost. I didn't fix this to save a few bytes of code space. */
  1560. /* generate volume title */
  1561. state->currentLocId = strdup("_TITLE");
  1562. state->outputFromLocId = state->currentLocId;
  1563. ret = ProcessOneTopic(options,fp,state,False);
  1564. /*free(state->currentLocId);*/
  1565. NewPage(options,fp,state,True);
  1566. /* generate abstract */
  1567. state->currentLocId = strdup("_ABSTRACT");
  1568. state->outputFromLocId = state->currentLocId;
  1569. ret = ProcessOneTopic(options,fp,state,False);
  1570. /*free(state->currentLocId);*/
  1571. /* Make a space between abstract and copyright */
  1572. if ( AvailContentLines(options,state,&state->indexHFF) > 3 )
  1573. OutputBlankLines(fp,state, 3);
  1574. else
  1575. NewPage(options,fp,state,True);
  1576. /* generate copyright */
  1577. state->currentLocId = strdup("_COPYRIGHT");
  1578. state->outputFromLocId = state->currentLocId;
  1579. ret = ProcessOneTopic(options,fp,state,False);
  1580. /*free(state->currentLocId);*/
  1581. /*state->currentLocId = NULL;*/
  1582. if (fp) fclose(fp);
  1583. return ret;
  1584. } /*$END$*/
  1585. #if DOC
  1586. ===================================================================
  1587. $PFUNBEG$: ProcessIndex()
  1588. $1LINER$: Process the TOC data to generate an index file
  1589. $DESCRIPT$:
  1590. Process the TOC data to generate an index file
  1591. $WARNING$:
  1592. This function uses state->pageNumber+1 as the first page
  1593. of the index.
  1594. $RETURNS$:
  1595. 0: success
  1596. -1: could not create or open a temp file
  1597. -2: could not get help topic info
  1598. $ARGS$:
  1599. ========================================================$SKIP$=====*/
  1600. #endif /*DOC*/
  1601. static
  1602. int ProcessIndex(
  1603. _DtHPrOptions * options,
  1604. char * * ret_resultsFile,
  1605. PrintState * state,
  1606. Toc * toc)
  1607. { /*$CODE$*/
  1608. FILE * fp;
  1609. int ret;
  1610. int availLines;
  1611. char * * indexEntriesList;
  1612. char * entryStr;
  1613. int entriesCnt;
  1614. *ret_resultsFile = NULL;
  1615. /* Get the index. Recall that the array and strings pointed to by
  1616. the indexEntriesList is owned by the open volume */
  1617. entriesCnt = _DtHelpCeGetKeywordList(state->volHandle,&indexEntriesList);
  1618. if (entriesCnt <= 0) return 0;
  1619. /* open file */
  1620. fp = OpenTmpFile(options,ret_resultsFile);
  1621. if (NULL == fp) return -1; /* RETURN: error */
  1622. /*** process index ***/
  1623. /* setup the state */
  1624. state->curPageNumber++; /* inc page number from prev. value */
  1625. state->inhibitOutput = False;
  1626. state->curLineNumber = 1;
  1627. state->sectNums[0] = 0; /* inhibit section num printing */
  1628. state->sectStr = _DTGETMESSAGE(PTSET,10,"Index"); /* $SECTNUM name */
  1629. /* add an index entry to the TOC */
  1630. TocNewEntry(toc,_DTGETMESSAGE(PTSET,30,"__GENERATED-INDEX"),
  1631. state->curPageNumber, 1,state->sectNums,state->sectStr);
  1632. /* start new page (but don't eject) and output header */
  1633. NewPage(options,fp,state,False);
  1634. PrintHeader(options,fp,state,&options->indexHF,&state->indexHFF);
  1635. /* calc number of available lines from top of page to footer */
  1636. availLines = AvailContentLines(options,state,&state->indexHFF);
  1637. /*** loop through the entries ***/
  1638. for ( entryStr = *indexEntriesList++;
  1639. NULL != entryStr;
  1640. entryStr = *indexEntriesList++ )
  1641. {
  1642. char * * topicIdsList;
  1643. int topicCnt;
  1644. int i;
  1645. TocEntry * tocEntry;
  1646. /* get the topics associated with this entry */
  1647. /* topicIdsList is set but not allocated & need not be freed */
  1648. topicCnt = _DtHelpCeFindKeyword(state->volHandle,
  1649. entryStr,&topicIdsList);
  1650. if (topicCnt <= 0) continue; /* CONTINUE */
  1651. /*** if only one topic, just put page number after the entry ***/
  1652. if (topicCnt == 1)
  1653. {
  1654. /* find the toc entry of the topic */
  1655. ret = TocFindSortedEntry(toc, *topicIdsList, NULL, &tocEntry);
  1656. if (ret < 0) continue; /* CONTINUE */
  1657. /* output the entry */
  1658. OutputBlankSpaces(fp,options->colsAdjLeftMargin);
  1659. {
  1660. char *_p;
  1661. int ret;
  1662. ret = IconvBuffer( state->volHandle, entryStr, &_p );
  1663. if ( ret ) {
  1664. fprintf(fp, _DTGETMESSAGE(PTSET,20,"%s, %d\n"),
  1665. _p, tocEntry->pageNumber);
  1666. } else {
  1667. fprintf(fp, _DTGETMESSAGE(PTSET,20,"%s, %d\n"),
  1668. entryStr, tocEntry->pageNumber);
  1669. }
  1670. }
  1671. state->curLineNumber++;
  1672. /* if at the end of a page, print footer, eject, and print header */
  1673. if (state->curLineNumber >= availLines)
  1674. {
  1675. PrintFooter(options,fp,state,&options->indexHF,&state->indexHFF);
  1676. NewPage(options,fp,state,True);
  1677. PrintHeader(options,fp,state,&options->indexHF,&state->indexHFF);
  1678. /* calc number of available lines from top of page to footer */
  1679. availLines = AvailContentLines(options,state,&state->indexHFF);
  1680. }
  1681. continue; /* CONTINUE */
  1682. }
  1683. /*** if more than one topic, list topic title & page number under the entry ***/
  1684. /* do we need a new page to start this entry? */
  1685. if ( (availLines - state->curLineNumber) < 3 )
  1686. {
  1687. PrintFooter(options,fp,state,&options->indexHF,&state->indexHFF);
  1688. NewPage(options,fp,state,True);
  1689. PrintHeader(options,fp,state,&options->indexHF,&state->indexHFF);
  1690. /* calc number of available lines from top of page to footer */
  1691. availLines = AvailContentLines(options,state,&state->indexHFF);
  1692. }
  1693. OutputBlankSpaces(fp,options->colsAdjLeftMargin);
  1694. {
  1695. char *_p;
  1696. int ret;
  1697. ret = IconvBuffer( state->volHandle, entryStr, &_p );
  1698. if ( ret ) {
  1699. fprintf(fp,"%s\n", _p );
  1700. } else {
  1701. fprintf(fp,"%s\n", entryStr);
  1702. }
  1703. }
  1704. state->curLineNumber++;
  1705. /* for all topics in an index entry */
  1706. for ( i=0;
  1707. i<topicCnt;
  1708. i++, topicIdsList++ )
  1709. {
  1710. char * topicTitle;
  1711. if (NULL == *topicIdsList) continue; /* CONTINUE */
  1712. /* find the toc entry of the topic */
  1713. ret = TocFindSortedEntry(toc, *topicIdsList, NULL, &tocEntry);
  1714. if (ret < 0) continue; /* CONTINUE */
  1715. /* get the topic title */
  1716. _DtHelpCeGetTopicTitle(state->canvasHandle, state->volHandle,
  1717. tocEntry->locationId, &topicTitle);
  1718. if (NULL == topicTitle)
  1719. topicTitle = _DTGETMESSAGE(PTSET,31,EMPTY_STR);
  1720. /* output the entry */
  1721. OutputBlankSpaces(fp,options->colsAdjLeftMargin);
  1722. {
  1723. char *_p;
  1724. int ret;
  1725. ret = IconvBuffer( state->volHandle, topicTitle, &_p );
  1726. if ( ret ) {
  1727. fprintf(fp,_DTGETMESSAGE(PTSET,21," %s, %d\n"),
  1728. _p, tocEntry->pageNumber);
  1729. } else {
  1730. fprintf(fp,_DTGETMESSAGE(PTSET,21," %s, %d\n"),
  1731. topicTitle, tocEntry->pageNumber);
  1732. }
  1733. }
  1734. state->curLineNumber++;
  1735. /* if at the end of a page, print footer, eject, and print header */
  1736. if (state->curLineNumber >= availLines)
  1737. {
  1738. PrintFooter(options,fp,state,&options->indexHF,&state->indexHFF);
  1739. NewPage(options,fp,state,True);
  1740. PrintHeader(options,fp,state,&options->indexHF,&state->indexHFF);
  1741. /* calc number of available lines from top of page to footer */
  1742. availLines = AvailContentLines(options,state,&state->indexHFF);
  1743. }
  1744. } /* for all topics in an index entry */
  1745. } /* for all index entries */
  1746. /* output footer */
  1747. PrintFooter(options,fp,state,&options->indexHF,&state->indexHFF);
  1748. if (fp) fclose(fp);
  1749. return 0;
  1750. } /*$END$*/
  1751. #if DOC
  1752. ===================================================================
  1753. $PFUNBEG$: ProcessToc()
  1754. $1LINER$: Process the TOC data to generate a toc file
  1755. $DESCRIPT$:
  1756. Process the TOC data to generate a toc file
  1757. $RETURNS$:
  1758. 0: success
  1759. -1: could not create or open a temp file
  1760. -2: could not get help topic info
  1761. $ARGS$:
  1762. ========================================================$SKIP$=====*/
  1763. #endif /*DOC*/
  1764. static
  1765. int ProcessToc(
  1766. _DtHPrOptions * options,
  1767. char * * ret_resultsFile,
  1768. PrintState * state,
  1769. Toc * toc)
  1770. { /*$CODE$*/
  1771. FILE * fp;
  1772. int availLines;
  1773. TocEntry * entry;
  1774. /* open file */
  1775. fp = OpenTmpFile(options,ret_resultsFile);
  1776. if (NULL == fp) return -1; /* RETURN: error */
  1777. /*** process toc ***/
  1778. /* setup the state */
  1779. state->inhibitOutput = False;
  1780. state->curPageNumber = 1;
  1781. state->curLineNumber = 1;
  1782. state->sectNums[0] = 0; /* inhibit section num printing */
  1783. state->sectStr = _DTGETMESSAGE(PTSET,11,"Table of Contents"); /* $SECTNUM name */
  1784. /* start new page and output header */
  1785. NewPage(options,fp,state,False);
  1786. PrintHeader(options,fp,state,&options->tocHF,&state->tocHFF);
  1787. /* calc number of available lines from top of page to footer */
  1788. availLines = AvailContentLines(options,state,&state->tocHFF);
  1789. /* walk through the toc; output the label, title string, and page num */
  1790. for ( entry = TocNextEntry(toc,NULL);
  1791. NULL != entry;
  1792. entry = TocNextEntry(toc,entry) )
  1793. {
  1794. char sectNumStr[MAXSECTS * 4 + 5]; /* $SECTNUM */
  1795. char * title = NULL;
  1796. wchar_t * wctitle;
  1797. int lhsWidth;
  1798. int titlelen;
  1799. int fillerChar;
  1800. int blanksCnt;
  1801. /* get the data to print */
  1802. SectNumStr(entry->sectNums,entry->sectStr,sectNumStr);
  1803. _DtHelpCeGetTopicTitle(state->canvasHandle, state->volHandle,
  1804. entry->locationId, &title);
  1805. if (NULL == title) title = EMPTY_STR;
  1806. /* set max length of title and calc num blanks needed */
  1807. lhsWidth = strlen(sectNumStr) + 1; /* 1=blank after sect num */
  1808. titlelen = strlen(title);
  1809. wctitle = malloc(sizeof(wchar_t) * (titlelen+1));
  1810. /* truncate the title using wchar_t */
  1811. if(wctitle)
  1812. {
  1813. /* convert title to wchar_t and get num chars */
  1814. mbstowcs(wctitle,title,titlelen+1);
  1815. titlelen = wcslen(wctitle);
  1816. /* truncate the title to fit on the line */
  1817. if (titlelen > options->colsTextWidth - lhsWidth)
  1818. {
  1819. wctitle[options->colsTextWidth - lhsWidth - 1] = EOS;
  1820. titlelen = wcslen(wctitle);
  1821. }
  1822. wcstombs(title,wctitle,titlelen+1);
  1823. free(wctitle);
  1824. }
  1825. /* truncate the title assuming single-byte */
  1826. else if (titlelen > options->colsTextWidth - lhsWidth)
  1827. {
  1828. title[options->colsTextWidth - lhsWidth - 1] = EOS;
  1829. titlelen = strlen(title);
  1830. }
  1831. lhsWidth += titlelen;
  1832. /* add a blank line before a major section */
  1833. if ( 0 == entry->sectNums[2] )
  1834. {
  1835. fprintf(fp,"\n");
  1836. state->curLineNumber++;
  1837. /* do we need a new page to start this section? */
  1838. if ( (availLines - state->curLineNumber) < 3 )
  1839. {
  1840. PrintFooter(options,fp,state,&options->tocHF,&state->tocHFF);
  1841. NewPage(options,fp,state,True);
  1842. PrintHeader(options,fp,state,&options->tocHF,&state->tocHFF);
  1843. /* calc number of available lines from top of page to footer */
  1844. availLines = AvailContentLines(options,state,&state->tocHFF);
  1845. }
  1846. }
  1847. /* output the beginning of the line */
  1848. if ( sectNumStr[0] == EOS ) /* no section number */
  1849. {
  1850. /* space between title and page num */
  1851. /* 1: no sect num so no space betw sect num & title */
  1852. /* -3: reserve 3 spaces for the page number */
  1853. blanksCnt = ((options->colsTextWidth - lhsWidth) - 3) + 1;
  1854. {
  1855. char *_p;
  1856. int ret;
  1857. ret = IconvBuffer( state->volHandle, title, &_p );
  1858. if ( ret ) {
  1859. fprintf(fp,"%*c%s", options->colsAdjLeftMargin, ' ', _p );
  1860. } else {
  1861. fprintf(fp,"%*c%s", options->colsAdjLeftMargin, ' ', title);
  1862. }
  1863. }
  1864. }
  1865. else /* valid section number */
  1866. {
  1867. /* space between title and page num */
  1868. /* -3: reserve 3 spaces for the page number */
  1869. blanksCnt = (options->colsTextWidth - lhsWidth) - 3;
  1870. {
  1871. char *_p;
  1872. int ret;
  1873. ret = IconvBuffer( state->volHandle, title, &_p );
  1874. if ( ret ) {
  1875. fprintf(fp,"%*c%s %s",
  1876. options->colsAdjLeftMargin, ' ', sectNumStr, _p );
  1877. } else {
  1878. fprintf(fp,"%*c%s %s",
  1879. options->colsAdjLeftMargin, ' ', sectNumStr, title);
  1880. }
  1881. }
  1882. }
  1883. /* output the filler and page number */
  1884. if ( (blanksCnt % 2) != 0) { fputc(' ',fp); blanksCnt--; }
  1885. for( ;blanksCnt > 0; blanksCnt -= 2) fprintf(fp," .");
  1886. fprintf(fp,"%3d\n", entry->pageNumber);
  1887. state->curLineNumber++;
  1888. /* if at the end of a page, print footer, eject, and print header */
  1889. if (state->curLineNumber >= availLines)
  1890. {
  1891. PrintFooter(options,fp,state,&options->tocHF,&state->tocHFF);
  1892. NewPage(options,fp,state,True);
  1893. PrintHeader(options,fp,state,&options->tocHF,&state->tocHFF);
  1894. /* calc number of available lines from top of page to footer */
  1895. availLines = AvailContentLines(options,state,&state->tocHFF);
  1896. }
  1897. } /* for all entries */
  1898. /* output footer */
  1899. PrintFooter(options,fp,state,&options->tocHF,&state->tocHFF);
  1900. if (fp) fclose(fp);
  1901. return 0;
  1902. } /*$END$*/
  1903. #if DOC
  1904. ===================================================================
  1905. $PFUNBEG$: ProcessTopics()
  1906. $1LINER$: Process the help volume to generate a topics file
  1907. $DESCRIPT$:
  1908. Process the TOC data to generate a toc file
  1909. $RETURNS$:
  1910. 0: success
  1911. -1: could not create or open a temp file
  1912. -2: could not get help topic info
  1913. $ARGS$:
  1914. outputFromLocId: output of topics occurs for this topic and all its
  1915. subtopics. This topic Id is strcasecmp()ed against the
  1916. current Id to determine a match. If NULL, the volume
  1917. top topic is used.
  1918. inhibitTopicsOutput: if true, output only starts when outputFromLocId is found
  1919. outputFromLocId inhibitOutput action
  1920. --------------- ------------- -------------------------------------
  1921. NULL True no output is generated
  1922. NULL False output begins with the top topic
  1923. != NULL True output begins with outputFromLocId
  1924. and stops after last subtopic of
  1925. outputFromLocId
  1926. != NULL False output begins with the top topic
  1927. and stops after last subtopic of
  1928. outputFromLocId
  1929. ========================================================$SKIP$=====*/
  1930. #endif /*DOC*/
  1931. static
  1932. int ProcessTopics(
  1933. _DtHPrOptions * options,
  1934. char * * ret_resultsFile,
  1935. PrintState * state,
  1936. Toc * toc,
  1937. Boolean processSubTopics,
  1938. char * outputFromLocId,
  1939. Boolean inhibitTopicsOutput)
  1940. { /*$CODE$*/
  1941. FILE * fp;
  1942. int ret;
  1943. /* don't print a single topic with no locId */
  1944. if ( processSubTopics == False
  1945. && (outputFromLocId == NULL || *outputFromLocId == EOS) )
  1946. return 0; /* RETURN: ok */
  1947. /* if no output is desired, set ptr to NULL */
  1948. if ( NULL == outputFromLocId && inhibitTopicsOutput )
  1949. fp = NULL;
  1950. else
  1951. { /* output is desired...open file */
  1952. fp = OpenTmpFile(options,ret_resultsFile);
  1953. if (NULL == fp) return -1; /* RETURN: error */
  1954. }
  1955. /*** process text ***/
  1956. /* if processing subtopics, start processing at the top */
  1957. if ( processSubTopics )
  1958. {
  1959. int offset;
  1960. /* get the top topic of the volume */
  1961. ret = _DtHelpCeGetTopTopicId(state->volHandle, &state->currentLocId);
  1962. if (ret != True) state->currentLocId = strdup("_HOMETOPIC");
  1963. }
  1964. else
  1965. { /* otherwise, process only where needed */
  1966. state->currentLocId = strdup(outputFromLocId);
  1967. }
  1968. /* set the other state values */
  1969. if ( NULL != outputFromLocId
  1970. && (ret = _DtHelpCeIsTopTopic(state->volHandle,outputFromLocId)) != 0 )
  1971. state->outputFromLocId = outputFromLocId;
  1972. else
  1973. state->outputFromLocId = state->currentLocId;
  1974. state->inhibitOutput = inhibitTopicsOutput;
  1975. state->curPageNumber = 1;
  1976. state->curLineNumber = 1;
  1977. /* output topics but don't inhibit */
  1978. if ( processSubTopics )
  1979. {
  1980. state->sectNums[0] = 1; /* support section num printing */
  1981. /* 0: level of the top topic; note tha this is diff from the
  1982. level of the top topic in an SDL volume, which is 1. This
  1983. is merely for convenience, to make addressing into the
  1984. sectNums array directly rather than subtracting 1 or 2 to
  1985. get the array index from the level. */
  1986. ret = ProcessSubTopics(options,fp,toc,0,state);
  1987. }
  1988. else
  1989. {
  1990. /* start new page but don't eject; output header;
  1991. output right number of blank lines to get to where topic starts */
  1992. state->sectNums[0] = 0; /* inhibit section num printing */
  1993. NewPage(options,fp,state,False); /* for top margin */
  1994. PrintHeader(options,fp,state,&options->bodyHF,&state->bodyHFF);
  1995. ret = ProcessOneTopic(options,fp,state,True);
  1996. /* output footer */
  1997. PrintFooter(options,fp,state,&options->bodyHF,&state->bodyHFF);
  1998. }
  1999. /* if the file was opened, close & check if anything written to it */
  2000. /* if empty, pretend the file wasn't created. */
  2001. if (fp)
  2002. {
  2003. Boolean empty = False;
  2004. long int pos;
  2005. pos = ftell(fp);
  2006. if (pos <= 0) empty = True;
  2007. fclose(fp);
  2008. if (empty)
  2009. {
  2010. unlink(*ret_resultsFile);
  2011. free(*ret_resultsFile);
  2012. *ret_resultsFile = NULL;
  2013. }
  2014. }
  2015. return ret;
  2016. } /*$END$*/
  2017. #if DOC
  2018. ===================================================================
  2019. $PFUNBEG$: MakePageBreakFile()
  2020. $1LINER$: Creates a file with only a page break char in it
  2021. $DESCRIPT$:
  2022. Creates a file with only a page break char in it.
  2023. If fails, file ptr is NULL
  2024. $RETURNS$:
  2025. $ARGS$:
  2026. ========================================================$SKIP$=====*/
  2027. #endif /*DOC*/
  2028. static
  2029. void MakePageBreakFile(
  2030. _DtHPrOptions * options,
  2031. char * * ret_resultsFile)
  2032. { /*$CODE$*/
  2033. FILE * fp;
  2034. fp = OpenTmpFile(options,ret_resultsFile);
  2035. if (NULL == fp)
  2036. {
  2037. free(*ret_resultsFile);
  2038. *ret_resultsFile = NULL;
  2039. return;
  2040. }
  2041. fprintf(fp," \n");
  2042. fclose(fp);
  2043. } /*$END$*/
  2044. #if DOC
  2045. ===================================================================
  2046. $PFUNBEG$: DoHelpTopicsProcessing()
  2047. $1LINER$: Passes through entire volume and generates toc and topic output
  2048. $DESCRIPT$:
  2049. Passes through entire volume and generates toc and topic output
  2050. $RETURNS$:
  2051. 0: success
  2052. -1: could not create or open a temp file
  2053. -2: could not get help topic info
  2054. -3: could not alloc memory
  2055. $ARGS$:
  2056. ========================================================$SKIP$=====*/
  2057. #endif /*DOC*/
  2058. static
  2059. int DoHelpTopicsProcessing(
  2060. _DtHPrOptions * options,
  2061. char * * ret_resultsFile,
  2062. Boolean processToc,
  2063. Boolean processIndex,
  2064. Boolean processFrontMatter,
  2065. Boolean processSubTopics,
  2066. char * outputFromLocId,
  2067. Boolean inhibitTopicsOutput)
  2068. { /*$CODE$*/
  2069. #define FM 0
  2070. #define TOC 1
  2071. #define TOPICS 2
  2072. #define INDEX 3
  2073. #define NUMPARTS 4
  2074. PrintState state;
  2075. Toc toc;
  2076. int ret = 0;
  2077. int i;
  2078. char * buf;
  2079. char * start;
  2080. char * next;
  2081. char * pgbrkFile = NULL;
  2082. char * partFiles[NUMPARTS];
  2083. Boolean validFile = False;
  2084. /* init larger vars to 0 */
  2085. memset(&toc,0,sizeof(Toc));
  2086. memset(&state,0,sizeof(state));
  2087. memset(partFiles,0,sizeof(partFiles));
  2088. /* create terminal-based canvas for text retrieval */
  2089. ret = _DtHelpTermCreateCanvas(options->colsTextWidth,&state.canvasHandle);
  2090. if ( ret != 0 ) return ret; /* RETURN: error */
  2091. /* open volume and get state.volHandle */
  2092. ret = _DtHelpCeOpenVolume(state.canvasHandle,
  2093. options->helpVolume, &state.volHandle);
  2094. if ( ret != 0 ) return ret; /* RETURN: error */
  2095. /* do some prepatory format string generation */
  2096. GenAllHeadFootFormatStrs(options,&state);
  2097. /* after this point, if we get an error, we don't return--we do the best we can */
  2098. /* so don't monitor the return values. */
  2099. /*** process a help volume; maybe create a topics file ***/
  2100. /* always do this, as all other processing (except FM) needs the data */
  2101. ret=ProcessTopics(options,&partFiles[TOPICS],&state,&toc,
  2102. processSubTopics,outputFromLocId,inhibitTopicsOutput);
  2103. /*** process toc to create an index and add an index entry to toc ***/
  2104. /* Do this right after processing topics so that page number info is right */
  2105. if (processIndex)
  2106. ret=ProcessIndex(options,&partFiles[INDEX],&state,&toc);
  2107. /*** process volume to create front matter ***/
  2108. if (processFrontMatter)
  2109. ret=ProcessFrontMatter(options,&partFiles[FM],&state);
  2110. /*** process toc to create a toc; do this last to get all entries ***/
  2111. if (processToc)
  2112. ret=ProcessToc(options,&partFiles[TOC],&state,&toc);
  2113. /*** create the final output file ***/
  2114. MakePageBreakFile(options,&pgbrkFile);
  2115. /* create a temporary file in $HOME/.dt/tmp to hold everything */
  2116. /* Put in $HOME/.dt/tmp so that if the printer operation is running
  2117. of a remote system, it can get to the (local) temp file.
  2118. This would not be possible if the file were put in /tmp */
  2119. *ret_resultsFile = _DtHPrCreateTmpFile(TMPFILE_PREFIX,TMPFILE_SUFFIX);
  2120. if (NULL == *ret_resultsFile) { ret = -1; goto cleanup; } /* RETURN: error */
  2121. buf = malloc(3000 * sizeof(char));
  2122. if (NULL == buf) { ret = -3; goto cleanup; } /* RETURN: error */
  2123. /* cat together the part files that got created in the array order */
  2124. /* separate them with a file containing only a page break */
  2125. strcpy(buf,"cat ");
  2126. start = buf + strlen(buf);
  2127. next = start;
  2128. for (i=0; i<NUMPARTS; i++)
  2129. {
  2130. if (partFiles[i])
  2131. {
  2132. /* if at least one file in cat list, separate from it with a pgbrk */
  2133. if (start != next && pgbrkFile)
  2134. {
  2135. sprintf(next,"%s ", pgbrkFile);
  2136. next += strlen(next);
  2137. }
  2138. sprintf(next,"%s ", partFiles[i]);
  2139. next += strlen(next);
  2140. validFile = True;
  2141. }
  2142. }
  2143. /* only do the operation if there are valid files */
  2144. if (validFile)
  2145. {
  2146. int rv;
  2147. sprintf(next,"> %s", *ret_resultsFile);
  2148. if(options->debugHelpPrint) printf("%s\n",buf);
  2149. rv = system(buf);
  2150. }
  2151. free(buf);
  2152. ret = 0;
  2153. /* if needed, iconv file and change filenames */
  2154. /* close the volume when done */
  2155. _DtHelpCeCloseVolume(state.canvasHandle,state.volHandle);
  2156. /*** cleanup ***/
  2157. cleanup:
  2158. /* delete all part files */
  2159. for (i=0; i<NUMPARTS; i++)
  2160. if (partFiles[i])
  2161. {
  2162. unlink(partFiles[i]);
  2163. free(partFiles[i]);
  2164. }
  2165. if(pgbrkFile) {
  2166. unlink(pgbrkFile);
  2167. }
  2168. /* NOTE: should free Toc here if interested in no leaks */
  2169. return ret;
  2170. } /*$END$*/
  2171. #if DOC
  2172. ===================================================================
  2173. $PFUNBEG$: GenerateTopicsFile()
  2174. $1LINER$: Recovers and formats help topic text and then sends to printer
  2175. $DESCRIPT$:
  2176. Recovers and formats help topic text and then sends to printer
  2177. $RETURNS$:
  2178. $ARGS$:
  2179. ========================================================$SKIP$=====*/
  2180. #endif /*DOC*/
  2181. static
  2182. int GenerateTopicsFile(
  2183. Display * dpy,
  2184. _DtHPrOptions * options,
  2185. char * * ret_resultsFile)
  2186. { /*$CODE$*/
  2187. int ret = 0;
  2188. Boolean allTopics = (options->allTopics != NULL);
  2189. Boolean subTopics = (options->subTopics != NULL);
  2190. Boolean toc = (options->toc != NULL);
  2191. Boolean index = (options->index != NULL);
  2192. Boolean frontMatter = (options->frontMatter != NULL);
  2193. Boolean oneTopic = (options->oneTopic != NULL);
  2194. Boolean dfltOneTopic;
  2195. char * locationId = options->locationId;
  2196. /* one topic is selected if other options aren't selected */
  2197. dfltOneTopic = !(allTopics || subTopics || toc || index);
  2198. /* This is sort of a kludge, but since we don't require the -One flag,
  2199. this keeps the _Hometopic from being printed along with
  2200. the front matter, when only front matter was specified */
  2201. if (frontMatter && !oneTopic && dfltOneTopic)
  2202. locationId = NULL; /* prevent printing the hometopic */
  2203. /* to generate a toc or index, we need to process all topics; if
  2204. processing all or subtopics wasn't requested, request it;
  2205. and set a locationId that will never match (an empty string) */
  2206. if ( (toc || index) && !allTopics )
  2207. {
  2208. if (!subTopics) locationId = "";
  2209. subTopics = True;
  2210. }
  2211. /* check the flags and do right thing */
  2212. if (oneTopic || dfltOneTopic)
  2213. /* False: no subtopics--output only locationId; False: don't inhibit output */
  2214. ret = DoHelpTopicsProcessing(
  2215. options, ret_resultsFile,
  2216. False, False, frontMatter,
  2217. False, locationId, False);
  2218. else if (allTopics)
  2219. /* start at root and don't inhibit output */
  2220. ret = DoHelpTopicsProcessing(
  2221. options, ret_resultsFile,
  2222. True, True, True,
  2223. True, NULL, False);
  2224. else
  2225. ret = DoHelpTopicsProcessing(
  2226. options, ret_resultsFile,
  2227. toc, index, frontMatter,
  2228. subTopics, locationId,True);
  2229. return ret;
  2230. } /*$END$*/
  2231. #if DOC
  2232. ===================================================================
  2233. $FUNBEG$: _DtHPrPrintHelpTopic()
  2234. $1LINER$: Recovers and formats help topic text and then sends to printer
  2235. $DESCRIPT$:
  2236. Recovers and formats help topic text and then sends to printer
  2237. $RETURNS$:
  2238. $ARGS$:
  2239. ========================================================$SKIP$=====*/
  2240. #endif /*DOC*/
  2241. int _DtHPrPrintHelpTopic(
  2242. Display * dpy,
  2243. _DtHPrOptions * options)
  2244. { /*$CODE$*/
  2245. char * printCommand;
  2246. char cmdFormat[100];
  2247. char prOffsetArg[30];
  2248. char * tmpFile;
  2249. int status;
  2250. char * path;
  2251. if ( NULL == options->helpVolume )
  2252. {
  2253. fprintf(stderr, _DTGETMESSAGE(PTSET,1,
  2254. "%s: Error: helpType is topic, "
  2255. "but no helpVolume specified.\n"),
  2256. options->programName);
  2257. return 1; /* RETURN error */
  2258. }
  2259. /* try to locate the volume */
  2260. path = _DtHelpFileLocate(DtHelpVOLUME_TYPE, options->helpVolume,
  2261. _DtHelpFileSuffixList,False,R_OK);
  2262. if (path == NULL)
  2263. {
  2264. fprintf(stderr, _DTGETMESSAGE(PTSET,2,
  2265. "%s Error: unable to locate help volume '%s'\n"),
  2266. options->programName, options->helpVolume);
  2267. return 1; /* RETURN error */
  2268. }
  2269. options->helpVolume = path; /* don't free old helpVolume: owned by Xrm */
  2270. /* generate a file containing the help topic */
  2271. status = GenerateTopicsFile(dpy,options,&tmpFile);
  2272. if (status != 0)
  2273. {
  2274. fprintf(stderr, _DTGETMESSAGE(PTSET,3,
  2275. "%s Error: problem processing help volume '%s'\n"),
  2276. options->programName, options->helpVolume);
  2277. return 1; /* RETURN error */
  2278. }
  2279. /* Alloc max shell command line len */
  2280. printCommand = malloc(MAX_COMMAND_LENGTH*sizeof(char));
  2281. if (printCommand == NULL)
  2282. {
  2283. fprintf(stderr, _DTGETMESSAGE(PTSET,4,
  2284. "%s Error: memory allocation failed\n"),
  2285. options->programName);
  2286. return 1; /* RETURN error */
  2287. }
  2288. /** generate the file **/
  2289. sprintf(printCommand,"cat %s",tmpFile);
  2290. status = _DtHPrGenFileOrPrint(options,"Help Topic(s)",printCommand);
  2291. unlink(tmpFile);
  2292. return(status);
  2293. } /*$END$*/
  2294. #if 0 /* This is left-over code that used to deal with printing
  2295. raster images. We don't need it for printing text-only.
  2296. I left it here for future reference. */
  2297. #if DOC
  2298. ===================================================================
  2299. $FUNBEG$: _DtHPrPrintHelpTopicWithXvp()
  2300. $1LINER$: Recovers and formats help topic text and then sends to printer
  2301. $DESCRIPT$:
  2302. Recovers and formats help topic text and then sends to printer
  2303. $STATUS$:
  2304. Code left over from VUE 3.0 help print
  2305. Has not been updated.
  2306. $RETURNS$:
  2307. $ARGS$:
  2308. ========================================================$SKIP$=====*/
  2309. #endif /*DOC*/
  2310. int _DtHPrPrintHelpTopicWithXvp(
  2311. Display * dpy,
  2312. VolumeHandle volHandle,
  2313. char * locationId)
  2314. { /*$CODE$*/
  2315. extern _DtHelpDisplayAreaStruct *Spoof();
  2316. GC gc;
  2317. GC pageNumberGC;
  2318. int screen;
  2319. Window main_window;
  2320. Display *dpy;
  2321. XFontStruct *defaultFont;
  2322. XFontStruct *pageNumberFont;
  2323. _DtHelpDisplayAreaStruct *pDAS;
  2324. char *lpDocName;
  2325. #ifdef RASTER_PRINT
  2326. char *displayNameX;
  2327. Display *dpyX;
  2328. Window main_windowX;
  2329. GC gcX;
  2330. GC invert_gcX;
  2331. int widthX;
  2332. int heightX;
  2333. XFontStruct *defaultFontX;
  2334. #endif
  2335. #define MY_WIDTH 400
  2336. #define MY_HEIGHT 400
  2337. #define DEFAULT_FONT "-agfa-courier-normal-r-normal-93950-0-120-300-300-m-0-hp-roman8"
  2338. #ifdef RASTER_PRINT
  2339. /* set color to bitonal */
  2340. value.addr = RN_bitonal;
  2341. value.size = strlen(RN_BITONAL) + 1;
  2342. XrmPutResource(&XvpDB, STAR_RN_helpColorUse, *str_type, &value);
  2343. #endif
  2344. #ifdef RASTER_PRINT
  2345. /********************/
  2346. /* Get display name */
  2347. /********************/
  2348. strcpy(resource_name, name_prefix);
  2349. strcat(resource_name, RN_display);
  2350. strcpy(resource_class, class_prefix);
  2351. strcat(resource_class, RC_display);
  2352. if (XrmGetResource(appDB, resource_name,
  2353. resource_class,
  2354. str_type, &value) == True)
  2355. displayNameX = value.addr;
  2356. else displayNameX = EMPTY_STR;
  2357. #endif
  2358. strcpy(resource_name, name_prefix);
  2359. strcat(resource_name, RN_jobTitle);
  2360. strcpy(resource_class, class_prefix);
  2361. strcat(resource_class, RC_jobTitle);
  2362. if (XrmGetResource(appDB, resource_name,
  2363. resource_class,
  2364. str_type, &value) == True)
  2365. lpDocName = (char *)value.addr;
  2366. else
  2367. lpDocName = DFLT_JOB_TITLE_STR;
  2368. status = XvpEscape(dpy, STARTDOC, strlen(lpDocName), lpDocName, NULL);
  2369. screen = DefaultScreen(dpy);
  2370. /* Calculate application page size */
  2371. _DtHPrCalculatePageSize(dpy, &x, &y, &width, &height);
  2372. /* create a window; x, y, width, and height are recorded */
  2373. main_window = XCreateSimpleWindow(dpy, XRootWindow(dpy, screen),
  2374. x, y,
  2375. width,
  2376. height,
  2377. 10, 0, XWhitePixel (dpy, screen));
  2378. /* 0, 0, MY_WIDTH, MY_HEIGHT, 10, 0, XWhitePixel (dpy, screen)); */
  2379. XSelectInput (dpy, main_window, ExposureMask);
  2380. XMapWindow (dpy, main_window);
  2381. XvpEscape(dpy, SET_IMAGE_RESOLUTION, 4, 100, NULL);
  2382. defaultFont = XLoadQueryFont (dpy, DEFAULT_FONT);
  2383. if (defaultFont == NULL)
  2384. {
  2385. printf ("Unable to get a font\n");
  2386. exit (1);
  2387. }
  2388. gc = DefaultGC(dpy, screen);
  2389. XSetForeground (dpy, gc, XBlackPixel (dpy, screen));
  2390. XSetBackground (dpy, gc, XWhitePixel (dpy, screen));
  2391. XSetFont(dpy, gc, defaultFont->fid);
  2392. XSetLineAttributes(dpy, gc, 2, LineSolid, CapButt, JoinMiter);
  2393. #ifndef RASTER_PRINT
  2394. pageNumberFont =
  2395. XLoadQueryFont (dpy,
  2396. "-agfa-univers-normal-r-normal-94021-0-100-300-300-p-0-iso8859-1");
  2397. if (pageNumberFont == NULL)
  2398. {
  2399. printf ("Unable to get a font\n");
  2400. exit (1);
  2401. }
  2402. pageNumberGC = XCreateGC(dpy, RootWindow(dpy, screen), NULL, NULL);
  2403. XSetForeground (dpy, pageNumberGC, XBlackPixel (dpy, screen));
  2404. XSetBackground (dpy, pageNumberGC, XWhitePixel (dpy, screen));
  2405. XSetFont(dpy, pageNumberGC, pageNumberFont->fid);
  2406. XSetLineAttributes(dpy, pageNumberGC, 2, LineSolid, CapButt, JoinMiter);
  2407. #endif
  2408. #ifdef RASTER_PRINT
  2409. widthX = width/3; /* hard coded for 300 dpi printers */
  2410. heightX = height/3;
  2411. status = CreateRealXObjects(displayNameX, widthX, heightX,
  2412. &dpyX, &main_windowX, &gcX,
  2413. &invert_gcX, &defaultFontX);
  2414. dpyX->db = dpy->db; /* carry over data base */
  2415. pDAS = Spoof (dpyX, gcX, invert_gcX, defaultFontX, widthX, heightX, lineLeading);
  2416. #else
  2417. pDAS = Spoof (dpy, gc, gc, defaultFont, width, height, lineLeading);
  2418. #endif
  2419. if (pDAS == NULL)
  2420. {
  2421. fprintf(stderr, "%s: Internal error.\n");
  2422. exit(1);
  2423. }
  2424. if (helpType == DtHELP_TYPE_TOPIC)
  2425. #ifdef RASTER_PRINT
  2426. status = printTopicAndChildrenX(helpVolume, locationId, allTopics, pDAS,
  2427. dpy, main_window, gc,
  2428. dpyX, main_windowX, gcX,
  2429. widthX, heightX);
  2430. #else
  2431. status = printTopicAndChildren(helpVolume, locationId, allTopics, pDAS,
  2432. dpy, main_window, gc, pageNumberGC );
  2433. #endif
  2434. /*
  2435. pDAS = (_DtHelpDisplayAreaStruct *) SetUp (pDAS, dpy, main_window, gc, defaultFont,
  2436. width,
  2437. height,
  2438. helpVolume,
  2439. locationId);
  2440. */
  2441. else if (helpType == DtHELP_TYPE_DYNAMIC_STRING)
  2442. {
  2443. #ifdef RASTER_PRINT
  2444. XImage *image;
  2445. pDAS = (_DtHelpDisplayAreaStruct *) SetUpDynamicString (pDAS, dpy, gc,
  2446. defaultFont,
  2447. width,
  2448. height,
  2449. stringData);
  2450. RenderLinesX (dpyX, main_windowX, pDAS, widthX, heightX, &image);
  2451. XvpPutImage(dpy, main_window, gcX, image, 0, 0, 0, 0,
  2452. (image->width)*3, (image->height*3) );
  2453. status = XvpEscape(dpy, NEWFRAME, NULL, NULL, NULL);
  2454. if (status > 0) ;
  2455. else if (status < 0)
  2456. fprintf (stdout, "XvpEscape(NEWFRAME) not implemented.\n");
  2457. else fprintf(stdout, "XvpEscape(NEWFRAME) not successful.\n");
  2458. #else
  2459. pDAS = (_DtHelpDisplayAreaStruct *) SetUpDynamicString (pDAS, dpy, gc,
  2460. defaultFont,
  2461. width,
  2462. height,
  2463. stringData);
  2464. RenderLines (dpy, main_window, pDAS);
  2465. #endif
  2466. }
  2467. else
  2468. {
  2469. fprintf(stderr, "%s Error: Illegal helpType %d.\n",
  2470. argv[0], helpType);
  2471. exit(1);
  2472. }
  2473. if (status == -1)
  2474. {
  2475. fprintf (stdout, "Error occurred in XvpEscape(STARTDOC)\n");
  2476. exit(1);
  2477. }
  2478. status = XvpEscape(dpy, ENDDOC, NULL, NULL, NULL);
  2479. if (status == -1)
  2480. {
  2481. fprintf (stdout, "Error occurred in XvpEscape(ENDDOC)\n");
  2482. exit(1);
  2483. }
  2484. exit(0);
  2485. } /*$END$*/
  2486. #endif /* #if 0 at function start */