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 int print_classic_label2index(THD_3dim_dataset * dset, char * labelname);
10 int print_classic_info       (THD_3dim_dataset * dset, char * dname, int verb);
11 int validate_field_struct(int verb);
12 
Syntax(TFORM targ,int detail)13 int Syntax(TFORM targ, int detail)
14 {
15    sphinx_printf(targ,"\n"
16 "Prints out sort-of-useful information from a 3D dataset's header\n"
17 "Usage: 3dinfo [-verb OR -short] dataset [dataset ...] ~1~\n"
18 "  -verb means to print out lots of stuff\n"
19 "  -VERB means even more stuff [including slice time offsets]\n"
20 "  -short means to print out less stuff [now the default]\n"
21 "%s"
22 "\n"
23 ":SPX:"
24 "\n.. note::\n\n   This could be anything. Just for the demo.\n\n"
25 ":SPX:"
26 "----------------------------------------------------------------------\n"
27 "Alternative Usage 1 (without either of the above options): ~1~\n"
28 "   Output a large block of text per dataset.  This has multiple options:\n"
29 "\n"
30 "   -label2index label dataset  : output index corresponding to label ~2~\n"
31 "\n"
32 "        example: 3dinfo -label2index aud#0_Coef stats.FT+tlrc\n"
33 "\n"
34 "        Prints to stdout the index corresponding to the sub-brick with\n"
35 "           the name label, or a blank line if label not found.\n"
36 "        The ONLY output is this sub-brick index.\n"
37 "        This is intended for used in a script, as in this tcsh fragment:LIT:\n"
38 "           set face = `3dinfo -label2index Face#0 AA_Decon+orig`\n"
39 "           set hous = `3dinfo -label2index House#0 AA_Decon+orig`\n"
40 "           3dcalc -a AA_Decon+orig\"[$face]\" -b AA_Decon+orig\"[$hous]\" ...:LR:\n"
41 "      * Added per the request and efforts of Colm Connolly.\n"
42 "\n"
43 "   -niml_hdr dataset           : output entire NIML-formatted header ~2~\n"
44 "\n"
45 "        example: 3dinfo -niml_hdr stats.FT+tlrc\n"
46 "\n"
47 "        Prints to stdout the NIML-formatted equivalent of the .HEAD file.\n"
48 "\n"
49 "   -subbrick_info dataset      : output only sub-brick part of info ~2~\n"
50 "\n"
51 "        example: 3dinfo -subbrick_info stats.FT+tlrc\n"
52 "\n"
53 "        Prints to stdout only the part of the full '3dinfo -VERB. output\n"
54 "        that includes sub-brick info.  The first such line might look like:\n"
55 "\n"
56 "           -- At sub-brick #0 'Full_Fstat' datum type is float:  0 to 971.2\n"
57 "\n"
58 "----------------------------------------------------------------------\n"
59 "Alternate Usage 2: ~1~\n"
60 "  3dinfo <OPTION> [OPTION ..] dataset [dataset ...]\n"
61 "  Outputs a specific piece of information depending on OPTION.\n"
62 "  This can form a table of outputs per dataset.\n"
63 "\n"
64 "  ==============================================================\n"
65 "  Options producing one value (string) ~2~\n"
66 "  ==============================================================\n"
67 "   -exists: 1 if dset is loadable, 0 otherwise\n"
68 "            This works on prefix also.\n"
69 "   -id: Idcodestring of dset\n"
70 "   -is_atlas: 1 if dset is an atlas.\n"
71 "   -is_atlas_or_labeltable: 1 if dset has an atlas or labeltable.\n"
72 "   -is_nifti: 1 if dset is NIFTI format, 0 otherwise\n"
73 "   -dset_extension: show filename extension for valid dataset (e.g. .nii.gz)\n"
74 "   -storage_mode: show internal storage mode of dataset (e.g. NIFTI)\n"
75 "   -space: dataset's space\n"
76 "   -gen_space: datasets generic space\n"
77 "   -av_space: AFNI format's view extension for the space\n"
78 "   -nifti_code: what AFNI would use for an output NIFTI (q)sform_code\n"
79 "   -is_oblique: 1 if dset is oblique\n"
80 "   -handedness: L if orientation is Left handed, R if it is right handed\n"
81 "   -obliquity: Angle from plumb direction.\n"
82 "               Angles of 0 (or close) are for cardinal orientations\n"
83 "\n"
84 "   -prefix: Return the prefix\n"
85 "   -prefix_noext: Return the prefix without extensions\n"
86 "   -ni: Return the number of voxels in i dimension\n"
87 "   -nj: Return the number of voxels in j dimension\n"
88 "   -nk: Return the number of voxels in k dimension\n"
89 "   -nijk: Return ni*nj*nk\n"
90 "   -nv: Return number of points in time or the number of sub-bricks\n"
91 "   -nt: same as -nv\n"
92 "   -n4: same as -ni -nj -nk -nv\n"
93 "   -nvi: The maximum sub-brick index (= nv -1 )\n"
94 "   -nti: same as -nvi\n"
95 "   -ntimes: Return number of sub-bricks points in time\n"
96 "        This is an option for debugging use, stay away from it.\n"
97 "   -max_node: For a surface-based dset, return the maximum node index\n"
98 "   -di: Signed displacement per voxel along i direction, aka dx\n"
99 "   -dj: Signed displacement per voxel along j direction, aka dy\n"
100 "   -dk: Signed displacement per voxel along k direction, aka dz\n"
101 "   -d3: same as -di -dj -dk\n"
102 "   -adi: Voxel size along i direction (abs(di))\n"
103 "   -adj: Voxel size along j direction (abs(dj))\n"
104 "   -adk: Voxel size along k direction (abs(dk))\n"
105 "   -ad3: same as -adi -adj -adk\n"
106 "   -voxvol: Voxel volume in cubic millimeters\n"
107 "   -oi: Volume origin along the i direction\n"
108 "   -oj: Volume origin along the j direction\n"
109 "   -ok: Volume origin along the k direction\n"
110 "   -o3: same as -oi -oj -ok\n"
111 "   -dcx: volumetric center in x direction (DICOM coordinates)\n"
112 "   -dcy: volumetric center in y direction (DICOM coordinates)\n"
113 "   -dcz: volumetric center in z direction (DICOM coordinates)\n"
114 "   -dc3: same as -dcx -dcy -dcz\n"
115 "   -tr: The TR value in seconds.\n"
116 "   -dmin: The dataset's minimum value, scaled by fac\n"
117 "   -dmax: The dataset's maximum value, scaled by fac\n"
118 "   -dminus: The dataset's minimum value, unscaled.\n"
119 "   -dmaxus: The dataset's maximum value, unscaled.\n"
120 "   -smode: Dset storage mode string.\n"
121 "   -header_name: Value of dset structure (sub)field 'header_name'\n"
122 "   -brick_name: Value of dset structure (sub)field 'brick_name'\n"
123 "   -iname: Name of dset as input on the command line\n"
124 "   -orient: Value of orientation string.\n"
125 "            For example, LPI means:\n"
126 "               i direction grows from Left(negative) to Right(positive).\n"
127 "               j direction grows from Posterior (neg.) to Anterior (pos.)\n"     "               k direction grows from Inferior (neg.) to Superior (pos.)\n"
128 "   -extent: The spatial extent of the dataset along R, L, A, P, I and S\n"
129 "   -Rextent: Extent along R\n"
130 "   -Lextent: Extent along L\n"
131 "   -Aextent: Extent along P\n"
132 "   -Pextent: Extent along P\n"
133 "   -Iextent: Extent along I\n"
134 "   -Sextent: Extent along S\n"
135 "   -all_names: Value of various dset structures handling filenames.\n"
136 "\n"
137 "  ==============================================================\n"
138 "  Options producing one value per sub-brick ~2~\n"
139 "  ==============================================================\n"
140 "   -fac: Return the float scaling factor\n"
141 "   -label: The label of each sub-brick\n"
142 "   -datum: The data storage type\n"
143 "   -min: The minimum value, scaled by fac\n"
144 "   -max: The maximum value, scaled by fac\n"
145 "   -minus: The minimum value, unscaled.\n"
146 "   -maxus: The maximum value, unscaled.\n"
147 "\n"
148 "  ==============================================================\n"
149 "  Options producing multiple values (strings of multiple lines) ~2~\n"
150 "  ==============================================================\n"
151 "   You can specify the delimiter between sub-brick parameters with\n"
152 "       -sb_delim DELIM. Default DELIM is \"|\"\n"
153 "   -labeltable: Show label table, if any\n"
154 "   -labeltable_as_atlas_points: Show label table in atlas point format.\n"
155 "   -atlas_points: Show atlas points list, if any\n"
156 "   -history: History note. \n"
157 "   -slice_timing: Show slice timing. \n"
158 "\n"
159 "  ==============================================================\n"
160 "  Options affecting output format ~2~\n"
161 "  ==============================================================\n"
162 "   -header_line: Output as the first line the names of attributes\n"
163 "                 in each field (column)\n"
164 "   -hdr: Same as -header_line\n"
165 "   -sb_delim SB_DELIM: Delimiter string between sub-brick values\n"
166 "                       Default SB_DELIM is \"|\"\n"
167 "   -NA_flag NAFLAG: String to use when a field is not found or not\n"
168 "                    applicable. Default is \"NA\"\n"
169 "   -atr_delim ATR_DELIM: Delimiter string between attributes\n"
170 "                         Default ATR_DELIM is the tab character.\n"
171 "\n"
172 "  ==============================================================\n"
173 "  Options for displaying ijk_to_xyz matrices ~2~\n"
174 "  ==============================================================\n"
175 "   A set of functions for displaying the matrices that tell us where\n"
176 "   the data actually is in space!  These 4x4---well 3x4, in practice,\n"
177 "   because the bottom row of the matrix *must* be (0, 0, 0, 1)---\n"
178 "   can be related to the NIFTI sform and qform matrices (which are LPI\n"
179 "   native), but these aform_* matrices are RAI (DICOM) native.\n"
180 ""
181 "   There are several types of matrices. Linear affine are the most general\n"
182 "   (containing translation, rotation, shear and scaling info), followed by\n"
183 "   orthogonal (no shear info; only translation, rotation and scale),\n"
184 "   followed by cardinal (no rotation info; only translation and scale).\n"
185 "   The 'scale' info is the voxel sizes. The 'translation' determines the\n"
186 "   origin location in space.  The 'rotation' describes a, well, rotation\n"
187 "   relative to the scanner coords---this is the dreaded 'obliquity'. The\n"
188 "   'shear'... well, that could also be present, but it is not common, at\n"
189 "   least to describe just-acquired data: it would tilt the axes away from\n"
190 "   being mutually 90 deg to each other (i.e., they wouldn't be\n"
191 "   orthogonal); this would likely just result from an alignment process.\n"
192 ""
193 "   Note: the NIFTI sform can be linear affine, in general; in practice, it\n"
194 "   is often just orthogonal.  The NIFTI qform is a quaternion representation\n"
195 "   of the orthogonalized sform; if sform is orthogonal, then they contain\n"
196 "   the same information (common, but not required).\n"
197 ""
198 "   The aform_real matrix is AFNI's equivalent of the NIFTI sform; it *can*\n"
199 "   encode general linear affine mappings. (In practice, it rarely does so.)\n"
200 "   The aform_orth is the orthogonalized aform_real, and thus equivalent\n"
201 "   to the NIFTI qform.  If aform_real is orthogonal (no shear info), then\n"
202 "   these two matrices are equal.  The aform_card is the cardinalized form of\n"
203 "   the aform_orth;  NIFTI does not have an equivalent.  AFNI typically uses\n"
204 "   this matrix to display your data on a rectangle that is parallel to your\n"
205 "   computer screen, without any need to regrid/resample the data (hence, no\n"
206 "   blurring introduced).  This can be though of displaying your dataset in\n"
207 "   a way that you *wish* your subject had been oriented.  Note that if\n"
208 "   there is no obliquity in the acquired data (that is, aform_orth does not\n"
209 "   contain any rotation relative to the scanner coords), then\n"
210 "    aform_card == aform_orth.\n"
211 ""
212 "   The aform_card is an AFNI convenience (ha!) matrix, it does not have an\n"
213 "   equivalent in the NIFTI stable of matrices.\n"
214 ""
215 "   -aform_real: Display full 3x4 'aform_real' matrix (AFNI's RAI equivalent\n"
216 "                of the sform matrix in NIFTI, may contain obliquity info),\n"
217 "                with comment line first.\n"
218 "   -aform_real_oneline: Display full 'aform_real' matrix (see '-aform_real')\n"
219 "                        as 1 row of 12 numbers. No additional comment.\n"
220 "   -aform_real_refit_ori XXX: Display full 3x4 'aform_real' matrix (see \n"
221 "                        '-aform_real')\n"
222 "                        *if* the dset were reoriented (via 3drefit) to\n"
223 "                        new orient XXX.  Includes comment line first.\n"
224 "   -is_aform_real_orth: if true, aform_real == aform_orth, which should be\n"
225 "                        a very common occurrence.\n"
226 "   -aform_orth: Display full 3x4 'aform_orth' matrix (AFNI's RAI matrix\n"
227 "                equivalent of the NIFTI quaternion, which may contain\n"
228 "                obliquity info), with comment line first.\n"
229 "                This matrix is the orthogonalized form of aform_real,\n"
230 "                and veeery often AFNI-produced dsets, we will have:\n"
231 "                aform_orth == aform_real.\n"
232 "  -perm_to_orient YYY: Display 3x3 permutation matrix to go from the\n"
233 "                       dset's current orientation to the YYY orient.\n"
234 "\n"
235 "  ==============================================================\n"
236 "  Options requiring dataset pairing at input ~2~\n"
237 "  ==============================================================\n"
238 "    3dinfo allows you to make some comparisons between dataset pairs.\n"
239 "    The comparison is always done in both directions whether or not\n"
240 "    the answer can be different. For example:\n"
241 "          3dinfo -same_grid dset1 dset2 \n"
242 "    will output two values, one comparing dset1 to dset2 and the second\n"
243 "    comparing dset2 to dset1. With -same_grid, the answers will always\n"
244 "    be identical, but this might be different for other queries.\n"
245 "    This behaviour allows you to mix options requiring dataset pairs\n"
246 "    with those that do not. For example:\n"
247 "          3dinfo -header_line -prefix -n4 -same_grid \\\n"
248 "                              DSET1+orig DSET2.nii DSET3.nii DSET4.nii\n"
249 "\n"
250 "   -same_grid: Output 1 if the grid is identical between two dsets\n"
251 "                      0 otherwise. \n"
252 "               For -same_grid to be 1, all of -same_dim, -same_delta,\n"
253 "               -same_orient, -same_center, and -same_obl must return 1\n"
254 "   -same_dim: 1 if dimensions are the same between dset pairs\n"
255 "   -same_delta: 1 if voxels sizes are the same between dset pairs\n"
256 "   -same_orient: 1 if orientation is the same between dset pairs\n"
257 "   -same_center: 1 if geometric center is the same between dset pairs\n"
258 "   -same_obl: 1 if obliquity is the same between dset pairs\n"
259 "   -same_all_grid: Equivalent to listing all of -same_dim -same_delta\n"
260 "                   -same_orient, -same_center, and -same_obl on the \n"
261 "                   command line.\n"
262 "   -val_diff: Output the sum of absolute differences of all voxels in the\n"
263 "              dataset pair.\n"
264 "   -sval_diff: Same as -val_diff, but the sum is divided (scaled) by the \n"
265 "               total number of voxels that are not zero in at least one\n"
266 "               of the two datasets.\n"
267 "\n"
268 "   -monog_pairs: Instead of pairing each dset with the first, pair each\n"
269 "                couple separately. This requires you to have an even\n"
270 "                number of dsets on the command line\n"
271 "\n"
272 " Examples with csh syntax using datasets in your afni binaries directory ~1~\n"
273 "\n"
274 "  0- First get some datasets with which we'll play\n"
275 "     set dsets = ( `apsearch -list_all_afni_P_dsets` )\n"
276 "\n"
277 "  1- The classic\n"
278 "     3dinfo $dsets[1]\n"
279 "\n"
280 "  2- Produce a table of results using 1-value-options for two datasets\n"
281 "     3dinfo  -echo_edu -prefix_noext -prefix -space -ni -nj -nk -nt  \\\n"
282 "               $dsets[1-2]\n"
283 "\n"
284 "  3- Use some of the options that operate on pairs, mix with other options\n"
285 "     3dinfo -echo_edu -header_line -prefix -n4 -same_grid $dsets[1-4]\n"
286 "\n"
287 "\n",
288    SUMA_Offset_SLines(get_help_help(),2)) ;
289    PRINT_COMPILE_DATE ; return(0) ;
290 }
291 
load_3dinfo_dataset(char * name)292 THD_3dim_dataset *load_3dinfo_dataset(char *name)
293 {
294    THD_3dim_dataset *dset = NULL;
295 
296    if( !name || name[0] == '\0' ) return(NULL);
297    dset = THD_open_dataset( name ) ;
298 
299    if( dset == NULL ){  /* open failed */
300 
301        /* 23 Jan 2008: try again with +orig, +acpc, +tlrc appended */
302 
303        if( strchr(name,'+')==NULL && strstr(name,".nii")==NULL ){
304          char str[THD_MAX_NAME] ; int vv , ll=strlen(name) ;
305          for( vv=0 ; vv <= LAST_VIEW_TYPE && dset == NULL ; vv++ ){
306            strcpy(str,name); if( str[ll-1] == '.' ) str[ll-1] = '\0';
307            strcat(str,"+") ; strcat(str,VIEW_codestr[vv]) ;
308            dset = THD_open_dataset(str) ;
309          }
310        }
311 
312    }
313    return(dset);
314 }
315 
316 typedef enum {
317    CLASSIC=0, DSET_SPACE, AV_DSET_SPACE, DSET_GEN_SPACE, INFO_NIFTI_CODE,
318    IS_NIFTI, DSET_EXISTS,
319    DSET_EXTENSION, STORAGE_MODE, /* 4 Jun 2019 [rickr] */
320    IS_ATLAS, IS_ATLAS_OR_LABELTABLE, IS_OBLIQUE, OBLIQUITY,
321    AFORM_REAL, AFORM_REAL_ONELINE, AFORM_REAL_REFIT_ORI, // [PT: Nov 13, 2020]
322    IS_AFORM_REAL_ORTH,
323    AFORM_ORTH,                                          // [PT: Nov 14, 2020]
324    PERM_TO_ORIENT,                                      // [PT: Nov 23, 2020]
325    PREFIX , PREFIX_NOEXT,
326    NI, NJ, NK, NT, NTI, NTIMES, MAX_NODE,
327    NV, NVI, NIJK,
328    N4,
329    DI, DJ, DK, D3,
330    OI, OJ, OK, O3,
331    ADI, ADJ, ADK, AD3,
332    DCX, DCY, DCZ, DC3,
333    LTABLE, LTABLE_AS_ATLAS_POINT_LIST, ATLAS_POINTS,
334    SLICE_TIMING,
335    FAC, DATUM, LABEL,
336    MIN, MAX, MINUS, MAXUS,
337    DMIN, DMAX, DMINUS, DMAXUS,
338    TR, HEADER_NAME, BRICK_NAME, ALL_NAMES,
339    HISTORY, ORIENT,
340    SAME_GRID, SAME_DIM, SAME_DELTA, SAME_ORIENT, SAME_CENTER,
341    SAME_OBL, SVAL_DIFF, VAL_DIFF, SAME_ALL_GRID, ID, SMODE,
342    VOXVOL, INAME, HANDEDNESS,
343    EXTENT_R, EXTENT_L, EXTENT_A, EXTENT_P, EXTENT_I, EXTENT_S, EXTENT,
344    N_FIELDS } INFO_FIELDS; /* Keep synchronized with Field_Names
345                               Leave N_FIELDS at the end */
346 
347 char Field_Names[][32]={
348    {"-classic-"}, {"space"}, {"AV_spc"}, {"gen_spc"}, {"nifti_code"},
349    {"nifti?"}, {"exist?"}, {"exten"}, {"smode"},
350    {"atlas?"}, {"atlas_or_lt?"}, {"oblq?"}, {"oblq"},
351    {"aformr"}, {"aformr_line"}, {"aformr_refit"},
352    {"aformr_orth?"}, {"aform_orth"}, {"perm2ori"},
353    {"prefix"}, {"pref_nx"},
354    {"Ni"}, {"Nj"}, {"Nk"}, {"Nt"}, {"Nti"}, {"Ntimes"}, {"MxNode"},
355    {"Nv"}, {"Nvi"}, {"Nijk"},
356    {"Ni_Nj_Nk_Nv"},
357    {"Di"}, {"Dj"}, {"Dk"}, {"Di_Dj_Dk"},
358    {"Oi"}, {"Oj"}, {"Ok"}, {"Oi_Oj_Ok"},
359    {"ADi"}, {"ADj"}, {"ADk"}, {"ADi_ADj_ADk"},
360    {"DCx"}, {"DCy"}, {"DCz"}, {"DCx_DCy_DCz"},
361    {"label_table"}, {"LT_as_atlas_point_list"}, {"atlas_point_list"},
362    {"slice_timing"},
363    {"factor"}, {"datum"}, {"label"},
364    {"min"}, {"max"}, {"minus"}, {"maxus"},
365    {"dmin"}, {"dmax"}, {"dminus"}, {"dmaxus"},
366    {"TR"}, {"hdr_nm"}, {"brk_nm"}, {"all_nms"},
367    {"hist"}, {"orient"},
368    {"=grid?"}, {"=dim?"}, {"=delt?"}, {"=ornt?"}, {"=cent?"},
369    {"=obl?"}, {"sDval"}, {"Dval"}, {"=dim_delta_orient_center_obl"},
370    {"id"}, {"smode"},
371    {"voxvol"}, {"iname"}, {"hand"},
372    {"Rext"}, {"Lext"},{"Aext"}, {"Pext"}, {"Iext"}, {"Sext"}, {"RLAPIS_ext"},
373    {"\0"} }; /* Keep synchronized with INFO_FIELDS */
374 
PrintForm(INFO_FIELDS sing,int namelen,byte ForHead)375 char *PrintForm(INFO_FIELDS sing , int namelen, byte ForHead)
376 {
377    static char form[5][15];
378    static int iret=-1;
379    ++iret; if (iret > 4) iret = 0;
380    if (ForHead) {
381       switch (sing) {
382          case PREFIX:
383          case PREFIX_NOEXT:
384             sprintf(form[iret],"%%%ds", namelen);
385             break;
386          default:
387             sprintf(form[iret],"%%s");
388       }
389    } else {
390       ERROR_message("Not ready for non-header format of %d\n", sing);
391       sprintf(form[iret],"F.ERROR:%%s");
392    }
393 
394    return(form[iret]);
395 }
396 
397 #define SPIT_DELIM(ii,N_ii, atrdelim) { \
398    if (N_ii > 1 && ii < N_ii-1) fprintf(stdout,"%s",atrdelim);  \
399    else fprintf(stdout,"\n"); \
400 }
401 
402 
main(int argc,char * argv[])403 int main( int argc , char *argv[] )
404 {
405    THD_3dim_dataset *dset=NULL;
406    int iarg , verbose = -1 ;
407    char *stmp=NULL;
408    char *classic_labelName = NULL;
409    char *sbdelim = {"|"};
410    char *NAflag = {"NA"};
411    char *atrdelim = {"\t"}, *form=NULL;
412    INFO_FIELDS sing[512];
413    int iis=0, N_sing = 0, isb=0, withhead = 0, itmp=0;
414    int ip=0, needpair = 0, namelen=0, monog_pairs = 0;
415    int classic_niml_hdr = 0;    /* classic: show niml header */
416    int classic_subb_info = 0;   /* classic: show sub-brick info */
417    THD_3dim_dataset *tttdset=NULL, *dsetp=NULL;
418    THD_fvec3 fv = {{-666.0, -666.0, -666.0}};
419    char *tempstr = NULL;
420    int extinit = 0;
421    float RL_AP_IS[6];
422 
423    char *aform_real_pbase= "(aform_real)";
424    char aform_real_pstr[100];
425    char *ocharB_aform_real=NULL;        // new orient for aform_real disp
426    mat44 dset_mat44_P;
427    char *aform_orth_pbase= "(aform_orth)";
428    char aform_orth_pstr[100];
429 
430    char *ochar_perm=NULL;        // new orient for perm calc
431    char perm_pstr[100];
432 
433    mainENTRY("3dinfo main") ; machdep() ;
434 
435    strcpy(perm_pstr, "");
436    strcpy(aform_real_pstr, aform_real_pbase);
437    strcpy(aform_orth_pstr, aform_orth_pbase);
438 
439    if( argc < 2) { Syntax(TXT,1) ; RETURN(0); }
440 
441    iarg = 1 ;
442    while (iarg < argc && argv[iarg][0] == '-') {
443       CHECK_HELP(argv[iarg],Syntax);
444            if( strncmp(argv[iarg],"-verb" ,5) == 0 ){
445             verbose =  0; iarg++; continue; }
446       else if( strncmp(argv[iarg],"-VERB" ,5) == 0 ){
447             verbose =  1; iarg++; continue; }
448       else if( strncmp(argv[iarg],"-short",5) == 0 ){
449             verbose = -1; iarg++; continue; }
450       else if( strcasecmp(argv[iarg],"-header_line") == 0 ||
451                strcasecmp(argv[iarg],"-hdr") == 0 ){
452             withhead = 1; iarg++; continue; }
453       else if( strcasecmp(argv[iarg],"-monog_pairs") == 0 ){
454             monog_pairs = 1; iarg++; continue; }
455       /* long-format classic options */
456       else if ( strncmp(argv[iarg],"-label2",7) == 0 )
457       {
458         iarg++;
459         if (iarg >= argc)
460            ERROR_exit( "3dinfo needs an argument after -label2number\n");
461         classic_labelName = malloc(sizeof(char) * 2048);
462         strcpy(classic_labelName, argv[iarg]);
463         iarg++; continue;
464       }
465       else if( strcmp(argv[iarg],"-niml_hdr") == 0) {
466         classic_niml_hdr = 1;  /* show niml header in classic case */
467         iarg++; continue;
468       }
469       else if( strcmp(argv[iarg],"-subbrick_info") == 0) {
470         classic_subb_info = 1;  /* show sub-brick part of info */
471         iarg++; continue;
472       }
473       /* end: long-format classic options */
474       else if( strcasecmp(argv[iarg],"-sb_delim") == 0) {
475          iarg++;
476          if (iarg >= argc)
477            ERROR_exit( "3dinfo needs a string after -sb_delim\n");
478          sbdelim = argv[iarg];
479          iarg++; continue;
480       }
481       else if( strcasecmp(argv[iarg],"-NA_flag") == 0) {
482          iarg++;
483          if (iarg >= argc)
484            ERROR_exit( "3dinfo needs a string after -NA_flag\n");
485          NAflag = argv[iarg];
486          iarg++; continue;
487       }
488       else if( strcasecmp(argv[iarg],"-atr_delim") == 0) {
489          iarg++;
490          if (iarg >= argc)
491            ERROR_exit( "3dinfo needs a string after -atr_delim\n");
492          atrdelim = argv[iarg];
493          iarg++; continue;
494       }
495       else if( strcasecmp(argv[iarg],"-space") == 0) {
496          sing[N_sing++] = DSET_SPACE; iarg++; continue;
497       } else if( strcasecmp(argv[iarg],"-av_space") == 0) {
498          sing[N_sing++] = AV_DSET_SPACE; iarg++; continue;
499       } else if( strcasecmp(argv[iarg],"-gen_space") == 0) {
500          sing[N_sing++] = DSET_GEN_SPACE; iarg++; continue;
501       } else if( strcasecmp(argv[iarg],"-nifti_code") == 0) {
502          sing[N_sing++] = INFO_NIFTI_CODE; iarg++; continue;
503       } else if( strcasecmp(argv[iarg],"-is_nifti") == 0) {
504          sing[N_sing++] = IS_NIFTI; iarg++; continue;
505       } else if( strcasecmp(argv[iarg],"-dset_extension") == 0) {
506          sing[N_sing++] = DSET_EXTENSION; iarg++; continue;
507       } else if( strcasecmp(argv[iarg],"-storage_mode") == 0) {
508          sing[N_sing++] = STORAGE_MODE; iarg++; continue;
509       } else if( strcasecmp(argv[iarg],"-is_atlas") == 0) {
510          sing[N_sing++] = IS_ATLAS; iarg++; continue;
511       } else if( strcasecmp(argv[iarg],"-is_atlas_or_labeltable") == 0) {
512          sing[N_sing++] = IS_ATLAS_OR_LABELTABLE; iarg++; continue;
513       } else if( strcasecmp(argv[iarg],"-exists") == 0) {
514          sing[N_sing++] = DSET_EXISTS; iarg++; continue;
515       } else if( strcasecmp(argv[iarg],"-is_oblique") == 0) {
516          sing[N_sing++] = IS_OBLIQUE; iarg++; continue;
517       } else if( strcasecmp(argv[iarg],"-obliquity") == 0) {
518          sing[N_sing++] = OBLIQUITY; iarg++; continue;
519       } else if( strcasecmp(argv[iarg],"-aform_real") == 0) {
520          sing[N_sing++] = AFORM_REAL; iarg++; continue;
521       } else if( strcasecmp(argv[iarg],"-aform_real_oneline") == 0) {
522          sing[N_sing++] = AFORM_REAL_ONELINE; iarg++; continue;
523       } else if( strcasecmp(argv[iarg],"-aform_real_refit_ori") == 0) {
524          iarg++;
525          if (iarg >= argc)
526            ERROR_exit( "3dinfo needs a string after -aform_real_refit_ori\n");
527          ocharB_aform_real = argv[iarg];
528          sing[N_sing++] = AFORM_REAL_REFIT_ORI; iarg++; continue;
529       } else if( strcasecmp(argv[iarg],"-is_aform_real_orth") == 0) {
530          sing[N_sing++] = IS_AFORM_REAL_ORTH; iarg++; continue;
531       } else if( strcasecmp(argv[iarg],"-aform_orth") == 0) {
532          sing[N_sing++] = AFORM_ORTH; iarg++; continue;
533       } else if( strcasecmp(argv[iarg],"-perm_to_orient") == 0) {
534          iarg++;
535          if (iarg >= argc)
536            ERROR_exit( "3dinfo needs a string after -perm_to_orient\n");
537          ochar_perm = argv[iarg];
538          sing[N_sing++] = PERM_TO_ORIENT; iarg++; continue;
539       } else if( strcasecmp(argv[iarg],"-handedness") == 0) {
540          sing[N_sing++] = HANDEDNESS; iarg++; continue;
541       } else if( strcasecmp(argv[iarg],"-prefix") == 0) {
542          sing[N_sing++] = PREFIX; iarg++; continue;
543       } else if( strcasecmp(argv[iarg],"-prefix_noext") == 0) {
544          sing[N_sing++] = PREFIX_NOEXT; iarg++; continue;
545       } else if( strcasecmp(argv[iarg],"-ni") == 0) {
546          sing[N_sing++] = NI; iarg++; continue;
547       } else if( strcasecmp(argv[iarg],"-nj") == 0) {
548          sing[N_sing++] = NJ; iarg++; continue;
549       } else if( strcasecmp(argv[iarg],"-nk") == 0) {
550          sing[N_sing++] = NK; iarg++; continue;
551       } else if( strcasecmp(argv[iarg],"-n4") == 0) {
552          sing[N_sing++] = NI;
553          sing[N_sing++] = NJ;
554          sing[N_sing++] = NK;
555          sing[N_sing++] = NV; iarg++;
556          continue;
557       } else if( strcasecmp(argv[iarg],"-Rextent") == 0) {
558          sing[N_sing++] = EXTENT_R; iarg++;
559          continue;
560       } else if( strcasecmp(argv[iarg],"-Lextent") == 0) {
561          sing[N_sing++] = EXTENT_L; iarg++;
562          continue;
563       } else if( strcasecmp(argv[iarg],"-Aextent") == 0) {
564          sing[N_sing++] = EXTENT_A; iarg++;
565          continue;
566       } else if( strcasecmp(argv[iarg],"-Pextent") == 0) {
567          sing[N_sing++] = EXTENT_P; iarg++;
568          continue;
569       } else if( strcasecmp(argv[iarg],"-Iextent") == 0) {
570          sing[N_sing++] = EXTENT_I; iarg++;
571          continue;
572       }  else if( strcasecmp(argv[iarg],"-Sextent") == 0) {
573          sing[N_sing++] = EXTENT_S; iarg++;
574          continue;
575       } else if( strcasecmp(argv[iarg],"-extent") == 0) {
576          sing[N_sing++] = EXTENT_R;
577          sing[N_sing++] = EXTENT_L;
578          sing[N_sing++] = EXTENT_A;
579          sing[N_sing++] = EXTENT_P;
580          sing[N_sing++] = EXTENT_I;
581          sing[N_sing++] = EXTENT_S;
582          iarg++;
583          continue;
584       } else if( strcasecmp(argv[iarg],"-di") == 0) {
585          sing[N_sing++] = DI; iarg++; continue;
586       } else if( strcasecmp(argv[iarg],"-dj") == 0) {
587          sing[N_sing++] = DJ; iarg++; continue;
588       } else if( strcasecmp(argv[iarg],"-dk") == 0) {
589          sing[N_sing++] = DK; iarg++; continue;
590       } else if( strcasecmp(argv[iarg],"-d3") == 0) {
591          sing[N_sing++] = DI;
592          sing[N_sing++] = DJ;
593          sing[N_sing++] = DK; iarg++;
594          continue;
595       } else if( strcasecmp(argv[iarg],"-adi") == 0) {
596          sing[N_sing++] = ADI; iarg++; continue;
597       } else if( strcasecmp(argv[iarg],"-adj") == 0) {
598          sing[N_sing++] = ADJ; iarg++; continue;
599       } else if( strcasecmp(argv[iarg],"-adk") == 0) {
600          sing[N_sing++] = ADK; iarg++; continue;
601       } else if( strcasecmp(argv[iarg],"-ad3") == 0) {
602          sing[N_sing++] = ADI;
603          sing[N_sing++] = ADJ;
604          sing[N_sing++] = ADK; iarg++;
605          continue;
606       } else if( strcasecmp(argv[iarg],"-dcx") == 0) {
607          sing[N_sing++] = DCX; iarg++; continue;
608       } else if( strcasecmp(argv[iarg],"-dcy") == 0) {
609          sing[N_sing++] = DCY; iarg++; continue;
610       } else if( strcasecmp(argv[iarg],"-dcz") == 0) {
611          sing[N_sing++] = DCZ; iarg++; continue;
612       } else if( strcasecmp(argv[iarg],"-dc3") == 0) {
613          sing[N_sing++] = DCX;
614          sing[N_sing++] = DCY;
615          sing[N_sing++] = DCZ; iarg++;
616          continue;
617       } else if( strcasecmp(argv[iarg],"-voxvol") == 0) {
618          sing[N_sing++] = VOXVOL; iarg++; continue;
619       } else if( strcasecmp(argv[iarg],"-iname") == 0) {
620          sing[N_sing++] = INAME; iarg++; continue;
621       } else if( strcasecmp(argv[iarg],"-oi") == 0) {
622          sing[N_sing++] = OI; iarg++; continue;
623       } else if( strcasecmp(argv[iarg],"-oj") == 0) {
624          sing[N_sing++] = OJ; iarg++; continue;
625       } else if( strcasecmp(argv[iarg],"-ok") == 0) {
626          sing[N_sing++] = OK; iarg++; continue;
627       } else if( strcasecmp(argv[iarg],"-o3") == 0) {
628          sing[N_sing++] = OI;
629          sing[N_sing++] = OJ;
630          sing[N_sing++] = OK; iarg++;
631          continue;
632       }else if( strcasecmp(argv[iarg],"-nt") == 0) {
633          sing[N_sing++] = NT; iarg++; continue;
634       } else if( strcasecmp(argv[iarg],"-nti") == 0) {
635          sing[N_sing++] = NTI; iarg++; continue;
636       } else if( strcasecmp(argv[iarg],"-nv") == 0) {
637          sing[N_sing++] = NV; iarg++; continue;
638       } else if( strcasecmp(argv[iarg],"-nvi") == 0) {
639          sing[N_sing++] = NVI; iarg++; continue;
640       } else if( strcasecmp(argv[iarg],"-ntimes") == 0) {
641          sing[N_sing++] = NTIMES; iarg++; continue;
642       } else if( strcasecmp(argv[iarg],"-max_node") == 0) {
643          sing[N_sing++] = MAX_NODE; iarg++; continue;
644       } else if( strcasecmp(argv[iarg],"-nijk") == 0) {
645          sing[N_sing++] = NIJK; iarg++; continue;
646       } else if( strcasecmp(argv[iarg],"-labeltable") == 0) {
647          sing[N_sing++] = LTABLE; iarg++; continue;
648       } else if( strcasecmp(argv[iarg],"-labeltable_as_atlas_points") == 0) {
649          sing[N_sing++] = LTABLE_AS_ATLAS_POINT_LIST; iarg++; continue;
650       } else if( strcasecmp(argv[iarg],"-atlas_points") == 0) {
651          sing[N_sing++] = ATLAS_POINTS; iarg++; continue;
652       } else if( strcasecmp(argv[iarg],"-fac") == 0) {
653          sing[N_sing++] = FAC; iarg++; continue;
654       } else if( strcasecmp(argv[iarg],"-datum") == 0) {
655          sing[N_sing++] = DATUM; iarg++; continue;
656       } else if( strcasecmp(argv[iarg],"-label") == 0) {
657          sing[N_sing++] = LABEL; iarg++; continue;
658       } else if( strcasecmp(argv[iarg],"-min") == 0) {
659          sing[N_sing++] = MIN; iarg++; continue;
660       } else if( strcasecmp(argv[iarg],"-max") == 0) {
661          sing[N_sing++] = MAX; iarg++; continue;
662       } else if( strcasecmp(argv[iarg],"-minus") == 0) {
663          sing[N_sing++] = MINUS; iarg++; continue;
664       } else if( strcasecmp(argv[iarg],"-maxus") == 0) {
665          sing[N_sing++] = MAXUS; iarg++; continue;
666       } else if( strcasecmp(argv[iarg],"-dmin") == 0) {
667          sing[N_sing++] = DMIN; iarg++; continue;
668       } else if( strcasecmp(argv[iarg],"-dmax") == 0) {
669          sing[N_sing++] = DMAX; iarg++; continue;
670       } else if( strcasecmp(argv[iarg],"-dminus") == 0) {
671          sing[N_sing++] = DMINUS; iarg++; continue;
672       } else if( strcasecmp(argv[iarg],"-dmaxus") == 0) {
673          sing[N_sing++] = DMAXUS; iarg++; continue;
674       } else if( strcasecmp(argv[iarg],"-TR") == 0) {
675          sing[N_sing++] = TR; iarg++; continue;
676       } else if( strcasecmp(argv[iarg],"-header_name") == 0) {
677          sing[N_sing++] = HEADER_NAME; iarg++; continue;
678       } else if( strcasecmp(argv[iarg],"-brick_name") == 0) {
679          sing[N_sing++] = BRICK_NAME; iarg++; continue;
680       } else if( strcasecmp(argv[iarg],"-history") == 0) {
681          sing[N_sing++] = HISTORY; iarg++; continue;
682       } else if( strcasecmp(argv[iarg],"-all_names") == 0) {
683          sing[N_sing++] = ALL_NAMES; iarg++; continue;
684       } else if( strcasecmp(argv[iarg],"-orient") == 0) {
685          sing[N_sing++] = ORIENT; iarg++; continue;
686       } else if( strcasecmp(argv[iarg],"-same_grid") == 0) {
687          sing[N_sing++] = SAME_GRID; needpair = 1; iarg++; continue;
688       } else if( strcasecmp(argv[iarg],"-same_dim") == 0) {
689          sing[N_sing++] = SAME_DIM; needpair = 1; iarg++; continue;
690       } else if( strcasecmp(argv[iarg],"-same_delta") == 0) {
691          sing[N_sing++] = SAME_DELTA; needpair = 1; iarg++; continue;
692       } else if( strcasecmp(argv[iarg],"-same_orient") == 0) {
693          sing[N_sing++] = SAME_ORIENT; needpair = 1; iarg++; continue;
694       } else if( strcasecmp(argv[iarg],"-same_center") == 0) {
695          sing[N_sing++] = SAME_CENTER; needpair = 1; iarg++; continue;
696       } else if( strcasecmp(argv[iarg],"-same_obl") == 0) {
697          sing[N_sing++] = SAME_OBL; needpair = 1; iarg++; continue;
698       } else if( strcasecmp(argv[iarg],"-slice_timing") == 0) {
699          sing[N_sing++] = SLICE_TIMING; iarg++; continue;
700       } else if( strcasecmp(argv[iarg],"-sval_diff") == 0) {
701          sing[N_sing++] = SVAL_DIFF; needpair = 1; iarg++; continue;
702       } else if( strcasecmp(argv[iarg],"-val_diff") == 0) {
703          sing[N_sing++] = VAL_DIFF; needpair = 1; iarg++; continue;
704       } else if( strcasecmp(argv[iarg],"-same_all_grid") == 0) {
705          sing[N_sing++] = SAME_DIM;
706          sing[N_sing++] = SAME_DELTA;
707          sing[N_sing++] = SAME_ORIENT;
708          sing[N_sing++] = SAME_CENTER;
709          sing[N_sing++] = SAME_OBL; needpair = 1; iarg++; continue;
710       } else if( strcasecmp(argv[iarg],"-id") == 0) {
711          sing[N_sing++] = ID; iarg++; continue;
712       } else if( strcasecmp(argv[iarg],"-smode") == 0) {
713          sing[N_sing++] = SMODE; iarg++; continue;
714       } else {
715          ERROR_message("Option %s unknown", argv[iarg]);
716          suggest_best_prog_option(argv[0], argv[iarg]);
717          exit(1);
718       }
719    }
720 
721    if (N_sing == 0) {
722       sing[N_sing++] = CLASSIC;
723    }
724 
725    if (sing[iis] == CLASSIC) PRINT_VERSION("3dinfo") ;
726 
727    /* be sure field struct matches enum     [26 Jul 2021 rickr] */
728    (void)validate_field_struct(verbose);
729 
730    THD_allow_empty_dataset(1) ;  /* 21 Mar 2007 */
731 
732    if (iarg == argc) {
733       ERROR_message("No dsets on command line? I have nothing to do.\n");
734       exit(1);
735    }
736 
737    if (needpair && monog_pairs) needpair = 2; /* pair each couple separately */
738 
739    if (needpair==2 && (argc-iarg) % 2) {
740       ERROR_message("Using options requiring dset pairs but have odd number\n"
741                     "of dsets (%d) on command line.\n", (argc-iarg));
742       exit (1);
743    } else if (needpair==1 && (argc-iarg) < 2) {
744       ERROR_message("Using options requiring dset pairs but have less than\n"
745                     "two dsets (%d) on command line.\n", (argc-iarg));
746       exit (1);
747    }
748 
749    ip = 0;
750    for( ; iarg < argc ; iarg++ ){
751       if (ip == 0) {
752          int kkk, nml; char *etr;
753          namelen = 0;
754          for (kkk=iarg; kkk<argc; ++kkk) {
755             if ((etr = THD_trailname(argv[kkk],0))) {
756                nml=strlen(etr);
757                if (nml < 48 && nml > namelen) namelen = nml;
758             }
759          }
760          if (namelen < 6) namelen = 6;
761          if (withhead) {
762             int havenew=0;
763             for (iis = 0; iis < N_sing; ++iis) {
764                if (sing[iis] != CLASSIC) {
765                   ++havenew;
766                   form = PrintForm(sing[iis], namelen, 1);
767                   /*fprintf(stderr,"ZSS: %d %s >%s<\n",
768                            sing[iis], Field_Names[sing[iis]], form);*/
769 
770                   fprintf(stdout, form, Field_Names[sing[iis]]);
771                }
772                if (havenew) {
773                   if (N_sing > 1 && iis < N_sing-1)
774                            fprintf(stdout,"%s",atrdelim);
775                   else fprintf(stdout,"\n");
776                }
777             }
778          }
779       }
780      if( argv[iarg][0] == '\0' ) continue ;  /* bad filename */
781 
782      set_obliquity_report(0); /* silence obliquity */
783 
784      if (!needpair) {
785       if (!(dset = load_3dinfo_dataset(argv[iarg]))) {
786         /* exit(1); */
787       }
788      } else {
789       if (needpair == 2) { /* Crazy idea of comparing each pair separately */
790          if (ip % 2 == 0) {
791             if (!(dset = load_3dinfo_dataset(argv[iarg] ))) {
792                /* exit(1); */
793             }
794             if (iarg+1==argc || argv[iarg+1][0] == '\0') {
795                ERROR_message("Bad dset pair for %s\n", argv[iarg]);
796                exit(1);
797             }
798             if (!(dsetp = load_3dinfo_dataset(argv[iarg+1] ))) {
799                /* exit(1); */
800             }
801          } else { /* swap the pair - this allows non pair requiring functions
802                      to work as before.*/
803             tttdset = dsetp;
804             dsetp = dset;
805             dset = tttdset; tttdset=NULL;
806          }
807       } else { /* always compare to very first dset */
808          if (ip==0) {
809             if (!(dset = load_3dinfo_dataset(argv[iarg] ))) {
810                /*exit(1);*/
811             }
812             if (!(dsetp = load_3dinfo_dataset(argv[iarg+1] ))) {
813                /*exit(1);*/
814             }
815          } else if (ip==1) { /* switch order of first two */
816             tttdset = dsetp;
817             dsetp = dset; /* now dsetp is the very first dset */
818             dset = tttdset; tttdset=NULL;
819          } else { /* pair with very first, which is dsetp */
820             if (!(dset = load_3dinfo_dataset(argv[iarg] ))) {
821                /*exit(1);*/
822             }
823          }
824       }
825      }
826      ++ip;
827 
828      if (0 && !dset) { /* allow for DSET_EXISTS option */
829          ERROR_exit("Should not get here");
830      }
831 
832      /* we should re-capture this per dataset   5 Feb 2019 [rickr] */
833      extinit = 0;
834 
835      for (iis = 0; iis < N_sing; ++iis) {
836         if (!dset) {
837          if (sing[iis] == CLASSIC) {
838             if( dset == NULL ){  /* still not open? */
839                ERROR_exit("Can't open dataset %s\n", argv[iarg]) ;
840             }
841          } else if (sing[iis] != DSET_EXISTS && sing[iis] != INAME) {
842             fprintf(stdout, "NO-DSET");
843             SPIT_DELIM(iis, N_sing, atrdelim);
844             continue;
845          }
846         }
847         switch (sing[iis]) {
848          case CLASSIC:
849             /* check for multiple cases under classic unbrella (make
850                new cases if this continues)      [10 Oct 2019 rickr] */
851 
852             if (classic_labelName != NULL ) { /*** get and output label ***/
853                print_classic_label2index(dset, classic_labelName);
854             } else if ( classic_niml_hdr ) {
855                if( ! THD_write_niml_to_stream(dset, "stdout:", 0) )
856                   ERROR_exit("Can't write NIML for dataset %s",argv[iarg]) ;
857             } else if ( classic_subb_info ) {
858                tempstr = THD_dset_subbrick_info(dset, 0);
859                if( tempstr ) {
860                   fputs(tempstr, stdout);
861                   free(tempstr);
862                   tempstr = NULL;
863                } else {
864                   ERROR_exit("failed subbrick_info for dset %s",argv[iarg]) ;
865                }
866 
867             } else { /*** real CLASSIC: get and output general info ***/
868                if( print_classic_info(dset, argv[iarg], verbose) )
869                   exit(1);
870             }
871 
872             THD_delete_3dim_dataset( dset , False ) ;
873             break;
874          case DSET_EXISTS:
875             fprintf(stdout, "%d", dset ? 1:0);
876             break;
877          case DSET_SPACE:
878             tempstr = THD_get_space(dset);
879             if(tempstr==NULL)
880                   fprintf(stdout, "-----");
881             else
882                   fprintf(stdout, "%s", tempstr);
883             break;
884          case DSET_GEN_SPACE:
885             tempstr = THD_get_generic_space(dset);
886             if(tempstr==NULL)
887                   fprintf(stdout, "-----");
888             else
889                   fprintf(stdout, "%s", tempstr);
890             break;
891          case INFO_NIFTI_CODE:
892             fprintf(stdout,"%d", space_to_NIFTI_code(dset));
893             break;
894          case AV_DSET_SPACE:
895             /* don't allow anything but the three AFNI views */
896             tempstr = THD_get_view_space(dset);
897             if(tempstr==NULL)
898                   fprintf(stdout, "+orig");
899             else if (!strncasecmp(tempstr,"ORIG",4))
900                   fprintf(stdout, "+orig");
901             else if (!strncasecmp(tempstr,"ACPC",4))
902                   fprintf(stdout, "+acpc");
903             else if (!strncasecmp(tempstr,"TLRC",4))
904                   fprintf(stdout, "+tlrc");
905             else  /* shouldn't get here */
906                   fprintf(stdout, "+orig");
907             break;
908          case IS_NIFTI:
909             if (  dset->dblk->diskptr &&
910                   dset->dblk->diskptr->storage_mode == STORAGE_BY_NIFTI ) {
911                fprintf(stdout,"1");
912             } else {
913                fprintf(stdout,"0");
914             }
915             break;
916          case DSET_EXTENSION:
917             tempstr = find_filename_extension(argv[iarg]);
918             if ( tempstr ) {
919                fprintf(stdout,"%s", tempstr);
920             } else {
921                fprintf(stdout,"-----");
922             }
923             break;
924          case STORAGE_MODE:
925             tempstr = storage_mode_name(storage_mode_from_filename(argv[iarg]));
926             /* equate UNDEFINED with NULL case */
927             if ( tempstr && strcmp(tempstr, "UNDEFINED") ) {
928                fprintf(stdout,"%s", tempstr);
929             } else {
930                fprintf(stdout,"-----");
931             }
932             break;
933          case IS_ATLAS:
934             if ( is_Dset_Atlasy(dset, NULL) ) {
935                fprintf(stdout,"1");
936             } else {
937                fprintf(stdout,"0");
938             }
939             break;
940          case IS_ATLAS_OR_LABELTABLE:
941             {
942                char *str    = NULL;
943                int iaol_val = 0;
944                if ( is_Dset_Atlasy(dset, NULL) ) {
945                   iaol_val = 1;
946                }
947                else if ( (str = Dtable_to_nimlstring(DSET_Label_Dtable(dset),
948                                                      "VALUE_LABEL_DTABLE")) ) {
949                   // 'else if' for speed
950                   iaol_val = 1;
951                   free(str);
952                }
953                fprintf(stdout,"%d", iaol_val);
954             }
955             break;
956          case IS_OBLIQUE:
957             if (dset_obliquity(dset,NULL) > 0) {
958                fprintf(stdout,"1");
959             } else {
960                fprintf(stdout,"0");
961             }
962             break;
963          case HANDEDNESS:
964             if (THD_handedness(dset) > 0) {
965                fprintf(stdout,"R");
966             } else {
967                fprintf(stdout,"L");
968             }
969             break;
970          case OBLIQUITY:
971             fprintf(stdout,"%.3f",
972                   THD_compute_oblique_angle(dset->daxes->ijk_to_dicom_real, 0));
973             break;
974          case AFORM_REAL:
975             DUMP_MAT44(aform_real_pstr, dset->daxes->ijk_to_dicom_real);
976             break;
977          case AFORM_REAL_ONELINE:
978             DUMP_MAT44_ONELINE(dset->daxes->ijk_to_dicom_real);
979             break;
980          case AFORM_REAL_REFIT_ORI:
981             {
982                char ostr[4];
983                // the work:
984                dset_mat44_P = THD_refit_orient_ijk_to_dicom_real( dset,
985                                                          ocharB_aform_real );
986                // display formatting/messaging:
987                THD_fill_orient_str_3(dset->daxes, ostr);
988                strcat(aform_real_pstr, " after reorienting from (current) ");
989                strcat(aform_real_pstr, ostr);
990                strcat(aform_real_pstr, " to ");
991                strcat(aform_real_pstr, ocharB_aform_real);
992                DUMP_MAT44(aform_real_pstr, dset_mat44_P);
993                //mat44 TEST;
994                //dset_mat44_P.m[0][2] = 1;
995                //nifti_orthogonalize_mat44(dset_mat44_P, TEST);
996             }
997             break;
998          case IS_AFORM_REAL_ORTH:
999             fprintf(stdout,"%d",
1000                     is_mat44_orthogonal(dset->daxes->ijk_to_dicom_real));
1001             break;
1002          case AFORM_ORTH:
1003             {
1004                mat44 aform_orth;
1005                aform_orth = nifti_orthogonalize_mat44(
1006                                              dset->daxes->ijk_to_dicom_real );
1007                DUMP_MAT44(aform_orth_pstr, aform_orth);
1008             break;
1009             }
1010          case PERM_TO_ORIENT:
1011             {
1012                mat33 P33;
1013                char ostr[4];
1014                // the work:
1015                P33 = THD_dset_reorient_perm_mat33(dset, ochar_perm);
1016 
1017                // display formatting/messaging:
1018                THD_fill_orient_str_3(dset->daxes, ostr);
1019                strcat(perm_pstr, "Perm from current ");
1020                strcat(perm_pstr, ostr);
1021                strcat(perm_pstr, " to ");
1022                strcat(perm_pstr, ochar_perm);
1023                DUMP_MAT33b(perm_pstr, P33);
1024             }
1025             break;
1026          case PREFIX:
1027             form = PrintForm(sing[iis], namelen, 1);
1028             fprintf(stdout,form, DSET_PREFIX(dset));
1029             break;
1030          case PREFIX_NOEXT:
1031             {
1032                form = PrintForm(sing[iis], namelen, 1);
1033                stmp=DSET_prefix_noext(dset);
1034                fprintf(stdout,form, stmp);
1035                free(stmp); stmp=NULL;
1036             }
1037             break;
1038          case HEADER_NAME:
1039             fprintf(stdout,"%s", dset->dblk->diskptr->header_name);
1040             break;
1041          case BRICK_NAME:
1042             fprintf(stdout,"%s", dset->dblk->diskptr->brick_name);
1043             break;
1044          case ALL_NAMES:
1045             THD_show_dataset_names(dset, "FOR_3DINFO", stdout);
1046             break;
1047          case HISTORY:
1048             stmp = tross_Get_History(dset);
1049             fprintf(stdout,"%s", stmp ? stmp:NAflag);
1050             if (stmp) free(stmp); stmp=NULL;
1051             break;
1052          case NI:
1053             fprintf(stdout,"%d", DSET_NX(dset));
1054             break;
1055          case NJ:
1056             fprintf(stdout,"%d", DSET_NY(dset));
1057             break;
1058          case NK:
1059             fprintf(stdout,"%d", DSET_NZ(dset));
1060             break;
1061          case NIJK:
1062             fprintf(stdout,"%d", DSET_NVOX(dset));
1063             break;
1064          case NTIMES:
1065             fprintf(stdout,"%d", DSET_NUM_TIMES(dset));
1066             break;
1067          case MAX_NODE:
1068             DSET_MAX_NODE(dset,itmp);
1069             fprintf(stdout,"%d", itmp);
1070             break;
1071          case NT:
1072          case NV:
1073             fprintf(stdout,"%d", DSET_NVALS(dset));
1074             break;
1075          case NTI:
1076          case NVI:
1077             fprintf(stdout,"%d", DSET_NVALS(dset)-1);
1078             break;
1079          case DI:
1080             fprintf(stdout,"%f", DSET_DX(dset));
1081             break;
1082          case DJ:
1083             fprintf(stdout,"%f", DSET_DY(dset));
1084             break;
1085          case DK:
1086             fprintf(stdout,"%f", DSET_DZ(dset));
1087             break;
1088          case OI:
1089             fprintf(stdout,"%f", DSET_XORG(dset));
1090             break;
1091          case OJ:
1092             fprintf(stdout,"%f", DSET_YORG(dset));
1093             break;
1094          case OK:
1095             fprintf(stdout,"%f", DSET_ZORG(dset));
1096             break;
1097          case ADI:
1098             fprintf(stdout,"%f", fabs(DSET_DX(dset)));
1099             break;
1100          case DCX:
1101             /* modular but inefficient, get C? each time */
1102             fv = THD_dataset_center(dset);
1103             fprintf(stdout,"%f", fv.xyz[0]);
1104             break;
1105          case DCY:
1106             /* modular but inefficient, get C? each time */
1107             fv = THD_dataset_center(dset);
1108             fprintf(stdout,"%f", fv.xyz[1]);
1109             break;
1110          case DCZ:
1111             /* modular but inefficient, get C? each time */
1112             fv = THD_dataset_center(dset);
1113             fprintf(stdout,"%f", fv.xyz[2]);
1114             break;
1115          case EXTENT_R:
1116          case EXTENT_L:
1117          case EXTENT_A:
1118          case EXTENT_P:
1119          case EXTENT_I:
1120          case EXTENT_S:
1121             {
1122                if (!extinit) {
1123                   THD_dset_extent(dset, '-', RL_AP_IS);
1124                   extinit = 1;
1125                }
1126                fprintf(stdout,"%f", RL_AP_IS[sing[iis]-EXTENT_R]);
1127             }
1128             break;
1129 
1130          case ADJ:
1131             fprintf(stdout,"%f", fabs(DSET_DY(dset)));
1132             break;
1133          case ADK:
1134             fprintf(stdout,"%f", fabs(DSET_DZ(dset)));
1135             break;
1136          case VOXVOL:
1137             fprintf(stdout,"%f", fabs(DSET_DX(dset))*
1138                                  fabs(DSET_DY(dset))*fabs(DSET_DZ(dset)));
1139             break;
1140          case INAME:
1141             fprintf(stdout,"%s", argv[iarg]);
1142             break;
1143          case LTABLE:
1144             {
1145                char *str;
1146                if ((str = Dtable_to_nimlstring(DSET_Label_Dtable(dset),                                                          "VALUE_LABEL_DTABLE"))) {
1147                   fprintf(stdout,"%s", str);
1148                   free(str);
1149                } else {
1150                   fprintf(stdout,"NO_LABEL_TABLE");
1151                }
1152             }
1153             break;
1154          case LTABLE_AS_ATLAS_POINT_LIST:
1155             {
1156                ATLAS_POINT_LIST *apl=NULL;
1157                if ((apl =
1158                      label_table_to_atlas_point_list(DSET_Label_Dtable(dset)))) {
1159                   atlas_list_to_niml(apl,NULL);
1160                   free_atlas_point_list(apl);
1161                } else {
1162                   fprintf(stdout,"NO_LABEL_TABLE");
1163                }
1164             }
1165             break;
1166          case  ATLAS_POINTS:
1167             {
1168                ATR_string *atr =
1169                   THD_find_string_atr( dset->dblk, "ATLAS_LABEL_TABLE");
1170                if (atr) {
1171                   fprintf(stdout,"%s", atr->ch);
1172                }  else {
1173                   fprintf(stdout,"NO_APL");
1174                }
1175             }
1176             break;
1177          case FAC:
1178             {
1179                for (isb=0; isb<DSET_NVALS(dset); ++isb) {
1180                   fprintf(stdout,"%f%s",
1181                         DSET_BRICK_FACTOR(dset,isb),
1182                         (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
1183                }
1184                break;
1185             }
1186          case DATUM:
1187             {
1188                for (isb=0; isb<DSET_NVALS(dset); ++isb) {
1189                   fprintf(stdout,"%s%s",
1190                         MRI_TYPE_name[DSET_BRICK_TYPE(dset,isb)],
1191                         (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
1192                }
1193                break;
1194             }
1195          case LABEL:
1196             {
1197                for (isb=0; isb<DSET_NVALS(dset); ++isb) {
1198                   fprintf(stdout,"%s%s",
1199                DSET_BRICK_LABEL(dset,isb) ? DSET_BRICK_LABEL(dset,isb):NAflag,
1200                         (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
1201                }
1202                break;
1203             }
1204          case MIN:
1205          case MINUS:
1206          case MAX:
1207          case MAXUS:
1208             {
1209                float vv=0.0, min, max;
1210                for (isb=0; isb<DSET_NVALS(dset); ++isb) {
1211                   if (!THD_subbrick_minmax(dset, isb,
1212                         (sing[iis] == MINUS || sing[iis] == MAXUS) ? 0:1,
1213                         &min, &max)) {
1214                      fprintf(stdout,"%s%s",
1215                         NAflag,
1216                         (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
1217                   } else {
1218                           if (sing[iis] == MINUS)
1219                         vv = min;
1220                      else if (sing[iis] == MAXUS)
1221                         vv = max;
1222                      else if (sing[iis] == MIN)
1223                         vv = min;
1224                      else if (sing[iis] == MAX)
1225                         vv = max;
1226                      fprintf(stdout,"%g%s",
1227                         vv,
1228                         (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
1229                   }
1230                }
1231                break;
1232             }
1233          case DMIN:
1234          case DMINUS:
1235          case DMAX:
1236          case DMAXUS:
1237             {
1238                float vv=0.0, min, max;
1239                if (!THD_dset_minmax(dset,
1240                      (sing[iis] == DMINUS || sing[iis] == DMAXUS) ? 0:1,
1241                      &min, &max)) {
1242                   fprintf(stdout,"%s%s",
1243                      NAflag,
1244                      (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
1245                } else {
1246                        if (sing[iis] == DMINUS)
1247                      vv = min;
1248                   else if (sing[iis] == DMAXUS)
1249                      vv = max;
1250                   else if (sing[iis] == DMIN)
1251                      vv = min;
1252                   else if (sing[iis] == DMAX)
1253                      vv = max;
1254                   fprintf(stdout,"%g%s",
1255                      vv,
1256                      (isb == (DSET_NVALS(dset)-1)) ? "" : sbdelim);
1257                }
1258                break;
1259             }
1260          case TR:
1261 #if 0
1262             fprintf(stdout,"%f", DSET_TR_SEC(dset));
1263 #else
1264             fprintf(stdout,"%f", DSET_TR(dset));
1265 #endif
1266             break;
1267          case ORIENT:
1268             {
1269                /* fprintf(stdout,"%c%c%c",
1270                 *         ORIENT_typestr[dset->daxes->xxorient][0], ... ); */
1271                char ostr[4];    /* just to show        23 Jan 2013 [rickr] */
1272                THD_fill_orient_str_3(dset->daxes, ostr);
1273                fprintf(stdout,"%3s", ostr);
1274             }
1275             break;
1276          case SAME_GRID:
1277             fprintf(stdout,"%d",
1278                !THD_dataset_mismatch( dset , dsetp ));
1279             break;
1280          case SAME_DIM:
1281             fprintf(stdout,"%d",
1282                !(THD_dataset_mismatch( dset , dsetp ) & MISMATCH_DIMEN));
1283             break;
1284          case SAME_DELTA:
1285             fprintf(stdout,"%d",
1286                !(THD_dataset_mismatch( dset , dsetp ) & MISMATCH_DELTA));
1287             break;
1288          case SAME_ORIENT:
1289             fprintf(stdout,"%d",
1290                !(THD_dataset_mismatch( dset , dsetp ) & MISMATCH_ORIENT));
1291             break;
1292          case SAME_CENTER:
1293             fprintf(stdout,"%d",
1294                !(THD_dataset_mismatch( dset , dsetp ) & MISMATCH_CENTER));
1295             break;
1296          case SAME_OBL:
1297             fprintf(stdout,"%d",
1298                !(THD_dataset_mismatch( dset , dsetp ) & MISMATCH_OBLIQ));
1299             break;
1300          case SLICE_TIMING:     /* 6 May 2013 [rickr] */
1301             {
1302                if( DSET_HAS_SLICE_TIMING(dset) ) {
1303                   DSET_UNMSEC(dset); /* make sure times are in seconds */
1304                   for (isb=0; isb<dset->taxis->nsl; ++isb) {
1305                      fprintf(stdout,"%s%f",
1306                            (isb > 0) ? sbdelim : "",
1307                            dset->taxis->toff_sl[isb]);
1308                   }
1309                } else { /* all slices times are at t=0.0 */
1310                   for (isb=0; isb<DSET_NZ(dset); ++isb) {
1311                      fprintf(stdout,"%s%f", (isb > 0) ? sbdelim : "", 0.0);
1312                   }
1313                }
1314             }
1315             break;
1316          case SVAL_DIFF:
1317             fprintf(stdout,"%f",THD_diff_vol_vals(dset, dsetp, 1));
1318             break;
1319          case VAL_DIFF:
1320             fprintf(stdout,"%f",THD_diff_vol_vals(dset, dsetp, 0));
1321             break;
1322          case ID:
1323             fprintf(stdout,"%s", DSET_IDCODE_STR(dset));
1324             break;
1325          case SMODE:
1326             fprintf(stdout,"%s", DSET_STORAGE_MODE_STR(dset));
1327             break;
1328          default:
1329             ERROR_message("Info field not set properly (%d)\n", sing[iis]);
1330             exit(1);
1331         }
1332         if (sing[iis] != CLASSIC) {
1333          SPIT_DELIM(iis, N_sing, atrdelim);
1334         }
1335       }
1336    }
1337 
1338    if( classic_labelName ) free(classic_labelName);
1339 
1340    exit(0) ;
1341 }
1342 
1343 /* validate Field_Names against INFO_FIELDS enum    [26 Jul 2021 rickr] */
validate_field_struct(int verb)1344 int validate_field_struct(int verb)
1345 {
1346    INFO_FIELDS   nfields = N_FIELDS;
1347    int           nfcount=-1, nfsize=-1, mismatch;
1348 
1349    ENTRY("validate_field_struct");
1350 
1351    /* only validate and warn in verbose mode, which defaults to -1 */
1352    if( verb < 0 )
1353       RETURN(0);
1354 
1355    /* compute nf by size, given that these are 32 char strings */
1356    /* (subtract 1 for the final empty string)                  */
1357    nfsize = (int)(sizeof(Field_Names)/sizeof(char[32])) - 1;
1358 
1359 
1360    for( nfcount = 0; Field_Names[nfcount][0]; nfcount++ )
1361       ;
1362 
1363    /* note mismatch before continuing */
1364    mismatch = nfields != nfcount || nfields != nfsize;
1365 
1366    /* possibly be verbose */
1367    if ( verb > 0 || mismatch ) {
1368       printf("++ checking INFO_FIELDS against Field_Names\n");
1369       printf("   N_FIELDS     = %d\n", nfields);
1370       printf("   nfcount      = %d\n", nfcount);
1371       printf("   nfsize       = %d\n", nfsize);
1372    }
1373 
1374    if( mismatch ) {
1375       fprintf(stderr,"** warning: INFO_FIELDS/Field_Names mismatch\n");
1376       RETURN(1);
1377    }
1378 
1379    RETURN(0);
1380 }
1381 
1382 /* try to print the index of the specified label */
print_classic_label2index(THD_3dim_dataset * dset,char * labelname)1383 int print_classic_label2index(THD_3dim_dataset * dset, char * labelname)
1384 {
1385    int nval_per;
1386    int foundLabel = 0;
1387    int ival=0;
1388 
1389    ENTRY("print_classic_labels");
1390 
1391    if( ! dset || ! labelname ) {
1392       ERROR_message("classic label2index: missing dset or label");
1393       RETURN(1);
1394    }
1395 
1396    nval_per = DSET_NVALS(dset);
1397 
1398    for (ival=0 ; ival < nval_per && !foundLabel; ival++ ) {
1399       if (strcmp(DSET_BRICK_LAB(dset,ival), labelname) == 0) {
1400          printf("%d\n", ival); foundLabel = 1;
1401       }
1402    }
1403    if (!foundLabel) printf("\n");
1404 
1405    RETURN(0);
1406 }
1407 
1408 /* try to print the index of the specified label */
print_classic_info(THD_3dim_dataset * dset,char * dname,int verb)1409 int print_classic_info(THD_3dim_dataset * dset, char * dname, int verb)
1410 {
1411    char * outbuf;
1412    ENTRY("print_classic_info");
1413 
1414    outbuf = THD_dataset_info( dset , verb ) ;
1415    if( outbuf != NULL ){
1416       printf("\n") ;
1417       puts(outbuf) ;
1418       free(outbuf) ; outbuf = NULL ;
1419       RETURN(0);
1420    } else {
1421       ERROR_message("Can't get info for dataset %s", dname);
1422       RETURN(1);
1423    }
1424 }
1425 
1426