#ifndef STR_H
#define STR_H

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include <stdarg.h>

#define XSTR(S)	STR(S)
#define STR(S)	#S


struct str {
	uint32_t cap;
	uint32_t len;
	char *ptr;
};


bool charisalpha(char c);

bool charisnum(char c);

bool charisblank(char c);

bool charislinebreak(char c);

bool charisspace(char c);

char lowerchar(char c);

uint32_t len(const char *s);

uint32_t lowers(char *s);

struct str str(char *s);

struct str nstr(uint32_t cap);

#define slen(s) (sizeof(s)-1)

#define sstr(s) ((struct str){.cap = 0, .len = slen(s), .ptr = s})

#define snstr(s, n) ((struct str){.cap = 0, .len = n, .ptr = s})

int resize_str(struct str *s, uint32_t nsize);

struct str dup_str(struct str s);

uint32_t lowerstr(struct str s);

struct str utostr(uint64_t n, int b);

// TODO: remove all instances of utostr where its not needed
#define sutostr(n) sstr(XSTR(n))

uint64_t strtou(struct str s);

#define NUMSTRS(...) (sizeof((struct str[]){{0}, ##__VA_ARGS__})/sizeof(struct str)-1)

uint64_t len_nstrs(uint64_t n, ...);

#define len_strs(...) \
	len_nstrs(NUMSTRS(__VA_ARGS__), __VA_ARGS__)

#define copy_str(dest, src) \
	if(dest.ptr != NULL && src.ptr != NULL){	\
		memcpy((dest).ptr+(dest).len, (src).ptr, (src).len); \
		(dest).len += (src).len;	\
	}

#define move_str(dest, src) \
	if(dest.ptr != NULL && src.ptr != NULL){	\
		memmove((dest).ptr+(dest).len, (src).ptr, (src).len); \
		(dest).len += (src).len;	\
	}

void copy_nstrs(struct str dst, uint64_t n, ...);

void move_nstrs(struct str dst, uint64_t n, ...);

#define copy_strs(d, ...) \
	copy_nstrs(d, NUMSTRS(__VA_ARGS__), __VA_ARGS__); \
	(d).len += len_nstrs(NUMSTRS(__VA_ARGS__), __VA_ARGS__)

#define move_strs(d, ...) \
	move_nstrs(d, NUMSTRS(__VA_ARGS__), __VA_ARGS__); \
	(d).len += len_nstrs(NUMSTRS(__VA_ARGS__), __VA_ARGS__)

struct str read_delim(char *buf, char d);

struct str sread_delim(char *buf, char d);

struct str read_delim_f(char *buf, bool (*func)(char), bool func_cond);

struct str sread_delim_f(char *buf, bool (*func)(char), bool func_cond);

uint32_t get_line_len(char *buf);

void fd_to_str(struct str *s, int fd, uint32_t len);

void file_to_str(struct str *s, FILE *fp, uint32_t len);

void print_str(struct str s);

void free_str(struct str *s);

char *charinstr(char c, struct str s); // move somewhere relevant

#endif
