/* * tkFileFilter.c -- * * Process the -filetypes option for the file dialogs on Windows and the * Mac. * * Copyright (c) 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. * * RCS: @(#) $Id: tkFileFilter.c,v 1.10.4.1 2009/03/03 23:54:11 patthoyts Exp $ */ #include "tkInt.h" #include "tkFileFilter.h" static int AddClause(Tcl_Interp *interp, FileFilter *filterPtr, Tcl_Obj *patternsObj, Tcl_Obj *ostypesObj, int isWindows); static void FreeClauses(FileFilter *filterPtr); static void FreeGlobPatterns(FileFilterClause *clausePtr); static void FreeMacFileTypes(FileFilterClause *clausePtr); 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. */ { int listObjc; Tcl_Obj ** listObjv = NULL; int i; 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; while (filterPtr != NULL) { toFree = filterPtr; filterPtr = filterPtr->next; FreeClauses(toFree); ckfree((char*)toFree->name); ckfree((char*)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; int globCount, ostypeCount, i, 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 */ Tcl_UtfToExternalDString(macRoman, strType, len, &osTypeDS); len = Tcl_DStringLength(&osTypeDS); Tcl_DStringFree(&osTypeDS); } if (len != 4) { Tcl_AppendResult(interp, "bad Macintosh file type \"", Tcl_GetString(ostypeList[i]), "\"", 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((unsigned int) len+1); globPtr->pattern[0] = '*'; strcpy(globPtr->pattern+1, str); } else if (isWindows) { if (strcmp(str, "*") == 0) { globPtr->pattern = (char*)ckalloc(4 * sizeof(char)); strcpy(globPtr->pattern, "*.*"); } else if (strcmp(str, "") == 0) { /* * An empty string means "match all files with no * extensions" * BUG: "*." actually matches with all files on Win95 */ globPtr->pattern = (char *) ckalloc(3 * sizeof(char)); strcpy(globPtr->pattern, "*."); } else { globPtr->pattern = (char *) ckalloc((unsigned int) len); strcpy(globPtr->pattern, str); } } else { globPtr->pattern = (char *) ckalloc((unsigned int) 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; for (; filterPtr; filterPtr=filterPtr->next) { if (strcmp(filterPtr->name, name) == 0) { return filterPtr; } } filterPtr = (FileFilter *) ckalloc(sizeof(FileFilter)); filterPtr->clauses = NULL; filterPtr->clausesTail = NULL; filterPtr->name = (char *) ckalloc((strlen(name)+1) * sizeof(char)); strcpy(filterPtr->name, name); if (flistPtr->filters == NULL) { flistPtr->filters = flistPtr->filtersTail = filterPtr; } else { flistPtr->filtersTail->next = filterPtr; flistPtr->filtersTail = filterPtr; } filterPtr->next = NULL; ++flistPtr->numFilters; return filterPtr; } /* *---------------------------------------------------------------------- * * FreeClauses -- * * Frees the malloc'ed file type clause * * Results: * None. * * Side effects: * The list of clauses in filterPtr->clauses are freed. * *---------------------------------------------------------------------- */ static void FreeClauses( FileFilter *filterPtr) /* FileFilter whose clauses are to be freed */ { FileFilterClause *clausePtr = filterPtr->clauses; while (clausePtr != NULL) { FileFilterClause *toFree = clausePtr; clausePtr = clausePtr->next; FreeGlobPatterns(toFree); FreeMacFileTypes(toFree); ckfree((char *) toFree); } filterPtr->clauses = NULL; filterPtr->clausesTail = NULL; } /* *---------------------------------------------------------------------- * * FreeGlobPatterns -- * * Frees the malloc'ed glob patterns in a clause * * Results: * None. * * Side effects: * The list of glob patterns in clausePtr->patterns are freed. * *---------------------------------------------------------------------- */ static void FreeGlobPatterns( FileFilterClause *clausePtr)/* The clause whose patterns are to be freed*/ { GlobPattern *globPtr = clausePtr->patterns; while (globPtr != NULL) { GlobPattern *toFree = globPtr; globPtr = globPtr->next; ckfree((char *) toFree->pattern); ckfree((char *) toFree); } clausePtr->patterns = NULL; } /* *---------------------------------------------------------------------- * * FreeMacFileTypes -- * * Frees the malloc'ed Mac file types in a clause * * Results: * None. * * Side effects: * The list of Mac file types in clausePtr->macTypes are freed. * *---------------------------------------------------------------------- */ static void FreeMacFileTypes( FileFilterClause *clausePtr)/* The clause whose mac types are to be * freed */ { MacFileType *mfPtr = clausePtr->macTypes; while (mfPtr != NULL) { MacFileType *toFree = mfPtr; mfPtr = mfPtr->next; ckfree((char *) toFree); } clausePtr->macTypes = NULL; } /* * Local Variables: * mode: c * c-basic-offset: 4 * fill-column: 78 * End: */