1 #include "mrilib.h"
2 #include "thd.h"
3 #include "suma_objs.h" /* 21 Apr 2020 */
4 /*------------------------------------------------------------*/
5
6 static int einit = 0 ;
7 static THD_string_array *elist = NULL ;
8
get_elist(void)9 THD_string_array *get_elist(void) {
10 if( !einit ){
11 einit = 1 ;
12 elist = THD_getpathprogs(NULL, 1) ;
13 }
14 return(elist);
15 }
16
17 /* local prototypes */
18 static int local_clean_zsh_punct(char * str);
19
20 /*----------------------------------------------------------------------------*/
21 /*! Find an executable in the PATH by its name, if it exists.
22 If not, NULL is returned. If it exists, a pointer to static storage
23 is returned (i.e., don't free() this pointer!).
24 ------------------------------------------------------------------------------*/
25
THD_find_executable(char * ename)26 char * THD_find_executable( char *ename )
27 {
28 char *etr , *str ;
29 int ii ;
30
31 ENTRY("THD_find_executable") ;
32
33 if( !einit ){ einit = 1 ; elist = THD_getpathprogs(NULL, 1) ; }
34 if( elist == NULL ) RETURN(NULL) ;
35
36 etr = THD_trailname( ename , 0 ) ;
37
38 for( ii=0 ; ii < elist->num ; ii++ ){
39 str = THD_trailname( elist->ar[ii] , 0 ) ;
40 if( strcmp(str,etr) == 0 ) RETURN(elist->ar[ii]) ;
41 }
42
43 RETURN(NULL) ;
44 }
45
46 /*----------------------------------------------------------------------------*/
47 /*! Find afni's bin directory if it exists.
48 If not, NULL is returned. If it exists, a pointer to the path is returned.
49 Do free it with free()
50 ------------------------------------------------------------------------------*/
THD_abindir(byte withslash)51 char * THD_abindir (byte withslash)
52 {
53 char *afr = NULL, *af=NULL;
54 int nn = 0, N_afni=strlen("afni");
55 THD_string_array *elist=NULL;
56
57 if (!(elist = get_elist()) ||
58 !(af = THD_find_executable("afni"))) {
59 ERROR_message("Could not find afni, we're doomed daddy!");
60 RETURN(NULL);
61 }
62
63 /* remove afni from the end to get the path */
64 nn = strlen(af);
65 if (strcmp(af+nn-N_afni,"afni")) {
66 ERROR_message("This should not be (%s)!", af+nn-N_afni);
67 RETURN(NULL);
68 }
69
70 afr = strdup(af);
71 afr[strlen(af)-N_afni]='\0';
72
73 /* remove slash */
74 while ( (nn=strlen(afr)-1) && afr[nn] == '/')
75 afr[nn] = '\0';
76
77 if (withslash) {
78 nn=strlen(afr);
79 afr[nn] = '/'; afr[nn+1]='\0';
80 }
81 return(afr);
82 }
83
find_readme_file(char * str)84 char *find_readme_file(char *str)
85 {
86 char **ws=NULL, *sout=NULL;
87 int N_ws=0, i;
88
89 ENTRY("find_readme_file");
90 if (!(ws = approx_str_sort_readmes(str, &N_ws))) {
91 ERROR_message("Could not find README files.\n"
92 "They should have been in directory %s on your machine\n",
93 THD_abindir(0));
94 RETURN(NULL);
95 }
96
97 if (strcasestr(ws[0],str)) sout = strdup(ws[0]);
98 for (i=0; i<N_ws; ++i) if (ws[i]) free(ws[i]);
99 free(ws);
100 RETURN(sout);
101 }
102
THD_facedir(byte withslash)103 char * THD_facedir(byte withslash)
104 {
105 char *ss=NULL, *so=NULL;
106
107 if (!(ss = THD_abindir(1))) return(NULL);
108 so = (char *)calloc(strlen(ss)+50, sizeof(char));
109 strcat(so,ss);
110 strcat(so,"funstuff/");
111 free(ss); ss = NULL;
112 if( !THD_is_directory(so) ) {
113 free(so); free(ss); return(NULL);
114 }
115 if (!withslash) so[strlen(so)-1]='\0';
116 return(so);
117 }
118
119 /*----------------------------------------------------------------------------*/
120 /*! Find a regular file in the PATH by its name, if it exists.
121 Does not include directories.
122 If not, NULL is returned.
123 If it exists, a pointer to malloc-ed storage is returned
124 (e.g., free it when you are done).
125
126 thispath is a user supplied ':' delimited path string of the form
127 somewhere/here:/over/there . If null then path is taken from
128 the env PATH
129 ------------------------------------------------------------------------------*/
130
THD_find_regular_file(char * ename,char * thispath)131 char * THD_find_regular_file( char *ename, char *thispath )
132 {
133 char *fullname , *str ;
134 int id , ii ;
135 char *epath;
136 ENTRY("THD_find_regular_file") ;
137
138 if (!thispath) epath = my_getenv( "PATH" ) ;
139 else epath = thispath;
140
141 if( epath != NULL ){
142 int epos =0 , ll = strlen(epath) ;
143 char *elocal ;
144 char dirname[THD_MAX_NAME] ;
145
146 /* copy path list into local memory */
147
148 elocal = (char *) malloc( sizeof(char) * (ll+2) ) ;
149 strcpy( elocal , epath ) ; elocal[ll] = ' ' ; elocal[ll+1] = '\0' ;
150 fullname = (char *) malloc( sizeof(char) * THD_MAX_NAME);
151
152 /* replace colons with blanks */
153 for( ii=0 ; ii < ll ; ii++ )
154 if( elocal[ii] == ':' ) elocal[ii] = ' ' ;
155
156 /* extract blank delimited strings,
157 use as directory names to get timeseries files */
158
159 do{
160 ii = sscanf( elocal+epos , "%s%n" , dirname , &id ) ;
161 if( ii < 1 ) break ; /* no read ==> end of work */
162 epos += id ; /* epos = char after last one scanned */
163
164 ii = strlen(dirname) ; /* make sure name has */
165 if( dirname[ii-1] != '/' ){ /* a trailing '/' on it */
166 dirname[ii] = '/' ; dirname[ii+1] = '\0' ;
167 }
168 if( !THD_is_directory(dirname) ) continue ; /* 25 Feb 2002 */
169
170 sprintf(fullname, "%s%s",dirname,ename);
171 if( THD_is_file(fullname) ) {
172 /* found the file in the current directory */
173 free(elocal) ;
174 RETURN(fullname);
175 }
176
177 } while( epos < ll ) ; /* scan until 'epos' is after end of epath */
178
179 free(elocal) ; free(fullname);
180 }
181
182 RETURN(NULL) ;
183 }
184
185 /*
186 Find a file somewhere afniish
187 Do not free returned pointer
188 Empty string means nothing was found
189 if altpath is not NULL, and nimlname does not
190 have an absolute path, altpath is considere before diving into the
191 default locations
192 */
find_afni_file(char * nimlname,int niname,char * altpath)193 char *find_afni_file(char * nimlname, int niname, char *altpath)
194 {
195 static char filestr[5][1024];
196 static int icall = -1;
197 static char *envlist[]={"AFNI_PLUGINPATH",
198 "AFNI_PLUGIN_PATH",
199 "AFNI_TTAPATH",
200 "AFNI_TTATLAS_DATASET", NULL };
201 char namebuf[1024];
202 char *fstr, *epath, *abpath=NULL;
203 int kk = 0;
204
205 ENTRY("find_afni_file");
206
207 ++icall; if (icall > 4) icall = 0;
208 filestr[icall][0]='\0';
209 namebuf[0] = '\0';
210
211 if(wami_verb() > 1)
212 INFO_message("trying to open %s \n",nimlname);
213 snprintf(namebuf, 1000*sizeof(char),
214 "%s", nimlname);
215 if (THD_is_file(namebuf)) goto GOTIT;
216
217 if(wami_verb() > 1)
218 INFO_message("%s not found, trying different paths, if no path is set.\n"
219 ,nimlname);
220
221 if (nimlname[0] == '/') { /* not found and have abs path, get out */
222 RETURN(filestr[icall]);
223 }
224
225 if (altpath) {
226 fstr = THD_find_regular_file(nimlname, altpath);
227 snprintf(namebuf, 1000*sizeof(char), "%s", fstr);
228 if (THD_is_file(namebuf)) goto GOTIT;
229 }
230
231 /* okay that didn't work, try the AFNI plugin directory */
232 kk = 0;
233 while (envlist[kk]) {
234 namebuf[0]='\0';
235 epath = getenv(envlist[kk]) ;
236 if( epath == NULL ) epath = getenv(envlist[kk]) ;
237 if( epath != NULL ) {
238 if(wami_verb() > 1)
239 INFO_message("trying to open %s in %s directory %s\n",
240 nimlname, envlist[kk], epath);
241 fstr = THD_find_regular_file(nimlname, epath);
242 if(fstr) {
243 if(wami_verb() > 1)
244 INFO_message("found %s in %s", nimlname, fstr);
245 snprintf(namebuf, 1000*sizeof(char), "%s", fstr);
246 if (THD_is_file(namebuf)) goto GOTIT;
247 if(wami_verb() > 1)
248 INFO_message("failed to open %s as %s\n",
249 nimlname, namebuf);
250 }
251 }
252 ++kk;
253 }
254
255 /* Look in AFNI data directory */
256 namebuf[0]='\0';
257 epath = THD_datadir(1);
258 if( epath[0] == '\0' ) RETURN(filestr[icall]) ; /* should not happen */
259 if(wami_verb() > 1)
260 INFO_message("trying to open %s in path as regular file\n %s\n",
261 nimlname, epath);
262
263 fstr = THD_find_regular_file(nimlname, epath);
264 if(fstr) {
265 if(wami_verb() > 1)
266 INFO_message("found %s in %s", nimlname, fstr);
267 snprintf(namebuf, 1000*sizeof(char), "%s", fstr);
268 if (THD_is_file(namebuf)) goto GOTIT;
269 if(wami_verb() > 1)
270 INFO_message("failed to open %s as %s\n",
271 nimlname, namebuf);
272 }
273
274 /* still can't find it. Maybe it's in the afni path */
275 namebuf[0]='\0';
276 abpath = THD_abindir(1);
277 if( abpath == NULL ) RETURN(filestr[icall]) ; /* bad-who has no afni?*/
278 if(wami_verb() > 1)
279 INFO_message("trying to open %s in path as regular file\n %s\n",
280 nimlname, abpath);
281
282 fstr = THD_find_regular_file(nimlname, abpath);
283 if(fstr) {
284 if(wami_verb() > 1)
285 INFO_message("found %s in %s", nimlname, fstr);
286 snprintf(namebuf, 1000*sizeof(char), "%s", fstr);
287 if (THD_is_file(namebuf)) goto GOTIT;
288 if(wami_verb() > 1)
289 INFO_message("failed to open %s as %s\n",
290 nimlname, namebuf);
291 }
292
293 if (abpath) free(abpath);
294 RETURN(filestr[icall]);
295
296 GOTIT:
297 if (niname) {
298 snprintf(filestr[icall], 1000*sizeof(char),
299 "file:%s", namebuf);
300 } else {
301 snprintf(filestr[icall], 1000*sizeof(char),
302 "%s", namebuf);
303 }
304
305 if (abpath) free(abpath);
306 RETURN(filestr[icall]);
307 }
308
309 /*===========================================================================*/
310 /*! Return a list of all executable files in the PATH and the dlist. */
311
THD_getpathprogs(THD_string_array * dlist,char exec_flag)312 THD_string_array * THD_getpathprogs( THD_string_array *dlist, char exec_flag )
313 {
314 int id , ii , ndir ;
315 char *epath , *eee ;
316 THD_string_array *elist , *tlist , *qlist ;
317
318 ENTRY("THD_getpathprogs") ;
319
320 /*----- sanity check and initialize -----*/
321
322 epath = my_getenv( "PATH" ) ;
323 ndir = (dlist != NULL) ? dlist->num : 0 ;
324
325 if( ndir == 0 && epath == NULL ) RETURN(NULL) ;
326
327 INIT_SARR(elist) ;
328 INIT_SARR(qlist) ; /* 04 Feb 2002: list of searched directories */
329
330 /*----- for each input directory, find all files / executable files -----*/
331
332 for( id=0 ; id < ndir ; id++ ){
333
334 tlist = THD_get_all_files( dlist->ar[id], exec_flag ) ;
335 if( tlist == NULL ) continue ;
336
337 for( ii=0 ; ii < tlist->num ; ii++ ) /* copy names to output array */
338 ADDTO_SARR( elist , tlist->ar[ii] ) ;
339
340 ADDTO_SARR(qlist,dlist->ar[id]) ; /* 04 Feb 2002 */
341
342 DESTROY_SARR(tlist) ;
343 }
344
345 /*----- also do directories in environment path, if any -----*/
346
347 if( epath != NULL ){
348 int epos =0 , ll = strlen(epath) ;
349 char *elocal ;
350 char ename[THD_MAX_NAME] ;
351
352 /* copy path list into local memory */
353
354 elocal = (char *) malloc( sizeof(char) * (ll+2) ) ;
355 strcpy( elocal , epath ) ; elocal[ll] = ' ' ; elocal[ll+1] = '\0' ;
356
357 /* replace colons with blanks */
358
359 for( ii=0 ; ii < ll ; ii++ )
360 if( elocal[ii] == ':' ) elocal[ii] = ' ' ;
361
362 /* extract blank delimited strings,
363 use as directory names to get timeseries files */
364
365 do{
366 ii = sscanf( elocal+epos , "%s%n" , ename , &id ) ;
367 if( ii < 1 ) break ; /* no read ==> end of work */
368 epos += id ; /* epos = char after last one scanned */
369
370 ii = strlen(ename) ; /* make sure name has */
371 if( ename[ii-1] != '/' ){ /* a trailing '/' on it */
372 ename[ii] = '/' ; ename[ii+1] = '\0' ;
373 }
374 if( !THD_is_directory(ename) ) continue ; /* 25 Feb 2002 */
375
376 /* 04 Feb 2002: check if we already searched this directory */
377
378 for( ii=0 ; ii < qlist->num ; ii++ )
379 if( THD_equiv_files(qlist->ar[ii],ename) ) break ;
380 if( ii < qlist->num ) continue ; /* skip this directory */
381 ADDTO_SARR(qlist,ename) ;
382
383 /* read this directory */
384 tlist = THD_get_all_files( ename, exec_flag ) ;
385 if( tlist != NULL ){
386 for( ii=0 ; ii < tlist->num ; ii++ ) /* move names to output */
387 ADDTO_SARR( elist , tlist->ar[ii] ) ;
388 DESTROY_SARR(tlist) ;
389 }
390
391 } while( epos < ll ) ; /* scan until 'epos' is after end of epath */
392
393 free(elocal) ;
394 }
395
396 if( SARR_NUM(elist) == 0 ) DESTROY_SARR(elist) ;
397
398 DESTROY_SARR(qlist) ; /* 04 Feb 2002 */
399 RETURN(elist) ;
400 }
401
402 /*--------------------------------------------------*/
403 /*! Read all regular files or executable filenames from a directory. */
404
THD_get_all_files(char * dname,char exec_flag)405 THD_string_array * THD_get_all_files( char *dname, char exec_flag )
406 {
407 int ir , ll , ii ;
408 char *fname , *tname ;
409 float *far ;
410 THD_string_array *outar, *alist, *rlist ;
411
412 ENTRY("THD_get_all_files") ;
413
414 /*----- sanity check and initialize -----*/
415
416 if( dname == NULL || strlen(dname) == 0 ) RETURN(NULL) ;
417
418 /*----- find all regular files -----*/
419
420 if(PRINT_TRACING){
421 char str[256];sprintf(str,"call THD_get_all_filenames(%s)",dname); STATUS(str);
422 }
423 alist = THD_get_all_filenames( dname ) ;
424
425 if( alist == NULL ) RETURN(NULL) ;
426 STATUS("call THD_extract_regular_files") ;
427 rlist = THD_extract_regular_files( alist ) ;
428 DESTROY_SARR( alist ) ;
429 if( rlist == NULL ) RETURN(NULL) ;
430
431 /* return regular list if not looking for executables */
432 if(!exec_flag) RETURN(rlist);
433
434 INIT_SARR( outar ) ;
435
436 /* 04 Feb 2002: don't include .so libraries, etc. */
437
438 for( ir=0 ; ir < rlist->num ; ir++ ){
439 fname = rlist->ar[ir] ;
440 if( THD_is_executable(fname) &&
441 !strstr(fname,".so") &&
442 !strstr(fname,".la") ) {
443 ADDTO_SARR(outar,fname) ;
444 }
445 }
446
447 DESTROY_SARR(rlist) ;
448
449 if( SARR_NUM(outar) == 0 ) DESTROY_SARR(outar) ;
450
451 RETURN( outar );
452 }
453
454 /*! Get all executables in directory where afni resides */
THD_get_all_afni_executables(void)455 THD_string_array * THD_get_all_afni_executables(void )
456 {
457 THD_string_array *outar=NULL, *elist=NULL;
458 char *af=NULL, *etr=NULL;
459 int N_af, iaf=0, ii=0, smode, *isrt=NULL;
460 char scomm[256]={""};
461
462 ENTRY("THD_get_all_afni_executables");
463
464 if (!(elist = get_elist()) ||
465 !(af = THD_abindir(1)) ) {
466 ERROR_message("Could not find afni, we're doomed daddy!");
467 RETURN(outar);
468 }
469
470 N_af = strlen(af);
471
472 /* Now get all executables under af */
473 INIT_SARR( outar );
474 for (ii=0, iaf=0; ii<elist->num ; ii++ ){
475 smode = storage_mode_from_filename(elist->ar[ii]);
476 etr = THD_trailname( elist->ar[ii] , 0 ) ;
477 if (
478 !THD_is_directory(elist->ar[ii]) &&
479 !strncmp(af, elist->ar[ii], N_af) &&
480 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".xml") &&
481 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".html") &&
482 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".jpg") &&
483 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".a") &&
484 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".c") &&
485 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".h") &&
486 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".f") &&
487 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".xbm") &&
488 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".tex") &&
489 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".lib") &&
490 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".dylib") &&
491 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".o") &&
492 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".so") &&
493 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".la") &&
494 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".txt") &&
495 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".R") &&
496 !(STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".py") &&
497 /* add a couple of python types to skip 20 Jul 2012 [rickr] */
498 (!strncmp(etr,"lib_",4) || !strncmp(etr,"gui_",4) ||
499 !strncmp(etr,"ui_",3)) ) &&
500 (smode <= STORAGE_UNDEFINED || smode >= LAST_STORAGE_MODE) &&
501 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".sumarc") &&
502 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".afnirc")&&
503 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], "lib.py") &&
504 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".pyc") &&
505 !STRING_HAS_SUFFIX_CASE(elist->ar[ii], ".Xdefaults") &&
506 /* skip README files, processed as scripts 20 Jul 2012 [rickr]
507 of note: README.atlas_building starts with the line:
508 README.atlas_building
509 such process recursion is not good for the system... */
510 strncmp(etr, "README.", 7)
511 ) {
512 ADDTO_SARR( outar , elist->ar[ii] ) ; ++iaf;
513 /* fprintf(stderr," %d- %s\n", iaf, etr); */
514 } else {
515 /* fprintf(stderr," skip %s (%s) %d--%d--%d isd %d\n",
516 elist->ar[ii], af, STORAGE_UNDEFINED, smode, LAST_STORAGE_MODE,
517 THD_is_directory(elist->ar[ii])); */
518 }
519 }
520
521 qsort(outar->ar, outar->num, sizeof(char*),
522 (int(*) (const void *, const void *))compare_string);
523
524 if( SARR_NUM(outar) == 0 ) DESTROY_SARR(outar) ;
525
526 if (af) free(af); af = NULL;
527
528 RETURN( outar );
529 }
530
531 /*! Get all readme files in directory where afni resides */
THD_get_all_afni_readmes(void)532 THD_string_array * THD_get_all_afni_readmes(void )
533 {
534 THD_string_array *outar=NULL, *elist=NULL;
535 char *af=NULL, *etr=NULL, *key="README.";
536 int N_af, N_afni=strlen("afni"), iaf=0, ii=0, *isrt=NULL, N_key=0;
537 char scomm[256]={""};
538
539 ENTRY("THD_get_all_afni_readmes");
540
541 if (!(elist = get_elist()) ||
542 !(af = THD_abindir(1))) {
543 ERROR_message("Could not find afni, we're doomed daddy!");
544 RETURN(outar);
545 }
546
547 /* remove afni from the end to get the path */
548 N_af = strlen(af);
549
550 elist = THD_get_all_files(af,'\0');
551
552 /* Now get all readmes under af */
553 N_key = strlen(key);
554 INIT_SARR( outar );
555 for (ii=0, iaf=0; ii<elist->num ; ii++ ){
556 etr = THD_trailname( elist->ar[ii] , 0 ) ;
557 if (!THD_is_directory(elist->ar[ii]) &&
558 !strncmp(af, elist->ar[ii], N_af) &&
559 !strncmp(key, etr, N_key)
560 ) {
561 ADDTO_SARR( outar , elist->ar[ii] ) ; ++iaf;
562 /* fprintf(stderr," %d- %s (%s)\n", iaf, elist->ar[ii], etr); */
563 } else {
564 /* fprintf(stderr," skip %s (%s)\n", elist->ar[ii], af); */
565 }
566 }
567
568 qsort(outar->ar, outar->num, sizeof(char*),
569 (int(*) (const void *, const void *))compare_string);
570
571 if( SARR_NUM(outar) == 0 ) DESTROY_SARR(outar) ;
572 if (af) free(af); af = NULL;
573 RETURN( outar );
574 }
575
576 /*! get all 3D datasets in directory where afni resides */
THD_get_all_afni_dsets(void)577 THD_string_array * THD_get_all_afni_dsets(void )
578 {
579 THD_string_array *outar=NULL, *elist=NULL;
580 char *af=NULL, *etr=NULL;
581 int N_af, N_afni=strlen("afni"), iaf=0, ii=0, smode, *isrt=NULL;
582 char scomm[256]={""};
583
584 ENTRY("THD_get_all_afni_dsets");
585
586 if (!(elist = get_elist()) ||
587 !(af = THD_abindir(1))) {
588 ERROR_message("Could not find afni, we're doomed daddy!");
589 RETURN(outar);
590 }
591
592 N_af = strlen(af);
593
594 elist = THD_get_all_files(af,'\0');
595
596 /* Now get all dsets under af */
597 INIT_SARR( outar );
598 for (ii=0, iaf=0; ii<elist->num ; ii++ ){
599 smode = storage_mode_from_filename(elist->ar[ii]);
600 etr = THD_trailname( elist->ar[ii] , 0 ) ;
601 if (
602 !THD_is_directory(elist->ar[ii]) &&
603 !strncmp(af, elist->ar[ii], N_af) &&
604 (smode > STORAGE_UNDEFINED && smode <= LAST_STORAGE_MODE) &&
605 (smode != STORAGE_BY_BRICK || /* don't want the .BRICK, just .HEAD */
606 STRING_HAS_SUFFIX(elist->ar[ii], ".HEAD")) &&
607 (smode != STORAGE_BY_NIFTI || /* don't want the .img */
608 !STRING_HAS_SUFFIX(elist->ar[ii], ".img")) &&
609 strcmp(etr,"AFNI_atlas_spaces.niml")
610 ) {
611 ADDTO_SARR( outar , elist->ar[ii] ) ; ++iaf;
612 /*fprintf(stderr," %d- %s smode %d[%d]%d\n", iaf, etr,
613 STORAGE_UNDEFINED, smode, LAST_STORAGE_MODE); */
614 } else {
615 /*fprintf(stderr," skip %s (%s) smode %d[%d]%d\n",
616 elist->ar[ii], af, STORAGE_UNDEFINED, smode, LAST_STORAGE_MODE); */
617 }
618 }
619
620 qsort(outar->ar, outar->num, sizeof(char*),
621 (int(*) (const void *, const void *))compare_string);
622
623 if( SARR_NUM(outar) == 0 ) DESTROY_SARR(outar) ;
624 if (af) free(af); af = NULL;
625 RETURN( outar );
626 }
627
list_afni_files(int type,int withpath,int withnum)628 int list_afni_files(int type, int withpath, int withnum)
629 {
630 int nprogs=0, ii=0;
631 char *etr=NULL, s[12];
632 THD_string_array *progs=NULL;
633
634 switch (type) {
635 case 0:
636 if (!(progs = THD_get_all_afni_executables())) {
637 ERROR_message(
638 "Cannot get list of programs from your afni bin directory %s",
639 THD_abindir(1));
640 RETURN(0);
641 }
642 break;
643 case 1:
644 if (!(progs = THD_get_all_afni_readmes())) {
645 ERROR_message(
646 "Cannot get list of readmes from your afni bin directory %s",
647 THD_abindir(1));
648 RETURN(0);
649 }
650 break;
651 case 2:
652 if (!(progs = THD_get_all_afni_dsets())) {
653 ERROR_message(
654 "Cannot get list of dsets from your afni bin directory %s",
655 THD_abindir(1));
656 RETURN(0);
657 }
658 break;
659 default:
660 ERROR_message("Whatchyoutalkinboutwillis?");
661 RETURN(0);
662 break;
663 }
664
665 for (ii=0; ii<progs->num ; ii++ ){
666 if (withpath) etr = progs->ar[ii];
667 else etr = THD_trailname( progs->ar[ii] , 0 ) ;
668 if (withnum) {
669 sprintf(s,"%d", ii);
670 fprintf(stdout," %3s. %s\n", s, etr);
671 } else {
672 fprintf(stdout,"%s\n", etr);
673 }
674 }
675 nprogs = progs->num;
676
677 DESTROY_SARR(progs);
678
679 return(nprogs);
680 }
681
list_afni_programs(int withpath,int withnum)682 int list_afni_programs(int withpath, int withnum) {
683 return(list_afni_files(0, withpath, withnum));
684 }
685
list_afni_readmes(int withpath,int withnum)686 int list_afni_readmes(int withpath, int withnum) {
687 return(list_afni_files(1, withpath, withnum));
688 }
689
list_afni_dsets(int withpath,int withnum)690 int list_afni_dsets(int withpath, int withnum) {
691 return(list_afni_files(2, withpath, withnum));
692 }
693
694 /* Include file that has C struct containing programs and all their options */
695 typedef struct {
696 char *program;
697 char *options;
698 int N_options;
699 } PROG_OPTS;
700
701 #include "prog_opts.c"
702
form_C_progopt_string_from_struct(PROG_OPTS po)703 char *form_C_progopt_string_from_struct(PROG_OPTS po)
704 {
705 char *sout=NULL, sbuf[128];
706 int maxch=0, i, jj, N_opts=0;
707
708 if (!po.program) return(NULL);
709
710 maxch = strlen(po.program)+strlen(po.options)+100;
711 if (!(sout = (char *)calloc((maxch+1), sizeof(char)))) {
712 ERROR_message("Failed to allocate for %d chars!", maxch+1);
713 return(NULL);
714 }
715
716 sout[0]='\0';
717 strncat(sout,"{ \"", maxch-1);
718 strncat(sout,po.program, maxch-strlen(sout)-1);
719 strncat(sout,"\", \"", maxch-strlen(sout)-1);
720 strncat(sout,po.options, maxch-strlen(sout)-1);
721 sprintf(sbuf,"\", %d", N_opts); strncat(sout,sbuf, maxch-strlen(sout)-1);
722
723 strncat(sout,"}", maxch-strlen(sout)-1);
724 if (strlen(sout)>=maxch-1) {
725 ERROR_message("Truncated complete string possible");
726 free(sout); sout=NULL;
727 return(sout);
728 }
729
730 return(sout);
731
732 }
733
form_C_progopt_string(char * prog,char ** ws,int N_ws)734 char *form_C_progopt_string(char *prog, char **ws, int N_ws)
735 {
736 char *sout=NULL, sbuf[128], *wsptr;
737 int maxch=0, i, jj, N_opts=0;
738 NI_str_array *nisa=NULL;
739
740 if (!prog || !ws) {
741 return(NULL);
742 }
743
744 maxch = 256;
745 for (i=0; i<N_ws; ++i) {
746 if (ws[i]) {
747 maxch+=strlen(ws[i])+10;
748 if (strlen(ws[i]) > 127) {
749 WARNING_message("Truncating atrocious option %s\n", ws[i]);
750 wsptr = ws[i]+127;
751 *wsptr = '\0';
752 }
753 }
754 }
755 if (!(sout = (char *)calloc((maxch+1), sizeof(char)))) {
756 ERROR_message("Failed to allocate for %d chars!", maxch+1);
757 return(NULL);
758 }
759 sout[0]='\0';
760 strncat(sout,"{ \"", maxch-1);
761 strncat(sout,prog, maxch-strlen(sout)-1);
762 strncat(sout,"\", \"", maxch-strlen(sout)-1);
763
764 N_opts = 0;
765 for (i=0; i<N_ws; ++i) {
766 if (ws[i] && (nisa = NI_strict_decode_string_list(ws[i] ,"/"))) {
767 for (jj=0; jj<nisa->num; ++jj) {
768 if (ws[i][0]=='-' && nisa->str[jj][0] != '-') {
769 snprintf(sbuf,127,"-%s; ", nisa->str[jj]);
770 } else {
771 snprintf(sbuf,127,"%s; ", nisa->str[jj]);
772 }
773 ++N_opts;
774 strncat(sout,sbuf, maxch-strlen(sout)-1);
775 NI_free(nisa->str[jj]);
776 }
777 if (nisa->str) NI_free(nisa->str);
778 NI_free(nisa); nisa=NULL;
779 }
780 }
781 sprintf(sbuf,"\", %d", N_opts); strncat(sout,sbuf, maxch-strlen(sout)-1);
782
783
784 strncat(sout,"}", maxch-strlen(sout)-1);
785 if (strlen(sout)>=maxch-1) {
786 ERROR_message("Truncated complete string possible");
787 free(sout); sout=NULL;
788 return(sout);
789 }
790
791 return(sout);
792 }
793
794 /*
795 Generate C array that lists all afni programs and their options
796
797 There is a most unholy relationship between this function and
798 the include line: #include "prog_opts.c"
799
800 This function is for internal machinations having to do with
801 automatic generation of help web pages. It is not for mass
802 consumption.
803
804 \param fout (FILE *): Pointer to output stream
805 \param verb (int): verbosity
806 \param thisprog (char *): If not NULL, then update the list of options for
807 program thisprog. Existing other programs option
808 are preserved (appendmode is forced to 1)
809 If NULL, then do this for all programs recognized
810 by THD_get_all_afni_executables()
811 \param appendmode (int): 1 --> Keep existing information about programs not
812 in THD_get_all_afni_executables() or other
813 than thisprog
814 0 --> Just output information on programs from
815 THD_get_all_afni_executables(). This is only
816 allowed when thisprog == 0
817 */
progopt_C_array(FILE * fout,int verb,char * thisprog,int appendmode)818 int progopt_C_array(FILE *fout, int verb, char *thisprog, int appendmode)
819 {
820 char **ws=NULL, *sout=NULL;
821 float *ws_score=NULL;
822 int N_ws=0, ii = 0, jj = 0, found=0;
823 THD_string_array *progs=NULL;
824
825 ENTRY("progopt_C_array");
826
827 if (!fout) fout = stdout;
828
829 if (thisprog) {
830 if (!appendmode) {
831 WARNING_message("Forcing append mode for one program");
832 appendmode = 1;
833 }
834 INIT_SARR( progs );
835 ADDTO_SARR( progs, thisprog );
836 } else {
837 if (!(progs = THD_get_all_afni_executables()) || progs->num < 1) {
838 ERROR_message("Could not get list of executables");
839 RETURN(1);
840 }
841 }
842
843 fprintf(fout,
844 "#ifndef PROG_OPTS_INCLUDED\n"
845 "#define PROG_OPTS_INCLUDED\n"
846 "\n"
847 "/* \n"
848 " *********** Manual Edits Can Get CLOBBERED! ***********\n"
849 " *************** File created automatically ******************\n"
850 "\n"
851 " This file was initially created by function progopt_C_array(), \n"
852 " via program apsearch with:\n"
853 " apsearch -C_all_prog_opt_array > prog_opts.c\n\n"
854 " To update entry for just one program (PROG) best use:\n"
855 " apsearch -C_all_prog_opt_array PROG > prog_opts.c\n\n"
856 "\n"
857 "You'll need to also touch thd_getpathprogs.c before rebuilding \n"
858 "libmri.a, etc.\n"
859 "*/\n\n"
860 "#if 0\n"
861 "static PROG_OPTS poptslist[] = {\n"
862 " {NULL, NULL, 0}\n"
863 "}\n"
864 "#else\n"
865 "static PROG_OPTS poptslist[] = {\n");
866
867 if (appendmode) { /* Keep programs not in list being sent*/
868 while (poptslist[jj].program != NULL) {
869 found = 0;
870 for (ii=0; ii<progs->num && !found; ++ii) {
871 if (!strcmp(THD_trailname(progs->ar[ii],0), poptslist[jj].program)) {
872 found = 1;
873 }
874 }
875 if (!found) { /* add it */
876 if ((sout = form_C_progopt_string_from_struct(poptslist[jj]))){
877 fprintf(fout, "%s,\n", sout);
878 free(sout); sout = NULL;
879 }
880 }
881 ++jj;
882 }
883 }
884
885 for (ii=0; ii<progs->num; ++ii) {
886 if (verb) fprintf(stderr,"Prog %d/%d: %s ", ii+1, progs->num,
887 THD_trailname(progs->ar[ii],0) );
888 if ((ws = approx_str_sort_all_popts(progs->ar[ii], 0, &N_ws,
889 1, &ws_score,
890 NULL, NULL, 1, 0, '\\'))) {
891 if (verb) fprintf(stderr,"%d opts\t ", N_ws);
892 if ((sout = form_C_progopt_string(
893 THD_trailname(progs->ar[ii], 0), ws, N_ws))){
894 fprintf(fout, "%s,\n", sout);
895 free(sout); sout = NULL;
896 }
897 for (jj=0; jj<N_ws; ++jj) if (ws[jj]) free(ws[jj]);
898 free(ws); ws = NULL;
899 if (ws_score) free(ws_score); ws_score=NULL;
900 }
901 }
902 fprintf(fout, " { NULL, NULL, 0 }\n};\n\n"
903 "#endif\n\n\n"
904 "#endif /* For #ifdef PROG_OPTS_INCLUDED */\n");
905
906 DESTROY_SARR(progs) ;
907
908 RETURN(0);
909 }
910
phelp_cmd(char * prog,TFORM targ,char cmd[512],char fout[128],int verb)911 int phelp_cmd(char *prog, TFORM targ, char cmd[512], char fout[128], int verb )
912 {
913 char uid[64];
914 char *hopt;
915
916 ENTRY("phelp_cmd");
917
918 if (!prog ) RETURN(0);
919 fout[0] = '\0';
920 cmd[0] = '\0';
921
922 switch(targ){
923 case WEB:
924 case NO_FORMAT:
925 hopt = "-h_raw";
926 if (!program_supports(prog, hopt, NULL, verb)) hopt = "-HELP";
927 if (!program_supports(prog, hopt, NULL, verb)) hopt = "-help";
928 break;
929 case ASPX:
930 case SPX:
931 hopt = "-h_spx";
932 if (!program_supports(prog, hopt, NULL, verb)) hopt = "-HELP";
933 if (!program_supports(prog, hopt, NULL, verb)) hopt = "-help";
934 break;
935 case TXT:
936 hopt = "-help";
937 break;
938 default:
939 ERROR_message("I hate myself for failing you with %d", targ);
940 RETURN(0);
941 }
942
943 UNIQ_idcode_fill(uid);
944 sprintf(fout,"/tmp/%s.%s.txt", APSEARCH_TMP_PREF, uid);
945 snprintf(cmd,500*sizeof(char),"\\echo '' 2>&1 | %s %s > %s 2>&1 ",
946 prog, hopt, fout);
947
948 RETURN(1);
949 }
950
phelp(char * prog,TFORM targ,int verb)951 char *phelp(char *prog, TFORM targ, int verb)
952 {
953 char cmd[512], tout[128];
954 char *help=NULL;
955
956 ENTRY("phelp");
957
958 if (!prog ) RETURN(help);
959
960 if (!phelp_cmd(prog, targ, cmd, tout, verb)) {
961 ERROR_message("Failed to get help command");
962 RETURN(0);
963 }
964
965 if (system(cmd)) {
966 if (0) {/* many programs finish help and set status afterwards. Naughty. */
967 ERROR_message("Failed to get help for %s\nCommand: %s\n", prog, cmd);
968 return 0;
969 }
970 }
971
972 if (!(help = AFNI_suck_file(tout))) {
973 if (verb) ERROR_message("File %s could not be read\n", tout);
974 RETURN(help);
975 }
976
977 snprintf(cmd,500*sizeof(char),"\\rm -f %s", tout);
978 system(cmd);
979
980 help = sphelp(prog, &help, targ, verb);
981
982 RETURN(help);
983 }
984
sphelp(char * prog,char ** str,TFORM targ,int verb)985 char *sphelp(char *prog, char **str, TFORM targ, int verb)
986 {
987 char cmd[512], tout[128];
988 char *help=NULL;
989
990 ENTRY("sphelp");
991
992 if (!prog || !str || !*str) RETURN(help);
993
994 switch(targ){
995 case WEB:
996 case NO_FORMAT:
997 case SPX:
998 case TXT:
999 /* This might be a repeated call in some instances */
1000 help = SUMA_Sphinx_String_Edit(str, targ, 0);
1001 break;
1002 case ASPX:
1003 if (!(help = sphinxize_prog_shelp(prog, *str, verb))) {
1004 if (verb) ERROR_message("Failed to autosphinxize string.");
1005 RETURN(*str);
1006 }
1007 free(*str); *str = help;
1008 break;
1009 default:
1010 ERROR_message("Sorry no formatting for you with %d", targ);
1011 help = *str;
1012 }
1013 RETURN(help);
1014 }
1015
1016 /* Check the static list in prog_opts.c to find whether
1017 or not an option exists for a particular program.
1018 Return 1: If program is found and the option exists
1019 0: If program found and option does not exist
1020 -1: If program was not in the list
1021 -2: If the caller needs brains.
1022 */
check_for_opt_in_prog_opts(char * prog,char * opt)1023 int check_for_opt_in_prog_opts(char *prog, char *opt)
1024 {
1025 PROG_OPTS PO;
1026 int i=0;
1027 char sbuf[64]={""}, *found;
1028
1029 if (!prog || !opt) return(-2);
1030 PO = poptslist[i++];
1031 while (PO.program) {
1032 if (!strcmp(THD_trailname(prog, 0),PO.program)) {
1033 snprintf(sbuf, 64, "%s;", opt);
1034 /* fprintf(stderr,"%s, %s-->%s, %s\n",
1035 prog, sbuf, PO.program, PO.options); */
1036 if ((found=strstr(PO.options,sbuf))) {
1037 return(1);
1038 } else {
1039 return(0);
1040 }
1041 }
1042 PO = poptslist[i++];
1043 }
1044 /* program not found */
1045 return(-1);
1046 }
1047
1048 /*
1049 Return 1 if program uprog has option option opt
1050 0 otherwsise
1051
1052 The function first checks if the program has an
1053 entry in array poptslist from file prog_opts.c included above.
1054
1055 If an entry is found, the decision is based on whether or not
1056 opt is listed for that program. Otherwise, if no entry is found,
1057 the function resorts to running the program with option opt
1058 followed by value oval (if not NULL). If the program returns a status
1059 of 1, OR creates no output in response to the option then the
1060 option is considered non-existent.
1061
1062 Obviously, this is not a general purpose option checker.
1063 It was written for the purpose of checking whether or not
1064 a program supports the newfangled -h_raw, etc. options.
1065
1066 If uprog is "ALL", the function check all existing programs
1067 for opt and returns the total number of programs that seem
1068 to support it.
1069 */
program_supports(char * uprog,char * opt,char * oval,int verb)1070 int program_supports(char *uprog, char *opt, char *oval, int verb)
1071 {
1072 char cmd[512], uid[64], tout[128], *prog=NULL;
1073 int sup=0, ii=0, quick=0;
1074 THD_string_array *progs=NULL;
1075
1076 ENTRY("program_supports");
1077
1078 if (!uprog || !opt) RETURN(sup);
1079
1080 if (!strcmp(uprog,"ALL")) {
1081 if (!(progs = THD_get_all_afni_executables()) || progs->num < 1) {
1082 ERROR_message("Could not get list of executables");
1083 RETURN(sup);
1084 }
1085 prog = progs->ar[ii++];
1086 } else {
1087 prog = uprog;
1088 }
1089
1090 if (!oval) oval = "";
1091 sup = 0;
1092 do {
1093 switch (quick = check_for_opt_in_prog_opts(prog, opt)) {
1094 case 1:
1095 sup += 1;
1096 if (verb) {
1097 fprintf(stderr,"%s -- OK for %s %s (quick)\n",
1098 prog, opt, oval);
1099 }
1100 break;
1101 case 0:
1102 sup += 0;
1103 if (verb) {
1104 fprintf(stderr,"%s -- No support for %s %s (quick)\n",
1105 prog, opt, oval);
1106 }
1107 break;
1108 case -1:
1109 /* DO NOT attempt to query program itself to find whether or
1110 not it supports an option. For scripts, that ask apsearch
1111 for help when they don't recognize an option, this will
1112 cause an ugly recursion. */
1113 #if 0
1114 UNIQ_idcode_fill(uid);
1115 sprintf(tout,"/tmp/%s.%s.ps.txt", APSEARCH_TMP_PREF, uid);
1116 snprintf(cmd,500*sizeof(char),"\\echo '' 2>&1 | %s %s %s > %s 2>&1 ",
1117 prog, opt, oval, tout);
1118 if (system(cmd) || !THD_filesize(tout)) {
1119 sup += 0;
1120 if (verb) {
1121 fprintf(stderr,"%s -- No support for %s %s\n",
1122 prog, opt, oval);
1123 }
1124 } else {
1125 sup += 1;
1126 if (verb) {
1127 fprintf(stderr,"%s -- OK for %s %s\n", prog, opt, oval);
1128 }
1129 }
1130 snprintf(cmd,500*sizeof(char),"\\rm -f %s", tout);
1131 system(cmd);
1132 #else
1133 sup += 0;
1134 if (verb) {
1135 fprintf(stderr,"** No entry for %s in prog_opts.c \n",
1136 prog);
1137 }
1138 #endif
1139 break;
1140 case -2:
1141 ERROR_message("Nonesense here?");
1142 break;
1143 }
1144
1145 if (progs && ii < progs->num) {
1146 prog = progs->ar[ii++];
1147 }else prog = NULL;
1148 } while (prog);
1149
1150 if (progs) {
1151 DESTROY_SARR(progs) ;
1152 }
1153
1154 RETURN(sup);
1155 }
1156
find_popt(char * sh,char * opt,int * nb)1157 char *find_popt(char *sh, char *opt, int *nb)
1158 {
1159 char *loc=NULL, *other=NULL;
1160 int ne = 0;
1161
1162 ENTRY("find_popt");
1163
1164 if (!sh || !opt) {
1165 ERROR_message("NULL option or null string");
1166 RETURN(loc);
1167 }
1168
1169 loc = line_begins_with(sh, opt, nb, "\t :]", "[]<>()", 5);
1170
1171 if (loc) { /* Check that we do not have more than one */
1172 if ((other = line_begins_with(loc+*nb+1, opt, NULL, "\t :]", "[]<>()", 5))) {
1173 char sbuf[128]={""}, *strt;
1174 snprintf(sbuf,127,
1175 "*+ WARNING: More than one match for 'opt' %s in \n>>",
1176 opt);
1177 strt = MAX(other-60,loc+*nb+1);
1178 write_string(strt, sbuf,
1179 "<< Returning first hit\n",
1180 (other-strt)+10,1,stderr);
1181 }
1182 }
1183
1184 RETURN(loc);
1185 }
1186
form_complete_command_string(char * prog,char ** ws,int N_ws,int shtp)1187 char *form_complete_command_string(char *prog, char **ws, int N_ws, int shtp) {
1188 char *sout=NULL, sbuf[128], *wsptr;
1189 int maxch=0, i, jj;
1190 int nargs = 0;
1191 NI_str_array *nisa=NULL;
1192
1193 if (!prog || !ws || shtp < 0) {
1194 return(NULL);
1195 }
1196
1197 maxch = 256;
1198 nargs = 0;
1199 for (i=0; i<N_ws; ++i) {
1200 if (ws[i]) {
1201 nargs++; /* count valid args, in case there are none */
1202 maxch+=strlen(ws[i])+10;
1203 if (strlen(ws[i]) > 127) {
1204 WARNING_message("Truncating atrocious option %s\n", ws[i]);
1205 wsptr = ws[i]+127;
1206 *wsptr = '\0';
1207 }
1208 }
1209 }
1210
1211 if (!(sout = (char *)calloc((maxch+1), sizeof(char)))) {
1212 ERROR_message("Failed to allocate for %d chars!", maxch+1);
1213 return(NULL);
1214 }
1215 sout[0]='\0';
1216
1217 /* if the list is empty, just say so */
1218 /* - zsh might whine if ARGS is an empty list list) */
1219 /* - do not leave an empty or non-existent file */
1220 if( nargs == 0 ) {
1221 sprintf(sbuf, "# %s : empty ARGS list\n", prog);
1222 strcpy(sout, sbuf);
1223 return(sout);
1224 }
1225
1226 switch (shtp) {
1227 default:
1228 case 0: /* csh/tcsh */
1229 strncat(sout,"set ARGS=(",maxch-strlen(sout)-1);
1230 break;
1231 case 1: /* bash */
1232 case 2: /* zsh - same main syntax as bash */
1233 strncat(sout,"ARGS=(",maxch-strlen(sout)-1);
1234 break;
1235 }
1236
1237 for (i=0; i<N_ws; ++i) {
1238 /* for zsh, remove any bad punctuation characters (=,>,|) */
1239 /* (note that '=' is in -dxyz=1, for example) */
1240 /* ('|' is a separator in 3dToyProg and 3dproject) */
1241 if( shtp == 2 )
1242 local_clean_zsh_punct(ws[i]);
1243
1244 if (ws[i] && (nisa = NI_strict_decode_string_list(ws[i] ,"/"))) {
1245 for (jj=0; jj<nisa->num; ++jj) {
1246 if (ws[i][0]=='-' && nisa->str[jj][0] != '-') {
1247 snprintf(sbuf,127,"'-%s' ", nisa->str[jj]);
1248 } else {
1249 snprintf(sbuf,127,"'%s' ", nisa->str[jj]);
1250 }
1251 strncat(sout,sbuf, maxch-strlen(sout)-1);
1252 NI_free(nisa->str[jj]);
1253 }
1254 if (nisa->str) NI_free(nisa->str);
1255 NI_free(nisa); nisa=NULL;
1256 }
1257 }
1258
1259 switch (shtp) {
1260 default:
1261 case 0: /* csh/tcsh */
1262 snprintf(sbuf,127,") ; "
1263 "complete %s \"C/-/($ARGS)/\" \"p/*/f:/\" ; ##%s##\n",prog, prog);
1264 break;
1265 case 1: /* bash */
1266 snprintf(sbuf,127,") ; "
1267 "complete -W \"${ARGS[*]}\" -o bashdefault -o default %s ; "
1268 "##%s##\n",prog, prog);
1269 break;
1270 case 2: /* zsh - syntax matches that of bash, mostly */
1271 snprintf(sbuf,127,") ; "
1272 "complete -W \"${ARGS[*]}\" -o bashdefault -o default %s ; "
1273 "##%s##\n",prog, prog);
1274 break;
1275 }
1276 if (strlen(sbuf) >= 127) {
1277 ERROR_message("Too short a buffer for complete command %s\n");
1278 free(sout); sout=NULL;
1279 return(sout);
1280 }
1281 strncat(sout,sbuf, maxch-strlen(sout)-1);
1282 if (strlen(sout)>=maxch-1) {
1283 ERROR_message("Truncated complete string possible");
1284 free(sout); sout=NULL;
1285 return(sout);
1286 }
1287
1288 return(sout);
1289 }
1290
prog_complete_command(char * prog,char * ofileu,int shtp)1291 int prog_complete_command (char *prog, char *ofileu, int shtp) {
1292 char **ws=NULL, *sout=NULL, *ofile=NULL;
1293 float *ws_score=NULL;
1294 int N_ws=0, ishtp=0, shtpmax = 0, i;
1295 FILE *fout=NULL;
1296
1297 if (!prog || !(ws = approx_str_sort_all_popts(prog, 0, &N_ws,
1298 1, &ws_score,
1299 NULL, NULL, 1, 0, '\\'))) {
1300 return 0;
1301 }
1302
1303 /* shell types are:
1304 * 0: tcsh
1305 * 1: bash
1306 * 2: zsh
1307 * set shtpmax to largest+1 (so 3, now) */
1308 if (shtp < 0) { shtp=0; shtpmax = 3;}
1309 else { shtpmax = shtp+1; }
1310
1311 for (ishtp=shtp; ishtp<shtpmax; ++ishtp) {
1312 if (ofileu) {
1313 if (shtpmax != shtp+1) { /* autoname */
1314 switch (ishtp) {
1315 default:
1316 case 0:
1317 ofile = strdup(ofileu);
1318 break;
1319 case 1:
1320 ofile = (char*)calloc((strlen(ofileu)+20), sizeof(char));
1321 strcat(ofile, ofileu);
1322 strcat(ofile, ".bash");
1323 break;
1324 case 2:
1325 ofile = (char*)calloc((strlen(ofileu)+20), sizeof(char));
1326 strcat(ofile, ofileu);
1327 strcat(ofile, ".zsh");
1328 break;
1329 }
1330 } else {
1331 ofile = strdup(ofileu);
1332 }
1333
1334 if (!(fout = fopen(ofile,"w"))) {
1335 ERROR_message("Failed to open %s for writing\n", ofile);
1336 return(0);
1337 }
1338
1339 } else {
1340 fout = stdout;
1341 }
1342
1343 if ((sout = form_complete_command_string(prog, ws, N_ws, ishtp))){
1344 fprintf(fout, "%s", sout);
1345 free(sout); sout = NULL;
1346 }
1347 if (ofileu) fclose(fout); fout=NULL;
1348 if (ofile) free(ofile); ofile=NULL;
1349 }
1350
1351 for (i=0; i<N_ws; ++i) if (ws[i]) free(ws[i]);
1352 free(ws); ws = NULL;
1353 if (ws_score) free(ws_score); ws_score=NULL;
1354 return 0;
1355 }
1356
1357
1358
view_prog_help(char * prog)1359 void view_prog_help(char *prog)
1360 {
1361 char *viewer=NULL, *hname=NULL;
1362 char *progname=NULL;
1363
1364 if (!prog) return;
1365 if (!(progname = THD_find_executable(prog))) {
1366 ERROR_message("Could not find executable %s.\n",
1367 prog);
1368 return;
1369 }
1370 if (!(viewer = GetAfniTextEditor())) {
1371 ERROR_message("No GUI editor defined, and guessing game failed.\n"
1372 "Set AFNI_GUI_EDITOR in your .afnirc for this option to work.\n");
1373 return;
1374 }
1375
1376 hname = get_updated_help_file(0, 0, progname, -1);
1377 if (hname[0]=='\0') { /* failed, no help file ... */
1378 ERROR_message("No help file for %s\n", progname);
1379 return;
1380 }
1381
1382 if (!(view_text_file(hname))) {
1383 ERROR_message("Failed to view %s\n", hname);
1384 }
1385 return;
1386 }
1387
web_prog_help_link(char * prog,int style)1388 char *web_prog_help_link(char *prog, int style)
1389 {
1390 char *progname=NULL;
1391 static char weblinka[10][1024]={""}, *weblink;
1392 static int n;
1393 /* point to the new AFNI program help page 16 Mar 2020 [rickr] */
1394 const char * sphinx_help =
1395 "https://afni.nimh.nih.gov/pub/dist/doc/htmldoc/programs";
1396 const char * old_help =
1397 "https://afni.nimh.nih.gov/pub/dist/doc/program_help";
1398
1399 ++n; if (n>9) n = 0;
1400 weblink = (char *)weblinka[n]; weblink[0]='\0';
1401
1402 if (!prog) return(weblink);
1403
1404 if (!strcmp(prog,"ALL")) {
1405 if (style == 0) {
1406 snprintf(weblink,1020*sizeof(char), "%s/%s.html", sphinx_help,
1407 "main_toc");
1408 } else {
1409 /* Nothing yet, return old */
1410 snprintf(weblink,1020*sizeof(char), "%s/%s.html", old_help,
1411 "all-of-them");
1412 }
1413 } else {
1414 if (!(progname = THD_find_executable(prog))) {
1415 ERROR_message("Could not find executable %s.\n",
1416 prog);
1417 return(weblink);
1418 }
1419
1420 if (style == 0) {
1421 snprintf(weblink,1020*sizeof(char), "%s/%s_sphx.html", sphinx_help,
1422 THD_trailname(progname,0));
1423 } else {
1424 /* Nothing yet, return old */
1425 snprintf(weblink,1020*sizeof(char), "%s/%s_sphx.html", sphinx_help,
1426 THD_trailname(progname,0));
1427 }
1428 }
1429
1430 return(weblink);
1431 }
1432
web_prog_help(char * prog,int style)1433 void web_prog_help(char *prog, int style)
1434 {
1435 char *progname=NULL;
1436 char *weblink;
1437
1438 if (!prog) return;
1439
1440 weblink = web_prog_help_link(prog, style);
1441 if (weblink[0] == '\0') return;
1442
1443 if (!(view_web_link(weblink,NULL))) {
1444 ERROR_message("Failed to web view %s\n", weblink);
1445 return;
1446 }
1447
1448 return;
1449 }
1450
web_class_docs(char * prog)1451 void web_class_docs(char *prog)
1452 {
1453 char weblink[1024]={""};
1454
1455 if (prog) {
1456 ERROR_message("Not ready for prog input %s.\n",
1457 prog);
1458 return;
1459 } else {
1460 snprintf(weblink,1020*sizeof(char),
1461 "https://afni.nimh.nih.gov/pub/dist/edu/latest");
1462 }
1463
1464 if (!(view_web_link(weblink,NULL))) {
1465 ERROR_message("Failed to web view %s\n", weblink);
1466 return;
1467 }
1468
1469 return;
1470 }
1471
view_web_link(char * link,char * browser)1472 int view_web_link(char *link, char *browser)
1473 {
1474 char cmd[1024];
1475 if (!link) return(0);
1476 if (!browser) browser = GetAfniWebBrowser();
1477
1478 if (!browser) {
1479 ERROR_message("No Web browse defined.\n"
1480 "Set AFNI_WEB_BROWSER in your .afnirc for this option to work.\n");
1481 return(0);
1482 }
1483
1484 snprintf(cmd,1020*sizeof(char),"%s %s &", browser, link);
1485 system(cmd);
1486 return(1);
1487 }
1488
view_text_file(char * progname)1489 int view_text_file(char *progname)
1490 {
1491 char *viewer=NULL, cmd[256];
1492
1493 if (!progname) {
1494 ERROR_message("No input!");
1495 return(0);
1496 }
1497 if (!THD_is_ondisk(progname)) {
1498 ERROR_message("file %s not on disk.\n", progname);
1499 return(0);
1500 }
1501 if (!(viewer = GetAfniTextEditor())) {
1502 ERROR_message("No GUI editor defined, and guessing game failed.\n"
1503 "Set AFNI_GUI_EDITOR in your .afnirc for this option to work.\n");
1504 return(0);
1505 }
1506 /* open help file in editor*/
1507 snprintf(cmd,250*sizeof(char),"%s %s &", viewer, progname);
1508 system(cmd);
1509 return(1);
1510 }
1511
1512 /* particularly for the case of zsh, set any of {'=', '>', '|'} to space,
1513 * which should result in them not being part of any option */
local_clean_zsh_punct(char * str)1514 static int local_clean_zsh_punct(char * str)
1515 {
1516 char * cp;
1517
1518 if( !str ) return 0;
1519
1520 /* convert bad chars to space; rely on null termination */
1521 for( cp=str; *cp; cp++ )
1522 if( *cp == '=' || *cp == '>' || *cp == '|' )
1523 *cp = ' ';
1524
1525 return 0;
1526 }
1527