home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume26 / tclx / part16 < prev    next >
Encoding:
Text File  |  1991-11-19  |  48.6 KB  |  1,452 lines

  1. Newsgroups: comp.sources.misc
  2. From: karl@sugar.neosoft.com (Karl Lehenbauer)
  3. Subject:  v26i016:  tclx - extensions and on-line help for tcl 6.1, Part16/23
  4. Message-ID: <1991Nov19.135536.1260@sparky.imd.sterling.com>
  5. X-Md4-Signature: a81d1694237d0e6cfc7073650d097a58
  6. Date: Tue, 19 Nov 1991 13:55:36 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: karl@sugar.neosoft.com (Karl Lehenbauer)
  10. Posting-number: Volume 26, Issue 16
  11. Archive-name: tclx/part16
  12. Environment: UNIX
  13.  
  14. #! /bin/sh
  15. # This is a shell archive.  Remove anything before this line, then unpack
  16. # it by saving it into a file and typing "sh file".  To overwrite existing
  17. # files, type "sh file -c".  You can also feed this as standard input via
  18. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  19. # will see the following message at the end:
  20. #        "End of archive 16 (of 23)."
  21. # Contents:  extended/src/handles.c extended/src/tclstartup.c
  22. #   extended/tcllib/buildhelp.tcl
  23. # Wrapped by karl@one on Wed Nov 13 21:50:28 1991
  24. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  25. if test -f 'extended/src/handles.c' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'extended/src/handles.c'\"
  27. else
  28. echo shar: Extracting \"'extended/src/handles.c'\" \(15132 characters\)
  29. sed "s/^X//" >'extended/src/handles.c' <<'END_OF_FILE'
  30. X/*
  31. X *
  32. X * handles.c --
  33. X *
  34. X * Tcl handles.  Provides a mechanism for managing expandable tables that are
  35. X * addressed by textual handles.
  36. X *---------------------------------------------------------------------------
  37. X * Copyright 1991 Karl Lehenbauer and Mark Diekhans.
  38. X *
  39. X * Permission to use, copy, modify, and distribute this software and its
  40. X * documentation for any purpose and without fee is hereby granted, provided
  41. X * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  42. X * Mark Diekhans make no representations about the suitability of this
  43. X * software for any purpose.  It is provided "as is" without express or
  44. X * implied warranty.
  45. X */
  46. X
  47. X#include "tclExtdInt.h"
  48. X
  49. X/*
  50. X * This is the table header.  It is separately allocated from the table body,
  51. X * since it must keep track of a table body that might move.  Each entry in the
  52. X * table is preceded with a header which has the free list link, which is a
  53. X * entry index of the next free entry.  Special values keep track of allocated
  54. X * entries.
  55. X */
  56. X
  57. X#define NULL_IDX      -1
  58. X#define ALLOCATED_IDX -2
  59. X
  60. Xtypedef unsigned char ubyte_t;
  61. Xtypedef ubyte_t *ubyte_pt;
  62. X
  63. Xtypedef struct {
  64. X    int      useCount;          /* Keeps track of the number sharing       */
  65. X    int      entrySize;         /* Entry size in bytes, including overhead */
  66. X    int      tableSize;         /* Current number of entries in the table  */
  67. X    int      freeHeadIdx;       /* Index of first free entry in the table  */
  68. X    ubyte_pt bodyP;             /* Pointer to table body                   */
  69. X    int      baseLength;        /* Length of handleBase.                   */
  70. X    char     handleBase [1];    /* Base handle name.  MUST BE LAST FIELD!  */
  71. X    } tblHeader_t;
  72. Xtypedef tblHeader_t *tblHeader_pt;
  73. X
  74. Xtypedef struct {
  75. X    int freeLink;
  76. X  } entryHeader_t;
  77. Xtypedef entryHeader_t *entryHeader_pt;
  78. X
  79. X/*
  80. X * This macro is used to return a pointer to an entry, given its index.
  81. X */
  82. X#define TBL_INDEX(hdrP, idx) \
  83. X    ((entryHeader_pt) (hdrP->bodyP + (hdrP->entrySize * idx)))
  84. X
  85. X/*
  86. X * This macros to convert between pointers to the user and header area of
  87. X * an table entry.
  88. X */
  89. X#define USER_AREA(entryPtr) \
  90. X (void_pt) (((ubyte_pt) entryPtr) + sizeof (entryHeader_t));
  91. X#define HEADER_AREA(entryPtr) \
  92. X (entryHeader_pt) (((ubyte_pt) entryPtr) - sizeof (entryHeader_t));
  93. X
  94. X/*
  95. X * Prototypes of internal functions.
  96. X */
  97. Xvoid
  98. XLinkInNewEntries _ANSI_ARGS_((tblHeader_pt tblHdrPtr,
  99. X                              int          newIdx,
  100. X                              int          numEntries));
  101. X
  102. Xvoid
  103. XExpandTable _ANSI_ARGS_((tblHeader_pt tblHdrPtr,
  104. X                         int          neededIdx));
  105. X
  106. XentryHeader_pt
  107. XAllocEntry _ANSI_ARGS_((tblHeader_pt  tblHdrPtr,
  108. X                        int          *entryIdxPtr));
  109. X
  110. Xint
  111. XHandleDecode _ANSI_ARGS_((Tcl_Interp   *interp,
  112. X                          tblHeader_pt  tblHdrPtr,
  113. X                          CONST char   *handle));
  114. X
  115. X/*=============================================================================
  116. X * LinkInNewEntries --
  117. X *   Build free links through the newly allocated part of a table.
  118. X *   
  119. X * Parameters:
  120. X *   o tblHdrPtr (I) - A pointer to the table header.
  121. X *   o newIdx (I) - Index of the first new entry.
  122. X *   o numEntries (I) - The number of new entries.
  123. X *-----------------------------------------------------------------------------
  124. X */
  125. Xstatic void
  126. XLinkInNewEntries (tblHdrPtr, newIdx, numEntries)
  127. X    tblHeader_pt tblHdrPtr;
  128. X    int          newIdx;
  129. X    int          numEntries;
  130. X{
  131. X    int            entIdx, lastIdx;
  132. X    entryHeader_pt entryPtr;
  133. X    
  134. X    lastIdx = newIdx + numEntries - 1;
  135. X
  136. X    for (entIdx = newIdx; entIdx < lastIdx; entIdx++) {
  137. X        entryPtr = TBL_INDEX (tblHdrPtr, entIdx);
  138. X        entryPtr->freeLink = entIdx + 1;
  139. X    }
  140. X    entryPtr = TBL_INDEX (tblHdrPtr, lastIdx);
  141. X    entryPtr->freeLink = tblHdrPtr->freeHeadIdx;
  142. X    tblHdrPtr->freeHeadIdx = newIdx;
  143. X
  144. X} /* LinkInNewEntries */
  145. X
  146. X/*=============================================================================
  147. X * ExpandTable --
  148. X *   Expand a handle table, doubling its size.
  149. X * Parameters:
  150. X *   o tblHdrPtr (I) - A pointer to the table header.
  151. X *   o neededIdx (I) - If positive, then the table will be expanded so that
  152. X *     this entry is available.  If -1, then just expand by the number of 
  153. X *     entries specified on table creation.  MUST be smaller than this size.
  154. X *-----------------------------------------------------------------------------
  155. X */
  156. Xstatic void
  157. XExpandTable (tblHdrPtr, neededIdx)
  158. X    tblHeader_pt tblHdrPtr;
  159. X    int          neededIdx;
  160. X{
  161. X    ubyte_pt oldBodyP = tblHdrPtr->bodyP;
  162. X    int      numNewEntries;
  163. X    int      newSize;
  164. X    
  165. X    if (neededIdx < 0)
  166. X        numNewEntries = tblHdrPtr->tableSize;
  167. X    else
  168. X        numNewEntries = (neededIdx - tblHdrPtr->tableSize) + 1;
  169. X    newSize = (tblHdrPtr->tableSize + numNewEntries) * tblHdrPtr->entrySize;
  170. X
  171. X    tblHdrPtr->bodyP = (ubyte_pt) ckalloc (newSize);
  172. X    memcpy (tblHdrPtr->bodyP, oldBodyP, newSize);
  173. X    LinkInNewEntries (tblHdrPtr, tblHdrPtr->tableSize, numNewEntries);
  174. X    tblHdrPtr->tableSize += numNewEntries;
  175. X    ckfree (oldBodyP);
  176. X    
  177. X} /* ExpandTable */
  178. X
  179. X/*=============================================================================
  180. X * AllocEntry --
  181. X *   Allocate a table entry, expanding if necessary.
  182. X *
  183. X * Parameters:
  184. X *   o tblHdrPtr (I) - A pointer to the table header.
  185. X *   o entryIdxPtr (O) - The index of the table entry is returned here.
  186. X * Returns:
  187. X *    The a pointer to the entry.
  188. X *-----------------------------------------------------------------------------
  189. X */
  190. Xstatic entryHeader_pt
  191. XAllocEntry (tblHdrPtr, entryIdxPtr)
  192. X    tblHeader_pt  tblHdrPtr;
  193. X    int          *entryIdxPtr;
  194. X{
  195. X    int            entryIdx;
  196. X    entryHeader_pt entryPtr;
  197. X
  198. X    if (tblHdrPtr->freeHeadIdx == NULL_IDX)
  199. X        ExpandTable (tblHdrPtr, -1);
  200. X
  201. X    entryIdx = tblHdrPtr->freeHeadIdx;    
  202. X    entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
  203. X    tblHdrPtr->freeHeadIdx = entryPtr->freeLink;
  204. X    entryPtr->freeLink = ALLOCATED_IDX;
  205. X    
  206. X    *entryIdxPtr = entryIdx;
  207. X    return entryPtr;
  208. X    
  209. X} /* AllocEntry */
  210. X
  211. X/*=============================================================================
  212. X * HandleDecode --
  213. X *   Decode handle into an entry number.
  214. X *
  215. X * Parameters:
  216. X *   o interp (I) - A error message may be returned in result.
  217. X *   o tblHdrPtr (I) - A pointer to the table header.
  218. X *   o handle (I) - Handle to decode.
  219. X * Returns:
  220. X *   The entry index decoded from the handle, or a negative number if an error
  221. X *   occured.
  222. X *-----------------------------------------------------------------------------
  223. X */
  224. Xstatic int
  225. XHandleDecode (interp, tblHdrPtr, handle)
  226. X    Tcl_Interp   *interp;
  227. X    tblHeader_pt  tblHdrPtr;
  228. X    CONST char   *handle;
  229. X{
  230. X    unsigned entryIdx;
  231. X
  232. X    if ((strncmp (tblHdrPtr->handleBase, (char *) handle, 
  233. X             tblHdrPtr->baseLength) != 0) ||
  234. X             !Tcl_StrToUnsigned (&handle [tblHdrPtr->baseLength], 10, 
  235. X                                 &entryIdx)) {
  236. X        Tcl_AppendResult (interp, "invalid ", tblHdrPtr->handleBase,
  237. X                          " handle: ", handle, (char *) NULL);
  238. X        return -1;
  239. X    }
  240. X    return entryIdx;
  241. X
  242. X} /* HandleDecode */
  243. X
  244. X/*=============================================================================
  245. X * Tcl_HandleTblInit --
  246. X *   Create and initialize a Tcl dynamic handle table.  The use count on the
  247. X *   table is set to one.
  248. X * Parameters:
  249. X *   o handleBase(I) - The base name of the handle, the handle will be returned
  250. X *     in the form "baseNN", where NN is the table entry number.
  251. X *   o entrySize (I) - The size of an entry, in bytes.
  252. X *   o initEntries (I) - Initial size of the table, in entries.
  253. X * Returns:
  254. X *   A pointer to the table header.  
  255. X *-----------------------------------------------------------------------------
  256. X */
  257. Xvoid_pt
  258. XTcl_HandleTblInit (handleBase, entrySize, initEntries)
  259. X    CONST char *handleBase;
  260. X    int         entrySize;
  261. X    int         initEntries;
  262. X{
  263. X    tblHeader_pt tblHdrPtr;
  264. X    int          baseLength = strlen ((char *) handleBase);
  265. X
  266. X    tblHdrPtr = (tblHeader_pt) ckalloc (sizeof (tblHeader_t) + baseLength + 1);
  267. X
  268. X    tblHdrPtr->useCount = 1;
  269. X    tblHdrPtr->baseLength = baseLength;
  270. X    strcpy (tblHdrPtr->handleBase, (char *) handleBase);
  271. X
  272. X    /* 
  273. X     * Calculate entry size, including header, rounded up to sizeof (int). 
  274. X     */
  275. X    tblHdrPtr->entrySize = entrySize + sizeof (entryHeader_t);
  276. X    tblHdrPtr->entrySize = ((tblHdrPtr->entrySize + sizeof (int) - 1) / 
  277. X                          sizeof (int)) * sizeof (int);
  278. X    tblHdrPtr->freeHeadIdx = NULL_IDX;
  279. X    tblHdrPtr->tableSize = initEntries;
  280. X    tblHdrPtr->bodyP = (ubyte_pt) ckalloc (initEntries * tblHdrPtr->entrySize);
  281. X    LinkInNewEntries (tblHdrPtr, 0, initEntries);
  282. X
  283. X    return (void_pt) tblHdrPtr;
  284. X
  285. X} /* Tcl_HandleTblInit */
  286. X
  287. X/*=============================================================================
  288. X * Tcl_HandleTblUseCount --
  289. X *   Alter the handle table use count by the specified amount, which can be
  290. X *   positive or negative.  Amount may be zero to retrieve the use count.
  291. X * Parameters:
  292. X *   o headerPtr (I) - Pointer to the table header.
  293. X *   o amount (I) - The amount to alter the use count by.
  294. X * Returns:
  295. X *   The resulting use count.
  296. X *-----------------------------------------------------------------------------
  297. X */
  298. Xint
  299. XTcl_HandleTblUseCount (headerPtr, amount)
  300. X    void_pt  headerPtr;
  301. X    int      amount;
  302. X{
  303. X    tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  304. X        
  305. X    tblHdrPtr->useCount += amount;
  306. X    return tblHdrPtr->useCount;
  307. X}
  308. X
  309. X/*=============================================================================
  310. X * Tcl_HandleTblRelease --
  311. X *   Decrement the use count on a Tcl dynamic handle table.  If the count
  312. X *   goes to zero or negative, then release the table.  It is designed to be 
  313. X *   called when a command is released.
  314. X * Parameters:
  315. X *   o headerPtr (I) - Pointer to the table header.
  316. X *-----------------------------------------------------------------------------
  317. X */
  318. Xvoid
  319. XTcl_HandleTblRelease (headerPtr)
  320. X    ClientData headerPtr;
  321. X{
  322. X    tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  323. X
  324. X    tblHdrPtr->useCount--;
  325. X    if (tblHdrPtr->useCount <= 0) {
  326. X        ckfree (tblHdrPtr->bodyP);
  327. X        ckfree ((char *) tblHdrPtr);
  328. X    }
  329. X}
  330. X
  331. X/*=============================================================================
  332. X * Tcl_HandleAlloc --
  333. X *   Allocate an entry and associate a handle with it.
  334. X *
  335. X * Parameters:
  336. X *   o headerPtr (I) - A pointer to the table header.
  337. X *   o handlePtr (O) - Buffer to return handle in. It must be big enough to
  338. X *     hold the name.
  339. X * Returns:
  340. X *   A pointer to the allocated entry (user part).
  341. X *-----------------------------------------------------------------------------
  342. X */
  343. Xvoid_pt
  344. XTcl_HandleAlloc (headerPtr, handlePtr)
  345. X    void_pt   headerPtr;
  346. X    char     *handlePtr;
  347. X{
  348. X    tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  349. X    entryHeader_pt entryPtr;
  350. X    int            entryIdx;
  351. X
  352. X    entryPtr = AllocEntry ((tblHeader_pt) headerPtr, &entryIdx);
  353. X    sprintf (handlePtr, "%s%d", tblHdrPtr->handleBase, entryIdx);
  354. X     
  355. X    return USER_AREA (entryPtr);
  356. X
  357. X} /* Tcl_HandleAlloc */
  358. X
  359. X/*=============================================================================
  360. X * Tcl_HandleXlate --
  361. X *   Translate a handle to a entry pointer.
  362. X *
  363. X * Parameters:
  364. X *   o interp (I) - A error message may be returned in result.
  365. X *   o headerPtr (I) - A pointer to the table header.
  366. X *   o handle (I) - The handle assigned to the entry.
  367. X * Returns:
  368. X *   A pointer to the entry, or NULL if an error occured.
  369. X *-----------------------------------------------------------------------------
  370. X */
  371. Xvoid_pt
  372. XTcl_HandleXlate (interp, headerPtr, handle)
  373. X    Tcl_Interp *interp;
  374. X    void_pt     headerPtr;
  375. X    CONST char *handle;
  376. X{
  377. X    tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  378. X    entryHeader_pt entryPtr;
  379. X    int            entryIdx;
  380. X    
  381. X    if ((entryIdx = HandleDecode (interp, tblHdrPtr, handle)) < 0)
  382. X        return NULL;
  383. X    entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
  384. X
  385. X    if ((entryIdx >= tblHdrPtr->tableSize) ||
  386. X            (entryPtr->freeLink != ALLOCATED_IDX)) {
  387. X        Tcl_AppendResult (interp, tblHdrPtr->handleBase, " is not open",
  388. X                          (char *) NULL);
  389. X        return NULL;
  390. X    }     
  391. X
  392. X    return USER_AREA (entryPtr);
  393. X} /* Tcl_HandleXlate */
  394. X
  395. X/*=============================================================================
  396. X * Tcl_HandleWalk --
  397. X *   Walk through and find every allocated entry in a table.  Entries may
  398. X *   be deallocated during a walk, but should not be allocated.
  399. X *
  400. X * Parameters:
  401. X *   o headerPtr (I) - A pointer to the table header.
  402. X *   o walkKeyPtr (I/O) - Pointer to a variable to use to keep track of the
  403. X *     place in the table.  The variable should be initialized to -1 before
  404. X *     the first call.
  405. X * Returns:
  406. X *   A pointer to the next allocated entry, or NULL if there are not more.
  407. X *-----------------------------------------------------------------------------
  408. X */
  409. Xvoid_pt
  410. XTcl_HandleWalk (headerPtr, walkKeyPtr)
  411. X    void_pt   headerPtr;
  412. X    int      *walkKeyPtr;
  413. X{
  414. X    tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  415. X    int            entryIdx;
  416. X    entryHeader_pt entryPtr;
  417. X
  418. X    if (*walkKeyPtr == -1)
  419. X        entryIdx = 0;
  420. X    else
  421. X        entryIdx = *walkKeyPtr + 1;
  422. X        
  423. X    while (entryIdx < tblHdrPtr->tableSize) {
  424. X        entryPtr = TBL_INDEX (tblHdrPtr, entryIdx);
  425. X        if (entryPtr->freeLink == ALLOCATED_IDX) {
  426. X            *walkKeyPtr = entryIdx;
  427. X            return USER_AREA (entryPtr);
  428. X        }
  429. X        entryIdx++;
  430. X    }
  431. X    return NULL;
  432. X
  433. X} /* Tcl_HandleWalk */
  434. X
  435. X/*=============================================================================
  436. X * Tcl_WalkKeyToHandle --
  437. X *   Convert a walk key, as returned from a call to Tcl_HandleWalk into a
  438. X *   handle.  The Tcl_HandleWalk must have succeeded.
  439. X * Parameters:
  440. X *   o headerPtr (I) - A pointer to the table header.
  441. X *   o walkKey (I) - The walk key.
  442. X *   o handlePtr (O) - Buffer to return handle in. It must be big enough to
  443. X *     hold the name.
  444. X *-----------------------------------------------------------------------------
  445. X */
  446. Xvoid
  447. XTcl_WalkKeyToHandle (headerPtr, walkKey, handlePtr)
  448. X    void_pt   headerPtr;
  449. X    int       walkKey;
  450. X    char     *handlePtr;
  451. X{
  452. X    tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  453. X
  454. X    sprintf (handlePtr, "%s%d", tblHdrPtr->handleBase, walkKey);
  455. X
  456. X} /* Tcl_WalkKeyToHandle */
  457. X
  458. X/*=============================================================================
  459. X * Tcl_HandleFree --
  460. X *   Frees a handle table entry.
  461. X *
  462. X * Parameters:
  463. X *   o headerPtr (I) - A pointer to the table header.
  464. X *   o entryPtr (I) - Entry to free.
  465. X *-----------------------------------------------------------------------------
  466. X */
  467. Xvoid
  468. XTcl_HandleFree (headerPtr, entryPtr)
  469. X    void_pt headerPtr;
  470. X    void_pt entryPtr;
  471. X{
  472. X    tblHeader_pt   tblHdrPtr = (tblHeader_pt)headerPtr;
  473. X    entryHeader_pt freeentryPtr;
  474. X
  475. X    freeentryPtr = HEADER_AREA (entryPtr);
  476. X    freeentryPtr->freeLink = tblHdrPtr->freeHeadIdx;
  477. X    tblHdrPtr->freeHeadIdx = (((ubyte_pt) entryPtr) - tblHdrPtr->bodyP) /
  478. X                           tblHdrPtr->entrySize;
  479. X    
  480. X} /* Tcl_HandleFree */
  481. X
  482. END_OF_FILE
  483. if test 15132 -ne `wc -c <'extended/src/handles.c'`; then
  484.     echo shar: \"'extended/src/handles.c'\" unpacked with wrong size!
  485. fi
  486. # end of 'extended/src/handles.c'
  487. fi
  488. if test -f 'extended/src/tclstartup.c' -a "${1}" != "-c" ; then 
  489.   echo shar: Will not clobber existing file \"'extended/src/tclstartup.c'\"
  490. else
  491. echo shar: Extracting \"'extended/src/tclstartup.c'\" \(15114 characters\)
  492. sed "s/^X//" >'extended/src/tclstartup.c' <<'END_OF_FILE'
  493. X/*
  494. X * tclstartup.c --
  495. X *
  496. X * Startup code for the Tcl shell and other interactive applications.  Also
  497. X * create special commands used just by Tcl shell features.
  498. X *---------------------------------------------------------------------------
  499. X * Copyright 1991 Karl Lehenbauer and Mark Diekhans.
  500. X *
  501. X * Permission to use, copy, modify, and distribute this software and its
  502. X * documentation for any purpose and without fee is hereby granted, provided
  503. X * that the above copyright notice appear in all copies.  Karl Lehenbauer and
  504. X * Mark Diekhans make no representations about the suitability of this
  505. X * software for any purpose.  It is provided "as is" without express or
  506. X * implied warranty.
  507. X */
  508. X
  509. X#include "tclExtdInt.h"
  510. X
  511. Xextern char * getenv ();
  512. X
  513. Xextern char *optarg;
  514. Xextern int   optind, opterr;
  515. X
  516. Xtypedef struct tclParms_t {
  517. X    int    execFile;      /* Run the specified file. (no searching)        */
  518. X    int    execCommand;   /* Execute the specified command.                */
  519. X    int    quickStartup;  /* Quick startup.                                */
  520. X    char  *execStr;       /* Command file or command to execute.           */
  521. X    char **tclArgv;       /* Arguments to pass to tcl script.              */
  522. X    int    tclArgc;       /* Count of arguments to pass to tcl script.     */
  523. X    char  *programName;   /* Name of program (less path).                  */
  524. X    } tclParms_t;
  525. X
  526. X/*
  527. X * Prototypes of internal functions.
  528. X */
  529. Xvoid
  530. XDumpTclError _ANSI_ARGS_((Tcl_Interp  *interp));
  531. X
  532. Xvoid
  533. XParseCmdArgs _ANSI_ARGS_((int          argc,
  534. X                          char       **argv,
  535. X                          tclParms_t  *tclParmsPtr));
  536. X
  537. Xint
  538. XFindDefaultFile _ANSI_ARGS_((Tcl_Interp  *interp,
  539. X                             char        *defaultFile));
  540. X
  541. Xvoid
  542. XProcessDefaultFile _ANSI_ARGS_((Tcl_Interp  *interp,
  543. X                                char        *defaultFile));
  544. X
  545. X
  546. X/*
  547. X *----------------------------------------------------------------------
  548. X *
  549. X * Tcl_SourcepartCmd --
  550. X *
  551. X *    This procedure is invoked to process the "sourcepart" Tcl command:
  552. X *          sourcepart fileName offset length
  553. X *      which evaluates a range of a file.
  554. X *
  555. X * Results:
  556. X *    A standard Tcl result.
  557. X *
  558. X *----------------------------------------------------------------------
  559. X */
  560. X
  561. X    /* ARGSUSED */
  562. Xstatic int
  563. XTcl_SourcepartCmd(dummy, interp, argc, argv)
  564. X    ClientData dummy;            /* Not used. */
  565. X    Tcl_Interp *interp;            /* Current interpreter. */
  566. X    int argc;                /* Number of arguments. */
  567. X    char **argv;            /* Argument strings. */
  568. X{
  569. X    Interp       *iPtr = (Interp *) interp;
  570. X    long          fileOffset;
  571. X    int           bytesToRead;
  572. X    int           fileId, result = TCL_ERROR;
  573. X    struct stat   statBuf;
  574. X    char         *oldScriptFile;
  575. X    char         *fileName, *cmdBuffer = NULL, *end;
  576. X
  577. X    if (argc != 4) {
  578. X    Tcl_AppendResult(interp, "wrong # args: should be \"",
  579. X        argv[0], " fileName offset length\"", (char *) NULL);
  580. X    return TCL_ERROR;
  581. X    }
  582. X
  583. X    if (Tcl_GetLong (interp, argv[2], &fileOffset) != TCL_OK)
  584. X        return TCL_ERROR;
  585. X    if (Tcl_GetInt (interp, argv[3], &bytesToRead) != TCL_OK)
  586. X        return TCL_ERROR;
  587. X
  588. X    fileName = argv [1];
  589. X    if (fileName [0] == '~')
  590. X        if ((fileName = Tcl_TildeSubst (interp, fileName)) == NULL)
  591. X            return TCL_ERROR;
  592. X
  593. X    fileId = open (fileName, O_RDONLY, 0);
  594. X    if (fileId < 0) {
  595. X    Tcl_AppendResult (interp, "open failed on: ", argv [1], ": ",
  596. X                          Tcl_UnixError (interp), (char *) NULL);
  597. X        return TCL_ERROR;
  598. X    }
  599. X    if (fstat(fileId, &statBuf) == -1) {
  600. X    Tcl_AppendResult (interp, "stat failed on: ", argv [1], ": ",
  601. X                          Tcl_UnixError (interp), (char *) NULL);
  602. X        goto exitPoint;
  603. X    }
  604. X    if (statBuf.st_size < fileOffset + bytesToRead) {
  605. X    Tcl_AppendResult (interp, "file not big enough for requested range: ",
  606. X                          argv [1], (char *) NULL);
  607. X        goto exitPoint;
  608. X    }
  609. X    if (lseek (fileId, fileOffset, 0) < 0) {
  610. X    Tcl_AppendResult (interp, "seek failed on: ", argv [1], ": ",
  611. X                          Tcl_UnixError (interp), (char *) NULL);
  612. X        goto exitPoint;
  613. X    }
  614. X
  615. X    cmdBuffer = (char *) ckalloc((unsigned) bytesToRead+1);
  616. X    if (read(fileId, cmdBuffer, (int) bytesToRead) != bytesToRead) {
  617. X    Tcl_AppendResult (interp, "read failed on: ", argv [1], ": ",
  618. X                          Tcl_UnixError (interp), (char *) NULL);
  619. X        goto exitPoint;
  620. X    }
  621. X    close(fileId);
  622. X    fileId = -1;  /* Mark as closed */
  623. X
  624. X    cmdBuffer[bytesToRead] = '\0';
  625. X
  626. X    oldScriptFile = iPtr->scriptFile;
  627. X    iPtr->scriptFile = fileName;
  628. X
  629. X    result = Tcl_Eval (interp, cmdBuffer, 0, &end);
  630. X
  631. X    iPtr->scriptFile = oldScriptFile;
  632. X    if (result == TCL_RETURN) {
  633. X    result = TCL_OK;
  634. X    }
  635. X    /*
  636. X     * Record information telling where the error occurred.
  637. X
  638. X     */
  639. X
  640. X    if (result == TCL_ERROR) {
  641. X        char buf [100];
  642. X        sprintf (buf, "\n    (file \"%.50s\" line %d)", argv [1],
  643. X                 interp->errorLine);
  644. X    Tcl_AddErrorInfo(interp, buf);
  645. X    }
  646. XexitPoint:
  647. X    if (cmdBuffer != NULL)
  648. X        ckfree((char *)cmdBuffer);
  649. X    if (fileId >= 0)
  650. X        close (fileId);
  651. X    return result;
  652. X}
  653. X
  654. X/*
  655. X *----------------------------------------------------------------------
  656. X *
  657. X * DumpTclError --
  658. X *
  659. X * Display error information and abort when an error is returned in the
  660. X * interp->result.
  661. X *
  662. X * Parameters:
  663. X *     o interp - A pointer to the interpreter, should contain the
  664. X *       error message in `result'.
  665. X *----------------------------------------------------------------------
  666. X */
  667. Xstatic void
  668. XDumpTclError (interp)
  669. X    Tcl_Interp  *interp;
  670. X{
  671. X    char *errorStack;
  672. X
  673. X    fflush (stdout);
  674. X    fprintf (stderr, "Error: %s\n", interp->result);
  675. X
  676. X    errorStack = Tcl_GetVar (interp, "errorInfo", 1);
  677. X    if (errorStack != NULL)
  678. X        fprintf (stderr, "%s\n", errorStack);
  679. X    exit (1);
  680. X}
  681. X
  682. X/*
  683. X *----------------------------------------------------------------------
  684. X *
  685. X * ParseCmdArgs --
  686. X *
  687. X * Parse the arguments passed to the Tcl shell
  688. X *
  689. X * Parameters:
  690. X *     o argc, argv - Arguments passed to main.
  691. X *     o tclParmsPtr - Results of the parsed Tcl shell command line.
  692. X *----------------------------------------------------------------------
  693. X */
  694. Xstatic void
  695. XParseCmdArgs (argc, argv, tclParmsPtr)
  696. X    int          argc;
  697. X    char       **argv;
  698. X    tclParms_t  *tclParmsPtr;
  699. X{
  700. X    char   *scanPtr, *programName;
  701. X    int     programNameLen;
  702. X    int     option;
  703. X
  704. X    tclParmsPtr->execFile = FALSE;
  705. X    tclParmsPtr->execCommand = FALSE;
  706. X    tclParmsPtr->quickStartup = FALSE;
  707. X    tclParmsPtr->execStr = NULL;
  708. X
  709. X    /*
  710. X     * Determine file name (less directories) that the Tcl interpreter is
  711. X     * being run under.
  712. X     */
  713. X    scanPtr = programName = argv[0];
  714. X    while (*scanPtr != '\0') {
  715. X        if (*scanPtr == '/')
  716. X            programName = scanPtr + 1;
  717. X        scanPtr++;
  718. X    }
  719. X    tclParmsPtr->programName = programName;
  720. X    programNameLen = strlen (programName);
  721. X    
  722. X    /*
  723. X     * Scan arguments looking for flags to process here rather than to pass
  724. X     * on to the scripts.  The '-c' or '-f' must also be the last option to
  725. X     * allow for script arguments starting with `-'.
  726. X     */
  727. X    while ((option = getopt (argc, argv, "qc:f:u")) != -1) {
  728. X        switch (option) {
  729. X            case 'q':
  730. X                if (tclParmsPtr->quickStartup)
  731. X                    goto usageError;
  732. X                tclParmsPtr->quickStartup = TRUE;
  733. X                break;
  734. X            case 'c':
  735. X                tclParmsPtr->execCommand = TRUE;
  736. X                tclParmsPtr->execStr = optarg;
  737. X                goto exitParse;
  738. X            case 'f':
  739. X                tclParmsPtr->execFile = TRUE;
  740. X                tclParmsPtr->execStr = optarg;
  741. X                goto exitParse;
  742. X            case 'u':
  743. X            default:
  744. X                goto usageError;
  745. X        }
  746. X    }
  747. X    exitParse:
  748. X  
  749. X    /*
  750. X     * If neither `-c' nor `-f' were specified and at least one parameter
  751. X     * is supplied, then if is the file to execute.  The rest of the arguments
  752. X     * are passed to the script.  Check for '--' as the last option, this also
  753. X     * is a terminator for the file to execute.
  754. X     */
  755. X    if ((!tclParmsPtr->execCommand) && (!tclParmsPtr->execFile) &&
  756. X        (optind != argc) && !STREQU (argv [optind-1], "--")) {
  757. X        tclParmsPtr->execFile = TRUE;
  758. X        tclParmsPtr->execStr = argv [optind];
  759. X        optind++;
  760. X    }
  761. X
  762. X    tclParmsPtr->tclArgv = &argv [optind];
  763. X    tclParmsPtr->tclArgc = argc - optind;
  764. X    return;
  765. X
  766. XusageError:
  767. X    fprintf (stderr, "usage: %s %s\n", argv [0],
  768. X             "[-qu] [[-f] script]|[-c command] [args]");
  769. X    exit (1);
  770. X}
  771. X
  772. X/*
  773. X *----------------------------------------------------------------------
  774. X * FindDefaultFile --
  775. X *
  776. X *   Find the Tcl default file.  If is looked for in the following order:
  777. X *       o A environment variable named `TCLDEFAULT'.
  778. X *       o A file named `TCLDEFAULT'.
  779. X *       o The specified defaultFile (which normally has an version number
  780. X *         appended.
  781. X *   A tcl variable `TCLDEFAULT', will contain the path of the default file
  782. X *   to use after this procedure is executed, or a null string if it is not
  783. X *   found.
  784. X * Parameters
  785. X *     o interp (I) - A pointer to the interpreter.
  786. X *     o defaultFile (I) - The file name of the default file to use, it
  787. X *       normally contains a version number.
  788. X * Returns:
  789. X *     TCL_OK if all is ok, TCL_ERROR if a error occured.
  790. X *----------------------------------------------------------------------
  791. X */
  792. Xstatic int
  793. XFindDefaultFile (interp, defaultFile)
  794. X    Tcl_Interp  *interp;
  795. X    char        *defaultFile;
  796. X{
  797. X    char        *defaultFileToUse;
  798. X    struct stat  statBuf;
  799. X
  800. X    if ((defaultFileToUse = getenv ("TCLDEFAULT")) == NULL) {
  801. X        defaultFileToUse = "TCLDEFAULT";
  802. X        if (stat (defaultFileToUse, &statBuf) < 0) {
  803. X            defaultFileToUse = defaultFile;
  804. X        }
  805. X    }
  806. X    if (stat (defaultFileToUse, &statBuf) < 0)
  807. X        defaultFileToUse = "";
  808. X    if (Tcl_SetVar (interp, "TCLDEFAULT", defaultFileToUse,
  809. X                    TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL)
  810. X        return TCL_ERROR;
  811. X    else
  812. X        return TCL_OK;
  813. X}
  814. X
  815. X/*
  816. X *----------------------------------------------------------------------
  817. X * ProcessDefaultFile --
  818. X *
  819. X *   Process the Tcl default file and TclInit files.  The default file
  820. X * is the only file at a fixed path. It is a script file that usaually 
  821. X * defines a variable "TCLINIT", which has the path of the  full
  822. X * initialization file. The default file can also set things such as path
  823. X * variables.  If the TCLINIT variable is set, that file is then evaluated.
  824. X * If usually does the full Tcl initialization.
  825. X *
  826. X * Parameters
  827. X *     o interp  (I) - A pointer to the interpreter.
  828. X *     o defaultFile (I) - The file name of the default file to use, it
  829. X *       normally contains a version number.
  830. X *----------------------------------------------------------------------
  831. X */
  832. Xstatic void
  833. XProcessDefaultFile (interp, defaultFile)
  834. X    Tcl_Interp  *interp;
  835. X    char        *defaultFile;
  836. X{
  837. X    char *defaultFileToUse, *initFile;
  838. X
  839. X    defaultFileToUse = Tcl_GetVar (interp, "TCLDEFAULT", 1);
  840. X    if (*defaultFileToUse == '\0') {
  841. X        fflush (stdout);
  842. X        fprintf (stderr, "Can't access Tcl default file,\n");
  843. X        fprintf (stderr, "  Located in one of the following ways:\n");
  844. X        fprintf (stderr, "    Environment variable: `%s',\n", "TCLDEFAULT");
  845. X        fprintf (stderr, "    File in current directory: `TCLDEFAULT', or\n");
  846. X        fprintf (stderr, "    File `%s'.\n", defaultFile);
  847. X        exit (1);
  848. X    }
  849. X    if (Tcl_EvalFile (interp, defaultFileToUse) != TCL_OK)
  850. X        goto errorAbort;
  851. X    Tcl_ResetResult (interp);
  852. X
  853. X    initFile = Tcl_GetVar (interp, "TCLINIT", 1);
  854. X    if (initFile != NULL) {
  855. X        if (Tcl_EvalFile (interp, initFile) != TCL_OK)
  856. X            goto errorAbort;
  857. X        }
  858. X    Tcl_ResetResult (interp);
  859. X    return;
  860. X
  861. XerrorAbort:
  862. X    DumpTclError (interp);
  863. X}
  864. X
  865. X/*
  866. X *----------------------------------------------------------------------
  867. X *
  868. X * Tcl_Startup --
  869. X *
  870. X *      Initializes the Tcl extended environment.  This function runs the
  871. X *      TclInit.tcl command file and optionally creates an interactive 
  872. X *      command loop. See the user documentation for a complete description
  873. X *      of how this procedure works.
  874. X *
  875. X * Parameters
  876. X *     o interp - A pointer to the interpreter.
  877. X *     o argc, argv - Arguments passed to main.
  878. X *     o defaultFile (I) - The file name of the default file to use, it
  879. X *       normally contains a version number.
  880. X * Returns:
  881. X *   TCL_OK if all is ok, TCL_ERROR if an error occured.
  882. X *----------------------------------------------------------------------
  883. X */
  884. Xvoid
  885. XTcl_Startup (interp, argc, argv, defaultFile)
  886. X    Tcl_Interp  *interp;
  887. X    int          argc;
  888. X    CONST char **argv;
  889. X    CONST char  *defaultFile;
  890. X{
  891. X    int         result;
  892. X    char       *args, *cmdBuf;
  893. X    tclParms_t  tclParms;
  894. X
  895. X    /*
  896. X     * Initialize special commands needed by the shell.
  897. X     */    
  898. X    Tcl_CreateCommand (interp, "sourcepart", Tcl_SourcepartCmd,
  899. X                      (ClientData)NULL, (void (*)())NULL);
  900. X
  901. X    /*
  902. X     * Process the arguments.
  903. X     */
  904. X    ParseCmdArgs (argc, (char **) argv, &tclParms);
  905. X
  906. X    /*
  907. X     * Set Tcl variables based on the arguments parsed.
  908. X     */    
  909. X    if (Tcl_SetVar (interp, "programName", tclParms.programName, 
  910. X                    TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL)
  911. X        goto errorAbort;
  912. X
  913. X
  914. X    if (Tcl_SetVar (interp, "interactiveSession", 
  915. X                    (tclParms.execStr == NULL ? "1" : "0"), 
  916. X                    TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL)
  917. X        goto errorAbort;
  918. X
  919. X    args = Tcl_Merge (tclParms.tclArgc, tclParms.tclArgv);
  920. X    if (Tcl_SetVar (interp, "argv", args,
  921. X                    TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL)
  922. X        result = TCL_ERROR;
  923. X    else
  924. X        result = TCL_OK;
  925. X    ckfree (args);
  926. X    if (result != TCL_OK)
  927. X        goto errorAbort;
  928. X
  929. X    if (Tcl_SetVar (interp, "scriptName", 
  930. X                    tclParms.execFile ? tclParms.execStr : "", 
  931. X                    TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL)
  932. X        goto errorAbort;
  933. X
  934. X    /*
  935. X     * Locate the default file and save in Tcl var TCLDEFAULT.
  936. X     */
  937. X    if (FindDefaultFile (interp, (char *) defaultFile) != TCL_OK)
  938. X        goto errorAbort;
  939. X
  940. X    /*
  941. X     * If not quick startup, process the Tcl default file and execute the 
  942. X     * Tcl initialization file.
  943. X     */
  944. X    if (!tclParms.quickStartup) 
  945. X        ProcessDefaultFile (interp, (char*) defaultFile);
  946. X
  947. X    /*
  948. X     * If the invoked tcl interactively, give the user an interactive session,
  949. X     * otherwise, source the command file or execute the specified command.
  950. X     */
  951. X    if (tclParms.execFile) {
  952. X        result = Tcl_EvalFile (interp, tclParms.execStr);
  953. X        if (result != TCL_OK)
  954. X            goto errorAbort;
  955. X        Tcl_ResetResult (interp);
  956. X    } else if (tclParms.execCommand) {
  957. X        result = Tcl_Eval (interp, tclParms.execStr, 0, NULL);
  958. X        if (result != TCL_OK)
  959. X            goto errorAbort;
  960. X        Tcl_ResetResult (interp);
  961. X    } else
  962. X        Tcl_CommandLoop (interp, stdin, stdout, TRUE);
  963. X    return;
  964. X
  965. XerrorAbort:
  966. X    DumpTclError (interp);
  967. X}
  968. X
  969. END_OF_FILE
  970. if test 15114 -ne `wc -c <'extended/src/tclstartup.c'`; then
  971.     echo shar: \"'extended/src/tclstartup.c'\" unpacked with wrong size!
  972. fi
  973. # end of 'extended/src/tclstartup.c'
  974. fi
  975. if test -f 'extended/tcllib/buildhelp.tcl' -a "${1}" != "-c" ; then 
  976.   echo shar: Will not clobber existing file \"'extended/tcllib/buildhelp.tcl'\"
  977. else
  978. echo shar: Extracting \"'extended/tcllib/buildhelp.tcl'\" \(14897 characters\)
  979. sed "s/^X//" >'extended/tcllib/buildhelp.tcl' <<'END_OF_FILE'
  980. X#-----------------------------------------------------------------------------
  981. X#                                buildhelp.tcl
  982. X#-----------------------------------------------------------------------------
  983. X#
  984. X# Program to extract help files from TCL manual pages or TCL script files.
  985. X# The help directories are built as a hierarchical tree of subjects and help
  986. X# files.  
  987. X#
  988. X# For nroff man pages, the areas of text to extract are delimited with:
  989. X#
  990. X#     '@help: subjectdir/helpfile
  991. X#     '@endhelp
  992. X#
  993. X# start in column one. The text between these markers is extracted and stored
  994. X# in help/subjectdir/help.  The file must not exists, this is done to enforced 
  995. X# cleaning out the directories before help file generation is started, thus
  996. X# removing any stale files.  The extracted text is run through:
  997. X#
  998. X#     nroff -man|col -xb   {col -b on BSD derived systems}
  999. X#
  1000. X# If there is other text to include in the helpfile, but not in the manual 
  1001. X# page, the text, along with nroff formatting commands, may be included using:
  1002. X#
  1003. X#     '@:Other text to include in the help page.
  1004. X#
  1005. X# A entry in the brief file, used by apropos my be included by:
  1006. X#
  1007. X#     '@brief: Short, one line description
  1008. X#
  1009. X# These brief request must occur with in the bounds of a help section.
  1010. X#
  1011. X# If some header text, such as nroff macros, need to be preappended to the
  1012. X# text streem before it is run through nroff, then that text can be bracketed
  1013. X# with:
  1014. X#
  1015. X#     '@header
  1016. X#     '@endheader
  1017. X#
  1018. X# If multiple header blocks are encountered, they will all be preappended.
  1019. X#
  1020. X# A similar construct is used for manual page name index generation:
  1021. X#
  1022. X#      ;@index: subject1 subjectN
  1023. X#
  1024. X# This is used by `installTcl' to generate the name index files.  There should
  1025. X# be one per file, usuall right before the name line.  The subjects listed are
  1026. X# all of the procedures or commands to link to the manual page, usually the
  1027. X# same as on the .SH NAME line.
  1028. X#
  1029. X# For TCL script files, which are indentified because they end in ".tcl",
  1030. X# the text to be extracted is delimited by:
  1031. X#
  1032. X#    #@help: subjectdir/helpfile
  1033. X#    #@endhelp
  1034. X#
  1035. X# And brief lines are in the form:
  1036. X#
  1037. X#     #@brief: Short, one line description
  1038. X#
  1039. X# The only processing done on text extracted from .tcl files it to replace
  1040. X# the # in column one with a space.
  1041. X#
  1042. X#
  1043. X#-----------------------------------------------------------------------------
  1044. X# 
  1045. X# To run this program:
  1046. X#
  1047. X#   tcl buildhelp.tcl [-m mergeTree] [-i nameindex] helpDir file-1 file-2 ...
  1048. X#
  1049. X# o -m mergeTree is a tree of help code, plus a brief file to merge with the
  1050. X#   help files that are to be extracted.  This will become part of the new
  1051. X#   help tree.  Used to merge in the documentation from UCB Tcl.
  1052. X# o -i nameindex is an name index file to create from the '@index markers in
  1053. X#   the man files.
  1054. X# o helpDir is the help tree root directory.  helpDir should  exists, but any
  1055. X#   subdirectories that don't exists will be created.  helpDir should be
  1056. X#   cleaned up before the start of manual page generation, as this program
  1057. X#   will not overwrite existing files.
  1058. X# o file-n are the nroff manual pages (.man) or .tcl or .tlib files to extract
  1059. X#   the help files from.
  1060. X#-----------------------------------------------------------------------------
  1061. X
  1062. X#-----------------------------------------------------------------------------
  1063. X# Truncate a file name of a help file if the system does not support long
  1064. X# file names.  If the name starts with `Tcl_', then this prefix is removed.
  1065. X# If the name is then over 14 characters, it is truncated to 14 charactes
  1066. X#  
  1067. Xproc TruncFileName {pathName} {
  1068. X    global G_truncFileNames
  1069. X
  1070. X    if {!$G_truncFileNames} {
  1071. X        return $pathName}
  1072. X    set fileName [file tail $pathName]
  1073. X    if {"[crange $fileName 0 3]" == "Tcl_"} {
  1074. X        set fileName [crange $fileName 4 end]}
  1075. X    set fileName [crange $fileName 0 13]
  1076. X    return "[file dirname $pathName]/$fileName"
  1077. X}
  1078. X
  1079. X#-----------------------------------------------------------------------------
  1080. X# Proc to ensure that all directories for the specified file path exists,
  1081. X# and if they don't create them.
  1082. X
  1083. Xproc EnsureDirs {filePath} {
  1084. X    set dirPath [file dirname $filePath]
  1085. X    if {![file exists $dirPath]} {
  1086. X        mkdir -path $dirPath}
  1087. X}
  1088. X
  1089. X
  1090. X#-----------------------------------------------------------------------------
  1091. X#
  1092. X# Proc to extract nroff text to use as a header to all pass to nroff when
  1093. X# processing a help file.
  1094. X#    manPageFH - The file handle of the manual page.
  1095. X#
  1096. X
  1097. Xproc ExtractNroffHeader {manPageFH} {
  1098. X    global nroffHeader
  1099. X    while {[gets $manPageFH manLine] >= 0} {
  1100. X        if {[string first "'@endheader" $manLine] == 0} {
  1101. X            break;
  1102. X            }
  1103. X        if {[string first "'@:" $manLine] == 0} {
  1104. X            set manLine [csubstr manLine 3 end]
  1105. X            }
  1106. X        append nroffHeader "$manLine\n"
  1107. X        }
  1108. X}
  1109. X
  1110. X#-----------------------------------------------------------------------------
  1111. X#
  1112. X# Proc to extract a nroff help file when it is located in the text.
  1113. X#    manPageFH - The file handle of the manual page.
  1114. X#    manLine - The '@help: line starting the data to extract.
  1115. X#
  1116. X
  1117. Xproc ExtractNroffHelp {manPageFH manLine} {
  1118. X    global G_helpDir nroffHeader G_briefHelpFH G_colArgs
  1119. X
  1120. X    set helpName [string trim [csubstr $manLine 7 end]]
  1121. X    set helpFile [TruncFileName "$G_helpDir/$helpName"]
  1122. X    if {[file exists $helpFile]} {
  1123. X        error "Help file already exists: $helpFile"}
  1124. X    EnsureDirs $helpFile
  1125. X    set helpFH [open "| nroff -man | col $G_colArgs > $helpFile" w]
  1126. X    echo "    creating help file $helpName"
  1127. X
  1128. X    # Nroff commands from .TH macro to get the formatting right.  The `\n'
  1129. X    # are newline separators to output, the `\\n' become `\n' in the text.
  1130. X        
  1131. X    puts $helpFH ".ad b\n.PD\n.nrIN \\n()Mu\n.nr)R 0\n.nr)I \\n()Mu"
  1132. X    puts $helpFH ".nr)R 0\n.\}E\n.DT\n.na\n.nh"
  1133. X    puts $helpFH $nroffHeader
  1134. X    set foundBrief 0
  1135. X    while {[gets $manPageFH manLine] >= 0} {
  1136. X        if {[string first "'@endhelp" $manLine] == 0} {
  1137. X            break;
  1138. X        }
  1139. X        if {[string first "'@brief:" $manLine] == 0} {
  1140. X            if $foundBrief {
  1141. X                error {Duplicate "'@brief" entry"}
  1142. X            }
  1143. X            set foundBrief 1
  1144. X        puts $G_briefHelpFH "$helpName\t[csubstr $manLine 8 end]"
  1145. X            continue;
  1146. X        }
  1147. X        if {[string first "'@:" $manLine] == 0} {
  1148. X            set manLine [csubstr $manLine 3 end]
  1149. X        }
  1150. X        if {[string first "'@help" $manLine] == 0} {
  1151. X            error {"'@help" found within another help section"}
  1152. X        }
  1153. X        puts $helpFH $manLine
  1154. X        }
  1155. X    close $helpFH
  1156. X    chmod a-w,a+r $helpFile
  1157. X}
  1158. X
  1159. X#-----------------------------------------------------------------------------
  1160. X#
  1161. X# Proc to extract a tcl script help file when it is located in the text.
  1162. X#    ScriptPageFH - The file handle of the .tcl file.
  1163. X#    ScriptLine - The #@help: line starting the data to extract.
  1164. X#
  1165. X
  1166. Xproc ExtractScriptHelp {ScriptPageFH ScriptLine} {
  1167. X    global G_helpDir G_briefHelpFH
  1168. X    set helpName [string trim [csubstr $ScriptLine 7 end]]
  1169. X    set helpFile "$G_helpDir/$helpName"
  1170. X    if {[file exists $helpFile]} {
  1171. X        error "Help file already exists: $helpFile"}
  1172. X    EnsureDirs $helpFile
  1173. X    set helpFH [open $helpFile w]
  1174. X    echo "    creating help file $helpName"
  1175. X    set foundBrief 0
  1176. X    while {[gets $ScriptPageFH ScriptLine] >= 0} {
  1177. X        if {[string first "#@endhelp" $ScriptLine] == 0} {
  1178. X            break;
  1179. X        }
  1180. X        if {[string first "#@brief:" $ScriptLine] == 0} {
  1181. X            if $foundBrief {
  1182. X                error {Duplicate "#@brief" entry"}
  1183. X            }
  1184. X            set foundBrief 1
  1185. X        puts $G_briefHelpFH "$helpName\t[csubstr $ScriptLine 8 end]"
  1186. X            continue;
  1187. X        }
  1188. X        if {[string first "#@help" $ScriptLine] == 0} {
  1189. X            error {"#@help" found within another help section"}
  1190. X        }
  1191. X        if {[clength $ScriptLine] > 1} {
  1192. X            set ScriptLine " [csubstr $ScriptLine 1 end]"
  1193. X        } else {
  1194. X            set ScriptLine ""
  1195. X        }
  1196. X        puts $helpFH $ScriptLine
  1197. X        }
  1198. X    close $helpFH
  1199. X    chmod a-w,a+r $helpFile
  1200. X}
  1201. X
  1202. X#-----------------------------------------------------------------------------
  1203. X#
  1204. X# Proc to scan a nroff manual file looking for the start of a help text
  1205. X# sections and extracting those sections.
  1206. X#    pathName - Full path name of file to extract documentation from.
  1207. X#
  1208. X
  1209. Xproc ProcessNroffFile {pathName} {
  1210. X   global G_nroffScanCT G_scriptScanCT nroffHeader
  1211. X
  1212. X   set fileName [file tail $pathName]
  1213. X
  1214. X   set nroffHeader {}
  1215. X   set manPageFH [open $pathName r]
  1216. X   echo "    scanning $pathName"
  1217. X   set matchInfo(fileName) [file tail $pathName]
  1218. X   scanfile $G_nroffScanCT $manPageFH
  1219. X   close $manPageFH
  1220. X}
  1221. X
  1222. X#-----------------------------------------------------------------------------
  1223. X#
  1224. X# Proc to scan a Tcl script file looking for the start of a
  1225. X# help text sections and extracting those sections.
  1226. X#    pathName - Full path name of file to extract documentation from.
  1227. X#
  1228. X
  1229. Xproc ProcessTclScript {pathName} {
  1230. X   global G_scriptScanCT nroffHeader
  1231. X
  1232. X   set scriptFH [open "$pathName" r]
  1233. X
  1234. X   echo "    scanning $pathName"
  1235. X   set matchInfo(fileName) [file tail $pathName]
  1236. X   scanfile $G_scriptScanCT $scriptFH
  1237. X   close $scriptFH
  1238. X}
  1239. X
  1240. X#-----------------------------------------------------------------------------
  1241. X# Proc to copy the help merge tree, excluding the brief file.
  1242. X# 
  1243. X
  1244. Xproc CopyMergeTree {helpDirPath mergeTree} {
  1245. X    if {"[cindex $helpDirPath 0]" != "/"} {
  1246. X        set helpDirPath "[pwd]/$helpDirPath"
  1247. X    }
  1248. X    set oldDir [pwd]
  1249. X    cd $mergeTree
  1250. X
  1251. X    set curHelpDir "."
  1252. X
  1253. X    for_recursive_glob mergeFile {.} {
  1254. X        if {"$mergeFile" == "./brief"} {
  1255. X            continue}
  1256. X            set helpFile "$helpDirPath/$mergeFile"
  1257. X        if {[file isdirectory $mergeFile]} {
  1258. X            if ![file exists $helpFile] {
  1259. X                mkdir $helpFile
  1260. X                chmod go-w,a+rx $helpFile
  1261. X            }
  1262. X        } else {
  1263. X            if {[file exists $helpFile]} {
  1264. X                error "Help file already exists: $helpFile"}
  1265. X            set inFH [open $mergeFile r]
  1266. X            set outFH [open $helpFile w]
  1267. X            copyfile $inFH $outFH
  1268. X            close $outFH
  1269. X            close $inFH
  1270. X            chmod a-w,a+r $helpFile
  1271. X        }
  1272. X    }
  1273. X    cd $oldDir
  1274. X}
  1275. X
  1276. X#-----------------------------------------------------------------------------
  1277. X# GenerateHelp: main procedure.  Generates help from specified files.
  1278. X#    helpDirPath - Directory were the help files go.
  1279. X#    mergeTree - Help file tree to merge with the extracted help files.
  1280. X#    manIndexFile - Manual page index file to build, or {} to not build one.
  1281. X#    sourceFiles - List of files to extract help files from.
  1282. X
  1283. Xproc GenerateHelp {helpDirPath mergeTree manIndexFile sourceFiles} {
  1284. X    global G_helpDir G_truncFileNames G_manIndexFH G_nroffScanCT
  1285. X    global G_scriptScanCT G_briefHelpFH G_colArgs
  1286. X
  1287. X    echo ""
  1288. X    echo "Begin building help tree"
  1289. X
  1290. X    # Determine version of col command to use (no -x on BSD)
  1291. X    if {[system {col -bx </dev/null >/dev/null 2>&1}] != 0} {
  1292. X        set G_colArgs {-b}
  1293. X    } else {
  1294. X        set G_colArgs {-bx}
  1295. X    }
  1296. X    set G_helpDir [glob $helpDirPath]
  1297. X
  1298. X    if {![file isdirectory $G_helpDir]} {
  1299. X        error [concat "$G_helpDir is not a directory or does not exist. "  
  1300. X                      "This should be the help root directory"]
  1301. X    }
  1302. X        
  1303. X    set status [catch {set tmpFH [open xxx $G_helpDir/AVeryVeryBigFileName w]}]
  1304. X    if {$status != 0} {
  1305. X        set G_truncFileNames 1
  1306. X    } else {
  1307. X        close $tmpFH
  1308. X        unlink $G_helpDir/AVeryVeryBigFileName
  1309. X        set G_truncFileNames 0
  1310. X    }
  1311. X
  1312. X    set G_manIndexFH {}
  1313. X    if {![lempty $manIndexFile]} {
  1314. X        set G_manIndexFH [open $manIndexFile w]
  1315. X    }
  1316. X
  1317. X    set G_nroffScanCT [scancontext create]
  1318. X
  1319. X    scanmatch $G_nroffScanCT "^'@help:" {
  1320. X        ExtractNroffHelp $matchInfo(handle) $matchInfo(line)
  1321. X        continue
  1322. X    }
  1323. X
  1324. X    scanmatch $G_nroffScanCT "^'@header" {
  1325. X        ExtractNroffHeader $matchInfo(handle)
  1326. X        continue
  1327. X    }
  1328. X    scanmatch $G_nroffScanCT "^'@endhelp" {
  1329. X        error [concat {"'@endhelp" without corresponding "'@help:"} \
  1330. X                 ", offset = $matchInfo(offset)"]
  1331. X    }
  1332. X    scanmatch $G_nroffScanCT "^'@brief" {
  1333. X        error [concat {"'@brief" without corresponding "'@help:"}
  1334. X                 ", offset = $matchInfo(offset)"]
  1335. X    }
  1336. X
  1337. X    scanmatch $G_nroffScanCT "^'@index:" {
  1338. X        global G_manIndexFH
  1339. X        if {[llength $matchInfo(line)] == 1} {
  1340. X            error "no subjects specified in \"'@index:\" line"}
  1341. X        if {![lempty $G_manIndexFH]} {
  1342. X            puts $G_manIndexFH [concat $matchInfo(fileName) \
  1343. X                                       [list [lrange $matchInfo(line) 1 end]]]
  1344. X        }
  1345. X    }
  1346. X
  1347. X    set G_scriptScanCT [scancontext create]
  1348. X    scanmatch $G_scriptScanCT "^#@help:" {
  1349. X        ExtractScriptHelp $matchInfo(handle) $matchInfo(line)
  1350. X    }
  1351. X
  1352. X    if ![lempty $mergeTree] {
  1353. X        echo "    Merging tree: $mergeTree"
  1354. X        CopyMergeTree $helpDirPath $mergeTree
  1355. X    }
  1356. X
  1357. X    set G_briefHelpFH [open "|sort > $G_helpDir/brief" w]
  1358. X
  1359. X    if {(![lempty $mergeTree]) && [file exists $mergeTree/brief]} {
  1360. X        echo "    Merging file: $mergeTree/brief"
  1361. X        set mergeBriefFH [open $mergeTree/brief r]
  1362. X        puts $G_briefHelpFH [read $mergeBriefFH]
  1363. X        close $mergeBriefFH
  1364. X    }
  1365. X    foreach manFile $sourceFiles {
  1366. X        set manFile [glob $manFile]
  1367. X        set ext [file extension $manFile]
  1368. X        if {"$ext" == ".man"} {
  1369. X            set status [catch {ProcessNroffFile $manFile} msg]
  1370. X        } else {
  1371. X            set status [catch {ProcessTclScript $manFile} msg]
  1372. X        }
  1373. X        if {$status != 0} {
  1374. X            echo "Error extracting help from: $manFile"
  1375. X            echo $msg
  1376. X            global errorInfo interactiveSession
  1377. X            if {!$interactiveSession} {
  1378. X                echo $errorInfo
  1379. X                exit 1
  1380. X            }
  1381. X        }
  1382. X    }
  1383. X
  1384. X    close $G_briefHelpFH
  1385. X    chmod a-w,a+r $G_helpDir/brief
  1386. X    close $G_manIndexFH
  1387. X    echo "*** completed extraction of all help files"
  1388. X}
  1389. X
  1390. X#-----------------------------------------------------------------------------
  1391. X# Print a usage message and exit the program
  1392. Xproc Usage {} {
  1393. X    echo {Wrong args: [-m mergetree] [-i index] helpdir manfile1 [manfile2..]}
  1394. X    exit 1
  1395. X}
  1396. X
  1397. X#-----------------------------------------------------------------------------
  1398. X# Main program body, decides if help is interactive or batch.
  1399. X
  1400. Xif {$interactiveSession} {
  1401. X    echo "To extract help, use the command:"
  1402. X    echo "  GenerateHelp helpDirPath [mergetree|{}] [namefile|{}] sourceFiles"
  1403. X} else {
  1404. X    set mergeTree {}
  1405. X    set manIndexFile {}
  1406. X    while {[string match "-*" [lindex $argv 0]]} {
  1407. X        set flag [lvarpop argv 0]
  1408. X        case $flag in {
  1409. X            "-m" {set mergeTree [lvarpop argv 0]}
  1410. X            "-i" {set manIndexFile [lvarpop argv 0]}
  1411. X            default Usage
  1412. X        }
  1413. X    }
  1414. X    if {[llength $argv] < 2} {
  1415. X        Usage
  1416. X    }
  1417. X    GenerateHelp [lindex $argv 0] $mergeTree $manIndexFile [lrange $argv 1 end]
  1418. X   
  1419. X}
  1420. END_OF_FILE
  1421. if test 14897 -ne `wc -c <'extended/tcllib/buildhelp.tcl'`; then
  1422.     echo shar: \"'extended/tcllib/buildhelp.tcl'\" unpacked with wrong size!
  1423. fi
  1424. # end of 'extended/tcllib/buildhelp.tcl'
  1425. fi
  1426. echo shar: End of archive 16 \(of 23\).
  1427. cp /dev/null ark16isdone
  1428. MISSING=""
  1429. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
  1430.     if test ! -f ark${I}isdone ; then
  1431.     MISSING="${MISSING} ${I}"
  1432.     fi
  1433. done
  1434. if test "${MISSING}" = "" ; then
  1435.     echo You have unpacked all 23 archives.
  1436.     echo "Now cd to "extended", edit the makefile, then do a "make""
  1437.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1438. else
  1439.     echo You still need to unpack the following archives:
  1440.     echo "        " ${MISSING}
  1441. fi
  1442. ##  End of shell archive.
  1443. exit 0
  1444.  
  1445. exit 0 # Just in case...
  1446. -- 
  1447. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1448. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1449. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1450. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1451.