1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2 * Copyright by The HDF Group. *
3 * Copyright by the Board of Trustees of the University of Illinois. *
4 * All rights reserved. *
5 * *
6 * This file is part of HDF5. The full HDF5 copyright notice, including *
7 * terms governing use, modification, and redistribution, is contained in *
8 * the COPYING file, which can be found at the root of the source code *
9 * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
10 * If you do not have access to either file, you may request a copy from *
11 * help@hdfgroup.org. *
12 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13
14 #include "H5private.h"
15 #include "h5diff.h"
16 #include "h5diff_common.h"
17 #include "h5tools.h"
18 #include "h5tools_utils.h"
19
20 static int check_n_input(const char*);
21 static int check_p_input(const char*);
22 static int check_d_input(const char*);
23
24 /*
25 * Command-line options: The user can specify short or long-named
26 * parameters.
27 */
28 static const char *s_opts = "hVrv:qn:d:p:NcelxE:S";
29 static struct long_options l_opts[] = {
30 { "help", no_arg, 'h' },
31 { "version", no_arg, 'V' },
32 { "report", no_arg, 'r' },
33 { "verbose", optional_arg, 'v' },
34 { "quiet", no_arg, 'q' },
35 { "count", require_arg, 'n' },
36 { "delta", require_arg, 'd' },
37 { "relative", require_arg, 'p' },
38 { "nan", no_arg, 'N' },
39 { "compare", no_arg, 'c' },
40 { "use-system-epsilon", no_arg, 'e' },
41 { "follow-symlinks", no_arg, 'l' },
42 { "no-dangling-links", no_arg, 'x' },
43 { "exclude-path", require_arg, 'E' },
44 { "enable-error-stack", no_arg, 'S' },
45 { NULL, 0, '\0' }
46 };
47
48 /*-------------------------------------------------------------------------
49 * Function: check_options
50 *
51 * Purpose: parse command line input
52 *
53 *-------------------------------------------------------------------------
54 */
check_options(diff_opt_t * opts)55 static void check_options(diff_opt_t* opts)
56 {
57 /*--------------------------------------------------------------
58 * check for mutually exclusive options
59 *--------------------------------------------------------------*/
60
61 /* check between -d , -p, --use-system-epsilon.
62 * These options are mutually exclusive.
63 */
64 if ((opts->d + opts->p + opts->use_system_epsilon) > 1) {
65 printf("%s error: -d, -p and --use-system-epsilon options are mutually-exclusive;\n", PROGRAMNAME);
66 printf("use no more than one.\n");
67 printf("Try '-h' or '--help' option for more information or see the %s entry in the 'HDF5 Reference Manual'.\n", PROGRAMNAME);
68 h5diff_exit(EXIT_FAILURE);
69 }
70 }
71
72
73 /*-------------------------------------------------------------------------
74 * Function: parse_command_line
75 *
76 * Purpose: parse command line input
77 *
78 *-------------------------------------------------------------------------
79 */
80
parse_command_line(int argc,const char * argv[],const char ** fname1,const char ** fname2,const char ** objname1,const char ** objname2,diff_opt_t * opts)81 void parse_command_line(int argc,
82 const char* argv[],
83 const char** fname1,
84 const char** fname2,
85 const char** objname1,
86 const char** objname2,
87 diff_opt_t* opts)
88 {
89 int i;
90 int opt;
91 struct exclude_path_list *exclude_head, *exclude_prev, *exclude_node;
92
93 /* process the command-line */
94 memset(opts, 0, sizeof (diff_opt_t));
95
96 /* assume equal contents initially */
97 opts->contents = 1;
98
99 /* NaNs are handled by default */
100 opts->do_nans = 1;
101
102 /* not Listing objects that are not comparable */
103 opts->m_list_not_cmp = 0;
104
105 /* initially no not-comparable. */
106 /**this is bad in mixing option with results**/
107 opts->not_cmp=0;
108
109 /* init for exclude-path option */
110 exclude_head = NULL;
111
112 /* parse command line options */
113 while ((opt = get_option(argc, argv, s_opts, l_opts)) != EOF) {
114 switch ((char)opt) {
115 default:
116 usage();
117 h5diff_exit(EXIT_FAILURE);
118 break;
119
120 case 'h':
121 usage();
122 h5diff_exit(EXIT_SUCCESS);
123 break;
124
125 case 'V':
126 print_version(h5tools_getprogname());
127 h5diff_exit(EXIT_SUCCESS);
128 break;
129
130 case 'v':
131 opts->m_verbose = 1;
132 /* This for loop is for handling style like
133 * -v, -v1, --verbose, --verbose=1.
134 */
135 for (i = 1; i < argc; i++) {
136 /*
137 * short opt
138 */
139 if (!strcmp (argv[i], "-v")) { /* no arg */
140 opt_ind--;
141 opts->m_verbose_level = 0;
142 break;
143 }
144 else if (!strncmp (argv[i], "-v", (size_t)2)) {
145 opts->m_verbose_level = atoi(&argv[i][2]);
146 break;
147 }
148
149 /*
150 * long opt
151 */
152 if (!strcmp (argv[i], "--verbose")) { /* no arg */
153 opts->m_verbose_level = 0;
154 break;
155 }
156 else if ( !strncmp (argv[i], "--verbose", (size_t)9) && argv[i][9]=='=') {
157 opts->m_verbose_level = atoi(&argv[i][10]);
158 break;
159 }
160 }
161 break;
162
163 case 'q':
164 /* use quiet mode; supress the message "0 differences found" */
165 opts->m_quiet = 1;
166 break;
167
168 case 'r':
169 opts->m_report = 1;
170 break;
171
172 case 'l':
173 opts->follow_links = TRUE;
174 break;
175
176 case 'x':
177 opts->no_dangle_links = 1;
178 break;
179
180 case 'S':
181 enable_error_stack = 1;
182 break;
183
184 case 'E':
185 opts->exclude_path = 1;
186
187 /* create linked list of excluding objects */
188 if( (exclude_node = (struct exclude_path_list*) HDmalloc(sizeof(struct exclude_path_list))) == NULL) {
189 printf("Error: lack of memory!\n");
190 h5diff_exit(EXIT_FAILURE);
191 }
192
193 /* init */
194 exclude_node->obj_path = (char*)opt_arg;
195 exclude_node->obj_type = H5TRAV_TYPE_UNKNOWN;
196 exclude_prev = exclude_head;
197
198 if (NULL == exclude_head) {
199 exclude_head = exclude_node;
200 exclude_head->next = NULL;
201 }
202 else {
203 while(NULL != exclude_prev->next)
204 exclude_prev=exclude_prev->next;
205
206 exclude_node->next = NULL;
207 exclude_prev->next = exclude_node;
208 }
209 break;
210
211 case 'd':
212 opts->d=1;
213
214 if (check_d_input(opt_arg) == - 1) {
215 printf("<-d %s> is not a valid option\n", opt_arg);
216 usage();
217 h5diff_exit(EXIT_FAILURE);
218 }
219 opts->delta = atof(opt_arg);
220
221 /* -d 0 is the same as default */
222 if (H5_DBL_ABS_EQUAL(opts->delta, (double)0.0F))
223 opts->d=0;
224 break;
225
226 case 'p':
227 opts->p=1;
228 if (check_p_input(opt_arg) == -1) {
229 printf("<-p %s> is not a valid option\n", opt_arg);
230 usage();
231 h5diff_exit(EXIT_FAILURE);
232 }
233 opts->percent = atof(opt_arg);
234
235 /* -p 0 is the same as default */
236 if (H5_DBL_ABS_EQUAL(opts->percent, (double)0.0F))
237 opts->p = 0;
238 break;
239
240 case 'n':
241 opts->n=1;
242 if ( check_n_input(opt_arg) == -1) {
243 printf("<-n %s> is not a valid option\n", opt_arg);
244 usage();
245 h5diff_exit(EXIT_FAILURE);
246 }
247 opts->count = HDstrtoull(opt_arg, NULL, 0);
248 break;
249
250 case 'N':
251 opts->do_nans = 0;
252 break;
253
254 case 'c':
255 opts->m_list_not_cmp = 1;
256 break;
257
258 case 'e':
259 opts->use_system_epsilon = 1;
260 break;
261 }
262 }
263
264 /* check options */
265 check_options(opts);
266
267 /* if exclude-path option is used, keep the exclude path list */
268 if (opts->exclude_path)
269 opts->exclude = exclude_head;
270
271 /* check for file names to be processed */
272 if (argc <= opt_ind || argv[ opt_ind + 1 ] == NULL) {
273 error_msg("missing file names\n");
274 usage();
275 h5diff_exit(EXIT_FAILURE);
276 }
277
278 *fname1 = argv[ opt_ind ];
279 *fname2 = argv[ opt_ind + 1 ];
280 *objname1 = argv[ opt_ind + 2 ];
281
282 if (*objname1 == NULL) {
283 *objname2 = NULL;
284 return;
285 }
286
287 if (argv[ opt_ind + 3 ] != NULL) {
288 *objname2 = argv[ opt_ind + 3 ];
289 }
290 else {
291 *objname2 = *objname1;
292 }
293
294
295 }
296
297
298 /*-------------------------------------------------------------------------
299 * Function: print_info
300 *
301 * Purpose: print several information messages after h5diff call
302 *
303 *-------------------------------------------------------------------------
304 */
305
print_info(diff_opt_t * opts)306 void print_info(diff_opt_t* opts)
307 {
308 if (opts->m_quiet || opts->err_stat)
309 return;
310
311 if (opts->cmn_objs == 0) {
312 printf("No common objects found. Files are not comparable.\n");
313 if (!opts->m_verbose)
314 printf("Use -v for a list of objects.\n");
315 }
316
317 if (opts->not_cmp == 1) {
318 if (opts->m_list_not_cmp == 0) {
319 printf("--------------------------------\n");
320 printf("Some objects are not comparable\n");
321 printf("--------------------------------\n");
322 if (opts->m_verbose)
323 printf("Use -c for a list of objects without details of differences.\n");
324 else
325 printf("Use -c for a list of objects.\n");
326 }
327 }
328 }
329
330 /*-------------------------------------------------------------------------
331 * Function: check_n_input
332 *
333 * Purpose: check for valid input
334 *
335 * Return: 1 for ok, -1 for fail
336 *
337 * Programmer: Pedro Vicente, pvn@ncsa.uiuc.edu
338 *
339 * Date: May 9, 2003
340 *
341 * Comments:
342 *
343 * Modifications:
344 *
345 *-------------------------------------------------------------------------
346 */
347 static int
check_n_input(const char * str)348 check_n_input( const char *str )
349 {
350 unsigned i;
351 char c;
352
353 for (i = 0; i < strlen(str); i++) {
354 c = str[i];
355 if (i == 0) {
356 if (c < 49 || c > 57) /* ascii values between 1 and 9 */
357 return -1;
358 }
359 else
360 if (c < 48 || c > 57) /* 0 also */
361 return -1;
362 }
363 return 1;
364 }
365
366 /*-------------------------------------------------------------------------
367 * Function: check_p_input
368 *
369 * Purpose: check for a valid p option input
370 *
371 * Return: 1 for ok, -1 for fail
372 *
373 * Date: May 9, 2003
374 *
375 * Comments:
376 *
377 * Modifications:
378 *
379 *-------------------------------------------------------------------------
380 */
381 static int
check_p_input(const char * str)382 check_p_input( const char *str )
383 {
384 double x;
385
386 /*
387 the atof return value on a hexadecimal input is different
388 on some systems; we do a character check for this
389 */
390 if (strlen(str) > 2 && str[0] == '0' && str[1] == 'x')
391 return -1;
392
393 x = atof(str);
394 if (x < 0)
395 return -1;
396
397 return 1;
398 }
399
400 /*-------------------------------------------------------------------------
401 * Function: check_d_input
402 *
403 * Purpose: check for a valid d option input
404 *
405 * Return: 1 for ok, -1 for fail
406 *
407 * Date: November 11, 2007
408 *
409 * Comments:
410 *
411 * Modifications:
412 *
413 *-------------------------------------------------------------------------
414 */
415 static int
check_d_input(const char * str)416 check_d_input( const char *str )
417 {
418 double x;
419
420 /*
421 the atof return value on a hexadecimal input is different
422 on some systems; we do a character check for this
423 */
424 if (strlen(str) > 2 && str[0] == '0' && str[1] == 'x')
425 return -1;
426
427 x = atof(str);
428 if (x < 0)
429 return -1;
430
431 return 1;
432 }
433
434 /*-------------------------------------------------------------------------
435 * Function: usage
436 *
437 * Purpose: print a usage message
438 *
439 * Return: void
440 *
441 *-------------------------------------------------------------------------
442 */
443
usage(void)444 void usage(void)
445 {
446 PRINTVALSTREAM(rawoutstream, "usage: h5diff [OPTIONS] file1 file2 [obj1[ obj2]]\n");
447 PRINTVALSTREAM(rawoutstream, " file1 File name of the first HDF5 file\n");
448 PRINTVALSTREAM(rawoutstream, " file2 File name of the second HDF5 file\n");
449 PRINTVALSTREAM(rawoutstream, " [obj1] Name of an HDF5 object, in absolute path\n");
450 PRINTVALSTREAM(rawoutstream, " [obj2] Name of an HDF5 object, in absolute path\n");
451 PRINTVALSTREAM(rawoutstream, "\n");
452 PRINTVALSTREAM(rawoutstream, " OPTIONS\n");
453 PRINTVALSTREAM(rawoutstream, " -h, --help\n");
454 PRINTVALSTREAM(rawoutstream, " Print a usage message and exit.\n");
455 PRINTVALSTREAM(rawoutstream, " -V, --version\n");
456 PRINTVALSTREAM(rawoutstream, " Print version number and exit.\n");
457 PRINTVALSTREAM(rawoutstream, " -r, --report\n");
458 PRINTVALSTREAM(rawoutstream, " Report mode. Print differences.\n");
459 PRINTVALSTREAM(rawoutstream, " -v --verbose\n");
460 PRINTVALSTREAM(rawoutstream, " Verbose mode. Print differences information and list of objects.\n");
461 PRINTVALSTREAM(rawoutstream, " -vN --verbose=N\n");
462 PRINTVALSTREAM(rawoutstream, " Verbose mode with level. Print differences and list of objects.\n");
463 PRINTVALSTREAM(rawoutstream, " Level of detail depends on value of N:\n");
464 PRINTVALSTREAM(rawoutstream, " 0 : Identical to '-v' or '--verbose'.\n");
465 PRINTVALSTREAM(rawoutstream, " 1 : All level 0 information plus one-line attribute\n");
466 PRINTVALSTREAM(rawoutstream, " status summary.\n");
467 PRINTVALSTREAM(rawoutstream, " 2 : All level 1 information plus extended attribute\n");
468 PRINTVALSTREAM(rawoutstream, " status report.\n");
469 PRINTVALSTREAM(rawoutstream, " -q, --quiet\n");
470 PRINTVALSTREAM(rawoutstream, " Quiet mode. Do not produce output.\n");
471 PRINTVALSTREAM(rawoutstream, " --enable-error-stack\n");
472 PRINTVALSTREAM(rawoutstream, " Prints messages from the HDF5 error stack as they occur.\n");
473 PRINTVALSTREAM(rawoutstream, " --follow-symlinks\n");
474 PRINTVALSTREAM(rawoutstream, " Follow symbolic links (soft links and external links and compare the)\n");
475 PRINTVALSTREAM(rawoutstream, " links' target objects.\n");
476 PRINTVALSTREAM(rawoutstream, " If symbolic link(s) with the same name exist in the files being\n");
477 PRINTVALSTREAM(rawoutstream, " compared, then determine whether the target of each link is an existing\n");
478 PRINTVALSTREAM(rawoutstream, " object (dataset, group, or named datatype) or the link is a dangling\n");
479 PRINTVALSTREAM(rawoutstream, " link (a soft or external link pointing to a target object that does\n");
480 PRINTVALSTREAM(rawoutstream, " not yet exist).\n");
481 PRINTVALSTREAM(rawoutstream, " - If both symbolic links are dangling links, they are treated as being\n");
482 PRINTVALSTREAM(rawoutstream, " the same; by default, h5diff returns an exit code of 0.\n");
483 PRINTVALSTREAM(rawoutstream, " If, however, --no-dangling-links is used with --follow-symlinks,\n");
484 PRINTVALSTREAM(rawoutstream, " this situation is treated as an error and h5diff returns an\n");
485 PRINTVALSTREAM(rawoutstream, " exit code of 2.\n");
486 PRINTVALSTREAM(rawoutstream, " - If only one of the two links is a dangling link,they are treated as\n");
487 PRINTVALSTREAM(rawoutstream, " being different and h5diff returns an exit code of 1.\n");
488 PRINTVALSTREAM(rawoutstream, " If, however, --no-dangling-links is used with --follow-symlinks,\n");
489 PRINTVALSTREAM(rawoutstream, " this situation is treated as an error and h5diff returns an\n");
490 PRINTVALSTREAM(rawoutstream, " exit code of 2.\n");
491 PRINTVALSTREAM(rawoutstream, " - If both symbolic links point to existing objects, h5diff compares the\n");
492 PRINTVALSTREAM(rawoutstream, " two objects.\n");
493 PRINTVALSTREAM(rawoutstream, " If any symbolic link specified in the call to h5diff does not exist,\n");
494 PRINTVALSTREAM(rawoutstream, " h5diff treats it as an error and returns an exit code of 2.\n");
495 PRINTVALSTREAM(rawoutstream, " --no-dangling-links\n");
496 PRINTVALSTREAM(rawoutstream, " Must be used with --follow-symlinks option; otherwise, h5diff shows\n");
497 PRINTVALSTREAM(rawoutstream, " error message and returns an exit code of 2.\n");
498 PRINTVALSTREAM(rawoutstream, " Check for any symbolic links (soft links or external links) that do not\n");
499 PRINTVALSTREAM(rawoutstream, " resolve to an existing object (dataset, group, or named datatype).\n");
500 PRINTVALSTREAM(rawoutstream, " If any dangling link is found, this situation is treated as an error\n");
501 PRINTVALSTREAM(rawoutstream, " and h5diff returns an exit code of 2.\n");
502 PRINTVALSTREAM(rawoutstream, " -c, --compare\n");
503 PRINTVALSTREAM(rawoutstream, " List objects that are not comparable\n");
504 PRINTVALSTREAM(rawoutstream, " -N, --nan\n");
505 PRINTVALSTREAM(rawoutstream, " Avoid NaNs detection\n");
506 PRINTVALSTREAM(rawoutstream, " -n C, --count=C\n");
507 PRINTVALSTREAM(rawoutstream, " Print differences up to C. C must be a positive integer.\n");
508 PRINTVALSTREAM(rawoutstream, " -d D, --delta=D\n");
509 PRINTVALSTREAM(rawoutstream, " Print difference if (|a-b| > D). D must be a positive number. Where a\n");
510 PRINTVALSTREAM(rawoutstream, " is the data point value in file1 and b is the data point value in file2.\n");
511 PRINTVALSTREAM(rawoutstream, " Can not use with '-p' or '--use-system-epsilon'.\n");
512 PRINTVALSTREAM(rawoutstream, " -p R, --relative=R\n");
513 PRINTVALSTREAM(rawoutstream, " Print difference if (|(a-b)/b| > R). R must be a positive number. Where a\n");
514 PRINTVALSTREAM(rawoutstream, " is the data point value in file1 and b is the data point value in file2.\n");
515 PRINTVALSTREAM(rawoutstream, " Can not use with '-d' or '--use-system-epsilon'.\n");
516 PRINTVALSTREAM(rawoutstream, " --use-system-epsilon\n");
517 PRINTVALSTREAM(rawoutstream, " Print difference if (|a-b| > EPSILON), EPSILON is system defined value. Where a\n");
518 PRINTVALSTREAM(rawoutstream, " is the data point value in file1 and b is the data point value in file2.\n");
519 PRINTVALSTREAM(rawoutstream, " If the system epsilon is not defined,one of the following predefined\n");
520 PRINTVALSTREAM(rawoutstream, " values will be used:\n");
521 PRINTVALSTREAM(rawoutstream, " FLT_EPSILON = 1.19209E-07 for floating-point type\n");
522 PRINTVALSTREAM(rawoutstream, " DBL_EPSILON = 2.22045E-16 for double precision type\n");
523 PRINTVALSTREAM(rawoutstream, " Can not use with '-p' or '-d'.\n");
524 PRINTVALSTREAM(rawoutstream, " --exclude-path \"path\"\n");
525 PRINTVALSTREAM(rawoutstream, " Exclude the specified path to an object when comparing files or groups.\n");
526 PRINTVALSTREAM(rawoutstream, " If a group is excluded, all member objects will also be excluded.\n");
527 PRINTVALSTREAM(rawoutstream, " The specified path is excluded wherever it occurs.\n");
528 PRINTVALSTREAM(rawoutstream, " This flexibility enables the same option to exclude either objects that\n");
529 PRINTVALSTREAM(rawoutstream, " exist only in one file or common objects that are known to differ.\n");
530 PRINTVALSTREAM(rawoutstream, "\n");
531 PRINTVALSTREAM(rawoutstream, " When comparing files, \"path\" is the absolute path to the excluded;\n");
532 PRINTVALSTREAM(rawoutstream, " object; when comparing groups, \"path\" is similar to the relative\n");
533 PRINTVALSTREAM(rawoutstream, " path from the group to the excluded object. This \"path\" can be\n");
534 PRINTVALSTREAM(rawoutstream, " taken from the first section of the output of the --verbose option.\n");
535 PRINTVALSTREAM(rawoutstream, " For example, if you are comparing the group /groupA in two files and\n");
536 PRINTVALSTREAM(rawoutstream, " you want to exclude /groupA/groupB/groupC in both files, the exclude\n");
537 PRINTVALSTREAM(rawoutstream, " option would read as follows:\n");
538 PRINTVALSTREAM(rawoutstream, " --exclude-path \"/groupB/groupC\"\n");
539 PRINTVALSTREAM(rawoutstream, "\n");
540 PRINTVALSTREAM(rawoutstream, " If there are multiple paths to an object, only the specified path(s)\n");
541 PRINTVALSTREAM(rawoutstream, " will be excluded; the comparison will include any path not explicitly\n");
542 PRINTVALSTREAM(rawoutstream, " excluded.\n");
543 PRINTVALSTREAM(rawoutstream, " This option can be used repeatedly to exclude multiple paths.\n");
544 PRINTVALSTREAM(rawoutstream, "\n");
545
546 PRINTVALSTREAM(rawoutstream, " Modes of output:\n");
547 PRINTVALSTREAM(rawoutstream, " Default mode: print the number of differences found and where they occured\n");
548 PRINTVALSTREAM(rawoutstream, " -r Report mode: print the above plus the differences\n");
549 PRINTVALSTREAM(rawoutstream, " -v Verbose mode: print the above plus a list of objects and warnings\n");
550 PRINTVALSTREAM(rawoutstream, " -q Quiet mode: do not print output\n");
551
552 PRINTVALSTREAM(rawoutstream, "\n");
553
554 PRINTVALSTREAM(rawoutstream, " File comparison:\n");
555 PRINTVALSTREAM(rawoutstream, " If no objects [obj1[ obj2]] are specified, the h5diff comparison proceeds as\n");
556 PRINTVALSTREAM(rawoutstream, " a comparison of the two files' root groups. That is, h5diff first compares\n");
557 PRINTVALSTREAM(rawoutstream, " the names of root group members, generates a report of root group objects\n");
558 PRINTVALSTREAM(rawoutstream, " that appear in only one file or in both files, and recursively compares\n");
559 PRINTVALSTREAM(rawoutstream, " common objects.\n");
560 PRINTVALSTREAM(rawoutstream, "\n");
561
562 PRINTVALSTREAM(rawoutstream, " Object comparison:\n");
563 PRINTVALSTREAM(rawoutstream, " 1) Groups\n");
564 PRINTVALSTREAM(rawoutstream, " First compares the names of member objects (relative path, from the\n");
565 PRINTVALSTREAM(rawoutstream, " specified group) and generates a report of objects that appear in only\n");
566 PRINTVALSTREAM(rawoutstream, " one group or in both groups. Common objects are then compared recursively.\n");
567 PRINTVALSTREAM(rawoutstream, " 2) Datasets\n");
568 PRINTVALSTREAM(rawoutstream, " Array rank and dimensions, datatypes, and data values are compared.\n");
569 PRINTVALSTREAM(rawoutstream, " 3) Datatypes\n");
570 PRINTVALSTREAM(rawoutstream, " The comparison is based on the return value of H5Tequal.\n");
571 PRINTVALSTREAM(rawoutstream, " 4) Symbolic links\n");
572 PRINTVALSTREAM(rawoutstream, " The paths to the target objects are compared.\n");
573 PRINTVALSTREAM(rawoutstream, " (The option --follow-symlinks overrides the default behavior when\n");
574 PRINTVALSTREAM(rawoutstream, " symbolic links are compared.).\n");
575 PRINTVALSTREAM(rawoutstream, "\n");
576
577 PRINTVALSTREAM(rawoutstream, " Exit code:\n");
578 PRINTVALSTREAM(rawoutstream, " 0 if no differences, 1 if differences found, 2 if error\n");
579 PRINTVALSTREAM(rawoutstream, "\n");
580 PRINTVALSTREAM(rawoutstream, " Examples of use:\n");
581 PRINTVALSTREAM(rawoutstream, " 1) h5diff file1 file2 /g1/dset1 /g1/dset2\n");
582 PRINTVALSTREAM(rawoutstream, " Compares object '/g1/dset1' in file1 with '/g1/dset2' in file2\n");
583 PRINTVALSTREAM(rawoutstream, "\n");
584 PRINTVALSTREAM(rawoutstream, " 2) h5diff file1 file2 /g1/dset1\n");
585 PRINTVALSTREAM(rawoutstream, " Compares object '/g1/dset1' in both files\n");
586 PRINTVALSTREAM(rawoutstream, "\n");
587 PRINTVALSTREAM(rawoutstream, " 3) h5diff file1 file2\n");
588 PRINTVALSTREAM(rawoutstream, " Compares all objects in both files\n");
589 PRINTVALSTREAM(rawoutstream, "\n");
590 PRINTVALSTREAM(rawoutstream, " Notes:\n");
591 PRINTVALSTREAM(rawoutstream, " file1 and file2 can be the same file.\n");
592 PRINTVALSTREAM(rawoutstream, " Use h5diff file1 file1 /g1/dset1 /g1/dset2 to compare\n");
593 PRINTVALSTREAM(rawoutstream, " '/g1/dset1' and '/g1/dset2' in the same file\n");
594 PRINTVALSTREAM(rawoutstream, "\n");
595 }
596