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