1 #define MAIN
2 #define SUMA_noFunc
3 
4 #include "mrilib.h"
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include "matrix.h"
8 #include "suma_objs.h" /* 21 Apr 2020 */
9 /*------------------------------------------------------------*/
10 
11 #define zischar(ch) ( ( ((ch) >= 'A' && (ch) <= 'Z' ) || ((ch) >= 'a' && (ch) <= 'z' ) ) ? 1 : 0 )
12 #define isnakedarg(s) ( ( (s)[0] == '-' && strlen(s) > 1 && zischar((s)[1]) ) ? 0 : 1 )
13 
count_procs(char * pname)14 int count_procs(char *pname)
15 {
16    char sbuf[1024]={""};
17    int nproc, jj;
18    FILE *fp=NULL;
19    int verb=0;
20 
21    if (!pname) pname = "apsearch";
22 
23    if (SUMA_isEnv("SUMA_CountProcs_Verb","YES")) verb = 1;
24 
25    if (verb) {
26       fprintf(stderr,"  Checking ps:\n");
27       sprintf(sbuf, "\\ps -caA | \\grep %s", pname);
28       system(sbuf);
29    }
30 
31    /* afni_util.py main moved to afni_python_wrapper.py  19 Feb 2020 [rickr] */
32    sprintf(sbuf, "afni_python_wrapper.py -print \"get_process_depth(prog='%s')\"", pname);
33    if (verb) fprintf(stderr," Executing %s\n", sbuf);
34 
35    fp = popen( sbuf , "r" ) ;
36    if( fp == NULL ){
37       ERROR_message(" popen fails\n");
38       exit(1);
39    }
40 
41    jj = fscanf(fp,"%d",&nproc) ;
42    if( jj != 1 ){
43       ERROR_message(" 1st fscanf fails\n");
44       pclose(fp);
45       exit(1);
46    }
47 
48    pclose(fp);
49    if (verb) fprintf(stderr,"Got %d\n", nproc);
50    return(nproc);
51 }
52 
update_help_for_afni_programs(int force_recreate,byte verb,byte clean,THD_string_array ** hlist)53 int update_help_for_afni_programs(int force_recreate,
54                                   byte verb, byte clean,
55                                   THD_string_array **hlist )
56 {
57    int ii, iaf, icomm, estat;
58    char hout[128], houtc[128], scomm[256], *etr=NULL, *hdir=NULL, *etm=NULL;
59    THD_string_array *progs=NULL;
60 
61 
62    ENTRY("produce_help_for_afni_programs");
63 
64    if (hlist && *hlist) {
65       ERROR_message("if hlist then must have *hlist = NULL\n");
66       RETURN(0);
67    }
68 
69    if (!(hdir = THD_get_helpdir(0))) {
70       ERROR_message("Have no help directory\n");
71       RETURN(0);
72    }
73 
74    if (!(progs = THD_get_all_afni_executables())) {
75       ERROR_message("Cannot get list of programs");
76       RETURN(0);
77    }
78 
79    if (hlist) INIT_SARR((*hlist));
80    icomm=0;
81    for (ii=0, iaf=0; ii<progs->num ; ii++ ){
82       /* ------------------------------------------------------------*/
83       /* THIS BLOCK is essentially get_updated_help_file()
84          But I keep it separate because of the need for
85          nap time. Knowing when to sleep in get_updated_help_file()
86          is not that simple.                                   */
87       etr = THD_trailname( progs->ar[ii] , 0 ) ;
88       if (!etr || strlen(etr) < 2) {
89          WARNING_message("Fishy executable named %s\n",progs->ar[ii]);
90          continue;
91       }
92       etm = THD_filetime(progs->ar[ii]);
93       if (etm[0] == '\0') {
94          etm = "NoTimeStamp";
95       }
96       snprintf(hout, 120*sizeof(char),
97                "%s/%s.%s.help", hdir, etr, etm);
98       snprintf(houtc, 120*sizeof(char),
99                "%s/%s.complete", hdir, etr);
100       if (!force_recreate && THD_is_file(hout)) {
101          if (verb)
102             fprintf(stderr,"Reusing %s (%d/%d)\n", hout, ii, progs->num );
103          if (!THD_is_file(houtc)) {
104             prog_complete_command(etr, houtc, -1);
105          }
106       } else {
107          if (verb)
108             fprintf(stderr,"Creating %s (%d/%d)\n", hout, ii, progs->num);
109          if (icomm > 25) { /* sleep a little to allow
110                               forked processes to end */
111             NI_sleep(250); icomm = 0;
112          }
113          /* The echo below is there to make programs that
114             don't like -help and expect stdin to shut up and quit
115             As a result, it is hard to get the status of -help
116             command and use it wisely here without risking
117             trouble.
118             */
119          if (THD_is_file( hout)) {
120             snprintf(scomm, 250*sizeof(char),
121                "chmod u+w %s", hout);
122             system(scomm);
123          }
124          snprintf(scomm, 250*sizeof(char),
125                "\\echo '' 2>&1 | %s -help > %s 2>&1 ", etr, hout);
126          system(scomm);
127          snprintf(scomm, 250*sizeof(char),
128                "chmod a-w %s", hout);
129          system(scomm);
130          prog_complete_command(etr, houtc, -1);
131          ++icomm;
132       }
133       /* ------------------------------------------------------------*/
134 
135       if (hlist) ADDTO_SARR((*hlist), hout);
136 
137    }
138    /* cleanup hdir */
139    if (verb) fprintf(stderr,"Cleaning help directory %s\n",hdir);
140    if (clean && system("@clean_help_dir")) {
141       WARNING_message("Failed cleaning help directory");
142    }
143 
144    DESTROY_SARR(progs) ;
145 
146    RETURN(1);
147 }
148 
149 
apsearch_usage(TFORM targ,int detail)150 int apsearch_usage(TFORM targ, int detail)
151 {
152    int i = 0;
153 
154    ENTRY("apsearch_usage");
155    /* print help message in three sections */
156    sphinx_fprintf(targ, stdout,
157    "\n"
158    "A program to perform simple approximate string searching. It's primary\n"
159    "purpose is to test string matching for atlas area locations.\n"
160    "\n"
161    "  apsearch <-word WORD> <[-file FILE] | [-text TEXT] | [-phelp PROG]> \n"
162    "           [OPTIONS]\n"
163    "\n%s", detail ? "":"use -h or -help for more help detail.\n");
164    if (detail) {
165       sphinx_printf (targ,
166 "Parameters:\n"
167 "===========\n"
168 "  -word WORD: WORD being sought\n"
169 "  -w WORD: Abbreviated version of -word WORD\n"
170 "  -file FILE: Search for WORD in text file FILE\n"
171 "  -files FILE1 FILE2 ...: Search for WORD in text files FILE1 FILE2 ...\n"
172 "  -text TEXT: Search for WORD in string TEXT\n"
173 "  -stdin: Search for WORD in text from stdin\n"
174 "  -: Same as -stdin\n"
175 "  -phelp PROG: Search for WORD in output of command PROG -help\n"
176 "  -popt PROG: Search for possible options of PROG that match WORD\n"
177 "              Make sure you add the '-' to WORD if you are looking\n"
178 "              for an actual option.\n"
179 "  -raw_phelp PROG: Spit out the help string for PROG without modification.\n"
180 "  -txt_phelp PROG: Format the output of PROG -help for simple text.\n"
181 "  -sphinx_phelp PROG: Format the output of PROG -help in a sphinxized way.\n"
182 "  -asphinx_phelp PROG: Format the output of PROG -help in an auto sphinxized\n"
183 "                       way.\n"
184 "  -doc_2_txt: Format AFNI markups from  -file/-files/-stdin content for text\n"
185 "              output.\n"
186 "  -doc_2_spx: Format AFNI markups from  -file/-files/-stdin content for\n"
187 "              Sphinx output.\n"
188 "  -hdoc_2_txt PNAME: Format program help output in  -file/-files/-stdin \n"
189 "              content for text output. PNAME is needed wherever the program\n"
190 "              name is needed in the output.\n"
191 "  -hdoc_2_spx PNAME: Format program help output in  -file/-files/-stdin \n"
192 "              content for Sphinx output. PNAME is needed wherever the program\n"
193 "              name is needed in the output.\n"
194 "  -hdoc_2_aspx PNAME: Format program help output in  -file/-files/-stdin  \n"
195 "              content for Sphinx output with autoformatting of options.\n"
196 "              PNAME is needed wherever the program name is needed in the \n"
197 "              output.:LR:\n"
198 "              Now, why use such an option as opposed to -asphinx_phelp ?\n"
199 "              That's because the -help option in some programs cannot handle\n"
200 "              any special markup within it so we write out that string as is\n"
201 "              to standard out and pipe it to apsearch with:LIT:\n"
202 "              3dinfo -h_raw | apsearch -hdoc_2_aspx 3dinfo -\n\n"
203 "  -race_check PNAME RMAX: Debugging option to test for race conditions where\n"
204 "              apsearch calls a program which for some reason ends up calling\n"
205 "              it back until you chew up all allowed processes -- not fun --!\n"
206 "              This program will now check for such recursive craziness using\n"
207 "              Rick Reynold's afni_util.py program. To see it in action, \n"
208 "              create the following script and call it @rory:LIT:\n"
209 "                 #!/bin/tcsh -f\n"
210 "                 echo \"Called! `date`\"\n"
211 "                 apsearch -DSUMA_CountProcs_Verb=YES -race_check `basename $0`\n"
212 "\n"
213 "              @rory should be executable and in your path.\n"
214 "              Now run @rory and watch it go.\n\n"
215 "  -doc_markup_sample: Shown an example of the types of markups available for\n"
216 "                      the documentation.\n"
217 "  -all_afni_help: Search for WORD in all afni help files.\n"
218 "                  This option is not all that clever at the moment.\n"
219 "  -all_popts PROG: TRY to guess at all the options for PROG\n"
220 "                  The list of options is not guaranteed to be full\n"
221 "                  or accurate. It is created by parsing the program's\n"
222 "                  -help output for likely candidates. \n"
223 "                  It is meant to act as an aid in locating\n"
224 "                  certain options.\n"
225 "  -list_popts PROG: Like -all_popts, but preserve unique set of options\n"
226 "                    only, no chunks of help output are preserved.\n"
227 "  -popts_complete_command PROG: Generate a csh command that can be sourced\n"
228 "                                to allow option autocompletion for program\n"
229 "                                PROG.\n"
230 "                          See also option -bash and -update_all_afni_help\n"
231 "                          See also option -zsh and -update_all_afni_help\n"
232 "  -bash: Use bash format for the complete command. Default is csh/tcsh\n"
233 "         This option MUST PRECEDE option -popts_complete_command\n"
234 "  -zsh: Use zsh format for the complete command. Default is csh/tcsh\n"
235 "         This option MUST PRECEDE option -popts_complete_command\n"
236 "  -ci: Case insensitive search (default)\n"
237 "  -cs: Case sensitive search\n"
238 "  -global_help: Show help for global options.\n"
239 "  -gopts_help:  Show help for global options.\n"
240 "  -max_hits MH: Return best MH hits only. Default MH = 3.\n"
241 "                Use -1 to get all results back.\n"
242 "  -m MH: Abbreviated version of -max_hits MH.\n"
243 "  -min_different_hits mDH: Keep outputing hits until you have dDH\n"
244 "                           dissimilar matches. \n"
245 "                           Default is -1 (no minimum).\n"
246 "  -unique_hits_only: Restrict output to novel hits only.\n"
247 "  -show_score: Show matching word's distance.\n"
248 "  -show_score_detail: That's right.\n"
249 "  -list_all_afni_progs: List all executables in AFNI's bin directory\n"
250 "  -list_all_afni_P_progs: Same as -list_all_afni_progs but with path\n"
251 "  -list_all_afni_readmes: List all README files in AFNI's bin directory\n"
252 "  -list_all_afni_P_readmes: Same as -list_all_afni_readmes but with path\n"
253 "  -list_all_afni_dsets: List all datasets in AFNI's bin directory\n"
254 "  -list_all_afni_P_dsets: Same as -list_all_afni_dsets but with path\n"
255 "  -update_all_afni_help: Build/update -help output under directory:\n"
256 "                     %s\n"
257 "                  If older help files differ by little they are deleted\n"
258 "                  Little differences would be the compile date or the\n"
259 "                  version number. See @clean_help_dir code for details.\n"
260 "                  This option also creates autocompletion code for \n"
261 "                  csh/tcsh, bash and zsh shells.\n"
262 "  -recreate_all_afni_help: Like -update_all_afni_help but force receration\n"
263 "                           even if nothing changed in the help\n"
264 "  -afni_help_dir: Print afni help directory location and quit.\n"
265 "  -afni_data_dir: Print afni data directory location and quit.\n"
266 "  -afni_bin_dir: Print afni's binaries directory location and quit.\n"
267 "  -afni_home_dir: Print afni's home directory and quit.\n"
268 "  -afni_rc_file: Pathname to .afnirc. You'll get one even if none exists.\n"
269 "  -afni_custom_atlas_dir: Print your afni's custom atlas directory \n"
270 "                          and quit.\n"
271 "  -afni_custom_atlas_file: Print your afni's custom atlas file (if any)\n"
272 "                          and quit.\n"
273 "  -afni_text_editor: Print the name of the GUI editor. Priority goes to \n"
274 "                     env. variable AFNI_GUI_EDITOR, otherwise afni\n"
275 "                     will try to find something suitable.\n"
276 "  -afni_web_browser: Print the name of the browser used by AFNI. \n"
277 "                     Priority goes to env. variable AFNI_WEB_BROWSER, \n"
278 "                     otherwise afni will try to find something suitable.\n"
279 "  -afni_web_downloader: Print the name of the downloader used by AFNI. \n"
280 "                     Priority goes to env. variable AFNI_WEB_DOWNLOADER, \n"
281 "                     otherwise afni will try to find something suitable.\n"
282 "  -view_text_file FILE: Open FILE with editor of -afni_text_editor\n"
283 "  -view_readme SOMETHING: Find a readme.SOMETHINGISH and open it\n"
284 "  -apsearch_log_file: Print the name of the logfile that is used to save\n"
285 "                      some results of apsearch's functions. This option\n"
286 "                      is for debugging purposes and is only activated if\n"
287 "                      the environment variable AFNI_LOG_BEST_PROG_OPTION\n"
288 "                      is set to YES.\n"
289 "  -view_prog_help PROG: Open the help file for PROG in a GUI editor.\n"
290 "                        This is like the option -hview in C programs.\n"
291 "  -web_prog_help PROG: Open the help file for PROG in a web brower.\n"
292 "                       This is like the option -hweb in C programs.\n"
293 "              Use ALL to view the page containing help for all programs.\n"
294 "  -web_class_docs: Open the webpage with latest class pdfs.\n"
295 "\n"
296 "  NOTE: The maximum number of results depends on the combination of\n"
297 "        -max_hits, -min_different_hits, and -unique_hits_only. \n"
298 "        Withoug -unique_hits_only, the output will continue \n"
299 "        while neither -max_hits or -min_different_hits conditions \n"
300 "        are met.\n"
301 "\n"
302 "  -func_test: Run sample function testing and quit. Debugging only.\n"
303 "\n"
304 "Wildcard expansion tools:\n"
305 "=========================\n"
306 "-wild_files 'PAT1 PAT2 ...' : Find files matching PAT1, or PAT2, etc.\n"
307 "                              Should include PAT1, etc. between quotes or \n"
308 "                              the shell will do the expansion for you.\n"
309 "                              Note that in addition to wildcard expansion, \n"
310 "                              the function also sorts the output so the order\n"
311 "                              is alphabetical. It also dumps duplicate names\n"
312 "                              which can happen when you start to remove \n"
313 "                              extensions known to AFNI. See -wild* options\n"
314 "                              below.\n"
315 "        Example: -wild_files '*.do *.HEAD'\n"
316 "-wild_files_noAext: After compiling list, remove all known AFNI extensions \n"
317 "                    and preserve unique set of resultant names\n"
318 "-wild_files_noAext_noAview: After compiling list, remove all known AFNI\n"
319 "                    extensions and any view such as +tlrc, +orig, +acpc, \n"
320 "                    and preserve unique set of resultant names\n"
321 "-wild_files_orig_name: Output unique list using orignal (full) filename, \n"
322 "                       rather than the names after extensions or views were\n"
323 "                       removed. This option makes a difference when using\n"
324 "                       one of -wild_files_noAext* options.\n"
325 "-wild_all_files: Show all files from wildcard expansion. Do not sort, do not\n"
326 "                 trim names, etc.\n"
327 "-wild_files_debug: Output results in debugging mode.\n"
328 "-wild_files_ci: When searching for unique set, use case insensitive matching\n"
329 "-test_unique_str: Run debugging tests for function unique_str().\n"
330 "\n"
331 "For hard coders only:\n"
332 "=====================\n"
333 "-C_all_prog_opt_array : Output all program options as an array of C structs.\n"
334 "                        Debugging is output to stderr, the beef is in stdout.\n"
335 "                        Executables not found in the afni binaries directory \n"
336 "                        (now %s) will be ignored.\n"
337 "-C_all_append_prog_opt_array: Keep programs already in C struct but no longer\n"
338 "                        in the new list of executables.\n"
339 "-C_prog_opt_array PROG: Insert/update PROG's options in an array of C \n"
340 "                        and output the results to stdout as for\n"
341 "                        option -C_all_prog_opt_array\n\n"
342 "            Example:    apsearch -C_prog_opt_array 3dToyProg > prog_opts.c\n"
343 "\n"
344 "Examples:\n"
345 "=========\n"
346 " 1- Search help output of program whereami for the word '-atlas'\n"
347 "        apsearch -ci -phelp whereami -word -atlas\n"
348 " 2- Search all atlas area names for some name (mistakes on purpose)\n"
349 "        whereami -show_atlas_code > all_atlas_area_names.txt\n"
350 "        apsearch -file all_atlas_area_names.txt -word hepp\n"
351 "        apsearch -file all_atlas_area_names.txt -word zipp \\\n"
352 "                  -min_different_hits 5 -unique_hits_only \n"
353 "        apsearch -file all_atlas_area_names.txt -word hipp \\\n"
354 "                  -min_different_hits 5 -unique_hits_only \n"
355 " 3- Debug stupid string matcher:\n"
356 "        apsearch -text 'u:Hippocampus' -word hipp -show_score_detail\n"
357 "        apsearch -text 'u:IPC' -word hipp -show_score_detail\n"
358 " 4- Search help of AFNI programs:\n"
359 "        apsearch -phelp afni -word port\n"
360 "        apsearch -phelp 3dSkullStrip -word hull\n"
361 "        apsearch -phelp afni  -word xt\n"
362 " 5- Suggest a valid option from a program:\n"
363 "        apsearch -popt afni -word xt\n"
364 "        apsearch -popt @ROI_Corr_Mat -word sel\n"
365 "        apsearch -popt @ROI_Corr_Mat -word -sel\n"
366 " 6- Show all(*) options for a program:\n"
367 "        apsearch -all_popts 3dSkullStrip\n"
368 "    (*) see -all_popts in help section\n"
369 " 7- Look for some area named something or other in some atlas:\n"
370 "        whereami -show_atlas_code -atlas DKD_Desai_MPM |\\\n"
371 "                                apsearch -stdin -word insola\n"
372 "    If you really screw up the spelling, you should help the search\n"
373 "    program a little as in:\n"
374 "        whereami -show_atlas_code -atlas DKD_Desai_MPM |\\\n"
375 "                                sed 's/[-_]/ /g' |\\\n"
376 "                                apsearch -stdin -word insolent\n"
377 " 8- Find 10 afni programs with something like 'Surface' in their names:\n"
378 "        apsearch -list_all_afni_progs | \\\n"
379 "             apsearch -stdin -word surface -max_hits 10\n"
380 " 9- Open the readme for driving AFNI:\n"
381 "        apsearch -view_readme driv\n"
382 " 10- Wildcard expansion and sorting:\n"
383 "        apsearch -wild_files '*.1D*' '*.HEAD *.BRIK*' \\\n"
384 "                 -wild_all_files \n"
385 "        apsearch -wild_files '*.1D*' '*.HEAD *.BRIK*' \\\n"
386 "                 -wild_files_noAext_noAview \n"
387 "        apsearch -wild_files '*.1D*' '*.HEAD *.BRIK*' \\\n"
388 "                 -wild_files_noAext_noAview -wild_files_orig_name \n"
389 "\n"
390 "Global Options:\n"
391 "===============\n"
392 "%s\n%s",
393    THD_helpdir(0), THD_abindir(1),
394    detail > 1 ? get_gopt_help():"",
395    detail > 1 ? SUMA_Offset_SLines(get_help_help(),2):"");
396    PRINT_COMPILE_DATE ;
397    }
398    return 0;
399 }
400 
401 
402 /*----------------------------------------------------------------------------*/
text_from_stdin(int * nread)403 char *text_from_stdin(int *nread)
404 {
405    int N_lbuf = 30000;
406    char lbuf[N_lbuf+1];
407    char *txt=NULL, *cpt=NULL;
408    int ex = 0, i, N_alloc=0, nchar=0, nnew;
409 
410 
411    if (nread) *nread = -1;
412 
413    i = 0; N_alloc=0; nchar=0, nnew=0;
414    do{
415       cpt = afni_fgets(lbuf,N_lbuf,stdin) ;
416       lbuf[N_lbuf] = '\0';
417       ex = feof(stdin);
418       if( cpt==NULL && !ex){
419          free(txt);
420          ERROR_message("Failure reading from stdin");
421          return(NULL);
422       }
423       if (!ex) {
424          nnew = strlen(lbuf);
425          if (nchar+nnew >= N_alloc) {
426             N_alloc += (nnew+10000);
427             txt = (char *)realloc(txt, sizeof(char)*N_alloc);
428          }
429          /* fprintf(stderr,"%d- %s",nchar, lbuf);*/
430          strcat(txt, lbuf); nchar += nnew;
431       }
432    } while (!ex);
433 
434 
435    txt = (char *)realloc(txt, sizeof(char)*(1+nchar));
436    txt[nchar]='\0';
437 
438    if (nread) *nread = nchar;
439 
440    return(txt);
441 }
442 
443 /* A function to test function unique_str. Use for debugging only */
Test_unique_str(void)444 int Test_unique_str(void)
445 {
446    /* dirty test for sorting */
447    char **ww, **ws;
448    int i, N_words=10, N_unq, *isrt=NULL;
449    ww = (char **)calloc(N_words, sizeof(char *));
450    i = 0;
451    ww[i++] = strdup("hello+orig.HEAD");
452    ww[i++] = strdup("hello+orig.BRIK.gz");
453    ww[i++] = NULL;
454    ww[i++] = strdup("HELLO+orig.HEAD");
455    ww[i++] = NULL;
456    ww[i++] = strdup("hello.nii");
457    ww[i++] = strdup("HELLO+orig.HEAD");
458    ww[i++] = strdup("james.nii");
459    if (i >= N_words) {
460       ERROR_message("Too many strings for allocated space"); return(1);
461    }
462 
463    fprintf(stdout,
464             "\nInitial list of %d strings:\n", N_words);
465    for (i=0; i<N_words; ++i) {
466       fprintf(stdout,"%d %s\n", i, ww[i]?ww[i]:"NULL");
467    }
468 
469    if ((ws = unique_str(ww, N_words, 0, 0, &N_unq, &isrt))) {
470       fprintf(stdout,
471             "\n%d/%d unique strings, case sensisitve, names as is:\n",
472                      N_unq, N_words);
473       for (i=0; i<N_words; ++i) {
474          fprintf(stdout,"%d %s (ww[%d]=%s)\n",
475                   i, ws[i]?ws[i]:"NULL - what follows is legit garbage",
476                   isrt[i], ww[isrt[i]]?ww[isrt[i]]:"NULL" );
477       }
478       if (isrt) free(isrt); isrt = NULL;
479       for (i=0; i<N_words; ++i) if (ws[i]) free(ws[i]);
480       free(ws); ws = NULL;
481    }
482    if ((ws = unique_str(ww, N_words, 1, 0, &N_unq, &isrt))) {
483       fprintf(stdout,
484                "\n%d/%d unique strings, case insensitive, names as is:\n",
485                      N_unq, N_words);
486       for (i=0; i<N_words; ++i) {
487          fprintf(stdout,"%d %s (ww[%d]=%s)\n",
488                   i, ws[i]?ws[i]:"NULL - what follows is legit garbage",
489                   isrt[i], ww[isrt[i]]?ww[isrt[i]]:"NULL" );
490       }
491       if (isrt) free(isrt); isrt = NULL;
492       for (i=0; i<N_words; ++i) if (ws[i]) free(ws[i]);
493       free(ws); ws = NULL;
494    }
495    if ((ws = unique_str(ww, N_words, 1, 1, &N_unq, &isrt))) {
496       fprintf(stdout,"\n%d/%d unique strings, case insensitive, noext\n",
497                      N_unq, N_words);
498       for (i=0; i<N_words; ++i) {
499          fprintf(stdout,"%d %s (ww[%d]=%s)\n",
500                   i, ws[i]?ws[i]:"NULL - what follows is legit garbage",
501                   isrt[i], ww[isrt[i]]?ww[isrt[i]]:"NULL" );
502       }
503       if (isrt) free(isrt); isrt = NULL;
504       for (i=0; i<N_words; ++i) if (ws[i]) free(ws[i]);
505       free(ws); ws = NULL;
506    }
507    if ((ws = unique_str(ww, N_words, 1, 2, &N_unq, &isrt))) {
508       fprintf(stdout,
509                "\n%d/%d unique strings, case insensitive, noext noview\n",
510                      N_unq, N_words);
511       for (i=0; i<N_words; ++i) {
512          fprintf(stdout,"%d %s (ww[%d]=%s)\n",
513                   i, ws[i]?ws[i]:"NULL - what follows is legit garbage",
514                   isrt[i], ww[isrt[i]]?ww[isrt[i]]:"NULL" );
515       }
516       if (isrt) free(isrt); isrt = NULL;
517       for (i=0; i<N_words; ++i) if (ws[i]) free(ws[i]);
518       free(ws); ws = NULL;
519    }
520 
521    if ((ws = unique_str(ww, N_words, 0, 2, &N_unq, &isrt))) {
522       fprintf(stdout,
523                "\n%d/%d unique strings, case sensitive, noext noview\n",
524                      N_unq, N_words);
525       for (i=0; i<N_words; ++i) {
526          fprintf(stdout,"%d %s (ww[%d]=%s)\n",
527                   i, ws[i]?ws[i]:"NULL - what follows is legit garbage",
528                   isrt[i], ww[isrt[i]]?ww[isrt[i]]:"NULL" );
529       }
530       if (isrt) free(isrt); isrt = NULL;
531       for (i=0; i<N_words; ++i) if (ws[i]) free(ws[i]);
532       free(ws); ws = NULL;
533    }
534 
535    for (i=0; i<N_words; ++i) if (ww[i]) free(ww[i]);
536       free(ww); ww = NULL;
537    return(0);
538 }
539 
main(int argc,char ** argv)540 int main(int argc, char **argv)
541 {
542    int iarg, N_ws, i, max_hits, test_only, new_score=0,
543        i_unique_score=0, min_different_hits=0, unq_only=0,
544        show_score=0, N_fnamev=0, MAX_FNAMES = 0, uopts=0,
545        compcom = 0, shtp = 0;
546    float *ws_score=NULL, last_score=-1.0;
547    char *fname=NULL, *text=NULL, *prog=NULL, *word="Ma fich haga", **ws=NULL,
548          *all_popts=NULL, *popt=NULL, stdinflag[] = " [+.-STDIN-.+] ",
549          *pname=NULL;
550    THD_string_array *fnamev = NULL;
551    APPROX_STR_DIFF *D=NULL;
552    THD_string_array *sar = NULL;
553    byte ci = 1;
554    char *wild_list=NULL, **wglob=NULL, **wsort=NULL;
555    int nglob, nsort, *isrt=NULL, wild_noext=0, nproc=0,
556        wild_all_files = 0, wild_orig_name = 0, wild_ci=0;
557    TFORM spx_tar = TFORM_NOT_SET;
558 
559    mainENTRY("apsearch main"); machdep() ;
560 
561    /* Check for race conditions, but do allow this program to call itself once
562    to accomodate the automatic handling of -h_apsx in mainENTRY(). */
563    if ((nproc = count_procs("apsearch")) > 2) {
564       ERROR_message("Race condition detected. I'm out");
565       exit(1);
566    }
567 
568    max_hits = 3;
569    test_only=0;
570    min_different_hits = -1;
571    if (argc <= 1) {
572       apsearch_usage(TXT, 0);
573       return(1);
574    }
575 
576    iarg = 1 ;
577    while( iarg < argc ){
578       CHECK_HELP(argv[iarg], apsearch_usage);
579       if (strcmp(argv[iarg],"-ci") == 0) {
580          ci = 1;
581          ++iarg;
582          continue;
583       }
584 
585       if (strcmp(argv[iarg],"-cs") == 0) {
586          ci = 0;
587          ++iarg;
588          continue;
589       }
590 
591       if (strcmp(argv[iarg],"-afni_help_dir") == 0) {
592          fprintf(stdout,"%s\n", THD_helpdir(0));
593          return(0);
594       }
595 
596       if (strcmp(argv[iarg],"-test_unique_str") == 0) {
597          Test_unique_str();
598          return(0);
599       }
600 
601       if (strcmp(argv[iarg],"-afni_data_dir") == 0) {
602          fprintf(stdout,"%s\n", THD_datadir(0));
603          return(0);
604       }
605 
606       if (strcmp(argv[iarg],"-afni_rc_file") == 0) {
607          fprintf(stdout,"%s\n", THD_afnirc());
608          return(0);
609       }
610 
611       if (strcmp(argv[iarg],"-afni_home_dir") == 0) {
612          fprintf(stdout,"%s\n", THD_homedir(0));
613          return(0);
614       }
615 
616       if (strcmp(argv[iarg],"-afni_custom_atlas_dir") == 0) {
617          fprintf(stdout,"%s\n", THD_custom_atlas_dir(0));
618          return(0);
619       }
620 
621       if (strcmp(argv[iarg],"-afni_custom_atlas_file") == 0) {
622          fprintf(stdout,"%s\n", THD_custom_atlas_file(NULL));
623          return(0);
624       }
625 
626       if (strcmp(argv[iarg],"-afni_bin_dir") == 0) {
627          fprintf(stdout,"%s\n", THD_abindir(0));
628          return(0);
629       }
630 
631       if (strcmp(argv[iarg],"-apsearch_log_file") == 0) {
632          fprintf(stdout,"%s\n", THD_helpsearchlog(0));
633          return(0);
634       }
635 
636       if (strcmp(argv[iarg],"-afni_text_editor") == 0) {
637          char *ss = GetAfniTextEditor();
638          fprintf(stdout,"%s\n", ss?ss:"NONE FOUND");
639          return(0);
640       }
641 
642       if (strcmp(argv[iarg],"-afni_web_downloader") == 0) {
643          char *ss = GetAfniWebDownloader();
644          fprintf(stdout,"%s\n", ss?ss:"NONE FOUND");
645          return(0);
646       }
647 
648       if (strcmp(argv[iarg],"-afni_web_browser") == 0) {
649          char *ss = GetAfniWebBrowser();
650          fprintf(stdout,"%s\n", ss?ss:"NONE FOUND");
651          return(0);
652       }
653 
654       if (strcmp(argv[iarg],"-show_score") == 0) {
655          show_score=1;
656          ++iarg;
657          continue;
658       }
659 
660       if (strcmp(argv[iarg],"-show_score_detail") == 0) {
661          show_score=2;
662          ++iarg;
663          continue;
664       }
665 
666       if (strcmp(argv[iarg],"-func_test") == 0) {
667          test_only = 0;
668          ++iarg;
669          continue;
670       }
671 
672       /* 3 Feb 2014 [rickr] */
673       if (strcmp(argv[iarg],"-global_help") == 0 ||
674           strcmp(argv[iarg],"-gopts_help") == 0) {
675          printf(
676       "--------------------------------------------------------------------\n"
677       "Global Options: options available to most AFNI programs, but usually\n"
678       "                not found in the -help output.\n"
679       "--------------------------------------------------------------------\n"
680              "%s\n%s", SUMA_Offset_SLines(get_help_help(),2), get_gopt_help());
681          return(0);
682       }
683 
684       if (strcmp(argv[iarg],"-race_check") == 0) {
685          char sbuf[100];
686          ++iarg;
687          if (iarg >= argc) {
688             fprintf( stderr,
689                      "** Error: Need a program name after -race_check\n");
690             return(1);
691          }
692          sprintf(sbuf,"%s -race_test",argv[iarg]);
693          fprintf(stderr,"Calling %s after a sec. nap\n", sbuf);
694          NI_sleep(1000);
695          system(sbuf);
696          ++iarg;
697          continue;
698       }
699 
700 
701 
702       if (strcmp(argv[iarg],"-file") == 0) {
703          ++iarg;
704          if (iarg >= argc) {
705             fprintf( stderr,
706                      "** Error: Need text file after -file\n"); return(1);
707          }
708 
709          fname = argv[iarg];
710          ++iarg;
711          continue;
712       }
713 
714       if (strcmp(argv[iarg],"-has-h_raw") == 0) {
715          char *s=NULL;
716          int ans;
717 
718          ++iarg;
719          if (iarg >= argc) {
720             fprintf( stderr,
721                "** Error: Need a program name after"
722                " -has-h_raw\n");
723             return(1);
724          }
725          ans = program_supports(argv[iarg], "-h_raw", NULL, 1);
726          fprintf(stdout, "%d\n", ans);
727          return(0);
728       }
729 
730       if (strcmp(argv[iarg],"-sphinx_phelp") == 0 ||
731           strcmp(argv[iarg],"-txt_phelp") == 0 ||
732           strcmp(argv[iarg],"-raw_phelp") == 0 ||
733           strcmp(argv[iarg],"-asphinx_phelp") == 0) {
734          TFORM form=NO_FORMAT;
735          char *s=NULL;
736          ++iarg;
737          if (iarg >= argc) {
738             fprintf( stderr,
739                "** Error: Need a program name after"
740                " -sphinx_phelp/-txt_phelp/-raw_phelp\n");
741             return(1);
742          }
743 
744               if (strcmp(argv[iarg-1],"-txt_phelp") == 0) form = TXT;
745          else if (strcmp(argv[iarg-1],"-sphinx_phelp") == 0) form = SPX;
746          else if (strcmp(argv[iarg-1],"-asphinx_phelp") == 0) form = ASPX;
747          else if (strcmp(argv[iarg-1],"-raw_phelp") == 0) form = NO_FORMAT;
748          else {
749             ERROR_message("Who wrote this thing?!?");
750             return(1);
751          }
752          if ((s = phelp(argv[iarg], form, 0))) {
753             fprintf(stdout, "%s", s);
754             free(s); s = NULL;
755          }
756          ++iarg;
757          return(0);
758          continue;
759       }
760 
761 
762 
763       if (!strcmp(argv[iarg],"-doc_markup_sample")) {
764          SUMA_Sphinx_String_Edit_Help(NULL,0);
765          ++iarg;
766          return(0);
767          continue;
768       }
769 
770       if (!strcmp(argv[iarg],"-doc_markup_sample_web")) {
771          SUMA_Sphinx_String_Edit_Help(NULL,1);
772          ++iarg;
773          return(0);
774          continue;
775       }
776 
777       if (!strcmp(argv[iarg],"-doc_2_txt")) {
778          spx_tar = TXT;
779          ++iarg; continue;
780       }
781 
782       if (!strcmp(argv[iarg],"-doc_2_spx")) {
783          spx_tar = SPX;
784          ++iarg; continue;
785       }
786 
787       if (!strcmp(argv[iarg],"-doc_2_aspx")) {
788          spx_tar = ASPX;
789          ++iarg; continue;
790       }
791 
792       if (!strcmp(argv[iarg],"-hdoc_2_txt")) {
793          ++iarg;
794          if (iarg >= argc || !strcmp(argv[iarg],"-")) {
795             fprintf( stderr,
796                      "** Error: Need a program name after -hdoc_*\n"); return(1);
797          }
798          pname = argv[iarg];
799          spx_tar = TXT;
800          ++iarg; continue;
801       }
802 
803       if (!strcmp(argv[iarg],"-hdoc_2_spx")) {
804          ++iarg;
805          if (iarg >= argc || !strcmp(argv[iarg],"-")) {
806             fprintf( stderr,
807                      "** Error: Need a program name after -hdoc_*\n"); return(1);
808          }
809          pname = argv[iarg];
810 
811          spx_tar = SPX;
812          ++iarg; continue;
813       }
814 
815       if (!strcmp(argv[iarg],"-hdoc_2_aspx")) {
816          ++iarg;
817          if (iarg >= argc || !strcmp(argv[iarg],"-")) {
818             fprintf( stderr,
819                      "** Error: Need a program name after -hdoc_*\n"); return(1);
820          }
821          pname = argv[iarg];
822 
823          spx_tar = ASPX;
824          ++iarg; continue;
825       }
826 
827 
828       if (strcmp(argv[iarg],"-files") == 0) {
829          ++iarg;
830          if (iarg >= argc) {
831             fprintf( stderr,
832                      "** Error: Need text files after -files\n"); return(1);
833          }
834          while (iarg < argc && argv[iarg][0] != '-') {
835             if ( ! fnamev ) INIT_SARR(fnamev);
836             if (!THD_is_file(argv[iarg])) {
837                ERROR_exit("Argument %s for -files is not a file on disk\n",
838                              argv[iarg]);
839             }
840             ADDUTO_SARR(fnamev, argv[iarg]);
841             ++iarg;
842          }
843          continue;
844       }
845 
846       if (!strcmp(argv[iarg],"-wild_files_noAext")) {
847          wild_noext = 1;
848          ++iarg; continue;
849       }
850 
851       if (!strcmp(argv[iarg],"-wild_files_noAext_noAview")) {
852          wild_noext = 2;
853          ++iarg; continue;
854       }
855 
856       if (!strcmp(argv[iarg],"-wild_files_orig_name")) {
857          wild_orig_name = 1;
858          ++iarg; continue;
859       }
860 
861       if (!strcmp(argv[iarg],"-wild_files_debug")) {
862          wild_orig_name = -1;
863          ++iarg; continue;
864       }
865 
866       if (!strcmp(argv[iarg],"-wild_all_files")) {
867          wild_all_files = 1;
868          ++iarg; continue;
869       }
870       if (!strcmp(argv[iarg],"-wild_files_ci")) {
871          wild_ci = 1;
872          ++iarg; continue;
873       }
874       if (!strcmp(argv[iarg],"-wild_files")) {
875          ++iarg;
876          if (iarg >= argc) {
877             fprintf( stderr,
878                "** Error: Need wildcards files after -wild_files\n"); return(1);
879          }
880          while (iarg < argc && argv[iarg][0] != '-') {
881             wild_list =
882                SUMA_append_replace_string(wild_list, argv[iarg], " ", 1);
883             ++iarg;
884          }
885          continue;
886       }
887 
888       if (strcmp(argv[iarg],"-stdin") == 0 || strcmp(argv[iarg],"-") == 0) {
889          fname = stdinflag;
890          ++iarg;
891          continue;
892       }
893 
894       if (strcmp(argv[iarg],"-view_prog_help") == 0) {
895          ++iarg;
896          if (iarg >= argc) {
897             fprintf( stderr,
898                      "** Error: Need program name after -view_prog_help\n");
899                      return(1);
900          }
901          view_prog_help(argv[iarg]);
902          return(0);
903          continue;
904       }
905 
906       if (strcmp(argv[iarg],"-web_prog_help") == 0) {
907          ++iarg;
908          if (iarg >= argc) {
909             fprintf( stderr,
910                      "** Error: Need program name after -web_prog_help\n");
911                      return(1);
912          }
913          web_prog_help(argv[iarg],0);
914          return(0);
915          continue;
916       }
917 
918       if (strcmp(argv[iarg],"-web_class_docs") == 0) {
919          web_class_docs(NULL);
920          return(0);
921          continue;
922       }
923 
924       if (strcmp(argv[iarg],"-view_readme") == 0) {
925          char *rout=NULL, **ws=NULL;
926          int N_ws, i;
927          ++iarg;
928          if (iarg >= argc) {
929             fprintf( stderr,
930                      "** Error: Need README name after -view_readme\n");
931                      return(1);
932          }
933          if ((rout = find_readme_file(argv[iarg]))) {
934             view_text_file(rout); free(rout);
935          } else {
936             fprintf( stderr,
937                      "** Error: Could not find solid match for readme %s\n"
938                "Try to pick a good one using apsearch -list_all_afni_readmes\n",
939                      argv[iarg]);
940             ws = approx_str_sort_readmes(argv[iarg], &N_ws);
941             if (N_ws) {
942                   fprintf( stderr, "   Perhaps you're looking for:\n");
943                for (i=0; i< N_ws; ++i) {
944                   if (i<max_hits) fprintf( stderr, "   %d- %s\n", i, ws[i]);
945                   free(ws[i]);
946                }
947                free(ws);
948             }
949          }
950          return(0);
951       }
952 
953       if (strcmp(argv[iarg],"-view_text_file") == 0) {
954          char *rout=NULL, **ws=NULL;
955          int N_ws, i;
956          ++iarg;
957          if (iarg >= argc) {
958             fprintf( stderr,
959                      "** Error: Need a filename after -view_text_file\n");
960                      return(1);
961          }
962          if (!THD_is_file(argv[iarg])) {
963             fprintf( stderr,
964                      "** Error: File %s not found.\n", argv[iarg]);
965                      return(1);
966          }
967          view_text_file(argv[iarg]);
968          return(0);
969       }
970 
971       if (strcmp(argv[iarg],"-text") == 0) {
972          ++iarg;
973          if (iarg >= argc) {
974             fprintf( stderr,
975                      "** Error: Need string after -text\n"); return(1);
976          }
977 
978          text = argv[iarg];
979          ++iarg;
980          continue;
981       }
982 
983       if (strcmp(argv[iarg],"-phelp") == 0 ||
984           strcmp(argv[iarg],"-popt") == 0 ) {
985          ++iarg;
986          if (iarg >= argc) {
987             fprintf( stderr,
988                "** Error: Need program name after -phelp or -popt\n"); return(1);
989          }
990 
991          if (strcmp(argv[iarg-1],"-popt") == 0) popt = argv[iarg];
992          else prog = argv[iarg];
993 
994          ++iarg;
995          continue;
996       }
997 
998       if (strcmp(argv[iarg],"-all_popts") == 0 ) {
999          ++iarg;
1000          if (iarg >= argc) {
1001             fprintf( stderr,
1002                "** Error: Need program name after -all_popts\n"); return(1);
1003          }
1004 
1005          all_popts = argv[iarg];
1006          uopts = 0;
1007          max_hits = -1;
1008          word = "-";
1009          ++iarg;
1010          continue;
1011       }
1012 
1013       if (strcmp(argv[iarg],"-list_popts") == 0 ) {
1014          ++iarg;
1015          if (iarg >= argc) {
1016             fprintf( stderr,
1017                "** Error: Need program name after -list_popts\n"); return(1);
1018          }
1019 
1020          all_popts = argv[iarg];
1021          uopts = 1;
1022          max_hits = -1;
1023          word = "-";
1024          ++iarg;
1025          continue;
1026       }
1027 
1028       if (strcmp(argv[iarg],"-C_all_prog_opt_array") == 0) {
1029          progopt_C_array(NULL, 1, NULL, 0);
1030          return(0);
1031          ++iarg;
1032          continue;
1033       }
1034 
1035       if (strcmp(argv[iarg],"-C_all_append_prog_opt_array") == 0) {
1036          progopt_C_array(NULL, 1, NULL, 1);
1037          return(0);
1038          ++iarg;
1039          continue;
1040       }
1041 
1042       if (strcmp(argv[iarg],"-C_prog_opt_array") == 0) {
1043          ++iarg;
1044          if (iarg >= argc) {
1045             fprintf( stderr,
1046                "** Error: Need program name after -C_prog_opt_array\n");
1047             return(1);
1048          }
1049          progopt_C_array(NULL, 1, argv[iarg], 1);
1050          return(0);
1051          ++iarg;
1052          continue;
1053       }
1054 
1055 
1056       if (strcmp(argv[iarg],"-bash") == 0) {
1057          shtp = 1;
1058          ++iarg;
1059          continue;
1060       }
1061 
1062       if (strcmp(argv[iarg],"-zsh") == 0) {
1063          shtp = 1;
1064          ++iarg;
1065          continue;
1066       }
1067 
1068       if (strcmp(argv[iarg],"-popts_complete_command") == 0 ) {
1069          ++iarg;
1070          if (iarg >= argc) {
1071             fprintf( stderr,
1072                "** Error: Need program name after -popts_complete_command\n");
1073             return(1);
1074          }
1075 
1076          all_popts = argv[iarg];
1077          if (1) {
1078             prog_complete_command(all_popts, NULL, shtp);
1079             return(0);
1080          }
1081 
1082          uopts = 1;
1083          compcom = 1;
1084          max_hits = -1;
1085          word = "-";
1086 
1087          ++iarg;
1088          continue;
1089       }
1090 
1091       if (strcmp(argv[iarg],"-word") == 0 || strcmp(argv[iarg],"-w") == 0) {
1092          ++iarg;
1093          if (iarg >= argc) {
1094             fprintf( stderr,
1095                      "** Error: Need text file after -file\n"); return(1);
1096          }
1097 
1098          word = argv[iarg];
1099          ++iarg;
1100          continue;
1101       }
1102 
1103       if (strcmp(argv[iarg],"-max_hits") == 0 || strcmp(argv[iarg],"-m") == 0) {
1104          ++iarg;
1105          if (iarg >= argc) {
1106             fprintf( stderr,
1107                      "** Error: Need an integer after -max_hits\n"); return(1);
1108          }
1109 
1110          max_hits = atoi(argv[iarg]);
1111          ++iarg;
1112          continue;
1113       }
1114 
1115       if (strcmp(argv[iarg],"-min_different_hits") == 0) {
1116          ++iarg;
1117          if (iarg >= argc) {
1118             fprintf( stderr,
1119                      "** Error: Need an integer after -min_different_hits\n");
1120                      return(1);
1121          }
1122 
1123          min_different_hits = atoi(argv[iarg]);
1124          ++iarg;
1125          continue;
1126       }
1127 
1128       if (strcmp(argv[iarg],"-unique_hits_only") == 0) {
1129          unq_only = 1;
1130          ++iarg;
1131          continue;
1132       }
1133 
1134       if (strcmp(argv[iarg],"-update_all_afni_help") == 0) {
1135          update_help_for_afni_programs(0, 1, 1, NULL); return(0);
1136          ++iarg;
1137          continue;
1138       }
1139 
1140       if (strcmp(argv[iarg],"-recreate_all_afni_help") == 0) {
1141          update_help_for_afni_programs(1, 1, 1, NULL); return(0);
1142          ++iarg;
1143          continue;
1144       }
1145 
1146       if (strcmp(argv[iarg],"-all_afni_help") == 0) {
1147          update_help_for_afni_programs(0, 0, 0, &fnamev);
1148          ++iarg;
1149          continue;
1150       }
1151 
1152       if (strcmp(argv[iarg],"-list_all_afni_progs") == 0) {
1153          list_afni_programs(0, 0); return(0);
1154          ++iarg;
1155          continue;
1156       }
1157 
1158       if (strcmp(argv[iarg],"-list_all_afni_P_progs") == 0) {
1159          list_afni_programs(1, 0); return(0);
1160          ++iarg;
1161          continue;
1162       }
1163 
1164       if (strcmp(argv[iarg],"-list_all_afni_readmes") == 0) {
1165          list_afni_readmes(0, 0); return(0);
1166          ++iarg;
1167          continue;
1168       }
1169 
1170       if (strcmp(argv[iarg],"-list_all_afni_P_readmes") == 0) {
1171          list_afni_readmes(1, 0); return(0);
1172          ++iarg;
1173          continue;
1174       }
1175 
1176       if (strcmp(argv[iarg],"-list_all_afni_dsets") == 0) {
1177          list_afni_dsets(0, 0); return(0);
1178          ++iarg;
1179          continue;
1180       }
1181 
1182       if (strcmp(argv[iarg],"-list_all_afni_P_dsets") == 0) {
1183          list_afni_dsets(1, 0); return(0);
1184          ++iarg;
1185          continue;
1186       }
1187 
1188       { /* bad news in tennis shoes */
1189          fprintf(stderr,"** Error %s: bad option %s\n", argv[0], argv[iarg]);
1190          suggest_best_prog_option(argv[0], argv[iarg]);
1191          return 1;
1192       }
1193 
1194    }
1195 
1196    if (fname && text) {
1197       ERROR_message("-file and -text are mutually exclusive");
1198       return 1;
1199    }
1200 
1201    if (min_different_hits<=0) min_different_hits = -1;
1202    if (max_hits <=0) max_hits = MRI_maxint;
1203 
1204    if (test_only) {
1205       test_approx_str_match();
1206       return 0;
1207    }
1208 
1209    if (wild_list) { /* some globbing action only */
1210       MCW_wildcards(wild_list, &nglob, &wglob);
1211       if (!wglob || nglob == 0) {
1212          SUMA_ifree(wild_list);
1213          exit(1); /* no files found */
1214       }
1215       if (wild_all_files) { /* No sorting */
1216          for (i=0; i<nglob; ++i) {
1217             fprintf(stdout,"%s\n", wglob[i]);
1218          }
1219          SUMA_ifree(wild_list);
1220          MCW_free_wildcards( nglob , wglob ) ;
1221          exit(0);
1222       }
1223       /* some sorting needed */
1224       if ((wsort = unique_str(wglob, nglob, wild_ci, wild_noext,
1225                               &nsort, &isrt))) {
1226          if (wild_orig_name == -1) {/* verbose output */
1227             fprintf(stdout, "\n%d/%d unique strings, noext = %d:\n",
1228                      nsort, nglob, wild_noext);
1229             for (i=0; i<nsort; ++i) {
1230                fprintf(stdout,"%d %s (wglob[%d]=%s)\n",
1231                  i, wsort[i]?wsort[i]:"NULL - what followsort is legit garbage",
1232                  isrt[i], wglob[isrt[i]]?wglob[isrt[i]]:"NULL" );
1233             }
1234          } else {
1235             if (wild_orig_name) { /* output original strings */
1236                for (i=0; i<nsort; ++i) {
1237                   fprintf(stdout,"%s\n", wglob[isrt[i]]);
1238                }
1239             } else { /* output trimmed strings */
1240                for (i=0; i<nsort; ++i) {
1241                   fprintf(stdout,"%s\n", wsort[i]);
1242                }
1243             }
1244          }
1245          if (isrt) free(isrt); isrt = NULL;
1246          for (i=0; i<nglob; ++i) if (wsort[i]) free(wsort[i]);
1247          free(wsort); wsort = NULL;
1248          SUMA_ifree(wild_list);
1249          MCW_free_wildcards( nglob , wglob ) ;
1250          exit(0);
1251       } else {
1252          ERROR_message("Failed to sort");
1253          SUMA_ifree(wild_list);
1254          MCW_free_wildcards( nglob , wglob ) ;
1255          exit(1);
1256       }
1257    }
1258 
1259    if ((fnamev || fname || text || prog || popt || all_popts)) {
1260       if (!strcmp(word,"Ma fich haga") && spx_tar == TFORM_NOT_SET) {
1261          ERROR_message(
1262             "I'd search the world over for you, if only you gave me -word");
1263          return 1;
1264       }
1265       if (fnamev) {
1266          fprintf(stderr,"Have %d files\n", fnamev->num);
1267          if (spx_tar != TFORM_NOT_SET) {
1268             for (i=0; i<fnamev->num; ++i) {
1269                char *sso=SUMA_Sphinx_File_Edit(fnamev->ar[i], spx_tar, 0);
1270                if (sso) {
1271                   fprintf(stdout,"%s", sso); free(sso); sso = NULL;
1272                } else {
1273                   ERROR_message("Failed to sphinx edit string in %s",
1274                                  fnamev->ar[i]);
1275                   return 1;
1276                }
1277             }
1278             return 0;
1279          } else {
1280             sar = approx_str_sort_Ntfile(
1281                         fnamev->ar, fnamev->num, word, ci, &ws_score,
1282                                NULL,
1283                                &D, 0, '\0');
1284             ws = sar->ar; N_ws = sar->num;
1285          }
1286       } else if (fname) {
1287          if (strcmp(fname,stdinflag)) {
1288             if (spx_tar != TFORM_NOT_SET) {
1289                char *sso=NULL;
1290                if (!pname) {
1291                   sso = SUMA_Sphinx_File_Edit(fname, spx_tar, 0);
1292                } else {
1293                   sso = AFNI_suck_file(fname);
1294                   sso = sphelp(pname, &sso, spx_tar, 0);
1295                }
1296                if (sso) {
1297                   fprintf(stdout,"%s", sso); free(sso); sso = NULL;
1298                } else {
1299                   ERROR_message("Failed to sphinx edit string in %s", fname);
1300                   return 1;
1301                }
1302                return 0;
1303             } else {
1304                ws = approx_str_sort_tfile(fname, 0, &N_ws, word,
1305                          ci, &ws_score,
1306                          NULL, &D, 1, '\0');
1307             }
1308          } else {
1309             char *stdtext=NULL;
1310             if (!(stdtext = text_from_stdin(&N_ws))) {
1311                ERROR_message("Failed to read from stdin");
1312                return 0;
1313             }
1314             if (spx_tar != TFORM_NOT_SET) {
1315                if (!pname) {
1316                   stdtext = SUMA_Sphinx_String_Edit(&stdtext, spx_tar, 0);
1317                } else {
1318                   stdtext = sphelp(pname, &stdtext, spx_tar, 0);
1319                }
1320                if (stdtext) {
1321                   fprintf(stdout,"%s", stdtext);
1322                   free(stdtext); stdtext=NULL;
1323                }
1324                return 0;
1325             } else {
1326                ws = approx_str_sort_text(stdtext, &N_ws, word,
1327                                ci, &ws_score,
1328                                NULL, &D, '\0');
1329                free(stdtext); stdtext=NULL;
1330             }
1331          }
1332       } else if (text) {
1333          ws = approx_str_sort_text(text, &N_ws, word,
1334                             ci, &ws_score,
1335                             NULL, &D, '\0');
1336       } else if (prog) {
1337          ws = approx_str_sort_phelp(prog, 0, &N_ws, word,
1338                             ci, &ws_score,
1339                             NULL, &D, 1, '\\');
1340       } else if (popt) {
1341          suggest_best_prog_option(popt, word);
1342          return 0;
1343       } else if (all_popts) {
1344          /* one can also use print_prog_options(all_popts); return(0); */
1345          ws = approx_str_sort_all_popts(all_popts, 0, &N_ws,
1346                             ci, &ws_score,
1347                             NULL, &D, uopts, 1, '\\');
1348       }
1349 
1350       i_unique_score = 0; last_score = -1.0; new_score=1;
1351       for (i=0; i<N_ws; ++i) {
1352          if (ws[i]) {
1353             new_score=0;
1354             if (ws_score[i] != last_score) {
1355                last_score = ws_score[i];
1356                new_score=1;
1357                ++i_unique_score;
1358             }
1359             if (i<max_hits || i_unique_score<=min_different_hits) {
1360                if (!unq_only || new_score) {
1361                   switch(show_score) {
1362                      case 0:
1363                         fprintf(stdout,"   ");
1364                         if ((D+i)->srcfile &&
1365                             strncmp((D+i)->srcfile,APSEARCH_TMP_PREF,
1366                                              strlen(APSEARCH_TMP_PREF)))
1367                            fprintf(stdout,"(%s) ",(D+i)->srcfile);
1368                         break;
1369                      case 1:
1370                         fprintf(stdout,"%03f ",
1371                                     ws_score[i]);
1372                         if ((D+i)->srcfile &&
1373                             strncmp((D+i)->srcfile,APSEARCH_TMP_PREF,
1374                                              strlen(APSEARCH_TMP_PREF)))
1375                            fprintf(stdout,"(%s) ",(D+i)->srcfile);
1376                         break;
1377                      case 2:
1378                         fprintf(stdout,"%s ",
1379                            approx_string_diff_info(D+i, NULL));
1380                         break;
1381                      default:
1382                         ERROR_exit("Bad show_score value");
1383                         break;
1384                   }
1385                   fprintf(stdout,"%s\n", ws[i]);
1386                }
1387             }
1388             free(ws[i]); ws[i]=NULL;
1389          }
1390       } free(ws);  if (ws_score) free(ws_score); ws_score=NULL;
1391       if (D) free(D); D=NULL;
1392    }
1393 
1394    if (fnamev) DESTROY_SARR(fnamev); fnamev=NULL;
1395    return 0;
1396 }
1397