/* * tkFileFilter.c -- * * Process the -filetypes option for the file dialogs on Windows and the * Mac. * * Copyright © 1996 Sun Microsystems, Inc. * * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tkInt.h" #include "tkFileFilter.h" static int AddClause(Tcl_Interp *interp, FileFilter *filterPtr, Tcl_Obj *patternsObj, Tcl_Obj *ostypesObj, int isWindows); static FileFilter * GetFilter(FileFilterList *flistPtr, const char *name); /* *---------------------------------------------------------------------- * * TkInitFileFilters -- * * Initializes a FileFilterList data structure. A FileFilterList must be * initialized EXACTLY ONCE before any calls to TkGetFileFilters() is * made. The usual flow of control is: * TkInitFileFilters(&flist); * TkGetFileFilters(&flist, ...); * TkGetFileFilters(&flist, ...); * ... * TkFreeFileFilters(&flist); * * Results: * None. * * Side effects: * The fields in flistPtr are initialized. * *---------------------------------------------------------------------- */ void TkInitFileFilters( FileFilterList *flistPtr) /* The structure to be initialized. */ { flistPtr->filters = NULL; flistPtr->filtersTail = NULL; flistPtr->numFilters = 0; } /* *---------------------------------------------------------------------- * * TkGetFileFilters -- * * This function is called by the Mac and Windows implementation of * tk_getOpenFile and tk_getSaveFile to translate the string value of the * -filetypes option into an easy-to-parse C structure (flistPtr). The * caller of this function will then use flistPtr to perform filetype * matching in a platform specific way. * * flistPtr must be initialized (See comments in TkInitFileFilters). * * Results: * A standard TCL return value. * * Side effects: * The fields in flistPtr are changed according to 'types'. * *---------------------------------------------------------------------- */ int TkGetFileFilters( Tcl_Interp *interp, /* Interpreter to use for error reporting. */ FileFilterList *flistPtr, /* Stores the list of file filters. */ Tcl_Obj *types, /* Value of the -filetypes option. */ int isWindows) /* True if we are running on Windows. */ { Tcl_Size i, listObjc; Tcl_Obj ** listObjv = NULL; if (types == NULL) { return TCL_OK; } if (Tcl_ListObjGetElements(interp, types, &listObjc, &listObjv) != TCL_OK) { return TCL_ERROR; } if (listObjc == 0) { return TCL_OK; } /* * Free the filter information that have been allocated the previous time; * the -filefilters option may have been used more than once in the * command line. */ TkFreeFileFilters(flistPtr); for (i = 0; ifilters; filterPtr != NULL; ) { for (clausePtr = filterPtr->clauses; clausePtr != NULL; ) { /* * Squelch each of the glob patterns. */ for (globPtr = clausePtr->patterns; globPtr != NULL; ) { ckfree(globPtr->pattern); toFree = globPtr; globPtr = globPtr->next; ckfree(toFree); } /* * Squelch each of the Mac file type codes. */ for (mfPtr = clausePtr->macTypes; mfPtr != NULL; ) { toFree = mfPtr; mfPtr = mfPtr->next; ckfree(toFree); } toFree = clausePtr; clausePtr = clausePtr->next; ckfree(toFree); } /* * Squelch the name of the filter and the overall structure. */ ckfree(filterPtr->name); toFree = filterPtr; filterPtr = filterPtr->next; ckfree(toFree); } flistPtr->filters = NULL; } /* *---------------------------------------------------------------------- * * AddClause -- * * Add one FileFilterClause to filterPtr. * * Results: * A standard TCL result. * * Side effects: * The list of filter clauses are updated in filterPtr. * *---------------------------------------------------------------------- */ static int AddClause( Tcl_Interp *interp, /* Interpreter to use for error reporting. */ FileFilter *filterPtr, /* Stores the new filter clause */ Tcl_Obj *patternsObj, /* A Tcl list of glob patterns. */ Tcl_Obj *ostypesObj, /* A Tcl list of Mac OSType strings. */ int isWindows) /* True if we are running on Windows; False if * we are running on the Mac; Glob patterns * need to be processed differently on these * two platforms */ { Tcl_Obj **globList = NULL, **ostypeList = NULL; Tcl_Size globCount, ostypeCount, i; int code = TCL_OK; FileFilterClause *clausePtr; Tcl_Encoding macRoman = NULL; if (Tcl_ListObjGetElements(interp, patternsObj, &globCount, &globList) != TCL_OK) { code = TCL_ERROR; goto done; } if (ostypesObj != NULL) { if (Tcl_ListObjGetElements(interp, ostypesObj, &ostypeCount, &ostypeList) != TCL_OK) { code = TCL_ERROR; goto done; } /* * We probably need this encoding now... */ macRoman = Tcl_GetEncoding(NULL, "macRoman"); /* * Might be cleaner to use 'Tcl_GetOSTypeFromObj' but that is actually * static to the MacOS X/Darwin version of Tcl, and would therefore * require further code refactoring. */ for (i=0; i= 4 && macRoman != NULL) { Tcl_DString osTypeDS; /* * Convert utf to macRoman, since MacOS types are defined to * be 4 macRoman characters long */ (void)Tcl_UtfToExternalDStringEx(macRoman, strType, len, TCL_ENCODING_NOCOMPLAIN, &osTypeDS); len = Tcl_DStringLength(&osTypeDS); Tcl_DStringFree(&osTypeDS); } if (len != 4) { Tcl_SetObjResult(interp, Tcl_ObjPrintf( "bad Macintosh file type \"%s\"", Tcl_GetString(ostypeList[i]))); Tcl_SetErrorCode(interp, "TK", "VALUE", "MAC_TYPE", NULL); code = TCL_ERROR; goto done; } } } /* * Add the clause into the list of clauses */ clausePtr = (FileFilterClause *)ckalloc(sizeof(FileFilterClause)); clausePtr->patterns = NULL; clausePtr->patternsTail = NULL; clausePtr->macTypes = NULL; clausePtr->macTypesTail = NULL; if (filterPtr->clauses == NULL) { filterPtr->clauses = filterPtr->clausesTail = clausePtr; } else { filterPtr->clausesTail->next = clausePtr; filterPtr->clausesTail = clausePtr; } clausePtr->next = NULL; if (globCount > 0 && globList != NULL) { for (i=0; ipattern = (char *)ckalloc(len + 1); globPtr->pattern[0] = '*'; strcpy(globPtr->pattern+1, str); } else if (isWindows) { if (strcmp(str, "*") == 0) { globPtr->pattern = (char *)ckalloc(4); strcpy(globPtr->pattern, "*.*"); } else if (strcmp(str, "") == 0) { /* * An empty string means "match all files with no * extensions" * TODO: "*." actually matches with all files on Win95 */ globPtr->pattern = (char *)ckalloc(3); strcpy(globPtr->pattern, "*."); } else { globPtr->pattern = (char *)ckalloc(len); strcpy(globPtr->pattern, str); } } else { globPtr->pattern = (char *)ckalloc(len); strcpy(globPtr->pattern, str); } /* * Add the glob pattern into the list of patterns. */ if (clausePtr->patterns == NULL) { clausePtr->patterns = clausePtr->patternsTail = globPtr; } else { clausePtr->patternsTail->next = globPtr; clausePtr->patternsTail = globPtr; } globPtr->next = NULL; } } if (ostypeList != NULL && ostypeCount > 0) { if (macRoman == NULL) { macRoman = Tcl_GetEncoding(NULL, "macRoman"); } for (i=0; itype = (OSType) string[0] << 24 | (OSType) string[1] << 16 | (OSType) string[2] << 8 | (OSType) string[3]; Tcl_DStringFree(&osTypeDS); /* * Add the Mac type pattern into the list of Mac types */ if (clausePtr->macTypes == NULL) { clausePtr->macTypes = clausePtr->macTypesTail = mfPtr; } else { clausePtr->macTypesTail->next = mfPtr; clausePtr->macTypesTail = mfPtr; } mfPtr->next = NULL; } } done: if (macRoman != NULL) { Tcl_FreeEncoding(macRoman); } return code; } /* *---------------------------------------------------------------------- * * GetFilter -- * * Add one FileFilter to flistPtr. * * Results: * A standard TCL result. * * Side effects: * The list of filters are updated in flistPtr. * *---------------------------------------------------------------------- */ static FileFilter * GetFilter( FileFilterList *flistPtr, /* The FileFilterList that contains the newly * created filter */ const char *name) /* Name of the filter. It is usually displayed * in the "File Types" listbox in the file * dialogs. */ { FileFilter *filterPtr = flistPtr->filters; size_t len; for (; filterPtr; filterPtr=filterPtr->next) { if (strcmp(filterPtr->name, name) == 0) { return filterPtr; } } filterPtr = (FileFilter *)ckalloc(sizeof(FileFilter)); filterPtr->clauses = NULL; filterPtr->clausesTail = NULL; len = strlen(name) + 1; filterPtr->name = (char *)ckalloc(len); memcpy(filterPtr->name, name, len); if (flistPtr->filters == NULL) { flistPtr->filters = flistPtr->filtersTail = filterPtr; } else { flistPtr->filtersTail->next = filterPtr; flistPtr->filtersTail = filterPtr; } filterPtr->next = NULL; ++flistPtr->numFilters; return filterPtr; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */