1 #include "SUMA_suma.h"
2 
usage_SUMA_quickspec(SUMA_GENERIC_ARGV_PARSE * ps)3 void usage_SUMA_quickspec(SUMA_GENERIC_ARGV_PARSE *ps)
4 {
5    static char FuncName[]={"usage_SUMA_quickspec"};
6    char * s = NULL, *sio=NULL;
7    sio  = SUMA_help_IO_Args(ps);
8 
9    printf (
10 "\nUsage:  quickspec \n"
11 "        <-tn TYPE NAME> ...\n"
12 "        <-tsn TYPE STATE NAME> ...\n"
13 "        [<-spec specfile>] [-h/-help]\n"
14 "  Use this spec file for quick and dirty way of \n"
15 "  loading a surface into SUMA or the command line programs.\n"
16 "\n"
17 "Options:\n"
18 "%s\n"
19 "   -tsnad TYPE STATE NAME ANATFLAG LDP: \n"
20 "                 specify surface type, state, name, anatomical correctness, \n"
21 "                 and its Local Domain Parent.\n"
22 "        ANATFLAG: 'Y' if surface is anatomically correct (default).\n"
23 "                  'N' if it is not anatomically correct.\n"
24 "        LDP: Name of Local Domain Parent surface.\n"
25 "             Use SAME (default) if surface is its own LDP.\n"
26 "   -tsnadm TYPE STATE NAME ANATFLAG LDP MARKER: \n"
27 "                 specify surface type, state, name, anatomical correctness, \n"
28 "                 Local Domain Parent, and node marker file.\n"
29 "        MARKER: A niml.do Displayable Object (DO) to put at every\n"
30 "                node of the surface. See @DO.examples for information\n"
31 "                about displayable objects\n"
32 "   -tsnadl TYPE STATE NAME ANATFLAG LDP LABELDSET: \n"
33 "                 specify surface type, state, name, anatomical correctness, \n"
34 "                 Local Domain Parent, and a label dataset file.\n"
35 "        LABELDSET: A surface dataset containing node labels.\n"
36 "   -spec specfile: Name of spec file output.\n"
37 "                   Default is quick.spec\n"
38 "                   The program will only overwrite \n"
39 "                   quick.spec (the default) spec file.\n"
40 "   -h or -help: This message here.\n"
41 "\n"
42 "  You can use any combinaton of -tn and -tsn options.\n"
43 "  Fields in the spec file that are (or cannot) be specified\n"
44 "  by this program are set to default values.\n"
45 "\n   This program was written to ward off righteous whiners and is\n"
46 "  not meant to replace the venerable @SUMA_Make_Spec_XX scripts.\n"
47 "\n"
48      , sio); SUMA_free(sio); sio = NULL;
49      s = SUMA_New_Additions(0, 1); printf("%s\n", s);SUMA_free(s); s = NULL;
50      printf("      Ziad S. Saad SSCC/NIMH/NIH saadz@mail.nih.gov \n\t\t Tue Dec 30\n"
51             "\n");
52     return;
53 }
54 
main(int argc,char * argv[])55 int main (int argc,char *argv[])
56 {/* Main */
57    static char FuncName[]={"quickspec"};
58    int detail, kar, i, j, N_surf, N_name, idefstate;
59    FILE *fid = NULL;
60    char *spec_name, stmp[500], *Unique_st;
61    SUMA_SO_File_Type TypeC[SUMA_MAX_N_SURFACE_SPEC];
62    static char
63          *State[SUMA_MAX_N_SURFACE_SPEC],
64          *Name_coord[SUMA_MAX_N_SURFACE_SPEC],
65          *Name_topo[SUMA_MAX_N_SURFACE_SPEC],
66          Anat[SUMA_MAX_N_SURFACE_SPEC],
67          *LDP[SUMA_MAX_N_SURFACE_SPEC],
68          *MARK[SUMA_MAX_N_SURFACE_SPEC],
69          *LABEL[SUMA_MAX_N_SURFACE_SPEC];
70    SUMA_GENERIC_ARGV_PARSE *ps;
71    SUMA_Boolean brk;
72 
73    SUMA_mainENTRY;
74 
75    /* allocate space for CommonFields structure */
76    SUMAg_CF = SUMA_Create_CommonFields ();
77    if (SUMAg_CF == NULL) {
78       fprintf( SUMA_STDERR,
79                "Error %s: Failed in SUMA_Create_CommonFields\n", FuncName);
80       exit(1);
81    }
82 
83    ps = SUMA_Parse_IO_Args(argc, argv, "-t;");
84 
85    if (argc < 3)
86        {
87           usage_SUMA_quickspec (ps);
88           exit (0);     /* status 0 on -help    18 Sep 2018 [rickr] */
89        }
90 
91    kar = 1;
92    brk = NOPE;
93    detail = 1;
94    N_surf = 0;
95    N_name = 0;
96    spec_name = NULL;
97    while (kar < argc) { /* loop accross command ine options */
98       /*fprintf(stdout, "%s verbose: Parsing command line...\n", FuncName);*/
99       if (strcmp(argv[kar], "-h") == 0 || strcmp(argv[kar], "-help") == 0) {
100           usage_SUMA_quickspec(ps);
101           exit (0);     /* status 0 on -help    18 Sep 2018 [rickr] */
102       }
103       if (!brk && (strcmp(argv[kar], "-spec") == 0)) {
104          kar ++;
105          if (kar >= argc)  {
106             fprintf (SUMA_STDERR, "need argument after -spec \n");
107             exit (1);
108          }
109          spec_name = argv[kar];
110          if (!THD_ok_overwrite() && SUMA_filexists(spec_name)) {
111             fprintf (SUMA_STDERR,
112                "File %s exists, choose another one.\n", spec_name);
113             exit(1);
114          }
115          brk = YUP;
116       }
117       if (!brk && (strcmp(argv[kar], "-tn") == 0)) {
118          if (N_surf >= SUMA_MAX_N_SURFACE_SPEC) {
119             SUMA_SL_Err("Exceeding maximum number of allowed surfaces...");
120             exit(1);
121          }
122          /* get the type */
123          kar ++;
124          if (kar >= argc)  {
125             fprintf (SUMA_STDERR, "Type argument must follow -tn \n");
126             exit (1);
127          }
128          TypeC[N_surf] = SUMA_SurfaceTypeCode(argv[kar]);
129          if (TypeC[N_surf] == SUMA_FT_ERROR ||
130              TypeC[N_surf] == SUMA_FT_NOT_SPECIFIED) {
131             fprintf (SUMA_STDERR, "%s is a bad file type.\n", argv[kar]);
132             exit(1);
133          }
134          /* get the name */
135          if (TypeC[N_surf] == SUMA_SUREFIT || TypeC[N_surf] == SUMA_VEC)
136             N_name = 2;
137          else N_name = 1;
138          if (kar+N_name >= argc)  {
139             fprintf (SUMA_STDERR, "need %d elements for NAME \n", N_name);
140             exit (1);
141          }
142          kar ++; Name_coord[N_surf] = argv[kar];
143          if (N_name == 2) {
144             kar ++; Name_topo[N_surf] = argv[kar];
145          } else {
146             Name_topo[N_surf] = NULL;
147          }
148          State[N_surf] = NULL;
149          Anat[N_surf] = 'Y';
150          LDP[N_surf] = NULL;
151          ++N_surf;
152          brk = YUP;
153       }
154       if (!brk && (strcmp(argv[kar], "-tsn") == 0)) {
155          if (N_surf >= SUMA_MAX_N_SURFACE_SPEC) {
156             SUMA_SL_Err("Exceeding maximum number of allowed surfaces...");
157             exit(1);
158          }
159          /* get the type */
160          kar ++;
161          if (kar >= argc)  {
162             fprintf (SUMA_STDERR, "TYPE argument must follow -tsn \n");
163             exit (1);
164          }
165          TypeC[N_surf] = SUMA_SurfaceTypeCode(argv[kar]);
166          if (  TypeC[N_surf] == SUMA_FT_ERROR ||
167                TypeC[N_surf] == SUMA_FT_NOT_SPECIFIED) {
168             fprintf (SUMA_STDERR, "%s is a bad file TYPE.\n", argv[kar]);
169             exit(1);
170          }
171          /* get the state */
172          kar ++;
173          if (kar >= argc)  {
174             fprintf (SUMA_STDERR,
175                      "STATE argument must follow TYPE with -tsn \n");
176             exit (1);
177          }
178          State[N_surf] = argv[kar];
179 
180          /* get the name */
181          if (  TypeC[N_surf] == SUMA_SUREFIT ||
182                TypeC[N_surf] == SUMA_VEC) N_name = 2;
183          else N_name = 1;
184          if (kar+N_name >= argc)  {
185             fprintf (SUMA_STDERR, "need %d elements for NAME \n", N_name);
186             exit (1);
187          }
188          kar ++; Name_coord[N_surf] = argv[kar];
189          if (N_name == 2) {
190             kar ++; Name_topo[N_surf] = argv[kar];
191          } else {
192             Name_topo[N_surf] = NULL;
193          }
194 
195          Anat[N_surf] = 'Y';
196          LDP[N_surf] = NULL;
197          ++N_surf;
198          brk = YUP;
199       }
200 
201       if (!brk && (strcmp(argv[kar], "-tsnad") == 0)) {
202          if (N_surf >= SUMA_MAX_N_SURFACE_SPEC) {
203             SUMA_SL_Err("Exceeding maximum number of allowed surfaces...");
204             exit(1);
205          }
206          /* get the type */
207          kar ++;
208          if (kar >= argc)  {
209             fprintf (SUMA_STDERR, "TYPE argument must follow -tsnad \n");
210             exit (1);
211          }
212          TypeC[N_surf] = SUMA_SurfaceTypeCode(argv[kar]);
213          if (  TypeC[N_surf] == SUMA_FT_ERROR ||
214                TypeC[N_surf] == SUMA_FT_NOT_SPECIFIED) {
215             fprintf (SUMA_STDERR, "%s is a bad file TYPE.\n", argv[kar]);
216             exit(1);
217          }
218          /* get the state */
219          kar ++;
220          if (kar >= argc)  {
221             fprintf (SUMA_STDERR,
222                      "STATE argument must follow TYPE with -tsnad \n");
223             exit (1);
224          }
225          State[N_surf] = argv[kar];
226 
227          /* get the name */
228          if (  TypeC[N_surf] == SUMA_SUREFIT ||
229                TypeC[N_surf] == SUMA_VEC) N_name = 2;
230          else N_name = 1;
231          if (kar+N_name >= argc)  {
232             fprintf (SUMA_STDERR, "need %d elements for NAME \n", N_name);
233             exit (1);
234          }
235          kar ++; Name_coord[N_surf] = argv[kar];
236          if (N_name == 2) {
237             kar ++; Name_topo[N_surf] = argv[kar];
238          } else {
239             Name_topo[N_surf] = NULL;
240          }
241 
242 
243          /* get the anatomical flag */
244          kar ++;
245          if (kar >= argc)  {
246             fprintf (SUMA_STDERR,
247                      "Anatomical flag must follow NAME with -tsnad \n");
248             exit (1);
249          }
250          Anat[N_surf] = SUMA_TO_UPPER_C(argv[kar][0]);
251          if (Anat[N_surf] != 'Y' && Anat[N_surf] != 'N') {
252             SUMA_S_Err("Anatomical flag must be either 'y' or 'n'");
253             exit (1);
254          }
255          /* get the LDP */
256          kar ++;
257          if (kar >= argc)  {
258             fprintf (SUMA_STDERR,
259                  "LocalDomainParent must follow Anatomical flag with -tsnad \n");
260             exit (1);
261          }
262          LDP[N_surf] = argv[kar];
263 
264          ++N_surf;
265          brk = YUP;
266       }
267 
268       if (!brk && (strcmp(argv[kar], "-tsnadm") == 0)) {
269          if (N_surf >= SUMA_MAX_N_SURFACE_SPEC) {
270             SUMA_SL_Err("Exceeding maximum number of allowed surfaces...");
271             exit(1);
272          }
273          /* get the type */
274          kar ++;
275          if (kar >= argc)  {
276             fprintf (SUMA_STDERR, "TYPE argument must follow -tsnad \n");
277             exit (1);
278          }
279          TypeC[N_surf] = SUMA_SurfaceTypeCode(argv[kar]);
280          if (  TypeC[N_surf] == SUMA_FT_ERROR ||
281                TypeC[N_surf] == SUMA_FT_NOT_SPECIFIED) {
282             fprintf (SUMA_STDERR, "%s is a bad file TYPE.\n", argv[kar]);
283             exit(1);
284          }
285          /* get the state */
286          kar ++;
287          if (kar >= argc)  {
288             fprintf (SUMA_STDERR,
289                      "STATE argument must follow TYPE with -tsnad \n");
290             exit (1);
291          }
292          State[N_surf] = argv[kar];
293 
294          /* get the name */
295          if (  TypeC[N_surf] == SUMA_SUREFIT ||
296                TypeC[N_surf] == SUMA_VEC) N_name = 2;
297          else N_name = 1;
298          if (kar+N_name >= argc)  {
299             fprintf (SUMA_STDERR, "need %d elements for NAME \n", N_name);
300             exit (1);
301          }
302          kar ++; Name_coord[N_surf] = argv[kar];
303          if (N_name == 2) {
304             kar ++; Name_topo[N_surf] = argv[kar];
305          } else {
306             Name_topo[N_surf] = NULL;
307          }
308 
309 
310          /* get the anatomical flag */
311          kar ++;
312          if (kar >= argc)  {
313             fprintf (SUMA_STDERR,
314                      "Anatomical flag must follow NAME with -tsnad \n");
315             exit (1);
316          }
317          Anat[N_surf] = SUMA_TO_UPPER_C(argv[kar][0]);
318          if (Anat[N_surf] != 'Y' && Anat[N_surf] != 'N') {
319             SUMA_S_Err("Anatomical flag must be either 'y' or 'n'");
320             exit (1);
321          }
322          /* get the LDP */
323          kar ++;
324          if (kar >= argc)  {
325             fprintf (SUMA_STDERR,
326                  "LocalDomainParent must follow Anatomical flag with -tsnad \n");
327             exit (1);
328          }
329          LDP[N_surf] = argv[kar];
330 
331          /* get the nodeMarker */
332          kar ++;
333          if (kar >= argc)  {
334             fprintf (SUMA_STDERR,
335                  "LocalDomainParent must follow Anatomical flag with -tsnad \n");
336             exit (1);
337          }
338          MARK[N_surf] = argv[kar];
339          ++N_surf;
340          brk = YUP;
341       }
342 
343       if (!brk && (strcmp(argv[kar], "-tsnadl") == 0)) {
344          if (N_surf >= SUMA_MAX_N_SURFACE_SPEC) {
345             SUMA_SL_Err("Exceeding maximum number of allowed surfaces...");
346             exit(1);
347          }
348          /* get the type */
349          kar ++;
350          if (kar >= argc)  {
351             fprintf (SUMA_STDERR, "TYPE argument must follow -tsnad \n");
352             exit (1);
353          }
354          TypeC[N_surf] = SUMA_SurfaceTypeCode(argv[kar]);
355          if (  TypeC[N_surf] == SUMA_FT_ERROR ||
356                TypeC[N_surf] == SUMA_FT_NOT_SPECIFIED) {
357             fprintf (SUMA_STDERR, "%s is a bad file TYPE.\n", argv[kar]);
358             exit(1);
359          }
360          /* get the state */
361          kar ++;
362          if (kar >= argc)  {
363             fprintf (SUMA_STDERR,
364                      "STATE argument must follow TYPE with -tsnad \n");
365             exit (1);
366          }
367          State[N_surf] = argv[kar];
368 
369          /* get the name */
370          if (  TypeC[N_surf] == SUMA_SUREFIT ||
371                TypeC[N_surf] == SUMA_VEC) N_name = 2;
372          else N_name = 1;
373          if (kar+N_name >= argc)  {
374             fprintf (SUMA_STDERR, "need %d elements for NAME \n", N_name);
375             exit (1);
376          }
377          kar ++; Name_coord[N_surf] = argv[kar];
378          if (N_name == 2) {
379             kar ++; Name_topo[N_surf] = argv[kar];
380          } else {
381             Name_topo[N_surf] = NULL;
382          }
383 
384 
385          /* get the anatomical flag */
386          kar ++;
387          if (kar >= argc)  {
388             fprintf (SUMA_STDERR,
389                      "Anatomical flag must follow NAME with -tsnad \n");
390             exit (1);
391          }
392          Anat[N_surf] = SUMA_TO_UPPER_C(argv[kar][0]);
393          if (Anat[N_surf] != 'Y' && Anat[N_surf] != 'N') {
394             SUMA_S_Err("Anatomical flag must be either 'y' or 'n'");
395             exit (1);
396          }
397          /* get the LDP */
398          kar ++;
399          if (kar >= argc)  {
400             fprintf (SUMA_STDERR,
401                  "LocalDomainParent must follow Anatomical flag with -tsnad \n");
402             exit (1);
403          }
404          LDP[N_surf] = argv[kar];
405 
406          /* get the nodeMarker */
407          kar ++;
408          if (kar >= argc)  {
409             fprintf (SUMA_STDERR,
410                  "LocalDomainParent must follow Anatomical flag with -tsnad \n");
411             exit (1);
412          }
413          LABEL[N_surf] = argv[kar];
414          ++N_surf;
415          brk = YUP;
416       }
417 
418       if (!brk) {
419          fprintf (SUMA_STDERR,
420                   "Error %s: Option %s not understood. Try -help for usage\n",
421                   FuncName, argv[kar]);
422          exit (1);
423       } else {
424          brk = NOPE;
425          kar ++;
426       }
427    }
428 
429    /* write out the comments */
430    if (!spec_name) {
431       fid = fopen("quick.spec", "w");
432    } else {
433       fid = fopen(spec_name,"w");
434    }
435    if (!fid){
436       SUMA_SL_Err("Failed to open file for output");
437       exit(1);
438    }
439    fprintf(fid,"# define the group\n");
440    fprintf(fid,"\tGroup = QuickSpec\n");
441 
442 
443    /* now create a list of unique states */
444    idefstate = 0;
445    if (!State[0]) {
446       Unique_st = SUMA_copy_string ("\tStateDef = S_1\n");
447       idefstate = 1;
448    } else {
449       sprintf(stmp, "\tStateDef = %s\n", State[0]);
450       Unique_st = SUMA_copy_string (stmp);
451    }
452    for (i=1; i < N_surf; ++i) {
453       if (!State[i]) {
454          ++idefstate;
455          sprintf(stmp,"\tStateDef = S_%d\n", idefstate);
456          Unique_st = SUMA_append_replace_string (Unique_st, stmp, "", 1);
457       } else {
458          if (SUMA_iswordin(Unique_st, State[i]) != 1) {
459             sprintf(stmp, "\tStateDef = %s\n", State[i]);
460             Unique_st = SUMA_append_replace_string(Unique_st, stmp, "", 1);
461          }
462       }
463    }
464    fprintf (fid, "# define the various States\n");
465    fprintf (fid, "%s\n", Unique_st);
466 
467    /* check on LDP correctness */
468    for (i=0; i < N_surf; ++i) {
469       if (LDP[i]) {
470          if (!strcmp(LDP[i],"same") || !strcmp(LDP[i],"Same"))
471             SUMA_TO_UPPER(LDP[i]);
472          if (strcmp(LDP[i],"SAME")) {
473             j= 0;
474             while (j<N_surf && strcmp(LDP[i], Name_coord[j])) ++j;
475             if (j == N_surf) {
476                SUMA_S_Errv("Could not find a surface named %s\n"
477                            "to be the local domain parent of %s\n",
478                            LDP[i], Name_coord[i]);
479                exit(1);
480             }
481             if (!strcmp(LDP[i], Name_coord[i])) {/* reset to SAME*/
482                LDP[i] = NULL; /* this results is SAME below */
483             }
484          }
485       }
486    }
487    /* now loop accross surfaces and write out the results */
488    idefstate = 0;
489    for (i=0; i < N_surf; ++i) {
490       fprintf(fid, "\nNewSurface\n");
491       fprintf(fid, "\tSurfaceType = %s\n", SUMA_SurfaceTypeString(TypeC[i]));
492       if (!State[i]) {
493          ++idefstate;
494          fprintf(fid, "\tSurfaceState = S_%d\n", idefstate);
495       } else fprintf(fid, "\tSurfaceState = %s\n", State[i]);
496       if (Name_topo[i]) {
497          fprintf(fid, "\tCoordFile = %s\n", Name_coord[i]);
498          fprintf(fid, "\tTopoFile = %s\n", Name_topo[i]);
499       } else {
500          fprintf(fid, "\tSurfaceName = %s\n", Name_coord[i]);
501       }
502       /* add LocalDomainParent */
503       if (LDP[i]) fprintf(fid, "\tLocalDomainParent = %s\n", LDP[i]);
504       else fprintf(fid, "\tLocalDomainParent = SAME\n");
505       /* add Anatomical */
506       if (Anat[i]) fprintf(fid, "\tAnatomical = %c\n", Anat[i]);
507       else fprintf(fid, "\tAnatomical = Y\n");
508       /* add nodeMarker */
509       if (MARK[i]) fprintf(fid, "\tNodeMarker = %s\n", MARK[i]);
510       if (LABEL[i]) fprintf(fid, "\tLabelDset = %s\n", LABEL[i]);
511 
512       /* binary ? */
513       switch (TypeC[i]) {
514          case SUMA_FREE_SURFER:
515             if (!SUMA_isExtension(Name_coord[i], ".asc")) {
516                fprintf(fid, "\tSurfaceFormat = BINARY\n");
517             }
518             break;
519          default:
520             break;
521       }
522    }
523 
524    fclose(fid); fid = NULL;
525 
526    if (Unique_st) SUMA_free(Unique_st); Unique_st = NULL;
527 
528    if (ps) SUMA_FreeGenericArgParse(ps); ps = NULL;
529    if (!SUMA_Free_CommonFields(SUMAg_CF)) {
530       fprintf(SUMA_STDERR,"Error %s: SUMAg_CF Cleanup Failed!\n", FuncName);
531       exit(1);
532    }
533 
534    SUMA_RETURN(0);
535 
536 }/* main quickspec */
537