os/persistentdata/persistentstorage/sqlite3api/TEST/TCL/tcldistribution/unix/tclLoadAout.c
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
sl@0
     1
/* 
sl@0
     2
 * tclLoadAout.c --
sl@0
     3
 *
sl@0
     4
 *	This procedure provides a version of the TclLoadFile that
sl@0
     5
 *	provides pseudo-static linking using version-7 compatible
sl@0
     6
 *	a.out files described in either sys/exec.h or sys/a.out.h.
sl@0
     7
 *
sl@0
     8
 * Copyright (c) 1995, by General Electric Company. All rights reserved.
sl@0
     9
 *
sl@0
    10
 * See the file "license.terms" for information on usage and redistribution
sl@0
    11
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
sl@0
    12
 *
sl@0
    13
 * This work was supported in part by the ARPA Manufacturing Automation
sl@0
    14
 * and Design Engineering (MADE) Initiative through ARPA contract
sl@0
    15
 * F33615-94-C-4400.
sl@0
    16
 *
sl@0
    17
 * RCS: @(#) $Id: tclLoadAout.c,v 1.14 2002/10/10 12:25:53 vincentdarley Exp $
sl@0
    18
 */
sl@0
    19
sl@0
    20
#include "tclInt.h"
sl@0
    21
#include <fcntl.h>
sl@0
    22
#ifdef HAVE_EXEC_AOUT_H
sl@0
    23
#   include <sys/exec_aout.h>
sl@0
    24
#endif
sl@0
    25
#ifdef HAVE_UNISTD_H
sl@0
    26
#   include <unistd.h>
sl@0
    27
#else
sl@0
    28
#   include "../compat/unistd.h"
sl@0
    29
#endif
sl@0
    30
sl@0
    31
/*
sl@0
    32
 * Some systems describe the a.out header in sys/exec.h, and some in
sl@0
    33
 * a.out.h.
sl@0
    34
 */
sl@0
    35
sl@0
    36
#ifdef USE_SYS_EXEC_H
sl@0
    37
#include <sys/exec.h>
sl@0
    38
#endif
sl@0
    39
#ifdef USE_A_OUT_H
sl@0
    40
#include <a.out.h>
sl@0
    41
#endif
sl@0
    42
#ifdef USE_SYS_EXEC_AOUT_H
sl@0
    43
#include <sys/exec_aout.h>
sl@0
    44
#define a_magic a_midmag
sl@0
    45
#endif
sl@0
    46
sl@0
    47
/*
sl@0
    48
 * TCL_LOADSHIM is the amount by which to shim the break when loading
sl@0
    49
 */
sl@0
    50
sl@0
    51
#ifndef TCL_LOADSHIM
sl@0
    52
#define TCL_LOADSHIM 0x4000L
sl@0
    53
#endif
sl@0
    54
sl@0
    55
/*
sl@0
    56
 * TCL_LOADALIGN must be a power of 2, and is the alignment to which
sl@0
    57
 * to force the origin of load modules
sl@0
    58
 */
sl@0
    59
sl@0
    60
#ifndef TCL_LOADALIGN
sl@0
    61
#define TCL_LOADALIGN 0x4000L
sl@0
    62
#endif
sl@0
    63
sl@0
    64
/*
sl@0
    65
 * TCL_LOADMAX is the maximum size of a load module, and is used as
sl@0
    66
 * a sanity check when loading
sl@0
    67
 */
sl@0
    68
sl@0
    69
#ifndef TCL_LOADMAX
sl@0
    70
#define TCL_LOADMAX 2000000L
sl@0
    71
#endif
sl@0
    72
sl@0
    73
/*
sl@0
    74
 * Kernel calls that appear to be missing from the system .h files:
sl@0
    75
 */
sl@0
    76
sl@0
    77
extern char * brk _ANSI_ARGS_((char *));
sl@0
    78
extern char * sbrk _ANSI_ARGS_((size_t));
sl@0
    79
sl@0
    80
/*
sl@0
    81
 * The static variable SymbolTableFile contains the file name where the
sl@0
    82
 * result of the last link was stored.  The file is kept because doing so
sl@0
    83
 * allows one load module to use the symbols defined in another.
sl@0
    84
 */
sl@0
    85
sl@0
    86
static char * SymbolTableFile = NULL;
sl@0
    87
sl@0
    88
/*
sl@0
    89
 * Type of the dictionary function that begins each load module.
sl@0
    90
 */
sl@0
    91
sl@0
    92
typedef Tcl_PackageInitProc * (* DictFn) _ANSI_ARGS_ ((CONST char * symbol));
sl@0
    93
sl@0
    94
/*
sl@0
    95
 * Prototypes for procedures referenced only in this file:
sl@0
    96
 */
sl@0
    97
sl@0
    98
static int FindLibraries _ANSI_ARGS_((Tcl_Interp * interp, Tcl_Obj * pathPtr,
sl@0
    99
				      Tcl_DString * buf));
sl@0
   100
static void UnlinkSymbolTable _ANSI_ARGS_((void));
sl@0
   101

sl@0
   102
/*
sl@0
   103
 *----------------------------------------------------------------------
sl@0
   104
 *
sl@0
   105
 * TclpDlopen --
sl@0
   106
 *
sl@0
   107
 *	Dynamically loads a binary code file into memory and returns
sl@0
   108
 *	a handle to the new code.
sl@0
   109
 *
sl@0
   110
 * Results:
sl@0
   111
 *	A standard Tcl completion code.  If an error occurs, an error
sl@0
   112
 *	message is left in the interp's result. 
sl@0
   113
 *
sl@0
   114
 * Side effects:
sl@0
   115
 *	New code suddenly appears in memory.
sl@0
   116
 *
sl@0
   117
 *
sl@0
   118
 * Bugs:
sl@0
   119
 *	This function does not attempt to handle the case where the
sl@0
   120
 *	BSS segment is not executable.  It will therefore fail on
sl@0
   121
 *	Encore Multimax, Pyramid 90x, and similar machines.  The
sl@0
   122
 *	reason is that the mprotect() kernel call, which would
sl@0
   123
 *	otherwise be employed to mark the newly-loaded text segment
sl@0
   124
 *	executable, results in a system crash on BSD/386.
sl@0
   125
 *
sl@0
   126
 *	In an effort to make it fast, this function eschews the
sl@0
   127
 *	technique of linking the load module once, reading its header
sl@0
   128
 *	to determine its size, allocating memory for it, and linking
sl@0
   129
 *	it again.  Instead, it `shims out' memory allocation by
sl@0
   130
 *	placing the module TCL_LOADSHIM bytes beyond the break,
sl@0
   131
 *	and assuming that any malloc() calls required to run the
sl@0
   132
 *	linker will not advance the break beyond that point.  If
sl@0
   133
 *	the break is advanced beyonnd that point, the load will
sl@0
   134
 *	fail with an `inconsistent memory allocation' error.
sl@0
   135
 *	It perhaps ought to retry the link, but the failure has
sl@0
   136
 *	not been observed in two years of daily use of this function.
sl@0
   137
 *----------------------------------------------------------------------
sl@0
   138
 */
sl@0
   139
sl@0
   140
int
sl@0
   141
TclpDlopen(interp, pathPtr, loadHandle, unloadProcPtr)
sl@0
   142
    Tcl_Interp *interp;		/* Used for error reporting. */
sl@0
   143
    Tcl_Obj *pathPtr;		/* Name of the file containing the desired
sl@0
   144
				 * code (UTF-8). */
sl@0
   145
    Tcl_LoadHandle *loadHandle;	/* Filled with token for dynamically loaded
sl@0
   146
				 * file which will be passed back to 
sl@0
   147
				 * (*unloadProcPtr)() to unload the file. */
sl@0
   148
    Tcl_FSUnloadFileProc **unloadProcPtr;	
sl@0
   149
				/* Filled with address of Tcl_FSUnloadFileProc
sl@0
   150
				 * function which should be used for
sl@0
   151
				 * this file. */
sl@0
   152
{
sl@0
   153
    char * inputSymbolTable;	/* Name of the file containing the 
sl@0
   154
				 * symbol table from the last link. */
sl@0
   155
    Tcl_DString linkCommandBuf;	/* Command to do the run-time relocation
sl@0
   156
				 * of the module.*/
sl@0
   157
    char * linkCommand;
sl@0
   158
    char relocatedFileName [L_tmpnam];
sl@0
   159
				/* Name of the file holding the relocated */
sl@0
   160
				/* text of the module */
sl@0
   161
    int relocatedFd;		/* File descriptor of the file holding
sl@0
   162
				 * relocated text */
sl@0
   163
    struct exec relocatedHead;	/* Header of the relocated text */
sl@0
   164
    unsigned long relocatedSize;/* Size of the relocated text */
sl@0
   165
    char * startAddress;	/* Starting address of the module */
sl@0
   166
    int status;			/* Status return from Tcl_ calls */
sl@0
   167
    char * p;
sl@0
   168
sl@0
   169
    /* Find the file that contains the symbols for the run-time link. */
sl@0
   170
    
sl@0
   171
    if (SymbolTableFile != NULL) {
sl@0
   172
	inputSymbolTable = SymbolTableFile;
sl@0
   173
    } else if (tclExecutableName == NULL) {
sl@0
   174
	Tcl_SetResult (interp, "can't find the tclsh executable", TCL_STATIC);
sl@0
   175
	return TCL_ERROR;
sl@0
   176
    } else {
sl@0
   177
	inputSymbolTable = tclExecutableName;
sl@0
   178
    }
sl@0
   179
    
sl@0
   180
    /* Construct the `ld' command that builds the relocated module */
sl@0
   181
    
sl@0
   182
    tmpnam (relocatedFileName);
sl@0
   183
    Tcl_DStringInit (&linkCommandBuf);
sl@0
   184
    Tcl_DStringAppend (&linkCommandBuf, "exec ld -o ", -1);
sl@0
   185
    Tcl_DStringAppend (&linkCommandBuf, relocatedFileName, -1);
sl@0
   186
#if defined(__mips) || defined(mips)
sl@0
   187
    Tcl_DStringAppend (&linkCommandBuf, " -G 0 ", -1);
sl@0
   188
#endif
sl@0
   189
    Tcl_DStringAppend (&linkCommandBuf, " -u TclLoadDictionary_", -1);
sl@0
   190
    TclGuessPackageName(Tcl_GetString(pathPtr), &linkCommandBuf);
sl@0
   191
    Tcl_DStringAppend (&linkCommandBuf, " -A ", -1);
sl@0
   192
    Tcl_DStringAppend (&linkCommandBuf, inputSymbolTable, -1);
sl@0
   193
    Tcl_DStringAppend (&linkCommandBuf, " -N -T XXXXXXXX ", -1);
sl@0
   194
    Tcl_DStringAppend (&linkCommandBuf, Tcl_GetString(pathPtr), -1);
sl@0
   195
    Tcl_DStringAppend (&linkCommandBuf, " ", -1);
sl@0
   196
    
sl@0
   197
    if (FindLibraries (interp, pathPtr, &linkCommandBuf) != TCL_OK) {
sl@0
   198
	Tcl_DStringFree (&linkCommandBuf);
sl@0
   199
	return TCL_ERROR;
sl@0
   200
    }
sl@0
   201
    
sl@0
   202
    linkCommand = Tcl_DStringValue (&linkCommandBuf);
sl@0
   203
    
sl@0
   204
    /* Determine the starting address, and plug it into the command */
sl@0
   205
    
sl@0
   206
    startAddress = (char *) (((unsigned long) sbrk (0)
sl@0
   207
			      + TCL_LOADSHIM + TCL_LOADALIGN - 1)
sl@0
   208
			     & (- TCL_LOADALIGN));
sl@0
   209
    p = strstr (linkCommand, "-T") + 3;
sl@0
   210
    sprintf (p, "%08lx", (long) startAddress);
sl@0
   211
    p [8] = ' ';
sl@0
   212
    
sl@0
   213
    /* Run the linker */
sl@0
   214
    
sl@0
   215
    status = Tcl_Eval (interp, linkCommand);
sl@0
   216
    Tcl_DStringFree (&linkCommandBuf);
sl@0
   217
    if (status != 0) {
sl@0
   218
	return TCL_ERROR;
sl@0
   219
    }
sl@0
   220
    
sl@0
   221
    /* Open the linker's result file and read the header */
sl@0
   222
    
sl@0
   223
    relocatedFd = open (relocatedFileName, O_RDONLY);
sl@0
   224
    if (relocatedFd < 0) {
sl@0
   225
	goto ioError;
sl@0
   226
    }
sl@0
   227
    status= read (relocatedFd, (char *) & relocatedHead, sizeof relocatedHead);
sl@0
   228
    if (status < sizeof relocatedHead) {
sl@0
   229
	goto ioError;
sl@0
   230
    }
sl@0
   231
    
sl@0
   232
    /* Check the magic number */
sl@0
   233
    
sl@0
   234
    if (relocatedHead.a_magic != OMAGIC) {
sl@0
   235
	Tcl_AppendResult (interp, "bad magic number in intermediate file \"",
sl@0
   236
			  relocatedFileName, "\"", (char *) NULL);
sl@0
   237
	goto failure;
sl@0
   238
    }
sl@0
   239
    
sl@0
   240
    /* Make sure that memory allocation is still consistent */
sl@0
   241
    
sl@0
   242
    if ((unsigned long) sbrk (0) > (unsigned long) startAddress) {
sl@0
   243
	Tcl_SetResult (interp, "can't load, memory allocation is inconsistent.",
sl@0
   244
		       TCL_STATIC);
sl@0
   245
	goto failure;
sl@0
   246
    }
sl@0
   247
    
sl@0
   248
    /* Make sure that the relocated module's size is reasonable */
sl@0
   249
    
sl@0
   250
    relocatedSize = relocatedHead.a_text + relocatedHead.a_data
sl@0
   251
      + relocatedHead.a_bss;
sl@0
   252
    if (relocatedSize > TCL_LOADMAX) {
sl@0
   253
	Tcl_SetResult (interp, "module too big to load", TCL_STATIC);
sl@0
   254
	goto failure;
sl@0
   255
    }
sl@0
   256
    
sl@0
   257
    /* Advance the break to protect the loaded module */
sl@0
   258
    
sl@0
   259
    (void) brk (startAddress + relocatedSize);
sl@0
   260
    
sl@0
   261
    /*
sl@0
   262
     * Seek to the start of the module's text.
sl@0
   263
     *
sl@0
   264
     * Note that this does not really work with large files (i.e. where
sl@0
   265
     * lseek64 exists and is different to lseek), but anyone trying to
sl@0
   266
     * dynamically load a binary that is larger than what can fit in
sl@0
   267
     * addressable memory is in trouble anyway...
sl@0
   268
     */
sl@0
   269
    
sl@0
   270
#if defined(__mips) || defined(mips)
sl@0
   271
    status = lseek (relocatedFd,
sl@0
   272
		    (off_t) N_TXTOFF (relocatedHead.ex_f, relocatedHead.ex_o),
sl@0
   273
		    SEEK_SET);
sl@0
   274
#else
sl@0
   275
    status = lseek (relocatedFd, (off_t) N_TXTOFF (relocatedHead), SEEK_SET);
sl@0
   276
#endif
sl@0
   277
    if (status < 0) {
sl@0
   278
	goto ioError;
sl@0
   279
    }
sl@0
   280
    
sl@0
   281
    /* Read in the module's text and data */
sl@0
   282
    
sl@0
   283
    relocatedSize = relocatedHead.a_text + relocatedHead.a_data;
sl@0
   284
    if (read (relocatedFd, startAddress, relocatedSize) < relocatedSize) {
sl@0
   285
	brk (startAddress);
sl@0
   286
      ioError:
sl@0
   287
	Tcl_AppendResult (interp, "error on intermediate file \"",
sl@0
   288
			  relocatedFileName, "\": ", Tcl_PosixError (interp),
sl@0
   289
			  (char *) NULL);
sl@0
   290
      failure:
sl@0
   291
	(void) unlink (relocatedFileName);
sl@0
   292
	return TCL_ERROR;
sl@0
   293
    }
sl@0
   294
    
sl@0
   295
    /* Close the intermediate file. */
sl@0
   296
    
sl@0
   297
    (void) close (relocatedFd);
sl@0
   298
    
sl@0
   299
    /* Arrange things so that intermediate symbol tables eventually get
sl@0
   300
    * deleted. */
sl@0
   301
    
sl@0
   302
    if (SymbolTableFile != NULL) {
sl@0
   303
	UnlinkSymbolTable ();
sl@0
   304
    } else {
sl@0
   305
	atexit (UnlinkSymbolTable);
sl@0
   306
    }
sl@0
   307
    SymbolTableFile = ckalloc (strlen (relocatedFileName) + 1);
sl@0
   308
    strcpy (SymbolTableFile, relocatedFileName);
sl@0
   309
    
sl@0
   310
    *loadHandle = startAddress;
sl@0
   311
    return TCL_OK;
sl@0
   312
}
sl@0
   313

sl@0
   314
/*
sl@0
   315
 *----------------------------------------------------------------------
sl@0
   316
 *
sl@0
   317
 * TclpFindSymbol --
sl@0
   318
 *
sl@0
   319
 *	Looks up a symbol, by name, through a handle associated with
sl@0
   320
 *	a previously loaded piece of code (shared library).
sl@0
   321
 *
sl@0
   322
 * Results:
sl@0
   323
 *	Returns a pointer to the function associated with 'symbol' if
sl@0
   324
 *	it is found.  Otherwise returns NULL and may leave an error
sl@0
   325
 *	message in the interp's result.
sl@0
   326
 *
sl@0
   327
 *----------------------------------------------------------------------
sl@0
   328
 */
sl@0
   329
Tcl_PackageInitProc*
sl@0
   330
TclpFindSymbol(interp, loadHandle, symbol) 
sl@0
   331
    Tcl_Interp *interp;
sl@0
   332
    Tcl_LoadHandle loadHandle;
sl@0
   333
    CONST char *symbol;
sl@0
   334
{
sl@0
   335
    /* Look up the entry point in the load module's dictionary. */
sl@0
   336
    DictFn dictionary = (DictFn) loadHandle;
sl@0
   337
    return (Tcl_PackageInitProc*) dictionary(sym1);
sl@0
   338
}
sl@0
   339
sl@0
   340

sl@0
   341
/*
sl@0
   342
 *------------------------------------------------------------------------
sl@0
   343
 *
sl@0
   344
 * FindLibraries --
sl@0
   345
 *
sl@0
   346
 *	Find the libraries needed to link a load module at run time.
sl@0
   347
 *
sl@0
   348
 * Results:
sl@0
   349
 *	A standard Tcl completion code.  If an error occurs,
sl@0
   350
 *	an error message is left in the interp's result.  The -l and -L
sl@0
   351
 *	flags are concatenated onto the dynamic string `buf'.
sl@0
   352
 *
sl@0
   353
 *------------------------------------------------------------------------
sl@0
   354
 */
sl@0
   355
sl@0
   356
static int
sl@0
   357
FindLibraries (interp, pathPtr, buf)
sl@0
   358
    Tcl_Interp * interp;	/* Used for error reporting */
sl@0
   359
    Tcl_Obj * pathPtr;		/* Name of the load module */
sl@0
   360
    Tcl_DString * buf;		/* Buffer where the -l an -L flags */
sl@0
   361
{
sl@0
   362
    FILE * f;			/* The load module */
sl@0
   363
    int c = 0;			/* Byte from the load module */
sl@0
   364
    char * p;
sl@0
   365
    CONST char *native;
sl@0
   366
sl@0
   367
    char *fileName = Tcl_GetString(pathPtr);
sl@0
   368
  
sl@0
   369
    /* Open the load module */
sl@0
   370
    
sl@0
   371
    native = Tcl_FSGetNativePath(pathPtr);
sl@0
   372
    f = fopen(native, "rb");				/* INTL: Native. */
sl@0
   373
    
sl@0
   374
    if (f == NULL) {
sl@0
   375
	Tcl_AppendResult (interp, "couldn't open \"", fileName, "\": ",
sl@0
   376
			  Tcl_PosixError (interp), (char *) NULL);
sl@0
   377
	return TCL_ERROR;
sl@0
   378
    }
sl@0
   379
    
sl@0
   380
    /* Search for the library list in the load module */
sl@0
   381
    
sl@0
   382
    p = "@LIBS: ";
sl@0
   383
    while (*p != '\0' && (c = getc (f)) != EOF) {
sl@0
   384
	if (c == *p) {
sl@0
   385
	    ++p;
sl@0
   386
	}
sl@0
   387
	else {
sl@0
   388
	    p = "@LIBS: ";
sl@0
   389
	    if (c == *p) {
sl@0
   390
		++p;
sl@0
   391
	    }
sl@0
   392
	}
sl@0
   393
    }
sl@0
   394
    
sl@0
   395
    /* No library list -- this must be an ill-formed module */
sl@0
   396
    
sl@0
   397
    if (c == EOF) {
sl@0
   398
	Tcl_AppendResult (interp, "File \"", fileName,
sl@0
   399
			  "\" is not a Tcl load module.", (char *) NULL);
sl@0
   400
	(void) fclose (f);
sl@0
   401
	return TCL_ERROR;
sl@0
   402
    }
sl@0
   403
    
sl@0
   404
    /* Accumulate the library list */
sl@0
   405
    
sl@0
   406
    while ((c = getc (f)) != '\0' && c != EOF) {
sl@0
   407
	char cc = c;
sl@0
   408
	Tcl_DStringAppend (buf, &cc, 1);
sl@0
   409
    }
sl@0
   410
    (void) fclose (f);
sl@0
   411
    
sl@0
   412
    if (c == EOF) {
sl@0
   413
	Tcl_AppendResult (interp, "Library directory in \"", fileName,
sl@0
   414
			  "\" ends prematurely.", (char *) NULL);
sl@0
   415
	return TCL_ERROR;
sl@0
   416
    }
sl@0
   417
sl@0
   418
    return TCL_OK;
sl@0
   419
}
sl@0
   420

sl@0
   421
/*
sl@0
   422
 *------------------------------------------------------------------------
sl@0
   423
 *
sl@0
   424
 * UnlinkSymbolTable --
sl@0
   425
 *
sl@0
   426
 *	Remove the symbol table file from the last dynamic link.
sl@0
   427
 *
sl@0
   428
 * Results:
sl@0
   429
 *	None.
sl@0
   430
 *
sl@0
   431
 * Side effects:
sl@0
   432
 *	The symbol table file from the last dynamic link is removed.
sl@0
   433
 *	This function is called when (a) a new symbol table is present
sl@0
   434
 *	because another dynamic link is complete, or (b) the process
sl@0
   435
 *	is exiting.
sl@0
   436
 *------------------------------------------------------------------------
sl@0
   437
 */
sl@0
   438
sl@0
   439
static void
sl@0
   440
UnlinkSymbolTable ()
sl@0
   441
{
sl@0
   442
    (void) unlink (SymbolTableFile);
sl@0
   443
    ckfree (SymbolTableFile);
sl@0
   444
    SymbolTableFile = NULL;
sl@0
   445
}
sl@0
   446

sl@0
   447
/*
sl@0
   448
 *----------------------------------------------------------------------
sl@0
   449
 *
sl@0
   450
 * TclpUnloadFile --
sl@0
   451
 *
sl@0
   452
 *	Unloads a dynamically loaded binary code file from memory.
sl@0
   453
 *	Code pointers in the formerly loaded file are no longer valid
sl@0
   454
 *	after calling this function.
sl@0
   455
 *
sl@0
   456
 * Results:
sl@0
   457
 *	None.
sl@0
   458
 *
sl@0
   459
 * Side effects:
sl@0
   460
 *	Does nothing.  Can anything be done?
sl@0
   461
 *
sl@0
   462
 *----------------------------------------------------------------------
sl@0
   463
 */
sl@0
   464
sl@0
   465
void
sl@0
   466
TclpUnloadFile(loadHandle)
sl@0
   467
    Tcl_LoadHandle loadHandle;	/* loadHandle returned by a previous call
sl@0
   468
				 * to TclpDlopen().  The loadHandle is 
sl@0
   469
				 * a token that represents the loaded 
sl@0
   470
				 * file. */
sl@0
   471
{
sl@0
   472
}
sl@0
   473

sl@0
   474
/*
sl@0
   475
 *----------------------------------------------------------------------
sl@0
   476
 *
sl@0
   477
 * TclGuessPackageName --
sl@0
   478
 *
sl@0
   479
 *	If the "load" command is invoked without providing a package
sl@0
   480
 *	name, this procedure is invoked to try to figure it out.
sl@0
   481
 *
sl@0
   482
 * Results:
sl@0
   483
 *	Always returns 0 to indicate that we couldn't figure out a
sl@0
   484
 *	package name;  generic code will then try to guess the package
sl@0
   485
 *	from the file name.  A return value of 1 would have meant that
sl@0
   486
 *	we figured out the package name and put it in bufPtr.
sl@0
   487
 *
sl@0
   488
 * Side effects:
sl@0
   489
 *	None.
sl@0
   490
 *
sl@0
   491
 *----------------------------------------------------------------------
sl@0
   492
 */
sl@0
   493
sl@0
   494
int
sl@0
   495
TclGuessPackageName(fileName, bufPtr)
sl@0
   496
    CONST char *fileName;	/* Name of file containing package (already
sl@0
   497
				 * translated to local form if needed). */
sl@0
   498
    Tcl_DString *bufPtr;	/* Initialized empty dstring.  Append
sl@0
   499
				 * package name to this if possible. */
sl@0
   500
{
sl@0
   501
    CONST char *p, *q;
sl@0
   502
    char *r;
sl@0
   503
sl@0
   504
    if ((q = strrchr(fileName,'/'))) {
sl@0
   505
	q++;
sl@0
   506
    } else {
sl@0
   507
	q = fileName;
sl@0
   508
    }
sl@0
   509
    if (!strncmp(q,"lib",3)) {
sl@0
   510
	q+=3;
sl@0
   511
    }
sl@0
   512
    p = q;
sl@0
   513
    while ((*p) && (*p != '.') && ((*p<'0') || (*p>'9'))) {
sl@0
   514
	p++;
sl@0
   515
    }
sl@0
   516
    if ((p>q+2) && !strncmp(p-2,"_G0.",4)) {
sl@0
   517
	p-=2;
sl@0
   518
    }
sl@0
   519
    if (p<q) {
sl@0
   520
	return 0;
sl@0
   521
    }
sl@0
   522
sl@0
   523
    Tcl_DStringAppend(bufPtr,q, p-q);
sl@0
   524
sl@0
   525
    r = Tcl_DStringValue(bufPtr);
sl@0
   526
    r += strlen(r) - (p-q);
sl@0
   527
sl@0
   528
    /*
sl@0
   529
     * Capitalize the string and then recompute the length.
sl@0
   530
     */
sl@0
   531
sl@0
   532
    Tcl_UtfToTitle(r);
sl@0
   533
    Tcl_DStringSetLength(bufPtr, strlen(Tcl_DStringValue(bufPtr)));
sl@0
   534
sl@0
   535
    return 1;
sl@0
   536
}