xsb_wildmatch.c

00001 /* File:      xsb_wildmatch.c
00002 ** Author(s): kifer
00003 ** Contact:   xsb-contact@cs.sunysb.edu
00004 ** 
00005 ** Copyright (C) The Research Foundation of SUNY, 1999
00006 ** 
00007 ** XSB is free software; you can redistribute it and/or modify it under the
00008 ** terms of the GNU Library General Public License as published by the Free
00009 ** Software Foundation; either version 2 of the License, or (at your option)
00010 ** any later version.
00011 ** 
00012 ** XSB is distributed in the hope that it will be useful, but WITHOUT ANY
00013 ** WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00014 ** FOR A PARTICULAR PURPOSE.  See the GNU Library General Public License for
00015 ** more details.
00016 ** 
00017 ** You should have received a copy of the GNU Library General Public License
00018 ** along with XSB; if not, write to the Free Software Foundation,
00019 ** Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00020 **
00021 ** $Id: xsb_wildmatch.c,v 1.14 2005/03/05 07:52:21 kifer Exp $
00022 ** 
00023 */
00024 
00025 
00026 #include "xsb_config.h"
00027 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <ctype.h>
00031 #include <string.h>
00032 #include <fnmatch.h>
00033 #include <glob.h>
00034 
00035 #include "auxlry.h"
00036 #include "cell_xsb.h"
00037 #include "error_xsb.h"
00038 #include "cinterf.h"
00039 
00040 /* Casefolding seems to be defined in some versions of gcc, but not in
00041    others. So, it is really not that portable.
00042 */
00043 #ifndef FNM_CASEFOLD
00044 #define FNM_CASEFOLD 0
00045 #define CASEFOLD_UNSUPPORTED 1
00046 #else
00047 #define CASEFOLD_UNSUPPORTED 0
00048 #endif
00049 
00050 extern char *p_charlist_to_c_string(prolog_term term, VarString *outstring,
00051                                     char *in_func, char *where);
00052 extern void c_string_to_p_charlist(char *name, prolog_term list,
00053                                    char *in_func, char *where);
00054 static prolog_term wild_term, input_string_term;
00055 
00056 static char *lowercase_string(char *str);
00057 
00058 static XSB_StrDefine(wild_buffer);
00059 static XSB_StrDefine(input_string_buffer);
00060 
00061 
00062 /* XSB wildcard matcher entry point 
00063 ** Arg1: wildcard, Arg2: string to be matched, Arg3: IgnoreCase flag */
00064 int do_wildmatch__(void)
00065 {
00066   int ignorecase=FALSE;
00067   int flags = 0; /* passed to wildcard matcher */
00068   char *wild_ptr=NULL, *input_string=NULL;
00069   int ret_code;
00070 
00071   wild_term = reg_term(1); /* Arg1: wildcard */
00072   input_string_term = reg_term(2); /* Arg2: string to find matches in */
00073   /* If arg 3 is bound to anything, then consider this as ignore case flag */
00074   if (! is_var(reg_term(3)))
00075     ignorecase = TRUE;
00076 
00077   flags = (ignorecase ? FNM_CASEFOLD : 0);
00078 
00079   /* check wildcard expression */
00080   if (is_string(wild_term))
00081     wild_ptr = string_val(wild_term);
00082   else if (is_list(wild_term))
00083     wild_ptr = p_charlist_to_c_string(wild_term, &wild_buffer,
00084                                       "WILDMATCH", "wildcard");
00085   else
00086     xsb_abort("[WILDMATCH] Wildcard (Arg 1) must be an atom or a character list");
00087 
00088   /* check string to be matched */
00089   if (is_string(input_string_term))
00090     input_string = string_val(input_string_term);
00091   else if (is_list(input_string_term)) {
00092     input_string = p_charlist_to_c_string(input_string_term,
00093                                           &input_string_buffer,
00094                                           "WILDMATCH", "input string");
00095   } else
00096     xsb_abort("[WILDMATCH] Input string (Arg 2) must be an atom or a character list");
00097 
00098   /* if the FNM_CASEFOLD flag is not supported,
00099      convert everything to lowercase before matching */
00100   if (CASEFOLD_UNSUPPORTED && ignorecase) {
00101     wild_ptr = lowercase_string(wild_ptr);
00102     input_string = lowercase_string(input_string);
00103   }
00104 
00105   ret_code = fnmatch(wild_ptr, input_string, flags);
00106 
00107   /* if we used lowercase_string, we must free up space to avoid memory leak */
00108   if (CASEFOLD_UNSUPPORTED && ignorecase) {
00109     free(input_string);
00110     free(wild_ptr);
00111   }
00112   if (ret_code == 0)
00113     return TRUE;
00114   return FALSE;
00115 }
00116 
00117 #ifndef GLOB_ABORTED
00118 #define GLOB_ABORTED    (-2)    /* Unignored error. */
00119 #endif
00120 #define GLOB_NOMATCH    (-3)    /* No match and GLOB_NOCHECK not set. */
00121 #define GLOB_NOSYS      (-4)    /* Function not supported. */
00122 #define GLOB_ABEND      GLOB_ABORTED
00123 
00124 
00125 /* XSB glob matcher: match files in current directory according to a wildcard.
00126 ** Arg1: wildcard, Arg2: Mark directories with `/' flag, Arg3: variable that
00127 ** gets the list of matched files.
00128 ** Arg4 tells if conversion into a charlist is required. */
00129 int do_glob_directory__(void)
00130 {
00131   glob_t file_vector;
00132   prolog_term listOfMatches, listHead, listTail;
00133   int markdirs=FALSE; /* flag: whether to append '/' to directories */
00134   int flags = 0;      /* passed to glob matcher */
00135   char *wild_ptr=NULL;
00136   int conversion_required, return_code, i;
00137 
00138   wild_term = reg_term(1); /* Arg1: wildcard */
00139   /* If arg 3 is bound to anything, then consider this as ignore case flag */
00140   if (! is_var(reg_term(2)))
00141     markdirs = TRUE;
00142 
00143   flags = (markdirs ? GLOB_MARK : 0);
00144 
00145   conversion_required = ptoc_int(4);
00146 
00147   /* check wildcard expression */
00148   if (is_string(wild_term))
00149     wild_ptr = string_val(wild_term);
00150   else if (is_list(wild_term)) {
00151     wild_ptr = p_charlist_to_c_string(wild_term, &wild_buffer,
00152                                       "GLOB_DIRECTORY", "wildcard");
00153   }
00154   else
00155     xsb_abort("[GLOB_DIRECTORY] Wildcard (Arg 1) must be an atom or a character list");
00156 
00157   file_vector.gl_offs = 0; /* put results right in the first element of
00158                              file_vector */
00159   return_code = glob(wild_ptr, flags, NULL, &file_vector);
00160 
00161 #if defined(__APPLE__)
00162 
00163   if (0 != return_code)
00164         {
00165     globfree(&file_vector);
00166     xsb_abort("[GLOB_DIRECTORY] Can't read directory or out of memory");
00167         }
00168   else if (0 == file_vector.gl_matchc)  // Case GLOB_NOMATCH:
00169         {
00170     globfree(&file_vector); /* glob allocates a long string, which must be freed to avoid memory leak */
00171     return FALSE;
00172         }
00173 
00174 #else
00175 
00176   switch (return_code) {
00177   case GLOB_NOMATCH:
00178     globfree(&file_vector); /* glob allocates a long string, which must be
00179                                freed to avoid memory leak */
00180     return FALSE;
00181   case 0: break;
00182   default:
00183     globfree(&file_vector);
00184     xsb_abort("[GLOB_DIRECTORY] Can't read directory or out of memory");
00185   }
00186 
00187 #endif
00188 
00189   /* matched successfully: now retrieve results */
00190   listTail = listOfMatches = reg_term(3);
00191   if (! is_var(listTail))
00192     xsb_abort("[GLOB_DIRECTORY] Argument 7 (list of matches) must be an unbound variable");
00193 
00194   for (i=0; i<file_vector.gl_pathc; i++) {
00195     c2p_list(listTail); /* make it into a list */
00196     listHead = p2p_car(listTail); /* get head of the list */
00197 
00198     if (conversion_required)
00199       c_string_to_p_charlist(file_vector.gl_pathv[i], listHead,
00200                              "GLOB_DIRECTORY", "arg 3");
00201     else
00202       c2p_string(file_vector.gl_pathv[i], listHead);
00203 
00204     listTail = p2p_cdr(listTail);
00205   }
00206 
00207   c2p_nil(listTail); /* bind tail to nil */
00208   globfree(&file_vector);
00209   return TRUE;
00210 }
00211 
00212 /* gets string, converts to lowercase, returns result; allocates space 
00213    so don't forget to clean up */
00214 static char *lowercase_string(char *str)
00215 {
00216   int i, len=strlen(str)+1;
00217   char *newstr = (char *) malloc(len);
00218 
00219   for (i=0; i<len; i++)
00220     *(newstr+i) = tolower(*(str+i));
00221   return newstr;
00222 }
00223 
00224 /* gets string, converts to uppercase, returns result; allocates space 
00225    so don't forget to clean up */
00226 static char *uppercase_string(char *str)
00227 {
00228   int i, len=strlen(str)+1;
00229   char *newstr = (char *) malloc(len);
00230 
00231   for (i=0; i<len; i++)
00232     *(newstr+i) = toupper(*(str+i));
00233   return newstr;
00234 }
00235 
00236 
00237 int do_convert_string__(void)
00238 {
00239   char *output_ptr=NULL, *input_string=NULL, *conversion_flag=NULL;
00240   prolog_term conversion_flag_term, output_term;
00241   int to_string_conversion_required=FALSE;
00242 
00243   input_string_term = reg_term(1); /* Arg1: string to convert */
00244 
00245   output_term = reg_term(2);
00246   if (! is_var(output_term))
00247     xsb_abort("[CONVERT_STRING] Output string (Arg 2) must be a variable");
00248 
00249   /* If arg 3 is bound to anything, then consider this as ignore case flag */
00250   conversion_flag_term = reg_term(3);
00251   if (! is_string(conversion_flag_term))
00252     xsb_abort("[CONVERT_STRING] Conversion flag (Arg 3) must be an atom");
00253 
00254   conversion_flag = string_val(conversion_flag_term);
00255 
00256   /* check string to be converted */
00257   if (is_string(input_string_term))
00258     input_string = string_val(input_string_term);
00259   else if (is_list(input_string_term)) {
00260     input_string = p_charlist_to_c_string(input_string_term,
00261                                           &input_string_buffer,
00262                                           "STRING_CONVERT", "input string");
00263     to_string_conversion_required = TRUE;
00264   } else
00265     xsb_abort("[CONVERT_STRING] Input string (Arg 1) must be an atom or a character list");
00266 
00267   if (0==strcmp(conversion_flag,"tolower"))
00268     output_ptr = lowercase_string(input_string);
00269   else if (0==strcmp(conversion_flag,"toupper"))
00270     output_ptr = uppercase_string(input_string);
00271   else
00272     xsb_abort("[CONVERT_STRING] Valid conversion flags (Arg 3): `tolower', `toupper'");
00273 
00274   if (to_string_conversion_required)
00275     c_string_to_p_charlist(output_ptr,output_term,"CONVERT_STRING","Arg 2");
00276   else
00277     c2p_string(output_ptr, output_term);
00278 
00279   /* free up space to avoid memory leak */
00280   free(output_ptr);
00281 
00282   return TRUE;
00283 }
00284 

Generated on Wed Jul 26 13:30:46 2006 for XSB by  doxygen 1.4.5