1 /*============================================================================
2 * Dump of Kernel I/O file for Code_Saturne
3 *============================================================================*/
4
5 /*
6 This file is part of Code_Saturne, a general-purpose CFD tool.
7
8 Copyright (C) 1998-2021 EDF S.A.
9
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
18 details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
22 Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 */
24
25 /*----------------------------------------------------------------------------*/
26
27 #define CS_IGNORE_MPI 1 /* No MPI for this application */
28
29 #include "cs_defs.h"
30
31 /*
32 Force LARGEFILE_SOURCE if large files enabled under 32-bit Linux or Blue Gene
33 (otherwise, we may encounter bugs with glibc 2.3 due to fseeko end ftello
34 not being correctly defined). Compiling with -D_GNU_SOURCE instead
35 of -D_POSIX_C_SOURCE=200112L seems to be another way to solve the problem.
36 */
37
38 #if (SIZEOF_LONG < 8) && (_FILE_OFFSET_BITS == 64)
39 # if defined(__linux__)
40 # if !defined(_POSIX_SOURCE)
41 # define _GNU_SOURCE 1
42 # endif
43 # if !defined(_GNU_SOURCE) && !defined(_LARGEFILE_SOURCE)
44 # define _LARGEFILE_SOURCE 1
45 # endif
46 # endif
47 #endif
48
49 /*----------------------------------------------------------------------------
50 * Standard C library headers
51 *----------------------------------------------------------------------------*/
52
53 #include <assert.h>
54 #include <errno.h>
55 #include <locale.h>
56 #include <stdarg.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60
61 /*----------------------------------------------------------------------------
62 * Local headers
63 *----------------------------------------------------------------------------*/
64
65 /*---------------------------------------------------------------------------*/
66
67 BEGIN_C_DECLS
68
69 /*! \cond DOXYGEN_SHOULD_SKIP_THIS */
70
71 /*============================================================================
72 * Local Type Definitions
73 *============================================================================*/
74
75 /* Structure used to index cs_io_file contents when reading */
76 /*----------------------------------------------------------*/
77
78 typedef struct {
79
80 size_t size; /* Current number of entries */
81 size_t max_size; /* Maximum number of entries */
82
83 /* For each entry, we need 8 values, which we store in h_vals :
84 * 0: number of values in section
85 * 1: location_id
86 * 2: index id
87 * 3: number of values per location
88 * 4: index of section name in names array
89 * 5: index of type name in types array
90 * 6: index of embedded data in data array + 1 if data is
91 * embedded, 0 otherwise
92 * 7: associated file id (in case of multiple files)
93 */
94
95 long long *h_vals; /* Base values associated
96 with each header */
97
98 long long *offset; /* Position of associated data
99 in file (-1 if embedded) */
100
101 size_t max_names_size; /* Maximum size of names array */
102 size_t names_size; /* Current size of names array */
103 char *names; /* Array containing section names */
104
105 size_t max_types_size; /* Maximum size of type names array */
106 size_t types_size; /* Current size of type names array */
107 char *types; /* Array containing section type names */
108
109 size_t max_data_size; /* Maximum size of embedded data array */
110 size_t data_size; /* Current size of data array */
111
112 unsigned char *data; /* Array containing embedded data */
113
114 } _cs_io_sec_index_t;
115
116 /* Main kernel IO state structure */
117 /*--------------------------------*/
118
119 /* File descriptor */
120
121 typedef struct {
122
123 const char *filename; /* File name */
124 FILE *f; /* File handle */
125
126 size_t header_size; /* Header default size */
127 size_t header_align; /* Header alignment */
128 size_t body_align; /* Body alignment */
129
130 size_t buffer_size; /* Current size of header buffer */
131 unsigned char *buffer; /* Header buffer */
132
133 size_t n_vals; /* Number of values in section header */
134 size_t location_id; /* Optional value location id (0 for none) */
135 size_t index_id; /* Optional index id (0 for none) */
136 size_t n_loc_vals; /* Optional, number of values per location */
137 size_t type_size; /* Size of current type */
138 const char *name; /* Pointer to name field in section header */
139 const char *type_name; /* Pointer to type field in section header */
140 void *data; /* Pointer to data in section header */
141
142 long long offset; /* Current position in file */
143 int swap_endian; /* Swap big-endian and little-endian ? */
144
145 _cs_io_sec_index_t *index; /* Optional section index (on read) */
146
147 } _cs_io_t;
148
149 /*============================================================================
150 * Local Macro Definitions
151 *============================================================================*/
152
153 /*
154 * Allocate memory for _ni items of type _type.
155 *
156 * This macro calls _mem_malloc(), automatically setting the
157 * allocated variable name and source file name and line arguments.
158 *
159 * parameters:
160 * _ptr --> pointer to allocated memory.
161 * _ni <-- number of items.
162 * _type <-- element type.
163 */
164
165 #define MEM_MALLOC(_ptr, _ni, _type) \
166 _ptr = (_type *) _mem_malloc(_ni, sizeof(_type), \
167 #_ptr, __FILE__, __LINE__)
168
169 /*
170 * Reallocate memory for _ni items of type _type.
171 *
172 * This macro calls _mem_realloc(), automatically setting the
173 * allocated variable name and source file name and line arguments.
174 *
175 * parameters:
176 * _ptr <-> pointer to allocated memory.
177 * _ni <-- number of items.
178 * _type <-- element type.
179 */
180
181 #define MEM_REALLOC(_ptr, _ni, _type) \
182 _ptr = (_type *) _mem_realloc(_ptr, _ni, sizeof(_type), \
183 #_ptr, __FILE__, __LINE__)
184
185 /*
186 * Free allocated memory.
187 *
188 * The freed pointer is set to NULL to avoid accidental reuse.
189 *
190 * parameters:
191 * _ptr <-> pointer to allocated memory.
192 */
193
194 #define MEM_FREE(_ptr) \
195 free(_ptr), _ptr = NULL
196
197 /*============================================================================
198 * Static global variables
199 *============================================================================*/
200
201 /*============================================================================
202 * Private function definitions
203 *============================================================================*/
204
205 /*----------------------------------------------------------------------------
206 * Print usage and exit.
207 *
208 * parameters:
209 * arg_0 <-- name of executable as given by argv[0]
210 * exit_code <-- EXIT_SUCCESS or EXIT_FAILURE
211 *----------------------------------------------------------------------------*/
212
213 static void
_usage(const char * arg_0,int exit_code)214 _usage(const char *arg_0,
215 int exit_code)
216 {
217 printf
218 (_("\n"
219 "Usage: %s [options] <file_name>\n"
220 " or: %s -d [options] <file_name_1> <file_name_2>\n\n"
221 "Dump headers and optionnaly content of a Code_Saturne Preprocessor,\n"
222 "Partitioner, or restart file, or compare two such files.\n\n"
223 "Options:\n\n"
224 " -d, --diff diff mode.\n\n"
225 " -e, --extract extract mode (extract full section data, with\n"
226 " no metadata).\n\n"
227 " --f-format <fmt> define format for floating-point numbers (default:\n"
228 " \"15.9e\" for floats, \"22.15e\" for doubles).\n"
229 " --location <id> only output section(s) with given location id.\n\n"
230 " -n <level> number of first and last elements of each section\n"
231 " to output (default: print headers only).\n\n"
232 " --section <name> only consider section matching given criteria.\n\n"
233 " --threshold <val> in diff mode, real value above which a difference is\n"
234 " considered significant (default: 1e-30).\n\n"
235 " -h, --help this message.\n\n"),
236 arg_0, arg_0);
237
238 exit(exit_code);
239 }
240
241 /*----------------------------------------------------------------------------
242 * Abort with error message.
243 *
244 * parameters:
245 * file_name <-- name of source file from which function is called.
246 * line_num <-- line of source file from which function is called.
247 * sys_error_code <-- error code if error in system or libc call,
248 * 0 otherwise.
249 * format <-- format string, as printf() and family.
250 * ... <-- variable arguments based on format string.
251 *----------------------------------------------------------------------------*/
252
253 static void
_error(const char * file_name,int line_num,int sys_error_code,const char * format,...)254 _error(const char *file_name,
255 int line_num,
256 int sys_error_code,
257 const char *format,
258 ...)
259 {
260 va_list arg_ptr;
261
262 va_start(arg_ptr, format);
263
264 fflush(stdout);
265
266 fprintf(stderr, "\n");
267
268 if (sys_error_code != 0)
269 fprintf(stderr, _("\nSystem error: %s\n"), strerror(sys_error_code));
270
271 fprintf(stderr, _("\n%s:%d: Fatal error.\n\n"), file_name, line_num);
272
273 vfprintf(stderr, format, arg_ptr);
274
275 fprintf(stderr, "\n\n");
276
277 va_end(arg_ptr);
278
279 assert(0);
280
281 exit(EXIT_FAILURE);
282 }
283
284 /*----------------------------------------------------------------------------
285 * Allocate memory and check result.
286 *
287 * This function simply wraps malloc() and calls _error() if it fails.
288 *
289 * parameters:
290 * ni <-- number of elements.
291 * size <-- element size.
292 * var_name <-- allocated variable name string.
293 * file_name <-- name of calling source file.
294 * line_num <-- line number in calling source file.
295 *
296 * returns:
297 * pointer to allocated memory.
298 *----------------------------------------------------------------------------*/
299
300 static void *
_mem_malloc(size_t ni,size_t size,const char * var_name,const char * file_name,int line_num)301 _mem_malloc(size_t ni,
302 size_t size,
303 const char *var_name,
304 const char *file_name,
305 int line_num)
306 {
307 void *p_ret;
308 size_t alloc_size = ni * size;
309
310 if (ni == 0)
311 return NULL;
312
313 /* Allocate memory and check return */
314
315 p_ret = malloc(alloc_size);
316
317 if (p_ret == NULL)
318 _error(file_name, line_num, errno,
319 _("Failure to allocate \"%s\" (%lu bytes)"),
320 var_name, (unsigned long)alloc_size);
321
322 return p_ret;
323 }
324
325 /*----------------------------------------------------------------------------
326 * Allocate memory and check result.
327 *
328 * This function simply wraps realloc() and calls _error() if it fails.
329 *
330 * parameters:
331 * ptr <-- pointer to previous memory location
332 * ni <-- number of elements.
333 * size <-- element size.
334 * var_name <-- allocated variable name string.
335 * file_name <-- name of calling source file.
336 * line_num <-- line number in calling source file.
337 *
338 * returns:
339 * pointer to reallocated memory.
340 *----------------------------------------------------------------------------*/
341
342 static void *
_mem_realloc(void * ptr,size_t ni,size_t size,const char * var_name,const char * file_name,int line_num)343 _mem_realloc(void *ptr,
344 size_t ni,
345 size_t size,
346 const char *var_name,
347 const char *file_name,
348 int line_num)
349 {
350 void *p_ret;
351
352 size_t realloc_size = ni * size;
353
354 p_ret = realloc(ptr, realloc_size);
355
356 if (size != 0 && p_ret == NULL)
357 _error(file_name, line_num, errno,
358 _("Failure to reallocate \"%s\" (%lu bytes)"),
359 var_name, (unsigned long)realloc_size);
360
361 return p_ret;
362 }
363
364 /*----------------------------------------------------------------------------
365 * Convert data from "little-endian" to "big-endian" or the reverse.
366 *
367 * The memory areas pointed to by src and dest should overlap either
368 * exactly or not at all.
369 *
370 * parameters:
371 * buf <-> pointer to converted data location.
372 * size <-- size of each item of data in bytes.
373 * ni <-- number of data items.
374 *----------------------------------------------------------------------------*/
375
376 static void
_swap_endian(void * buf,size_t size,size_t ni)377 _swap_endian(void *buf,
378 size_t size,
379 size_t ni)
380 {
381 size_t i, ib, shift;
382 unsigned char tmpswap;
383
384 unsigned char *pdest = (unsigned char *)buf;
385 const unsigned char *psrc = (const unsigned char *)buf;
386
387 for (i = 0; i < ni; i++) {
388
389 shift = i * size;
390
391 for (ib = 0; ib < (size / 2); ib++) {
392
393 tmpswap = *(psrc + shift + ib);
394 *(pdest + shift + ib) = *(psrc + shift + (size - 1) - ib);
395 *(pdest + shift + (size - 1) - ib) = tmpswap;
396
397 }
398 }
399 }
400
401 /*----------------------------------------------------------------------------
402 * Read data to a buffer using standard C IO.
403 *
404 * parameters:
405 * buf --> pointer to location receiving data
406 * size <-- size of each item of data in bytes
407 * ni <-- number of items to read
408 * inp <-> input file descriptor
409 *
410 * returns:
411 * the number of items (not bytes) sucessfully read;
412 *----------------------------------------------------------------------------*/
413
414 static size_t
_file_read(void * buf,size_t size,size_t ni,_cs_io_t * inp)415 _file_read(void *buf,
416 size_t size,
417 size_t ni,
418 _cs_io_t *inp)
419 {
420 size_t retval = 0;
421
422 assert(inp->f != NULL);
423
424 if (ni != 0)
425 retval = fread(buf, size, ni, inp->f);
426
427 inp->offset += size*ni;
428
429 /* In case of error, determine error type */
430
431 if (retval != ni) {
432 int err_num = ferror(inp->f);
433 if (err_num != 0)
434 _error(__FILE__, __LINE__, 0,
435 _("Error reading file \"%s\":\n\n %s"),
436 inp->filename, strerror(err_num));
437 else if (feof(inp->f) != 0)
438 _error(__FILE__, __LINE__, 0,
439 _("Premature end of file \"%s\""), inp->filename);
440 else
441 _error(__FILE__, __LINE__, 0,
442 _("Error reading file \"%s\""), inp->filename);
443 }
444
445 if (inp->swap_endian)
446 _swap_endian(buf, size, ni);
447
448 return retval;
449 }
450
451 /*----------------------------------------------------------------------------
452 * Update the file pointer according to whence.
453 *
454 * parameters:
455 * inp <-- input file descriptor
456 * offset <-- add to position specified to whence to obtain new position,
457 * measured in characters from the beginning of the file
458 * whence <-- beginning if SEEK_SET, current if SEEK_CUR, or end-of-file
459 * if SEEK_END
460 *
461 * returns:
462 * 0 upon success, nonzero otherwise; currently, errors are fatal.
463 *----------------------------------------------------------------------------*/
464
465 static int
_file_seek(_cs_io_t * inp,long long offset,int whence)466 _file_seek(_cs_io_t *inp,
467 long long offset,
468 int whence)
469 {
470 int retval = 0;
471
472 assert(inp != NULL);
473
474 if (inp->f != NULL) {
475
476 #if (SIZEOF_LONG < 8)
477
478 /* For 32-bit systems, large file support may be necessary */
479
480 # if defined(HAVE_FSEEKO) && (_FILE_OFFSET_BITS == 64)
481
482 retval = fseeko(inp->f, (off_t)offset, whence);
483
484 if (retval != 0)
485 _error(__FILE__, __LINE__, errno,
486 _("Error setting position in file \"%s\":\n\n %s"),
487 inp->filename, strerror(errno));
488 # else
489
490 /* Test if offset larger than allowed */
491
492 long _offset = offset;
493
494 if (_offset == offset) {
495 retval = fseek(inp->f, (long)offset, whence);
496 if (retval != 0)
497 _error(__FILE__, __LINE__, errno,
498 _("Error setting position in file \"%s\":\n\n %s"),
499 inp->filename, strerror(errno));
500 }
501 else {
502 retval = -1;
503 _error
504 (__FILE__, __LINE__, 0,
505 _("Error setting position in file \"%s\":\n\n %s"),
506 inp->filename,
507 _("sizeof(off_t) > sizeof(long) but fseeko() not available"));
508 }
509
510 # endif /* defined(HAVE_FSEEKO) && (_FILE_OFFSET_BITS == 64) */
511
512 #else /* SIZEOF_LONG >= 8 */
513
514 /* For 64-bit systems, standard fseek should be enough */
515
516 retval = fseek(inp->f, (long)offset, whence);
517 if (retval != 0)
518 _error(__FILE__, __LINE__, errno,
519 _("Error setting position in file \"%s\":\n\n %s"),
520 inp->filename, strerror(errno));
521
522 #endif /* SIZEOF_LONG */
523 }
524
525 return retval;
526 }
527
528 /*----------------------------------------------------------------------------
529 * Return the position of the file pointer.
530 *
531 * parameters:
532 * inp <-- input file descriptor
533 *
534 * returns:
535 * current position of the file pointer
536 *----------------------------------------------------------------------------*/
537
538 static long long
_file_tell(_cs_io_t * inp)539 _file_tell(_cs_io_t *inp)
540 {
541 long long offset = 0;
542 assert(inp != NULL);
543
544 if (inp->f != NULL) {
545
546 /* For 32-bit systems, large file support may be necessary */
547
548 #if (SIZEOF_LONG < 8)
549
550 # if defined(HAVE_FSEEKO) && (_FILE_OFFSET_BITS == 64)
551 offset = ftello(inp->f);
552 # else
553 /*
554 Without ftello, ftell will fail above 2 Gigabytes, in which case
555 offset == -1 and errno == EOVERFLOW, but should work on smaller
556 files. We prefer not to be too strict about fseeko availability, as
557 the only 32-bit case without ftello we have encountered is Cygwin
558 (for which ftello requires additional non-default libraries), which
559 is expected to be used mainly for small cases.
560 */
561 offset = ftell(inp->f);
562 # endif
563
564 /* For 64-bit systems, standard ftell should be enough */
565
566 #else /* SIZEOF_LONG >= 8 */
567 offset = ftell(inp->f);
568 #endif
569
570 }
571
572 if (offset < 0)
573 _error(__FILE__, __LINE__, 0,
574 _("Error obtaining position in file \"%s\":\n\n %s"),
575 inp->filename, strerror(errno));
576
577 return offset;
578 }
579
580 /*----------------------------------------------------------------------------
581 * Convert a buffer of type uint64_t to size_t
582 *
583 * parameters:
584 * f <-- pointer to file
585 * val --> array to which values are read
586 * n <-- number of values to read
587 *----------------------------------------------------------------------------*/
588
589 static void
_convert_size(unsigned char buf[],size_t val[],size_t n)590 _convert_size(unsigned char buf[],
591 size_t val[],
592 size_t n)
593 {
594 size_t i;
595
596 #if (__STDC_VERSION__ >= 199901L)
597
598 for (i = 0; i < n; i++)
599 val[i] = ((uint64_t *)buf)[i];
600
601 #else
602
603 if (sizeof(size_t) == 8) {
604 for (i = 0; i < n; i++)
605 val[i] = ((size_t *)buf)[i];
606 }
607 else if (sizeof(unsigned long long) == 8) {
608 for (i = 0; i < n; i++)
609 val[i] = ((unsigned long long *)buf)[i];
610 }
611 else
612 _error(__FILE__, __LINE__, 0,
613 "Compilation configuration / porting error:\n"
614 "Unable to determine a 64-bit unsigned int type.\n"
615 "size_t is %d bits, unsigned long long %d bits",
616 sizeof(size_t)*8, sizeof(unsigned long long)*8);
617
618 #endif
619 }
620
621 /*----------------------------------------------------------------------------
622 * Open input file, testing magic string for type.
623 *
624 * parameters:
625 * filename <-- file name
626 * mode <-- 0 for dump, 1 for extract, 2 for diff
627 *
628 * returns:
629 * File metadata structure
630 *----------------------------------------------------------------------------*/
631
632 static _cs_io_t
_open_input(const char * filename,int mode)633 _open_input(const char *filename,
634 int mode)
635 {
636 unsigned int_endian;
637 size_t alignments[3];
638 char header_buf[65];
639
640 _cs_io_t inp;
641
642 inp.filename = filename;
643 inp.f = NULL;
644 inp.header_size = 0;
645 inp.header_align = 0;
646 inp.body_align = 0;
647 inp.buffer_size = 0;
648 inp.buffer = NULL;
649
650 inp.n_vals = 0;
651 inp.location_id = 0;
652 inp.index_id = 0,
653 inp.n_loc_vals = 0;
654 inp.type_size = 0;
655 inp.name = NULL;
656 inp.type_name = NULL;
657 inp.data = NULL;
658
659 inp.offset = 0;
660 inp.swap_endian = 0;
661
662 inp.index = NULL;
663
664 /* Check if system is "big-endian" or "little-endian" */
665
666 int_endian = 0;
667 *((char *)(&int_endian)) = '\1';
668 if (int_endian == 1)
669 inp.swap_endian = 1;
670
671 /* Open file */
672
673 if (mode != 1)
674 printf(_("\nOpening input file: \"%s\"\n\n"), filename) ;
675
676 fflush(stdout);
677
678 inp.f = fopen(inp.filename, "rb");
679
680 if (inp.f == NULL)
681 _error(__FILE__, __LINE__, 0,
682 _("Error opening file \"%s\":\n\n"
683 " %s"), inp.filename, strerror(errno));
684
685 /* Read "magic string" */
686
687 _file_read(header_buf, 1, 64, &inp);
688
689 if (strncmp(header_buf, "Code_Saturne I/O, BE, R0", 64) != 0) {
690 header_buf[64] = '\0';
691 _error(__FILE__, __LINE__, 0,
692 _("File format of \"%s\" is not recognized:\n"
693 "First %d bytes: \"%s\"."),
694 filename, 64, header_buf);
695 }
696
697 _file_read(header_buf, 1, 64, &inp);
698
699 header_buf[64] = '\0';
700 if (mode != 1)
701 printf(_(" File type: %s\n"), header_buf);
702
703 _file_read(header_buf, 8, 3, &inp);
704
705 _convert_size((unsigned char*)header_buf, alignments, 3);
706
707 inp.header_size = alignments[0];
708 inp.header_align = alignments[1];
709 inp.body_align = alignments[2];
710
711 if (mode != 1)
712 printf(_("\n"
713 " Base header size: %d\n"
714 " Header alignment: %d\n"
715 " Body alignment: %d\n"),
716 (int)(inp.header_size),
717 (int)(inp.header_align),
718 (int)(inp.body_align));
719
720 inp.buffer_size = inp.header_size;
721 MEM_MALLOC(inp.buffer, inp.buffer_size, unsigned char);
722
723 /* Finish */
724
725 return inp;
726 }
727
728 /*----------------------------------------------------------------------------
729 * Close input file
730 *
731 * parameters:
732 * f <-> pointer to file object
733 * mode <-- 0 for dump, 1 for extract, 2 for diff
734 *----------------------------------------------------------------------------*/
735
736 static void
_close_input(_cs_io_t * inp,int mode)737 _close_input(_cs_io_t *inp,
738 int mode)
739 {
740 if (inp != NULL) {
741 if (inp->f != NULL) {
742 int retval = 0;
743 if (mode == 0)
744 printf(_("\nClosing input: \"%s\"\n\n"), inp->filename);
745 retval = fclose(inp->f);
746 inp->f = NULL;
747 if (retval != 0)
748 _error(__FILE__, __LINE__, 0,
749 _("Error closing file \"%s\":\n\n"
750 " %s"), inp->filename, strerror(errno));
751 }
752 inp->header_size = 0;
753 inp->header_align = 0;
754 inp->body_align = 0;
755 inp->buffer_size = 0;
756 inp->filename = NULL;
757 MEM_FREE(inp->buffer);
758 }
759 }
760
761 /*----------------------------------------------------------------------------
762 * Convert an argument to an integer and check its validity
763 *
764 * parameters:
765 * arg_id <-- index of argument in argv
766 * argc <-- number of command line arguments
767 * argv <-- array of command line arguments
768 *
769 * returns:
770 * integer value
771 *----------------------------------------------------------------------------*/
772
773 #if (__STDC_VERSION__ >= 199901L)
774 static long long
_arg_to_int(int arg_id,int argc,char * argv[])775 _arg_to_int(int arg_id,
776 int argc,
777 char *argv[])
778 {
779 char *start = NULL;
780 char *end = NULL;
781 long long retval = 0;
782
783 if (arg_id < argc) {
784 start = argv[arg_id];
785 end = start + strlen(start);
786 retval = strtoll(start, &end, 0);
787 if (end != start + strlen(start))
788 _usage(argv[0], EXIT_FAILURE);
789 }
790 else
791 _usage(argv[0], EXIT_FAILURE);
792
793 return retval;
794 }
795
796 #else /* (__STDC_VERSION__ == 1989) */
797
798 static long
_arg_to_int(int arg_id,int argc,char * argv[])799 _arg_to_int(int arg_id,
800 int argc,
801 char *argv[])
802 {
803 char *start = NULL;
804 char *end = NULL;
805 long retval = 0;
806
807 if (arg_id < argc) {
808 start = argv[arg_id];
809 end = start + strlen(start);
810 retval = strtol(start, &end, 0);
811 if (end != start + strlen(start))
812 _usage(argv[0], EXIT_FAILURE);
813 }
814 else
815 _usage(argv[0], EXIT_FAILURE);
816
817 return retval;
818 }
819
820 #endif /* (__STDC_VERSION__) */
821
822 /*----------------------------------------------------------------------------
823 * Read command line arguments.
824 *
825 * parameters:
826 * argc <-- number of command line arguments
827 * argv <-- array of command line arguments
828 * mode --> 0 for dump, 1 for extract, 2 for diff
829 * echo --> echo (verbosity) level
830 * location_id --> if >= 0 location id filter
831 * sec_name_arg_id --> if > 0, id of command line argument defining
832 * section name filter
833 * f_fmt_arg_id --> if > 0, id of command line argument defining format
834 * for output of floating-point values
835 * threshold --> threshold above which 2 floating-point values are
836 * considered different.
837 * file_name_arg_id --> index of command line arguments defining file names
838 *----------------------------------------------------------------------------*/
839
840 static void
_read_args(int argc,char ** argv,int * mode,size_t * echo,int * location_id,int * sec_name_arg_id,int * f_fmt_arg_id,double * threshold,int file_name_arg_id[2])841 _read_args(int argc,
842 char **argv,
843 int *mode,
844 size_t *echo,
845 int *location_id,
846 int *sec_name_arg_id,
847 int *f_fmt_arg_id,
848 double *threshold,
849 int file_name_arg_id[2])
850 {
851 int i = 1;
852 int n_files = 0;
853
854 /* Initialize return arguments */
855
856 *echo = 0;
857 *mode = 0;
858 *location_id = -1;
859 *sec_name_arg_id = 0;
860 *f_fmt_arg_id = 0;
861 *threshold = 1.e-30;
862 *file_name_arg_id = 0;
863
864 /* Parse and check command line */
865
866 if (argc < 2)
867 _usage(argv[0], EXIT_FAILURE);
868
869 while (i < argc) {
870
871 if (strcmp(argv[i], "--f-format") == 0) {
872 i++;
873 if (i < argc)
874 *f_fmt_arg_id = i;
875 else
876 _usage(argv[0], EXIT_FAILURE);
877 }
878
879 else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--diff") == 0) {
880 if (*mode == 0)
881 *mode = 2;
882 else
883 _usage(argv[0], EXIT_SUCCESS);
884 }
885
886 else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--extract") == 0) {
887 if (*mode == 0)
888 *mode = 1;
889 else
890 _usage(argv[0], EXIT_SUCCESS);
891 }
892
893 else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0)
894 _usage(argv[0], EXIT_SUCCESS);
895
896 else if (strcmp(argv[i], "-n") == 0) {
897 i++;
898 *echo = _arg_to_int(i, argc, argv);
899 }
900
901 else if (strcmp(argv[i], "--location") == 0) {
902 i++;
903 *location_id = _arg_to_int(i, argc, argv);
904 }
905
906 else if (strcmp(argv[i], "--section") == 0) {
907 i++;
908 if (i < argc)
909 *sec_name_arg_id = i;
910 else
911 _usage(argv[0], EXIT_FAILURE);
912 }
913
914 else if (strcmp(argv[i], "--threshold") == 0) {
915 i++;
916 if (i < argc) {
917 char *end = argv[i] + strlen(argv[i]);
918 *threshold = strtod(argv[i], &end);
919 if (end == argv[i])
920 _usage(argv[0], EXIT_FAILURE);
921 }
922 else
923 _usage(argv[0], EXIT_FAILURE);
924 }
925
926 else {
927
928 if (n_files == 0 || (n_files == 1 && *mode == 2))
929 file_name_arg_id[n_files++] = i;
930 else
931 _usage(argv[0], EXIT_FAILURE);
932
933 }
934
935 i++;
936 }
937
938 if ((*mode != 2 && n_files != 1) || (*mode == 2 && n_files != 2))
939 _usage(argv[0], EXIT_FAILURE);
940
941 /* At this point, command line seems correct */
942
943 if (*mode != 1)
944 printf(_("\n"
945 " .----------------------------.\n"
946 " | Code_Saturne file dump |\n"
947 " `----------------------------'\n"));
948 }
949
950 /*----------------------------------------------------------------------------
951 * Echo values depending on type.
952 *
953 * Type name should already have been checked when this function is called,
954 * so no additional check is done here.
955 *
956 * parameters:
957 * n_values <-- number of values to echo
958 * n_values_shift <-- shift to second (end) series of values to echo
959 * buffer <-- pointer to data
960 * type_name <-- name of data type
961 * f_fmt <-- if != NULL, format for output of floating-point values
962 *----------------------------------------------------------------------------*/
963
964 static void
_echo_values(size_t n_values,size_t n_values_shift,const void * buffer,const char type_name[],const char * f_fmt)965 _echo_values(size_t n_values,
966 size_t n_values_shift,
967 const void *buffer,
968 const char type_name[],
969 const char *f_fmt)
970 {
971 size_t i;
972
973 /* Check type name */
974
975 if (type_name[0] == 'c') {
976 const char *_buffer = buffer;
977 for (i = 0; i < n_values; i++)
978 printf(" %10lu : '%c'\n",
979 (unsigned long)(i + n_values_shift),
980 _buffer[i]);
981 }
982
983 #if (__STDC_VERSION__ >= 199901L)
984
985 else if (type_name[0] == 'i' && type_name[1] == '4') {
986 const int32_t *_buffer = buffer;
987 for (i = 0; i < n_values; i++)
988 printf(" %10lu : %d\n",
989 (unsigned long)(i + n_values_shift),
990 (int)(_buffer[i]));
991 }
992
993 else if (type_name[0] == 'i' && type_name[1] == '8') {
994 const int64_t *_buffer = buffer;
995 for (i = 0; i < n_values; i++)
996 printf(" %10lu : %ld\n",
997 (unsigned long)(i + n_values_shift),
998 (long)(_buffer[i]));
999 }
1000
1001 else if (type_name[0] == 'u' && type_name[1] == '4') {
1002 const uint32_t *_buffer = buffer;
1003 for (i = 0; i < n_values; i++)
1004 printf(" %10lu : %u\n",
1005 (unsigned long)(i + n_values_shift),
1006 (unsigned)(_buffer[i]));
1007 }
1008
1009 else if (type_name[0] == 'u' && type_name[1] == '8') {
1010 const uint64_t *_buffer = buffer;
1011 for (i = 0; i < n_values; i++)
1012 printf(" %10lu : %lu\n",
1013 (unsigned long)(i + n_values_shift),
1014 (unsigned long)(_buffer[i]));
1015 }
1016
1017 #else /* (__STDC_VERSION__ < 199901L) */
1018
1019 else if (type_name[0] == 'i' && type_name[1] == '4') {
1020 if (sizeof(int) == 4) {
1021 const int *_buffer = buffer;
1022 for (i = 0; i < n_values; i++)
1023 printf(" %10lu : %d\n",
1024 (unsigned long)(i + n_values_shift),
1025 _buffer[i]);
1026 }
1027 else if (sizeof(short) == 4) {
1028 const short *_buffer = buffer;
1029 for (i = 0; i < n_values; i++)
1030 printf(" %10lu : %d\n",
1031 (unsigned long)(i + n_values_shift),
1032 (int)(_buffer[i]));
1033 }
1034 else
1035 printf(" int32_t undefined"
1036 " (porting error, C99 compiler needed)\n");
1037 }
1038
1039 else if (type_name[0] == 'i' && type_name[1] == '8') {
1040 if (sizeof(long) == 8) {
1041 const long *_buffer = buffer;
1042 for (i = 0; i < n_values; i++)
1043 printf(" %10lu : %ld\n",
1044 (unsigned long)(i + n_values_shift),
1045 _buffer[i]);
1046 }
1047 else if (sizeof(long long) == 8) {
1048 const long long *_buffer = buffer;
1049 for (i = 0; i < n_values; i++)
1050 printf(" %10lu : %ld\n",
1051 (unsigned long)(i + n_values_shift),
1052 (long)(_buffer[i]));
1053 }
1054 else
1055 printf(" int64_t undefined"
1056 " (porting error, C99 compiler needed)\n");
1057 }
1058
1059 else if (type_name[0] == 'u' && type_name[1] == '4') {
1060 if (sizeof(unsigned) == 4) {
1061 const unsigned *_buffer = buffer;
1062 for (i = 0; i < n_values; i++)
1063 printf(" %10lu : %u\n",
1064 (unsigned long)(i + n_values_shift),
1065 _buffer[i]);
1066 }
1067 else if (sizeof(unsigned short) == 4) {
1068 const unsigned short *_buffer = buffer;
1069 for (i = 0; i < n_values; i++)
1070 printf(" %10lu : %u\n",
1071 (unsigned long)(i + n_values_shift),
1072 (unsigned)(_buffer[i]));
1073 }
1074 else
1075 printf(" uint32_t undefined"
1076 " (porting error, C99 compiler needed)\n");
1077 }
1078
1079 else if (type_name[0] == 'u' && type_name[1] == '8') {
1080 if (sizeof(unsigned long) == 8) {
1081 const unsigned long *_buffer = buffer;
1082 for (i = 0; i < n_values; i++)
1083 printf(" %10lu : %lu\n",
1084 (unsigned long)(i + n_values_shift),
1085 (unsigned long)(_buffer[i]));
1086 }
1087 else if (sizeof(unsigned long long) == 8) {
1088 const unsigned long long *_buffer = buffer;
1089 for (i = 0; i < n_values; i++)
1090 printf(" %10lu : %lu\n",
1091 (unsigned long)(i + n_values_shift),
1092 (unsigned long)(_buffer[i]));
1093 }
1094 else
1095 printf(" uint64_t undefined"
1096 " (porting error, C99 compiler needed)\n");
1097 }
1098
1099 #endif /* (__STDC_VERSION__) */
1100
1101 else if (type_name[0] == 'r' && type_name[1] == '4') {
1102 const float *_buffer = buffer;
1103 if (f_fmt == NULL) {
1104 for (i = 0; i < n_values; i++)
1105 printf(" %10lu : %15.9e\n",
1106 (unsigned long)(i + n_values_shift),
1107 (double)(_buffer[i]));
1108 }
1109 else {
1110 char format[64] = " %10lu : %";
1111 strncat(format, f_fmt, 48);
1112 strcat(format, "\n");
1113 for (i = 0; i < n_values; i++)
1114 printf(format,
1115 (unsigned long)(i + n_values_shift),
1116 (double)(_buffer[i]));
1117 }
1118 }
1119
1120 else if (type_name[0] == 'r' && type_name[1] == '8') {
1121 const double *_buffer = buffer;
1122 if (f_fmt == NULL) {
1123 for (i = 0; i < n_values; i++)
1124 printf(" %10lu : %22.15e\n",
1125 (unsigned long)(i + n_values_shift),
1126 _buffer[i]);
1127 }
1128 else {
1129 char format[64] = " %10lu : %";
1130 strncat(format, f_fmt, 48);
1131 strcat(format, "\n");
1132 for (i = 0; i < n_values; i++)
1133 printf(format,
1134 (unsigned long)(i + n_values_shift),
1135 _buffer[i]);
1136 }
1137 }
1138
1139 }
1140
1141 /*----------------------------------------------------------------------------
1142 * Determine a type's size based on its name.
1143 *
1144 * parameters:
1145 * type_name <-- type name
1146 *
1147 * returns:
1148 * size of data type
1149 *----------------------------------------------------------------------------*/
1150
1151 static size_t
_type_size_from_name(const char * type_name)1152 _type_size_from_name(const char *type_name)
1153 {
1154 size_t type_size = 0;
1155
1156 assert(type_name != NULL);
1157
1158 /* Check type name and compute size of data */
1159
1160 if (type_name[0] == 'c' && type_name[1] == ' ')
1161 type_size = 1;
1162
1163 else if ( type_name[0] == 'i'
1164 || type_name[0] == 'u'
1165 || type_name[0] == 'r') {
1166
1167 if (type_name[1] == '4')
1168 type_size = 4;
1169 else if (type_name[1] == '8')
1170 type_size = 8;
1171 }
1172
1173 if (type_size == 0)
1174 _error(__FILE__, __LINE__, 0,
1175 _("Type \"%s\" is not known\n"
1176 "Known types: \"c \", \"i4\", \"i8\", \"u4\", \"u8\", "
1177 "\"r4\", \"r8\"."), type_name);
1178 return type_size;
1179 }
1180
1181 /*----------------------------------------------------------------------------
1182 * Read section header.
1183 *
1184 * parameters:
1185 * inp <-> pointer to input object
1186 *
1187 * returns:
1188 * number of bytes in section body
1189 *----------------------------------------------------------------------------*/
1190
1191 static size_t
_read_section_header(_cs_io_t * inp)1192 _read_section_header(_cs_io_t *inp)
1193 {
1194 size_t body_size = 0;
1195 size_t header_vals[6];
1196 unsigned int_endian = 0;
1197
1198 *((char *)(&int_endian)) = '\1'; /* Determine if we are little-endian */
1199
1200 assert(inp != NULL);
1201 assert(inp->f != NULL);
1202 assert(inp->buffer != NULL);
1203
1204 /* Position read pointer if necessary */
1205 /*------------------------------------*/
1206
1207 {
1208 long long offset = _file_tell(inp);
1209 size_t ha = inp->header_align;
1210 offset += (ha - (offset % ha)) % ha;
1211 _file_seek(inp, offset, SEEK_SET);
1212 }
1213
1214 /* Read header */
1215 /*-------------*/
1216
1217 _file_read(inp->buffer, 1, inp->header_size, inp);
1218
1219 if (int_endian == 1)
1220 _swap_endian(inp->buffer, 8, 6);
1221
1222 _convert_size(inp->buffer, header_vals, 6);
1223
1224 if (header_vals[0] > inp->header_size) {
1225
1226 if (header_vals[0] > inp->buffer_size) {
1227 while (header_vals[0] > inp->buffer_size)
1228 inp->buffer_size *=2;
1229 MEM_REALLOC(inp->buffer, inp->buffer_size, unsigned char);
1230 }
1231
1232 _file_read(inp->buffer + inp->header_size,
1233 1,
1234 header_vals[0] - inp->header_size,
1235 inp);
1236
1237 }
1238
1239 /* Set pointers to data fields */
1240
1241 inp->n_vals = header_vals[1];
1242 inp->location_id = header_vals[2];
1243 inp->index_id = header_vals[3];
1244 inp->n_loc_vals = header_vals[4];
1245 inp->type_size = 0;
1246 inp->data = NULL;
1247 inp->type_name = (char *)(inp->buffer + 48);
1248 inp->name = (char *)(inp->buffer + 56);
1249
1250 if (header_vals[1] > 0 && inp->type_name[7] == 'e')
1251 inp->data = inp->buffer + 56 + header_vals[5];
1252
1253 inp->type_size = 0;
1254
1255 if (inp->n_vals > 0) {
1256
1257 inp->type_size = _type_size_from_name(inp->type_name);
1258
1259 if (inp->data == NULL)
1260 body_size = inp->type_size*inp->n_vals;
1261
1262 else if (int_endian == 1 && inp->type_size > 1)
1263 _swap_endian(inp->data, inp->type_size, inp->n_vals);
1264 }
1265
1266 return body_size;
1267 }
1268
1269 /*----------------------------------------------------------------------------
1270 * Read section values and print associated info
1271 *
1272 * If values are already embedded in the header, no actual reading is done
1273 *
1274 * parameters:
1275 * inp <-> pointer to input object
1276 * echo <-- number of values to print
1277 * f_fmt <-- if != NULL, format for output of floating-point values
1278 *----------------------------------------------------------------------------*/
1279
1280 static void
_read_section_values(_cs_io_t * inp,size_t echo,const char * f_fmt)1281 _read_section_values(_cs_io_t *inp,
1282 size_t echo,
1283 const char *f_fmt)
1284 {
1285 size_t n_print = 0, n_skip = 0;
1286 unsigned char *buffer = NULL;
1287 const unsigned char *data = NULL;
1288
1289 assert(inp->n_vals > 0);
1290
1291 if (inp->data != NULL)
1292 printf(_(" Values in header\n"));
1293
1294 /* Compute number of values to skip */
1295
1296 if (inp->n_vals > echo*2) {
1297 n_skip = inp->n_vals - echo*2;
1298 n_print = echo;
1299 }
1300 else {
1301 n_skip = 0;
1302 n_print = inp->n_vals;
1303 }
1304
1305 /* Position read pointer if non-embedded data is present */
1306
1307 if (inp->data == NULL) {
1308
1309 long long offset = _file_tell(inp);
1310 size_t ba = inp->body_align;
1311 offset += (ba - (offset % ba)) % ba;
1312 _file_seek(inp, offset, SEEK_SET);
1313
1314 /* Allocate buffer */
1315
1316 if (n_print > 0) {
1317 MEM_MALLOC(buffer, n_print*inp->type_size, unsigned char);
1318 _file_read(buffer, inp->type_size, n_print, inp);
1319 data = buffer;
1320 }
1321 }
1322
1323 else if (n_print > 0)
1324 data = inp->data;
1325
1326 /* Print first part of data */
1327
1328 if (n_print > 0) {
1329
1330 if (n_skip > 0)
1331 printf(_(" %lu first and last elements:\n"), (unsigned long)echo);
1332 else
1333 printf(_(" elements:\n"));
1334
1335 _echo_values(n_print,
1336 1,
1337 data,
1338 inp->type_name,
1339 f_fmt);
1340
1341 if (n_skip > 0)
1342 printf(" .......... ..........\n");
1343
1344 }
1345
1346 /* Move to tail of data and read if necessary */
1347
1348 if (n_skip > 0) {
1349
1350 if (inp->data == NULL) {
1351
1352 long long offset = _file_tell(inp) + n_skip*inp->type_size;
1353 _file_seek(inp, offset, SEEK_SET);
1354
1355 if (n_print > 0) {
1356 _file_read(buffer, inp->type_size, n_print, inp);
1357 data = buffer;
1358 }
1359 }
1360
1361 else if (n_print > 0)
1362 data = ((unsigned char *)inp->data) + ((n_print+n_skip)*inp->type_size);
1363
1364 if (n_print > 0)
1365 _echo_values(n_print,
1366 inp->n_vals - n_print + 1,
1367 data,
1368 inp->type_name,
1369 f_fmt);
1370
1371 }
1372
1373 if (buffer != NULL)
1374 MEM_FREE(buffer);
1375 }
1376
1377 /*----------------------------------------------------------------------------
1378 * Skip section values
1379 *
1380 * If values are already embedded in the header, no actual reading is done
1381 *
1382 * parameters:
1383 * inp <-> pointer to input object
1384 *----------------------------------------------------------------------------*/
1385
1386 static void
_skip_section_values(_cs_io_t * inp)1387 _skip_section_values(_cs_io_t *inp)
1388 {
1389 assert(inp->n_vals > 0);
1390
1391 /* Position read pointer if non-embedded data is present */
1392
1393 if (inp->data == NULL) {
1394 long long offset = _file_tell(inp);
1395 size_t ba = inp->body_align;
1396 offset += (ba - (offset % ba)) % ba + inp->n_vals*inp->type_size;
1397 _file_seek(inp, offset, SEEK_SET);
1398 }
1399 }
1400
1401 /*----------------------------------------------------------------------------
1402 * Extract section values and print associated info
1403 *
1404 * If values are already embedded in the header, no actual reading is done
1405 *
1406 * parameters:
1407 * inp <-> pointer to input object
1408 * f_fmt <-- if != NULL, format for output of floating-point values
1409 *----------------------------------------------------------------------------*/
1410
1411 static void
_extract_section_values(_cs_io_t * inp,const char * f_fmt)1412 _extract_section_values(_cs_io_t *inp,
1413 const char *f_fmt)
1414 {
1415 size_t i;
1416 size_t n_vals = inp->n_vals;
1417 void *data = NULL;
1418 const char *type_name = inp->type_name;
1419
1420 /* Position read pointer if non-embedded data is present */
1421
1422 if (inp->data == NULL) {
1423
1424 _file_seek(inp, inp->offset, SEEK_SET);
1425
1426 /* Allocate buffer */
1427
1428 if (n_vals > 0) {
1429 MEM_MALLOC(data, n_vals*inp->type_size, unsigned char);
1430 _file_read(data, inp->type_size, n_vals, inp);
1431 }
1432 }
1433
1434 else if (n_vals > 0)
1435 data = inp->data;
1436
1437 /* Print data */
1438
1439 if (n_vals > 0) {
1440
1441 /* Check type name */
1442
1443 if (type_name[0] == 'c') {
1444 if (inp->location_id == 0) {
1445 char *_data = NULL;
1446 MEM_MALLOC(_data, n_vals + 1, char);
1447 memcpy(_data, data, n_vals);
1448 for (i = 0; i < n_vals; i++)
1449 if (_data[i] == '\0')
1450 _data[i] = '\n';
1451 _data[n_vals] = '\0';
1452 printf("%s", _data);
1453 MEM_FREE(_data);
1454 }
1455 else {
1456 char *_data = data;
1457 for (i = 0; i < n_vals; i++)
1458 printf("%d\n", (int)(_data[i]));
1459 }
1460 }
1461
1462 #if (__STDC_VERSION__ >= 199901L)
1463
1464 else if (type_name[0] == 'i' && type_name[1] == '4') {
1465 const int32_t *_data = data;
1466 for (i = 0; i < n_vals; i++)
1467 printf("%d\n", (int)(_data[i]));
1468 }
1469
1470 else if (type_name[0] == 'i' && type_name[1] == '8') {
1471 const int64_t *_data = data;
1472 for (i = 0; i < n_vals; i++)
1473 printf("%ld\n", (long)(_data[i]));
1474 }
1475
1476 else if (type_name[0] == 'u' && type_name[1] == '4') {
1477 const uint32_t *_data = data;
1478 for (i = 0; i < n_vals; i++)
1479 printf("%u\n", (unsigned)(_data[i]));
1480 }
1481
1482 else if (type_name[0] == 'u' && type_name[1] == '8') {
1483 const uint64_t *_data = data;
1484 for (i = 0; i < n_vals; i++)
1485 printf("%lu\n", (unsigned long)(_data[i]));
1486 }
1487
1488 #else /* (__STDC_VERSION__ < 199901L) */
1489
1490 else if (type_name[0] == 'i' && type_name[1] == '4') {
1491 if (sizeof(int) == 4) {
1492 const int *_data = data;
1493 for (i = 0; i < n_vals; i++)
1494 printf("%d\n", _data[i]);
1495 }
1496 else if (sizeof(short) == 4) {
1497 const short *_data = data;
1498 for (i = 0; i < n_vals; i++)
1499 printf("%d\n", (int)(_data[i]));
1500 }
1501 else
1502 printf(" int32_t undefined"
1503 " (porting error, C99 compiler needed)\n");
1504 }
1505
1506 else if (type_name[0] == 'i' && type_name[1] == '8') {
1507 if (sizeof(long) == 8) {
1508 const long *_data = data;
1509 for (i = 0; i < n_vals; i++)
1510 printf("%ld\n", _data[i]);
1511 }
1512 else if (sizeof(long long) == 8) {
1513 const long long *_data = data;
1514 for (i = 0; i < n_vals; i++)
1515 printf("%ld\n", (long)(_data[i]));
1516 }
1517 else
1518 printf(" int64_t undefined"
1519 " (porting error, C99 compiler needed)\n");
1520 }
1521
1522 else if (type_name[0] == 'u' && type_name[1] == '4') {
1523 if (sizeof(unsigned) == 4) {
1524 const unsigned *_data = data;
1525 for (i = 0; i < n_vals; i++)
1526 printf("%u\n", _data[i]);
1527 }
1528 else if (sizeof(unsigned short) == 4) {
1529 const unsigned short *_data = data;
1530 for (i = 0; i < n_vals; i++)
1531 printf("%u\n", (unsigned)(_data[i]));
1532 }
1533 else
1534 printf(" uint32_t undefined"
1535 " (porting error, C99 compiler needed)\n");
1536 }
1537
1538 else if (type_name[0] == 'u' && type_name[1] == '8') {
1539 if (sizeof(unsigned long) == 8) {
1540 const unsigned long *_data = data;
1541 for (i = 0; i < n_vals; i++)
1542 printf("%lu\n", (unsigned long)(_data[i]));
1543 }
1544 else if (sizeof(unsigned long long) == 8) {
1545 const unsigned long long *_data = data;
1546 for (i = 0; i < n_vals; i++)
1547 printf("%lu\n", (unsigned long)(_data[i]));
1548 }
1549 else
1550 printf(" uint64_t undefined"
1551 " (porting error, C99 compiler needed)\n");
1552 }
1553
1554 #endif /* (__STDC_VERSION__) */
1555
1556 else if (type_name[0] == 'r' && type_name[1] == '4') {
1557 const float *_data = data;
1558 if (f_fmt == NULL) {
1559 for (i = 0; i < n_vals; i++)
1560 printf("%15.9e\n", (double)(_data[i]));
1561 }
1562 else {
1563 char format[64] = "%";
1564 strncat(format, f_fmt, 48);
1565 strcat(format, "\n");
1566 for (i = 0; i < n_vals; i++)
1567 printf(format, (double)(_data[i]));
1568 }
1569 }
1570
1571 else if (type_name[0] == 'r' && type_name[1] == '8') {
1572 const double *_data = data;
1573 if (f_fmt == NULL) {
1574 for (i = 0; i < n_vals; i++)
1575 printf("%22.15e\n", _data[i]);
1576 }
1577 else {
1578 char format[64] = "%";
1579 strncat(format, f_fmt, 48);
1580 strcat(format, "\n");
1581 for (i = 0; i < n_vals; i++)
1582 printf(format, _data[i]);
1583 }
1584 }
1585 }
1586
1587 if (inp->data == NULL)
1588 MEM_FREE(data);
1589 }
1590
1591 /*----------------------------------------------------------------------------
1592 * Read section.
1593 *
1594 * parameters:
1595 * inp <-> pointer to input object
1596 * echo <-- number of values to print
1597 * location_id <-- if >= 0 location id filter
1598 * sec_name <-- if != NULL, section name filter
1599 * f_fmt <-- if != NULL, format for output of floating-point values
1600 *----------------------------------------------------------------------------*/
1601
1602 static void
_read_section(_cs_io_t * inp,int echo,int location_id,const char * sec_name,const char * f_fmt)1603 _read_section(_cs_io_t *inp,
1604 int echo,
1605 int location_id,
1606 const char *sec_name,
1607 const char *f_fmt)
1608 {
1609 int read_section = 0;
1610
1611 assert(inp != NULL);
1612 assert(inp->f != NULL);
1613
1614 /* Read section header and print basic information */
1615
1616 _read_section_header(inp);
1617
1618 if ( (location_id < 0 || (unsigned)location_id == inp->location_id)
1619 && (sec_name == NULL || !strcmp(sec_name, inp->name)))
1620 read_section = 1;
1621
1622 if (read_section) {
1623
1624 printf(_("\n"
1625 " Section: \"%s\"\n"
1626 " Number of values: %lu\n"),
1627 inp->name, (unsigned long)(inp->n_vals));
1628
1629 if (inp->n_vals > 0)
1630 printf(_(" Type: \"%s\"\n"), inp->type_name);
1631
1632 printf(_(" Location id: %lu\n"
1633 " Index id: %lu\n"
1634 " Values per location: %lu\n"),
1635 (unsigned long)(inp->location_id),
1636 (unsigned long)(inp->index_id),
1637 (unsigned long)(inp->n_loc_vals));
1638 }
1639
1640 if (inp->n_vals > 0) {
1641 if (read_section)
1642 _read_section_values(inp, echo, f_fmt);
1643 else
1644 _skip_section_values(inp);
1645 }
1646 }
1647
1648 /*----------------------------------------------------------------------------
1649 * Update an index structure with info from the last header read
1650 *
1651 * Also sets the file position for the next read
1652 *
1653 * parameters:
1654 * inp <-> input kernel IO structure
1655 *----------------------------------------------------------------------------*/
1656
1657 static void
_update_index_and_shift(_cs_io_t * inp)1658 _update_index_and_shift(_cs_io_t *inp)
1659 {
1660 size_t id = 0;
1661 size_t new_names_size = 0;
1662 size_t new_types_size = 0;
1663 size_t new_data_size = 0;
1664
1665 _cs_io_sec_index_t *idx = inp->index;
1666
1667 if (idx == NULL)
1668 return;
1669
1670 /* Reallocate if necessary */
1671
1672 if (idx->size + 1 == idx->max_size) {
1673 if (idx->max_size == 0)
1674 idx->max_size = 32;
1675 else
1676 idx->max_size *= 2;
1677 MEM_REALLOC(idx->h_vals, idx->max_size*8, long long);
1678 MEM_REALLOC(idx->offset, idx->max_size, long long);
1679 };
1680
1681 new_names_size = idx->names_size + strlen(inp->name) + 1;
1682 new_types_size = idx->types_size + strlen(inp->type_name) + 1;
1683
1684 if (inp->data != NULL)
1685 new_data_size = idx->data_size + (inp->n_vals * inp->type_size);
1686
1687 if (new_names_size > idx->max_names_size) {
1688 if (idx->max_names_size == 0)
1689 idx->max_names_size = 128;
1690 while (new_names_size > idx->max_names_size)
1691 idx->max_names_size *= 2;
1692 MEM_REALLOC(idx->names, idx->max_names_size, char);
1693 }
1694
1695 if (new_types_size > idx->max_types_size) {
1696 if (idx->max_types_size == 0)
1697 idx->max_types_size = 128;
1698 while (new_types_size > idx->max_types_size)
1699 idx->max_types_size *= 2;
1700 MEM_REALLOC(idx->types, idx->max_types_size, char);
1701 }
1702
1703 if (new_data_size > idx->max_data_size) {
1704 if (idx->max_data_size == 0)
1705 idx->max_data_size = 128;
1706 while (new_data_size > idx->max_data_size)
1707 idx->max_data_size *= 2;
1708 MEM_REALLOC(idx->data, idx->max_data_size, unsigned char);
1709 }
1710
1711 /* Set values */
1712
1713 id = idx->size;
1714
1715 idx->h_vals[id*8] = inp->n_vals;
1716 idx->h_vals[id*8 + 1] = inp->location_id;
1717 idx->h_vals[id*8 + 2] = inp->index_id;
1718 idx->h_vals[id*8 + 3] = inp->n_loc_vals;
1719 idx->h_vals[id*8 + 4] = idx->names_size;
1720 idx->h_vals[id*8 + 5] = idx->types_size;
1721 idx->h_vals[id*8 + 6] = 0;
1722
1723 strcpy(idx->names + idx->names_size, inp->name);
1724 idx->names[new_names_size - 1] = '\0';
1725 idx->names_size = new_names_size;
1726
1727 strcpy(idx->types + idx->types_size, inp->type_name);
1728 idx->types[new_types_size - 1] = '\0';
1729 idx->types_size = new_types_size;
1730
1731 if (inp->data == NULL) {
1732 long long offset = _file_tell(inp);
1733 long long data_shift = inp->n_vals * inp->type_size;
1734 if (inp->body_align > 0) {
1735 size_t ba = inp->body_align;
1736 idx->offset[id] = offset + (ba - (offset % ba)) % ba;
1737 }
1738 else
1739 idx->offset[id] = offset;
1740 _file_seek(inp, idx->offset[id] + data_shift, SEEK_SET);
1741 }
1742 else {
1743 idx->h_vals[id*8 + 6] = idx->data_size + 1;
1744 memcpy(idx->data + idx->data_size,
1745 inp->data,
1746 new_data_size - idx->data_size);
1747 idx->data_size = new_data_size;
1748 idx->offset[id] = -1;
1749 }
1750
1751 idx->size += 1;
1752 }
1753
1754 /*----------------------------------------------------------------------------
1755 * Create an index structure to a _cs_io_t structure.
1756 *
1757 * parameters:
1758 * inp <-> pointer to cs_io_t structure
1759 * end_offset <-- file size
1760 *----------------------------------------------------------------------------*/
1761
1762 static void
_create_index(_cs_io_t * inp,long long end_offset)1763 _create_index(_cs_io_t *inp,
1764 long long end_offset)
1765 {
1766 _cs_io_sec_index_t *idx = NULL;
1767
1768 MEM_MALLOC(idx, 1, _cs_io_sec_index_t);
1769
1770 /* Set structure fields */
1771
1772 idx->size = 0;
1773 idx->max_size = 32;
1774
1775 MEM_MALLOC(idx->h_vals, idx->max_size*8, long long);
1776 MEM_MALLOC(idx->offset, idx->max_size, long long);
1777
1778 idx->max_names_size = 256;
1779 idx->names_size = 0;
1780
1781 MEM_MALLOC(idx->names, idx->max_names_size, char);
1782
1783 idx->max_types_size = 64;
1784 idx->types_size = 0;
1785
1786 MEM_MALLOC(idx->types, idx->max_names_size, char);
1787
1788 idx->max_data_size = 256;
1789 idx->data_size = 0;
1790
1791 MEM_MALLOC(idx->data, idx->max_data_size, unsigned char);
1792
1793 /* Add structure */
1794
1795 inp->index = idx;
1796
1797 /* Read headers to build index index */
1798
1799 while (_file_tell(inp) + (long long)(inp->header_size) <= end_offset) {
1800 _read_section_header(inp);
1801 _update_index_and_shift(inp);
1802 }
1803 }
1804
1805 /*----------------------------------------------------------------------------
1806 * Destroy a cs_io_t structure's optional index structure.
1807 *
1808 * parameters:
1809 * inp <-> pointer to cs_io_t structure
1810 *----------------------------------------------------------------------------*/
1811
1812 static void
_destroy_index(_cs_io_t * inp)1813 _destroy_index(_cs_io_t *inp)
1814 {
1815 _cs_io_sec_index_t *idx = inp->index;
1816
1817 if (idx == NULL)
1818 return;
1819
1820 MEM_FREE(idx->h_vals);
1821 MEM_FREE(idx->offset);
1822 MEM_FREE(idx->names);
1823 MEM_FREE(idx->types);
1824 MEM_FREE(idx->data);
1825
1826 MEM_FREE(inp->index);
1827 }
1828
1829 /*----------------------------------------------------------------------------
1830 * Ready cs_io_t structure to read a given indexed section
1831 *
1832 * parameters:
1833 * inp <-> pointer to input object
1834 * section_id <-- section id
1835 *----------------------------------------------------------------------------*/
1836
1837 static void
_set_indexed_section(_cs_io_t * inp,int section_id)1838 _set_indexed_section(_cs_io_t *inp,
1839 int section_id)
1840 {
1841 const _cs_io_sec_index_t *index = inp->index;
1842 const long long *h_vals = index->h_vals + section_id*8;
1843
1844 inp->n_vals = h_vals[0];
1845 inp->location_id = h_vals[1];
1846 inp->index_id = h_vals[2];
1847 inp->n_loc_vals = h_vals[3];
1848 inp->type_size = 0;
1849 inp->data = NULL;
1850 if (h_vals[6] != 0)
1851 inp->data = index->data + h_vals[6] - 1;
1852 inp->name = index->names + h_vals[4];
1853 inp->type_name = index->types + h_vals[5];
1854 inp->offset = index->offset[section_id];
1855 inp->type_size = _type_size_from_name(inp->type_name);
1856 }
1857
1858 /*----------------------------------------------------------------------------
1859 * Extract data from a cs_io_t structure whose index has been built
1860 *
1861 * parameters:
1862 * inp <-> pointer to input object
1863 * location_id <-- if >= 0 location id filter
1864 * sec_name <-- if != NULL, section name filter
1865 * f_fmt <-- if != NULL, format for output of floating-point values
1866 *----------------------------------------------------------------------------*/
1867
1868 static void
_find_and_extract_section(_cs_io_t * inp,int location_id,const char * sec_name,const char * f_fmt)1869 _find_and_extract_section(_cs_io_t *inp,
1870 int location_id,
1871 const char *sec_name,
1872 const char *f_fmt)
1873 {
1874 size_t id;
1875 int extract_id = -1;
1876 _cs_io_sec_index_t *index = inp->index;
1877
1878 /* Find matching sections */
1879
1880 for (id = 0; id < index->size; id++) {
1881
1882 int match = 1;
1883 const long long *h_vals = index->h_vals + id*8;
1884 const char *_name = index->names + h_vals[4];
1885 const int _location = h_vals[1];
1886
1887 if (sec_name != NULL && strcmp(sec_name, _name))
1888 match = 0;
1889 if (location_id >= 0 && location_id != _location)
1890 match = 0;
1891
1892 if (match == 1) {
1893 if (extract_id < 0)
1894 extract_id = id;
1895 else
1896 _error(__FILE__, __LINE__, 0,
1897 _("File \"%s\" contains multiple sections\n"
1898 "named \"%s\" with location id %d\n\n"),
1899 inp->filename, _name, _location);
1900 }
1901 }
1902
1903 /* If section to extract found, output it */
1904
1905 if (extract_id > -1) {
1906 _set_indexed_section(inp, extract_id);
1907 _extract_section_values(inp, f_fmt);
1908 }
1909 }
1910
1911 /*----------------------------------------------------------------------------
1912 * Copy data to compare buffer
1913 *
1914 * This allows comparing arrays of similar but not identical types.
1915 *
1916 * Type name should already have been checked when this function is called,
1917 * so no additional check is done here.
1918 *
1919 * parameters:
1920 * dest --> pointer to comparable (destination) data
1921 * buffer <-- pointer to data
1922 * type_named <-- name of data type
1923 * n_values <-- number of values to echo
1924 *----------------------------------------------------------------------------*/
1925
1926 static void
_copy_to_cmp(void * dest,const void * buffer,const char type_name[],size_t n_values)1927 _copy_to_cmp(void *dest,
1928 const void *buffer,
1929 const char type_name[],
1930 size_t n_values)
1931 {
1932 size_t i;
1933
1934 /* Check type name */
1935
1936 if (type_name[0] == 'c')
1937 memcpy(dest, buffer, n_values);
1938
1939 #if (__STDC_VERSION__ >= 199901L)
1940
1941 else if (type_name[0] == 'i' && type_name[1] == '4') {
1942 const int32_t *_buffer = buffer;
1943 long long *_dest = dest;
1944 for (i = 0; i < n_values; i++)
1945 _dest[i] = _buffer[i];
1946 }
1947
1948 else if (type_name[0] == 'i' && type_name[1] == '8') {
1949 const int64_t *_buffer = buffer;
1950 long long *_dest = dest;
1951 for (i = 0; i < n_values; i++)
1952 _dest[i] = _buffer[i];
1953 }
1954
1955 else if (type_name[0] == 'u' && type_name[1] == '4') {
1956 const uint32_t *_buffer = buffer;
1957 long long *_dest = dest;
1958 for (i = 0; i < n_values; i++)
1959 _dest[i] = _buffer[i];
1960 }
1961
1962 else if (type_name[0] == 'u' && type_name[1] == '8') {
1963 const uint64_t *_buffer = buffer;
1964 long long *_dest = dest;
1965 for (i = 0; i < n_values; i++)
1966 _dest[i] = _buffer[i];
1967 }
1968
1969 #else /* (__STDC_VERSION__ < 199901L) */
1970
1971 else if (type_name[0] == 'i' && type_name[1] == '4') {
1972 if (sizeof(int) == 4) {
1973 const int *_buffer = buffer;
1974 long long *_dest = dest;
1975 for (i = 0; i < n_values; i++)
1976 _dest[i] = _buffer[i];
1977 }
1978 else if (sizeof(short) == 4) {
1979 const short *_buffer = buffer;
1980 long long *_dest = dest;
1981 for (i = 0; i < n_values; i++)
1982 _dest[i] = _buffer[i];
1983 }
1984 else
1985 printf(" int32_t undefined"
1986 " (porting error, C99 compiler needed)\n");
1987 }
1988
1989 else if (type_name[0] == 'i' && type_name[1] == '8') {
1990 if (sizeof(long) == 8) {
1991 const long *_buffer = buffer;
1992 long long *_dest = dest;
1993 for (i = 0; i < n_values; i++)
1994 _dest[i] = _buffer[i];
1995 }
1996 else if (sizeof(long long) == 8) {
1997 const long long *_buffer = buffer;
1998 long long *_dest = dest;
1999 for (i = 0; i < n_values; i++)
2000 _dest[i] = _buffer[i];
2001 }
2002 else
2003 printf(" int64_t undefined"
2004 " (porting error, C99 compiler needed)\n");
2005 }
2006
2007 else if (type_name[0] == 'u' && type_name[1] == '4') {
2008 if (sizeof(unsigned) == 4) {
2009 const unsigned *_buffer = buffer;
2010 long long *_dest = dest;
2011 for (i = 0; i < n_values; i++)
2012 _dest[i] = _buffer[i];
2013 }
2014 else if (sizeof(unsigned short) == 4) {
2015 const unsigned short *_buffer = buffer;
2016 long long *_dest = dest;
2017 for (i = 0; i < n_values; i++)
2018 _dest[i] = _buffer[i];
2019 }
2020 else
2021 printf(" uint32_t undefined"
2022 " (porting error, C99 compiler needed)\n");
2023 }
2024
2025 else if (type_name[0] == 'u' && type_name[1] == '8') {
2026 if (sizeof(unsigned long) == 8) {
2027 const unsigned long *_buffer = buffer;
2028 long long *_dest = dest;
2029 for (i = 0; i < n_values; i++)
2030 _dest[i] = _buffer[i];
2031 }
2032 else if (sizeof(unsigned long long) == 8) {
2033 const unsigned long long *_buffer = buffer;
2034 long long *_dest = dest;
2035 for (i = 0; i < n_values; i++)
2036 _dest[i] = _buffer[i];
2037 }
2038 else
2039 printf(" uint64_t undefined"
2040 " (porting error, C99 compiler needed)\n");
2041 }
2042
2043 #endif /* (__STDC_VERSION__) */
2044
2045 else if (type_name[0] == 'r' && type_name[1] == '4') {
2046 const float *_buffer = buffer;
2047 double *_dest = dest;
2048 for (i = 0; i < n_values; i++)
2049 _dest[i] = _buffer[i];
2050 }
2051
2052 else if (type_name[0] == 'r' && type_name[1] == '8') {
2053 const double *_buffer = buffer;
2054 double *_dest = dest;
2055 for (i = 0; i < n_values; i++)
2056 _dest[i] = _buffer[i];
2057 }
2058
2059 }
2060
2061 /*----------------------------------------------------------------------------
2062 * Utility function to print header info for sections with differences.
2063 *
2064 * parameters:
2065 * inp1 <-- pointer to first input object
2066 * inp2 <-- pointer to second input object
2067 *----------------------------------------------------------------------------*/
2068
2069 static void
_echo_diff_headers(const _cs_io_t * inp1,const _cs_io_t * inp2)2070 _echo_diff_headers(const _cs_io_t *inp1,
2071 const _cs_io_t *inp2)
2072 {
2073 if (strcmp(inp1->type_name, inp2->type_name))
2074 printf(_(" \"%-32s\"; Location: %2lu Size: %llu\n"
2075 " Type: %-6s; | Type: %-6s; \n"),
2076 inp1->name, inp1->location_id,
2077 (unsigned long long)inp1->n_vals,
2078 inp1->type_name, inp2->type_name);
2079 else
2080 printf(_(" \"%-32s\"; Location: %2lu; Type: %-6s; Size: %llu\n"),
2081 inp1->name, inp1->location_id, inp1->type_name,
2082 (unsigned long long)inp1->n_vals);
2083 }
2084
2085 /*----------------------------------------------------------------------------
2086 * Compare character data from 2 cs_io_t section buffers in different files
2087 *
2088 * parameters:
2089 * inp1 <-> pointer to first input object
2090 * inp2 <-> pointer to second input object
2091 * cmp1 <-- buffer with characters from first file
2092 * cmp1 <-- buffer with characters from second file
2093 * block_start <-- buffer start id in total array
2094 * block_size <-- buffer size
2095 * n_echo <-- number of values to echo
2096 * n_echo_cur <-> number of values already echoed
2097 *
2098 * returns:
2099 * number of different values
2100 *----------------------------------------------------------------------------*/
2101
2102 static size_t
_compare_chars(_cs_io_t * inp1,_cs_io_t * inp2,const char cmp1[],const char cmp2[],size_t block_start,size_t block_size,size_t n_echo,long long * n_echo_cur)2103 _compare_chars(_cs_io_t *inp1,
2104 _cs_io_t *inp2,
2105 const char cmp1[],
2106 const char cmp2[],
2107 size_t block_start,
2108 size_t block_size,
2109 size_t n_echo,
2110 long long *n_echo_cur)
2111 {
2112 size_t i;
2113 size_t n_diffs = 0;
2114
2115 for (i = 0; i < block_size; i++) {
2116 if (cmp1[i] != cmp2[i])
2117 n_diffs++;
2118 }
2119
2120 if (n_diffs > 0) {
2121
2122 if (*n_echo_cur < 0) {
2123 _echo_diff_headers(inp1, inp2);
2124 *n_echo_cur = 0;
2125 }
2126
2127 for (i = 0; i < block_size && (size_t)(*n_echo_cur) < n_echo; i++) {
2128 if (cmp1[i] != cmp2[i]) {
2129 unsigned long long j = block_start + i + 1;
2130 printf(" %12llu: %c | %c\n", j, cmp1[i], cmp2[i]);
2131 *n_echo_cur += 1;
2132 }
2133 }
2134 }
2135
2136 return n_diffs;
2137 }
2138
2139 /*----------------------------------------------------------------------------
2140 * Compare character data from 2 cs_io_t section buffers in different files
2141 *
2142 * parameters:
2143 * inp1 <-> pointer to first input object
2144 * inp2 <-> pointer to second input object
2145 * cmp1 <-- buffer with integers from first file
2146 * cmp1 <-- buffer with integers from second file
2147 * block_start <-- buffer start id in total array
2148 * block_size <-- buffer size
2149 * n_echo <-- number of values to echo
2150 * n_echo_cur <-> number of values already echoed
2151 *
2152 * returns:
2153 * number of different values
2154 *----------------------------------------------------------------------------*/
2155
2156 static size_t
_compare_ints(_cs_io_t * inp1,_cs_io_t * inp2,const long long cmp1[],const long long cmp2[],size_t block_start,size_t block_size,size_t n_echo,long long * n_echo_cur)2157 _compare_ints(_cs_io_t *inp1,
2158 _cs_io_t *inp2,
2159 const long long cmp1[],
2160 const long long cmp2[],
2161 size_t block_start,
2162 size_t block_size,
2163 size_t n_echo,
2164 long long *n_echo_cur)
2165 {
2166 size_t i;
2167 size_t n_diffs = 0;
2168
2169 for (i = 0; i < block_size; i++) {
2170 if (cmp1[i] != cmp2[i])
2171 n_diffs++;
2172 }
2173
2174 if (n_diffs > 0) {
2175
2176 if (*n_echo_cur < 0) {
2177 _echo_diff_headers(inp1, inp2);
2178 *n_echo_cur = 0;
2179 }
2180
2181 for (i = 0; i < block_size && (size_t)(*n_echo_cur) < n_echo; i++) {
2182 if (cmp1[i] != cmp2[i]) {
2183 unsigned long long j = block_start + i + 1;
2184 printf(" %12llu: %lld | %lld\n", j, cmp1[i], cmp2[i]);
2185 *n_echo_cur += 1;
2186 }
2187 }
2188 }
2189
2190 return n_diffs;
2191 }
2192
2193 /*----------------------------------------------------------------------------
2194 * Compare floating-point data from 2 cs_io_t section buffers in different
2195 * files
2196 *
2197 * parameters:
2198 * inp1 <-> pointer to first input object
2199 * inp2 <-> pointer to second input object
2200 * cmp1 <-- buffer with integers from first file
2201 * cmp1 <-- buffer with integers from second file
2202 * f_fmt <-- if != NULL, format for output of floating-point values
2203 * f_threshold <-- threshold above which 2 floating-point values are
2204 * considered different.
2205 * block_start <-- buffer start id in total array
2206 * block_size <-- buffer size
2207 * n_echo <-- number of values to echo
2208 * n_echo_cur <-> number of values already echoed
2209 * f_stats <-> max, total, max relative, total relative difference
2210 *
2211 * returns:
2212 * number of different values
2213 *----------------------------------------------------------------------------*/
2214
2215 static size_t
_compare_floats(_cs_io_t * inp1,_cs_io_t * inp2,const double cmp1[],const double cmp2[],const char * f_fmt,double f_threshold,size_t block_start,size_t block_size,size_t n_echo,long long * n_echo_cur,double f_stats[4])2216 _compare_floats(_cs_io_t *inp1,
2217 _cs_io_t *inp2,
2218 const double cmp1[],
2219 const double cmp2[],
2220 const char *f_fmt,
2221 double f_threshold,
2222 size_t block_start,
2223 size_t block_size,
2224 size_t n_echo,
2225 long long *n_echo_cur,
2226 double f_stats[4])
2227 {
2228 size_t i;
2229 size_t n_diffs = 0;
2230
2231 for (i = 0; i < block_size; i++) {
2232 double delta = cmp1[i] - cmp2[i];
2233 if (delta < 0.0)
2234 delta = -delta;
2235 if (delta > f_threshold) {
2236 double delta_r = delta / CS_MAX(CS_ABS(cmp1[i]), CS_ABS(cmp2[i]));
2237 n_diffs++;
2238 if (delta > f_stats[0])
2239 f_stats[0] = delta;
2240 if (delta_r > f_stats[2])
2241 f_stats[2] = delta_r;
2242 f_stats[1] += delta;
2243 f_stats[3] += delta_r;
2244 }
2245 }
2246
2247 if (n_diffs > 0) {
2248
2249 char fmt[128] = " %12llu: %22.15e | %22.15e\n";
2250
2251 if (f_fmt != NULL) {
2252 strcpy(fmt, " %12llu: %");
2253 strcat(fmt, f_fmt);
2254 strcat(fmt, " | %");
2255 strcat(fmt, f_fmt);
2256 strcat(fmt, "\n");
2257 }
2258
2259 if (*n_echo_cur < 0) {
2260 _echo_diff_headers(inp1, inp2);
2261 *n_echo_cur = 0;
2262 }
2263
2264 for (i = 0; i < block_size && (size_t)(*n_echo_cur) < n_echo; i++) {
2265 double delta = cmp1[i] - cmp2[i];
2266 if (delta < 0.0)
2267 delta = -delta;
2268 if (delta > f_threshold) {
2269 unsigned long long j = block_start + i + 1;
2270 printf(fmt, j, cmp1[i], cmp2[i]);
2271 *n_echo_cur += 1;
2272 }
2273 }
2274 }
2275
2276 return n_diffs;
2277 }
2278
2279 /*----------------------------------------------------------------------------
2280 * Compare data from 2 cs_io_t sections in different files
2281 *
2282 * This function is expected to be called for sections with identical
2283 * names and locations.
2284 *
2285 * parameters:
2286 * inp1 <-> pointer to first input object
2287 * inp2 <-> pointer to second input object
2288 * id1 <-- id of section in first input
2289 * id2 <-- id of section in second input
2290 * f_fmt <-- if != NULL, format for output of floating-point values
2291 * f_threshold <-- threshold above which 2 floating-point values are
2292 * considered different.
2293 * n_echo <-- maximum number of differences to output
2294 *
2295 * returns:
2296 * 1 if data differs, 0 otherwise
2297 *----------------------------------------------------------------------------*/
2298
2299 static int
_compare_sections(_cs_io_t * inp1,_cs_io_t * inp2,size_t id1,size_t id2,const char * f_fmt,double f_threshold,size_t n_echo)2300 _compare_sections(_cs_io_t *inp1,
2301 _cs_io_t *inp2,
2302 size_t id1,
2303 size_t id2,
2304 const char *f_fmt,
2305 double f_threshold,
2306 size_t n_echo)
2307 {
2308 char compare_type1 = ' ', compare_type2 = ' ';
2309 int retval = 0;
2310 const char no_type[] = " ";
2311 const _cs_io_sec_index_t *index1 = inp1->index;
2312 const _cs_io_sec_index_t *index2 = inp2->index;
2313 const long long *h_vals1 = index1->h_vals + id1*8;
2314 const long long *h_vals2 = index2->h_vals + id2*8;
2315 const char *type1 = no_type;
2316 const char *type2 = no_type;
2317 const unsigned long long n_vals1 = h_vals1[0];
2318 const unsigned long long n_vals2 = h_vals2[0];
2319 const char *name = index1->names + h_vals1[4];
2320 const unsigned long location = h_vals1[1];
2321
2322 /* If both sections have zero elements, they are identical
2323 (as their names have already been compared) */
2324
2325 if (n_vals1 == 0 && n_vals2 == 0)
2326 return 0;
2327
2328 /* Determine "equivalent" types for comparison; to reduce combinations,
2329 we will transform floats to doubles, and all integer
2330 types to 64-bit signed integers */
2331
2332 if (n_vals1 > 0) {
2333 type1 = index1->types + h_vals1[5];
2334 compare_type1 = type1[0];
2335 if (type1[0] == 'u')
2336 compare_type1 = 'i';
2337 }
2338 if (n_vals2 > 0) {
2339 type2 = index2->types + h_vals2[5];
2340 compare_type2 = type2[0];
2341 if (type2[0] == 'u')
2342 compare_type2 = 'i';
2343 }
2344
2345 /* If number differs or types are incompatible, sections differ */
2346
2347 if (n_vals1 != n_vals2 || compare_type1 != compare_type2) {
2348 if (n_vals1 == n_vals2)
2349 printf(_(" \"%-32s\"; Location: %2lu; Size: %llu\n"
2350 " Type: %-6s; | Type: %-6s\n\n"),
2351 name, location, n_vals1, type1, type2);
2352 else if (!strcmp(type1, type2))
2353 printf(_(" \"%-32s\"; Location: %2lu; Type: %-6s\n"
2354 " Size: %llu | Size: %llu\n\n"),
2355 name, location, type1, n_vals1, n_vals2);
2356 else
2357 printf(_(" \"%-32s\"; Location: %2lu\n"
2358 " Type: %-6s; Size: %llu | Type: %-6s; Size: %llu\n\n"),
2359 name, location, type1, n_vals1, type2, n_vals2);
2360 return 1;
2361 }
2362
2363 /* If sections are comparable, their contents must be compared */
2364
2365 else {
2366
2367 unsigned long long n_diffs = 0;
2368 unsigned long long n_read = 0;
2369 long long n_echo_cur = -1;
2370 size_t block_size = n_vals1;
2371 size_t max_block_size = 2 << 16;
2372 void *buf1 = NULL, *buf2 = NULL;
2373 void *cmp1 = NULL, *cmp2 = NULL;
2374 double f_stats[4] = {0.0, 0.0, 0.0, 0.0};
2375 const size_t type_size1 = _type_size_from_name(type1);
2376 const size_t type_size2 = _type_size_from_name(type2);
2377
2378 _set_indexed_section(inp1, id1);
2379 _set_indexed_section(inp2, id2);
2380
2381 if (inp1->data == NULL && inp2->data == NULL && block_size > max_block_size)
2382 block_size = max_block_size;
2383
2384 MEM_MALLOC(cmp1, block_size*8, unsigned char);
2385 MEM_MALLOC(cmp2, block_size*8, unsigned char);
2386
2387 if (inp1->data == NULL) {
2388 MEM_MALLOC(buf1, block_size*type_size1, unsigned char);
2389 _file_seek(inp1, inp1->offset, SEEK_SET);
2390 }
2391 else
2392 buf1 = inp1->data;
2393
2394 if (inp2->data == NULL) {
2395 MEM_MALLOC(buf2, block_size*type_size2, unsigned char);
2396 _file_seek(inp2, inp2->offset, SEEK_SET);
2397 }
2398 else
2399 buf2 = inp2->data;
2400
2401 for (n_read = 0; n_read < n_vals1; n_read += block_size) {
2402
2403 if (n_read + block_size > n_vals1)
2404 block_size = n_vals1 - n_read;
2405
2406 if (inp1->data == NULL)
2407 _file_read(buf1, inp1->type_size, block_size, inp1);
2408 if (inp2->data == NULL)
2409 _file_read(buf2, inp2->type_size, block_size, inp2);
2410
2411 _copy_to_cmp(cmp1, buf1, type1, block_size);
2412 _copy_to_cmp(cmp2, buf2, type2, block_size);
2413
2414 if (compare_type1 == 'c')
2415 n_diffs += _compare_chars(inp1, inp2,
2416 cmp1, cmp2,
2417 n_read, block_size,
2418 n_echo, &n_echo_cur);
2419 else if (compare_type1 == 'i')
2420 n_diffs += _compare_ints(inp1, inp2,
2421 cmp1, cmp2,
2422 n_read, block_size,
2423 n_echo, &n_echo_cur);
2424 else if (compare_type1 == 'r')
2425 n_diffs += _compare_floats(inp1, inp2,
2426 cmp1, cmp2,
2427 f_fmt,
2428 f_threshold,
2429 n_read, block_size,
2430 n_echo, &n_echo_cur,
2431 f_stats);
2432 }
2433
2434 if (n_diffs > 0) {
2435 if (type1[0] == 'r')
2436 printf(_(" Differences: %llu; Max: %g; Mean: %g; "
2437 "Rel Max: %6.2e; Rel Mean: %6.2e\n\n"),
2438 n_diffs, f_stats[0], f_stats[1]/n_diffs,
2439 f_stats[2], f_stats[3]/n_diffs);
2440 else
2441 printf(_(" Differences: %llu\n\n"), n_diffs);
2442 retval = 1;
2443 }
2444
2445 MEM_FREE(cmp1);
2446 MEM_FREE(cmp2);
2447
2448 if (buf1 != inp1->data)
2449 MEM_FREE(buf1);
2450 if (buf2 != inp2->data)
2451 MEM_FREE(buf2);
2452 }
2453
2454 return retval;
2455 }
2456
2457 /*----------------------------------------------------------------------------
2458 * Compare data from 2 cs_io_t structures whose indexes have been built
2459 *
2460 * parameters:
2461 * index <-- pointer to first index
2462 * id <-- id of section in index
2463 *----------------------------------------------------------------------------*/
2464
2465 static void
_echo_indexed_header(const _cs_io_sec_index_t * index,const size_t id)2466 _echo_indexed_header(const _cs_io_sec_index_t *index,
2467 const size_t id)
2468 {
2469 const long long *h_vals = index->h_vals + id*8;
2470 const char *name = index->names + h_vals[4];
2471 const long long n_vals = h_vals[0];
2472
2473 if (n_vals > 0) {
2474 const char *type = index->types + h_vals[5];
2475 const unsigned long location = h_vals[1];
2476 printf(_(" \"%-32s\"; Type: %-6s; Location: %2lu; Size: %llu\n"),
2477 name, type, location, n_vals);
2478 }
2479 else
2480 printf(_(" \"%-32s\"\n"), name);
2481 }
2482
2483 /*----------------------------------------------------------------------------
2484 * Compare data from 2 cs_io_t structures whose indexes have been built
2485 *
2486 * parameters:
2487 * inp1 <-> pointer to first input object
2488 * inp2 <-> pointer to second input object
2489 * location_id <-- if >= 0 location id filter
2490 * sec_name <-- if != NULL, section name filter
2491 * f_fmt <-- if != NULL, format for output of floating-point values
2492 * f_threshold <-- threshold above which 2 floating-point values are
2493 * considered different.
2494 * n_echo <-- maximum number of differences to output
2495 *
2496 * returns:
2497 * 0 if contents are identical, 1 if they differ
2498 *----------------------------------------------------------------------------*/
2499
2500 static int
_compare_files(_cs_io_t * inp1,_cs_io_t * inp2,int location_id,const char * sec_name,const char * f_fmt,double f_threshold,size_t n_echo)2501 _compare_files(_cs_io_t *inp1,
2502 _cs_io_t *inp2,
2503 int location_id,
2504 const char *sec_name,
2505 const char *f_fmt,
2506 double f_threshold,
2507 size_t n_echo)
2508 {
2509 size_t i, j;
2510 size_t n_diffs = 0;
2511 int has_unmatched1 = 0, has_unmatched2 = 0;
2512 int *compared1 = NULL, *compared2 = NULL;
2513 _cs_io_sec_index_t *index1 = inp1->index;
2514 _cs_io_sec_index_t *index2 = inp2->index;
2515
2516 int retval = 0;
2517
2518 /* Prepare marker on first file to flag sections with no match in
2519 second file, and marker on second file to flag sections compared
2520 during loop on first file. */
2521
2522 MEM_MALLOC(compared1, index1->size, int);
2523 for (i = 0; i < index1->size; i++)
2524 compared1[i] = 0;
2525
2526 MEM_MALLOC(compared2, index2->size, int);
2527 for (i = 0; i < index2->size; i++)
2528 compared2[i] = 0;
2529
2530 /* Find matching sections */
2531
2532 for (i = 0; i < index1->size; i++) {
2533
2534 int match_filter = 1;
2535 const long long *h_vals1 = index1->h_vals + i*8;
2536 const char *_name1 = index1->names + h_vals1[4];
2537 const int _location1 = h_vals1[1];
2538
2539 if (sec_name != NULL && strcmp(sec_name, _name1))
2540 match_filter = 0;
2541 if (location_id >= 0 && location_id != _location1)
2542 match_filter = 0;
2543
2544 /* Search for matching section in second file */
2545
2546 if (match_filter == 1) {
2547
2548 for (j = 0; j < index2->size; j++) {
2549
2550 const long long *h_vals2 = index2->h_vals + j*8;
2551 const char *_name2 = index2->names + h_vals2[4];
2552 const int _location2 = h_vals2[1];
2553
2554 /* If matching section is found, compare it */
2555
2556 if (!strcmp(_name1, _name2) && (_location1 == _location2)) {
2557 n_diffs += _compare_sections(inp1, inp2, i, j,
2558 f_fmt, f_threshold, n_echo);
2559 compared1[i] = 1;
2560 compared2[j] = 1;
2561 }
2562 }
2563 }
2564 else
2565 compared1[i] = 1;
2566 }
2567
2568 /* List unmatched sections from first file */
2569
2570 for (i = 0; i < index1->size; i++) {
2571 if (!compared1[i])
2572 has_unmatched1 = 1;
2573 }
2574
2575 if (has_unmatched1) {
2576
2577 printf(_("Sections only found in file \"%s\":\n\n"), inp1->filename);
2578
2579 for (i = 0; i < index1->size; i++) {
2580 if (!compared1[i])
2581 _echo_indexed_header(index1, i);
2582 }
2583
2584 printf("\n");
2585 }
2586
2587 /* List unmatched sections from second file */
2588
2589 for (i = 0; i < index2->size; i++) {
2590
2591 const long long *h_vals2 = index2->h_vals + i*8;
2592 const char *_name2 = index2->names + h_vals2[4];
2593 const int _location2 = h_vals2[1];
2594
2595 if ( (sec_name != NULL && strcmp(sec_name, _name2))
2596 || (location_id >= 0 && location_id != _location2))
2597 compared2[i] = 1;
2598
2599 else if (!compared2[i])
2600 has_unmatched2 = 1;
2601 }
2602
2603 if (has_unmatched2) {
2604
2605 printf(_("Sections only found in file \"%s\":\n\n"), inp2->filename);
2606
2607 for (i = 0; i < index2->size; i++) {
2608 if (!compared2[i])
2609 _echo_indexed_header(index2, i);
2610 }
2611 }
2612
2613 MEM_FREE(compared1);
2614 MEM_FREE(compared2);
2615
2616 if (n_diffs > 0 || has_unmatched1 || has_unmatched2)
2617 retval = 1;
2618
2619 return retval;
2620 }
2621
2622 /*! (DOXYGEN_SHOULD_SKIP_THIS) \endcond */
2623
2624 /*============================================================================
2625 * Public function definitions
2626 *============================================================================*/
2627
2628 int
main(int argc,char * argv[])2629 main (int argc, char *argv[])
2630 {
2631 int file_name_arg[2] = {0, 0};
2632 size_t echo = 0;
2633 int mode = 0, location_id = -1, sec_name_arg_id = 0, f_fmt_arg_id = 0;
2634 double f_threshold = 1.e-30;
2635
2636 long long start_offset = 0, end_offset = 0;
2637 _cs_io_t inp;
2638
2639 int retval = EXIT_SUCCESS;
2640
2641 const char *sec_name = NULL, *f_fmt = NULL;
2642
2643 if (getenv("LANG") != NULL)
2644 setlocale(LC_ALL,"");
2645 else
2646 setlocale(LC_ALL,"C");
2647 setlocale(LC_NUMERIC,"C");
2648
2649 #if defined(ENABLE_NLS)
2650 bindtextdomain(PACKAGE, LOCALEDIR);
2651 textdomain(PACKAGE);
2652 #endif
2653
2654 /* Parse command line arguments */
2655
2656 _read_args(argc,
2657 argv,
2658 &mode,
2659 &echo,
2660 &location_id,
2661 &sec_name_arg_id,
2662 &f_fmt_arg_id,
2663 &f_threshold,
2664 file_name_arg);
2665
2666 if (sec_name_arg_id > 0)
2667 sec_name = argv[sec_name_arg_id];
2668
2669 if (f_fmt_arg_id > 0)
2670 f_fmt = argv[f_fmt_arg_id];
2671
2672 /* Initialize return arguments */
2673
2674 inp = _open_input(argv[file_name_arg[0]], mode);
2675
2676 /* Determine end of file;
2677 feof() may not work when using seeks,
2678 so we determine the size of the file first */
2679
2680 start_offset = _file_tell(&inp);
2681 _file_seek(&inp, 0, SEEK_END);
2682 end_offset = _file_tell(&inp);
2683 _file_seek(&inp, start_offset, SEEK_SET);
2684
2685 /* Standard dump mode */
2686
2687 if (mode == 0) {
2688
2689 /* Read file sections (or portions thereof) */
2690
2691 while ( _file_tell(&inp) + (long long)(inp.header_size)
2692 <= end_offset)
2693 _read_section(&inp, echo, location_id, sec_name, f_fmt);
2694
2695 }
2696
2697 /* Extraction mode (build index to check for duplicates and find section) */
2698
2699 else if (mode == 1) {
2700 _create_index(&inp, end_offset);
2701 _find_and_extract_section(&inp, location_id, sec_name, f_fmt);
2702 _destroy_index(&inp);
2703 }
2704
2705 /* Diff mode */
2706
2707 else if (mode == 2) {
2708
2709 long long _start_offset = 0, _end_offset = 0;
2710 _cs_io_t inp2 = _open_input(argv[file_name_arg[1]], mode);
2711
2712 /* Determine end of file as for first file */
2713 _start_offset = _file_tell(&inp);
2714 _file_seek(&inp2, 0, SEEK_END);
2715 _end_offset = _file_tell(&inp2);
2716 _file_seek(&inp2, _start_offset, SEEK_SET);
2717
2718 /* Create indexes for both files */
2719
2720 _create_index(&inp, end_offset);
2721 _create_index(&inp2, _end_offset);
2722
2723 printf("\n");
2724
2725 retval = _compare_files(&inp, &inp2, location_id, sec_name,
2726 f_fmt, f_threshold, echo);
2727
2728 _destroy_index(&inp2);
2729 _destroy_index(&inp);
2730
2731 printf("\n");
2732
2733 _close_input(&inp2, mode);
2734 }
2735
2736 /* Clean-up */
2737
2738 _close_input(&inp, mode);
2739
2740 exit(retval);
2741 }
2742
2743 /*----------------------------------------------------------------------------*/
2744
2745 END_C_DECLS
2746