OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [insight/] [tcl/] [unix/] [tclUnixFile.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
/*
2
 * tclUnixFile.c --
3
 *
4
 *      This file contains wrappers around UNIX file handling functions.
5
 *      These wrappers mask differences between Windows and UNIX.
6
 *
7
 * Copyright (c) 1995 Sun Microsystems, Inc.
8
 *
9
 * See the file "license.terms" for information on usage and redistribution
10
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11
 *
12
 * RCS: @(#) $Id: tclUnixFile.c,v 1.1.1.1 2002-01-16 10:25:37 markom Exp $
13
 */
14
 
15
#include "tclInt.h"
16
#include "tclPort.h"
17
 
18
/*
19
 * The variable below caches the name of the current working directory
20
 * in order to avoid repeated calls to getcwd.  The string is malloc-ed.
21
 * NULL means the cache needs to be refreshed.
22
 */
23
 
24
static char *currentDir =  NULL;
25
static int currentDirExitHandlerSet = 0;
26
 
27
/*
28
 * The variable below is set if the exit routine for deleting the string
29
 * containing the executable name has been registered.
30
 */
31
 
32
static int executableNameExitHandlerSet = 0;
33
 
34
extern pid_t waitpid _ANSI_ARGS_((pid_t pid, int *stat_loc, int options));
35
 
36
/*
37
 * Static routines for this file:
38
 */
39
 
40
static void     FreeCurrentDir _ANSI_ARGS_((ClientData clientData));
41
static void     FreeExecutableName _ANSI_ARGS_((ClientData clientData));
42
 
43
/*
44
 *----------------------------------------------------------------------
45
 *
46
 * FreeCurrentDir --
47
 *
48
 *      Frees the string stored in the currentDir variable. This routine
49
 *      is registered as an exit handler and will be called during shutdown.
50
 *
51
 * Results:
52
 *      None.
53
 *
54
 * Side effects:
55
 *      Frees the memory occuppied by the currentDir value.
56
 *
57
 *----------------------------------------------------------------------
58
 */
59
 
60
        /* ARGSUSED */
61
static void
62
FreeCurrentDir(clientData)
63
    ClientData clientData;      /* Not used. */
64
{
65
    if (currentDir != (char *) NULL) {
66
        ckfree(currentDir);
67
        currentDir = (char *) NULL;
68
        currentDirExitHandlerSet = 0;
69
    }
70
}
71
 
72
/*
73
 *----------------------------------------------------------------------
74
 *
75
 * FreeExecutableName --
76
 *
77
 *      Frees the string stored in the tclExecutableName variable. This
78
 *      routine is registered as an exit handler and will be called
79
 *      during shutdown.
80
 *
81
 * Results:
82
 *      None.
83
 *
84
 * Side effects:
85
 *      Frees the memory occuppied by the tclExecutableName value.
86
 *
87
 *----------------------------------------------------------------------
88
 */
89
 
90
        /* ARGSUSED */
91
static void
92
FreeExecutableName(clientData)
93
    ClientData clientData;      /* Not used. */
94
{
95
    if (tclExecutableName != (char *) NULL) {
96
        ckfree(tclExecutableName);
97
        tclExecutableName = (char *) NULL;
98
    }
99
}
100
 
101
/*
102
 *----------------------------------------------------------------------
103
 *
104
 * TclChdir --
105
 *
106
 *      Change the current working directory.
107
 *
108
 * Results:
109
 *      The result is a standard Tcl result.  If an error occurs and
110
 *      interp isn't NULL, an error message is left in interp->result.
111
 *
112
 * Side effects:
113
 *      The working directory for this application is changed.  Also
114
 *      the cache maintained used by TclGetCwd is deallocated and
115
 *      set to NULL.
116
 *
117
 *----------------------------------------------------------------------
118
 */
119
 
120
int
121
TclChdir(interp, dirName)
122
    Tcl_Interp *interp;         /* If non NULL, used for error reporting. */
123
    char *dirName;              /* Path to new working directory. */
124
{
125
    if (currentDir != NULL) {
126
        ckfree(currentDir);
127
        currentDir = NULL;
128
    }
129
    if (chdir(dirName) != 0) {
130
        if (interp != NULL) {
131
            Tcl_AppendResult(interp, "couldn't change working directory to \"",
132
                    dirName, "\": ", Tcl_PosixError(interp), (char *) NULL);
133
        }
134
        return TCL_ERROR;
135
    }
136
    return TCL_OK;
137
}
138
 
139
/*
140
 *----------------------------------------------------------------------
141
 *
142
 * TclGetCwd --
143
 *
144
 *      Return the path name of the current working directory.
145
 *
146
 * Results:
147
 *      The result is the full path name of the current working
148
 *      directory, or NULL if an error occurred while figuring it out.
149
 *      The returned string is owned by the TclGetCwd routine and must
150
 *      not be freed by the caller.  If an error occurs and interp
151
 *      isn't NULL, an error message is left in interp->result.
152
 *
153
 * Side effects:
154
 *      The path name is cached to avoid having to recompute it
155
 *      on future calls;  if it is already cached, the cached
156
 *      value is returned.
157
 *
158
 *----------------------------------------------------------------------
159
 */
160
 
161
char *
162
TclGetCwd(interp)
163
    Tcl_Interp *interp;         /* If non NULL, used for error reporting. */
164
{
165
    char buffer[MAXPATHLEN+1];
166
 
167
    if (currentDir == NULL) {
168
        if (!currentDirExitHandlerSet) {
169
            currentDirExitHandlerSet = 1;
170
            Tcl_CreateExitHandler(FreeCurrentDir, (ClientData) NULL);
171
        }
172
#ifdef USEGETWD
173
        if ((int)getwd(buffer) == (int)NULL) {
174
            if (interp != NULL) {
175
                Tcl_AppendResult(interp,
176
                        "error getting working directory name: ",
177
                        buffer, (char *)NULL);
178
            }
179
            return NULL;
180
        }
181
#else
182
        if (getcwd(buffer, MAXPATHLEN+1) == NULL) {
183
            if (interp != NULL) {
184
                if (errno == ERANGE) {
185
                    Tcl_SetResult(interp,
186
                            "working directory name is too long",
187
                            TCL_STATIC);
188
                } else {
189
                    Tcl_AppendResult(interp,
190
                            "error getting working directory name: ",
191
                            Tcl_PosixError(interp), (char *) NULL);
192
                }
193
            }
194
            return NULL;
195
        }
196
#endif
197
        currentDir = (char *) ckalloc((unsigned) (strlen(buffer) + 1));
198
        strcpy(currentDir, buffer);
199
    }
200
    return currentDir;
201
}
202
 
203
/*
204
 *----------------------------------------------------------------------
205
 *
206
 * Tcl_FindExecutable --
207
 *
208
 *      This procedure computes the absolute path name of the current
209
 *      application, given its argv[0] value.
210
 *
211
 * Results:
212
 *      None.
213
 *
214
 * Side effects:
215
 *      The variable tclExecutableName gets filled in with the file
216
 *      name for the application, if we figured it out.  If we couldn't
217
 *      figure it out, Tcl_FindExecutable is set to NULL.
218
 *
219
 *----------------------------------------------------------------------
220
 */
221
 
222
void
223
Tcl_FindExecutable(argv0)
224
    char *argv0;                /* The value of the application's argv[0]. */
225
{
226
    char *name, *p, *cwd;
227
    Tcl_DString buffer;
228
    int length;
229
    struct stat statBuf;
230
 
231
    Tcl_DStringInit(&buffer);
232
    if (tclExecutableName != NULL) {
233
        ckfree(tclExecutableName);
234
        tclExecutableName = NULL;
235
    }
236
 
237
    name = argv0;
238
    for (p = name; *p != 0; p++) {
239
        if (*p == '/') {
240
            /*
241
             * The name contains a slash, so use the name directly
242
             * without doing a path search.
243
             */
244
 
245
            goto gotName;
246
        }
247
    }
248
 
249
    p = getenv("PATH");
250
    if (p == NULL) {
251
        /*
252
         * There's no PATH environment variable; use the default that
253
         * is used by sh.
254
         */
255
 
256
        p = ":/bin:/usr/bin";
257
    } else if (*p == '\0') {
258
        /*
259
         * An empty path is equivalent to ".".
260
         */
261
 
262
        p = "./";
263
    }
264
 
265
    /*
266
     * Search through all the directories named in the PATH variable
267
     * to see if argv[0] is in one of them.  If so, use that file
268
     * name.
269
     */
270
 
271
    while (*p != 0) {
272
        while (isspace(UCHAR(*p))) {
273
            p++;
274
        }
275
        name = p;
276
        while ((*p != ':') && (*p != 0)) {
277
            p++;
278
        }
279
        Tcl_DStringSetLength(&buffer, 0);
280
        if (p != name) {
281
            Tcl_DStringAppend(&buffer, name, p-name);
282
            if (p[-1] != '/') {
283
                Tcl_DStringAppend(&buffer, "/", 1);
284
            }
285
        }
286
        Tcl_DStringAppend(&buffer, argv0, -1);
287
        if ((TclAccess(Tcl_DStringValue(&buffer), X_OK) == 0)
288
                && (TclStat(Tcl_DStringValue(&buffer), &statBuf) == 0)
289
                && S_ISREG(statBuf.st_mode)) {
290
            name = Tcl_DStringValue(&buffer);
291
            goto gotName;
292
        }
293
        if (*p == 0) {
294
            break;
295
        } else if (*(p+1) == 0) {
296
            p = "./";
297
        } else {
298
            p++;
299
        }
300
    }
301
    goto done;
302
 
303
    /*
304
     * If the name starts with "/" then just copy it to tclExecutableName.
305
     */
306
 
307
    gotName:
308
    if (name[0] == '/')  {
309
        tclExecutableName = (char *) ckalloc((unsigned) (strlen(name) + 1));
310
        strcpy(tclExecutableName, name);
311
        goto done;
312
    }
313
 
314
    /*
315
     * The name is relative to the current working directory.  First
316
     * strip off a leading "./", if any, then add the full path name of
317
     * the current working directory.
318
     */
319
 
320
    if ((name[0] == '.') && (name[1] == '/')) {
321
        name += 2;
322
    }
323
    cwd = TclGetCwd((Tcl_Interp *) NULL);
324
    if (cwd == NULL) {
325
        tclExecutableName = NULL;
326
        goto done;
327
    }
328
    length = strlen(cwd);
329
    tclExecutableName = (char *) ckalloc((unsigned)
330
            (length + strlen(name) + 2));
331
    strcpy(tclExecutableName, cwd);
332
    tclExecutableName[length] = '/';
333
    strcpy(tclExecutableName + length + 1, name);
334
 
335
    done:
336
    Tcl_DStringFree(&buffer);
337
 
338
    if (!executableNameExitHandlerSet) {
339
        executableNameExitHandlerSet = 1;
340
        Tcl_CreateExitHandler(FreeExecutableName, (ClientData) NULL);
341
    }
342
}
343
 
344
/*
345
 *----------------------------------------------------------------------
346
 *
347
 * TclGetUserHome --
348
 *
349
 *      This function takes the passed in user name and finds the
350
 *      corresponding home directory specified in the password file.
351
 *
352
 * Results:
353
 *      The result is a pointer to a static string containing
354
 *      the new name.  If there was an error in processing the
355
 *      user name then the return value is NULL.  Otherwise the
356
 *      result is stored in bufferPtr, and the caller must call
357
 *      Tcl_DStringFree(bufferPtr) to free the result.
358
 *
359
 * Side effects:
360
 *      Information may be left in bufferPtr.
361
 *
362
 *----------------------------------------------------------------------
363
 */
364
 
365
char *
366
TclGetUserHome(name, bufferPtr)
367
    char *name;                 /* User name to use to find home directory. */
368
    Tcl_DString *bufferPtr;     /* May be used to hold result.  Must not hold
369
                                 * anything at the time of the call, and need
370
                                 * not even be initialized. */
371
{
372
    struct passwd *pwPtr;
373
 
374
    pwPtr = getpwnam(name);
375
    if (pwPtr == NULL) {
376
        endpwent();
377
        return NULL;
378
    }
379
    Tcl_DStringInit(bufferPtr);
380
    Tcl_DStringAppend(bufferPtr, pwPtr->pw_dir, -1);
381
    endpwent();
382
    return bufferPtr->string;
383
}
384
 
385
/*
386
 *----------------------------------------------------------------------
387
 *
388
 * TclMatchFiles --
389
 *
390
 *      This routine is used by the globbing code to search a
391
 *      directory for all files which match a given pattern.
392
 *
393
 * Results:
394
 *      If the tail argument is NULL, then the matching files are
395
 *      added to the interp->result.  Otherwise, TclDoGlob is called
396
 *      recursively for each matching subdirectory.  The return value
397
 *      is a standard Tcl result indicating whether an error occurred
398
 *      in globbing.
399
 *
400
 * Side effects:
401
 *      None.
402
 *
403
 *----------------------------------------------------------------------
404
 */
405
 
406
int
407
TclMatchFiles(interp, separators, dirPtr, pattern, tail)
408
    Tcl_Interp *interp;         /* Interpreter to receive results. */
409
    char *separators;           /* Path separators to pass to TclDoGlob. */
410
    Tcl_DString *dirPtr;        /* Contains path to directory to search. */
411
    char *pattern;              /* Pattern to match against. */
412
    char *tail;                 /* Pointer to end of pattern. */
413
{
414
    char *dirName, *patternEnd = tail;
415
    char savedChar = 0;          /* Initialization needed only to prevent
416
                                 * compiler warning from gcc. */
417
    DIR *d;
418
    struct stat statBuf;
419
    struct dirent *entryPtr;
420
    int matchHidden;
421
    int result = TCL_OK;
422
    int baseLength = Tcl_DStringLength(dirPtr);
423
 
424
    /*
425
     * Make sure that the directory part of the name really is a
426
     * directory.  If the directory name is "", use the name "."
427
     * instead, because some UNIX systems don't treat "" like "."
428
     * automatically.  Keep the "" for use in generating file names,
429
     * otherwise "glob foo.c" would return "./foo.c".
430
     */
431
 
432
    if (dirPtr->string[0] == '\0') {
433
        dirName = ".";
434
    } else {
435
        dirName = dirPtr->string;
436
    }
437
    if ((TclStat(dirName, &statBuf) != 0) || !S_ISDIR(statBuf.st_mode)) {
438
        return TCL_OK;
439
    }
440
 
441
    /*
442
     * Check to see if the pattern needs to compare with hidden files.
443
     */
444
 
445
    if ((pattern[0] == '.')
446
            || ((pattern[0] == '\\') && (pattern[1] == '.'))) {
447
        matchHidden = 1;
448
    } else {
449
        matchHidden = 0;
450
    }
451
 
452
    /*
453
     * Now open the directory for reading and iterate over the contents.
454
     */
455
 
456
    d = opendir(dirName);
457
    if (d == NULL) {
458
        Tcl_ResetResult(interp);
459
 
460
        /*
461
         * Strip off a trailing '/' if necessary, before reporting the error.
462
         */
463
 
464
        if (baseLength > 0) {
465
            savedChar = dirPtr->string[baseLength-1];
466
            if (savedChar == '/') {
467
                dirPtr->string[baseLength-1] = '\0';
468
            }
469
        }
470
        Tcl_AppendResult(interp, "couldn't read directory \"",
471
                dirPtr->string, "\": ", Tcl_PosixError(interp), (char *) NULL);
472
        if (baseLength > 0) {
473
            dirPtr->string[baseLength-1] = savedChar;
474
        }
475
        return TCL_ERROR;
476
    }
477
 
478
    /*
479
     * Clean up the end of the pattern and the tail pointer.  Leave
480
     * the tail pointing to the first character after the path separator
481
     * following the pattern, or NULL.  Also, ensure that the pattern
482
     * is null-terminated.
483
     */
484
 
485
    if (*tail == '\\') {
486
        tail++;
487
    }
488
    if (*tail == '\0') {
489
        tail = NULL;
490
    } else {
491
        tail++;
492
    }
493
    savedChar = *patternEnd;
494
    *patternEnd = '\0';
495
 
496
    while (1) {
497
        entryPtr = readdir(d);
498
        if (entryPtr == NULL) {
499
            break;
500
        }
501
 
502
        /*
503
         * Don't match names starting with "." unless the "." is
504
         * present in the pattern.
505
         */
506
 
507
        if (!matchHidden && (*entryPtr->d_name == '.')) {
508
            continue;
509
        }
510
 
511
        /*
512
         * Now check to see if the file matches.  If there are more
513
         * characters to be processed, then ensure matching files are
514
         * directories before calling TclDoGlob. Otherwise, just add
515
         * the file to the result.
516
         */
517
 
518
        if (Tcl_StringMatch(entryPtr->d_name, pattern)) {
519
            Tcl_DStringSetLength(dirPtr, baseLength);
520
            Tcl_DStringAppend(dirPtr, entryPtr->d_name, -1);
521
            if (tail == NULL) {
522
                Tcl_AppendElement(interp, dirPtr->string);
523
            } else if ((TclStat(dirPtr->string, &statBuf) == 0)
524
                    && S_ISDIR(statBuf.st_mode)) {
525
                Tcl_DStringAppend(dirPtr, "/", 1);
526
                result = TclDoGlob(interp, separators, dirPtr, tail);
527
                if (result != TCL_OK) {
528
                    break;
529
                }
530
            }
531
        }
532
    }
533
    *patternEnd = savedChar;
534
 
535
    closedir(d);
536
    return result;
537
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.