/* - allcases - supply cvec for all case counterparts of a chr (including itself) * This is a shortcut, preferably an efficient one, for simple characters; * messy cases are done via range(). ^ static struct cvec *allcases(struct vars *, pchr); */ static struct cvec * allcases( struct vars *v, /* context */ pchr pc) /* character to get case equivs of */ { struct cvec *cv; chr c = (chr)pc; chr lc, uc, tc; lc = Tcl_UniCharToLower((chr)c); uc = Tcl_UniCharToUpper((chr)c); tc = Tcl_UniCharToTitle((chr)c); if (tc != uc) { cv = getcvec(v, 3, 0); addchr(cv, tc); } else { cv = getcvec(v, 2, 0); } addchr(cv, lc); if (lc != uc) { addchr(cv, uc); } return cv; }
/* - range - supply cvec for a range, including legality check ^ static struct cvec *range(struct vars *, celt, celt, int); */ static struct cvec * range( struct vars *v, /* context */ celt a, /* range start */ celt b, /* range end, might equal a */ int cases) /* case-independent? */ { int nchrs; struct cvec *cv; celt c, lc, uc, tc; if (a != b && !before(a, b)) { ERR(REG_ERANGE); return NULL; } if (!cases) { /* easy version */ cv = getcvec(v, 0, 1); NOERRN(); addrange(cv, a, b); return cv; } /* * When case-independent, it's hard to decide when cvec ranges are usable, * so for now at least, we won't try. We allocate enough space for two * case variants plus a little extra for the two title case variants. */ nchrs = (b - a + 1)*2 + 4; cv = getcvec(v, nchrs, 0); NOERRN(); for (c=a; c<=b; c++) { addchr(cv, c); lc = Tcl_UniCharToLower((chr)c); uc = Tcl_UniCharToUpper((chr)c); tc = Tcl_UniCharToTitle((chr)c); if (c != lc) { addchr(cv, lc); } if (c != uc) { addchr(cv, uc); } if (c != tc && tc != uc) { addchr(cv, tc); } } return cv; }
static int ConvertFileNameFormat( Tcl_Interp *interp, /* The interp we are using for errors. */ int objIndex, /* The index of the attribute. */ CONST char *fileName, /* The name of the file. */ int longShort, /* 0 to short name, 1 to long name. */ Tcl_Obj **attributePtrPtr) /* A pointer to return the object with. */ { int pathc, i; char **pathv, **newv; char *resultStr; Tcl_DString resultDString; int result = TCL_OK; Tcl_SplitPath(fileName, &pathc, &pathv); newv = (char **) ckalloc(pathc * sizeof(char *)); if (pathc == 0) { Tcl_AppendStringsToObj(Tcl_GetObjResult(interp), "could not read \"", fileName, "\": no such file or directory", (char *) NULL); result = TCL_ERROR; goto cleanup; } for (i = 0; i < pathc; i++) { if ((pathv[i][0] == '/') || ((strlen(pathv[i]) == 3) && (pathv[i][1] == ':')) || (strcmp(pathv[i], ".") == 0) || (strcmp(pathv[i], "..") == 0)) { /* * Handle "/", "//machine/export", "c:/", "." or ".." by just * copying the string literally. Uppercase the drive letter, * just because it looks better under Windows to do so. */ simple: pathv[i][0] = (char) Tcl_UniCharToUpper(UCHAR(pathv[i][0])); newv[i] = (char *) ckalloc(strlen(pathv[i]) + 1); lstrcpyA(newv[i], pathv[i]); } else { char *str; TCHAR *nativeName; Tcl_DString ds; WIN32_FIND_DATAT data; HANDLE handle; DWORD attr; Tcl_DStringInit(&resultDString); str = Tcl_JoinPath(i + 1, pathv, &resultDString); nativeName = Tcl_WinUtfToTChar(str, -1, &ds); handle = (*tclWinProcs->findFirstFileProc)(nativeName, &data); if (handle == INVALID_HANDLE_VALUE) { /* * FindFirstFile() doesn't like root directories. We * would only get a root directory here if the caller * specified "c:" or "c:." and the current directory on the * drive was the root directory */ attr = (*tclWinProcs->getFileAttributesProc)(nativeName); if ((attr != 0xFFFFFFFF) && (attr & FILE_ATTRIBUTE_DIRECTORY)) { Tcl_DStringFree(&ds); Tcl_DStringFree(&resultDString); goto simple; } } Tcl_DStringFree(&ds); Tcl_DStringFree(&resultDString); if (handle == INVALID_HANDLE_VALUE) { pathc = i - 1; StatError(interp, fileName); result = TCL_ERROR; goto cleanup; } if (tclWinProcs->useWide) { nativeName = (TCHAR *) data.w.cAlternateFileName; if (longShort) { if (data.w.cFileName[0] != '\0') { nativeName = (TCHAR *) data.w.cFileName; } } else { if (data.w.cAlternateFileName[0] == '\0') { nativeName = (TCHAR *) data.w.cFileName; } } } else { nativeName = (TCHAR *) data.a.cAlternateFileName; if (longShort) { if (data.a.cFileName[0] != '\0') { nativeName = (TCHAR *) data.a.cFileName; } } else { if (data.a.cAlternateFileName[0] == '\0') { nativeName = (TCHAR *) data.a.cFileName; } } } /* * Purify reports a extraneous UMR in Tcl_WinTCharToUtf() trying * to dereference nativeName as a Unicode string. I have proven * to myself that purify is wrong by running the following * example when nativeName == data.w.cAlternateFileName and * noting that purify doesn't complain about the first line, * but does complain about the second. * * fprintf(stderr, "%d\n", data.w.cAlternateFileName[0]); * fprintf(stderr, "%d\n", ((WCHAR *) nativeName)[0]); */ Tcl_WinTCharToUtf(nativeName, -1, &ds); newv[i] = ckalloc(Tcl_DStringLength(&ds) + 1); lstrcpyA(newv[i], Tcl_DStringValue(&ds)); Tcl_DStringFree(&ds); FindClose(handle); } } Tcl_DStringInit(&resultDString); resultStr = Tcl_JoinPath(pathc, newv, &resultDString); *attributePtrPtr = Tcl_NewStringObj(resultStr, Tcl_DStringLength(&resultDString)); Tcl_DStringFree(&resultDString); cleanup: for (i = 0; i < pathc; i++) { ckfree(newv[i]); } ckfree((char *) newv); ckfree((char *) pathv); return result; }