Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Implementation of [file tempdir]; hand-tested on OSX... |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | tip-431 |
Files: | files | file ages | folders |
SHA3-256: |
db87bf0a1206eba064c5aa545403c7e3 |
User & Date: | dkf 2019-04-30 18:31:47.196 |
Context
2019-04-30
| ||
20:18 | Document it check-in: 28b9c0cccf user: dkf tags: tip-431 | |
18:31 | Implementation of [file tempdir]; hand-tested on OSX... check-in: db87bf0a12 user: dkf tags: tip-431 | |
13:35 | Export API check-in: f19a5c884c user: dkf tags: tip-431 | |
Changes
Changes to generic/tclCmdAH.c.
︙ | ︙ | |||
1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 | {"rootname", PathRootNameCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"separator", FilesystemSeparatorCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {"size", FileAttrSizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"split", PathSplitCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"stat", FileAttrStatCmd, TclCompileBasic2ArgCmd, NULL, NULL, 1}, {"system", PathFilesystemCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {"tail", PathTailCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"tempfile", TclFileTemporaryCmd, TclCompileBasic0To2ArgCmd, NULL, NULL, 1}, {"type", FileAttrTypeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"volumes", FilesystemVolumesCmd, TclCompileBasic0ArgCmd, NULL, NULL, 1}, {"writable", FileAttrIsWritableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {NULL, NULL, NULL, NULL, NULL, 0} }; return TclMakeEnsemble(interp, "file", initMap); | > | 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 | {"rootname", PathRootNameCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"separator", FilesystemSeparatorCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {"size", FileAttrSizeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"split", PathSplitCmd, TclCompileBasic1ArgCmd, NULL, NULL, 0}, {"stat", FileAttrStatCmd, TclCompileBasic2ArgCmd, NULL, NULL, 1}, {"system", PathFilesystemCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 0}, {"tail", PathTailCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"tempdir", TclFileTempDirCmd, TclCompileBasic0Or1ArgCmd, NULL, NULL, 1}, {"tempfile", TclFileTemporaryCmd, TclCompileBasic0To2ArgCmd, NULL, NULL, 1}, {"type", FileAttrTypeCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {"volumes", FilesystemVolumesCmd, TclCompileBasic0ArgCmd, NULL, NULL, 1}, {"writable", FileAttrIsWritableCmd, TclCompileBasic1ArgCmd, NULL, NULL, 1}, {NULL, NULL, NULL, NULL, NULL, 0} }; return TclMakeEnsemble(interp, "file", initMap); |
︙ | ︙ |
Changes to generic/tclFCmd.c.
︙ | ︙ | |||
1341 1342 1343 1344 1345 1346 1347 | Tcl_DecrRefCount(contents); return TCL_OK; } /* *--------------------------------------------------------------------------- * | | | 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 | Tcl_DecrRefCount(contents); return TCL_OK; } /* *--------------------------------------------------------------------------- * * TclFileTemporaryCmd -- * * This function implements the "tempfile" subcommand of the "file" * command. * * Results: * Returns a standard Tcl result. * |
︙ | ︙ | |||
1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 | Tcl_UnregisterChannel(interp, chan); return TCL_ERROR; } } Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetChannelName(chan), -1)); return TCL_OK; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 | Tcl_UnregisterChannel(interp, chan); return TCL_ERROR; } } Tcl_SetObjResult(interp, Tcl_NewStringObj(Tcl_GetChannelName(chan), -1)); return TCL_OK; } /* *--------------------------------------------------------------------------- * * TclFileTempDirCmd -- * * This function implements the "tempdir" subcommand of the "file" * command. * * Results: * Returns a standard Tcl result. * * Side effects: * Creates a temporary directory. * *--------------------------------------------------------------------------- */ int TclFileTempDirCmd( ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) { Tcl_Obj *dirNameObj; /* Object that will contain the directory * name. */ Tcl_Obj *baseDirObj = NULL, *nameBaseObj = NULL; /* Pieces of template. Each piece is NULL if * it is omitted. The platform temporary file * engine might ignore some pieces. */ if (objc < 1 || objc > 2) { Tcl_WrongNumArgs(interp, 1, objv, "?template?"); return TCL_ERROR; } if (objc > 1) { int length; Tcl_Obj *templateObj = objv[1]; const char *string = TclGetStringFromObj(templateObj, &length); const int onWindows = (tclPlatform == TCL_PLATFORM_WINDOWS); /* * Treat an empty string as if it wasn't there. */ if (length == 0) { goto makeTemporary; } /* * The template only gives a directory if there is a directory * separator in it, and only gives a base name if there's at least one * character after the last directory separator. */ if (strchr(string, '/') == NULL && (!onWindows || strchr(string, '\\') == NULL)) { /* * No directory separator, so just assume we have a file name. * This is a bit wrong on Windows where we could have problems * with disk name prefixes... but those are much less common in * naked form so we just pass through and let the OS figure it out * instead. */ nameBaseObj = templateObj; Tcl_IncrRefCount(nameBaseObj); } else if (string[length-1] != '/' && (!onWindows || string[length-1] != '\\')) { /* * If the template has a non-terminal directory separator, split * into dirname and tail. */ baseDirObj = TclPathPart(interp, templateObj, TCL_PATH_DIRNAME); nameBaseObj = TclPathPart(interp, templateObj, TCL_PATH_TAIL); } else { /* * Otherwise, there must be a terminal directory separator, so * just the directory is given. */ baseDirObj = templateObj; Tcl_IncrRefCount(baseDirObj); } /* * Only allow creation of temporary directories in the native * filesystem since they are frequently used for integration with * external tools or system libraries. */ if (baseDirObj != NULL && Tcl_FSGetFileSystemForPath(baseDirObj) != &tclNativeFilesystem) { TclDecrRefCount(baseDirObj); baseDirObj = NULL; } } /* * Convert empty parts of the template into unspecified parts. */ if (baseDirObj && !TclGetString(baseDirObj)[0]) { TclDecrRefCount(baseDirObj); baseDirObj = NULL; } if (nameBaseObj && !TclGetString(nameBaseObj)[0]) { TclDecrRefCount(nameBaseObj); nameBaseObj = NULL; } /* * Create and open the temporary file. */ makeTemporary: dirNameObj = TclpCreateTemporaryDirectory(baseDirObj, nameBaseObj); /* * If we created pieces of template, get rid of them now. */ if (baseDirObj) { TclDecrRefCount(baseDirObj); } if (nameBaseObj) { TclDecrRefCount(nameBaseObj); } /* * Deal with results. */ if (dirNameObj == NULL) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "can't create temporary directory: %s", Tcl_PosixError(interp))); return TCL_ERROR; } Tcl_SetObjResult(interp, dirNameObj); return TCL_OK; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */ |
Changes to generic/tclInt.h.
︙ | ︙ | |||
2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 | MODULE_SCOPE Tcl_ObjCmdProc TclFileAttrsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileCopyCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileDeleteCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileLinkCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileMakeDirsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileReadLinkCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileRenameCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTemporaryCmd; MODULE_SCOPE void TclCreateLateExitHandler(Tcl_ExitProc *proc, ClientData clientData); MODULE_SCOPE void TclDeleteLateExitHandler(Tcl_ExitProc *proc, ClientData clientData); MODULE_SCOPE char * TclDStringAppendObj(Tcl_DString *dsPtr, Tcl_Obj *objPtr); | > | 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 | MODULE_SCOPE Tcl_ObjCmdProc TclFileAttrsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileCopyCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileDeleteCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileLinkCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileMakeDirsCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileReadLinkCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileRenameCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTempDirCmd; MODULE_SCOPE Tcl_ObjCmdProc TclFileTemporaryCmd; MODULE_SCOPE void TclCreateLateExitHandler(Tcl_ExitProc *proc, ClientData clientData); MODULE_SCOPE void TclDeleteLateExitHandler(Tcl_ExitProc *proc, ClientData clientData); MODULE_SCOPE char * TclDStringAppendObj(Tcl_DString *dsPtr, Tcl_Obj *objPtr); |
︙ | ︙ |
Changes to unix/tclUnixFCmd.c.
︙ | ︙ | |||
2310 2311 2312 2313 2314 2315 2316 | string = TclGetString(dirObj); Tcl_UtfToExternalDString(NULL, string, dirObj->length, &template); } else { Tcl_DStringInit(&template); Tcl_DStringAppend(&template, DefaultTempDir(), -1); /* INTL: native */ } | > | > | 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 | string = TclGetString(dirObj); Tcl_UtfToExternalDString(NULL, string, dirObj->length, &template); } else { Tcl_DStringInit(&template); Tcl_DStringAppend(&template, DefaultTempDir(), -1); /* INTL: native */ } if (Tcl_DStringValue(&template)[Tcl_DStringLength(&template) - 1] != '/') { TclDStringAppendLiteral(&template, "/"); } if (basenameObj) { string = TclGetString(basenameObj); if (basenameObj->length) { Tcl_UtfToExternalDString(NULL, string, basenameObj->length, &tmp); TclDStringAppendDString(&template, &tmp); Tcl_DStringFree(&tmp); |
︙ | ︙ |
Changes to win/tclWinFCmd.c.
︙ | ︙ | |||
1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 | Tcl_Obj * TclpCreateTemporaryDirectory( Tcl_Obj *dirObj, Tcl_Obj *basenameObj) { Tcl_DString base, name; /* Contains WCHARs */ int baseLen; /* * Build the path in writable memory from the user-supplied pieces and * some defaults. First, the parent temporary directory. */ if (dirObj) { Tcl_GetString(dirObj); if (dirObj->length < 1) { goto useSystemTemp; } Tcl_WinUtfToTChar(Tcl_GetString(dirObj), -1, &base); | > | | | 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 | Tcl_Obj * TclpCreateTemporaryDirectory( Tcl_Obj *dirObj, Tcl_Obj *basenameObj) { Tcl_DString base, name; /* Contains WCHARs */ int baseLen; DWORD error; /* * Build the path in writable memory from the user-supplied pieces and * some defaults. First, the parent temporary directory. */ if (dirObj) { Tcl_GetString(dirObj); if (dirObj->length < 1) { goto useSystemTemp; } Tcl_WinUtfToTChar(Tcl_GetString(dirObj), -1, &base); if (dirObj->bytes[dirObj->length - 1] != '\\') { TclUtfToWCharDString("\\", -1, &base); } } else { useSystemTemp: WCHAR tempBuf[MAX_PATH + 1]; DWORD len = GetTempPathW(MAX_PATH, tempBuf); Tcl_DStringInit(&base); |
︙ | ︙ | |||
2018 2019 2020 2021 2022 2023 2024 | Tcl_DStringFree(&name); } else { TclUtfToWCharDString(DEFAULT_TEMP_DIR_PREFIX, -1, &base); } TclUtfToWCharDString("_", -1, &base); /* | | > | | > | > > > > > > > > > > > > | 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 | Tcl_DStringFree(&name); } else { TclUtfToWCharDString(DEFAULT_TEMP_DIR_PREFIX, -1, &base); } TclUtfToWCharDString("_", -1, &base); /* * Now we keep on trying random suffixes until we get one that works * (i.e., that doesn't trigger the ERROR_ALREADY_EXISTS error). Note that * SUFFIX_LENGTH is longer than on Unix because we expect to be not on a * case-sensitive filesystem. */ baseLen = Tcl_DStringLength(&base); do { char tempbuf[SUFFIX_LENGTH + 1]; int i; static const char randChars[] = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890"; static const int numRandChars = sizeof(randChars) - 1; /* * Put a random suffix on the end. */ error = ERROR_SUCCESS; tempbuf[SUFFIX_LENGTH] = '\0'; for (i = 0 ; i < SUFFIX_LENGTH; i++) { tempbuf[i] = randChars[(int) (rand() * numRandChars)]; } Tcl_DStringSetLength(&base, baseLen); TclUtfToWCharDString(tempbuf, -1, &base); } while (!CreateDirectoryW((LPCWSTR) Tcl_DStringValue(&base), NULL) && (error = GetLastError()) == ERROR_ALREADY_EXISTS); /* * Check for other errors. The big ones are ERROR_PATH_NOT_FOUND and * ERROR_ACCESS_DENIED. */ if (error != ERROR_SUCCESS) { TclWinConvertError(error); Tcl_DStringFree(&base); return NULL; } /* * We actually made the directory, so we're done! Report what we made back * as a (clean) Tcl_Obj. */ Tcl_WinTCharToUtf((LPCWSTR) Tcl_DStringValue(&base), -1, &name); |
︙ | ︙ |