fuzzer_parser_init:
   33|  1.81k|readstat_parser_t *fuzzer_parser_init(const uint8_t *Data, size_t Size) {
   34|  1.81k|    readstat_parser_t *parser = readstat_parser_init();
   35|  1.81k|    readstat_set_open_handler(parser, rt_open_handler);
   36|  1.81k|    readstat_set_close_handler(parser, rt_close_handler);
   37|  1.81k|    readstat_set_seek_handler(parser, rt_seek_handler);
   38|  1.81k|    readstat_set_read_handler(parser, rt_read_handler);
   39|  1.81k|    readstat_set_update_handler(parser, rt_update_handler);
   40|       |
   41|  1.81k|    readstat_set_metadata_handler(parser, &handle_metadata);
   42|  1.81k|    readstat_set_note_handler(parser, &handle_note);
   43|  1.81k|    readstat_set_variable_handler(parser, &handle_variable);
   44|  1.81k|    readstat_set_fweight_handler(parser, &handle_fweight);
   45|  1.81k|    readstat_set_value_handler(parser, &handle_value);
   46|  1.81k|    readstat_set_value_label_handler(parser, &handle_value_label);
   47|       |
   48|  1.81k|    return parser;
   49|  1.81k|}
fuzz_format.c:handle_metadata:
    8|  1.23k|static int handle_metadata(readstat_metadata_t *metadata, void *ctx) {
    9|  1.23k|    return READSTAT_HANDLER_OK;
  ------------------
  |  |   22|  1.23k|#define READSTAT_HANDLER_OK             0
  ------------------
   10|  1.23k|}
fuzz_format.c:handle_variable:
   21|  18.5k|                           const char *val_labels, void *ctx) {
   22|  18.5k|    return READSTAT_HANDLER_OK;
  ------------------
  |  |   22|  18.5k|#define READSTAT_HANDLER_OK             0
  ------------------
   23|  18.5k|}
fuzz_format.c:handle_value:
   25|  89.4k|static int handle_value(int obs_index, readstat_variable_t *variable, readstat_value_t value, void *ctx) {
   26|  89.4k|    return READSTAT_HANDLER_OK;
  ------------------
  |  |   22|  89.4k|#define READSTAT_HANDLER_OK             0
  ------------------
   27|  89.4k|}

LLVMFuzzerTestOneInput:
   10|  1.81k|int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
   11|  1.81k|    rt_buffer_t buffer = { .bytes = (char *)Data, .size = Size, .used = Size };
   12|  1.81k|    rt_buffer_ctx_t buffer_ctx = { .buffer = &buffer };
   13|       |
   14|  1.81k|    readstat_parser_t *parser = fuzzer_parser_init(Data, Size);
   15|  1.81k|    readstat_set_io_ctx(parser, &buffer_ctx);
   16|       |
   17|  1.81k|    readstat_parse_xport(parser, NULL, NULL);
   18|  1.81k|    readstat_parser_free(parser);
   19|  1.81k|    return 0;
   20|  1.81k|}

machine_is_little_endian:
   11|   211k|int machine_is_little_endian(void) {
   12|   211k|    int test_byte_order = 1;
   13|   211k|    return ((char *)&test_byte_order)[0];
   14|   211k|}
byteswap2:
   40|   972k|uint16_t byteswap2(uint16_t num) {
   41|   972k|    return ((num & 0xFF00) >> 8) | ((num & 0x00FF) << 8);
   42|   972k|}
byteswap4:
   44|  96.9k|uint32_t byteswap4(uint32_t num) {
   45|  96.9k|    num = ((num & 0xFFFF0000) >> 16) | ((num & 0x0000FFFF) << 16);
   46|  96.9k|    return ((num & 0xFF00FF00) >> 8) | ((num & 0x00FF00FF) << 8);
   47|  96.9k|}

readstat_convert:
   39|   433k|readstat_error_t readstat_convert(char *dst, size_t dst_len, const char *src, size_t src_len, iconv_t converter) {
   40|   433k|    return readstat_convert_impl(dst, dst_len, src, src_len, converter, 1);
   41|   433k|}
readstat_convert.c:readstat_convert_impl:
    8|   433k|        iconv_t converter, int trim_spaces) {
    9|       |    /* strip off spaces from the input because the programs use ASCII space
   10|       |     * padding even with non-ASCII encoding. */
   11|  6.66M|    while (src_len && ((trim_spaces && src[src_len-1] == ' ') || src[src_len-1] == '\0')) {
  ------------------
  |  Branch (11:12): [True: 6.39M, False: 272k]
  |  Branch (11:25): [True: 6.39M, False: 0]
  |  Branch (11:40): [True: 3.19M, False: 3.19M]
  |  Branch (11:66): [True: 3.03M, False: 160k]
  ------------------
   12|  6.23M|        src_len--;
   13|  6.23M|    }
   14|   433k|    if (dst_len == 0) {
  ------------------
  |  Branch (14:9): [True: 0, False: 433k]
  ------------------
   15|      0|        return READSTAT_ERROR_CONVERT_LONG_STRING;
   16|   433k|    } else if (converter) {
  ------------------
  |  Branch (16:16): [True: 0, False: 433k]
  ------------------
   17|      0|        size_t dst_left = dst_len - 1;
   18|      0|        char *dst_end = dst;
   19|      0|        size_t status = iconv(converter, (readstat_iconv_inbuf_t)&src, &src_len, &dst_end, &dst_left);
   20|      0|        if (status == (size_t)-1) {
  ------------------
  |  Branch (20:13): [True: 0, False: 0]
  ------------------
   21|      0|            if (errno == E2BIG) {
  ------------------
  |  Branch (21:17): [True: 0, False: 0]
  ------------------
   22|      0|                return READSTAT_ERROR_CONVERT_LONG_STRING;
   23|      0|            } else if (errno == EILSEQ) {
  ------------------
  |  Branch (23:24): [True: 0, False: 0]
  ------------------
   24|      0|                return READSTAT_ERROR_CONVERT_BAD_STRING;
   25|      0|            } else if (errno != EINVAL) { /* EINVAL indicates improper truncation; accept it */
  ------------------
  |  Branch (25:24): [True: 0, False: 0]
  ------------------
   26|      0|                return READSTAT_ERROR_CONVERT;
   27|      0|            }
   28|      0|        }
   29|      0|        dst[dst_len - dst_left - 1] = '\0';
   30|   433k|    } else if (src_len + 1 > dst_len) {
  ------------------
  |  Branch (30:16): [True: 23, False: 433k]
  ------------------
   31|     23|        return READSTAT_ERROR_CONVERT_LONG_STRING;
   32|   433k|    } else {
   33|   433k|        memcpy(dst, src, src_len);
   34|   433k|        dst[src_len] = '\0';
   35|   433k|    }
   36|   433k|    return READSTAT_OK;
   37|   433k|}

unistd_io_init:
  121|  1.81k|readstat_error_t unistd_io_init(readstat_parser_t *parser) {
  122|  1.81k|    readstat_error_t retval = READSTAT_OK;
  123|  1.81k|    unistd_io_ctx_t *io_ctx = NULL;
  124|       |
  125|  1.81k|    if ((retval = readstat_set_open_handler(parser, unistd_open_handler)) != READSTAT_OK)
  ------------------
  |  Branch (125:9): [True: 0, False: 1.81k]
  ------------------
  126|      0|        return retval;
  127|       |
  128|  1.81k|    if ((retval = readstat_set_close_handler(parser, unistd_close_handler)) != READSTAT_OK)
  ------------------
  |  Branch (128:9): [True: 0, False: 1.81k]
  ------------------
  129|      0|        return retval;
  130|       |
  131|  1.81k|    if ((retval = readstat_set_seek_handler(parser, unistd_seek_handler)) != READSTAT_OK)
  ------------------
  |  Branch (131:9): [True: 0, False: 1.81k]
  ------------------
  132|      0|        return retval;
  133|       |
  134|  1.81k|    if ((retval = readstat_set_read_handler(parser, unistd_read_handler)) != READSTAT_OK)
  ------------------
  |  Branch (134:9): [True: 0, False: 1.81k]
  ------------------
  135|      0|        return retval;
  136|       |
  137|  1.81k|    if ((readstat_set_update_handler(parser, unistd_update_handler)) != READSTAT_OK)
  ------------------
  |  Branch (137:9): [True: 0, False: 1.81k]
  ------------------
  138|      0|        return retval;
  139|       |
  140|  1.81k|    io_ctx = calloc(1, sizeof(unistd_io_ctx_t));
  141|  1.81k|    io_ctx->fd = -1;
  142|       |
  143|  1.81k|    retval = readstat_set_io_ctx(parser, (void*) io_ctx);
  144|  1.81k|    parser->io->io_ctx_needs_free = 1;
  145|       |
  146|  1.81k|    return retval;
  147|  1.81k|}

readstat_malloc:
   10|  1.26k|void *readstat_malloc(size_t len) {
   11|  1.26k|    if (len > MAX_MALLOC_SIZE || len == 0) {
  ------------------
  |  |    3|  2.52k|#define MAX_MALLOC_SIZE 0x1000000
  ------------------
  |  Branch (11:9): [True: 12, False: 1.25k]
  |  Branch (11:34): [True: 0, False: 1.25k]
  ------------------
   12|     12|        return NULL;
   13|     12|    }
   14|  1.25k|    return malloc(len);
   15|  1.26k|}
readstat_calloc:
   17|  1.25k|void *readstat_calloc(size_t count, size_t size) {
   18|  1.25k|    if (count > MAX_MALLOC_SIZE || size > MAX_MALLOC_SIZE || count * size > MAX_MALLOC_SIZE) {
  ------------------
  |  |    3|  2.50k|#define MAX_MALLOC_SIZE 0x1000000
  ------------------
                  if (count > MAX_MALLOC_SIZE || size > MAX_MALLOC_SIZE || count * size > MAX_MALLOC_SIZE) {
  ------------------
  |  |    3|  2.49k|#define MAX_MALLOC_SIZE 0x1000000
  ------------------
                  if (count > MAX_MALLOC_SIZE || size > MAX_MALLOC_SIZE || count * size > MAX_MALLOC_SIZE) {
  ------------------
  |  |    3|  1.23k|#define MAX_MALLOC_SIZE 0x1000000
  ------------------
  |  Branch (18:9): [True: 14, False: 1.23k]
  |  Branch (18:36): [True: 0, False: 1.23k]
  |  Branch (18:62): [True: 0, False: 1.23k]
  ------------------
   19|     14|        return NULL;
   20|     14|    }
   21|  1.23k|    if (count == 0 || size == 0) {
  ------------------
  |  Branch (21:9): [True: 1, False: 1.23k]
  |  Branch (21:23): [True: 0, False: 1.23k]
  ------------------
   22|      1|        return NULL;
   23|      1|    }
   24|  1.23k|    return calloc(count, size);
   25|  1.23k|}
readstat_realloc:
   27|  40.3k|void *readstat_realloc(void *ptr, size_t len) {
   28|  40.3k|    if (len > MAX_MALLOC_SIZE || len == 0) {
  ------------------
  |  |    3|  80.7k|#define MAX_MALLOC_SIZE 0x1000000
  ------------------
  |  Branch (28:9): [True: 0, False: 40.3k]
  |  Branch (28:34): [True: 0, False: 40.3k]
  ------------------
   29|      0|        if (ptr)
  ------------------
  |  Branch (29:13): [True: 0, False: 0]
  ------------------
   30|      0|            free(ptr);
   31|      0|        return NULL;
   32|      0|    }
   33|  40.3k|    return realloc(ptr, len);
   34|  40.3k|}

readstat_parser_init:
    6|  1.81k|readstat_parser_t *readstat_parser_init(void) {
    7|  1.81k|    readstat_parser_t *parser = calloc(1, sizeof(readstat_parser_t));
    8|  1.81k|    parser->io = calloc(1, sizeof(readstat_io_t));
    9|  1.81k|    if (unistd_io_init(parser) != READSTAT_OK) {
  ------------------
  |  Branch (9:9): [True: 0, False: 1.81k]
  ------------------
   10|      0|        readstat_parser_free(parser);
   11|      0|        return NULL;
   12|      0|    }
   13|  1.81k|    parser->output_encoding = "UTF-8";
   14|  1.81k|    return parser;
   15|  1.81k|}
readstat_parser_free:
   17|  1.81k|void readstat_parser_free(readstat_parser_t *parser) {
   18|  1.81k|    if (parser) {
  ------------------
  |  Branch (18:9): [True: 1.81k, False: 0]
  ------------------
   19|  1.81k|        if (parser->io) {
  ------------------
  |  Branch (19:13): [True: 1.81k, False: 0]
  ------------------
   20|       |            readstat_set_io_ctx(parser, NULL);
   21|  1.81k|            free(parser->io);
   22|  1.81k|        }
   23|  1.81k|        free(parser);
   24|  1.81k|    }
   25|  1.81k|}
readstat_set_metadata_handler:
   27|  1.81k|readstat_error_t readstat_set_metadata_handler(readstat_parser_t *parser, readstat_metadata_handler metadata_handler) {
   28|  1.81k|    parser->handlers.metadata = metadata_handler;
   29|  1.81k|    return READSTAT_OK;
   30|  1.81k|}
readstat_set_note_handler:
   32|  1.81k|readstat_error_t readstat_set_note_handler(readstat_parser_t *parser, readstat_note_handler note_handler) {
   33|  1.81k|    parser->handlers.note = note_handler;
   34|  1.81k|    return READSTAT_OK;
   35|  1.81k|}
readstat_set_variable_handler:
   37|  1.81k|readstat_error_t readstat_set_variable_handler(readstat_parser_t *parser, readstat_variable_handler variable_handler) {
   38|  1.81k|    parser->handlers.variable = variable_handler;
   39|  1.81k|    return READSTAT_OK;
   40|  1.81k|}
readstat_set_value_handler:
   42|  1.81k|readstat_error_t readstat_set_value_handler(readstat_parser_t *parser, readstat_value_handler value_handler) {
   43|  1.81k|    parser->handlers.value = value_handler;
   44|  1.81k|    return READSTAT_OK;
   45|  1.81k|}
readstat_set_value_label_handler:
   47|  1.81k|readstat_error_t readstat_set_value_label_handler(readstat_parser_t *parser, readstat_value_label_handler label_handler) {
   48|  1.81k|    parser->handlers.value_label = label_handler;
   49|  1.81k|    return READSTAT_OK;
   50|  1.81k|}
readstat_set_fweight_handler:
   62|  1.81k|readstat_error_t readstat_set_fweight_handler(readstat_parser_t *parser, readstat_fweight_handler fweight_handler) {
   63|  1.81k|    parser->handlers.fweight = fweight_handler;
   64|  1.81k|    return READSTAT_OK;
   65|  1.81k|}
readstat_set_open_handler:
   67|  3.62k|readstat_error_t readstat_set_open_handler(readstat_parser_t *parser, readstat_open_handler open_handler) {
   68|  3.62k|    parser->io->open = open_handler;
   69|  3.62k|    return READSTAT_OK;
   70|  3.62k|}
readstat_set_close_handler:
   72|  3.62k|readstat_error_t readstat_set_close_handler(readstat_parser_t *parser, readstat_close_handler close_handler) {
   73|  3.62k|    parser->io->close = close_handler;
   74|  3.62k|    return READSTAT_OK;
   75|  3.62k|}
readstat_set_seek_handler:
   77|  3.62k|readstat_error_t readstat_set_seek_handler(readstat_parser_t *parser, readstat_seek_handler seek_handler) {
   78|  3.62k|    parser->io->seek = seek_handler;
   79|  3.62k|    return READSTAT_OK;
   80|  3.62k|}
readstat_set_read_handler:
   82|  3.62k|readstat_error_t readstat_set_read_handler(readstat_parser_t *parser, readstat_read_handler read_handler) {
   83|  3.62k|    parser->io->read = read_handler;
   84|  3.62k|    return READSTAT_OK;
   85|  3.62k|}
readstat_set_update_handler:
   87|  3.62k|readstat_error_t readstat_set_update_handler(readstat_parser_t *parser, readstat_update_handler update_handler) {
   88|  3.62k|    parser->io->update = update_handler;
   89|  3.62k|    return READSTAT_OK;
   90|  3.62k|}
readstat_set_io_ctx:
   92|  5.43k|readstat_error_t readstat_set_io_ctx(readstat_parser_t *parser, void *io_ctx) {
   93|  5.43k|    if (parser->io->io_ctx_needs_free) {
  ------------------
  |  Branch (93:9): [True: 1.81k, False: 3.62k]
  ------------------
   94|  1.81k|        free(parser->io->io_ctx);
   95|  1.81k|    }
   96|       |
   97|  5.43k|    parser->io->io_ctx = io_ctx;
   98|  5.43k|    parser->io->io_ctx_needs_free = 0;
   99|       |
  100|  5.43k|    return READSTAT_OK;
  101|  5.43k|}

memreverse:
   22|   113k|void memreverse(void *intp_void, int l) {
   23|   113k|    if (!machine_is_little_endian())
  ------------------
  |  Branch (23:9): [True: 0, False: 113k]
  ------------------
   24|      0|        return;
   25|       |
   26|   113k|    int i,j;
   27|   113k|    char save;
   28|   113k|    char *intp = (char *)intp_void;
   29|       |
   30|   113k|    j = l/2;
   31|   340k|    for (i=0;i<j;i++) {
  ------------------
  |  Branch (31:14): [True: 227k, False: 113k]
  ------------------
   32|   227k|        save = intp[i];
   33|   227k|        intp[i] = intp[l-i-1];
   34|   227k|        intp[l-i-1] = save;
   35|   227k|    }
   36|   113k|}
cnxptiee:
   39|  45.5k|{
   40|  45.5k|    unsigned char *from = (unsigned char *)from_bytes;
   41|  45.5k|    unsigned char *to = (unsigned char *)to_bytes;
   42|  45.5k|    unsigned char temp[8];
   43|  45.5k|    int i;
   44|       |
   45|  45.5k|    if (fromtype == CN_TYPE_NATIVE) {
  ------------------
  |  |    1|  45.5k|#define CN_TYPE_NATIVE 0
  ------------------
  |  Branch (45:9): [True: 0, False: 45.5k]
  ------------------
   46|      0|        fromtype = FLOATREP;
  ------------------
  |  |   18|      0|#define FLOATREP get_native()
  ------------------
   47|      0|    }
   48|  45.5k|    switch(fromtype) {
   49|      0|        case CN_TYPE_IEEEL :
  ------------------
  |  |    4|      0|#define CN_TYPE_IEEEL 3
  ------------------
  |  Branch (49:9): [True: 0, False: 45.5k]
  ------------------
   50|      0|            if (totype == CN_TYPE_IEEEL)
  ------------------
  |  |    4|      0|#define CN_TYPE_IEEEL 3
  ------------------
  |  Branch (50:17): [True: 0, False: 0]
  ------------------
   51|      0|                break;
   52|      0|            for (i=7;i>=0;i--) {
  ------------------
  |  Branch (52:22): [True: 0, False: 0]
  ------------------
   53|      0|                temp[7-i] = from[i];
   54|      0|            }
   55|      0|            from = temp;
   56|      0|            fromtype = CN_TYPE_IEEEB;
  ------------------
  |  |    3|      0|#define CN_TYPE_IEEEB 2
  ------------------
   57|       |            /* Break intentionally omitted. */
   58|      0|        case CN_TYPE_IEEEB :
  ------------------
  |  |    3|      0|#define CN_TYPE_IEEEB 2
  ------------------
  |  Branch (58:9): [True: 0, False: 45.5k]
  ------------------
   59|       |            /* Break intentionally omitted. */
   60|  45.5k|        case CN_TYPE_XPORT :
  ------------------
  |  |    2|  45.5k|#define CN_TYPE_XPORT 1
  ------------------
  |  Branch (60:9): [True: 45.5k, False: 0]
  ------------------
   61|  45.5k|            break;
   62|      0|        default:
  ------------------
  |  Branch (62:9): [True: 0, False: 45.5k]
  ------------------
   63|      0|            return(-1);
   64|  45.5k|    }
   65|  45.5k|    if (totype == CN_TYPE_NATIVE) {
  ------------------
  |  |    1|  45.5k|#define CN_TYPE_NATIVE 0
  ------------------
  |  Branch (65:9): [True: 45.5k, False: 0]
  ------------------
   66|  45.5k|        totype = FLOATREP;
  ------------------
  |  |   18|  45.5k|#define FLOATREP get_native()
  ------------------
   67|  45.5k|    }
   68|  45.5k|    switch(totype) {
   69|      0|        case CN_TYPE_XPORT :
  ------------------
  |  |    2|      0|#define CN_TYPE_XPORT 1
  ------------------
  |  Branch (69:9): [True: 0, False: 45.5k]
  ------------------
   70|      0|        case CN_TYPE_IEEEB :
  ------------------
  |  |    3|      0|#define CN_TYPE_IEEEB 2
  ------------------
  |  Branch (70:9): [True: 0, False: 45.5k]
  ------------------
   71|  45.5k|        case CN_TYPE_IEEEL :
  ------------------
  |  |    4|  45.5k|#define CN_TYPE_IEEEL 3
  ------------------
  |  Branch (71:9): [True: 45.5k, False: 0]
  ------------------
   72|  45.5k|            break;
   73|      0|        default:
  ------------------
  |  Branch (73:9): [True: 0, False: 45.5k]
  ------------------
   74|      0|            return(-2);
   75|  45.5k|    }
   76|  45.5k|    if (fromtype == totype) {
  ------------------
  |  Branch (76:9): [True: 0, False: 45.5k]
  ------------------
   77|      0|        memcpy(to,from,8);
   78|      0|        return(0);
   79|      0|    }
   80|  45.5k|    switch(fromtype) {
  ------------------
  |  Branch (80:12): [True: 45.5k, False: 0]
  ------------------
   81|      0|        case CN_TYPE_IEEEB :
  ------------------
  |  |    3|      0|#define CN_TYPE_IEEEB 2
  ------------------
  |  Branch (81:9): [True: 0, False: 45.5k]
  ------------------
   82|      0|            if (totype == CN_TYPE_XPORT)
  ------------------
  |  |    2|      0|#define CN_TYPE_XPORT 1
  ------------------
  |  Branch (82:17): [True: 0, False: 0]
  ------------------
   83|      0|                ieee2xpt(from,to);
   84|      0|            else memcpy(to,from,8);
   85|      0|            break;
   86|  45.5k|        case CN_TYPE_XPORT :
  ------------------
  |  |    2|  45.5k|#define CN_TYPE_XPORT 1
  ------------------
  |  Branch (86:9): [True: 45.5k, False: 0]
  ------------------
   87|  45.5k|            xpt2ieee(from,to);
   88|  45.5k|            break;
   89|  45.5k|    }
   90|  45.5k|    if (totype == CN_TYPE_IEEEL) {
  ------------------
  |  |    4|  45.5k|#define CN_TYPE_IEEEL 3
  ------------------
  |  Branch (90:9): [True: 45.5k, False: 0]
  ------------------
   91|  45.5k|        memcpy(temp,to,8);
   92|   409k|        for (i=7;i>=0;i--) {
  ------------------
  |  Branch (92:18): [True: 364k, False: 45.5k]
  ------------------
   93|   364k|            to[7-i] = temp[i];
   94|   364k|        }
   95|  45.5k|    }
   96|  45.5k|    return(0);
   97|  45.5k|}
get_native:
   99|  45.5k|int get_native(void) {
  100|  45.5k|    static unsigned char float_reps[][8] = {
  101|  45.5k|        {0x41,0x10,0x00,0x00,0x00,0x00,0x00,0x00},
  102|  45.5k|        {0x3f,0xf0,0x00,0x00,0x00,0x00,0x00,0x00},
  103|  45.5k|        {0x00,0x00,0x00,0x00,0x00,0x00,0xf0,0x3f}
  104|  45.5k|    };
  105|       |
  106|  45.5k|    static double one = 1.00;
  107|       |
  108|  45.5k|    int i,j;
  109|  45.5k|    j = sizeof(float_reps)/8;
  110|   136k|    for (i=0;i<j;i++)  {
  ------------------
  |  Branch (110:14): [True: 136k, False: 0]
  ------------------
  111|   136k|        if (memcmp(&one,float_reps+i,8) == 0)
  ------------------
  |  Branch (111:13): [True: 45.5k, False: 91.0k]
  ------------------
  112|  45.5k|            return(i+1);
  113|   136k|    }
  114|      0|    return(-1);
  115|  45.5k|}
ieee.c:xpt2ieee:
  117|  45.5k|void xpt2ieee(unsigned char *xport, unsigned char *ieee) {
  118|  45.5k|    char temp[8];
  119|  45.5k|    register int shift;
  120|  45.5k|    register int nib;
  121|  45.5k|    uint32_t ieee1,ieee2;
  122|  45.5k|    uint32_t xport1 = 0;
  123|  45.5k|    uint32_t xport2 = 0;
  124|       |
  125|  45.5k|    memcpy(temp,xport,8);
  126|  45.5k|    memset(ieee,0,8);
  127|       |
  128|  45.5k|    if (*temp && memcmp(temp+1,ieee,7) == 0) {
  ------------------
  |  Branch (128:9): [True: 11.4k, False: 34.0k]
  |  Branch (128:18): [True: 246, False: 11.2k]
  ------------------
  129|    246|        ieee[0] = ieee[1] = 0xff;
  130|    246|        ieee[2] = ~(*temp);
  131|    246|        return;
  132|    246|    }
  133|       |
  134|  45.2k|    memcpy(&xport1,temp,sizeof(uint32_t));
  135|  45.2k|    memreverse(&xport1,sizeof(uint32_t));
  136|  45.2k|    memcpy(&xport2,temp+4,sizeof(uint32_t));
  137|  45.2k|    memreverse(&xport2,sizeof(uint32_t));
  138|       |
  139|       |    /***************************************************************/
  140|       |    /* Translate IBM format floating point numbers into IEEE */
  141|       |    /* format floating point numbers. */
  142|       |    /* */
  143|       |    /* IEEE format: */
  144|       |    /* */
  145|       |    /* 6 5 0 */
  146|       |    /* 3 1 0 */
  147|       |    /* */
  148|       |    /* SEEEEEEEEEEEMMMM ............ MMMM */
  149|       |    /* */
  150|       |    /* Sign bit, 11 bits exponent, 52 bit fraction. Exponent is */
  151|       |    /* excess 1023. The fraction is multiplied by a power of 2 of */
  152|       |
  153|       |    /* the actual exponent. Normalized floating point numbers are */
  154|       |    /* represented with the binary point immediately to the left */
  155|       |    /* of the fraction with an implied "1" to the left of the */
  156|       |    /* binary point. */
  157|       |    /* */
  158|       |    /* IBM format: */
  159|       |    /* */
  160|       |    /* 6 5 0 */
  161|       |    /* 3 1 0 */
  162|       |    /* */
  163|       |    /* SEEEEEEEMMMM ......... MMMM */
  164|       |    /* */
  165|       |    /* Sign bit, 7 bit exponent, 56 bit fraction. Exponent is */
  166|       |    /* excess 64. The fraction is multiplied bya power of 16 of */
  167|       |    /* the actual exponent. Normalized floating point numbers are */
  168|       |    /* represented with the radix point immediately to the left of*/
  169|       |    /* the high order hex fraction digit. */
  170|       |    /* */
  171|       |    /* How do you translate from IBM format to IEEE? */
  172|       |    /* */
  173|       |    /* Translating back to ieee format from ibm is easier than */
  174|       |    /* going the other way. You lose at most, 3 bits of fraction, */
  175|       |    /* but nothing can be done about that. The only tricky parts */
  176|       |    /* are setting up the correct binary exponent from the ibm */
  177|       |    /* hex exponent, and removing the implicit "1" bit of the ieee*/
  178|       |    /* fraction (see vzctdbl). We must shift down the high order */
  179|       |    /* nibble of the ibm fraction until it is 1. This is the */
  180|       |    /* implicit 1. The bit is then cleared and the exponent */
  181|       |    /* adjusted by the number of positions shifted. A more */
  182|       |    /* thorough discussion is in vzctdbl.c. */
  183|       |
  184|  45.2k|    if ((xport1 & 0x7fffffff) == 0x7fffffff && xport2 == 0xffffffff) {
  ------------------
  |  Branch (184:9): [True: 662, False: 44.5k]
  |  Branch (184:48): [True: 194, False: 468]
  ------------------
  185|    194|        ieee1 = (xport1 & 0x80000000) | 0x7ff00000;
  186|    194|        ieee2 = 0;
  187|    194|        goto doret;
  188|    194|    }
  189|       |
  190|       |    /* Get the first half of the ibm number without the exponent */
  191|       |    /* into the ieee number */
  192|  45.0k|    ieee1 = xport1 & 0x00ffffff;
  193|       |
  194|       |    /* get the second half of the ibm number into the second half */
  195|       |    /* of the ieee number . If both halves were 0. then just */
  196|       |    /* return since the ieee number is zero. */
  197|  45.0k|    if ((!(ieee2 = xport2)) && !xport1)
  ------------------
  |  Branch (197:9): [True: 40.9k, False: 4.11k]
  |  Branch (197:32): [True: 33.7k, False: 7.19k]
  ------------------
  198|  33.7k|        return;
  199|       |
  200|       |    /* The fraction bit to the left of the binary point in the */
  201|       |    /* ieee format was set and the number was shifted 0, 1, 2, or */
  202|       |    /* 3 places. This will tell us how to adjust the ibm exponent */
  203|       |    /* to be a power of 2 ieee exponent and how to shift the */
  204|       |    /* fraction bits to restore the correct magnitude. */
  205|       |
  206|  11.3k|    if ((nib = (int)xport1) & 0x00800000) {
  ------------------
  |  Branch (206:9): [True: 2.80k, False: 8.50k]
  ------------------
  207|  2.80k|        shift = 3;
  208|  8.50k|    } else if (nib & 0x00400000) {
  ------------------
  |  Branch (208:16): [True: 820, False: 7.68k]
  ------------------
  209|    820|        shift = 2;
  210|  7.68k|    } else if (nib & 0x00200000) {
  ------------------
  |  Branch (210:16): [True: 7.14k, False: 538]
  ------------------
  211|  7.14k|        shift = 1;
  212|  7.14k|    } else {
  213|    538|        shift = 0;
  214|    538|    }
  215|       |
  216|  11.3k|    if (shift) {
  ------------------
  |  Branch (216:9): [True: 10.7k, False: 538]
  ------------------
  217|       |        /* shift the ieee number down the correct number of places */
  218|       |        /* then set the second half of the ieee number to be the */
  219|       |        /* second half of the ibm number shifted appropriately, */
  220|       |        /* ored with the bits from the first half that would have */
  221|       |        /* been shifted in if we could shift a double. All we are */
  222|       |        /* worried about are the low order 3 bits of the first */
  223|       |        /* half since we're only shifting by 1, 2, or 3. */
  224|  10.7k|        ieee1 >>= shift;
  225|  10.7k|        ieee2 = (xport2 >> shift) |
  226|  10.7k|            ((xport1 & 0x00000007) << (29 + (3 - shift)));
  227|  10.7k|    }
  228|       |
  229|       |    /* clear the 1 bit to the left of the binary point */
  230|  11.3k|    ieee1 &= 0xffefffff;
  231|       |
  232|       |    /* set the exponent of the ieee number to be the actual */
  233|       |    /* exponent plus the shift count + 1023. Or this into the */
  234|       |    /* first half of the ieee number. The ibm exponent is excess */
  235|       |    /* 64 but is adjusted by 65 since during conversion to ibm */
  236|       |    /* format the exponent is incremented by 1 and the fraction */
  237|       |    /* bits left 4 positions to the right of the radix point. */
  238|  11.3k|    ieee1 |=
  239|  11.3k|        (((((int32_t)(*temp & 0x7f) - 65) * 4) + shift + 1023) << 20) |
  240|  11.3k|        (xport1 & 0x80000000);
  241|       |
  242|  11.5k|doret:
  243|  11.5k|    memreverse(&ieee1,sizeof(uint32_t));
  244|  11.5k|    memcpy(ieee,&ieee1,sizeof(uint32_t));
  245|  11.5k|    memreverse(&ieee2,sizeof(uint32_t));
  246|  11.5k|    memcpy(ieee+4,&ieee2,sizeof(uint32_t));
  247|  11.5k|    return;
  248|  11.3k|}

sas_validate_tag:
  600|  34.3k|readstat_error_t sas_validate_tag(char tag) {
  601|  34.3k|    if (tag == '_' || (tag >= 'A' && tag <= 'Z'))
  ------------------
  |  Branch (601:9): [True: 195, False: 34.2k]
  |  Branch (601:24): [True: 414, False: 33.7k]
  |  Branch (601:38): [True: 205, False: 209]
  ------------------
  602|    400|        return READSTAT_OK;
  603|       |
  604|  33.9k|    return READSTAT_ERROR_TAGGED_VALUE_IS_OUT_OF_RANGE;
  605|  34.3k|}

xport_namestr_bswap:
   10|  96.9k|void xport_namestr_bswap(xport_namestr_t *namestr) {
   11|  96.9k|    if (!machine_is_little_endian())
  ------------------
  |  Branch (11:9): [True: 0, False: 96.9k]
  ------------------
   12|      0|        return;
   13|       |
   14|  96.9k|    namestr->ntype = byteswap2(namestr->ntype);
   15|  96.9k|    namestr->nhfun = byteswap2(namestr->nhfun);
   16|  96.9k|    namestr->nlng = byteswap2(namestr->nlng);
   17|  96.9k|    namestr->nvar0 = byteswap2(namestr->nvar0);
   18|       |
   19|  96.9k|    namestr->nfl = byteswap2(namestr->nfl);
   20|  96.9k|    namestr->nfd = byteswap2(namestr->nfd);
   21|  96.9k|    namestr->nfj = byteswap2(namestr->nfj);
   22|       |
   23|  96.9k|    namestr->nifl = byteswap2(namestr->nifl);
   24|  96.9k|    namestr->nifd = byteswap2(namestr->nifd);
   25|  96.9k|    namestr->npos = byteswap4(namestr->npos);
   26|       |
   27|  96.9k|    namestr->labeln  = byteswap2(namestr->labeln);
   28|  96.9k|}

readstat_parse_xport:
  757|  1.81k|readstat_error_t readstat_parse_xport(readstat_parser_t *parser, const char *path, void *user_ctx) {
  758|  1.81k|    readstat_error_t retval = READSTAT_OK;
  759|  1.81k|    readstat_io_t *io = parser->io;
  760|       |
  761|  1.81k|    xport_ctx_t *ctx = xport_ctx_init();
  762|  1.81k|    ctx->handle = parser->handlers;
  763|  1.81k|    ctx->input_encoding = parser->input_encoding;
  764|  1.81k|    ctx->output_encoding = parser->output_encoding;
  765|  1.81k|    ctx->user_ctx = user_ctx;
  766|  1.81k|    ctx->io = io;
  767|  1.81k|    ctx->row_limit = parser->row_limit;
  768|  1.81k|    if (parser->row_offset > 0)
  ------------------
  |  Branch (768:9): [True: 0, False: 1.81k]
  ------------------
  769|      0|        ctx->row_offset = parser->row_offset;
  770|       |
  771|  1.81k|    if (io->open(path, io->io_ctx) == -1) {
  ------------------
  |  Branch (771:9): [True: 0, False: 1.81k]
  ------------------
  772|      0|        retval = READSTAT_ERROR_OPEN;
  773|      0|        goto cleanup;
  774|      0|    }
  775|       |
  776|  1.81k|    if ((ctx->file_size = io->seek(0, READSTAT_SEEK_END, io->io_ctx)) == -1) {
  ------------------
  |  Branch (776:9): [True: 0, False: 1.81k]
  ------------------
  777|      0|        retval = READSTAT_ERROR_SEEK;
  778|      0|        goto cleanup;
  779|      0|    }
  780|       |
  781|  1.81k|    if (io->seek(0, READSTAT_SEEK_SET, io->io_ctx) == -1) {
  ------------------
  |  Branch (781:9): [True: 0, False: 1.81k]
  ------------------
  782|      0|        retval = READSTAT_ERROR_SEEK;
  783|      0|        goto cleanup;
  784|      0|    }
  785|       |
  786|  1.81k|    if (ctx->input_encoding && ctx->output_encoding && strcmp(ctx->input_encoding, ctx->output_encoding) != 0) {
  ------------------
  |  Branch (786:9): [True: 0, False: 1.81k]
  |  Branch (786:32): [True: 0, False: 0]
  |  Branch (786:56): [True: 0, False: 0]
  ------------------
  787|      0|        iconv_t converter = iconv_open(ctx->output_encoding, ctx->input_encoding);
  788|      0|        if (converter == (iconv_t)-1) {
  ------------------
  |  Branch (788:13): [True: 0, False: 0]
  ------------------
  789|      0|            retval = READSTAT_ERROR_UNSUPPORTED_CHARSET;
  790|      0|            goto cleanup;
  791|      0|        }
  792|      0|        ctx->converter = converter;
  793|      0|    }
  794|       |
  795|  1.81k|    retval = xport_read_library_record(ctx);
  796|  1.81k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (796:9): [True: 213, False: 1.59k]
  ------------------
  797|    213|        goto cleanup;
  798|       |
  799|  1.59k|    retval = xport_skip_record(ctx);
  800|  1.59k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (800:9): [True: 10, False: 1.58k]
  ------------------
  801|     10|        goto cleanup;
  802|       |
  803|  1.58k|    retval = xport_read_timestamp_record(ctx);
  804|  1.58k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (804:9): [True: 12, False: 1.57k]
  ------------------
  805|     12|        goto cleanup;
  806|       |
  807|  1.57k|    retval = xport_expect_header_record(ctx, "MEMBER", "MEMBV8");
  808|  1.57k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (808:9): [True: 138, False: 1.43k]
  ------------------
  809|    138|        goto cleanup;
  810|       |
  811|  1.43k|    retval = xport_expect_header_record(ctx, "DSCRPTR", "DSCPTV8");
  812|  1.43k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (812:9): [True: 20, False: 1.41k]
  ------------------
  813|     20|        goto cleanup;
  814|       |
  815|  1.41k|    retval = xport_read_table_name_record(ctx);
  816|  1.41k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (816:9): [True: 12, False: 1.40k]
  ------------------
  817|     12|        goto cleanup;
  818|       |
  819|  1.40k|    retval = xport_read_file_label_record(ctx);
  820|  1.40k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (820:9): [True: 27, False: 1.37k]
  ------------------
  821|     27|        goto cleanup;
  822|       |
  823|  1.37k|    retval = xport_read_namestr_header_record(ctx);
  824|  1.37k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (824:9): [True: 141, False: 1.23k]
  ------------------
  825|    141|        goto cleanup;
  826|       |
  827|  1.23k|    retval = xport_read_variables(ctx);
  828|  1.23k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (828:9): [True: 592, False: 646]
  ------------------
  829|    592|        goto cleanup;
  830|       |
  831|    646|    if (ctx->row_length) {
  ------------------
  |  Branch (831:9): [True: 632, False: 14]
  ------------------
  832|    632|        retval = xport_read_data(ctx);
  833|    632|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (833:13): [True: 6, False: 626]
  ------------------
  834|      6|            goto cleanup;
  835|    632|    }
  836|       |
  837|  1.81k|cleanup:
  838|  1.81k|    io->close(io->io_ctx);
  839|  1.81k|    xport_ctx_free(ctx);
  840|       |
  841|  1.81k|    return retval;
  842|    646|}
readstat_xport_read.c:xport_ctx_init:
   48|  1.81k|static xport_ctx_t *xport_ctx_init(void) {
   49|  1.81k|    xport_ctx_t *ctx = calloc(1, sizeof(xport_ctx_t));
   50|  1.81k|    return ctx;
   51|  1.81k|}
readstat_xport_read.c:xport_read_library_record:
  198|  1.81k|static readstat_error_t xport_read_library_record(xport_ctx_t *ctx) {
  199|  1.81k|    xport_header_record_t xrecord;
  200|  1.81k|    readstat_error_t retval = xport_read_header_record(ctx, &xrecord);
  201|  1.81k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (201:9): [True: 26, False: 1.78k]
  ------------------
  202|     26|        goto cleanup;
  203|       |
  204|  1.78k|    if (strcmp(xrecord.name, "LIBRARY") == 0) {
  ------------------
  |  Branch (204:9): [True: 268, False: 1.51k]
  ------------------
  205|    268|        ctx->version = 5;
  206|  1.51k|    } else if (strcmp(xrecord.name, "LIBV8") == 0) {
  ------------------
  |  Branch (206:16): [True: 1.33k, False: 187]
  ------------------
  207|  1.33k|        ctx->version = 8;
  208|  1.33k|    } else {
  209|    187|        retval = READSTAT_ERROR_UNSUPPORTED_FILE_FORMAT_VERSION;
  210|    187|        goto cleanup;
  211|    187|    }
  212|       |
  213|  1.81k|cleanup:
  214|  1.81k|    return retval;
  215|  1.78k|}
readstat_xport_read.c:xport_read_header_record:
  106|  7.49k|static readstat_error_t xport_read_header_record(xport_ctx_t *ctx, xport_header_record_t *xrecord) {
  107|  7.49k|    char line[LINE_LEN+1];
  108|  7.49k|    readstat_error_t retval = READSTAT_OK;
  109|       |
  110|  7.49k|    retval = xport_read_record(ctx, line);
  111|  7.49k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (111:9): [True: 124, False: 7.36k]
  ------------------
  112|    124|        return retval;
  113|       |
  114|  7.36k|    memset(xrecord, 0, sizeof(xport_header_record_t));
  115|  7.36k|    int matches = sscanf(line,
  116|  7.36k|            "HEADER RECORD*******%8s HEADER RECORD!!!!!!!"
  117|  7.36k|            "%05d%05d%05d" "%05d%05d%05d", xrecord->name,
  118|  7.36k|            &xrecord->num1, &xrecord->num2, &xrecord->num3,
  119|  7.36k|            &xrecord->num4, &xrecord->num5, &xrecord->num6);
  120|       |
  121|  7.36k|    if (matches < 2) {
  ------------------
  |  Branch (121:9): [True: 17, False: 7.35k]
  ------------------
  122|     17|        return READSTAT_ERROR_PARSE;
  123|     17|    }
  124|       |
  125|       |    /* V8 files store the observation count as a 15-character field
  126|       |     * immediately after the 48-character header prefix. Older writers
  127|       |     * may leave it blank or zero, in which case it stays unknown. */
  128|  7.35k|    if (strcmp(xrecord->name, "OBSV8") == 0) {
  ------------------
  |  Branch (128:9): [True: 163, False: 7.18k]
  ------------------
  129|    163|        char obs_count[16];
  130|    163|        memcpy(obs_count, &line[48], 15);
  131|    163|        obs_count[15] = '\0';
  132|       |
  133|    163|        char *end = NULL;
  134|    163|        long count = strtol(obs_count, &end, 10);
  135|    163|        if (end != obs_count && count > 0) {
  ------------------
  |  Branch (135:13): [True: 159, False: 4]
  |  Branch (135:33): [True: 107, False: 52]
  ------------------
  136|    107|            ctx->obs_count = count;
  137|    107|        }
  138|    163|    }
  139|       |
  140|  7.35k|    return READSTAT_OK;
  141|  7.36k|}
readstat_xport_read.c:xport_read_record:
   96|  11.9k|static readstat_error_t xport_read_record(xport_ctx_t *ctx, char *record) {
   97|  11.9k|    ssize_t bytes_read = read_bytes(ctx, record, LINE_LEN);
  ------------------
  |  |   16|  11.9k|#define LINE_LEN        80
  ------------------
   98|  11.9k|    if (bytes_read < LINE_LEN)
  ------------------
  |  |   16|  11.9k|#define LINE_LEN        80
  ------------------
  |  Branch (98:9): [True: 175, False: 11.7k]
  ------------------
   99|    175|        return READSTAT_ERROR_READ;
  100|       |
  101|  11.7k|    record[LINE_LEN] = '\0';
  ------------------
  |  |   16|  11.7k|#define LINE_LEN        80
  ------------------
  102|       |
  103|  11.7k|    return READSTAT_OK;
  104|  11.9k|}
readstat_xport_read.c:read_bytes:
   69|   202k|static ssize_t read_bytes(xport_ctx_t *ctx, void *dst, size_t dst_len) {
   70|   202k|    readstat_io_t *io = (readstat_io_t *)ctx->io;
   71|   202k|    return io->read(dst, dst_len, io->io_ctx);
   72|   202k|}
readstat_xport_read.c:xport_skip_record:
   74|  1.59k|static readstat_error_t xport_skip_record(xport_ctx_t *ctx) {
   75|  1.59k|    readstat_io_t *io = (readstat_io_t *)ctx->io;
   76|  1.59k|    if (io->seek(LINE_LEN, READSTAT_SEEK_CUR, io->io_ctx) == -1)
  ------------------
  |  |   16|  1.59k|#define LINE_LEN        80
  ------------------
  |  Branch (76:9): [True: 10, False: 1.58k]
  ------------------
   77|     10|        return READSTAT_ERROR_SEEK;
   78|       |
   79|  1.58k|    return READSTAT_OK;
   80|  1.59k|}
readstat_xport_read.c:xport_read_timestamp_record:
  217|  1.58k|static readstat_error_t xport_read_timestamp_record(xport_ctx_t *ctx) {
  218|  1.58k|    char line[LINE_LEN+1];
  219|  1.58k|    readstat_error_t retval = READSTAT_OK;
  220|  1.58k|    struct tm ts = { .tm_isdst = -1 };
  221|  1.58k|    char month[4];
  222|  1.58k|    int i;
  223|       |
  224|  1.58k|    retval = xport_read_record(ctx, line);
  225|  1.58k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (225:9): [True: 12, False: 1.57k]
  ------------------
  226|     12|        goto cleanup;
  227|       |
  228|  1.57k|    sscanf(line,
  229|  1.57k|            "%02d%3s%02d:%02d:%02d:%02d",
  230|  1.57k|            &ts.tm_mday, month, &ts.tm_year, &ts.tm_hour, &ts.tm_min, &ts.tm_sec);
  231|       |
  232|  15.1k|    for (i=0; i<sizeof(_xport_months)/sizeof(_xport_months[0]); i++) {
  ------------------
  |  Branch (232:15): [True: 14.1k, False: 1.02k]
  ------------------
  233|  14.1k|        if (strcmp(month, _xport_months[i]) == 0) {
  ------------------
  |  Branch (233:13): [True: 548, False: 13.6k]
  ------------------
  234|    548|            ts.tm_mon = i;
  235|    548|            break;
  236|    548|        }
  237|  14.1k|    }
  238|       |
  239|  1.57k|    if (ts.tm_year < 60) {
  ------------------
  |  Branch (239:9): [True: 1.56k, False: 15]
  ------------------
  240|  1.56k|        ts.tm_year += 100;
  241|  1.56k|    }
  242|       |
  243|  1.57k|    ctx->timestamp = mktime(&ts);
  244|       |
  245|  1.58k|cleanup:
  246|  1.58k|    return retval;
  247|  1.57k|}
readstat_xport_read.c:xport_expect_header_record:
  144|  3.25k|        const char *v5_name, const char *v8_name) {
  145|  3.25k|    readstat_error_t retval = READSTAT_OK;
  146|  3.25k|    xport_header_record_t xrecord;
  147|       |
  148|  3.25k|    retval = xport_read_header_record(ctx, &xrecord);
  149|  3.25k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (149:9): [True: 101, False: 3.15k]
  ------------------
  150|    101|        goto cleanup;
  151|       |
  152|  3.15k|    if (ctx->version == 5 && strcmp(xrecord.name, v5_name) != 0) {
  ------------------
  |  Branch (152:9): [True: 532, False: 2.62k]
  |  Branch (152:30): [True: 89, False: 443]
  ------------------
  153|     89|        retval = READSTAT_ERROR_PARSE;
  154|     89|        goto cleanup;
  155|  3.06k|    } else if (ctx->version == 8 && strcmp(xrecord.name, v8_name) != 0) {
  ------------------
  |  Branch (155:16): [True: 2.62k, False: 443]
  |  Branch (155:37): [True: 150, False: 2.47k]
  ------------------
  156|    150|        retval = READSTAT_ERROR_PARSE;
  157|    150|        goto cleanup;
  158|    150|    }
  159|       |
  160|  3.25k|cleanup:
  161|  3.25k|    return retval;
  162|  3.15k|}
readstat_xport_read.c:xport_read_table_name_record:
  164|  1.41k|static readstat_error_t xport_read_table_name_record(xport_ctx_t *ctx) {
  165|  1.41k|    char line[LINE_LEN+1];
  166|  1.41k|    readstat_error_t retval = READSTAT_OK;
  167|       |
  168|  1.41k|    retval = xport_read_record(ctx, line);
  169|  1.41k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (169:9): [True: 12, False: 1.40k]
  ------------------
  170|     12|        goto cleanup;
  171|       |
  172|  1.40k|    retval = readstat_convert(ctx->table_name, sizeof(ctx->table_name), &line[8],
  173|  1.40k|            ctx->version == 5 ? 8 : 32, ctx->converter);
  ------------------
  |  Branch (173:13): [True: 186, False: 1.22k]
  ------------------
  174|  1.40k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (174:9): [True: 0, False: 1.40k]
  ------------------
  175|      0|        goto cleanup;
  176|       |
  177|  1.41k|cleanup:
  178|  1.41k|    return retval;
  179|  1.40k|}
readstat_xport_read.c:xport_read_file_label_record:
  181|  1.40k|static readstat_error_t xport_read_file_label_record(xport_ctx_t *ctx) {
  182|  1.40k|    char line[LINE_LEN+1];
  183|  1.40k|    readstat_error_t retval = READSTAT_OK;
  184|       |
  185|  1.40k|    retval = xport_read_record(ctx, line);
  186|  1.40k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (186:9): [True: 27, False: 1.37k]
  ------------------
  187|     27|        goto cleanup;
  188|       |
  189|  1.37k|    retval = readstat_convert(ctx->file_label, sizeof(ctx->file_label), &line[32],
  190|  1.37k|            40, ctx->converter);
  191|  1.37k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (191:9): [True: 0, False: 1.37k]
  ------------------
  192|      0|        goto cleanup;
  193|       |
  194|  1.40k|cleanup:
  195|  1.40k|    return retval;
  196|  1.37k|}
readstat_xport_read.c:xport_read_namestr_header_record:
  249|  1.37k|static readstat_error_t xport_read_namestr_header_record(xport_ctx_t *ctx) {
  250|  1.37k|    xport_header_record_t xrecord;
  251|  1.37k|    readstat_error_t retval = READSTAT_OK;
  252|       |
  253|  1.37k|    retval = xport_read_header_record(ctx, &xrecord);
  254|  1.37k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (254:9): [True: 2, False: 1.37k]
  ------------------
  255|      2|        goto cleanup;
  256|       |
  257|  1.37k|    if (ctx->version == 5 && strcmp(xrecord.name, "NAMESTR") != 0) {
  ------------------
  |  Branch (257:9): [True: 182, False: 1.19k]
  |  Branch (257:30): [True: 62, False: 120]
  ------------------
  258|     62|        retval = READSTAT_ERROR_PARSE;
  259|     62|        goto cleanup;
  260|  1.31k|    } else if (ctx->version == 8 && strcmp(xrecord.name, "NAMSTV8") != 0) {
  ------------------
  |  Branch (260:16): [True: 1.19k, False: 120]
  |  Branch (260:37): [True: 62, False: 1.13k]
  ------------------
  261|     62|        retval = READSTAT_ERROR_PARSE;
  262|     62|        goto cleanup;
  263|     62|    }
  264|       |
  265|  1.25k|    ctx->var_count = xrecord.num2;
  266|  1.25k|    ctx->variables = readstat_calloc(ctx->var_count, sizeof(readstat_variable_t *));
  267|  1.25k|    if (ctx->variables == NULL) {
  ------------------
  |  Branch (267:9): [True: 15, False: 1.23k]
  ------------------
  268|     15|        retval = READSTAT_ERROR_MALLOC;
  269|     15|        goto cleanup;
  270|     15|    }
  271|       |
  272|  1.23k|    if (ctx->handle.metadata) {
  ------------------
  |  Branch (272:9): [True: 1.23k, False: 0]
  ------------------
  273|  1.23k|        readstat_metadata_t metadata = {
  274|  1.23k|            .row_count = -1,
  275|  1.23k|            .var_count = ctx->var_count,
  276|  1.23k|            .file_label = ctx->file_label,
  277|  1.23k|            .table_name = ctx->table_name,
  278|  1.23k|            .creation_time = ctx->timestamp,
  279|  1.23k|            .modified_time = ctx->timestamp,
  280|  1.23k|            .file_format_version = ctx->version
  281|  1.23k|        };
  282|  1.23k|        if (ctx->handle.metadata(&metadata, ctx->user_ctx) != READSTAT_HANDLER_OK) {
  ------------------
  |  |   22|  1.23k|#define READSTAT_HANDLER_OK             0
  ------------------
  |  Branch (282:13): [True: 0, False: 1.23k]
  ------------------
  283|      0|            retval = READSTAT_ERROR_USER_ABORT;
  284|      0|            goto cleanup;
  285|      0|        }
  286|  1.23k|    }
  287|       |
  288|  1.37k|cleanup:
  289|  1.37k|    return retval;
  290|  1.23k|}
readstat_xport_read.c:xport_read_variables:
  490|  1.23k|static readstat_error_t xport_read_variables(xport_ctx_t *ctx) {
  491|  1.23k|    int i;
  492|  1.23k|    readstat_error_t retval = READSTAT_OK;
  493|  98.1k|    for (i=0; i<ctx->var_count; i++) {
  ------------------
  |  Branch (493:15): [True: 96.9k, False: 1.17k]
  ------------------
  494|  96.9k|        xport_namestr_t namestr;
  495|  96.9k|        ssize_t bytes_read = read_bytes(ctx, &namestr, sizeof(xport_namestr_t));
  496|  96.9k|        if (bytes_read < sizeof(xport_namestr_t)) {
  ------------------
  |  Branch (496:13): [True: 67, False: 96.9k]
  ------------------
  497|     67|            retval = READSTAT_ERROR_READ;
  498|     67|            goto cleanup;
  499|     67|        }
  500|  96.9k|        xport_namestr_bswap(&namestr);
  501|       |
  502|  96.9k|        readstat_variable_t *variable = calloc(1, sizeof(readstat_variable_t));
  503|       |
  504|  96.9k|        variable->index = i;
  505|  96.9k|        variable->type = namestr.ntype == SAS_COLUMN_TYPE_CHR ? READSTAT_TYPE_STRING : READSTAT_TYPE_DOUBLE;
  ------------------
  |  |   91|  96.9k|#define SAS_COLUMN_TYPE_CHR  0x02
  ------------------
  |  Branch (505:26): [True: 129, False: 96.7k]
  ------------------
  506|  96.9k|        variable->storage_width = namestr.nlng;
  507|  96.9k|        variable->display_width = namestr.nfl;
  508|  96.9k|        variable->decimals = namestr.nfd;
  509|  96.9k|        variable->alignment = namestr.nfj ? READSTAT_ALIGNMENT_RIGHT : READSTAT_ALIGNMENT_LEFT;
  ------------------
  |  Branch (509:31): [True: 59.9k, False: 36.9k]
  ------------------
  510|       |
  511|  96.9k|        if (ctx->version == 5) {
  ------------------
  |  Branch (511:13): [True: 4.28k, False: 92.6k]
  ------------------
  512|  4.28k|            retval = readstat_convert(variable->name, sizeof(variable->name),
  513|  4.28k|                    namestr.nname, sizeof(namestr.nname), ctx->converter);
  514|  92.6k|        } else {
  515|  92.6k|            retval = readstat_convert(variable->name, sizeof(variable->name),
  516|  92.6k|                    namestr.longname, sizeof(namestr.longname), ctx->converter);
  517|  92.6k|        }
  518|  96.9k|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (518:13): [True: 0, False: 96.9k]
  ------------------
  519|      0|            goto cleanup;
  520|       |
  521|  96.9k|        retval = readstat_convert(variable->label, sizeof(variable->label),
  522|  96.9k|                namestr.nlabel, sizeof(namestr.nlabel), ctx->converter);
  523|  96.9k|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (523:13): [True: 0, False: 96.9k]
  ------------------
  524|      0|            goto cleanup;
  525|       |
  526|  96.9k|        retval = xport_construct_format(variable->format, sizeof(variable->format),
  527|  96.9k|                namestr.nform, sizeof(namestr.nform),
  528|  96.9k|                namestr.nfl, namestr.nfd);
  529|  96.9k|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (529:13): [True: 0, False: 96.9k]
  ------------------
  530|      0|            goto cleanup;
  531|       |
  532|  96.9k|        retval = xport_construct_format(variable->informat, sizeof(variable->informat),
  533|  96.9k|                namestr.niform, sizeof(namestr.niform),
  534|  96.9k|                namestr.nifl, namestr.nifd);
  535|  96.9k|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (535:13): [True: 0, False: 96.9k]
  ------------------
  536|      0|            goto cleanup;
  537|       |
  538|  96.9k|        ctx->variables[i] = variable;
  539|  96.9k|    }
  540|       |
  541|  1.17k|    retval = xport_skip_rest_of_record(ctx);
  542|  1.17k|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (542:9): [True: 31, False: 1.14k]
  ------------------
  543|     31|        goto cleanup;
  544|       |
  545|  1.14k|    if (ctx->version == 5) {
  ------------------
  |  Branch (545:9): [True: 92, False: 1.04k]
  ------------------
  546|     92|        retval = xport_read_obs_header_record(ctx);
  547|     92|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (547:13): [True: 35, False: 57]
  ------------------
  548|     35|            goto cleanup;
  549|  1.04k|    } else {
  550|  1.04k|        xport_header_record_t xrecord;
  551|  1.04k|        retval = xport_read_header_record(ctx, &xrecord);
  552|  1.04k|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (552:13): [True: 12, False: 1.03k]
  ------------------
  553|     12|            goto cleanup;
  554|       |
  555|  1.03k|        if (strcmp(xrecord.name, "OBSV8") == 0) {
  ------------------
  |  Branch (555:13): [True: 79, False: 957]
  ------------------
  556|       |            /* void */
  557|    957|        } else if (strcmp(xrecord.name, "LABELV8") == 0) {
  ------------------
  |  Branch (557:20): [True: 195, False: 762]
  ------------------
  558|    195|            retval = xport_read_labels_v8(ctx, xrecord.num1);
  559|    762|        } else if (strcmp(xrecord.name, "LABELV9") == 0) {
  ------------------
  |  Branch (559:20): [True: 254, False: 508]
  ------------------
  560|    254|            retval = xport_read_labels_v9(ctx, xrecord.num1);
  561|    254|        }
  562|  1.03k|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (562:13): [True: 447, False: 589]
  ------------------
  563|    447|            goto cleanup;
  564|  1.03k|    }
  565|       |
  566|    646|    ctx->row_length = 0;
  567|       |
  568|    646|    int index_after_skipping = 0;
  569|       |
  570|  19.1k|    for (i=0; i<ctx->var_count; i++) {
  ------------------
  |  Branch (570:15): [True: 18.5k, False: 646]
  ------------------
  571|  18.5k|        readstat_variable_t *variable = ctx->variables[i];
  572|  18.5k|        variable->index_after_skipping = index_after_skipping;
  573|       |
  574|  18.5k|        int cb_retval = READSTAT_HANDLER_OK;
  ------------------
  |  |   22|  18.5k|#define READSTAT_HANDLER_OK             0
  ------------------
  575|  18.5k|        if (ctx->handle.variable) {
  ------------------
  |  Branch (575:13): [True: 18.5k, False: 0]
  ------------------
  576|  18.5k|            cb_retval = ctx->handle.variable(i, variable, variable->format, ctx->user_ctx);
  577|  18.5k|        }
  578|  18.5k|        if (cb_retval == READSTAT_HANDLER_ABORT) {
  ------------------
  |  |   23|  18.5k|#define READSTAT_HANDLER_ABORT          1
  ------------------
  |  Branch (578:13): [True: 0, False: 18.5k]
  ------------------
  579|      0|            retval = READSTAT_ERROR_USER_ABORT;
  580|      0|            goto cleanup;
  581|      0|        }
  582|  18.5k|        if (cb_retval == READSTAT_HANDLER_SKIP_VARIABLE) {
  ------------------
  |  |   24|  18.5k|#define READSTAT_HANDLER_SKIP_VARIABLE  2
  ------------------
  |  Branch (582:13): [True: 0, False: 18.5k]
  ------------------
  583|      0|            variable->skip = 1;
  584|  18.5k|        } else {
  585|  18.5k|            index_after_skipping++;
  586|  18.5k|        }
  587|       |
  588|  18.5k|        ctx->row_length += variable->storage_width;
  589|  18.5k|    }
  590|       |
  591|  1.23k|cleanup:
  592|  1.23k|    return retval;
  593|    646|}
readstat_xport_read.c:xport_construct_format:
  297|   193k|        const char *src, size_t src_len, int width, int decimals) {
  298|   193k|    char *format = malloc(4 * src_len + 1);
  299|   193k|    if (format == NULL) return READSTAT_ERROR_MALLOC;
  ------------------
  |  Branch (299:9): [True: 0, False: 193k]
  ------------------
  300|   193k|    readstat_error_t retval = readstat_convert(format, 4 * src_len + 1, src, src_len, NULL);
  301|       |
  302|   193k|    if (retval != READSTAT_OK) {
  ------------------
  |  Branch (302:9): [True: 0, False: 193k]
  ------------------
  303|      0|        free(format);
  304|      0|        return retval;
  305|      0|    }
  306|       |
  307|   193k|    char *pos = dst;
  308|   193k|    *dst = '\0';
  309|   193k|    if (format[0]) {
  ------------------
  |  Branch (309:9): [True: 69.0k, False: 124k]
  ------------------
  310|  69.0k|        pos += snprintf(dst, dst_len, "%s", format);
  311|  69.0k|    }
  312|   193k|    if (width) {
  ------------------
  |  Branch (312:9): [True: 119k, False: 74.1k]
  ------------------
  313|   119k|        pos += snprintf(pos, dst_len-(pos-dst), "%d", width);
  314|   119k|    }
  315|   193k|    if (decimals) {
  ------------------
  |  Branch (315:9): [True: 119k, False: 74.4k]
  ------------------
  316|   119k|        pos += snprintf(pos, dst_len-(pos-dst), ".%d", decimals);
  317|   119k|    }
  318|       |
  319|   193k|    free(format);
  320|   193k|    return retval;
  321|   193k|}
readstat_xport_read.c:xport_skip_rest_of_record:
   82|  1.36k|static readstat_error_t xport_skip_rest_of_record(xport_ctx_t *ctx) {
   83|  1.36k|    readstat_io_t *io = (readstat_io_t *)ctx->io;
   84|  1.36k|    off_t pos = io->seek(0, READSTAT_SEEK_CUR, io->io_ctx);
   85|  1.36k|    if (pos == -1)
  ------------------
  |  Branch (85:9): [True: 0, False: 1.36k]
  ------------------
   86|      0|        return READSTAT_ERROR_SEEK;
   87|       |
   88|  1.36k|    if (pos % LINE_LEN) {
  ------------------
  |  |   16|  1.36k|#define LINE_LEN        80
  ------------------
  |  Branch (88:9): [True: 1.20k, False: 159]
  ------------------
   89|  1.20k|        if (io->seek(LINE_LEN - (pos % LINE_LEN), READSTAT_SEEK_CUR, io->io_ctx) == -1)
  ------------------
  |  |   16|  1.20k|#define LINE_LEN        80
  ------------------
                      if (io->seek(LINE_LEN - (pos % LINE_LEN), READSTAT_SEEK_CUR, io->io_ctx) == -1)
  ------------------
  |  |   16|  1.20k|#define LINE_LEN        80
  ------------------
  |  Branch (89:13): [True: 76, False: 1.13k]
  ------------------
   90|     76|            return READSTAT_ERROR_SEEK;
   91|  1.20k|    }
   92|       |
   93|  1.28k|    return READSTAT_OK;
   94|  1.36k|}
readstat_xport_read.c:xport_read_obs_header_record:
  292|    241|static readstat_error_t xport_read_obs_header_record(xport_ctx_t *ctx) {
  293|    241|    return xport_expect_header_record(ctx, "OBS", "OBSV8");
  294|    241|}
readstat_xport_read.c:xport_read_labels_v8:
  323|    195|static readstat_error_t xport_read_labels_v8(xport_ctx_t *ctx, int label_count) {
  324|    195|    readstat_error_t retval = READSTAT_OK;
  325|    195|    uint16_t labeldef[3];
  326|    195|    char *name = NULL;
  327|    195|    char *label = NULL;
  328|    195|    int i;
  329|    700|    for (i=0; i<label_count; i++) {
  ------------------
  |  Branch (329:15): [True: 608, False: 92]
  ------------------
  330|    608|        int index, name_len, label_len;
  331|    608|        if (read_bytes(ctx, labeldef, sizeof(labeldef)) != sizeof(labeldef)) {
  ------------------
  |  Branch (331:13): [True: 26, False: 582]
  ------------------
  332|     26|            retval = READSTAT_ERROR_READ;
  333|     26|            goto cleanup;
  334|     26|        }
  335|       |
  336|    582|        if (machine_is_little_endian()) {
  ------------------
  |  Branch (336:13): [True: 582, False: 0]
  ------------------
  337|    582|            index = byteswap2(labeldef[0]);
  338|    582|            name_len = byteswap2(labeldef[1]);
  339|    582|            label_len = byteswap2(labeldef[2]);
  340|    582|        } else {
  341|      0|            index = labeldef[0];
  342|      0|            name_len = labeldef[1];
  343|      0|            label_len = labeldef[2];
  344|      0|        }
  345|       |
  346|    582|        if (index > ctx->var_count || index == 0) {
  ------------------
  |  Branch (346:13): [True: 17, False: 565]
  |  Branch (346:39): [True: 12, False: 553]
  ------------------
  347|     29|            retval = READSTAT_ERROR_PARSE;
  348|     29|            goto cleanup;
  349|     29|        }
  350|       |
  351|    553|        char *tmp_name = realloc(name, name_len + 1);
  352|    553|        if (tmp_name == NULL) { retval = READSTAT_ERROR_MALLOC; goto cleanup; }
  ------------------
  |  Branch (352:13): [True: 0, False: 553]
  ------------------
  353|    553|        name = tmp_name;
  354|       |
  355|    553|        char *tmp_label = realloc(label, label_len + 1);
  356|    553|        if (tmp_label == NULL) { retval = READSTAT_ERROR_MALLOC; goto cleanup; }
  ------------------
  |  Branch (356:13): [True: 0, False: 553]
  ------------------
  357|    553|        label = tmp_label;
  358|       |
  359|    553|        readstat_variable_t *variable = ctx->variables[index-1];
  360|       |
  361|    553|        if (read_bytes(ctx, name, name_len) != name_len ||
  ------------------
  |  Branch (361:13): [True: 25, False: 528]
  ------------------
  362|    528|                read_bytes(ctx, label, label_len) != label_len) {
  ------------------
  |  Branch (362:17): [True: 19, False: 509]
  ------------------
  363|     44|            retval = READSTAT_ERROR_READ;
  364|     44|            goto cleanup;
  365|     44|        }
  366|       |
  367|    509|        retval = readstat_convert(variable->name, sizeof(variable->name),
  368|    509|                name, name_len, ctx->converter);
  369|    509|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (369:13): [True: 2, False: 507]
  ------------------
  370|      2|            goto cleanup;
  371|       |
  372|    507|        retval = readstat_convert(variable->label, sizeof(variable->label),
  373|    507|                label, label_len, ctx->converter);
  374|    507|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (374:13): [True: 2, False: 505]
  ------------------
  375|      2|            goto cleanup;
  376|    507|    }
  377|       |
  378|     92|    retval = xport_skip_rest_of_record(ctx);
  379|     92|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (379:9): [True: 20, False: 72]
  ------------------
  380|     20|        goto cleanup;
  381|       |
  382|     72|    retval = xport_read_obs_header_record(ctx);
  383|     72|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (383:9): [True: 71, False: 1]
  ------------------
  384|     71|        goto cleanup;
  385|       |
  386|    195|cleanup:
  387|    195|    free(name);
  388|    195|    free(label);
  389|    195|    return retval;
  390|     72|}
readstat_xport_read.c:xport_read_labels_v9:
  392|    254|static readstat_error_t xport_read_labels_v9(xport_ctx_t *ctx, int label_count) {
  393|    254|    readstat_error_t retval = READSTAT_OK;
  394|    254|    uint16_t labeldef[5];
  395|    254|    int i;
  396|    254|    char *name = NULL;
  397|    254|    char *label = NULL;
  398|    254|    char *format = NULL;
  399|    254|    char *informat = NULL;
  400|       |
  401|    554|    for (i=0; i<label_count; i++) {
  ------------------
  |  Branch (401:15): [True: 452, False: 102]
  ------------------
  402|    452|        int index, name_len, label_len, format_len, informat_len;
  403|    452|        if (read_bytes(ctx, labeldef, sizeof(labeldef)) != sizeof(labeldef)) {
  ------------------
  |  Branch (403:13): [True: 28, False: 424]
  ------------------
  404|     28|            retval = READSTAT_ERROR_READ;
  405|     28|            goto cleanup;
  406|     28|        }
  407|       |
  408|    424|        if (machine_is_little_endian()) {
  ------------------
  |  Branch (408:13): [True: 424, False: 0]
  ------------------
  409|    424|            index = byteswap2(labeldef[0]);
  410|    424|            name_len = byteswap2(labeldef[1]);
  411|    424|            label_len = byteswap2(labeldef[2]);
  412|    424|            format_len = byteswap2(labeldef[3]);
  413|    424|            informat_len = byteswap2(labeldef[4]);
  414|    424|        } else {
  415|      0|            index = labeldef[0];
  416|      0|            name_len = labeldef[1];
  417|      0|            label_len = labeldef[2];
  418|      0|            format_len = labeldef[3];
  419|      0|            informat_len = labeldef[4];
  420|      0|        }
  421|       |
  422|    424|        if (index > ctx->var_count || index == 0) {
  ------------------
  |  Branch (422:13): [True: 15, False: 409]
  |  Branch (422:39): [True: 12, False: 397]
  ------------------
  423|     27|            retval = READSTAT_ERROR_PARSE;
  424|     27|            goto cleanup;
  425|     27|        }
  426|       |
  427|    397|        char *tmp_name = realloc(name, name_len + 1);
  428|    397|        if (tmp_name == NULL) { retval = READSTAT_ERROR_MALLOC; goto cleanup; }
  ------------------
  |  Branch (428:13): [True: 0, False: 397]
  ------------------
  429|    397|        name = tmp_name;
  430|       |
  431|    397|        char *tmp_label = realloc(label, label_len + 1);
  432|    397|        if (tmp_label == NULL) { retval = READSTAT_ERROR_MALLOC; goto cleanup; }
  ------------------
  |  Branch (432:13): [True: 0, False: 397]
  ------------------
  433|    397|        label = tmp_label;
  434|       |
  435|    397|        char *tmp_format = realloc(format, format_len + 1);
  436|    397|        if (tmp_format == NULL) { retval = READSTAT_ERROR_MALLOC; goto cleanup; }
  ------------------
  |  Branch (436:13): [True: 0, False: 397]
  ------------------
  437|    397|        format = tmp_format;
  438|       |
  439|    397|        char *tmp_informat = realloc(informat, informat_len + 1);
  440|    397|        if (tmp_informat == NULL) { retval = READSTAT_ERROR_MALLOC; goto cleanup; }
  ------------------
  |  Branch (440:13): [True: 0, False: 397]
  ------------------
  441|    397|        informat = tmp_informat;
  442|       |
  443|    397|        readstat_variable_t *variable = ctx->variables[index-1];
  444|       |
  445|    397|        if (read_bytes(ctx, name, name_len) != name_len ||
  ------------------
  |  Branch (445:13): [True: 27, False: 370]
  ------------------
  446|    370|                read_bytes(ctx, label, label_len) != label_len ||
  ------------------
  |  Branch (446:17): [True: 18, False: 352]
  ------------------
  447|    352|                read_bytes(ctx, format, format_len) != format_len ||
  ------------------
  |  Branch (447:17): [True: 16, False: 336]
  ------------------
  448|    336|                read_bytes(ctx, informat, informat_len) != informat_len) {
  ------------------
  |  Branch (448:17): [True: 17, False: 319]
  ------------------
  449|     78|            retval = READSTAT_ERROR_READ;
  450|     78|            goto cleanup;
  451|     78|        }
  452|       |
  453|    319|        retval = readstat_convert(variable->name, sizeof(variable->name),
  454|    319|                name, name_len, ctx->converter);
  455|    319|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (455:13): [True: 1, False: 318]
  ------------------
  456|      1|            goto cleanup;
  457|       |
  458|    318|        retval = readstat_convert(variable->label, sizeof(variable->label),
  459|    318|                label, label_len, ctx->converter);
  460|    318|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (460:13): [True: 2, False: 316]
  ------------------
  461|      2|            goto cleanup;
  462|       |
  463|    316|        retval = readstat_convert(variable->format, sizeof(variable->format),
  464|    316|                format, format_len, ctx->converter);
  465|    316|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (465:13): [True: 13, False: 303]
  ------------------
  466|     13|            goto cleanup;
  467|       |
  468|    303|        retval = readstat_convert(variable->informat, sizeof(variable->informat),
  469|    303|                informat, informat_len, ctx->converter);
  470|    303|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (470:13): [True: 3, False: 300]
  ------------------
  471|      3|            goto cleanup;
  472|    303|    }
  473|       |
  474|    102|    retval = xport_skip_rest_of_record(ctx);
  475|    102|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (475:9): [True: 25, False: 77]
  ------------------
  476|     25|        goto cleanup;
  477|       |
  478|     77|    retval = xport_read_obs_header_record(ctx);
  479|     77|    if (retval != READSTAT_OK)
  ------------------
  |  Branch (479:9): [True: 76, False: 1]
  ------------------
  480|     76|        goto cleanup;
  481|       |
  482|    254|cleanup:
  483|    254|    free(name);
  484|    254|    free(format);
  485|    254|    free(informat);
  486|    254|    free(label);
  487|    254|    return retval;
  488|     77|}
readstat_xport_read.c:xport_read_data:
  661|    632|static readstat_error_t xport_read_data(xport_ctx_t *ctx) {
  662|    632|    if (!ctx->row_length)
  ------------------
  |  Branch (662:9): [True: 0, False: 632]
  ------------------
  663|      0|        return READSTAT_OK;
  664|       |
  665|    632|    if (!ctx->handle.value)
  ------------------
  |  Branch (665:9): [True: 0, False: 632]
  ------------------
  666|      0|        return READSTAT_OK;
  667|       |
  668|    632|    readstat_error_t retval = READSTAT_OK;
  669|    632|    char *row = readstat_malloc(ctx->row_length);
  670|    632|    char *blank_row = readstat_malloc(ctx->row_length);
  671|    632|    int num_blank_rows = 0;
  672|    632|    long rows_read = 0;
  673|       |
  674|    632|    if (row == NULL || blank_row == NULL) {
  ------------------
  |  Branch (674:9): [True: 6, False: 626]
  |  Branch (674:24): [True: 0, False: 626]
  ------------------
  675|      6|        retval = READSTAT_ERROR_MALLOC;
  676|      6|        goto cleanup;
  677|      6|    }
  678|       |
  679|    626|    memset(blank_row, ' ', ctx->row_length);
  680|  90.1k|    while (1) {
  ------------------
  |  Branch (680:12): [True: 90.1k, Folded]
  ------------------
  681|  90.1k|        if (ctx->obs_count > 0 && rows_read == ctx->obs_count)
  ------------------
  |  Branch (681:13): [True: 1.08k, False: 89.0k]
  |  Branch (681:35): [True: 3, False: 1.08k]
  ------------------
  682|      3|            break;
  683|       |
  684|  90.1k|        ssize_t bytes_read = read_bytes(ctx, row, ctx->row_length);
  685|  90.1k|        if (bytes_read == -1) {
  ------------------
  |  Branch (685:13): [True: 0, False: 90.1k]
  ------------------
  686|      0|            retval = READSTAT_ERROR_READ;
  687|      0|            goto cleanup;
  688|  90.1k|        } else if (bytes_read < ctx->row_length) {
  ------------------
  |  Branch (688:20): [True: 623, False: 89.4k]
  ------------------
  689|    623|            break;
  690|    623|        }
  691|  89.4k|        rows_read++;
  692|       |
  693|  89.4k|        off_t pos = 0;
  694|       |
  695|       |        /* When the row count is known, blank rows are real data rather
  696|       |         * than potential end-of-file padding */
  697|  89.4k|        int row_is_blank = ctx->obs_count <= 0;
  698|       |
  699|   244k|        for (pos=0; pos<ctx->row_length; pos++) {
  ------------------
  |  Branch (699:21): [True: 201k, False: 43.5k]
  ------------------
  700|   201k|            if (row[pos] != ' ') {
  ------------------
  |  Branch (700:17): [True: 45.9k, False: 155k]
  ------------------
  701|  45.9k|                row_is_blank = 0;
  702|  45.9k|                break;
  703|  45.9k|            }
  704|   201k|        }
  705|       |
  706|  89.4k|        if (row_is_blank) {
  ------------------
  |  Branch (706:13): [True: 43.1k, False: 46.2k]
  ------------------
  707|  43.1k|            num_blank_rows++;
  708|  43.1k|            continue;
  709|  43.1k|        }
  710|       |
  711|  88.6k|        while (num_blank_rows) {
  ------------------
  |  Branch (711:16): [True: 42.3k, False: 46.2k]
  ------------------
  712|  42.3k|            retval = xport_process_row(ctx, blank_row, ctx->row_length);
  713|  42.3k|            if (retval != READSTAT_OK)
  ------------------
  |  Branch (713:17): [True: 0, False: 42.3k]
  ------------------
  714|      0|                goto cleanup;
  715|       |
  716|  42.3k|            if (ctx->row_limit > 0 && ctx->parsed_row_count == ctx->row_limit)
  ------------------
  |  Branch (716:17): [True: 0, False: 42.3k]
  |  Branch (716:39): [True: 0, False: 0]
  ------------------
  717|      0|                goto cleanup;
  718|       |
  719|  42.3k|            num_blank_rows--;
  720|  42.3k|        }
  721|       |
  722|  46.2k|        retval = xport_process_row(ctx, row, ctx->row_length);
  723|  46.2k|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (723:13): [True: 0, False: 46.2k]
  ------------------
  724|      0|            goto cleanup;
  725|       |
  726|  46.2k|        retval = xport_update_progress(ctx);
  727|  46.2k|        if (retval != READSTAT_OK)
  ------------------
  |  Branch (727:13): [True: 0, False: 46.2k]
  ------------------
  728|      0|            goto cleanup;
  729|       |
  730|  46.2k|        if (ctx->row_limit > 0 && ctx->parsed_row_count == ctx->row_limit)
  ------------------
  |  Branch (730:13): [True: 0, False: 46.2k]
  |  Branch (730:35): [True: 0, False: 0]
  ------------------
  731|      0|            break;
  732|  46.2k|    }
  733|       |
  734|       |    /* Padding never fills a whole line, so blank rows at least a line
  735|       |     * wide are data rather than end-of-file padding */
  736|    626|    if (ctx->row_length >= LINE_LEN) {
  ------------------
  |  |   16|    626|#define LINE_LEN        80
  ------------------
  |  Branch (736:9): [True: 166, False: 460]
  ------------------
  737|    743|        while (num_blank_rows) {
  ------------------
  |  Branch (737:16): [True: 577, False: 166]
  ------------------
  738|    577|            if (ctx->row_limit > 0 && ctx->parsed_row_count == ctx->row_limit)
  ------------------
  |  Branch (738:17): [True: 0, False: 577]
  |  Branch (738:39): [True: 0, False: 0]
  ------------------
  739|      0|                break;
  740|       |
  741|    577|            retval = xport_process_row(ctx, blank_row, ctx->row_length);
  742|    577|            if (retval != READSTAT_OK)
  ------------------
  |  Branch (742:17): [True: 0, False: 577]
  ------------------
  743|      0|                goto cleanup;
  744|       |
  745|    577|            num_blank_rows--;
  746|    577|        }
  747|    166|    }
  748|       |
  749|    632|cleanup:
  750|    632|    if (row)
  ------------------
  |  Branch (750:9): [True: 626, False: 6]
  ------------------
  751|    626|        free(row);
  752|    632|    if (blank_row)
  ------------------
  |  Branch (752:9): [True: 626, False: 6]
  ------------------
  753|    626|        free(blank_row);
  754|    632|    return retval;
  755|    626|}
readstat_xport_read.c:xport_process_row:
  595|  89.2k|static readstat_error_t xport_process_row(xport_ctx_t *ctx, const char *row, size_t row_length) {
  596|  89.2k|    readstat_error_t retval = READSTAT_OK;
  597|  89.2k|    int i;
  598|  89.2k|    off_t pos = 0;
  599|  89.2k|    char *string = NULL;
  600|   178k|    for (i=0; i<ctx->var_count; i++) {
  ------------------
  |  Branch (600:15): [True: 89.4k, False: 89.2k]
  ------------------
  601|  89.4k|        readstat_variable_t *variable = ctx->variables[i];
  602|  89.4k|        readstat_value_t value = { .type = variable->type };
  603|       |
  604|  89.4k|        if (variable->type == READSTAT_TYPE_STRING) {
  ------------------
  |  Branch (604:13): [True: 40.3k, False: 49.0k]
  ------------------
  605|  40.3k|            string = readstat_realloc(string, 4*variable->storage_width+1);
  606|  40.3k|            if (string == NULL) {
  ------------------
  |  Branch (606:17): [True: 0, False: 40.3k]
  ------------------
  607|      0|                retval = READSTAT_ERROR_MALLOC;
  608|      0|                goto cleanup;
  609|      0|            }
  610|  40.3k|            retval = readstat_convert(string, 4*variable->storage_width+1,
  611|  40.3k|                    &row[pos], variable->storage_width, ctx->converter);
  612|  40.3k|            if (retval != READSTAT_OK)
  ------------------
  |  Branch (612:17): [True: 0, False: 40.3k]
  ------------------
  613|      0|                goto cleanup;
  614|       |
  615|  40.3k|            value.v.string_value = string;
  616|  49.0k|        } else {
  617|  49.0k|            double dval = NAN;
  618|  49.0k|            if (variable->storage_width <= XPORT_MAX_DOUBLE_SIZE &&
  ------------------
  |  |   45|  98.1k|#define XPORT_MAX_DOUBLE_SIZE   8
  ------------------
  |  Branch (618:17): [True: 48.1k, False: 923]
  ------------------
  619|  48.1k|                    variable->storage_width >= XPORT_MIN_DOUBLE_SIZE) {
  ------------------
  |  |   44|  48.1k|#define XPORT_MIN_DOUBLE_SIZE   3
  ------------------
  |  Branch (619:21): [True: 46.0k, False: 2.04k]
  ------------------
  620|  46.0k|                char full_value[8] = { 0 };
  621|  46.0k|                if (memcmp(&full_value[1], &row[pos+1], variable->storage_width - 1) == 0 &&
  ------------------
  |  Branch (621:21): [True: 34.5k, False: 11.5k]
  ------------------
  622|  34.5k|                        (row[pos] == '.' || sas_validate_tag(row[pos]) == READSTAT_OK)) {
  ------------------
  |  Branch (622:26): [True: 194, False: 34.3k]
  |  Branch (622:45): [True: 400, False: 33.9k]
  ------------------
  623|    594|                    if (row[pos] == '.') {
  ------------------
  |  Branch (623:25): [True: 194, False: 400]
  ------------------
  624|    194|                        value.is_system_missing = 1;
  625|    400|                    } else {
  626|    400|                        value.tag = row[pos];
  627|    400|                        value.is_tagged_missing = 1;
  628|    400|                    }
  629|  45.5k|                } else {
  630|  45.5k|                    memcpy(full_value, &row[pos], variable->storage_width);
  631|  45.5k|                    int rc = cnxptiee(full_value, CN_TYPE_XPORT, &dval, CN_TYPE_NATIVE);
  ------------------
  |  |    2|  45.5k|#define CN_TYPE_XPORT 1
  ------------------
                                  int rc = cnxptiee(full_value, CN_TYPE_XPORT, &dval, CN_TYPE_NATIVE);
  ------------------
  |  |    1|  45.5k|#define CN_TYPE_NATIVE 0
  ------------------
  632|  45.5k|                    if (rc != 0) {
  ------------------
  |  Branch (632:25): [True: 0, False: 45.5k]
  ------------------
  633|      0|                        retval = READSTAT_ERROR_CONVERT;
  634|      0|                        goto cleanup;
  635|      0|                    }
  636|  45.5k|                }
  637|  46.0k|            }
  638|       |
  639|  49.0k|            value.v.double_value = dval;
  640|  49.0k|        }
  641|  89.4k|        pos += variable->storage_width;
  642|       |
  643|  89.4k|        if (ctx->handle.value && !ctx->variables[i]->skip && !ctx->row_offset) {
  ------------------
  |  Branch (643:13): [True: 89.4k, False: 0]
  |  Branch (643:34): [True: 89.4k, False: 0]
  |  Branch (643:62): [True: 89.4k, False: 0]
  ------------------
  644|  89.4k|            if (ctx->handle.value(ctx->parsed_row_count, variable, value, ctx->user_ctx) != READSTAT_HANDLER_OK) {
  ------------------
  |  |   22|  89.4k|#define READSTAT_HANDLER_OK             0
  ------------------
  |  Branch (644:17): [True: 0, False: 89.4k]
  ------------------
  645|      0|                retval = READSTAT_ERROR_USER_ABORT;
  646|      0|                goto cleanup;
  647|      0|            }
  648|  89.4k|        }
  649|  89.4k|    }
  650|  89.2k|    if (ctx->row_offset) {
  ------------------
  |  Branch (650:9): [True: 0, False: 89.2k]
  ------------------
  651|      0|        ctx->row_offset--;
  652|  89.2k|    } else {
  653|  89.2k|        ctx->parsed_row_count++;
  654|  89.2k|    }
  655|       |
  656|  89.2k|cleanup:
  657|  89.2k|    free(string);
  658|  89.2k|    return retval;
  659|  89.2k|}
readstat_xport_read.c:xport_update_progress:
   43|  46.2k|static readstat_error_t xport_update_progress(xport_ctx_t *ctx) {
   44|  46.2k|    readstat_io_t *io = ctx->io;
   45|  46.2k|    return io->update(ctx->file_size, ctx->handle.progress, ctx->user_ctx, io->io_ctx);
   46|  46.2k|}
readstat_xport_read.c:xport_ctx_free:
   53|  1.81k|static void xport_ctx_free(xport_ctx_t *ctx) {
   54|  1.81k|    if (ctx->variables) {
  ------------------
  |  Branch (54:9): [True: 1.23k, False: 573]
  ------------------
   55|  1.23k|        int i;
   56|   670k|        for (i=0; i<ctx->var_count; i++) {
  ------------------
  |  Branch (56:19): [True: 669k, False: 1.23k]
  ------------------
   57|   669k|            if (ctx->variables[i])
  ------------------
  |  Branch (57:17): [True: 96.9k, False: 572k]
  ------------------
   58|  96.9k|                free(ctx->variables[i]);
   59|   669k|        }
   60|  1.23k|        free(ctx->variables);
   61|  1.23k|    }
   62|  1.81k|    if (ctx->converter) {
  ------------------
  |  Branch (62:9): [True: 0, False: 1.81k]
  ------------------
   63|      0|        iconv_close(ctx->converter);
   64|      0|    }
   65|       |
   66|  1.81k|    free(ctx);
   67|  1.81k|}

rt_open_handler:
    8|  1.81k|int rt_open_handler(const char *path, void *io_ctx) {
    9|  1.81k|    return 0;
   10|  1.81k|}
rt_close_handler:
   12|  1.81k|int rt_close_handler(void *io_ctx) {
   13|  1.81k|    return 0;
   14|  1.81k|}
rt_seek_handler:
   17|  7.79k|        readstat_io_flags_t whence, void *io_ctx) {
   18|  7.79k|    rt_buffer_ctx_t *buffer_ctx = (rt_buffer_ctx_t *)io_ctx;
   19|  7.79k|    readstat_off_t newpos = -1;
   20|  7.79k|    if (whence == READSTAT_SEEK_SET) {
  ------------------
  |  Branch (20:9): [True: 1.81k, False: 5.98k]
  ------------------
   21|  1.81k|        newpos = offset;
   22|  5.98k|    } else if (whence == READSTAT_SEEK_CUR) {
  ------------------
  |  Branch (22:16): [True: 4.16k, False: 1.81k]
  ------------------
   23|  4.16k|        newpos = buffer_ctx->pos + offset;
   24|  4.16k|    } else if (whence == READSTAT_SEEK_END) {
  ------------------
  |  Branch (24:16): [True: 1.81k, False: 0]
  ------------------
   25|  1.81k|        newpos = buffer_ctx->buffer->used + offset;
   26|  1.81k|    }
   27|       |
   28|  7.79k|    if (newpos < 0)
  ------------------
  |  Branch (28:9): [True: 0, False: 7.79k]
  ------------------
   29|      0|        return -1;
   30|       |
   31|  7.79k|    if (newpos > buffer_ctx->buffer->used)
  ------------------
  |  Branch (31:9): [True: 86, False: 7.70k]
  ------------------
   32|     86|        return -1;
   33|       |
   34|  7.70k|    buffer_ctx->pos = newpos;
   35|  7.70k|    return newpos;
   36|  7.79k|}
rt_read_handler:
   38|   202k|ssize_t rt_read_handler(void *buf, size_t nbytes, void *io_ctx) {
   39|   202k|    rt_buffer_ctx_t *buffer_ctx = (rt_buffer_ctx_t *)io_ctx;
   40|   202k|    ssize_t bytes_copied = 0;
   41|   202k|    ssize_t bytes_left = buffer_ctx->buffer->used - buffer_ctx->pos;
   42|   202k|    if (nbytes <= bytes_left) {
  ------------------
  |  Branch (42:9): [True: 201k, False: 1.04k]
  ------------------
   43|   201k|        memcpy(buf, buffer_ctx->buffer->bytes + buffer_ctx->pos, nbytes);
   44|   201k|        bytes_copied = nbytes;
   45|   201k|    } else if (bytes_left > 0) {
  ------------------
  |  Branch (45:16): [True: 147, False: 894]
  ------------------
   46|    147|        memcpy(buf, buffer_ctx->buffer->bytes + buffer_ctx->pos, bytes_left);
   47|    147|        bytes_copied = bytes_left;
   48|    147|    }
   49|   202k|    buffer_ctx->pos += bytes_copied;
   50|   202k|    return bytes_copied;
   51|   202k|}
rt_update_handler:
   54|  46.2k|        void *user_ctx, void *io_ctx) {
   55|  46.2k|    if (!progress_handler)
  ------------------
  |  Branch (55:9): [True: 46.2k, False: 0]
  ------------------
   56|  46.2k|        return READSTAT_OK;
   57|       |
   58|      0|    rt_buffer_ctx_t *buffer_ctx = (rt_buffer_ctx_t *)io_ctx;
   59|       |
   60|      0|    if (progress_handler(1.0 * buffer_ctx->pos / buffer_ctx->buffer->used, user_ctx))
  ------------------
  |  Branch (60:9): [True: 0, False: 0]
  ------------------
   61|      0|        return READSTAT_ERROR_USER_ABORT;
   62|       |
   63|      0|    return READSTAT_OK;
   64|      0|}

