/* which witch is which? * * witch - the rich implementation of which * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Copyright (c) 2007, William A. Rowe, Jr. * * 0.1.0 - initial design * 0.1.1 - minor win32 compilation fixes */ #include #include #include #include #include #include #include #define APP_VERSION \ "witch v0.1.1 Copyright (c) 2007, William A. Rowe, Jr.\n" \ "Licensed by one or more contributors under the Apache Software License v2.0\n" #if defined(WIN32) || defined(OS2) #define APP_HELP APP_VERSION \ "Syntax: %s [-afcxrv?] [-p PATHS] [-d DELPATHS] [-e EXTS] files ...\n" \ " -a\tall matches\n" \ " -f\tplain files (doesn't test exec flag, no default -e value)\n" \ " -c\tinclude cwd (default for %PATH% search, when -p is not specified)\n" \ " -x\texclude cwd (default if -p is specified)\n" \ " -r\trelative paths (default behavior expands full path names)\n" \ " -v\tprogram version\n" \ " -?\tthis message\n" \ " -p PATHS\tlist to search (';' delimeted, default is %PATH%)\n" \ " -d DELPATHS\tlist to omit (';' delimiteded)\n" \ " -e EXTLIST\textensions to match (';' delimited, default is %PATHEXT%)\n" #else #define APP_HELP APP_VERSION \ "Syntax: %s [-afcxrv?] [-p PATHS] [-d DELPATHS] [-e EXTS] files ...\n" \ " -a\tall matches\n" \ " -f\tplain files (doesn't test exec flag, no default -e value)\n" \ " -c\tinclude cwd (prior to first directory of -p or $PATH)\n" \ " -x\texclude cwd (default)\n" \ " -r\trelative paths (default behavior expands full path names)\n" \ " -v\tprogram version\n" \ " -?\tthis message\n" \ " -p PATHS\tlist to search (':' delimited, default is $PATH)\n" \ " -d DELPATHS\tlist to omit (':' delimited)\n" \ " -e EXTLIST\textensions to match (':' delimited, implies -f)\n" #endif #define EXECUTE (APR_FPROT_UEXECUTE | APR_FPROT_GEXECUTE | APR_FPROT_WEXECUTE) int main (int argc, char const* const* argv, char const* const* env) { apr_status_t rv; apr_pool_t *toppool, *tmppool; apr_getopt_t *opts; char argch; const char *argval, **elt; int allmatches = 0, plainfiles = 0; int pathrooted = 1, currentdir = -1; int seenexts = 0, seenpaths = 0; apr_array_header_t *array, *paths, *exts; char **path, **ext, *name; int x, y, found; apr_finfo_t finfo; rv = apr_app_initialize(&argc, &argv, &env); atexit(apr_terminate); rv = apr_pool_create_ex(&toppool, NULL, NULL, NULL); rv = apr_pool_create_ex(&tmppool, toppool, NULL, NULL); paths = apr_array_make(toppool, 0, sizeof(char*)); exts = apr_array_make(toppool, 0, sizeof(char*)); rv = apr_getopt_init(&opts, toppool, argc, argv); while ((rv = apr_getopt(opts, "afcxrv?p:d:e:", &argch, &argval)) == APR_SUCCESS) { switch (argch) { case 'a': /* all */ allmatches = 1; break; case 'f': /* files (non-exec) */ plainfiles = 1; break; case 'c': /* include current */ if (currentdir >= 0) { goto outch; } currentdir = 1; break; case 'x': /* include current */ if (currentdir >= 0) { goto outch; } currentdir = 0; break; case 'r': /* relative file paths */ pathrooted = 0; break; case 'p': /* paths */ if (currentdir < 0) currentdir = 0; if (currentdir) { *(char const**)apr_array_push(paths) = "."; currentdir = 0; } rv = apr_filepath_list_split(&array, argval, toppool); apr_array_cat(paths, array); seenpaths = 1; break; case 'd': /* deletepaths */ if (!seenpaths) { rv = apr_env_get((char**)&argval, "PATH", toppool); #if defined(WIN32) || defined(OS2) if (currentdir != 0) { currentdir = 1; #else if (currentdir == 1) { #endif elt = apr_array_push(paths); *elt = "."; } rv = apr_filepath_list_split(&array, argval, toppool); apr_array_cat(paths, array); seenpaths = 1; } rv = apr_filepath_list_split(&array, argval, tmppool); /* XXX TODO - remove elts of array from array 'paths' */ apr_pool_clear(tmppool); break; case 'e': /* exts */ plainfiles = 1; rv = apr_filepath_list_split(&array, argval, toppool); if (!seenexts && ((*argval == ';') || (*argval == ':'))) *(char const**)apr_array_push(exts) = ""; apr_array_cat(exts, array); seenexts = 1; break; case 'v': /* version */ fputs(APP_VERSION, stdout); return 0; case '?': /* help */ fprintf(stdout, APP_HELP, argv[0]); return 0; otherwise: goto outch; } } if ((rv != APR_EOF) || ((opts->ind >= opts->argc))) { outch: fprintf(stderr, APP_HELP, argv[0]); return 255; } if (!seenpaths) { rv = apr_env_get((char**)&argval, "PATH", toppool); #if defined(WIN32) || defined(OS2) if (currentdir != 0) { currentdir = 1; #else if (currentdir == 1) { #endif elt = apr_array_push(paths); *elt = "."; } rv = apr_filepath_list_split(&array, argval, toppool); apr_array_cat(paths, array); apr_pool_clear(tmppool); } if (!seenexts) { #if defined(WIN32) || defined(OS2) if (!plainfiles) { rv = apr_env_get((char**)&argval, "PATHEXT", toppool); rv = apr_filepath_list_split(&exts, argval, toppool); apr_pool_clear(tmppool); } else #endif *(char const**)apr_array_push(exts) = ""; } for (path = (void*)paths->elts, x = 0; x < paths->nelts; ++path, ++x) { rv = apr_filepath_merge(path, pathrooted ? NULL : "", *path, APR_FILEPATH_NATIVE, toppool); } while (opts->ind < opts->argc) { argval = opts->argv[opts->ind]; ++opts->ind; path = (void*)paths->elts; found = 0; for (x = 0; x < paths->nelts && (allmatches || !found); ++path, ++x) { ext = (void*)exts->elts; for (y = 0; y < exts->nelts && (allmatches || !found); ++ext, ++y) { name = apr_pstrcat(tmppool, argval, *ext, NULL); rv = apr_filepath_merge(&name, *path, name, APR_FILEPATH_NATIVE, tmppool); rv = apr_stat(&finfo, name, plainfiles ? APR_FINFO_MIN : APR_FINFO_MIN | APR_FINFO_PROT, tmppool); if (!rv && (finfo.filetype == APR_REG)) { if (!plainfiles && !(finfo.protection & EXECUTE)) continue; fputs(apr_pstrcat(tmppool, name, "\n", NULL), stdout); found = 1; } } apr_pool_clear(tmppool); } if (!found) { char *pathlist; rv = apr_filepath_list_merge(&pathlist, paths, tmppool); if ((exts->nelts > 1) || ((char**)exts->elts)[0][0]) { char *extlist; rv = apr_filepath_list_merge(&extlist, exts, tmppool); fputs(apr_pstrcat(tmppool, argv[0], ": no ", argval, " of (", extlist, ") in (", pathlist, ")\n", NULL), stdout); } else fputs(apr_pstrcat(tmppool, argv[0], ": no ", argval, " in (", pathlist, ")\n", NULL), stdout); apr_pool_clear(tmppool); } } return 0; }