LCOV - code coverage report
Current view: top level - clients/examples/C - bincopydata.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 206 232 88.8 %
Date: 2024-10-03 20:03:20 Functions: 19 20 95.0 %

          Line data    Source code
       1             : /*
       2             :  * SPDX-License-Identifier: MPL-2.0
       3             :  *
       4             :  * This Source Code Form is subject to the terms of the Mozilla Public
       5             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       6             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       7             :  *
       8             :  * Copyright 2024 MonetDB Foundation;
       9             :  * Copyright August 2008 - 2023 MonetDB B.V.;
      10             :  * Copyright 1997 - July 2008 CWI.
      11             :  */
      12             : 
      13             : #include "bincopydata.h"
      14             : 
      15             : #ifdef _MSC_VER
      16             : #include <io.h>
      17             : #include <fcntl.h>
      18             : #endif
      19             : 
      20             : static char *exe_name = "<to_be_filled_in>";
      21             : 
      22             : static void
      23           4 : gen_tinyints(FILE *f, bool byteswap, long nrecs, char *arg)
      24             : {
      25           4 :         (void)arg;
      26     4000004 :         for (long i = 0; i < nrecs; i++) {
      27     4000000 :                 uint8_t v = (uint8_t)i;
      28     4000000 :                 (void)byteswap;
      29     4000000 :                 fwrite(&v, sizeof(v), 1, f);
      30             :         }
      31           4 : }
      32             : 
      33             : static void
      34           8 : gen_smallints(FILE *f, bool byteswap, long nrecs, char *arg)
      35             : {
      36           8 :         (void)arg;
      37     4000056 :         for (long i = 0; i < nrecs; i++) {
      38     4000048 :                 uint16_t v = (uint16_t)i;
      39     4000048 :                 if (byteswap) {
      40     1000012 :                         copy_binary_convert16(&v);
      41             :                 }
      42     4000048 :                 fwrite(&v, sizeof(v), 1, f);
      43             :         }
      44           8 : }
      45             : 
      46             : static void
      47           4 : gen_bigints(FILE *f, bool byteswap, long nrecs, char *arg)
      48             : {
      49           4 :         (void)arg;
      50     4000004 :         for (long i = 0; i < nrecs; i++) {
      51     4000000 :                 uint64_t v = (uint64_t)i;
      52     4000000 :                 if (byteswap) {
      53     1000000 :                         copy_binary_convert64(&v);
      54             :                 }
      55     4000000 :                 fwrite(&v, sizeof(v), 1, f);
      56             :         }
      57           4 : }
      58             : 
      59             : #ifdef HAVE_HGE
      60             : static void
      61           1 : gen_hugeints(FILE *f, bool byteswap, long nrecs, char *arg)
      62             : {
      63           1 :         (void)arg;
      64     1000001 :         for (long i = 0; i < nrecs; i++) {
      65     1000000 :                 uhge v = (uhge)i;
      66     1000000 :                 if (byteswap) {
      67           0 :                         copy_binary_convert128(&v);
      68             :                 }
      69     1000000 :                 fwrite(&v, sizeof(v), 1, f);
      70             :         }
      71           1 : }
      72             : #endif
      73             : 
      74             : static void
      75           4 : gen_ints(FILE *f, bool byteswap, long nrecs, char *arg)
      76             : {
      77           4 :         (void)arg;
      78           4 :         assert((uintmax_t)nrecs <= (uintmax_t) UINT32_MAX);
      79           4 :         uint32_t n = (uint32_t) nrecs;
      80     4000004 :         for (uint32_t i = 0; i < n; i++) {
      81     4000000 :                 uint32_t v = i;
      82     4000000 :                 if (byteswap) {
      83     1000000 :                         copy_binary_convert32(&v);
      84             :                 }
      85     4000000 :                 fwrite(&v, sizeof(v), 1, f);
      86             :         }
      87           4 : }
      88             : 
      89             : static void
      90           1 : gen_more_ints(FILE *f, bool byteswap, long nrecs, char *arg)
      91             : {
      92           1 :         (void)arg;
      93           1 :         assert((uintmax_t)nrecs <= (uintmax_t) UINT32_MAX);
      94           1 :         uint32_t n = (uint32_t) nrecs;
      95     1000001 :         for (uint32_t i = 0; i < n; i++) {
      96     1000000 :                 uint32_t v = i + 1;
      97     1000000 :                 if (byteswap) {
      98           0 :                         copy_binary_convert32(&v);
      99             :                 }
     100     1000000 :                 fwrite(&v, sizeof(v), 1, f);
     101             :         }
     102           1 : }
     103             : 
     104             : static void
     105           1 : gen_null_ints(FILE *f, bool byteswap, long nrecs, char *arg)
     106             : {
     107           1 :         (void)arg;
     108           1 :         assert((uintmax_t)nrecs <= (uintmax_t) UINT32_MAX);
     109           1 :         uint32_t n = (uint32_t) nrecs;
     110           1 :         uint32_t nil = 0x80000000;
     111     1000001 :         for (uint32_t i = 0; i < n; i++) {
     112     1000000 :                 uint32_t v = i % 2 == 0 ? nil : i;
     113     1000000 :                 if (byteswap) {
     114           0 :                         copy_binary_convert32(&v);
     115             :                 }
     116     1000000 :                 fwrite(&v, sizeof(v), 1, f);
     117             :         }
     118           1 : }
     119             : 
     120             : static void
     121           1 : gen_bools(FILE *f, bool byteswap, long nrecs, char *arg)
     122             : {
     123           1 :         (void)arg;
     124     1000001 :         for (long i = 0; i < nrecs; i++) {
     125     1000000 :                 char b = i % 2;
     126     1000000 :                 (void)byteswap;
     127     1000000 :                 fwrite(&b, sizeof(b), 1, f);
     128             :         }
     129           1 : }
     130             : 
     131             : static void
     132           8 : gen_floats(FILE *f, bool byteswap, long nrecs, char *arg)
     133             : {
     134           8 :         (void)arg;
     135             :         // Assume for now that the raw bits are portable enough
     136             : 
     137     4000056 :         for (long i = 0; i < nrecs; i++) {
     138     4000048 :                 float fl = (float)i;
     139     4000048 :                 fl += 0.5;
     140     4000048 :                 if (byteswap)
     141     1000012 :                         copy_binary_convert32(&fl);
     142     4000048 :                 fwrite(&fl, sizeof(fl), 1, f);
     143             :         }
     144           8 : }
     145             : 
     146             : static void
     147           8 : gen_doubles(FILE *f, bool byteswap, long nrecs, char *arg)
     148             : {
     149           8 :         (void)arg;
     150             :         // Assume for now that the raw bits are portable enough
     151             : 
     152     4000056 :         for (long i = 0; i < nrecs; i++) {
     153     4000048 :                 double fl = (double)i;
     154     4000048 :                 fl += 0.5;
     155     4000048 :                 if (byteswap)
     156     1000012 :                         copy_binary_convert64(&fl);
     157     4000048 :                 fwrite(&fl, sizeof(fl), 1, f);
     158             :         }
     159           8 : }
     160             : 
     161             : static void
     162           1 : gen_strings(FILE *f, bool byteswap, long nrecs, char *arg)
     163             : {
     164           1 :         (void)arg;
     165           1 :         (void)byteswap;
     166     1000001 :         for (long i = 0; i < nrecs; i++) {
     167     1000000 :                 fprintf(f, "int%ld", i);
     168     1000000 :                 fputc(0, f);
     169             :         }
     170           1 : }
     171             : 
     172             : static void
     173           1 : gen_large_strings(FILE *f, bool byteswap, long nrecs, char *arg)
     174             : {
     175           1 :         (void)arg;
     176           1 :         size_t n = 280000;
     177           1 :         char *buf = malloc(n);
     178           1 :         memset(buf, 'a', n);
     179     1000001 :         for (long i = 0; i < nrecs; i++) {
     180     1000000 :                 fprintf(f, "int%06ld", i);
     181     1000000 :                 if (i % 10000 == 0)
     182         100 :                         fwrite(buf, n, 1, f);
     183     1000000 :                 fputc(0, f);
     184             :         }
     185           1 :         free(buf);
     186           1 :         (void)byteswap;
     187           1 : }
     188             : 
     189             : static void
     190           1 : gen_broken_strings(FILE *f, bool byteswap, long nrecs, char *arg)
     191             : {
     192           1 :         (void)arg;
     193             :         // "bröken"
     194           1 :         char utf8[] =   {0x62, 0x72,   0xc3, 0xb6,   0x6b, 0x65, 0x6e, 0x00};
     195           1 :         char latin1[] = {0x62, 0x72,   0xf6,         0x6b, 0x65, 0x6e, 0x00};
     196             : 
     197           1 :         (void)byteswap;
     198     1000001 :         for (long i = 0; i < nrecs; i++) {
     199     1000000 :                 if (i == 123456)
     200           1 :                         fwrite(latin1, sizeof(latin1), 1, f);
     201             :                 else
     202      999999 :                         fwrite(utf8, sizeof(utf8), 1, f);
     203             :         }
     204           1 : }
     205             : 
     206             : static void
     207           1 : gen_newline_strings(FILE *f, bool byteswap, long nrecs, char *arg)
     208             : {
     209           1 :         (void)arg;
     210           1 :         (void)byteswap;
     211     1000001 :         for (long i = 0; i < nrecs; i++) {
     212     1000000 :                 fprintf(f, "RN\r\nR\r%ld", i);
     213     1000000 :                 fputc(0, f);
     214             :         }
     215           1 : }
     216             : 
     217             : static void
     218           1 : gen_null_strings(FILE *f, bool byteswap, long nrecs, char *arg)
     219             : {
     220           1 :         (void)arg;
     221           1 :         (void)byteswap;
     222     1000001 :         for (long i = 0; i < nrecs; i++) {
     223     1000000 :                 if (i % 2 == 0)
     224      500000 :                         fputc(0x80, f);
     225             :                 else
     226      500000 :                         fputs("banana", f);
     227     1000000 :                 fputc(0, f);
     228             :         }
     229           1 : }
     230             : 
     231             : static void
     232           3 : gen_null_blobs(FILE *f, bool byteswap, long nrecs, char *arg)
     233             : {
     234           3 :         (void)arg;
     235           3 :         uint8_t *buffer = malloc(nrecs);
     236     3000003 :         for (long i = 0; i < nrecs; i++) {
     237     3000000 :                 buffer[i] = 0xD0 + 3 - (i % 3);
     238             :         }
     239             : 
     240     3000003 :         for (long i = 0; i < nrecs; i++) {
     241     3000000 :                 uint64_t header;
     242     3000000 :                 size_t n;
     243     3000000 :                 if (i % 3 == 2) {
     244             :                         // null
     245      999999 :                         n = 0;
     246      999999 :                         header = (uint64_t)-1;
     247             :                 } else {
     248     2000001 :                         n = (i % 1000);
     249     2000001 :                         header = n;
     250             :                 }
     251     3000000 :                 if (byteswap)
     252     1000000 :                         copy_binary_convert64(&header);
     253     3000000 :                 assert(sizeof(header) == 8);
     254     3000000 :                 fwrite(&header, sizeof(header), 1, f);
     255     3000000 :                 if (n > 0)
     256     1998000 :                         fwrite(buffer, 1, n, f);
     257             :         }
     258           3 :         free(buffer);
     259           3 : }
     260             : 
     261             : static void
     262           1 : gen_json(FILE *f, bool byteswap, long nrecs, char *arg)
     263             : {
     264           1 :         (void)arg;
     265           1 :         (void)byteswap;
     266     1000001 :         for (long i = 0; i < nrecs; i++) {
     267     1000000 :                 if (i % 100 == 99) {
     268       10000 :                         fputc('\x80', f);
     269             :                 } else {
     270      990000 :                         fprintf(f, "{\"id\":%ld,\"msg\":\"int%ld\"}", i, i);
     271             :                 }
     272     1000000 :                 fputc('\0', f);
     273             :         }
     274           1 : }
     275             : 
     276             : #define FUNCNAME gen_decimal_tinyints
     277             : #define STYP int8_t
     278             : #define UTYP uint8_t
     279             : // #define CONVERT
     280             : #include "bincopydecimal_impl.h"
     281             : 
     282             : #define FUNCNAME gen_decimal_smallints
     283             : #define STYP int16_t
     284             : #define UTYP uint16_t
     285             : #define CONVERT copy_binary_convert16
     286             : #include "bincopydecimal_impl.h"
     287             : 
     288             : #define FUNCNAME gen_decimal_ints
     289             : #define STYP int32_t
     290             : #define UTYP uint32_t
     291             : #define CONVERT copy_binary_convert32
     292             : #include "bincopydecimal_impl.h"
     293             : 
     294             : 
     295             : #define FUNCNAME gen_decimal_bigints
     296             : #define STYP int64_t
     297             : #define UTYP uint64_t
     298             : #define CONVERT copy_binary_convert64
     299             : #include "bincopydecimal_impl.h"
     300             : 
     301             : #ifdef HAVE_HGE
     302             :         #define FUNCNAME gen_decimal_hugeints
     303             :         #define STYP hge
     304             :         #define UTYP uhge
     305             :         #define CONVERT copy_binary_convert128
     306             :         #include "bincopydecimal_impl.h"
     307             : #endif
     308             : 
     309             : typedef void (*generator_t)(FILE *f, bool byteswap, long nrecs, char *argument);
     310             : 
     311             : static struct gen {
     312             :         char *name;
     313             :         generator_t gen;
     314             :         bool arg_allowed;
     315             : } generators[] = {
     316             :         { "ints", gen_ints },
     317             :         { "more_ints", gen_more_ints },
     318             :         { "null_ints", gen_null_ints },
     319             :         { "bools", gen_bools },
     320             :         { "floats", gen_floats },
     321             :         { "doubles", gen_doubles },
     322             :         { "tinyints", gen_tinyints },
     323             :         { "smallints", gen_smallints },
     324             :         { "bigints", gen_bigints },
     325             : #ifdef HAVE_HGE
     326             :         { "hugeints", gen_hugeints },
     327             : #endif
     328             :         //
     329             :         { "dec_tinyints", gen_decimal_tinyints, .arg_allowed=true },
     330             :         { "dec_smallints", gen_decimal_smallints, .arg_allowed=true },
     331             :         { "dec_ints", gen_decimal_ints, .arg_allowed=true },
     332             :         { "dec_bigints", gen_decimal_bigints, .arg_allowed=true },
     333             : #ifdef HAVE_HGE
     334             :         { "dec_hugeints", gen_decimal_hugeints, .arg_allowed=true },
     335             : #endif
     336             :         //
     337             :         { "strings", gen_strings },
     338             :         { "large_strings", gen_large_strings },
     339             :         { "broken_strings", gen_broken_strings },
     340             :         { "newline_strings", gen_newline_strings },
     341             :         { "null_strings", gen_null_strings },
     342             :         { "null_blobs", gen_null_blobs },
     343             :         //
     344             :         { "timestamps", gen_timestamps },
     345             :         { "timestamp_times", gen_timestamp_times },
     346             :         { "timestamp_dates", gen_timestamp_dates },
     347             :         { "timestamp_ms", gen_timestamp_ms },
     348             :         { "timestamp_seconds", gen_timestamp_seconds },
     349             :         { "timestamp_minutes", gen_timestamp_minutes },
     350             :         { "timestamp_hours", gen_timestamp_hours },
     351             :         { "timestamp_days", gen_timestamp_days },
     352             :         { "timestamp_months", gen_timestamp_months },
     353             :         { "timestamp_years", gen_timestamp_years },
     354             : 
     355             :         { "json_objects", gen_json },
     356             : 
     357             :         { "binary_uuids", gen_bin_uuids },
     358             :         { "text_uuids", gen_text_uuids },
     359             : 
     360             :         { NULL, NULL },
     361             : };
     362             : 
     363             : /* Format the message and write it to stderr. Then exit with the given status.
     364             :  * If status is 1, include USAGE in the message.
     365             :  * Otherwise, if errno is set, include the error message.
     366             :  */
     367             : void
     368           0 : croak(int status, const char *ctx, ...)
     369             : {
     370           0 :         va_list ap;
     371             : 
     372           0 :         fprintf(stderr, "Error: ");
     373           0 :         if (ctx != NULL) {
     374           0 :                 fprintf(stderr, " ");
     375           0 :                 va_start(ap, ctx);
     376           0 :                 vfprintf(stderr, ctx, ap);
     377           0 :                 va_end(ap);
     378             :         }
     379           0 :         fprintf(stderr, "\n");
     380           0 :         if (errno) {
     381           0 :                 fprintf(stderr, "Possibly due to: %s\n", strerror(errno));
     382           0 :         } else if (status == 1) {
     383           0 :                 fprintf(stderr, "USAGE: %s TYPE NRECS DESTFILE\n", exe_name);
     384           0 :                 fprintf(stderr, "TYPE:\n");
     385           0 :                 for (struct gen *g = generators; g->name != NULL; g++) {
     386           0 :                         fprintf(stderr, "  - %s\n", g->name);
     387             :                 }
     388             :         }
     389           0 :         exit(status);
     390             : }
     391             : 
     392             : static generator_t
     393          65 : pick_generator(const char *full_name, char **arg)
     394             : {
     395          65 :         char *name = strdup(full_name);
     396          65 :         *arg = NULL;
     397             : 
     398          65 :         char *sep = strchr(name, '!');
     399          65 :         if (sep != NULL) {
     400           4 :                 *arg = strdup(sep + 1);
     401           4 :                 *sep = '\0';
     402             :         }
     403             : 
     404          65 :         generator_t gen = NULL;
     405         806 :         for (struct gen *g = generators; g->name; g++) {
     406         806 :                 if (strcmp(g->name, name) == 0) {
     407          65 :                         if (*arg && !g->arg_allowed)
     408           0 :                                 croak(2, "Generator '%s' does not take arguments", name);
     409          65 :                         gen = g->gen;
     410          65 :                         break;
     411             :                 }
     412             :         }
     413             : 
     414          65 :         free(name);
     415             : 
     416          65 :         return gen;
     417             : }
     418             : 
     419             : 
     420             : int
     421          65 : main(int argc, char *argv[])
     422             : {
     423          65 :         exe_name = argv[0];
     424          65 :         generator_t gen;
     425          65 :         char *gen_arg = NULL;
     426          65 :         long nrecs;
     427          65 :         FILE *dest;
     428          65 :         bool byteswap = false;
     429          65 :         bool i_am_little_endian =
     430             : #ifdef WORDS_BIGENDIAN
     431             :                 false
     432             : #else
     433             :                 true
     434             : #endif
     435             :         ;
     436          65 :         bool i_am_big_endian = !i_am_little_endian;
     437             : 
     438          65 :         char **args = &argv[1];
     439          65 :         char **args_end = &argv[argc];
     440             : 
     441          94 :         while (args < args_end && **args == '-') {
     442          29 :                 char *arg = *args++;
     443          29 :                 if (strcmp(arg, "--native-endian") == 0)
     444             :                         byteswap = false;
     445          20 :                 else if (strcmp(arg, "--big-endian") == 0)
     446             :                         byteswap = i_am_little_endian;
     447          10 :                 else if (strcmp(arg, "--little-endian") == 0)
     448             :                         byteswap = i_am_big_endian;
     449             :                 else
     450           0 :                         croak(1, "Unexpected argument: %s", arg);
     451             :         }
     452             : 
     453          65 :         if (args_end - args != 3)
     454           0 :                 croak(1, "Unexpected number of arguments");
     455             : 
     456          65 :         gen = pick_generator(args[0], &gen_arg);
     457          65 :         if (gen == NULL)
     458           0 :                 croak(1, "Unknown TYPE: %s", args[0]);
     459             : 
     460          65 :         char *end;
     461          65 :         nrecs = strtol(args[1], &end, 10);
     462          65 :         if (*end != '\0')
     463           0 :                 croak(1, "NRECS must be an integer, not '%s'", args[1]);
     464             : 
     465          65 :         char *destfilename = args[2];
     466          65 :         if (strcmp(destfilename, "-") == 0) {
     467             : #ifdef _MSC_VER
     468             :                 _setmode(1, O_BINARY);
     469             : #endif
     470          12 :                 dest = stdout;
     471             :         } else {
     472          53 :                 dest = fopen(destfilename, "wb");
     473             :         }
     474             : 
     475          65 :         if (dest == NULL)
     476           0 :                 croak(2, "Cannot open '%s' for writing", args[2]);
     477             : 
     478          65 :         gen(dest, byteswap, nrecs, gen_arg);
     479             : 
     480          65 :         fclose(dest);
     481          65 :         free(gen_arg);
     482             : 
     483          65 :         return 0;
     484             : }

Generated by: LCOV version 1.14