PrintTopics.c 88 KB

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