1 /*
2  * Copyright (c) 2009-2018 Tony Bybell.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20  * DEALINGS IN THE SOFTWARE.
21  *
22  * SPDX-License-Identifier: MIT
23  */
24 
25 /*
26  * possible disables:
27  *
28  * FST_DYNAMIC_ALIAS_DISABLE : dynamic aliases are not processed
29  * FST_DYNAMIC_ALIAS2_DISABLE : new encoding for dynamic aliases is not generated
30  * FST_WRITEX_DISABLE : fast write I/O routines are disabled
31  *
32  * possible enables:
33  *
34  * FST_DEBUG : not for production use, only enable for development
35  * FST_REMOVE_DUPLICATE_VC : glitch removal (has writer performance impact)
36  * HAVE_LIBPTHREAD -> FST_WRITER_PARALLEL : enables inclusion of parallel writer code
37  * FST_DO_MISALIGNED_OPS (defined automatically for x86 and some others) : CPU architecture can handle misaligned loads/stores
38  * _WAVE_HAVE_JUDY : use Judy arrays instead of Jenkins (undefine if LGPL is not acceptable)
39  *
40  */
41 
42 #ifndef FST_CONFIG_INCLUDE
43 # define FST_CONFIG_INCLUDE <config.h>
44 #endif
45 #include FST_CONFIG_INCLUDE
46 
47 #include "fstapi.h"
48 #include "fastlz.h"
49 #include "lz4.h"
50 #include <errno.h>
51 
52 #ifndef HAVE_LIBPTHREAD
53 #undef FST_WRITER_PARALLEL
54 #endif
55 
56 #ifdef FST_WRITER_PARALLEL
57 #include <pthread.h>
58 #endif
59 
60 #ifdef __MINGW32__
61 #include <windows.h>
62 #endif
63 
64 #ifdef HAVE_ALLOCA_H
65 #include <alloca.h>
66 #elif defined(__GNUC__)
67 #ifndef __MINGW32__
68 #ifndef alloca
69 #define alloca __builtin_alloca
70 #endif
71 #else
72 #include <malloc.h>
73 #endif
74 #elif defined(_MSC_VER)
75 #include <malloc.h>
76 #define alloca _alloca
77 #endif
78 
79 #ifndef PATH_MAX
80 #define PATH_MAX (4096)
81 #endif
82 
83 #if defined(_MSC_VER)
84 typedef int64_t fst_off_t;
85 #else
86 typedef off_t fst_off_t;
87 #endif
88 
89 /* note that Judy versus Jenkins requires more experimentation: they are  */
90 /* functionally equivalent though it appears Jenkins is slightly faster.  */
91 /* in addition, Jenkins is not bound by the LGPL.                         */
92 #ifdef _WAVE_HAVE_JUDY
93 #include <Judy.h>
94 #else
95 /* should be more than enough for fstWriterSetSourceStem() */
96 #define FST_PATH_HASHMASK               ((1UL << 16) - 1)
97 typedef const void *Pcvoid_t;
98 typedef void *Pvoid_t;
99 typedef void **PPvoid_t;
100 #define JudyHSIns(a,b,c,d) JenkinsIns((a),(b),(c),(hashmask))
101 #define JudyHSFreeArray(a,b) JenkinsFree((a),(hashmask))
102 void JenkinsFree(void *base_i, uint32_t hashmask);
103 void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask);
104 #endif
105 
106 
107 #ifndef FST_WRITEX_DISABLE
108 #define FST_WRITEX_MAX                  (64 * 1024)
109 #else
110 #define fstWritex(a,b,c) fstFwrite((b), (c), 1, fv)
111 #endif
112 
113 
114 /* these defines have a large impact on writer speed when a model has a */
115 /* huge number of symbols.  as a default, use 128MB and increment when  */
116 /* every 1M signals are defined.                                        */
117 #define FST_BREAK_SIZE                  (1UL << 27)
118 #define FST_BREAK_ADD_SIZE              (1UL << 22)
119 #define FST_BREAK_SIZE_MAX              (1UL << 31)
120 #define FST_ACTIVATE_HUGE_BREAK         (1000000)
121 #define FST_ACTIVATE_HUGE_INC           (1000000)
122 
123 #define FST_WRITER_STR                  "fstWriter"
124 #define FST_ID_NAM_SIZ                  (512)
125 #define FST_ID_NAM_ATTR_SIZ             (65536+4096)
126 #define FST_DOUBLE_ENDTEST              (2.7182818284590452354)
127 #define FST_HDR_SIM_VERSION_SIZE        (128)
128 #define FST_HDR_DATE_SIZE               (119)
129 #define FST_HDR_FILETYPE_SIZE           (1)
130 #define FST_HDR_TIMEZERO_SIZE           (8)
131 #define FST_GZIO_LEN                    (32768)
132 #define FST_HDR_FOURPACK_DUO_SIZE       (4*1024*1024)
133 
134 #if defined(__i386__) || defined(__x86_64__) || defined(_AIX)
135 #define FST_DO_MISALIGNED_OPS
136 #endif
137 
138 #if defined(__APPLE__) && defined(__MACH__)
139 #define FST_MACOSX
140 #include <sys/sysctl.h>
141 #endif
142 
143 #ifdef __GNUC__
144 /* Boolean expression more often true than false */
145 #define FST_LIKELY(x) __builtin_expect(!!(x), 1)
146 /* Boolean expression more often false than true */
147 #define FST_UNLIKELY(x) __builtin_expect(!!(x), 0)
148 #else
149 #define FST_LIKELY(x) (!!(x))
150 #define FST_UNLIKELY(x) (!!(x))
151 #endif
152 
153 #define FST_APIMESS "FSTAPI  | "
154 
155 /***********************/
156 /***                 ***/
157 /*** common function ***/
158 /***                 ***/
159 /***********************/
160 
161 #ifdef __MINGW32__
162 #include <io.h>
163 #ifndef HAVE_FSEEKO
164 #define ftello _ftelli64
165 #define fseeko _fseeki64
166 #endif
167 #endif
168 
169 /*
170  * the recoded "extra" values...
171  * note that FST_RCV_Q is currently unused and is for future expansion.
172  * its intended use is as another level of escape such that any arbitrary
173  * value can be stored as the value: { time_delta, 8 bits, FST_RCV_Q }.
174  * this is currently not implemented so that the branchless decode is:
175  * uint32_t shcnt = 2 << (vli & 1); tdelta = vli >> shcnt;
176  */
177 #define FST_RCV_X (1 | (0<<1))
178 #define FST_RCV_Z (1 | (1<<1))
179 #define FST_RCV_H (1 | (2<<1))
180 #define FST_RCV_U (1 | (3<<1))
181 #define FST_RCV_W (1 | (4<<1))
182 #define FST_RCV_L (1 | (5<<1))
183 #define FST_RCV_D (1 | (6<<1))
184 #define FST_RCV_Q (1 | (7<<1))
185 
186 #define FST_RCV_STR "xzhuwl-?"
187 /*                   01234567 */
188 
189 
190 /*
191  * prevent old file overwrite when currently being read
192  */
unlink_fopen(const char * nam,const char * mode)193 static FILE *unlink_fopen(const char *nam, const char *mode)
194 {
195 unlink(nam);
196 return(fopen(nam, mode));
197 }
198 
199 
200 /*
201  * system-specific temp file handling
202  */
203 #ifdef __MINGW32__
204 
tmpfile_open(char ** nam)205 static FILE* tmpfile_open(char **nam)
206 {
207 char *fname = NULL;
208 TCHAR szTempFileName[MAX_PATH];
209 TCHAR lpTempPathBuffer[MAX_PATH];
210 DWORD dwRetVal = 0;
211 UINT uRetVal = 0;
212 FILE *fh = NULL;
213 
214 if(nam) /* cppcheck warning fix: nam is always defined, so this is not needed */
215         {
216         dwRetVal = GetTempPath(MAX_PATH, lpTempPathBuffer);
217         if((dwRetVal > MAX_PATH) || (dwRetVal == 0))
218                 {
219                 fprintf(stderr, FST_APIMESS "GetTempPath() failed in " __FILE__ " line %d, exiting.\n", __LINE__);
220                 exit(255);
221                 }
222                 else
223                 {
224                 uRetVal = GetTempFileName(lpTempPathBuffer, TEXT("FSTW"), 0, szTempFileName);
225                 if (uRetVal == 0)
226                         {
227                         fprintf(stderr, FST_APIMESS "GetTempFileName() failed in " __FILE__ " line %d, exiting.\n", __LINE__);
228                         exit(255);
229                         }
230                         else
231                         {
232                         fname = strdup(szTempFileName);
233                         }
234                 }
235 
236         if(fname)
237                 {
238                 *nam = fname;
239                 fh = unlink_fopen(fname, "w+b");
240                 }
241         }
242 
243 return(fh);
244 }
245 
246 #else
247 
tmpfile_open(char ** nam)248 static FILE* tmpfile_open(char **nam)
249 {
250 FILE *f = tmpfile(); /* replace with mkstemp() + fopen(), etc if this is not good enough */
251 if(nam) { *nam = NULL; }
252 return(f);
253 }
254 
255 #endif
256 
257 
tmpfile_close(FILE ** f,char ** nam)258 static void tmpfile_close(FILE **f, char **nam)
259 {
260 if(f)
261         {
262         if(*f) { fclose(*f); *f = NULL; }
263         }
264 
265 if(nam)
266         {
267         if(*nam)
268                 {
269                 unlink(*nam);
270                 free(*nam);
271                 *nam = NULL;
272                 }
273         }
274 }
275 
276 /*****************************************/
277 
278 
279 /*
280  * to remove warn_unused_result compile time messages
281  * (in the future there needs to be results checking)
282  */
fstFread(void * buf,size_t siz,size_t cnt,FILE * fp)283 static size_t fstFread(void *buf, size_t siz, size_t cnt, FILE *fp)
284 {
285 return(fread(buf, siz, cnt, fp));
286 }
287 
fstFwrite(const void * buf,size_t siz,size_t cnt,FILE * fp)288 static size_t fstFwrite(const void *buf, size_t siz, size_t cnt, FILE *fp)
289 {
290 return(fwrite(buf, siz, cnt, fp));
291 }
292 
fstFtruncate(int fd,fst_off_t length)293 static int fstFtruncate(int fd, fst_off_t length)
294 {
295 return(ftruncate(fd, length));
296 }
297 
298 
299 /*
300  * realpath compatibility
301  */
fstRealpath(const char * path,char * resolved_path)302 static char *fstRealpath(const char *path, char *resolved_path)
303 {
304 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __CYGWIN__ || defined HAVE_REALPATH
305 #if (defined(__MACH__) && defined(__APPLE__))
306 if(!resolved_path)
307         {
308         resolved_path = (char *)malloc(PATH_MAX+1); /* fixes bug on Leopard when resolved_path == NULL */
309         }
310 #endif
311 
312 return(realpath(path, resolved_path));
313 
314 #else
315 #ifdef __MINGW32__
316 if(!resolved_path)
317         {
318         resolved_path = (char *)malloc(PATH_MAX+1);
319         }
320 return(_fullpath(resolved_path, path, PATH_MAX));
321 #else
322 (void)path;
323 (void)resolved_path;
324 return(NULL);
325 #endif
326 #endif
327 }
328 
329 
330 /*
331  * mmap compatibility
332  */
333 #if defined __CYGWIN__ || defined __MINGW32__
334 #include <limits.h>
335 #define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off))
336 #define fstMunmap(__addr,__len)                         free(__addr)
337 
fstMmap2(size_t __len,int __fd,fst_off_t __off)338 static void *fstMmap2(size_t __len, int __fd, fst_off_t __off)
339 {
340 (void)__off;
341 
342 unsigned char *pnt = (unsigned char *)malloc(__len);
343 fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
344 size_t i;
345 
346 lseek(__fd, 0, SEEK_SET);
347 for(i=0;i<__len;i+=SSIZE_MAX)
348         {
349         read(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
350         }
351 lseek(__fd, cur_offs, SEEK_SET);
352 return(pnt);
353 }
354 #else
355 #include <sys/mman.h>
356 #if defined(__SUNPRO_C)
357 #define FST_CADDR_T_CAST (caddr_t)
358 #else
359 #define FST_CADDR_T_CAST
360 #endif
361 #define fstMmap(__addr,__len,__prot,__flags,__fd,__off) (void*)mmap(FST_CADDR_T_CAST (__addr),(__len),(__prot),(__flags),(__fd),(__off))
362 #define fstMunmap(__addr,__len)                         { if(__addr) munmap(FST_CADDR_T_CAST (__addr),(__len)); }
363 #endif
364 
365 
366 /*
367  * regular and variable-length integer access functions
368  */
369 #ifdef FST_DO_MISALIGNED_OPS
370 #define fstGetUint32(x) (*(uint32_t *)(x))
371 #else
fstGetUint32(unsigned char * mem)372 static uint32_t fstGetUint32(unsigned char *mem)
373 {
374 uint32_t u32;
375 unsigned char *buf = (unsigned char *)(&u32);
376 
377 buf[0] = mem[0];
378 buf[1] = mem[1];
379 buf[2] = mem[2];
380 buf[3] = mem[3];
381 
382 return(*(uint32_t *)buf);
383 }
384 #endif
385 
386 
fstWriterUint64(FILE * handle,uint64_t v)387 static int fstWriterUint64(FILE *handle, uint64_t v)
388 {
389 unsigned char buf[8];
390 int i;
391 
392 for(i=7;i>=0;i--)
393         {
394         buf[i] = v & 0xff;
395         v >>= 8;
396         }
397 
398 fstFwrite(buf, 8, 1, handle);
399 return(8);
400 }
401 
402 
fstReaderUint64(FILE * f)403 static uint64_t fstReaderUint64(FILE *f)
404 {
405 uint64_t val = 0;
406 unsigned char buf[sizeof(uint64_t)];
407 unsigned int i;
408 
409 fstFread(buf, sizeof(uint64_t), 1, f);
410 for(i=0;i<sizeof(uint64_t);i++)
411         {
412         val <<= 8;
413         val |= buf[i];
414         }
415 
416 return(val);
417 }
418 
419 
fstGetVarint32(unsigned char * mem,int * skiplen)420 static uint32_t fstGetVarint32(unsigned char *mem, int *skiplen)
421 {
422 unsigned char *mem_orig = mem;
423 uint32_t rc = 0;
424 while(*mem & 0x80)
425         {
426         mem++;
427         }
428 
429 *skiplen = mem - mem_orig + 1;
430 for(;;)
431         {
432         rc <<= 7;
433         rc |= (uint32_t)(*mem & 0x7f);
434         if(mem == mem_orig)
435                 {
436                 break;
437                 }
438         mem--;
439         }
440 
441 return(rc);
442 }
443 
444 
fstGetVarint32Length(unsigned char * mem)445 static uint32_t fstGetVarint32Length(unsigned char *mem)
446 {
447 unsigned char *mem_orig = mem;
448 
449 while(*mem & 0x80)
450         {
451         mem++;
452         }
453 
454 return(mem - mem_orig + 1);
455 }
456 
457 
fstGetVarint32NoSkip(unsigned char * mem)458 static uint32_t fstGetVarint32NoSkip(unsigned char *mem)
459 {
460 unsigned char *mem_orig = mem;
461 uint32_t rc = 0;
462 while(*mem & 0x80)
463         {
464         mem++;
465         }
466 
467 for(;;)
468         {
469         rc <<= 7;
470         rc |= (uint32_t)(*mem & 0x7f);
471         if(mem == mem_orig)
472                 {
473                 break;
474                 }
475         mem--;
476         }
477 
478 return(rc);
479 }
480 
481 
fstCopyVarint32ToLeft(unsigned char * pnt,uint32_t v)482 static unsigned char *fstCopyVarint32ToLeft(unsigned char *pnt, uint32_t v)
483 {
484 unsigned char *spnt;
485 uint32_t nxt = v;
486 int cnt = 1;
487 int i;
488 
489 while((nxt = nxt>>7)) /* determine len to avoid temp buffer copying to cut down on load-hit-store */
490         {
491         cnt++;
492         }
493 
494 pnt -= cnt;
495 spnt = pnt;
496 cnt--;
497 
498 for(i=0;i<cnt;i++) /* now generate left to right as normal */
499         {
500         nxt = v>>7;
501         *(spnt++) = ((unsigned char)v) | 0x80;
502         v = nxt;
503         }
504 *spnt = (unsigned char)v;
505 
506 return(pnt);
507 }
508 
509 
fstCopyVarint64ToRight(unsigned char * pnt,uint64_t v)510 static unsigned char *fstCopyVarint64ToRight(unsigned char *pnt, uint64_t v)
511 {
512 uint64_t nxt;
513 
514 while((nxt = v>>7))
515         {
516         *(pnt++) = ((unsigned char)v) | 0x80;
517         v = nxt;
518         }
519 *(pnt++) = (unsigned char)v;
520 
521 return(pnt);
522 }
523 
524 
fstGetVarint64(unsigned char * mem,int * skiplen)525 static uint64_t fstGetVarint64(unsigned char *mem, int *skiplen)
526 {
527 unsigned char *mem_orig = mem;
528 uint64_t rc = 0;
529 while(*mem & 0x80)
530         {
531         mem++;
532         }
533 
534 *skiplen = mem - mem_orig + 1;
535 for(;;)
536         {
537         rc <<= 7;
538         rc |= (uint64_t)(*mem & 0x7f);
539         if(mem == mem_orig)
540                 {
541                 break;
542                 }
543         mem--;
544         }
545 
546 return(rc);
547 }
548 
549 
fstReaderVarint32(FILE * f)550 static uint32_t fstReaderVarint32(FILE *f)
551 {
552 unsigned char buf[5];
553 unsigned char *mem = buf;
554 uint32_t rc = 0;
555 int ch;
556 
557 do
558         {
559         ch = fgetc(f);
560         *(mem++) = ch;
561         } while(ch & 0x80);
562 mem--;
563 
564 for(;;)
565         {
566         rc <<= 7;
567         rc |= (uint32_t)(*mem & 0x7f);
568         if(mem == buf)
569                 {
570                 break;
571                 }
572         mem--;
573         }
574 
575 return(rc);
576 }
577 
578 
fstReaderVarint32WithSkip(FILE * f,uint32_t * skiplen)579 static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen)
580 {
581 unsigned char buf[5];
582 unsigned char *mem = buf;
583 uint32_t rc = 0;
584 int ch;
585 
586 do
587         {
588         ch = fgetc(f);
589         *(mem++) = ch;
590         } while(ch & 0x80);
591 *skiplen = mem - buf;
592 mem--;
593 
594 for(;;)
595         {
596         rc <<= 7;
597         rc |= (uint32_t)(*mem & 0x7f);
598         if(mem == buf)
599                 {
600                 break;
601                 }
602         mem--;
603         }
604 
605 return(rc);
606 }
607 
608 
fstReaderVarint64(FILE * f)609 static uint64_t fstReaderVarint64(FILE *f)
610 {
611 unsigned char buf[16];
612 unsigned char *mem = buf;
613 uint64_t rc = 0;
614 int ch;
615 
616 do
617         {
618         ch = fgetc(f);
619         *(mem++) = ch;
620         } while(ch & 0x80);
621 mem--;
622 
623 for(;;)
624         {
625         rc <<= 7;
626         rc |= (uint64_t)(*mem & 0x7f);
627         if(mem == buf)
628                 {
629                 break;
630                 }
631         mem--;
632         }
633 
634 return(rc);
635 }
636 
637 
fstWriterVarint(FILE * handle,uint64_t v)638 static int fstWriterVarint(FILE *handle, uint64_t v)
639 {
640 uint64_t nxt;
641 unsigned char buf[10]; /* ceil(64/7) = 10 */
642 unsigned char *pnt = buf;
643 int len;
644 
645 while((nxt = v>>7))
646         {
647         *(pnt++) = ((unsigned char)v) | 0x80;
648         v = nxt;
649         }
650 *(pnt++) = (unsigned char)v;
651 
652 len = pnt-buf;
653 fstFwrite(buf, len, 1, handle);
654 return(len);
655 }
656 
657 
658 /* signed integer read/write routines are currently unused */
fstGetSVarint64(unsigned char * mem,int * skiplen)659 static int64_t fstGetSVarint64(unsigned char *mem, int *skiplen)
660 {
661 unsigned char *mem_orig = mem;
662 int64_t rc = 0;
663 const int64_t one = 1;
664 const int siz = sizeof(int64_t) * 8;
665 int shift = 0;
666 unsigned char byt;
667 
668 do      {
669         byt = *(mem++);
670         rc |= ((int64_t)(byt & 0x7f)) << shift;
671         shift += 7;
672 
673         } while(byt & 0x80);
674 
675 if((shift<siz) && (byt & 0x40))
676         {
677         rc |= -(one << shift); /* sign extend */
678         }
679 
680 *skiplen = mem - mem_orig;
681 
682 return(rc);
683 }
684 
685 
686 #ifndef FST_DYNAMIC_ALIAS2_DISABLE
fstWriterSVarint(FILE * handle,int64_t v)687 static int fstWriterSVarint(FILE *handle, int64_t v)
688 {
689 unsigned char buf[15]; /* ceil(64/7) = 10 + sign byte padded way up */
690 unsigned char byt;
691 unsigned char *pnt = buf;
692 int more = 1;
693 int len;
694 
695 do      {
696         byt = v | 0x80;
697         v >>= 7;
698 
699         if (((!v) && (!(byt & 0x40))) || ((v == -1) && (byt & 0x40)))
700                 {
701                 more = 0;
702                 byt &= 0x7f;
703                 }
704 
705         *(pnt++) = byt;
706         } while(more);
707 
708 len = pnt-buf;
709 fstFwrite(buf, len, 1, handle);
710 return(len);
711 }
712 #endif
713 
714 
715 /***********************/
716 /***                 ***/
717 /*** writer function ***/
718 /***                 ***/
719 /***********************/
720 
721 /*
722  * private structs
723  */
724 struct fstBlackoutChain
725 {
726 struct fstBlackoutChain *next;
727 uint64_t tim;
728 unsigned active : 1;
729 };
730 
731 
732 struct fstWriterContext
733 {
734 FILE *handle;
735 FILE *hier_handle;
736 FILE *geom_handle;
737 FILE *valpos_handle;
738 FILE *curval_handle;
739 FILE *tchn_handle;
740 
741 unsigned char *vchg_mem;
742 
743 fst_off_t hier_file_len;
744 
745 uint32_t *valpos_mem;
746 unsigned char *curval_mem;
747 
748 unsigned char *outval_mem; /* for two-state / Verilator-style value changes */
749 uint32_t outval_alloc_siz;
750 
751 char *filename;
752 
753 fstHandle maxhandle;
754 fstHandle numsigs;
755 uint32_t maxvalpos;
756 
757 unsigned vc_emitted : 1;
758 unsigned is_initial_time : 1;
759 unsigned fourpack : 1;
760 unsigned fastpack : 1;
761 
762 int64_t timezero;
763 fst_off_t section_header_truncpos;
764 uint32_t tchn_cnt, tchn_idx;
765 uint64_t curtime;
766 uint64_t firsttime;
767 uint32_t vchg_siz;
768 uint32_t vchg_alloc_siz;
769 
770 uint32_t secnum;
771 fst_off_t section_start;
772 
773 uint32_t numscopes;
774 double nan; /* nan value for uninitialized doubles */
775 
776 struct fstBlackoutChain *blackout_head;
777 struct fstBlackoutChain *blackout_curr;
778 uint32_t num_blackouts;
779 
780 uint64_t dump_size_limit;
781 
782 unsigned char filetype; /* default is 0, FST_FT_VERILOG */
783 
784 unsigned compress_hier : 1;
785 unsigned repack_on_close : 1;
786 unsigned skip_writing_section_hdr : 1;
787 unsigned size_limit_locked : 1;
788 unsigned section_header_only : 1;
789 unsigned flush_context_pending : 1;
790 unsigned parallel_enabled : 1;
791 unsigned parallel_was_enabled : 1;
792 
793 /* should really be semaphores, but are bytes to cut down on read-modify-write window size */
794 unsigned char already_in_flush; /* in case control-c handlers interrupt */
795 unsigned char already_in_close; /* in case control-c handlers interrupt */
796 
797 #ifdef FST_WRITER_PARALLEL
798 pthread_mutex_t mutex;
799 pthread_t thread;
800 pthread_attr_t thread_attr;
801 struct fstWriterContext *xc_parent;
802 #endif
803 unsigned in_pthread : 1;
804 
805 size_t fst_orig_break_size;
806 size_t fst_orig_break_add_size;
807 
808 size_t fst_break_size;
809 size_t fst_break_add_size;
810 
811 size_t fst_huge_break_size;
812 
813 fstHandle next_huge_break;
814 
815 Pvoid_t path_array;
816 uint32_t path_array_count;
817 
818 unsigned fseek_failed : 1;
819 
820 char *geom_handle_nam;
821 char *valpos_handle_nam;
822 char *curval_handle_nam;
823 char *tchn_handle_nam;
824 
825 fstEnumHandle max_enumhandle;
826 };
827 
828 
fstWriterFseeko(struct fstWriterContext * xc,FILE * stream,fst_off_t offset,int whence)829 static int fstWriterFseeko(struct fstWriterContext *xc, FILE *stream, fst_off_t offset, int whence)
830 {
831 int rc = fseeko(stream, offset, whence);
832 
833 if(rc<0)
834         {
835         xc->fseek_failed = 1;
836 #ifdef FST_DEBUG
837         fprintf(stderr, FST_APIMESS "Seek to #%" PRId64 " (whence = %d) failed!\n", offset, whence);
838         perror("Why");
839 #endif
840         }
841 
842 return(rc);
843 }
844 
845 
fstWriterUint32WithVarint32(struct fstWriterContext * xc,uint32_t * u,uint32_t v,const void * dbuf,uint32_t siz)846 static uint32_t fstWriterUint32WithVarint32(struct fstWriterContext *xc, uint32_t *u, uint32_t v, const void *dbuf, uint32_t siz)
847 {
848 unsigned char *buf = xc->vchg_mem + xc->vchg_siz;
849 unsigned char *pnt = buf;
850 uint32_t nxt;
851 uint32_t len;
852 
853 #ifdef FST_DO_MISALIGNED_OPS
854 (*(uint32_t *)(pnt)) = (*(uint32_t *)(u));
855 #else
856 memcpy(pnt, u, sizeof(uint32_t));
857 #endif
858 pnt += 4;
859 
860 while((nxt = v>>7))
861         {
862         *(pnt++) = ((unsigned char)v) | 0x80;
863         v = nxt;
864         }
865 *(pnt++) = (unsigned char)v;
866 memcpy(pnt, dbuf, siz);
867 
868 len = pnt-buf + siz;
869 return(len);
870 }
871 
872 
fstWriterUint32WithVarint32AndLength(struct fstWriterContext * xc,uint32_t * u,uint32_t v,const void * dbuf,uint32_t siz)873 static uint32_t fstWriterUint32WithVarint32AndLength(struct fstWriterContext *xc, uint32_t *u, uint32_t v, const void *dbuf, uint32_t siz)
874 {
875 unsigned char *buf = xc->vchg_mem + xc->vchg_siz;
876 unsigned char *pnt = buf;
877 uint32_t nxt;
878 uint32_t len;
879 
880 #ifdef FST_DO_MISALIGNED_OPS
881 (*(uint32_t *)(pnt)) = (*(uint32_t *)(u));
882 #else
883 memcpy(pnt, u, sizeof(uint32_t));
884 #endif
885 pnt += 4;
886 
887 while((nxt = v>>7))
888         {
889         *(pnt++) = ((unsigned char)v) | 0x80;
890         v = nxt;
891         }
892 *(pnt++) = (unsigned char)v;
893 
894 v = siz;
895 while((nxt = v>>7))
896         {
897         *(pnt++) = ((unsigned char)v) | 0x80;
898         v = nxt;
899         }
900 *(pnt++) = (unsigned char)v;
901 
902 memcpy(pnt, dbuf, siz);
903 
904 len = pnt-buf + siz;
905 return(len);
906 }
907 
908 
909 /*
910  * header bytes, write here so defines are set up before anything else
911  * that needs to use them
912  */
fstWriterEmitHdrBytes(struct fstWriterContext * xc)913 static void fstWriterEmitHdrBytes(struct fstWriterContext *xc)
914 {
915 char vbuf[FST_HDR_SIM_VERSION_SIZE];
916 char dbuf[FST_HDR_DATE_SIZE];
917 double endtest = FST_DOUBLE_ENDTEST;
918 time_t walltime;
919 
920 #define FST_HDR_OFFS_TAG                        (0)
921 fputc(FST_BL_HDR, xc->handle);                  /* +0 tag */
922 
923 #define FST_HDR_OFFS_SECLEN                     (FST_HDR_OFFS_TAG + 1)
924 fstWriterUint64(xc->handle, 329);               /* +1 section length */
925 
926 #define FST_HDR_OFFS_START_TIME                 (FST_HDR_OFFS_SECLEN + 8)
927 fstWriterUint64(xc->handle, 0);                 /* +9 start time */
928 
929 #define FST_HDR_OFFS_END_TIME                   (FST_HDR_OFFS_START_TIME + 8)
930 fstWriterUint64(xc->handle, 0);                 /* +17 end time */
931 
932 #define FST_HDR_OFFS_ENDIAN_TEST                (FST_HDR_OFFS_END_TIME + 8)
933 fstFwrite(&endtest, 8, 1, xc->handle);          /* +25 endian test for reals */
934 
935 #define FST_HDR_OFFS_MEM_USED                   (FST_HDR_OFFS_ENDIAN_TEST + 8)
936 fstWriterUint64(xc->handle, xc->fst_break_size);/* +33 memory used by writer */
937 
938 #define FST_HDR_OFFS_NUM_SCOPES                 (FST_HDR_OFFS_MEM_USED + 8)
939 fstWriterUint64(xc->handle, 0);                 /* +41 scope creation count */
940 
941 #define FST_HDR_OFFS_NUM_VARS                   (FST_HDR_OFFS_NUM_SCOPES + 8)
942 fstWriterUint64(xc->handle, 0);                 /* +49 var creation count */
943 
944 #define FST_HDR_OFFS_MAXHANDLE                  (FST_HDR_OFFS_NUM_VARS + 8)
945 fstWriterUint64(xc->handle, 0);                 /* +57 max var idcode */
946 
947 #define FST_HDR_OFFS_SECTION_CNT                (FST_HDR_OFFS_MAXHANDLE + 8)
948 fstWriterUint64(xc->handle, 0);                 /* +65 vc section count */
949 
950 #define FST_HDR_OFFS_TIMESCALE                  (FST_HDR_OFFS_SECTION_CNT + 8)
951 fputc((-9)&255, xc->handle);                    /* +73 timescale 1ns */
952 
953 #define FST_HDR_OFFS_SIM_VERSION                (FST_HDR_OFFS_TIMESCALE + 1)
954 memset(vbuf, 0, FST_HDR_SIM_VERSION_SIZE);
955 strcpy(vbuf, FST_WRITER_STR);
956 fstFwrite(vbuf, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle); /* +74 version */
957 
958 #define FST_HDR_OFFS_DATE                       (FST_HDR_OFFS_SIM_VERSION + FST_HDR_SIM_VERSION_SIZE)
959 memset(dbuf, 0, FST_HDR_DATE_SIZE);
960 time(&walltime);
961 strcpy(dbuf, asctime(localtime(&walltime)));
962 fstFwrite(dbuf, FST_HDR_DATE_SIZE, 1, xc->handle);      /* +202 date */
963 
964 /* date size is deliberately overspecified at 119 bytes (originally 128) in order to provide backfill for new args */
965 
966 #define FST_HDR_OFFS_FILETYPE                   (FST_HDR_OFFS_DATE + FST_HDR_DATE_SIZE)
967 fputc(xc->filetype, xc->handle);                /* +321 filetype */
968 
969 #define FST_HDR_OFFS_TIMEZERO                   (FST_HDR_OFFS_FILETYPE + FST_HDR_FILETYPE_SIZE)
970 fstWriterUint64(xc->handle, xc->timezero);      /* +322 timezero */
971 
972 #define FST_HDR_LENGTH                          (FST_HDR_OFFS_TIMEZERO + FST_HDR_TIMEZERO_SIZE)
973                                                 /* +330 next section starts here */
974 fflush(xc->handle);
975 }
976 
977 
978 /*
979  * mmap functions
980  */
fstWriterMmapSanity(void * pnt,const char * file,int line,const char * usage)981 static void fstWriterMmapSanity(void *pnt, const char *file, int line, const char *usage)
982 {
983 #if !defined(__CYGWIN__) && !defined(__MINGW32__)
984 if(pnt == MAP_FAILED)
985 	{
986 	fprintf(stderr, "fstMmap() assigned to %s failed: errno: %d, file %s, line %d.\n", usage, errno, file, line);
987 	perror("Why");
988 	pnt = NULL;
989 	}
990 #endif
991 }
992 
993 
fstWriterCreateMmaps(struct fstWriterContext * xc)994 static void fstWriterCreateMmaps(struct fstWriterContext *xc)
995 {
996 fst_off_t curpos = ftello(xc->handle);
997 
998 fflush(xc->hier_handle);
999 
1000 /* write out intermediate header */
1001 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET);
1002 fstWriterUint64(xc->handle, xc->firsttime);
1003 fstWriterUint64(xc->handle, xc->curtime);
1004 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET);
1005 fstWriterUint64(xc->handle, xc->numscopes);
1006 fstWriterUint64(xc->handle, xc->numsigs);
1007 fstWriterUint64(xc->handle, xc->maxhandle);
1008 fstWriterUint64(xc->handle, xc->secnum);
1009 fstWriterFseeko(xc, xc->handle, curpos, SEEK_SET);
1010 fflush(xc->handle);
1011 
1012 /* do mappings */
1013 if(!xc->valpos_mem)
1014         {
1015         fflush(xc->valpos_handle);
1016 	errno = 0;
1017 	if(xc->maxhandle)
1018 		{
1019 	        fstWriterMmapSanity(xc->valpos_mem = (uint32_t *)fstMmap(NULL, xc->maxhandle * 4 * sizeof(uint32_t), PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->valpos_handle), 0), __FILE__, __LINE__, "xc->valpos_mem");
1020 		}
1021         }
1022 if(!xc->curval_mem)
1023         {
1024         fflush(xc->curval_handle);
1025 	errno = 0;
1026 	if(xc->maxvalpos)
1027 		{
1028 	        fstWriterMmapSanity(xc->curval_mem = (unsigned char *)fstMmap(NULL, xc->maxvalpos, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->curval_handle), 0), __FILE__, __LINE__, "xc->curval_handle");
1029 		}
1030         }
1031 }
1032 
1033 
fstDestroyMmaps(struct fstWriterContext * xc,int is_closing)1034 static void fstDestroyMmaps(struct fstWriterContext *xc, int is_closing)
1035 {
1036 #if !defined __CYGWIN__ && !defined __MINGW32__
1037 (void)is_closing;
1038 #endif
1039 
1040 fstMunmap(xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
1041 xc->valpos_mem = NULL;
1042 
1043 #if defined __CYGWIN__ || defined __MINGW32__
1044 if(xc->curval_mem)
1045         {
1046         if(!is_closing) /* need to flush out for next emulated mmap() read */
1047                 {
1048                 unsigned char *pnt = xc->curval_mem;
1049                 int __fd = fileno(xc->curval_handle);
1050                 fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR);
1051                 size_t i;
1052                 size_t __len = xc->maxvalpos;
1053 
1054                 lseek(__fd, 0, SEEK_SET);
1055                 for(i=0;i<__len;i+=SSIZE_MAX)
1056                         {
1057                         write(__fd, pnt + i, ((__len - i) >= SSIZE_MAX) ? SSIZE_MAX : (__len - i));
1058                         }
1059                 lseek(__fd, cur_offs, SEEK_SET);
1060                 }
1061         }
1062 #endif
1063 
1064 fstMunmap(xc->curval_mem, xc->maxvalpos);
1065 xc->curval_mem = NULL;
1066 }
1067 
1068 
1069 /*
1070  * set up large and small memory usages
1071  * crossover point in model is FST_ACTIVATE_HUGE_BREAK number of signals
1072  */
fstDetermineBreakSize(struct fstWriterContext * xc)1073 static void fstDetermineBreakSize(struct fstWriterContext *xc)
1074 {
1075 #if defined(__linux__) || defined(FST_MACOSX)
1076 int was_set = 0;
1077 
1078 #ifdef __linux__
1079 FILE *f = fopen("/proc/meminfo", "rb");
1080 
1081 if(f)
1082         {
1083         char buf[257];
1084         char *s;
1085         while(!feof(f))
1086                 {
1087                 buf[0] = 0;
1088                 s = fgets(buf, 256, f);
1089                 if(s && *s)
1090                         {
1091                         if(!strncmp(s, "MemTotal:", 9))
1092                                 {
1093                                 size_t v = atol(s+10);
1094                                 v *= 1024; /* convert to bytes */
1095                                 v /= 8; /* chop down to 1/8 physical memory */
1096                                 if(v > FST_BREAK_SIZE)
1097                                         {
1098                                         if(v > FST_BREAK_SIZE_MAX)
1099                                                 {
1100                                                 v = FST_BREAK_SIZE_MAX;
1101                                                 }
1102 
1103                                         xc->fst_huge_break_size = v;
1104                                         was_set = 1;
1105                                         break;
1106                                         }
1107                                 }
1108                         }
1109                 }
1110 
1111         fclose(f);
1112         }
1113 
1114 if(!was_set)
1115         {
1116         xc->fst_huge_break_size = FST_BREAK_SIZE;
1117         }
1118 #else
1119 int mib[2];
1120 int64_t v;
1121 size_t length;
1122 
1123 mib[0] = CTL_HW;
1124 mib[1] = HW_MEMSIZE;
1125 length = sizeof(int64_t);
1126 if(!sysctl(mib, 2, &v, &length, NULL, 0))
1127         {
1128         v /= 8;
1129 
1130         if(v > (int64_t)FST_BREAK_SIZE)
1131                 {
1132                 if(v > (int64_t)FST_BREAK_SIZE_MAX)
1133                         {
1134                         v = FST_BREAK_SIZE_MAX;
1135                         }
1136 
1137                 xc->fst_huge_break_size = v;
1138                 was_set = 1;
1139                 }
1140         }
1141 
1142 if(!was_set)
1143         {
1144         xc->fst_huge_break_size = FST_BREAK_SIZE;
1145         }
1146 #endif
1147 #else
1148 xc->fst_huge_break_size = FST_BREAK_SIZE;
1149 #endif
1150 
1151 xc->fst_break_size = xc->fst_orig_break_size = FST_BREAK_SIZE;
1152 xc->fst_break_add_size = xc->fst_orig_break_add_size = FST_BREAK_ADD_SIZE;
1153 xc->next_huge_break = FST_ACTIVATE_HUGE_BREAK;
1154 }
1155 
1156 
1157 /*
1158  * file creation and close
1159  */
fstWriterCreate(const char * nam,int use_compressed_hier)1160 void *fstWriterCreate(const char *nam, int use_compressed_hier)
1161 {
1162 struct fstWriterContext *xc = (struct fstWriterContext *)calloc(1, sizeof(struct fstWriterContext));
1163 
1164 xc->compress_hier = use_compressed_hier;
1165 fstDetermineBreakSize(xc);
1166 
1167 if((!nam)||
1168         (!(xc->handle=unlink_fopen(nam, "w+b"))))
1169         {
1170         free(xc);
1171         xc=NULL;
1172         }
1173         else
1174         {
1175         int flen = strlen(nam);
1176         char *hf = (char *)calloc(1, flen + 6);
1177 
1178         memcpy(hf, nam, flen);
1179         strcpy(hf + flen, ".hier");
1180         xc->hier_handle = unlink_fopen(hf, "w+b");
1181 
1182         xc->geom_handle = tmpfile_open(&xc->geom_handle_nam);           /* .geom */
1183         xc->valpos_handle = tmpfile_open(&xc->valpos_handle_nam);       /* .offs */
1184         xc->curval_handle = tmpfile_open(&xc->curval_handle_nam);       /* .bits */
1185         xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam);           /* .tchn */
1186         xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size;
1187         xc->vchg_mem = (unsigned char *)malloc(xc->vchg_alloc_siz);
1188 
1189         if(xc->hier_handle && xc->geom_handle && xc->valpos_handle && xc->curval_handle && xc->vchg_mem && xc->tchn_handle)
1190                 {
1191                 xc->filename = strdup(nam);
1192                 xc->is_initial_time = 1;
1193 
1194                 fstWriterEmitHdrBytes(xc);
1195                 xc->nan = strtod("NaN", NULL);
1196 #ifdef FST_WRITER_PARALLEL
1197                 pthread_mutex_init(&xc->mutex, NULL);
1198                 pthread_attr_init(&xc->thread_attr);
1199                 pthread_attr_setdetachstate(&xc->thread_attr, PTHREAD_CREATE_DETACHED);
1200 #endif
1201                 }
1202                 else
1203                 {
1204                 fclose(xc->handle);
1205                 if(xc->hier_handle) { fclose(xc->hier_handle); unlink(hf); }
1206                 tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam);
1207                 tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam);
1208                 tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam);
1209                 tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
1210                 free(xc->vchg_mem);
1211                 free(xc);
1212                 xc=NULL;
1213                 }
1214 
1215         free(hf);
1216         }
1217 
1218 return(xc);
1219 }
1220 
1221 
1222 /*
1223  * generation and writing out of value change data sections
1224  */
fstWriterEmitSectionHeader(void * ctx)1225 static void fstWriterEmitSectionHeader(void *ctx)
1226 {
1227 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1228 
1229 if(xc)
1230         {
1231         unsigned long destlen;
1232         unsigned char *dmem;
1233         int rc;
1234 
1235         destlen = xc->maxvalpos;
1236         dmem = (unsigned char *)malloc(compressBound(destlen));
1237         rc = compress2(dmem, &destlen, xc->curval_mem, xc->maxvalpos, 4); /* was 9...which caused performance drag on traces with many signals */
1238 
1239         fputc(FST_BL_SKIP, xc->handle);                 /* temporarily tag the section, use FST_BL_VCDATA on finalize */
1240         xc->section_start = ftello(xc->handle);
1241 #ifdef FST_WRITER_PARALLEL
1242         if(xc->xc_parent) xc->xc_parent->section_start = xc->section_start;
1243 #endif
1244         xc->section_header_only = 1;                    /* indicates truncate might be needed */
1245         fstWriterUint64(xc->handle, 0);                 /* placeholder = section length */
1246         fstWriterUint64(xc->handle, xc->is_initial_time ? xc->firsttime : xc->curtime);         /* begin time of section */
1247         fstWriterUint64(xc->handle, xc->curtime);       /* end time of section (placeholder) */
1248         fstWriterUint64(xc->handle, 0);                 /* placeholder = amount of buffer memory required in reader for full vc traversal */
1249         fstWriterVarint(xc->handle, xc->maxvalpos);     /* maxvalpos = length of uncompressed data */
1250 
1251         if((rc == Z_OK) && (destlen < xc->maxvalpos))
1252                 {
1253                 fstWriterVarint(xc->handle, destlen);   /* length of compressed data */
1254                 }
1255                 else
1256                 {
1257                 fstWriterVarint(xc->handle, xc->maxvalpos); /* length of (unable to be) compressed data */
1258                 }
1259         fstWriterVarint(xc->handle, xc->maxhandle);     /* max handle associated with this data (in case of dynamic facility adds) */
1260 
1261         if((rc == Z_OK) && (destlen < xc->maxvalpos))
1262                 {
1263                 fstFwrite(dmem, destlen, 1, xc->handle);
1264                 }
1265                 else /* comparison between compressed / decompressed len tells if compressed */
1266                 {
1267                 fstFwrite(xc->curval_mem, xc->maxvalpos, 1, xc->handle);
1268                 }
1269 
1270         free(dmem);
1271         }
1272 }
1273 
1274 
1275 /*
1276  * only to be called directly by fst code...otherwise must
1277  * be synced up with time changes
1278  */
1279 #ifdef FST_WRITER_PARALLEL
fstWriterFlushContextPrivate2(void * ctx)1280 static void fstWriterFlushContextPrivate2(void *ctx)
1281 #else
1282 static void fstWriterFlushContextPrivate(void *ctx)
1283 #endif
1284 {
1285 #ifdef FST_DEBUG
1286 int cnt = 0;
1287 #endif
1288 unsigned int i;
1289 unsigned char *vchg_mem;
1290 FILE *f;
1291 fst_off_t fpos, indxpos, endpos;
1292 uint32_t prevpos;
1293 int zerocnt;
1294 unsigned char *scratchpad;
1295 unsigned char *scratchpnt;
1296 unsigned char *tmem;
1297 fst_off_t tlen;
1298 fst_off_t unc_memreq = 0; /* for reader */
1299 unsigned char *packmem;
1300 unsigned int packmemlen;
1301 uint32_t *vm4ip;
1302 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1303 #ifdef FST_WRITER_PARALLEL
1304 struct fstWriterContext *xc2 = xc->xc_parent;
1305 #else
1306 struct fstWriterContext *xc2 = xc;
1307 #endif
1308 
1309 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1310 Pvoid_t PJHSArray = (Pvoid_t) NULL;
1311 #ifndef _WAVE_HAVE_JUDY
1312 uint32_t hashmask =  xc->maxhandle;
1313 hashmask |= hashmask >> 1;
1314 hashmask |= hashmask >> 2;
1315 hashmask |= hashmask >> 4;
1316 hashmask |= hashmask >> 8;
1317 hashmask |= hashmask >> 16;
1318 #endif
1319 #endif
1320 
1321 if((xc->vchg_siz <= 1)||(xc->already_in_flush)) return;
1322 xc->already_in_flush = 1; /* should really do this with a semaphore */
1323 
1324 xc->section_header_only = 0;
1325 scratchpad = (unsigned char *)malloc(xc->vchg_siz);
1326 
1327 vchg_mem = xc->vchg_mem;
1328 
1329 f = xc->handle;
1330 fstWriterVarint(f, xc->maxhandle);      /* emit current number of handles */
1331 fputc(xc->fourpack ? '4' : (xc->fastpack ? 'F' : 'Z'), f);
1332 fpos = 1;
1333 
1334 packmemlen = 1024;                      /* maintain a running "longest" allocation to */
1335 packmem = (unsigned char *)malloc(packmemlen);           /* prevent continual malloc...free every loop iter */
1336 
1337 for(i=0;i<xc->maxhandle;i++)
1338         {
1339         vm4ip = &(xc->valpos_mem[4*i]);
1340 
1341         if(vm4ip[2])
1342                 {
1343                 uint32_t offs = vm4ip[2];
1344                 uint32_t next_offs;
1345                 unsigned int wrlen;
1346 
1347                 vm4ip[2] = fpos;
1348 
1349                 scratchpnt = scratchpad + xc->vchg_siz;         /* build this buffer backwards */
1350                 if(vm4ip[1] <= 1)
1351                         {
1352                         if(vm4ip[1] == 1)
1353                                 {
1354                                 wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */
1355 #ifndef FST_REMOVE_DUPLICATE_VC
1356                                 xc->curval_mem[vm4ip[0]] = vchg_mem[offs + 4 + wrlen]; /* checkpoint variable */
1357 #endif
1358                                 while(offs)
1359                                         {
1360                                         unsigned char val;
1361                                         uint32_t time_delta, rcv;
1362                                         next_offs = fstGetUint32(vchg_mem + offs);
1363                                         offs += 4;
1364 
1365                                         time_delta = fstGetVarint32(vchg_mem + offs, (int *)&wrlen);
1366                                         val = vchg_mem[offs+wrlen];
1367                                         offs = next_offs;
1368 
1369                                         switch(val)
1370                                                 {
1371                                                 case '0':
1372                                                 case '1':               rcv = ((val&1)<<1) | (time_delta<<2);
1373                                                                         break; /* pack more delta bits in for 0/1 vchs */
1374 
1375                                                 case 'x': case 'X':     rcv = FST_RCV_X | (time_delta<<4); break;
1376                                                 case 'z': case 'Z':     rcv = FST_RCV_Z | (time_delta<<4); break;
1377                                                 case 'h': case 'H':     rcv = FST_RCV_H | (time_delta<<4); break;
1378                                                 case 'u': case 'U':     rcv = FST_RCV_U | (time_delta<<4); break;
1379                                                 case 'w': case 'W':     rcv = FST_RCV_W | (time_delta<<4); break;
1380                                                 case 'l': case 'L':     rcv = FST_RCV_L | (time_delta<<4); break;
1381                                                 default:                rcv = FST_RCV_D | (time_delta<<4); break;
1382                                                 }
1383 
1384                                         scratchpnt = fstCopyVarint32ToLeft(scratchpnt, rcv);
1385                                         }
1386                                 }
1387                                 else
1388                                 {
1389                                 /* variable length */
1390                                 /* fstGetUint32 (next_offs) + fstGetVarint32 (time_delta) + fstGetVarint32 (len) + payload */
1391                                 unsigned char *pnt;
1392                                 uint32_t record_len;
1393                                 uint32_t time_delta;
1394 
1395                                 while(offs)
1396                                         {
1397                                         next_offs = fstGetUint32(vchg_mem + offs);
1398                                         offs += 4;
1399                                         pnt = vchg_mem + offs;
1400                                         offs = next_offs;
1401                                         time_delta = fstGetVarint32(pnt, (int *)&wrlen);
1402                                         pnt += wrlen;
1403                                         record_len = fstGetVarint32(pnt, (int *)&wrlen);
1404                                         pnt += wrlen;
1405 
1406                                         scratchpnt -= record_len;
1407                                         memcpy(scratchpnt, pnt, record_len);
1408 
1409                                         scratchpnt = fstCopyVarint32ToLeft(scratchpnt, record_len);
1410                                         scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1)); /* reserve | 1 case for future expansion */
1411                                         }
1412                                 }
1413                         }
1414                         else
1415                         {
1416                         wrlen = fstGetVarint32Length(vchg_mem + offs + 4); /* used to advance and determine wrlen */
1417 #ifndef FST_REMOVE_DUPLICATE_VC
1418                         memcpy(xc->curval_mem + vm4ip[0], vchg_mem + offs + 4 + wrlen, vm4ip[1]); /* checkpoint variable */
1419 #endif
1420                         while(offs)
1421                                 {
1422                                 unsigned int idx;
1423                                 char is_binary = 1;
1424                                 unsigned char *pnt;
1425                                 uint32_t time_delta;
1426 
1427                                 next_offs = fstGetUint32(vchg_mem + offs);
1428                                 offs += 4;
1429 
1430                                 time_delta = fstGetVarint32(vchg_mem + offs, (int *)&wrlen);
1431 
1432                                 pnt = vchg_mem+offs+wrlen;
1433                                 offs = next_offs;
1434 
1435                                 for(idx=0;idx<vm4ip[1];idx++)
1436                                         {
1437                                         if((pnt[idx] == '0') || (pnt[idx] == '1'))
1438                                                 {
1439                                                 continue;
1440                                                 }
1441                                                 else
1442                                                 {
1443                                                 is_binary = 0;
1444                                                 break;
1445                                                 }
1446                                         }
1447 
1448                                 if(is_binary)
1449                                         {
1450                                         unsigned char acc = 0;
1451                                         /* new algorithm */
1452                                         idx = ((vm4ip[1]+7) & ~7);
1453                                         switch(vm4ip[1] & 7)
1454                                                 {
1455                                                 case 0: do {    acc  = (pnt[idx+7-8] & 1) << 0; /* fallthrough */
1456                                                 case 7:         acc |= (pnt[idx+6-8] & 1) << 1; /* fallthrough */
1457                                                 case 6:         acc |= (pnt[idx+5-8] & 1) << 2; /* fallthrough */
1458                                                 case 5:         acc |= (pnt[idx+4-8] & 1) << 3; /* fallthrough */
1459                                                 case 4:         acc |= (pnt[idx+3-8] & 1) << 4; /* fallthrough */
1460                                                 case 3:         acc |= (pnt[idx+2-8] & 1) << 5; /* fallthrough */
1461                                                 case 2:         acc |= (pnt[idx+1-8] & 1) << 6; /* fallthrough */
1462                                                 case 1:         acc |= (pnt[idx+0-8] & 1) << 7;
1463                                                                 *(--scratchpnt) = acc;
1464                                                                 idx -= 8;
1465                                                         } while(idx);
1466                                                 }
1467 
1468                                         scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1));
1469                                         }
1470                                         else
1471                                         {
1472                                         scratchpnt -= vm4ip[1];
1473                                         memcpy(scratchpnt, pnt, vm4ip[1]);
1474 
1475                                         scratchpnt = fstCopyVarint32ToLeft(scratchpnt, (time_delta << 1) | 1);
1476                                         }
1477                                 }
1478                         }
1479 
1480                 wrlen = scratchpad + xc->vchg_siz - scratchpnt;
1481                 unc_memreq += wrlen;
1482                 if(wrlen > 32)
1483                         {
1484                         unsigned long destlen = wrlen;
1485                         unsigned char *dmem;
1486                         unsigned int rc;
1487 
1488                         if(!xc->fastpack)
1489                                 {
1490                                 if(wrlen <= packmemlen)
1491                                         {
1492                                         dmem = packmem;
1493                                         }
1494                                         else
1495                                         {
1496                                         free(packmem);
1497                                         dmem = packmem = (unsigned char *)malloc(compressBound(packmemlen = wrlen));
1498                                         }
1499 
1500                                 rc = compress2(dmem, &destlen, scratchpnt, wrlen, 4);
1501                                 if(rc == Z_OK)
1502                                         {
1503 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1504                                         PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, destlen, NULL);
1505                                         if(*pv)
1506                                                 {
1507                                                 uint32_t pvi = (intptr_t)(*pv);
1508                                                 vm4ip[2] = -pvi;
1509                                                 }
1510                                                 else
1511                                                 {
1512                                                 *pv = (void *)(intptr_t)(i+1);
1513 #endif
1514                                                 fpos += fstWriterVarint(f, wrlen);
1515                                                 fpos += destlen;
1516                                                 fstFwrite(dmem, destlen, 1, f);
1517 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1518                                                 }
1519 #endif
1520                                         }
1521                                         else
1522                                         {
1523 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1524                                         PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL);
1525                                         if(*pv)
1526                                                 {
1527                                                 uint32_t pvi = (intptr_t)(*pv);
1528                                                 vm4ip[2] = -pvi;
1529                                                 }
1530                                                 else
1531                                                 {
1532                                                 *pv = (void *)(intptr_t)(i+1);
1533 #endif
1534                                                 fpos += fstWriterVarint(f, 0);
1535                                                 fpos += wrlen;
1536                                                 fstFwrite(scratchpnt, wrlen, 1, f);
1537 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1538                                                 }
1539 #endif
1540                                         }
1541                                 }
1542                                 else
1543                                 {
1544                                 /* this is extremely conservative: fastlz needs +5% for worst case, lz4 needs siz+(siz/255)+16 */
1545                                 if(((wrlen * 2) + 2) <= packmemlen)
1546                                         {
1547                                         dmem = packmem;
1548                                         }
1549                                         else
1550                                         {
1551                                         free(packmem);
1552                                         dmem = packmem = (unsigned char *)malloc(packmemlen = (wrlen * 2) + 2);
1553                                         }
1554 
1555                                 rc = (xc->fourpack) ? LZ4_compress((char *)scratchpnt, (char *)dmem, wrlen) : fastlz_compress(scratchpnt, wrlen, dmem);
1556                                 if(rc < destlen)
1557                                         {
1558 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1559                                         PPvoid_t pv = JudyHSIns(&PJHSArray, dmem, rc, NULL);
1560                                         if(*pv)
1561                                                 {
1562                                                 uint32_t pvi = (intptr_t)(*pv);
1563                                                 vm4ip[2] = -pvi;
1564                                                 }
1565                                                 else
1566                                                 {
1567                                                 *pv = (void *)(intptr_t)(i+1);
1568 #endif
1569                                                 fpos += fstWriterVarint(f, wrlen);
1570                                                 fpos += rc;
1571                                                 fstFwrite(dmem, rc, 1, f);
1572 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1573                                                 }
1574 #endif
1575                                         }
1576                                         else
1577                                         {
1578 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1579                                         PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL);
1580                                         if(*pv)
1581                                                 {
1582                                                 uint32_t pvi = (intptr_t)(*pv);
1583                                                 vm4ip[2] = -pvi;
1584                                                 }
1585                                                 else
1586                                                 {
1587                                                 *pv = (void *)(intptr_t)(i+1);
1588 #endif
1589                                                 fpos += fstWriterVarint(f, 0);
1590                                                 fpos += wrlen;
1591                                                 fstFwrite(scratchpnt, wrlen, 1, f);
1592 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1593                                                 }
1594 #endif
1595                                         }
1596                                 }
1597                         }
1598                         else
1599                         {
1600 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1601                         PPvoid_t pv = JudyHSIns(&PJHSArray, scratchpnt, wrlen, NULL);
1602                         if(*pv)
1603                                 {
1604                                 uint32_t pvi = (intptr_t)(*pv);
1605                                 vm4ip[2] = -pvi;
1606                                 }
1607                                 else
1608                                 {
1609                                 *pv = (void *)(intptr_t)(i+1);
1610 #endif
1611                                 fpos += fstWriterVarint(f, 0);
1612                                 fpos += wrlen;
1613                                 fstFwrite(scratchpnt, wrlen, 1, f);
1614 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1615                                 }
1616 #endif
1617                         }
1618 
1619                 /* vm4ip[3] = 0; ...redundant with clearing below */
1620 #ifdef FST_DEBUG
1621                 cnt++;
1622 #endif
1623                 }
1624         }
1625 
1626 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1627 JudyHSFreeArray(&PJHSArray, NULL);
1628 #endif
1629 
1630 free(packmem); packmem = NULL; /* packmemlen = 0; */ /* scan-build */
1631 
1632 prevpos = 0; zerocnt = 0;
1633 free(scratchpad); scratchpad = NULL;
1634 
1635 indxpos = ftello(f);
1636 xc->secnum++;
1637 
1638 #ifndef FST_DYNAMIC_ALIAS2_DISABLE
1639 if(1)
1640         {
1641         uint32_t prev_alias = 0;
1642 
1643         for(i=0;i<xc->maxhandle;i++)
1644                 {
1645                 vm4ip = &(xc->valpos_mem[4*i]);
1646 
1647                 if(vm4ip[2])
1648                         {
1649                         if(zerocnt)
1650                                 {
1651                                 fpos += fstWriterVarint(f, (zerocnt << 1));
1652                                 zerocnt = 0;
1653                                 }
1654 
1655                         if(vm4ip[2] & 0x80000000)
1656                                 {
1657                                 if(vm4ip[2] != prev_alias)
1658                                         {
1659                                         fpos += fstWriterSVarint(f, (((int64_t)((int32_t)(prev_alias = vm4ip[2]))) << 1) | 1);
1660                                         }
1661                                         else
1662                                         {
1663                                         fpos += fstWriterSVarint(f, (0 << 1) | 1);
1664                                         }
1665                                 }
1666                                 else
1667                                 {
1668                                 fpos += fstWriterSVarint(f, ((vm4ip[2] - prevpos) << 1) | 1);
1669                                 prevpos = vm4ip[2];
1670                                 }
1671                         vm4ip[2] = 0;
1672                         vm4ip[3] = 0; /* clear out tchn idx */
1673                         }
1674                         else
1675                         {
1676                         zerocnt++;
1677                         }
1678                 }
1679         }
1680         else
1681 #endif
1682         {
1683         for(i=0;i<xc->maxhandle;i++)
1684                 {
1685                 vm4ip = &(xc->valpos_mem[4*i]);
1686 
1687                 if(vm4ip[2])
1688                         {
1689                         if(zerocnt)
1690                                 {
1691                                 fpos += fstWriterVarint(f, (zerocnt << 1));
1692                                 zerocnt = 0;
1693                                 }
1694 
1695                         if(vm4ip[2] & 0x80000000)
1696                                 {
1697                                 fpos += fstWriterVarint(f, 0); /* signal, note that using a *signed* varint would be more efficient than this byte escape! */
1698                                 fpos += fstWriterVarint(f, (-(int32_t)vm4ip[2]));
1699                                 }
1700                                 else
1701                                 {
1702                                 fpos += fstWriterVarint(f, ((vm4ip[2] - prevpos) << 1) | 1);
1703                                 prevpos = vm4ip[2];
1704                                 }
1705                         vm4ip[2] = 0;
1706                         vm4ip[3] = 0; /* clear out tchn idx */
1707                         }
1708                         else
1709                         {
1710                         zerocnt++;
1711                         }
1712                 }
1713         }
1714 
1715 if(zerocnt)
1716         {
1717         /* fpos += */ fstWriterVarint(f, (zerocnt << 1)); /* scan-build */
1718         }
1719 #ifdef FST_DEBUG
1720 fprintf(stderr, FST_APIMESS "value chains: %d\n", cnt);
1721 #endif
1722 
1723 xc->vchg_mem[0] = '!';
1724 xc->vchg_siz = 1;
1725 
1726 endpos = ftello(xc->handle);
1727 fstWriterUint64(xc->handle, endpos-indxpos);            /* write delta index position at very end of block */
1728 
1729 /*emit time changes for block */
1730 fflush(xc->tchn_handle);
1731 tlen = ftello(xc->tchn_handle);
1732 fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET);
1733 
1734 errno = 0;
1735 fstWriterMmapSanity(tmem = (unsigned char *)fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->tchn_handle), 0), __FILE__, __LINE__, "tmem");
1736 if(tmem)
1737         {
1738         unsigned long destlen = tlen;
1739         unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen));
1740         int rc = compress2(dmem, &destlen, tmem, tlen, 9);
1741 
1742         if((rc == Z_OK) && (((fst_off_t)destlen) < tlen))
1743                 {
1744                 fstFwrite(dmem, destlen, 1, xc->handle);
1745                 }
1746                 else /* comparison between compressed / decompressed len tells if compressed */
1747                 {
1748                 fstFwrite(tmem, tlen, 1, xc->handle);
1749                 destlen = tlen;
1750                 }
1751         free(dmem);
1752         fstMunmap(tmem, tlen);
1753         fstWriterUint64(xc->handle, tlen);              /* uncompressed */
1754         fstWriterUint64(xc->handle, destlen);           /* compressed */
1755         fstWriterUint64(xc->handle, xc->tchn_cnt);      /* number of time items */
1756         }
1757 
1758 xc->tchn_cnt = xc->tchn_idx = 0;
1759 fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET);
1760 fstFtruncate(fileno(xc->tchn_handle), 0);
1761 
1762 /* write block trailer */
1763 endpos = ftello(xc->handle);
1764 fstWriterFseeko(xc, xc->handle, xc->section_start, SEEK_SET);
1765 fstWriterUint64(xc->handle, endpos - xc->section_start);        /* write block length */
1766 fstWriterFseeko(xc, xc->handle, 8, SEEK_CUR);                           /* skip begin time */
1767 fstWriterUint64(xc->handle, xc->curtime);                       /* write end time for section */
1768 fstWriterUint64(xc->handle, unc_memreq);                        /* amount of buffer memory required in reader for full traversal */
1769 fflush(xc->handle);
1770 
1771 fstWriterFseeko(xc, xc->handle, xc->section_start-1, SEEK_SET);         /* write out FST_BL_VCDATA over FST_BL_SKIP */
1772 
1773 #ifndef FST_DYNAMIC_ALIAS_DISABLE
1774 #ifndef FST_DYNAMIC_ALIAS2_DISABLE
1775 fputc(FST_BL_VCDATA_DYN_ALIAS2, xc->handle);
1776 #else
1777 fputc(FST_BL_VCDATA_DYN_ALIAS, xc->handle);
1778 #endif
1779 #else
1780 fputc(FST_BL_VCDATA, xc->handle);
1781 #endif
1782 
1783 fflush(xc->handle);
1784 
1785 fstWriterFseeko(xc, xc->handle, endpos, SEEK_SET);                              /* seek to end of file */
1786 
1787 xc2->section_header_truncpos = endpos;                          /* cache in case of need to truncate */
1788 if(xc->dump_size_limit)
1789         {
1790         if(endpos >= ((fst_off_t)xc->dump_size_limit))
1791                 {
1792                 xc2->skip_writing_section_hdr = 1;
1793                 xc2->size_limit_locked = 1;
1794                 xc2->is_initial_time = 1; /* to trick emit value and emit time change */
1795 #ifdef FST_DEBUG
1796                 fprintf(stderr, FST_APIMESS "<< dump file size limit reached, stopping dumping >>\n");
1797 #endif
1798                 }
1799         }
1800 
1801 if(!xc2->skip_writing_section_hdr)
1802         {
1803         fstWriterEmitSectionHeader(xc);                         /* emit next section header */
1804         }
1805 fflush(xc->handle);
1806 
1807 xc->already_in_flush = 0;
1808 }
1809 
1810 
1811 #ifdef FST_WRITER_PARALLEL
fstWriterFlushContextPrivate1(void * ctx)1812 static void *fstWriterFlushContextPrivate1(void *ctx)
1813 {
1814 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1815 struct fstWriterContext *xc_parent;
1816 
1817 pthread_mutex_lock(&(xc->xc_parent->mutex));
1818 fstWriterFlushContextPrivate2(xc);
1819 
1820 #ifdef FST_REMOVE_DUPLICATE_VC
1821 free(xc->curval_mem);
1822 #endif
1823 free(xc->valpos_mem);
1824 free(xc->vchg_mem);
1825 tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
1826 xc_parent = xc->xc_parent;
1827 free(xc);
1828 
1829 xc_parent->in_pthread = 0;
1830 pthread_mutex_unlock(&(xc_parent->mutex));
1831 
1832 return(NULL);
1833 }
1834 
1835 
fstWriterFlushContextPrivate(void * ctx)1836 static void fstWriterFlushContextPrivate(void *ctx)
1837 {
1838 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1839 
1840 if(xc->parallel_enabled)
1841         {
1842         struct fstWriterContext *xc2 = (struct fstWriterContext *)malloc(sizeof(struct fstWriterContext));
1843         unsigned int i;
1844 
1845         pthread_mutex_lock(&xc->mutex);
1846         pthread_mutex_unlock(&xc->mutex);
1847 
1848         xc->xc_parent = xc;
1849         memcpy(xc2, xc, sizeof(struct fstWriterContext));
1850 
1851         xc2->valpos_mem = (uint32_t *)malloc(xc->maxhandle * 4 * sizeof(uint32_t));
1852         memcpy(xc2->valpos_mem, xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t));
1853 
1854         /* curval mem is updated in the thread */
1855 #ifdef FST_REMOVE_DUPLICATE_VC
1856         xc2->curval_mem = (unsigned char *)malloc(xc->maxvalpos);
1857         memcpy(xc2->curval_mem, xc->curval_mem, xc->maxvalpos);
1858 #endif
1859 
1860         xc->vchg_mem = (unsigned char *)malloc(xc->vchg_alloc_siz);
1861         xc->vchg_mem[0] = '!';
1862         xc->vchg_siz = 1;
1863 
1864         for(i=0;i<xc->maxhandle;i++)
1865                 {
1866                 uint32_t *vm4ip = &(xc->valpos_mem[4*i]);
1867                 vm4ip[2] = 0; /* zero out offset val */
1868                 vm4ip[3] = 0; /* zero out last time change val */
1869                 }
1870 
1871         xc->tchn_cnt = xc->tchn_idx = 0;
1872         xc->tchn_handle = tmpfile_open(&xc->tchn_handle_nam); /* child thread will deallocate file/name */
1873         fstWriterFseeko(xc, xc->tchn_handle, 0, SEEK_SET);
1874         fstFtruncate(fileno(xc->tchn_handle), 0);
1875 
1876         xc->section_header_only = 0;
1877         xc->secnum++;
1878 
1879 	while (xc->in_pthread)
1880 		{
1881 		pthread_mutex_lock(&xc->mutex);
1882 		pthread_mutex_unlock(&xc->mutex);
1883 		};
1884 
1885         pthread_mutex_lock(&xc->mutex);
1886 	xc->in_pthread = 1;
1887         pthread_mutex_unlock(&xc->mutex);
1888 
1889         pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2);
1890         }
1891         else
1892         {
1893         if(xc->parallel_was_enabled) /* conservatively block */
1894                 {
1895                 pthread_mutex_lock(&xc->mutex);
1896                 pthread_mutex_unlock(&xc->mutex);
1897                 }
1898 
1899         xc->xc_parent = xc;
1900         fstWriterFlushContextPrivate2(xc);
1901         }
1902 }
1903 #endif
1904 
1905 
1906 /*
1907  * queues up a flush context operation
1908  */
fstWriterFlushContext(void * ctx)1909 void fstWriterFlushContext(void *ctx)
1910 {
1911 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1912 if(xc)
1913         {
1914         if(xc->tchn_idx > 1)
1915                 {
1916                 xc->flush_context_pending = 1;
1917                 }
1918         }
1919 }
1920 
1921 
1922 /*
1923  * close out FST file
1924  */
fstWriterClose(void * ctx)1925 void fstWriterClose(void *ctx)
1926 {
1927 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
1928 
1929 #ifdef FST_WRITER_PARALLEL
1930 if(xc)
1931         {
1932         pthread_mutex_lock(&xc->mutex);
1933         pthread_mutex_unlock(&xc->mutex);
1934         }
1935 #endif
1936 
1937 if(xc && !xc->already_in_close && !xc->already_in_flush)
1938         {
1939         unsigned char *tmem = NULL;
1940         fst_off_t fixup_offs, tlen, hlen;
1941 
1942         xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */
1943 
1944         if(xc->section_header_only && xc->section_header_truncpos && (xc->vchg_siz <= 1) && (!xc->is_initial_time))
1945                 {
1946                 fstFtruncate(fileno(xc->handle), xc->section_header_truncpos);
1947                 fstWriterFseeko(xc, xc->handle, xc->section_header_truncpos, SEEK_SET);
1948                 xc->section_header_only = 0;
1949                 }
1950                 else
1951                 {
1952                 xc->skip_writing_section_hdr = 1;
1953                 if(!xc->size_limit_locked)
1954                         {
1955                         if(FST_UNLIKELY(xc->is_initial_time)) /* simulation time never advanced so mock up the changes as time zero ones */
1956                                 {
1957                                 fstHandle dupe_idx;
1958 
1959                                 fstWriterEmitTimeChange(xc, 0); /* emit some time change just to have one */
1960                                 for(dupe_idx = 0; dupe_idx < xc->maxhandle; dupe_idx++) /* now clone the values */
1961                                         {
1962                                         fstWriterEmitValueChange(xc, dupe_idx+1, xc->curval_mem + xc->valpos_mem[4*dupe_idx]);
1963                                         }
1964                                 }
1965                         fstWriterFlushContextPrivate(xc);
1966 #ifdef FST_WRITER_PARALLEL
1967                         pthread_mutex_lock(&xc->mutex);
1968                         pthread_mutex_unlock(&xc->mutex);
1969 
1970 			while (xc->in_pthread)
1971 				{
1972 				pthread_mutex_lock(&xc->mutex);
1973 				pthread_mutex_unlock(&xc->mutex);
1974 				};
1975 #endif
1976                         }
1977                 }
1978         fstDestroyMmaps(xc, 1);
1979 	if(xc->outval_mem)
1980 		{
1981 		free(xc->outval_mem); xc->outval_mem = NULL;
1982 		xc->outval_alloc_siz = 0;
1983 		}
1984 
1985         /* write out geom section */
1986         fflush(xc->geom_handle);
1987         tlen = ftello(xc->geom_handle);
1988 	errno = 0;
1989 	if(tlen)
1990 		{
1991 	        fstWriterMmapSanity(tmem = (unsigned char *)fstMmap(NULL, tlen, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->geom_handle), 0), __FILE__, __LINE__, "tmem");
1992 		}
1993 
1994         if(tmem)
1995                 {
1996                 unsigned long destlen = tlen;
1997                 unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen));
1998                 int rc = compress2(dmem, &destlen, tmem, tlen, 9);
1999 
2000                 if((rc != Z_OK) || (((fst_off_t)destlen) > tlen))
2001                         {
2002                         destlen = tlen;
2003                         }
2004 
2005                 fixup_offs = ftello(xc->handle);
2006                 fputc(FST_BL_SKIP, xc->handle);                 /* temporary tag */
2007                 fstWriterUint64(xc->handle, destlen + 24);      /* section length */
2008                 fstWriterUint64(xc->handle, tlen);              /* uncompressed */
2009                                                                 /* compressed len is section length - 24 */
2010                 fstWriterUint64(xc->handle, xc->maxhandle);     /* maxhandle */
2011                 fstFwrite((((fst_off_t)destlen) != tlen) ? dmem : tmem, destlen, 1, xc->handle);
2012                 fflush(xc->handle);
2013 
2014                 fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET);
2015                 fputc(FST_BL_GEOM, xc->handle);                 /* actual tag */
2016 
2017                 fstWriterFseeko(xc, xc->handle, 0, SEEK_END);           /* move file pointer to end for any section adds */
2018                 fflush(xc->handle);
2019 
2020                 free(dmem);
2021                 fstMunmap(tmem, tlen);
2022                 }
2023 
2024         if(xc->num_blackouts)
2025                 {
2026                 uint64_t cur_bl = 0;
2027                 fst_off_t bpos, eos;
2028                 uint32_t i;
2029 
2030                 fixup_offs = ftello(xc->handle);
2031                 fputc(FST_BL_SKIP, xc->handle);                 /* temporary tag */
2032                 bpos = fixup_offs + 1;
2033                 fstWriterUint64(xc->handle, 0);                 /* section length */
2034                 fstWriterVarint(xc->handle, xc->num_blackouts);
2035 
2036                 for(i=0;i<xc->num_blackouts;i++)
2037                         {
2038                         fputc(xc->blackout_head->active, xc->handle);
2039                         fstWriterVarint(xc->handle, xc->blackout_head->tim - cur_bl);
2040                         cur_bl = xc->blackout_head->tim;
2041                         xc->blackout_curr = xc->blackout_head->next;
2042                         free(xc->blackout_head);
2043                         xc->blackout_head = xc->blackout_curr;
2044                         }
2045 
2046                 eos = ftello(xc->handle);
2047                 fstWriterFseeko(xc, xc->handle, bpos, SEEK_SET);
2048                 fstWriterUint64(xc->handle, eos - bpos);
2049                 fflush(xc->handle);
2050 
2051                 fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET);
2052                 fputc(FST_BL_BLACKOUT, xc->handle);     /* actual tag */
2053 
2054                 fstWriterFseeko(xc, xc->handle, 0, SEEK_END);   /* move file pointer to end for any section adds */
2055                 fflush(xc->handle);
2056                 }
2057 
2058         if(xc->compress_hier)
2059                 {
2060                 fst_off_t hl, eos;
2061                 gzFile zhandle;
2062                 int zfd;
2063                 int fourpack_duo = 0;
2064 #ifndef __MINGW32__
2065                 char *fnam = (char *)malloc(strlen(xc->filename) + 5 + 1);
2066 #endif
2067 
2068                 fixup_offs = ftello(xc->handle);
2069                 fputc(FST_BL_SKIP, xc->handle);                 /* temporary tag */
2070                 hlen = ftello(xc->handle);
2071                 fstWriterUint64(xc->handle, 0);                 /* section length */
2072                 fstWriterUint64(xc->handle, xc->hier_file_len); /* uncompressed length */
2073 
2074                 if(!xc->fourpack)
2075                         {
2076                         unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN);
2077                         zfd = dup(fileno(xc->handle));
2078                         fflush(xc->handle);
2079                         zhandle = gzdopen(zfd, "wb4");
2080                         if(zhandle)
2081                                 {
2082                                 fstWriterFseeko(xc, xc->hier_handle, 0, SEEK_SET);
2083                                 for(hl = 0; hl < xc->hier_file_len; hl += FST_GZIO_LEN)
2084                                         {
2085                                         unsigned len = ((xc->hier_file_len - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (xc->hier_file_len - hl);
2086                                         fstFread(mem, len, 1, xc->hier_handle);
2087                                         gzwrite(zhandle, mem, len);
2088                                         }
2089                                 gzclose(zhandle);
2090                                 }
2091                                 else
2092                                 {
2093                                 close(zfd);
2094                                 }
2095                         free(mem);
2096                         }
2097                         else
2098                         {
2099                         int lz4_maxlen;
2100                         unsigned char *mem;
2101                         unsigned char *hmem = NULL;
2102                         int packed_len;
2103 
2104                         fflush(xc->handle);
2105 
2106                         lz4_maxlen = LZ4_compressBound(xc->hier_file_len);
2107                         mem = (unsigned char *)malloc(lz4_maxlen);
2108 			errno = 0;
2109 			if(xc->hier_file_len)
2110 				{
2111 	                        fstWriterMmapSanity(hmem = (unsigned char *)fstMmap(NULL, xc->hier_file_len, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->hier_handle), 0), __FILE__, __LINE__, "hmem");
2112 				}
2113                         packed_len = LZ4_compress((char *)hmem, (char *)mem, xc->hier_file_len);
2114                         fstMunmap(hmem, xc->hier_file_len);
2115 
2116                         fourpack_duo = (!xc->repack_on_close) && (xc->hier_file_len > FST_HDR_FOURPACK_DUO_SIZE); /* double pack when hierarchy is large */
2117 
2118                         if(fourpack_duo)        /* double packing with LZ4 is faster than gzip */
2119                                 {
2120                                 unsigned char *mem_duo;
2121                                 int lz4_maxlen_duo;
2122                                 int packed_len_duo;
2123 
2124                                 lz4_maxlen_duo = LZ4_compressBound(packed_len);
2125                                 mem_duo = (unsigned char *)malloc(lz4_maxlen_duo);
2126                                 packed_len_duo = LZ4_compress((char *)mem, (char *)mem_duo, packed_len);
2127 
2128                                 fstWriterVarint(xc->handle, packed_len); /* 1st round compressed length */
2129                                 fstFwrite(mem_duo, packed_len_duo, 1, xc->handle);
2130                                 free(mem_duo);
2131                                 }
2132                                 else
2133                                 {
2134                                 fstFwrite(mem, packed_len, 1, xc->handle);
2135                                 }
2136 
2137                         free(mem);
2138                         }
2139 
2140                 fstWriterFseeko(xc, xc->handle, 0, SEEK_END);
2141                 eos = ftello(xc->handle);
2142                 fstWriterFseeko(xc, xc->handle, hlen, SEEK_SET);
2143                 fstWriterUint64(xc->handle, eos - hlen);
2144                 fflush(xc->handle);
2145 
2146                 fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET);
2147                 fputc(xc->fourpack ?
2148                         ( fourpack_duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4) :
2149                         FST_BL_HIER, xc->handle); /* actual tag now also == compression type */
2150 
2151                 fstWriterFseeko(xc, xc->handle, 0, SEEK_END);   /* move file pointer to end for any section adds */
2152                 fflush(xc->handle);
2153 
2154 #ifndef __MINGW32__
2155                 sprintf(fnam, "%s.hier", xc->filename);
2156                 unlink(fnam);
2157                 free(fnam);
2158 #endif
2159                 }
2160 
2161         /* finalize out header */
2162         fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_START_TIME, SEEK_SET);
2163         fstWriterUint64(xc->handle, xc->firsttime);
2164         fstWriterUint64(xc->handle, xc->curtime);
2165         fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_NUM_SCOPES, SEEK_SET);
2166         fstWriterUint64(xc->handle, xc->numscopes);
2167         fstWriterUint64(xc->handle, xc->numsigs);
2168         fstWriterUint64(xc->handle, xc->maxhandle);
2169         fstWriterUint64(xc->handle, xc->secnum);
2170         fflush(xc->handle);
2171 
2172         tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
2173         free(xc->vchg_mem); xc->vchg_mem = NULL;
2174         tmpfile_close(&xc->curval_handle, &xc->curval_handle_nam);
2175         tmpfile_close(&xc->valpos_handle, &xc->valpos_handle_nam);
2176         tmpfile_close(&xc->geom_handle, &xc->geom_handle_nam);
2177         if(xc->hier_handle) { fclose(xc->hier_handle); xc->hier_handle = NULL; }
2178         if(xc->handle)
2179                 {
2180                 if(xc->repack_on_close)
2181                         {
2182                         FILE *fp;
2183                         fst_off_t offpnt, uclen;
2184                         int flen = strlen(xc->filename);
2185                         char *hf = (char *)calloc(1, flen + 5);
2186 
2187                         strcpy(hf, xc->filename);
2188                         strcpy(hf+flen, ".pak");
2189                         fp = fopen(hf, "wb");
2190 
2191                         if(fp)
2192                                 {
2193                                 gzFile dsth;
2194                                 int zfd;
2195                                 char gz_membuf[FST_GZIO_LEN];
2196 
2197                                 fstWriterFseeko(xc, xc->handle, 0, SEEK_END);
2198                                 uclen = ftello(xc->handle);
2199 
2200                                 fputc(FST_BL_ZWRAPPER, fp);
2201                                 fstWriterUint64(fp, 0);
2202                                 fstWriterUint64(fp, uclen);
2203                                 fflush(fp);
2204 
2205                                 fstWriterFseeko(xc, xc->handle, 0, SEEK_SET);
2206                                 zfd = dup(fileno(fp));
2207                                 dsth = gzdopen(zfd, "wb4");
2208                                 if(dsth)
2209                                         {
2210                                         for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN)
2211                                                 {
2212                                                 size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt);
2213                                                 fstFread(gz_membuf, this_len, 1, xc->handle);
2214                                                 gzwrite(dsth, gz_membuf, this_len);
2215                                                 }
2216                                         gzclose(dsth);
2217                                         }
2218                                         else
2219                                         {
2220                                         close(zfd);
2221                                         }
2222                                 fstWriterFseeko(xc, fp, 0, SEEK_END);
2223                                 offpnt = ftello(fp);
2224                                 fstWriterFseeko(xc, fp, 1, SEEK_SET);
2225                                 fstWriterUint64(fp, offpnt - 1);
2226                                 fclose(fp);
2227                                 fclose(xc->handle); xc->handle = NULL;
2228 
2229                                 unlink(xc->filename);
2230                                 rename(hf, xc->filename);
2231                                 }
2232                                 else
2233                                 {
2234                                 xc->repack_on_close = 0;
2235                                 fclose(xc->handle); xc->handle = NULL;
2236                                 }
2237 
2238                         free(hf);
2239                         }
2240                         else
2241                         {
2242                         fclose(xc->handle); xc->handle = NULL;
2243                         }
2244                 }
2245 
2246 #ifdef __MINGW32__
2247         {
2248         int flen = strlen(xc->filename);
2249         char *hf = (char *)calloc(1, flen + 6);
2250         strcpy(hf, xc->filename);
2251 
2252         if(xc->compress_hier)
2253                 {
2254                 strcpy(hf + flen, ".hier");
2255                 unlink(hf); /* no longer needed as a section now exists for this */
2256                 }
2257 
2258         free(hf);
2259         }
2260 #endif
2261 
2262 #ifdef FST_WRITER_PARALLEL
2263         pthread_mutex_destroy(&xc->mutex);
2264         pthread_attr_destroy(&xc->thread_attr);
2265 #endif
2266 
2267         if(xc->path_array)
2268                 {
2269 #ifndef _WAVE_HAVE_JUDY
2270                 const uint32_t hashmask = FST_PATH_HASHMASK;
2271 #endif
2272                 JudyHSFreeArray(&(xc->path_array), NULL);
2273                 }
2274 
2275         free(xc->filename); xc->filename = NULL;
2276         free(xc);
2277         }
2278 }
2279 
2280 
2281 /*
2282  * functions to set miscellaneous header/block information
2283  */
fstWriterSetDate(void * ctx,const char * dat)2284 void fstWriterSetDate(void *ctx, const char *dat)
2285 {
2286 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2287 if(xc)
2288         {
2289         char s[FST_HDR_DATE_SIZE];
2290         fst_off_t fpos = ftello(xc->handle);
2291         int len = strlen(dat);
2292 
2293         fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_DATE, SEEK_SET);
2294         memset(s, 0, FST_HDR_DATE_SIZE);
2295         memcpy(s, dat, (len < FST_HDR_DATE_SIZE) ? len : FST_HDR_DATE_SIZE);
2296         fstFwrite(s, FST_HDR_DATE_SIZE, 1, xc->handle);
2297         fflush(xc->handle);
2298         fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
2299         }
2300 }
2301 
2302 
fstWriterSetVersion(void * ctx,const char * vers)2303 void fstWriterSetVersion(void *ctx, const char *vers)
2304 {
2305 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2306 if(xc && vers)
2307         {
2308         char s[FST_HDR_SIM_VERSION_SIZE];
2309         fst_off_t fpos = ftello(xc->handle);
2310         int len = strlen(vers);
2311 
2312         fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_SIM_VERSION, SEEK_SET);
2313         memset(s, 0, FST_HDR_SIM_VERSION_SIZE);
2314         memcpy(s, vers, (len < FST_HDR_SIM_VERSION_SIZE) ? len : FST_HDR_SIM_VERSION_SIZE);
2315         fstFwrite(s, FST_HDR_SIM_VERSION_SIZE, 1, xc->handle);
2316         fflush(xc->handle);
2317         fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
2318         }
2319 }
2320 
2321 
fstWriterSetFileType(void * ctx,enum fstFileType filetype)2322 void fstWriterSetFileType(void *ctx, enum fstFileType filetype)
2323 {
2324 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2325 if(xc)
2326         {
2327         if(/*(filetype >= FST_FT_MIN) &&*/ (filetype <= FST_FT_MAX))
2328                 {
2329                 fst_off_t fpos = ftello(xc->handle);
2330 
2331                 xc->filetype = filetype;
2332 
2333                 fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_FILETYPE, SEEK_SET);
2334                 fputc(xc->filetype, xc->handle);
2335                 fflush(xc->handle);
2336                 fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
2337                 }
2338         }
2339 }
2340 
2341 
fstWriterSetAttrDoubleArgGeneric(void * ctx,int typ,uint64_t arg1,uint64_t arg2)2342 static void fstWriterSetAttrDoubleArgGeneric(void *ctx, int typ, uint64_t arg1, uint64_t arg2)
2343 {
2344 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2345 if(xc)
2346         {
2347         unsigned char buf[11]; /* ceil(64/7) = 10 + null term */
2348         unsigned char *pnt = fstCopyVarint64ToRight(buf, arg1);
2349         if(arg1)
2350                 {
2351                 *pnt = 0; /* this converts any *nonzero* arg1 when made a varint into a null-term string */
2352                 }
2353 
2354         fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, (char *)buf, arg2);
2355         }
2356 }
2357 
2358 
fstWriterSetAttrGeneric(void * ctx,const char * comm,int typ,uint64_t arg)2359 static void fstWriterSetAttrGeneric(void *ctx, const char *comm, int typ, uint64_t arg)
2360 {
2361 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2362 if(xc && comm)
2363         {
2364         char *s = strdup(comm);
2365         char *sf = s;
2366 
2367         while(*s)
2368                 {
2369                 if((*s == '\n') || (*s == '\r')) *s = ' ';
2370                 s++;
2371                 }
2372 
2373         fstWriterSetAttrBegin(xc, FST_AT_MISC, typ, sf, arg);
2374         free(sf);
2375         }
2376 }
2377 
2378 
fstWriterSetSourceStem_2(void * ctx,const char * path,unsigned int line,unsigned int use_realpath,int typ)2379 static void fstWriterSetSourceStem_2(void *ctx, const char *path, unsigned int line, unsigned int use_realpath, int typ)
2380 {
2381 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2382 
2383 if(xc && path && path[0])
2384         {
2385         uint64_t sidx = 0;
2386         int slen = strlen(path);
2387 #ifndef _WAVE_HAVE_JUDY
2388         const uint32_t hashmask = FST_PATH_HASHMASK;
2389         const unsigned char *path2 = (const unsigned char *)path;
2390 	PPvoid_t pv;
2391 #else
2392         char *path2 = (char *)alloca(slen + 1); /* judy lacks const qualifier in its JudyHSIns definition */
2393 	PPvoid_t pv;
2394         strcpy(path2, path);
2395 #endif
2396 
2397         pv = JudyHSIns(&(xc->path_array), path2, slen, NULL);
2398         if(*pv)
2399                 {
2400                 sidx = (intptr_t)(*pv);
2401                 }
2402                 else
2403                 {
2404                 char *rp = NULL;
2405 
2406                 sidx = ++xc->path_array_count;
2407                 *pv = (void *)(intptr_t)(xc->path_array_count);
2408 
2409                 if(use_realpath)
2410                         {
2411                         rp = fstRealpath(
2412 #ifndef _WAVE_HAVE_JUDY
2413                                 (const char *)
2414 #endif
2415                                 path2, NULL);
2416                         }
2417 
2418                 fstWriterSetAttrGeneric(xc, rp ? rp :
2419 #ifndef _WAVE_HAVE_JUDY
2420                         (const char *)
2421 #endif
2422                         path2, FST_MT_PATHNAME, sidx);
2423 
2424                 if(rp)
2425                         {
2426                         free(rp);
2427                         }
2428                 }
2429 
2430         fstWriterSetAttrDoubleArgGeneric(xc, typ, sidx, line);
2431         }
2432 }
2433 
2434 
fstWriterSetSourceStem(void * ctx,const char * path,unsigned int line,unsigned int use_realpath)2435 void fstWriterSetSourceStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath)
2436 {
2437 fstWriterSetSourceStem_2(ctx, path, line, use_realpath, FST_MT_SOURCESTEM);
2438 }
2439 
2440 
fstWriterSetSourceInstantiationStem(void * ctx,const char * path,unsigned int line,unsigned int use_realpath)2441 void fstWriterSetSourceInstantiationStem(void *ctx, const char *path, unsigned int line, unsigned int use_realpath)
2442 {
2443 fstWriterSetSourceStem_2(ctx, path, line, use_realpath, FST_MT_SOURCEISTEM);
2444 }
2445 
2446 
fstWriterSetComment(void * ctx,const char * comm)2447 void fstWriterSetComment(void *ctx, const char *comm)
2448 {
2449 fstWriterSetAttrGeneric(ctx, comm, FST_MT_COMMENT, 0);
2450 }
2451 
2452 
fstWriterSetValueList(void * ctx,const char * vl)2453 void fstWriterSetValueList(void *ctx, const char *vl)
2454 {
2455 fstWriterSetAttrGeneric(ctx, vl, FST_MT_VALUELIST, 0);
2456 }
2457 
2458 
fstWriterSetEnvVar(void * ctx,const char * envvar)2459 void fstWriterSetEnvVar(void *ctx, const char *envvar)
2460 {
2461 fstWriterSetAttrGeneric(ctx, envvar, FST_MT_ENVVAR, 0);
2462 }
2463 
2464 
fstWriterSetTimescale(void * ctx,int ts)2465 void fstWriterSetTimescale(void *ctx, int ts)
2466 {
2467 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2468 if(xc)
2469         {
2470         fst_off_t fpos = ftello(xc->handle);
2471         fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET);
2472         fputc(ts & 255, xc->handle);
2473         fflush(xc->handle);
2474         fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
2475         }
2476 }
2477 
2478 
fstWriterSetTimescaleFromString(void * ctx,const char * s)2479 void fstWriterSetTimescaleFromString(void *ctx, const char *s)
2480 {
2481 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2482 if(xc && s)
2483         {
2484         int mat = 0;
2485         int seconds_exp = -9;
2486         int tv = atoi(s);
2487         const char *pnt = s;
2488 
2489         while(*pnt)
2490                 {
2491                 switch(*pnt)
2492                         {
2493                         case 'm': seconds_exp =  -3; mat = 1; break;
2494                         case 'u': seconds_exp =  -6; mat = 1; break;
2495                         case 'n': seconds_exp =  -9; mat = 1; break;
2496                         case 'p': seconds_exp = -12; mat = 1; break;
2497                         case 'f': seconds_exp = -15; mat = 1; break;
2498                         case 'a': seconds_exp = -18; mat = 1; break;
2499                         case 'z': seconds_exp = -21; mat = 1; break;
2500                         case 's': seconds_exp =   0; mat = 1; break;
2501                         default: break;
2502                         }
2503 
2504                 if(mat) break;
2505                 pnt++;
2506                 }
2507 
2508         if(tv == 10)
2509                 {
2510                 seconds_exp++;
2511                 }
2512         else
2513         if(tv == 100)
2514                 {
2515                 seconds_exp+=2;
2516                 }
2517 
2518         fstWriterSetTimescale(ctx, seconds_exp);
2519         }
2520 }
2521 
2522 
fstWriterSetTimezero(void * ctx,int64_t tim)2523 void fstWriterSetTimezero(void *ctx, int64_t tim)
2524 {
2525 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2526 if(xc)
2527         {
2528         fst_off_t fpos = ftello(xc->handle);
2529         fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET);
2530         fstWriterUint64(xc->handle, (xc->timezero = tim));
2531         fflush(xc->handle);
2532         fstWriterFseeko(xc, xc->handle, fpos, SEEK_SET);
2533         }
2534 }
2535 
2536 
fstWriterSetPackType(void * ctx,enum fstWriterPackType typ)2537 void fstWriterSetPackType(void *ctx, enum fstWriterPackType typ)
2538 {
2539 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2540 if(xc)
2541         {
2542         xc->fastpack     = (typ != FST_WR_PT_ZLIB);
2543         xc->fourpack     = (typ == FST_WR_PT_LZ4);
2544         }
2545 }
2546 
2547 
fstWriterSetRepackOnClose(void * ctx,int enable)2548 void fstWriterSetRepackOnClose(void *ctx, int enable)
2549 {
2550 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2551 if(xc)
2552         {
2553         xc->repack_on_close = (enable != 0);
2554         }
2555 }
2556 
2557 
fstWriterSetParallelMode(void * ctx,int enable)2558 void fstWriterSetParallelMode(void *ctx, int enable)
2559 {
2560 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2561 if(xc)
2562         {
2563         xc->parallel_was_enabled |= xc->parallel_enabled; /* make sticky */
2564         xc->parallel_enabled = (enable != 0);
2565 #ifndef FST_WRITER_PARALLEL
2566         if(xc->parallel_enabled)
2567                 {
2568                 fprintf(stderr, FST_APIMESS "fstWriterSetParallelMode(), FST_WRITER_PARALLEL not enabled during compile, exiting.\n");
2569                 exit(255);
2570                 }
2571 #endif
2572         }
2573 }
2574 
2575 
fstWriterSetDumpSizeLimit(void * ctx,uint64_t numbytes)2576 void fstWriterSetDumpSizeLimit(void *ctx, uint64_t numbytes)
2577 {
2578 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2579 if(xc)
2580         {
2581         xc->dump_size_limit = numbytes;
2582         }
2583 }
2584 
2585 
fstWriterGetDumpSizeLimitReached(void * ctx)2586 int fstWriterGetDumpSizeLimitReached(void *ctx)
2587 {
2588 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2589 if(xc)
2590         {
2591         return(xc->size_limit_locked != 0);
2592         }
2593 
2594 return(0);
2595 }
2596 
2597 
fstWriterGetFseekFailed(void * ctx)2598 int fstWriterGetFseekFailed(void *ctx)
2599 {
2600 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2601 if(xc)
2602         {
2603         return(xc->fseek_failed != 0);
2604         }
2605 
2606 return(0);
2607 }
2608 
2609 
2610 /*
2611  * writer attr/scope/var creation:
2612  * fstWriterCreateVar2() is used to dump VHDL or other languages, but the
2613  * underlying variable needs to map to Verilog/SV via the proper fstVarType vt
2614  */
fstWriterCreateVar2(void * ctx,enum fstVarType vt,enum fstVarDir vd,uint32_t len,const char * nam,fstHandle aliasHandle,const char * type,enum fstSupplementalVarType svt,enum fstSupplementalDataType sdt)2615 fstHandle fstWriterCreateVar2(void *ctx, enum fstVarType vt, enum fstVarDir vd,
2616         uint32_t len, const char *nam, fstHandle aliasHandle,
2617         const char *type, enum fstSupplementalVarType svt, enum fstSupplementalDataType sdt)
2618 {
2619 fstWriterSetAttrGeneric(ctx, type ? type : "", FST_MT_SUPVAR, (svt<<FST_SDT_SVT_SHIFT_COUNT) | (sdt & FST_SDT_ABS_MAX));
2620 return(fstWriterCreateVar(ctx, vt, vd, len, nam, aliasHandle));
2621 }
2622 
2623 
fstWriterCreateVar(void * ctx,enum fstVarType vt,enum fstVarDir vd,uint32_t len,const char * nam,fstHandle aliasHandle)2624 fstHandle fstWriterCreateVar(void *ctx, enum fstVarType vt, enum fstVarDir vd,
2625         uint32_t len, const char *nam, fstHandle aliasHandle)
2626 {
2627 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2628 unsigned int i;
2629 int nlen, is_real;
2630 
2631 if(xc && nam)
2632         {
2633         if(xc->valpos_mem)
2634                 {
2635                 fstDestroyMmaps(xc, 0);
2636                 }
2637 
2638         fputc(vt, xc->hier_handle);
2639         fputc(vd, xc->hier_handle);
2640         nlen = strlen(nam);
2641         fstFwrite(nam, nlen, 1, xc->hier_handle);
2642         fputc(0, xc->hier_handle);
2643         xc->hier_file_len += (nlen+3);
2644 
2645         if((vt == FST_VT_VCD_REAL) || (vt == FST_VT_VCD_REAL_PARAMETER) || (vt == FST_VT_VCD_REALTIME) || (vt == FST_VT_SV_SHORTREAL))
2646                 {
2647                 is_real = 1;
2648                 len = 8; /* recast number of bytes to that of what a double is */
2649                 }
2650                 else
2651                 {
2652                 is_real = 0;
2653                 if(vt == FST_VT_GEN_STRING)
2654                         {
2655                         len = 0;
2656                         }
2657                 }
2658 
2659         xc->hier_file_len += fstWriterVarint(xc->hier_handle, len);
2660 
2661         if(aliasHandle > xc->maxhandle) aliasHandle = 0;
2662         xc->hier_file_len += fstWriterVarint(xc->hier_handle, aliasHandle);
2663         xc->numsigs++;
2664         if(xc->numsigs == xc->next_huge_break)
2665                 {
2666                 if(xc->fst_break_size < xc->fst_huge_break_size)
2667                         {
2668                         xc->next_huge_break += FST_ACTIVATE_HUGE_INC;
2669                         xc->fst_break_size += xc->fst_orig_break_size;
2670                         xc->fst_break_add_size += xc->fst_orig_break_add_size;
2671 
2672                         xc->vchg_alloc_siz = xc->fst_break_size + xc->fst_break_add_size;
2673                         if(xc->vchg_mem)
2674                                 {
2675                                 xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz);
2676                                 }
2677                         }
2678                 }
2679 
2680         if(!aliasHandle)
2681                 {
2682                 uint32_t zero = 0;
2683 
2684                 if(len)
2685                         {
2686                         fstWriterVarint(xc->geom_handle, !is_real ? len : 0); /* geom section encodes reals as zero byte */
2687                         }
2688                         else
2689                         {
2690                         fstWriterVarint(xc->geom_handle, 0xFFFFFFFF);         /* geom section encodes zero len as 32b -1 */
2691                         }
2692 
2693                 fstFwrite(&xc->maxvalpos, sizeof(uint32_t), 1, xc->valpos_handle);
2694                 fstFwrite(&len, sizeof(uint32_t), 1, xc->valpos_handle);
2695                 fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle);
2696                 fstFwrite(&zero, sizeof(uint32_t), 1, xc->valpos_handle);
2697 
2698                 if(!is_real)
2699                         {
2700                         for(i=0;i<len;i++)
2701                                 {
2702                                 fputc('x', xc->curval_handle);
2703                                 }
2704                         }
2705                         else
2706                         {
2707                         fstFwrite(&xc->nan, 8, 1, xc->curval_handle); /* initialize doubles to NaN rather than x */
2708                         }
2709 
2710                 xc->maxvalpos+=len;
2711                 xc->maxhandle++;
2712                 return(xc->maxhandle);
2713                 }
2714                 else
2715                 {
2716                 return(aliasHandle);
2717                 }
2718         }
2719 
2720 return(0);
2721 }
2722 
2723 
fstWriterSetScope(void * ctx,enum fstScopeType scopetype,const char * scopename,const char * scopecomp)2724 void fstWriterSetScope(void *ctx, enum fstScopeType scopetype,
2725                 const char *scopename, const char *scopecomp)
2726 {
2727 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2728 
2729 if(xc)
2730         {
2731         fputc(FST_ST_VCD_SCOPE, xc->hier_handle);
2732         if(/*(scopetype < FST_ST_VCD_MODULE) ||*/ (scopetype > FST_ST_MAX)) { scopetype = FST_ST_VCD_MODULE; }
2733         fputc(scopetype, xc->hier_handle);
2734         fprintf(xc->hier_handle, "%s%c%s%c",
2735                 scopename ? scopename : "", 0,
2736                 scopecomp ? scopecomp : "", 0);
2737 
2738         if(scopename)
2739                 {
2740                 xc->hier_file_len += strlen(scopename);
2741                 }
2742         if(scopecomp)
2743                 {
2744                 xc->hier_file_len += strlen(scopecomp);
2745                 }
2746 
2747         xc->hier_file_len += 4; /* FST_ST_VCD_SCOPE + scopetype + two string terminating zeros */
2748         xc->numscopes++;
2749         }
2750 }
2751 
2752 
fstWriterSetUpscope(void * ctx)2753 void fstWriterSetUpscope(void *ctx)
2754 {
2755 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2756 
2757 if(xc)
2758         {
2759         fputc(FST_ST_VCD_UPSCOPE, xc->hier_handle);
2760         xc->hier_file_len++;
2761         }
2762 }
2763 
2764 
fstWriterSetAttrBegin(void * ctx,enum fstAttrType attrtype,int subtype,const char * attrname,uint64_t arg)2765 void fstWriterSetAttrBegin(void *ctx, enum fstAttrType attrtype, int subtype,
2766                 const char *attrname, uint64_t arg)
2767 {
2768 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2769 
2770 if(xc)
2771         {
2772         fputc(FST_ST_GEN_ATTRBEGIN, xc->hier_handle);
2773         if(/*(attrtype < FST_AT_MISC) ||*/ (attrtype > FST_AT_MAX)) { attrtype = FST_AT_MISC; subtype = FST_MT_UNKNOWN; }
2774         fputc(attrtype, xc->hier_handle);
2775 
2776         switch(attrtype)
2777                 {
2778                 case FST_AT_ARRAY:      if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE; break;
2779                 case FST_AT_ENUM:       if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER; break;
2780                 case FST_AT_PACK:       if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE; break;
2781 
2782                 case FST_AT_MISC:
2783                 default:                break;
2784                 }
2785 
2786         fputc(subtype, xc->hier_handle);
2787         fprintf(xc->hier_handle, "%s%c",
2788                 attrname ? attrname : "", 0);
2789 
2790         if(attrname)
2791                 {
2792                 xc->hier_file_len += strlen(attrname);
2793                 }
2794 
2795         xc->hier_file_len += 4; /* FST_ST_GEN_ATTRBEGIN + type + subtype + string terminating zero */
2796         xc->hier_file_len += fstWriterVarint(xc->hier_handle, arg);
2797         }
2798 }
2799 
2800 
fstWriterSetAttrEnd(void * ctx)2801 void fstWriterSetAttrEnd(void *ctx)
2802 {
2803 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2804 
2805 if(xc)
2806         {
2807         fputc(FST_ST_GEN_ATTREND, xc->hier_handle);
2808         xc->hier_file_len++;
2809         }
2810 }
2811 
2812 
fstWriterCreateEnumTable(void * ctx,const char * name,uint32_t elem_count,unsigned int min_valbits,const char ** literal_arr,const char ** val_arr)2813 fstEnumHandle fstWriterCreateEnumTable(void *ctx, const char *name, uint32_t elem_count, unsigned int min_valbits, const char **literal_arr, const char **val_arr)
2814 {
2815 fstEnumHandle handle = 0;
2816 unsigned int *literal_lens = NULL;
2817 unsigned int *val_lens = NULL;
2818 int lit_len_tot = 0;
2819 int val_len_tot = 0;
2820 int name_len;
2821 char elem_count_buf[16];
2822 int elem_count_len;
2823 int total_len;
2824 int pos = 0;
2825 char *attr_str = NULL;
2826 
2827 if(ctx && name && literal_arr && val_arr && (elem_count != 0))
2828 	{
2829 	struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2830 
2831 	uint32_t i;
2832 
2833 	name_len = strlen(name);
2834 	elem_count_len = sprintf(elem_count_buf, "%" PRIu32, elem_count);
2835 
2836 	literal_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
2837 	val_lens = (unsigned int *)calloc(elem_count, sizeof(unsigned int));
2838 
2839 	for(i=0;i<elem_count;i++)
2840 		{
2841 		literal_lens[i] = strlen(literal_arr[i]);
2842 		lit_len_tot += fstUtilityBinToEscConvertedLen((unsigned char*)literal_arr[i], literal_lens[i]);
2843 
2844 		val_lens[i] =  strlen(val_arr[i]);
2845 		val_len_tot += fstUtilityBinToEscConvertedLen((unsigned char*)val_arr[i], val_lens[i]);
2846 
2847 		if(min_valbits > 0)
2848 			{
2849 			if(val_lens[i] < min_valbits)
2850 				{
2851 				val_len_tot += (min_valbits - val_lens[i]); /* additional converted len is same for '0' character */
2852 				}
2853 			}
2854 		}
2855 
2856 	total_len = name_len + 1 + elem_count_len + 1 + lit_len_tot + elem_count + val_len_tot + elem_count;
2857 
2858 	attr_str = (char*)malloc(total_len);
2859 	pos = 0;
2860 
2861 	memcpy(attr_str+pos, name, name_len);
2862 	pos += name_len;
2863 	attr_str[pos++] = ' ';
2864 
2865 	memcpy(attr_str+pos, elem_count_buf, elem_count_len);
2866 	pos += elem_count_len;
2867 	attr_str[pos++] = ' ';
2868 
2869 	for(i=0;i<elem_count;i++)
2870 		{
2871 		pos += fstUtilityBinToEsc((unsigned char*)attr_str+pos, (unsigned char*)literal_arr[i], literal_lens[i]);
2872 		attr_str[pos++] = ' ';
2873 		}
2874 
2875 	for(i=0;i<elem_count;i++)
2876 		{
2877 		if(min_valbits > 0)
2878 			{
2879 			if(val_lens[i] < min_valbits)
2880 				{
2881 				memset(attr_str+pos, '0', min_valbits - val_lens[i]);
2882 				pos += (min_valbits - val_lens[i]);
2883 				}
2884 			}
2885 
2886 		pos += fstUtilityBinToEsc((unsigned char*)attr_str+pos, (unsigned char*)val_arr[i], val_lens[i]);
2887 		attr_str[pos++] = ' ';
2888 		}
2889 
2890 	attr_str[pos-1] = 0;
2891 
2892 #ifdef FST_DEBUG
2893 	fprintf(stderr, FST_APIMESS "fstWriterCreateEnumTable() total_len: %d, pos: %d\n", total_len, pos);
2894 	fprintf(stderr, FST_APIMESS "*%s*\n", attr_str);
2895 #endif
2896 
2897 	fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, attr_str, handle = ++xc->max_enumhandle);
2898 
2899 	free(attr_str);
2900 	free(val_lens);
2901 	free(literal_lens);
2902 	}
2903 
2904 return(handle);
2905 }
2906 
2907 
fstWriterEmitEnumTableRef(void * ctx,fstEnumHandle handle)2908 void fstWriterEmitEnumTableRef(void *ctx, fstEnumHandle handle)
2909 {
2910 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2911 if(xc && handle)
2912 	{
2913 	fstWriterSetAttrBegin(xc, FST_AT_MISC, FST_MT_ENUMTABLE, NULL, handle);
2914         }
2915 }
2916 
2917 
2918 /*
2919  * value and time change emission
2920  */
fstWriterEmitValueChange(void * ctx,fstHandle handle,const void * val)2921 void fstWriterEmitValueChange(void *ctx, fstHandle handle, const void *val)
2922 {
2923 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
2924 const unsigned char *buf = (const unsigned char *)val;
2925 uint32_t offs;
2926 int len;
2927 
2928 if(FST_LIKELY((xc) && (handle <= xc->maxhandle)))
2929         {
2930         uint32_t fpos;
2931         uint32_t *vm4ip;
2932 
2933         if(FST_UNLIKELY(!xc->valpos_mem))
2934                 {
2935                 xc->vc_emitted = 1;
2936                 fstWriterCreateMmaps(xc);
2937                 }
2938 
2939         handle--; /* move starting at 1 index to starting at 0 */
2940         vm4ip = &(xc->valpos_mem[4*handle]);
2941 
2942         len  = vm4ip[1];
2943         if(FST_LIKELY(len)) /* len of zero = variable length, use fstWriterEmitVariableLengthValueChange */
2944                 {
2945                 if(FST_LIKELY(!xc->is_initial_time))
2946                         {
2947                         fpos = xc->vchg_siz;
2948 
2949                         if(FST_UNLIKELY((fpos + len + 10) > xc->vchg_alloc_siz))
2950                                 {
2951                                 xc->vchg_alloc_siz += (xc->fst_break_add_size + len); /* +len added in the case of extremely long vectors and small break add sizes */
2952                                 xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz);
2953                                 if(FST_UNLIKELY(!xc->vchg_mem))
2954                                         {
2955                                         fprintf(stderr, FST_APIMESS "Could not realloc() in fstWriterEmitValueChange, exiting.\n");
2956                                         exit(255);
2957                                         }
2958                                 }
2959 #ifdef FST_REMOVE_DUPLICATE_VC
2960                         offs = vm4ip[0];
2961 
2962                         if(len != 1)
2963                                 {
2964                                 if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2]))
2965                                         {
2966                                         unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */
2967                                         while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ }
2968                                         memcpy(old_value, buf, len); /* overlay new value */
2969 
2970                                         memcpy(xc->curval_mem + offs, buf, len);
2971                                         return;
2972                                         }
2973                                 else
2974                                         {
2975                                         if(!memcmp(xc->curval_mem + offs, buf, len))
2976                                                 {
2977                                                 if(!xc->curtime)
2978                                                         {
2979                                                         int i;
2980                                                         for(i=0;i<len;i++)
2981                                                                 {
2982                                                                 if(buf[i]!='x') break;
2983                                                                 }
2984 
2985                                                         if(i<len) return;
2986                                                         }
2987                                                         else
2988                                                         {
2989                                                         return;
2990                                                         }
2991                                                 }
2992                                         }
2993 
2994                                 memcpy(xc->curval_mem + offs, buf, len);
2995                                 }
2996                                 else
2997                                 {
2998                                 if((vm4ip[3]==xc->tchn_idx)&&(vm4ip[2]))
2999                                         {
3000                                         unsigned char *old_value = xc->vchg_mem + vm4ip[2] + 4; /* the +4 skips old vm4ip[2] value */
3001                                         while(*(old_value++) & 0x80) { /* skips over varint encoded "xc->tchn_idx - vm4ip[3]" */ }
3002                                         *old_value = *buf; /* overlay new value */
3003 
3004                                         *(xc->curval_mem + offs) = *buf;
3005                                         return;
3006                                         }
3007                                 else
3008                                         {
3009                                         if((*(xc->curval_mem + offs)) == (*buf))
3010                                                 {
3011                                                 if(!xc->curtime)
3012                                                         {
3013                                                         if(*buf != 'x') return;
3014                                                         }
3015                                                         else
3016                                                         {
3017                                                         return;
3018                                                         }
3019                                                 }
3020                                         }
3021 
3022                                 *(xc->curval_mem + offs) = *buf;
3023                                 }
3024 #endif
3025                         xc->vchg_siz += fstWriterUint32WithVarint32(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */
3026                         vm4ip[3] = xc->tchn_idx;
3027                         vm4ip[2] = fpos;
3028                         }
3029                         else
3030                         {
3031                         offs = vm4ip[0];
3032                         memcpy(xc->curval_mem + offs, buf, len);
3033                         }
3034                 }
3035         }
3036 }
3037 
fstWriterEmitValueChange32(void * ctx,fstHandle handle,uint32_t bits,uint32_t val)3038 void fstWriterEmitValueChange32(void *ctx, fstHandle handle,
3039                                 uint32_t bits, uint32_t val) {
3040         char buf[32];
3041         char *s = buf;
3042         uint32_t i;
3043         for (i = 0; i < bits; ++i)
3044         {
3045                 *s++ = '0' + ((val >> (bits - i - 1)) & 1);
3046         }
3047         fstWriterEmitValueChange(ctx, handle, buf);
3048 }
fstWriterEmitValueChange64(void * ctx,fstHandle handle,uint32_t bits,uint64_t val)3049 void fstWriterEmitValueChange64(void *ctx, fstHandle handle,
3050                                 uint32_t bits, uint64_t val) {
3051         char buf[64];
3052         char *s = buf;
3053         uint32_t i;
3054         for (i = 0; i < bits; ++i)
3055         {
3056                 *s++ = '0' + ((val >> (bits - i - 1)) & 1);
3057         }
3058         fstWriterEmitValueChange(ctx, handle, buf);
3059 }
fstWriterEmitValueChangeVec32(void * ctx,fstHandle handle,uint32_t bits,const uint32_t * val)3060 void fstWriterEmitValueChangeVec32(void *ctx, fstHandle handle,
3061                                    uint32_t bits, const uint32_t *val) {
3062         struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
3063         if (FST_UNLIKELY(bits <= 32))
3064         {
3065                 fstWriterEmitValueChange32(ctx, handle, bits, val[0]);
3066         }
3067         else if(FST_LIKELY(xc))
3068         {
3069                 int bq = bits / 32;
3070                 int br = bits & 31;
3071                 int i;
3072                 int w;
3073                 uint32_t v;
3074                 unsigned char* s;
3075                 if (FST_UNLIKELY(bits > xc->outval_alloc_siz))
3076                 {
3077                         xc->outval_alloc_siz = bits*2 + 1;
3078                         xc->outval_mem = (unsigned char*)realloc(xc->outval_mem, xc->outval_alloc_siz);
3079                         if (FST_UNLIKELY(!xc->outval_mem))
3080                         {
3081                                 fprintf(stderr,
3082                                         FST_APIMESS "Could not realloc() in fstWriterEmitValueChangeVec32, exiting.\n");
3083                                 exit(255);
3084                         }
3085                 }
3086                 s = xc->outval_mem;
3087                 {
3088                         w = bq;
3089                         v = val[w];
3090                         for (i = 0; i < br; ++i)
3091                         {
3092                                 *s++ = '0' + ((v >> (br - i - 1)) & 1);
3093                         }
3094                 }
3095                 for (w = bq - 1; w >= 0; --w)
3096                 {
3097                         v = val[w];
3098                         for (i = (32 - 4); i >= 0; i -= 4) {
3099                                 s[0] = '0' + ((v >> (i + 3)) & 1);
3100                                 s[1] = '0' + ((v >> (i + 2)) & 1);
3101                                 s[2] = '0' + ((v >> (i + 1)) & 1);
3102                                 s[3] = '0' + ((v >> (i + 0)) & 1);
3103                                 s += 4;
3104                         }
3105                 }
3106                 fstWriterEmitValueChange(ctx, handle, xc->outval_mem);
3107         }
3108 }
fstWriterEmitValueChangeVec64(void * ctx,fstHandle handle,uint32_t bits,const uint64_t * val)3109 void fstWriterEmitValueChangeVec64(void *ctx, fstHandle handle,
3110                                    uint32_t bits, const uint64_t *val) {
3111         struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
3112         if (FST_UNLIKELY(bits <= 64))
3113         {
3114                 fstWriterEmitValueChange64(ctx, handle, bits, val[0]);
3115         }
3116         else if(FST_LIKELY(xc))
3117         {
3118                 int bq = bits / 64;
3119                 int br = bits & 63;
3120                 int i;
3121                 int w;
3122                 uint32_t v;
3123                 unsigned char* s;
3124                 if (FST_UNLIKELY(bits > xc->outval_alloc_siz))
3125                 {
3126                         xc->outval_alloc_siz = bits*2 + 1;
3127                         xc->outval_mem = (unsigned char*)realloc(xc->outval_mem, xc->outval_alloc_siz);
3128                         if (FST_UNLIKELY(!xc->outval_mem))
3129                         {
3130                                 fprintf(stderr,
3131                                         FST_APIMESS "Could not realloc() in fstWriterEmitValueChangeVec64, exiting.\n");
3132                                 exit(255);
3133                         }
3134                 }
3135                 s = xc->outval_mem;
3136                 {
3137                         w = bq;
3138                         v = val[w];
3139                         for (i = 0; i < br; ++i)
3140                         {
3141                                 *s++ = '0' + ((v >> (br - i - 1)) & 1);
3142                         }
3143                 }
3144                 for (w = bq - 1; w >= 0; --w) {
3145                         v = val[w];
3146                         for (i = (64 - 4); i >= 0; i -= 4)
3147                         {
3148                                 s[0] = '0' + ((v >> (i + 3)) & 1);
3149                                 s[1] = '0' + ((v >> (i + 2)) & 1);
3150                                 s[2] = '0' + ((v >> (i + 1)) & 1);
3151                                 s[3] = '0' + ((v >> (i + 0)) & 1);
3152                                 s += 4;
3153                         }
3154                 }
3155                 fstWriterEmitValueChange(ctx, handle, xc->outval_mem);
3156         }
3157 }
3158 
3159 
fstWriterEmitVariableLengthValueChange(void * ctx,fstHandle handle,const void * val,uint32_t len)3160 void fstWriterEmitVariableLengthValueChange(void *ctx, fstHandle handle, const void *val, uint32_t len)
3161 {
3162 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
3163 const unsigned char *buf = (const unsigned char *)val;
3164 
3165 if(FST_LIKELY((xc) && (handle <= xc->maxhandle)))
3166         {
3167         uint32_t fpos;
3168         uint32_t *vm4ip;
3169 
3170         if(FST_UNLIKELY(!xc->valpos_mem))
3171                 {
3172                 xc->vc_emitted = 1;
3173                 fstWriterCreateMmaps(xc);
3174                 }
3175 
3176         handle--; /* move starting at 1 index to starting at 0 */
3177         vm4ip = &(xc->valpos_mem[4*handle]);
3178 
3179         /* there is no initial time dump for variable length value changes */
3180         if(FST_LIKELY(!vm4ip[1])) /* len of zero = variable length */
3181                 {
3182                 fpos = xc->vchg_siz;
3183 
3184                 if(FST_UNLIKELY((fpos + len + 10 + 5) > xc->vchg_alloc_siz))
3185                         {
3186                         xc->vchg_alloc_siz += (xc->fst_break_add_size + len + 5); /* +len added in the case of extremely long vectors and small break add sizes */
3187                         xc->vchg_mem = (unsigned char *)realloc(xc->vchg_mem, xc->vchg_alloc_siz);
3188                         if(FST_UNLIKELY(!xc->vchg_mem))
3189                                 {
3190                                 fprintf(stderr, FST_APIMESS "Could not realloc() in fstWriterEmitVariableLengthValueChange, exiting.\n");
3191                                 exit(255);
3192                                 }
3193                         }
3194 
3195                 xc->vchg_siz += fstWriterUint32WithVarint32AndLength(xc, &vm4ip[2], xc->tchn_idx - vm4ip[3], buf, len); /* do one fwrite op only */
3196                 vm4ip[3] = xc->tchn_idx;
3197                 vm4ip[2] = fpos;
3198                 }
3199         }
3200 }
3201 
3202 
fstWriterEmitTimeChange(void * ctx,uint64_t tim)3203 void fstWriterEmitTimeChange(void *ctx, uint64_t tim)
3204 {
3205 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
3206 unsigned int i;
3207 int skip = 0;
3208 if(xc)
3209         {
3210         if(FST_UNLIKELY(xc->is_initial_time))
3211                 {
3212                 if(xc->size_limit_locked)       /* this resets xc->is_initial_time to one */
3213                         {
3214                         return;
3215                         }
3216 
3217                 if(!xc->valpos_mem)
3218                         {
3219                         fstWriterCreateMmaps(xc);
3220                         }
3221 
3222                 skip = 1;
3223 
3224                 xc->firsttime = (xc->vc_emitted) ? 0: tim;
3225                 xc->curtime = 0;
3226                 xc->vchg_mem[0] = '!';
3227                 xc->vchg_siz = 1;
3228                 fstWriterEmitSectionHeader(xc);
3229                 for(i=0;i<xc->maxhandle;i++)
3230                         {
3231                         xc->valpos_mem[4*i+2] = 0; /* zero out offset val */
3232                         xc->valpos_mem[4*i+3] = 0; /* zero out last time change val */
3233                         }
3234                 xc->is_initial_time = 0;
3235                 }
3236                 else
3237                 {
3238                 if((xc->vchg_siz >= xc->fst_break_size) || (xc->flush_context_pending))
3239                         {
3240                         xc->flush_context_pending = 0;
3241                         fstWriterFlushContextPrivate(xc);
3242                         xc->tchn_cnt++;
3243                         fstWriterVarint(xc->tchn_handle, xc->curtime);
3244                         }
3245                 }
3246 
3247         if(!skip)
3248                 {
3249                 xc->tchn_idx++;
3250                 }
3251         fstWriterVarint(xc->tchn_handle, tim - xc->curtime);
3252         xc->tchn_cnt++;
3253         xc->curtime = tim;
3254         }
3255 }
3256 
3257 
fstWriterEmitDumpActive(void * ctx,int enable)3258 void fstWriterEmitDumpActive(void *ctx, int enable)
3259 {
3260 struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
3261 
3262 if(xc)
3263         {
3264         struct fstBlackoutChain *b = (struct fstBlackoutChain *)calloc(1, sizeof(struct fstBlackoutChain));
3265 
3266         b->tim = xc->curtime;
3267         b->active = (enable != 0);
3268 
3269         xc->num_blackouts++;
3270         if(xc->blackout_curr)
3271                 {
3272                 xc->blackout_curr->next = b;
3273                 xc->blackout_curr = b;
3274                 }
3275                 else
3276                 {
3277                 xc->blackout_head = b;
3278                 xc->blackout_curr = b;
3279                 }
3280         }
3281 }
3282 
3283 
3284 /***********************/
3285 /***                 ***/
3286 /*** reader function ***/
3287 /***                 ***/
3288 /***********************/
3289 
3290 /*
3291  * private structs
3292  */
3293 static const char *vartypes[] = {
3294         "event", "integer", "parameter", "real", "real_parameter",
3295         "reg", "supply0", "supply1", "time", "tri",
3296         "triand", "trior", "trireg", "tri0", "tri1",
3297         "wand", "wire", "wor", "port", "sparray", "realtime",
3298         "string",
3299         "bit", "logic", "int", "shortint", "longint", "byte", "enum", "shortreal"
3300         };
3301 
3302 static const char *modtypes[] = {
3303         "module", "task", "function", "begin", "fork", "generate", "struct", "union", "class", "interface", "package", "program",
3304         "vhdl_architecture", "vhdl_procedure", "vhdl_function", "vhdl_record", "vhdl_process", "vhdl_block", "vhdl_for_generate", "vhdl_if_generate", "vhdl_generate", "vhdl_package"
3305         };
3306 
3307 static const char *attrtypes[] = {
3308         "misc", "array", "enum", "class"
3309         };
3310 
3311 static const char *arraytypes[] = {
3312         "none", "unpacked", "packed", "sparse"
3313         };
3314 
3315 static const char *enumvaluetypes[] = {
3316         "integer", "bit", "logic", "int", "shortint", "longint", "byte",
3317         "unsigned_integer", "unsigned_bit", "unsigned_logic", "unsigned_int", "unsigned_shortint", "unsigned_longint", "unsigned_byte"
3318         };
3319 
3320 static const char *packtypes[] = {
3321         "none", "unpacked", "packed", "tagged_packed"
3322         };
3323 
3324 
3325 struct fstCurrHier
3326 {
3327 struct fstCurrHier *prev;
3328 void *user_info;
3329 int len;
3330 };
3331 
3332 
3333 struct fstReaderContext
3334 {
3335 /* common entries */
3336 
3337 FILE *f, *fh;
3338 
3339 uint64_t start_time, end_time;
3340 uint64_t mem_used_by_writer;
3341 uint64_t scope_count;
3342 uint64_t var_count;
3343 fstHandle maxhandle;
3344 uint64_t num_alias;
3345 uint64_t vc_section_count;
3346 
3347 uint32_t *signal_lens;                  /* maxhandle sized */
3348 unsigned char *signal_typs;             /* maxhandle sized */
3349 unsigned char *process_mask;            /* maxhandle-based, bitwise sized */
3350 uint32_t longest_signal_value_len;      /* longest len value encountered */
3351 unsigned char *temp_signal_value_buf;   /* malloced for len in longest_signal_value_len */
3352 
3353 signed char timescale;
3354 unsigned char filetype;
3355 
3356 unsigned use_vcd_extensions : 1;
3357 unsigned double_endian_match : 1;
3358 unsigned native_doubles_for_cb : 1;
3359 unsigned contains_geom_section : 1;
3360 unsigned contains_hier_section : 1;        /* valid for hier_pos */
3361 unsigned contains_hier_section_lz4duo : 1; /* valid for hier_pos (contains_hier_section_lz4 always also set) */
3362 unsigned contains_hier_section_lz4 : 1;    /* valid for hier_pos */
3363 unsigned limit_range_valid : 1;            /* valid for limit_range_start, limit_range_end */
3364 
3365 char version[FST_HDR_SIM_VERSION_SIZE + 1];
3366 char date[FST_HDR_DATE_SIZE + 1];
3367 int64_t timezero;
3368 
3369 char *filename, *filename_unpacked;
3370 fst_off_t hier_pos;
3371 
3372 uint32_t num_blackouts;
3373 uint64_t *blackout_times;
3374 unsigned char *blackout_activity;
3375 
3376 uint64_t limit_range_start, limit_range_end;
3377 
3378 /* entries specific to read value at time functions */
3379 
3380 unsigned rvat_data_valid : 1;
3381 uint64_t *rvat_time_table;
3382 uint64_t rvat_beg_tim, rvat_end_tim;
3383 unsigned char *rvat_frame_data;
3384 uint64_t rvat_frame_maxhandle;
3385 fst_off_t *rvat_chain_table;
3386 uint32_t *rvat_chain_table_lengths;
3387 uint64_t rvat_vc_maxhandle;
3388 fst_off_t rvat_vc_start;
3389 uint32_t *rvat_sig_offs;
3390 int rvat_packtype;
3391 
3392 uint32_t rvat_chain_len;
3393 unsigned char *rvat_chain_mem;
3394 fstHandle rvat_chain_facidx;
3395 
3396 uint32_t rvat_chain_pos_tidx;
3397 uint32_t rvat_chain_pos_idx;
3398 uint64_t rvat_chain_pos_time;
3399 unsigned rvat_chain_pos_valid : 1;
3400 
3401 /* entries specific to hierarchy traversal */
3402 
3403 struct fstHier hier;
3404 struct fstCurrHier *curr_hier;
3405 fstHandle current_handle;
3406 char *curr_flat_hier_nam;
3407 int flat_hier_alloc_len;
3408 unsigned do_rewind : 1;
3409 char str_scope_nam[FST_ID_NAM_SIZ+1];
3410 char str_scope_comp[FST_ID_NAM_SIZ+1];
3411 
3412 unsigned fseek_failed : 1;
3413 
3414 /* self-buffered I/O for writes */
3415 
3416 #ifndef FST_WRITEX_DISABLE
3417 int writex_pos;
3418 int writex_fd;
3419 unsigned char writex_buf[FST_WRITEX_MAX];
3420 #endif
3421 
3422 char *f_nam;
3423 char *fh_nam;
3424 };
3425 
3426 
fstReaderFseeko(struct fstReaderContext * xc,FILE * stream,fst_off_t offset,int whence)3427 int fstReaderFseeko(struct fstReaderContext *xc, FILE *stream, fst_off_t offset, int whence)
3428 {
3429 int rc = fseeko(stream, offset, whence);
3430 
3431 if(rc<0)
3432         {
3433         xc->fseek_failed = 1;
3434 #ifdef FST_DEBUG
3435         fprintf(stderr, FST_APIMESS "Seek to #%" PRId64 " (whence = %d) failed!\n", offset, whence);
3436         perror("Why");
3437 #endif
3438         }
3439 
3440 return(rc);
3441 }
3442 
3443 
3444 #ifndef FST_WRITEX_DISABLE
fstWritex(struct fstReaderContext * xc,void * v,int len)3445 static void fstWritex(struct fstReaderContext *xc, void *v, int len)
3446 {
3447 unsigned char *s = (unsigned char *)v;
3448 
3449 if(len)
3450         {
3451         if(len < FST_WRITEX_MAX)
3452                 {
3453                 if(xc->writex_pos + len >= FST_WRITEX_MAX)
3454                         {
3455                         fstWritex(xc, NULL, 0);
3456                         }
3457 
3458                 memcpy(xc->writex_buf + xc->writex_pos, s, len);
3459                 xc->writex_pos += len;
3460                 }
3461                 else
3462                 {
3463                 fstWritex(xc, NULL, 0);
3464                 if (write(xc->writex_fd, s, len)) { };
3465                 }
3466         }
3467         else
3468         {
3469         if(xc->writex_pos)
3470                 {
3471                 if(write(xc->writex_fd, xc->writex_buf, xc->writex_pos)) { };
3472                 xc->writex_pos = 0;
3473                 }
3474         }
3475 }
3476 #endif
3477 
3478 
3479 /*
3480  * scope -> flat name handling
3481  */
fstReaderDeallocateScopeData(struct fstReaderContext * xc)3482 static void fstReaderDeallocateScopeData(struct fstReaderContext *xc)
3483 {
3484 struct fstCurrHier *chp;
3485 
3486 free(xc->curr_flat_hier_nam); xc->curr_flat_hier_nam = NULL;
3487 while(xc->curr_hier)
3488         {
3489         chp = xc->curr_hier->prev;
3490         free(xc->curr_hier);
3491         xc->curr_hier = chp;
3492         }
3493 }
3494 
3495 
fstReaderGetCurrentFlatScope(void * ctx)3496 const char *fstReaderGetCurrentFlatScope(void *ctx)
3497 {
3498 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3499 if(xc)
3500         {
3501         return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : "");
3502         }
3503         else
3504         {
3505         return(NULL);
3506         }
3507 }
3508 
3509 
fstReaderGetCurrentScopeUserInfo(void * ctx)3510 void *fstReaderGetCurrentScopeUserInfo(void *ctx)
3511 {
3512 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3513 if(xc)
3514         {
3515         return(xc->curr_hier ? xc->curr_hier->user_info : NULL);
3516         }
3517         else
3518         {
3519         return(NULL);
3520         }
3521 }
3522 
3523 
fstReaderPopScope(void * ctx)3524 const char *fstReaderPopScope(void *ctx)
3525 {
3526 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3527 if(xc && xc->curr_hier)
3528         {
3529         struct fstCurrHier *ch = xc->curr_hier;
3530         if(xc->curr_hier->prev)
3531                 {
3532                 xc->curr_flat_hier_nam[xc->curr_hier->prev->len] = 0;
3533                 }
3534                 else
3535                 {
3536                 *xc->curr_flat_hier_nam = 0;
3537                 }
3538         xc->curr_hier = xc->curr_hier->prev;
3539         free(ch);
3540         return(xc->curr_flat_hier_nam ? xc->curr_flat_hier_nam : "");
3541         }
3542 
3543 return(NULL);
3544 }
3545 
3546 
fstReaderResetScope(void * ctx)3547 void fstReaderResetScope(void *ctx)
3548 {
3549 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3550 
3551 if(xc)
3552         {
3553         while(fstReaderPopScope(xc)); /* remove any already-built scoping info */
3554         }
3555 }
3556 
3557 
fstReaderPushScope(void * ctx,const char * nam,void * user_info)3558 const char *fstReaderPushScope(void *ctx, const char *nam, void *user_info)
3559 {
3560 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3561 if(xc)
3562         {
3563         struct fstCurrHier *ch = (struct fstCurrHier *)malloc(sizeof(struct fstCurrHier));
3564         int chl = xc->curr_hier ? xc->curr_hier->len : 0;
3565         int len = chl + 1 + strlen(nam);
3566         if(len >= xc->flat_hier_alloc_len)
3567                 {
3568                 xc->curr_flat_hier_nam = xc->curr_flat_hier_nam ? (char *)realloc(xc->curr_flat_hier_nam, len+1) : (char *)malloc(len+1);
3569                 }
3570 
3571         if(chl)
3572                 {
3573                 xc->curr_flat_hier_nam[chl] = '.';
3574                 strcpy(xc->curr_flat_hier_nam + chl + 1, nam);
3575                 }
3576                 else
3577                 {
3578                 strcpy(xc->curr_flat_hier_nam, nam);
3579                 len--;
3580                 }
3581 
3582         ch->len = len;
3583         ch->prev = xc->curr_hier;
3584         ch->user_info = user_info;
3585         xc->curr_hier = ch;
3586         return(xc->curr_flat_hier_nam);
3587         }
3588 
3589 return(NULL);
3590 }
3591 
3592 
fstReaderGetCurrentScopeLen(void * ctx)3593 int fstReaderGetCurrentScopeLen(void *ctx)
3594 {
3595 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3596 
3597 if(xc && xc->curr_hier)
3598         {
3599         return(xc->curr_hier->len);
3600         }
3601 
3602 return(0);
3603 }
3604 
3605 
fstReaderGetFseekFailed(void * ctx)3606 int fstReaderGetFseekFailed(void *ctx)
3607 {
3608 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3609 if(xc)
3610         {
3611         return(xc->fseek_failed != 0);
3612         }
3613 
3614 return(0);
3615 }
3616 
3617 
3618 /*
3619  * iter mask manipulation util functions
3620  */
fstReaderGetFacProcessMask(void * ctx,fstHandle facidx)3621 int fstReaderGetFacProcessMask(void *ctx, fstHandle facidx)
3622 {
3623 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3624 
3625 if(xc)
3626         {
3627         facidx--;
3628         if(facidx<xc->maxhandle)
3629                 {
3630                 int process_idx = facidx/8;
3631                 int process_bit = facidx&7;
3632 
3633                 return( (xc->process_mask[process_idx]&(1<<process_bit)) != 0 );
3634                 }
3635         }
3636 return(0);
3637 }
3638 
3639 
fstReaderSetFacProcessMask(void * ctx,fstHandle facidx)3640 void fstReaderSetFacProcessMask(void *ctx, fstHandle facidx)
3641 {
3642 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3643 
3644 if(xc)
3645         {
3646         facidx--;
3647         if(facidx<xc->maxhandle)
3648                 {
3649                 int idx = facidx/8;
3650                 int bitpos = facidx&7;
3651 
3652                 xc->process_mask[idx] |= (1<<bitpos);
3653                 }
3654         }
3655 }
3656 
3657 
fstReaderClrFacProcessMask(void * ctx,fstHandle facidx)3658 void fstReaderClrFacProcessMask(void *ctx, fstHandle facidx)
3659 {
3660 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3661 
3662 if(xc)
3663         {
3664         facidx--;
3665         if(facidx<xc->maxhandle)
3666                 {
3667                 int idx = facidx/8;
3668                 int bitpos = facidx&7;
3669 
3670                 xc->process_mask[idx] &= (~(1<<bitpos));
3671                 }
3672         }
3673 }
3674 
3675 
fstReaderSetFacProcessMaskAll(void * ctx)3676 void fstReaderSetFacProcessMaskAll(void *ctx)
3677 {
3678 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3679 
3680 if(xc)
3681         {
3682         memset(xc->process_mask, 0xff, (xc->maxhandle+7)/8);
3683         }
3684 }
3685 
3686 
fstReaderClrFacProcessMaskAll(void * ctx)3687 void fstReaderClrFacProcessMaskAll(void *ctx)
3688 {
3689 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3690 
3691 if(xc)
3692         {
3693         memset(xc->process_mask, 0x00, (xc->maxhandle+7)/8);
3694         }
3695 }
3696 
3697 
3698 /*
3699  * various utility read/write functions
3700  */
fstReaderGetTimescale(void * ctx)3701 signed char fstReaderGetTimescale(void *ctx)
3702 {
3703 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3704 return(xc ? xc->timescale : 0);
3705 }
3706 
3707 
fstReaderGetStartTime(void * ctx)3708 uint64_t fstReaderGetStartTime(void *ctx)
3709 {
3710 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3711 return(xc ? xc->start_time : 0);
3712 }
3713 
3714 
fstReaderGetEndTime(void * ctx)3715 uint64_t fstReaderGetEndTime(void *ctx)
3716 {
3717 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3718 return(xc ? xc->end_time : 0);
3719 }
3720 
3721 
fstReaderGetMemoryUsedByWriter(void * ctx)3722 uint64_t fstReaderGetMemoryUsedByWriter(void *ctx)
3723 {
3724 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3725 return(xc ? xc->mem_used_by_writer : 0);
3726 }
3727 
3728 
fstReaderGetScopeCount(void * ctx)3729 uint64_t fstReaderGetScopeCount(void *ctx)
3730 {
3731 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3732 return(xc ? xc->scope_count : 0);
3733 }
3734 
3735 
fstReaderGetVarCount(void * ctx)3736 uint64_t fstReaderGetVarCount(void *ctx)
3737 {
3738 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3739 return(xc ? xc->var_count : 0);
3740 }
3741 
3742 
fstReaderGetMaxHandle(void * ctx)3743 fstHandle fstReaderGetMaxHandle(void *ctx)
3744 {
3745 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3746 return(xc ? xc->maxhandle : 0);
3747 }
3748 
3749 
fstReaderGetAliasCount(void * ctx)3750 uint64_t fstReaderGetAliasCount(void *ctx)
3751 {
3752 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3753 return(xc ? xc->num_alias : 0);
3754 }
3755 
3756 
fstReaderGetValueChangeSectionCount(void * ctx)3757 uint64_t fstReaderGetValueChangeSectionCount(void *ctx)
3758 {
3759 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3760 return(xc ? xc->vc_section_count : 0);
3761 }
3762 
3763 
fstReaderGetDoubleEndianMatchState(void * ctx)3764 int fstReaderGetDoubleEndianMatchState(void *ctx)
3765 {
3766 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3767 return(xc ? xc->double_endian_match : 0);
3768 }
3769 
3770 
fstReaderGetVersionString(void * ctx)3771 const char *fstReaderGetVersionString(void *ctx)
3772 {
3773 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3774 return(xc ? xc->version : NULL);
3775 }
3776 
3777 
fstReaderGetDateString(void * ctx)3778 const char *fstReaderGetDateString(void *ctx)
3779 {
3780 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3781 return(xc ? xc->date : NULL);
3782 }
3783 
3784 
fstReaderGetFileType(void * ctx)3785 int fstReaderGetFileType(void *ctx)
3786 {
3787 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3788 return(xc ? (int)xc->filetype : (int)FST_FT_VERILOG);
3789 }
3790 
3791 
fstReaderGetTimezero(void * ctx)3792 int64_t fstReaderGetTimezero(void *ctx)
3793 {
3794 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3795 return(xc ? xc->timezero : 0);
3796 }
3797 
3798 
fstReaderGetNumberDumpActivityChanges(void * ctx)3799 uint32_t fstReaderGetNumberDumpActivityChanges(void *ctx)
3800 {
3801 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3802 return(xc ? xc->num_blackouts : 0);
3803 }
3804 
3805 
fstReaderGetDumpActivityChangeTime(void * ctx,uint32_t idx)3806 uint64_t fstReaderGetDumpActivityChangeTime(void *ctx, uint32_t idx)
3807 {
3808 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3809 
3810 if(xc && (idx < xc->num_blackouts) && (xc->blackout_times))
3811         {
3812         return(xc->blackout_times[idx]);
3813         }
3814         else
3815         {
3816         return(0);
3817         }
3818 }
3819 
3820 
fstReaderGetDumpActivityChangeValue(void * ctx,uint32_t idx)3821 unsigned char fstReaderGetDumpActivityChangeValue(void *ctx, uint32_t idx)
3822 {
3823 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3824 
3825 if(xc && (idx < xc->num_blackouts) && (xc->blackout_activity))
3826         {
3827         return(xc->blackout_activity[idx]);
3828         }
3829         else
3830         {
3831         return(0);
3832         }
3833 }
3834 
3835 
fstReaderSetLimitTimeRange(void * ctx,uint64_t start_time,uint64_t end_time)3836 void fstReaderSetLimitTimeRange(void *ctx, uint64_t start_time, uint64_t end_time)
3837 {
3838 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3839 
3840 if(xc)
3841         {
3842         xc->limit_range_valid = 1;
3843         xc->limit_range_start = start_time;
3844         xc->limit_range_end = end_time;
3845         }
3846 }
3847 
3848 
fstReaderSetUnlimitedTimeRange(void * ctx)3849 void fstReaderSetUnlimitedTimeRange(void *ctx)
3850 {
3851 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3852 
3853 if(xc)
3854         {
3855         xc->limit_range_valid = 0;
3856         }
3857 }
3858 
3859 
fstReaderSetVcdExtensions(void * ctx,int enable)3860 void fstReaderSetVcdExtensions(void *ctx, int enable)
3861 {
3862 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3863 
3864 if(xc)
3865         {
3866         xc->use_vcd_extensions = (enable != 0);
3867         }
3868 }
3869 
3870 
fstReaderIterBlocksSetNativeDoublesOnCallback(void * ctx,int enable)3871 void fstReaderIterBlocksSetNativeDoublesOnCallback(void *ctx, int enable)
3872 {
3873 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
3874 if(xc)
3875         {
3876         xc->native_doubles_for_cb = (enable != 0);
3877         }
3878 }
3879 
3880 /*
3881  * hierarchy processing
3882  */
fstVcdID(char * buf,unsigned int value)3883 static void fstVcdID(char *buf, unsigned int value)
3884 {
3885 char *pnt = buf;
3886 
3887 /* zero is illegal for a value...it is assumed they start at one */
3888 while (value)
3889         {
3890         value--;
3891         *(pnt++) = (char)('!' + value % 94);
3892         value = value / 94;
3893         }
3894 
3895 *pnt = 0;
3896 }
3897 
fstVcdIDForFwrite(char * buf,unsigned int value)3898 static int fstVcdIDForFwrite(char *buf, unsigned int value)
3899 {
3900 char *pnt = buf;
3901 
3902 /* zero is illegal for a value...it is assumed they start at one */
3903 while (value)
3904         {
3905         value--;
3906         *(pnt++) = (char)('!' + value % 94);
3907         value = value / 94;
3908         }
3909 
3910 return(pnt - buf);
3911 }
3912 
3913 
fstReaderRecreateHierFile(struct fstReaderContext * xc)3914 static int fstReaderRecreateHierFile(struct fstReaderContext *xc)
3915 {
3916 int pass_status = 1;
3917 
3918 if(!xc->fh)
3919         {
3920         fst_off_t offs_cache = ftello(xc->f);
3921         char *fnam = (char *)malloc(strlen(xc->filename) + 6 + 16 + 32 + 1);
3922         unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN);
3923         fst_off_t hl, uclen;
3924         fst_off_t clen = 0;
3925         gzFile zhandle = NULL;
3926         int zfd;
3927         int htyp = FST_BL_SKIP;
3928 
3929         /* can't handle both set at once should never happen in a real file */
3930         if(!xc->contains_hier_section_lz4 && xc->contains_hier_section)
3931                 {
3932                 htyp = FST_BL_HIER;
3933                 }
3934         else
3935         if(xc->contains_hier_section_lz4 && !xc->contains_hier_section)
3936                 {
3937                 htyp = xc->contains_hier_section_lz4duo ? FST_BL_HIER_LZ4DUO : FST_BL_HIER_LZ4;
3938                 }
3939 
3940         sprintf(fnam, "%s.hier_%d_%p", xc->filename, getpid(), (void *)xc);
3941         fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET);
3942         uclen = fstReaderUint64(xc->f);
3943 #ifndef __MINGW32__
3944         fflush(xc->f);
3945 #endif
3946         if(htyp == FST_BL_HIER)
3947                 {
3948                 fstReaderFseeko(xc, xc->f, xc->hier_pos, SEEK_SET);
3949                 uclen = fstReaderUint64(xc->f);
3950 #ifndef __MINGW32__
3951                 fflush(xc->f);
3952 #endif
3953                 zfd = dup(fileno(xc->f));
3954                 zhandle = gzdopen(zfd, "rb");
3955                 if(!zhandle)
3956                         {
3957                         close(zfd);
3958                         free(mem);
3959                         free(fnam);
3960                         return(0);
3961                         }
3962                 }
3963         else
3964         if((htyp == FST_BL_HIER_LZ4) || (htyp == FST_BL_HIER_LZ4DUO))
3965                 {
3966                 fstReaderFseeko(xc, xc->f, xc->hier_pos - 8, SEEK_SET); /* get section len */
3967                 clen =  fstReaderUint64(xc->f) - 16;
3968                 uclen = fstReaderUint64(xc->f);
3969 #ifndef __MINGW32__
3970                 fflush(xc->f);
3971 #endif
3972                 }
3973 
3974 #ifndef __MINGW32__
3975         xc->fh = fopen(fnam, "w+b");
3976         if(!xc->fh)
3977 #endif
3978                 {
3979                 xc->fh = tmpfile_open(&xc->fh_nam);
3980                 free(fnam); fnam = NULL;
3981                 if(!xc->fh)
3982                         {
3983                         tmpfile_close(&xc->fh, &xc->fh_nam);
3984                         free(mem);
3985                         return(0);
3986                         }
3987                 }
3988 
3989 #ifndef __MINGW32__
3990         if(fnam) unlink(fnam);
3991 #endif
3992 
3993         if(htyp == FST_BL_HIER)
3994                 {
3995                 for(hl = 0; hl < uclen; hl += FST_GZIO_LEN)
3996                         {
3997                         size_t len = ((uclen - hl) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - hl);
3998                         size_t gzreadlen = gzread(zhandle, mem, len); /* rc should equal len... */
3999                         size_t fwlen;
4000 
4001                         if(gzreadlen != len)
4002                                 {
4003                                 pass_status = 0;
4004                                 break;
4005                                 }
4006 
4007                         fwlen = fstFwrite(mem, len, 1, xc->fh);
4008                         if(fwlen != 1)
4009                                 {
4010                                 pass_status = 0;
4011                                 break;
4012                                 }
4013                         }
4014                 gzclose(zhandle);
4015                 }
4016         else
4017         if(htyp == FST_BL_HIER_LZ4DUO)
4018                 {
4019                 unsigned char *lz4_cmem  = (unsigned char *)malloc(clen);
4020                 unsigned char *lz4_ucmem = (unsigned char *)malloc(uclen);
4021                 unsigned char *lz4_ucmem2;
4022                 uint64_t uclen2;
4023                 int skiplen2 = 0;
4024 
4025                 fstFread(lz4_cmem, clen, 1, xc->f);
4026 
4027                 uclen2 = fstGetVarint64(lz4_cmem, &skiplen2);
4028                 lz4_ucmem2 = (unsigned char *)malloc(uclen2);
4029                 pass_status = (uclen2 == (uint64_t)LZ4_decompress_safe_partial ((char *)lz4_cmem + skiplen2, (char *)lz4_ucmem2, clen - skiplen2, uclen2, uclen2));
4030                 if(pass_status)
4031                         {
4032                         pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_ucmem2, (char *)lz4_ucmem, uclen2, uclen, uclen));
4033 
4034                         if(fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1)
4035                                 {
4036                                 pass_status = 0;
4037                                 }
4038                         }
4039 
4040                 free(lz4_ucmem2);
4041                 free(lz4_ucmem);
4042                 free(lz4_cmem);
4043                 }
4044         else
4045         if(htyp == FST_BL_HIER_LZ4)
4046                 {
4047                 unsigned char *lz4_cmem  = (unsigned char *)malloc(clen);
4048                 unsigned char *lz4_ucmem = (unsigned char *)malloc(uclen);
4049 
4050                 fstFread(lz4_cmem, clen, 1, xc->f);
4051                 pass_status = (uclen == LZ4_decompress_safe_partial ((char *)lz4_cmem, (char *)lz4_ucmem, clen, uclen, uclen));
4052 
4053                 if(fstFwrite(lz4_ucmem, uclen, 1, xc->fh) != 1)
4054                         {
4055                         pass_status = 0;
4056                         }
4057 
4058                 free(lz4_ucmem);
4059                 free(lz4_cmem);
4060                 }
4061         else /* FST_BL_SKIP */
4062                 {
4063                 pass_status = 0;
4064                 if(xc->fh)
4065                         {
4066                         fclose(xc->fh); xc->fh = NULL; /* needed in case .hier file is missing and there are no hier sections */
4067                         }
4068                 }
4069 
4070         free(mem);
4071         free(fnam);
4072 
4073         fstReaderFseeko(xc, xc->f, offs_cache, SEEK_SET);
4074         }
4075 
4076 return(pass_status);
4077 }
4078 
4079 
fstReaderIterateHierRewind(void * ctx)4080 int fstReaderIterateHierRewind(void *ctx)
4081 {
4082 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4083 int pass_status = 0;
4084 
4085 if(xc)
4086         {
4087         pass_status = 1;
4088         if(!xc->fh)
4089                 {
4090                 pass_status = fstReaderRecreateHierFile(xc);
4091                 }
4092 
4093         xc->do_rewind = 1;
4094         }
4095 
4096 return(pass_status);
4097 }
4098 
4099 
fstReaderIterateHier(void * ctx)4100 struct fstHier *fstReaderIterateHier(void *ctx)
4101 {
4102 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4103 int isfeof;
4104 fstHandle alias;
4105 char *pnt;
4106 int ch;
4107 
4108 if(!xc) return(NULL);
4109 
4110 if(!xc->fh)
4111         {
4112         if(!fstReaderRecreateHierFile(xc))
4113                 {
4114                 return(NULL);
4115                 }
4116         }
4117 
4118 if(xc->do_rewind)
4119         {
4120         xc->do_rewind = 0;
4121         xc->current_handle = 0;
4122         fstReaderFseeko(xc, xc->fh, 0, SEEK_SET);
4123         clearerr(xc->fh);
4124         }
4125 
4126 if(!(isfeof=feof(xc->fh)))
4127         {
4128         int tag = fgetc(xc->fh);
4129         switch(tag)
4130                 {
4131                 case FST_ST_VCD_SCOPE:
4132                         xc->hier.htyp = FST_HT_SCOPE;
4133                         xc->hier.u.scope.typ = fgetc(xc->fh);
4134                         xc->hier.u.scope.name = pnt = xc->str_scope_nam;
4135                         while((ch = fgetc(xc->fh)))
4136                                 {
4137                                 *(pnt++) = ch;
4138                                 }; /* scopename */
4139                         *pnt = 0;
4140                         xc->hier.u.scope.name_length = pnt - xc->hier.u.scope.name;
4141 
4142                         xc->hier.u.scope.component = pnt = xc->str_scope_comp;
4143                         while((ch = fgetc(xc->fh)))
4144                                 {
4145                                 *(pnt++) = ch;
4146                                 }; /* scopecomp */
4147                         *pnt = 0;
4148                         xc->hier.u.scope.component_length = pnt - xc->hier.u.scope.component;
4149                         break;
4150 
4151                 case FST_ST_VCD_UPSCOPE:
4152                         xc->hier.htyp = FST_HT_UPSCOPE;
4153                         break;
4154 
4155                 case FST_ST_GEN_ATTRBEGIN:
4156                         xc->hier.htyp = FST_HT_ATTRBEGIN;
4157                         xc->hier.u.attr.typ = fgetc(xc->fh);
4158                         xc->hier.u.attr.subtype = fgetc(xc->fh);
4159                         xc->hier.u.attr.name = pnt = xc->str_scope_nam;
4160                         while((ch = fgetc(xc->fh)))
4161                                 {
4162                                 *(pnt++) = ch;
4163                                 }; /* scopename */
4164                         *pnt = 0;
4165                         xc->hier.u.attr.name_length = pnt - xc->hier.u.scope.name;
4166 
4167                         xc->hier.u.attr.arg = fstReaderVarint64(xc->fh);
4168 
4169                         if(xc->hier.u.attr.typ == FST_AT_MISC)
4170                                 {
4171                                 if((xc->hier.u.attr.subtype == FST_MT_SOURCESTEM)||(xc->hier.u.attr.subtype == FST_MT_SOURCEISTEM))
4172                                         {
4173                                         int sidx_skiplen_dummy = 0;
4174                                         xc->hier.u.attr.arg_from_name = fstGetVarint64((unsigned char *)xc->str_scope_nam, &sidx_skiplen_dummy);
4175                                         }
4176                                 }
4177                         break;
4178 
4179                 case FST_ST_GEN_ATTREND:
4180                         xc->hier.htyp = FST_HT_ATTREND;
4181                         break;
4182 
4183                 case FST_VT_VCD_EVENT:
4184                 case FST_VT_VCD_INTEGER:
4185                 case FST_VT_VCD_PARAMETER:
4186                 case FST_VT_VCD_REAL:
4187                 case FST_VT_VCD_REAL_PARAMETER:
4188                 case FST_VT_VCD_REG:
4189                 case FST_VT_VCD_SUPPLY0:
4190                 case FST_VT_VCD_SUPPLY1:
4191                 case FST_VT_VCD_TIME:
4192                 case FST_VT_VCD_TRI:
4193                 case FST_VT_VCD_TRIAND:
4194                 case FST_VT_VCD_TRIOR:
4195                 case FST_VT_VCD_TRIREG:
4196                 case FST_VT_VCD_TRI0:
4197                 case FST_VT_VCD_TRI1:
4198                 case FST_VT_VCD_WAND:
4199                 case FST_VT_VCD_WIRE:
4200                 case FST_VT_VCD_WOR:
4201                 case FST_VT_VCD_PORT:
4202                 case FST_VT_VCD_SPARRAY:
4203                 case FST_VT_VCD_REALTIME:
4204                 case FST_VT_GEN_STRING:
4205                 case FST_VT_SV_BIT:
4206                 case FST_VT_SV_LOGIC:
4207                 case FST_VT_SV_INT:
4208                 case FST_VT_SV_SHORTINT:
4209                 case FST_VT_SV_LONGINT:
4210                 case FST_VT_SV_BYTE:
4211                 case FST_VT_SV_ENUM:
4212                 case FST_VT_SV_SHORTREAL:
4213                         xc->hier.htyp = FST_HT_VAR;
4214                         xc->hier.u.var.svt_workspace = FST_SVT_NONE;
4215                         xc->hier.u.var.sdt_workspace = FST_SDT_NONE;
4216                         xc->hier.u.var.sxt_workspace = 0;
4217                         xc->hier.u.var.typ = tag;
4218                         xc->hier.u.var.direction = fgetc(xc->fh);
4219                         xc->hier.u.var.name = pnt = xc->str_scope_nam;
4220                         while((ch = fgetc(xc->fh)))
4221                                 {
4222                                 *(pnt++) = ch;
4223                                 }; /* varname */
4224                         *pnt = 0;
4225                         xc->hier.u.var.name_length = pnt - xc->hier.u.var.name;
4226                         xc->hier.u.var.length = fstReaderVarint32(xc->fh);
4227                         if(tag == FST_VT_VCD_PORT)
4228                                 {
4229                                 xc->hier.u.var.length -= 2; /* removal of delimiting spaces */
4230                                 xc->hier.u.var.length /= 3; /* port -> signal size adjust */
4231                                 }
4232 
4233                         alias = fstReaderVarint32(xc->fh);
4234 
4235                         if(!alias)
4236                                 {
4237                                 xc->current_handle++;
4238                                 xc->hier.u.var.handle = xc->current_handle;
4239                                 xc->hier.u.var.is_alias = 0;
4240                                 }
4241                                 else
4242                                 {
4243                                 xc->hier.u.var.handle = alias;
4244                                 xc->hier.u.var.is_alias = 1;
4245                                 }
4246 
4247                         break;
4248 
4249                 default:
4250                         isfeof = 1;
4251                         break;
4252                 }
4253         }
4254 
4255 return(!isfeof ? &xc->hier : NULL);
4256 }
4257 
4258 
fstReaderProcessHier(void * ctx,FILE * fv)4259 int fstReaderProcessHier(void *ctx, FILE *fv)
4260 {
4261 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4262 char *str;
4263 char *pnt;
4264 int ch, scopetype;
4265 int vartype;
4266 uint32_t len, alias;
4267 /* uint32_t maxvalpos=0; */
4268 unsigned int num_signal_dyn = 65536;
4269 int attrtype, subtype;
4270 uint64_t attrarg;
4271 fstHandle maxhandle_scanbuild;
4272 
4273 if(!xc) return(0);
4274 
4275 xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */
4276 
4277 if(!xc->fh)
4278         {
4279         if(!fstReaderRecreateHierFile(xc))
4280                 {
4281                 return(0);
4282                 }
4283         }
4284 
4285 str = (char *)malloc(FST_ID_NAM_ATTR_SIZ+1);
4286 
4287 if(fv)
4288         {
4289         char time_dimension[2] = {0, 0};
4290         int time_scale = 1;
4291 
4292         fprintf(fv, "$date\n\t%s\n$end\n", xc->date);
4293         fprintf(fv, "$version\n\t%s\n$end\n", xc->version);
4294         if(xc->timezero) fprintf(fv, "$timezero\n\t%" PRId64 "\n$end\n", xc->timezero);
4295 
4296         switch(xc->timescale)
4297                 {
4298                 case  2:        time_scale = 100;               time_dimension[0] = 0;   break;
4299                 case  1:        time_scale = 10; /* fallthrough */
4300                 case  0:                                        time_dimension[0] = 0;   break;
4301 
4302                 case -1:        time_scale = 100;               time_dimension[0] = 'm'; break;
4303                 case -2:        time_scale = 10; /* fallthrough */
4304                 case -3:                                        time_dimension[0] = 'm'; break;
4305 
4306                 case -4:        time_scale = 100;               time_dimension[0] = 'u'; break;
4307                 case -5:        time_scale = 10; /* fallthrough */
4308                 case -6:                                        time_dimension[0] = 'u'; break;
4309 
4310                 case -10:       time_scale = 100;               time_dimension[0] = 'p'; break;
4311                 case -11:       time_scale = 10; /* fallthrough */
4312                 case -12:                                       time_dimension[0] = 'p'; break;
4313 
4314                 case -13:       time_scale = 100;               time_dimension[0] = 'f'; break;
4315                 case -14:       time_scale = 10; /* fallthrough */
4316                 case -15:                                       time_dimension[0] = 'f'; break;
4317 
4318                 case -16:       time_scale = 100;               time_dimension[0] = 'a'; break;
4319                 case -17:       time_scale = 10; /* fallthrough */
4320                 case -18:                                       time_dimension[0] = 'a'; break;
4321 
4322                 case -19:       time_scale = 100;               time_dimension[0] = 'z'; break;
4323                 case -20:       time_scale = 10; /* fallthrough */
4324                 case -21:                                       time_dimension[0] = 'z'; break;
4325 
4326                 case -7:        time_scale = 100;               time_dimension[0] = 'n'; break;
4327                 case -8:        time_scale = 10; /* fallthrough */
4328                 case -9:
4329                 default:                                        time_dimension[0] = 'n'; break;
4330                 }
4331 
4332         if(fv) fprintf(fv, "$timescale\n\t%d%ss\n$end\n", time_scale, time_dimension);
4333         }
4334 
4335 xc->maxhandle = 0;
4336 xc->num_alias = 0;
4337 
4338 free(xc->signal_lens);
4339 xc->signal_lens = (uint32_t *)malloc(num_signal_dyn*sizeof(uint32_t));
4340 
4341 free(xc->signal_typs);
4342 xc->signal_typs = (unsigned char *)malloc(num_signal_dyn*sizeof(unsigned char));
4343 
4344 fstReaderFseeko(xc, xc->fh, 0, SEEK_SET);
4345 while(!feof(xc->fh))
4346         {
4347         int tag = fgetc(xc->fh);
4348         switch(tag)
4349                 {
4350                 case FST_ST_VCD_SCOPE:
4351                         scopetype = fgetc(xc->fh);
4352                         if((scopetype < FST_ST_MIN) || (scopetype > FST_ST_MAX)) scopetype = FST_ST_VCD_MODULE;
4353                         pnt = str;
4354                         while((ch = fgetc(xc->fh)))
4355                                 {
4356                                 *(pnt++) = ch;
4357                                 }; /* scopename */
4358                         *pnt = 0;
4359                         while(fgetc(xc->fh)) { }; /* scopecomp */
4360 
4361                         if(fv) fprintf(fv, "$scope %s %s $end\n", modtypes[scopetype], str);
4362                         break;
4363 
4364                 case FST_ST_VCD_UPSCOPE:
4365                         if(fv) fprintf(fv, "$upscope $end\n");
4366                         break;
4367 
4368                 case FST_ST_GEN_ATTRBEGIN:
4369                         attrtype = fgetc(xc->fh);
4370                         subtype = fgetc(xc->fh);
4371                         pnt = str;
4372                         while((ch = fgetc(xc->fh)))
4373                                 {
4374                                 *(pnt++) = ch;
4375                                 }; /* attrname */
4376                         *pnt = 0;
4377 
4378                         if(!str[0]) { strcpy(str, "\"\""); }
4379 
4380                         attrarg = fstReaderVarint64(xc->fh);
4381 
4382                         if(fv && xc->use_vcd_extensions)
4383                                 {
4384                                 switch(attrtype)
4385                                         {
4386                                         case FST_AT_ARRAY:      if((subtype < FST_AR_NONE) || (subtype > FST_AR_MAX)) subtype = FST_AR_NONE;
4387                                                                 fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], arraytypes[subtype], str, attrarg);
4388                                                                 break;
4389                                         case FST_AT_ENUM:       if((subtype < FST_EV_SV_INTEGER) || (subtype > FST_EV_MAX)) subtype = FST_EV_SV_INTEGER;
4390                                                                 fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], enumvaluetypes[subtype], str, attrarg);
4391                                                                 break;
4392                                         case FST_AT_PACK:       if((subtype < FST_PT_NONE) || (subtype > FST_PT_MAX)) subtype = FST_PT_NONE;
4393                                                                 fprintf(fv, "$attrbegin %s %s %s %" PRId64 " $end\n", attrtypes[attrtype], packtypes[subtype], str, attrarg);
4394                                                                 break;
4395                                         case FST_AT_MISC:
4396                                         default:                attrtype = FST_AT_MISC;
4397                                                                 if(subtype == FST_MT_COMMENT)
4398                                                                         {
4399                                                                         fprintf(fv, "$comment\n\t%s\n$end\n", str);
4400                                                                         }
4401                                                                         else
4402                                                                         {
4403                                                                         if((subtype == FST_MT_SOURCESTEM)||(subtype == FST_MT_SOURCEISTEM))
4404                                                                                 {
4405                                                                                 int sidx_skiplen_dummy = 0;
4406                                                                                 uint64_t sidx = fstGetVarint64((unsigned char *)str, &sidx_skiplen_dummy);
4407 
4408                                                                                 fprintf(fv, "$attrbegin %s %02x %" PRId64 " %" PRId64 " $end\n", attrtypes[attrtype], subtype, sidx, attrarg);
4409                                                                                 }
4410                                                                                 else
4411                                                                                 {
4412                                                                                 fprintf(fv, "$attrbegin %s %02x %s %" PRId64 " $end\n", attrtypes[attrtype], subtype, str, attrarg);
4413                                                                                 }
4414                                                                         }
4415                                                                 break;
4416                                         }
4417                                 }
4418                         break;
4419 
4420                 case FST_ST_GEN_ATTREND:
4421                         if(fv && xc->use_vcd_extensions) fprintf(fv, "$attrend $end\n");
4422                         break;
4423 
4424                 case FST_VT_VCD_EVENT:
4425                 case FST_VT_VCD_INTEGER:
4426                 case FST_VT_VCD_PARAMETER:
4427                 case FST_VT_VCD_REAL:
4428                 case FST_VT_VCD_REAL_PARAMETER:
4429                 case FST_VT_VCD_REG:
4430                 case FST_VT_VCD_SUPPLY0:
4431                 case FST_VT_VCD_SUPPLY1:
4432                 case FST_VT_VCD_TIME:
4433                 case FST_VT_VCD_TRI:
4434                 case FST_VT_VCD_TRIAND:
4435                 case FST_VT_VCD_TRIOR:
4436                 case FST_VT_VCD_TRIREG:
4437                 case FST_VT_VCD_TRI0:
4438                 case FST_VT_VCD_TRI1:
4439                 case FST_VT_VCD_WAND:
4440                 case FST_VT_VCD_WIRE:
4441                 case FST_VT_VCD_WOR:
4442                 case FST_VT_VCD_PORT:
4443                 case FST_VT_VCD_SPARRAY:
4444                 case FST_VT_VCD_REALTIME:
4445                 case FST_VT_GEN_STRING:
4446                 case FST_VT_SV_BIT:
4447                 case FST_VT_SV_LOGIC:
4448                 case FST_VT_SV_INT:
4449                 case FST_VT_SV_SHORTINT:
4450                 case FST_VT_SV_LONGINT:
4451                 case FST_VT_SV_BYTE:
4452                 case FST_VT_SV_ENUM:
4453                 case FST_VT_SV_SHORTREAL:
4454                         vartype = tag;
4455                         /* vardir = */ fgetc(xc->fh); /* unused in VCD reader, but need to advance read pointer */
4456                         pnt = str;
4457                         while((ch = fgetc(xc->fh)))
4458                                 {
4459                                 *(pnt++) = ch;
4460                                 }; /* varname */
4461                         *pnt = 0;
4462                         len = fstReaderVarint32(xc->fh);
4463                         alias = fstReaderVarint32(xc->fh);
4464 
4465                         if(!alias)
4466                                 {
4467                                 if(xc->maxhandle == num_signal_dyn)
4468                                         {
4469                                         num_signal_dyn *= 2;
4470                                         xc->signal_lens = (uint32_t *)realloc(xc->signal_lens, num_signal_dyn*sizeof(uint32_t));
4471                                         xc->signal_typs = (unsigned char *)realloc(xc->signal_typs, num_signal_dyn*sizeof(unsigned char));
4472                                         }
4473                                 xc->signal_lens[xc->maxhandle] = len;
4474                                 xc->signal_typs[xc->maxhandle] = vartype;
4475 
4476                                 /* maxvalpos+=len; */
4477                                 if(len > xc->longest_signal_value_len)
4478                                         {
4479                                         xc->longest_signal_value_len = len;
4480                                         }
4481 
4482                                 if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL))
4483                                         {
4484                                         len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32;
4485                                         xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL;
4486                                         }
4487                                 if(fv)
4488                                         {
4489                                         char vcdid_buf[16];
4490                                         uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3);
4491                                         fstVcdID(vcdid_buf, xc->maxhandle+1);
4492                                         fprintf(fv, "$var %s %" PRIu32 " %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str);
4493                                         }
4494                                 xc->maxhandle++;
4495                                 }
4496                                 else
4497                                 {
4498                                 if((vartype == FST_VT_VCD_REAL) || (vartype == FST_VT_VCD_REAL_PARAMETER) || (vartype == FST_VT_VCD_REALTIME) || (vartype == FST_VT_SV_SHORTREAL))
4499                                         {
4500                                         len = (vartype != FST_VT_SV_SHORTREAL) ? 64 : 32;
4501                                         xc->signal_typs[xc->maxhandle] = FST_VT_VCD_REAL;
4502                                         }
4503                                 if(fv)
4504                                         {
4505                                         char vcdid_buf[16];
4506                                         uint32_t modlen = (vartype != FST_VT_VCD_PORT) ? len : ((len - 2) / 3);
4507                                         fstVcdID(vcdid_buf, alias);
4508                                         fprintf(fv, "$var %s %" PRIu32 " %s %s $end\n", vartypes[vartype], modlen, vcdid_buf, str);
4509                                         }
4510                                 xc->num_alias++;
4511                                 }
4512 
4513                         break;
4514 
4515                 default:
4516                         break;
4517                 }
4518         }
4519 if(fv) fprintf(fv, "$enddefinitions $end\n");
4520 
4521 maxhandle_scanbuild = xc->maxhandle ? xc->maxhandle : 1; /*scan-build warning suppression, in reality we have at least one signal */
4522 
4523 xc->signal_lens = (uint32_t *)realloc(xc->signal_lens, maxhandle_scanbuild*sizeof(uint32_t));
4524 xc->signal_typs = (unsigned char *)realloc(xc->signal_typs, maxhandle_scanbuild*sizeof(unsigned char));
4525 
4526 free(xc->process_mask);
4527 xc->process_mask = (unsigned char *)calloc(1, (maxhandle_scanbuild+7)/8);
4528 
4529 free(xc->temp_signal_value_buf);
4530 xc->temp_signal_value_buf = (unsigned char *)malloc(xc->longest_signal_value_len + 1);
4531 
4532 xc->var_count = xc->maxhandle + xc->num_alias;
4533 
4534 free(str);
4535 return(1);
4536 }
4537 
4538 
4539 /*
4540  * reader file open/close functions
4541  */
fstReaderInit(struct fstReaderContext * xc)4542 int fstReaderInit(struct fstReaderContext *xc)
4543 {
4544 fst_off_t blkpos = 0;
4545 fst_off_t endfile;
4546 uint64_t seclen;
4547 int sectype;
4548 uint64_t vc_section_count_actual = 0;
4549 int hdr_incomplete = 0;
4550 int hdr_seen = 0;
4551 int gzread_pass_status = 1;
4552 
4553 sectype = fgetc(xc->f);
4554 if(sectype == FST_BL_ZWRAPPER)
4555         {
4556         FILE *fcomp;
4557         fst_off_t offpnt, uclen;
4558         char gz_membuf[FST_GZIO_LEN];
4559         gzFile zhandle;
4560         int zfd;
4561         int flen = strlen(xc->filename);
4562         char *hf;
4563 
4564         seclen = fstReaderUint64(xc->f);
4565         uclen = fstReaderUint64(xc->f);
4566 
4567         if(!seclen) return(0); /* not finished compressing, this is a failed read */
4568 
4569         hf = (char *)calloc(1, flen + 16 + 32 + 1);
4570 
4571         sprintf(hf, "%s.upk_%d_%p", xc->filename, getpid(), (void *)xc);
4572         fcomp = fopen(hf, "w+b");
4573         if(!fcomp)
4574                 {
4575                 fcomp = tmpfile_open(&xc->f_nam);
4576                 free(hf); hf = NULL;
4577                 if(!fcomp) { tmpfile_close(&fcomp, &xc->f_nam); return(0); }
4578                 }
4579 
4580 #if defined(FST_MACOSX)
4581         setvbuf(fcomp, (char *)NULL, _IONBF, 0);   /* keeps gzip from acting weird in tandem with fopen */
4582 #endif
4583 
4584 #ifdef __MINGW32__
4585         setvbuf(fcomp, (char *)NULL, _IONBF, 0);   /* keeps gzip from acting weird in tandem with fopen */
4586         xc->filename_unpacked = hf;
4587 #else
4588         if(hf)
4589                 {
4590                 unlink(hf);
4591                 free(hf);
4592                 }
4593 #endif
4594 
4595         fstReaderFseeko(xc, xc->f, 1+8+8, SEEK_SET);
4596 #ifndef __MINGW32__
4597         fflush(xc->f);
4598 #endif
4599 
4600         zfd = dup(fileno(xc->f));
4601         zhandle = gzdopen(zfd, "rb");
4602         if(zhandle)
4603                 {
4604                 for(offpnt = 0; offpnt < uclen; offpnt += FST_GZIO_LEN)
4605                         {
4606                         size_t this_len = ((uclen - offpnt) > FST_GZIO_LEN) ? FST_GZIO_LEN : (uclen - offpnt);
4607                         size_t gzreadlen = gzread(zhandle, gz_membuf, this_len);
4608                         size_t fwlen;
4609 
4610                         if(gzreadlen != this_len)
4611                                 {
4612                                 gzread_pass_status = 0;
4613                                 break;
4614                                 }
4615                         fwlen = fstFwrite(gz_membuf, this_len, 1, fcomp);
4616                         if(fwlen != 1)
4617                                 {
4618                                 gzread_pass_status = 0;
4619                                 break;
4620                                 }
4621                         }
4622                 gzclose(zhandle);
4623                 }
4624                 else
4625                 {
4626                 close(zfd);
4627                 }
4628         fflush(fcomp);
4629         fclose(xc->f);
4630         xc->f = fcomp;
4631         }
4632 
4633 if(gzread_pass_status)
4634         {
4635         fstReaderFseeko(xc, xc->f, 0, SEEK_END);
4636         endfile = ftello(xc->f);
4637 
4638         while(blkpos < endfile)
4639                 {
4640                 fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET);
4641 
4642                 sectype = fgetc(xc->f);
4643                 seclen = fstReaderUint64(xc->f);
4644 
4645                 if(sectype == EOF)
4646                         {
4647                         break;
4648                         }
4649 
4650                 if((hdr_incomplete) && (!seclen))
4651                         {
4652                         break;
4653                         }
4654 
4655                 if(!hdr_seen && (sectype != FST_BL_HDR))
4656                         {
4657                         break;
4658                         }
4659 
4660                 blkpos++;
4661                 if(sectype == FST_BL_HDR)
4662                         {
4663                         if(!hdr_seen)
4664                                 {
4665                                 int ch;
4666                                 double dcheck;
4667 
4668                                 xc->start_time = fstReaderUint64(xc->f);
4669                                 xc->end_time = fstReaderUint64(xc->f);
4670 
4671                                 hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0);
4672 
4673                                 fstFread(&dcheck, 8, 1, xc->f);
4674                                 xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST);
4675                                 if(!xc->double_endian_match)
4676                                         {
4677                                         union   {
4678                                                 unsigned char rvs_buf[8];
4679                                                 double d;
4680                                                 } vu;
4681 
4682                                         unsigned char *dcheck_alias = (unsigned char *)&dcheck;
4683                                         int rvs_idx;
4684 
4685                                         for(rvs_idx=0;rvs_idx<8;rvs_idx++)
4686                                                 {
4687                                                 vu.rvs_buf[rvs_idx] = dcheck_alias[7-rvs_idx];
4688                                                 }
4689                                         if(vu.d != FST_DOUBLE_ENDTEST)
4690                                                 {
4691                                                 break; /* either corrupt file or wrong architecture (offset +33 also functions as matchword) */
4692                                                 }
4693                                         }
4694 
4695                                 hdr_seen = 1;
4696 
4697                                 xc->mem_used_by_writer = fstReaderUint64(xc->f);
4698                                 xc->scope_count = fstReaderUint64(xc->f);
4699                                 xc->var_count = fstReaderUint64(xc->f);
4700                                 xc->maxhandle = fstReaderUint64(xc->f);
4701                                 xc->num_alias = xc->var_count - xc->maxhandle;
4702                                 xc->vc_section_count = fstReaderUint64(xc->f);
4703                                 ch = fgetc(xc->f);
4704                                 xc->timescale = (signed char)ch;
4705                                 fstFread(xc->version, FST_HDR_SIM_VERSION_SIZE, 1, xc->f);
4706                                 xc->version[FST_HDR_SIM_VERSION_SIZE] = 0;
4707                                 fstFread(xc->date, FST_HDR_DATE_SIZE, 1, xc->f);
4708                                 xc->date[FST_HDR_DATE_SIZE] = 0;
4709                                 ch = fgetc(xc->f);
4710                                 xc->filetype = (unsigned char)ch;
4711                                 xc->timezero = fstReaderUint64(xc->f);
4712                                 }
4713                         }
4714                 else if((sectype == FST_BL_VCDATA) || (sectype == FST_BL_VCDATA_DYN_ALIAS) || (sectype == FST_BL_VCDATA_DYN_ALIAS2))
4715                         {
4716                         if(hdr_incomplete)
4717                                 {
4718                                 uint64_t bt = fstReaderUint64(xc->f);
4719                                 xc->end_time = fstReaderUint64(xc->f);
4720 
4721                                 if(!vc_section_count_actual) { xc->start_time = bt; }
4722                                 }
4723 
4724                         vc_section_count_actual++;
4725                         }
4726                 else if(sectype == FST_BL_GEOM)
4727                         {
4728                         if(!hdr_incomplete)
4729                                 {
4730                                 uint64_t clen = seclen - 24;
4731                                 uint64_t uclen = fstReaderUint64(xc->f);
4732                                 unsigned char *ucdata = (unsigned char *)malloc(uclen);
4733                                 unsigned char *pnt = ucdata;
4734                                 unsigned int i;
4735 
4736                                 xc->contains_geom_section = 1;
4737                                 xc->maxhandle = fstReaderUint64(xc->f);
4738                                 xc->longest_signal_value_len = 32; /* arbitrarily set at 32...this is much longer than an expanded double */
4739 
4740                                 free(xc->process_mask);
4741                                 xc->process_mask = (unsigned char *)calloc(1, (xc->maxhandle+7)/8);
4742 
4743                                 if(clen != uclen)
4744                                         {
4745                                         unsigned char *cdata = (unsigned char *)malloc(clen);
4746                                         unsigned long destlen = uclen;
4747                                         unsigned long sourcelen = clen;
4748                                         int rc;
4749 
4750                                         fstFread(cdata, clen, 1, xc->f);
4751                                         rc = uncompress(ucdata, &destlen, cdata, sourcelen);
4752 
4753                                         if(rc != Z_OK)
4754                                                 {
4755                                                 fprintf(stderr, FST_APIMESS "fstReaderInit(), geom uncompress rc = %d, exiting.\n", rc);
4756                                                 exit(255);
4757                                                 }
4758 
4759                                         free(cdata);
4760                                         }
4761                                         else
4762                                         {
4763                                         fstFread(ucdata, uclen, 1, xc->f);
4764                                         }
4765 
4766                                 free(xc->signal_lens);
4767                                 xc->signal_lens = (uint32_t *)malloc(sizeof(uint32_t) * xc->maxhandle);
4768                                 free(xc->signal_typs);
4769                                 xc->signal_typs = (unsigned char *)malloc(sizeof(unsigned char) * xc->maxhandle);
4770 
4771                                 for(i=0;i<xc->maxhandle;i++)
4772                                         {
4773                                         int skiplen;
4774                                         uint64_t val = fstGetVarint32(pnt, &skiplen);
4775 
4776                                         pnt += skiplen;
4777 
4778                                         if(val)
4779                                                 {
4780                                                 xc->signal_lens[i] = (val != 0xFFFFFFFF) ? val : 0;
4781                                                 xc->signal_typs[i] = FST_VT_VCD_WIRE;
4782                                                 if(xc->signal_lens[i] > xc->longest_signal_value_len)
4783                                                         {
4784                                                         xc->longest_signal_value_len = xc->signal_lens[i];
4785                                                         }
4786                                                 }
4787                                                 else
4788                                                 {
4789                                                 xc->signal_lens[i] = 8; /* backpatch in real */
4790                                                 xc->signal_typs[i] = FST_VT_VCD_REAL;
4791                                                 /* xc->longest_signal_value_len handled above by overly large init size */
4792                                                 }
4793                                         }
4794 
4795                                 free(xc->temp_signal_value_buf);
4796                                 xc->temp_signal_value_buf = (unsigned char *)malloc(xc->longest_signal_value_len + 1);
4797 
4798                                 free(ucdata);
4799                                 }
4800                         }
4801                 else if(sectype == FST_BL_HIER)
4802                         {
4803                         xc->contains_hier_section = 1;
4804                         xc->hier_pos = ftello(xc->f);
4805                         }
4806                 else if(sectype == FST_BL_HIER_LZ4DUO)
4807                         {
4808                         xc->contains_hier_section_lz4    = 1;
4809                         xc->contains_hier_section_lz4duo = 1;
4810                         xc->hier_pos = ftello(xc->f);
4811                         }
4812                 else if(sectype == FST_BL_HIER_LZ4)
4813                         {
4814                         xc->contains_hier_section_lz4 = 1;
4815                         xc->hier_pos = ftello(xc->f);
4816                         }
4817                 else if(sectype == FST_BL_BLACKOUT)
4818                         {
4819                         uint32_t i;
4820                         uint64_t cur_bl = 0;
4821                         uint64_t delta;
4822 
4823                         xc->num_blackouts = fstReaderVarint32(xc->f);
4824                         free(xc->blackout_times);
4825                         xc->blackout_times = (uint64_t *)calloc(xc->num_blackouts, sizeof(uint64_t));
4826                         free(xc->blackout_activity);
4827                         xc->blackout_activity = (unsigned char *)calloc(xc->num_blackouts, sizeof(unsigned char));
4828 
4829                         for(i=0;i<xc->num_blackouts;i++)
4830                                 {
4831                                 xc->blackout_activity[i] = fgetc(xc->f) != 0;
4832                                 delta = fstReaderVarint64(xc->f);
4833                                 cur_bl += delta;
4834                                 xc->blackout_times[i] = cur_bl;
4835                                 }
4836                         }
4837 
4838                 blkpos += seclen;
4839                 if(!hdr_seen) break;
4840                 }
4841 
4842         if(hdr_seen)
4843                 {
4844                 if(xc->vc_section_count != vc_section_count_actual)
4845                         {
4846                         xc->vc_section_count = vc_section_count_actual;
4847                         }
4848 
4849                 if(!xc->contains_geom_section)
4850                         {
4851                         fstReaderProcessHier(xc, NULL); /* recreate signal_lens/signal_typs info */
4852                         }
4853                 }
4854         }
4855 
4856 return(hdr_seen);
4857 }
4858 
4859 
fstReaderOpenForUtilitiesOnly(void)4860 void *fstReaderOpenForUtilitiesOnly(void)
4861 {
4862 struct fstReaderContext *xc = (struct fstReaderContext *)calloc(1, sizeof(struct fstReaderContext));
4863 
4864 return(xc);
4865 }
4866 
4867 
fstReaderOpen(const char * nam)4868 void *fstReaderOpen(const char *nam)
4869 {
4870 struct fstReaderContext *xc = (struct fstReaderContext *)calloc(1, sizeof(struct fstReaderContext));
4871 
4872 if((!nam)||(!(xc->f=fopen(nam, "rb"))))
4873         {
4874         free(xc);
4875         xc=NULL;
4876         }
4877         else
4878         {
4879         int flen = strlen(nam);
4880         char *hf = (char *)calloc(1, flen + 6);
4881         int rc;
4882 
4883 #if defined(__MINGW32__) || defined(FST_MACOSX)
4884         setvbuf(xc->f, (char *)NULL, _IONBF, 0);   /* keeps gzip from acting weird in tandem with fopen */
4885 #endif
4886 
4887         memcpy(hf, nam, flen);
4888         strcpy(hf + flen, ".hier");
4889         xc->fh = fopen(hf, "rb");
4890 
4891         free(hf);
4892         xc->filename = strdup(nam);
4893         rc = fstReaderInit(xc);
4894 
4895         if((rc) && (xc->vc_section_count) && (xc->maxhandle) && ((xc->fh)||(xc->contains_hier_section||(xc->contains_hier_section_lz4))))
4896                 {
4897                 /* more init */
4898                 xc->do_rewind = 1;
4899                 }
4900                 else
4901                 {
4902                 fstReaderClose(xc);
4903                 xc = NULL;
4904                 }
4905         }
4906 
4907 return(xc);
4908 }
4909 
4910 
fstReaderDeallocateRvatData(void * ctx)4911 static void fstReaderDeallocateRvatData(void *ctx)
4912 {
4913 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4914 if(xc)
4915         {
4916         free(xc->rvat_chain_mem); xc->rvat_chain_mem = NULL;
4917         free(xc->rvat_frame_data); xc->rvat_frame_data = NULL;
4918         free(xc->rvat_time_table); xc->rvat_time_table = NULL;
4919         free(xc->rvat_chain_table); xc->rvat_chain_table = NULL;
4920         free(xc->rvat_chain_table_lengths); xc->rvat_chain_table_lengths = NULL;
4921 
4922         xc->rvat_data_valid = 0;
4923         }
4924 }
4925 
4926 
fstReaderClose(void * ctx)4927 void fstReaderClose(void *ctx)
4928 {
4929 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4930 
4931 if(xc)
4932         {
4933         fstReaderDeallocateScopeData(xc);
4934         fstReaderDeallocateRvatData(xc);
4935         free(xc->rvat_sig_offs); xc->rvat_sig_offs = NULL;
4936 
4937         free(xc->process_mask); xc->process_mask = NULL;
4938         free(xc->blackout_times); xc->blackout_times = NULL;
4939         free(xc->blackout_activity); xc->blackout_activity = NULL;
4940         free(xc->temp_signal_value_buf); xc->temp_signal_value_buf = NULL;
4941         free(xc->signal_typs); xc->signal_typs = NULL;
4942         free(xc->signal_lens); xc->signal_lens = NULL;
4943         free(xc->filename); xc->filename = NULL;
4944 
4945         if(xc->fh)
4946                 {
4947                 tmpfile_close(&xc->fh, &xc->fh_nam);
4948                 }
4949 
4950         if(xc->f)
4951                 {
4952                 tmpfile_close(&xc->f, &xc->f_nam);
4953                 if(xc->filename_unpacked)
4954                         {
4955                         unlink(xc->filename_unpacked);
4956                         free(xc->filename_unpacked);
4957                         }
4958                 }
4959 
4960         free(xc);
4961         }
4962 }
4963 
4964 
4965 /*
4966  * read processing
4967  */
4968 
4969 /* normal read which re-interleaves the value change data */
fstReaderIterBlocks(void * ctx,void (* value_change_callback)(void * user_callback_data_pointer,uint64_t time,fstHandle facidx,const unsigned char * value),void * user_callback_data_pointer,FILE * fv)4970 int fstReaderIterBlocks(void *ctx,
4971         void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
4972         void *user_callback_data_pointer, FILE *fv)
4973 {
4974 return(fstReaderIterBlocks2(ctx, value_change_callback, NULL, user_callback_data_pointer, fv));
4975 }
4976 
4977 
fstReaderIterBlocks2(void * ctx,void (* value_change_callback)(void * user_callback_data_pointer,uint64_t time,fstHandle facidx,const unsigned char * value),void (* value_change_callback_varlen)(void * user_callback_data_pointer,uint64_t time,fstHandle facidx,const unsigned char * value,uint32_t len),void * user_callback_data_pointer,FILE * fv)4978 int fstReaderIterBlocks2(void *ctx,
4979         void (*value_change_callback)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value),
4980         void (*value_change_callback_varlen)(void *user_callback_data_pointer, uint64_t time, fstHandle facidx, const unsigned char *value, uint32_t len),
4981         void *user_callback_data_pointer, FILE *fv)
4982 {
4983 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
4984 
4985 uint64_t previous_time = UINT64_MAX;
4986 uint64_t *time_table = NULL;
4987 uint64_t tsec_nitems;
4988 unsigned int secnum = 0;
4989 int blocks_skipped = 0;
4990 fst_off_t blkpos = 0;
4991 uint64_t seclen, beg_tim;
4992 uint64_t end_tim;
4993 uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle;
4994 fst_off_t vc_start;
4995 fst_off_t indx_pntr, indx_pos;
4996 fst_off_t *chain_table = NULL;
4997 uint32_t *chain_table_lengths = NULL;
4998 unsigned char *chain_cmem;
4999 unsigned char *pnt;
5000 long chain_clen;
5001 fstHandle idx, pidx=0, i;
5002 uint64_t pval;
5003 uint64_t vc_maxhandle_largest = 0;
5004 uint64_t tsec_uclen = 0, tsec_clen = 0;
5005 int sectype;
5006 uint64_t mem_required_for_traversal;
5007 unsigned char *mem_for_traversal = NULL;
5008 uint32_t traversal_mem_offs;
5009 uint32_t *scatterptr, *headptr, *length_remaining;
5010 uint32_t cur_blackout = 0;
5011 int packtype;
5012 unsigned char *mc_mem = NULL;
5013 uint32_t mc_mem_len; /* corresponds to largest value encountered in chain_table_lengths[i] */
5014 int dumpvars_state = 0;
5015 
5016 if(!xc) return(0);
5017 
5018 scatterptr = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
5019 headptr = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
5020 length_remaining = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
5021 
5022 if(fv)
5023         {
5024 #ifndef FST_WRITEX_DISABLE
5025         fflush(fv);
5026         setvbuf(fv, (char *) NULL, _IONBF, 0); /* even buffered IO is slow so disable it and use our own routines that don't need seeking */
5027         xc->writex_fd = fileno(fv);
5028 #endif
5029         }
5030 
5031 for(;;)
5032         {
5033         uint32_t *tc_head = NULL;
5034         traversal_mem_offs = 0;
5035 
5036         fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET);
5037 
5038         sectype = fgetc(xc->f);
5039         seclen = fstReaderUint64(xc->f);
5040 
5041         if((sectype == EOF) || (sectype == FST_BL_SKIP))
5042                 {
5043 #ifdef FST_DEBUG
5044                 fprintf(stderr, FST_APIMESS "<< EOF >>\n");
5045 #endif
5046                 break;
5047                 }
5048 
5049         blkpos++;
5050         if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && (sectype != FST_BL_VCDATA_DYN_ALIAS2))
5051                 {
5052                 blkpos += seclen;
5053                 continue;
5054                 }
5055 
5056         if(!seclen) break;
5057 
5058         beg_tim = fstReaderUint64(xc->f);
5059         end_tim = fstReaderUint64(xc->f);
5060 
5061         if(xc->limit_range_valid)
5062                 {
5063                 if(end_tim < xc->limit_range_start)
5064                         {
5065                         blocks_skipped++;
5066                         blkpos += seclen;
5067                         continue;
5068                         }
5069 
5070                 if(beg_tim > xc->limit_range_end) /* likely the compare in for(i=0;i<tsec_nitems;i++) below would do this earlier */
5071                         {
5072                         break;
5073                         }
5074                 }
5075 
5076 
5077         mem_required_for_traversal = fstReaderUint64(xc->f);
5078         mem_for_traversal = (unsigned char *)malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */
5079 #ifdef FST_DEBUG
5080         fprintf(stderr, FST_APIMESS "sec: %u seclen: %d begtim: %d endtim: %d\n",
5081                 secnum, (int)seclen, (int)beg_tim, (int)end_tim);
5082         fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal);
5083 #endif
5084         /* process time block */
5085         {
5086         unsigned char *ucdata;
5087         unsigned char *cdata;
5088         unsigned long destlen /* = tsec_uclen */; /* scan-build */
5089         unsigned long sourcelen /*= tsec_clen */; /* scan-build */
5090         int rc;
5091         unsigned char *tpnt;
5092         uint64_t tpval;
5093         unsigned int ti;
5094 
5095         if(fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET) != 0) break;
5096         tsec_uclen = fstReaderUint64(xc->f);
5097         tsec_clen = fstReaderUint64(xc->f);
5098         tsec_nitems = fstReaderUint64(xc->f);
5099 #ifdef FST_DEBUG
5100         fprintf(stderr, FST_APIMESS "time section unc: %d, com: %d (%d items)\n",
5101                 (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems);
5102 #endif
5103         if(tsec_clen > seclen) break; /* corrupted tsec_clen: by definition it can't be larger than size of section */
5104         ucdata = (unsigned char *)malloc(tsec_uclen);
5105         if(!ucdata) break; /* malloc fail as tsec_uclen out of range from corrupted file */
5106         destlen = tsec_uclen;
5107         sourcelen = tsec_clen;
5108 
5109         fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR);
5110 
5111         if(tsec_uclen != tsec_clen)
5112                 {
5113                 cdata = (unsigned char *)malloc(tsec_clen);
5114                 fstFread(cdata, tsec_clen, 1, xc->f);
5115 
5116                 rc = uncompress(ucdata, &destlen, cdata, sourcelen);
5117 
5118                 if(rc != Z_OK)
5119                         {
5120                         fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), tsec uncompress rc = %d, exiting.\n", rc);
5121                         exit(255);
5122                         }
5123 
5124                 free(cdata);
5125                 }
5126                 else
5127                 {
5128                 fstFread(ucdata, tsec_uclen, 1, xc->f);
5129                 }
5130 
5131         free(time_table);
5132         time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t));
5133         tpnt = ucdata;
5134         tpval = 0;
5135         for(ti=0;ti<tsec_nitems;ti++)
5136                 {
5137                 int skiplen;
5138                 uint64_t val = fstGetVarint64(tpnt, &skiplen);
5139                 tpval = time_table[ti] = tpval + val;
5140                 tpnt += skiplen;
5141                 }
5142 
5143         tc_head = (uint32_t *)calloc(tsec_nitems /* scan-build */ ? tsec_nitems : 1, sizeof(uint32_t));
5144         free(ucdata);
5145         }
5146 
5147         fstReaderFseeko(xc, xc->f, blkpos+32, SEEK_SET);
5148 
5149         frame_uclen = fstReaderVarint64(xc->f);
5150         frame_clen = fstReaderVarint64(xc->f);
5151         frame_maxhandle = fstReaderVarint64(xc->f);
5152 
5153         if(secnum == 0)
5154                 {
5155                 if((beg_tim != time_table[0]) || (blocks_skipped))
5156                         {
5157                         unsigned char *mu = (unsigned char *)malloc(frame_uclen);
5158                         uint32_t sig_offs = 0;
5159 
5160                         if(fv)
5161                                 {
5162                                 char wx_buf[32];
5163                                 int wx_len;
5164 
5165                                 if(beg_tim)
5166                                         {
5167 					if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
5168                                         wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", beg_tim);
5169                                         fstWritex(xc, wx_buf, wx_len);
5170 					if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
5171                                         }
5172                                 if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
5173                                         {
5174                                         if(beg_tim == xc->blackout_times[cur_blackout])
5175                                                 {
5176                                                 wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
5177                                                 fstWritex(xc, wx_buf, wx_len);
5178                                                 }
5179                                         }
5180                                 }
5181 
5182                         if(frame_uclen == frame_clen)
5183                                 {
5184                                 fstFread(mu, frame_uclen, 1, xc->f);
5185                                 }
5186                                 else
5187                                 {
5188                                 unsigned char *mc = (unsigned char *)malloc(frame_clen);
5189                                 int rc;
5190 
5191                                 unsigned long destlen = frame_uclen;
5192                                 unsigned long sourcelen = frame_clen;
5193 
5194                                 fstFread(mc, sourcelen, 1, xc->f);
5195                                 rc = uncompress(mu, &destlen, mc, sourcelen);
5196                                 if(rc != Z_OK)
5197                                         {
5198                                         fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), frame uncompress rc: %d, exiting.\n", rc);
5199                                         exit(255);
5200                                         }
5201                                 free(mc);
5202                                 }
5203 
5204 
5205                         for(idx=0;idx<frame_maxhandle;idx++)
5206                                 {
5207                                 int process_idx = idx/8;
5208                                 int process_bit = idx&7;
5209 
5210                                 if(xc->process_mask[process_idx]&(1<<process_bit))
5211                                         {
5212                                         if(xc->signal_lens[idx] <= 1)
5213                                                 {
5214                                                 if(xc->signal_lens[idx] == 1)
5215                                                         {
5216                                                         unsigned char val = mu[sig_offs];
5217                                                         if(value_change_callback)
5218                                                                 {
5219                                                                 xc->temp_signal_value_buf[0] = val;
5220                                                                 xc->temp_signal_value_buf[1] = 0;
5221                                                                 value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
5222                                                                 }
5223                                                                 else
5224                                                                 {
5225                                                                 if(fv)
5226                                                                         {
5227                                                                         char vcd_id[16];
5228 
5229                                                                         int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
5230                                                                         vcd_id[0] = val; /* collapse 3 writes into one I/O call */
5231                                                                         vcd_id[vcdid_len + 1] = '\n';
5232                                                                         fstWritex(xc, vcd_id, vcdid_len + 2);
5233                                                                         }
5234                                                                 }
5235                                                         }
5236                                                         else
5237                                                         {
5238                                                         /* variable-length ("0" length) records have no initial state */
5239                                                         }
5240                                                 }
5241                                                 else
5242                                                 {
5243                                                 if(xc->signal_typs[idx] != FST_VT_VCD_REAL)
5244                                                         {
5245                                                         if(value_change_callback)
5246                                                                 {
5247                                                                 memcpy(xc->temp_signal_value_buf, mu+sig_offs, xc->signal_lens[idx]);
5248                                                                 xc->temp_signal_value_buf[xc->signal_lens[idx]] = 0;
5249                                                                 value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
5250                                                                 }
5251                                                                 else
5252                                                                 {
5253                                                                 if(fv)
5254                                                                         {
5255                                                                         char vcd_id[16];
5256                                                                         int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
5257 
5258                                                                         vcd_id[0] = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
5259                                                                         fstWritex(xc, vcd_id, 1);
5260                                                                         fstWritex(xc,mu+sig_offs, xc->signal_lens[idx]);
5261 
5262                                                                         vcd_id[0] = ' '; /* collapse 3 writes into one I/O call */
5263                                                                         vcd_id[vcdid_len + 1] = '\n';
5264                                                                         fstWritex(xc, vcd_id, vcdid_len + 2);
5265                                                                         }
5266                                                                 }
5267                                                         }
5268                                                         else
5269                                                         {
5270                                                         double d;
5271                                                         unsigned char *clone_d;
5272                                                         unsigned char *srcdata = mu+sig_offs;
5273 
5274                                                         if(value_change_callback)
5275                                                                 {
5276                                                                 if(xc->native_doubles_for_cb)
5277                                                                         {
5278                                                                         if(xc->double_endian_match)
5279                                                                                 {
5280                                                                                 clone_d = srcdata;
5281                                                                                 }
5282                                                                                 else
5283                                                                                 {
5284                                                                                 int j;
5285 
5286                                                                                 clone_d = (unsigned char *)&d;
5287                                                                                 for(j=0;j<8;j++)
5288                                                                                         {
5289                                                                                         clone_d[j] = srcdata[7-j];
5290                                                                                         }
5291                                                                                 }
5292                                                                         value_change_callback(user_callback_data_pointer, beg_tim, idx+1, clone_d);
5293                                                                         }
5294                                                                         else
5295                                                                         {
5296                                                                         clone_d = (unsigned char *)&d;
5297                                                                         if(xc->double_endian_match)
5298                                                                                 {
5299                                                                                 memcpy(clone_d, srcdata, 8);
5300                                                                                 }
5301                                                                                 else
5302                                                                                 {
5303                                                                                 int j;
5304 
5305                                                                                 for(j=0;j<8;j++)
5306                                                                                         {
5307                                                                                         clone_d[j] = srcdata[7-j];
5308                                                                                         }
5309                                                                                 }
5310                                                                         sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
5311                                                                         value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf);
5312                                                                         }
5313                                                                 }
5314                                                                 else
5315                                                                 {
5316                                                                 if(fv)
5317                                                                         {
5318                                                                         char vcdid_buf[16];
5319                                                                         char wx_buf[64];
5320                                                                         int wx_len;
5321 
5322                                                                         clone_d = (unsigned char *)&d;
5323                                                                         if(xc->double_endian_match)
5324                                                                                 {
5325                                                                                 memcpy(clone_d, srcdata, 8);
5326                                                                                 }
5327                                                                                 else
5328                                                                                 {
5329                                                                                 int j;
5330 
5331                                                                                 for(j=0;j<8;j++)
5332                                                                                         {
5333                                                                                         clone_d[j] = srcdata[7-j];
5334                                                                                         }
5335                                                                                 }
5336 
5337                                                                         fstVcdID(vcdid_buf, idx+1);
5338                                                                         wx_len = sprintf(wx_buf, "r%.16g %s\n", d, vcdid_buf);
5339                                                                         fstWritex(xc, wx_buf, wx_len);
5340                                                                         }
5341                                                                 }
5342                                                         }
5343                                                 }
5344                                         }
5345 
5346                                 sig_offs += xc->signal_lens[idx];
5347                                 }
5348 
5349                         free(mu);
5350                         fstReaderFseeko(xc, xc->f, -((fst_off_t)frame_clen), SEEK_CUR);
5351                         }
5352                 }
5353 
5354         fstReaderFseeko(xc, xc->f, (fst_off_t)frame_clen, SEEK_CUR); /* skip past compressed data */
5355 
5356         vc_maxhandle = fstReaderVarint64(xc->f);
5357         vc_start = ftello(xc->f);       /* points to '!' character */
5358         packtype = fgetc(xc->f);
5359 
5360 #ifdef FST_DEBUG
5361         fprintf(stderr, FST_APIMESS "frame_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n",
5362                 (int)frame_uclen, (int)frame_clen, (int)frame_maxhandle);
5363         fprintf(stderr, FST_APIMESS "vc_maxhandle: %d, packtype: %c\n", (int)vc_maxhandle, packtype);
5364 #endif
5365 
5366         indx_pntr = blkpos + seclen - 24 -tsec_clen -8;
5367         fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET);
5368         chain_clen = fstReaderUint64(xc->f);
5369         indx_pos = indx_pntr - chain_clen;
5370 #ifdef FST_DEBUG
5371         fprintf(stderr, FST_APIMESS "indx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen);
5372 #endif
5373         chain_cmem = (unsigned char *)malloc(chain_clen);
5374         if(!chain_cmem) goto block_err;
5375         fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET);
5376         fstFread(chain_cmem, chain_clen, 1, xc->f);
5377 
5378         if(vc_maxhandle > vc_maxhandle_largest)
5379                 {
5380                 free(chain_table);
5381                 free(chain_table_lengths);
5382 
5383                 vc_maxhandle_largest = vc_maxhandle;
5384                 chain_table = (fst_off_t *)calloc((vc_maxhandle+1), sizeof(fst_off_t));
5385                 chain_table_lengths = (uint32_t *)calloc((vc_maxhandle+1), sizeof(uint32_t));
5386                 }
5387 
5388         if(!chain_table || !chain_table_lengths) goto block_err;
5389 
5390         pnt = chain_cmem;
5391         idx = 0;
5392         pval = 0;
5393 
5394         if(sectype == FST_BL_VCDATA_DYN_ALIAS2)
5395                 {
5396                 uint32_t prev_alias = 0;
5397 
5398                 do      {
5399                         int skiplen;
5400 
5401                         if(*pnt & 0x01)
5402                                 {
5403                                 int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1;
5404                                 if(shval > 0)
5405                                         {
5406                                         pval = chain_table[idx] = pval + shval;
5407                                         if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; }
5408                                         pidx = idx++;
5409                                         }
5410                                 else if(shval < 0)
5411                                         {
5412                                         chain_table[idx] = 0;                                   /* need to explicitly zero as calloc above might not run */
5413                                         chain_table_lengths[idx] = prev_alias = shval;          /* because during this loop iter would give stale data! */
5414                                         idx++;
5415                                         }
5416                                 else
5417                                         {
5418                                         chain_table[idx] = 0;                                   /* need to explicitly zero as calloc above might not run */
5419                                         chain_table_lengths[idx] = prev_alias;                  /* because during this loop iter would give stale data! */
5420                                         idx++;
5421                                         }
5422                                 }
5423                                 else
5424                                 {
5425                                 uint64_t val = fstGetVarint32(pnt, &skiplen);
5426 
5427                                 fstHandle loopcnt = val >> 1;
5428                                 for(i=0;i<loopcnt;i++)
5429                                         {
5430                                         chain_table[idx++] = 0;
5431                                         }
5432                                 }
5433 
5434                         pnt += skiplen;
5435                         } while (pnt != (chain_cmem + chain_clen));
5436                 }
5437                 else
5438                 {
5439                 do      {
5440                         int skiplen;
5441                         uint64_t val = fstGetVarint32(pnt, &skiplen);
5442 
5443                         if(!val)
5444                                 {
5445                                 pnt += skiplen;
5446                                 val = fstGetVarint32(pnt, &skiplen);
5447                                 chain_table[idx] = 0;                   /* need to explicitly zero as calloc above might not run */
5448                                 chain_table_lengths[idx] = -val;        /* because during this loop iter would give stale data! */
5449                                 idx++;
5450                                 }
5451                         else
5452                         if(val&1)
5453                                 {
5454                                 pval = chain_table[idx] = pval + (val >> 1);
5455                                 if(idx) { chain_table_lengths[pidx] = pval - chain_table[pidx]; }
5456                                 pidx = idx++;
5457                                 }
5458                         else
5459                                 {
5460                                 fstHandle loopcnt = val >> 1;
5461                                 for(i=0;i<loopcnt;i++)
5462                                         {
5463                                         chain_table[idx++] = 0;
5464                                         }
5465                                 }
5466 
5467                         pnt += skiplen;
5468                         } while (pnt != (chain_cmem + chain_clen));
5469                 }
5470 
5471         chain_table[idx] = indx_pos - vc_start;
5472         chain_table_lengths[pidx] = chain_table[idx] - chain_table[pidx];
5473 
5474         for(i=0;i<idx;i++)
5475                 {
5476                 int32_t v32 = chain_table_lengths[i];
5477                 if((v32 < 0) && (!chain_table[i]))
5478                         {
5479                         v32 = -v32;
5480                         v32--;
5481                         if(((uint32_t)v32) < i) /* sanity check */
5482                                 {
5483                                 chain_table[i] = chain_table[v32];
5484                                 chain_table_lengths[i] = chain_table_lengths[v32];
5485                                 }
5486                         }
5487                 }
5488 
5489 #ifdef FST_DEBUG
5490         fprintf(stderr, FST_APIMESS "decompressed chain idx len: %" PRIu32 "\n", idx);
5491 #endif
5492 
5493         mc_mem_len = 16384;
5494         mc_mem = (unsigned char *)malloc(mc_mem_len); /* buffer for compressed reads */
5495 
5496         /* check compressed VC data */
5497         if(idx > xc->maxhandle) idx = xc->maxhandle;
5498         for(i=0;i<idx;i++)
5499                 {
5500                 if(chain_table[i])
5501                         {
5502                         int process_idx = i/8;
5503                         int process_bit = i&7;
5504 
5505                         if(xc->process_mask[process_idx]&(1<<process_bit))
5506                                 {
5507                                 int rc = Z_OK;
5508                                 uint32_t val;
5509                                 uint32_t skiplen;
5510                                 uint32_t tdelta;
5511 
5512                                 fstReaderFseeko(xc, xc->f, vc_start + chain_table[i], SEEK_SET);
5513                                 val = fstReaderVarint32WithSkip(xc->f, &skiplen);
5514                                 if(val)
5515                                         {
5516                                         unsigned char *mu = mem_for_traversal + traversal_mem_offs; /* uncomp: dst */
5517                                         unsigned char *mc;                                          /* comp:   src */
5518                                         unsigned long destlen = val;
5519                                         unsigned long sourcelen = chain_table_lengths[i];
5520 
5521                                         if(mc_mem_len < chain_table_lengths[i])
5522                                                 {
5523                                                 free(mc_mem);
5524                                                 mc_mem = (unsigned char *)malloc(mc_mem_len = chain_table_lengths[i]);
5525                                                 }
5526                                         mc = mc_mem;
5527 
5528                                         fstFread(mc, chain_table_lengths[i], 1, xc->f);
5529 
5530                                         switch(packtype)
5531                                                 {
5532                                                 case '4': rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) ? Z_OK : Z_DATA_ERROR;
5533                                                           break;
5534                                                 case 'F': fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */
5535                                                           break;
5536                                                 default:  rc = uncompress(mu, &destlen, mc, sourcelen);
5537                                                           break;
5538                                                 }
5539 
5540                                         /* data to process is for(j=0;j<destlen;j++) in mu[j] */
5541                                         headptr[i] = traversal_mem_offs;
5542                                         length_remaining[i] = val;
5543                                         traversal_mem_offs += val;
5544                                         }
5545                                         else
5546                                         {
5547                                         int destlen = chain_table_lengths[i] - skiplen;
5548                                         unsigned char *mu = mem_for_traversal + traversal_mem_offs;
5549                                         fstFread(mu, destlen, 1, xc->f);
5550                                         /* data to process is for(j=0;j<destlen;j++) in mu[j] */
5551                                         headptr[i] = traversal_mem_offs;
5552                                         length_remaining[i] = destlen;
5553                                         traversal_mem_offs += destlen;
5554                                         }
5555 
5556                                 if(rc != Z_OK)
5557                                         {
5558                                         fprintf(stderr, FST_APIMESS "fstReaderIterBlocks2(), fac: %d clen: %d (rc=%d), exiting.\n", (int)i, (int)val, rc);
5559                                         exit(255);
5560                                         }
5561 
5562                                 if(xc->signal_lens[i] == 1)
5563                                         {
5564                                         uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]);
5565                                         uint32_t shcnt = 2 << (vli & 1);
5566                                         tdelta = vli >> shcnt;
5567                                         }
5568                                         else
5569                                         {
5570                                         uint32_t vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[i]);
5571                                         tdelta = vli >> 1;
5572                                         }
5573 
5574                                 scatterptr[i] = tc_head[tdelta];
5575                                 tc_head[tdelta] = i+1;
5576                                 }
5577                         }
5578                 }
5579 
5580         free(mc_mem); /* there is no usage below for this, no real need to clear out mc_mem or mc_mem_len */
5581 
5582         for(i=0;i<tsec_nitems;i++)
5583                 {
5584                 uint32_t tdelta;
5585                 int skiplen, skiplen2;
5586                 uint32_t vli;
5587 
5588                 if(fv)
5589                         {
5590                         char wx_buf[32];
5591                         int wx_len;
5592 
5593                         if(time_table[i] != previous_time)
5594                                 {
5595                                 if(xc->limit_range_valid)
5596                                         {
5597                                         if(time_table[i] > xc->limit_range_end)
5598                                                 {
5599                                                 break;
5600                                                 }
5601                                         }
5602 
5603 				if(dumpvars_state == 1) { wx_len = sprintf(wx_buf, "$end\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 2; }
5604                                 wx_len = sprintf(wx_buf, "#%" PRIu64 "\n", time_table[i]);
5605                                 fstWritex(xc, wx_buf, wx_len);
5606 				if(!dumpvars_state) { wx_len = sprintf(wx_buf, "$dumpvars\n"); fstWritex(xc, wx_buf, wx_len); dumpvars_state = 1; }
5607 
5608                                 if((xc->num_blackouts)&&(cur_blackout != xc->num_blackouts))
5609                                         {
5610                                         if(time_table[i] == xc->blackout_times[cur_blackout])
5611                                                 {
5612                                                 wx_len = sprintf(wx_buf, "$dump%s $end\n", (xc->blackout_activity[cur_blackout++]) ? "on" : "off");
5613                                                 fstWritex(xc, wx_buf, wx_len);
5614                                                 }
5615                                         }
5616                                 previous_time = time_table[i];
5617                                 }
5618                         }
5619 
5620                 while(tc_head[i])
5621                         {
5622                         idx = tc_head[i] - 1;
5623                         vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
5624 
5625                         if(xc->signal_lens[idx] <= 1)
5626                                 {
5627                                 if(xc->signal_lens[idx] == 1)
5628                                         {
5629                                         unsigned char val;
5630                                         if(!(vli & 1))
5631                                                 {
5632                                                 /* tdelta = vli >> 2; */ /* scan-build */
5633                                                 val = ((vli >> 1) & 1) | '0';
5634                                                 }
5635                                                 else
5636                                                 {
5637                                                 /* tdelta = vli >> 4; */ /* scan-build */
5638                                                 val = FST_RCV_STR[((vli >> 1) & 7)];
5639                                                 }
5640 
5641                                         if(value_change_callback)
5642                                                 {
5643                                                 xc->temp_signal_value_buf[0] = val;
5644                                                 xc->temp_signal_value_buf[1] = 0;
5645                                                 value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
5646                                                 }
5647                                                 else
5648                                                 {
5649                                                 if(fv)
5650                                                         {
5651                                                         char vcd_id[16];
5652                                                         int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
5653 
5654                                                         vcd_id[0] = val;
5655                                                         vcd_id[vcdid_len+1] = '\n';
5656                                                         fstWritex(xc, vcd_id, vcdid_len+2);
5657                                                         }
5658                                                 }
5659                                         headptr[idx] += skiplen;
5660                                         length_remaining[idx] -= skiplen;
5661 
5662                                         tc_head[i] = scatterptr[idx];
5663                                         scatterptr[idx] = 0;
5664 
5665                                         if(length_remaining[idx])
5666                                                 {
5667                                                 int shamt;
5668                                                 vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
5669                                                 shamt = 2 << (vli & 1);
5670                                                 tdelta = vli >> shamt;
5671 
5672                                                 scatterptr[idx] = tc_head[i+tdelta];
5673                                                 tc_head[i+tdelta] = idx+1;
5674                                                 }
5675                                         }
5676                                         else
5677                                         {
5678                                         unsigned char *vdata;
5679                                         uint32_t len;
5680 
5681                                         vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
5682                                         len = fstGetVarint32(mem_for_traversal + headptr[idx] + skiplen, &skiplen2);
5683                                         /* tdelta = vli >> 1; */ /* scan-build */
5684                                         skiplen += skiplen2;
5685                                         vdata = mem_for_traversal + headptr[idx] + skiplen;
5686 
5687                                         if(!(vli & 1))
5688                                                 {
5689                                                 if(value_change_callback_varlen)
5690                                                         {
5691                                                         value_change_callback_varlen(user_callback_data_pointer, time_table[i], idx+1, vdata, len);
5692                                                         }
5693                                                         else
5694                                                         {
5695                                                         if(fv)
5696                                                                 {
5697                                                                 char vcd_id[16];
5698                                                                 int vcdid_len;
5699 
5700                                                                 vcd_id[0] = 's';
5701                                                                 fstWritex(xc, vcd_id, 1);
5702 
5703                                                                 vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
5704                                                                 {
5705                                                                 unsigned char *vesc = (unsigned char *)malloc(len*4 + 1);
5706                                                                 int vlen = fstUtilityBinToEsc(vesc, vdata, len);
5707                                                                 fstWritex(xc, vesc, vlen);
5708                                                                 free(vesc);
5709                                                                 }
5710 
5711                                                                 vcd_id[0] = ' ';
5712                                                                 vcd_id[vcdid_len + 1] = '\n';
5713                                                                 fstWritex(xc, vcd_id, vcdid_len+2);
5714                                                                 }
5715                                                         }
5716                                                 }
5717 
5718                                         skiplen += len;
5719                                         headptr[idx] += skiplen;
5720                                         length_remaining[idx] -= skiplen;
5721 
5722                                         tc_head[i] = scatterptr[idx];
5723                                         scatterptr[idx] = 0;
5724 
5725                                         if(length_remaining[idx])
5726                                                 {
5727                                                 vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
5728                                                 tdelta = vli >> 1;
5729 
5730                                                 scatterptr[idx] = tc_head[i+tdelta];
5731                                                 tc_head[i+tdelta] = idx+1;
5732                                                 }
5733                                         }
5734                                 }
5735                                 else
5736                                 {
5737                                 uint32_t len = xc->signal_lens[idx];
5738                                 unsigned char *vdata;
5739 
5740                                 vli = fstGetVarint32(mem_for_traversal + headptr[idx], &skiplen);
5741                                 /* tdelta = vli >> 1; */ /* scan-build */
5742                                 vdata = mem_for_traversal + headptr[idx] + skiplen;
5743 
5744                                 if(xc->signal_typs[idx] != FST_VT_VCD_REAL)
5745                                         {
5746                                         if(!(vli & 1))
5747                                                 {
5748                                                 int byte = 0;
5749                                                 int bit;
5750                                                 unsigned int j;
5751 
5752                                                 for(j=0;j<len;j++)
5753                                                         {
5754                                                         unsigned char ch;
5755                                                         byte = j/8;
5756                                                         bit = 7 - (j & 7);
5757                                                         ch = ((vdata[byte] >> bit) & 1) | '0';
5758                                                         xc->temp_signal_value_buf[j] = ch;
5759                                                         }
5760                                                 xc->temp_signal_value_buf[j] = 0;
5761 
5762                                                 if(value_change_callback)
5763                                                         {
5764                                                         value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
5765                                                         }
5766                                                         else
5767                                                         {
5768                                                         if(fv)  {
5769                                                                 unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
5770 
5771                                                                 fstWritex(xc, &ch_bp, 1);
5772                                                                 fstWritex(xc, xc->temp_signal_value_buf, len);
5773                                                                 }
5774                                                         }
5775 
5776                                                 len = byte+1;
5777                                                 }
5778                                                 else
5779                                                 {
5780                                                 if(value_change_callback)
5781                                                         {
5782                                                         memcpy(xc->temp_signal_value_buf, vdata, len);
5783                                                         xc->temp_signal_value_buf[len] = 0;
5784                                                         value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
5785                                                         }
5786                                                         else
5787                                                         {
5788                                                         if(fv)
5789                                                                 {
5790                                                                 unsigned char ch_bp =  (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p';
5791 
5792                                                                 fstWritex(xc, &ch_bp, 1);
5793                                                                 fstWritex(xc, vdata, len);
5794                                                                 }
5795                                                         }
5796                                                 }
5797                                         }
5798                                         else
5799                                         {
5800                                         double d;
5801                                         unsigned char *clone_d /*= (unsigned char *)&d */; /* scan-build */
5802                                         unsigned char buf[8];
5803                                         unsigned char *srcdata;
5804 
5805                                         if(!(vli & 1))  /* very rare case, but possible */
5806                                                 {
5807                                                 int bit;
5808                                                 int j;
5809 
5810                                                 for(j=0;j<8;j++)
5811                                                         {
5812                                                         unsigned char ch;
5813                                                         bit = 7 - (j & 7);
5814                                                         ch = ((vdata[0] >> bit) & 1) | '0';
5815                                                         buf[j] = ch;
5816                                                         }
5817 
5818                                                 len = 1;
5819                                                 srcdata = buf;
5820                                                 }
5821                                                 else
5822                                                 {
5823                                                 srcdata = vdata;
5824                                                 }
5825 
5826                                         if(value_change_callback)
5827                                                 {
5828                                                 if(xc->native_doubles_for_cb)
5829                                                         {
5830                                                         if(xc->double_endian_match)
5831                                                                 {
5832                                                                 clone_d = srcdata;
5833                                                                 }
5834                                                                 else
5835                                                                 {
5836                                                                 int j;
5837 
5838                                                                 clone_d = (unsigned char *)&d;
5839                                                                 for(j=0;j<8;j++)
5840                                                                         {
5841                                                                         clone_d[j] = srcdata[7-j];
5842                                                                         }
5843                                                                 }
5844                                                         value_change_callback(user_callback_data_pointer, time_table[i], idx+1, clone_d);
5845                                                         }
5846                                                         else
5847                                                         {
5848                                                         clone_d = (unsigned char *)&d;
5849                                                         if(xc->double_endian_match)
5850                                                                 {
5851                                                                 memcpy(clone_d, srcdata, 8);
5852                                                                 }
5853                                                                 else
5854                                                                 {
5855                                                                 int j;
5856 
5857                                                                 for(j=0;j<8;j++)
5858                                                                         {
5859                                                                         clone_d[j] = srcdata[7-j];
5860                                                                         }
5861                                                                 }
5862                                                         sprintf((char *)xc->temp_signal_value_buf, "%.16g", d);
5863                                                         value_change_callback(user_callback_data_pointer, time_table[i], idx+1, xc->temp_signal_value_buf);
5864                                                         }
5865                                                 }
5866                                                 else
5867                                                 {
5868                                                 if(fv)
5869                                                         {
5870                                                         char wx_buf[32];
5871                                                         int wx_len;
5872 
5873                                                         clone_d = (unsigned char *)&d;
5874                                                         if(xc->double_endian_match)
5875                                                                 {
5876                                                                 memcpy(clone_d, srcdata, 8);
5877                                                                 }
5878                                                                 else
5879                                                                 {
5880                                                                 int j;
5881 
5882                                                                 for(j=0;j<8;j++)
5883                                                                         {
5884                                                                         clone_d[j] = srcdata[7-j];
5885                                                                         }
5886                                                                 }
5887 
5888                                                         wx_len = sprintf(wx_buf, "r%.16g", d);
5889                                                         fstWritex(xc, wx_buf, wx_len);
5890                                                         }
5891                                                 }
5892                                         }
5893 
5894                                 if(fv)
5895                                         {
5896                                         char vcd_id[16];
5897                                         int vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1);
5898                                         vcd_id[0] = ' ';
5899                                         vcd_id[vcdid_len+1] = '\n';
5900                                         fstWritex(xc, vcd_id, vcdid_len+2);
5901                                         }
5902 
5903                                 skiplen += len;
5904                                 headptr[idx] += skiplen;
5905                                 length_remaining[idx] -= skiplen;
5906 
5907                                 tc_head[i] = scatterptr[idx];
5908                                 scatterptr[idx] = 0;
5909 
5910                                 if(length_remaining[idx])
5911                                         {
5912                                         vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]);
5913                                         tdelta = vli >> 1;
5914 
5915                                         scatterptr[idx] = tc_head[i+tdelta];
5916                                         tc_head[i+tdelta] = idx+1;
5917                                         }
5918                                 }
5919                         }
5920                 }
5921 
5922 block_err:
5923         free(tc_head);
5924         free(chain_cmem);
5925         free(mem_for_traversal); mem_for_traversal = NULL;
5926 
5927         secnum++;
5928         if(secnum == xc->vc_section_count) break; /* in case file is growing, keep with original block count */
5929         blkpos += seclen;
5930         }
5931 
5932 if(mem_for_traversal) free(mem_for_traversal); /* scan-build */
5933 free(length_remaining);
5934 free(headptr);
5935 free(scatterptr);
5936 
5937 if(chain_table) free(chain_table);
5938 if(chain_table_lengths) free(chain_table_lengths);
5939 
5940 free(time_table);
5941 
5942 #ifndef FST_WRITEX_DISABLE
5943 if(fv)
5944         {
5945         fstWritex(xc, NULL, 0);
5946         }
5947 #endif
5948 
5949 return(1);
5950 }
5951 
5952 
5953 /* rvat functions */
5954 
fstExtractRvatDataFromFrame(struct fstReaderContext * xc,fstHandle facidx,char * buf)5955 static char *fstExtractRvatDataFromFrame(struct fstReaderContext *xc, fstHandle facidx, char *buf)
5956 {
5957 if(facidx >= xc->rvat_frame_maxhandle)
5958         {
5959         return(NULL);
5960         }
5961 
5962 if(xc->signal_lens[facidx] == 1)
5963         {
5964         buf[0] = (char)xc->rvat_frame_data[xc->rvat_sig_offs[facidx]];
5965         buf[1] = 0;
5966         }
5967         else
5968         {
5969         if(xc->signal_typs[facidx] != FST_VT_VCD_REAL)
5970                 {
5971                 memcpy(buf, xc->rvat_frame_data + xc->rvat_sig_offs[facidx], xc->signal_lens[facidx]);
5972                 buf[xc->signal_lens[facidx]] = 0;
5973                 }
5974                 else
5975                 {
5976                 double d;
5977                 unsigned char *clone_d = (unsigned char *)&d;
5978                 unsigned char *srcdata = xc->rvat_frame_data + xc->rvat_sig_offs[facidx];
5979 
5980                 if(xc->double_endian_match)
5981                         {
5982                         memcpy(clone_d, srcdata, 8);
5983                         }
5984                         else
5985                         {
5986                         int j;
5987 
5988                         for(j=0;j<8;j++)
5989                                 {
5990                                 clone_d[j] = srcdata[7-j];
5991                                 }
5992                         }
5993 
5994                 sprintf((char *)buf, "%.16g", d);
5995                 }
5996         }
5997 
5998 return(buf);
5999 }
6000 
6001 
fstReaderGetValueFromHandleAtTime(void * ctx,uint64_t tim,fstHandle facidx,char * buf)6002 char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf)
6003 {
6004 struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
6005 fst_off_t blkpos = 0, prev_blkpos;
6006 uint64_t beg_tim, end_tim, beg_tim2, end_tim2;
6007 int sectype;
6008 unsigned int secnum = 0;
6009 uint64_t seclen;
6010 uint64_t tsec_uclen = 0, tsec_clen = 0;
6011 uint64_t tsec_nitems;
6012 uint64_t frame_uclen, frame_clen;
6013 #ifdef FST_DEBUG
6014 uint64_t mem_required_for_traversal;
6015 #endif
6016 fst_off_t indx_pntr, indx_pos;
6017 long chain_clen;
6018 unsigned char *chain_cmem;
6019 unsigned char *pnt;
6020 fstHandle idx, pidx=0, i;
6021 uint64_t pval;
6022 
6023 if((!xc) || (!facidx) || (facidx > xc->maxhandle) || (!buf) || (!xc->signal_lens[facidx-1]))
6024         {
6025         return(NULL);
6026         }
6027 
6028 if(!xc->rvat_sig_offs)
6029         {
6030         uint32_t cur_offs = 0;
6031 
6032         xc->rvat_sig_offs = (uint32_t *)calloc(xc->maxhandle, sizeof(uint32_t));
6033         for(i=0;i<xc->maxhandle;i++)
6034                 {
6035                 xc->rvat_sig_offs[i] = cur_offs;
6036                 cur_offs += xc->signal_lens[i];
6037                 }
6038         }
6039 
6040 if(xc->rvat_data_valid)
6041         {
6042         if((xc->rvat_beg_tim <= tim) && (tim <= xc->rvat_end_tim))
6043                 {
6044                 goto process_value;
6045                 }
6046 
6047         fstReaderDeallocateRvatData(xc);
6048         }
6049 
6050 xc->rvat_chain_pos_valid = 0;
6051 
6052 for(;;)
6053         {
6054         fstReaderFseeko(xc, xc->f, (prev_blkpos = blkpos), SEEK_SET);
6055 
6056         sectype = fgetc(xc->f);
6057         seclen = fstReaderUint64(xc->f);
6058 
6059         if((sectype == EOF) || (sectype == FST_BL_SKIP) || (!seclen))
6060                 {
6061                 return(NULL); /* if this loop exits on break, it's successful */
6062                 }
6063 
6064         blkpos++;
6065         if((sectype != FST_BL_VCDATA) && (sectype != FST_BL_VCDATA_DYN_ALIAS) && (sectype != FST_BL_VCDATA_DYN_ALIAS2))
6066                 {
6067                 blkpos += seclen;
6068                 continue;
6069                 }
6070 
6071         beg_tim = fstReaderUint64(xc->f);
6072         end_tim = fstReaderUint64(xc->f);
6073 
6074         if((beg_tim <= tim) && (tim <= end_tim))
6075                 {
6076                 if((tim == end_tim) && (tim != xc->end_time))
6077                         {
6078                         fst_off_t cached_pos = ftello(xc->f);
6079                         fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET);
6080 
6081                         sectype = fgetc(xc->f);
6082                         seclen = fstReaderUint64(xc->f);
6083 
6084                         beg_tim2 = fstReaderUint64(xc->f);
6085                         end_tim2 = fstReaderUint64(xc->f);
6086 
6087                         if(((sectype != FST_BL_VCDATA)&&(sectype != FST_BL_VCDATA_DYN_ALIAS)&&(sectype != FST_BL_VCDATA_DYN_ALIAS2)) || (!seclen) || (beg_tim2 != tim))
6088                                 {
6089                                 blkpos = prev_blkpos;
6090                                 break;
6091                                 }
6092                         beg_tim = beg_tim2;
6093                         end_tim = end_tim2;
6094                         fstReaderFseeko(xc, xc->f, cached_pos, SEEK_SET);
6095                         }
6096                 break;
6097                 }
6098 
6099         blkpos += seclen;
6100         secnum++;
6101         }
6102 
6103 xc->rvat_beg_tim = beg_tim;
6104 xc->rvat_end_tim = end_tim;
6105 
6106 #ifdef FST_DEBUG
6107 mem_required_for_traversal =
6108 #endif
6109         fstReaderUint64(xc->f);
6110 
6111 #ifdef FST_DEBUG
6112 fprintf(stderr, FST_APIMESS "rvat sec: %u seclen: %d begtim: %d endtim: %d\n",
6113         secnum, (int)seclen, (int)beg_tim, (int)end_tim);
6114 fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal);
6115 #endif
6116 
6117 /* process time block */
6118 {
6119 unsigned char *ucdata;
6120 unsigned char *cdata;
6121 unsigned long destlen /* = tsec_uclen */; /* scan-build */
6122 unsigned long sourcelen /* = tsec_clen */; /* scan-build */
6123 int rc;
6124 unsigned char *tpnt;
6125 uint64_t tpval;
6126 unsigned int ti;
6127 
6128 fstReaderFseeko(xc, xc->f, blkpos + seclen - 24, SEEK_SET);
6129 tsec_uclen = fstReaderUint64(xc->f);
6130 tsec_clen = fstReaderUint64(xc->f);
6131 tsec_nitems = fstReaderUint64(xc->f);
6132 #ifdef FST_DEBUG
6133 fprintf(stderr, FST_APIMESS "time section unc: %d, com: %d (%d items)\n",
6134         (int)tsec_uclen, (int)tsec_clen, (int)tsec_nitems);
6135 #endif
6136 ucdata = (unsigned char *)malloc(tsec_uclen);
6137 destlen = tsec_uclen;
6138 sourcelen = tsec_clen;
6139 
6140 fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR);
6141 if(tsec_uclen != tsec_clen)
6142         {
6143         cdata = (unsigned char *)malloc(tsec_clen);
6144         fstFread(cdata, tsec_clen, 1, xc->f);
6145 
6146         rc = uncompress(ucdata, &destlen, cdata, sourcelen);
6147 
6148         if(rc != Z_OK)
6149                 {
6150                 fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), tsec uncompress rc = %d, exiting.\n", rc);
6151                 exit(255);
6152                 }
6153 
6154         free(cdata);
6155         }
6156         else
6157         {
6158         fstFread(ucdata, tsec_uclen, 1, xc->f);
6159         }
6160 
6161 xc->rvat_time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t));
6162 tpnt = ucdata;
6163 tpval = 0;
6164 for(ti=0;ti<tsec_nitems;ti++)
6165         {
6166         int skiplen;
6167         uint64_t val = fstGetVarint64(tpnt, &skiplen);
6168         tpval = xc->rvat_time_table[ti] = tpval + val;
6169         tpnt += skiplen;
6170         }
6171 
6172 free(ucdata);
6173 }
6174 
6175 fstReaderFseeko(xc, xc->f, blkpos+32, SEEK_SET);
6176 
6177 frame_uclen = fstReaderVarint64(xc->f);
6178 frame_clen = fstReaderVarint64(xc->f);
6179 xc->rvat_frame_maxhandle = fstReaderVarint64(xc->f);
6180 xc->rvat_frame_data = (unsigned char *)malloc(frame_uclen);
6181 
6182 if(frame_uclen == frame_clen)
6183         {
6184         fstFread(xc->rvat_frame_data, frame_uclen, 1, xc->f);
6185         }
6186         else
6187         {
6188         unsigned char *mc = (unsigned char *)malloc(frame_clen);
6189         int rc;
6190 
6191         unsigned long destlen = frame_uclen;
6192         unsigned long sourcelen = frame_clen;
6193 
6194         fstFread(mc, sourcelen, 1, xc->f);
6195         rc = uncompress(xc->rvat_frame_data, &destlen, mc, sourcelen);
6196         if(rc != Z_OK)
6197                 {
6198                 fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), frame decompress rc: %d, exiting.\n", rc);
6199                 exit(255);
6200                 }
6201         free(mc);
6202         }
6203 
6204 xc->rvat_vc_maxhandle = fstReaderVarint64(xc->f);
6205 xc->rvat_vc_start = ftello(xc->f);      /* points to '!' character */
6206 xc->rvat_packtype = fgetc(xc->f);
6207 
6208 #ifdef FST_DEBUG
6209 fprintf(stderr, FST_APIMESS "frame_uclen: %d, frame_clen: %d, frame_maxhandle: %d\n",
6210         (int)frame_uclen, (int)frame_clen, (int)xc->rvat_frame_maxhandle);
6211 fprintf(stderr, FST_APIMESS "vc_maxhandle: %d\n", (int)xc->rvat_vc_maxhandle);
6212 #endif
6213 
6214 indx_pntr = blkpos + seclen - 24 -tsec_clen -8;
6215 fstReaderFseeko(xc, xc->f, indx_pntr, SEEK_SET);
6216 chain_clen = fstReaderUint64(xc->f);
6217 indx_pos = indx_pntr - chain_clen;
6218 #ifdef FST_DEBUG
6219 fprintf(stderr, FST_APIMESS "indx_pos: %d (%d bytes)\n", (int)indx_pos, (int)chain_clen);
6220 #endif
6221 chain_cmem = (unsigned char *)malloc(chain_clen);
6222 fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET);
6223 fstFread(chain_cmem, chain_clen, 1, xc->f);
6224 
6225 xc->rvat_chain_table = (fst_off_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(fst_off_t));
6226 xc->rvat_chain_table_lengths = (uint32_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(uint32_t));
6227 
6228 pnt = chain_cmem;
6229 idx = 0;
6230 pval = 0;
6231 
6232 if(sectype == FST_BL_VCDATA_DYN_ALIAS2)
6233         {
6234         uint32_t prev_alias = 0;
6235 
6236         do      {
6237                 int skiplen;
6238 
6239                 if(*pnt & 0x01)
6240                         {
6241                         int64_t shval = fstGetSVarint64(pnt, &skiplen) >> 1;
6242                         if(shval > 0)
6243                                 {
6244                                 pval = xc->rvat_chain_table[idx] = pval + shval;
6245                                 if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; }
6246                                 pidx = idx++;
6247                                 }
6248                         else if(shval < 0)
6249                                 {
6250                                 xc->rvat_chain_table[idx] = 0;                                   /* need to explicitly zero as calloc above might not run */
6251                                 xc->rvat_chain_table_lengths[idx] = prev_alias = shval;          /* because during this loop iter would give stale data! */
6252                                 idx++;
6253                                 }
6254                         else
6255                                 {
6256                                 xc->rvat_chain_table[idx] = 0;                                   /* need to explicitly zero as calloc above might not run */
6257                                 xc->rvat_chain_table_lengths[idx] = prev_alias;                  /* because during this loop iter would give stale data! */
6258                                 idx++;
6259                                 }
6260                         }
6261                         else
6262                         {
6263                         uint64_t val = fstGetVarint32(pnt, &skiplen);
6264 
6265                         fstHandle loopcnt = val >> 1;
6266                         for(i=0;i<loopcnt;i++)
6267                                 {
6268                                 xc->rvat_chain_table[idx++] = 0;
6269                                 }
6270                         }
6271 
6272                 pnt += skiplen;
6273                 } while (pnt != (chain_cmem + chain_clen));
6274         }
6275         else
6276 	{
6277 	do
6278 	        {
6279 	        int skiplen;
6280 	        uint64_t val = fstGetVarint32(pnt, &skiplen);
6281 
6282 	        if(!val)
6283 	                {
6284 	                pnt += skiplen;
6285 	                val = fstGetVarint32(pnt, &skiplen);
6286 	                xc->rvat_chain_table[idx] = 0;
6287 	                xc->rvat_chain_table_lengths[idx] = -val;
6288 	                idx++;
6289 	                }
6290 	        else
6291 	        if(val&1)
6292 	                {
6293 	                pval = xc->rvat_chain_table[idx] = pval + (val >> 1);
6294 	                if(idx) { xc->rvat_chain_table_lengths[pidx] = pval - xc->rvat_chain_table[pidx]; }
6295 	                pidx = idx++;
6296 	                }
6297 	                else
6298 	                {
6299 	                fstHandle loopcnt = val >> 1;
6300 	                for(i=0;i<loopcnt;i++)
6301 	                        {
6302 	                        xc->rvat_chain_table[idx++] = 0;
6303 	                        }
6304 	                }
6305 
6306 	        pnt += skiplen;
6307 	        } while (pnt != (chain_cmem + chain_clen));
6308 	}
6309 
6310 free(chain_cmem);
6311 xc->rvat_chain_table[idx] = indx_pos - xc->rvat_vc_start;
6312 xc->rvat_chain_table_lengths[pidx] = xc->rvat_chain_table[idx] - xc->rvat_chain_table[pidx];
6313 
6314 for(i=0;i<idx;i++)
6315         {
6316         int32_t v32 = xc->rvat_chain_table_lengths[i];
6317         if((v32 < 0) && (!xc->rvat_chain_table[i]))
6318                 {
6319                 v32 = -v32;
6320                 v32--;
6321                 if(((uint32_t)v32) < i) /* sanity check */
6322                         {
6323                         xc->rvat_chain_table[i] = xc->rvat_chain_table[v32];
6324                         xc->rvat_chain_table_lengths[i] = xc->rvat_chain_table_lengths[v32];
6325                         }
6326                 }
6327         }
6328 
6329 #ifdef FST_DEBUG
6330 fprintf(stderr, FST_APIMESS "decompressed chain idx len: %" PRIu32 "\n", idx);
6331 #endif
6332 
6333 xc->rvat_data_valid = 1;
6334 
6335 /* all data at this point is loaded or resident in fst cache, process and return appropriate value */
6336 process_value:
6337 if(facidx > xc->rvat_vc_maxhandle)
6338         {
6339         return(NULL);
6340         }
6341 
6342 facidx--; /* scale down for array which starts at zero */
6343 
6344 
6345 if(((tim == xc->rvat_beg_tim)&&(!xc->rvat_chain_table[facidx])) || (!xc->rvat_chain_table[facidx]))
6346         {
6347         return(fstExtractRvatDataFromFrame(xc, facidx, buf));
6348         }
6349 
6350 if(facidx != xc->rvat_chain_facidx)
6351         {
6352         if(xc->rvat_chain_mem)
6353                 {
6354                 free(xc->rvat_chain_mem);
6355                 xc->rvat_chain_mem = NULL;
6356 
6357                 xc->rvat_chain_pos_valid = 0;
6358                 }
6359         }
6360 
6361 if(!xc->rvat_chain_mem)
6362         {
6363         uint32_t skiplen;
6364         fstReaderFseeko(xc, xc->f, xc->rvat_vc_start + xc->rvat_chain_table[facidx], SEEK_SET);
6365         xc->rvat_chain_len = fstReaderVarint32WithSkip(xc->f, &skiplen);
6366         if(xc->rvat_chain_len)
6367                 {
6368                 unsigned char *mu = (unsigned char *)malloc(xc->rvat_chain_len);
6369                 unsigned char *mc = (unsigned char *)malloc(xc->rvat_chain_table_lengths[facidx]);
6370                 unsigned long destlen = xc->rvat_chain_len;
6371                 unsigned long sourcelen = xc->rvat_chain_table_lengths[facidx];
6372                 int rc = Z_OK;
6373 
6374                 fstFread(mc, xc->rvat_chain_table_lengths[facidx], 1, xc->f);
6375 
6376                 switch(xc->rvat_packtype)
6377 			{
6378                         case '4': rc = (destlen == (unsigned long)LZ4_decompress_safe_partial((char *)mc, (char *)mu, sourcelen, destlen, destlen)) ? Z_OK : Z_DATA_ERROR;
6379                         	break;
6380                         case 'F': fastlz_decompress(mc, sourcelen, mu, destlen); /* rc appears unreliable */
6381                         	break;
6382                         default:  rc = uncompress(mu, &destlen, mc, sourcelen);
6383                         	break;
6384                         }
6385 
6386                 free(mc);
6387 
6388                 if(rc != Z_OK)
6389                         {
6390                         fprintf(stderr, FST_APIMESS "fstReaderGetValueFromHandleAtTime(), rvat decompress clen: %d (rc=%d), exiting.\n", (int)xc->rvat_chain_len, rc);
6391                         exit(255);
6392                         }
6393 
6394                 /* data to process is for(j=0;j<destlen;j++) in mu[j] */
6395                 xc->rvat_chain_mem = mu;
6396                 }
6397                 else
6398                 {
6399                 int destlen = xc->rvat_chain_table_lengths[facidx] - skiplen;
6400                 unsigned char *mu = (unsigned char *)malloc(xc->rvat_chain_len = destlen);
6401                 fstFread(mu, destlen, 1, xc->f);
6402                 /* data to process is for(j=0;j<destlen;j++) in mu[j] */
6403                 xc->rvat_chain_mem = mu;
6404                 }
6405 
6406         xc->rvat_chain_facidx = facidx;
6407         }
6408 
6409 /* process value chain here */
6410 
6411 {
6412 uint32_t tidx = 0, ptidx = 0;
6413 uint32_t tdelta;
6414 int skiplen;
6415 unsigned int iprev = xc->rvat_chain_len;
6416 uint32_t pvli = 0;
6417 int pskip = 0;
6418 
6419 if((xc->rvat_chain_pos_valid)&&(tim >= xc->rvat_chain_pos_time))
6420         {
6421         i = xc->rvat_chain_pos_idx;
6422         tidx = xc->rvat_chain_pos_tidx;
6423         }
6424         else
6425         {
6426         i = 0;
6427         tidx = 0;
6428         xc->rvat_chain_pos_time = xc->rvat_beg_tim;
6429         }
6430 
6431 if(xc->signal_lens[facidx] == 1)
6432         {
6433         while(i<xc->rvat_chain_len)
6434                 {
6435                 uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen);
6436                 uint32_t shcnt = 2 << (vli & 1);
6437                 tdelta = vli >> shcnt;
6438 
6439                 if(xc->rvat_time_table[tidx + tdelta] <= tim)
6440                         {
6441                         iprev = i;
6442                         pvli = vli;
6443                         ptidx = tidx;
6444                         /* pskip = skiplen; */ /* scan-build */
6445 
6446                         tidx += tdelta;
6447                         i+=skiplen;
6448                         }
6449                         else
6450                         {
6451                         break;
6452                         }
6453                 }
6454         if(iprev != xc->rvat_chain_len)
6455                 {
6456                 xc->rvat_chain_pos_tidx = ptidx;
6457                 xc->rvat_chain_pos_idx = iprev;
6458                 xc->rvat_chain_pos_time = tim;
6459                 xc->rvat_chain_pos_valid = 1;
6460 
6461                 if(!(pvli & 1))
6462                         {
6463                         buf[0] = ((pvli >> 1) & 1) | '0';
6464                         }
6465                         else
6466                         {
6467                         buf[0] = FST_RCV_STR[((pvli >> 1) & 7)];
6468                         }
6469                 buf[1] = 0;
6470                 return(buf);
6471                 }
6472                 else
6473                 {
6474                 return(fstExtractRvatDataFromFrame(xc, facidx, buf));
6475                 }
6476         }
6477         else
6478         {
6479         while(i<xc->rvat_chain_len)
6480                 {
6481                 uint32_t vli = fstGetVarint32(xc->rvat_chain_mem + i, &skiplen);
6482                 tdelta = vli >> 1;
6483 
6484                 if(xc->rvat_time_table[tidx + tdelta] <= tim)
6485                         {
6486                         iprev = i;
6487                         pvli = vli;
6488                         ptidx = tidx;
6489                         pskip = skiplen;
6490 
6491                         tidx += tdelta;
6492                         i+=skiplen;
6493 
6494                         if(!(pvli & 1))
6495                                 {
6496                                 i+=((xc->signal_lens[facidx]+7)/8);
6497                                 }
6498                                 else
6499                                 {
6500                                 i+=xc->signal_lens[facidx];
6501                                 }
6502                         }
6503                         else
6504                         {
6505                         break;
6506                         }
6507                 }
6508 
6509         if(iprev != xc->rvat_chain_len)
6510                 {
6511                 unsigned char *vdata = xc->rvat_chain_mem + iprev + pskip;
6512 
6513                 xc->rvat_chain_pos_tidx = ptidx;
6514                 xc->rvat_chain_pos_idx = iprev;
6515                 xc->rvat_chain_pos_time = tim;
6516                 xc->rvat_chain_pos_valid = 1;
6517 
6518                 if(xc->signal_typs[facidx] != FST_VT_VCD_REAL)
6519                         {
6520                         if(!(pvli & 1))
6521                                 {
6522                                 int byte = 0;
6523                                 int bit;
6524                                 unsigned int j;
6525 
6526                                 for(j=0;j<xc->signal_lens[facidx];j++)
6527                                         {
6528                                         unsigned char ch;
6529                                         byte = j/8;
6530                                         bit = 7 - (j & 7);
6531                                         ch = ((vdata[byte] >> bit) & 1) | '0';
6532                                         buf[j] = ch;
6533                                         }
6534                                 buf[j] = 0;
6535 
6536                                 return(buf);
6537                                 }
6538                                 else
6539                                 {
6540                                 memcpy(buf, vdata, xc->signal_lens[facidx]);
6541                                 buf[xc->signal_lens[facidx]] = 0;
6542                                 return(buf);
6543                                 }
6544                         }
6545                         else
6546                         {
6547                         double d;
6548                         unsigned char *clone_d = (unsigned char *)&d;
6549                         unsigned char bufd[8];
6550                         unsigned char *srcdata;
6551 
6552                         if(!(pvli & 1)) /* very rare case, but possible */
6553                                 {
6554                                 int bit;
6555                                 int j;
6556 
6557                                 for(j=0;j<8;j++)
6558                                         {
6559                                         unsigned char ch;
6560                                         bit = 7 - (j & 7);
6561                                         ch = ((vdata[0] >> bit) & 1) | '0';
6562                                         bufd[j] = ch;
6563                                         }
6564 
6565                                 srcdata = bufd;
6566                                 }
6567                                 else
6568                                 {
6569                                 srcdata = vdata;
6570                                 }
6571 
6572                         if(xc->double_endian_match)
6573                                 {
6574                                 memcpy(clone_d, srcdata, 8);
6575                                 }
6576                                 else
6577                                 {
6578                                 int j;
6579 
6580                                 for(j=0;j<8;j++)
6581                                         {
6582                                         clone_d[j] = srcdata[7-j];
6583                                         }
6584                                 }
6585 
6586                         sprintf(buf, "r%.16g", d);
6587                         return(buf);
6588                         }
6589                 }
6590                 else
6591                 {
6592                 return(fstExtractRvatDataFromFrame(xc, facidx, buf));
6593                 }
6594         }
6595 }
6596 
6597 /* return(NULL); */
6598 }
6599 
6600 
6601 
6602 /**********************************************************************/
6603 #ifndef _WAVE_HAVE_JUDY
6604 
6605 /***********************/
6606 /***                 ***/
6607 /***  jenkins hash   ***/
6608 /***                 ***/
6609 /***********************/
6610 
6611 /*
6612 --------------------------------------------------------------------
6613 mix -- mix 3 32-bit values reversibly.
6614 For every delta with one or two bits set, and the deltas of all three
6615   high bits or all three low bits, whether the original value of a,b,c
6616   is almost all zero or is uniformly distributed,
6617 * If mix() is run forward or backward, at least 32 bits in a,b,c
6618   have at least 1/4 probability of changing.
6619 * If mix() is run forward, every bit of c will change between 1/3 and
6620   2/3 of the time.  (Well, 22/100 and 78/100 for some 2-bit deltas.)
6621 mix() was built out of 36 single-cycle latency instructions in a
6622   structure that could supported 2x parallelism, like so:
6623       a -= b;
6624       a -= c; x = (c>>13);
6625       b -= c; a ^= x;
6626       b -= a; x = (a<<8);
6627       c -= a; b ^= x;
6628       c -= b; x = (b>>13);
6629       ...
6630   Unfortunately, superscalar Pentiums and Sparcs can't take advantage
6631   of that parallelism.  They've also turned some of those single-cycle
6632   latency instructions into multi-cycle latency instructions.  Still,
6633   this is the fastest good hash I could find.  There were about 2^^68
6634   to choose from.  I only looked at a billion or so.
6635 --------------------------------------------------------------------
6636 */
6637 #define mix(a,b,c) \
6638 { \
6639   a -= b; a -= c; a ^= (c>>13); \
6640   b -= c; b -= a; b ^= (a<<8); \
6641   c -= a; c -= b; c ^= (b>>13); \
6642   a -= b; a -= c; a ^= (c>>12);  \
6643   b -= c; b -= a; b ^= (a<<16); \
6644   c -= a; c -= b; c ^= (b>>5); \
6645   a -= b; a -= c; a ^= (c>>3);  \
6646   b -= c; b -= a; b ^= (a<<10); \
6647   c -= a; c -= b; c ^= (b>>15); \
6648 }
6649 
6650 /*
6651 --------------------------------------------------------------------
6652 j_hash() -- hash a variable-length key into a 32-bit value
6653   k       : the key (the unaligned variable-length array of bytes)
6654   len     : the length of the key, counting by bytes
6655   initval : can be any 4-byte value
6656 Returns a 32-bit value.  Every bit of the key affects every bit of
6657 the return value.  Every 1-bit and 2-bit delta achieves avalanche.
6658 About 6*len+35 instructions.
6659 
6660 The best hash table sizes are powers of 2.  There is no need to do
6661 mod a prime (mod is sooo slow!).  If you need less than 32 bits,
6662 use a bitmask.  For example, if you need only 10 bits, do
6663   h = (h & hashmask(10));
6664 In which case, the hash table should have hashsize(10) elements.
6665 
6666 If you are hashing n strings (uint8_t **)k, do it like this:
6667   for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
6668 
6669 By Bob Jenkins, 1996.  bob_jenkins@burtleburtle.net.  You may use this
6670 code any way you wish, private, educational, or commercial.  It's free.
6671 
6672 See http://burtleburtle.net/bob/hash/evahash.html
6673 Use for hash table lookup, or anything where one collision in 2^^32 is
6674 acceptable.  Do NOT use for cryptographic purposes.
6675 --------------------------------------------------------------------
6676 */
6677 
j_hash(const uint8_t * k,uint32_t length,uint32_t initval)6678 static uint32_t j_hash(const uint8_t *k, uint32_t length, uint32_t initval)
6679 {
6680    uint32_t a,b,c,len;
6681 
6682    /* Set up the internal state */
6683    len = length;
6684    a = b = 0x9e3779b9;  /* the golden ratio; an arbitrary value */
6685    c = initval;         /* the previous hash value */
6686 
6687    /*---------------------------------------- handle most of the key */
6688    while (len >= 12)
6689    {
6690       a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24));
6691       b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24));
6692       c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24));
6693       mix(a,b,c);
6694       k += 12; len -= 12;
6695    }
6696 
6697    /*------------------------------------- handle the last 11 bytes */
6698    c += length;
6699    switch(len)              /* all the case statements fall through */
6700    {
6701    case 11: c+=((uint32_t)k[10]<<24); /* fallthrough */
6702    case 10: c+=((uint32_t)k[9]<<16); /* fallthrough */
6703    case 9 : c+=((uint32_t)k[8]<<8); /* fallthrough */
6704       /* the first byte of c is reserved for the length */
6705    case 8 : b+=((uint32_t)k[7]<<24); /* fallthrough */
6706    case 7 : b+=((uint32_t)k[6]<<16); /* fallthrough */
6707    case 6 : b+=((uint32_t)k[5]<<8); /* fallthrough */
6708    case 5 : b+=k[4]; /* fallthrough */
6709    case 4 : a+=((uint32_t)k[3]<<24); /* fallthrough */
6710    case 3 : a+=((uint32_t)k[2]<<16); /* fallthrough */
6711    case 2 : a+=((uint32_t)k[1]<<8); /* fallthrough */
6712    case 1 : a+=k[0];
6713      /* case 0: nothing left to add */
6714    }
6715    mix(a,b,c);
6716    /*-------------------------------------------- report the result */
6717    return(c);
6718 }
6719 
6720 /********************************************************************/
6721 
6722 /***************************/
6723 /***                     ***/
6724 /***  judy HS emulation  ***/
6725 /***                     ***/
6726 /***************************/
6727 
6728 struct collchain_t
6729 {
6730 struct collchain_t *next;
6731 void *payload;
6732 uint32_t fullhash, length;
6733 unsigned char mem[1];
6734 };
6735 
6736 
JenkinsIns(void * base_i,const unsigned char * mem,uint32_t length,uint32_t hashmask)6737 void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint32_t hashmask)
6738 {
6739 struct collchain_t ***base = (struct collchain_t ***)base_i;
6740 uint32_t hf, h;
6741 struct collchain_t **ar;
6742 struct collchain_t *chain, *pchain;
6743 
6744 if(!*base)
6745         {
6746         *base = (struct collchain_t **)calloc(1, (hashmask + 1) * sizeof(void *));
6747         }
6748 ar = *base;
6749 
6750 h = (hf = j_hash(mem, length, length)) & hashmask;
6751 pchain = chain = ar[h];
6752 while(chain)
6753         {
6754         if((chain->fullhash == hf) && (chain->length == length) && !memcmp(chain->mem, mem, length))
6755                 {
6756                 if(pchain != chain) /* move hit to front */
6757                         {
6758                         pchain->next = chain->next;
6759                         chain->next = ar[h];
6760                         ar[h] = chain;
6761                         }
6762                 return(&(chain->payload));
6763                 }
6764 
6765         pchain = chain;
6766         chain = chain->next;
6767         }
6768 
6769 chain = (struct collchain_t *)calloc(1, sizeof(struct collchain_t) + length - 1);
6770 memcpy(chain->mem, mem, length);
6771 chain->fullhash = hf;
6772 chain->length = length;
6773 chain->next = ar[h];
6774 ar[h] = chain;
6775 return(&(chain->payload));
6776 }
6777 
6778 
JenkinsFree(void * base_i,uint32_t hashmask)6779 void JenkinsFree(void *base_i, uint32_t hashmask)
6780 {
6781 struct collchain_t ***base = (struct collchain_t ***)base_i;
6782 uint32_t h;
6783 struct collchain_t **ar;
6784 struct collchain_t *chain, *chain_next;
6785 
6786 if(base && *base)
6787         {
6788         ar = *base;
6789         for(h=0;h<=hashmask;h++)
6790                 {
6791                 chain = ar[h];
6792                 while(chain)
6793                         {
6794                         chain_next = chain->next;
6795                         free(chain);
6796                         chain = chain_next;
6797                         }
6798                 }
6799 
6800         free(*base);
6801         *base = NULL;
6802         }
6803 }
6804 
6805 #endif
6806 
6807 /**********************************************************************/
6808 
6809 /************************/
6810 /***                  ***/
6811 /*** utility function ***/
6812 /***                  ***/
6813 /************************/
6814 
fstUtilityBinToEscConvertedLen(const unsigned char * s,int len)6815 int fstUtilityBinToEscConvertedLen(const unsigned char *s, int len)
6816 {
6817 const unsigned char *src = s;
6818 int dlen = 0;
6819 int i;
6820 
6821 for(i=0;i<len;i++)
6822         {
6823         switch(src[i])
6824                 {
6825                 case '\a':      /* fallthrough */
6826                 case '\b':	/* fallthrough */
6827                 case '\f':	/* fallthrough */
6828                 case '\n':	/* fallthrough */
6829                 case '\r':	/* fallthrough */
6830                 case '\t':	/* fallthrough */
6831                 case '\v':	/* fallthrough */
6832                 case '\'':	/* fallthrough */
6833                 case '\"':	/* fallthrough */
6834                 case '\\':	/* fallthrough */
6835                 case '\?':      dlen += 2; break;
6836                 default:        if((src[i] > ' ') && (src[i] <= '~')) /* no white spaces in output */
6837                                         {
6838 					dlen++;
6839                                         }
6840                                         else
6841                                         {
6842 					dlen += 4;
6843                                         }
6844                                 break;
6845                 }
6846         }
6847 
6848 return(dlen);
6849 }
6850 
6851 
fstUtilityBinToEsc(unsigned char * d,const unsigned char * s,int len)6852 int fstUtilityBinToEsc(unsigned char *d, const unsigned char *s, int len)
6853 {
6854 const unsigned char *src = s;
6855 unsigned char *dst = d;
6856 unsigned char val;
6857 int i;
6858 
6859 for(i=0;i<len;i++)
6860         {
6861         switch(src[i])
6862                 {
6863                 case '\a':      *(dst++) = '\\'; *(dst++) = 'a'; break;
6864                 case '\b':      *(dst++) = '\\'; *(dst++) = 'b'; break;
6865                 case '\f':      *(dst++) = '\\'; *(dst++) = 'f'; break;
6866                 case '\n':      *(dst++) = '\\'; *(dst++) = 'n'; break;
6867                 case '\r':      *(dst++) = '\\'; *(dst++) = 'r'; break;
6868                 case '\t':      *(dst++) = '\\'; *(dst++) = 't'; break;
6869                 case '\v':      *(dst++) = '\\'; *(dst++) = 'v'; break;
6870                 case '\'':      *(dst++) = '\\'; *(dst++) = '\''; break;
6871                 case '\"':      *(dst++) = '\\'; *(dst++) = '\"'; break;
6872                 case '\\':      *(dst++) = '\\'; *(dst++) = '\\'; break;
6873                 case '\?':      *(dst++) = '\\'; *(dst++) = '\?'; break;
6874                 default:        if((src[i] > ' ') && (src[i] <= '~')) /* no white spaces in output */
6875                                         {
6876                                         *(dst++) = src[i];
6877                                         }
6878                                         else
6879                                         {
6880                                         val = src[i];
6881                                         *(dst++) = '\\';
6882                                         *(dst++) = (val/64) + '0'; val = val & 63;
6883                                         *(dst++) = (val/8)  + '0'; val = val & 7;
6884                                         *(dst++) = (val) + '0';
6885                                         }
6886                                 break;
6887                 }
6888         }
6889 
6890 return(dst - d);
6891 }
6892 
6893 
6894 /*
6895  * this overwrites the original string if the destination pointer is NULL
6896  */
fstUtilityEscToBin(unsigned char * d,unsigned char * s,int len)6897 int fstUtilityEscToBin(unsigned char *d, unsigned char *s, int len)
6898 {
6899 unsigned char *src = s;
6900 unsigned char *dst = (!d) ? s : (s = d);
6901 unsigned char val[3];
6902 int i;
6903 
6904 for(i=0;i<len;i++)
6905         {
6906         if(src[i] != '\\')
6907                 {
6908                 *(dst++) = src[i];
6909                 }
6910                 else
6911                 {
6912                 switch(src[++i])
6913                         {
6914                         case 'a':       *(dst++) = '\a'; break;
6915                         case 'b':       *(dst++) = '\b'; break;
6916                         case 'f':       *(dst++) = '\f'; break;
6917                         case 'n':       *(dst++) = '\n'; break;
6918                         case 'r':       *(dst++) = '\r'; break;
6919                         case 't':       *(dst++) = '\t'; break;
6920                         case 'v':       *(dst++) = '\v'; break;
6921                         case '\'':      *(dst++) = '\''; break;
6922                         case '\"':      *(dst++) = '\"'; break;
6923                         case '\\':      *(dst++) = '\\'; break;
6924                         case '\?':      *(dst++) = '\?'; break;
6925 
6926                         case 'x':       val[0] = toupper(src[++i]);
6927                                         val[1] = toupper(src[++i]);
6928                                         val[0] = ((val[0]>='A')&&(val[0]<='F')) ? (val[0] - 'A' + 10) : (val[0] - '0');
6929                                         val[1] = ((val[1]>='A')&&(val[1]<='F')) ? (val[1] - 'A' + 10) : (val[1] - '0');
6930                                         *(dst++) = val[0] * 16 + val[1];
6931                                         break;
6932 
6933                         case '0':
6934                         case '1':
6935                         case '2':
6936                         case '3':
6937                         case '4':
6938                         case '5':
6939                         case '6':
6940                         case '7':       val[0] = src[  i] - '0';
6941                                         val[1] = src[++i] - '0';
6942                                         val[2] = src[++i] - '0';
6943                                         *(dst++) = val[0] * 64 + val[1] * 8 + val[2];
6944                                         break;
6945 
6946                         default:        *(dst++) = src[i]; break;
6947                         }
6948                 }
6949         }
6950 
6951 return(dst - s);
6952 }
6953 
6954 
fstUtilityExtractEnumTableFromString(const char * s)6955 struct fstETab *fstUtilityExtractEnumTableFromString(const char *s)
6956 {
6957 struct fstETab *et = NULL;
6958 int num_spaces = 0;
6959 int i;
6960 int newlen;
6961 
6962 if(s)
6963 	{
6964 	const char *csp = strchr(s, ' ');
6965 	int cnt = atoi(csp+1);
6966 
6967 	for(;;)
6968 		{
6969 		csp = strchr(csp+1, ' ');
6970 		if(csp) { num_spaces++; } else { break; }
6971 		}
6972 
6973 	if(num_spaces == (2*cnt))
6974 		{
6975 		char *sp, *sp2;
6976 
6977 		et = (struct fstETab*)calloc(1, sizeof(struct fstETab));
6978 		et->elem_count = cnt;
6979 		et->name = strdup(s);
6980 		et->literal_arr = (char**)calloc(cnt, sizeof(char *));
6981 		et->val_arr = (char**)calloc(cnt, sizeof(char *));
6982 
6983 		sp = strchr(et->name, ' ');
6984 		*sp = 0;
6985 
6986 		sp = strchr(sp+1, ' ');
6987 
6988 		for(i=0;i<cnt;i++)
6989 			{
6990 			sp2 = strchr(sp+1, ' ');
6991 			*(char*)sp2 = 0;
6992 			et->literal_arr[i] = sp+1;
6993 			sp = sp2;
6994 
6995 			newlen = fstUtilityEscToBin(NULL, (unsigned char*)et->literal_arr[i], strlen(et->literal_arr[i]));
6996 			et->literal_arr[i][newlen] = 0;
6997 			}
6998 
6999 		for(i=0;i<cnt;i++)
7000 			{
7001 			sp2 = strchr(sp+1, ' ');
7002 			if(sp2) { *sp2 = 0; }
7003 			et->val_arr[i] = sp+1;
7004 			sp = sp2;
7005 
7006 			newlen = fstUtilityEscToBin(NULL, (unsigned char*)et->val_arr[i], strlen(et->val_arr[i]));
7007 			et->val_arr[i][newlen] = 0;
7008 			}
7009 		}
7010 	}
7011 
7012 return(et);
7013 }
7014 
7015 
fstUtilityFreeEnumTable(struct fstETab * etab)7016 void fstUtilityFreeEnumTable(struct fstETab *etab)
7017 {
7018 if(etab)
7019 	{
7020 	free(etab->literal_arr);
7021 	free(etab->val_arr);
7022 	free(etab->name);
7023 	free(etab);
7024 	}
7025 }
7026