1 /*
2 Assortment of generic functions needed to support I/O functions
3 in suma_datasets.c
4 */
5
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <assert.h>
9 #include <string.h>
10 #include <sys/time.h>
11 #include <math.h>
12 #include "mrilib.h"
13 #include "niml.h"
14 #include "../niml/niml_private.h"
15 #include "suma_objs.h" /* 21 Apr 2020 */
16 /*------------------------------------------------------------*/
17
18 #if defined SUMA_COMPILED
19 extern SUMA_CommonFields *SUMAg_CF;
20 extern int SUMAg_N_DOv;
21 extern SUMA_DO *SUMAg_DOv;
22 #endif
23
24 /*------------------------------------------------------------*/
25
26 /*! ********** Begin Multiplexed Vectors Functions ************* */
27 /*!
28 \brief A function to create a multiplexed vector structure
29 \param tp (SUMA_VARTYPE) type of data in array. Only SUMA_double for now.
30 \param N_dims (int) Number of array dimensions
31 \param *dims (int) Size of each dimension
32 \param first_dim_first (byte) 1 = first dimension first
33 (column major, for a matrix)
34 only 1 is accepted at the moment
35 \return mxv (SUMA_MX_VEC *) the structure with enough memory allocated to
36 the pointer of interest.
37 (mxv->dv for SUMA_double).
38 - Use SUMA_FreeMxVec to free mxv
39 - see macros mxvd* to handle data in mxv
40 */
SUMA_NewMxNullVec(SUMA_VARTYPE tp,int N_dims,int * dims,byte first_dim_first)41 SUMA_MX_VEC *SUMA_NewMxNullVec(SUMA_VARTYPE tp, int N_dims, int *dims, byte first_dim_first)
42 {
43 static char FuncName[]={"SUMA_NewMxNullVec"};
44 SUMA_MX_VEC *mxv=NULL;
45 int n_vals=0, i = 0;
46
47 SUMA_ENTRY;
48
49 if (first_dim_first != 1) {
50 SUMA_SL_Err("first_dim_first must be 1 for now");
51 SUMA_RETURN(NULL);
52 }
53
54 if (N_dims < 1) {
55 SUMA_SL_Err("N_dims < 1");
56 SUMA_RETURN(NULL);
57 } else if (N_dims > SUMA_MX_VEC_MAX_DIMS-1) {
58 SUMA_SL_Err("N_dims > 49");
59 SUMA_RETURN(NULL);
60 }
61 if (!dims) {
62 SUMA_SL_Err("NULL dims");
63 SUMA_RETURN(NULL);
64 }
65 mxv = (SUMA_MX_VEC *)SUMA_calloc(1,sizeof(SUMA_MX_VEC));
66 mxv->fdf = 1;
67 mxv->bv = NULL;
68 mxv->sv = NULL;
69 mxv->iv = NULL;
70 mxv->fv = NULL;
71 mxv->dv = NULL;
72 mxv->cv = NULL;
73 mxv->v = NULL;
74 mxv->m = NULL;
75 mxv->N_dims = N_dims;
76 mxv->N_vals = dims[0];
77 mxv->dims[0] = dims[0];
78 for (i=1; i<N_dims; ++i) {
79 mxv->N_vals = mxv->N_vals * dims[i];
80 mxv->dims[i] = dims[i];
81 }
82 for (i=N_dims; i< SUMA_MX_VEC_MAX_DIMS; ++i) mxv->dims[i] = 1;
83 if (mxv->N_vals <= 0) {
84 SUMA_SL_Err("Negative dims");
85 SUMA_free(mxv); SUMA_RETURN(NULL);
86 }
87
88 mxv->tp = tp;
89
90 /* mutlipliers for first_dim_first */
91 mxv->fdfm[0] = mxv->dims[0];
92 for (i=1; i<N_dims-1; ++i) {
93 mxv->fdfm[i] = mxv->fdfm[i-1]*mxv->dims[i];
94 }
95
96 SUMA_RETURN(mxv);
97
98 }
99
SUMA_MxVecInit(SUMA_MX_VEC * mxv,void * val)100 int SUMA_MxVecInit(SUMA_MX_VEC *mxv, void *val)
101 {
102 static char FuncName[]={"SUMA_MxVecInit"};
103 int i, ii;
104 byte bb;
105 short ss;
106 float ff;
107 complex cc;
108 double dd;
109
110 SUMA_ENTRY;
111
112 if (!mxv->v) {
113 SUMA_S_Err("null vector pointer");
114 SUMA_RETURN(0);
115 }
116 switch (mxv->tp) {
117 case SUMA_byte:
118 bb = *((byte *)val);
119 mxv->bv = (byte *)mxv->v;
120 for (i=0;i<mxv->N_vals;++i) mxv->bv[i] = bb;
121 break;
122 case SUMA_short:
123 ss = *((short *)val);
124 mxv->sv = (short *)mxv->v;
125 for (i=0;i<mxv->N_vals;++i) mxv->sv[i] = ss;
126 break;
127 case SUMA_int:
128 ii = *((int *)val);
129 mxv->iv = (int *)mxv->v;
130 for (i=0;i<mxv->N_vals;++i) mxv->iv[i] = ii;
131 break;
132 case SUMA_float:
133 ff = *((float *)val);
134 mxv->fv = (float *)mxv->v;
135 for (i=0;i<mxv->N_vals;++i) mxv->fv[i] = ff;
136 break;
137 case SUMA_double:
138 dd = *((double *)val);
139 mxv->dv = (double *)mxv->v;
140 for (i=0;i<mxv->N_vals;++i) mxv->dv[i] = 1.0;
141 break;
142 case SUMA_complex:
143 cc = *((complex *)val);
144 mxv->cv = (complex *)mxv->v;
145 for (i=0; i<mxv->N_vals; ++i)
146 { mxv->cv[i].r = cc.r; mxv->cv[i].i = cc.i; }
147 break;
148 default:
149 SUMA_SL_Err("Bad type");
150 SUMA_RETURN(0);
151 }
152
153 SUMA_RETURN(1);
154 }
SUMA_NewMxAllocVec(SUMA_MX_VEC * mxv)155 int SUMA_NewMxAllocVec(SUMA_MX_VEC *mxv)
156 {
157 static char FuncName[]={"SUMA_NewMxAllocVec"};
158 int i, ip;
159
160 SUMA_ENTRY;
161
162 if (mxv->v || mxv->bv || mxv->sv || mxv->iv || mxv->fv || mxv->dv || mxv->cv || mxv->m) {
163 SUMA_S_Err("Non null vector pointers");
164 SUMA_RETURN(0);
165 }
166
167 switch (mxv->tp) {
168 case SUMA_byte:
169 mxv->v = SUMA_calloc(mxv->N_vals, sizeof(byte));
170 mxv->bv = (byte *)mxv->v;
171 break;
172 case SUMA_short:
173 mxv->v = SUMA_calloc(mxv->N_vals, sizeof(short));
174 mxv->sv = (short *)mxv->v;
175 break;
176 case SUMA_int:
177 mxv->v = SUMA_calloc(mxv->N_vals, sizeof(int));
178 mxv->iv = (int *)mxv->v;
179 break;
180 case SUMA_float:
181 mxv->v = SUMA_calloc(mxv->N_vals, sizeof(float));
182 mxv->fv = (float *)mxv->v;
183 break;
184 case SUMA_double:
185 mxv->v = SUMA_calloc(mxv->N_vals, sizeof(double));
186 mxv->dv = (double *)mxv->v;
187 break;
188 case SUMA_complex:
189 mxv->v = SUMA_calloc(mxv->N_vals, sizeof(complex));
190 mxv->cv = (complex *)mxv->v;
191 if (mxv->v) {
192 for (i=0; i<mxv->N_vals; ++i) {
193 mxv->cv[i].r = 0.0; mxv->cv[i].i = 0.0;
194 }
195 }
196 break;
197 default:
198 SUMA_SL_Err("Bad type");
199 SUMA_RETURN(0);
200 }
201
202 if (!mxv->v) {
203 SUMA_SL_Crit("Failed to allocate");
204 SUMA_RETURN(0);
205 }
206 mxv->m = NULL; /* just to be sure */
207 SUMA_RETURN(1);
208 }
209
SUMA_NewMxVec(SUMA_VARTYPE tp,int N_dims,int * dims,byte first_dim_first)210 SUMA_MX_VEC *SUMA_NewMxVec(SUMA_VARTYPE tp, int N_dims, int *dims,
211 byte first_dim_first)
212 {
213 static char FuncName[]={"SUMA_NewMxVec"};
214 SUMA_MX_VEC *mxv=NULL;
215 int n_vals=0, i = 0;
216 SUMA_Boolean LocalHead = NOPE;
217
218 SUMA_ENTRY;
219
220 /* blank holder */
221 mxv = SUMA_NewMxNullVec(tp, N_dims, dims, first_dim_first);
222 if (LocalHead) SUMA_ShowMxVec(mxv, 1, NULL, "\nmxv in NewMx\n");
223 /* allocator */
224 if (!SUMA_NewMxAllocVec(mxv)) {
225 SUMA_SL_Crit("Failed to allocate");
226 SUMA_free(mxv); SUMA_RETURN(NULL);
227 }
228
229 SUMA_RETURN(mxv);
230 }
231
SUMA_VecToMxVec(SUMA_VARTYPE tp,int N_dims,int * dims,byte first_dim_first,void * vec)232 SUMA_MX_VEC *SUMA_VecToMxVec(SUMA_VARTYPE tp, int N_dims, int *dims,
233 byte first_dim_first, void *vec)
234 {
235 static char FuncName[]={"SUMA_VecToMxVec"};
236 SUMA_MX_VEC *mxv=NULL;
237 int n_vals=0, i = 0;
238
239 SUMA_ENTRY;
240
241 /* blank holder */
242 mxv = SUMA_NewMxNullVec(tp, N_dims, dims, first_dim_first);
243
244 if (!vec) SUMA_RETURN(mxv);
245
246 mxv->v = vec;
247 switch (mxv->tp) {
248 case SUMA_byte:
249 mxv->bv = (byte *)mxv->v;
250 break;
251 case SUMA_short:
252 mxv->sv = (short *)mxv->v;
253 break;
254 case SUMA_int:
255 mxv->iv = (int *)mxv->v;
256 break;
257 case SUMA_float:
258 mxv->fv = (float *)mxv->v;
259 break;
260 case SUMA_double:
261 mxv->dv = (double *)mxv->v;
262 break;
263 case SUMA_complex:
264 mxv->cv = (complex *)mxv->v;
265 break;
266 default:
267 SUMA_SL_Err("Bad type");
268 SUMA_free(mxv); SUMA_RETURN(NULL);
269 }
270
271 SUMA_RETURN(mxv);
272 }
273
274
SUMA_FreeMxVec(SUMA_MX_VEC * mxv)275 SUMA_MX_VEC *SUMA_FreeMxVec(SUMA_MX_VEC *mxv)
276 {
277 static char FuncName[]={"SUMA_FreeMxVec"};
278 int i;
279 SUMA_ENTRY;
280
281 if (mxv) {
282 if (mxv->v) SUMA_free(mxv->v);
283 if (mxv->m) {
284 if (mxv->m->elts) {
285 for (i=0; i<mxv->m->rows; ++i)
286 if (mxv->m->elts[i]) SUMA_free(mxv->m->elts[i]);
287 SUMA_free(mxv->m->elts);
288 }
289 SUMA_free(mxv->m);
290 }
291 mxv->m = NULL;
292 SUMA_free(mxv);
293 }
294
295 SUMA_RETURN(NULL);
296 }
297
SUMA_ShowMxVec(SUMA_MX_VEC * mxv,int detail,FILE * out,char * title)298 void SUMA_ShowMxVec (SUMA_MX_VEC *mxv, int detail, FILE *out, char *title)
299 {
300 static char FuncName[]={"SUMA_ShowMxVec"};
301 char *si = NULL;
302
303 SUMA_ENTRY;
304
305 if (!out) out = SUMA_STDERR;
306
307 si = SUMA_MxVec_Info(mxv, detail, title);
308
309 fprintf(out,"%s\n", si);
310
311 if (si) SUMA_free(si); si = NULL;
312
313 SUMA_RETURNe;
314
315 }
316
317 /*!
318 \brief Function to return info on SUMA_DSET
319
320 - You must free the returned string on your own
321 \sa SUMA_ShowDset
322 */
SUMA_MxVec_Info(SUMA_MX_VEC * mxv,int detail,char * title)323 char *SUMA_MxVec_Info (SUMA_MX_VEC *mxv, int detail, char *title)
324 {
325 static char FuncName[]={"SUMA_MxVec_Info"};
326 int i, imx = 5, j;
327 SUMA_COL_TYPE ctp;
328 char *s=NULL, stmp[200];
329 SUMA_STRING *SS=NULL;
330 SUMA_Boolean LocalHead = NOPE;
331
332 SUMA_ENTRY;
333
334 SS = SUMA_StringAppend(NULL, NULL);
335
336 if (mxv) {
337 SUMA_LH("Have mxv");
338 if (title) SS = SUMA_StringAppend_va(SS, "%s", title);
339 SS = SUMA_StringAppend_va(SS, "mxv: %p\n"
340 "data type: %d (%s)\n"
341 "fdf: %d\n"
342 "N_dims: %d\n"
343 "N_vals: %d\n"
344 , mxv, mxv->tp,
345 SUMA_VarType2CTypeName(mxv->tp), mxv->fdf,
346 mxv->N_dims, mxv->N_vals);
347 if (mxv->m) {
348 SUMA_LH("Working m");
349 SS = SUMA_StringAppend_va(SS,
350 "m is setup (rows: %d, cols: %d)\n", mxv->m->rows, mxv->m->cols);
351 SUMA_LH("Working m");
352 for (i=0; i < mxv->m->rows && i < imx; ++i) {
353 for (j=0; j < mxv->m->cols && j < imx; ++j) {
354 SUMA_LH("elts[][]\n");
355 SS = SUMA_StringAppend_va(SS,"%g ", mxv->m->elts[i][j]);
356 }
357 if (mxv->m->cols > imx) SS = SUMA_StringAppend(SS,"...\n");
358 else SS = SUMA_StringAppend(SS,"\n");
359 }
360 if (mxv->m->rows > imx)
361 SS = SUMA_StringAppend(SS,"... ... ... ... ...\n");
362 else SS = SUMA_StringAppend(SS,"\n");
363 SUMA_LH("Done with m");
364 } else {
365 SUMA_LH("NULL m");
366 SS = SUMA_StringAppend(SS, "m is NULL\n");
367 }
368 SUMA_LH("dims time");
369 SS = SUMA_StringAppend_va(SS, "dims: ");
370 for (i=0; i<mxv->N_dims; ++i) {
371 SS = SUMA_StringAppend_va(SS, "%d ", mxv->dims[i]);
372 }
373 SS = SUMA_StringAppend_va(SS, "\n");
374
375 if (mxv->v) {
376 if (detail < 0) {
377 imx = mxv->N_vals;
378 } else {
379 imx = 5*detail;
380 }
381 s = SUMA_ShowMeSome( mxv->v,
382 mxv->tp,
383 mxv->N_vals, imx, NULL);
384 SS = SUMA_StringAppend_va(SS, " %s\n", s);
385 SUMA_free(s); s = NULL;
386 } else SS = SUMA_StringAppend_va(SS, " NULL\n");
387 } else {
388 SS = SUMA_StringAppend(SS, "NULL mxv.");
389 }
390
391 SUMA_SS2S(SS, s);
392
393 SUMA_RETURN(s);
394 }
395
396 /****************** Command line and Env parsing functions. ************** */
397 /****************** Help strings. Filename parsing. ************** */
398
399 static int no_suma_rc_found;
400
NoSumaRcFound(void)401 int NoSumaRcFound (void) { return (no_suma_rc_found);}
402
403 /*!
404 Return number of Icosahedron
405 depth (int) depth of subdivision (value of -ld or -rd in CreateIcosahedron)
406 bin (byte) 1 --> equiv to -rd in CreateIcosahedron
407 0 --> -ld in CreateIcosahedron
408 what (char) 'v' or 'n' :return number of nodes
409 't': return number of triangles
410 'e': return number of edges
411 */
SUMA_IcoNums(int depth,byte bin,char what)412 int SUMA_IcoNums(int depth, byte bin, char what) {
413 int dd=-1;
414 if (depth < 0) return (dd);
415 if (bin) { /* binary subdivisions */
416 switch (what){
417 case 'v':
418 case 'n':
419 dd = (int)(pow(2, (2*depth)))*10 + 2;
420 break;
421 case 't':
422 dd = (int)(pow(2, (2*depth)))*20;
423 break;
424 case 'e':
425 dd = (int)(pow(2, (2*depth)))*30;
426 break;
427 }
428 } else { /* linear subdivisions */
429 switch (what){
430 case 'v':
431 case 'n':
432 dd = 2 + (10 * depth * depth);
433 break;
434 case 't':
435 dd = 20 * depth * depth;
436 break;
437 case 'e':
438 dd = 30 * depth * depth;
439 break;
440 }
441 }
442 return(dd);
443 }
444
445 /*!
446 \brief load the environment variables first from
447 $HOME/.sumarc and $HOME/.afnirc
448 if HOME is not defined then try .afnirc and .sumarc
449 Shameless wrapper for AFNI_process_environ
450
451 No fancies here, this function is called before CommonFields
452 */
SUMA_process_environ(void)453 void SUMA_process_environ(void)
454 {
455 static char FuncName[]={"SUMA_process_environ"};
456 struct stat stbuf;
457 char *sumarc = NULL, *homeenv=NULL;
458 SUMA_Boolean LocalHead = NOPE;
459
460 no_suma_rc_found = 0;
461
462 if (LocalHead)
463 fprintf (SUMA_STDERR,"%s: Entering SUMA_process_environ\n", FuncName);
464
465 sumarc = (char *)malloc( sizeof(char)*
466 (SUMA_MAX_NAME_LENGTH+SUMA_MAX_DIR_LENGTH+1));
467
468 /* load the environment variables from .sumarc and .afnirc*/
469 homeenv = getenv("HOME");
470
471 if (!homeenv) sprintf(sumarc, ".sumarc");
472 else sprintf(sumarc,"%s/.sumarc", homeenv);
473 if (stat(sumarc, &stbuf) != -1) {
474 if (LocalHead)
475 fprintf (SUMA_STDERR,"%s: Loading %s ...\n", FuncName, sumarc);
476 AFNI_process_environ(sumarc);
477 } else {
478 if (LocalHead)
479 fprintf (SUMA_STDERR,"%s: No sumarc file found.\n", FuncName);
480 no_suma_rc_found = 1;
481 }
482
483 if (!homeenv) sprintf(sumarc, ".afnirc");
484 else sprintf(sumarc,"%s/.afnirc", homeenv);
485 if (stat(sumarc, &stbuf) != -1) {
486 if (LocalHead)
487 fprintf (SUMA_STDERR,"%s: Loading %s ...\n", FuncName, sumarc);
488 AFNI_process_environ(sumarc);
489 } else {
490 if (LocalHead)
491 fprintf (SUMA_STDERR,"%s: No afnirc file found.\n", FuncName);
492 }
493
494 if (sumarc) free(sumarc); sumarc = NULL; /* allocated before CommonFields */
495
496 AFNI_mark_environ_done(); /* flag environment rc files as read */
497
498 if (LocalHead)
499 fprintf (SUMA_STDERR,"%s: Exiting SUMA_process_environ\n", FuncName);
500
501 return;
502 }
503
SUMA_help_basics()504 char *SUMA_help_basics()
505 {
506 SUMA_STRING *SS = NULL;
507 char *s=NULL;
508 static char FuncName[]={"SUMA_help_basics"};
509
510 SUMA_ENTRY;
511
512 SS = SUMA_StringAppend(NULL, NULL);
513 SS = SUMA_StringAppend_va(SS,
514 " [-novolreg]: Ignore any Rotate, Volreg, Tagalign, \n"
515 " or WarpDrive transformations present in \n"
516 " the Surface Volume.\n"
517 " [-noxform]: Same as -novolreg\n"
518 " [-setenv \"'ENVname=ENVvalue'\"]: Set environment variable ENVname\n"
519 " to be ENVvalue. Quotes are necessary.\n"
520 " Example: suma -setenv \"'SUMA_BackgroundColor = 1 0 1'\"\n"
521 " See also options -update_env, -environment, etc\n"
522 " in the output of 'suma -help'\n"
523 " Common Debugging Options:\n"
524 " [-trace]: Turns on In/Out debug and Memory tracing.\n"
525 " For speeding up the tracing log, I recommend \n"
526 " you redirect stdout to a file when using this option.\n"
527 " For example, if you were running suma you would use:\n"
528 " suma -spec lh.spec -sv ... > TraceFile\n"
529 " This option replaces the old -iodbg and -memdbg.\n"
530 " [-TRACE]: Turns on extreme tracing.\n"
531 " [-nomall]: Turn off memory tracing.\n"
532 " [-yesmall]: Turn on memory tracing (default).\n"
533 " NOTE: For programs that output results to stdout\n"
534 " (that is to your shell/screen), the debugging info\n"
535 " might get mixed up with your results.\n"
536 "\n"
537 "\n"
538 "Global Options (available to all AFNI/SUMA programs)\n"
539 "%s\n",
540 SUMA_Offset_SLines(get_help_help(),2), get_gopt_help() );
541 SUMA_SS2S(SS,s);
542 SUMA_RETURN(s);
543 }
544
545
SUMA_help_talk()546 char *SUMA_help_talk()
547 {
548 SUMA_STRING *SS = NULL;
549 char *s=NULL;
550 static char FuncName[]={"SUMA_help_talk"};
551
552 SUMA_ENTRY;
553
554 SS = SUMA_StringAppend(NULL, NULL);
555 SS = SUMA_StringAppend_va(SS,
556 " SUMA communication options:\n"
557 " -talk_suma: Send progress with each iteration to SUMA.\n"
558 " -refresh_rate rps: Maximum number of updates to SUMA per second.\n"
559 " The default is the maximum speed.\n"
560 " -send_kth kth: Send the kth element to SUMA (default is 1).\n"
561 " This allows you to cut down on the number of elements\n"
562 " being sent to SUMA.\n"
563 " -sh <SumaHost>: Name (or IP address) of the computer running SUMA.\n"
564 " This parameter is optional, the default is 127.0.0.1 \n"
565 " -ni_text: Use NI_TEXT_MODE for data transmission.\n"
566 " -ni_binary: Use NI_BINARY_MODE for data transmission.\n"
567 " (default is ni_binary).\n"
568 " -feed_afni: Send updates to AFNI via SUMA's talk.\n"
569 "%s"
570 "\n", get_np_help());
571 SUMA_SS2S(SS,s);
572 SUMA_RETURN(s);
573 }
574
SUMA_help_dset()575 char *SUMA_help_dset()
576 {
577 SUMA_STRING *SS = NULL;
578 char *s=NULL;
579 static char FuncName[]={"SUMA_help_dset"};
580
581 SUMA_ENTRY;
582
583 SS = SUMA_StringAppend(NULL, NULL);
584 SS = SUMA_StringAppend(SS,
585 " SUMA dataset input options:\n"
586 " -input DSET: Read DSET1 as input.\n"
587 " In programs accepting multiple input datasets\n"
588 " you can use -input DSET1 -input DSET2 or \n"
589 " input DSET1 DSET2 ...\n"
590 " NOTE: Selecting subsets of a dataset:\n"
591 " Much like in AFNI, you can select subsets of a dataset\n"
592 " by adding qualifiers to DSET.\n"
593 " Append #SEL# to select certain nodes.\n"
594 " Append [SEL] to select certain columns.\n"
595 " Append {SEL} to select certain rows.\n"
596 " The format of SEL is the same as in AFNI, see section:\n"
597 " 'INPUT DATASET NAMES' in 3dcalc -help for details.\n"
598 " Append [i] to get the node index column from\n"
599 " a niml formatted dataset.\n"
600 " * SUMA does not preserve the selection order \n"
601 " for any of the selectors.\n"
602 " For example:\n"
603 " dset[44,10..20] is the same as dset[10..20,44]\n"
604 " Also, duplicate values are not supported.\n"
605 " so dset[13, 13] is the same as dset[13].\n"
606 " I am not proud of these limitations, someday I'll get\n"
607 " around to fixing them.\n"
608 "\n");
609 SUMA_SS2S(SS,s);
610 SUMA_RETURN(s);
611 }
612
SUMA_help_cmap()613 char *SUMA_help_cmap()
614 {
615 SUMA_STRING *SS = NULL;
616 char *s=NULL;
617 static char FuncName[]={"SUMA_help_mask"};
618
619 SUMA_ENTRY;
620
621 SS = SUMA_StringAppend(NULL, NULL);
622 SS = SUMA_StringAppend(SS,
623 " Selecting Colormaps: \n"
624 " -cmap MapName:\n"
625 " choose one of the standard colormaps available with SUMA:\n"
626 " RGYBR20, BGYR19, BW20, GRAY20, MATLAB_DEF_BYR64, \n"
627 " ROI64, ROI128. See Suma's colormap chooser for a list of names.\n"
628 " -cmapdb Palfile: read color maps from AFNI .pal file\n"
629 " In addition to the default paned AFNI colormaps, you\n"
630 " can load colormaps from a .pal file.\n"
631 " To access maps in the Palfile you must use the -cmap option\n"
632 " with the label formed by the name of the palette, its sign\n"
633 " and the number of panes. For example, to following palette:\n"
634 " ***PALETTES deco [13]\n"
635 " should be accessed with -cmap deco_n13\n"
636 " ***PALETTES deco [13+]\n"
637 " should be accessed with -cmap deco_p13\n"
638 " -cmapfile Mapfile: read color map from Mapfile.\n"
639 " Mapfile:1D formatted ascii file containing colormap.\n"
640 " each row defines a color in one of two ways:\n"
641 " R G B or\n"
642 " R G B f \n"
643 " where R, G, B specify the red, green and blue values, \n"
644 " between 0 and 1 and f specifies the fraction of the range\n"
645 " reached at this color. THINK values of right of AFNI colorbar.\n"
646 " The use of fractions (it is optional) would allow you to create\n"
647 " non-linear color maps where colors cover differing fractions of \n"
648 " the data range.\n"
649 " Sample colormap with positive range only (a la AFNI):\n"
650 " 0 0 1 1.0\n"
651 " 0 1 0 0.8\n"
652 " 1 0 0 0.6\n"
653 " 1 1 0 0.4\n"
654 " 0 1 1 0.2\n"
655 " Note the order in which the colors and fractions are specified.\n"
656 " The bottom color of the +ve colormap should be at the bottom of the\n"
657 " file and have the lowest +ve fraction. The fractions here define a\n"
658 " a linear map so they are not necessary but they illustrate the format\n"
659 " of the colormaps.\n"
660 " Comparable colormap with negative range included:\n"
661 " 0 0 1 1.0\n"
662 " 0 1 0 0.6\n"
663 " 1 0 0 0.2\n"
664 " 1 1 0 -0.2\n"
665 " 0 1 1 -0.6\n"
666 " The bottom color of the -ve colormap should have the \n"
667 " lowest -ve fraction. \n"
668 " You can use -1 -1 -1 for a color to indicate a no color\n"
669 " (like the 'none' color in AFNI). Values mapped to this\n"
670 " 'no color' will be masked as with the -msk option.\n"
671 " If your 1D color file has more than three or 4 columns,\n"
672 " you can use the [] convention adopted by AFNI programs\n"
673 " to select the columns you need.\n"
674 );
675
676 SUMA_SS2S(SS,s);
677 SUMA_RETURN(s);
678 }
679
SUMA_help_mask()680 char *SUMA_help_mask()
681 {
682 SUMA_STRING *SS = NULL;
683 char *s=NULL;
684 static char FuncName[]={"SUMA_help_mask"};
685
686 SUMA_ENTRY;
687
688 SS = SUMA_StringAppend(NULL, NULL);
689 SS = SUMA_StringAppend(SS,
690 " SUMA mask options:\n"
691 " -n_mask INDEXMASK: Apply operations to nodes listed in\n"
692 " INDEXMASK only. INDEXMASK is a 1D file.\n"
693 " -b_mask BINARYMASK: Similar to -n_mask, except that the BINARYMASK\n"
694 " 1D file contains 1 for nodes to filter and\n"
695 " 0 for nodes to be ignored.\n"
696 " The number of rows in filter_binary_mask must be\n"
697 " equal to the number of nodes forming the\n"
698 " surface.\n"
699 " -c_mask EXPR: Masking based on the result of EXPR. \n"
700 " Use like afni's -cmask options. \n"
701 " See explanation in 3dmaskdump -help \n"
702 " and examples in output of 3dVol2Surf -help\n"
703 " NOTE: Unless stated otherwise, if n_mask, b_mask and c_mask \n"
704 " are used simultaneously, the resultant mask is the intersection\n"
705 " (AND operation) of all masks.\n"
706 "\n");
707 SUMA_SS2S(SS,s);
708 SUMA_RETURN(s);
709 }
710
711 /*!
712 \brief parse command line arguments for input/output debugging and
713 memory debugging. Use no fancies in this function!
714
715 This function is to be called after SUMAg_CF has been created,
716 if #ifdef SUMA_COMPILED
717
718 Default for iotrace = 0
719 memtrace = 1
720 Those defaults are common to all apps
721
722 */
723 static int Domemtrace=0, Doiotrace=0, IgnoreXforms=0;
get_Domemtrace(void)724 int get_Domemtrace(void) {
725 return (Domemtrace);
726 }
set_Domemtrace(int s)727 void set_Domemtrace(int s) {
728 Domemtrace = s;
729 return;
730 }
get_Doiotrace(void)731 int get_Doiotrace(void) {
732 return (Doiotrace);
733 }
set_Doiotrace(int s)734 void set_Doiotrace(int s) {
735 Doiotrace = s;
736 return;
737 }
get_IgnoreXforms(void)738 int get_IgnoreXforms(void) {
739 return (IgnoreXforms);
740 }
set_IgnoreXforms(int s)741 void set_IgnoreXforms(int s) {
742 IgnoreXforms = s;
743 return;
744 }
745
746
747 /*!
748 No fancy macros and allocation here please
749 */
SUMA_ParseInput_basics_eng(char * argv[],int argc)750 int SUMA_ParseInput_basics_eng (char *argv[], int argc)
751 {
752
753 static char FuncName[]={"SUMA_ParseInput_basics_eng"};
754 int brk = 0;
755 int kar;
756
757 if (!argv) return (0);
758 set_Domemtrace(1);
759 set_Doiotrace(0);
760
761 /* if (argc < 2) return (0); why insist on two parameters? */
762
763 kar = 1;
764 brk = 0;
765 while (kar < argc) { /* loop accross tracing and debugging
766 command line options */
767 if ((strcmp(argv[kar], "-memdbg") == 0) ||
768 (strcmp(argv[kar], "-yesmall") == 0) ) {
769 fprintf(SUMA_STDOUT,"Warning %s: running in memory trace mode.\n",
770 FuncName);
771 set_Domemtrace(1);
772 brk = 1;
773 }
774
775 if (!brk && (strcmp(argv[kar], "-nomall") == 0)) {
776 fprintf(SUMA_STDOUT,"Warning %s: turning off memory trace mode.\n",
777 FuncName);
778 set_Domemtrace(0);
779 brk = 1;
780 }
781
782 if (!brk && ( (strcmp(argv[kar], "-trace") == 0) ||
783 (strcmp(argv[kar], "-iodbg") == 0)) ){
784 fprintf( SUMA_STDERR,
785 "Warning %s: SUMA running in I/O trace mode.\n", FuncName);
786 set_Doiotrace(1);
787 brk = 1;
788 }
789
790 if (!brk && (strcmp(argv[kar], "-TRACE") == 0)) {
791 fprintf( SUMA_STDERR,
792 "Warning %s: SUMA running in detailed I/O trace mode.\n",
793 FuncName);
794 set_Doiotrace(2);
795 brk = 1;
796 }
797
798 if (!brk &&
799 ( strcmp(argv[kar], "-novolreg") == 0 ||
800 strcmp(argv[kar], "-noxform") == 0)) {
801 set_IgnoreXforms(1);
802 brk = 1;
803 }
804
805 brk = 0;
806 kar ++;
807 }
808
809 return (1);
810 }
811
812 /*!
813 No fancy macros and allocation here please
814 */
SUMA_ParseInput_basics_ns(char * argv[],int argc)815 void SUMA_ParseInput_basics_ns(char *argv[], int argc) /* for non-suma programs */
816 {
817 static char FuncName[]={"SUMA_ParseInput_basics_ns"};
818
819 if (!argv) return;
820 /*if (argc < 2) return; why insist on two parameters? */
821
822 if (!SUMA_ParseInput_basics_eng (argv, argc)) return;
823
824 if (get_Doiotrace()) { SUMA_INOUT_NOTIFY_ON; }
825 if (get_Domemtrace()) { SUMA_MEMTRACE_ON; }
826
827 /* some more special ones */
828 #ifdef USE_TRACING
829 if (get_Doiotrace() == 2) { DBG_trace = 2; }
830 #endif
831
832 return;
833
834 }
835
836 /*!
837 A function version of macro SUMA_TO_LOWER
838 what gets returned is actually the same pointer
839 s but s now points to a lowercase string.
840 */
SUMA_to_lower(char * s)841 char * SUMA_to_lower(char *s) {
842 int i, d;
843 if (s) {
844 d = 'a' - 'A';
845 for (i=0; i < strlen(s); ++i) {
846 if (s[i] >= 'A' && s[i] <= 'Z') s[i] = s[i] + d;
847 }
848 }
849 return(s);
850 }
851
852 /*!**
853
854 Purpose :
855
856 splits a path/filename into its path and filename components
857
858 Usage :
859 Ans = SUMA_StripPath (Name)
860
861
862 Input parameters :
863 \param Name (char *) something like /hello/something
864
865 Returns :
866 \return ans (SUMA_FileName) .Path (char *) and .FileName (char *)
867
868 Support :
869 \sa SUMA_define.h
870
871 NOTE: SUMA_ParseFname() is better than this function
872
873 To Compile as stand alone:
874 gcc -DSUMA_StripPath_STAND_ALONE -Wall -o $1 $1.c -SUMA_lib.a -I/usr/X11R6/include -I./
875 ***/
SUMA_StripPath(char * FileName)876 SUMA_FileName SUMA_StripPath (char *FileName)
877 {/*SUMA_StripPath*/
878 static char FuncName[] = {"SUMA_StripPath"}, PathDelimiter[]={"/"};
879 int i, j, NotFound=1, N_FileName;
880 SUMA_FileName NewName;
881
882 N_FileName = strlen(FileName);
883 if (N_FileName ){
884 i = N_FileName -1;
885 while (i > -1 && NotFound) {
886 if (FileName[i] == PathDelimiter[0]) NotFound = 0;
887 --i;
888 }
889 if (!NotFound && i > -1) {
890 NewName.Path = (char *)SUMA_malloc(sizeof(char)*(N_FileName+1));
891 NewName.FileName = (char *)SUMA_malloc(sizeof(char)*(N_FileName+1));
892 if (NewName.Path == NULL || NewName.FileName == NULL) {
893 SUMA_SL_Err("Failed to allocate");
894 return (NewName);
895 }
896 for (j=0; j<=i+1; ++j) {
897 NewName.Path[j] = FileName[j];
898 }
899 NewName.Path[j] = '\0';
900
901 /*fprintf(stdout,"jbegin=%d/%d\n", i+2, N_FileName);*/
902 for (j=i+2; j < N_FileName; ++j) NewName.FileName[j-i-2] = FileName[j];
903 NewName.FileName[j-i-2] = '\0';
904
905 /* fprintf(stdout,"All Path (%d chars)/%d: %s\n",
906 (i+2), strlen(NewName.Path), NewName.Path);
907 fprintf(stdout,"All FileName (%d chars)/%d: %s\n",
908 (N_FileName-i-2), strlen(NewName.FileName),
909 NewName.FileName); */
910 }
911 else {
912 NewName.Path = (char *)SUMA_malloc(sizeof(char)*(N_FileName+1));
913 NewName.FileName = (char *)SUMA_malloc(sizeof(char)*(N_FileName+1));
914 if (NewName.Path == NULL || NewName.FileName == NULL) {
915 SUMA_SL_Err("Failed to allocate");
916 return (NewName);
917 }
918 sprintf(NewName.Path,"./");
919 sprintf(NewName.FileName,"%s", FileName);
920 }
921 }
922 else {
923 NewName.Path = NULL;
924 NewName.FileName = NULL;
925 }
926 return (NewName);
927 }/*SUMA_StripPath*/
928
SUMA_ShowParsedFname(SUMA_PARSED_NAME * pn,FILE * out)929 SUMA_Boolean SUMA_ShowParsedFname(SUMA_PARSED_NAME *pn, FILE *out)
930 {
931 static char FuncName[]={"SUMA_ShowParsedFname"};
932 char *s=NULL;
933 SUMA_STRING *SS=NULL;
934 SUMA_Boolean LocalHead = NOPE;
935
936 SUMA_ENTRY;
937
938 if (!out) out = SUMA_STDOUT;
939
940 SS = SUMA_StringAppend(NULL, NULL);
941 if (!pn) {
942 SS = SUMA_StringAppend_va(SS, "NULL parsed name");
943 } else {
944 SS = SUMA_StringAppend_va(SS, "AbsPath :%s\n", pn->AbsPath);
945 SS = SUMA_StringAppend_va(SS, "RelDir :%s\n", pn->RelDir);
946 SS = SUMA_StringAppend_va(SS, "RelPath :%s\n", pn->RelPath);
947 SS = SUMA_StringAppend_va(SS, "Path :%s\n", pn->Path);
948 SS = SUMA_StringAppend_va(SS, "FileName :%s\n", pn->FileName);
949 SS = SUMA_StringAppend_va(SS, "Prefix :%s\n", pn->Prefix);
950 SS = SUMA_StringAppend_va(SS, "View :%s\n", pn->View);
951 SS = SUMA_StringAppend_va(SS, "Ext :%s\n", pn->Ext);
952 SS = SUMA_StringAppend_va(SS, "TypeExt :%s\n", pn->TypeExt);
953 SS = SUMA_StringAppend_va(SS, "StorageMode :%d\n", pn->StorageMode);
954 SS = SUMA_StringAppend_va(SS, "StorageModeNm.:%s\n", pn->StorageModeName);
955 SS = SUMA_StringAppend_va(SS, "FileName_NoExt:%s\n", pn->FileName_NoExt);
956 SS = SUMA_StringAppend_va(SS, "FNameNoAfniExt:%s\n", \
957 without_afni_filename_extension(pn->FileName));
958 SS = SUMA_StringAppend_va(SS, "FNameLabel :%s\n", \
959 without_afni_filename_extension(pn->Prefix));
960 SS = SUMA_StringAppend_va(SS, "Col. Selector :%s\n", pn->ColSelect);
961 SS = SUMA_StringAppend_va(SS, "Node Selector :%s\n", pn->NodeSelect);
962 SS = SUMA_StringAppend_va(SS, "Row Selector :%s\n", pn->RowSelect);
963 SS = SUMA_StringAppend_va(SS, "Range Selector:%s\n", pn->RangeSelect);
964 SS = SUMA_StringAppend_va(SS, "Only index col:%d\n", pn->only_index);
965 SS = SUMA_StringAppend_va(SS, "FullName :%s\n", pn->FullName);
966 SS = SUMA_StringAppend_va(SS, "FullName_NoSel:%s\n", pn->FullName_NoSel);
967 SS = SUMA_StringAppend_va(SS, "RelName :%s%s\n",
968 pn->RelPath,pn->FileName);
969 SS = SUMA_StringAppend_va(SS, "HeadName :%s\n", pn->HeadName);
970 SS = SUMA_StringAppend_va(SS, "BrikName :%s\n", pn->BrikName);
971 SS = SUMA_StringAppend_va(SS, "OnDisk :%d\n", pn->OnDisk);
972 SS = SUMA_StringAppend_va(SS, "ExistsAs :%s\n",
973 pn->ExistsAs?pn->ExistsAs:"");
974 SS = SUMA_StringAppend_va(SS, "Size :%d\n", pn->Size);
975 SS = SUMA_StringAppend_va(SS, "NameAsParsed :%s\n", pn->NameAsParsed);
976 SS = SUMA_StringAppend_va(SS, "cwdAsParsed :%s\n", pn->cwdAsParsed);
977
978 }
979
980 SUMA_SS2S(SS,s);
981
982 fprintf(out, "%s", s); SUMA_free(s); s= NULL;
983 fflush(out);
984
985 SUMA_RETURN(YUP);
986 }
987
SUMA_getcwd(void)988 char *SUMA_getcwd(void)
989 {
990 static char FuncName[]={"SUMA_getcwd"};
991 char *cwd = NULL;
992
993 SUMA_ENTRY;
994
995 cwd = (char *)SUMA_malloc(sizeof(char)*(SUMA_MAX_DIR_LENGTH+1));
996 getcwd(cwd, SUMA_MAX_DIR_LENGTH);
997
998 SUMA_RETURN(cwd);
999 }
1000
SUMA_ParseFname(char * FileName,char * ucwd)1001 SUMA_PARSED_NAME * SUMA_ParseFname (char *FileName, char *ucwd)
1002 {
1003 return(SUMA_ParseFname_eng(FileName, ucwd, 1));
1004 }
1005
1006 /*!
1007 \brief ans = SUMA_ParseFname (FileName, cwd, diskcheck);
1008 parses a file name into its elements
1009 \param FileName (char *) obvious ...
1010 \param ucwd (char *) if not null, this is the user supplied current work. dir.
1011 \param diskcheck (int) if not 0 check for file's size and existence on disk
1012 \return ans (SUMA_PARSED_NAME *) pointer to structure with following fields:
1013 .FileName (char *) containing filename without path and without selectors (see below).
1014 if empty .FileName[0] = '\0'
1015 .Path (char *) containing path including last slash.
1016 If no path exists, Path is "./"
1017 .AbsPath (char *) containing absolute path, which is
1018 the same as .Path if .Path starts with '/'
1019 or cwd/.Path if .Path does not start with '/'
1020 AND cwd is specified.
1021 If cwd is null then it is determined inside the function.
1022 .Ext (char *) containing extension including the dot.
1023 If no extension exists, Ext[0] = '\0'
1024 .FileName_NoExt (char *) filename without extension.
1025 .NodeSelect (char *) Node selector part; between ## ; The () were already taken
1026 .ColSelect (char *) Column selector part; between []
1027 .RowSelect (char *) Row selector part; between {}
1028 .RangeSelect (char *) Range selector part; between <>
1029
1030 \sa SUMA_Free_Parsed_Name, SUMA_ShowParsedFname
1031 */
SUMA_ParseFname_eng(char * FileName,char * ucwd,int diskcheck)1032 SUMA_PARSED_NAME * SUMA_ParseFname_eng (char *FileName, char *ucwd,
1033 int diskcheck)
1034 {/*SUMA_ParseFname*/
1035 static char FuncName[]={"SUMA_ParseFname_eng"};
1036 char PathDelimiter='/';
1037 char *cwd=NULL;
1038 int i, j, iExt , iFile, iPath, iColSel, iRowSel, iNodeSel,
1039 iRangeSel, N_FileName, iFirstSel, nc,
1040 iAtSel, only_index;
1041 SUMA_PARSED_NAME *NewName = NULL;
1042 SUMA_Boolean FoundPath = NOPE,
1043 FoundExt, FoundFile, FoundRowSel ,
1044 FoundNodeSel, FoundColSel, FoundRangeSel;
1045 SUMA_Boolean LocalHead = NOPE;
1046
1047 SUMA_ENTRY;
1048
1049
1050 if (!FileName) {
1051 SUMA_S_Err("Null input");
1052 SUMA_RETURN(NULL);
1053 }
1054
1055 /* work cwd */
1056 if (ucwd) {
1057 if (ucwd[0] != '/') {
1058 SUMA_S_Err("Current working directory must start with '/'");
1059 SUMA_RETURN(NULL);
1060 }
1061 cwd = SUMA_copy_string(ucwd);
1062 } else {
1063 cwd = SUMA_getcwd();
1064 if (cwd[0] != '/') {
1065 SUMA_S_Err("STRANGE! Current working directory must start with '/'");
1066 SUMA_free(cwd); cwd = NULL;
1067 SUMA_RETURN(NULL);
1068 }
1069 }
1070 nc = strlen(cwd);
1071 if (cwd[nc-1] == PathDelimiter) { cwd[nc-1] = '\0'; --nc; }
1072
1073 SUMA_LH("Checking chars");
1074 N_FileName = strlen(FileName);
1075 iExt = N_FileName;
1076 iPath = -1;
1077 iFile = 0;
1078 iColSel = -1;
1079 iRowSel = -1;
1080 iNodeSel = -1;
1081 iRangeSel = -1;
1082 iAtSel = -1;
1083 only_index = 0;
1084 iFirstSel = N_FileName;
1085 FoundPath = NOPE;
1086 FoundExt = NOPE;
1087 FoundRowSel = NOPE;
1088 FoundNodeSel = NOPE;
1089 FoundColSel = NOPE;
1090 FoundRangeSel = NOPE;
1091
1092 NewName = (SUMA_PARSED_NAME *) SUMA_calloc(1,sizeof(SUMA_PARSED_NAME));
1093 NewName->NameAsParsed = SUMA_copy_string(FileName);
1094 NewName->cwdAsParsed = SUMA_copy_string(ucwd);
1095
1096 if (N_FileName ){
1097 i = N_FileName -1;
1098 while (i > -1 && !FoundPath) {
1099 if (FileName[i] == '.' && !FoundExt &&
1100 !(FoundColSel && iColSel < 0) && /* Not whilst column selection */
1101 !(FoundRowSel && iRowSel < 0) && /* Not whilst row selection */
1102 !(FoundNodeSel && iNodeSel < 0) && /* Not whilst node selection */
1103 !(FoundRangeSel && iRangeSel < 0) /* Not whilst range selection */ ) {
1104 iExt = i;
1105 FoundExt = YUP;
1106 } else if (FileName[i] == PathDelimiter) {
1107 FoundPath = YUP;
1108 iPath = i;
1109 iFile = i+1;
1110 } else if (FileName[i] == ']') {
1111 FoundColSel = YUP;
1112 } else if (FileName[i] == '[' && FoundColSel) {
1113 iColSel = i; if (iColSel < iFirstSel) iFirstSel = iColSel;
1114 } else if (FileName[i] == '}') {
1115 FoundRowSel = YUP;
1116 } else if (FileName[i] == '{' && FoundRowSel) {
1117 iRowSel = i; if (iRowSel < iFirstSel) iFirstSel = iRowSel;
1118 } else if (FileName[i] == '#' && !FoundNodeSel) {
1119 FoundNodeSel = YUP;
1120 } else if (FileName[i] == '#' && FoundNodeSel) {
1121 iNodeSel = i; if (iNodeSel < iFirstSel) iFirstSel = iNodeSel;
1122 } else if (FileName[i] == '>') {
1123 FoundRangeSel = YUP;
1124 } else if (FileName[i] == '<' && FoundRangeSel) {
1125 iRangeSel = i; if (iRangeSel < iFirstSel) iFirstSel = iRangeSel;
1126 } else if ( 0 && /* Don't need that, using [i] instead */
1127 FileName[i] == '@' && /* Not whilst reading */
1128 !FoundExt && /* pre extension*/
1129 !(FoundColSel && iColSel < 0) && /* column selection */
1130 !(FoundRowSel && iRowSel < 0) && /* row selection */
1131 !(FoundNodeSel && iNodeSel < 0) && /* node selection */
1132 !(FoundRangeSel && iRangeSel < 0) ) {/* range selection */
1133 iAtSel = i; if (iAtSel < iFirstSel) iFirstSel = iAtSel;
1134 only_index = 1;
1135 }
1136 --i;
1137 }
1138
1139 if (FoundColSel && iColSel < 0) {
1140 FoundColSel = NOPE; /* need both of [ ] */
1141 }
1142 if (FoundRowSel && iRowSel < 0) {
1143 FoundRowSel = NOPE; /* need both of { } */
1144 }
1145 if (FoundNodeSel && iNodeSel < 0) {
1146 FoundNodeSel = NOPE; /* need both of # # */
1147 }
1148 if (FoundRangeSel && iRangeSel < 0) {
1149 FoundRangeSel = NOPE; /* need both of < > */
1150 }
1151
1152 if (iFile == iExt) {
1153 /* .file, not an extension */
1154 FoundExt = NOPE;
1155 }
1156
1157 if (iFile == N_FileName) FoundFile = NOPE;
1158 else FoundFile = YUP;
1159
1160 SUMA_LH("Storing stuff");
1161
1162 if (FoundPath) {
1163 NewName->Path = (char *)SUMA_malloc(sizeof(char)*(iPath+2));
1164 for (i=0; i<= iPath; ++i) NewName->Path[i] = FileName[i];
1165 NewName->Path[i] = '\0';
1166 }else {
1167 NewName->Path = (char *)SUMA_malloc(sizeof(char)*(3));
1168 sprintf(NewName->Path, "./");
1169 }
1170 if (NewName->Path[0] == '/') {
1171 NewName->AbsPath = SUMA_copy_string(NewName->Path);
1172 } else {
1173 char *ptmp = NewName->Path;
1174 if (ptmp[0] == '.') {
1175 /* just searching for ./ here? 15 Aug 2011 [rickr]
1176 * ... problem noted by Ryan from Princeton
1177 * if (strstr(NewName->Path,"./") && ptmp[1] == '/') ptmp = ptmp+2;
1178 * else ptmp = ptmp+1; */
1179
1180 if ( ptmp[1] == '/' ) ptmp = ptmp+2;
1181 else if ( ptmp[1] == '\0' ) ptmp = ptmp+1;
1182 }
1183 NewName->AbsPath = SUMA_append_replace_string(cwd, ptmp, "/", 0);
1184 ptmp = NULL;
1185 }
1186 /* store the current directory, and put back the slash */
1187 NewName->RelDir = SUMA_append_string(cwd, "/");
1188 /* get the relative path (assumes both end with / )*/
1189 {
1190 int nback=0, imatch=0;
1191 i=0; /* go as far as the directories match */
1192 while (i < strlen(NewName->RelDir) &&
1193 i < strlen(NewName->AbsPath) &&
1194 NewName->RelDir[i] == NewName->AbsPath[i] ) ++i;
1195 /* backup i until you hit the last '/' */
1196 while (i>=0 && NewName->RelDir[i] != '/') --i;
1197 if (NewName->RelDir[i] == '/') ++i; /* and back up one */
1198
1199 /* how many extra directories do we have left in NewName->RelDir ?*/
1200 imatch = i;
1201 while (i < strlen(NewName->RelDir)) {
1202 if (NewName->RelDir[i] == '/') ++nback;
1203 ++i;
1204 }
1205 NewName->RelPath = SUMA_calloc(sizeof(char),
1206 strlen(NewName->AbsPath)-imatch+nback*3+10);
1207 NewName->RelPath[0]= '\0';
1208 for (i=0; i<nback; ++i) {
1209 strcat(NewName->RelPath, "../");
1210 }
1211 strcat(NewName->RelPath,NewName->AbsPath+imatch);
1212 if (!strlen(NewName->RelPath)) strcat(NewName->RelPath, "./");
1213 }
1214 if (FoundFile) {
1215 NewName->FileName =
1216 (char *)SUMA_malloc(sizeof(char)*(N_FileName - iFile + 2));
1217 for (i=iFile; i< iFirstSel; ++i)
1218 NewName->FileName[i-iFile] = FileName[i];
1219 NewName->FileName[i-iFile] = '\0';
1220 }else {
1221 NewName->FileName = (char *)SUMA_malloc(sizeof(char));
1222 NewName->FileName[0] = '\0';
1223 }
1224
1225 if (FoundExt) {
1226 NewName->FileName_NoExt =
1227 (char *)SUMA_malloc(sizeof(char)*(N_FileName - iFile +2));
1228 NewName->Ext =
1229 (char *)SUMA_malloc(sizeof(char)*(N_FileName - iExt+2));
1230 for (i=iFile; i< iExt; ++i)
1231 NewName->FileName_NoExt[i-iFile] = FileName[i];
1232 NewName->FileName_NoExt[i-iFile] = '\0';
1233 for (i=iExt; i < iFirstSel; ++i)
1234 NewName->Ext[i-iExt] = FileName[i];
1235 NewName->Ext[i-iExt] = '\0';
1236 } else {
1237 NewName->FileName_NoExt = SUMA_copy_string(NewName->FileName);
1238 NewName->Ext = (char *)SUMA_malloc(sizeof(char));
1239 NewName->Ext[0] = '\0';
1240 }
1241
1242 if (FoundNodeSel) {
1243 NewName->NodeSelect = (char *)SUMA_malloc(sizeof(char)*
1244 (N_FileName - iNodeSel + 2));
1245 for (i=iNodeSel; i< N_FileName; ++i) {
1246 NewName->NodeSelect[i-iNodeSel] = FileName[i];
1247 if (FileName[i] == '#' && i >iNodeSel) { ++i; break; }
1248 }
1249 NewName->NodeSelect[i-iNodeSel] = '\0';
1250 }else {
1251 NewName->NodeSelect = (char *)SUMA_malloc(sizeof(char));
1252 NewName->NodeSelect[0] = '\0';
1253 }
1254
1255 if (FoundRowSel) {
1256 NewName->RowSelect = (char *)SUMA_malloc( sizeof(char)*
1257 (N_FileName - iRowSel + 2));
1258 for (i=iRowSel; i< N_FileName; ++i) {
1259 NewName->RowSelect[i-iRowSel] = FileName[i];
1260 if (FileName[i] == '}') { ++i; break; }
1261 }
1262 NewName->RowSelect[i-iRowSel] = '\0';
1263 }else {
1264 NewName->RowSelect = (char *)SUMA_malloc(sizeof(char));
1265 NewName->RowSelect[0] = '\0';
1266 }
1267
1268 if (FoundColSel) {
1269 NewName->ColSelect =
1270 (char *)SUMA_malloc(sizeof(char)*(N_FileName - iColSel + 2));
1271 for (i=iColSel; i< N_FileName; ++i) {
1272 NewName->ColSelect[i-iColSel] = FileName[i];
1273 if (FileName[i] == ']') { ++i; break; }
1274 }
1275 NewName->ColSelect[i-iColSel] = '\0';
1276 if (NewName->ColSelect[1] == 'i') {
1277 only_index = 1;
1278 NewName->ColSelect[0] = '\0';
1279 }
1280 }else {
1281 NewName->ColSelect = (char *)SUMA_malloc(sizeof(char));
1282 NewName->ColSelect[0] = '\0';
1283 }
1284
1285 if (FoundRangeSel) {
1286 NewName->RangeSelect =
1287 (char *)SUMA_malloc( sizeof(char)* (N_FileName - iRangeSel + 2));
1288 for (i=iRangeSel; i< N_FileName; ++i) {
1289 NewName->RangeSelect[i-iRangeSel] = FileName[i];
1290 if (FileName[i] == '>') { ++i; break; }
1291 }
1292 NewName->RangeSelect[i-iRangeSel] = '\0';
1293 }else {
1294 NewName->RangeSelect = (char *)SUMA_malloc(sizeof(char));
1295 NewName->RangeSelect[0] = '\0';
1296 }
1297
1298 NewName->only_index = only_index;
1299
1300 NewName->FullName_NoSel=NULL;
1301 NewName->FullName_NoSel=
1302 SUMA_append_replace_string(NewName->FullName_NoSel,
1303 NewName->AbsPath, "", 1);
1304 NewName->FullName_NoSel=
1305 SUMA_append_replace_string(NewName->FullName_NoSel,
1306 NewName->FileName, "", 1);
1307
1308 NewName->StorageMode = storage_mode_from_prefix(NewName->FullName_NoSel);
1309 NewName->StorageModeName = storage_mode_name(NewName->StorageMode);
1310
1311 NewName->FullName=NULL;
1312 NewName->FullName=
1313 SUMA_append_replace_string(NewName->FullName,
1314 NewName->AbsPath, "", 1);
1315 NewName->FullName=
1316 SUMA_append_replace_string(NewName->FullName,
1317 NewName->FileName, "", 1);
1318 NewName->FullName=
1319 SUMA_append_replace_string(NewName->FullName,
1320 NewName->NodeSelect, "", 1);
1321 NewName->FullName=
1322 SUMA_append_replace_string(NewName->FullName,
1323 NewName->RowSelect, "", 1);
1324 NewName->FullName=
1325 SUMA_append_replace_string(NewName->FullName,
1326 NewName->ColSelect, "", 1);
1327
1328 if (!(NewName->TypeExt = SUMA_copy_string(
1329 find_filename_extension(NewName->FileName)))) {
1330 NewName->TypeExt = SUMA_copy_string("");
1331 }
1332
1333 if (NewName->StorageMode == STORAGE_BY_BRICK) {
1334 int dotted = 0;
1335 NewName->Prefix = SUMA_copy_string(NewName->FileName);
1336 NewName->Prefix[strlen(NewName->FileName)-
1337 strlen(NewName->TypeExt)]='\0';
1338 if (NewName->Prefix[strlen(NewName->Prefix)-1] == '.') {
1339 dotted = 1;
1340 }
1341 if (dotted) {
1342 if (STRING_HAS_SUFFIX(NewName->Prefix, "+orig.") ){
1343 NewName->View = SUMA_copy_string("+orig");
1344 } else if (STRING_HAS_SUFFIX(NewName->Prefix, "+acpc.") ) {
1345 NewName->View = SUMA_copy_string("+acpc");
1346 } else if (STRING_HAS_SUFFIX(NewName->Prefix, "+tlrc.") ){
1347 NewName->View = SUMA_copy_string("+tlrc");
1348 }
1349 NewName->Prefix[strlen(NewName->Prefix)-6]='\0';
1350 } else {
1351 if (STRING_HAS_SUFFIX(NewName->Prefix, "+orig") ) {
1352 NewName->View = SUMA_copy_string("+orig");
1353 } else if (STRING_HAS_SUFFIX(NewName->Prefix, "+acpc") ) {
1354 NewName->View = SUMA_copy_string("+acpc");
1355 } else if (STRING_HAS_SUFFIX(NewName->Prefix, "+tlrc") ) {
1356 NewName->View = SUMA_copy_string("+tlrc");
1357 }
1358 NewName->Prefix[strlen(NewName->Prefix)-5]='\0';
1359 }
1360 } else {
1361 NewName->Prefix = SUMA_copy_string(NewName->FileName);
1362 NewName->View = SUMA_copy_string("");
1363 }
1364 }
1365
1366
1367
1368 if (NewName->StorageMode == STORAGE_BY_BRICK) {
1369 if (NewName->View[0] != '\0') {
1370 NewName->HeadName = SUMA_append_string(NewName->Path,NewName->Prefix);
1371 NewName->HeadName = SUMA_append_replace_string(NewName->HeadName,
1372 NewName->View, "",1);
1373 NewName->BrikName = SUMA_append_string(NewName->HeadName, ".BRIK");
1374 NewName->HeadName = SUMA_append_string(NewName->HeadName, ".HEAD");
1375 } else {
1376 NewName->BrikName = SUMA_copy_string("");
1377 NewName->HeadName = SUMA_copy_string("");
1378 }
1379 } else {
1380 NewName->HeadName = SUMA_append_string(NewName->Path,NewName->FileName);
1381 NewName->BrikName = SUMA_append_string(NewName->Path,NewName->FileName);
1382 }
1383 NewName->OnDisk = -1;
1384 NewName->Size = -1;
1385 if (diskcheck) {
1386 SUMA_LH("Setting OnDisk for %s...", NewName->HeadName);
1387 NewName->OnDisk = THD_is_file(NewName->HeadName);
1388 if (NewName->OnDisk) {
1389 SUMA_LH("Setting filesize for %s...", NewName->HeadName);
1390 NewName->Size = THD_filesize(NewName->HeadName);
1391 }
1392 if (!NewName->OnDisk) {
1393 NewName->ExistsAs = NULL;
1394 if (NewName->View[0] == '\0') {
1395 char *sss = NULL;
1396 /* See if anything is there with
1397 +orig, +acpc, +tlrc anything */
1398 if (!NewName->ExistsAs) {
1399 sss = SUMA_append_replace_string(NewName->Path,"+orig.HEAD",
1400 NewName->Prefix, 0);
1401 if (THD_is_file(sss)) {
1402 NewName->ExistsAs = sss; sss = NULL;
1403 } else {
1404 SUMA_ifree(sss); sss = NULL;
1405 }
1406 }
1407 if (!NewName->ExistsAs) {
1408 sss = SUMA_append_replace_string(NewName->Path,"+acpc.HEAD",
1409 NewName->Prefix, 0);
1410 if (THD_is_file(sss)) {
1411 NewName->ExistsAs = sss; sss = NULL;
1412 } else {
1413 SUMA_ifree(sss); sss = NULL;
1414 }
1415 }
1416 if (!NewName->ExistsAs) {
1417 sss = SUMA_append_replace_string(NewName->Path,"+tlrc.HEAD",
1418 NewName->Prefix, 0);
1419 if (THD_is_file(sss)) {
1420 NewName->ExistsAs = sss; sss = NULL;
1421 } else {
1422 SUMA_ifree(sss); sss = NULL;
1423 }
1424 }
1425 }
1426 } else {
1427 NewName->ExistsAs = SUMA_copy_string(NewName->HeadName);
1428 }
1429 if (!NewName->ExistsAs) { /* no nulls please */
1430 NewName->ExistsAs = (char*)SUMA_malloc(1*sizeof(char));
1431 NewName->ExistsAs[0] = '\0';
1432 }
1433 }
1434 if (LocalHead) {
1435 SUMA_ShowParsedFname(NewName, NULL);
1436 }
1437 if (cwd) SUMA_free(cwd);
1438
1439 SUMA_RETURN (NewName);
1440 }/*SUMA_ParseFname_eng*/
1441
1442 /*!
1443 \brief Lazy function calls to get at various parts of a file name without the
1444 pains of freeing and allocating. Do NOT free the returned string
1445
1446 Valid options for sel:
1447 "pa": path
1448 "Pa": Absolute path
1449 "e": Extension
1450 "fne": filename without path and without extension
1451 "f": filename without path
1452 "F": filename with path
1453
1454 Note that the function can leak ONE allocated and filed SUMA_PARSED_NAME in
1455 a program's life cycle, unless one calls SUMA_FnameGet(NULL, NULL) at the end
1456
1457 WARNING: You can't use this function more than MAX_NUM_STR_FG times as
1458 argument to a *printf command. Otherwise, you'll end up with the
1459 repeated strings for call numbers that exceed MAX_NUM_STR_FG!
1460 */
1461 #define MAX_NUM_STR_FG 10
SUMA_FnameGet(char * Fname,char * sel,char * cccwd)1462 char *SUMA_FnameGet(char *Fname, char *sel, char *cccwd)
1463 {
1464 static char FuncName[]={"SUMA_FnameGet"};
1465 static char str[MAX_NUM_STR_FG]
1466 [SUMA_MAX_DIR_LENGTH+SUMA_MAX_NAME_LENGTH+20]={""};
1467 static char lastid[SUMA_IDCODE_LENGTH]={""};
1468 char *currid=NULL;
1469 static int istr=-1;
1470 static SUMA_PARSED_NAME *ParsedFname=NULL;
1471 SUMA_Boolean LocalHead = NOPE;
1472
1473 SUMA_ENTRY;
1474
1475 istr = (istr+1) % 10;
1476 str[istr][0] = '\0';
1477
1478 if (!Fname) {
1479 /* cleanup */
1480 if (ParsedFname) SUMA_Free_Parsed_Name(ParsedFname); ParsedFname = NULL;
1481 SUMA_RETURN(str[istr]);
1482 }
1483 if (!sel) {
1484 SUMA_S_Err("no selection");
1485 SUMA_RETURN(str[istr]);
1486 }
1487
1488
1489 /* is this a new name?*/
1490 if (!lastid[0]) { /* a fresh start, ParsedFname should be NULL */
1491 if (ParsedFname) {
1492 SUMA_S_Err("Oh boy oh boy, that's not good!");
1493 SUMA_RETURN(str[istr]);
1494 }
1495 if (!(ParsedFname = SUMA_ParseFname(Fname, cccwd)))
1496 SUMA_RETURN(str[istr]);
1497 currid = UNIQ_hashcode(Fname);
1498 strcpy (lastid, currid); /* store id */
1499 free(currid); currid = NULL;
1500 } else {
1501 currid = UNIQ_hashcode(Fname);
1502 if (strcmp(currid,lastid)) { /* different name */
1503 if (ParsedFname) SUMA_Free_Parsed_Name(ParsedFname); /* free the old */
1504 if (!(ParsedFname = SUMA_ParseFname(Fname, cccwd)))
1505 SUMA_RETURN(str[istr]);
1506 strcpy (lastid, currid); /* store id */
1507 } else { /* same name, reuse old stuff */
1508 free(currid); currid = NULL;
1509 }
1510 }
1511 /* Now that you have the parsed name, return what user wants */
1512 if (sel[0] == 'p' && sel[1] == 'a')
1513 strcpy (str[istr], ParsedFname->Path);
1514 else if (sel[0] == 'P' && sel[1] == 'a')
1515 strcpy (str[istr], ParsedFname->AbsPath);
1516 else if (sel[0] == 'f' && sel[1] == '\0')
1517 strcpy (str[istr], ParsedFname->FileName);
1518 else if (sel[0] == 'F' && sel[1] == '\0')
1519 strcpy (str[istr], ParsedFname->FullName);
1520 else if (sel[0] == 'e' && sel[1] == '\0')
1521 strcpy (str[istr], ParsedFname->Ext);
1522 else if (sel[0] == 'f' && sel[1] == 'n' && sel[2] == 'e' )
1523 strcpy (str[istr], ParsedFname->FileName_NoExt);
1524 else if (sel[0] == 'l') {
1525 strcpy (str[istr], without_afni_filename_extension(ParsedFname->Prefix));
1526 } else {
1527 SUMA_S_Err("Selection not understood");
1528 }
1529
1530 if (LocalHead) {
1531 SUMA_ShowParsedFname(ParsedFname, NULL);
1532 fprintf(SUMA_STDERR,
1533 "++ %s\n"
1534 "for >>%s<<\n"
1535 "sel >>%s<<\n"
1536 "ret.>>%s<<\n",
1537 FuncName, Fname, sel, str[istr]);
1538 }
1539
1540 SUMA_RETURN(str[istr]);
1541 }
1542
SUMA_ParseModifyName(char * Fname,char * what,char * val,char * cwd)1543 SUMA_PARSED_NAME * SUMA_ParseModifyName(char *Fname, char *what, char *val,
1544 char *cwd)
1545 {
1546 SUMA_PARSED_NAME *pn=NULL, *pno=NULL;
1547 if (!Fname || !what) return(NULL);
1548 pn = SUMA_ParseFname(Fname, cwd);
1549 if (!pn) return(NULL);
1550 pno = SUMA_ModifyParsedName (pn, what, val);
1551 SUMA_Free_Parsed_Name(pn);
1552 return(pno);
1553 }
1554
SUMA_ModifyName(char * Fname,char * what,char * val,char * cwd)1555 char * SUMA_ModifyName(char *Fname, char *what, char *val, char *cwd)
1556 {
1557 char *oname=NULL;
1558 SUMA_PARSED_NAME *pn=NULL, *pno=NULL;
1559 if (!Fname || !what) return(NULL);
1560 pn = SUMA_ParseFname(Fname, cwd);
1561 if (!pn) return(NULL);
1562 pno = SUMA_ModifyParsedName (pn, what, val);
1563 SUMA_Free_Parsed_Name(pn);
1564 if (pno) {
1565 oname = SUMA_append_replace_string(pno->Path,pno->FileName,"",0);
1566 oname = SUMA_append_replace_string(oname, pno->NodeSelect,"",1);
1567 oname = SUMA_append_replace_string(oname, pno->RowSelect,"",1);
1568 oname = SUMA_append_replace_string(oname, pno->ColSelect,"",1);
1569 SUMA_Free_Parsed_Name(pno);
1570 }
1571 return(oname);
1572 }
1573
SUMA_DuplicateParsedName(SUMA_PARSED_NAME * pn)1574 SUMA_PARSED_NAME * SUMA_DuplicateParsedName(SUMA_PARSED_NAME *pn) {
1575
1576 if (pn && pn->NameAsParsed) {
1577 return(SUMA_ParseFname(pn->NameAsParsed, pn->cwdAsParsed));
1578 }
1579 return(NULL);
1580 }
1581
SUMA_ModifyParsedName(SUMA_PARSED_NAME * pn,char * what,char * val)1582 SUMA_PARSED_NAME * SUMA_ModifyParsedName (SUMA_PARSED_NAME *pn,
1583 char *what, char *val)
1584 {
1585 static char FuncName[]={"SUMA_ModifyParsedName"};
1586 char *fullname=NULL;
1587 SUMA_PARSED_NAME *pno=NULL;
1588
1589 SUMA_ENTRY;
1590
1591 if (!what || !pn) SUMA_RETURN(NULL);
1592
1593 if (!strcmp(what,"prepend")) {
1594 if (!val) SUMA_RETURN(NULL);
1595 if (pn->StorageMode == STORAGE_BY_BRICK) {
1596 fullname=NULL;
1597 if(strstr(pn->NameAsParsed,"/"))
1598 fullname = SUMA_append_replace_string(fullname,
1599 pn->Path, "", 1);
1600 fullname = SUMA_append_replace_string(fullname,
1601 val, "", 1);
1602 fullname = SUMA_append_replace_string(fullname,
1603 pn->Prefix, "", 1);
1604 fullname = SUMA_append_replace_string(fullname,
1605 pn->View, "",1);
1606 fullname = SUMA_append_replace_string(fullname,
1607 pn->TypeExt, "",1);
1608 fullname = SUMA_append_replace_string(fullname,
1609 pn->NodeSelect, "", 1);
1610 fullname = SUMA_append_replace_string(fullname,
1611 pn->RowSelect, "", 1);
1612 fullname = SUMA_append_replace_string(fullname,
1613 pn->ColSelect, "", 1);
1614 pno=SUMA_ParseFname(fullname, pn->RelDir);
1615 SUMA_free(fullname); fullname=NULL;
1616 } else {
1617 fullname=NULL;
1618 if(strstr(pn->NameAsParsed,"/"))
1619 fullname = SUMA_append_replace_string(fullname,
1620 pn->Path, "", 1);
1621 fullname = SUMA_append_replace_string(fullname,
1622 val, "", 1);
1623 fullname = SUMA_append_replace_string(fullname,
1624 pn->Prefix, "", 1);
1625 fullname = SUMA_append_replace_string(fullname,
1626 pn->NodeSelect, "", 1);
1627 fullname = SUMA_append_replace_string(fullname,
1628 pn->RowSelect, "", 1);
1629 fullname = SUMA_append_replace_string(fullname,
1630 pn->ColSelect, "", 1);
1631 pno=SUMA_ParseFname(fullname, pn->RelDir);
1632 SUMA_free(fullname); fullname=NULL;
1633 }
1634 } else if (!strcmp(what,"append")) {
1635 if (!val) SUMA_RETURN(NULL);
1636 if (pn->StorageMode == STORAGE_BY_BRICK) {
1637 fullname=NULL;
1638 if(strstr(pn->NameAsParsed,"/"))
1639 fullname = SUMA_append_replace_string(fullname,
1640 pn->Path, "", 1);
1641 fullname = SUMA_append_replace_string(fullname,
1642 pn->Prefix, "", 1);
1643 fullname = SUMA_append_replace_string(fullname,
1644 val, "", 1);
1645 fullname = SUMA_append_replace_string(fullname,
1646 pn->View, "",1);
1647 fullname = SUMA_append_replace_string(fullname,
1648 pn->TypeExt, "",1);
1649 fullname = SUMA_append_replace_string(fullname,
1650 pn->NodeSelect, "", 1);
1651 fullname = SUMA_append_replace_string(fullname,
1652 pn->RowSelect, "", 1);
1653 fullname = SUMA_append_replace_string(fullname,
1654 pn->ColSelect, "", 1);
1655 pno=SUMA_ParseFname(fullname, pn->RelDir);
1656 SUMA_free(fullname); fullname=NULL;
1657 } else {
1658 fullname=NULL;
1659 if(strstr(pn->NameAsParsed,"/"))
1660 fullname = SUMA_append_replace_string(fullname,
1661 pn->Path, "", 1);
1662 fullname = SUMA_append_replace_string(fullname,
1663 pn->Prefix, "", 1);
1664 fullname[strlen(fullname)-strlen(pn->TypeExt)]='\0';
1665 fullname = SUMA_append_replace_string(fullname,
1666 val, "", 1);
1667 fullname = SUMA_append_replace_string(fullname,
1668 pn->TypeExt, "",1);
1669 fullname = SUMA_append_replace_string(fullname,
1670 pn->NodeSelect, "", 1);
1671 fullname = SUMA_append_replace_string(fullname,
1672 pn->RowSelect, "", 1);
1673 fullname = SUMA_append_replace_string(fullname,
1674 pn->ColSelect, "", 1);
1675 pno=SUMA_ParseFname(fullname, pn->RelDir);
1676 SUMA_free(fullname); fullname=NULL;
1677 }
1678 } else if (!strcmp(what,"view")) {
1679 char vval[6]={""};
1680 if (!val) SUMA_RETURN(NULL);
1681 if (val[0] != '+') sprintf(vval,"+%c%c%c%c",val[0],val[1],val[2],val[3]);
1682 else sprintf(vval,"%c%c%c%c%c",val[0],val[1],val[2],val[3], val[4]);
1683 if (pn->StorageMode == STORAGE_BY_BRICK ||
1684 pn->StorageMode == STORAGE_UNDEFINED) {
1685 fullname=NULL;
1686 if(strstr(pn->NameAsParsed,"/"))
1687 fullname = SUMA_append_replace_string(fullname,
1688 pn->Path, "", 1);
1689 fullname = SUMA_append_replace_string(fullname,
1690 pn->Prefix, "", 1);
1691 fullname = SUMA_append_replace_string(fullname,
1692 vval,"",1);
1693 fullname = SUMA_append_replace_string(fullname,
1694 pn->TypeExt, "",1);
1695 fullname = SUMA_append_replace_string(fullname,
1696 pn->NodeSelect, "", 1);
1697 fullname = SUMA_append_replace_string(fullname,
1698 pn->RowSelect, "", 1);
1699 fullname = SUMA_append_replace_string(fullname,
1700 pn->ColSelect, "", 1);
1701 pno=SUMA_ParseFname(fullname, pn->RelDir);
1702 SUMA_free(fullname); fullname=NULL;
1703 } else {
1704 pno = SUMA_DuplicateParsedName(pn);
1705 }
1706 }
1707
1708 SUMA_RETURN(pno);
1709 }
1710 /*!
1711 \brief ans = SUMA_isExtension(filename, ext);
1712 YUP if filename has the extension ext
1713 */
SUMA_isExtension(char * filename,char * ext)1714 SUMA_Boolean SUMA_isExtension(char *filename, char *ext)
1715 {
1716 static char FuncName[]={"SUMA_isExtension"};
1717 int cnt, N_ext, N_filename;
1718
1719 SUMA_ENTRY;
1720
1721 if (!filename) SUMA_RETURN(NOPE);
1722 if (!ext) SUMA_RETURN(NOPE);
1723 N_ext = strlen(ext);
1724 N_filename = strlen(filename);
1725 if (N_ext > N_filename) SUMA_RETURN(NOPE);
1726
1727 cnt = 1;
1728 while (cnt <= N_ext) {
1729 if (filename[N_filename-cnt] != ext[N_ext-cnt]) SUMA_RETURN(NOPE);
1730 ++cnt;
1731 }
1732
1733 SUMA_RETURN(YUP);
1734 }
1735
SUMA_CropExtension(char * filename,char * ext)1736 char * SUMA_CropExtension(char *filename, char *ext)
1737 {
1738 static char FuncName[]={"SUMA_CropExtension"};
1739 int cnt, N_ext, N_filename;
1740
1741 SUMA_ENTRY;
1742
1743 if (!filename) SUMA_RETURN(filename);
1744 if (!ext) SUMA_RETURN(filename);
1745 N_ext = strlen(ext);
1746 N_filename = strlen(filename);
1747 if (N_ext > N_filename) SUMA_RETURN(filename);
1748
1749 cnt = 1;
1750 while (cnt <= N_ext) {
1751 if (filename[N_filename-cnt] != ext[N_ext-cnt]) SUMA_RETURN(filename);
1752 ++cnt;
1753 }
1754 filename[N_filename-N_ext] = '\0';
1755
1756 SUMA_RETURN(filename);
1757 }
1758
1759 /*!
1760 \brief ans = SUMA_Extension(filename, ext, Remove);
1761 removes or enforces an arbitrary extension from/to a filename
1762
1763 \param filename(char *) input filename
1764 \param ext (char *) extension
1765 \param Remove (SUMA_Boolean) YUP = Remove extension if found
1766 Do nothing if it is not there already
1767 NOPE = Add extension if not there
1768 Do nothing if it is there already
1769 \returns ans (char*) containing modified filename
1770
1771 - You must free ans on your own
1772 Examples:
1773 {
1774 char *ans=NULL;
1775 ans = SUMA_Extension("Junk.niml.roi", ".niml.roi", YUP);
1776 SUMA_LH(ans); SUMA_free(ans);
1777
1778 ans = SUMA_Extension("Junk.niml.roi", ".niml.roi", NOPE);
1779 SUMA_LH(ans); SUMA_free(ans);
1780
1781 ans = SUMA_Extension("Junk.niml.roi", ".niml.roxi", NOPE);
1782 SUMA_LH(ans); SUMA_free(ans);
1783
1784 ans = SUMA_Extension("Junk.niml.roi", ".niml.roxi", YUP);
1785 SUMA_LH(ans); SUMA_free(ans);
1786
1787 ans = SUMA_Extension("Junk.niml.roi", "", YUP);
1788 SUMA_LH(ans); SUMA_free(ans);
1789
1790 ans = SUMA_Extension(".roi", "Junk.niml.roi", NOPE);
1791 SUMA_LH(ans); SUMA_free(ans);
1792
1793 ans = SUMA_Extension("", "", NOPE);
1794 SUMA_LH(ans); SUMA_free(ans);
1795
1796 exit(1);
1797 }
1798
1799 */
1800
SUMA_Extension(char * filename,char * ext,SUMA_Boolean Remove)1801 char *SUMA_Extension(char *filename, char *ext, SUMA_Boolean Remove)
1802 {
1803 static char FuncName[]={"SUMA_Extension"};
1804 char *ans = NULL;
1805 int i, next, nfilename, ifile;
1806 SUMA_Boolean NoMatch = NOPE;
1807 SUMA_Boolean LocalHead = NOPE;
1808
1809 SUMA_ENTRY;
1810
1811 if (!filename) SUMA_RETURN(NULL);
1812 nfilename = strlen(filename);
1813
1814 if (!ext) {
1815 ans = (char *)SUMA_malloc((nfilename+1)*sizeof(char));
1816 ans = strcpy(ans,filename);
1817 SUMA_RETURN(ans);
1818 }
1819 next = strlen(ext);
1820
1821 if (next > nfilename && Remove) {
1822 ans = (char *)SUMA_malloc((nfilename+1)*sizeof(char));
1823 ans = strcpy(ans,filename);
1824 SUMA_RETURN(ans);
1825 }
1826 #if 0
1827 if (nfilename < next || next < 1 || nfilename < 1) {
1828 ans = (char *)SUMA_malloc((nfilename+1)*sizeof(char));
1829 ans = strcpy(ans,filename);
1830 SUMA_RETURN(ans);
1831 }
1832 #endif
1833
1834
1835 ifile = nfilename - next;
1836 if (ifile > 0) {
1837 NoMatch = NOPE;
1838 i = 0;
1839 do {
1840 if (LocalHead)
1841 fprintf (SUMA_STDERR,
1842 "%s: Comparing %c %c\n",
1843 FuncName, filename[ifile+i], ext[i]);
1844 if (filename[ifile+i] != ext[i]) NoMatch = YUP;
1845 ++i;
1846 } while (ifile < nfilename && i < next && !NoMatch);
1847 } else {
1848 NoMatch = YUP;
1849 }
1850
1851 if (NoMatch) {
1852 if (Remove) { /* nothing to do */
1853 SUMA_LH("NoMatch, nothing to do");
1854 ans = (char *)SUMA_malloc((nfilename+1)*sizeof(char));
1855 ans = strcpy(ans,filename);
1856 SUMA_RETURN(ans);
1857 } else { /* add extension */
1858 SUMA_LH("NoMatch, adding extension");
1859 ans = SUMA_append_extension(filename, ext);
1860 SUMA_RETURN(ans);
1861 }
1862 }else {
1863 if (Remove) { /* remove it */
1864 SUMA_LH("Match, removing extension");
1865 ans = (char *)SUMA_malloc((nfilename - next+2)*sizeof(char));
1866 for (i=0; i< nfilename - next; ++i) ans[i] = filename[i];
1867 ans[nfilename - next] = '\0'; /* for good measure */
1868 } else { /* nothing to do */
1869 SUMA_LH("Match, nothing to do");
1870 ans = (char *)SUMA_malloc((nfilename+1)*sizeof(char));
1871 ans = strcpy(ans,filename);
1872 SUMA_RETURN(ans);
1873 }
1874 }
1875
1876 SUMA_RETURN (ans);
1877
1878 }
1879
SUMA_Free_Parsed_Name(SUMA_PARSED_NAME * Test)1880 void *SUMA_Free_Parsed_Name(SUMA_PARSED_NAME *Test)
1881 {
1882 static char FuncName[]={"SUMA_Free_Parsed_Name"};
1883
1884 SUMA_ENTRY;
1885
1886 if (!Test) SUMA_RETURN (NULL);
1887 if (Test->AbsPath) SUMA_free(Test->AbsPath);
1888 if (Test->RelPath) SUMA_free(Test->RelPath);
1889 if (Test->RelDir) SUMA_free(Test->RelDir);
1890 if (Test->Path) SUMA_free(Test->Path);
1891 if (Test->FileName) SUMA_free(Test->FileName);
1892 if (Test->FullName) SUMA_free(Test->FullName);
1893 if (Test->Ext) SUMA_free(Test->Ext);
1894 if (Test->FileName_NoExt) SUMA_free(Test->FileName_NoExt);
1895 if (Test->RowSelect) SUMA_free(Test->RowSelect);
1896 if (Test->ColSelect) SUMA_free(Test->ColSelect);
1897 if (Test->NodeSelect) SUMA_free(Test->NodeSelect);
1898 if (Test->RangeSelect) SUMA_free(Test->RangeSelect);
1899 if (Test->NameAsParsed) SUMA_free(Test->NameAsParsed);
1900 if (Test->cwdAsParsed) SUMA_free(Test->cwdAsParsed);
1901 if (Test->ExistsAs) SUMA_free(Test->ExistsAs);
1902
1903 SUMA_free(Test);
1904
1905 SUMA_RETURN (NULL);
1906 }
1907
1908
1909
1910 /*! Taken from filexists
1911 returns 1 if file can be read/found
1912 */
SUMA_filexists(char * f_name)1913 int SUMA_filexists (char *f_name)
1914 {/*SUMA_filexists*/
1915 FILE *outfile;
1916 static char FuncName[]={"SUMA_filexists"};
1917
1918 SUMA_ENTRY;
1919
1920 outfile = fopen (f_name,"r");
1921 /*fprintf(stderr,"%s %p\n", f_name, outfile);*/
1922 if (outfile == NULL) {
1923 SUMA_RETURN(0);
1924 } else {
1925 fclose (outfile);
1926 }
1927
1928 SUMA_RETURN(1);
1929
1930 }/*SUMA_filexists*/
1931
1932 /*! \brief A function that attempts to find a file that is readable.
1933 If *fname has a full path, then returns 1 if readable, 0 otherwise
1934 If *fname has no path,
1935 Try finding file under SUMAg_cwd/ if found -> 1, else, continue
1936 If a search path is given, then that path is searched
1937 if file is found -> 1 else -> 0
1938 If no search path is given, then path from user's environment is searched.
1939 If file is found, old name is freed and new one put in its place.
1940 */
SUMA_search_file(char ** fnamep,char * epath)1941 int SUMA_search_file(char **fnamep, char *epath)
1942 {
1943 static char FuncName[]={"SUMA_search_file"};
1944 SUMA_PARSED_NAME *pn = NULL;
1945 char dname[THD_MAX_NAME], ename[THD_MAX_NAME], *elocal=NULL, *af=NULL;
1946 int epos=0, ll=0, ii=0, id = 0, imode=1;
1947 SUMA_Boolean LocalHead = NOPE;
1948
1949 SUMA_ENTRY;
1950
1951 /* does it exist? */
1952 if ( SUMA_filexists(*fnamep) ) {
1953 SUMA_LH("Found file %s as named", *fnamep);
1954 SUMA_RETURN(1); /* all is well */
1955 }
1956
1957 SUMA_LH("Searching for variations on %s", *fnamep);
1958 #if defined SUMA_COMPILED
1959 /* else, the hard work, first check with cwd options
1960 for suma programs*/
1961 pn = SUMA_ParseFname(*fnamep, SUMAg_CF->cwd);
1962 if ( SUMA_filexists(pn->FullName) ) {
1963 SUMA_free(*fnamep);
1964 *fnamep = SUMA_copy_string(pn->FullName);
1965 pn = SUMA_Free_Parsed_Name(pn);
1966 SUMA_RETURN(1); /* all is well */
1967 }
1968 pn = SUMA_Free_Parsed_Name(pn);
1969 /* try again perhaps for compressed data */
1970 elocal = SUMA_append_string(*fnamep, ".gz");
1971 pn = SUMA_ParseFname(elocal, SUMAg_CF->cwd);
1972 if ( SUMA_filexists(pn->FullName) ) {
1973 SUMA_free(*fnamep);
1974 *fnamep = SUMA_copy_string(pn->FullName);
1975 pn = SUMA_Free_Parsed_Name(pn);
1976 SUMA_RETURN(2); /* all is well */
1977 }
1978 pn = SUMA_Free_Parsed_Name(pn);
1979 #endif
1980
1981 /* Now work the path (based on code form get_atlas function */
1982 if (!epath) {
1983 #if 0 /* overkill, as Yaroslav Halchenko pointed out*/
1984 epath = getenv("PATH") ;
1985 if( epath == NULL ) SUMA_RETURN(NOPE) ; /* nothing left to do */
1986 #else
1987 /* Search in AFNI's standard locations */
1988 af = find_afni_file(*fnamep, 0, NULL);
1989 if (af[0] != '\0') {
1990 SUMA_free(*fnamep);
1991 *fnamep = SUMA_copy_string(af);
1992 SUMA_RETURN(1);
1993 }
1994 #endif
1995 SUMA_RETURN(NOPE); /* miserable pathless failure */
1996 }
1997
1998 /*----- copy path list into local memory -----*/
1999
2000 ll = strlen(epath) ;
2001 elocal = (char *)SUMA_calloc(ll+2, sizeof(char));
2002
2003 /*----- put a blank at the end -----*/
2004 strcpy( elocal , epath ) ; elocal[ll] = ' ' ; elocal[ll+1] = '\0' ;
2005
2006 /*----- replace colons with blanks -----*/
2007 for( ii=0 ; ii < ll ; ii++ )
2008 if( elocal[ii] == ':' ) elocal[ii] = ' ' ;
2009
2010 /*----- extract blank delimited strings;
2011 use as directory names to look for atlas -----*/
2012 imode = 1;
2013 while (imode < 3) {
2014 epos = 0 ;
2015 do{
2016 ii = sscanf( elocal+epos , "%s%n" , ename , &id ); /* next substring */
2017 if( ii < 1 ) break ; /* none -> done */
2018
2019 epos += id ; /* char after last scanned */
2020
2021 ii = strlen(ename) ; /* make sure name has */
2022 if( ename[ii-1] != '/' ){ /* a trailing '/' on it */
2023 ename[ii] = '/' ; ename[ii+1] = '\0' ;
2024 }
2025 strcpy(dname,ename) ;
2026 SUMA_strncat(dname,*fnamep, THD_MAX_NAME-1) ; /* add dataset name */
2027 if (imode == 2) {
2028 SUMA_strncat(dname,".gz", THD_MAX_NAME-1); /* add compression flag */
2029 }
2030 if ( SUMA_filexists(dname) ) {
2031 SUMA_free(*fnamep); *fnamep = SUMA_copy_string(dname);
2032 SUMA_free(elocal); elocal=NULL;
2033 SUMA_RETURN(imode); /* all is well */
2034 }
2035
2036 } while( epos < ll ) ; /* scan until 'epos' is after end of epath */
2037 ++imode;
2038 }
2039 /* nothing */
2040 SUMA_free(elocal); elocal=NULL;
2041
2042 SUMA_RETURN(0); /* bummer */
2043 }
2044
2045 /*!
2046 \brief function that tests whether a string contains N numbers
2047
2048 WARNING: This function will deform s !
2049
2050 \param str (char *) null terminated string
2051 \param N (void *) This is an integer in disguise
2052 \return 1: If str is NULL or N numbers were found in str
2053
2054 \sa SUMA_isNumString
2055 */
SUMA_CleanNumString(char * s,void * p)2056 int SUMA_CleanNumString (char *s, void *p)
2057 {
2058 static char FuncName[]={"SUMA_CleanNumString"};
2059 char *endp, *strtp;
2060 int nd, N;
2061 int eos, FoundTip;
2062 double d;
2063 int LocalHead = 0;
2064
2065 SUMA_ENTRY;
2066
2067 if (!s) SUMA_RETURN(1);
2068
2069 #if INT_MAX < LONG_MAX
2070 N = (int)(long int)p;
2071 #else
2072 N = (int)p;
2073 #endif
2074
2075 /* clean s by removing trailing junk then replacing non characters by space*/
2076 if (LocalHead) fprintf (stderr, "%s: string begins:%s:\n", FuncName, s);
2077 FoundTip = 0;
2078 for (nd=strlen(s)-1; nd >=0; --nd) {
2079 if (!isdigit(s[nd]) && s[nd] != '.' && s[nd] != '-' && s[nd] != '+') {
2080 if (!FoundTip) {
2081 s[nd]= '\0'; /* remove */
2082 } else {
2083 s[nd] = ' '; /* blank */
2084 }
2085 }else {
2086 FoundTip = 1;
2087 }
2088 }
2089
2090 if (LocalHead) fprintf (stderr, "%s: string now:%s:\n", FuncName, s);
2091 if (strlen(s) == 1 && (s[0] == '+' || s[0] == '-' || s[0] == '.')) {
2092 SUMA_RETURN(0);
2093 }
2094
2095 /* parse s */
2096 strtp = s;
2097 endp = NULL;
2098 nd = 0;
2099 eos = 0;
2100 while (!eos) {
2101 errno=0;
2102 d = strtod(strtp, &endp);
2103 /* See SUMA_strtod() for an example on exception handling for strtod */
2104 SUMA_LHv("value %f, ERANGE: %d, EDOM %d, errno %d\n",
2105 d, ERANGE, EDOM, errno);
2106
2107
2108 if (endp == strtp && *endp=='\0') {
2109 eos = 1;
2110 } else {
2111 strtp = endp;
2112 ++nd;
2113 if (nd > N && nd > 1000) {
2114 SUMA_SL_Err("Fishy fish");
2115 fprintf (stderr, "%s: >>>%s<<<", FuncName, s);
2116 SUMA_RETURN(0);
2117 }
2118 }
2119 }
2120
2121 if (LocalHead) fprintf (stderr,"%s: Read %d/%d values.\n", FuncName, nd,N);
2122 if (N != nd) {
2123 SUMA_RETURN(0);
2124 } else {
2125 SUMA_RETURN(1);
2126 }
2127
2128 }
2129
SUMA_CleanNumStringSide(char * s,void * p)2130 int SUMA_CleanNumStringSide (char *s, void *p)
2131 {
2132 static char FuncName[]={"SUMA_CleanNumStringSide"};
2133 char *s2=NULL, c ='\0';
2134 int nn=0;
2135
2136 SUMA_ENTRY;
2137
2138 if (!s) SUMA_RETURN(SUMA_CleanNumString(s,p));
2139 deblank_name(s);
2140
2141 nn = strlen(s);
2142 if (s[0]=='r' || s[0]=='R') {
2143 c = 'R';
2144 s2 = SUMA_copy_string(s+1);
2145 } else if (s[nn-1]=='r' || s[nn-1]=='R') {
2146 c = 'R';
2147 s[nn-1]='\0'; s2 = SUMA_copy_string(s);
2148 } else if (s[0]=='l' || s[0]=='L') {
2149 c = 'L';
2150 s2 = SUMA_copy_string(s+1);
2151 } else if (s[nn-1]=='l' || s[nn-1]=='L') {
2152 c = 'L';
2153 s[nn-1]='\0'; s2 = SUMA_copy_string(s);
2154 } else {
2155 /* nothing to do */
2156 SUMA_RETURN(SUMA_CleanNumString(s,p));
2157 }
2158
2159 /* Now clean s2 */
2160 s2 = SUMA_copy_string(s);
2161 nn = SUMA_CleanNumString(s2,p);
2162
2163 /* Put side back in string */
2164 sprintf(s,"%c%s",c,s2);
2165 SUMA_free(s2); s2=NULL;
2166
2167 SUMA_RETURN(nn);
2168 }
2169
2170 /*
2171 Much like SUMA_CleanNumString, but leaves s untouched
2172 */
SUMA_isNumString(char * s,void * p)2173 int SUMA_isNumString (char *s, void *p)
2174 {
2175 static char FuncName[]={"SUMA_isNumString"};
2176 int ans;
2177 char *sc;
2178
2179 SUMA_ENTRY;
2180
2181 sc = SUMA_copy_string(s);
2182 ans = SUMA_CleanNumString(sc,p);
2183 if(sc) SUMA_free(sc); sc = NULL;
2184 SUMA_RETURN(ans);
2185 }
2186
2187
SUMA_NumStringUnits(char * s,int marktip)2188 int SUMA_NumStringUnits (char *s, int marktip)
2189 {
2190 static char FuncName[]={"SUMA_NumStringUnits"};
2191 int unt = SUMA_NO_NUM_UNITS;
2192 int FoundTip = 0, nd = 0, ndm=0, tiploc=-1;
2193 int LocalHead = 0;
2194
2195 SUMA_ENTRY;
2196
2197 if (!s) SUMA_RETURN(unt);
2198
2199 /* go back until you hit the tip of the number */
2200 FoundTip = 0;
2201 ndm = strlen(s);
2202 nd=ndm-1;
2203 while ( nd >=0 && !FoundTip) {
2204 if (isdigit(s[nd]) || s[nd] == '.' || s[nd] == '-' || s[nd] == '+') {
2205 FoundTip = 1;
2206 } else {
2207 --nd;
2208 }
2209 }
2210 SUMA_LHv("Fount tip %d on %s at %d\n",FoundTip, s, nd);
2211 if (!FoundTip) SUMA_RETURN(unt);
2212
2213
2214 /* now move forward, skipping blanks, commas, parenthesis */
2215 SUMA_LH("Got tip, goind forward");
2216 ++nd;
2217 FoundTip = 0;
2218 tiploc = -1;
2219 while (nd < ndm && !FoundTip) {
2220 if ( isspace(s[nd]) || s[nd] == ',' ||
2221 s[nd] == '[' || s[nd] == '(' || s[nd] == '{') {
2222 ++nd;
2223 } else {
2224 FoundTip = 1;
2225 tiploc=nd;
2226 }
2227 }
2228 SUMA_LHv("Fount tip %d on %s at %d\n",FoundTip, s, nd);
2229
2230 /* now look for unit string */
2231 SUMA_LH("%s",(s+nd));
2232 unt = SUMA_NO_NUM_UNITS;
2233 if (0) ; /* order of following else ifs matters */
2234 else if (!strncmp((s+nd), "mm", 2))
2235 unt = SUMA_MM_UNITS;
2236 else if (!strncmp((s+nd), "p", 1))
2237 unt = SUMA_P_VALUE_UNITS;
2238 else if (!strncmp((s+nd), "q",1))
2239 unt = SUMA_Q_VALUE_UNITS;
2240 else if (!strncmp((s+nd), "%",1))
2241 unt = SUMA_PERC_VALUE_UNITS;
2242
2243 if (marktip && tiploc>-1) s[tiploc] = '\0';
2244
2245 SUMA_RETURN(unt);
2246 }
2247
SUMA_strtod(char * n,double * valp)2248 int SUMA_strtod(char *n, double *valp)
2249 {
2250 static char FuncName[]={"SUMA_strtod"};
2251 char *stp=NULL;
2252 SUMA_Boolean LocalHead = NOPE;
2253
2254 SUMA_ENTRY;
2255 if (!n || !valp) SUMA_RETURN(0);
2256
2257 errno = 0;
2258 *valp = strtod (n, &stp);
2259
2260 #if 0
2261 /* Not all constants below are standard */
2262 SUMA_LHv("s=%s, stp=%s, val=%f, \n"
2263 "errno=%d, HUGE_VAL=%g,%Lg,%g, EINVAL=%d,ERANGE=%d\n",
2264 (char *)n, CHECK_NULL_STR(stp), *valp, errno,
2265 HUGE_VAL, HUGE_VALL, HUGE_VALF, EINVAL, ERANGE);
2266 #endif
2267
2268 if ((errno == ERANGE &&(*valp == LONG_MAX || *valp == LONG_MIN))
2269 || (errno != 0 && *valp == 0) ||
2270 stp == n /* nothing numeric was read */) {
2271 SUMA_RETURN(0);
2272 }
2273
2274 /* all is well */
2275 SUMA_RETURN(1);
2276 }
2277
2278 /*!
2279 \brief function that parses a string of numbers into a float vector
2280
2281 \param str (char *) null terminated string
2282 \param vv (void*) vector where values will be stored
2283 \param N (int) This is the number of values desired
2284 \param prec (int) 1=float 2=double
2285 \return int: This is the number of values read.
2286 The function will not register in fv more than N values
2287 (to keep from running over preallocated space), but it
2288 will return the full number of values found.
2289
2290 -1 in case of error
2291 \sa SUMA_CleanNumString
2292 \sa SUMA_strtol_vec
2293 \sa SUMA_AdvancePastNumbers
2294 \sa SUMA_NumStringUnits
2295 */
2296
SUMA_StringToNum(char * s,void * vv,int N,int prec)2297 int SUMA_StringToNum (char *s, void *vv, int N, int prec)
2298 {
2299 static char FuncName[]={"SUMA_StringToNum"};
2300 char *endp, *strtp;
2301 int nd;
2302 int eos, FoundTip;
2303 double d;
2304 float *fv=NULL;
2305 double *dv=NULL;
2306 int LocalHead = 0;
2307
2308 SUMA_ENTRY;
2309
2310 if (!s || prec < 1) SUMA_RETURN(0);
2311
2312 if (LocalHead) fprintf (stderr, "%s: string was:%s:\n", FuncName, s);
2313 /* clean s by removing trailing junk then replacing non characters by space*/
2314 FoundTip = 0;
2315 for (nd=strlen(s)-1; nd >=0; --nd) {
2316 if (!SUMA_IS_NUM_CHAR(s,nd)) {
2317 if (!FoundTip) {
2318 s[nd]= '\0'; /* remove */
2319 } else {
2320 s[nd] = ' '; /* blank */
2321 }
2322 }else {
2323 FoundTip = 1;
2324 }
2325 }
2326
2327 if (LocalHead) fprintf (stderr, "%s: string now:%s:\n", FuncName, s);
2328
2329 if (prec > 1) dv = (double *)vv;
2330 else fv = (float *)vv;
2331
2332 /* parse s */
2333 strtp = s;
2334 endp = NULL;
2335 nd = 0;
2336 eos = 0;
2337 while (!eos) {
2338 errno = 0;
2339 d = strtod(strtp, &endp);
2340 /* See SUMA_strtod() for an example on exception handling for strtod */
2341
2342 if (endp == strtp && *endp=='\0') {
2343 eos = 1;
2344 } else {
2345 if (nd < N) {
2346 if (prec > 1) dv[nd] = d;
2347 else fv[nd] = (float)d;
2348 }
2349 strtp = endp;
2350 ++nd;
2351 if (nd > N && nd >1000) {
2352 SUMA_SL_Err("Something's fishy");
2353 fprintf (stderr, "s = >>>%s<<<\nnd = %d\n", s, nd);
2354 SUMA_RETURN(-1);
2355 }
2356 }
2357 }
2358
2359 if (LocalHead) fprintf (stderr,"%s: Read %d/%d values.\n", FuncName, nd, N);
2360
2361 SUMA_RETURN(nd);
2362
2363 }
2364
2365 /* Like SUMA_StringToNum but looks for side flags in beginning or end
2366 Those would be L or R at the very beginning or very end.
2367 Function also deblanks s
2368 */
SUMA_StringToNumSide(char * s,void * vv,int N,int prec,int * Side)2369 int SUMA_StringToNumSide(char *s, void *vv, int N, int prec, int *Side)
2370 {
2371 static char FuncName[]={"SUMA_StringToNumSide"};
2372 int nn = 0;
2373
2374 SUMA_ENTRY;
2375
2376 *Side = SUMA_NO_SIDE;
2377 if (!s) SUMA_RETURN(SUMA_StringToNum(s,vv,N,prec));
2378
2379 deblank_name(s);
2380 /* Could get something like 'v"55R"' from DriveSuma. clean a little */
2381 if (s[0] == 'v') {
2382 ++s;
2383 dequote_name(s, '\0');
2384 }
2385 nn = strlen(s);
2386 if (s[0]=='r' || s[0]=='R') {
2387 *Side = SUMA_RIGHT;
2388 ++s;
2389 } else if (s[nn-1]=='r' || s[nn-1]=='R') {
2390 *Side = SUMA_RIGHT;
2391 s[nn-1]='\0';
2392 } else if (s[0]=='l' || s[0]=='L') {
2393 *Side = SUMA_LEFT;
2394 ++s;
2395 } else if (s[nn-1]=='l' || s[nn-1]=='L') {
2396 *Side = SUMA_LEFT;
2397 s[nn-1]='\0';
2398 }
2399
2400 SUMA_RETURN(SUMA_StringToNum(s,vv,N,prec));
2401 }
2402
2403
2404 /*!
2405 \brief forces a string to be of a certain length.
2406 If truncation is necessary, ... are inserted at
2407 the end of the string.
2408
2409 You need to free the returned pointer
2410 */
SUMA_set_string_length(char * buf,char cp,int n)2411 char *SUMA_set_string_length(char *buf, char cp, int n)
2412 {
2413 static char FuncName[]={"SUMA_set_string_length"};
2414 char *lbl=NULL, *lbl30=NULL;
2415
2416 SUMA_ENTRY;
2417
2418 if (!buf) SUMA_RETURN(NULL);
2419
2420 lbl = SUMA_truncate_string (buf, n);
2421 if (!lbl) {
2422 SUMA_SL_Err("Failed to truncate");
2423 SUMA_RETURN(NULL);
2424 }
2425
2426 if (strlen(lbl) != n) {
2427 lbl30 = SUMA_pad_string(lbl, cp, n, 1);
2428 SUMA_free(lbl); lbl = NULL;
2429 } else {
2430 lbl30 = lbl; lbl = NULL;
2431 }
2432
2433 SUMA_RETURN(lbl30);
2434 }
2435
2436 /*!
2437 \brief padds a string to a certain length.
2438 You can use this function to crop a string to
2439 the specified number of characters n
2440 Padding is done with character cp
2441 The original string is not modified.
2442
2443 s_tr = SUMA_pad_string(s1, cp, n, add2end);
2444
2445 \sa SUMA_pad_str
2446 \sa SUMA_truncate_string
2447 - free returned pointer with: if(s_tr) SUMA_free(s_tr);
2448 */
SUMA_pad_string(char * buf,char cp,int n,int add2end)2449 char *SUMA_pad_string(char *buf, char cp, int n, int add2end)
2450 {
2451 static char FuncName[]={"SUMA_pad_string"};
2452 char *atr = NULL;
2453 int i, ib, nb;
2454 SUMA_Boolean LocalHead = NOPE;
2455
2456 SUMA_ENTRY;
2457
2458 if (!buf) SUMA_RETURN(NULL);
2459
2460 atr = (char *) SUMA_calloc(n+2, sizeof(char));
2461 nb = strlen(buf);
2462
2463 if (add2end) { /* add to end */
2464 i=0;
2465 while (i < n) {
2466 if (i<nb) atr[i] = buf[i];
2467 else atr[i] = cp;
2468 ++i;
2469 }
2470 atr[i] = '\0';
2471 } else {
2472 atr[n] = '\0';
2473 i = n -1;
2474 ib = nb - 1;
2475 while (i >= 0) {
2476 if (ib >=0) atr[i] = buf[ib];
2477 else atr[i] = cp;
2478 --i; --ib;
2479 }
2480
2481 }
2482
2483 if (LocalHead) {
2484 fprintf(SUMA_STDERR,"%s:\nin\t:%s:\nout\t:%s:\n", FuncName, buf, atr);
2485 }
2486 SUMA_RETURN(atr);
2487 }
2488
2489 /*!
2490 \brief truncates a string to a certain length.
2491 Adds ... as the last characters of the string
2492 The original string is not modified.
2493
2494 s_tr = SUMA_truncate_string(s1, n);
2495
2496 - free returned pointer with: if(s_tr) SUMA_free(s_tr);
2497 */
SUMA_truncate_string(char * buf,int n)2498 char *SUMA_truncate_string(char *buf, int n)
2499 {
2500 static char FuncName[]={"SUMA_truncate_string"};
2501 char *atr = NULL;
2502 int i;
2503
2504 SUMA_ENTRY;
2505
2506 if (!buf) SUMA_RETURN(NULL);
2507
2508 if (n < 5) {
2509 fprintf(stderr,"Error %s:\nNot worth the effort. N < 5.", FuncName);
2510 SUMA_RETURN(NULL);
2511 }
2512
2513 if (strlen(buf) <= n) {
2514 atr = (char *) SUMA_calloc(strlen(buf)+2, sizeof(char));
2515 sprintf(atr, "%s", buf);
2516 SUMA_RETURN (atr);
2517 }else {
2518 atr = (char *) SUMA_calloc(n+3, sizeof(char));
2519 i=0;
2520 while (i < n - 3) {
2521 atr[i] = buf[i];
2522 ++i;
2523 }
2524 atr[i] = atr[i+1] = atr[i+2] = '.';
2525 atr[i+3] = '\0';
2526 }
2527
2528 SUMA_RETURN(atr);
2529 }
2530
2531 /*!
2532 \brief returns a copy of a null terminated string .
2533 s_cp = SUMA_copy_string(s1);
2534
2535 - free returned pointer with: if(s_cp) SUMA_free(s_cp);
2536 */
SUMA_copy_string(char * buf)2537 char *SUMA_copy_string(char *buf)
2538 {
2539 static char FuncName[]={"SUMA_copy_string"};
2540 char *atr = NULL;
2541 int i;
2542
2543 SUMA_ENTRY;
2544
2545 if (!buf) SUMA_RETURN(NULL);
2546
2547 atr = (char *) SUMA_calloc(strlen(buf)+2, sizeof(char));
2548
2549 i=0;
2550 while (buf[i]) {
2551 atr[i] = buf[i];
2552 ++i;
2553 }
2554 atr[i] = '\0';
2555
2556 SUMA_RETURN(atr);
2557 }
2558
2559 /*!
2560 brief Return a copy of string between quotes q1 and q2
2561 s (char*) input string
2562 eop (char *) if != NULL, stop when s reaches eop, else keep going
2563 till end of s if necessary
2564 q1 (char) opening quote. If '\0', take opening quote as s[0]
2565 after you deblank s
2566 q2 (char) closing quote. If '\0', q2 = q1
2567 is_closed (int *) on return, set to 1 if found opening and closing quotes
2568 0 otherwise
2569 deblank (int) remove blanks after q1 and before q2
2570 withqotes (int) if 1 then put quotes back on output
2571
2572 returns qs (char *) the quoted string. Free with SUMA_free(qs);
2573 */
SUMA_copy_quoted(char * s,char * eop,char q1,char q2,int deblank,int withquotes,int * is_closed)2574 char *SUMA_copy_quoted( char *s, char *eop,
2575 char q1, char q2,
2576 int deblank, int withquotes,
2577 int *is_closed ) {
2578 static char FuncName[]={"SUMA_copy_quoted"};
2579 char *strn=NULL;
2580 char *op=s, *op2=NULL;
2581
2582 SUMA_ENTRY;
2583
2584 if (!s) SUMA_RETURN(strn);
2585 SUMA_SKIP_BLANK(s,eop);
2586
2587 op=s;
2588 if (q1 == '\0') { q1=*op;}
2589 if (q2 == '\0') { q2=q1; }
2590
2591 SUMA_SKIP_TO_NEXT_CHAR(op, eop, q1);
2592
2593 op2=op+1;
2594 SUMA_SKIP_TO_NEXT_CHAR(op2, eop, q2);
2595
2596 /* decide on closure, op and op2 are at the quotes*/
2597 if (is_closed) {
2598 if (*op == q1 && *op2 == q2) *is_closed = 1;
2599 else *is_closed = 0;
2600 }
2601 /* deblanking */
2602 if (deblank) {
2603 /* move up from q1 and skip blanks */
2604 ++op;
2605 while (SUMA_IS_BLANK(*op) && op < op2) { ++op; }
2606 --op; *op=q1;/* go back one and put q1 back */
2607
2608 /* move down from q2 and skip blanls */
2609 --op2;
2610 while (SUMA_IS_BLANK(*op2) && op2 > op) { --op2; }
2611 ++op2; *op2=q2;/* go forward one and put q2 back */
2612 }
2613
2614 if (withquotes) { ++op2; SUMA_COPY_TO_STRING(op,op2,strn); }
2615 else { ++op; SUMA_COPY_TO_STRING(op,op2,strn);}
2616
2617 SUMA_RETURN(strn);
2618 }
2619
2620 /*!
2621 Put all arguments between opening and closing quotes into one string
2622 The function starts by looking for argv[*kar] that begins with opq
2623 If opq is found, it continues looking until it finds argv[K] with ends
2624 with cloq. If a closing quote is found, a catenation of all the argvs
2625 is returned. Also *kar is updated to indicate the last used argument.
2626 */
args_in_quotes(char ** argv,int * kar,int N_argv,char * opq,char * cloq,int clearused)2627 char *args_in_quotes(char **argv, int *kar, int N_argv,
2628 char *opq, char *cloq, int clearused)
2629 {
2630 static char FuncName[]={"args_in_quotes"};
2631 char *aq=NULL;
2632 int n, closed, n2;
2633 SUMA_Boolean LocalHead=NOPE;
2634
2635 SUMA_ENTRY;
2636
2637 if (!argv || !N_argv || !kar || *kar >= N_argv || !opq) RETURN(aq);
2638
2639 n = *kar;
2640 if (begins_with(argv[n], opq,1)) {
2641 aq = SUMA_copy_string(argv[n]);
2642 } else {
2643 SUMA_RETURN(NULL);
2644 }
2645 SUMA_LHv("Begin aq %s, n=%d, argv[n]=%s, N=%d\n", aq, n, argv[n], N_argv);
2646 closed = 0;
2647 while (!(closed=ends_with(argv[n],cloq,1)) && n<N_argv-1) {
2648 aq = SUMA_append_replace_string(aq,argv[++n]," ",1);
2649 SUMA_LHv("added aq %s, n=%d, argv[n]=%s, N=%d\n", aq, n, argv[n], N_argv);
2650 }
2651 if (!closed) {
2652 SUMA_LHv("Could not find closing %s\n",cloq);
2653 SUMA_free(aq);
2654 aq = NULL;
2655 } else {
2656 if (clearused) {
2657 n2 = *kar;
2658 while (n2 < n) {
2659 argv[n2][0] = '\0'; ++n2;
2660 }
2661 }
2662 *kar = n; /* the last argument to be used */
2663 }
2664
2665 SUMA_RETURN(aq);
2666 }
2667
args_in_niml_quotes(char ** argv,int * kar,int N_argv,int clearused)2668 char *args_in_niml_quotes(char **argv, int *kar, int N_argv, int clearused)
2669 {
2670 char *aq=NULL;
2671
2672 if ((aq=args_in_quotes(argv, kar, N_argv,"<","/>", clearused))) {
2673 return(aq);
2674 } else if ((aq=args_in_quotes(argv, kar, N_argv,"'<","/>'", clearused))) {
2675 return(aq);
2676 } else if ((aq=args_in_quotes(argv, kar, N_argv,"\"<","/>\"", clearused))) {
2677 return(aq);
2678 }
2679 return(NULL);
2680 }
2681
args_in_simple_quotes(char ** argv,int * kar,int N_argv,int clearused)2682 char *args_in_simple_quotes(char **argv, int *kar, int N_argv, int clearused)
2683 {
2684 char *aq=NULL;
2685
2686 if ((aq=args_in_quotes(argv, kar, N_argv,"'","'", clearused))) {
2687 return(aq);
2688 } else if ((aq=args_in_quotes(argv, kar, N_argv,"\"","\"", clearused))) {
2689 return(aq);
2690 }
2691 return(NULL);
2692 }
2693
SUMA_append_extension(char * s1,char * s2)2694 char * SUMA_append_extension(char *s1, char *s2)
2695 {
2696 static char FuncName[]={"SUMA_append_extension"};
2697 char *s1c = NULL;
2698 int ns1c=0;
2699
2700 SUMA_ENTRY;
2701
2702 /* remove last dot */
2703 if (s1) {
2704 s1c = SUMA_copy_string(s1);
2705 ns1c = strlen(s1);
2706 if (s1c[ns1c-1]=='.') s1c[ns1c-1]='\0';
2707 }
2708
2709 /* remove first dot */
2710 if (s2 && s2[0] == '.') ++s2;
2711
2712 /* put them together */
2713 SUMA_RETURN(SUMA_append_replace_string(s1c, s2, ".", 1));
2714 }
2715
2716 /*!
2717 \brief appends two null terminated strings.
2718
2719 s_ap = SUMA_append_string(s1, s2);
2720
2721 - s1 and s2 are copied into a new string
2722 -free returned pointer with: if(s_ap) SUMA_free(s_ap);
2723 - None of the strings passed to the function
2724 are freed.
2725
2726 \sa SUMA_append_replace_string
2727 */
SUMA_append_string(char * s1,char * s2)2728 char * SUMA_append_string(char *s1, char *s2)
2729 {
2730 static char FuncName[]={"SUMA_append_string"};
2731 char *atr = NULL;
2732 int i,cnt, N_s2, N_s1;
2733
2734
2735 SUMA_ENTRY;
2736
2737 if (!s1 && !s2) SUMA_RETURN(NULL);
2738 if (!s1) N_s1 = 0;
2739 else N_s1 = strlen(s1);
2740
2741 if (!s2) N_s2 = 0;
2742 else N_s2 = strlen(s2);
2743
2744 atr = (char *) SUMA_calloc(N_s1+N_s2+2, sizeof(char));
2745
2746 /* copy first string */
2747 cnt = 0;
2748 if (N_s1){
2749 i=0;
2750 while (s1[i]) {
2751 atr[cnt] = s1[i];
2752 ++i;
2753 ++cnt;
2754 }
2755 }
2756 if (N_s2) {
2757 i=0;
2758 while (s2[i]) {
2759 atr[cnt] = s2[i];
2760 ++i;
2761 ++cnt;
2762 }
2763 }
2764 atr[cnt] = '\0';
2765
2766 SUMA_RETURN(atr);
2767 }
2768
2769
2770 /*!
2771 \brief appends two null terminated strings.
2772
2773 s_ap = SUMA_append_replace_string(s1, s2, spc, whichTofree);
2774
2775 \param s1 (char *) string 1
2776 \param s2 (char *) string 2
2777 \param spc (char *) spacing string
2778 \param whichTofree (int) 0 free none,
2779 1 free s1
2780 2 free s2
2781 3 free s1 and s2
2782 \return s_ap (char *) a string formed by "%s%s%s", s1, spc, s2
2783
2784 - s1 and s2 are copied into a new string with spc in between
2785 - s1 (but not s2 or spc ) IS FREED inside this function
2786 -free returned pointer with: if(s_ap) SUMA_free(s_ap);
2787
2788 \sa SUMA_append_string, SUMA_ar_string, SUMA_append_replace_string_eng
2789 */
SUMA_append_replace_string(char * s1,char * s2,char * Spc,int whichTofree)2790 char * SUMA_append_replace_string(char *s1, char *s2, char *Spc, int whichTofree)
2791 {
2792 return(SUMA_append_replace_string_eng(s1, s2, Spc, whichTofree, 0));
2793 }
SUMA_ar_string(char * s1,char * s2,char * Spc,int whichTofree)2794 char * SUMA_ar_string(char *s1, char *s2, char *Spc, int whichTofree)
2795 {
2796 return(SUMA_append_replace_string_eng(s1, s2, Spc, whichTofree, 1));
2797 }
SUMA_append_replace_string_eng(char * s1,char * s2,char * Spc,int whichTofree,int cleanstart)2798 char * SUMA_append_replace_string_eng(char *s1, char *s2, char *Spc,
2799 int whichTofree, int cleanstart)
2800 {
2801 static char FuncName[]={"SUMA_append_replace_string_eng"};
2802 char *atr = NULL;
2803 int i,cnt, N_s2, N_s1, N_Spc=0;
2804
2805
2806 SUMA_ENTRY;
2807
2808 if (!s1 && !s2) SUMA_RETURN(NULL);
2809
2810 if (!s1) N_s1 = 0;
2811 else N_s1 = strlen(s1);
2812
2813 if (!s2) N_s2 = 0;
2814 else N_s2 = strlen(s2);
2815
2816 if (!Spc) N_Spc = 0;
2817 else N_Spc = strlen(Spc);
2818
2819 atr = (char *) SUMA_calloc(N_s1+N_s2+N_Spc+2, sizeof(char));
2820
2821 /* copy first string */
2822 i=0;
2823 cnt = 0;
2824 if (s1) {
2825 while (s1[i]) {
2826 atr[cnt] = s1[i];
2827 ++i;
2828 ++cnt;
2829 }
2830 }
2831
2832 i=0;
2833 if (Spc && (N_s1 || !cleanstart)) {
2834 while (Spc[i]) {
2835 atr[cnt] = Spc[i];
2836 ++i;
2837 ++cnt;
2838 }
2839 }
2840
2841 i=0;
2842 if (s2) {
2843 while (s2[i]) {
2844 atr[cnt] = s2[i];
2845 ++i;
2846 ++cnt;
2847 }
2848 }
2849 atr[cnt] = '\0';
2850
2851 switch (whichTofree) {
2852 case 0:
2853 break;
2854 case 1:
2855 if (s1) free(s1);
2856 break;
2857 case 2:
2858 if (s2) free(s2);
2859 break;
2860 case 3:
2861 if (s1) free(s1);
2862 if (s2) free(s2);
2863 break;
2864 default:
2865 fprintf(stderr, "Error %s:\nBad freeing parameter\n"
2866 "No variables were freed.\n",
2867 FuncName);
2868 break;
2869 }
2870
2871 SUMA_RETURN(atr);
2872 }
2873
SUMA_replace_string(char * s1,char * s2)2874 char * SUMA_replace_string(char *s1, char *s2)
2875 {
2876 if (s1) SUMA_free(s1);
2877 return(SUMA_copy_string(s2));
2878 }
2879
SUMA_append_replace_num(char * s1,char * form,double num,SUMA_VARTYPE tp,int whichTofree)2880 char * SUMA_append_replace_num(char *s1, char *form, double num,
2881 SUMA_VARTYPE tp, int whichTofree)
2882 {
2883 static char FuncName[]={"SUMA_append_replace_num"};
2884 char *atr = NULL, sbuf[500];
2885 int i,cnt, N_s2, N_s1, N_Spc=0;
2886
2887
2888 SUMA_ENTRY;
2889
2890 if (!form) SUMA_RETURN(NULL);
2891 if (!s1 && !form) SUMA_RETURN(NULL);
2892 if (whichTofree > 1) {
2893 SUMA_S_Err("Can only free s1");
2894 SUMA_RETURN(NULL);
2895 }
2896 if (!s1) N_s1 = 0;
2897 else N_s1 = strlen(s1);
2898
2899 switch(tp) {
2900 case SUMA_short:
2901 case SUMA_int:
2902 snprintf(sbuf, 450, form, (int)num);
2903 break;
2904 case SUMA_float:
2905 case SUMA_double:
2906 snprintf(sbuf, 450, form, (double)num);
2907 break;
2908 default:
2909 snprintf(sbuf, 450, "NUM_FORMAT_ERROR");
2910 break;
2911 }
2912
2913 /* fprintf(SUMA_STDERR,"%s: Have %lf num, form:>%s<, sbuf>%s<\n",
2914 FuncName, num, form, sbuf); */
2915
2916 atr = SUMA_append_replace_string(s1, sbuf, "", whichTofree);
2917
2918
2919 SUMA_RETURN(atr);
2920 }
2921
2922 /*!
2923 \brief Appends newstring to string in SS->s while taking care of resizing space allocated for s
2924
2925 \param SS (SUMA_STRING *) pointer to string structure
2926 \param newstring (char *) pointer to string to add to SS
2927 \return SS (SUMA_STRING *) pointer to string structure
2928 with SS->s now containing newstring
2929 - When SS is null, 1000 characters are allocated for s (initialization)
2930 and s[0] = '\0';
2931 - When newstring is NULL, space allocated for SS->s is resized to the
2932 correct dimension and a null character is placed at the end.
2933 \sa SUMA_SS2S
2934 */
SUMA_StringAppend(SUMA_STRING * SS,char * newstring)2935 SUMA_STRING * SUMA_StringAppend (SUMA_STRING *SS, char *newstring)
2936 {
2937 static char FuncName[]={"SUMA_StringAppend"};
2938 int N_inc = 0, N_cur = 0;
2939 int N_chunk = 1000;
2940 int i=0;
2941 SUMA_Boolean LocalHead = NOPE;
2942
2943 SUMA_ENTRY;
2944
2945 if (!SS) {
2946 if (LocalHead) fprintf (SUMA_STDERR, "%s: Allocating for SS.\n", FuncName);
2947 SS = (SUMA_STRING *) SUMA_malloc (sizeof(SUMA_STRING));
2948 SS->s = (char *) SUMA_calloc (N_chunk, sizeof(char));
2949 SS->s[0] = '\0';
2950 SS->N_alloc = N_chunk;
2951 SUMA_RETURN (SS);
2952 }
2953
2954 if (newstring) {
2955 if (LocalHead)
2956 fprintf (SUMA_STDERR, "%s: Appending to SS->s.\n", FuncName);
2957 N_inc = strlen (newstring);
2958 N_cur = strlen (SS->s);
2959 if (SS->N_alloc < N_cur+N_inc+1) { /* must reallocate */
2960 if (LocalHead)
2961 fprintf (SUMA_STDERR, "%s: Must reallocate for SS->s.\n", FuncName);
2962 SS->N_alloc = N_cur+N_inc+N_chunk+1;
2963 SS->s = (char *)SUMA_realloc (SS->s, sizeof(char)*SS->N_alloc);
2964 if (!SS->s) {
2965 fprintf (SUMA_STDERR,
2966 "Error %s: Failed to reallocate for s.\n", FuncName);
2967 SUMA_RETURN (NULL);
2968 }
2969 }
2970 /* append */
2971 for (i=N_cur;i<N_cur+N_inc; ++i)
2972 SS->s[i] = newstring[i-N_cur];
2973 SS->s[N_cur+N_inc] = '\0';
2974 }else {
2975 /* shrink SS->s to small size */
2976 N_cur = strlen (SS->s);
2977 if (SS->N_alloc > N_cur+1) {
2978 if (LocalHead)
2979 fprintf (SUMA_STDERR, "%s: Shrink realloc for SS->s.\n", FuncName);
2980 SS->N_alloc = N_cur+1;
2981 SS->s = (char *)SUMA_realloc (SS->s, sizeof(char)*SS->N_alloc);
2982 if (!SS->s) {
2983 fprintf (SUMA_STDERR,
2984 "Error %s: Failed to reallocate for s.\n", FuncName);
2985 SUMA_RETURN (NULL);
2986 }
2987 /*put a null at the end */
2988 SS->s[SS->N_alloc-1] = '\0';
2989 }
2990 }
2991
2992 SUMA_RETURN (SS);
2993
2994 }
2995
2996 /*!
2997 \brief Appends newstring to string in SS->s while taking care of resizing space allocated for s
2998 A variable argument version of SUMA_StringAppend
2999
3000 \param SS (SUMA_STRING *) pointer to string structure
3001 \param newstring (char *) pointer to string to add to SS
3002 \param ..... the remaining parameters a la printf manner
3003 \return SS (SUMA_STRING *) pointer to string structure with SS->s now containing newstring
3004 - When SS is null, 1000 characters are allocated for s (initialization) and s[0] = '\0';
3005 - When newstring is NULL, space allocated for SS->s is resized to the correct dimension and
3006 a null character is placed at the end.
3007
3008 - For this function, the formatted length of newstring should not be > than MAX_APPEND-1
3009 If that occurs, the string will be trunctated and no one should get hurt
3010
3011 NOTE: DO NOT SEND NULL pointers in the variable argument parts or crashes will occur on SUN
3012 Such NULL pointers do not result in null vararg_ptr and cause a seg fault in vsnprintf
3013
3014 \sa SUMA_StringAppend
3015 \sa SUMA_SS2S
3016 */
3017
3018 #define MAX_APPEND 30000
3019
3020
SUMA_StringAppend_va(SUMA_STRING * SS,char * newstring,...)3021 SUMA_STRING * SUMA_StringAppend_va (SUMA_STRING *SS, char *newstring, ... )
3022 {
3023 static char FuncName[]={"SUMA_StringAppend_va"};
3024 char sbuf[MAX_APPEND+2];
3025 int nout;
3026 va_list vararg_ptr ;
3027 SUMA_Boolean LocalHead = NOPE;
3028
3029 SUMA_ENTRY;
3030
3031 if (!SS) {
3032 SUMA_LH("NULL SS");
3033 /* let the other one handle this */
3034 SUMA_RETURN (SUMA_StringAppend(SS,newstring));
3035 }
3036
3037 if (newstring) {
3038 SUMA_LH("newstring %s...", newstring);
3039 /* form the newstring and send it to the olde SUMA_StringAppend */
3040 va_start( vararg_ptr , newstring) ;
3041 if (strlen(newstring) >= MAX_APPEND -1 ) {
3042 SUMA_SL_Err("newstring too long.\nCannot use SUMA_StringAppend_va");
3043 SUMA_RETURN(SUMA_StringAppend(SS,"Error SUMA_StringAppend_va: "
3044 "***string too long to add ***"));
3045 }
3046 if (LocalHead) {
3047 SUMA_LH("Calling vsnprintf");
3048 if (vararg_ptr) {
3049 SUMA_LH("Non NULL vararg_ptr");
3050 } else {
3051 SUMA_LH("NULL vararg_ptr");
3052 }
3053 }
3054 nout = vsnprintf (sbuf, MAX_APPEND * sizeof(char), newstring, vararg_ptr);
3055 if (LocalHead)
3056 fprintf(SUMA_STDERR,"%s:\n Calling va_end, nout = %d\n",
3057 FuncName, nout);
3058 va_end(vararg_ptr); /* cleanup */
3059
3060 if (nout < 0) {
3061 SUMA_SL_Err("Error reported by vsnprintf");
3062 SUMA_RETURN(SUMA_StringAppend(SS,
3063 "Error SUMA_StringAppend_va:"
3064 " ***Error reported by vsnprintf"));
3065 }
3066 if (nout >= MAX_APPEND) {
3067 SUMA_LH("String trunctated by vsnprintf");
3068 SUMA_StringAppend(SS,sbuf);
3069 SUMA_RETURN(SUMA_StringAppend(SS,
3070 "\nWARNING: "
3071 "***Previous string trunctated because "
3072 "of its length. ***\n"));
3073 }
3074 SUMA_LH("Calling StringAppend on %s", sbuf);
3075 SUMA_RETURN (SUMA_StringAppend(SS,sbuf));
3076 }else {
3077 SUMA_LH("NULL newstring");
3078 /* let the other one handle this */
3079 SUMA_RETURN (SUMA_StringAppend(SS,newstring));
3080 }
3081
3082 /* should not be here */
3083 SUMA_RETURN (NULL);
3084
3085 }
3086
3087 /* ***************** Environment value access begin **********************/
3088 static ENV_SPEC envlist[] = {
3089 { "Incremental arrow rotation angle in degrees",
3090 "SUMA_ArrowRotAngle",
3091 "5" } ,
3092 { "Color pattern (AFNI, EURO, PRINT, DEFAULT)",
3093 "SUMA_ColorPattern",
3094 "EURO" },
3095 { "Swap mouse buttons 1 and 3",
3096 "SUMA_SwapButtons_1_3",
3097 "NO" },
3098 { "Background color r g b. No space between values",
3099 "SUMA_BackgroundColor",
3100 "0.0,0.0,0.0" },
3101 { "ROI color map (bgyr64, roi64, roi128, roi256)",
3102 "SUMA_ROIColorMap",
3103 "ROI_i256" },
3104 { "Number of smoothing operations to run on convexity data",
3105 "SUMA_NumConvSmooth",
3106 "5" },
3107 { "Colormap for convexity (gray02, gray_i02, ngray20, bgyr64, etc.)",
3108 "SUMA_ConvColorMap",
3109 "gray02" },
3110 { "Brightness factor for convexity ",
3111 "SUMA_ConvBrightFactor",
3112 "0.5" },
3113 { "Number of smoothing operations to run on mixed foregroung color plane\n"
3114 " before mixing with background",
3115 "SUMA_NumForeSmoothing",
3116 "0" },
3117 { "Number of smoothing operations to run on final set of mixed colors.\n"
3118 " This would be the mixed foreground and background colors",
3119 "SUMA_NumFinalSmoothing",
3120 "0" },
3121 { "Setup the color mixing mode (ORIG, MOD1) ",
3122 "SUMA_ColorMixingMode",
3123 "ORIG" },
3124 { "** OBSOLETE: Port for communicating with AFNI\n"
3125 " Listening ports are derived from SUMA_AFNI_TCP_PORT\n"
3126 " Listening port i\n"
3127 " SUMA_AFNI_TCP_PORT + i (i > 0)",
3128 "SUMA_AFNI_TCP_PORT",
3129 "0" /* used to be 53211 */},
3130 { "Warn before closing with the Escape key (YES/NO)",
3131 "SUMA_WarnBeforeClose",
3132 "YES" },
3133 { "Mask node values\n"
3134 " 0 ? YES/NO",
3135 "SUMA_MaskZero",
3136 "YES" },
3137 { "Threshold if Val < thr (NO) or | Val | < | Thr | (YES)",
3138 "SUMA_AbsThreshold",
3139 "YES" },
3140 { "Threshold scale precision. 2 is the minimum allowed. \n"
3141 " This value might be overriden in SUMA.",
3142 "SUMA_ThresholdScalePower",
3143 "2" },
3144 { "Center of Rotation is based on nodes used in the mesh and not \n"
3145 " on all the nodes in NodeList",
3146 "SUMA_CenterOnPatch",
3147 "NO" },
3148 { "Use cross ticks on axis ?",
3149 "SUMA_UseCrossTicks",
3150 "NO" },
3151 { "Warn if 1D file looks like it needs a transpose",
3152 "SUMA_1D_Transpose_Warn",
3153 "YES" },
3154 { "Adjust roation and translation factor of mouse with changes \n"
3155 " in zoom levels ",
3156 "SUMA_AdjustMouseMotionWithZoom",
3157 "YES" },
3158 { "Use orthographic projection ",
3159 "SUMA_ViewOrthographicProjection",
3160 "NO" },
3161 { "Percent gain for zooming in and out with the 'z' and 'Z' keys. \n"
3162 " Typical range from 0 to 50",
3163 "SUMA_KeyZoomGain",
3164 "5" },
3165 { "Original FOV. Set between 1.0 and 100.0 \n"
3166 " Default is 30.0, -1 == auto",
3167 "SUMA_FOV_Original",
3168 "-1" },
3169 { "Original windows size and width in pixels \n"
3170 " :SPX:Allowed values are:\n\n"
3171 " 'TopLeft'\n\n"
3172 " 'RightOffset'\n\n"
3173 " 'X Y' Sets only the position to top left corner\n\n"
3174 " 'X Y Xwidth Ywidth' Set also width of window\n\n"
3175 " :DEF:Allowed values are: 'TopLeft'\n"
3176 " 'RightOffset' \n"
3177 " 'X Y' Sets only the position to top left corner\n"
3178 " 'X Y Xwidth Ywidth' Set also width of window\n"
3179 " :SPX:",
3180 "SUMA_Position_Original",
3181 "TopLeft" },
3182 { "light0 color",
3183 "SUMA_Light0Color",
3184 "1.0,1.0,1.0" },
3185 { "Ambient light ",
3186 "SUMA_AmbientLight",
3187 "1.0,1.0,1.0" },
3188 { "Allow for replacement of pre-loaded dsets",
3189 "SUMA_AllowDsetReplacement",
3190 "YES" },
3191 { "Allow a dataset to be assigned to a surface, even if\n"
3192 "domain of dset is specified and different for the surface.\n",
3193 "SUMA_AlwaysAssignSurface",
3194 "YES" },
3195 { "Allow for surfaces with same DomainGrandParentID to share overlays",
3196 "SUMA_ShareGrandChildrenOverlays",
3197 "NO" },
3198 { "Increase the resolution of images recorded with 'r' button.\n"
3199 " Increase is done by taking multiple shots that once stitched \n"
3200 " together form a high-resolution image.\n"
3201 " The maximum resolution is set by the GL_MAX_VIEWPORT_DIMS of your\n"
3202 " graphics card. I have 4096 pixels.\n"
3203 " If you exceed this number, SUMA will make adjustments automatically.\n"
3204 " Assemble images with program 2dcat.",
3205 "SUMA_SnapshotOverSampling",
3206 "1" },
3207 { "Ignore consecutive duplicate images in recorder",
3208 "SUMA_NoDuplicatesInRecorder",
3209 "YES" },
3210 { "start NIML (can't do this for more than one suma at a time!)",
3211 "SUMA_START_NIML",
3212 "YES" },
3213 { "Allow (YES) datasets with the same filename but differing ID \n"
3214 " to be considered the same.\n"
3215 " This is only useful with SUMA_AllowDsetReplacement",
3216 "SUMA_AllowFilenameDsetMatch",
3217 "YES" },
3218 { "Freeze zoom across states",
3219 "SUMA_FreezeFOVAcrossStates",
3220 "NO" },
3221 { "Dset color map",
3222 "SUMA_DsetColorMap",
3223 "Spectrum:red_to_blue" },
3224 { "Show only selected dset in suma's surface controller.",
3225 "SUMA_ShowOneOnly",
3226 "YES" },
3227 { "Update graphs, even SUMA_ShowOneOnly (or suma's '1 Only') is turned on.",
3228 "SUMA_GraphHidden",
3229 "YES" },
3230 { "Fraction of colormap to rotate with up/down arrow keys.",
3231 "SUMA_ColorMapRotationFraction",
3232 "0.05"},
3233 { "Size of surface controller font. \n"
3234 " Values are SMALL, BIG (old style).",
3235 "SUMA_SurfContFontSize",
3236 "SMALL"},
3237 { "Where to position SUMA window when first opened.\n"
3238 " Values are POINTER (at the mouse pointer's location)\n"
3239 " DEFAULT (let the window manager decide)\n",
3240 "SUMA_StartUpLocation",
3241 "DEFAULT"},
3242 { "Numer of nodes to jump with the 'alt+arrow' keys. \n"
3243 " Valid range from 1 to 10",
3244 "SUMA_KeyNodeJump",
3245 "1" },
3246 { "Numer of seconds to wait for SUMA to respond to DriveSuma. \n"
3247 " Valid range from 0 to 60000, see also env SUMA_DriveSumaMaxCloseWait",
3248 "SUMA_DriveSumaMaxWait",
3249 "300.0" },
3250 { "String to use in creating left hemisphere dataset wildcards.",
3251 "SUMA_LEFT_FILE_DSET_IDENTIFIER",
3252 "*lh*.dset" },
3253 { "String to use in creating left hemisphere dataset wildcards.",
3254 "SUMA_RIGHT_FILE_DSET_IDENTIFIER",
3255 "*rh*.dset" },
3256 { "String to use in creating left hemisphere roi wildcards.",
3257 "SUMA_LEFT_FILE_ROI_IDENTIFIER",
3258 "*lh*.roi" },
3259 { "String to use in creating right hemisphere roi wildcards.",
3260 "SUMA_RIGHT_FILE_ROI_IDENTIFIER",
3261 "*rh*.roi" },
3262 { "String to use in creating left hemisphere roi wildcards.",
3263 "SUMA_LEFT_FILE_OTHER_IDENTIFIER",
3264 "*lh*" },
3265 { "String to use in creating right hemisphere roi wildcards.",
3266 "SUMA_RIGHT_FILE_OTHER_IDENTIFIER",
3267 "*rh*" },
3268 { "Initial Convexity Datasest opacity.",
3269 "SUMA_ConvexityDsetOpacity",
3270 "0.85" },
3271 { "Display mode of Label Datasest specified in spec file at startup.\n"
3272 ":SPX:"
3273 "\n"
3274 " 'YES' or 'Col': Shows it in color\n\n"
3275 " 'Con': Shows only contours (see also env SUMA_ContourThickness).\n\n"
3276 " 'C&C': Shows both colors and contours \n\n"
3277 " 'XXX'or 'No': Does not show it.\n\n"
3278 ":DEF:"
3279 " 'YES' or 'Col': Shows it in color\n"
3280 " 'Con': Shows only contours (see also env SUMA_ContourThickness).\n"
3281 " 'C&C': Shows both colors and contours \n"
3282 " 'XXX'or 'No': Does not show it.\n"
3283 ":SPX:",
3284 "SUMA_ShowLabelDsetAtStartup",
3285 "XXX" },
3286 { "Show label at cross hair in viewer\n"
3287 "You can toggle the display at such labels with F9\n",
3288 "SUMA_ShowLabelsAtCrossHair",
3289 "YES" },
3290 { "Initial Label Datasest opacity.",
3291 "SUMA_LabelDsetOpacity",
3292 "0.2" },
3293 { "Attempt to recover from AFNI <--> SUMA disconnection bug.\n",
3294 "SUMA_AttemptTalkRecover",
3295 "Yes" },
3296 { "Name of directory containing user's own SUMA color maps"
3297 " (:SPX:`*`:DEF:*:SPX:.cmap)\n",
3298 "SUMA_CmapsDir",
3299 "None" },
3300 { "Name of color map for datasets of retinotopy angles.\n"
3301 "These would be produced by 3dRetinoPhase\n",
3302 "SUMA_RetinoAngle_DsetColorMap",
3303 "rgybr20" },
3304 { "Name of color map for VFR datasets produced by SurfRetinoMap\n",
3305 "SUMA_VFR_DsetColorMap",
3306 "afni_n2" },
3307 { "Coordinate units of surface nodes. Choose from 'mm' or 'cm'\n"
3308 "A bad choice can make the surfaces render with many artifacts.\n",
3309 "SUMA_NodeCoordsUnits",
3310 "mm" },
3311 { "Which anatomically correct surf. states should not NOT be sent to AFNI?\n"
3312 "This is mostly for deciding whether one of 'white' or 'smoothwm'\n"
3313 "FreeSurfer states should not be sent to AFNI.\n"
3314 "The default is to let them all go.\n"
3315 "You can specify multiple states with a , delimited list (no spaces!). \n"
3316 "By default nothing is excluded.\n",
3317 "SUMA_DoNotSendStates",
3318 "N/A" },
3319 { "Prefix for autorecord (suma's Ctrl+R) files. \n"
3320 "FreeSurfer states should not be sent to AFNI.\n"
3321 "Add a path if you want the files to endup in a particular directory.\n"
3322 "You can also add an extension to prefix to specify the output type.\n"
3323 "Choose from .jpg, .ppm, or .1D . The fallback type is .jpg\n",
3324 "SUMA_AutoRecordPrefix",
3325 "./SUMA_Recordings/autorecord.jpg" },
3326 { "Font for cross hair label in SUMA viewer\n"
3327 "Choose one of: f8 f9 tr10 tr24 he10 he12 he18\n",
3328 "SUMA_CrossHairLabelFont",
3329 "f9" },
3330 { "Linking mode of I and T sub-brick selectors\n"
3331 "Choose one of: None, Same, Stat\n",
3332 "SUMA_IxT_LinkMode",
3333 "Stat" },
3334 { "Minimum Number of sub-bricks to trigger use of arrow field for \n"
3335 "sub-brick selectors.\n",
3336 "SUMA_ArrowFieldSelectorTrigger",
3337 "200" },
3338 { "Use symmetric Intensity range at startup? Valid options are:\n"
3339 " YES or NO: For your preference if no decision is made by the software\n"
3340 " FYES or FNO: To force your preference and keep software from deciding\n",
3341 "SUMA_Sym_I_Range",
3342 "YES" },
3343 { "Set auto Intensity range by default (YES or NO)\n",
3344 "SUMA_Auto_I_Range",
3345 "NO" },
3346 { "Set auto Brightness range by default (YES or NO)\n",
3347 "SUMA_Auto_B_Range",
3348 "NO" },
3349 { "Set thickness of dataset contours\n",
3350 "SUMA_ContourThickness",
3351 "1.0" },
3352 { "Merge separated left/right states for inflated/spherical/etc. surfaces\n"
3353 "Choose from YES or NO",
3354 "SUMA_LHunify",
3355 "YES" },
3356 { "Put surface controllers in same window\n"
3357 "Choose from YES or NO",
3358 "SUMA_SameSurfCont",
3359 "YES" },
3360 { "Adjust offset of Surface Viewers as they are first open\n"
3361 "Choose from AUTO or provide two X Y offsets.",
3362 "SUMA_WindowOffset",
3363 "Auto" },
3364 { "Lock views across viewers\n"
3365 "Choose from YES or NO.",
3366 "SUMA_LockViewers",
3367 "YES" },
3368 { "Set colormap for volumes, choose any of the standard list",
3369 "SUMA_VO_ColorMap",
3370 "bw20" },
3371 { "Force reorienting of read volume.\nTo force reorientation,\n"
3372 "Choose from RAI, LPI, RAS. etc...\n"
3373 "Use NO to avoid reorientation. This env. is for debugging purposes.\n",
3374 "SUMA_VO_Reorient",
3375 "NO" },
3376 { "Set maximum waiting time for proper detection of closed stream\n"
3377 "This is to avoid DriveSuma's: Failed to detect closed stream ...\n"
3378 "complaint which results in a forced stream closing. Time unit is\n"
3379 "in seconds. See also env SUMA_DriveSumaMaxWait\n",
3380 "SUMA_DriveSumaMaxCloseWait",
3381 "5" },
3382 { "Set order in which object types are rendered. This order will affect\n"
3383 "the resultant image in the few instances where alpha transparency is\n"
3384 "used. The order can be specified for only three types of objects for \n"
3385 "now: graphs, surfaces, and volumes. If you want to render graphs first,\n"
3386 "followed by volumes then surfaces then set SUMA_ObjectDisplayOrder to\n"
3387 "something like: 'graph,vol,surf'. Do not include spaces between the\n"
3388 "type names.",
3389 "SUMA_ObjectDisplayOrder",
3390 "vol,surf,graph" },
3391 { "Font for datasets in SUMA viewer\n"
3392 "Choose one of: f8 f9 tr10 tr24 he10 he12 he18\n",
3393 "SUMA_Dset_Font",
3394 "f9" },
3395 { "Method for representing connections to a certain node in a graph"
3396 " dataset.\n"
3397 "Choose one of: Edge, Color, Radius, C&R, XXX\n",
3398 "SUMA_Dset_NodeConnections",
3399 "Edge" },
3400 { "Set which slices should be shown when a volume is first loaded.\n"
3401 "You can set parameters for each of the Ax, Sa, and Co planes, and\n"
3402 "the volume rendering.\n"
3403 "Each plane gets its own string formatted as such: PL:SL:MON:INC\n"
3404 "where:\n"
3405 ":SPX:\n"
3406 " PL is the plane (Ax, Co, Sa, or Vr)\n\n"
3407 " SL is the slice number, you can also set the number as \n"
3408 " a fraction of the number of slices in the volume.\n\n"
3409 " MON is the number of montage slices\n\n"
3410 " INC is the increment between montage slices. You can use \n"
3411 " fractions for this parameter also.\n\n"
3412 ":DEF:"
3413 " PL is the plane (Ax, Co, Sa, or Vr)\n"
3414 " SL is the slice number, you can also set the number as \n"
3415 " a fraction of the number of slices in the volume.\n"
3416 " MON is the number of montage slices\n"
3417 " INC is the increment between montage slices. You can use \n"
3418 " fractions for this parameter also.\n"
3419 ":SPX:"
3420 "If you want to set parameters for a certain plane, but do not\n"
3421 "want to see it, prepend the plane name with 'h' (for hide) as in 'hAx'\n"
3422 "Note that for Vr, there are no SL, MON, and INC qualifiers\n"
3423 "Also, SUMA will force the display of at least one plane because\n"
3424 "otherwise you have no way of opening a volume controller\n"
3425 "Example: 'Ax:0.5:3:10,Co:123:2:50,Vr'",
3426 "SUMA_VO_InitSlices",
3427 "Ax:0.5,Sa:0.5:2:0.5,hCo:0.5" },
3428 { "Allow selection of voxels on 3D rendering.\n"
3429 "Choose one of: YES or NO\n",
3430 "SUMA_VrSelectable",
3431 "YES" },
3432 { "Perform 'Home' call in SUMA after each prying.\n"
3433 "If YES, objects are repositioned to stay in the middle of the viewer\n"
3434 "as you pry the surfaces apart. This behavior is desired in general, \n"
3435 "unless you don't like the initial positioning in the first place.\n"
3436 "Choose from YES or NO",
3437 "SUMA_HomeAfterPrying",
3438 "YES" },
3439 { "Assume surface in TESSCON units if range is extreme\n"
3440 "If YES, surfaces with a big difference between max and min dims are\n"
3441 "scaled by 319.7. Don't set this env to YES unless this jibber jabber \n"
3442 "means.\n"
3443 "Choose from YES or NO",
3444 "SUMA_SUMA_TESSCON_AutoScale",
3445 "NO" },
3446 { "Turn on verbose mode for function count_procs() that checks for \n"
3447 "recursive calls to a program. Do not keep this env set to YES unless\n"
3448 "you are debugging.\n",
3449 "SUMA_CountProcs_Verb",
3450 "NO" },
3451 { "Number of transparency levels to jump with each 'o' key press\n"
3452 "Choose one of 1, 2, 4, or 8\n",
3453 "SUMA_Transparency_Step",
3454 "4" },
3455 { "If YES, then automatically load datasets with names matching those \n"
3456 "the surface just read.\n"
3457 "For example, if you load a surface named PATH/TOY.gii, for instance,\n"
3458 "and there exists a file called PATH/TOY.niml.dset then that file\n"
3459 "is automatically loaded onto surface TOY.gii. This would work for\n"
3460 "all surface types (e.g. TOY.ply) and dataset types (e.g. TOY.1D.dset)\n"
3461 "Choose from YES or NO\n",
3462 "SUMA_AutoLoad_Matching_Dset",
3463 "YES" },
3464 { "Colorize labeled datasets without attempting to make colors match\n"
3465 "what would be displayed in AFNI (YES or NO). Set to YES to match\n"
3466 "old style colorization preceding the addition of this variable\n",
3467 "SUMA_Classic_Label_Colors",
3468 "NO" },
3469 { "Multiplier for range of thresholding scale.\n",
3470 "SUMA_Range_Multiplier",
3471 "1.0" },
3472 { "Default p value to adopt when switching to a new sub-brick.\n"
3473 "Negative values mean leave the threshold alone when switching.\n",
3474 "SUMA_pval_at_switch",
3475 "-1.0" },
3476 { "If YES, then reduce messages to only errors while driving suma\n"
3477 "Choose from YES or NO",
3478 "SUMA_DriveSumaQuiet",
3479 "NO" },
3480 { "If YES, then show popup message windows in suma\n"
3481 "Choose from YES or NO",
3482 "SUMA_SHOWPOPUPS",
3483 "NO" },
3484
3485 { NULL, NULL, NULL }
3486 };
3487
SUMA_envlistelement(int i)3488 ENV_SPEC SUMA_envlistelement(int i) {
3489 ENV_SPEC se = envlist[i];
3490 return(se);
3491 }
3492
SUMA_EnvVal(char * env)3493 char * SUMA_EnvVal(char *env)
3494 {
3495 static char FuncName[]={"SUMA_EnvVal"};
3496 char *eee=NULL;
3497 int i=0;
3498
3499 SUMA_ENTRY;
3500
3501 if (!env) SUMA_RETURN(NULL);
3502 if ((eee = getenv(env))) { SUMA_RETURN(eee); }
3503
3504 /* search defaults*/
3505 i = 0;
3506 while (envlist[i].envhelp) {
3507 if ( envlist[i].envname &&
3508 !strcmp(envlist[i].envname, env) ) {
3509 SUMA_RETURN(envlist[i].envval);
3510 }
3511 ++i;
3512 }
3513 SUMA_RETURN(NULL);
3514 }
3515
3516 /* Returns non 0 if the env variable matches sval
3517
3518 The Function can handle an env that returns
3519 some character separated list if sep is not NULL
3520 For example, say env = {"The, olde, fox"}
3521 SUMA_EnvEquals(env,"olde", 0,NULL) returns 0
3522 but
3523 SUMA_EnvEquals(env,"olde", 0,",") returns 2
3524 because olde in the second word in env
3525 */
SUMA_EnvEquals(char * env,char * sval,byte ci,char * sep)3526 int SUMA_EnvEquals(char *env, char *sval, byte ci, char *sep)
3527 {
3528 static char FuncName[]={"SUMA_EnvEquals"};
3529 char *eee=NULL;
3530 NI_str_array *sar=NULL;
3531 int i=0;
3532 SUMA_Boolean LocalHead = NOPE;
3533
3534 SUMA_ENTRY;
3535
3536 if (!env) SUMA_RETURN(0);
3537
3538 if (!(eee = getenv(env))) {
3539 /* search defaults*/
3540 i = 0;
3541 while (envlist[i].envhelp && !eee) {
3542 if ( envlist[i].envname &&
3543 !strcmp(envlist[i].envname, env) ) {
3544 eee = envlist[i].envval;
3545 }
3546 ++i;
3547 }
3548 }
3549
3550 if (eee==NULL) {
3551 if (sval==NULL) SUMA_RETURN(1);
3552 else SUMA_RETURN(0);
3553 }
3554
3555 /* have env value of some sort */
3556 if (sval == NULL) SUMA_RETURN(0);
3557 if (LocalHead)
3558 fprintf(SUMA_STDERR,
3559 "%s: eee %s, sval %s, sep %s\n", FuncName, eee, sval, sep?sep:"NULL");
3560 if (!sep) {
3561 if (ci) SUMA_RETURN(!(strcasecmp(eee,sval)));
3562 else SUMA_RETURN(!(strcmp(eee,sval)));
3563 }
3564
3565 /* need to breakup into subsets */
3566 if (!(sar = SUMA_NI_decode_string_list( eee , sep ))) SUMA_RETURN(0);
3567 if (LocalHead)
3568 fprintf(SUMA_STDERR,
3569 "%s: Have %d vals in %s\n", FuncName, sar->num, eee);
3570 for (i=0; i<sar->num; ++i) {
3571 if (LocalHead)
3572 fprintf(SUMA_STDERR,
3573 "%s: Comapring %s to %s\n", FuncName, sval, sar->str[i]);
3574 if ( (ci && !(strcasecmp(sval,sar->str[i]))) ||
3575 !strcmp(sval, sar->str[i]) ) {
3576 sar = SUMA_free_NI_str_array(sar);
3577 SUMA_RETURN(i+1);
3578 }
3579 }
3580 sar = SUMA_free_NI_str_array(sar);
3581 SUMA_RETURN(0);
3582 }
3583
3584
SUMA_env_list_help(int DEFAULT_values,TFORM targ)3585 char * SUMA_env_list_help(int DEFAULT_values, TFORM targ){
3586 static char FuncName[]={"SUMA_env_list_help"};
3587 int i=0;
3588 char *sli=NULL;
3589 SUMA_STRING *SS=NULL;
3590 char *s=NULL, *eee=NULL, *userval=NULL;
3591 ENV_SPEC se;
3592
3593 SUMA_ENTRY;
3594
3595 SS = SUMA_StringAppend(NULL, NULL);
3596
3597 se = SUMA_envlistelement(i);
3598 while (se.envhelp) {
3599 if (!DEFAULT_values) {
3600 /* find the user's setting */
3601 eee = getenv(se.envname);
3602 }
3603 if (userval)
3604 SUMA_free(userval);
3605 userval=NULL;
3606 if (!eee) userval = SUMA_copy_string(se.envval);
3607 else userval = SUMA_copy_string(eee);
3608 switch (targ) {
3609 default:
3610 case TXT: /* default */
3611 sli = SUMA_ReplaceChars(se.envhelp, "\n","\n// ");
3612 sli = SUMA_Sphinx_String_Edit(&sli, targ, 0);
3613 SS = SUMA_StringAppend_va(SS,
3614 "// %03d-%s:\n"
3615 "// %s\n"
3616 "// default: %s = %s\n"
3617 " %s = %s\n",
3618 i, se.envname,
3619 sli,
3620 se.envname,
3621 se.envval,
3622 se.envname,
3623 userval);
3624 SUMA_free(sli); sli = NULL;
3625 break;
3626 case ASPX:
3627 case SPX: /* Sphinxy */
3628 sli = SUMA_copy_string(se.envhelp);
3629 sli = SUMA_Sphinx_String_Edit(&sli, targ, 0);
3630 SS = SUMA_StringAppend_va(SS,
3631 ".. _%s:\n\n"
3632 ":ref:`%s (env)<%s>`: %s\n\n"
3633 " default value: %s = %s\n\n",
3634 se.envname,
3635 se.envname, se.envname, sli,
3636 se.envname, se.envval);
3637 SUMA_free(sli); sli = NULL;
3638 break;
3639 }
3640 ++i;
3641 se = SUMA_envlistelement(i);
3642 }
3643 SUMA_SS2S(SS,s);
3644
3645 SUMA_RETURN(s);
3646 }
3647
3648
3649
3650 /*!
3651 If !env return NULL
3652 if !sval and env is an environment variable, its value is returned
3653 if sval and env then env's value is compared (case insensitive) and
3654 NULL is returned if there is no match, else the environment
3655 variable value is returned
3656 Partial match is allowed
3657 DO NOT free the returned pointer
3658 */
SUMA_isEnv(char * env,char * sval)3659 char *SUMA_isEnv(char *env, char *sval) {
3660 static char FuncName[]={"SUMA_isEnv"};
3661 char *eee = NULL, svalv[256]={""}, eeev[256]={""};
3662 int i=0;
3663
3664 SUMA_ENTRY;
3665
3666 if (!env) SUMA_RETURN(NULL);
3667
3668 eee = SUMA_EnvVal(env);
3669
3670 if (!sval || !eee) SUMA_RETURN(eee);
3671 /* have eee and sval, compare them */
3672 strncpy(svalv,sval, 255);
3673 strncpy(eeev, eee, 255);
3674 SUMA_TO_LOWER(eeev); SUMA_TO_LOWER(svalv);
3675
3676 if (!strlen(eee)) {
3677 /* set but no value. Does user seek "" ?*/
3678 if (!strlen(sval)) SUMA_RETURN(eee);
3679 else SUMA_RETURN(NULL);
3680 }
3681 for (i=0; i<strlen(svalv) && i<strlen(eeev); ++i)
3682 if (svalv[i] != eeev[i]) SUMA_RETURN(NULL);
3683
3684 SUMA_RETURN(eee);
3685 }
3686
SUMA_floatEnv(char * env,float defval)3687 float SUMA_floatEnv(char *env, float defval)
3688 {
3689 static char FuncName[]={"SUMA_floatEnv"};
3690 float fv = defval;
3691 char *eee=NULL, *eend=NULL;
3692 SUMA_ENTRY;
3693
3694 if ((eee = SUMA_EnvVal(env))) {
3695 fv = (float)strtod(eee, &eend);
3696 if (eee == eend) { /* failed */
3697 fv = defval;
3698 }
3699 }
3700
3701 SUMA_RETURN(fv);
3702 }
3703
3704 /* ***************** Environment value access end **********************/
3705
3706 /*! ********** Searching/Sorting Functions ************* */
3707
3708 /* Find the array index k where NodeIndex[n] == k
3709 Function assumes NodeIndex is monotonic ascending */
SUMA_NodeIndex_To_Index(int * NodeIndex,int N_Node,int n)3710 int SUMA_NodeIndex_To_Index(int *NodeIndex, int N_Node, int n)
3711 {
3712 static char FuncName[]={"SUMA_NodeIndex_To_Index"};
3713 if (!NodeIndex || n < 0) return(n);
3714 if (n < N_Node && NodeIndex[n]==n) return(n);
3715 else { /* have to search */
3716 return(SUMA_ibinFind(NodeIndex, N_Node, n));
3717 }
3718 }
3719
3720 /*!
3721 SUMA_binSearch( nodeList, target, seg, ematch);
3722
3723 This function performs a binary search. The indices of the elements in nodeList surrounding target will be stored in (overwrite) seg; thus seg[0]=seg[1]=i implies that an exact match was found at index i.
3724 \param nodeList (float *) vector of sorted values
3725 \param target (float) value seeking
3726 \param seg (int *) contains begin and end point of segment being searched
3727 \param ematch (byte) 1: Exact match enforced. 0: Closest
3728 \return found (SUMA_Boolean) YUP if all passed correctly and target within segment, NOPE otherwise
3729
3730 Written by Brenna Argall
3731 */
SUMA_binSearch(float * nodeList,float target,int * seg,byte ematch)3732 SUMA_Boolean SUMA_binSearch( float *nodeList, float target, int *seg,
3733 byte ematch)
3734 {
3735 static char FuncName[]={"SUMA_binSearch"};
3736 int mid=0;
3737 int beg = seg[0], end = seg[1];
3738 SUMA_Boolean found=YUP;
3739 SUMA_Boolean LocalHead = NOPE;
3740
3741
3742 SUMA_LHv("%f < %f < %f\n", nodeList[beg], target, nodeList[end]);
3743 if ( end<beg) {
3744 SUMA_S_Errv("Segment must be passed with seg[0]=%d <= seg[1]=%d.\n",
3745 seg[0], seg[1]);
3746 return (found = NOPE);
3747 }
3748 if ( nodeList[end]<nodeList[beg] ) {
3749 SUMA_S_Errv("Nodelist must be passed sorted and in ascending order.\n"
3750 "nodeList[%d]=%f<nodeList[%d]=%f\n",
3751 end, nodeList[end], beg, nodeList[beg]);
3752 return (found = NOPE);
3753 }
3754 if ( (nodeList[beg]>target) || (nodeList[end]<target) ) {
3755 SUMA_LHv("Don't bother, target (%f) does not lie within segment ]%f, %f[\n"
3756 , target, nodeList[beg], nodeList[end]);
3757 return (found = NOPE);
3758 }
3759
3760 if (beg!=end) {
3761 mid =(end-beg)/2 + beg;
3762 /**no exact match, but elements above and below found*/
3763 if (beg+1==end) {
3764 if (nodeList[end]==target) {
3765 seg[0] = end;
3766 seg[1] = end;
3767 } else if (nodeList[beg]==target) {
3768 seg[0] = beg;
3769 seg[1] = beg;
3770 } else {
3771 if (!ematch) {
3772 seg[0] = beg;
3773 seg[1] = end;
3774 } else {
3775 return(found = NOPE);
3776 }
3777 }
3778 }
3779 else if (target==nodeList[mid]) {
3780 seg[0] = mid;
3781 seg[1] = mid;
3782 }
3783 /**keep searching*/
3784 else if ( target < nodeList[mid]) {
3785 seg[0] = beg; seg[1] = mid;
3786 found = SUMA_binSearch( nodeList, target, seg, ematch);
3787 }
3788 else if ( target > nodeList[mid]) {
3789 seg[0] = mid; seg[1] = end;
3790 found = SUMA_binSearch( nodeList, target, seg, ematch);
3791 }
3792 }
3793 /**exact match; beg==end or target==nodeList[ indexList[mid] ]*/
3794 else {
3795 seg[0] = mid;
3796 seg[1] = mid;
3797 }
3798
3799 return(found);
3800 }
3801
SUMA_binFind(float * indexList,int N_node,float target,byte ematch)3802 int SUMA_binFind( float *indexList, int N_node, float target, byte ematch) {
3803 int seg[2]={0, N_node -1};
3804 if (SUMA_binSearch(indexList, target, seg, ematch)) return(seg[0]);
3805 else return(-1);
3806 }
3807
3808 /*!
3809 SUMA_ibinSearch( nodeList, target, seg);
3810
3811 This function performs a binary search. See SUMA_binSearch for comments
3812 \param nodeList (float *) vector of sorted values
3813 \param target (float) value seeking
3814 \param seg (int *) contains begin and end point of segment being searched
3815 \return found (SUMA_Boolean) YUP if all passed correctly and target within segment, NOPE otherwise
3816
3817 */
3818
SUMA_ibinSearch(int * indexList,int target,int * seg)3819 SUMA_Boolean SUMA_ibinSearch( int *indexList, int target, int *seg)
3820 {
3821 static char FuncName[]={"SUMA_ibinSearch"};
3822 int mid=0;
3823 int beg = seg[0], end = seg[1];
3824 SUMA_Boolean found=YUP;
3825 SUMA_Boolean LocalHead = NOPE;
3826
3827 if ( end<beg) {
3828 SUMA_S_Errv("Segment must be passed with seg[0]=%d <= seg[1]=%d.\n",
3829 seg[0], seg[1]);
3830 return (found = NOPE);
3831 }
3832 if (indexList[end]<indexList[beg] ) {
3833 SUMA_S_Errv("indexList must be passed sorted and in ascending order.\n"
3834 "indexList[%d]=%d<indexList[%d]=%d\n",
3835 end, indexList[end], beg, indexList[beg]);
3836 return (found = NOPE);
3837 }
3838 if ( (indexList[beg]>target) || (indexList[end]<target) ) {
3839 SUMA_LHv("Don't bother, target (%d) does not lie within segment ]%d, %d[\n"
3840 , target, indexList[beg], indexList[end]);
3841 return (found = NOPE);
3842 }
3843
3844 if (beg!=end) {
3845 mid =(end-beg)/2 + beg;
3846 /**no exact match, but elements above and below found*/
3847 if (beg+1==end) {
3848 if (indexList[end]==target) {
3849 seg[0] = end;
3850 seg[1] = end;
3851 } else if (indexList[beg]==target) {
3852 seg[0] = beg;
3853 seg[1] = beg;
3854 } else {
3855 return (found = NOPE);
3856 }
3857 }
3858 else if (target==indexList[mid]) {
3859 seg[0] = mid;
3860 seg[1] = mid;
3861 }
3862 /**keep searching*/
3863 else if ( target < indexList[mid]) {
3864 seg[0] = beg; seg[1] = mid;
3865 found = SUMA_ibinSearch( indexList, target, seg);
3866 }
3867 else if ( target > indexList[mid]) {
3868 seg[0] = mid; seg[1] = end;
3869 found = SUMA_ibinSearch( indexList, target, seg);
3870 }
3871 }
3872 /**exact match; beg==end or target==indexList[ indexList[mid] ]*/
3873 else {
3874 seg[0] = mid;
3875 seg[1] = mid;
3876 }
3877
3878 return(found);
3879 }
3880
SUMA_ibinFind(int * indexList,int N_node,int target)3881 int SUMA_ibinFind( int *indexList, int N_node, int target) {
3882 static char FuncName[]={"SUMA_ibinFind"};
3883 int seg[2]={0, N_node -1};
3884 if (SUMA_ibinSearch(indexList, target, seg)) return(seg[0]);
3885 else return(-1);
3886 }
3887
3888 /*!
3889 \brief creates a reordered version of a vector
3890 yr = SUMA_reorder(y, isort, N_isort);
3891
3892 \param y (int *) vector, if y is NULL what
3893 you get back in yr is a copy
3894 of isort.
3895 \param isort (int *) vector containing sorting order
3896 \param N_isort (int ) number of elements in isort
3897 \return yr (int *) reordered version of y where:
3898 yr[i] = y[isort[i]];
3899
3900 - you should free yr with SUMA_free(yr) when done with it
3901 - obviously it's your business to ensure that
3902 isort[i] cannot be larger than then number
3903 of elements in y
3904 */
SUMA_reorder(int * y,int * isort,int N_isort)3905 int *SUMA_reorder(int *y, int *isort, int N_isort)
3906 {
3907 static char FuncName[]={"SUMA_reorder"};
3908 int i = 0, *yr = NULL;
3909
3910 SUMA_ENTRY;
3911
3912 if (!isort || N_isort <= 0) SUMA_RETURN(yr);
3913
3914 yr = (int *)SUMA_calloc( N_isort, sizeof(int));
3915 if (!yr) SUMA_RETURN(yr);
3916
3917 if (!y) for (i=0; i<N_isort; ++i) yr[i] = isort[i];
3918 else for (i=0; i<N_isort; ++i) yr[i] = y[isort[i]];
3919
3920 SUMA_RETURN(yr);
3921 }
3922
3923 /* Careful to only free returned pointer after
3924 calling function is done with it. Do not free
3925 individual strings in returned pointer */
SUMA_sreorder(char ** y,int * isort,int N_isort)3926 char **SUMA_sreorder(char **y, int *isort, int N_isort)
3927 {
3928 static char FuncName[]={"SUMA_sreorder"};
3929 int i = 0;
3930 char **yr = NULL;
3931
3932 SUMA_ENTRY;
3933
3934 if (!y || !isort || N_isort <= 0) SUMA_RETURN(yr);
3935
3936 yr = (char **)SUMA_calloc( N_isort, sizeof(char*));
3937 if (!yr) SUMA_RETURN(yr);
3938
3939 for (i=0; i<N_isort; ++i) yr[i] = y[isort[i]];
3940
3941 SUMA_RETURN(yr);
3942 }
3943
SUMA_breorder(byte * y,int * isort,int N_isort)3944 byte *SUMA_breorder(byte *y, int *isort, int N_isort)
3945 {
3946 static char FuncName[]={"SUMA_breorder"};
3947 int i = 0;
3948 byte *yr = NULL;
3949
3950 SUMA_ENTRY;
3951
3952 if (!y || !isort || N_isort <= 0) SUMA_RETURN(yr);
3953
3954 yr = (byte *)SUMA_calloc( N_isort, sizeof(byte));
3955 if (!yr) SUMA_RETURN(yr);
3956
3957 for (i=0; i<N_isort; ++i) yr[i] = y[isort[i]];
3958
3959 SUMA_RETURN(yr);
3960 }
3961
3962
SUMA_freorder(float * y,int * isort,int N_isort)3963 float *SUMA_freorder(float *y, int *isort, int N_isort)
3964 {
3965 static char FuncName[]={"SUMA_freorder"};
3966 int i = 0;
3967 float *yr = NULL;
3968
3969 SUMA_ENTRY;
3970
3971 if (!y || !isort || N_isort <= 0) SUMA_RETURN(yr);
3972
3973 yr = (float *)SUMA_calloc( N_isort, sizeof(float));
3974 if (!yr) SUMA_RETURN(yr);
3975
3976 for (i=0; i<N_isort; ++i) yr[i] = y[isort[i]];
3977
3978 SUMA_RETURN(yr);
3979 }
3980
SUMA_freorder_triplets(float * y,int * isort,int N_isort)3981 float *SUMA_freorder_triplets(float *y, int *isort, int N_isort)
3982 {
3983 static char FuncName[]={"SUMA_freorder_triplets"};
3984 int i = 0;
3985 float *yr = NULL;
3986
3987 SUMA_ENTRY;
3988
3989 if (!y || !isort || N_isort <= 0) SUMA_RETURN(yr);
3990
3991 yr = (float *)SUMA_calloc( N_isort*3, sizeof(float));
3992 if (!yr) SUMA_RETURN(yr);
3993
3994 for (i=0; i<N_isort; ++i) {
3995 yr[3*i] = y[3*isort[i]];
3996 yr[3*i+1] = y[3*isort[i]+1];
3997 yr[3*i+2] = y[3*isort[i]+2];
3998 }
3999
4000 SUMA_RETURN(yr);
4001 }
4002
SUMA_dreorder(double * y,int * isort,int N_isort)4003 double *SUMA_dreorder(double *y, int *isort, int N_isort)
4004 {
4005 static char FuncName[]={"SUMA_dreorder"};
4006 int i = 0;
4007 double *yr = NULL;
4008
4009 SUMA_ENTRY;
4010
4011 if (!y || !isort || N_isort <= 0) SUMA_RETURN(yr);
4012
4013 yr = (double *)SUMA_calloc( N_isort, sizeof(double));
4014 if (!yr) SUMA_RETURN(yr);
4015
4016 for (i=0; i<N_isort; ++i) yr[i] = y[isort[i]];
4017
4018 SUMA_RETURN(yr);
4019 }
4020
4021
SUMA_string_to_RGBA(char * s,float * here,float scl,int * Err)4022 float *SUMA_string_to_RGBA(char *s, float *here, float scl, int *Err)
4023 {
4024 static char FuncName[]={"SUMA_string_to_RGBA"};
4025
4026 static int icall=0;
4027 static float fv[10][4];
4028 char *sc=NULL, i, err, one, twofif, N;
4029 float all[12];
4030 SUMA_Boolean LocalHead = NOPE;
4031
4032 SUMA_ENTRY;
4033
4034 if (!here) {
4035 ++icall; if (icall > 9) icall = 0;
4036 here = (float *)(&fv[icall]);
4037 }
4038 here[0] = here[1] = here[2] = here[3] = 1.0;
4039 if (Err) *Err=1; /* initialize with problem */
4040
4041 if (!s) SUMA_RETURN(here);
4042
4043 sc = SUMA_copy_string(s);
4044
4045 /* deblank borders */
4046 sc = deblank_name(sc);
4047 if (!strcasecmp(sc,"red") || !strcasecmp(sc,"r")) {
4048 here[0] = 1.0; here[1] = 0.0; here[2] = 0.0; here[3] = 1.0;
4049 if (Err) *Err=0;
4050 } else if (!strcasecmp(sc,"green") || !strcasecmp(sc,"g")) {
4051 here[0] = 0.0; here[1] = 1.0; here[2] = 0.0; here[3] = 1.0;
4052 if (Err) *Err=0;
4053 } else if (!strcasecmp(sc,"blue") || !strcasecmp(sc,"b")) {
4054 here[0] = 0.0; here[1] = 0.0; here[2] = 1.0; here[3] = 1.0;
4055 if (Err) *Err=0;
4056 } else if (!strcasecmp(sc,"yellow") || !strcasecmp(sc,"y")) {
4057 here[0] = 1.0; here[1] = 1.0; here[2] = 0.0; here[3] = 1.0;
4058 if (Err) *Err=0;
4059 } else if (!strcasecmp(sc,"cyan") || !strcasecmp(sc,"c")) {
4060 here[0] = 0.0; here[1] = 1.0; here[2] = 1.0; here[3] = 1.0;
4061 if (Err) *Err=0;
4062 } else if (!strcasecmp(sc,"purple") || !strcasecmp(sc,"p")) {
4063 here[0] = 1.0; here[1] = 0.0; here[2] = 1.0; here[3] = 1.0;
4064 if (Err) *Err=0;
4065 } else if (!strcasecmp(sc,"white") || !strcasecmp(sc,"w")) {
4066 here[0] = 1.0; here[1] = 1.0; here[2] = 1.0; here[3] = 1.0;
4067 if (Err) *Err=0;
4068 } else if (SUMA_CleanNumString(sc,(void *)4)) {
4069 SUMA_LH("Have RGBA");
4070 N=4;
4071 SUMA_StringToNum(sc, (void*)all, N, 1);
4072 one = 0; twofif = 0; err = 0;
4073 if (scl == 0.0f) {
4074 for (i=0; i<N; ++i) {
4075 if (all[i] >= 0.0 && all[i] <= 1.0) {
4076 ++one;
4077 } else if (all[i] >= 0.0 && all[i] <= 255.0) {
4078 ++twofif;
4079 } else {
4080 SUMA_S_Err("Bad col param %d in %s", i, sc);
4081 ++err;
4082 }
4083 }
4084 if (err) {
4085 SUMA_ifree(sc); SUMA_RETURN(here);
4086 }
4087 if (twofif == 0) scl = 1.0;
4088 else scl = 1.0/255.0;
4089 }
4090 for (i=0; i<N; ++i) { here[i] = all[i]*scl; }
4091 if (Err) *Err=0;
4092 } else if (SUMA_CleanNumString(sc,(void *)3)) {
4093 SUMA_LH("Have RGB");
4094 N=3;
4095 SUMA_StringToNum(sc, (void*)all, N, 1);
4096 one = 0; twofif = 0; err = 0;
4097 if (scl == 0.0f) {
4098 for (i=0; i<N; ++i) {
4099 if (all[i] >= 0.0 && all[i] <= 1.0) {
4100 ++one;
4101 } else if (all[i] >= 0.0 && all[i] <= 255.0) {
4102 ++twofif;
4103 } else {
4104 SUMA_S_Err("Bad col param %d in %s", i, sc);
4105 ++err;
4106 }
4107 }
4108 if (err) {
4109 SUMA_ifree(sc); SUMA_RETURN(here);
4110 }
4111 if (twofif == 0) scl = 1.0;
4112 else scl = 1.0/255.0;
4113 }
4114 for (i=0; i<N; ++i) { here[i] = all[i]*scl; }
4115 here[3] = 1.0*scl;
4116 if (Err) *Err=0;
4117 } else if (SUMA_CleanNumString(sc,(void *)1)) {
4118 SUMA_LH("Have 1 color, going gray scale");
4119 N=1;
4120 SUMA_StringToNum(sc, (void*)all, N, 1);
4121 one = 0; twofif = 0; err = 0;
4122 if (scl == 0.0f) {
4123 for (i=0; i<N; ++i) {
4124 if (all[i] >= 0.0 && all[i] <= 1.0) {
4125 ++one;
4126 } else if (all[i] >= 0.0 && all[i] <= 255.0) {
4127 ++twofif;
4128 } else {
4129 SUMA_S_Err("Bad col param %d in %s", i, sc);
4130 ++err;
4131 }
4132 }
4133 if (err) {
4134 SUMA_ifree(sc); SUMA_RETURN(here);
4135 }
4136 if (twofif == 0) scl = 1.0;
4137 else scl = 1.0/255.0;
4138 }
4139 for (i=0; i<4; ++i) { here[i] = all[0]*scl; }
4140 if (Err) *Err=0;
4141 } else if (SUMA_CleanNumString(sc,(void *)0)) {
4142 SUMA_LH("Have no numbers");
4143 }
4144 SUMA_ifree(sc);
4145 SUMA_RETURN(here);
4146 }
4147
SUMA_floats_to_string(float * rgba,int N,float scl,char * here,int * Err,char * sep,int MVf)4148 char *SUMA_floats_to_string(float *rgba, int N, float scl, char *here, int *Err,
4149 char *sep, int MVf)
4150 {
4151 static char FuncName[]={"SUMA_floats_to_string"};
4152 static int icall=0;
4153 static char fv[10][64];
4154 char *sc=NULL, i, err, one, twofif;
4155 float all[12];
4156 SUMA_Boolean LocalHead = NOPE;
4157
4158 SUMA_ENTRY;
4159
4160 if (!here) {
4161 ++icall; if (icall > 9) icall = 0;
4162 here = (char *)(&fv[icall]);
4163 }
4164 here[0] = '\0';
4165 if (Err) *Err=1; /* initialize with problem */
4166
4167 if (!rgba) SUMA_RETURN(here);
4168 if (!sep) sep = ",";
4169 if (scl == 0.0) scl = 1.0;
4170
4171 if (N == 4) {
4172 if (MVf > 0) {
4173 snprintf(here, 63, "%s%s%s%s%s%s%s",
4174 MV_format_fval2(rgba[0]*scl, MVf), sep,
4175 MV_format_fval2(rgba[1]*scl, MVf), sep,
4176 MV_format_fval2(rgba[2]*scl, MVf), sep,
4177 MV_format_fval2(rgba[3]*scl, MVf));
4178 } else if (MVf == 0) {
4179 snprintf(here, 63, "%f%s%f%s%f%s%f",
4180 rgba[0]*scl, sep, rgba[1]*scl, sep,
4181 rgba[2]*scl, sep, rgba[3]*scl);
4182 } else if (MVf == -1) {
4183 snprintf(here, 63, "%.1f%s%.1f%s%.1f%s%.1f",
4184 rgba[0]*scl, sep, rgba[1]*scl, sep,
4185 rgba[2]*scl, sep, rgba[3]*scl);
4186 } else if (MVf == -2) {
4187 snprintf(here, 63, "%.2f%s%.2f%s%.2f%s%.2f",
4188 rgba[0]*scl, sep, rgba[1]*scl, sep,
4189 rgba[2]*scl, sep, rgba[3]*scl);
4190 } else if (MVf == -3) {
4191 snprintf(here, 63, "%.3f%s%.3f%s%.3f%s%.3f",
4192 rgba[0]*scl, sep, rgba[1]*scl, sep,
4193 rgba[2]*scl, sep, rgba[3]*scl);
4194 }
4195 } else if (N == 3) {
4196 if (MVf > 0) {
4197 snprintf(here, 63, "%s%s%s%s%s",
4198 MV_format_fval2(rgba[0]*scl, MVf), sep,
4199 MV_format_fval2(rgba[1]*scl, MVf), sep,
4200 MV_format_fval2(rgba[2]*scl, MVf));
4201 } else if (MVf == 0) {
4202 snprintf(here, 63, "%f%s%f%s%f",
4203 rgba[0]*scl, sep, rgba[1]*scl, sep,
4204 rgba[2]*scl);
4205 } else if (MVf == -1) {
4206 snprintf(here, 63, "%.1f%s%.1f%s%.1f",
4207 rgba[0]*scl, sep, rgba[1]*scl, sep,
4208 rgba[2]*scl);
4209 } else if (MVf == -2) {
4210 snprintf(here, 63, "%.2f%s%.2f%s%.2f",
4211 rgba[0]*scl, sep, rgba[1]*scl, sep,
4212 rgba[2]*scl);
4213 } else if (MVf == -3) {
4214 snprintf(here, 63, "%.3f%s%.3f%s%.3f",
4215 rgba[0]*scl, sep, rgba[1]*scl, sep,
4216 rgba[2]*scl);
4217 }
4218 } else if (N == 1) {
4219 if (MVf > 0) {
4220 snprintf(here, 63, "%s",
4221 MV_format_fval2(rgba[0]*scl, MVf));
4222 } else if (MVf == 0) {
4223 snprintf(here, 63, "%f",
4224 rgba[0]*scl);
4225 } else if (MVf == -1) {
4226 snprintf(here, 63, "%.1f",
4227 rgba[0]*scl);
4228 } else if (MVf == -2) {
4229 snprintf(here, 63, "%.2f",
4230 rgba[0]*scl);
4231 } else if (MVf == -3) {
4232 snprintf(here, 63, "%.3f",
4233 rgba[0]*scl);
4234 }
4235 }
4236 SUMA_RETURN(here);
4237 }
4238