]> cvs.zerfleddert.de Git - micropolis/blob - src/tclx/src/tclxlib.c
Fixes for compilation with gcc 15
[micropolis] / src / tclx / src / tclxlib.c
1 /*
2 * tclXlib.c --
3 *
4 * Tcl commands to load libraries of Tcl code.
5 *-----------------------------------------------------------------------------
6 * Copyright 1992 Karl Lehenbauer and Mark Diekhans.
7 *
8 * Permission to use, copy, modify, and distribute this software and its
9 * documentation for any purpose and without fee is hereby granted, provided
10 * that the above copyright notice appear in all copies. Karl Lehenbauer and
11 * Mark Diekhans make no representations about the suitability of this
12 * software for any purpose. It is provided "as is" without express or
13 * implied warranty.
14 *-----------------------------------------------------------------------------
15 * $Id: tclXlib.c,v 2.0 1992/10/16 04:50:55 markd Rel $
16 *-----------------------------------------------------------------------------
17 */
18
19 /*-----------------------------------------------------------------------------
20 *
21 * The following data structures are used by the Tcl library code. All
22 * structures are kept in the global array TCLENV, so that Tcl procs may be
23 * written to access them.
24 *
25 * o fileId - This is a small string used to uniquely identify a file, it is
26 * in the form "@$dev:$inode", where dev and inode are the values obtained
27 * from stat.
28 *
29 * o TCLENV(fileId} filePath - This entry translates a file id to an
30 * file name, which may be an absolute path to a file or the name of
31 * a file to find by searching a path.
32 *
33 * o TCLENV(PKG:$packageName) {$fileId $offset $length} - This entry
34 * translates a package name into a fileId of the file containing the
35 * package and the byte and offset length of the package within the file.
36 *
37 * o TCLENV(PROC:$proc) {P $packageName} - This form of a procedure entry
38 * translates a procedure into a package name.
39 *
40 * o TCLENV(PROC:$proc) {F $fileName} 0 - This form of a procedure entry
41 * translates a procedure into a file name. The file name may be an
42 * absolute path to the file or a file to be found by searching TCLPATH
43 * or auto_path.
44 *-----------------------------------------------------------------------------
45 */
46 #include "tclxint.h"
47
48 typedef char fileId_t [64];
49
50 /*
51 * Prototypes of internal functions.
52 */
53 static int
54 EvalFilePart _ANSI_ARGS_((Tcl_Interp *interp,
55 char *fileName,
56 long offset,
57 unsigned length));
58
59 static char *
60 MakeAbsFile _ANSI_ARGS_((Tcl_Interp *interp,
61 char *fileName,
62 char *buffer,
63 int bufferSize));
64
65 static int
66 GenerateFileId _ANSI_ARGS_((Tcl_Interp *interp,
67 char *filePath,
68 fileId_t fileId));
69
70 static int
71 SetTCLENVFileIdEntry _ANSI_ARGS_((Tcl_Interp *interp,
72 fileId_t fileId,
73 char *filePath));
74
75 static int
76 CheckTCLENVFileIdEntry _ANSI_ARGS_((Tcl_Interp *interp,
77 char *filePath));
78
79 static char *
80 GetTCLENVFileIdEntry _ANSI_ARGS_((Tcl_Interp *interp,
81 fileId_t fileId));
82
83 static int
84 SetTCLENVPkgEntry _ANSI_ARGS_((Tcl_Interp *interp,
85 char *packageName,
86 fileId_t fileId,
87 char *offset,
88 char *length));
89
90 static int
91 GetTCLENVPkgEntry _ANSI_ARGS_((Tcl_Interp *interp,
92 char *packageName,
93 char *fileId,
94 long *offsetPtr,
95 unsigned *lengthPtr));
96
97 static int
98 SetTCLENVProcEntry _ANSI_ARGS_((Tcl_Interp *interp,
99 char *procName,
100 char *type,
101 char *location));
102
103 static int
104 GetTCLENVProcEntry _ANSI_ARGS_((Tcl_Interp *interp,
105 char *procName,
106 char *typePtr,
107 char **locationPtr));
108
109 static int
110 ProcessIndexFile _ANSI_ARGS_((Tcl_Interp *interp,
111 char *tlibFilePath,
112 char *tndxFilePath));
113
114 static int
115 BuildPackageIndex _ANSI_ARGS_((Tcl_Interp *interp,
116 char *tlibFilePath));
117
118 static int
119 LoadPackageIndex _ANSI_ARGS_((Tcl_Interp *interp,
120 char *tlibFilePath,
121 int pathLen,
122 int dirLen));
123
124 static int
125 LoadOusterIndex _ANSI_ARGS_((Tcl_Interp *interp,
126 char *indexFilePath,
127 int dirLen));
128
129 static int
130 LoadDirIndexes _ANSI_ARGS_((Tcl_Interp *interp,
131 char *dirName));
132
133 static int
134 LoadPackageIndexes _ANSI_ARGS_((Tcl_Interp *interp,
135 char *path));
136
137 static int
138 LoadProc _ANSI_ARGS_((Tcl_Interp *interp,
139 char *procName,
140 int *foundPtr));
141
142 \f
143 /*
144 *-----------------------------------------------------------------------------
145 *
146 * EvalFilePart --
147 *
148 * Read in a byte range of a file and evaulate it.
149 *
150 * Parameters:
151 * o interp (I) - A pointer to the interpreter, error returned in result.
152 * o fileName (I) - The file to evaulate.
153 * o offset (I) - Byte offset into the file of the area to evaluate
154 * o length (I) - Number of bytes to evaulate..
155 *
156 * Results:
157 * A standard Tcl result.
158 *-----------------------------------------------------------------------------
159 */
160 static int
161 EvalFilePart (Tcl_Interp *interp, char *fileName, long offset, unsigned length)
162 {
163 Interp *iPtr = (Interp *) interp;
164 int fileNum, result;
165 struct stat statBuf;
166 char *oldScriptFile, *cmdBuffer;
167
168
169 if (fileName [0] == '~')
170 if ((fileName = Tcl_TildeSubst (interp, fileName)) == NULL)
171 return TCL_ERROR;
172
173 fileNum = open (fileName, O_RDONLY, 0);
174 if (fileNum < 0) {
175 Tcl_AppendResult (interp, "open failed on: ", fileName, ": ",
176 Tcl_UnixError (interp), (char *) NULL);
177 return TCL_ERROR;
178 }
179 if (fstat (fileNum, &statBuf) == -1)
180 goto accessError;
181
182 if ((statBuf.st_size < offset + length) || (offset < 0)) {
183 Tcl_AppendResult (interp, "range to eval outside of file bounds \"",
184 fileName, "\"", (char *) NULL);
185 close (fileNum);
186 return TCL_ERROR;
187 }
188 if (lseek (fileNum, offset, 0) < 0)
189 goto accessError;
190
191 cmdBuffer = ckalloc (length + 1);
192 if (read (fileNum, cmdBuffer, length) != length)
193 goto accessError;
194
195 cmdBuffer [length] = '\0';
196
197 if (close (fileNum) != 0)
198 goto accessError;
199
200 oldScriptFile = iPtr->scriptFile;
201 iPtr->scriptFile = fileName;
202
203 result = Tcl_Eval (interp, cmdBuffer, 0, (char **) NULL);
204
205 iPtr->scriptFile = oldScriptFile;
206 ckfree (cmdBuffer);
207
208 if (result != TCL_ERROR)
209 return TCL_OK;
210
211 /*
212 * An error occured. Record information telling where it came from.
213 */
214 {
215 char buf [100];
216 sprintf (buf, "\n (file \"%.50s\" line %d)", fileName,
217 interp->errorLine);
218 Tcl_AddErrorInfo(interp, buf);
219 }
220 return TCL_ERROR;
221
222 /*
223 * Errors accessing the file once its opened are handled here.
224 */
225 accessError:
226 Tcl_AppendResult (interp, "error accessing: ", fileName, ": ",
227 Tcl_UnixError (interp), (char *) NULL);
228
229 close (fileNum);
230 return TCL_ERROR;
231 }
232 \f
233 /*
234 *-----------------------------------------------------------------------------
235 *
236 * MakeAbsFile --
237 *
238 * Convert a file name to an absolute path. This handles tilde substitution
239 * and preappend the current directory name if the path is relative.
240 *
241 * Parameters
242 * o interp (I) - A pointer to the interpreter, error returned in result.
243 * o fileName (I) - File name (should not start with a "/").
244 * o buffer (O) - Buffer to store string in, if it will fit.
245 * o bufferSize (I) - Size of buffer.
246 * Returns:
247 * A pointer to the file name. If the string would fit in buffer, then
248 * a pointer to buffer is returned, otherwise a dynamicaly allocated file
249 * name. NULL is returned if an error occured.
250 *-----------------------------------------------------------------------------
251 */
252 static char *
253 MakeAbsFile (Tcl_Interp *interp, char *fileName, char *buffer, int bufferSize)
254 {
255 char curDir [MAXPATHLEN+1];
256 char *pathName;
257 int pathLen;
258
259 if (fileName [0] == '~') {
260 fileName = Tcl_TildeSubst (interp, fileName);
261 if (fileName == NULL)
262 return NULL;
263 pathLen = strlen (fileName);
264 if (pathLen < bufferSize)
265 pathName = buffer;
266 else
267 pathName = ckalloc (pathLen + 1);
268 strcpy (pathName, fileName);
269 return pathName;
270 }
271
272 #if TCL_GETWD
273 if (getwd (curDir) == NULL) {
274 Tcl_AppendResult (interp, "error getting working directory name: ",
275 curDir, (char *) NULL);
276 }
277 #else
278 if (getcwd (curDir, MAXPATHLEN) == 0) {
279 Tcl_AppendResult (interp, "error getting working directory name: ",
280 Tcl_UnixError (interp), (char *) NULL);
281 }
282 #endif
283 pathLen = strlen (curDir) + strlen (fileName) + 1; /* For `/' */
284 if (pathLen < bufferSize)
285 pathName = buffer;
286 else
287 pathName = ckalloc (pathLen + 1);
288 strcpy (pathName, curDir);
289 strcat (pathName, "/");
290 strcat (pathName, fileName);
291
292 return pathName;
293 }
294 \f
295 /*
296 *-----------------------------------------------------------------------------
297 *
298 * GenerateFileId --
299 *
300 * Given a path to a file, generate its file Id, in the form:
301 *
302 * "@dev:inode"
303 *
304 * Parameters
305 * o interp (I) - A pointer to the interpreter, error returned in result.
306 * o filepath (I) - Absolute path to the file.
307 * o fileId (O) - File id is returned here.
308 * Returns:
309 * TCL_OK or TCL_ERROR.
310 *-----------------------------------------------------------------------------
311 */
312 static int
313 GenerateFileId (Tcl_Interp *interp, char *filePath, fileId_t fileId)
314 {
315 struct stat statInfo;
316
317 if (stat (filePath, &statInfo) < 0) {
318 Tcl_AppendResult (interp, "stat of \"", filePath, "\" failed: ",
319 Tcl_UnixError (interp), (char *) NULL);
320 return TCL_ERROR;
321 }
322
323 sprintf (fileId, "@%d:%d", statInfo.st_dev, statInfo.st_ino);
324
325 return TCL_OK;
326 }
327 \f
328 /*
329 *-----------------------------------------------------------------------------
330 *
331 * SetTCLENVFileIdEntry --
332 *
333 * Set a file entry in the TCLENV array for a file path in the form:
334 *
335 * TCLENV(@dev:inode) filepath
336 *
337 * This entry translates a dev:info into a full file path.
338 *
339 * Parameters
340 * o interp (I) - A pointer to the interpreter, error returned in result.
341 * o fileId (I) - The file Id for the file.
342 * o filepath (I) - Absolute path to the file.
343 * Returns:
344 * TCL_OK or TCL_ERROR.
345 *-----------------------------------------------------------------------------
346 */
347 static int
348 SetTCLENVFileIdEntry (Tcl_Interp *interp, fileId_t fileId, char *filePath)
349 {
350
351 if (Tcl_SetVar2 (interp, "TCLENV", fileId, filePath,
352 TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL)
353 return TCL_ERROR;
354
355 return TCL_OK;
356 }
357 \f
358 /*
359 *-----------------------------------------------------------------------------
360 *
361 * CheckTCLENVFileIdEntry --
362 *
363 * Check if there is a file entry in for the specified file.
364 *
365 * Parameters
366 * o interp (I) - A pointer to the interpreter.
367 * o filePath (I) - Absolute path to the library file.
368 * Returns:
369 * TRUE is returned if the entry exists, FALSE if it doesn't.
370 *-----------------------------------------------------------------------------
371 */
372 static int
373 CheckTCLENVFileIdEntry (Tcl_Interp *interp, char *filePath)
374 {
375 fileId_t fileId;
376
377 /*
378 * If we can't generate the Id (stat failed), then just say it doesn't
379 * exists, other, complain later when an attempt is made to process it.
380 */
381 if (GenerateFileId (interp, filePath, fileId) != TCL_OK) {
382 Tcl_ResetResult (interp);
383 return FALSE;
384 }
385
386 if (Tcl_GetVar2 (interp, "TCLENV", fileId, TCL_GLOBAL_ONLY) == NULL)
387 return FALSE;
388
389 return TRUE;
390 }
391 \f
392 /*
393 *-----------------------------------------------------------------------------
394 *
395 * GetTCLENVFileIdEntry --
396 *
397 * Translate a file id into a file path.
398 *
399 * Parameters
400 * o interp (I) - A pointer to the interpreter.
401 * o fileId (I) - The file identifier, in the form: "@$dev:$inode"
402 * Returns:
403 * A pointer to the absolute path to the library file is returned
404 * here. This pointer remains valid until the TCLENV entry is changed,
405 * do not free.
406 *-----------------------------------------------------------------------------
407 */
408 static char *
409 GetTCLENVFileIdEntry (Tcl_Interp *interp, fileId_t fileId)
410 {
411 char *filePath;
412
413 filePath = Tcl_GetVar2 (interp, "TCLENV", fileId, TCL_GLOBAL_ONLY);
414 if (filePath == NULL) {
415 Tcl_AppendResult (interp, "TCLENV file id entry not found for: \"",
416 fileId, "\"", (char *) NULL);
417 return NULL;
418 }
419
420 return filePath;
421 }
422 \f
423 /*
424 *-----------------------------------------------------------------------------
425 *
426 * SetTCLENVPkgEntry --
427 *
428 * Set the package entry in the TCLENV array for a package in the form:
429 *
430 * TCLENV(PKG:$packageName) [list $fileId $offset $length]
431 *
432 * Duplicate package names are rejected.
433 *
434 * Parameters
435 * o interp (I) - A pointer to the interpreter, error returned in result.
436 * o packageName (I) - Package name.
437 * o fileId (I) - File id for the file.
438 * o offset (I) - String containing the numeric start of the package.
439 * o length (I) - Strign containing the numeric length of the package.
440 * Returns:
441 * TCL_OK,r TCL_ERROR of TCL_CONTINUE if the package name is already defined
442 * and should be skipped.
443 *-----------------------------------------------------------------------------
444 */
445 static int
446 SetTCLENVPkgEntry (Tcl_Interp *interp, char *packageName, fileId_t fileId, char *offset, char *length)
447 {
448 int nameLen;
449 char indexBuffer [64], *indexPtr;
450 char *pkgDataArgv [3], *dataStr, *setResult;
451
452 nameLen = strlen (packageName) + 5; /* includes "PKG:" and '\0' */
453 if (nameLen <= sizeof (indexBuffer))
454 indexPtr = indexBuffer;
455 else
456 indexPtr = ckalloc (nameLen);
457
458 strcpy (indexPtr, "PKG:");
459 strcpy (indexPtr + 4, packageName);
460
461 /*
462 * Check for duplicate package name.
463 */
464 if (Tcl_GetVar2 (interp, "TCLENV", indexPtr, TCL_GLOBAL_ONLY) != NULL) {
465 if (indexPtr != indexBuffer)
466 ckfree (indexPtr);
467 return TCL_CONTINUE;
468 }
469
470 pkgDataArgv [0] = fileId;
471 pkgDataArgv [1] = offset;
472 pkgDataArgv [2] = length;
473 dataStr = Tcl_Merge (3, pkgDataArgv);
474
475 setResult = Tcl_SetVar2 (interp, "TCLENV", indexPtr, dataStr,
476 TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG);
477 ckfree (dataStr);
478 if (indexPtr != indexBuffer)
479 ckfree (indexPtr);
480
481 return (setResult == NULL) ? TCL_ERROR : TCL_OK;
482 }
483 \f
484 /*
485 *-----------------------------------------------------------------------------
486 *
487 * GetTCLENVPkgEntry --
488 *
489 * Get the package entry in the TCLENV array for a package.
490 *
491 * Parameters
492 * o interp (I) - A pointer to the interpreter, error returned in result.
493 * o packageName (I) - Package name to find.
494 * o fileId (O) - The fileId for the library file is returned here.
495 * o offsetPtr (O) - Start of the package in the library.
496 * o lengthPtr (O) - Length of the package in the library.
497 * Returns:
498 * TCL_OK or TCL_ERROR.
499 *-----------------------------------------------------------------------------
500 */
501 static int
502 GetTCLENVPkgEntry (Tcl_Interp *interp, char *packageName, fileId_t fileId, long *offsetPtr, unsigned *lengthPtr)
503 {
504 int nameLen, pkgDataArgc;
505 char indexBuffer [64], *indexPtr;
506 char *dataStr, **pkgDataArgv = NULL;
507 register char *srcPtr, *destPtr;
508
509 nameLen = strlen (packageName) + 5; /* includes "PKG:" and '\0' */
510 if (nameLen <= sizeof (indexBuffer))
511 indexPtr = indexBuffer;
512 else
513 indexPtr = ckalloc (nameLen);
514
515 strcpy (indexPtr, "PKG:");
516 strcpy (indexPtr + 4, packageName);
517
518 dataStr = Tcl_GetVar2 (interp, "TCLENV", indexPtr, TCL_GLOBAL_ONLY);
519 if (dataStr == NULL) {
520 Tcl_AppendResult (interp, "entry not found in TCLENV for package \"",
521 packageName, "\"", (char *) NULL);
522 if (indexPtr != indexBuffer)
523 ckfree (indexPtr);
524 return TCL_ERROR;
525 }
526
527 /*
528 * Extract the data from the array entry.
529 */
530
531 if (Tcl_SplitList (interp, dataStr, &pkgDataArgc,
532 &pkgDataArgv) != TCL_OK)
533 goto invalidEntry;
534 if (pkgDataArgc != 3)
535 goto invalidEntry;
536 if (strlen (pkgDataArgv [0]) >= sizeof (fileId_t))
537 goto invalidEntry;
538 strcpy (fileId, pkgDataArgv [0]);
539 if (!Tcl_StrToLong (pkgDataArgv [1], 0, offsetPtr))
540 goto invalidEntry;
541 if (!Tcl_StrToUnsigned (pkgDataArgv [2], 0, lengthPtr))
542 goto invalidEntry;
543
544 ckfree (pkgDataArgv);
545 if (indexPtr != indexBuffer)
546 ckfree (indexPtr);
547 return TCL_OK;
548
549 /*
550 * Exit point when an invalid entry is found.
551 */
552 invalidEntry:
553 if (pkgDataArgv != NULL)
554 ckfree (pkgDataArgv);
555 Tcl_ResetResult (interp);
556 Tcl_AppendResult (interp, "invalid entry for package library: TCLENV(",
557 indexPtr,") is \"", dataStr, "\"", (char *) NULL);
558 if (indexPtr != indexBuffer)
559 ckfree (indexPtr);
560 return TCL_ERROR;
561 }
562 \f
563 /*
564 *-----------------------------------------------------------------------------
565 *
566 * SetTCLENVProcEntry --
567 *
568 * Set the proc entry in the TCLENV array for a package in the form:
569 *
570 * TCLENV(PROC:$proc) [list P $packageName]
571 * or
572 * TCLENV(PROC:$proc) [list F $fileId]
573 *
574 * Parameters
575 * o interp (I) - A pointer to the interpreter, error returned in result.
576 * o procName (I) - The Tcl proc name.
577 * o type (I) - "P" for a package entry or "F" for a file entry.
578 * o location (I) - Either the package name or file name containing the
579 * procedure.
580 * Returns:
581 * TCL_OK or TCL_ERROR.
582 *-----------------------------------------------------------------------------
583 */
584 static int
585 SetTCLENVProcEntry (Tcl_Interp *interp, char *procName, char *type, char *location)
586 {
587 int nameLen;
588 char indexBuffer [64], *indexPtr;
589 char *procDataArgv [2], *dataStr, *setResult;
590
591 nameLen = strlen (procName) + 6; /* includes "PROC:" and '\0' */
592 if (nameLen <= sizeof (indexBuffer))
593 indexPtr = indexBuffer;
594 else
595 indexPtr = ckalloc (nameLen);
596
597 strcpy (indexPtr, "PROC:");
598 strcpy (indexPtr + 5, procName);
599
600 procDataArgv [0] = type;
601 procDataArgv [1] = location;
602 dataStr = Tcl_Merge (2, procDataArgv);
603
604 setResult = Tcl_SetVar2 (interp, "TCLENV", indexPtr, dataStr,
605 TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG);
606 ckfree (dataStr);
607 if (indexPtr != indexBuffer)
608 ckfree (indexPtr);
609
610 return (setResult == NULL) ? TCL_ERROR : TCL_OK;
611 }
612 \f
613 /*
614 *-----------------------------------------------------------------------------
615 *
616 * GetTCLENVProcEntry --
617 *
618 * Get the proc entry in the TCLENV array for a package.
619 *
620 * Parameters
621 * o interp (I) - A pointer to the interpreter, error returned in result.
622 * o procName (I) - The Tcl proc name.
623 * o typePtr (O) - 'P' for a package entry or 'F' for a file entry. This
624 * is a single character result.
625 * o location (O) - Either the package name or the file name. It is
626 * dynamically allocated and must be freed when finished. NULL is
627 * return if the procedure is not found.
628 * Returns:
629 * TCL_OK or TCL_ERROR.
630 *-----------------------------------------------------------------------------
631 */
632 static int
633 GetTCLENVProcEntry (Tcl_Interp *interp, char *procName, char *typePtr, char **locationPtr)
634 {
635 int nameLen, procDataArgc;
636 char indexBuffer [64], *indexPtr;
637 char *dataStr, *setResult, **procDataArgv;
638 register char *srcPtr, *destPtr;
639
640 nameLen = strlen (procName) + 6; /* includes "PROC:" and '\0' */
641 if (nameLen <= sizeof (indexBuffer))
642 indexPtr = indexBuffer;
643 else
644 indexPtr = ckalloc (nameLen);
645
646 strcpy (indexPtr, "PROC:");
647 strcpy (indexPtr + 5, procName);
648
649 dataStr = Tcl_GetVar2 (interp, "TCLENV", indexPtr, TCL_GLOBAL_ONLY);
650 if (dataStr == NULL) {
651 if (indexPtr != indexBuffer)
652 ckfree (indexPtr);
653 *locationPtr = NULL;
654 return TCL_OK;
655 }
656
657 /*
658 * Extract the data from the array entry.
659 */
660
661 if (Tcl_SplitList (interp, dataStr, &procDataArgc,
662 &procDataArgv) != TCL_OK)
663 goto invalidEntry;
664 if ((procDataArgc != 2) || (procDataArgv [0][1] != '\0'))
665 goto invalidEntry;
666 if (!((procDataArgv [0][0] == 'F') || (procDataArgv [0][0] == 'P')))
667 goto invalidEntry;
668 *typePtr = procDataArgv [0][0];
669
670 /*
671 * Now do a nasty trick to save a malloc. Since procDataArgv contains
672 * the string, just move the string to the top and type cast.
673 */
674 destPtr = (char *) procDataArgv;
675 srcPtr = procDataArgv [1];
676 while (*srcPtr != '\0')
677 *(destPtr++) = *(srcPtr++);
678 *destPtr = '\0';
679 *locationPtr = (char *) procDataArgv;
680
681 if (indexPtr != indexBuffer)
682 ckfree (indexPtr);
683 return TCL_OK;
684
685 /*
686 * Exit point when an invalid entry is found.
687 */
688 invalidEntry:
689 if (procDataArgv != NULL)
690 ckfree (procDataArgv);
691 Tcl_ResetResult (interp);
692 Tcl_AppendResult (interp, "invalid entry for procedure: TCLENV(",
693 indexPtr,") is \"", dataStr, "\"", (char *) NULL);
694 if (indexPtr != indexBuffer)
695 ckfree (indexPtr);
696 return TCL_ERROR;
697 }
698 \f
699 /*
700 *-----------------------------------------------------------------------------
701 *
702 * ProcessIndexFile --
703 *
704 * Open and process a package library index file (.tndx). Creates an
705 * entry in the form:
706 *
707 * TCLENV(PKG:$packageName) [list $fileId $start $len]
708 *
709 * for each package and a entry in the from
710 *
711 * TCLENV(PROC:$proc) [list P $packageName]
712 *
713 * for each entry procedure in a package. If the package is already defined,
714 * it it skipped.
715 *
716 * Parameters
717 * o interp (I) - A pointer to the interpreter, error returned in result.
718 * o tlibFilePath (I) - Absolute path name to the library file.
719 * o tndxFilePath (I) - Absolute path name to the library file index.
720 * Returns:
721 * TCL_OK or TCL_ERROR.
722 *-----------------------------------------------------------------------------
723 */
724 static int
725 ProcessIndexFile (Tcl_Interp *interp, char *tlibFilePath, char *tndxFilePath)
726 {
727 fileId_t fileId;
728 FILE *indexFilePtr;
729 dynamicBuf_t lineBuffer;
730 int lineArgc, idx, result;
731 char **lineArgv = NULL;
732
733 if (GenerateFileId (interp, tlibFilePath, fileId) != TCL_OK)
734 return TCL_ERROR;
735
736 indexFilePtr = fopen (tndxFilePath, "r");
737 if (indexFilePtr == NULL) {
738 Tcl_AppendResult (interp, "open failed on: ", tndxFilePath, ": ",
739 Tcl_UnixError (interp), (char *) NULL);
740 return TCL_ERROR;
741 }
742
743 Tcl_DynBufInit (&lineBuffer);
744
745 while (TRUE) {
746 switch (Tcl_DynamicFgets (&lineBuffer, indexFilePtr, FALSE)) {
747 case 0: /* EOF */
748 goto reachedEOF;
749 case -1: /* Error */
750 Tcl_AppendResult (interp, Tcl_UnixError (interp), (char *) NULL);
751 goto errorExit;
752 }
753 if ((Tcl_SplitList (interp, lineBuffer.ptr, &lineArgc,
754 &lineArgv) != TCL_OK) || (lineArgc < 4))
755 goto formatError;
756
757 /*
758 * lineArgv [0] is the package name.
759 * lineArgv [1] is the package offset in the library.
760 * lineArgv [2] is the package length in the library.
761 * lineArgv [3-n] are the entry procedures for the package.
762 */
763 result = SetTCLENVPkgEntry (interp, lineArgv [0], fileId, lineArgv [1],
764 lineArgv [2]);
765 if (result == TCL_ERROR)
766 goto errorExit;
767
768 /*
769 * If the package is not duplicated, add the procedures.
770 */
771 if (result != TCL_CONTINUE) {
772 for (idx = 3; idx < lineArgc; idx++) {
773 if (SetTCLENVProcEntry (interp, lineArgv [idx], "P",
774 lineArgv [0]) != TCL_OK)
775 goto errorExit;
776 }
777 }
778 ckfree (lineArgv);
779 lineArgv = NULL;
780 }
781
782 reachedEOF:
783 fclose (indexFilePtr);
784 Tcl_DynBufFree (&lineBuffer);
785
786 if (SetTCLENVFileIdEntry (interp, fileId, tlibFilePath) != TCL_OK)
787 return TCL_ERROR;
788
789 return TCL_OK;
790
791 /*
792 * Handle format error in library input line.
793 */
794 formatError:
795 Tcl_ResetResult (interp);
796 Tcl_AppendResult (interp, "format error in library index \"",
797 tndxFilePath, "\" (", lineBuffer.ptr, ")",
798 (char *) NULL);
799 goto errorExit;
800
801 /*
802 * Error exit here, releasing resources and closing the file.
803 */
804 errorExit:
805 if (lineArgv != NULL)
806 ckfree (lineArgv);
807 Tcl_DynBufFree (&lineBuffer);
808 fclose (indexFilePtr);
809 return TCL_ERROR;
810 }
811 \f
812 /*
813 *-----------------------------------------------------------------------------
814 *
815 * BuildPackageIndex --
816 *
817 * Call the "buildpackageindex" Tcl procedure to rebuild a package index.
818 * If the procedure has not been loaded, then load it. It MUST have an
819 * proc record setup by autoload.
820 *
821 * Parameters
822 * o interp (I) - A pointer to the interpreter, error returned in result.
823 * o tlibFilePath (I) - Absolute path name to the library file.
824 * Returns:
825 * TCL_OK or TCL_ERROR.
826 *-----------------------------------------------------------------------------
827 */
828 static int
829 BuildPackageIndex (Tcl_Interp *interp, char *tlibFilePath)
830 {
831 char *cmdPtr, *initCmd;
832
833 /*
834 * Load buildpackageindex if it is not loaded
835 */
836 if (TclFindProc ((Interp *) interp, "buildpackageindex") == NULL) {
837
838 cmdPtr = "demand_load buildpackageindex";
839
840 if (Tcl_Eval (interp, cmdPtr, 0, (char **) NULL) != TCL_OK)
841 return TCL_ERROR;
842
843 if (!STREQU (interp->result, "1")) {
844 Tcl_ResetResult (interp);
845 interp->result =
846 "can not find \"buildpackageindex\" on \"TCLPATH\"";
847 return TCL_ERROR;
848 }
849 Tcl_ResetResult (interp);
850 }
851
852 /*
853 * Build the package index.
854 */
855 initCmd = "buildpackageindex ";
856
857 cmdPtr = ckalloc (strlen (initCmd) + strlen (tlibFilePath) + 1);
858 strcpy (cmdPtr, initCmd);
859 strcat (cmdPtr, tlibFilePath);
860
861 if (Tcl_Eval (interp, cmdPtr, 0, (char **) NULL) != TCL_OK) {
862 ckfree (cmdPtr);
863 return TCL_ERROR;
864 }
865 ckfree (cmdPtr);
866 Tcl_ResetResult (interp);
867 return TCL_OK;
868 }
869 \f
870 /*
871 *-----------------------------------------------------------------------------
872 *
873 * LoadPackageIndex --
874 *
875 * Load a package .tndx file. Rebuild .tlib if non-existant or out of
876 * date. An entry is made in the TCLENV array indicating that this file
877 * has been loaded.
878 *
879 * Parameters
880 * o interp (I) - A pointer to the interpreter, error returned in result.
881 * o tlibFilePath (I) - Absolute path name to the library file.
882 * o pathLen (I) - Length of tlibFilePath.
883 * o dirLen (I) - The length of the leading directory path in the name.
884 * Returns:
885 * TCL_OK or TCL_ERROR.
886 *-----------------------------------------------------------------------------
887 */
888 static int
889 LoadPackageIndex (Tcl_Interp *interp, char *tlibFilePath, int pathLen, int dirLen)
890 {
891 char *tndxFilePath, tndxPathBuf [64], *msg;
892 struct stat tlibStat;
893 struct stat tndxStat;
894
895 if (pathLen < sizeof (tndxPathBuf))
896 tndxFilePath = tndxPathBuf;
897 else
898 tndxFilePath = ckalloc (pathLen + 1);
899 strcpy (tndxFilePath, tlibFilePath);
900 tndxFilePath [pathLen - 3] = 'n';
901 tndxFilePath [pathLen - 2] = 'd';
902 tndxFilePath [pathLen - 1] = 'x';
903
904 /*
905 * Get library's modification time. If the file can't be accessed, set
906 * time so the library does not get built. Other code will report the
907 * error.
908 */
909 if (stat (tlibFilePath, &tlibStat) < 0)
910 tlibStat.st_mtime = MAXINT;
911
912 /*
913 * Get the time for the index. If the file does not exists or is
914 * out of date, rebuild it.
915 */
916
917 if ((stat (tndxFilePath, &tndxStat) < 0) ||
918 (tndxStat.st_mtime < tlibStat.st_mtime)) {
919 if (BuildPackageIndex (interp, tlibFilePath) != TCL_OK)
920 goto errorExit;
921 }
922
923 if (ProcessIndexFile (interp, tlibFilePath, tndxFilePath) != TCL_OK)
924 goto errorExit;
925 if (tndxFilePath != tndxPathBuf)
926 ckfree (tndxFilePath);
927 return TCL_OK;
928
929 errorExit:
930 if (tndxFilePath != tndxPathBuf)
931 ckfree (tndxFilePath);
932 msg = ckalloc (strlen (tlibFilePath) + 60);
933 strcpy (msg, "\n while loading Tcl package library index \"");
934 strcat (msg, tlibFilePath);
935 strcat (msg, "\"");
936 Tcl_AddErrorInfo (interp, msg);
937 ckfree (msg);
938 return TCL_ERROR;
939 }
940 \f
941 /*
942 *-----------------------------------------------------------------------------
943 *
944 * LoadOusterIndex --
945 *
946 * Load a standard Tcl index (tclIndex). An entry is made in the TCLENV
947 * array indicating that this file has been loaded.
948 *
949 * Parameters
950 * o interp (I) - A pointer to the interpreter, error returned in result.
951 * o indexFilePath (I) - Absolute path name to the tclIndex file.
952 * o dirLen (I) - The length of the directory component of indexFilePath.
953 * Returns:
954 * TCL_OK or TCL_ERROR.
955 *-----------------------------------------------------------------------------
956 */
957 static int
958 LoadOusterIndex (Tcl_Interp *interp, char *indexFilePath, int dirLen)
959 {
960 FILE *indexFilePtr;
961 fileId_t fileId;
962 dynamicBuf_t lineBuffer;
963 int lineArgc, result, filePathLen;
964 char **lineArgv = NULL, *filePath, filePathBuf [64], *msg;
965
966 indexFilePtr = fopen (indexFilePath, "r");
967 if (indexFilePtr == NULL) {
968 Tcl_AppendResult (interp, "open failed on: ", indexFilePath, ": ",
969 Tcl_UnixError (interp), (char *) NULL);
970 return TCL_ERROR;
971 }
972
973 Tcl_DynBufInit (&lineBuffer);
974
975 while (TRUE) {
976 switch (Tcl_DynamicFgets (&lineBuffer, indexFilePtr, FALSE)) {
977 case 0: /* EOF */
978 goto reachedEOF;
979 case -1: /* Error */
980 Tcl_AppendResult (interp, "read filed on: ", indexFilePath, ": ",
981 Tcl_UnixError (interp), (char *) NULL);
982 goto errorExit;
983 }
984 if ((lineBuffer.ptr [0] == '\0') || (lineBuffer.ptr [0] == '#'))
985 continue;
986
987 if (Tcl_SplitList (interp, lineBuffer.ptr, &lineArgc,
988 &lineArgv) != TCL_OK)
989 goto formatError;
990 if (! ((lineArgc == 0) || (lineArgc == 2)))
991 goto formatError;
992
993 if (lineArgc != 0) {
994 filePathLen = strlen (lineArgv [1]) + dirLen + 1;
995 if (filePathLen < sizeof (filePathBuf))
996 filePath = filePathBuf;
997 else
998 filePath = ckalloc (filePathLen + 1);
999 strncpy (filePath, indexFilePath, dirLen + 1);
1000 strcpy (filePath + dirLen + 1, lineArgv [1]);
1001
1002 result = SetTCLENVProcEntry (interp, lineArgv [0], "F", filePath);
1003
1004 if (filePath != filePathBuf)
1005 ckfree (filePath);
1006 if (result != TCL_OK)
1007 goto errorExit;
1008 }
1009 ckfree (lineArgv);
1010 lineArgv = NULL;
1011 }
1012
1013 reachedEOF:
1014 Tcl_DynBufFree (&lineBuffer);
1015 fclose (indexFilePtr);
1016
1017 if (GenerateFileId (interp, indexFilePath, fileId) != TCL_OK)
1018 return TCL_ERROR;
1019 if (SetTCLENVFileIdEntry (interp, fileId, indexFilePath) != TCL_OK)
1020 return TCL_ERROR;
1021
1022 return TCL_OK;
1023
1024 /*
1025 * Handle format error in library input line. If data is already in the
1026 * result, its assumed to be the error that brought us here.
1027 */
1028 formatError:
1029 if (interp->result [0] != '\0')
1030 Tcl_AppendResult (interp, "\n", (char *) NULL);
1031 Tcl_AppendResult (interp, "format error in library index \"",
1032 indexFilePath, "\" (", lineBuffer.ptr, ")",
1033 (char *) NULL);
1034
1035 /*
1036 * Error exit here, releasing resources and closing the file.
1037 */
1038 errorExit:
1039 if (lineArgv != NULL)
1040 ckfree (lineArgv);
1041 Tcl_DynBufFree (&lineBuffer);
1042 fclose (indexFilePtr);
1043
1044 msg = ckalloc (strlen (indexFilePath) + 45);
1045 strcpy (msg, "\n while loading Tcl procedure index \"");
1046 strcat (msg, indexFilePath);
1047 strcat (msg, "\"");
1048 Tcl_AddErrorInfo (interp, msg);
1049 ckfree (msg);
1050 return TCL_ERROR;
1051 }
1052 \f
1053 /*
1054 *-----------------------------------------------------------------------------
1055 *
1056 * LoadDirIndexes --
1057 *
1058 * Load the indexes for all package library (.tlib) or a Ousterhout
1059 * "tclIndex" file in a directory. Nonexistent or unreadable directories
1060 * are skipped.
1061 *
1062 * Parameters
1063 * o interp (I) - A pointer to the interpreter, error returned in result.
1064 * o dirName (I) - The absolute path name of the directory to search for
1065 * libraries.
1066 * Results:
1067 * A standard Tcl result.
1068 *-----------------------------------------------------------------------------
1069 */
1070 static int
1071 LoadDirIndexes (Tcl_Interp *interp, char *dirName)
1072 {
1073 DIR *dirPtr;
1074 struct dirent *entryPtr;
1075 int dirLen, nameLen;
1076 char *filePath = NULL;
1077 int filePathSize = 0;
1078
1079 dirLen = strlen (dirName);
1080
1081 dirPtr = opendir (dirName);
1082 if (dirPtr == NULL)
1083 return TCL_OK; /* Skip directory */
1084
1085 while (TRUE) {
1086 entryPtr = readdir (dirPtr);
1087 if (entryPtr == NULL)
1088 break;
1089 nameLen = strlen (entryPtr->d_name);
1090
1091 if ((nameLen > 5) &&
1092 ((STREQU (entryPtr->d_name + nameLen - 5, ".tlib")) ||
1093 (STREQU (entryPtr->d_name, "tclIndex")))) {
1094
1095 /*
1096 * Expand the filePath buffer if necessary (always allow extra).
1097 */
1098 if ((nameLen + dirLen + 2) > filePathSize) {
1099 if (filePath != NULL)
1100 ckfree (filePath);
1101 filePathSize = nameLen + dirLen + 2 + 16;
1102 filePath = ckalloc (filePathSize);
1103 strcpy (filePath, dirName);
1104 filePath [dirLen] = '/';
1105 }
1106 strcpy (filePath + dirLen + 1, entryPtr->d_name);
1107
1108 /*
1109 * Skip index if it has been loaded before or if it can't be
1110 * accessed.
1111 */
1112 if (CheckTCLENVFileIdEntry (interp, filePath) ||
1113 (access (filePath, R_OK) < 0))
1114 continue;
1115
1116 if (entryPtr->d_name [nameLen - 5] == '.') {
1117 if (LoadPackageIndex (interp, filePath, dirLen + nameLen + 1,
1118 dirLen) != TCL_OK)
1119 goto errorExit;
1120 } else {
1121 if (LoadOusterIndex (interp, filePath, dirLen) != TCL_OK)
1122 goto errorExit;
1123 }
1124 }
1125 }
1126
1127 if (filePath != NULL)
1128 ckfree (filePath);
1129 closedir (dirPtr);
1130 return TCL_OK;
1131
1132 errorExit:
1133 if (filePath != NULL)
1134 ckfree (filePath);
1135 closedir (dirPtr);
1136 return TCL_ERROR;
1137
1138 }
1139 \f
1140 /*
1141 *-----------------------------------------------------------------------------
1142 *
1143 * LoadPackageIndexes --
1144 *
1145 * Loads the all indexes for all package libraries (.tlib)* or a
1146 * Ousterhout "tclIndex" files found in all directories in the path.
1147 * If an index has already been loaded, it will not be reloaded.
1148 * Non-existent or unreadable directories are skipped.
1149 *
1150 * Results:
1151 * A standard Tcl result. Tcl array variable TCLENV is updated to
1152 * indicate the procedures that were defined in the library.
1153 *
1154 *-----------------------------------------------------------------------------
1155 */
1156 static int
1157 LoadPackageIndexes (Tcl_Interp *interp, char *path)
1158 {
1159 char *dirName, dirNameBuf [64];
1160 int idx, dirLen, pathArgc, status;
1161 char **pathArgv;
1162
1163 if (Tcl_SplitList (interp, path, &pathArgc, &pathArgv) != TCL_OK)
1164 return TCL_OK;
1165
1166 for (idx = 0; idx < pathArgc; idx++) {
1167 /*
1168 * Get the absolute dir name. if the conversion fails (most likely
1169 * invalid "~") or thje directory cann't be read, skip it.
1170 */
1171 dirName = pathArgv [idx];
1172 if (dirName [0] != '/') {
1173 dirName = MakeAbsFile (interp, dirName, dirNameBuf,
1174 sizeof (dirNameBuf));
1175 if (dirName == NULL)
1176 continue;
1177 }
1178 if (access (dirName, X_OK) == 0)
1179 status = LoadDirIndexes (interp, dirName);
1180 else
1181 status = TCL_OK;
1182
1183 if ((dirName != pathArgv [idx]) && (dirName != dirNameBuf))
1184 ckfree (dirName);
1185 if (status != TCL_OK)
1186 goto errorExit;
1187 }
1188 ckfree (pathArgv);
1189 return TCL_OK;
1190
1191 errorExit:
1192 ckfree (pathArgv);
1193 return TCL_ERROR;
1194
1195 }
1196 \f
1197 /*
1198 *-----------------------------------------------------------------------------
1199 *
1200 * LoadProc --
1201 *
1202 * Attempt to load a procedure (or command) by checking the TCLENV
1203 * array for its location (either in a file or package library).
1204 *
1205 * Parameters
1206 * o interp (I) - A pointer to the interpreter, error returned in result.
1207 * o procName (I) - The name of the procedure (or command) to load
1208 * libraries.
1209 * o foundPtr (O) - TRUE is returned if the procedure or command was
1210 * loaded, FALSE if it was not.
1211 * Results:
1212 * A standard Tcl result.
1213 *
1214 *-----------------------------------------------------------------------------
1215 */
1216 static int
1217 LoadProc (Tcl_Interp *interp, char *procName, int *foundPtr)
1218 {
1219 Interp *iPtr = (Interp *) interp;
1220 char type, *location, *filePath, *cmdPtr, cmdBuf [80];
1221 int cmdLen, result;
1222 long offset;
1223 unsigned length;
1224 fileId_t fileId;
1225 Tcl_HashEntry *cmdEntryPtr;
1226
1227 if (GetTCLENVProcEntry (interp, procName, &type, &location) != TCL_OK)
1228 return TCL_ERROR;
1229 if (location == NULL) {
1230 *foundPtr = FALSE;
1231 return TCL_OK;
1232 }
1233
1234 /*
1235 * If this is a file entry (type = 'F'), location is a file name or
1236 * absolute file path. If it's an absolute path, just eval it, otherwise
1237 * load the source using the "load" procdure (still in Tcl). If this is a
1238 * package entry, location is a package name. Source part of the package
1239 * library (Must look up the file, offset and length in the package entry
1240 * in TCLENV).
1241 */
1242 if (type == 'F') {
1243 if (location [0] == '/') {
1244 result = Tcl_EvalFile (interp, location);
1245 } else {
1246 cmdLen = strlen (location) + 5;
1247 if (cmdLen < sizeof (cmdBuf))
1248 cmdPtr = cmdBuf;
1249 else
1250 cmdPtr = ckalloc (cmdLen + 1);
1251 strcpy (cmdPtr, "load ");
1252 strcat (cmdPtr, location);
1253
1254 result = Tcl_Eval (interp, cmdPtr, 0, NULL);
1255 if (cmdPtr != cmdBuf)
1256 ckfree (cmdPtr);
1257 }
1258 } else {
1259 result = GetTCLENVPkgEntry (interp, location, fileId, &offset,
1260 &length);
1261 if (result == TCL_OK) {
1262 filePath = GetTCLENVFileIdEntry (interp, fileId);
1263 if (filePath == NULL)
1264 result = TCL_ERROR;
1265 }
1266
1267 if (result == TCL_OK)
1268 result = EvalFilePart (interp, filePath, offset, length);
1269
1270 }
1271
1272 ckfree (location);
1273
1274 /*
1275 * If we are ok to this point, make sure that the procedure or command is
1276 * actually loaded.
1277 */
1278 if (result == TCL_OK) {
1279 cmdEntryPtr = Tcl_FindHashEntry (&iPtr->commandTable, procName);
1280 *foundPtr = (cmdEntryPtr != NULL);
1281 }
1282
1283 return result;
1284 }
1285 \f
1286 /*
1287 *-----------------------------------------------------------------------------
1288 *
1289 * Tcl_LoadlibindexCmd --
1290 *
1291 * This procedure is invoked to process the "Loadlibindex" Tcl command:
1292 *
1293 * loadlibindex libfile
1294 *
1295 * which loads the index for a package library (.tlib) or a Ousterhout
1296 * "tclIndex" file.
1297 *
1298 * Results:
1299 * A standard Tcl result. Tcl array variable TCLENV is updated to
1300 * indicate the procedures that were defined in the library.
1301 *
1302 *-----------------------------------------------------------------------------
1303 */
1304 int
1305 Tcl_LoadlibindexCmd (
1306 ClientData dummy,
1307 Tcl_Interp *interp,
1308 int argc,
1309 char **argv
1310 )
1311 {
1312 char *pathName, pathNameBuf [64];
1313 int pathLen, dirLen;
1314
1315 if (argc != 2) {
1316 Tcl_AppendResult (interp, tclXWrongArgs, argv [0], " libFile",
1317 (char *) NULL);
1318 return TCL_ERROR;
1319 }
1320
1321 pathName = argv [1];
1322 if (pathName [0] != '/') {
1323 pathName = MakeAbsFile (interp, pathName, pathNameBuf,
1324 sizeof (pathNameBuf));
1325 if (pathName == NULL)
1326 return TCL_ERROR;
1327 }
1328
1329 /*
1330 * Find the length of the directory name. Validate that we have a .tlib
1331 * extension or file name is "tclIndex" and call the routine to process
1332 * the specific type of index.
1333 */
1334 pathLen = strlen (pathName);
1335 for (dirLen = pathLen - 1; pathName [dirLen] != '/'; dirLen--)
1336 continue;
1337
1338 if ((pathLen > 5) && (pathName [pathLen - 5] == '.')) {
1339 if (!STREQU (pathName + pathLen - 5, ".tlib"))
1340 goto invalidName;
1341 if (LoadPackageIndex (interp, pathName, pathLen, dirLen) != TCL_OK)
1342 goto errorExit;
1343 } else {
1344 if (!STREQU (pathName + dirLen, "/tclIndex"))
1345 goto invalidName;
1346 if (LoadOusterIndex (interp, pathName, dirLen) != TCL_OK)
1347 goto errorExit;
1348 }
1349 if ((pathName != argv [1]) && (pathName != pathNameBuf))
1350 ckfree (pathName);
1351 return TCL_OK;
1352
1353 invalidName:
1354 Tcl_AppendResult (interp, "invalid library name, must have an extension ",
1355 "of \".tlib\" or the name \"tclIndex\", got \"",
1356 argv [1], "\"", (char *) NULL);
1357
1358 errorExit:
1359 if ((pathName != argv [1]) && (pathName != pathNameBuf))
1360 ckfree (pathName);
1361 return TCL_ERROR;;
1362 }
1363 \f
1364 /*
1365 *-----------------------------------------------------------------------------
1366 *
1367 * Tcl_Demand_loadCmd --
1368 *
1369 * This procedure is invoked to process the "demand_load" Tcl command:
1370 *
1371 * demand_load proc
1372 *
1373 * which searchs the TCLENV tables for the specified procedure. If it
1374 * is not found, an attempt is made to load unloaded libraries, first
1375 * the variable "TCLPATH" is searched. If the procedure is not defined
1376 * after that, then "auto_path" is searched.
1377 *
1378 * Results:
1379 * A standard Tcl result.
1380 *
1381 *-----------------------------------------------------------------------------
1382 */
1383 int
1384 Tcl_Demand_loadCmd (
1385 ClientData dummy,
1386 Tcl_Interp *interp,
1387 int argc,
1388 char **argv
1389 )
1390 {
1391 int found;
1392 char *path, *msg;
1393
1394 if (argc != 2) {
1395 Tcl_AppendResult (interp, tclXWrongArgs, argv [0], " procedure",
1396 (char *) NULL);
1397 return TCL_ERROR;
1398 }
1399
1400 if (LoadProc (interp, argv [1], &found) != TCL_OK)
1401 goto errorExit;
1402 if (found) {
1403 interp->result = "1";
1404 return TCL_OK;
1405 }
1406
1407 /*
1408 * Slow path, load the libraries indices on "TCLPATH".
1409 */
1410 path = Tcl_GetVar (interp, "TCLPATH", TCL_GLOBAL_ONLY);
1411 if (path != NULL) {
1412 if (LoadPackageIndexes (interp, path) != TCL_OK)
1413 goto errorExit;
1414 if (LoadProc (interp, argv [1], &found) != TCL_OK)
1415 goto errorExit;
1416 if (found) {
1417 interp->result = "1";
1418 return TCL_OK;
1419 }
1420 }
1421
1422 /*
1423 * Final gasp, check the "auto_path"
1424 */
1425 path = Tcl_GetVar (interp, "auto_path", TCL_GLOBAL_ONLY);
1426 if (path != NULL) {
1427 if (LoadPackageIndexes (interp, path) != TCL_OK)
1428 goto errorExit;
1429 if (LoadProc (interp, argv [1], &found) != TCL_OK)
1430 goto errorExit;
1431 if (found) {
1432 interp->result = "1";
1433 return TCL_OK;
1434 }
1435 }
1436
1437 /*
1438 * Procedure or command was not found.
1439 */
1440 interp->result = "0";
1441 return TCL_OK;
1442
1443 errorExit:
1444 msg = ckalloc (strlen (argv [1]) + 35);
1445 strcpy (msg, "\n while demand loading \"");
1446 strcat (msg, argv [1]);
1447 strcat (msg, "\"");
1448 Tcl_AddErrorInfo (interp, msg);
1449 ckfree (msg);
1450 return TCL_ERROR;
1451 }
1452
Impressum, Datenschutz