whichman-2.4/0040755000076500001440000000000010037370621012213 5ustar guidouserswhichman-2.4/whichman.c0100644000076500001440000004341307605652243014171 0ustar guidousers/* vim: set sw=8 ts=8 si et: */ /* * Author: Guido Socher. This program is distributed * under the terms of the Gnu Public License (GPL). */ #include #include #include #include #include #include #include #include "levdist.h" static void help(); static char **splitman(); static int findmandir(char *manpathcomponent, char *key); static void matchfilename(char *path, char *key); static int stringmatch(char *s1, char *s2); static int maybemandir(const char *dirname); static char *removemanextesions(char *manpagefilename); static int streq(const char *a,const char *b); /*global for simplicity:*/ static int printdist=0; static int casesensitive=0; static int nomanfilefound=1; /*searchmethod indicates the tolerance level for Lev. Dist search *-2 not set, *-1 exact match, * 0 = exact match with wildcards, * 1-255 max distance value*/ static int searchmethod=-2; int main(int argc, char *argv[]) { char searchkey[MAXLEN +1]; char **pathcomp; int optnum; char *c,*oarg; if (argc < 2 ) help(); /* * After this while loop. argv[0] is the next argument if available * * options that take an argument write *c=0;break; others write * "c++;break;" * * This parser looks a bit complicated but it can take options * like -23 and -ac is the same as "-a -c" */ optnum=argc; while (--optnum>0) { argv++; c = *argv; /* c is pointer to one argument/option */ if (*c != '-'){ argv--; break; /*stop at the first non option argument*/ } c++; if (*c == '-' && *(c + 1)=='\0'){ /* you can write a double -- to stop option * parsing. This is useful if you need to search * for a string that is called "-something" */ --optnum; break; /*stop option parsing*/ } while (*c) { switch (*c) { case 'e': searchmethod=-1; c++;break; case 'h': help(); /*no break, help does not return*/ case 'p': printdist=1; c++;break; case 'I': casesensitive=1; c++;break; case 't': /* you can write -t11 or -t 11*/ /* first the normal -t11 case: */ oarg=c+1; /* then the -t 11 case: */ if(*(c + 1)=='\0'){ if(--optnum) oarg=*++argv; } if (searchmethod !=-1 ){ /*ignore -e -t1 */ searchmethod = atoi(oarg); if (searchmethod > 255 || searchmethod <0) searchmethod = 255; } *c=0;break; default: if (isdigit((int)*c)){ if (searchmethod !=-1 ){ /*ignore -e -t1 */ searchmethod = atoi(c); if (searchmethod > 255 || searchmethod <0) searchmethod = 255; } }else{ fprintf(stderr,"ERROR: No such option. Use -h to get help.\n"); exit(1); } *c=0; } } } if (optnum<0) optnum=0; /* can be less then zero due to a option * with arg at last pos and missing arg*/ /* *optnum is now the number of argmunts left after *option parsing. Example: option a,c take no arg, option b has arg: * thisprogram -a -b xx -c d e * This results in: * optnum==2 and argv[1] points to d * argv[2] points to e */ if (optnum != 1) { /* you must provide exactly one argument */ help(); /*help does not return */ } if (casesensitive){ strncpy(searchkey, argv[1],MAXLEN); searchkey[MAXLEN]=0; }else{ /*we translate everything to lower case in order to do case *insensitive match: */ lowercaseword(searchkey, argv[1],MAXLEN,0); } if (searchmethod == -2){ /*tolerance for Levenshtein Distance search: */ searchmethod = stdtolerance(searchkey); } pathcomp = splitman(); while (*pathcomp) { findmandir(*pathcomp, searchkey); pathcomp++; } return (nomanfilefound); } /*__END OF MAIN__*/ /* * Try to find all .../manX subdirectories. * This function considers also internationalized man-directory * structures of the tpye manpathcomponent//manX * and the traditional man structures with manpathcomponent/manX * X may be somthing like 1,2,3..l,3s,... * This function is recursive and calls it self max once. * manpathcomponent is a null pointer if the function calls it self * again and the vaiable manpath contains the path. * NOTE: this is a recursive function * The return value is not significant. */ int findmandir(char *manpathcomponent, char *key) { /*1024 should definitly be a conservative limit for one part of *the man-path:*/ static char manpath[1024]; char *manpathendptr; int len=0; struct stat stbuff; DIR *dp; /*note: * The pointer returned by readdir() points to data which may * be overwritten by another call to readdir() on the same * directory stream. This data is not overwritten by another * call to readdir() on a different directory stream. Thus * we must be sure to open a directory only once.*/ struct dirent *entry; manpathendptr=manpath; /* manpathcomponent is NULL if this function was recursively called*/ if (manpathcomponent == NULL){ /*find the end of the manpath string:*/ manpathendptr+=strlen(manpath); }else{ /*we were called the first time and manpathcomponent *contains the path. Thus copy it into manpath. *manpathendptr must point to the end of the path *at the end of this loop*/ while (*manpathcomponent && len < 800) { *manpathendptr=*manpathcomponent; manpathcomponent++; manpathendptr++; len++; } *manpathendptr='\0'; } if ((dp = opendir(manpath)) == NULL) { /* we get here if we have invalid manpath component*/ return(0); } if (*(manpathendptr-1) != '/'){ *manpathendptr='/'; manpathendptr++; *manpathendptr='\0'; } /* manpathendptr points now to the end of: * /usr/man/de/ or /usr/man/ */ while ((entry = readdir(dp)) != NULL) { /*ignore . or .. or .file :*/ if (*(entry->d_name) == '.') continue; /*we have enough memory left, * this should succeed:*/ strcpy(manpathendptr,entry->d_name); if (maybemandir(entry->d_name)){ /*manpath is now something like * /usr/man/man1 or /usr/man/de/man1 * but manpathendptr is still unchanged*/ /*now search the file, no more recursion:*/ matchfilename(manpath,key); }else{ /*the path extension is max *one component of the path. We might have catched *a file not a directory */ if (stat(manpath, &stbuff) < 0) continue; if (manpathcomponent != NULL && S_ISDIR(stbuff.st_mode)){ strcpy(manpathendptr,entry->d_name); findmandir(NULL,key); } } } closedir(dp); return(0); } /* * match all entries in the directory variable path points to * against the key. * This function sets the global variable nomanfilefound */ void matchfilename(char *path, char *key) { char *manname; int d; DIR *dp; struct dirent *entry; if ((dp = opendir(path)) != NULL) { while ((entry = readdir(dp)) != NULL) { /*ignore . or .. or .file: */ if (*(entry->d_name) == '.') continue; /* xxxxx.1.gz ->xxxxx :*/ manname=removemanextesions(entry->d_name); d=stringmatch(manname,key); if (d != -1){ if (printdist) printf("%03d ",d); printf("%s/%s\n", path, entry->d_name); nomanfilefound = 0; } } closedir(dp); } } /* * check if this is a man directory. This is faster than a stat * system call. Man directories look like: man1, man11, manl, man3s * but not: manpage,man.1 * return 1 on 'may be a man directory' and 0 on 'definitly no man dir' */ int maybemandir(const char *dirname) { static char man[] = "man"; int i = 0; while (*dirname && i < 3) { if (*dirname != man[i]) return (0); dirname++; i++; } if (i != 3) return (0); if (isalnum((int)*dirname) == 0) return (0); dirname++; if (*dirname == '\0') return (1); if (isalnum((int)*dirname) == 0) return (0); return (1); } /* * string match * For substring matches s2 has to be a substring of s1 * Parameters: * s1=string to search in, s2=search key, * searchmethod=-1 or searchmethod='tolerance for Levenshtein Distance' * This function consults the global variables casesensitive in order * to see if matching should be casesensitive or not. If matching is * not casesensitive (casesensitive=0) then s2 has to be already lower case. * * Return values: * searchmethod == -1: exact match, Return values: 0 on match -1 on no match * searchmethod >= 0 : LD match, Return values: distance value or -1 on failure */ int stringmatch(char *s1,char *s2) { char c; if (searchmethod == -1) { /*fast exact match:*/ while (*s1) { c=*s1; if (!casesensitive) c=tolower(*s1); if (c != *s2) { return (-1); } s1++;s2++; } /*the length of s2 and s1 must also be equal in order to match:*/ if (*s2 == '\0') return (0); }else{ /*approximate matching and substr match:*/ return (levdist(s1, s2, searchmethod,casesensitive)); } return (-1); } /* * remove the extensions from the man-file name string * xxx.n becomes xxx * yyy.l.gz becomes yyy * passwd.nntp.5 becomes passwd.nntp * aaa.zzz.3s.gz becomes aaa.zzz * wish.addition.1.gz becomes wish.addition * sem_init.3thr becomes sem_init * innwatch.ctl.5 becomes innwatch.ctl * * the string must follow the pattern : * something.[.gz or .Z or .bz2] becomes something */ char *removemanextesions(char *manpagefilename) { char *rightdot; static char tmp[MAXLEN]; /* the zero at the end is the terminator:*/ int i=0; /*first copy then try to remove a .gz or .Z*/ rightdot = NULL; while (*manpagefilename && i < MAXLEN -1 ){ tmp[i]=*manpagefilename; if (*manpagefilename == '.'){ rightdot=tmp + i; } i++; manpagefilename++; } tmp[i]='\0';/* in case we reached MAXLEN*/ if (rightdot == NULL){ /*now this is rather strange we do not have a dot *so let's return the whole string*/ return(tmp); } if (streq(rightdot,".gz")){ *rightdot='\0'; } if (streq(rightdot,".bz2")){ *rightdot='\0'; } if (streq(rightdot,".bz")){ *rightdot='\0'; } if (streq(rightdot,".Z")){ *rightdot='\0'; } /*now we should have something like xxxx.1 or xxxx.3s *and we remove everything from the dot on*/ manpagefilename = tmp; /*work on the copy*/ rightdot=NULL; while (*manpagefilename ){ if (*manpagefilename == '.'){ rightdot=manpagefilename; } manpagefilename++; } if (rightdot){ /*cut at the right most dot:*/ *rightdot='\0'; } return(tmp); } /* * split MANPATH into substrings and return a pointer to * a 2 dimmentional array with all the sub-strings of the * MANPATH. */ char **splitman() { char *mpath; /* man path */ char *cmpath;/* copy of man path */ static char **pathcomp; int i=0; int notseen=1; char *start; int compind = 0; /* index of *pathcomp[] */ int complen = 1; /* len of one component in the path + 16 */ mpath = (char *) getenv("MANPATH"); if (mpath == NULL || *mpath == '\0') { fprintf(stderr,"Warning: MANPATH not defined, using /usr/man:/usr/share/man\n"); mpath="/usr/man:/usr/share/man"; } /* make a copy that is static */ cmpath = (char *)malloc(sizeof(char)*(strlen(mpath) + 2)); strcpy(cmpath, mpath); start = cmpath; /* count the number of colons in the path to find how many * components we have in the path */ while (*cmpath) { if (*cmpath == ':') i++; cmpath++; } i+=3; /*some space in case we have corruped path below*/ pathcomp=(char **)malloc(sizeof(char *)*i); /* split the path by replacing : with \0 */ cmpath = start; pathcomp[compind]=cmpath; while (*cmpath) { if (*cmpath == ':') { *cmpath = '\0'; if (complen > 1) { /*ignore zero length comp. e.g :: */ /* now check if it is a duplicate path * component that we can just ignore: */ i=0;notseen=1; while(notseen && i < compind){ if(streq(pathcomp[compind],pathcomp[i])){ notseen=0; } i++; } if (notseen) compind++; } /* remove any tailing slashes but not if it is * only the root dir (just a "/") */ if (complen > 2 && *(cmpath-1) == '/') *(cmpath-1)='\0'; pathcomp[compind] = cmpath+1; complen = 0; } cmpath++; complen++; } if (complen < 2){ /*we have some corrupted path, this happens when you have a *colon at the end of the path */ pathcomp[compind] = NULL; /*terminate */ }else{ /* now check if the last one is a duplicate path * component that we can just ignore: */ i=0;notseen=1; while(notseen && i < compind){ if(streq(pathcomp[compind],pathcomp[i])){ notseen=0; } i++; } if (notseen) compind++; pathcomp[compind] = NULL; /*terminate */ } return (&pathcomp[0]); } /* return 1 if the 2 strings a and b are equal */ int streq(const char *a,const char *b){ while(*a && *b){ if(*a != *b) return(0); a++;b++; } /* both must be at \0 */ if(*a || *b) return(0); return(1); } /* * help */ void help() { printf("whichman -- fault tolerant approximate search command for man-pages\n\ \n\ USAGE: whichman [-#hIep][-t#] [--] man-page-name\n\ \n\ Supported wildcards: * -- any arbitrary number of character\n\ ? -- one character\n\ \n\ OPTIONS: -h this help\n\ -I search case sensitive (default is case in-sensitive)\n\ -e do exact match (disables also the wildcards * and ?)\n\ -p print the actual distance (tolerance) value in front of the\n\ man-page file name.\n\ -# set fault tolerance level to # (integer in the range 0-255)\n\ It specifies the maximum distance. This is the number of\n\ errors permitted for finding the approximate match.\n\ -t# same as -# for backward compatibility\n\ \n\ With no option specified search is fault tolerant using a tolerance\n\ level of: (string length of searchpattern - number of wildcards)/6 +1\n"); printf("%s\n",MYVERSION); exit(0); } /*__END__*/ whichman-2.4/Makefile0100600000076500001440000000274510037370436013654 0ustar guidousers# written by Guido Socher # overwrite with: make prefix=/some/where install prefix=$(DESTDIR)/usr INSTALL=install mandir=$(prefix)/share/man MANP=man1/whichman.1 man1/ftff.1 man1/ftwhich.1 CC=gcc CFLAGS= -Wall -O2 #sun c/c++-compiler: #CC=CC #CFLAGS= -O all:whichman ftff ftwhich whichman: whichman.o levdist.o $(CC) -o $@ whichman.o levdist.o ftwhich: ftwhich.o levdist.o $(CC) -o $@ ftwhich.o levdist.o ftff: ftff.o levdist.o $(CC) -o $@ ftff.o levdist.o whichman.o: whichman.c $(CC) $(CFLAGS) -c whichman.c ftwhich.o: ftwhich.c $(CC) $(CFLAGS) -c ftwhich.c ftff.o: ftff.c $(CC) $(CFLAGS) -c ftff.c levdist.o: levdist.c levdist.h $(CC) $(CFLAGS) -c levdist.c install: whichman ftff ftwhich $(MANP) strip whichman strip ftwhich strip ftff [ -d "$(prefix)/bin" ] || $(INSTALL) -d $(prefix)/bin [ -d "$(mandir)/man1" ] || $(INSTALL) -d $(mandir)/man1 $(INSTALL) -m 755 whichman $(prefix)/bin $(INSTALL) -m 755 ftwhich $(prefix)/bin $(INSTALL) -m 755 ftff $(prefix)/bin for p in $(MANP) ; do \ echo "installing $$p in $(mandir)/man1"; \ $(INSTALL) -m 644 $$p $(mandir)/man1 ;\ done install_with_cp: whichman ftff ftwhich $(MANP) chmod 755 whichman ftff ftwhich [ -d "$(prefix)/bin" ] || mkdir -p $(prefix)/bin cp whichman ftff ftwhich $(prefix)/bin chmod 644 $(MANP) [ -d "$(mandir)/man1" ] || mkdir -p $(mandir)/man1 cp $(MANP) $(mandir)/man1 debug: levdist.c $(CC) $(CFLAGS) -o levdebug -DDEBUG -DRETURNVALUE levdist.c clean: rm -f whichman ftff ftwhich *.o levdebug whichman-2.4/man1/0040755000076500001440000000000007274614433013062 5ustar guidouserswhichman-2.4/man1/whichman.10100644000076500001440000000500607274614433014740 0ustar guidousers.\" .\" This is free software and only distributed under the .\" terms of the Gnu Public License. Author: Guido Socher .\" .TH whichman 1 "April 1998" "Search utilities" \" -*- nroff -*- .SH NAME whichman \- show the location of a man page using a fault tolerant approximate matching algorithm .SH SYNOPSIS .B whichman [\-#ehIp][\-t#] man\-page\-name .SH DESCRIPTION .B whichman is a "which" alike search command for man pages. .B whichman searches the .B MANPATH environment variable. .PP Unlike "which" this program does not stop on the first match. The name should probably have been something like whereman as this is not a "which" at all. whichman shows all man-pages that match and allows you to identify the different sections to which the pages belong. .PP .B whichman can handle international manpage path names for different languages. Man pages in different languages may be stored in .../man//man[1\-9]/... .PP By default, .B whichman does fault tolerant approximate string matching. With a default tolerance level of: (strlen(searchpattern) - number of wildcards)/6 + 1 .SH OPTIONS .TP .I \-h Prints a little help/usage information. .TP .I \-I Do case sensitive search (default is case in\-sensitive) .TP .I \-e Use exact matching when searching for a given man-page and the wildcards * and ? are disabled. .TP .I \-p print the actual tolerance level in front of the man page name. .TP .I \-# or \-t# Set the fault tolerance level to #. The fault tolerance level is a integer # in the range 0-255. It specifies the maximum number of errors permitted in finding the approximate match. A tolerance_level of zero allows exact matches only but does NOT disable the wildcards * and ?. .PP The search key may contain the wildcards * and ? (but see -e option): .TP .BR '*' any arbitrary number of character .TP .BR '?' one character .PP The last argument to whichman is not parsed for options as the program needs at least one man-page-name argument. This means that .I whichman -x will not complain about a wrong option but search for the man-page named -x. .SH EXAMPLE .I whichman .RB print .PP This will e.g. find the man-pages: .br /usr/man/man1/printf.1.gz .br /usr/man/man3/printf.3.gz .br /usr/man/man3/rint.3.gz .SH BUGS The wildcards .BR '?' and .BR '*' can not be escaped. These characters function always as wildcards. This is however not a big problem since there is hardly any man-page that has these characters in its name. .SH AUTHOR Guido Socher (guido@linuxfocus.org) .SH SEE ALSO ftff(1) man(1) whichman-2.4/man1/ftff.10100644000076500001440000000654207274614403014072 0ustar guidousers.\" .\" This is free software and distributed under the .\" terms of the Gnu Public License. .\" .TH FTFF 1 "August 1998" "Search utilities" \" -*- nroff -*- .SH NAME ftff \- fault tolerant file find utiltiy .SH SYNOPSIS .B ftff [\-#fFhIpq][\-t#][start_directory] file_to_find .SH DESCRIPTION .B ftff recursively descends the directory hierarchy and reports all objects in the file system with a name that approximately matches the given filename. .PP .B ftff achieves fault tolerance by calculating the so called Weighted Levenshtein Distance. The Levenshtein Distance is defined as the minimum number of character insertions, deletions and replacements that transform a string .I A into a string .I B. .PP .B ftff behaves like .PP .RB 'find\ start_directory\ \-name\ file_to_find\ \-print' .PP with the following differences: .TP \- ftff is fault tolerant .TP \- ftff is NOT case sensitive .TP \- the level of fault tolerance can be adjusted by specifying the optional parameter .B tolerance. A .B tolerance of 0 specifies exact match. .SH OPTIONS .TP .I \-h Prints a little help/usage information. .TP .I \-f Follow symbolic links on directories. Note: a symbolic link like "somewhere \-> .." causes naturally an endless loop. By default .B ftff does not follow symbolic links to directories. .TP .I \-F Classify the file type by appending a character to each file name. This character is: .br .I '*' for regular files that are executable .br .I '/' for directories .br .I '@' for symbolic links .br .I '|' for FIFOs .br .I '=' for sockets .TP .I \-p print the actual distance value in front of the filename. This value is equal to the number of insertions, deletions and replacements necessary to transform the file that was found into the search key (the file_to_find). .TP .I \-q keep quiet and do not print any warning about non readable directories. .TP .I \-# or \-t# Set the fault tolerance level to #. The fault tolerance level is an integer in the range 0-255. It specifies the maximum number of errors permitted in finding the approximate match. The default tolerance is (strlen(searchpattern) - number of wildcards)/6 + 1 .TP .I \-I Do case sensitive search (default is case in-sensitive) .PP .TP .I file_to_find The filename to search for. .RB '*' and .RB '?' can be used as wildcards. .br .RB '?' denotes one single character. .br .RB '*' denotes an arbitrary number of characters. .TP .I start_directory The directory to start the search. The current directory is the default. .PP The last argument to ftff is not parsed for options as the program needs at least one file-name argument. This means that .I ftff -x will not complain about a wrong option but search for the file named -x. .SH EXAMPLE .I ftff .RB samething .PP This will e.g. find a file called something or sameting or sum-thing or ... .PP To find all files that start with any prefix, have something like IOComm in between and end on a two letter suffix: .PP .I ftff .RB '*iocomm.??' .PP To find all files that exactly start with the prefix DuPeg: .PP .I ftff \-0 .RB 'dupeg*' .PP .SH BUGS The wildcards .BR '?' and .BR '*' can not be escaped. These characters function always as wildcards. This is however not a big problem since there is normally hardly any file that has these characters in its name. .SH AUTHOR Guido Socher (guido@linuxfocus.org) .SH SEE ALSO whichman(1) find(1) whichman-2.4/man1/ftwhich.10100644000076500001440000000637607274614412014606 0ustar guidousers.\" .\" This is free software and distributed under the .\" terms of the Gnu Public License. .\" .TH ftwhich 15 "January 1999" "Search utilities" \" -*- nroff -*- .SH NAME ftwhich \- fault tolerant search for a command name .SH SYNOPSIS .B ftwhich [\-#hIp][\-t#] program_name .SH DESCRIPTION .B ftwhich is a fault tolerant version of the which(1) command. .B ftwhich searches for a given program in all directories included in your PATH environment variable and reports all files with a name that approximately matches the given .B program_name. .PP .B ftwhich achieves fault tolerance by calculating the so called Weighted Levenshtein Distance. The Levenshtein Distance is defined as the minimum number of character insertions, deletions and replacements that transform a string .I A into a string .I B. .PP .I ftwhich is similar to the .I which command with the following differences: .TP \- ftwhich is by default NOT case sensitive .TP \- ftwhich is fault tolerant .TP \- Some shells have a build in .I which command that will also search aliases. .I ftwhich can naturaly not search for aliases as it does not know about alias definitions. .TP \- .B ftwhich lists all files that approximatly match. The files first shown take preference over files of the same name printed later as they are from directories listed earlier in the PATH. .TP \- The level of fault tolerance can be adjusted by specifying the optional parameter .B tolerance. A .B tolerance of 0 specifies exact match. .SH OPTIONS .TP .I \-h Prints help/usage information. .TP .I \-I Do case sensitive search (default is case in\-sensitive) .TP .I \-p print the actual distance value in front of the found filename. This value is equal to the number of insertions, deletions and replacements necessary to transform the name of the found program into the search key. .TP .I \-# or \-t# Set the fault tolerance level to #. The fault tolerance level is an integer in the range 0-255. It specifies the maximum number of errors permitted in finding the approximate match. The default tolerance is (strlen(searchpattern) - number of wildcards)/6 + 1 .PP .TP .I program_name The program file to search for. .RB '*' and .RB '?' can be used as wildcards. .br .RB '?' denotes one single character. .br .RB '*' denotes an arbitrary number of characters. .PP The last argument to ftwhich is not parsed for options as the program needs at least one program_name argument. This means that .I ftwhich -x will not complain about a wrong option but search for the program named -x. .SH EXAMPLE Search for all programs like gcc in your PATH: .br .I ftwhich gcc .br This will e.g. find gcc or cc or CC ... .PP To find all files that start with any prefix and end in .I config and differ in 2 letters from the word .I config: .br .I ftwhich \-2 .RB '*config' .PP To find all files that exactly start with the prefix .I if: .br .I ftwhich \-0 .RB 'if*' .PP To find all clock programs: .br .I ftwhich \-0 '*clock*' .PP .SH BUGS The wildcards .BR '?' and .BR '*' can not be escaped. These characters function always as wildcards. This is however not a big problem since there is normally hardly any command that has these characters in its name. .SH AUTHOR Guido Socher (guido@linuxfocus.org) .SH SEE ALSO whichman(1) ftff(1) whichman-2.4/README0100644000076500001440000001103710037370621013072 0ustar guidousersThis package holds THREE little search utilities. ------------------------------------------------------------- whichman -- search utility for man pages and it works much like the well known unix command "where". It shows the the location of a given man-page by looking at your MANPATH environment variable. whichman is especially useful if you have forgotten the precise name of a man-page/command since it performs case in-senstitive approximate pattern searches. It does this be computing the Levenshtein Distance between the search pattern and the man-page name. Here is a demonstration on how whichman compensates typing errors or forgotten command names: > whichman erep /usr/man/man1/grep.1 /usr/man/man1/egrep.1 > whichman netwhat /usr/man/man8/netstat.8 > whichman print /usr/man/man1/printf.1.gz /usr/man/man3/printf.3.gz /usr/man/man3/rint.3.gz ... or to see in what sections a command is available: > whichman -0 exit /usr/man/man2/exit.2 /usr/man/man3/exit.3 /usr/man/man3/Exit.3 /usr/man/mann/exit.n ------------------------------------------------------------- ftff -- a fault tolerant file finder ftff works like the whichman above but searches the directory tree. This is a case in-sensitive and fault tolerant way of 'find . -name xxxx -print' ------------------------------------------------------------- ftwhich -- a fault tolerant "which" command ftwhich finds files (programs) which are in one of the directories in your PATH and uses a fault tolerant search algorithem. Example, search all clocks: > ftwhich -0 '*clock*' /usr/X11/bin/xclock /usr/X11/bin/rclock /usr/X11/bin/moonclock /usr/X11/bin/oclock /usr/X11/bin/xdaliclock /usr/openwin/bin/clock ------------------------------------------------------------- For further documentation see as well the "find" article from LinuxFocus.org: http://linuxfocus.org/English/September1998/article64.html ------------------------------------------------------------- Installation: on most systems (especially Linux) you can just type make make install This installes everything into /usr/... To install into /usr/local you can run make PREFIX=/usr/local install instead. The above method used the install program. To use normal copy instead you can run: make PREFIX=/usr/local install_with_cp A spec file to build an rpm-package is also provided. This utility set is free software and comes without any warrenty. It falls under the terms of the Gnu Public License (GPL). You can get a copy of the GPL at sunsite.unc.edu /pub/Linux/LICENSES/gpl.license Regards Guido Socher ------------------------------------------------------------- History of whichman: version 1.0 -first public release version 1.1 -approximate stringmatch added version 1.2 -optimisation in the approximate string match -ftff added version 1.3 -whichman bug fix. some.page.1 was before this version read as 'some' -show distance values with option -p -bug fixes in the ftff.1 man page. -option -f for ftff added. version 1.4 -ftff bug fix: ftff /home/ something did produce 1998-04-17 duplicated slashes as e.g /home//xyz/something -whichman, language dependent man pages can now also be searched. version 1.5 -ftff and whichman: new option parser 1999-01-29 and new option for case sensitive search. -ftwhich added version 1.6 -better Makefile 1999-05-17 -ftwhich: check if this is an executable file. -ftwhich,whichman: better handling of broken path settings version 1.7 -whichman did seg fault when MANPATH had spaces at the end, fixed 1999-09-16 version 1.8 -doc for ftff updated. Follow symlink and a symlink to .. 2000-04-11 causes naturaly an endless loop -option -q to keep ftff quiet when it can not read a directory. -option parser changed to accept -- as argumant to stop option reading. -Now we use option -I instead of -s version 1.9 -print version in help text 2000-05-10 -whichman: accept manpages compressed with bz2 version 2.0 -calculate standard tolerance level with out 2001-05-04 taking wildcards into account. version 2.1 -clean up warnings that you get with modern gcc 2002-10-07 version 2.2 -updated specfile 2003-01-04 version 2.3 -updated Makefile 2004-01-19 version 2.4 -gentoo ebuild file added and Makefile adjusted 2004-04-14 ------------------------------------------------------------- whichman's home is http://main.linuxfocus.org/~guido/ Author: Guido Socher, guido(at)linuxfocus.org whichman-2.4/ftff.c0100644000076500001440000002657207274613523013327 0ustar guidousers/* vim: set sw=8 ts=8 si et: */ /* * ftff, fault tolerant file-find. * This program is distributed under the terms * of the Gnu Public License (GPL). */ #include #include #include #include #include #include #include #include #include #include "levdist.h" #ifndef S_IXUSR #define S_IXUSR S_IEXEC #endif #ifndef S_IXGRP #define S_IXGRP (S_IEXEC >> 3) #endif #ifndef S_IXOTH #define S_IXOTH (S_IEXEC >> 6) #endif #ifndef S_IXUGO #define S_IXUGO (S_IXUSR | S_IXGRP | S_IXOTH) #endif static void help(); /* global for efficiency reasons: */ static char *search; static char *fullpath; static int tolerance=-1; /*-1 indicates tolerance is not set*/ static int opt_p=0; static int opt_q=0; static int opt_F=0; static int opt_I=0; static int opt_f=0; #define PATH_MAX_LEN 1000 char *allocpath(void) { char *ptr; if ((ptr = (char *) malloc(PATH_MAX_LEN + 2)) == NULL) { perror("Error: malloc() failed"); exit(1); } return ptr; } /* classify the file type an produce a charater like ls -F */ char filetype(struct stat buffer){ #ifdef linux /*umode_t mode;*/ /*__mode_t mode;*/ mode_t mode; /* these days it's all mode_t */ #else /* linux */ #ifdef sun /* solaris: */ mode_t mode; #else /* sun */ /* other unix os lands here: */ /*unsigned long mode;*/ mode_t mode; #endif /* sun */ #endif /* linux */ mode=buffer.st_mode; switch(mode & S_IFMT) { #ifdef S_IFIFO case S_IFIFO: return '|'; #endif #ifdef S_IFDIR case S_IFDIR: return '/'; #endif #ifdef S_ISLNK case S_IFLNK: return '@'; #endif #ifdef S_IFSOCK case S_IFSOCK: return '='; #endif case S_IFREG: if (mode & S_IXUGO) { return '*'; } return ' '; /* no default */ } return ' '; } /* *check for the file names ".." and "." *return 0 if dir is exactly ".." or "." otherwise return 1 */ int isnotdotdir(char *dir) { int cnt=0; while(*dir){ if(*dir != '.'){ return(1); } if (cnt > 1){ return(1); } cnt++; dir++; } return(0); } /* Traverse directory tree but we don't follow symbolic links * unless opt_f is set. The link-names are processed in any case. * * Return 0 on sucessful file find. * * object = "name of object in FS" * fullpath = "path"+object (this is a global variable) * This is a recursive function. * Uses also the following global var: opt_p,opt_f,opt_I,opt_q */ int traversetree(char *object) { /* for efficiency reasons: */ static struct stat buffer; /*these variables must be local:*/ DIR *dp; struct dirent *dirp; char *ptr; /* must be static:*/ static int result =1; int d,len; if (lstat(fullpath, &buffer) < 0) { if (opt_q==0){ fprintf(stderr, "Warning: %s, ", fullpath); perror(""); } return(result); } #ifdef DEBUG fprintf(stderr, "debug,f:%s o:%s s:%s\n", fullpath,object,search); #endif /*the first time that we are called obj is ".", skip that:*/ if (isnotdotdir(object)){ d=levdist(object, search, tolerance,opt_I); if (d != -1) { if (opt_p) printf("%03d ",d); printf("%s", fullpath); if (opt_F){ printf("%c\n",filetype(buffer)); }else{ printf("\n"); } result = 0; } } if (opt_f && S_ISLNK(buffer.st_mode)){ if (stat(fullpath, &buffer) < 0) { if (opt_q==0){ fprintf(stderr, "Warning: %s, ", fullpath); perror(""); } return(result); } } if (S_ISDIR(buffer.st_mode)) { if (NULL == (dp = opendir(fullpath))) { if (opt_q==0){ fprintf(stderr, "Warning: %s, ", fullpath); perror(""); } return(result); } len=strlen(fullpath); ptr = fullpath + len; /* protection against endless loops due to symbolic links * to .. */ if (len < PATH_MAX_LEN -100){ if (*(ptr -1) != '/'){ /* do not append a "/" if the user did already * provide one in the start_dirictory name */ *ptr = '/'; ptr++; } *ptr = '\0'; while (NULL != (dirp = readdir(dp))) { if (isnotdotdir(dirp->d_name)){ /* Append to fullpath without changing * ptr this will always succeed since * we allocated enough memory.*/ strcpy(ptr, dirp->d_name); traversetree(dirp->d_name); } } closedir(dp); /*shorten fullpath again to current directory:*/ ptr--; } *ptr='\0'; } return (result); } int main(int argc,char *argv[]) { int result,optnum; struct stat buf; char *c,*oarg; if (argc < 2 ) help(); /* * After this while loop. argv[0] is the next argument if available * * options that take an argument write *c=0;break; others write * "c++;break;" * * This parser looks a bit complicated but it can take options * like -23 and -ac is the same as "-a -c" Because we number options * are allowed we can not use on of the standard option parsers. */ optnum=argc; while (--optnum>0) { argv++; c = *argv; /* c is pointer to one argument/option */ if (*c != '-'){ argv--; break; /*stop at the first non option argument*/ } c++; if (*c == '-' && *(c + 1)=='\0'){ /* you can write a double -- to stop option * parsing. This is useful if you need to search * for a string that is called "-something" */ --optnum; break; /*stop option parsing*/ } while (*c) { switch (*c) { case 'f': opt_f=1; c++;break; case 'F': opt_F=1; c++;break; case 'h': help(); /*no break, help does not return*/ case 'p': opt_p=1; c++;break; case 'q': opt_q=1; c++;break; case 'I': opt_I=1; c++;break; case 't': /* you can write -t11 or -t 11*/ /* first the normal -t11 case: */ oarg=c+1; /* then the -t 11 case: */ if(*(c + 1)=='\0'){ if(--optnum) oarg=*++argv; } tolerance = atoi(oarg); if (tolerance > 255 || tolerance <0) tolerance = 255; *c=0;break; default: if (isdigit((int)*c)){ tolerance = atoi(c); if (tolerance > 255 || tolerance <0) tolerance = 255; }else{ fprintf(stderr,"ERROR: No such option. Use -h to get help.\n"); exit(1); } *c=0; } } } if (optnum<0) optnum=0; /* can be less then zero due to a option * with arg at last pos and missing arg*/ /* *optnum is now the number of argmunts left after *option parsing. Example: option a,c take no arg, option b has arg: * thisprogram -a -b xx -c d e * This results in: * optnum==2 and argv[1] points to d * argv[2] points to e */ fullpath = allocpath(); if (1 == optnum) { search = argv[1]; /*start directory is current directory*/ strcpy(fullpath, "."); } else if (2 == optnum) { search = argv[2]; strncpy(fullpath, argv[1],PATH_MAX_LEN); fullpath[PATH_MAX_LEN]=0; if (stat(fullpath, &buf) < 0) { fprintf(stderr, "ERROR: no such directory, %s\n", fullpath); exit(1); } if (!S_ISDIR(buf.st_mode)){ fprintf(stderr, "ERROR: %s is not a directory -h for help.\n",fullpath); exit(1); } } else { help(); } if (tolerance == -1) tolerance=stdtolerance(search); result=traversetree("."); return result; } /* * help */ void help() { printf("ftff -- fault tolerant file find utility\n\ \n\ USAGE: ftff [-#fFhIpq][-t#] [--] [start_dir] filename \n\ \n\ ftff uses an approximate string matching algorithm to match the file names.\n\ \n\ Supported wildcards: * : any arbitrary number of character\n\ ? : one character\n\ \n\ OPTIONS: -f follow symbolic links on directories.\n\ -F classify the file type like \"ls -F\".\n\ -h this help.\n\ -I search case sensitive (default is case in-sensitive)\n\ -p print the actual distance value in front of the file name.\n\ -q Quiet. Do not print a warning when a directory can not be read.\n\ -# set fault tolerance level to # (integer in the range 0-255) \n\ This is the maximum number of permitted errors.\n\ -t# same as -# for backward compatibility\n\ \n\ The default start_dir is the current directory. The default fault tolerance\n\ is (string length of searchpattern - number of wildcards)/6 +1.\n"); printf("%s\n",MYVERSION); exit(0); } /*__END__*/ whichman-2.4/levdist.c0100644000076500001440000001401607550377323014044 0ustar guidousers/* vim: set sw=8 ts=8 si et: */ /* * levdist.c, String distance calculation. * This program is distributed under the terms * of the Gnu Public License (GPL). */ /* * Weighted Levenshtein Distance (WLD) calculation. * The Levenshtein Distance is defined as the number * of replacements, insertions and deletions that are * necessary to transform a word into the search pattern. * * The Levenshtein Distance between SOmestr and 'SO?e*r' * is: * |SOmestr * J1234567 |I * |---------| * S |0123456 |1 * O |1012345 |2 * ? |2101234 |3 * e |3210123 |4 * * |3210000 |5 * r |4321110 |6 The min distance is always in the lower right * corner. * * here the number at (J,I) = (4,2) = 2 indicates that the distance * between 'SOme' and 'SO' is 2. I.e you must insert 2 characters * to transform the substrings into each other. * * The algorithm below knows about the wildcards '?' and '*'. * ? = any single character (exactly one) * * = any character (including no character) * * The minimum distance is alwasy at least as big as the * minimum in each row. This allows to terminate the search * already at an early stage if a limit is given. The minimum * distance can only increase from top to bottom. * An second example: * * distance between SOmestr and '*mxest*r' * |SOmestr * |-------- * * |0000000 min:0 * m |1101111 min:0 * x |2211222 min:1 * e |3321233 min:1 * s |3432123 min:1 * t |4443212 min:1 * * |4443211 min:1 * r |5554321 The total min distance is 1 * */ #include #include #include #include #include "levdist.h" /* * compute a standard tolerance value based on search string lenght * minus number of wildchards in searchsting */ int stdtolerance(const char *searchpat) { int len = 0; while (*searchpat && len < 200) { if (*searchpat == '?' || *searchpat == '*'){ searchpat++; continue; } searchpat++; len++; } len=(len/6)+1; return (len); } /* * Translate string to lower-case and return word lenght * With casesensitive=1 only the word lenght is returned and the * string is copied unmodified from word to lowword. */ int lowercaseword(char *lowword,const char *word, int maxlen,int casesensitive) { int len = 0; while (*word && len < maxlen -1) { if(casesensitive){ *lowword=*word; }else{ *lowword=tolower(*word); } word++;lowword++; len++; } *lowword=0; /*in case maxlen was reached*/ return len; } /* *calculate the minimum of a,b,c and return it */ inline int minimum(int a,int b, int c) { if (a < b) b = a; if (b < c) c = b; return(c); } /* * Calculate the Levenshtein distance between iword and ipattern * Return 'the real distance' if the distance is less or equal * to a given limit. * return -1 if the distance between iword and ipattern is higher * than the given limit. * For casesensitive=1 the algorithm is case sensitive. */ int levdist(const char *iword, const char *ipattern, int limit,int casesensitive) { int dmin, p,pp,q,lpat,lwrd,d1,d2,i,j; char c,word[MAXLEN],pattern[MAXLEN]; int dstprof[MAXLEN]; if (! *iword) return(-1); /*no empty word*/ if (! *ipattern) return(-1); /*no empty pattern*/ lwrd = lowercaseword(word,iword,MAXLEN,casesensitive); lpat = lowercaseword(pattern,ipattern,MAXLEN,casesensitive); /*calculate the first row, that is: distance against *the first character of the pattern */ if (*pattern == '*') { /*the first row has distance 0 if pattern starts with a star*/ for (j = 0; j <= lwrd; j++) { dstprof[j] = 0; } #ifdef DEBUG printf("0..0"); #endif //DEBUG } else { dstprof[0] =1; i = (*pattern == '?') ? 0 : 1; for (j = 0; j < lwrd; j++) { if (*pattern == *(word + j)) { i = 0; } dstprof[j+1] = j + i; #ifdef DEBUG printf("%d",dstprof[j+1]); #endif //DEBUG } } #ifdef DEBUG printf("\n"); #endif //DEBUG i=1; dmin=dstprof[1]; while(i < lpat && dmin <= limit){ c = *(pattern + i ); pp=1;q=1; /*default*/ if (c == '*' || c == '?') pp = 0; if (c == '*') q = 0; d2 = dstprof[0]; dmin = d2 + q; dstprof[0] = dmin; i++; for (j = 1; j <= lwrd; j++) { d1 = d2; d2 = dstprof[j]; p = pp; /*default unless c == word character at pos.*/ if (c == *(word + j -1)) p =0; dstprof[j] = minimum(d1 + p,d2 + q,dstprof[j-1] + q); if (dstprof[j] < dmin) { dmin = dstprof[j]; } #ifdef DEBUG printf("%d",dstprof[j]); #endif //DEBUG } #ifdef DEBUG printf("\n"); #endif //DEBUG } if (dstprof[lwrd] <= limit){ /*we have a match between word and pattern, they * are within the distance limit */ return(dstprof[lwrd]); } return (-1); } #ifdef RETURNVALUE int main(int argc, char **argv) { int d,limit; char *word; char *pattern; if (argc == 5) { word = argv[1]; pattern = argv[2]; limit = atoi(argv[3]); if (*argv[4] == '1'){ printf("not case sensitive\n"); d=levdist(word, pattern, limit,1); }else{ printf("match case sensitive\n"); d=levdist(word, pattern, limit,0); } #ifdef DEBUG printf("distance: %d\n",d); #endif //DEBUG return(d); } else { fprintf(stderr,"Usage: %s word pattern dist_limit case_sensitive\n", argv[0]); fprintf(stderr,"case_sensitive: 1|0 dist_limit:0-255\n"); fprintf(stderr,"Example: %s hello hallo 5 1\n", argv[0]); } return(0); } #endif //RETURNVALUE whichman-2.4/levdist.h0100644000076500001440000000056110004360164014030 0ustar guidousers#ifndef LEVDIST #define LEVDIST 1 /*max search pattern length: */ #define MAXLEN 256 #define MYVERSION "@(#)Version: 2.3" extern int levdist(const char *iword, const char *ipattern, int limit,int casesensitive); extern int stdtolerance(const char *searchpat); extern int lowercaseword(char *lowword,const char *word, int maxlen,int casesensitive); #endif //LEVDIST whichman-2.4/ftwhich.c0100644000076500001440000002527307274613544014036 0ustar guidousers/* vim: set sw=8 ts=8 si et: */ /* * Author: Guido Socher. This program is distributed * under the terms of the Gnu Public License (GPL). */ #include #include #include #include #include #include #include #include "levdist.h" static void help(); static char **splitpath(); static int checkftype(char *path, char *filename); static void matchfilename(char *path, char *key); static int streq(const char *a,const char *b); /*global for simplicity:*/ static int printdist=0; static int casesensitive=0; static int nomatchfound=1; /*matchlimit indicates the tolerance level for Lev. Dist search *-2 not set, * 0 = exact match with wildcards, * 1-255 max distance value*/ static int matchlimit=-2; int main(int argc, char *argv[]) { char searchkey[MAXLEN +1]; char **pathcomp; int optnum; char *c,*oarg; if (argc < 2 ) help(); /* * After this while loop. argv[0] is the next argument if available * * options that take an argument write *c=0;break; others write * "c++;break;" * * This parser looks a bit complicated but it can take options * like -23 and -ac is the same as "-a -c" */ optnum=argc; while (--optnum>0) { argv++; c = *argv; /* c is pointer to one argument/option */ if (*c != '-'){ argv--; break; /*stop at the first non option argument*/ } c++; if (*c == '-' && *(c + 1)=='\0'){ /* you can write a double -- to stop option * parsing. This is useful if you need to search * for a string that is called "-something" */ --optnum; break; /*stop option parsing*/ } while (*c) { switch (*c) { case 'h': help(); /*no break, help does not return*/ case 'p': printdist=1; c++;break; case 'I': casesensitive=1; c++;break; case 't': /* you can write -t11 or -t 11*/ /* first the normal -t11 case: */ oarg=c+1; /* then the -t 11 case: */ if(*(c + 1)=='\0'){ if(--optnum) oarg=*++argv; } matchlimit = atoi(oarg); if (matchlimit > 255 || matchlimit <0) matchlimit = 255; *c=0;break; default: if (isdigit((int)*c)){ if (matchlimit !=-1 ){ /*ignore -e -t1 */ matchlimit = atoi(c); if (matchlimit > 255 || matchlimit <0) matchlimit = 255; } }else{ fprintf(stderr,"ERROR: No such option. Use -h to get help.\n"); exit(1); } *c=0; } } } if (optnum<0) optnum=0; /* can be less then zero due to a option * with arg at last pos and missing arg*/ /* *optnum is now the number of argmunts left after *option parsing. Example: option a,c take no arg, option b has arg: * thisprogram -a -b xx -c d e * This results in: * optnum==2 and argv[1] points to d * argv[2] points to e */ if (optnum != 1) { /* you must provide exactly one argument */ help(); /*help does not return */ } strncpy(searchkey, argv[1],MAXLEN); if (matchlimit == -2){ /*tolerance for Levenshtein Distance search: */ matchlimit = stdtolerance(searchkey); } pathcomp = splitpath(); while (*pathcomp) { matchfilename(*pathcomp, searchkey); pathcomp++; } return (nomatchfound); } /*__END OF MAIN__*/ /* * check that the file is a normal executable. * The abs. path to the file is "path/filename" * Return 1 if it is normal executable or a link to an normal executable */ #define MAXFULLPATHLEN 500 int checkftype(char *path, char *filename) { struct stat stbuf; static char fullpath[MAXFULLPATHLEN]; int i; /*construct the full path to the file:*/ i=0; while(*path && i < MAXFULLPATHLEN-7){ /* -7 so, we have some room */ fullpath[i]=*path; i++;path++; } if (fullpath[i-1]!='/'){ fullpath[i]='/'; i++; } while(*filename && i < MAXFULLPATHLEN-1){ fullpath[i]=*filename; i++;filename++; } fullpath[i]='\0'; /*check if file exists:*/ if (stat(fullpath,&stbuf)!=0) return(0); /*not a regular file*/ if ((stbuf.st_mode & S_IFREG)==0) return(0); /* test if executable for user or grp or others */ if ((stbuf.st_mode & S_IXUSR) || (stbuf.st_mode & S_IXGRP)\ ||(stbuf.st_mode & S_IXOTH)) return(1); return(0); } /* * match all entries in the directory variable path points to * against the key. * This function sets the global variable nomatchfound */ void matchfilename(char *path, char *key) { int dist; DIR *dp; struct dirent *entry; if ((dp = opendir(path)) != NULL) { while ((entry = readdir(dp)) != NULL) { /*ignore . or .. or .file: */ if (*(entry->d_name) == '.') continue; dist=levdist(entry->d_name, key, matchlimit,casesensitive); if (dist != -1 && checkftype(path,entry->d_name)){ if (printdist) printf("%03d ",dist); printf("%s/%s\n", path, entry->d_name); nomatchfound = 0; } } closedir(dp); } } /* * split PATH into substrings and return a pointer to * a 2 dimmentional array with all the sub-strings of the * PATH. */ char **splitpath() { char *spath; /* search path */ char *cspath;/* copy of search path */ static char **pathcomp; int i=0; int notseen=1; char *start; int compind = 0; /* index of *pathcomp[] */ int complen = 1; /* len of one component in the path + 16 */ spath = (char *) getenv("PATH"); if (spath == NULL || *spath == '\0') { fprintf(stderr,"Warning: PATH not defined, using /bin:/usr/bin\n"); spath="/bin:/usr/bin"; } /* make a copy that is static */ cspath = (char *)malloc(strlen(spath) + 2); strcpy(cspath, spath); start = cspath; /* count the number of colons in the path to find how many * components we have in the path */ while (*cspath) { if (*cspath == ':') i++; cspath++; } i+=3; /*some space in case we have corruped path below*/ pathcomp=(char **)malloc(sizeof(char *)*i); /* split the path by replacing : with \0 */ cspath = start; pathcomp[compind]=cspath; while (*cspath) { if (*cspath == ':') { *cspath = '\0'; if (complen > 1) { /*ignore zero length comp. e.g :: */ /* now check if it is a duplicate path * component that we can just ignore: */ i=0;notseen=1; while(notseen && i < compind){ if(streq(pathcomp[compind],pathcomp[i])){ notseen=0; } i++; } if (notseen) compind++; } /* remove any tailing slashes but not if it is * only the root dir (just a "/") */ if (complen > 2 && *(cspath-1) == '/') *(cspath-1)='\0'; pathcomp[compind] = cspath+1; complen = 0; } cspath++; complen++; } if (complen < 2){ /*we have some corrupted path, this happens when you have a *colon at the end of the path */ pathcomp[compind] = NULL; /*terminate */ }else{ /* now check if the last one is a duplicate path * component that we can just ignore: */ i=0;notseen=1; while(notseen && i < compind){ if(streq(pathcomp[compind],pathcomp[i])){ notseen=0; } i++; } if (notseen) compind++; pathcomp[compind] = NULL; /*terminate */ } return (&pathcomp[0]); } /* return 1 if the 2 strings a and b are equal */ int streq(const char *a,const char *b){ while(*a && *b){ if(*a != *b) return(0); a++;b++; } /* both must be at \0 */ if(*a || *b) return(0); return(1); } /* * help */ void help() { printf("ftwhich -- fault tolerant approximate search command for programs\n\ \n\ USAGE: ftwhich [-#hIp][-t#] [--] program-name\n\ \n\ Supported wildcards: * -- any arbitrary number of character\n\ ? -- one character\n\ \n\ OPTIONS: -h this help\n\ -I search case sensitive (default is case in-sensitive)\n\ -p print the actual distance (tolerance) value in front of the\n\ file name.\n\ -# set fault tolerance level to # (integer in the range 0-255)\n\ It specifies the maximum distance. This is the number of\n\ errors permitted for finding the approximate match.\n\ -t# same as -# for backward compatibility\n\ \n\ With no option specified search is fault tolerant using a tolerance\n\ level of: (string length of searchpattern - number of wildcards)/6 +1\n"); printf("%s\n",MYVERSION); exit(0); } /*__END__*/ whichman-2.4/whichman-2.3.lsm0100644000076500001440000000272410004360262015022 0ustar guidousersBegin3 Title: whichman, ftff, ftwhich -- Fault tolerant search utilities Version: 2.3 Entered-date: 19JAN04 Description: whichman uses a fault tolerant approximate matching algorithm to search for man-pages that match approximately the specified name. It can be used to locate the right page in case the man-page is available in several sections. The fault tolerant matching is very useful in cases where you remember only roughly the name of a command. Example: whichman netwhat This finds netstat.8: /usr/man/man8/netstat.8 The package contains also a fault tolerant file find utility (ftff) and a fault tolerant version of the "which" command (ftwhich). Both use the same algorithm as whichman. The error tolerant approximate string match is based on the Levenshtein Distance between two strings. This is a measure for the number of replacements, insertions and deletions that are necessary to transform string A into string B Keywords: man, which, search, find Author: guido@linuxfocus.org (Guido Socher) Maintained-by: guido(at)linuxfocus.org (Guido Socher) Primary-site: www.ibiblio.org /pub/Linux/apps/doctools/ 1k whichman-2.2.lsm 19k whichman-2.2.tar.gz Original-site: http://main.linuxfocus.org/~guido/ Platforms: Linux, probably any Unix Copying-policy: GPL End whichman-2.4/whichman.spec0100644000076500001440000000210110004360333014645 0ustar guidousersSummary: Fault tolerant search utilities Name: whichman Version: 2.3 Release: 1 Copyright: GPL Group: Utilities/File Source: http://main.linuxfocus.org/~guido/whichman-2.3.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-root %description ftff, ftwhich and whichman are fault tolerant search utilities. whichman allows to search for man pages that match approximately the specified search key. ftff is a fault tolerant file find utility and ftwhich is a fault tolerant version for the 'which' command. The error tolerant approximate string match is based on the Levenshtein Distance between two strings. This is a measure for the number of replacements, insertions and deletions that are necessary to transform string A into string B. %prep %setup %build make %install rm -rf $RPM_BUILD_ROOT make instroot=$RPM_BUILD_ROOT MANDIR=%{_mandir} install %files %doc README %{_mandir}/*/whichman.* %{_mandir}/*/ftff.* %{_mandir}/*/ftwhich.* /usr/bin/whichman /usr/bin/ftff /usr/bin/ftwhich %changelog * Sat Jan 4 2003 Guido Socher first rpm version with changelog whichman-2.4/whichman-2.4-r1.ebuild0100644000076500001440000000122710037370553016023 0ustar guidousers# Copyright 1999-2003 Gentoo Technologies, Inc. # Distributed under the terms of the GNU General Public License v2 # $Header: /home/cvsroot/gentoo-x86/net-misc/wget/wget-1.9-r2.ebuild,v 1.4 2003/12/05 02:13:04 seemant Exp $ IUSE="" DESCRIPTION="fault tolerant search utilities" HOMEPAGE="http://main.linuxfocus.org/~guido/" SRC_URI="http://main.linuxfocus.org/~guido/${P}.tar.gz" SLOT="0" LICENSE="GPL-2" KEYWORDS="x86 sparc alpha amd64 ia64" DEPEND="virtual/glibc sys-devel/gcc" src_unpack() { unpack ${P}.tar.gz } src_compile() { emake || die } src_install() { #make prefix=${D}/usr install || die make DESTDIR=${D} install || die dodoc README }