<commit_before>/*
 * tns.c
 *
 * Copyright 2011, <NAME>
 *
 * Licensed under Three-Clause BSD
 *
 */

#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <assert.h>
#include "tns.h"
#ifdef _TNS_FDPARSE
#include <unistd.h>
#endif

#define GUARD(got, error) if ((got) == (error)) return NULL
#define JUMP(got, error, jump) do{if ((got) == (error)) {goto jump;}}while(0)

#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
#endif

struct CTNetStr{
    tns_type    type;
    union {
        void *  ptr;
        int     integer;
        char *  str;
    } payload;
};

tnetstr None = {tns_None, NULL};
tnetstr Yes = {.type = tns_Boolean, .payload.integer = 1};
tnetstr No = {.type = tns_Boolean, .payload.integer = 0};


static int next_fragment(char * in, char ** start, size_t * size, tns_type * );
static tnetstr * parse_Boolean(char * input, size_t len);
static tnetstr * parse_Integer(char * input, size_t len);
static tnetstr * parse_HT(char * input, size_t len);
static tnetstr * parse_List(char * input, size_t len);
static tnetstr * parse_String(char * input, size_t len);
static tnetstr * new_tnetstr(tns_type type);
static tns_type get_msg_type(char t);
static int get_msg_size(char * input, size_t * trailing, size_t * offset);
static int free_tns_ht(size_t s, const char * k, const void * v, void * d);

/* Public functions */

#ifdef _TNS_FDPARSE


/* TODO: make a nonblocking-enabled version of this function */
tnetstr * tns_fdparse(int fd){
    size_t n = 0;
    char c = 0;
    char * payload = NULL;
    tns_type type = tns_Unknown;
    char acc = 0;

    while (read(fd, &c, 1) != -1 && c != ':'){
        acc++;
        if (acc < 10 && isdigit(c) && c - '0' =< SIZE_MAX - n)
            n = 10 * n + c - '0';
        else
            return NULL;
    }
    
    GUARD(acc, 0);

    payload = malloc(n);
    read(fd, payload, n);
    read(fd, &c, 1);
    type = get_msg_type(c);

    return tns_parser(payload, n, type);
}

#endif

tnetstr * tns_fileparse(FILE * file){
    char * payload = NULL;
    tns_type type = tns_Unknown;
    int size = 0;
    int total = 0;

	if (file == NULL)
		return NULL;
		
    GUARD(fscanf(file, "%d:", &size), 0);
    if (size > SIZE_MAX)
		return NULL;
    
    payload = malloc(size);
    GUARD(payload, NULL);

    total = fread(payload, (size_t) size, 1, file);
    if (total < size && ferror(file)){
		free(payload);
        return NULL;
	}

    return tns_parser(payload, size, type);
}

tnetstr * tns_parse(char * input){
    size_t trailing = 0;
    size_t offset = 0;
    int total = -1;
    char * payload = NULL;
    tns_type type = tns_Unknown;

	GUARD(input, NULL);
    total = get_msg_size(input, &trailing, &offset);
    GUARD(total, -1);
    
    payload = input + offset;
    type = get_msg_type((size_t) input[total]);

    return tns_parser(payload, trailing, type);
}


tnetstr * tns_parser(char * payload, size_t size, tns_type type){
    tnetstr * ret = NULL;
    
    GUARD(payload, NULL);

    switch(type){

        case tns_String:
            ret = parse_String(payload, size);
            break;

        case tns_None:
            ret = new_tnetstr(tns_None);
            break;

        case tns_List:
            ret = parse_List(payload, size);
            break;

        case tns_Boolean:
            ret = parse_Boolean(payload, size);
            break;

        case tns_Integer:
            ret = parse_Integer(payload, size);
            break;

        case tns_HT:<commit_msg>Parser dies if Null is encoded with len > 0<commit_after>/*
 * tns.c
 *
 * Copyright 2011, <NAME>
 *
 * Licensed under Three-Clause BSD
 *
 */

#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
#include <assert.h>
#include "tns.h"
#ifdef _TNS_FDPARSE
#include <unistd.h>
#endif

#define GUARD(got, error) if ((got) == (error)) return NULL
#define JUMP(got, error, jump) do{if ((got) == (error)) {goto jump;}}while(0)

#ifndef SIZE_MAX
#define SIZE_MAX ((size_t)-1)
#endif

struct CTNetStr{
    tns_type    type;
    union {
        void *  ptr;
        int     integer;
        char *  str;
    } payload;
};

tnetstr None = {tns_None, NULL};
tnetstr Yes = {.type = tns_Boolean, .payload.integer = 1};
tnetstr No = {.type = tns_Boolean, .payload.integer = 0};


static int next_fragment(char * in, char ** start, size_t * size, tns_type * );
static tnetstr * parse_Boolean(char * input, size_t len);
static tnetstr * parse_Integer(char * input, size_t len);
static tnetstr * parse_HT(char * input, size_t len);
static tnetstr * parse_List(char * input, size_t len);
static tnetstr * parse_String(char * input, size_t len);
static tnetstr * new_tnetstr(tns_type type);
static tns_type get_msg_type(char t);
static int get_msg_size(char * input, size_t * trailing, size_t * offset);
static int free_tns_ht(size_t s, const char * k, const void * v, void * d);

/* Public functions */

#ifdef _TNS_FDPARSE


/* TODO: make a nonblocking-enabled version of this function */
tnetstr * tns_fdparse(int fd){
    size_t n = 0;
    char c = 0;
    char * payload = NULL;
    tns_type type = tns_Unknown;
    char acc = 0;

    while (read(fd, &c, 1) != -1 && c != ':'){
        acc++;
        if (acc < 10 && isdigit(c) && c - '0' =< SIZE_MAX - n)
            n = 10 * n + c - '0';
        else
            return NULL;
    }
    
    GUARD(acc, 0);

    payload = malloc(n);
    read(fd, payload, n);
    read(fd, &c, 1);
    type = get_msg_type(c);

    return tns_parser(payload, n, type);
}

#endif

tnetstr * tns_fileparse(FILE * file){
    char * payload = NULL;
    tns_type type = tns_Unknown;
    int size = 0;
    int total = 0;

	if (file == NULL)
		return NULL;
		
    GUARD(fscanf(file, "%d:", &size), 0);
    if (size > SIZE_MAX)
		return NULL;
    
    payload = malloc(size);
    GUARD(payload, NULL);

    total = fread(payload, (size_t) size, 1, file);
    if (total < size && ferror(file)){
		free(payload);
        return NULL;
	}

    return tns_parser(payload, size, type);
}

tnetstr * tns_parse(char * input){
    size_t trailing = 0;
    size_t offset = 0;
    int total = -1;
    char * payload = NULL;
    tns_type type = tns_Unknown;

	GUARD(input, NULL);
    total = get_msg_size(input, &trailing, &offset);
    GUARD(total, -1);
    
    payload = input + offset;
    type = get_msg_type((size_t) input[total]);

    return tns_parser(payload, trailing, type);
}


tnetstr * tns_parser(char * payload, size_t size, tns_type type){
    tnetstr * ret = NULL;
    
    GUARD(payload, NULL);

    switch(type){

        case tns_String:
            ret = parse_String(payload, size);
            break;

        case tns_None:
			GUARD(size, 0);
            ret = new_tnetstr(tns_None);
            break;

        case tns_List:
            ret = parse_List(payload, size);
            break;

        case tns_Boolean:
            ret = parse_Boolean(payload, size);
            break;

        case tns_Integer:
            ret = parse_Integer(payload, size);
            break;

        case tns_HT:
{'fraction_non_alphanumeric': 0.13341804320203304, 'fraction_numerical': 0.00847098686997035, 'mean_word_length': 2.6198262646908534, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 22, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3155804', 'n_tokens_mistral': 2669, 'n_tokens_neox': 2544, 'n_words': 701}