1 /*****************************************************************************
2    Major portions of this software are copyrighted by the Medical College
3    of Wisconsin, 1994-2000, and are released under the Gnu General Public
4    License, Version 2.  See the file README.Copyright for details.
5 ******************************************************************************/
6 
7 #include "mrilib.h"
8 
9 static ATR_float *Update_float_atr(char *aname, char *fvstring);
10 static ATR_int *Update_int_atr(char *aname, char *ivstring);
11 
12 extern void Obliquity_to_coords(THD_3dim_dataset *);
13 
Syntax(int detail)14 void Syntax(int detail)
15 {
16    int ii ;
17 
18    printf(
19 "Changes some of the information inside a 3D dataset's header. ~1~\n"
20         "Note that this program does NOT change the .BRIK file at all;\n"
21         "the main purpose of 3drefit is to fix up errors made when\n"
22         "using to3d.\n"
23         "To see the current values stored in a .HEAD file, use the command\n"
24         "'3dinfo dataset'.  Using 3dinfo both before and after 3drefit is\n"
25         "a good idea to make sure the changes have been made correctly!\n"
26         "\n"
27         "20 Jun 2006: 3drefit will now work on NIfTI datasets (but it will write\n"
28         "             out the entire dataset, into the current working directory)\n\n"
29          ) ;
30 
31    printf(
32 "Usage: 3drefit [options] dataset ... ~1~\n"
33 "where the options are\n"
34 "  -quiet          Turn off the verbose progress messages\n"
35 "\n"
36 "  -orient code    Sets the orientation of the 3D volume(s) in the .BRIK.\n"
37 "                  The code must be 3 letters, one each from the\n"
38 "                  pairs {R,L} {A,P} {I,S}.  The first letter gives\n"
39 "                  the orientation of the x-axis, the second the\n"
40 "                  orientation of the y-axis, the third the z-axis:\n"
41 "                     R = right-to-left         L = left-to-right\n"
42 "                     A = anterior-to-posterior P = posterior-to-anterior\n"
43 "                     I = inferior-to-superior  S = superior-to-inferior\n"
44 "               ** WARNING: when changing the orientation, you must be sure\n"
45 "                  to check the origins as well, to make sure that the volume\n"
46 "                  is positioned correctly in space.\n"
47 "\n"
48 "  -xorigin distx  Puts the center of the edge voxel off at the given\n"
49 "  -yorigin disty  distance, for the given axis (x,y,z); distances in mm.\n"
50 "  -zorigin distz  (x=first axis, y=second axis, z=third axis).\n"
51 "                  Usually, only -zorigin makes sense.  Note that this\n"
52 "                  distance is in the direction given by the corresponding\n"
53 "                  letter in the -orient code.  For example, '-orient RAI'\n"
54 "                  would mean that '-zorigin 30' sets the center of the\n"
55 "                  first slice at 30 mm Inferior.  See the to3d manual\n"
56 "                  for more explanations of axes origins.\n"
57 "               ** SPECIAL CASE: you can use the string 'cen' in place of\n"
58 "                  a distance to force that axis to be re-centered.\n"
59 "\n"
60 "  -xorigin_raw xx Puts the center of the edge voxel at the given COORDINATE\n"
61 "  -yorigin_raw yy rather than the given DISTANCE.  That is, these values\n"
62 "  -zorigin_raw zz directly replace the offsets in the dataset header,\n"
63 "                  without any possible sign changes.\n"
64 "\n"
65 "  -duporigin cset Copies the xorigin, yorigin, and zorigin values from\n"
66 "                  the header of dataset 'cset'.\n"
67 "\n"
68 "  -dxorigin dx    Adds distance 'dx' (or 'dy', or 'dz') to the center\n"
69 "  -dyorigin dy    coordinate of the edge voxel.  Can be used with the\n"
70 "  -dzorigin dz    values input to the 'Nudge xyz' plugin.\n"
71 "               ** WARNING: you can't use these options at the same\n"
72 "                  time you use -orient.\n"
73 "               ** WARNING: consider -shift_tags if dataset has tags\n"
74 "\n"
75 "  -xdel dimx      Makes the size of the voxel the given dimension,\n"
76 "  -ydel dimy      for the given axis (x,y,z); dimensions in mm.\n"
77 "  -zdel dimz   ** WARNING: if you change a voxel dimension, you will\n"
78 "                  probably have to change the origin as well.\n"
79 "  -keepcen        When changing a voxel dimension with -xdel (etc.),\n"
80 "                  also change the corresponding origin to keep the\n"
81 "                  center of the dataset at the same coordinate location.\n"
82 "  -xyzscale fac   Scale the size of the dataset voxels by the factor 'fac'.\n"
83 "                  This is equivalent to using -xdel, -ydel, -zdel together.\n"
84 "                  -keepcen is used on the first input dataset, and then\n"
85 "                  any others will be shifted the same amount, to maintain\n"
86 "                  their alignment with the first one.\n"
87 "               ** WARNING: -xyzscale can't be used with any of the other\n"
88 "                  options that change the dataset grid coordinates!\n"
89 "               ** N.B.: 'fac' must be positive, and using fac=1.0 is stupid.\n"
90 "\n"
91 "  -TR time        Changes the TR time to a new value (see 'to3d -help').\n"
92 "               ** You can also put the name of a dataset in for 'time', in\n"
93 "                  which case the TR for that dataset will be used.\n"
94 "               ** N.B.: If the dataset has slice time offsets, these will\n"
95 "                  be scaled by the factor newTR/oldTR. This scaling does not\n"
96 "                  apply if you use '-Tslices' in the same 3drefit run.\n"
97 "  -notoff         Removes the slice-dependent time-offsets.\n"
98 "  -Torg ttt       Set the time origin of the dataset to value 'ttt'.\n"
99 "                  (Time origins are set to 0 in to3d.)\n"
100 "               ** WARNING: These 3 options apply only to 3D+time datasets.\n"
101 "                   **N.B.: Using '-TR' on a dataset without a time axis\n"
102 "                           will add a time axis to the dataset.\n"
103 "\n"
104 "  -Tslices a b c d ...\n"
105 "                  Reset the slice time offsets to be 'a', 'b', 'c', ...\n"
106 "                  (in seconds). The number of values following '-Tslices'\n"
107 "                  should be the same as the number of slices in the dataset,\n"
108 "                  but 3drefit does NOT check that this is true.\n"
109 "               ** If any offset time is < 0 or >= TR, a warning will be\n"
110 "                  printed (to stderr), but this is not illegal even though\n"
111 "                  it is a bad idea.\n"
112 "               ** If the dataset does not have a TR set, then '-Tslices'\n"
113 "                  will fail. You can use '-TR' to set the inter-volume time\n"
114 "                  spacing in the same 3drefit command.\n"
115 "               ** If you have the slices times stored (e.g., from DICOM) in\n"
116 "                  some other units, you can scale them to be in seconds by\n"
117 "                  putting a scale factor after the '-Tslices' option as follows:\n"
118 "                    -Tslices '*0.001' 300 600 900 ...\n"
119 "                  which would be used to scale from milliseconds to seconds.\n"
120 "                  The format is to start the scale factor with a '*' to tell\n"
121 "                  3drefit that this number is not a slice offset but is to be\n"
122 "                  used a a scale factor for the rest of the following values.\n"
123 "                  Since '*' is a filename wildcard, it needs to be in quotes!\n"
124 "               ** The program stops looking for number values after '-Tslices'\n"
125 "                  when it runs into something that does not look like a number.\n"
126 "                  Here, 'look like a number' means a character string that:\n"
127 "                    * starts with a digit 0..9\n"
128 "                    * starts with a decimal point '.' followed by a digit\n"
129 "                    * starts with a minus sign '-' followed by a digit\n"
130 "                    * starts with '-.' followed by a digit\n"
131 "                  So if the input dataset name starts with a digit, and the\n"
132 "                  last command line option '-Tslices', 3drefit will think\n"
133 "                  the filename is actually a number for a slice offset time.\n"
134 "                  To avoid this problem, you can do one of these things:\n"
135 "                    * Put in an option that is just the single character '-'\n"
136 "                    * Don't use '-Tslices' as the last option\n"
137 "                    * Put a directory name before the dataset name, as in\n"
138 "                      './Galacticon.nii'\n"
139 "                ** If you have the slice time offsets stored in a text file\n"
140 "                   as a list of values, then you can input these values on\n"
141 "                   the command line using the Unix backquote operator, as in\n"
142 "                     -Tslices `cat SliceTimes.1D`\n"
143 "                ** For example, if the slice time offsets are in a JSON\n"
144 "                   sidecar (a la BIDS), you might be able to something like\n"
145 "                   the following to extract the timings into a file:\n"
146 "  abids_json_tool.py -json2txt -input sub-10506_task-pamenc_bold.json -prefix junk.txt\n"
147 "  grep SliceTiming junk.txt | sed -e 's/^SliceTiming *://' > SliceTimes.1D\n"
148 "  \\rm junk.txt\n"
149 "\n"
150 "  -newid          Changes the ID code of this dataset as well.\n"
151 "\n"
152 "  -nowarp         Removes all warping information from dataset.\n"
153 "\n"
154 "  -apar aset      Set the dataset's anatomy parent dataset to 'aset'\n"
155 "               ** N.B.: The anatomy parent is the dataset from which the\n"
156 "                  transformation from +orig to +acpc and +tlrc coordinates\n"
157 "                  is taken.  It is appropriate to use -apar when there is\n"
158 "                  more than 1 anatomical dataset in a directory that has\n"
159 "                  been transformed.  In this way, you can be sure that\n"
160 "                  AFNI will choose the correct transformation.  You would\n"
161 "                  use this option on all the +orig dataset that are\n"
162 "                  aligned with 'aset' (i.e., that were acquired in the\n"
163 "                  same scanning session).\n"
164 "               ** N.B.: Special cases of 'aset'\n"
165 "                   aset = NULL --> remove the anat parent info from the dataset\n"
166 "                   aset = SELF --> set the anat parent to be the dataset itself\n"
167 "\n"
168 "  -wpar wset      Set the warp parent (the +orig version of a +tlrc dset).\n"
169 "                  This option is used by @auto_tlrc. Do not use it unless\n"
170 "                  you know what you're doing. \n"
171 "\n"
172 "  -clear_bstat    Clears the statistics (min and max) stored for each sub-brick\n"
173 "                  in the dataset.  This is useful if you have done something to\n"
174 "                  modify the contents of the .BRIK file associated with this\n"
175 "                  dataset.\n"
176 "  -redo_bstat     Re-computes the statistics for each sub-brick.  Requires\n"
177 "                  reading the .BRIK file, of course.  Also does -clear_bstat\n"
178 "                  before recomputing statistics, so that if the .BRIK read\n"
179 "                  fails for some reason, then you'll be left without stats.\n"
180 "\n"
181 "  -statpar v ...  Changes the statistical parameters stored in this\n"
182 "                  dataset.  See 'to3d -help' for more details.\n"
183 "\n"
184 "  -markers        Adds an empty set of AC-PC markers to the dataset,\n"
185 "                  if it can handle them (is anatomical, is in the +orig\n"
186 "                  view, and isn't 3D+time).\n"
187 "               ** WARNING: this will erase any markers that already exist!\n"
188 "\n"
189 "  -shift_tags     Apply -dxorigin (and y and z) changes to tags.\n"
190 "\n"
191 "  -dxtag dx       Add dx to the coordinates of all tags.\n"
192 "  -dytag dy       Add dy to the coordinates of all tags.\n"
193 "  -dztag dz       Add dz to the coordinates of all tags.\n"
194 "\n"
195 "  -view code      Changes the 'view' to be 'code', where the string 'code'\n"
196 "                  is one of 'orig', 'acpc', or 'tlrc'.\n"
197 "               ** WARNING: The program will also change the .HEAD and .BRIK\n"
198 "                  filenames to match.  If the dataset filenames already\n"
199 "                  exist in the '+code' view, then this option will fail.\n"
200 "                  You will have to rename the dataset files before trying\n"
201 "                  to use '-view'.  If you COPY the files and then use\n"
202 "                  '-view', don't forget to use '-newid' as well!\n"
203 "               ** WARNING2: Changing the view without specifying the new \n"
204 "                  might lead to conflicting information. Consider specifying\n"
205 "                  the space along with -view\n"
206 "  -space spcname  Associates the dataset with a specific template type, e.g.\n"
207 "                  TLRC, MNI, ORIG. The default assumed for +tlrc datasets is\n"
208 "                  'TLRC'. One use for this attribute is to use MNI space\n"
209 "                  coordinates and atlases instead of the default TLRC space.\n"
210 "               ** See WARNING2 for -view option.\n"
211 "  -cmap cmaptype  Associate colormap type with dataset. Available choices are\n"
212 "                  CONT_CMAP (the default), INT_CMAP (integer colormap display)\n"
213 "                  and SPARSE_CMAP (for sparse integer colormaps). INT_CMAP is\n"
214 "                  appropriate for showing ROI mask datasets or Atlas datasets\n"
215 "                  where the continuous color scales are not useful.\n"
216 "\n"
217 "  -label2 llll    Set the 'label2' field in a dataset .HEAD file to the\n"
218 "                  string 'llll'.  (Can be used as in AFNI window titlebars.)\n"
219 "  -labeltable TTT Inset the label table TTT in the .HEAD file.\n"
220 "                  The label table format is described in README.environment\n"
221 "                  under the heading: 'Variable: AFNI_VALUE_LABEL_DTABLE'\n"
222 "              See also -copytables\n"
223 "\n"
224 "  -denote         Means to remove all possibly-identifying notes from\n"
225 "                  the header.  This includes the History Note, other text\n"
226 "                  Notes, keywords, and labels.\n"
227 "\n"
228 "  -deoblique      Replace transformation matrix in header with cardinal matrix.\n"
229 "                  This option DOES NOT deoblique the volume. To do so\n"
230 "                  you should use 3dWarp -deoblique. This option is not \n"
231 "                  to be used unless you really know what you're doing.\n"
232 "\n"
233 "  -oblique_origin\n"
234 "                  assume origin and orientation from oblique transformation\n"
235 "                  matrix rather than traditional cardinal information\n"
236 "\n"
237 "  -oblique_recenter\n"
238 "                  Adjust the origin so that the cardinalized 0,0,0 is in\n"
239 "                  the same brain location as that of the original (oblique?)\n"
240 "                  (scanner?) coordinates.\n"
241 "                  Round this to the nearest voxel center.\n"
242 "                * Even if cardinal, rounding might cause an origin shift\n"
243 "                  (see -oblique_recenter_raw).\n"
244 "\n"
245 "  -oblique_recenter_raw\n"
246 "                  Like -oblique_recenter, but do not round.\n"
247 "                  So coordinate 0,0,0 is in the exact same location, even\n"
248 "                  if not at a voxel center.\n"
249 "\n"
250 
251 "  -byteorder bbb  Sets the byte order string in the header.\n"
252 "                  Allowable values for 'bbb' are:\n"
253 "                     LSB_FIRST   MSB_FIRST   NATIVE_ORDER\n"
254 "                  Note that this does not change the .BRIK file!\n"
255 "                  This is done by programs 2swap and 4swap.\n"
256 "\n"
257 "  -checkaxes      Doesn't alter the input dataset; rather, this just\n"
258 "                  checks the dataset axes orientation codes and the\n"
259 "                  axes matrices for consistency.  (This option was\n"
260 "                  added primarily to check for bugs in various codes.)\n"
261 "\n"
262 "  -appkey ll      Appends the string 'll' to the keyword list for the\n"
263 "                  whole dataset.\n"
264 "  -repkey ll      Replaces the keyword list for the dataset with the\n"
265 "                  string 'll'.\n"
266 "  -empkey         Destroys the keyword list for the dataset.\n"
267    ) ;
268 
269    printf(
270     "\n"
271     "  -atrcopy dd nn  Copy AFNI header attribute named 'nn' from dataset 'dd'\n"
272     "                  into the header of the dataset(s) being modified.\n"
273     "                  For more information on AFNI header attributes, see\n"
274     "                  documentation file README.attributes. More than one\n"
275     "                  '-atrcopy' option can be used.\n"
276     "          **N.B.: This option is for those who know what they are doing!\n"
277     "                  Without the -saveatr option, this option is\n"
278     "                  meant to be used to alter attributes that are NOT\n"
279     "                  directly mapped into dataset internal structures, since\n"
280     "                  those structures are mapped back into attribute values\n"
281     "                  as the dataset is being written to disk.  If you want\n"
282     "                  to change such an attribute, you have to use the\n"
283     "                  corresponding 3drefit option directly or use the \n"
284     "                  -saveatr option.\n"
285     "\n"
286     "                  If you are confused, try to understand this: \n"
287     "                  Option -atrcopy was never intended to modify AFNI-\n"
288     "                  specific attributes. Rather, it was meant to copy\n"
289     "                  user-specific attributes that had been added to some\n"
290     "                  dataset using -atrstring option. A cursed day came when\n"
291     "                  it was convenient to use -atrcopy to copy an AFNI-specific\n"
292     "                  attribute (BRICK_LABS to be exact) and for that to\n"
293     "                  take effect in the output, the option -saveatr was added.\n"
294     "                  Contact Daniel Glen and/or Rick Reynolds for further \n"
295     "                  clarification and any other needs you may have.\n"
296     "\n"
297     "                  Do NOT use -atrcopy or -atrstring with other modification\n"
298     "                  options.\n"
299     "          See also -copyaux\n"
300     "\n"
301     "  -atrstring n 'x' Copy the string 'x' into the dataset(s) being\n"
302     "                   modified, giving it the attribute name 'n'.\n"
303     "                   To be safe, the 'x' string should be in quotes.\n"
304     "          **N.B.: You can store attributes with almost any name in\n"
305     "                  the .HEAD file.  AFNI will ignore those it doesn't\n"
306     "                  know anything about.  This technique can be a way of\n"
307     "                  communicating information between programs.  However,\n"
308     "                  when most AFNI programs write a new dataset, they will\n"
309     "                  not preserve any such non-standard attributes.\n"
310     "          **N.B.: Special case: if the string 'x' is of the form\n"
311     "                  'file:name', then the contents of the file 'name' will\n"
312     "                  be read in as a single string and stored in the attribute.\n"
313     "  -atrfloat name 'values'\n"
314     "  -atrint name 'values'\n"
315     "                  Create or modify floating point or integer attributes.\n"
316     "                  The input values may be specified as a single string\n"
317     "                  in quotes or as a 1D filename or string. For example,\n"
318     "     3drefit -atrfloat IJK_TO_DICOM_REAL '1 0.2 0 0 -0.2 1 0 0 0 0 1 0'"
319           " dset+orig\n"
320     "     3drefit -atrfloat IJK_TO_DICOM_REAL flipZ.1D dset+orig\n"
321     "     3drefit -atrfloat IJK_TO_DICOM_REAL \\ \n"
322     "       '1D:1,0.2,2@0,-0.2,1,2@0,2@0,1,0' \\ \n"
323     "       dset+orig\n"
324     "                  Almost all afni attributes can be modified in this way\n"
325     "  -saveatr        (default) Copy the attributes that are known to AFNI into \n"
326     "                  the dset->dblk structure thereby forcing changes to known\n"
327     "                  attributes to be present in the output.\n"
328     "                  This option only makes sense with -atrcopy\n"
329     "          **N.B.: Don't do something like copy labels of a dataset with \n"
330     "                  30 sub-bricks to one that has only 10, or vice versa.\n"
331     "                  This option is for those who would deservedly earn a\n"
332     "                  hunting license.\n"
333     "  -nosaveatr      Opposite of -saveatr\n"
334     "     Example: \n"
335     "     3drefit -saveatr -atrcopy WithLabels+tlrc BRICK_LABS NeedsLabels+tlrc\n"
336    ) ;
337 
338    printf(
339     "\n"
340     "  -'type'         Changes the type of data that is declared for this\n"
341     "                  dataset, where 'type' is chosen from the following:\n"
342    ) ;
343    printf("       ANATOMICAL TYPES\n") ;
344    for( ii=FIRST_ANAT_TYPE ; ii <= LAST_ANAT_TYPE ; ii++ ){
345       printf("     %8s == %-16.16s",ANAT_prefixstr[ii],ANAT_typestr[ii] ) ;
346       if( (ii-FIRST_ANAT_TYPE)%2 == 1 ) printf("\n") ;
347    }
348    if( (ii-FIRST_ANAT_TYPE)%2 == 1 ) printf("\n") ;
349    printf("       FUNCTIONAL TYPES\n") ;
350    for( ii=FIRST_FUNC_TYPE ; ii <= LAST_FUNC_TYPE ; ii++ ){
351       printf("     %8s == %-16.16s",FUNC_prefixstr[ii],FUNC_typestr[ii] ) ;
352       if( (ii-FIRST_ANAT_TYPE)%2 == 1 ) printf("\n") ;
353    }
354    if( (ii-FIRST_ANAT_TYPE)%2 == 1 ) printf("\n") ;
355 
356    printf(           /* 08 Jun 2004 */
357     "\n"
358     "  -copyaux auxset Copies the 'auxiliary' data from dataset 'auxset'\n"
359     "                  over the auxiliary data for the dataset being\n"
360     "                  modified.  Auxiliary data comprises sub-brick labels,\n"
361     "                  keywords, statistics codes, nodelists, and labeltables\n"
362     "                  AND/OR atlas point lists.\n"
363     "                  '-copyaux' occurs BEFORE the '-sub' operations below,\n"
364     "                  so you can use those to alter the auxiliary data\n"
365     "                  that is copied from auxset.\n"
366     "\n" ) ;
367 
368    printf(           /* 11 Jan 2012 */
369     "\n"
370     "  -copytables tabset Copies labeltables AND/OR atlas point lists, if any,\n"
371     "                  from tabset to the input dataset.\n"
372     "                  '-copyaux' occurs BEFORE the '-sub' operations below,\n"
373     "                  so you can use those to alter the auxiliary data\n"
374     "                  that is copied from tabset. \n"
375     "\n" ) ;
376 
377 
378    printf(
379     "  -relabel_all xx  Reads the file 'xx', breaks it into strings,\n"
380     "                   and puts these strings in as the sub-brick\n"
381     "                   labels.  Basically a batch way of doing\n"
382     "                   '-sublabel' many times, for n=0, 1, ...\n"
383     "                 ** This option is executed BEFORE '-sublabel',\n"
384     "                    so any labels from '-sublabel' will over-ride\n"
385     "                    labels from this file.\n"
386     "                 ** Strings in the 'xx' file are separated by\n"
387     "                    whitespace (blanks, tabs, new lines).\n"
388     "\n" ) ;
389 
390    printf(
391     "  -relabel_all_str 'lab0 lab1 ... lab_p': Just like -relabel_all\n"
392     "                   but with labels all present in one string\n"
393     "\n" ) ;
394 
395    printf(
396     "  -sublabel_prefix PP: Prefix each sub-brick's label with PP\n"
397     "  -sublabel_suffix SS: Suffix each sub-brick's label with SS\n"
398     "\n" ) ;
399 
400    printf(
401     "The options below attach auxiliary data to sub-bricks in the dataset. ~1~\n"
402     "Each option may be used more than once so that\n"
403     "multiple sub-bricks can be modified in a single run of 3drefit.\n"
404     "\n"
405     "  -sublabel  n ll  Attach to sub-brick #n the label string 'll'.\n"
406     "  -subappkey n ll  Add to sub-brick #n the keyword string 'll'.\n"
407     "  -subrepkey n ll  Replace sub-brick #n's keyword string with 'll'.\n"
408     "  -subempkey n     Empty out sub-brick #n' keyword string\n"
409     "\n"
410     "  -substatpar n type v ...\n"
411     "                  Attach to sub-brick #n the statistical type and\n"
412     "                  the auxiliary parameters given by values 'v ...',\n"
413     "                  where 'type' is one of the following:\n"
414    ) ;
415    printf("         Stat Types: ~2~\n"
416           "         type  Description  PARAMETERS\n"
417           "         ----  -----------  ----------------------------------------\n" ) ;
418    for( ii=FIRST_FUNC_TYPE ; ii <= LAST_FUNC_TYPE ; ii++ ){
419      if( FUNC_IS_STAT(ii) )
420        printf("         %4s  %-11.11s  %s\n",
421               FUNC_prefixstr[ii] , FUNC_typestr[ii]+6 , FUNC_label_stat_aux[ii] ) ;
422    }
423    printf(
424      "\n"
425      "You can also use option '-unSTAT' to remove all statistical encodings\n"
426      "from sub-bricks in the dataset.  This operation would be desirable if\n"
427      "you modified the values in the dataset (e.g., via 3dcalc).\n"
428      " ['-unSTAT' is done BEFORE the '-substatpar' operations, so you can  ]\n"
429      " [combine these options to completely redo the sub-bricks, if needed.]\n"
430      " [Option '-unSTAT' also implies that '-unFDR' will be carried out.   ]\n"
431    ) ;
432 
433    printf(
434     "\n"
435     "The following options allow you to modify VOLREG fields: ~1~\n"
436     "  -vr_mat val1 ... val12  Use these twelve values for VOLREG_MATVEC_index.\n"
437     "  -vr_mat_ind index       Index of VOLREG_MATVEC_index field to be modified.\n"
438     "                          Optional, default index is 0.\n"
439     "NB: You can only modify one VOLREG_MATVEC_index at a time\n"
440     "  -vr_center_old x y z    Use these 3 values for VOLREG_CENTER_OLD.\n"
441     "  -vr_center_base x y z   Use these 3 values for VOLREG_CENTER_BASE.\n"
442     "\n"
443    );
444 
445    printf(
446     "\n"
447     "The following options let you modify the FDR curves stored in the header: ~1~\n"
448     "\n"
449     " -addFDR = For each sub-brick marked with a statistical code, (re)compute\n"
450     "           the FDR curve of z(q) vs. statistic, and store in the dataset header\n"
451     "           * '-addFDR' runs as if '-new -pmask' were given to 3dFDR, so that\n"
452     "              stat values == 0 will be ignored in the FDR algorithm.\n"
453     "\n"
454     " -FDRmask mset = load dataset 'mset' and use it as a mask\n"
455     " -STATmask mset  for the '-addFDR' calculations.\n"
456     "                 * This can be useful if you ran 3dDeconvolve/3dREMLFIT\n"
457     "                    without a mask, and want to apply a mask to improve\n"
458     "                    the FDR estimation procedure.\n"
459     "                 * If '-addFDR' is NOT given, then '-FDRmask' does nothing.\n"
460     "                 * 3drefit does not generate an automask for FDR purposes\n"
461     "                    (unlike 3dREMLfit and 3dDeconvolve), since the input\n"
462     "                    dataset may contain only statistics and no structural\n"
463     "                    information about the brain.\n"
464     "\n"
465     " -unFDR  = Remove all FDR curves from the header\n"
466     "           [you will want to do this if you have done something to ]\n"
467     "           [modify the values in the dataset statistical sub-bricks]\n"
468     "\n"
469    ) ;
470 
471    printf("++ Last program update: 27 Mar 2009\n");
472 
473    PRINT_COMPILE_DATE ; exit(0) ;
474 }
475 
SynErr(char * str)476 void SynErr(char *str)
477 {
478    if (str) ERROR_exit(str) ;  /* does not return */
479    else Syntax(0);
480    return;
481 }
482 
483 
484 #define ASET_NULL 1
485 #define ASET_SELF 2
486 
main(int argc,char * argv[])487 int main( int argc , char *argv[] )
488 {
489    THD_3dim_dataset * dset = NULL, * aset = NULL , *waset = NULL;
490                       int aset_code = 0    ; /* 14 Dec 1999 */
491                       int waset_code = 0;
492    THD_dataxes      * daxes = NULL;
493    int new_stuff = 0 ;
494    int new_orient = 0 ; char orient_code[4]={"LOV"} ; int xxor=0,yyor=0,zzor=0 ;
495    int new_xorg   = 0 ; float xorg = 0.0; int cxorg=0, dxorg=0 , duporg=0 ;
496    int new_yorg   = 0 ; float yorg = 0.0; int cyorg=0, dyorg=0 ;
497    int new_zorg   = 0 ; float zorg = 0.0; int czorg=0, dzorg=0 ;
498    int new_tags   = 0 ; int shift_tags = 0 ; /* 08 May 2006 [rickr] */
499                         float dxtag=0.0, dytag=0.0, dztag=0.0 ;
500    int new_xdel   = 0 ; float xdel = 0.0;
501    int new_ydel   = 0 ; float ydel = 0.0;
502    int new_zdel   = 0 ; float zdel = 0.0;
503    int new_TR     = 0 ; float TR = 0.0;
504    int new_Tslices= 0 ; float *Tslices = NULL ; /* 18 Dec 2018 */
505    int new_Torg   = 0 ; float Torg = 0.0; /* 29 Jan 2003 */
506    int new_tunits = 0 ; int tunits = 0;
507    int new_idcode = 0 ;
508    int new_nowarp = 0 ;
509    int new_stataux= 0 ; float stataux[MAX_STAT_AUX] ;
510    int new_type   = 0 ; int dtype = 0 , ftype = 0, nvals = 0;
511    int new_markers= 0 ;
512    int new_view   = 0 ; int vtype = 0;
513    int new_key    = 0 ; char * key = NULL;
514    int new_byte_order = 0 ;          /* 25 Apr 1998 */
515    int new_toff_sl    = 0 ;          /* 12 Feb 2001 */
516    int clear_bstat    = 0 ;          /* 28 May 2002 */
517    int redo_bstat     = 0 ;          /* 01 Feb 2005 */
518    int copyaux        = 0 ;          /* 08 Jun 2004 */
519    int copytabs       = 0 ;          /* 11 Jan 2012 */
520    THD_3dim_dataset *auxset=NULL ;   /* 08 Jun 2004 */
521    THD_3dim_dataset *tabset=NULL ;   /* 11 Jan 2012 */
522    char *new_label2   = NULL ;       /* 21 Dec 2004 */
523    char *labeltable   = NULL;        /* 25 Feb 2010 ZSS */
524    int denote         = 0 ;          /* 08 Jul 2005 */
525    RwcBoolean write_output ;         /* 20 Jun 2006 [rickr] */
526    int keepcen        = 0 ;          /* 17 Jul 2006 [RWCox] */
527    float xyzscale     = 0.0f ;       /* 17 Jul 2006 */
528    int deoblique  = 0;               /* 20 Jun 2007 [drg] */
529    int use_oblique_origin = 0;       /* 01 Dec 2008 */
530    int do_FDR = 0 ;                  /* 23 Jan 2008 [RWCox] */
531    int do_killSTAT = 0 ;             /* 24 Jan 2008 [RWCox] */
532    int space          = 0 ;          /* 16 Mar 2009 [drg]*/
533    char *spacename = NULL;
534    byte *FDRmask = NULL ;            /* 27 Mar 2009 [RWcox] */
535    int  nFDRmask = 0 ;
536    int   ndone=0 ;                   /* 18 Jul 2006 */
537    int   verb =1 ;
538    int   did_something ;             /* 30 Mar 2010 */
539    int cmap = -1;                    /* colormap handling */
540    NI_str_array *sar_relab=NULL ;    /* 18 Apr 2011 */
541    int geom_change = 0;              /* 04 Nov 2011 [drg] */
542    int do_checkaxes = 0 ;            /* 27 Jun 2014 [RWCox] */
543    int obl_recenter = 0 ;            /* 17 Mar 2020 [rickr] */
544 
545 #define VINFO(x) do{ if(verb)ININFO_message(x) ; } while(0)
546 
547    char str[256] ;
548    int  iarg , ii ;
549 
550    typedef struct { int iv ; char lab[THD_MAX_SBLABEL] ; }     SUBlabel   ;
551    typedef struct { int iv ; float par[MAX_STAT_AUX+2] ; } SUBstatpar ;
552    typedef struct { int iv , code ; char * keyword ; }     SUBkeyword ;
553    int nsublab     = 0 ; SUBlabel *   sublab     = NULL ;
554    int nsubstatpar = 0 ; SUBstatpar * substatpar = NULL ;
555    int nsubkeyword = 0 ; SUBkeyword * subkeyword = NULL ;
556    char *cpt ;
557    int iv ;
558 
559    float volreg_mat[12];
560    float center_old[3];
561    float center_base[3];
562    int Do_volreg_mat = 0, Do_center_old = 0, Do_center_base = 0,
563        volreg_matind = 0, icnt = 0;
564    char *lcpt=NULL, *subsuff=NULL, *subpref=NULL;
565 
566    int   num_atrcopy = 0 ;    /* 03 Aug 2005 */
567    ATR_any **atrcopy = NULL ;
568    ATR_float  *atr_flt ;
569 
570    int saveatr = 1;
571    int atrmod = 0;  /* if no ATR is modified, don't overwrite normal changes */
572                                                       /* 28 Jul 2006 [rickr] */
573    THD_dmat33 tmat ;
574    THD_dfvec3 tvec ;
575 
576    int code, acount;
577 
578    /*-------------------------- help me if you can? --------------------------*/
579 
580    /*-- 20 Apr 2001: addto the arglist, if user wants to [RWCox] --*/
581 
582    mainENTRY("3drefit main"); machdep() ; PRINT_VERSION("3drefit") ; AUTHOR("RW Cox") ;
583    set_obliquity_report(0); /* silence obliquity */
584    { int new_argc ; char ** new_argv ;
585      addto_args( argc , argv , &new_argc , &new_argv ) ;
586      if( new_argv != NULL ){ argc = new_argc ; argv = new_argv ; }
587    }
588 
589    AFNI_logger("3drefit",argc,argv) ;
590    AFNI_setenv("AFNI_COMPRESSOR=NONE") ; /* 26 Jul 2013 */
591 
592    iarg = 1 ;
593    while( iarg < argc && argv[iarg][0] == '-' ){
594       if(strcmp(argv[iarg],"-h") == 0 ||
595          strncmp(argv[iarg],"-help",4) == 0 )
596          Syntax(strlen(argv[iarg]) > 3 ? 2:1) ;
597 
598       if( strcmp(argv[iarg],"-") == 0 ){ iarg++ ; continue ; } /* 18 Dec 2018 */
599 
600       /*----- -checkaxes [27 Jun 2014] -----*/
601 
602       if( strcasecmp(argv[iarg],"-checkaxes") == 0 ){
603         do_checkaxes = 1 ;  new_stuff++ ; iarg++ ; continue ;
604       }
605 
606       /*----- -addFDR [23 Jan 2008] -----*/
607 
608       if( strcasecmp(argv[iarg],"-addFDR") == 0 ){
609         do_FDR = 1 ;  new_stuff++ ; iarg++ ; continue ;
610       }
611       if( strcasecmp(argv[iarg],"-killFDR") == 0 || strcasecmp(argv[iarg],"-unFDR") == 0 ){
612         do_FDR = -1 ;  new_stuff++ ; iarg++ ; continue ;
613       }
614       if( strcasecmp(argv[iarg],"-killSTAT") == 0 || strcasecmp(argv[iarg],"-unSTAT") == 0 ){
615         do_killSTAT = 1 ; do_FDR = -1 ; new_stuff++ ; iarg++ ; continue ;
616       }
617 
618       if( strcasecmp(argv[iarg],"-FDRmask")  == 0 ||
619           strcasecmp(argv[iarg],"-STATmask") == 0   ){   /*-- 27 Mar 2009 --*/
620 
621         bytevec *bvec ;  /* 15 Jul 2010 */
622 
623         if( iarg+1 >= argc ) SynErr("need 1 argument after -FDRmask!") ;
624         if( nFDRmask > 0 )   SynErr("can't have two -FDRmask options!") ;
625         bvec = THD_create_mask_from_string(argv[++iarg]) ;
626         if( bvec == NULL ) ERROR_exit("Can't decipher %s",argv[iarg-1]) ;
627         FDRmask = bvec->ar ; nFDRmask = bvec->nar ;
628         ii = THD_countmask(nFDRmask,FDRmask) ;
629         if( ii < 100 ){
630           WARNING_message("-FDRmask has only %d nonzero voxels: ignoring",ii) ;
631           KILL_bytevec(bvec) ; FDRmask = NULL ; nFDRmask = 0 ;
632         } else {
633           INFO_message("%s has %d nonzero voxels (out of %d total)",
634                        argv[iarg-1],ii,nFDRmask) ;
635         }
636         iarg++ ; continue ;
637       }
638 
639       /*----- -atrcopy dd nn [03 Aug 2005] -----*/
640 
641       if( strcmp(argv[iarg],"-atrcopy") == 0 ){
642         THD_3dim_dataset *qset ; ATR_any *atr ;
643 
644         if( iarg+2 >= argc ) SynErr("need 2 arguments after -atrcopy!") ;
645 
646         qset = THD_open_dataset( argv[++iarg] ) ;
647         if( qset == NULL ){
648           WARNING_message("Can't open -atrcopy dataset %s",argv[iarg]) ;
649           iarg++ ; goto atrcopy_done ;
650         }
651         atr = THD_find_atr( qset->dblk , argv[++iarg] ) ;
652         if( atr == NULL ){
653           WARNING_message("Can't find attribute %s in -atrcopy dataset %s",
654                           argv[iarg],argv[iarg-1]) ;
655           DSET_delete(qset) ; goto atrcopy_done ;
656         }
657 
658         atrcopy = (ATR_any **)realloc( (void *)atrcopy ,
659                                        sizeof(ATR_any *)*(num_atrcopy+1) ) ;
660         atrcopy[num_atrcopy++] = THD_copy_atr( atr ) ;
661         /* atr_print( atr, NULL , NULL, '\0', 1) ;  */
662         DSET_delete(qset) ;
663         atrmod = 1;  /* replaced new_stuff   28 Jul 2006 rcr */
664 
665       atrcopy_done:
666         iarg++ ; continue ;
667       }
668 
669       /*----- -atrstring nn xx [03 Aug 2005] -----*/
670 
671       if( strcmp(argv[iarg],"-atrstring") == 0 ){
672         ATR_string *atr ; char *aname , *xx , *yy=NULL ;
673 
674         if( iarg+2 >= argc ) SynErr("need 2 arguments after -atrstring!") ;
675 
676         aname = argv[++iarg] ;
677         if( !THD_filename_pure(aname) ){
678           WARNING_message("Illegal -atrstring name %s",aname) ;
679           iarg++ ; goto atrstring_done ;
680         }
681         xx  = argv[++iarg] ;
682         atr = (ATR_string *)RwcMalloc(sizeof(ATR_string)) ;
683 
684         if( strncmp(xx,"file:",5) == 0 && strlen(xx) > 5 ){  /* 08 Jul 2010 */
685           int ii ;
686           yy = AFNI_suck_file(xx+5) ;
687           if( yy == NULL ){
688             WARNING_message("Can't read '%s'",xx) ; goto atrstring_done ;
689           }
690           xx = yy ;
691           for( ii=strlen(yy)-1 ; ii > 0 && isspace(yy[ii]) ; ii-- )
692             yy[ii] = '\0' ;   /* truncate trailing whitespace */
693         }
694 
695         atr->type = ATR_STRING_TYPE ;
696         atr->name = RwcNewString( aname ) ;
697         atr->nch  = strlen(xx)+1 ; ;
698         atr->ch   = (char *)RwcMalloc( sizeof(char) * atr->nch ) ;
699         memcpy( atr->ch , xx , sizeof(char) * atr->nch ) ;
700 
701         if( yy != NULL ) free(yy) ;  /* 08 Jul 2010 */
702 
703         atrcopy = (ATR_any **)realloc( (void *)atrcopy ,
704                                        sizeof(ATR_any *)*(num_atrcopy+1) ) ;
705         atrcopy[num_atrcopy++] = (ATR_any *)atr ;
706 
707         atrmod = 1;  /* replaced new_stuff++   28 Jul 2006 [rickr] */
708        atrstring_done:
709         iarg++ ; continue ;
710       }
711 
712 
713       /*----- -atrfloat name "xx.xx yy.yy ..." [02 Oct 2008] -----*/
714       if( strcmp(argv[iarg],"-atrfloat") == 0 ){
715         ATR_float *atr ;
716 
717         if( iarg+2 >= argc ) SynErr("need 2 arguments after -atrfloat!") ;
718         atr = Update_float_atr(argv[iarg+1], argv[iarg+2]);
719         if(atr) {
720            /* add this float attribute to list of attributes being modified */
721            atrcopy = (ATR_any **)realloc( (void *)atrcopy ,
722                                        sizeof(ATR_any *)*(num_atrcopy+1) ) ;
723            atrcopy[num_atrcopy++] = (ATR_any *)atr ;
724 
725            atrmod = 1;  /* replaced new_stuff++   28 Jul 2006 [rickr] */
726         }
727 
728         iarg+=3 ; continue ;
729       }
730 
731       /*----- -atrint name "xx.xx yy.yy ..." [06 Oct 2008] -----*/
732       if( strcmp(argv[iarg],"-atrint") == 0 ){
733         ATR_int *atr ;
734 
735         if( iarg+2 >= argc ) SynErr("need 2 arguments after -atrint!") ;
736         atr = Update_int_atr(argv[iarg+1], argv[iarg+2]);
737         if(atr) {
738            /* add this int attribute to list of attributes being modified */
739            atrcopy = (ATR_any **)realloc( (void *)atrcopy ,
740                                        sizeof(ATR_any *)*(num_atrcopy+1) ) ;
741            atrcopy[num_atrcopy++] = (ATR_any *)atr ;
742 
743            atrmod = 1;  /* new or modified attribute */
744         }
745 
746         iarg+=3 ; continue ;
747       }
748 
749 
750       if( strcmp(argv[iarg],"-saveatr") == 0 ){
751         saveatr = 1 ; iarg++ ; continue ;
752       }
753 
754       if( strcmp(argv[iarg],"-nosaveatr") == 0 ){
755         saveatr = 0 ; iarg++ ; continue ;
756       }
757 
758       /*----- -denote [08 Jul 2005] -----*/
759 
760       if( strcmp(argv[iarg],"-denote") == 0 ){
761         denote = 1 ; new_stuff++ ; iarg++ ; continue ;
762       }
763 
764       /*----- -copyaux auxset [08 Jun 2004] -----*/
765 
766       if( strcmp(argv[iarg],"-copyaux") == 0 ){
767 
768          if( iarg+1 >= argc ) SynErr("need 1 argument after -copyaux!") ;
769 
770          if( auxset != NULL ) SynErr("Can't have more than one -copyaux option!") ;
771 
772          iarg++ ; copyaux = 1 ;
773          if( strcmp(argv[iarg],"NULL") == 0 ){  /* special case */
774             auxset = NULL ;
775          } else {
776             auxset = THD_open_one_dataset( argv[iarg] ) ;
777             if( auxset == NULL ) SynErr("Can't open -copyaux dataset!") ;
778          }
779 
780          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
781       }
782 
783       /*----- -copytables tabset [12 Jan 2012] -----*/
784 
785       if( strcmp(argv[iarg],"-copytables") == 0 ){
786 
787          if( iarg+1 >= argc ) SynErr("need 1 argument after -copytables!") ;
788 
789          if( tabset != NULL ) SynErr("Can't have more than one -copytables option!") ;
790 
791          iarg++ ; copytabs = 1 ;
792 
793          tabset = THD_open_one_dataset( argv[iarg] ) ;
794          if( tabset == NULL ) SynErr("Can't open -copytables dataset!") ;
795 
796          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
797       }
798 
799       /*----- -apar aset [14 Oct 1999] -----*/
800 
801       if( strcmp(argv[iarg],"-apar")       == 0 ||
802           strcmp(argv[iarg],"-anatparent") == 0 ||
803           strcmp(argv[iarg],"-aset")       == 0    ){
804 
805          if( iarg+1 >= argc )
806             SynErr("need 1 argument after -apar!") ;
807 
808          if( aset != NULL || aset_code != 0 )                 /* 13-14 Dec 1999 */
809             SynErr("Can't have more than one -apar option!");
810 
811          iarg++ ;
812          if( strcmp(argv[iarg],"NULL") == 0 ){    /* 14 Dec 1999: special cases */
813             aset_code = ASET_NULL ;
814          } else if( strcmp(argv[iarg],"SELF") == 0 ){
815             aset_code = ASET_SELF ;
816          } else {
817             aset = THD_open_one_dataset( argv[iarg] ) ;
818             if( aset == NULL )
819                SynErr("Can't open -apar dataset!") ;
820          }
821 
822          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
823       }
824 
825       /*----- -wpar wset [ZSS June 06] -----*/
826 
827       if( strcmp(argv[iarg],"-wpar")       == 0 ||
828           strcmp(argv[iarg],"-warpparent") == 0 ||
829           strcmp(argv[iarg],"-wset")       == 0    ){
830 
831          if( iarg+1 >= argc )
832             SynErr("need 1 argument after -wpar!") ;
833 
834          if( waset != NULL || waset_code != 0 )
835             SynErr("Can't have more than one -wpar option!");
836 
837          iarg++ ;
838          if( strcmp(argv[iarg],"NULL") == 0 ){
839             waset_code = ASET_NULL ;
840          } else if( strcmp(argv[iarg],"SELF") == 0 ){
841             waset_code = ASET_SELF ;
842          } else {
843             waset = THD_open_one_dataset( argv[iarg] ) ;
844             if( waset == NULL )
845                SynErr("Can't open -wpar dataset!") ;
846          }
847 
848          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
849       }
850 
851       /*----- -clear_bstat option [28 May 2002] -----*/
852 
853       if( strcmp(argv[iarg],"-clear_bstat") == 0 ){
854          clear_bstat = 1 ;
855          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
856       }
857 
858       if( strcmp(argv[iarg],"-redo_bstat") == 0 ){  /* 01 Feb 2005 */
859          clear_bstat = 1 ; redo_bstat = 1 ;
860          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
861       }
862 
863       /*----- -byteorder option [25 April 1998] -----*/
864 
865       if( strncmp(argv[iarg],"-byteorder",7) == 0 ){
866          if( iarg+1 >= argc )
867             SynErr("need 1 argument after -byteorder!") ;
868 
869          iarg++ ;
870          if( strcmp(argv[iarg],LSB_FIRST_STRING) == 0 )
871             new_byte_order = LSB_FIRST ;
872          else if( strcmp(argv[iarg],MSB_FIRST_STRING) == 0 )
873             new_byte_order = MSB_FIRST ;
874          else if( strcmp(argv[iarg],NATIVE_STRING) == 0 )
875             new_byte_order = mri_short_order() ;
876          else
877             SynErr("illegal argument after -byteorder!") ;
878 
879          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
880       }
881 
882       /*----- -relabel_all option -----*/
883 
884       if( strcmp(argv[iarg],"-relabel_all") == 0 ||
885           strcmp(argv[iarg],"-relabel_all_str") == 0){   /* 18 Apr 2011 */
886         if( ++iarg >= argc ) SynErr("Need argument after -relabel_all*") ;
887         if (strcmp(argv[iarg-1],"-relabel_all") == 0 ) {
888            char *str ;
889            str = AFNI_suck_file(argv[iarg]) ;
890            if( str == NULL || *str == '\0' )
891              SynErr("Can't read file after -relabel_all") ;
892            sar_relab = NI_decode_string_list( str , "`" ) ; free(str) ;
893         } else {
894            sar_relab = NI_decode_string_list( argv[iarg], "`"  );
895         }
896         if( sar_relab == NULL || sar_relab->num < 1 )
897           SynErr("Can't decode file or string after -relabel_all*") ;
898         INFO_message("-relabel_all* %s contains %d label%s" ,
899               argv[iarg] , sar_relab->num , (sar_relab->num==1) ? "\0" : "s" ) ;
900         new_stuff++ ; iarg++ ; continue ;
901       }
902 
903 
904       /*----- -sublabel_prefix -----*/
905 
906       if( strcmp(argv[iarg],"-sublabel_prefix") == 0 ){   /* 15 Aug 2012 */
907         char *str ;
908         if( ++iarg >= argc ) SynErr("Need argument after -sublabel_prefix") ;
909         subpref = argv[iarg];
910 
911         new_stuff++ ; iarg++ ; continue ;
912       }
913 
914       /*----- -sublabel_suffix -----*/
915 
916       if( strcmp(argv[iarg],"-sublabel_suffix") == 0 ){   /* 15 Aug 2012 */
917         char *str ;
918         if( ++iarg >= argc ) SynErr("Need argument after -sublabel_suffix") ;
919         subsuff = argv[iarg] ;
920 
921         new_stuff++ ; iarg++ ; continue ;
922       }
923 
924       /*----- -sublabel option -----*/
925 
926       if( strncmp(argv[iarg],"-sublabel",7) == 0 ){
927          if( iarg+2 >= argc )
928             SynErr("need 2 arguments after -sublabel!") ;
929 
930          iv = strtol( argv[++iarg] , &cpt , 10 ) ;
931          if( iv < 0 || (iv == 0 && cpt == argv[iarg]) )
932             SynErr("illegal sub-brick index after -sublabel!") ;
933 
934          sublab = (SUBlabel *) RwcRealloc( (char *)sublab ,
935                                           sizeof(SUBlabel) * (nsublab+1) ) ;
936 
937          sublab[nsublab].iv = iv ;
938          /* max sublabel = 64, 10/28/2011 drg */
939          MCW_strncpy( sublab[nsublab].lab , argv[++iarg] , THD_MAX_SBLABEL ) ;
940          nsublab++ ; new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
941       }
942 
943       /*----- -subkeyword options -----*/
944 
945       if( strncmp(argv[iarg],"-subappkey",7) == 0 ||
946           strncmp(argv[iarg],"-subrepkey",7) == 0 ||
947           strncmp(argv[iarg],"-subempkey",7) == 0   ){
948 
949          int code , npl ;
950               if( strncmp(argv[iarg],"-subappkey",7) == 0 ) code = 1 ;
951          else if( strncmp(argv[iarg],"-subrepkey",7) == 0 ) code = 2 ;
952          else                                               code = 3 ;
953 
954          npl = (code == 3) ? 1 : 2 ;
955          if( iarg+npl >= argc )
956             SynErr("need arguments after -sub...key!") ;
957 
958          iv = strtol( argv[++iarg] , &cpt , 10 ) ;
959          if( iv < 0 || (iv == 0 && cpt == argv[iarg]) )
960             SynErr("illegal sub-brick index after -sub...key!") ;
961 
962          subkeyword = (SUBkeyword *) RwcRealloc( (char *)subkeyword ,
963                                                 sizeof(SUBkeyword)*(nsubkeyword+1) ) ;
964 
965          subkeyword[nsubkeyword].iv   = iv ;
966          subkeyword[nsubkeyword].code = code ;
967          if( code != 3 ) subkeyword[nsubkeyword].keyword = argv[++iarg] ;
968 
969          nsubkeyword++ ; new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
970       }
971 
972       /*----- -keywords options -----*/
973 
974       if( strncmp(argv[iarg],"-appkey",4) == 0 ||
975           strncmp(argv[iarg],"-repkey",4) == 0 ||
976           strncmp(argv[iarg],"-empkey",4) == 0   ){
977 
978          int code , npl ;
979               if( strncmp(argv[iarg],"-appkey",4) == 0 ) code = 1 ;
980          else if( strncmp(argv[iarg],"-repkey",4) == 0 ) code = 2 ;
981          else                                            code = 3 ;
982 
983          npl = (code == 3) ? 0 : 1 ;
984          if( iarg+code >= argc )
985             SynErr("need arguments after -...key!") ;
986 
987          new_key = code ;
988          if( code != 3 ) key = argv[++iarg] ;
989          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
990       }
991 
992       /*----- -substatpar option -----*/
993 
994       if( strncmp(argv[iarg],"-substatpar",7) == 0 ){
995          int fc ; float val ;
996 
997          if( iarg+2 >= argc )
998             SynErr("need at least 2 arguments after -substatpar!") ;
999 
1000          iv = strtol( argv[++iarg] , &cpt , 10 ) ;
1001          if( iv < 0 || (iv == 0 && cpt == argv[iarg]) )
1002             SynErr("illegal sub-brick index after -substatpar!") ;
1003 
1004          iarg++ ;
1005          if( strlen(argv[iarg]) < 3 )
1006             SynErr("illegal type code after -substatpar!") ;
1007          fc = (argv[iarg][0] == '-') ? 1 : 0 ;
1008 
1009          for( ii=FIRST_FUNC_TYPE ; ii <= LAST_FUNC_TYPE ; ii++ ){
1010             if( ! FUNC_IS_STAT(ii) ) continue ;
1011             if( strncmp( &(argv[iarg][fc]) ,
1012                          FUNC_prefixstr[ii] , THD_MAX_PREFIX ) == 0 ) break ;
1013          }
1014 
1015          if( ii > LAST_FUNC_TYPE )
1016             SynErr("unknown type code after -substatpar!") ;
1017 
1018          substatpar = (SUBstatpar *) RwcRealloc( (char *)substatpar ,
1019                                                 sizeof(SUBstatpar) * (nsubstatpar+1) ) ;
1020 
1021          substatpar[nsubstatpar].iv     = iv ;
1022          substatpar[nsubstatpar].par[0] = ii ;
1023          substatpar[nsubstatpar].par[1] = MAX_STAT_AUX ;
1024 
1025          for( ii=0 ; ii < MAX_STAT_AUX ; ii++ )
1026             substatpar[nsubstatpar].par[ii+2] = 0.0 ;
1027 
1028          ii = 2 ; iarg++ ;
1029          do{
1030             val = strtod( argv[iarg] , &cpt ) ;
1031             if( *cpt != '\0' ) break ;
1032             substatpar[nsubstatpar].par[ii++] = val ;
1033             iarg++ ;
1034          } while( iarg < argc && ii-2 < MAX_STAT_AUX ) ;
1035 
1036          nsubstatpar++ ; new_stuff++ ; continue ;  /* go to next arg */
1037       }
1038 
1039       /*----- -orient code option -----*/
1040 
1041 #define ORCODE(aa) \
1042   ( (aa)=='R' ? ORI_R2L_TYPE : (aa)=='L' ? ORI_L2R_TYPE : \
1043     (aa)=='P' ? ORI_P2A_TYPE : (aa)=='A' ? ORI_A2P_TYPE : \
1044     (aa)=='I' ? ORI_I2S_TYPE : (aa)=='S' ? ORI_S2I_TYPE : ILLEGAL_TYPE )
1045 
1046 #define OR3OK(x,y,z) ( ((x)&6) + ((y)&6) + ((z)&6) == 6 )
1047 
1048       if( strncmp(argv[iarg],"-orient",4) == 0 ){
1049          char acod ;
1050 
1051          if( iarg+1 >= argc ) SynErr("need an argument after -orient!");
1052 
1053          MCW_strncpy(orient_code,argv[++iarg],4) ;
1054          if( strlen(orient_code) != 3 ) SynErr("Illegal -orient code") ;
1055 
1056          acod = toupper(orient_code[0]) ; xxor = ORCODE(acod) ;
1057          acod = toupper(orient_code[1]) ; yyor = ORCODE(acod) ;
1058          acod = toupper(orient_code[2]) ; zzor = ORCODE(acod) ;
1059 
1060         if( xxor<0 || yyor<0 || zzor<0 || ! OR3OK(xxor,yyor,zzor) )
1061            SynErr("Unusable -orient code!") ;
1062 
1063          new_orient = 1 ; new_stuff++ ;
1064          iarg++ ; continue ;  /* go to next arg */
1065       }
1066 
1067       /** -?origin dist **/
1068 
1069       if( strcmp(argv[iarg],"-xorigin") == 0 ){
1070          if( ++iarg >= argc ) SynErr("need an argument after -xorigin!");
1071          if( strncmp(argv[iarg],"cen",3) == 0 ) cxorg = 1 ;
1072          else                                   xorg  = strtod(argv[iarg],NULL) ;
1073          dxorg = 0 ; new_xorg = 1 ; new_stuff++ ;
1074          geom_change = 1;
1075          iarg++ ; continue ;  /* go to next arg */
1076       }
1077 
1078       if( strcmp(argv[iarg],"-yorigin") == 0 ){
1079          if( ++iarg >= argc ) SynErr("need an argument after -yorigin!");
1080          if( strncmp(argv[iarg],"cen",3) == 0 ) cyorg = 1 ;
1081          else                                   yorg  = strtod(argv[iarg],NULL) ;
1082          dyorg = 0 ; new_yorg = 1 ; new_stuff++ ;
1083          geom_change = 1;
1084          iarg++ ; continue ;  /* go to next arg */
1085       }
1086 
1087       if( strcmp(argv[iarg],"-zorigin") == 0 ){
1088          if( ++iarg >= argc ) SynErr("need an argument after -zorigin!");
1089          if( strncmp(argv[iarg],"cen",3) == 0 ) czorg = 1 ;
1090          else                                   zorg  = strtod(argv[iarg],NULL) ;
1091          dzorg = 0 ; new_zorg = 1 ; new_stuff++ ;
1092          geom_change = 1;
1093          iarg++ ; continue ;  /* go to next arg */
1094       }
1095 
1096       /* 13 Sep 2000: -duporigin */
1097 
1098       if( strcmp(argv[iarg],"-duporigin") == 0 ){
1099          THD_3dim_dataset * cset ;
1100          if( ++iarg >= argc ) SynErr("need an argument after -duporigin!");
1101          cset = THD_open_dataset( argv[iarg] ) ;
1102          if( cset == NULL ) SynErr("couldn't open -duporigin dataset!");
1103          daxes = cset->daxes ;
1104          xorg = daxes->xxorg ; yorg = daxes->yyorg ; zorg = daxes->zzorg ;
1105          cxorg = cyorg = czorg = dxorg = dyorg = dzorg = 0 ;
1106          new_xorg = new_yorg = new_zorg = duporg = 1 ; new_stuff++ ;
1107          DSET_delete(cset) ;
1108          geom_change = 1;
1109          iarg++ ; continue ;  /* go to next arg */
1110       }
1111 
1112       /* 02 Mar 2000: -d?origin stuff, to go with plug_nudge.c */
1113 
1114       if( strcmp(argv[iarg],"-oblique_recenter") == 0 ){
1115          obl_recenter = 2 ;
1116          new_stuff++ ;
1117          /* no geom change */
1118          iarg++ ; continue ;  /* go to next arg */
1119       }
1120 
1121       if( strcmp(argv[iarg],"-oblique_recenter_raw") == 0 ){
1122          obl_recenter = 1 ;
1123          new_stuff++ ;
1124          /* no geom change */
1125          iarg++ ; continue ;  /* go to next arg */
1126       }
1127 
1128       if( strncmp(argv[iarg],"-dxorigin",4) == 0 ){
1129          if( ++iarg >= argc ) SynErr("need an argument after -dxorigin!");
1130          xorg = strtod(argv[iarg],NULL) ; dxorg = 1 ; cxorg = 0 ;
1131          new_xorg = 1 ; new_stuff++ ;
1132          geom_change = 1;
1133          iarg++ ; continue ;  /* go to next arg */
1134       }
1135 
1136       if( strncmp(argv[iarg],"-dyorigin",4) == 0 ){
1137          if( ++iarg >= argc ) SynErr("need an argument after -dyorigin!");
1138          yorg = strtod(argv[iarg],NULL) ; dyorg = 1 ; cyorg = 0 ;
1139          new_yorg = 1 ; new_stuff++ ;
1140          geom_change = 1;
1141          iarg++ ; continue ;  /* go to next arg */
1142       }
1143 
1144       if( strncmp(argv[iarg],"-dzorigin",4) == 0 ){
1145          if( ++iarg >= argc ) SynErr("need an argument after -dzorigin!");
1146          zorg = strtod(argv[iarg],NULL) ; dzorg = 1 ; czorg = 0 ;
1147          new_zorg = 1 ; new_stuff++ ;
1148          geom_change = 1;
1149          iarg++ ; continue ;  /* go to next arg */
1150       }
1151 
1152       /** 04 Oct 2002: _raw origins **/
1153 
1154       if( strcmp(argv[iarg],"-xorigin_raw") == 0 ){
1155          if( ++iarg >= argc ) SynErr("need an argument after -xorigin_raw!");
1156          xorg     = strtod(argv[iarg],NULL) ; cxorg = dxorg = 0 ;
1157          new_xorg = 2 ; new_stuff++ ;
1158          geom_change = 1;
1159          iarg++ ; continue ;  /* go to next arg */
1160       }
1161 
1162       if( strcmp(argv[iarg],"-yorigin_raw") == 0 ){
1163          if( ++iarg >= argc ) SynErr("need an argument after -yorigin_raw!");
1164          yorg     = strtod(argv[iarg],NULL) ; cyorg = dyorg = 0 ;
1165          new_yorg = 2 ; new_stuff++ ;
1166          geom_change = 1;
1167          iarg++ ; continue ;  /* go to next arg */
1168       }
1169 
1170       if( strcmp(argv[iarg],"-zorigin_raw") == 0 ){
1171          if( ++iarg >= argc ) SynErr("need an argument after -zorigin_raw!");
1172          zorg     = strtod(argv[iarg],NULL) ; czorg = dzorg = 0 ;
1173          new_zorg = 2 ; new_stuff++ ;
1174          geom_change = 1;
1175          iarg++ ; continue ;  /* go to next arg */
1176       }
1177 
1178       /** 04 Oct 2002: zadd VOLREG fields **/
1179       if( strcmp(argv[iarg],"-vr_mat") == 0 ){
1180          if( iarg+12 >= argc ) SynErr("need 12 arguments after -vr_mat!");
1181          icnt = 0;
1182          while (icnt < 12) {
1183             ++iarg;
1184             volreg_mat[icnt] = strtod(argv[iarg], &lcpt) ; if (*lcpt != '\0') SynErr("Bad syntax in list of numbers!");
1185             ++icnt;
1186          }
1187          Do_volreg_mat = 1; new_stuff++ ;
1188          ++iarg;
1189          continue ;  /* go to next arg */
1190       }
1191 
1192       if( strcmp(argv[iarg],"-vr_mat_ind") == 0) {
1193          if (++iarg >= argc) SynErr("need 1 argument after -vr_mat_ind!");
1194          volreg_matind = (int)strtol(argv[iarg], &lcpt, 10); if (*lcpt != '\0') SynErr("Bad syntax in number argument!");
1195          ++iarg;
1196          continue ;  /* go to next arg */
1197       }
1198 
1199       if( strcmp(argv[iarg],"-vr_center_old") == 0) {
1200          if (iarg+3 >= argc) SynErr("need 3 arguments after -vr_center_old");
1201          ++iarg;
1202          center_old[0] = strtod(argv[iarg],&lcpt) ; ++iarg; if (*lcpt != '\0') SynErr("Bad syntax in list of numbers!");
1203          center_old[1] = strtod(argv[iarg],&lcpt) ; ++iarg; if (*lcpt != '\0') SynErr("Bad syntax in list of numbers!");
1204          center_old[2] = strtod(argv[iarg],&lcpt) ;  if (*lcpt != '\0') SynErr("Bad syntax in list of numbers!");
1205          Do_center_old = 1; new_stuff++ ;
1206          ++iarg;
1207          continue ;  /* go to next arg */
1208       }
1209 
1210       if( strcmp(argv[iarg],"-vr_center_base") == 0) {
1211          if (iarg+3 >= argc) SynErr("need 3 arguments after -vr_center_base");
1212          ++iarg;
1213          center_base[0] = strtod(argv[iarg],&lcpt) ; ++iarg; if (*lcpt != '\0') SynErr("Bad syntax in list of numbers!");
1214          center_base[1] = strtod(argv[iarg],&lcpt) ; ++iarg; if (*lcpt != '\0') SynErr("Bad syntax in list of numbers!");
1215          center_base[2] = strtod(argv[iarg],&lcpt) ;  if (*lcpt != '\0') SynErr("Bad syntax in list of numbers!");
1216          Do_center_base = 1; new_stuff++ ;
1217          ++iarg;
1218          continue ;  /* go to next arg */
1219       }
1220 
1221       /** -?del dim **/
1222 
1223       if( strncmp(argv[iarg],"-xdel",4) == 0 ){
1224          if( iarg+1 >= argc ) SynErr("need an argument after -xdel!");
1225          xdel = strtod( argv[++iarg]  , NULL ) ;
1226          if( xdel <= 0.0 ) SynErr("argument after -xdel must be positive!") ;
1227          new_xdel = 1 ; new_stuff++ ;
1228          geom_change = 1;
1229          iarg++ ; continue ;  /* go to next arg */
1230       }
1231 
1232       if( strncmp(argv[iarg],"-ydel",4) == 0 ){
1233          if( iarg+1 >= argc ) SynErr("need an argument after -ydel!");
1234          ydel = strtod( argv[++iarg]  , NULL ) ;
1235          if( ydel <= 0.0 ) SynErr("argument after -ydel must be positive!") ;
1236          new_ydel = 1 ; new_stuff++ ;
1237          geom_change = 1;
1238          iarg++ ; continue ;  /* go to next arg */
1239       }
1240 
1241       if( strncmp(argv[iarg],"-zdel",4) == 0 ){
1242          if( iarg+1 >= argc ) SynErr("need an argument after -zdel!");
1243          zdel = strtod( argv[++iarg]  , NULL ) ;
1244          if( zdel <= 0.0 ) SynErr("argument after -zdel must be positive!") ;
1245          new_zdel = 1 ; new_stuff++ ;
1246          geom_change = 1;
1247          iarg++ ; continue ;  /* go to next arg */
1248       }
1249 
1250       if( strncmp(argv[iarg],"-keepcen",7) == 0 ){  /* 17 Jul 2006 */
1251          keepcen = 1 ;
1252          geom_change = 1;
1253          iarg++ ; continue ;  /* go to next arg */
1254       }
1255 
1256       if( strcmp(argv[iarg],"-verb") == 0 ){
1257          verb++ ; iarg++ ; continue ;
1258       }
1259       if( strcmp(argv[iarg],"-quiet") == 0 ){ /* 18 Dec 2017 */
1260          verb = 0 ; iarg++ ; continue ;
1261       }
1262 
1263       if( strncmp(argv[iarg],"-xyzscale",8) == 0 ){ /* 17 Jul 2006 */
1264          if( iarg+1 >= argc ) SynErr("need an argument after -xyzscale!");
1265          xyzscale = strtod( argv[++iarg] , NULL ) ;
1266          if( xyzscale <= 0.0f ) SynErr("argument after -xyzscale must be positive!");
1267          if( xyzscale == 1.0f )
1268            WARNING_message(
1269             "-xyzscale 1.0 really makes no sense, but if that's what you want" ) ;
1270          geom_change = 1;
1271          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
1272       }
1273 
1274       /** -TR **/
1275 
1276       if( strncmp(argv[iarg],"-TR",3) == 0 ){
1277          char *eptr = "\0" ;
1278          if( ++iarg >= argc ) SynErr("need an argument after -TR!");
1279 
1280          if( isalpha(argv[iarg][0])             ||
1281              strstr(argv[iarg],"+orig") != NULL ||
1282              strstr(argv[iarg],"+tlrc") != NULL ||
1283              strstr(argv[iarg],".nii")  != NULL    ){
1284            THD_3dim_dataset *qset = THD_open_dataset(argv[iarg]) ;
1285            if( qset != NULL ){
1286              DSET_UNMSEC(qset) ;
1287              TR = DSET_TR(qset); tunits = DSET_TIMEUNITS(qset);
1288              DSET_delete(qset) ; new_tunits = (tunits != ILLEGAL_TYPE) ;
1289              if( verb && TR > 0.0f ) INFO_message("new TR will be %g",TR) ;
1290            } else {
1291              ERROR_exit("-TR: can't open '%s' as a dataset",argv[iarg]) ;
1292            }
1293          } else {
1294            TR = strtod( argv[iarg]  , &eptr ) ;
1295          }
1296          if( TR <= 0.0 ) SynErr("argument after -TR must give a positive result!") ;
1297 
1298          if( strcmp(eptr,"ms")==0 || strcmp(eptr,"msec")==0 ){
1299             new_tunits = 1 ; tunits = UNITS_MSEC_TYPE ;
1300             ERROR_exit("TR expressed in milliseconds is no longer allowed.") ;
1301          } else if( strcmp(eptr,"s")==0 || strcmp(eptr,"sec")==0 ){
1302             new_tunits = 1 ; tunits = UNITS_SEC_TYPE ;
1303          } else if( strcmp(eptr,"Hz")==0 || strcmp(eptr,"Hertz")==0 ){
1304             new_tunits = 1 ; tunits = UNITS_HZ_TYPE ;
1305          }
1306 
1307          new_TR = 1 ; new_stuff++ ;
1308          iarg++ ; continue ;  /* go to next arg */
1309       }
1310 
1311       /** -Tslices [18 Dec 2018] **/
1312 
1313 #define IS_NUMERIC(sss)                                           \
1314  ( (                                       isdigit((sss)[0]) ) || \
1315    ( (sss)[0] == '.'                    && isdigit((sss)[1]) ) || \
1316    ( (sss)[0] == '-'                    && isdigit((sss)[1]) ) || \
1317    ( (sss)[0] == '-' && (sss)[1] == '.' && isdigit((sss)[2]) )   )
1318 
1319       if( strcasecmp(argv[iarg],"-Tslices") == 0 ){
1320         int ival ; float val , fac=1.0f ; char *cpt , *thisopt=argv[iarg];
1321          if( new_toff_sl > 0 )
1322            ERROR_exit("You cannot use -notoff and -Tslices in the same 3drefit command!") ;
1323         if( new_Tslices > 0 )
1324           ERROR_exit("You cannot uses option '%s' twice!",argv[iarg]) ;
1325         if( ++iarg >= argc )
1326           ERROR_exit("Option '%s' cannot be the last value on command line!",thisopt) ;
1327         if( argv[iarg][0] == '*' && IS_NUMERIC(argv[iarg]+1) ){
1328           fac = (float)strtod(argv[iarg]+1,&cpt ) ;
1329           if( fac <= 0.0f )
1330             ERROR_exit("Factor '%s' after option '%s' is illegal :(",argv[iarg],thisopt) ;
1331           iarg++ ;
1332 #if 0
1333 INFO_message("Set %s factor to %g",thisopt,fac) ;
1334 #endif
1335         }
1336         for( ival=0 ; iarg+ival < argc && IS_NUMERIC(argv[iarg+ival]) ; ival++ ){
1337           val = (float)strtod(argv[iarg+ival], &cpt ) ;
1338           if( cpt == argv[iarg+ival] ) break ;  /* something bad */
1339           Tslices = (float *)realloc( Tslices , sizeof(float)*(ival+1) ) ;
1340           Tslices[ival] = fac * val ;
1341           if( val < 0.0f )
1342             WARNING_message("Value '%s' (#%d after option '%s') is negative :(",
1343                             argv[iarg+ival] , iarg+1 , thisopt ) ;
1344         }
1345         new_Tslices = ival ;
1346         if( new_Tslices == 0 )
1347           ERROR_exit("No number values found after option '%s' :(",thisopt) ;
1348         else if( new_Tslices == 1 )
1349           ERROR_exit("Only one number value found after option '%s' :(",thisopt) ;
1350 #if 0
1351 { int qq ; fprintf(stderr,"%s values:",thisopt) ;
1352 for( qq=0 ; qq < new_Tslices ; qq++ ) fprintf(stderr," %g",Tslices[qq]) ;
1353 fprintf(stderr,"\n") ; }
1354 #endif
1355         iarg += ival ; new_stuff++ ;continue ;
1356       }
1357 
1358       /** -notoff (12 Feb 2001) **/
1359 
1360       if( strncmp(argv[iarg],"-notoff",7) == 0 ){
1361          if( new_Tslices > 0 )
1362            ERROR_exit("You cannot use -notoff and -Tslices in the same 3drefit command!") ;
1363          new_toff_sl = 1 ; new_stuff++ ;
1364          iarg++ ; continue ;  /* go to next arg */
1365       }
1366 
1367       /** -Torg (29 Jan 2003) **/
1368 
1369       if( strncmp(argv[iarg],"-Torg",5) == 0 ){
1370         char *eptr ;
1371         if( iarg+1 >= argc ) SynErr("need an argument after -Torg!");
1372         Torg = strtod( argv[++iarg]  , &eptr ) ;
1373         if( *eptr != '\0' )
1374           WARNING_message("-Torg %s ends in unexpected character\n",argv[iarg]) ;
1375         new_Torg = 1 ; new_stuff++ ;
1376         iarg++ ; continue ;  /* go to next arg */
1377       }
1378 
1379       /** -newid **/
1380 
1381       if( strncmp(argv[iarg],"-newid",4) == 0 ){
1382          new_idcode = 1 ; new_stuff++ ;
1383          iarg++ ; continue ;  /* go to next arg */
1384       }
1385 
1386       /** -nowarp **/
1387 
1388       if( strncmp(argv[iarg],"-nowarp",6) == 0 ){
1389          new_nowarp = 1 ; new_stuff++ ;
1390          iarg++ ; continue ;  /* go to next arg */
1391       }
1392 
1393       /** -statpar x x x **/
1394 
1395       if( strncmp(argv[iarg],"-statpar",4) == 0 ){
1396          float val ; char * ptr ;
1397 
1398          if( ++iarg >= argc ) SynErr("need an argument after -statpar!") ;
1399 
1400          for( ii=0 ; ii < MAX_STAT_AUX ; ii++ ) stataux[ii] = 0.0 ;
1401 
1402          ii = 0 ;
1403          do{
1404             val = strtod( argv[iarg] , &ptr ) ;
1405             if( *ptr != '\0' ) break ;
1406             stataux[ii++] = val ;
1407             iarg++ ;
1408          } while( iarg < argc ) ;
1409 
1410          if( ii == 0 ) SynErr("No numbers given after -statpar?") ;
1411 
1412          new_stataux = 1 ; new_stuff++ ;
1413          continue ;
1414       }
1415 
1416       /** -markers **/
1417 
1418       if( strncmp(argv[iarg],"-markers",4) == 0 ){
1419          new_markers = 1 ; new_stuff++ ;
1420          iarg++ ; continue ;  /* go to next arg */
1421       }
1422 
1423       /** -label2 [21 Dec 2004] **/
1424 
1425       if( strcmp(argv[iarg],"-label2") == 0 ){
1426         new_label2 = argv[++iarg] ; new_stuff++ ;
1427         iarg++ ; continue ;  /* go to next arg */
1428       }
1429 
1430       /** -labeltable [25 Feb 2010 ZSS] **/
1431 
1432       if( strcmp(argv[iarg],"-labeltable") == 0 ){
1433         labeltable = argv[++iarg] ; new_stuff++ ;
1434         iarg++ ; continue ;  /* go to next arg */
1435       }
1436 
1437       /** -view code **/
1438 
1439       if( strncmp(argv[iarg],"-view",4) == 0 ){
1440          char * code ;
1441          if( iarg+1 >= argc ) SynErr("need an argument after -view!") ;
1442          code = argv[++iarg] ; if( code[0] == '+' ) code++ ;
1443          for( vtype=0 ; vtype <= LAST_VIEW_TYPE ; vtype++ )
1444             if( strcmp(code,VIEW_codestr[vtype]) == 0 ) break ;
1445          if( vtype > LAST_VIEW_TYPE ) SynErr("argument after -view is illegal!") ;
1446          new_view = 1 ; new_stuff++ ;
1447          iarg++ ; continue ;  /* go to next arg */
1448       }
1449 
1450       /* tag options    08 May 2006 [rickr] */
1451 
1452       /* -shift_tags, apply -d?origin to tags */
1453       if( strncmp(argv[iarg],"-shift_tags",11) == 0 ){
1454          shift_tags = 1 ;
1455          iarg++ ; continue ;  /* go to next arg */
1456       }
1457 
1458       if( strncmp(argv[iarg],"-dxtag",6) == 0 ){
1459          if( ++iarg >= argc ) SynErr("need an argument after -dxtag!");
1460          dxtag = strtod(argv[iarg],NULL) ;
1461          new_tags = 1 ; new_stuff++ ;
1462          iarg++ ; continue ;  /* go to next arg */
1463       }
1464 
1465       if( strncmp(argv[iarg],"-dytag",6) == 0 ){
1466          if( ++iarg >= argc ) SynErr("need an argument after -dytag!");
1467          dytag = strtod(argv[iarg],NULL) ;
1468          new_tags = 1 ; new_stuff++ ;
1469          iarg++ ; continue ;  /* go to next arg */
1470       }
1471 
1472       if( strncmp(argv[iarg],"-dztag",6) == 0 ){
1473          if( ++iarg >= argc ) SynErr("need an argument after -dztag!");
1474          dztag = strtod(argv[iarg],NULL) ;
1475          new_tags = 1 ; new_stuff++ ;
1476          iarg++ ; continue ;  /* go to next arg */
1477       }
1478 
1479       /*----- -deoblique option [20 Jun 2007] -----*/
1480 
1481       if( strcmp(argv[iarg],"-deoblique") == 0 ){
1482          deoblique = 1 ;
1483          THD_set_oblique_report(0,0); /* turn off obliquity warning */
1484          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
1485       }
1486 
1487       /*----- -oblique_origin option [01 Dec 2008] -----*/
1488 
1489       if( strcmp(argv[iarg],"-oblique_origin") == 0 ){
1490          use_oblique_origin = 1 ;
1491          THD_set_oblique_report(0,0); /* turn off obliquity warning */
1492          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
1493       }
1494 
1495       /*----- -space option [16 Mar 2009] -----*/
1496 
1497       if( strcmp(argv[iarg],"-space") == 0 ){
1498          space = 1 ;
1499          spacename = argv[++iarg] ;
1500          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
1501       }
1502 
1503       /*----- -cmap option [31 Mar 2009] -----*/
1504       if( strcmp(argv[iarg],"-cmap") == 0 ){
1505          if( ++iarg >= argc ) SynErr("need an argument after -cmap!");
1506          if(strcmp(argv[iarg],"CONT_CMAP")==0)
1507             cmap = CONT_CMAP;
1508 
1509          else {
1510             if(strcmp(argv[iarg],"INT_CMAP")==0) cmap = INT_CMAP;
1511             else {
1512                if(strcmp(argv[iarg],"SPARSE_CMAP")==0) cmap = SPARSE_CMAP;
1513                else SynErr("cmap value not valid");
1514             }
1515          }
1516          new_stuff++ ; iarg++ ; continue ;  /* go to next arg */
1517       }
1518 
1519       /** anything else must be a -type **/
1520       /*  try the anatomy prefixes */
1521 
1522       for( ii=FIRST_ANAT_TYPE ; ii <= LAST_ANAT_TYPE ; ii++ )
1523          if( strncmp( &(argv[iarg][1]) ,
1524                       ANAT_prefixstr[ii] , THD_MAX_PREFIX ) == 0 ) break ;
1525 
1526       /* fprintf(stderr,"== have type %d\n", ii); */
1527 
1528       if( ii <= LAST_ANAT_TYPE ){
1529          ftype = ii ;
1530          dtype = HEAD_ANAT_TYPE ;
1531          nvals = ANAT_nvals[ftype] ;
1532          new_type = 1 ; new_stuff++ ;
1533          iarg++ ; continue ;
1534       }
1535 
1536       /* try the function prefixes */
1537 
1538       for( ii=FIRST_FUNC_TYPE ; ii <= LAST_FUNC_TYPE ; ii++ )
1539          if( strncmp( &(argv[iarg][1]) ,
1540                       FUNC_prefixstr[ii] , THD_MAX_PREFIX ) == 0 ) break ;
1541 
1542       if( ii <= LAST_FUNC_TYPE ){
1543          ftype = ii ;
1544          dtype = HEAD_FUNC_TYPE ;
1545          nvals = FUNC_nvals[ftype] ;
1546          new_type = 1 ; new_stuff++ ;
1547          iarg++ ; continue ;
1548       }
1549 
1550       /** error **/
1551 
1552       { char str[256] ;
1553         sprintf(str,"Unknown option %s. Check 3drefit -help.",argv[iarg]) ;
1554         ERROR_message(str);
1555         suggest_best_prog_option(argv[0], argv[iarg]);
1556         exit(1);
1557       }
1558 
1559    }  /* end of loop over switches */
1560    if (iarg < 2) Syntax(1) ;
1561 
1562    /*-- some checks for erroneous inputs --*/
1563 
1564    if( new_stuff == 0 && atrmod == 0 ) SynErr("No options given!?") ;
1565    if( new_stuff == 1 && atrmod == 1 ){       /* 28 Jul 2006 [rickr] */
1566       fprintf(stderr,"** Cannot use -atrcopy or -atrstring with other "
1567                      "modification options.\n");
1568       SynErr("Illegal attribute syntax.");
1569    }
1570    if( iarg >= argc   ) SynErr("No datasets given!?") ;
1571 
1572    if( xyzscale != 0.0f &&
1573        (new_orient || new_xorg || new_yorg || new_zorg ||
1574         keepcen    || new_xdel || new_ydel || new_zdel   ) ){  /* 18 Jul 2006 */
1575     SynErr(
1576     "-xyzscale is incompatible with other options for changing voxel grid");
1577    }
1578 
1579    if( obl_recenter &&  /* 17 Mar 2020 [rickr] */
1580        (new_orient || new_xorg || new_yorg || new_zorg ||
1581         keepcen    || new_xdel || new_ydel || new_zdel   ) ){
1582     SynErr(
1583     "-oblique_recenter is not compatible with other voxel grid modifications");
1584    }
1585 
1586    if( new_orient && (dxorg || dyorg || dzorg) )     /* 02 Mar 2000 */
1587       SynErr("Can't use -orient with -d?origin!?") ;
1588 
1589    if( new_tags || shift_tags ){                     /* 08 May 2006 [rickr] */
1590       if( new_tags && shift_tags )
1591          SynErr("Cant' use -shift_tags with -d{xyz}tag") ;
1592       if( new_orient )
1593          SynErr("Can't use -orient with -shift_tags or -d{xyz}tags") ;
1594       if( shift_tags && !dxorg && !dyorg && !dzorg )
1595          SynErr("-shift_tags option requires a -d{xyz}origin option") ;
1596 
1597       if( shift_tags ){    /* then copy shifts to tag vars */
1598          if( dxorg ) dxtag = xorg ;
1599          if( dyorg ) dytag = yorg ;
1600          if( dzorg ) dztag = zorg ;
1601       }
1602    }
1603 
1604    /*--- process datasets ---*/
1605    for( ; iarg < argc ; iarg++ ){
1606       write_output = False ;   /* some datasets will be overwritten */
1607       did_something = 0 ;
1608 
1609       dset = THD_open_one_dataset( argv[iarg] ) ;
1610       if( dset == NULL ){
1611         ERROR_message("Can't open dataset %s\n",argv[iarg]) ;
1612         continue ;
1613       }
1614       if( DSET_IS_MINC(dset) ){
1615         ERROR_message("Can't process MINC dataset %s\n",argv[iarg]);
1616         continue ;
1617       }
1618       if( DSET_IS_ANALYZE(dset) ){
1619         ERROR_message("Can't process ANALYZE dataset %s\n",argv[iarg]);
1620         continue ;
1621       }
1622       if( DSET_IS_1D(dset) ){
1623         ERROR_message("Can't process 1D dataset %s\n",argv[iarg]);
1624         continue ;
1625       }
1626       if( DSET_IS_CTFMRI(dset) || DSET_IS_CTFSAM(dset) ){
1627         ERROR_message("Can't process CTF dataset %s\n",argv[iarg]);
1628         continue ;
1629       }
1630       if( DSET_IS_MPEG(dset) ){
1631         ERROR_message("Can't process MPEG dataset %s\n",argv[iarg]);
1632         continue ;
1633       }
1634 
1635       /* any surviving non-AFNI dataset needs the data written out */
1636       if( IS_VALID_NON_AFNI_DSET(dset) ){
1637         write_output = True ;     /* 13 Jul 2006 [rickr] */
1638       }
1639 
1640       INFO_message("Processing AFNI dataset %s\n",argv[iarg]) ;
1641 
1642       /*-- First off: check the axes for consistency --*/
1643 
1644       if( do_checkaxes ){
1645         THD_dataxes *copy_dax , *orig_dax ; float dif ;
1646         orig_dax = dset->daxes ;
1647         copy_dax = (THD_dataxes *)malloc(sizeof(THD_dataxes)) ;
1648         memcpy( copy_dax , orig_dax , sizeof(THD_dataxes) ) ;
1649         LOAD_ZERO_MAT( copy_dax->to_dicomm ) ;
1650         THD_daxes_to_mat44( copy_dax ) ;
1651 
1652         dif = MAT44_FLDIF( orig_dax->ijk_to_dicom , copy_dax->ijk_to_dicom ) ;
1653         if( dif > 0.001f ){
1654           WARNING_message("===== ijk_to_dicom from dataset header and from axes differ") ;
1655           DUMP_MAT44("ijk_to_dicom from dataset header",orig_dax->ijk_to_dicom) ;
1656           DUMP_MAT44("ijk_to_dicom from dataset axes"  ,copy_dax->ijk_to_dicom) ;
1657         } else {
1658           INFO_message   ("===== ijk_to_dicom from dataset header and from axes are equivalent") ;
1659           DUMP_MAT44("ijk_to_dicom from dataset header",orig_dax->ijk_to_dicom) ;
1660         }
1661 
1662         dif = MAT44_FLDIF( orig_dax->dicom_to_ijk , copy_dax->dicom_to_ijk ) ;
1663         if( dif > 0.001f ){
1664           WARNING_message("===== dicom_to_ijk from dataset header and from axes differ") ;
1665           DUMP_MAT44("dicom_to_ijk from dataset header",orig_dax->dicom_to_ijk) ;
1666           DUMP_MAT44("dicom_to_ijk from dataset axes"  ,copy_dax->dicom_to_ijk) ;
1667         } else {
1668           INFO_message   ("===== dicom_to_ijk from dataset header and from axes are equivalent") ;
1669           DUMP_MAT44("dicom_to_ijk from dataset header",orig_dax->dicom_to_ijk) ;
1670         }
1671 
1672         dif = MAT44_FLDIF( orig_dax->ijk_to_dicom , orig_dax->ijk_to_dicom_real ) ;
1673         if( dif > 0.001f ){
1674           WARNING_message("===== ijk_to_dicom and ijk_to_dicom_real from dataset header differ") ;
1675           DUMP_MAT44("ijk_to_dicom      from dataset header",orig_dax->ijk_to_dicom) ;
1676           DUMP_MAT44("ijk_to_dicom_real from dataset header",orig_dax->ijk_to_dicom_real) ;
1677         } else {
1678           DUMP_MAT44("ijk_to_dicom      from dataset header",orig_dax->ijk_to_dicom) ;
1679           INFO_message   ("===== ijk_to_dicom and ijk_to_dicom_real from dataset header are equivalent") ;
1680         }
1681 
1682         if( new_stuff == 1 ){ DSET_delete(dset) ; continue ; }  /* nothing else to do */
1683       }
1684 
1685       tross_Make_History( "3drefit" , argc,argv, dset ) ;
1686 
1687       /* 21 Dec 2004: -label2 option */
1688 
1689       if( new_label2 != NULL ){
1690         EDIT_dset_items( dset , ADN_label2 , new_label2 , ADN_none ) ;
1691         VINFO("setting label2") ;
1692         did_something++ ; /* 30 Mar 2010 */
1693       }
1694 
1695       if(labeltable != NULL) {
1696          char *str = NULL;
1697          Dtable *vl_dtable=NULL ;
1698 
1699          if (dset->Label_Dtable) {
1700             destroy_Dtable(dset->Label_Dtable); dset->Label_Dtable=NULL;
1701          }
1702          /* read the table */
1703          if (!(str = AFNI_suck_file( labeltable))) {
1704             ERROR_exit("Failed to read %s", labeltable);
1705          }
1706          if (!(vl_dtable = Dtable_from_nimlstring(str))) {
1707             ERROR_exit("Could not parse labeltable");
1708          }
1709          destroy_Dtable(vl_dtable); vl_dtable = NULL;
1710          THD_set_string_atr( dset->dblk , "VALUE_LABEL_DTABLE" , str ) ;
1711          VINFO("setting labeltable") ;
1712          free(str);
1713         did_something++ ; /* 30 Mar 2010 */
1714       }
1715 
1716       /* 14 Oct 1999: change anat parent */
1717       /* 14 Dec 1999: allow special cases: SELF and NULL */
1718 
1719       if( aset != NULL ){
1720          EDIT_dset_items( dset , ADN_anat_parent , aset , ADN_none ) ;
1721          VINFO("setting Anat parent") ;
1722         did_something++ ; /* 30 Mar 2010 */
1723       } else if( aset_code == ASET_SELF ){
1724          EDIT_dset_items( dset , ADN_anat_parent , dset , ADN_none ) ;
1725          VINFO("setting Anat parent") ;
1726         did_something++ ; /* 30 Mar 2010 */
1727       } else if( aset_code == ASET_NULL ){
1728          EDIT_ZERO_ANATOMY_PARENT_ID( dset ) ;
1729          dset->anat_parent_name[0] = '\0' ;
1730          VINFO("clearing Anat parent") ;
1731         did_something++ ; /* 30 Mar 2010 */
1732       }
1733 
1734       /* ZSS June 06, add a warp parent field please */
1735       if( waset != NULL ){
1736          EDIT_dset_items( dset , ADN_warp_parent , waset , ADN_none ) ;
1737          VINFO("setting Warp parent") ;
1738         did_something++ ; /* 30 Mar 2010 */
1739       } else if( waset_code == ASET_SELF ){
1740          EDIT_dset_items( dset , ADN_warp_parent , dset , ADN_none ) ;
1741          VINFO("setting Warp parent") ;
1742         did_something++ ; /* 30 Mar 2010 */
1743       } else if( waset_code == ASET_NULL ){
1744          EDIT_ZERO_ANATOMY_PARENT_ID( dset ) ;
1745          dset->warp_parent_name[0] = '\0' ;
1746          VINFO("clearing Warp parent") ;
1747         did_something++ ; /* 30 Mar 2010 */
1748       }
1749       /* Oct 04/02: zmodify volreg fields */
1750       if (Do_volreg_mat) {
1751          sprintf(str,"VOLREG_MATVEC_%06d", volreg_matind) ;
1752          if( verb ) ININFO_message("Modifying %s ...\n", str);
1753          THD_set_float_atr( dset->dblk , str , 12 , volreg_mat ) ;
1754         did_something++ ; /* 30 Mar 2010 */
1755       }
1756 
1757       if (Do_center_old) {
1758          VINFO("Modifying VOLREG_CENTER_OLD ...\n");
1759          THD_set_float_atr( dset->dblk , "VOLREG_CENTER_OLD" , 3 , center_old ) ;
1760         did_something++ ; /* 30 Mar 2010 */
1761       }
1762 
1763       if (Do_center_base) {
1764         VINFO("Modifying VOLREG_CENTER_BASE ...\n");
1765         THD_set_float_atr( dset->dblk , "VOLREG_CENTER_BASE" , 3 , center_base ) ;
1766         did_something++ ; /* 30 Mar 2010 */
1767       }
1768 
1769       /* 28 May 2002: clear brick stats */
1770 
1771       if( clear_bstat ){
1772         if( !ISVALID_STATISTIC(dset->stats) ){
1773           WARNING_message("-clear_bstat: dataset has no brick statistics\n") ;
1774         } else {
1775           KILL_STATISTIC(dset->stats) ;
1776           REMOVEFROM_KILL( dset->kl , dset->stats ) ;
1777           REMOVEFROM_KILL( dset->kl , dset->stats->bstat ) ;
1778           dset->stats = NULL ;
1779           VINFO("clearing brick statistics") ;
1780         did_something++ ; /* 30 Mar 2010 */
1781         }
1782       }
1783 
1784       if( redo_bstat ){
1785         VINFO("reloading brick statistics") ;
1786         THD_load_statistics( dset ) ;   /* 01 Feb 2005 */
1787         did_something++ ; /* 30 Mar 2010 */
1788       }
1789 
1790       if( new_byte_order > 0 ){
1791          VINFO("changing byte order") ;
1792          dset->dblk->diskptr->byte_order = new_byte_order ; /* 25 April 1998 */
1793         did_something++ ; /* 30 Mar 2010 */
1794       }
1795 
1796       /*-- change space axes (lots of possibilities here) --*/
1797 
1798       daxes = dset->daxes ;
1799 
1800       if( new_orient ){
1801          VINFO("changing orientation codes") ;
1802          daxes->xxorient = xxor ;
1803          daxes->yyorient = yyor ;
1804          daxes->zzorient = zzor ;
1805         did_something++ ; /* 30 Mar 2010 */
1806       }
1807 
1808       if( xyzscale > 0.0f ){  /* 18 Jul 2006 */
1809         float dxp = daxes->xxdel * xyzscale ;  /* new grid */
1810         float dyp = daxes->yydel * xyzscale ;  /* spacings */
1811         float dzp = daxes->zzdel * xyzscale ;
1812         int   rl  = abs(THD_get_axis_direction(daxes,ORI_R2L_TYPE)) ;
1813         int   ap  = abs(THD_get_axis_direction(daxes,ORI_A2P_TYPE)) ;
1814         int   is  = abs(THD_get_axis_direction(daxes,ORI_I2S_TYPE)) ;
1815         float xop , yop , zop ;
1816         static float shift[3] ;
1817 
1818         VINFO("applying -xyzscale") ;
1819 
1820         if( rl == 0 || ap == 0 || is == 0 )
1821           ERROR_exit("-xyzscale: Indeterminate axis directions!") ;
1822 
1823         if( ndone == 0 ){  /* for the first dataset */
1824           float op[3] , oo[3] ;
1825           op[0] = xop = daxes->xxorg + (daxes->xxdel-dxp)*0.5f*(daxes->nxx-1) ;
1826           op[1] = yop = daxes->yyorg + (daxes->yydel-dyp)*0.5f*(daxes->nyy-1) ;
1827           op[2] = zop = daxes->zzorg + (daxes->zzdel-dzp)*0.5f*(daxes->nzz-1) ;
1828           oo[0] = daxes->xxorg ;
1829           oo[1] = daxes->yyorg ;
1830           oo[2] = daxes->zzorg ;
1831           shift[0] = op[rl-1] - xyzscale * oo[rl-1] ;   /* RL shift */
1832           shift[1] = op[ap-1] - xyzscale * oo[ap-1] ;   /* AP shift */
1833           shift[2] = op[is-1] - xyzscale * oo[is-1] ;   /* IS shift */
1834 
1835         } else {           /* for later datasets */
1836 
1837           xop = xyzscale * daxes->xxorg + shift[daxes->xxorient/2] ;
1838           yop = xyzscale * daxes->yyorg + shift[daxes->yyorient/2] ;
1839           zop = xyzscale * daxes->zzorg + shift[daxes->zzorient/2] ;
1840         }
1841 
1842         daxes->xxdel = dxp ; daxes->yydel = dyp ; daxes->zzdel = dzp ;
1843         daxes->xxorg = xop ; daxes->yyorg = yop ; daxes->zzorg = zop ;
1844         did_something++ ; /* 30 Mar 2010 */
1845       }
1846 
1847       if( !new_xorg ) xorg = fabs(daxes->xxorg) ;
1848       if( !new_yorg ) yorg = fabs(daxes->yyorg) ;
1849       if( !new_zorg ) zorg = fabs(daxes->zzorg) ;
1850 
1851       if( !new_xdel ) xdel = fabs(daxes->xxdel) ;
1852       if( !new_ydel ) ydel = fabs(daxes->yydel) ;
1853       if( !new_zdel ) zdel = fabs(daxes->zzdel) ;
1854 
1855       /* 17 Jul 2006 - deal with the '-keepcen' option */
1856 
1857       if( keepcen && !new_xdel && !new_ydel && !new_zdel ){
1858         WARNING_message("-keepcen needs at least one of -xdel, -ydel, -zdel") ;
1859         keepcen = 0 ;
1860       }
1861       if( keepcen && (new_xorg || new_yorg || new_zorg || new_orient) ){
1862         WARNING_message(
1863          "-keepcen incompatible with explicit origin or orientation changes") ;
1864         keepcen = 0 ;
1865       }
1866       if( keepcen ){
1867         VINFO("applying -keepcen") ;
1868         if( new_xdel ){
1869           dxorg = 1 ; xorg = 0.5f*(daxes->nxx-1)*(fabs(daxes->xxdel)-xdel) ;
1870           if( ORIENT_sign[daxes->xxorient] == '-' ) xorg = -xorg ;
1871         }
1872         if( new_ydel ){
1873           dyorg = 1 ; yorg = 0.5f*(daxes->nyy-1)*(fabs(daxes->yydel)-ydel) ;
1874           if( ORIENT_sign[daxes->yyorient] == '-' ) yorg = -yorg ;
1875         }
1876         if( new_zdel ){
1877           dzorg = 1 ; zorg = 0.5f*(daxes->nzz-1)*(fabs(daxes->zzdel)-zdel) ;
1878           if( ORIENT_sign[daxes->zzorient] == '-' ) zorg = -zorg ;
1879         }
1880       }
1881 
1882       if( cxorg ) xorg = 0.5 * (daxes->nxx - 1) * xdel ;
1883       if( cyorg ) yorg = 0.5 * (daxes->nyy - 1) * ydel ;
1884       if( czorg ) zorg = 0.5 * (daxes->nzz - 1) * zdel ;
1885 
1886       if( dxorg )
1887       {  daxes->xxorg += xorg ; did_something++ ; }
1888       else if( duporg || new_xorg==2 )
1889       {  daxes->xxorg = xorg ; did_something++ ; }
1890       else if( new_xorg==1 || new_orient )
1891       {  daxes->xxorg = (ORIENT_sign[daxes->xxorient] == '+') ? (-xorg) : (xorg) ; did_something++ ; }
1892 
1893       if( dyorg )
1894       {  daxes->yyorg += yorg ; did_something++ ; }
1895       else if( duporg || new_yorg==2 )
1896       {  daxes->yyorg = yorg ; did_something++ ; }
1897       else if( new_yorg==1 || new_orient )
1898       {  daxes->yyorg = (ORIENT_sign[daxes->yyorient] == '+') ? (-yorg) : (yorg) ; did_something++ ; }
1899 
1900       if( dzorg )
1901       {  daxes->zzorg += zorg ; did_something++ ; }
1902       else if( duporg || new_zorg==2 )
1903       {  daxes->zzorg = zorg ; did_something++ ; }
1904       else if( new_zorg==1 || new_orient )
1905       {  daxes->zzorg = (ORIENT_sign[daxes->zzorient] == '+') ? (-zorg) : (zorg) ; did_something++ ; }
1906 
1907       if( new_xdel || new_orient )
1908       {  daxes->xxdel = (ORIENT_sign[daxes->xxorient] == '+') ? (xdel) : (-xdel) ; did_something++ ; }
1909 
1910       if( new_ydel || new_orient )
1911       {  daxes->yydel = (ORIENT_sign[daxes->yyorient] == '+') ? (ydel) : (-ydel) ; did_something++ ; }
1912 
1913       if( new_zdel || new_orient )
1914       {  daxes->zzdel = (ORIENT_sign[daxes->zzorient] == '+') ? (zdel) : (-zdel) ; did_something++ ; }
1915 
1916       /* shift ijk_to_dicom xyz=0,0,0 to match ijk_to_dicom_real=0,0,0, and */
1917       /* round to voxel center if not _raw version      [23 Mar 2020 rickr] */
1918       if( obl_recenter ) {
1919          THD_fvec3 coords={{0.0, 0.0, 0.0}};          /* dicom 0,0,0 */
1920 
1921          /* map 0,0,0 from scanner to cardinalized coords */
1922          if( THD_dicom_real_to_card(dset, & coords, obl_recenter==2) )
1923             ERROR_exit("-oblique_recenter failure");
1924 
1925          /* convert from dicom to to dataset coords (permute) */
1926          coords = THD_dicomm_to_3dmm(dset, coords);
1927 
1928          /* and subtract to re-center */
1929          daxes->xxorg -= coords.xyz[0];
1930          daxes->yyorg -= coords.xyz[1];
1931          daxes->zzorg -= coords.xyz[2];
1932 
1933          INFO_message("shifting origin by %g %g %g",
1934                       -coords.xyz[0], -coords.xyz[1], -coords.xyz[2]);
1935 
1936          did_something++;
1937       }
1938 
1939       /*-- deoblique - assume the data is cardinal  6/20/2007 */
1940       /* this should be after any other axis,
1941          orientation, origin, voxel size changes */
1942       if(deoblique || geom_change) {   /* geom_change  04 Nov 2011 mod drg */
1943          /* replace transformation matrix with cardinal form */
1944          /* lose obliquity if using 3dWarp for any transformation */
1945          /* recompute Tc (Cardinal transformation matrix for new grid output */
1946          THD_make_cardinal(dset);
1947          VINFO("deoblique") ;
1948          did_something++ ; /* 30 Mar 2010 */
1949       }
1950 
1951 
1952       /* if user has selected, get origin from obliquity */
1953       /*   overriding all the previous command-line options */
1954       if(use_oblique_origin){
1955          Obliquity_to_coords(dset);
1956          VINFO("oblique origin") ;
1957         did_something++ ; /* 30 Mar 2010 */
1958       }
1959 
1960       /* set the space of the dataset */
1961       if(space) {
1962          int old_vtype = dset->view_type ;
1963          /* check if trying to assign a non-orig space to orig view data */
1964          if( strcmp("orig",VIEW_codestr[old_vtype]) == 0 ) {
1965             if(strncmp(spacename, "ORIG", 4)!=0){
1966                WARNING_message("Changing the space of an ORIG view dataset may cause confusion!");
1967                WARNING_message(" NIFTI copies will be interpreted as TLRC view (not TLRC space).");
1968                WARNING_message(" Consider changing the view of the dataset to TLRC view also");
1969             }
1970          }
1971          /* check if trying to assign orig space to tlrc view data */
1972          else if( strcmp("tlrc",VIEW_codestr[old_vtype]) == 0 ) {
1973             if(strncmp(spacename, "ORIG", 4)==0){
1974                WARNING_message("Changing the space of a TLRC view dataset to an ORIG type may cause confusion!");
1975                WARNING_message(" NIFTI copies will be interpreted as ORIG view.");
1976                WARNING_message(" Consider changing the view of the dataset to ORIG view also");
1977             }
1978          }
1979          /* actually update the space */
1980          MCW_strncpy(dset->atlas_space, spacename, THD_MAX_NAME);
1981          did_something++;
1982       }
1983 
1984       /* set the colormap type of the dataset */
1985       if(cmap>=0)
1986       {
1987             dset->int_cmap = cmap;
1988             did_something++;
1989       }
1990 
1991       /*-- change time axis --*/
1992 
1993       if( new_TR ){
1994          if( dset->taxis == NULL ){
1995             if( DSET_NVALS(dset) < 2 ){
1996               WARNING_message("Can't process -TR for this dataset!") ;
1997             } else {
1998               WARNING_message("Adding time axis to this dataset") ;
1999               EDIT_dset_items( dset ,
2000                                  ADN_ntt   , DSET_NVALS(dset) ,
2001                                  ADN_ttdel , TR ,
2002                                  ADN_tunits, UNITS_SEC_TYPE ,
2003                                  ADN_nsl   , 0 ,
2004                                ADN_none ) ;
2005               did_something++ ; /* 30 Mar 2010 */
2006             }
2007          } else {
2008             float frac = TR / dset->taxis->ttdel ;
2009             int ii ;
2010 
2011             VINFO("changing TR") ;
2012             dset->taxis->ttdel = TR ;
2013             if( new_tunits ) dset->taxis->units_type = tunits ;
2014             if( dset->taxis->nsl > 0 ){
2015                for( ii=0 ; ii < dset->taxis->nsl ; ii++ )
2016                   dset->taxis->toff_sl[ii] *= frac ;
2017             }
2018             did_something++ ; /* 30 Mar 2010 */
2019          }
2020       }
2021 
2022       if( new_Torg ){                   /* 29 Jan 2003 */
2023         if( dset->taxis == NULL ){
2024           WARNING_message("Can't process -Torg for this dataset!\n") ;
2025         } else {
2026           VINFO("changing Torg") ;
2027           dset->taxis->ttorg = Torg ;
2028           did_something++ ; /* 30 Mar 2010 */
2029         }
2030       }
2031 
2032       if( new_toff_sl ){              /* 12 Feb 2001 */
2033          if( dset->taxis == NULL ){
2034             WARNING_message("-notoff: dataset has no time axis to clear!\n") ;
2035          } else if( dset->taxis->nsl <= 0 ){
2036             WARNING_message("-notoff: dataset has no time-offsets to clear!\n") ;
2037          } else {
2038             VINFO("clearing slice time offsets") ;
2039             EDIT_dset_items( dset , ADN_nsl,0 , ADN_none ) ;
2040             did_something++ ; /* 30 Mar 2010 */
2041          }
2042       }
2043 
2044       if( new_Tslices > 0 ){          /* 18 Dec 2018 */
2045          if( dset->taxis == NULL ){
2046            WARNING_message("-Tslices: dataset has no time axis to add slice offset to!") ;
2047          } else {
2048            int qq ; float dt=DSET_TR(dset) ;
2049            if( dset->taxis->nsl > 0 )
2050              WARNING_message("-Tslices: altering existing slice offsets!") ;
2051            else
2052              VINFO("setting slice time offsets") ;
2053            EDIT_dset_items( dset ,
2054                               ADN_nsl     , new_Tslices ,
2055                               ADN_toff_sl , Tslices     ,
2056                             ADN_none ) ;
2057            if( new_Tslices != dset->daxes->nzz )
2058              WARNING_message("-Tslices count %d is different than number of slices %d",
2059                              new_Tslices , dset->daxes->nzz ) ;
2060            for( qq=0 ; qq < new_Tslices ; qq++ ){
2061              if( Tslices[qq] >= dt )
2062                WARNING_message("-Tslices value %g (#%d) is %s TR=%g",
2063                                Tslices[qq] , qq+1 ,
2064                                (Tslices[qq] == dt) ? "equal to" : "greater than" ,
2065                                dt ) ;
2066            }
2067            did_something++ ;
2068          }
2069       }
2070 
2071       if( (new_orient || new_zorg) && dset->taxis != NULL && dset->taxis->nsl > 0 ){
2072          VINFO("changing time axis slice offset z-origin") ;
2073          dset->taxis->zorg_sl = daxes->zzorg ;
2074          did_something++ ; /* 30 Mar 2010 */
2075       }
2076 
2077       if( (new_orient || new_zdel) && dset->taxis != NULL && dset->taxis->nsl > 0 ){
2078          VINFO("changing time axis slice offset z-spacing") ;
2079          dset->taxis->dz_sl = daxes->zzdel ;
2080          did_something++ ; /* 30 Mar 2010 */
2081       }
2082 
2083       if( new_idcode ){
2084         VINFO("changing ID code") ;
2085         dset->idcode = MCW_new_idcode() ;
2086         did_something++ ; /* 30 Mar 2010 */
2087       }
2088 
2089       if( new_nowarp ){
2090          VINFO("clearing warp") ;
2091          ZERO_IDCODE( dset->warp_parent_idcode ) ;
2092          dset->warp_parent_name[0] = '\0' ;
2093          dset->warp = NULL ;
2094          did_something++ ; /* 30 Mar 2010 */
2095       }
2096 
2097       if( new_type ){
2098 #if 0
2099 /* removed these tests where nvals is used as number of values per sub-brick
2100    instead of number of sub-bricks. Apparently from another era, these are
2101    limited to a value of 1 or 2 in 3ddata.h for each data type */
2102 /*          if( nvals > 1 && dset->taxis != NULL ){
2103             ERROR_message("Can't change 3D+time dataset to new type:\n"
2104                           " *    new type has more than one value per voxel!\n") ;
2105          } else if( dset->taxis == NULL && nvals != dset->dblk->nvals &&
2106                     ((dtype==HEAD_FUNC_TYPE && ftype!=FUNC_BUCK_TYPE)||
2107                      (dtype==HEAD_ANAT_TYPE && ftype!=ANAT_BUCK_TYPE)  ) ){
2108 
2109             ERROR_message("Can't change dataset to new type:\n"
2110                           " *     mismatch in number of sub-bricks!\n") ;
2111          } else {
2112  */
2113 #endif
2114             VINFO("changing dataset 'type' marker") ;
2115             dset->type      = dtype ;
2116             dset->func_type = ftype ;
2117 
2118             if( ISBUCKET(dset) && dset->taxis != NULL ){   /* 29 April 1998 */
2119               WARNING_message("changing 3D+time dataset to bucket [no time axis]\n") ;
2120               EDIT_dset_items( dset , ADN_ntt , 0 , ADN_none ) ;
2121             }
2122 
2123             did_something++ ; /* set either way   17 Nov 2011 [rickr, dglen] */
2124 /*         }*/
2125       }
2126 
2127       if( new_stataux ){
2128          for( ii=0 ; ii < MAX_STAT_AUX ; ii++ ){
2129             dset->stat_aux[ii] = stataux[ii] ;
2130          }
2131          did_something++ ; /* 30 Mar 2010 */
2132          VINFO("new stataux") ;
2133       }
2134 
2135       if( new_view && dset->view_type != vtype ){
2136          int  old_vtype = dset->view_type ;
2137          char old_head[THD_MAX_NAME] , old_brik[THD_MAX_NAME] ;
2138          char new_head[THD_MAX_NAME] , new_brik[THD_MAX_NAME] ;
2139          int brick_ccode = COMPRESS_filecode( DSET_BRIKNAME(dset) ) ;
2140 
2141          VINFO("changing dataset view code") ;
2142          strcpy(old_head,DSET_HEADNAME(dset)) ;
2143          strcpy(old_brik,DSET_BRIKNAME(dset)) ;
2144          dset->view_type = vtype ;
2145          THD_init_diskptr_names( dset->dblk->diskptr ,
2146                                  NULL , NULL , NULL , vtype , True ) ;
2147 
2148          #if 0 /* HEADNAME now has path, no need for catenation ZSS Fev 2012 */
2149          strcpy(new_head,DSET_DIRNAME(dset)) ;
2150          strcat(new_head,DSET_HEADNAME(dset)) ;
2151          strcpy(new_brik,DSET_DIRNAME(dset)) ;
2152          strcat(new_brik,DSET_BRIKNAME(dset)) ;
2153          #else
2154          strcpy(new_head,DSET_HEADNAME(dset)) ;
2155          strcpy(new_brik,DSET_BRIKNAME(dset)) ;
2156          #endif
2157 
2158          if( THD_is_file(new_head) ){
2159             dset->view_type = old_vtype ;
2160             THD_init_diskptr_names( dset->dblk->diskptr ,
2161                                     NULL , NULL , NULL , old_vtype , True ) ;
2162             /* if not changing the current file, fail
2163                (i.e. accept in case of NIfTI or similar in -space)
2164                (suggested by I Schwabacher)         24 Apr 2013 [rickr] */
2165             if( strcmp(old_head, new_head) )
2166              ERROR_exit("Can't change view: would overwrite existing files!\n");
2167          } else {
2168             /* check whether this succeeds    [16 Aug 2019 rickr/dglen] */
2169             if( rename( old_head , new_head ) )
2170                ERROR_exit("3drefit: failed to rename %s to %s\n",
2171                           old_head, new_head) ;
2172 
2173             { char * fff = COMPRESS_filename(old_brik) ;
2174               if( fff != NULL ){
2175                  char * ggg = malloc( sizeof(char) * (strlen(fff)+32) ) ;
2176                  strcpy(ggg,new_brik) ;
2177                  if( brick_ccode >= 0 )
2178                     strcat(ggg,COMPRESS_suffix[brick_ccode]) ;
2179                  if( rename( fff , ggg ) )
2180                     ERROR_exit("3drefit: failed to rename %s to %s\n",fff,ggg);
2181 
2182                  free(fff) ; free(ggg) ;
2183               }
2184             }
2185             ININFO_message("Changed dataset view type and filenames.\n") ;
2186             did_something++ ; /* 30 Mar 2010 */
2187          }
2188       }
2189 
2190       /* check for tag shifts                  08 May 2006 [rickr] */
2191       if( new_tags || shift_tags ){
2192          THD_usertag * tag;
2193          if( !dset->tagset ) WARNING_message("No tags to shift\n") ;
2194          else {
2195             ININFO_message("modifying tags") ;
2196             for( ii = 0; ii < dset->tagset->num; ii++ ){
2197                tag = dset->tagset->tag + ii ;
2198                tag->x += dxtag;  tag->y += dytag;  tag->z += dztag;
2199             }
2200             did_something++ ; /* 30 Mar 2010 */
2201          }
2202       } else if ( dset->tagset && ( new_xorg || new_yorg || new_zorg ||
2203                                     new_xdel || new_ydel || new_zdel ) )
2204          WARNING_message("modifying coordinates of dataset with tags") ;
2205 
2206       /* code moved to edt_emptycopy.c                   13 Sep 2005 [rickr] */
2207       if( new_markers && okay_to_add_markers(dset) ){
2208          dset->markers = create_empty_marker_set() ;
2209          did_something++ ; /* 30 Mar 2010 */
2210          VINFO("empty marker set") ;
2211 
2212       } else if( new_markers ){
2213          WARNING_message("Can't add markers to this dataset\n") ;
2214       } /* end of markers */
2215 
2216       /*-- 08 Jun 2004: copyaux? --*/
2217 
2218       if( copyaux ){
2219         if( auxset != NULL ){
2220           THD_copy_datablock_auxdata( auxset->dblk , dset->dblk );
2221           INIT_STAT_AUX( dset , MAX_STAT_AUX , auxset->stat_aux ) ;
2222           did_something++ ; /* 30 Mar 2010 */
2223           VINFO("copy auxdata") ;
2224         } else {
2225           THD_copy_datablock_auxdata( NULL , dset->dblk );
2226           VINFO("null auxdata") ;
2227           did_something++ ; /* 30 Mar 2010 */
2228         }
2229       }
2230 
2231       /*-- 11 Jan 2012: copytables? --*/
2232 
2233       if( copytabs ){
2234         if( tabset != NULL ){
2235           if (!THD_copy_labeltable_atr( dset->dblk , tabset->dblk )) {
2236             WARNING_message("Failed to copy labletable attributes");
2237           }
2238           did_something++ ;
2239           VINFO("copy tabledata") ;
2240         }
2241       }
2242 
2243 
2244       /*-- relabel_all? [18 Apr 2011] --*/
2245 
2246       if( sar_relab != NULL ){
2247         for( ii=0 ; ii < sar_relab->num && ii < DSET_NVALS(dset) ; ii++ ){
2248           if( sar_relab->str[ii][0] != '\0' ){
2249             EDIT_BRICK_LABEL( dset , ii , sar_relab->str[ii] ) ;
2250             did_something++ ;
2251           }
2252         }
2253         VINFO("relabel_all") ;
2254       }
2255 
2256       /*-- new aux data? --*/
2257 
2258       if( nsublab > 0 ){
2259          for( ii=0 ; ii < nsublab ; ii++ ){
2260             iv = sublab[ii].iv ;
2261             if( iv < 0 || iv >= DSET_NVALS(dset) ){
2262                WARNING_message("Can't put label on sub-brick %d\n",iv) ;
2263             } else {
2264                EDIT_dset_items( dset ,
2265                                    ADN_brick_label_one + iv , sublab[ii].lab ,
2266                                 ADN_none ) ;
2267                did_something++ ; /* 30 Mar 2010 */
2268                VINFO("edit sub-brick label") ;
2269             }
2270          }
2271       }
2272 
2273       /* add suffix to labels? */
2274       if (subsuff) {
2275          char *olab=NULL, *sss=NULL;
2276          for( ii=0 ; ii < DSET_NVALS(dset) ; ii++ ){
2277             olab = DSET_BRICK_LABEL(dset,ii); if (!olab) { olab = ""; }
2278             sss = (char *)calloc(strlen(olab)+strlen(subsuff)+1, sizeof(char));
2279             sprintf(sss,"%s%s", olab, subsuff);
2280             EDIT_BRICK_LABEL( dset , ii , sss ) ;
2281             free(sss);
2282             did_something++ ;
2283          }
2284          VINFO("sublabel_suffix") ;
2285       }
2286 
2287       /* add prefix to labels? */
2288       if (subpref) {
2289          char *olab=NULL, *sss=NULL;
2290          for( ii=0 ; ii < DSET_NVALS(dset) ; ii++ ){
2291             olab = DSET_BRICK_LABEL(dset,ii); if (!olab) { olab = ""; }
2292             sss = (char *)calloc(strlen(olab)+strlen(subpref)+1, sizeof(char));
2293             sprintf(sss,"%s%s", subpref, olab);
2294             EDIT_BRICK_LABEL( dset , ii , sss ) ;
2295             free(sss);
2296             did_something++ ;
2297          }
2298          VINFO("sublabel_prefix") ;
2299       }
2300 
2301       if( nsubkeyword > 0 ){
2302          int code ;
2303          for( ii=0 ; ii < nsubkeyword ; ii++ ){
2304             iv = subkeyword[ii].iv ; code = subkeyword[ii].code ;
2305             if( iv < 0 || iv >= DSET_NVALS(dset) ){
2306                WARNING_message("Can't put keyword on sub-brick %d\n",iv) ;
2307             } else if( code == 1 ){
2308                EDIT_dset_items( dset ,
2309                                    ADN_brick_keywords_append_one + iv ,
2310                                    subkeyword[ii].keyword ,
2311                                 ADN_none ) ;
2312                did_something++ ; /* 30 Mar 2010 */
2313                VINFO("edit sub-brick keywords") ;
2314             } else if( code == 2 ){
2315                EDIT_dset_items( dset ,
2316                                    ADN_brick_keywords_replace_one + iv ,
2317                                    subkeyword[ii].keyword ,
2318                                 ADN_none ) ;
2319                did_something++ ; /* 30 Mar 2010 */
2320                VINFO("edit sub-brick keywords") ;
2321             } else if( code == 3 && dset->dblk->brick_keywords != NULL ){
2322                EDIT_dset_items( dset ,
2323                                    ADN_brick_keywords_replace_one + iv ,
2324                                    NULL ,
2325                                 ADN_none ) ;
2326                VINFO("nullify sub-brick keywords") ;
2327                did_something++ ; /* 30 Mar 2010 */
2328             }
2329          }
2330       }
2331 
2332       switch( new_key ){
2333         case 1: EDIT_dset_items(dset, ADN_keywords_append , key , ADN_none); did_something++; break;
2334         case 2: EDIT_dset_items(dset, ADN_keywords_replace, key , ADN_none); did_something++; break;
2335         case 3: EDIT_dset_items(dset, ADN_keywords_replace, NULL, ADN_none); did_something++; break;
2336       }
2337 
2338       if( do_killSTAT ){   /* 24 Jan 2008 */
2339         for( iv=0 ; iv < DSET_NVALS(dset) ; iv++ ){
2340           EDIT_BRICK_TO_NOSTAT(dset,iv) ;
2341         }
2342         VINFO("kill statistics") ;
2343         did_something++ ; /* 30 Mar 2010 */
2344       }
2345 
2346       if( nsubstatpar > 0 ){
2347         for( ii=0 ; ii < nsubstatpar ; ii++ ){
2348           iv = substatpar[ii].iv ;
2349           if( iv < 0 || iv >= DSET_NVALS(dset) ){
2350             WARNING_message("Can't put statpar on sub-brick %d",iv) ;
2351           } else {
2352             EDIT_dset_items( dset ,
2353                                ADN_brick_stataux_one + iv , substatpar[ii].par ,
2354                              ADN_none ) ;
2355             did_something++ ; /* 30 Mar 2010 */
2356             if( verb )
2357               INFO_message("changed statcode[%d] to %d",iv,(int)substatpar[ii].par[0]) ;
2358           }
2359         }
2360       }
2361 
2362       /* 03 Aug 2005: implement atrcopy */
2363       if( num_atrcopy > 0 )
2364       {
2365          ATR_any *atr;
2366          for( ii=0 ; ii < num_atrcopy ; ii++ ) {
2367            THD_insert_atr( dset->dblk , atrcopy[ii] ) ;
2368          }
2369          did_something++ ; /* 30 Mar 2010 */
2370          VINFO("atrcopy") ;
2371       }
2372       /* 23 Jan 2008: the FDR stuff */
2373 
2374       if( do_FDR ){
2375         DSET_BRICK_FDRCURVE_ALLKILL(dset) ;
2376         DSET_BRICK_MDFCURVE_ALLKILL(dset) ;  /* 22 Oct 2008 */
2377         if( do_FDR > 0 ){
2378           int nf ;
2379           mri_fdr_setmask( (nFDRmask == DSET_NVOX(dset)) ? FDRmask : NULL ) ;
2380           nf = THD_create_all_fdrcurves(dset) ;
2381           if( nf > 0 ){
2382             did_something += nf ; /* 30 Mar 2010 */
2383             ININFO_message("created %d FDR curve%s in dataset header",nf,(nf==1)?"\0":"s") ;
2384           } else {
2385             ININFO_message("failed to create FDR curves in dataset header") ;
2386           }
2387         }
2388       }
2389 
2390       /* Do we want to force new attributes into output ? ZSS Jun 06*/
2391       /* (only if -atrcopy or -atrstring)       28 Jul 2006 [rickr] */
2392       if ( saveatr && atrmod ){
2393          THD_set_dset_atr_status(0);
2394 /*         THD_updating_obliquity(1);*/ /* allow the possibility to update the obliquity -
2395                                             otherwise gets overwritten with cardinal matrix in
2396                                             THD_set_dataset_attributes() */
2397          /* apply attributes to header - dataxes and dblk*/
2398          INFO_message("applying attributes");
2399          THD_datablock_from_atr(dset->dblk , DSET_DIRNAME(dset) ,
2400                                   dset->dblk->diskptr->header_name);
2401          THD_datablock_apply_atr(dset );
2402       }
2403 
2404       if( denote ){ THD_anonymize_write(1); did_something++; VINFO("denote");}   /* 08 Jul 2005 */
2405 
2406       if( !did_something ){
2407         ININFO_message("Didn't make any changes for dataset %s !",argv[iarg]) ;
2408       } else {
2409         if( write_output ) {
2410             ININFO_message(
2411                "loading and re-writing dataset %s (%s in %s storage)\n",
2412                   argv[iarg], dset->dblk->diskptr->header_name,
2413                   storage_mode_str(dset->dblk->diskptr->storage_mode) ) ;
2414             DSET_load(dset) ;    /* 20 Jun 2006 */
2415         }
2416         THD_force_ok_overwrite(1);             /* 24 Sep 2007 */
2417         THD_set_quiet_overwrite(1);
2418         THD_write_3dim_dataset( THD_filepath(argv[iarg]),NULL ,
2419                                 dset , write_output ) ;
2420       }
2421       THD_delete_3dim_dataset( dset , False ) ;
2422 
2423       ndone++ ;   /* 18 Jul 2006: number of datasets done */
2424 
2425    } /* end of loop over datasets to be refitted */
2426 
2427    /*--- DONE ---*/
2428 
2429    INFO_message("3drefit processed %d datasets",ndone) ;
2430    exit(0) ;
2431 }
2432 
2433 /* read float values from string or file into float attribute */
2434 static ATR_float *
Update_float_atr(char * aname,char * fvstring)2435 Update_float_atr(char *aname, char *fvstring)
2436 {
2437    ATR_float *atr ;
2438    MRI_IMAGE *mri_matrix = NULL;
2439    float *fptr;
2440    int nx, ny, nxy,ii, acount;
2441 
2442    ENTRY("Update_float_atr");
2443    if( !THD_filename_pure(aname) ){
2444      WARNING_message("Illegal atrfloat name %s",aname) ;
2445      RETURN(NULL) ;
2446    }
2447 
2448    atr = (ATR_float *)RwcMalloc(sizeof(ATR_float)) ;
2449    atr->type = ATR_FLOAT_TYPE ;
2450    atr->name = RwcNewString( aname ) ;
2451 
2452    /* parse floats from string to attribute */
2453    /* try reading as float file or 1D: expression */
2454    mri_matrix = mri_read_1D(fvstring);  /* string could be file name or commandline string */
2455    if (mri_matrix == NULL)   {
2456       mri_matrix = mri_1D_fromstring(fvstring);
2457    }
2458 
2459    if (mri_matrix == NULL)   {
2460       printf("Error reading floating point attribute file");
2461       RETURN(NULL);
2462    }
2463 
2464    /* number of floats in attribute */
2465    nx = mri_matrix->nx; ny = mri_matrix->ny; acount = nx*ny;
2466    atr->nfl  = acount ;
2467    atr->fl   = (float *) RwcMalloc( sizeof(float) * acount ) ;
2468    fptr = MRI_FLOAT_PTR (mri_matrix);
2469    for( ii=0 ; ii < acount ; ii++ ){
2470       atr->fl[ii] = *fptr++;
2471    }
2472    RETURN(atr);
2473 }
2474 
2475 /* read integer values from string or file into int attribute */
2476 static ATR_int *
Update_int_atr(char * aname,char * ivstring)2477 Update_int_atr(char *aname, char *ivstring)
2478 {
2479    ATR_int *atr ;
2480    MRI_IMAGE *mri_matrix = NULL;
2481    float *fptr;
2482    int nx, ny, nxy,ii, acount;
2483 
2484    ENTRY("Update_int_atr");
2485    if( !THD_filename_pure(aname) ){
2486      WARNING_message("Illegal atrint name %s",aname) ;
2487      RETURN(NULL) ;
2488    }
2489 
2490    atr = (ATR_int *)RwcMalloc(sizeof(ATR_int)) ;
2491    atr->type = ATR_INT_TYPE ;
2492    atr->name = RwcNewString( aname ) ;
2493 
2494    /* parse floats from string to attribute */
2495    /* try reading as float file or 1D: expression */
2496    mri_matrix = mri_read_1D(ivstring);  /* string could be file name or commandline string */
2497    if (mri_matrix == NULL)   {
2498       mri_matrix = mri_1D_fromstring(ivstring);
2499    }
2500 
2501    if (mri_matrix == NULL)   {
2502       WARNING_message("Error reading integer attribute file");
2503       RETURN(NULL);
2504    }
2505 
2506    /* number of floats in attribute */
2507    nx = mri_matrix->nx; ny = mri_matrix->ny; acount = nx*ny;
2508    atr->nin  = acount ;
2509    atr->in   = (int *) RwcMalloc( sizeof(int) * acount ) ;
2510    fptr = MRI_FLOAT_PTR (mri_matrix);
2511    for( ii=0 ; ii < acount ; ii++ ){
2512       atr->in[ii] = *fptr++;
2513    }
2514 
2515    RETURN(atr);
2516 }
2517