WONKY



LOG | FILES | OVERVIEW


F diff --git a/build/cmake/libs/misc.txt b/build/cmake/libs/misc.txt --- a/build/cmake/libs/misc.txt +++ b/build/cmake/libs/misc.txt
src/misc/queue.c
src/misc/stack.c
src/misc/wonky_malloc.c
+ src/misc/wonky_array.c
)
F diff --git a/src/common.h b/src/common.h --- a/src/common.h +++ b/src/common.h
#define WONKY_COMMON_H WONKY_COMMON_H
#include <config.h>
+ #include <stddef.h>
#define SHOULD_NOT_REACH_HERE (!"should not reach here")
#define FIRST_TOKEN_IN_TOKEN_QUEUE 0
F diff --git a/src/misc/galib.c b/src/misc/galib.c new file mode 100644 --- /dev/null +++ b/src/misc/galib.c
+ #ifndef GALIB_C
+ #define GALIB_C GALIB_C
+
+ #if defined(GALIB_ALL)
+
+ /*this is the list of all the options that galib takes*/
+
+ #define GALIB_ALL
+ #define GALIB_REGEX
+ #define GALIB_CURL /*-lcurl*/
+ #define GALIB_POSIX
+ #define GALIB_WEB
+ #define GALIB_SYSTEM
+ #define GALIB_TIDY /*-ltidy*/
+ #define GALIB_RESOLV /*-lresolv*/
+ #define GALIB_XML /*-lxml2*/
+ #define GALIB_MYSQL /*-lmysqlclient*/
+ #define GALIB_OPENSSL /*-lcrypto*/
+ #endif
+
+ #ifdef GALIB_SYSTEM
+ #define GALIB_POSIX
+ #define GALIB_REGEX
+ #endif
+
+ #ifdef GALIB_WEB
+ #define GALIB_CURL
+ #define GALIB_TIDY
+ #define GALIB_RESOLV
+ #endif
+
+ #ifdef GALIB_RSS
+ #define GALIB_CURL
+ #define GALIB_XML
+ #endif
+
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <stdint.h>
+ #include <string.h>
+ #include <stddef.h>
+ #include <limits.h>
+ #include <stdarg.h>
+ #include <math.h>
+
+ #ifdef GALIB_REGEX
+ #include <regex.h>
+ #endif
+
+ #ifdef GALIB_POSIX
+ #include <sys/types.h>
+ #include <sys/wait.h>
+ #include <unistd.h>
+ #endif
+
+ #ifdef GALIB_CURL
+ #include <curl/curl.h> /*curl-config --libs --cflags*/
+ #endif
+
+ #ifdef GALIB_TIDY
+ #include <tidy/tidy.h>
+ #include <tidy/tidybuffio.h>
+ #endif
+
+ #ifdef GALIB_RESOLV
+ #include <netinet/in.h>
+ //#include <arpa/nameserver.h>
+ #include <resolv.h>
+ #endif
+
+ #ifdef GALIB_XML
+ #include <libxml/parser.h> /*xml2-config --libs --cflags*/
+ #include <libxml/tree.h>
+ #endif
+
+ #ifdef GALIB_MYSQL
+ #include <mysql.h> /*mysql_config --include --libs ; -lmysqlclient*/
+ #endif
+
+ #ifdef GALIB_OPENSSL
+ #include <openssl/evp.h>
+ #include <openssl/rand.h>
+ #endif
+
+ #ifndef ga_malloc
+ #define ga_malloc(x) malloc(x)
+ #endif
+ #ifndef ga_free
+ #define ga_free(x) free(x)
+ #endif
+ #ifndef ga_realloc
+ #define ga_realloc realloc
+ #endif
+ #ifndef ga_abort
+ #define ga_abort abort
+ #endif
+ #ifndef ga_exit
+ #define ga_exit exit
+ #endif
+
+ /*use this to tag pointers to ga_arrays*/
+ #define _garray
+
+ /*
+ TODO:
+ openssl stuff
+ sqlite / etc ...
+ general graph stuff
+ utf8 stuff
+ command line argument parsing
+ signal stuff
+ seccomp
+ ssh
+ dns stuff
+ fuzzing stuff
+ tor stuff
+ torrent stuff
+ gdb stuff
+ image magick
+ str_explode with regex
+ gnuplot/general plotting stuff (over points mostly)
+ opencl stuff
+ curl user agent randomisation
+ str to ascii art
+ sdl stuff
+ opengl stuff
+ game 2d stuff
+ game 3d stuff
+ elf file parser
+ ncurses stuff
+ change uint32_t to glyph_t in string operations
+ */
+
+
+
+ typedef int ga_hash_t;
+ typedef unsigned long ga_usek_t;
+
+ enum ga__scanformat_modifier
+ {
+ GA__MOD_NONE,
+ GA__MOD_SHORT,
+ GA__MOD_SHORT_SHORT,
+ GA__MOD_LONG,
+ GA__MOD_LONG_LONG,
+ GA__MOD_LONG_DOUBLE,
+ GA__MOD_INTMAX,
+ GA__MOD_SIZE_T,
+ GA__MOD_PTRDIFF,
+ GA__MOD_END
+ };
+ enum ga__scanformat_conversion
+ {
+ GA__CONVERSION_INT_DECIMAL,
+ GA__CONVERSION_INT_UNSIGNED_DECIMAL,
+ GA__CONVERSION_INT_OCTAL,
+ GA__CONVERSION_INT_HEXADECIMAL,
+ GA__CONVERSION_DOUBLE_EXPONENT,
+ GA__CONVERSION_DOUBLE_DECIMAL,
+ GA__CONVERSION_DOUBLE_HEXADECIMAL,
+ GA__CONVERSION_CHAR,
+ GA__CONVERSION_CSTRING,
+ GA__CONVERSION_POINTER,
+ GA__CONVERSION_PERCENT,
+ /*custom*/
+ /*
+ * prints n bits from memory at addres p starting from bit m
+ * takes argumens p , n , m
+ * */
+ GA__CONVERSION_BITS,
+ GA__CONVERSION_END
+ };
+ struct ga__scanformat
+ {
+ size_t forward_crawl;
+ enum ga__scanformat_modifier modifier;
+ enum ga__scanformat_conversion conversion;
+ _Bool alternate_form;
+ };
+ void ga__parse_scan_format(const char *begining, struct ga__scanformat *destination);
+
+ enum ga_stream_type
+ {
+ GA_STREAM_TYPE_OOM,
+ GA_STREAM_TYPE_STRING,
+ GA_STREAM_TYPE_FILE,
+ GA_STREAM_TYPE_SYSTEM,
+ GA_STREAM_TYPE_CURL,
+ GA_STREAM_TYPE_END
+ };
+
+ struct ga_stream
+ {
+ ssize_t (*read)(void *state,void *dst,size_t num_bytes);
+ ssize_t (*write)(void *state,void *src,size_t num_bytes);
+ _Bool (*fseek)(void *state,size_t where,int whence);
+ _Bool (*eof)(void *state);
+ enum ga_stream_type type;
+
+ void *state;
+ };
+
+
+ ssize_t ga_read(struct ga_stream *s,void *dst,size_t num_bytes);
+ ssize_t ga_write(struct ga_stream *s,void *src,size_t num_bytes);
+ ssize_t ga_fseek(struct ga_stream *s,size_t where,int whence);
+ ssize_t ga_eof(struct ga_stream *s);
+ int ga_printf(const char *format,...);
+ int ga_vprintf(const char *format,va_list args);
+ int ga_fprintf(struct ga_stream *s,const char *format,...);
+ int ga_vfprintf(struct ga_stream *s,const char *format,va_list args);
+
+ void ga__from_scanformat(struct ga__scanformat *fmt,va_list args,struct ga_stream *destination);
+
+ ssize_t ga_stream_int_to_decimal(struct ga_stream *s,intmax_t a);
+ ssize_t ga_stream_uint_to_decimal(struct ga_stream *s,uintmax_t a);
+ ssize_t ga_stream_uint_to_hexadecimal(struct ga_stream *s,uintmax_t a);
+ ssize_t ga_stream_uint_to_octal(struct ga_stream *s,uintmax_t a);
+ ssize_t ga_stream_double_to_decimal(struct ga_stream *s,double d);
+ ssize_t ga_stream_from_fraction(struct ga_stream *s,uint64_t a,uint64_t b,int precision);
+
+
+ ssize_t ga__FILE_read(void *state,void *dst,size_t num_bytes);
+ ssize_t ga__FILE_write(void *state,void *src,size_t num_bytes);
+ _Bool ga__FILE_fseek(void *state,size_t where,int whence);
+ _Bool ga__FILE_eof(void *state);
+
+ ssize_t ga__fail_read(void *state,void *dst,size_t num_bytes);
+ ssize_t ga__fail_write(void *state,void *src,size_t num_bytes);
+ _Bool ga__fail_fseek(void *state,size_t where,int whence);
+ _Bool ga__fail_eof(void *state);
+
+ struct ga_stream ga_stream_from_file(FILE *f);
+
+ void ga_stream_delete(struct ga_stream *s);
+
+
+ /*generic resizable array stuff*/
+ #define gar__hash_sneed 0xBABACECA
+ struct ga_array_internals
+ {
+ size_t size;
+ size_t capacity;
+ size_t element_size;
+ unsigned char bytes[];
+ };
+
+ void* _garray gar_alloc(size_t number_of_elements,size_t element_size);
+ void* _garray gar_expand(void * _garray arr,size_t expansion_size);
+ void* _garray gar_resize(void * _garray arr,size_t new_size);
+ void gar_delete_elements(void * _garray arr,size_t start_index,size_t number_of_elements);
+ void gar_shrink(void * _garray arr,size_t shrink_size);
+ void gar_delete(void * _garray arr);
+ size_t gar_size(void * _garray arr);
+ size_t gar_last_index(void * _garray arr);
+ _Bool gar_oom(void * _garray arr);
+ void _garray * gar_copy(void * _garray arr);
+ struct ga_array_internals* gar_get_internals(void * _garray arr);
+ ga_hash_t gar_hash(void * _garray arr);
+
+ ga_hash_t ga_hash_bytes(void *bytes,size_t number_of_bytes);
+
+
+
+ /*text stuff*/
+ struct ga_str
+ {
+ /*cstring*/
+ unsigned char * _garray cs; /*ga_array that is also \0 terminated*/
+ size_t number_of_glyphs;
+ };
+
+ struct ga_str_mark
+ {
+ size_t beginning_byte_index;
+ size_t size;
+ };
+
+
+ struct ga_str gas_make();
+ struct ga_str gas_copy(const struct ga_str str);
+ struct ga_str gas_read_file(const char *filename);
+ struct ga_str gas_cstr(const char *str);
+ struct ga_str gas_fread_line(FILE *in);
+ struct ga_str gas_fread_input(FILE *in);
+ size_t gas_number_of_bytes(const struct ga_str str);
+ size_t gas_recount_glyphs(struct ga_str *str);
+ size_t gas_length(const struct ga_str str);
+ _Bool gas_oom(struct ga_str str);
+
+ /*get element(unicode) value from index'th glyph, indices starting from 0*/
+ uint32_t gas_glyph(const struct ga_str str,size_t glyph_index);
+ /*returns the index of the starting byte of the utf8 encoded glyph_indexed glyph*/
+ size_t gas_glyph_position(const struct ga_str str,size_t glyph_index);
+ /*returns index of starting byte of next valid glyph after byte_index'th byte in string*/
+ size_t gas_following_glyph_position(const struct ga_str str,size_t byte_index);
+ /*
+ returns index of starting byte of next valid glyph going backwards in string after
+ byte_index'th byte in string.
+ TODO: currently not implemented and returns byte_index
+ */
+ size_t gas_previous_glyph_position(const struct ga_str str,size_t byte_index);
+ /*
+ returns glyph value of utf8 encoded glyph starting at byte_index'th index'th byte of string
+ if utf8 encoded glyph at byte_index'th byte is invalid this function returns 0
+ */
+ uint32_t gas_glyph_at_position(const struct ga_str str,size_t byte_index);
+ struct ga_str_mark* gas_mark_lines(const struct ga_str str); /*returns a ga_array of marks*/
+
+
+
+ _Bool gas_push_codepoint(struct ga_str *str,uint32_t ch);
+ _Bool gas_push_byte(struct ga_str *str,unsigned char ch);
+ _Bool gas_append(struct ga_str *str,const char *right); /*right is \0 terminated*/
+ _Bool gas_preppend(struct ga_str *str,char *left); /*left is \0 terminated*/
+ _Bool gas_insert(struct ga_str *str,char *infix,size_t glyph_index);/*infix is \0 terminated*/
+ _Bool gas_delete_chars(struct ga_str *str,size_t starting_glyph_index,size_t number_of_glyphs);
+
+ _Bool gas_to_file(const struct ga_str str,const char *filename);
+ struct ga_str gas_read_file(const char *filename);
+
+ struct ga_str gas_read_line(FILE *in);
+ struct ga_str gas_read_input(FILE *in);
+
+ _Bool gas_eqal(const struct ga_str a,const struct ga_str b);
+ _Bool gas_cequal(const struct ga_str a,const char *b);
+
+
+ int gas_printf(struct ga_str *destination,const char *format,...);
+ int gas_vprintf(struct ga_str *destination,const char *format,va_list args);
+ void gas__from_scanformat(struct ga__scanformat *fmt,va_list args,struct ga_str *destination);
+
+ int gas_sscanf(struct ga_str *source,const char *format,...);
+ int gas_vsscanf(struct ga_str *source,const char *format,va_list args);
+
+ void gas__from_scanformat(struct ga__scanformat *fmt,va_list args,struct ga_str *destination);
+
+ void gas_normalize(struct ga_str *str);
+
+ ga_hash_t gas_hash(struct ga_str str);
+
+
+
+ struct gas__stream_state
+ {
+ struct ga_str *str;
+ size_t where;
+ };
+
+ ssize_t gas__stream_read(void *state,void *dst,size_t num_bytes);
+ ssize_t gas__stream_write(void *state,void *src,size_t num_bytes);
+ _Bool gas__stream_fseek(void *state,size_t where,int whence);
+ _Bool gas__stream_eof(void *state);
+
+ struct ga_stream gas_stream(struct ga_str *str);
+ void gas_stream_delete(struct ga_stream *stream);
+
+
+ void gas_delete(struct ga_str *str);
+
+ short ga__utf8_get_glyph_size_from_starting_codepoint(unsigned char leading_byte);
+ short ga__utf8_glyph_size(struct ga_str str,size_t byte_index);
+ uint32_t ga__utf8_glyph_value(struct ga_str str,size_t byte_index,short glyph_size);
+ short ga__utf8_codepoint_size(uint32_t codepoint);
+ void ga__utf8_encode_codepoint(unsigned char *where,uint32_t codepoint,short size);
+
+
+ /*virtual filesystem stuff*/
+ enum ga_vfs_entry_type
+ {
+ GA_VFS_ENTRY_TYPE_FILE,
+ GA_VFS_ENTRY_TYPE_DIRECTORY,
+ GA_VFS_ENTRY_TYPE_END
+ };
+ struct ga_vfs_entry
+ {
+ enum ga_vfs_entry_type type;
+ };
+ struct ga_vfs
+ {
+ struct ga_vfs_entry* (*get_root)();
+ struct ga_vfs_entry* (*get_first_child)(struct ga_vfs_entry *parent);
+ struct ga_vfs_entry* (*get_next_sibling)(struct ga_vfs_entry *sibling);
+ char* (*get_name)(struct ga_vfs_entry *entry);
+ struct ga_stream (*open)(struct ga_vfs_entry *entry);
+ };
+
+
+
+
+
+ #ifdef GALIB_REGEX
+ void ga_grep_lines(ga_lines_t *lines,char *regex);/*deletes non matching lines*/
+ _Bool ga_grep_line(char *line,char *regex);/*works with C strings and ga_str_t*/
+ #endif
+
+
+ /*float = 1 bit sign | 8 bit exponent | 23 bit mantissa*/
+ _Bool ga_float_is_negative(float f);
+ int16_t ga_float_get_exponent(float f);
+ uint32_t ga_float_get_mantissa(float f);
+ float ga_float_set_sign(float f,_Bool is_negative);
+ float ga_float_set_exponent(float f,int16_t exponent);
+ float ga_float_set_base(float f,uint32_t mantissa);
+
+ /*double = 1 bit sign | 11 bit exponent | 52 bit mantissa*/
+ _Bool ga_double_is_negative(double d);
+ int16_t ga_double_get_exponent(double d);
+ uint64_t ga_double_get_mantissa(double d);
+ double ga_double_set_sign(double d,_Bool is_negative);
+ double ga_double_set_exponent(double d,int16_t exponent);
+ double ga_double_set_mantissa(double d,uint64_t mantissa);
+
+
+ size_t ga_file_number_of_remaning_bytes(FILE *file);
+ size_t ga_file_size(FILE *file);
+ size_t ga_file_number_of_remaining_lines(FILE *file);
+
+
+
+
+
+
+
+ /*hash map stuff*/
+
+
+
+
+
+ struct ga__hash_table_underarray_slot
+ {
+ _Bool is_alive:1;
+ _Bool is_tombstone:1;
+ ga_hash_t hash;
+ size_t where_in_array;
+ };
+ struct ga_hash_table
+ {
+ size_t used_slots;
+ size_t tombstones;
+
+ size_t used_slots_threshold;
+ size_t tombstones_threshold;
+
+ size_t number_of_slots;
+
+ _Bool oom;
+
+ struct ga__hash_table_underarray_slot slots[];
+ };
+
+ #define ga__hash_table_init_slot_number 128
+ #define ga__hash_table_init_slots_thresholds 10
+ #define ga__hash_table_init_tombstones_thresholds 10
+
+
+ struct ga_hash_table* gah_make();
+ _Bool gah_oom(struct ga_hash_table *h);
+ ga_hash_t gah_hash_on_step(ga_hash_t hash,size_t step);
+ _Bool gah_slot_is_taken(struct ga_hash_table *h,ga_hash_t hash,size_t step);
+ _Bool gah_slot_is_tombstone(struct ga_hash_table *h,ga_hash_t hash,size_t step);
+ size_t gah_geti(struct ga_hash_table *h,ga_hash_t hash,size_t step);
+ size_t gah_get_slot_index(struct ga_hash_table *h,ga_hash_t hash,size_t step);
+ struct ga_hash_table* gah_expand(struct ga_hash_table *h);
+ struct ga_hash_table* gah_clean_tombstones(struct ga_hash_table *h);
+ struct ga_hash_table* gah_push(struct ga_hash_table *h,ga_hash_t hash,size_t step,size_t index);
+ struct ga_hash_table* gah_remove(struct ga_hash_table *h,ga_hash_t hash,size_t step);
+ void gah_delete(struct ga_hash_table *h);
+
+
+
+ struct ga_string_hash_table
+ {
+ struct ga_hash_table *table;
+ struct ga_str * _garray keys;
+ void * _garray values;
+ size_t value_size;
+ _Bool oom;
+ };
+
+ struct ga_string_hash_table* gahs_make(size_t value_size);
+ struct ga_string_hash_table* gahs_push(struct ga_string_hash_table *h,struct ga_str key,void *value);
+ struct ga_string_hash_table* gahs_remove(struct ga_string_hash_table *h,struct ga_str key);
+ void* gahs_get(struct ga_string_hash_table *h,struct ga_str key);
+ _Bool gahs_oom(struct ga_string_hash_table *h);
+ void gahs_delete(struct ga_string_hash_table *h);
+
+
+ struct ga_memory_hash_table
+ {
+ struct ga_hash_table *table;
+ void* _garray keys;
+ void* _garray values;
+ size_t key_size;
+ size_t value_size;
+ _Bool oom;
+ };
+
+ struct ga_memory_hash_table* gahm_make(size_t key_size,size_t value_size);
+ struct ga_memory_hash_table* gahm_push(struct ga_memory_hash_table *h,void* key,void* value);
+ struct ga_memory_hash_table* gahm_remove(struct ga_memory_hash_table *h,void* key);
+ void* gahm_get(struct ga_memory_hash_table *h,void* key);
+ _Bool gahm_oom(struct ga_memory_hash_table *h);
+ void gahm_delete(struct ga_memory_hash_table *h);
+
+
+
+ struct ga_list_head
+ {
+ struct ga_list_head *next,*previous;
+ };
+
+ void ga_list_head_init(struct ga_list_head *node);
+ struct ga_list_head* ga_list_find_first(struct ga_list_head *node);
+ struct ga_list_head* ga_list_find_last(struct ga_list_head *node);
+ void ga_list_push_front(struct ga_list_head *list_node,struct ga_list_head *new_node);
+ void ga_list_delete_node(struct ga_list_head *list_node);
+ void ga_list_push_after(struct ga_list_head *list_node,struct ga_list_head *new_node);
+ void ga_list_push_before(struct ga_list_head *list_node,struct ga_list_head *new_node);
+
+ struct ga_stack_head
+ {
+ struct ga_stack_head *next;
+ };
+ void ga_stack_init(struct ga_stack_head *node);
+ void ga_stack_push(struct ga_stack_head *top,struct ga_stack_head *new);
+ struct ga_stack_head* ga_stack_pop(struct ga_stack_head *top);
+
+
+
+ /*system stuff*/
+ void ga_die(const char *fmt, ...);
+
+
+ #ifdef GALIB_POSIX
+
+
+
+ struct ga_child
+ {
+ struct ga_str * _garray args;
+ struct ga_stream stdio;
+ pid_t pid;
+ };
+ struct ga__system_stream_state
+ {
+ int pipe_out;
+ int pipe_in;
+ _Bool has_cached_byte;
+ unsigned char cached_byte;
+ };
+ struct ga_child* ga_system(const char *format,...);
+ _Bool ga_child_executed(struct ga_child *child);
+ int ga_wait_child(struct ga_child *child);
+ _Bool ga_wait_child_timed(struct ga_child *child,ga_usek_t usek,int *ret);
+ void ga_delete_child(struct ga_child *child);
+
+ void ga__system_stream_delete(struct ga_stream *s);
+ ssize_t ga__system_stream_read(void *state,void *dst,size_t num_bytes);
+ ssize_t ga__system_stream_write(void *state,void *src,size_t num_bytes);
+ _Bool ga__system_stream_fseek(void *state,size_t where,int whence);
+ _Bool ga__system_stream_eof(void *state);
+ _Bool ga_is_executable_present(const char *exe);
+ #endif
+
+
+ /*internet stuff*/
+ #ifdef GALIB_CURL
+
+ enum ga_curl_type
+ {
+ GA_CURL_TYPE_HTTP_GET,
+ GA_CURL_TYPE_HTTP_POST,
+ GA_CURL_TYPE_END
+ };
+ struct ga_curl
+ {
+ enum ga_curl_type type;
+ struct ga_str url;
+ CURL *handle;
+ };
+
+ struct ga_curl_http_get
+ {
+ enum ga_curl_type type;
+ struct ga_str url;
+ CURL *handle;
+ CURLM *mhandle;
+ struct curl_slist *sent_headers;
+
+ struct ga_stream out;
+
+ struct ga_str * _garray returned_header_names;
+ struct ga_str * _garray returned_header_values;
+
+ _Bool still_running;
+
+ unsigned char * _garray buffer;
+ };
+
+
+ struct ga_curl_http_get* ga_curl_make_http_get_request(const char *url);
+ _Bool ga_curl_set_add_http_header(struct ga_curl *curl,const char *header_name,const char *header_value);
+ _Bool ga_curl_set_credentials(struct ga_curl *curl,const char *username,const char *password);
+ void ga_curl_delete(struct ga_curl *curl);
+
+ size_t ga__curl_get_read_callback(void *data,size_t size,size_t nmemb,void *closure);
+ ssize_t ga__curl_get_read(void *state,void *dst,size_t num_bytes);
+ ssize_t ga__curl_post_write(void *state,void *src,size_t num_bytes);
+ _Bool ga__curl_get_fseek(void *state,size_t where,int whence);
+ _Bool ga__curl_get_eof(void *state);
+
+ #endif
+
+ enum ga_html_node_type
+ {
+ GA_HTML_NODE_TYPE_TAG,
+ GA_HTML_NODE_TYPE_TEXT,
+ GA_HTML_NODE_TYPE_END
+ };
+ struct ga_html_document
+ {
+ struct ga_html_node * _garray nodes;
+ };
+ struct ga_html_node
+ {
+ enum ga_html_node_type type;
+ struct ga_str name;
+ struct ga_str text;
+ struct ga_str * _garray attribute_names;
+ struct ga_str * _garray attribute_values;
+ struct ga_html_node *parent;
+ struct ga_html_node ** _garray children;
+ };
+ struct ga__html_parse_info
+ {
+ unsigned char *buff;
+ struct ga_stream *input;
+ };
+ void ga_delete_html_document(struct ga_html_document *doc);
+ void ga_print_html_node(struct ga_stream *out,struct ga_html_node *node);
+ void ga_print_html_document(struct ga_stream *out,struct ga_html_document *doc);
+ struct ga_html_node* ga_html_get_path(struct ga_html_node *node,int depth,...);
+ ssize_t ga_html_attribute_index(struct ga_html_node *node,char *attr_name);
+ Bool ga__html_parse_eof_helper(void *closure);
+ int ga__html_parse_get_byte_helper(void *closure);
+ void ga__html_parse_unget_byte_helper(void *closure,byte bt);
+ void ga__print_html_node_inner(struct ga_stream *out,struct ga_html_node *node,size_t indent);
+
+ #ifdef GALIB_TIDY
+ #define GALIB__TIDY_PARSE_BUFFER_SIZE 1024
+ struct ga_html_node* _garray ga__tidy_node_to_ga_node_internal(TidyNode node,TidyDoc doc,struct ga_html_node **where_to_push,struct ga_html_node *parent);
+ size_t ga__get_number_of_html_nodes(TidyNode node,TidyDoc doc);
+ struct ga_html_document* _garray ga_html_parse(struct ga_stream *in);
+ struct ga_html_document* _garray ga__parse_tidy(struct ga_stream *in,_Bool is_xml);
+ #endif
+
+ #if 0
+
+ #ifdef GALIB_XML
+ struct ga_rss_channel_item
+ {
+ ga_str_t title;
+ ga_str_t link;
+ ga_str_t description;
+ ga_str_t author;
+ };
+ struct ga_rss_channel
+ {
+ /*these are only the mandatory elements (the other types are really stupid and not needed)*/
+ ga_str_t title;
+ ga_str_t author;
+ ga_str_t description;
+ struct ga_rss_channel_item *items; /*ga array of items*/
+ };
+ struct ga_html_node* ga_parse_xml(ga_str_t xml);
+ struct ga_rss_channel* ga_parse_rss_feed(ga_str_t rss);
+ void ga_delete_rss_feed(struct ga_rss_channel **feed);
+ #endif
+
+
+ #ifdef GALIB_MYSQL
+ enum ga_mysql_state
+ {
+ GA_MYSQL_STATE_START,
+ GA_MYSQL_STATE_USING_DATABASE,
+ GA_MYSQL_STATE_LOADING_ARGUMENTS,
+ GA_MYSQL_STATE_ERROR,
+ GA_MYSQL_STATE_END
+ };
+ struct ga_mysql
+ {
+ enum ga_mysql_state state;
+ MYSQL *connection;
+ MYSQL_STMT *statement;
+ MYSQL_BIND *bind;/*ga_array of binds: holds input*/
+ MYSQL_BIND *result_bind; /*ga_array of binds: holds ouput row*/
+ _Bool has_remaining_rows;
+ };
+
+ struct ga_mysql* ga_mysql_connect(const char *url,const char *user,const char *pass);
+ _Bool ga_mysql_use(struct ga_mysql *mysql,const char *database);
+ _Bool ga_mysql_prepare(struct ga_mysql *mysql,const char *statement);
+ void ga_mysql_disconnect(struct ga_mysql *mysql);
+
+
+ _Bool ga_mysql_bind_int(struct ga_mysql *mysql,size_t index,int data);
+ _Bool ga_mysql_bind_double(struct ga_mysql *mysql,size_t index,double data);
+ _Bool ga_mysql_bind_string(struct ga_mysql *mysql,size_t index,char *data);
+ _Bool ga_mysql_bind_blob(struct ga_mysql *mysql,size_t index,void *data,size_t data_size);
+ _Bool ga_mysql_execute(struct ga_mysql *mysql);
+ _Bool ga_mysql_has_remaining_rows(struct ga_mysql *mysql);
+ size_t ga_mysql_number_of_remaining_rows(struct ga_mysql *mysql);
+ _Bool ga_mysql_next_row(struct ga_mysql *mysql);
+
+ _Bool ga_mysql_get_int(struct ga_mysql *mysql,size_t index,int *destination);
+ _Bool ga_mysql_get_double(struct ga_mysql *mysql,size_t index,double *destination);
+ ga_str_t ga_mysql_get_string(struct ga_mysql *mysql,size_t index);
+ ga_str_t ga_mysql_get_blob(struct ga_mysql *mysql,size_t index);
+
+ _Bool ga_mysql_start_transaction(struct ga_mysql *mysql);
+ _Bool ga_mysql_end_transaction(struct ga_mysql *mysql);
+
+ _Bool ga_mysql_has_errors(struct ga_mysql *mysql);
+
+ _Bool ga__mysql_drop_prepared_statement(struct ga_mysql *mysql);
+ _Bool ga__mysql_reset_args(struct ga_mysql *mysql);
+ _Bool ga__mysql_reset_arg(MYSQL_BIND *bind,size_t arg_index);
+ void ga__mysql_clear_stored_results(struct ga_mysql *mysql);
+ #endif
+
+
+ #ifdef GALIB_OPENSSL
+ ga_bytes_t ga_openssl_hash(void *bytes,size_t num_bytes,char *hash_name);
+ ga_bytes_t ga_openssl_get_random_bytes(size_t num_bytes);
+ void ga_openssl_put_random_bytes(void *where,size_t num_bytes);
+ #endif
+
+ /*json stuff*/
+ enum ga_json_type
+ {
+ GA_JSON_ARRAY,
+ GA_JSON_OBJECT,
+ GA_JSON_STRING,
+ GA_JSON_FALSE,
+ GA_JSON_TRUE,
+ GA_JSON_NULL,
+ GA_JSON_NUMBER,
+ GA_JSON_TYPE_END
+ };
+ struct ga_json
+ {
+ enum ga_json_type type;
+ };
+ struct ga_json_array
+ {
+ enum ga_json_type type;
+ size_t number_of_elements;
+ struct ga_json **elements;
+ };
+ struct ga_json_object
+ {
+ enum ga_json_type type;
+ size_t number_of_attributes;
+ char **attribute_names;/*c strings are \0 terminated*/
+ struct ga_json **attribute_values;
+ };
+ struct ga_json_string
+ {
+ enum ga_json_type type;
+ size_t str_len;
+ ga_str_t str;
+ };
+ struct ga_json_number
+ {
+ enum ga_json_type type;
+ long double number;
+ };
+
+
+ struct ga_json* ga_parse_json(char *json,size_t json_size);
+ struct ga_json* ga__parse_object_inner(ga_str_t json);
+
+
+
+
+
+ #endif
+
+
+ ssize_t ga_read(struct ga_stream *s,void *dst,size_t num_bytes)
+ {
+ return s->read(s->state,dst,num_bytes);
+ }
+ ssize_t ga_write(struct ga_stream *s,void *src,size_t num_bytes)
+ {
+ return s->write(s->state,src,num_bytes);
+ }
+ ssize_t ga_fseek(struct ga_stream *s,size_t where,int whence)
+ {
+ return s->fseek(s->state,where,whence);
+ }
+ ssize_t ga_eof(struct ga_stream *s)
+ {
+ return s->eof(s->state);
+ }
+
+ int ga_printf(const char *format,...)
+ {
+ va_list args;
+ int ret;
+ struct ga_stream s=ga_stream_from_file(stdout);
+
+ va_start(args,format);
+ ret=ga_vfprintf(&s,format,args);
+ va_end(args);
+
+ fflush(stdout);
+ return ret;
+ }
+ int ga_vprintf(const char *format,va_list args)
+ {
+ struct ga_stream s=ga_stream_from_file(stdout);
+ return ga_vfprintf(&s,format,args);
+ }
+
+ int ga_fprintf(struct ga_stream *s,const char *format,...)
+ {
+ va_list args;
+ int ret;
+
+ va_start(args,format);
+ ret=ga_vfprintf(s,format,args);
+ va_end(args);
+
+ return ret;
+ }
+ int ga_vfprintf(struct ga_stream *s,const char *format,va_list args)
+ {
+ if(format==NULL || s==NULL)
+ return 0;
+
+ struct ga__scanformat fmt;
+
+ for(size_t i=0;format[i]!='\0';)
+ {
+ if(format[i]=='%')
+ {
+ ga__parse_scan_format(format+i,&fmt);
+ ga__from_scanformat(&fmt,args,s);
+ i+=fmt.forward_crawl;
+ }else
+ {
+ ga_write(s,(void*)format+i,1);
+ ++i;
+ }
+ }
+
+ }
+
+ ssize_t ga_stream_int_to_decimal(struct ga_stream *s,intmax_t a)
+ {
+ char hold[2]={0,0};
+ ssize_t ret=0;
+ ssize_t hret;
+
+ if(a==0)
+ return ga_write(s,"0",1);
+ else if(a<0)
+ {
+ ret=ga_write(s,"-",1);
+ a=-a;
+ }
+
+
+ while(a)
+ {
+ hold[0]=a%10+'0';
+ hret=ga_write(s,hold,1);
+ if(hret<0)
+ return -ret;
+ else
+ ret+=hret;
+ a/=10;
+ }
+ return ret;
+ }
+ ssize_t ga_stream_uint_to_decimal(struct ga_stream *s,uintmax_t a)
+ {
+ char hold[2]={0,0};
+ ssize_t ret=0;
+ ssize_t hret;
+
+ if(a==0)
+ return ga_write(s,"0",1);
+
+ while(a)
+ {
+ hold[0]=a%10+'0';
+ hret=ga_write(s,hold,1);
+ if(hret<0)
+ return -ret;
+ else
+ ret+=hret;
+ a/=10;
+ }
+ return ret;
+ }
+ ssize_t ga_stream_uint_to_hexadecimal(struct ga_stream *s,uintmax_t a)
+ {
+ char hold[2]={0,0};
+ ssize_t ret=0;
+ ssize_t hret;
+ if(a==0)
+ return ga_write(s,"0",1);
+
+ while(a)
+ {
+ if(a%16<10)
+ hold[0]=a%16+'0';
+ else
+ hold[0]=a%16-10+'A';
+ hret=ga_write(s,hold,1);
+ if(hret<0)
+ return -ret;
+ else
+ ret+=hret;
+ a/=16;
+ }
+ return ret;
+ }
+ ssize_t ga_stream_uint_to_octal(struct ga_stream *s,uintmax_t a)
+ {
+ char hold[2]={0,0};
+ ssize_t ret=0;
+ ssize_t hret;
+
+ if(a==0)
+ return ga_write(s,"0",1);
+
+ while(a)
+ {
+ hold[0]=a%8+'0';
+ hret=ga_write(s,hold,1);
+ if(hret<0)
+ return -ret;
+ else
+ ret+=hret;
+ a/=8;
+ }
+ return ret;
+ }
+ ssize_t ga_stream_double_to_decimal(struct ga_stream *s,double d)
+ {
+ int32_t exponent;
+ uint64_t mantissa;
+ ssize_t ret=0;
+ ssize_t hret;
+
+ exponent=ga_double_get_exponent(d)-1023;
+ mantissa=ga_double_get_mantissa(d)|0x0010000000000000;
+
+
+ for(mantissa;(mantissa&1)==0;mantissa>>=1,++exponent);
+ exponent-=52;
+
+ if(ga_double_is_negative(d))
+ {
+ hret=ga_write(s,"-",1);
+ if(hret<0)
+ return hret;
+ else
+ ret+=hret;
+ }
+
+ if(exponent<0)
+ {
+ if(-exponent<64)
+ {
+ hret=ga_stream_from_fraction(s,mantissa,(uint64_t)1<<-exponent,10);
+ if(hret<0)
+ return hret;
+ }else
+ {
+ hret=ga_stream_uint_to_decimal(s,mantissa);
+ if(hret<0)
+ return hret;
+ else
+ ret+=hret;
+ hret=ga_write(s,"e",1);
+ if(hret<0)
+ return -ret;
+ else
+ ret+=hret;
+ hret=ga_stream_int_to_decimal(s,exponent);
+ if(hret<0)
+ return -ret;
+ else
+ ret+=hret;
+ }
+ }else
+ {
+ hret=ga_stream_uint_to_decimal(s,mantissa);
+ if(hret<0)
+ return hret;
+ else
+ ret+=hret;
+ hret=ga_write(s,"e",1);
+ if(hret<0)
+ return -ret;
+ else
+ ret+=hret;
+
+ hret=ga_stream_int_to_decimal(s,exponent);
+ if(hret<0)
+ return -ret;
+ else
+ ret+=hret;
+ }
+
+
+ return ret;
+
+ }
+ ssize_t ga_stream_from_fraction(struct ga_stream *s,uint64_t a,uint64_t b,int precision)
+ {
+ char hold[2]={0,0};
+ ssize_t ret=0;
+ ssize_t hret;
+ if(a==0)
+ {
+ return ga_write(s,"0",1);
+ }else
+ {
+ hret=ga_stream_int_to_decimal(s,a/b);
+ if(hret<0)
+ return hret;
+ else
+ ret+=hret;
+
+ hret=ga_write(s,".",1);
+ if(hret<0)
+ return -ret;
+ else
+ ret+=hret;
+ a=a%b*10;
+ --precision;
+ while(precision>=0 && a!=0)
+ {
+ hold[0]=a/b+'0';
+ hret=ga_write(s,hold,1);
+ a=(a%b)*10;
+ --precision;
+ }
+ }
+
+ return ret;
+ }
+ void ga__from_scanformat(struct ga__scanformat *fmt,va_list args,struct ga_stream *s)
+ {
+ switch(fmt->conversion)
+ {
+ case GA__CONVERSION_PERCENT:
+ ga_write(s,"%",1);
+ break;
+ case GA__CONVERSION_INT_DECIMAL:
+ {
+ switch(fmt->modifier)
+ {
+ case GA__MOD_LONG:
+ ga_stream_int_to_decimal(s,va_arg(args,long int));
+ break;
+ case GA__MOD_LONG_LONG:
+ ga_stream_int_to_decimal(s,va_arg(args,long long int));
+ break;
+ case GA__MOD_INTMAX:
+ ga_stream_int_to_decimal(s,va_arg(args,intmax_t));
+ break;
+ case GA__MOD_SIZE_T:
+ ga_stream_int_to_decimal(s,va_arg(args,ssize_t));
+ break;
+ case GA__MOD_PTRDIFF:
+ ga_stream_int_to_decimal(s,va_arg(args,ptrdiff_t));
+ break;
+ default:
+ ga_stream_int_to_decimal(s,va_arg(args,int));
+ break;
+ }
+ }
+ break;
+ case GA__CONVERSION_INT_OCTAL:
+ {
+ switch(fmt->modifier)
+ {
+ case GA__MOD_LONG:
+ ga_stream_uint_to_octal(s,va_arg(args,long unsigned int));
+ break;
+ case GA__MOD_LONG_LONG:
+ ga_stream_uint_to_octal(s,va_arg(args,long long unsigned int));
+ break;
+ case GA__MOD_INTMAX:
+ ga_stream_uint_to_octal(s,va_arg(args,uintmax_t));
+ break;
+ case GA__MOD_SIZE_T:
+ ga_stream_uint_to_octal(s,va_arg(args,size_t));
+ break;
+ case GA__MOD_PTRDIFF:
+ ga_stream_uint_to_octal(s,va_arg(args,ptrdiff_t));
+ break;
+ default:
+ ga_stream_uint_to_octal(s,va_arg(args,unsigned int));
+ break;
+ }
+ }
+ break;
+ case GA__CONVERSION_INT_HEXADECIMAL:
+ {
+ switch(fmt->modifier)
+ {
+ case GA__MOD_LONG:
+ ga_stream_uint_to_hexadecimal(s,va_arg(args,long unsigned int));
+ break;
+ case GA__MOD_LONG_LONG:
+ ga_stream_uint_to_hexadecimal(s,va_arg(args,long long unsigned int));
+ break;
+ case GA__MOD_INTMAX:
+ ga_stream_uint_to_hexadecimal(s,va_arg(args,uintmax_t));
+ break;
+ case GA__MOD_SIZE_T:
+ ga_stream_uint_to_hexadecimal(s,va_arg(args,size_t));
+ break;
+ case GA__MOD_PTRDIFF:
+ ga_stream_uint_to_hexadecimal(s,va_arg(args,ptrdiff_t));
+ break;
+ default:
+ ga_stream_uint_to_hexadecimal(s,va_arg(args,unsigned int));
+ break;
+ }
+ }
+ break;
+ case GA__CONVERSION_INT_UNSIGNED_DECIMAL:
+ {
+ switch(fmt->modifier)
+ {
+ case GA__MOD_LONG:
+ ga_stream_uint_to_decimal(s,va_arg(args,long unsigned int));
+ break;
+ case GA__MOD_LONG_LONG:
+ ga_stream_uint_to_decimal(s,va_arg(args,long long unsigned int));
+ break;
+ case GA__MOD_INTMAX:
+ ga_stream_uint_to_decimal(s,va_arg(args,uintmax_t));
+ break;
+ case GA__MOD_SIZE_T:
+ ga_stream_uint_to_decimal(s,va_arg(args,size_t));
+ break;
+ case GA__MOD_PTRDIFF:
+ ga_stream_uint_to_decimal(s,va_arg(args,ptrdiff_t));
+ break;
+ default:
+ ga_stream_uint_to_decimal(s,va_arg(args,unsigned int));
+ break;
+ }
+ }
+ break;
+ case GA__CONVERSION_CHAR:
+ {
+ char a=va_arg(args,int);
+ ga_write(s,&a,1);
+ }
+ break;
+ case GA__CONVERSION_DOUBLE_DECIMAL:
+ {
+ switch(fmt->modifier)
+ {
+ case GA__MOD_LONG:
+ case GA__MOD_LONG_LONG:
+ ga_stream_double_to_decimal(s,va_arg(args,long double));
+ break;
+ default:
+ ga_stream_double_to_decimal(s,va_arg(args,double));
+ break;
+ }
+ }
+ break;
+ case GA__CONVERSION_CSTRING:
+ {
+ char *st=va_arg(args,char*);
+ if(st==NULL)
+ {
+ ga_write(s,"(null)",sizeof("(null)")-1);
+ }else
+ {
+ size_t l=strlen(st);
+ ga_write(s,st,l);
+ }
+ }
+ break;
+ case GA__CONVERSION_BITS:
+ {
+ const size_t start_bit=va_arg(args,size_t);
+ const size_t number_of_bits=va_arg(args,size_t);
+ const unsigned char *bytes=va_arg(args,unsigned char*);
+ size_t i;
+ char a;
+ for(i=start_bit;i<8 && i<number_of_bits+start_bit; ++i)
+ {
+ a=(!!(bytes[0]&(1<<(7-i)))+'0');
+ ga_write(s,&a,1);
+ }
+ for(i;i<number_of_bits+start_bit;++i)
+ {
+ a=(!!(bytes[i/8]&(1<<(7-i%8)))+'0');
+ ga_write(s,&a,1);
+ }
+ }
+ break;
+
+ }
+ }
+
+ ssize_t ga__FILE_read(void *state,void *dst,size_t num_bytes)
+ {
+ return fread(dst,1,num_bytes,(FILE*)state);
+ }
+ ssize_t ga__FILE_write(void *state,void *src,size_t num_bytes)
+ {
+ return fwrite(src,1,num_bytes,(FILE*)state);
+ }
+ _Bool ga__FILE_fseek(void *state,size_t where,int whence)
+ {
+ return !fseek((FILE*)state,where,whence);
+ }
+ _Bool ga__FILE_eof(void *state)
+ {
+ return feof((FILE*)state);
+ }
+
+ ssize_t ga__fail_read(void *state,void *dst,size_t num_bytes)
+ {
+ return -1;
+ }
+ ssize_t ga__fail_write(void *state,void *src,size_t num_bytes)
+ {
+ return -1;
+ }
+ _Bool ga__fail_fseek(void *state,size_t where,int whence)
+ {
+ return 0;
+ }
+ _Bool ga__fail_eof(void *state)
+ {
+ return 0;
+ }
+ struct ga_stream ga_stream_from_file(FILE *f)
+ {
+ return (struct ga_stream) {
+ .read=ga__FILE_read,
+ .write=ga__FILE_write,
+ .fseek=ga__FILE_fseek,
+ .eof=ga__FILE_eof,
+ .type=GA_STREAM_TYPE_FILE,
+ .state=f
+
+ };
+ }
+ void ga_stream_delete(struct ga_stream *s)
+ {
+ switch(s->type)
+ {
+ case GA_STREAM_TYPE_STRING:
+ gas_stream_delete(s);
+ break;
+ #ifdef GALIB_POSIX
+ case GA_STREAM_TYPE_SYSTEM:
+ ga__system_stream_delete(s);
+ break;
+ #endif
+ }
+ }
+
+ void* gar_alloc(size_t number_of_elements,size_t element_size)
+ {
+ struct ga_array_internals *internals;
+ if(element_size==0)
+ return NULL;
+ /*
+ allocate one element extra so that ga_array_last_index
+ can always give an index for valid memory
+ */
+ internals=ga_malloc(sizeof(struct ga_array_internals)+element_size*(number_of_elements?number_of_elements:1));
+ if(internals==NULL)
+ return NULL;
+
+ internals->size=number_of_elements;
+ internals->capacity=1;
+
+ if((element_size*number_of_elements)/element_size!=number_of_elements)
+ internals->element_size=0;
+ else
+ internals->element_size=element_size;
+
+ return internals->bytes;
+ }
+ void* gar_expand(void *arr,size_t expansion_size)
+ {
+ struct ga_array_internals *internals;
+ internals=gar_get_internals(arr);
+
+
+ if(internals->element_size==0 || expansion_size==0) /*check for oom state or no expansion*/
+ {
+ return arr;
+ }else if(internals->size+expansion_size<=internals->size) /*check for size overflow*/
+ {
+ internals->element_size=0;/*oom state*/
+ return arr;
+ }else
+ {
+ if(internals->size+expansion_size<=internals->capacity)
+ {
+ internals->size+=expansion_size;
+ return arr;
+ }else
+ {
+ struct ga_array_internals *new_internals=NULL;
+ size_t new_capacity=internals->capacity;
+
+ while(new_capacity<internals->size+expansion_size)
+ {
+ /*check for overflow*/
+ if( (new_capacity<<1) > new_capacity &&
+ (new_capacity<<1)*internals->element_size+sizeof(struct ga_array_internals)
+ >
+ new_capacity*internals->element_size+sizeof(struct ga_array_internals)
+ )
+ {
+ new_capacity<<=1;
+ }else
+ {
+ internals->element_size=0;/*oom state*/
+ return arr;
+ }
+ }
+ new_internals=ga_realloc(internals,sizeof(struct ga_array_internals)+new_capacity*internals->element_size);
+
+ if(new_internals==NULL)
+ {
+ internals->element_size=0; /*oom state*/
+ return arr;
+ }else
+ {
+ new_internals->capacity=new_capacity;
+ new_internals->size+=expansion_size;
+ return new_internals->bytes;
+ }
+ }
+
+ }
+ }
+ void* gar_resize(void *arr,size_t new_size)
+ {
+ struct ga_array_internals *internals;
+ internals=gar_get_internals(arr);
+ if(new_size>internals->capacity)
+ {
+ arr=gar_expand(arr,new_size-internals->size);
+ internals=gar_get_internals(arr);
+ }
+ internals->size=new_size;
+ return arr;
+ }
+ void gar_delete_elements(void *arr,size_t start_index,size_t number_of_elements)
+ {
+ if(arr)
+ {
+ struct ga_array_internals *internals;
+ internals=gar_get_internals(arr);
+ if(start_index<internals->size)
+ {
+ if(number_of_elements>internals->size ||
+ start_index>internals->size-number_of_elements ||
+ start_index>SIZE_MAX-number_of_elements)
+ {
+ internals->size=start_index+1;
+ return;
+ }
+ memmove(internals->bytes+start_index*internals->element_size,
+ internals->bytes+(start_index+number_of_elements)*internals->element_size,
+ (internals->size-start_index-number_of_elements)*internals->element_size);
+ internals->size-=number_of_elements;
+
+ }
+ }
+ }
+ void gar_shrink(void *arr,size_t shrink_size)
+ {
+ struct ga_array_internals *internals;
+ internals=gar_get_internals(arr);
+ if(internals->size<shrink_size)
+ internals->size=0;
+ else
+ internals->size-=shrink_size;
+ }
+ void gar_delete(void *arr)
+ {
+ if(arr)
+ {
+ struct ga_array_internals *internals;
+ internals=gar_get_internals(arr);
+ ga_free(internals);
+ }
+ }
+ size_t gar_size(void *arr)
+ {
+ return gar_get_internals(arr)->size;
+ }
+ size_t gar_last_index(void *arr)
+ {
+ struct ga_array_internals *internals;
+ internals=gar_get_internals(arr);
+ if(internals->size==0)
+ return 0;
+ else
+ return internals->size-1;
+ }
+ _Bool gar_oom(void *arr)
+ {
+ if(arr)
+ return gar_get_internals(arr)->element_size==0;
+ else
+ return 1;
+ }
+ void* gar_copy(void *arr)
+ {
+ if(arr)
+ {
+ struct ga_array_internals *internals;
+ void* ret_arr;
+
+ internals=gar_get_internals(arr);
+ ret_arr=gar_alloc(internals->size,internals->element_size);
+ if(!gar_oom(ret_arr))
+ {
+ memcpy(ret_arr,internals->bytes,internals->size*internals->element_size);
+ return ret_arr;
+ }else
+ {
+ return ret_arr;
+ }
+ }else
+ {
+ return NULL;
+ }
+ }
+ struct ga_array_internals* gar_get_internals(void *arr)
+ {
+ return (struct ga_array_internals*)(arr-offsetof(struct ga_array_internals,bytes));
+ }
+
+ ga_hash_t gar_hash(void * _garray arr)
+ {
+ if(arr==NULL || gar_oom(arr))
+ return (ga_hash_t)gar__hash_sneed;
+ struct ga_array_internals *internals=gar_get_internals(arr);
+
+ return ga_hash_bytes(arr,internals->size*internals->element_size);
+ }
+ ga_hash_t ga_hash_bytes(void *bytes,size_t number_of_bytes)
+ {
+ unsigned char *key;
+ static const unsigned int magic = 0x5bd1e995;
+ static const int reeeee = 24;
+ ga_hash_t hash = gar__hash_sneed ^ number_of_bytes;
+ uint32_t hold_word;
+ size_t key_size;
+
+ key=bytes;
+ key_size=number_of_bytes;
+
+ while(key_size >= 4)
+ {
+ hold_word = *(uint32_t *)key;
+ hold_word *= magic;
+ hold_word ^= hold_word >> reeeee;
+ hold_word *= magic;
+ hash *= magic;
+ hash ^= hold_word;
+ key += 4;
+ key_size -= 4;
+ }
+
+ switch(key_size)
+ {
+ case 3:
+ hash ^= key[2] << 16;
+ case 2:
+ hash ^= key[1] << 8;
+ case 1:
+ hash ^= key[0];
+
+ hash *= magic;
+ }
+
+ hash ^= hash >> 13;
+ hash *= magic;
+ hash ^= hash >> 15;
+
+ return hash;
+
+ }
+
+ struct ga_str gas_make()
+ {
+ struct ga_str ret;
+ ret.cs=gar_alloc(1,1);
+ if(!gar_oom(ret.cs))
+ {
+ ret.cs[0]='\0';
+ ret.number_of_glyphs=1;/*\0 is a glyph*/
+ }else
+ {
+ ret.cs=NULL;
+ ret.number_of_glyphs=0;
+ }
+ return ret; //ret is basically a pointer so there is no problem returning it
+ }
+ struct ga_str gas_copy(const struct ga_str str)
+ {
+ struct ga_str ret=(struct ga_str){.cs=gar_copy(str.cs),.number_of_glyphs=str.number_of_glyphs};
+ gas_recount_glyphs(&ret);
+ return ret;
+ }
+ struct ga_str gas_read_file(const char *filename)
+ {
+ if(filename)
+ {
+ FILE *f;
+ f=fopen(filename,"r");
+ if(f)
+ {
+ if(fseek(f,0,SEEK_END))
+ {
+ fclose(f);
+ return gas_cstr("");
+ }else
+ {
+ struct ga_str ret;
+ long int file_size;
+
+ file_size=ftell(f);
+ if(file_size==-1)
+ {
+ fclose(f);
+ return gas_cstr("");
+ }
+ ret.cs=gar_alloc(file_size+1,1);
+ if(!gar_oom(ret.cs))
+ {
+ if(fread(ret.cs,1,file_size,f)!=file_size)
+ {
+ gar_delete(ret.cs);
+ fclose(f);
+ return gas_cstr("");
+ }
+ ret.cs[gar_last_index(ret.cs)]='\0';
+ fclose(f);
+ ret.number_of_glyphs=1;
+ gas_recount_glyphs(&ret);
+ return ret;
+ }else
+ {
+ fclose(f);
+ return gas_cstr("");
+ }
+ }
+
+ }else
+ {
+ return gas_cstr("");
+ }
+ }else
+ {
+ return gas_cstr("");
+ }
+ }
+ struct ga_str gas_read_line(FILE *in)
+ {
+ struct ga_str ret;
+ int temp;
+ ret=gas_make();
+ while( (temp=fgetc(in)) != EOF && temp!='\n' )
+ gas_push_byte(&ret,temp);
+ return ret;
+ }
+ struct ga_str gas_read_input(FILE *in)
+ {
+ struct ga_str ret;
+ int temp;
+ ret=gas_make();
+ while( (temp=fgetc(in)) != EOF )
+ gas_push_byte(&ret,temp);
+ return ret;
+ }
+ struct ga_str gas_cstr(const char *str)
+ {
+ struct ga_str ret;
+ if(str)
+ {
+ size_t str_len;
+ str_len=strlen(str);
+ ret.cs=gar_alloc(str_len+1,1);
+ ret.number_of_glyphs=1;
+ if(!gar_oom(ret.cs))
+ memcpy(ret.cs,str,str_len+1);
+ gas_recount_glyphs(&ret);
+ return ret;
+ }else
+ {
+ ret.cs=NULL;
+ ret.number_of_glyphs=0;
+ }
+ return ret;
+ }
+ struct ga_str gas_fread_line(FILE *in)
+ {
+ struct ga_str ret;
+ int temp;
+
+ ret=gas_make();
+
+ while((temp=fgetc(in))!=EOF && temp!='\n')
+ gas_push_codepoint(&ret,(uint32_t)temp);
+ gas_recount_glyphs(&ret);
+ return ret;
+ }
+ struct ga_str gas_fread_input(FILE *in)
+ {
+ struct ga_str ret;
+ int temp;
+
+ ret=gas_make();
+
+ while((temp=fgetc(in))!=EOF)
+ gas_push_codepoint(&ret,(uint32_t)temp);
+ gas_recount_glyphs(&ret);
+ return ret;
+ }
+ size_t gas_number_of_bytes(const struct ga_str str)
+ {
+ if(!gar_oom(str.cs))
+ return gar_size(str.cs);
+ else
+ return 0;
+ }
+ size_t gas_recount_glyphs(struct ga_str *str)
+ {
+ size_t glyph_count=0;
+ for(size_t i=0,j=1;j!=i && i<gas_number_of_bytes(*str);j=i,i=gas_following_glyph_position(*str,i))
+ {
+ ++glyph_count;
+ }
+ str->number_of_glyphs=glyph_count;
+ return glyph_count;
+ }
+ size_t gas_length(const struct ga_str str)
+ {
+ return str.number_of_glyphs;
+ }
+ _Bool gas_oom(struct ga_str str)
+ {
+ return gar_oom(str.cs);
+ }
+ uint32_t gas_glyph(const struct ga_str str,size_t index)
+ {
+ /*get byte index of glyph then extract the value and return it*/
+ return gas_glyph_at_position(str,gas_glyph_position(str,index));
+ }
+ size_t gas_glyph_position(const struct ga_str str,size_t glyph_index)
+ {
+ size_t byte_index,i;
+ /*walk glyphs till we reach glyph_index or run out of bytes*/
+ for(byte_index=0,i=0;i<glyph_index;++i,byte_index=gas_following_glyph_position(str,byte_index));
+ /*if this could be last byte index in string*/
+ return byte_index;
+ }
+ size_t gas_following_glyph_position(const struct ga_str str,size_t byte_index)
+ {
+ short glyph_size=0;
+ /*skip invalid bytes*/
+ while(byte_index<gas_number_of_bytes(str) && (glyph_size=ga__utf8_glyph_size(str,byte_index))==0)
+ {
+ ++byte_index;
+ }
+ byte_index+=glyph_size;
+ return (byte_index<gas_number_of_bytes(str)?byte_index:gar_last_index(str.cs)+1);
+ }
+ size_t gas_previous_glyph_position(const struct ga_str str,size_t byte_index)
+ {
+ /*TODO*/
+ return byte_index;
+ }
+ uint32_t gas_glyph_at_position(const struct ga_str str,size_t byte_index)
+ {
+ short glyph_size;
+ glyph_size=ga__utf8_glyph_size(str,byte_index);
+ if(glyph_size==0)
+ return 0;
+ else
+ return ga__utf8_glyph_value(str,byte_index,glyph_size);
+ }
+ struct ga_str_mark* gas_mark_lines(const struct ga_str str)
+ {
+ struct ga_str_mark *ret;
+ size_t last_beginning=0;
+ size_t last_size=0;
+ uint32_t hold_glyph;
+ ret=gar_alloc(0,sizeof(struct ga_str_mark));
+
+ if(gar_oom(ret))
+ return ret;
+
+ for(size_t byte_index=0;byte_index<gas_number_of_bytes(str);byte_index=gas_following_glyph_position(str,byte_index))
+ {
+ hold_glyph=gas_glyph_at_position(str,byte_index);
+ if( (hold_glyph==(uint32_t)'\n' || hold_glyph==(uint32_t)'\r') )
+ {
+ if(last_size>0)
+ {
+ ret=gar_expand(ret,1);
+ ret[gar_last_index(ret)]=(struct ga_str_mark){.beginning_byte_index=last_beginning,.size=last_size};
+ last_beginning=byte_index;
+ last_size=0;
+ }else
+ {
+ ++last_beginning;
+ }
+ }else
+ {
+ ++last_size;
+ }
+ }
+ if(last_size>0)
+ {
+ ret=gar_expand(ret,1);
+ ret[gar_last_index(ret)]=(struct ga_str_mark){.beginning_byte_index=last_beginning,.size=last_size};
+ }
+ return ret;
+ }
+ _Bool gas_push_codepoint(struct ga_str *str,uint32_t ch)
+ {
+ short codepoint_size;
+
+ codepoint_size=ga__utf8_codepoint_size(ch);
+ str->cs=gar_expand(str->cs,codepoint_size);
+
+ if(gar_oom(str->cs))
+ return 0;
+
+
+ str->cs[gar_last_index(str->cs)]='\0';
+ ga__utf8_encode_codepoint(str->cs+gar_last_index(str->cs)-codepoint_size,ch,codepoint_size);
+
+ ++str->number_of_glyphs;
+ return 1;
+ }
+ _Bool gas_push_byte(struct ga_str *str,unsigned char ch)
+ {
+ if(str==NULL || gar_oom(str->cs))
+ return 0;
+ str->cs=gar_expand(str->cs,1);
+ if(gar_oom(str->cs))
+ return 0;
+
+ str->cs[gar_last_index(str->cs)]='\0';
+ str->cs[gar_last_index(str->cs)-1]=ch;
+ return 1;
+ }
+
+ _Bool gas_append(struct ga_str *str,const char *right)
+ {
+ if(str==NULL || right==NULL)
+ return 0;
+
+ size_t right_size;
+ right_size=strlen(right);
+ str->cs=gar_expand(str->cs,right_size);
+
+ if(gar_oom(str->cs))
+ return 0;
+
+ memmove(str->cs+gar_last_index(str->cs)-right_size,right,right_size);
+ str->cs[gar_last_index(str->cs)]='\0';
+
+ gas_recount_glyphs(str);
+ return 1;
+
+ }
+ _Bool gas_preppend(struct ga_str *str,char *left)
+ {
+ if(str==NULL || left==NULL)
+ return 0;
+
+ size_t left_size;
+ left_size=strlen(left);
+ str->cs=gar_expand(str->cs,left_size);
+
+ if(gar_oom(str->cs))
+ return 0;
+
+ memmove(str->cs+left_size,str->cs,gas_number_of_bytes(*str)-left_size);
+ memmove(str->cs,left,left_size);
+
+ gas_recount_glyphs(str);
+ return 1;
+ }
+ _Bool gas_insert(struct ga_str *str,char *infix,size_t glyph_index)
+ {
+ if(str==NULL || infix==NULL || glyph_index>gas_length(*str)-1)
+ return 0;
+
+ size_t infix_size;
+ size_t where;
+ infix_size=strlen(infix);
+ where=gas_glyph_position(*str,glyph_index);
+ str->cs=gar_expand(str->cs,infix_size);
+
+ if(gar_oom(str->cs))
+ return 0;
+
+ memmove(str->cs+where+infix_size,str->cs+where,gas_number_of_bytes(*str)-where-infix_size);
+ memmove(str->cs+where,infix,infix_size);
+
+ gas_recount_glyphs(str);
+ return 1;
+ }
+ _Bool gas_delete_chars(struct ga_str *str,size_t starting_glyph_index,size_t number_of_glyphs)
+ {
+ if(str==NULL)
+ return 0;
+ size_t start_offset=gas_glyph_position(*str,starting_glyph_index);
+ size_t offset=start_offset;
+ for(size_t i=0;i<number_of_glyphs;++i,offset=gas_following_glyph_position(*str,offset));
+ if(offset==0 || offset>gas_number_of_bytes(*str))
+ return 0;
+ memmove(str->cs+start_offset,str->cs+offset,gas_number_of_bytes(*str)-offset+start_offset);
+ gar_shrink(str->cs,offset-start_offset);
+ gas_recount_glyphs(str);
+ return 1;
+ }
+
+ _Bool gas_to_file(const struct ga_str str,const char *filename)
+ {
+ FILE *out;
+ if(filename==NULL)
+ return 0;
+ out=fopen(filename,"w");
+ if(out==NULL)
+ return 0;
+
+ if(fwrite(str.cs,1,gas_number_of_bytes(str)-1,out)!=gas_number_of_bytes(str)-1)
+ {
+ fclose(out);
+ return 0;
+ }
+
+ fclose(out);
+ return 1;
+ }
+
+ _Bool gas_seq(const struct ga_str a,const struct ga_str b)
+ {
+ if(gas_number_of_bytes(a)!=gas_number_of_bytes(b))
+ return 0;
+ return !memcmp(a.cs,b.cs,gas_number_of_bytes(a));
+ }
+ _Bool gas_ceq(const struct ga_str a,const char *b)
+ {
+ return !strncmp(a.cs,b,gas_number_of_bytes(a));
+ }
+
+ void ga__parse_scan_format(const char *begining, struct ga__scanformat *destination)
+ {
+ destination->forward_crawl=1;
+ destination->modifier=GA__MOD_END;
+ destination->conversion=GA__CONVERSION_END;
+ destination->alternate_form=0;
+ switch(begining[destination->forward_crawl])
+ {
+ case 'h':
+ ++destination->forward_crawl;
+ if(begining[destination->forward_crawl]=='h')
+ {
+ ++destination->forward_crawl;
+ destination->modifier=GA__MOD_SHORT_SHORT;
+ }else
+ {
+ destination->modifier=GA__MOD_SHORT;
+ }
+ break;
+ case 'l':
+ ++destination->forward_crawl;
+ if(begining[destination->forward_crawl]=='l')
+ {
+ ++destination->forward_crawl;
+ destination->modifier=GA__MOD_LONG_LONG;
+ }else
+ {
+ destination->modifier=GA__MOD_LONG;
+ }
+ break;
+ case 'L':
+ ++destination->forward_crawl;
+ destination->modifier=GA__MOD_LONG_DOUBLE;
+ break;
+ case 'j':
+ ++destination->forward_crawl;
+ destination->modifier=GA__MOD_INTMAX;
+ break;
+ case 'z':
+ ++destination->forward_crawl;
+ destination->modifier=GA__MOD_SIZE_T;
+ break;
+ case 't':
+ ++destination->forward_crawl;
+ destination->modifier=GA__MOD_PTRDIFF;
+ break;
+ }
+ switch(begining[destination->forward_crawl])
+ {
+ case 'd':
+ case 'i':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_INT_DECIMAL;
+ break;
+ case 'o':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_INT_OCTAL;
+ break;
+ case 'u':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_INT_UNSIGNED_DECIMAL;
+ break;
+ case 'x':
+ case 'X':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_INT_HEXADECIMAL;
+ break;
+ case 'e':
+ case 'E':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_DOUBLE_EXPONENT;
+ break;
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_DOUBLE_DECIMAL;
+ break;
+ case 'a':
+ case 'A':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_DOUBLE_HEXADECIMAL;
+ break;
+ case 'c':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_CHAR;
+ break;
+ case 's':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_CSTRING;
+ break;
+ case 'p':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_POINTER;
+ break;
+ case '%':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_PERCENT;
+ break;
+ case 'b':
+ ++destination->forward_crawl;
+ destination->conversion=GA__CONVERSION_BITS;
+ break;
+
+ }
+ }
+ int gas_printf(struct ga_str *destination,const char *format,...)
+ {
+ va_list args;
+ int ret;
+
+ va_start(args,format);
+ ret=gas_vprintf(destination,format,args);
+ va_end(args);
+
+ return ret;
+ }
+ void gas__from_scanformat(struct ga__scanformat *fmt,va_list args,struct ga_str *destination)
+ {
+ struct ga_stream s=gas_stream(destination);
+ ga_fseek(&s,0,SEEK_END);
+ ga__from_scanformat(fmt,args,&s);
+ ga_stream_delete(&s);
+ }
+ int gas_vprintf(struct ga_str *destination,const char *format,va_list args)
+ {
+ if(format==NULL || destination==NULL)
+ return 0;
+
+ struct ga__scanformat fmt;
+ struct ga_stream s=gas_stream(destination);
+ ga_fseek(&s,0,SEEK_END);
+
+ for(size_t i=0;format[i]!='\0';)
+ {
+ if(format[i]=='%')
+ {
+ ga__parse_scan_format(format+i,&fmt);
+ ga__from_scanformat(&fmt,args,&s);
+ i+=fmt.forward_crawl;
+ }else
+ {
+ ga_write(&s,(void*)format+i,1);
+ ++i;
+ }
+ }
+ ga_stream_delete(&s);
+
+ return 0;
+ }
+
+ int ga_str_sscanf(struct ga_str *source,const char *format,...);
+ int ga_str_vsscanf(struct ga_str *source,const char *format,va_list args);
+
+
+ ga_hash_t gas_hash(struct ga_str str)
+ {
+ return gar_hash(str.cs);
+ }
+ ssize_t gas__stream_read(void *state,void *dst,size_t num_bytes)
+ {
+ if(state==NULL)
+ return -1;
+ struct gas__stream_state *s=(struct gas__stream_state*)state;
+ uint8_t *d=(uint8_t*)dst;
+ size_t i;
+
+ if(gas_oom(*s->str))
+ return -1;
+
+ for(s->where,i=0;s->where<gar_size(s->str->cs)-1 && i<num_bytes;++i,++s->where)
+ d[i]=s->str->cs[i];
+
+ return i;
+ }
+ ssize_t gas__stream_write(void *state,void *src,size_t num_bytes)
+ {
+ if(state==NULL)
+ return -1;
+ struct gas__stream_state *s=(struct gas__stream_state*)state;
+ uint8_t *sr=(uint8_t*)src;
+ size_t i;
+
+ if(gas_oom(*s->str))
+ return -1;
+
+ for(s->where,i=0;s->where<gar_size(s->str->cs)-1 && i<num_bytes;++i,++s->where)
+ s->str->cs[i]=sr[i];
+ for(i;i<num_bytes && !gas_oom(*s->str);++i,++s->where)
+ gas_push_byte(s->str,(unsigned char)sr[i]);
+ gas_recount_glyphs(s->str);
+
+ return i;
+ }
+ _Bool gas__stream_fseek(void *state,size_t where,int whence)
+ {
+ if(state==NULL)
+ return 0;
+
+ struct gas__stream_state *s=(struct gas__stream_state*)state;
+
+ if(gas_oom(*s->str))
+ return -1;
+
+ switch(whence)
+ {
+ case SEEK_SET:
+ if(where<gar_size(s->str->cs)-1)
+ {
+ s->where=where;
+ return 1;
+ }else
+ {
+ s->where=gar_size(s->str->cs)-1;
+ return 0;
+ }
+ case SEEK_CUR:
+ if(where<gar_size(s->str->cs)-s->where-1)
+ {
+ s->where+=where;
+ return 1;
+ }else
+ {
+ s->where=gar_size(s->str->cs)-1;
+ return 0;
+ }
+ case SEEK_END:
+ if(where<gar_size(s->str->cs)-1)
+ {
+ s->where=gar_size(s->str->cs)-1-where;
+ return 1;
+ }else
+ {
+ s->where=gar_size(s->str->cs)-1;
+ return 0;
+ }
+ default:
+ return 0;
+ }
+ return 0;
+ }
+ _Bool gas__stream_eof(void *state)
+ {
+ if(state==NULL)
+ return 1;
+
+ struct gas__stream_state *s=(struct gas__stream_state*)state;
+ return s->where<gar_size(s->str->cs)-1;
+ }
+ struct ga_stream gas_stream(struct ga_str *str)
+ {
+ struct gas__stream_state *state=ga_malloc(sizeof(struct gas__stream_state));
+
+ if(state)
+ {
+ state->str=str;
+ state->where=0;
+ }
+ return (struct ga_stream){
+ .read=gas__stream_read,
+ .write=gas__stream_write,
+ .fseek=gas__stream_fseek,
+ .eof=gas__stream_eof,
+ .type=GA_STREAM_TYPE_STRING,
+ .state=state
+ };
+ }
+ void gas_stream_delete(struct ga_stream *stream)
+ {
+ if(stream)
+ if(stream->state)
+ {
+ ga_free(stream->state);
+ stream->state=NULL;
+ }
+ }
+ void gas_delete(struct ga_str *str)
+ {
+ str->number_of_glyphs=0;
+ gar_delete(str->cs);
+ }
+
+
+ short ga__utf8_get_glyph_size_from_starting_codepoint(unsigned char leading_byte)
+ {
+ if(leading_byte<0x7F)
+ return 1;
+ else if(leading_byte&0xE0==0xC0)
+ return 2;
+ else if(leading_byte&0xF0==0xE0)
+ return 3;
+ else if(leading_byte&0xF8==0xF0)
+ return 4;
+ else if(leading_byte&0xFC==0xF8)
+ return 5;
+ else if(leading_byte&0xFE==0xFC)
+ return 6;
+ else
+ return 0;
+ }
+ short ga__utf8_glyph_size(struct ga_str str,size_t byte_index)
+ {
+
+ if(str.cs[byte_index]<0x7F) /*we were on top of an ascii char*/
+ {
+ return 1;
+ }else if((str.cs[byte_index]&0xE0) == 0xC0)
+ {
+ if(byte_index+2<gas_number_of_bytes(str)
+ && (str.cs[byte_index+1]&0xC0)==0x80)
+ return 2;
+ else
+ return 0;
+ }else if( (str.cs[byte_index]&0xF0) == 0xE0)
+ {
+ if(byte_index+3<gas_number_of_bytes(str)
+ && (str.cs[byte_index+1]&0xC0)==0x80
+ && (str.cs[byte_index+2]&0xC0)==0x80)
+ return 3;
+ else
+ return 0;
+ }else if( (str.cs[byte_index]&0xF8) == 0xF0)
+ {
+ if(byte_index+4<gas_number_of_bytes(str)
+ && (str.cs[byte_index+1]&0xC0)==0x80
+ && (str.cs[byte_index+2]&0xC0)==0x80
+ && (str.cs[byte_index+3]&0xC0)==0x80)
+ return 4;
+ else
+ return 0;
+ }else if( (str.cs[byte_index]&0xFC) == 0xF8)
+ {
+ if(byte_index+5<gas_number_of_bytes(str)
+ && (str.cs[byte_index+1]&0xC0)==0x80
+ && (str.cs[byte_index+2]&0xC0)==0x80
+ && (str.cs[byte_index+3]&0xC0)==0x80
+ && (str.cs[byte_index+4]&0xC0)==0x80)
+ return byte_index+5;
+ else
+ ++byte_index;
+ }else if( (str.cs[byte_index]&0xFE) == 0xFC)
+ {
+ if(byte_index+5<gas_number_of_bytes(str)
+ && (str.cs[byte_index+1]&0xC0)==0x80
+ && (str.cs[byte_index+2]&0xC0)==0x80
+ && (str.cs[byte_index+3]&0xC0)==0x80
+ && (str.cs[byte_index+4]&0xC0)==0x80
+ && (str.cs[byte_index+5]&0xC0)==0x80)
+ return 6;
+ else
+ return 0;
+ }else
+ {
+ return 0;
+ }
+ }
+
+ uint32_t ga__utf8_glyph_value(struct ga_str str,size_t byte_index,short glyph_size)
+ {
+ uint32_t ret=str.cs[byte_index]&(0xff>>glyph_size);
+ for(short i=1;i<glyph_size;++i)
+ {
+ ret<<=6;
+ ret+=(0x3F&str.cs[byte_index+i]);
+ }
+ return ret;
+ }
+ short ga__utf8_codepoint_size(uint32_t codepoint)
+ {
+ if(codepoint<=0x7Fu)
+ return 1;
+ else if(codepoint<=0x7FFu)
+ return 2;
+ else if(codepoint<=0xFFFFu)
+ return 3;
+ else if(codepoint<=0x1FFFFFu)
+ return 4;
+ else if(codepoint<=0x3FFFFFFu)
+ return 5;
+ else if(codepoint<=0x7FFFFFFFu)
+ return 6;
+ else
+ return 0;
+
+ }
+ void ga__utf8_encode_codepoint(unsigned char *where,uint32_t codepoint,short size)
+ {
+ if(size==1)
+ {
+ where[0]=codepoint;
+ }else
+ {
+ where[0]=(0xFF<<(8-size))|(codepoint>>((size-1)*6));
+ for(short i=1;i<size;++i)
+ where[i]=0x80|((codepoint>>((size-i-1)*6))&0x3F);
+ }
+ }
+
+ void ga_die(const char *fmt, ...)
+ {
+ va_list args;
+ struct ga_stream s=ga_stream_from_file(stderr);
+ va_start(args,fmt);
+ ga_vfprintf(&s,fmt,args);
+ va_end(args);
+ ga_stream_delete(&s);
+ ga_exit(1);
+ }
+
+
+ #ifdef GALIB_REGEX
+ void ga_grep_lines(ga_lines_t *lines,char *regex);/*deletes non matching lines*/
+ _Bool ga_grep_line(char *line,char *regex);/*works with C strings and ga_str_t*/
+ #endif
+
+
+ /*############################################ TODO REMOVE THIS COMMENT ####################################################*/
+
+ struct ga_hash_table* gah_make()
+ {
+ struct ga_hash_table *ret;
+
+ ret=ga_malloc(sizeof(struct ga_hash_table)+ga__hash_table_init_slot_number*sizeof(struct ga__hash_table_underarray_slot));
+
+ if(ret!=NULL)
+ {
+ ret->used_slots=0;
+ ret->tombstones=0;
+ ret->used_slots_threshold=ga__hash_table_init_slots_thresholds;
+ ret->tombstones_threshold=ga__hash_table_init_tombstones_thresholds;
+ ret->number_of_slots=ga__hash_table_init_slot_number;
+ ret->oom=0;
+
+ for(size_t i=0;i<ret->number_of_slots;++i)
+ ret->slots[i]=(struct ga__hash_table_underarray_slot){.is_alive=0,.is_tombstone=0,.where_in_array=0};
+ }
+
+ return ret;
+ }
+ _Bool gah_oom(struct ga_hash_table *h)
+ {
+ return (h==NULL) || h->oom;
+ }
+ ga_hash_t gah_hash_on_step(ga_hash_t hash,size_t step)
+ {
+ if(step%2)
+ return ((~((hash+step)<<1))/3);
+ else
+ return (((hash-step)<<1)/3);
+ }
+ _Bool gah_slot_is_taken(struct ga_hash_table *h,ga_hash_t hash,size_t step)
+ {
+ hash=gah_hash_on_step(hash,step);
+ return h->slots[hash%h->number_of_slots].is_alive || h->slots[hash%h->number_of_slots].is_tombstone;
+ }
+ _Bool gah_slot_is_tombstone(struct ga_hash_table *h,ga_hash_t hash,size_t step)
+ {
+ hash=gah_hash_on_step(hash,step);
+ return h->slots[hash%h->number_of_slots].is_tombstone;
+ }
+ size_t gah_geti(struct ga_hash_table *h,ga_hash_t hash,size_t step)
+ {
+ hash=gah_hash_on_step(hash,step);
+ return h->slots[hash%h->number_of_slots].where_in_array;
+ }
+ size_t gah_get_slot_index(struct ga_hash_table *h,ga_hash_t hash,size_t step)
+ {
+ return gah_hash_on_step(hash,step)%h->number_of_slots;
+ }
+ struct ga_hash_table* gah_expand(struct ga_hash_table *h)
+ {
+ struct ga_hash_table *ret;
+
+ if(h->number_of_slots>SIZE_MAX/2-sizeof(struct ga_hash_table))
+ {
+ h->oom=1;
+ return h;
+ }
+
+ ret=ga_malloc(sizeof(struct ga_hash_table)+h->number_of_slots*2*sizeof(struct ga__hash_table_underarray_slot));
+
+ if(ret==NULL)
+ {
+ h->oom=1;
+ return h;
+ }
+
+ ret->used_slots=h->used_slots;
+ ret->tombstones=0;
+
+ ret->used_slots_threshold=h->used_slots_threshold;
+ ret->tombstones_threshold=h->tombstones_threshold;
+
+ ret->number_of_slots=h->number_of_slots*2;
+
+ ret->oom=0;
+
+ for(size_t i=0;i<ret->number_of_slots;++i)
+ ret->slots[i]=(struct ga__hash_table_underarray_slot){.is_alive=0,.is_tombstone=0,.where_in_array=0};
+
+ for(size_t i=0;i<h->number_of_slots;++i)
+ {
+ if(h->slots[i].is_alive)
+ {
+ size_t j;
+ for(j=0;gah_slot_is_taken(ret,h->slots[i].hash,j);++j);
+
+ j=gah_get_slot_index(ret,h->slots[i].hash,j);
+ /*
+ * we assume that distinct element in the previous hash table is unique
+ * so we skip the check for equality (we can't do it even if we want to though)
+ **/
+
+ ret->slots[j].is_alive=1;
+ ret->slots[j].hash=h->slots[i].hash;
+ ret->slots[j].where_in_array=h->slots[i].where_in_array;
+ }
+ }
+
+ ga_free(h);
+
+ return ret;
+ }
+ struct ga_hash_table* gah_clean_tombstones(struct ga_hash_table *h)
+ {
+ struct ga_hash_table *ret;
+
+
+ ret=ga_malloc(sizeof(struct ga_hash_table)+h->number_of_slots*sizeof(struct ga__hash_table_underarray_slot));
+
+ if(ret==NULL)
+ {
+ h->oom=1;
+ return h;
+ }
+
+ ret->used_slots=h->used_slots;
+ ret->tombstones=0;
+
+ ret->used_slots_threshold=h->used_slots_threshold;
+ ret->tombstones_threshold=h->tombstones_threshold;
+
+ ret->number_of_slots=h->number_of_slots;
+
+ ret->oom=0;
+
+ for(size_t i=0;i<ret->number_of_slots;++i)
+ ret->slots[i]=(struct ga__hash_table_underarray_slot){.is_alive=0,.is_tombstone=0,.where_in_array=0};
+
+ for(size_t i=0;i<h->number_of_slots;++i)
+ {
+ if(h->slots[i].is_alive)
+ {
+ size_t j;
+ for(j=0;gah_slot_is_taken(ret,h->slots[i].hash,j);++j);
+
+ j=gah_get_slot_index(ret,h->slots[i].hash,j);
+ /*
+ * we assume that distinct element in the previous hash table is unique
+ * so we skip the check for equality (we can't do it even if we want to though)
+ **/
+
+ ret->slots[j].is_alive=1;
+ ret->slots[j].hash=h->slots[i].hash;
+ ret->slots[j].where_in_array=h->slots[i].where_in_array;
+ }
+ }
+
+ ga_free(h);
+
+ return ret;
+
+ }
+ struct ga_hash_table* gah_push(struct ga_hash_table *h,ga_hash_t hash,size_t step,size_t index)
+ {
+ size_t j;
+ if(h->used_slots>=h->number_of_slots/h->used_slots_threshold)
+ {
+ h=gah_expand(h);
+ if(h->oom)
+ return h;
+ for(j=0;gah_slot_is_taken(h,hash,j);++j);
+ j=gah_get_slot_index(h,hash,j);
+ h->slots[j].is_alive=1;
+ h->slots[j].is_tombstone=0;
+ h->slots[j].hash=hash;
+ h->slots[j].where_in_array=index;
+ h->used_slots++;
+
+ return h;
+ }else
+ {
+ j=gah_get_slot_index(h,hash,step);
+ h->slots[j].is_alive=1;
+ h->slots[j].is_tombstone=0;
+ h->slots[j].hash=hash;
+ h->slots[j].where_in_array=index;
+ h->used_slots++;
+ return h;
+ }
+
+ }
+ struct ga_hash_table* gah_remove(struct ga_hash_table *h,ga_hash_t hash,size_t step)
+ {
+ size_t j;
+ if(h->tombstones>=h->number_of_slots/h->tombstones_threshold)
+ {
+ h=gah_clean_tombstones(h);
+ if(h->oom)
+ return h;
+ for(j=0;gah_slot_is_taken(h,hash,j);++j);
+ j=gah_get_slot_index(h,hash,j);
+ h->slots[j].is_alive=0;
+ h->slots[j].is_tombstone=1;
+ h->slots[j].where_in_array=0;
+ h->tombstones++;
+ h->used_slots--;
+
+ return h;
+
+ }else
+ {
+
+ j=gah_get_slot_index(h,hash,step);
+ h->slots[j].is_alive=0;
+ h->slots[j].is_tombstone=1;
+ h->slots[j].where_in_array=0;
+ h->used_slots--;
+ h->tombstones++;
+ return h;
+
+ }
+
+ }
+ void gah_delete(struct ga_hash_table *h)
+ {
+ ga_free(h);
+ }
+
+ struct ga_string_hash_table* gahs_make(size_t value_size)
+ {
+ struct ga_string_hash_table *ret;
+
+ if(value_size==0)
+ return NULL;
+
+ ret=ga_malloc(sizeof(struct ga_string_hash_table));
+ if(ret==NULL)
+ return ret;
+ ret->table=gah_make();
+ ret->keys=gar_alloc(0,sizeof(struct ga_str));
+ ret->values=gar_alloc(0,value_size);
+ ret->value_size=value_size;
+ ret->oom=gar_oom(ret->keys)||gar_oom(ret->values)||gah_oom(ret->table);
+
+ return ret;
+ }
+ struct ga_string_hash_table* gahs_push(struct ga_string_hash_table *h,struct ga_str key,void *value)
+ {
+
+
+ ga_hash_t hash;
+ size_t j,ht;
+
+ if(!h || h->oom)
+ return h;
+
+ hash=gas_hash(key);
+ ht=h->table->number_of_slots;
+ for(j=0;gah_slot_is_taken(h->table,hash,j) && !gas_seq(key,h->keys[gah_geti(h->table,hash,j)]) ;++j)
+ if(gah_slot_is_tombstone(h->table,hash,j))
+ ht=j;
+
+ if(gah_slot_is_taken(h->table,hash,j))
+ {
+ ht=gah_geti(h->table,hash,j);
+ memcpy(h->values+h->value_size*ht,value,h->value_size);
+ }else
+ {
+ if(ht==h->table->number_of_slots)
+ ht=j;
+
+ h->keys=gar_expand(h->keys,1);
+ h->values=gar_expand(h->values,1);
+ memcpy(h->values+h->value_size*gar_last_index(h->values),value,h->value_size);
+ h->keys[gar_last_index(h->keys)]=gas_copy(key);
+
+ h->table=gah_push(h->table,hash,ht,gar_last_index(h->values));
+
+ h->oom=gar_oom(h->keys)||gar_oom(h->values)||gah_oom(h->table);
+ }
+
+ return h;
+ }
+ struct ga_string_hash_table* gahs_remove(struct ga_string_hash_table *h,struct ga_str key)
+ {
+ ga_hash_t hash;
+ size_t j;
+
+ if(!h || h->oom)
+ return h;
+
+ hash=gas_hash(key);
+ for(j=0;gah_slot_is_taken(h->table,hash,j) && !gas_seq(key,h->keys[gah_geti(h->table,hash,j)]) ;++j);
+
+ if(gah_slot_is_taken(h->table,hash,j))
+ {
+ size_t i;
+ i=gah_geti(h->table,hash,j);
+
+ gas_delete(h->keys+i);
+ gar_delete_elements(h->keys,i,1);
+ gar_delete_elements(h->values,i,1);
+ h->table=gah_remove(h->table,hash,j);
+ /*it's a bit slow :-(*/
+ for(j=0;j<h->table->number_of_slots;++j)
+ if(h->table->slots[j].is_alive && h->table->slots[j].where_in_array>i)
+ h->table->slots[j].where_in_array--; //shift the indices after the deleted element
+ }
+ return h;
+ }
+ void* gahs_get(struct ga_string_hash_table *h,struct ga_str key)
+ {
+ ga_hash_t hash;
+ size_t j;
+
+ if(!h || h->oom)
+ return NULL; //technically we can be oom and still extract stuff from the ht, but this is more noticable
+
+ hash=gas_hash(key);
+ for(j=0;gah_slot_is_taken(h->table,hash,j) && !gas_seq(key,h->keys[gah_geti(h->table,hash,j)]) ;++j);
+
+ if(gah_slot_is_taken(h->table,hash,j) && gas_seq(key,h->keys[gah_geti(h->table,hash,j)]))
+ return h->values+gah_geti(h->table,hash,j)*h->value_size;
+ else
+ return NULL;
+ }
+ _Bool gahs_oom(struct ga_string_hash_table *h)
+ {
+ return h==NULL || h->oom;
+ }
+ void gahs_delete(struct ga_string_hash_table *h)
+ {
+ if(h==NULL)
+ return;
+ if(h->keys)
+ {
+ for(size_t i=0;i<gar_size(h->keys);++i)
+ gas_delete(h->keys+i);
+ gar_delete(h->keys);
+ }
+
+ if(h->values)
+ {
+ gar_delete(h->values);
+ }
+
+ if(h->table)
+ {
+ gah_delete(h->table);
+ }
+ ga_free(h);
+ }
+
+ struct ga_memory_hash_table* gahm_make(size_t key_size,size_t value_size)
+ {
+ struct ga_memory_hash_table *ret;
+
+ if(value_size==0)
+ return NULL;
+
+ ret=ga_malloc(sizeof(struct ga_memory_hash_table));
+ if(ret==NULL)
+ return ret;
+ ret->table=gah_make();
+ ret->keys=gar_alloc(0,key_size);
+ ret->values=gar_alloc(0,value_size);
+ ret->key_size=key_size;
+ ret->value_size=value_size;
+ ret->oom=gar_oom(ret->keys)||gar_oom(ret->values)||gah_oom(ret->table);
+
+ return ret;
+ }
+ struct ga_memory_hash_table* gahm_push(struct ga_memory_hash_table *h,void* key,void* value)
+ {
+ ga_hash_t hash;
+ size_t j,ht;
+
+ if(!h || h->oom)
+ return h;
+
+ hash=ga_hash_bytes(key,h->key_size);
+ ht=h->table->number_of_slots;
+ for(j=0;gah_slot_is_taken(h->table,hash,j) && memcmp(key,h->keys+h->key_size*gah_geti(h->table,hash,j),h->key_size) ;++j)
+ if(gah_slot_is_tombstone(h->table,hash,j))
+ ht=j;
+
+ if(gah_slot_is_taken(h->table,hash,j))
+ {
+ ht=gah_geti(h->table,hash,j);
+ memcpy(h->values+h->value_size*ht,value,h->value_size);
+ }else
+ {
+ if(ht==h->table->number_of_slots)
+ ht=j;
+
+ h->keys=gar_expand(h->keys,1);
+ h->values=gar_expand(h->values,1);
+ memcpy(h->values+h->value_size*gar_last_index(h->values),value,h->value_size);
+ memcpy(h->keys+h->key_size*gar_last_index(h->keys),key,h->key_size);
+
+ h->table=gah_push(h->table,hash,ht,gar_last_index(h->values));
+
+ h->oom=gar_oom(h->keys)||gar_oom(h->values)||gah_oom(h->table);
+ }
+
+ return h;
+ }
+ struct ga_memory_hash_table* gahm_remove(struct ga_memory_hash_table *h,void* key)
+ {
+
+ ga_hash_t hash;
+ size_t j;
+
+ if(!h || h->oom)
+ return h;
+
+ hash=ga_hash_bytes(key,h->key_size);
+ for(j=0;gah_slot_is_taken(h->table,hash,j) && memcmp(key,h->keys+h->key_size*gah_geti(h->table,hash,j),h->key_size) ;++j);
+
+ if(gah_slot_is_taken(h->table,hash,j))
+ {
+ size_t i;
+ i=gah_geti(h->table,hash,j);
+
+ gar_delete_elements(h->keys,i,1);
+ gar_delete_elements(h->values,i,1);
+ h->table=gah_remove(h->table,hash,j);
+ /*it's a bit slow :-(*/
+ for(j=0;j<h->table->number_of_slots;++j)
+ if(h->table->slots[j].is_alive && h->table->slots[j].where_in_array>i)
+ h->table->slots[j].where_in_array--; //shift the indices after the deleted element
+ }
+ return h;
+ }
+ void* gahm_get(struct ga_memory_hash_table *h,void* key)
+ {
+ ga_hash_t hash;
+ size_t j;
+
+ if(!h || h->oom)
+ return NULL; //technically we can be oom and still extract stuff from the ht, but this is more noticable
+
+ hash=ga_hash_bytes(key,h->key_size);
+ for(j=0;gah_slot_is_taken(h->table,hash,j) && memcmp(key,h->keys+h->key_size*gah_geti(h->table,hash,j),h->key_size) ;++j);
+
+ if(gah_slot_is_taken(h->table,hash,j) && !memcmp(key,h->keys+h->key_size*gah_geti(h->table,hash,j),h->key_size))
+ return h->values+gah_geti(h->table,hash,j)*h->value_size;
+ else
+ return NULL;
+ }
+ _Bool gahm_oom(struct ga_memory_hash_table *h)
+ {
+ return h==NULL || h->oom;
+ }
+ void gahm_delete(struct ga_memory_hash_table *h)
+ {
+ if(h==NULL)
+ return;
+ if(h->keys)
+ gar_delete(h->keys);
+
+ if(h->values)
+ gar_delete(h->values);
+
+ if(h->table)
+ gah_delete(h->table);
+ ga_free(h);
+ }
+ void ga_list_head_init(struct ga_list_head *node)
+ {
+ node->next=node->previous=NULL;
+ }
+ struct ga_list_head* ga_list_find_first(struct ga_list_head *node)
+ {
+ while(node->previous!=NULL)
+ node=node->previous;
+
+ return node;
+ }
+ struct ga_list_head* ga_list_find_last(struct ga_list_head *node)
+ {
+ while(node->next!=NULL)
+ node=node->next;
+ return node;
+ }
+ void ga_list_push_front(struct ga_list_head *list_node,struct ga_list_head *new_node)
+ {
+ list_node=ga_list_find_first(list_node);
+ new_node->next=list_node;
+ list_node->previous=new_node;
+ new_node->previous=NULL;
+ }
+ void ga_list_delete_node(struct ga_list_head *list_node)
+ {
+ if(list_node->previous)
+ {
+ list_node->previous->next=list_node->next;
+ list_node->previous=NULL;
+ }
+ if(list_node->next)
+ {
+ list_node->next->previous=list_node->previous;
+ list_node->previous=NULL;
+ }
+ }
+ void ga_list_push_after(struct ga_list_head *list_node,struct ga_list_head *new_node)
+ {
+ new_node->previous=list_node;
+ new_node->next=list_node->next;
+ if(list_node->next)
+ list_node->next->previous=new_node;
+ list_node->next=new_node;
+ }
+ void ga_list_push_before(struct ga_list_head *list_node,struct ga_list_head *new_node)
+ {
+ new_node->next=list_node;
+ new_node->previous=list_node->previous;
+ if(list_node->previous)
+ list_node->previous->next=new_node;
+ list_node->previous=new_node;
+ }
+
+ void ga_stack_init(struct ga_stack_head *node)
+ {
+ node->next=NULL;
+ }
+ void ga_stack_push(struct ga_stack_head *top,struct ga_stack_head *new)
+ {
+ new->next=top;
+ }
+ struct ga_stack_head* ga_stack_pop(struct ga_stack_head *top)
+ {
+ struct ga_stack_head *ret=top->next;
+ top->next=NULL;
+ return ret;
+ }
+
+
+ #ifdef GALIB_CURL
+
+ size_t ga__curl_get_read_callback(void *data,size_t size,size_t nmemb,void *closure)
+ {
+ struct ga_curl_http_get *curl=closure;
+ size_t hold_last_index=gar_last_index(curl->buffer);
+ curl->buffer=gar_expand(curl->buffer,size*nmemb);
+ memmove(curl->buffer+hold_last_index,data,nmemb*size);
+ return size*nmemb;
+ }
+ ssize_t ga__curl_read(void *state,void *dst,size_t num_bytes)
+ {
+ int running_handles;
+ struct ga_curl_http_get *curl=state;
+ if(curl->still_running)
+ {
+
+ if(num_bytes<gar_size(curl->buffer))
+ {
+ memmove(dst,curl->buffer,gar_size(curl->buffer));
+ memcpy(curl->buffer,curl->buffer+num_bytes,gar_size(curl->buffer)-num_bytes);
+ gar_shrink(curl->buffer,num_bytes);
+ return num_bytes;
+ }else
+ {
+ do {
+ CURLMcode mc;
+ mc=curl_multi_perform(curl->mhandle,&running_handles);
+ curl->still_running=running_handles;
+ if(!mc && running_handles)
+ {
+ mc=curl_multi_poll(curl->mhandle,NULL,0,1000,NULL);
+ }else
+ {
+ break;
+ }
+ if(gar_size(curl->buffer)>=num_bytes)
+ break;
+ }while(1);
+
+ memmove(dst,curl->buffer,num_bytes);
+ memcpy(curl->buffer,curl->buffer+num_bytes,gar_size(curl->buffer)-num_bytes);
+ gar_shrink(curl->buffer,num_bytes);
+
+ return num_bytes;
+ }
+
+
+ }else
+ {
+ if(gar_size(curl->buffer))
+ {
+ if(num_bytes<=gar_size(curl->buffer))
+ {
+ memmove(dst,curl->buffer,num_bytes);
+ memcpy(curl->buffer,curl->buffer+num_bytes,gar_size(curl->buffer)-num_bytes);
+ gar_shrink(curl->buffer,num_bytes);
+ return num_bytes;
+ }else
+ {
+ ssize_t hold_size=gar_size(curl->buffer);
+ memmove(dst,curl->buffer,hold_size);
+ curl->buffer=gar_resize(curl->buffer,0);
+ return hold_size;
+
+ }
+ }else
+ {
+ return -1;
+ }
+ }
+ }
+ ssize_t ga__curl_write(void *state,void *src,size_t num_bytes);
+ _Bool ga__curl_fseek(void *state,size_t where,int whence);
+ _Bool ga__curl_get_eof(void *state)
+ {
+ struct ga_curl_http_get *curl=state;
+ return !curl->still_running && !gar_size(curl->buffer);
+ }
+
+ struct ga_curl_http_get* ga_curl_make_http_get_request(const char *url)
+ {
+ struct ga_curl_http_get *ret;
+
+ ret=ga_malloc(sizeof(struct ga_curl_http_get));
+
+ if(ret==NULL)
+ return NULL;
+
+ ret->type=GA_CURL_TYPE_HTTP_GET;
+ ret->url=gas_cstr(url);
+ if(gas_oom(ret->url))
+ {
+ ga_free(ret);
+ return NULL;
+ }
+ ret->out.read=ga__curl_read;
+ ret->out.write=ga__fail_write;
+ ret->out.fseek=ga__fail_fseek;
+ ret->out.eof=ga__curl_get_eof;
+ ret->out.type=GA_STREAM_TYPE_OOM;
+ ret->out.state=ret;
+ ret->handle=curl_easy_init();
+ ret->mhandle=curl_multi_init();
+ ret->sent_headers=NULL;
+ ret->returned_header_names=gar_alloc(0,sizeof(struct ga_str));
+ ret->returned_header_values=gar_alloc(0,sizeof(struct ga_str));
+ ret->still_running=1;
+ ret->buffer=gar_alloc(0,1);
+
+ if(ret->handle==NULL)
+ {
+ gas_delete(&ret->url);
+ ga_free(ret);
+ return NULL;
+ }
+
+ curl_multi_add_handle(ret->mhandle,ret->handle);
+ curl_easy_setopt(ret->handle,CURLOPT_URL,url);
+ curl_easy_setopt(ret->handle,CURLOPT_WRITEFUNCTION,ga__curl_get_read_callback);
+ curl_easy_setopt(ret->handle,CURLOPT_WRITEDATA,(void*)ret);
+
+ return ret;
+ }
+
+ _Bool ga_curl_set_add_http_header(struct ga_curl *curl,const char *header_name,const char *header_value)
+ {
+ struct ga_str temp;
+ if(!curl || !header_name || (curl->type!=GA_CURL_TYPE_HTTP_POST && curl->type!=GA_CURL_TYPE_HTTP_GET))
+ return 0;
+
+ temp=gas_cstr(header_name);
+ if(gas_oom(temp))
+ return 0;
+ gas_append(&temp,header_value);
+ if(curl->type==GA_CURL_TYPE_HTTP_GET)
+ ((struct ga_curl_http_get*)curl)->sent_headers = curl_slist_append(((struct ga_curl_http_get*)curl)->sent_headers, temp.cs);
+ gas_delete(&temp);
+
+ return 1;
+ }
+ _Bool ga_curl_set_credentials(struct ga_curl *curl,const char *username,const char *password)
+ {
+ if(!curl || !username)
+ return 0;
+ curl_easy_setopt(curl->handle, CURLOPT_USERNAME, username);
+ if(password)
+ curl_easy_setopt(curl->handle, CURLOPT_PASSWORD, password);
+ return 1;
+ }
+
+ void ga_curl_delete(struct ga_curl *curl)
+ {
+
+ }
+
+ #endif
+
+ #ifdef GALIB_TIDY
+ struct ga_html_node* _garray ga__tidy_node_to_ga_node_internal(TidyNode node,TidyDoc doc,struct ga_html_node * _garray * where_to_push,struct ga_html_node *parent)
+ {
+ struct ga_html_node *ret;
+ TidyNodeType type;
+ type=tidyNodeGetType(node);
+
+ *where_to_push=gar_expand(*where_to_push,1);
+ (*where_to_push)[gar_last_index(*where_to_push)].name=gas_make();
+ (*where_to_push)[gar_last_index(*where_to_push)].text=gas_make();
+ (*where_to_push)[gar_last_index(*where_to_push)].attribute_names=gar_alloc(0,sizeof(struct ga_str));
+ (*where_to_push)[gar_last_index(*where_to_push)].attribute_values=gar_alloc(0,sizeof(struct ga_str));
+ (*where_to_push)[gar_last_index(*where_to_push)].children=gar_alloc(0,sizeof(struct ga_html_node*));
+ ret=*where_to_push+gar_last_index(*where_to_push);
+ ret->parent=parent;
+
+
+ if(type==TidyNode_Text)
+ {
+ TidyBuffer txt={0};
+ tidyNodeGetText(doc,node,&txt);
+ struct ga_stream ss;
+ ss=gas_stream(&ret->text);
+ ga_write(&ss,txt.bp,txt.size-1);
+
+ tidyBufFree(&txt);
+ ga_stream_delete(&ss);
+ ret->type=GA_HTML_NODE_TYPE_TEXT;
+ }else
+ {
+ TidyAttr it;
+
+ ret->type=GA_HTML_NODE_TYPE_TAG;
+
+ {
+ struct ga_stream ss;
+ ss=gas_stream(&ret->name);
+ ga_fprintf(&ss,"%s",tidyNodeGetName(node));
+ ga_stream_delete(&ss);
+ }
+
+ for(it=tidyAttrFirst(node);it!=NULL;it=tidyAttrNext(it))
+ {
+ ret->attribute_names=gar_expand(ret->attribute_names,1);
+ ret->attribute_values=gar_expand(ret->attribute_values,1);
+
+ ret->attribute_names[gar_last_index(ret->attribute_names)]=gas_cstr(tidyAttrName(it));
+ ret->attribute_values[gar_last_index(ret->attribute_values)]=gas_cstr(tidyAttrValue(it));
+ }
+
+ for(TidyNode child=tidyGetChild(node);child!=NULL;child=tidyGetNext(child))
+ {
+ ret->children=gar_expand(ret->children,1);
+ ret->children[gar_last_index(ret->children)]=ga__tidy_node_to_ga_node_internal(child,doc,where_to_push,ret);
+ }
+
+ }
+
+ return ret;
+ }
+ Bool ga__html_parse_eof_helper(void *closure)
+ {
+ struct ga__html_parse_info *i=closure;
+ return gar_size(i->buff)==0 && ga_eof(i->input);
+ }
+ int ga__html_parse_get_byte_helper(void *closure)
+ {
+ struct ga__html_parse_info *i=closure;
+ if(gar_size(i->buff))
+ {
+ int ret;
+ ret=(int)i->buff[0];
+ gar_delete_elements(i->buff,0,1);
+ return ret;
+ }else
+ {
+ if(ga_eof(i->input))
+ return EOF;
+ else
+ {
+ char ret;
+ ga_read(i->input,&ret,1);
+ return (int)ret;
+ }
+ }
+ }
+ void ga__html_parse_unget_byte_helper(void *closure,byte bt)
+ {
+ struct ga__html_parse_info *i=closure;
+ i->buff=gar_expand(i->buff,1);
+ i->buff[gar_last_index(i->buff)]=bt;
+ }
+ size_t ga__get_number_of_html_nodes(TidyNode node,TidyDoc doc)
+ {
+ size_t ret=1;
+ for(TidyNode child=tidyGetChild(node);child!=NULL;child=tidyGetNext(child))
+ {
+ ret+=ga__get_number_of_html_nodes(child,doc);
+ }
+ return ret;
+ }
+ struct ga_html_document* ga_html_parse(struct ga_stream *in)
+ {
+ TidyDoc doc;
+ TidyInputSource src;
+ struct ga__html_parse_info info;
+ struct ga_html_node * _garray ret_nodes=NULL;
+ struct ga_html_document *ret;
+ ssize_t buff_read_size;
+
+ if(!in)
+ return NULL;
+
+
+ if(!in || ga_eof(in))
+ return NULL;
+
+ ret_nodes=gar_alloc(0,sizeof(struct ga_html_node));
+ if(gar_oom(ret_nodes))
+ {
+ gar_delete(ret_nodes);
+ return NULL;
+ }
+
+ doc=tidyCreate();
+ tidyOptSetBool(doc,TidyShowWarnings,no);
+ tidyOptSetInt(doc,TidyShowErrors,0);
+ tidyOptSetBool(doc,TidyShowInfo,no);
+ tidyOptSetBool(doc, TidyForceOutput, yes);
+ //tidyOptSetBool(doc, TidyXhtmlOut, yes);
+
+ info.buff=gar_alloc(0,1);
+ info.input=in;
+
+ if(gar_oom(info.buff))
+ {
+ gar_delete(info.buff);
+ gar_delete(ret_nodes);
+ return NULL;
+ }
+
+ src.eof=ga__html_parse_eof_helper;
+ src.getByte=ga__html_parse_get_byte_helper;
+ src.sourceData=&info;
+ src.ungetByte=ga__html_parse_unget_byte_helper;
+
+ tidyParseSource(doc,&src);
+
+ gar_delete(info.buff);
+
+ //tidyCleanAndRepair(doc);
+
+
+ ret_nodes=gar_resize(ret_nodes,ga__get_number_of_html_nodes(tidyGetRoot(doc),doc));
+ ret_nodes=gar_resize(ret_nodes,0);
+ ga__tidy_node_to_ga_node_internal(tidyGetRoot(doc),doc,&ret_nodes,NULL);
+
+ //tidyBufFree(&buffer); the attached html is freed with ga_delete_array
+ //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ tidyRelease(doc);
+
+ ret_nodes->parent=ret_nodes;
+
+ ret=ga_malloc(sizeof(*ret));
+ if(ret==NULL)
+ gar_delete(ret_nodes);
+ else
+ ret->nodes=ret_nodes;
+ return ret;
+ }
+ #endif
+ ssize_t ga_html_attribute_index(struct ga_html_node *node,char *attr_name)
+ {
+ size_t attr_len;
+ attr_len=strlen(attr_name);
+
+ if(node)
+ {
+ for(size_t i=0;i<gar_size(node->attribute_names);++i)
+ {
+ if(!memcmp(node->attribute_names[i].cs,attr_name,attr_len))
+ {
+ if(i<gar_size(node->attribute_values))
+ return (ssize_t)i;
+ else
+ return (ssize_t)-1;
+ }
+
+ }
+ }
+
+ return (ssize_t)-1;
+ }
+
+ void ga_print_html_node(struct ga_stream *out,struct ga_html_node *node)
+ {
+ ga__print_html_node_inner(out,node,0);
+ }
+ void ga_print_html_document(struct ga_stream *out,struct ga_html_document *doc)
+ {
+ ga__print_html_node_inner(out,doc->nodes,0);
+ }
+ void ga__print_html_node_inner(struct ga_stream *out,struct ga_html_node *node,size_t indent)
+ {
+ if(node)
+ {
+ if(node->type==GA_HTML_NODE_TYPE_TAG)
+ {
+ for(size_t i=0;i<indent;++i)
+ ga_fprintf(out,"\t");
+ ga_fprintf(out,"<%s ",node->name.cs);
+ for(size_t i=0;i<gar_size(node->attribute_names);++i)
+ ga_fprintf(out,"%s=\"%s\" ",node->attribute_names[i].cs,node->attribute_values[i].cs);
+ ga_fprintf(out,">\n");
+ for(size_t i=0;i<gar_size(node->children);++i)
+ ga__print_html_node_inner(out,node->children[i],indent+1);
+
+ for(size_t i=0;i<indent;++i)
+ ga_fprintf(out,"\t");
+ ga_fprintf(out,"</%s>\n",node->name.cs);
+ }else
+ {
+ for(size_t i=0;i<indent;++i)
+ ga_fprintf(out,"\t");
+ ga_fprintf(out,"%s\n",node->text.cs);
+ }
+ }
+ }
+ struct ga_html_node* ga_html_get_path(struct ga_html_node *node,int depth,...)
+ {
+ va_list args;
+ int hold_arg;
+ va_start(args,depth);
+
+ if(depth>100)/*this prob isn't going to happen*/
+ return NULL;
+
+ for(int i=0;i<depth && node;++i)
+ {
+ hold_arg=va_arg(args,int);
+
+ if(hold_arg<gar_size(node->children))
+ {
+ node=node->children[hold_arg];
+ }else
+ {
+ node=NULL;
+ break;
+ }
+ }
+
+ va_end(args);
+
+ return node;
+
+ }
+ void ga_delete_html_nodes(struct ga_html_node **nodes)
+ {
+ }
+
+ #ifdef GALIB_XML
+ static struct ga_html_node* ga__parse_xml_condense(xmlNode *node,struct ga_html_node **where_to_push,struct ga_html_node *parent)
+ {
+ struct ga_html_node *ret;
+ ga_push_element(where_to_push,((struct ga_html_node){.name=NULL,.text=NULL,.attribute_names=NULL,.attribute_values=NULL,.children=NULL,.parent=NULL}));
+ ret=&ga_last_element(*where_to_push);
+ ret->parent=parent;
+
+ if(node->type==XML_TEXT_NODE || node->type==XML_CDATA_SECTION_NODE)
+ {
+ ret->text=ga_cstr_to_str(node->content);
+ }else
+ {
+ ret->name=ga_cstr_to_str(node->name);
+ for(xmlAttr *it=node->properties;it!=NULL;it=it->next)
+ {
+ ga_push_element(&(ret->attribute_names),ga_cstr_to_str(it->name));
+ ga_push_element(&(ret->attribute_values),ga_cstr_to_str(it->children->content));
+ }
+ for(xmlNode *it=node->children;it!=NULL;it=it->next)
+ {
+ ga_push_element(&(ret->children),ga__parse_xml_condense(it,where_to_push,ret));
+ }
+ }
+ return ret;
+
+ }
+ static size_t ga__parse_xml_get_node_count(xmlNode *node)
+ {
+ xmlNode *it=NULL;
+ size_t ret=0;
+
+ for(it=node;it!=NULL;it=it->next)
+ {
+ if(it->type==XML_ELEMENT_NODE)
+ ret+=1+ga__parse_xml_get_node_count(it->children);/*children+parent*/
+ else
+ ret+=1;
+ }
+
+ return ret;
+
+ }
+ struct ga_html_node* ga_parse_xml(ga_str_t xml)
+ {
+ xmlDocPtr doc=NULL;
+ xmlNode *root=NULL;
+ struct ga_html_node *ret=NULL;
+ size_t number_of_nodes;
+
+ LIBXML_TEST_VERSION
+ doc=xmlReadMemory(xml,ga_str_size(xml), "noname.xml", NULL, 0);
+
+ if(doc)
+ {
+ root=xmlDocGetRootElement(doc);
+ number_of_nodes=ga__parse_xml_get_node_count(root);
+
+ ga_resize_array(&ret,number_of_nodes);
+ ga_resize_array(&ret,0);
+ ga__parse_xml_condense(root,&ret,ret);
+ }
+
+
+ xmlFreeDoc(doc);
+ xmlCleanupParser();
+
+ return ret;
+ }
+ static ga_str_t ga__parse_rss_children_to_str(struct ga_html_node *parent)
+ {
+ ga_str_t ret=NULL;
+ for(size_t i=0;i<ga_array_size(parent->children);++i)
+ {
+ ga_str_append_str(&ret,ga_html_node_to_str(parent->children[i]));
+ }
+ return ret;
+
+ }
+ static void ga__parse_rss_channel_item(struct ga_html_node *item_node,struct ga_rss_channel_item **where_to_push)
+ {
+ struct ga_rss_channel_item hold_item={.title=NULL,.link=NULL,.description=NULL,.author=NULL};
+ for(size_t i=0;i<ga_array_size(item_node->children);++i)
+ {
+ if(ga_str_eq(item_node->children[i]->name,"title"))
+ {
+ if(hold_item.title)
+ ga_delete_str(&hold_item.title);
+ hold_item.title=ga__parse_rss_children_to_str(item_node->children[i]);
+ }
+ else if(ga_str_eq(item_node->children[i]->name,"author"))
+ {
+ if(hold_item.author)
+ ga_delete_str(&hold_item.author);
+ hold_item.author=ga__parse_rss_children_to_str(item_node->children[i]);
+ }else if(ga_str_eq(item_node->children[i]->name,"description"))
+ {
+ if(hold_item.description)
+ ga_delete_str(&hold_item.description);
+ hold_item.description=ga__parse_rss_children_to_str(item_node->children[i]);
+ }else if(ga_str_eq(item_node->children[i]->name,"link"))
+ {
+ if(hold_item.link)
+ ga_delete_str(&hold_item.link);
+ hold_item.link=ga__parse_rss_children_to_str(item_node->children[i]);
+ }else if(ga_str_eq(item_node->children[i]->name,"group"))/*youtube stuff*/
+ {
+ for(size_t j=0;j<ga_array_size(item_node->children[i]->children);++j)
+ {
+
+ if(ga_str_eq(item_node->children[i]->children[j]->name,"title"))
+ {
+ if(hold_item.title)
+ ga_delete_str(&hold_item.title);
+ hold_item.title=ga__parse_rss_children_to_str(item_node->children[i]);
+ }
+ else if(ga_str_eq(item_node->children[i]->children[j]->name,"content"))
+ {
+ if(hold_item.link)
+ ga_delete_str(&hold_item.link);
+ hold_item.link=ga_get_value_of_attribute(item_node->children[i]->children[j],"url");
+
+ }else if(ga_str_eq(item_node->children[i]->children[j]->name,"description"))
+ {
+ if(hold_item.description)
+ ga_delete_str(&hold_item.description);
+ hold_item.description=ga__parse_rss_children_to_str(item_node->children[i]->children[j]);
+ }
+ }
+ }
+ }
+ ga_push_element(where_to_push,hold_item);
+ }
+ static void ga__parse_rss_channel(struct ga_html_node *channel_node,struct ga_rss_channel **where_to_push)
+ {
+ struct ga_rss_channel hold_channel={.title=NULL,.description=NULL,.author=NULL,.items=NULL};
+
+ for(size_t i=0;i<ga_array_size(channel_node->children);++i)
+ {
+ if(ga_str_eq(channel_node->children[i]->name,"title"))
+ {
+ if(hold_channel.title)
+ ga_delete_str(&hold_channel.title);
+ hold_channel.title=ga__parse_rss_children_to_str(channel_node->children[i]);
+ }
+ else if(ga_str_eq(channel_node->children[i]->name,"author"))
+ {
+ if(hold_channel.author)
+ ga_delete_str(&hold_channel.author);
+ hold_channel.author=ga__parse_rss_children_to_str(channel_node->children[i]);
+ }else if(ga_str_eq(channel_node->children[i]->name,"description"))
+ {
+ if(hold_channel.description)
+ ga_delete_str(&hold_channel.description);
+ hold_channel.description=ga__parse_rss_children_to_str(channel_node->children[i]);
+ }else if(
+ ga_str_eq(channel_node->children[i]->name,"item")
+ || ga_str_eq(channel_node->children[i]->name,"entry")
+ )
+ {
+ ga__parse_rss_channel_item(channel_node->children[i],&(hold_channel.items));
+ }
+ }
+ ga_push_element(where_to_push,hold_channel);
+ }
+ struct ga_rss_channel* ga_parse_rss_feed(ga_str_t rss)
+ {
+ struct ga_html_node *hold_nodes;
+ struct ga_html_node *rss_node=NULL;
+ struct ga_html_node *feed_node=NULL;
+ struct ga_rss_channel *ret=NULL;
+ size_t i;
+
+ hold_nodes=ga_parse_xml(rss);
+
+ for(i=0;i<ga_array_size(hold_nodes);++i)
+ {
+ if(ga_str_eq(hold_nodes[i].name,"rss"))
+ {
+ rss_node=hold_nodes+i;
+ break;
+ }else if(ga_str_eq(hold_nodes[i].name,"feed"))
+ {
+ feed_node=hold_nodes+i;
+ break;
+ }
+
+ }
+
+ if(rss_node)
+ {
+ for(i=0;i<ga_array_size(rss_node->children);++i)
+ {
+ if(ga_str_eq(rss_node->children[i]->name,"channel"))
+ ga__parse_rss_channel(rss_node->children[i],&ret);
+ }
+ }else if(feed_node)
+ {
+ ga__parse_rss_channel(feed_node,&ret);
+ }
+
+
+ ga_delete_html_nodes(&hold_nodes);
+
+ return ret;
+ }
+ void ga_delete_rss_feed(struct ga_rss_channel **feed)
+ {
+ for(size_t i=0;i<ga_array_size(*feed);++i)
+ {
+ ga_delete_array(&((*feed)[i].items));
+ }
+
+ ga_delete_array(feed);
+ }
+
+ #endif
+
+
+ #ifdef GALIB_MYSQL
+
+ struct ga_mysql* ga_mysql_connect(const char *url,const char *user,const char *pass)
+ {
+ struct ga_mysql *ret=NULL;
+
+ ret=ga_malloc(sizeof(struct ga_mysql));
+
+ if(ret==NULL)
+ return NULL;
+ ret->connection=mysql_init(NULL);
+ ret->state=GA_MYSQL_STATE_START;
+ ret->statement=NULL;
+ ret->bind=NULL;
+ ret->result_bind=NULL;
+ ret->has_remaining_rows=0;
+
+ if(ret->connection==NULL)
+ {
+ ga_free(ret);
+ return NULL;
+ }
+
+ if(mysql_real_connect(ret->connection,url,user,pass,NULL,0,NULL,0)==NULL)
+ {
+ mysql_close(ret->connection);
+ ga_free(ret);
+ return NULL;
+ }
+
+ return ret;
+ }
+ _Bool ga_mysql_use(struct ga_mysql *mysql,const char *database)
+ {
+ if(mysql && mysql->state!=GA_MYSQL_STATE_ERROR)
+ {
+ if(mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS)
+ {
+ if(!ga__mysql_drop_prepared_statement(mysql))
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }
+
+ if(mysql_select_db(mysql->connection,database))
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_USING_DATABASE;
+ return 1;
+ }
+ }else
+ {
+ return 0;
+ }
+
+ }
+ _Bool ga_mysql_prepare(struct ga_mysql *mysql,const char *statement)
+ {
+ if(statement && mysql && (mysql->state==GA_MYSQL_STATE_USING_DATABASE || mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS))
+ {
+ if(mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS)
+ {
+ if(!ga__mysql_drop_prepared_statement(mysql))
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }
+
+ mysql->statement=mysql_stmt_init(mysql->connection);
+ if(mysql->statement==NULL)
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }else
+ {
+ size_t statement_len;
+ size_t num_param=0;
+ statement_len=strnlen(statement,1000);
+
+ if(mysql_stmt_prepare(mysql->statement,statement,statement_len))
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_LOADING_ARGUMENTS;
+ mysql_free_result(mysql_stmt_result_metadata(mysql->statement));
+
+ for(size_t i=0;i<statement_len;++i)
+ if(statement[i]=='?')
+ ++num_param;
+
+ ga_resize_array(&(mysql->bind),num_param);
+ ga_resize_array(&(mysql->result_bind),mysql_stmt_field_count(mysql->statement));
+ if(mysql->bind==NULL || mysql->result_bind==NULL)
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+
+
+ memset(mysql->bind,0,num_param*sizeof(mysql->bind[0]));
+ memset(mysql->result_bind,0,ga_array_size(mysql->result_bind)*sizeof(mysql->bind[0]));
+ return 1;
+ }
+ }
+
+ }else
+ {
+ if(mysql)
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ }
+ return 0;
+ }
+
+ }
+ _Bool ga__mysql_drop_prepared_statement(struct ga_mysql *mysql)
+ {
+ if(mysql)
+ {
+ ga__mysql_reset_args(mysql);
+ if(mysql->statement)
+ mysql_stmt_close(mysql->statement);
+ ga_delete_array(&mysql->bind);
+ ga_delete_array(&mysql->result_bind);
+ mysql->bind=NULL;
+ mysql->result_bind=NULL;
+ mysql->has_remaining_rows=0;
+ return 1;
+ }else
+ {
+ return 0;
+ }
+ }
+ void ga_mysql_disconnect(struct ga_mysql *mysql)
+ {
+ ga__mysql_drop_prepared_statement(mysql);
+ mysql_close(mysql->connection);
+ mysql->state=GA_MYSQL_STATE_END;
+ }
+ _Bool ga_mysql_bind_int(struct ga_mysql *mysql,size_t index,int data)
+ {
+ int *gimp;
+ if(mysql && mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS && mysql->bind && index<ga_array_size(mysql->bind) )
+ {
+ ga__mysql_reset_arg(mysql->bind,index);/*reset data if there was any in*/
+ gimp=ga_malloc(sizeof(int));
+ if(gimp)
+ {
+ *gimp=data;
+ mysql->bind[index].buffer=gimp;
+ mysql->bind[index].buffer_type=MYSQL_TYPE_LONG;
+ mysql->bind[index].buffer_length=sizeof(int);
+ mysql->bind[index].length=&(mysql->bind[index].buffer_length);
+ mysql->bind[index].is_unsigned=0;
+ return 1;
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }
+ _Bool ga_mysql_bind_double(struct ga_mysql *mysql,size_t index,double data)
+ {
+ double *gimp;
+ if(mysql && mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS && mysql->bind && index<ga_array_size(mysql->bind) )
+ {
+ ga__mysql_reset_arg(mysql->bind,index);/*reset data if there was any in*/
+ gimp=ga_malloc(sizeof(double));
+ if(gimp)
+ {
+ *gimp=data;
+ mysql->bind[index].buffer=gimp;
+ mysql->bind[index].buffer_type=MYSQL_TYPE_DOUBLE;
+ mysql->bind[index].buffer_length=sizeof(double);
+ mysql->bind[index].length=&(mysql->bind[index].buffer_length);
+ mysql->bind[index].is_unsigned=0;
+ return 1;
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }
+
+ _Bool ga_mysql_bind_string(struct ga_mysql *mysql,size_t index,char *data)
+ {
+ ga_str_t gimp;
+ if(mysql && mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS && mysql->bind && index<ga_array_size(mysql->bind) )
+ {
+ ga__mysql_reset_arg(mysql->bind,index);/*reset data if there was any in*/
+ gimp=ga_cstr_to_str(data);
+ if(gimp)
+ {
+ mysql->bind[index].buffer=gimp;
+ mysql->bind[index].buffer_type=MYSQL_TYPE_STRING;
+ mysql->bind[index].buffer_length=ga_str_size(gimp);
+ mysql->bind[index].length=&(mysql->bind[index].buffer_length);
+ mysql->bind[index].is_unsigned=0;
+ return 1;
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }
+ _Bool ga_mysql_bind_blob(struct ga_mysql *mysql,size_t index,void *data,size_t data_size)
+ {
+ ga_str_t gimp=NULL;
+ if(mysql && mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS && mysql->bind && index<ga_array_size(mysql->bind) )
+ {
+ ga__mysql_reset_arg(mysql->bind,index);/*reset data if there was any in*/
+ ga_resize_str(&gimp,data_size);
+ if(gimp)
+ {
+ memcpy(gimp,data,data_size);
+ mysql->bind[index].buffer=gimp;
+ mysql->bind[index].buffer_type=MYSQL_TYPE_STRING;
+ mysql->bind[index].buffer_length=ga_str_size(gimp);
+ mysql->bind[index].length=&(mysql->bind[index].buffer_length);
+ mysql->bind[index].is_unsigned=0;
+ return 1;
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }
+ _Bool ga_mysql_execute(struct ga_mysql *mysql)
+ {
+ if(mysql && mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS)
+ {
+ _Bool ret=1;
+
+ ret=!mysql_stmt_bind_param(mysql->statement,mysql->bind);
+ ret=!mysql_stmt_bind_result(mysql->statement,mysql->result_bind) && ret;
+
+ ret=!mysql_stmt_execute(mysql->statement);
+ if(ret && mysql_stmt_fetch(mysql->statement)!=1)
+ {
+ mysql->has_remaining_rows=mysql_stmt_num_rows(mysql->statement);
+ ret=ga__mysql_reset_args(mysql) && ret;
+ return ret;
+ }else
+ {
+ return 0;
+ }
+ }else
+ {
+ return 0;
+ }
+ }
+ _Bool ga_mysql_has_remaining_rows(struct ga_mysql *mysql)
+ {
+ return mysql->has_remaining_rows;
+ }
+ _Bool ga_mysql_next_row(struct ga_mysql *mysql)
+ {
+ if(mysql && mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS && mysql->result_bind)
+ {
+ switch(mysql_stmt_fetch(mysql->statement))
+ {
+ case 0:
+ case MYSQL_DATA_TRUNCATED:
+ mysql->has_remaining_rows=1;
+ return 1;
+ case 1:
+ mysql->has_remaining_rows=0;
+ return 0;
+ case MYSQL_NO_DATA:
+ mysql->has_remaining_rows=0;
+ return 1;
+ }
+ return 0;
+ }else
+ {
+ mysql->state=GA_MYSQL_STATE_ERROR;
+ mysql->has_remaining_rows=0;
+ return 0;
+ }
+ }
+ _Bool ga__mysql_reset_args(struct ga_mysql *mysql)
+ {
+ if(mysql && mysql->state!=GA_MYSQL_STATE_ERROR)
+ {
+ for(size_t i=0;i<ga_array_size(mysql->bind);++i)
+ if(!ga__mysql_reset_arg(mysql->bind,i))
+ return 0;
+
+ return 1;
+ }else
+ {
+ return 0;
+ }
+ }
+ _Bool ga__mysql_reset_arg(MYSQL_BIND *bind,size_t arg_index)
+ {
+ if(bind[arg_index].buffer)
+ {
+ switch(bind[arg_index].buffer_type)
+ {
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ case MYSQL_TYPE_TINY:
+ ga_free(bind[arg_index].buffer);
+ break;
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_BLOB:
+ ga_delete_str((ga_str_t *)&(bind[arg_index].buffer));
+ break;
+ case MYSQL_TYPE_NULL:
+ break;
+ default:
+ return 0;
+ }
+ }
+ memset(bind+arg_index,0,sizeof(bind[arg_index]));
+ return 1;
+ }
+ _Bool ga_mysql_get_int(struct ga_mysql *mysql,size_t index,int *destination)
+ {
+ _Bool ret;
+ if(mysql && mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS && index<ga_array_size(mysql->result_bind) )
+ {
+ mysql->result_bind[index].buffer_type=MYSQL_TYPE_LONG;
+ mysql->result_bind[index].buffer=destination;
+ mysql->result_bind[index].buffer_length=sizeof(int);
+ ret=!mysql_stmt_fetch_column(mysql->statement,mysql->result_bind+index,index,0);
+ mysql->result_bind[index].buffer=NULL;
+ return ret;
+ }else
+ {
+ return 0;
+ }
+ }
+ _Bool ga_mysql_get_double(struct ga_mysql *mysql,size_t index,double *destination)
+ {
+ _Bool ret;
+ if(mysql && mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS && index<ga_array_size(mysql->result_bind) )
+ {
+ mysql->result_bind[index].buffer_type=MYSQL_TYPE_DOUBLE;
+ mysql->result_bind[index].buffer=destination;
+ mysql->result_bind[index].buffer_length=sizeof(double);
+ ret=!mysql_stmt_fetch_column(mysql->statement,mysql->result_bind+index,index,0);
+ mysql->result_bind[index].buffer=NULL;
+ return ret;
+ }else
+ {
+ return 0;
+ }
+ }
+ ga_str_t ga__mysql_get_str_blob(struct ga_mysql *mysql,size_t index,int type)
+ {
+ ga_str_t ret=NULL;
+ if(mysql && mysql->state==GA_MYSQL_STATE_LOADING_ARGUMENTS && index<ga_array_size(mysql->result_bind) )
+ {
+ unsigned long int real_number_of_bytes=0;
+ unsigned char byte;
+
+
+ mysql->result_bind[index].buffer_type=type;
+ mysql->result_bind[index].buffer=&byte;
+ /*horribly inefficient? Prob buffered in lib*/
+ mysql->result_bind[index].buffer_length=1;
+ mysql->result_bind[index].length=&real_number_of_bytes;
+ /*hacky loop*/
+ for(unsigned long offset=0;!mysql_stmt_fetch_column(mysql->statement,mysql->result_bind+index,index,offset) && offset<real_number_of_bytes;++offset)
+ {
+ ga_str_push_char(&ret,byte);
+ }
+ mysql->result_bind[index].buffer=NULL;
+ mysql->result_bind[index].buffer_length=0;
+ mysql->result_bind[index].length=NULL;
+ return ret;
+ }else
+ {
+ return NULL;
+ }
+ }
+ ga_str_t ga_mysql_get_string(struct ga_mysql *mysql,size_t index)
+ {
+ return ga__mysql_get_str_blob(mysql,index,MYSQL_TYPE_STRING);
+ }
+ ga_str_t ga_mysql_get_blob(struct ga_mysql *mysql,size_t index)
+ {
+ return ga__mysql_get_str_blob(mysql,index,MYSQL_TYPE_BLOB);
+ }
+ _Bool ga_mysql_start_transaction(struct ga_mysql *mysql)
+ {
+ if(mysql && mysql->connection && mysql->state!=GA_MYSQL_STATE_ERROR)
+ {
+ if(!mysql_query(mysql->connection,"START TRANSACTION"))
+ return 1;
+ else
+ return 0;
+ }else
+ {
+ return 0;
+ }
+ }
+ _Bool ga_mysql_end_transaction(struct ga_mysql *mysql)
+ {
+ if(mysql && mysql->connection && mysql->state!=GA_MYSQL_STATE_ERROR)
+ {
+ if(!mysql_query(mysql->connection,"COMMIT"))
+ return 1;
+ else
+ return 0;
+ }else
+ {
+ return 0;
+ }
+ }
+ _Bool ga_mysql_has_errors(struct ga_mysql *mysql)
+ {
+ return mysql==NULL || mysql->state==GA_MYSQL_STATE_ERROR || mysql->state>=GA_MYSQL_STATE_END;
+ }
+ #endif
+
+ #ifdef GALIB_OPENSSL
+ ga_bytes_t ga_openssl_hash(void *bytes,size_t num_bytes,char *hash_name)
+ {
+
+ EVP_MD_CTX *mdctx;
+ const EVP_MD *md;
+ ga_bytes_t ret=NULL;
+ unsigned int ret_len=0;
+
+
+ md=EVP_get_digestbyname(hash_name);
+ if(md==NULL)
+ return NULL;
+
+ ga_resize_array(&ret,EVP_MAX_MD_SIZE);
+
+ if(ret)
+ {
+ mdctx=EVP_MD_CTX_new();
+ EVP_DigestInit_ex(mdctx, md, NULL);
+ EVP_DigestUpdate(mdctx, bytes, num_bytes);
+ EVP_DigestFinal_ex(mdctx, ret, &ret_len);
+ EVP_MD_CTX_free(mdctx);
+
+ ga_resize_array(&ret,ret_len);
+ }
+
+ return ret;
+
+ }
+ ga_bytes_t ga_openssl_get_random_bytes(size_t num_bytes)
+ {
+ ga_bytes_t ret=NULL;
+ ga_resize_array(&ret,num_bytes);
+
+ if(ret)
+ {
+ RAND_priv_bytes(ret,ga_array_size(ret));
+ }
+
+ return ret;
+ }
+ void ga_openssl_put_random_bytes(void *where,size_t num_bytes)
+ {
+ RAND_priv_bytes(where,num_bytes);
+ }
+ #endif
+
+ #if 0
+ /*json must not be NULL*/
+ size_t ga__parse_skip_white_space(char *json,size_t json_size)
+ {
+ size_t i;
+ for(i=0;i<json_size && (json[i]==' ' || json[i]=='\t' || json[i]=='\n' || json[i]=='\r');++i);
+
+ return i;
+ }
+ struct ga_json* ga_parse_json(char *json,size_t json_size)
+ {
+ if(json)
+ {
+ if(json[0]=='\0')
+ {
+ return NULL;
+ }else if(json[0]=='{')
+ {
+ return ga__parse_object_inner(
+ }else if(json[0]=='[')
+ {
+
+ }else if(json[0]
+ }else
+ {
+ return NULL;
+ }
+ }
+ #endif
+ #endif
+
+ /*uint32_t takes care of endianness*/
+ _Bool ga_float_is_negative(float f)
+ {
+ return (*((uint32_t*)(void*)&f))&0x80000000u;
+ }
+
+ int16_t ga_float_get_exponent(float f)
+ {
+ return (((*((uint32_t*)(void*)&f))&0x7F800000u)>>23);
+ }
+ uint32_t ga_float_get_mantissa(float f)
+ {
+ return (*((uint32_t*)(void*)&f))&0x007FFFFFu;
+ }
+ float ga_float_set_sign(float f,_Bool is_negative)
+ {
+ uint32_t *as_uint=(void*)&f;
+ if(is_negative)
+ *as_uint=((*as_uint)|0x80000000u);
+ else
+ *as_uint=((*as_uint)&0x7FFFFFFFu);
+ return *(float*)(void*)as_uint;
+ }
+ float ga_float_set_exponent(float f,int16_t exponent)
+ {
+ uint32_t *as_uint=(void*)&f;
+ *as_uint=((*as_uint)&0x807FFFFFu)|((0xFu&(uint32_t)(exponent+0x7F))<<23);
+ return *(float*)(void*)as_uint;
+ }
+ float ga_float_set_base(float f,uint32_t base)
+ {
+ uint32_t *as_uint=(void*)&f;
+ *as_uint=((*as_uint)&0xFF800000u)|((0x007FFFFFu)&base);
+ return *(float*)(void*)as_uint;
+ }
+ /*uint64_t takes care of endianness*/
+ _Bool ga_double_is_negative(double d)
+ {
+ return (*((uint64_t*)(void*)&d))&0x8000000000000000ull;
+ }
+ int16_t ga_double_get_exponent(double d)
+ {
+ return ((*((uint64_t*)(void*)&d))&0x7FF0000000000000ull)>>52;
+ }
+ uint64_t ga_double_get_mantissa(double d)
+ {
+ return (*((uint64_t*)(void*)&d))&0x000FFFFFFFFFFFFFull;
+ }
+ double ga_double_set_sign(double d,_Bool is_negative)
+ {
+ uint64_t *as_uint=(void*)&d;
+ if(is_negative)
+ *as_uint=((*as_uint)|0x8000000000000000ull);
+ else
+ *as_uint=((*as_uint)&0x7FFFFFFFFFFFFFFFull);
+ return *(double*)(void*)as_uint;
+ }
+ double ga_double_set_exponent(double d,int16_t exponent)
+ {
+ uint64_t *as_uint=(void*)&d;
+ *as_uint=((*as_uint)&0x800FFFFFFFFFFFFFull)|((0x7Fu&(uint64_t)exponent)<<52);
+ return *(double*)(void*)as_uint;
+ }
+ double ga_double_set_mantissa(double d,uint64_t mantissa)
+ {
+ uint64_t *as_uint=(void*)&d;
+ *as_uint=((*as_uint)&0xFFF0000000000000ull)|((0x000FFFFFFFFFFFFFull)&mantissa);
+ return *(double*)(void*)as_uint;
+ }
+
+
+ #ifdef GALIB_POSIX
+ struct ga_child* ga_system(const char *format,...)
+ {
+ struct ga_str * _garray args;
+ char * _garray * _garray arguments_raw;
+ struct ga__scanformat fmt;
+ pid_t pid;
+ int pipe_in[2],pipe_out[2];
+ va_list vargs;
+ struct ga_child *ret;
+
+ va_start(vargs,format);
+
+ ret=ga_malloc(sizeof(struct ga_child));
+ if(ret==NULL)
+ {
+ va_end(vargs);
+ return NULL;
+ }
+ ret->stdio.state=ga_malloc(sizeof(struct ga__system_stream_state));
+ args=gar_alloc(1,sizeof(struct ga_str));
+ if(gar_oom(args) || ret->stdio.state==NULL)
+ {
+ ga_free(ret);
+ va_end(vargs);
+ return NULL;
+ }
+ args[0]=gas_make();
+
+ for(size_t i=0;format[i]!='\0';)
+ {
+ if(format[i]=='%')
+ {
+ ga__parse_scan_format(format+i,&fmt);
+ gas__from_scanformat(&fmt,vargs,args+gar_last_index(args));
+ i+=fmt.forward_crawl;
+ }else if(format[i]==' ' || format[i]=='\t' || format[i]=='\n' || format[i]=='\r')
+ {
+ if(gas_length(args[gar_last_index(args)])!=1) // null is one glyph
+ {
+ args=gar_expand(args,1);
+ args[gar_last_index(args)]=gas_make();
+ }
+ ++i;
+ }else
+ {
+ gas_push_codepoint(args+gar_last_index(args),(uint32_t)format[i]);
+ ++i;
+ }
+ }
+
+ va_end(vargs);
+
+ arguments_raw=gar_alloc(gar_size(args)+1,sizeof(char *));
+
+ if(gas_ceq(args[0],"") || gar_oom(args) || gar_oom(arguments_raw))
+ {
+ for(size_t i=0;i<gar_size(args);++i)
+ gas_delete(args+i);
+ gar_delete(arguments_raw);
+ ga_free(ret->stdio.state);
+ ga_free(ret);
+ return NULL;
+ }
+
+ for(size_t i=0;i<gar_size(args);++i)
+ arguments_raw[i]=(char*)args[i].cs;
+ arguments_raw[gar_last_index(arguments_raw)]=NULL;
+
+ pipe(pipe_in);
+ pipe(pipe_out);
+
+ pid=fork();
+ if(pid==0)
+ {
+ close(pipe_out[0]);
+ close(pipe_in[1]);
+ close(0);
+ dup(pipe_in[0]);
+ close(1);
+ dup(pipe_out[1]);
+ close(2);
+ dup(pipe_out[1]);
+ execvp(arguments_raw[0],arguments_raw);
+ exit(1);
+ }
+ close(pipe_in[0]);
+ close(pipe_out[1]);
+
+ ret->pid=pid;
+ ret->args=args;
+
+ ret->stdio.write=ga__system_stream_write;
+ ret->stdio.read=ga__system_stream_read;
+ ret->stdio.fseek=ga__system_stream_fseek;
+ ret->stdio.eof=ga__system_stream_eof;
+ ret->stdio.type=GA_STREAM_TYPE_SYSTEM;
+ struct ga__system_stream_state *s=(struct ga__system_stream_state*)ret->stdio.state;
+ s->pipe_in=pipe_out[0];
+ s->pipe_out=pipe_in[1];
+ s->has_cached_byte=0;
+ s->cached_byte=0;
+
+
+ gar_delete(arguments_raw);
+ return ret;
+ }
+ void ga__system_stream_delete(struct ga_stream *s)
+ {
+
+ struct ga__system_stream_state *ss=(struct ga__system_stream_state*)s->state;
+ close(ss->pipe_in);
+ close(ss->pipe_out);
+ ga_free(s->state);
+ }
+ ssize_t ga__system_stream_read(void *state,void *dst,size_t num_bytes)
+ {
+ struct ga__system_stream_state *s=(struct ga__system_stream_state*)state;
+ if(num_bytes && s->has_cached_byte)
+ {
+ ((unsigned char*)dst)[0]=s->cached_byte;
+ s->has_cached_byte=0;
+ --num_bytes;
+ }
+ return 1+read(s->pipe_in,dst+1,num_bytes);
+ }
+ ssize_t ga__system_stream_write(void *state,void *src,size_t num_bytes)
+ {
+ struct ga__system_stream_state *s=(struct ga__system_stream_state*)state;
+ return write(s->pipe_out,src,num_bytes);
+ }
+ _Bool ga__system_stream_fseek(void *state,size_t where,int whence)
+ {
+ return 0;
+ }
+ _Bool ga__system_stream_eof(void *state)
+ {
+ struct ga__system_stream_state *s=(struct ga__system_stream_state*)state;
+ if(s->has_cached_byte)
+ return 1;
+ else
+ return !(s->has_cached_byte=read(s->pipe_in,&s->cached_byte,1));
+ }
+ _Bool ga_is_executable_present(const char *exe)
+ {
+ struct ga_child *hold;
+ int ret;
+ hold=ga_system("test %s",exe);
+ ret=ga_wait_child(hold);
+ ga_delete_child(hold);
+
+ return !ret;
+ }
+ int ga_wait_child(struct ga_child *child)
+ {
+ int ret=0;
+ if(child->pid!=0)
+ waitpid(child->pid,&ret,0);
+ return ret;
+ }
+ _Bool ga_wait_child_timed(struct ga_child *child,ga_usek_t usek,int *ret)
+ {
+
+ }
+ void ga_delete_child(struct ga_child *child)
+ {
+ ga_stream_delete(&child->stdio);
+ for(size_t i=0;i<gar_size(child->args);++i)
+ gas_delete(child->args+i);
+ gar_delete(child->args);
+ ga_free(child);
+ }
+ #endif
+
+
F diff --git a/src/misc/wonky_array.c b/src/misc/wonky_array.c new file mode 100644 --- /dev/null +++ b/src/misc/wonky_array.c
+ #ifndef WONKY_ARRAY_C
+ #define WONKY_ARRAY_C WONKY_ARRAY_C
+ #include <wonky_array.h>
+
+ #define wonky_array_malloc(x) wonky_malloc(x)
+ #define wonky_array_realloc(x,y) wonky_realloc(x,y)
+ #define wonky_array_free(x) wonky_free(x)
+
+ void* _wonky_arr wonky_arr_alloc(size_t number_of_elements,size_t element_size)
+ {
+ struct wonky_array_internals *internals;
+ if(element_size==0)
+ return NULL;
+ /*
+ allocate one element extra so that wonky_array_last_index
+ can always give an index for valid memory
+ */
+ internals=wonky_array_malloc(sizeof(struct wonky_array_internals)+element_size*(number_of_elements?number_of_elements:1));
+ if(internals==NULL)
+ return NULL;
+
+ internals->size=number_of_elements;
+ internals->capacity=1;
+
+ if((element_size*number_of_elements)/element_size!=number_of_elements)
+ internals->element_size=0;
+ else
+ internals->element_size=element_size;
+
+ return internals->bytes;
+ }
+ void* _wonky_arr wonky_arr_expand(void * _wonky_arr arr,size_t expansion_size)
+ {
+ struct wonky_array_internals *internals;
+ internals=wonky_arr_get_internals(arr);
+
+
+ if(internals->element_size==0 || expansion_size==0) /*check for oom state or no expansion*/
+ {
+ return arr;
+ }else if(internals->size+expansion_size<=internals->size) /*check for size overflow*/
+ {
+ internals->element_size=0;/*oom state*/
+ return arr;
+ }else
+ {
+ if(internals->size+expansion_size<=internals->capacity)
+ {
+ internals->size+=expansion_size;
+ return arr;
+ }else
+ {
+ struct wonky_array_internals *new_internals=NULL;
+ size_t new_capacity=internals->capacity;
+
+ while(new_capacity<internals->size+expansion_size)
+ {
+ /*check for overflow*/
+ if( (new_capacity<<1) > new_capacity &&
+ (new_capacity<<1)*internals->element_size+sizeof(struct wonky_array_internals)
+ >
+ new_capacity*internals->element_size+sizeof(struct wonky_array_internals)
+ )
+ {
+ new_capacity<<=1;
+ }else
+ {
+ internals->element_size=0;/*oom state*/
+ return arr;
+ }
+ }
+ new_internals=wonky_array_realloc(internals,sizeof(struct wonky_array_internals)+new_capacity*internals->element_size);
+
+ if(new_internals==NULL)
+ {
+ internals->element_size=0; /*oom state*/
+ return arr;
+ }else
+ {
+ new_internals->capacity=new_capacity;
+ new_internals->size+=expansion_size;
+ return new_internals->bytes;
+ }
+ }
+
+ }
+ }
+ void* _wonky_arr wonky_arr_resize(void * _wonky_arr arr,size_t new_size)
+ {
+ struct wonky_array_internals *internals;
+ internals=wonky_arr_get_internals(arr);
+ if(new_size>internals->capacity)
+ {
+ arr=wonky_arr_expand(arr,new_size-internals->size);
+ internals=wonky_arr_get_internals(arr);
+ }
+ internals->size=new_size;
+ return arr;
+ }
+ void wonky_arr_delete_elements(void * _wonky_arr arr,size_t start_index,size_t number_of_elements)
+ {
+ if(arr)
+ {
+ struct wony_array_internals *internals;
+ internals=wonky_arr_get_internals(arr);
+ if(start_index<internals->size)
+ {
+ if(number_of_elements>internals->size ||
+ start_index>internals->size-number_of_elements ||
+ start_index>SIZE_MAX-number_of_elements)
+ {
+ internals->size=start_index+1;
+ return;
+ }
+ gmemmove(internals->bytes+start_index*internals->element_size,
+ internals->bytes+(start_index+number_of_elements)*internals->element_size,
+ (internals->size-start_index-number_of_elements)*internals->element_size);
+ internals->size-=number_of_elements;
+
+ }
+ }
+ }
+ void wonky_arr_shrink(void * _wonky_arr arr,size_t shrink_size)
+ {
+ struct wonky_array_internals *internals;
+ internals=wonky_arr_get_internals(arr);
+ if(internals->size<shrink_size)
+ internals->size=0;
+ else
+ internals->size-=shrink_size;
+ }
+ void wonky_arr_delete(void * _wonky_arr arr)
+ {
+ if(arr)
+ {
+ struct wonky_array_internals *internals;
+ internals=wonky_arr_get_internals(arr);
+ wonky_array_free(internals);
+ }
+ }
+ size_t wonky_arr_size(void * _wonky_arr arr)
+ {
+ return wonky_arr_get_internals(arr)->size;
+ }
+ size_t wonky_arr_last_index(void * _wonky_arr arr)
+ {
+ struct wonky_array_internals *internals;
+ internals=wonky_arr_get_internals(arr);
+ if(internals->size==0)
+ return 0;
+ else
+ return internals->size-1;
+ }
+ _Bool wonky_arr_oom(void * _wonky_arr arr)
+ {
+ if(arr)
+ return wonky_arr_get_internals(arr)->element_size==0;
+ else
+ return 1;
+ }
+ void _wonky_arr * wonky_arr_copy(void * _wonky_arr arr)
+ {
+ if(arr)
+ {
+ struct wonky_array_internals *internals;
+ void* ret_arr;
+
+ internals=wonky_get_internals(arr);
+ ret_arr=wonky_arr_alloc(internals->size,internals->element_size);
+ if(!wonky_arr_oom(ret_arr))
+ {
+ gmemcpy(ret_arr,internals->bytes,internals->size*internals->element_size);
+ return ret_arr;
+ }else
+ {
+ return ret_arr;
+ }
+ }else
+ {
+ return NULL;
+ }
+ }
+ }
+ struct wonky_array_internals* wonky_arr_get_internals(void * _wonky_arr arr)
+ {
+ return (struct wonky_array_internals*)(arr-offsetof(struct wonky_array_internals,bytes));
+ }
+
+ #endif
F diff --git a/src/misc/wonky_array.h b/src/misc/wonky_array.h new file mode 100644 --- /dev/null +++ b/src/misc/wonky_array.h
+ #ifndef WONKY_ARRAY_H
+ #define WONKY_ARRAY_H WONKY_ARRAY_H
+ #include <wonky_array.hh>
+
+ #include <common.h>
+ #include <wonky_malloc.h>
+
+ #define _wonky_arr
+
+ /*generic resizable array stuff*/
+ struct wonky_array_internals
+ {
+ size_t size;
+ size_t capacity;
+ size_t element_size;
+ unsigned char bytes[];
+ };
+
+ void* _wonky_arr wonky_arr_alloc(size_t number_of_elements,size_t element_size);
+ void* _wonky_arr wonky_arr_expand(void * _wonky_arr arr,size_t expansion_size);
+ void* _wonky_arr wonky_arr_resize(void * _wonky_arr arr,size_t new_size);
+ void wonky_arr_delete_elements(void * _wonky_arr arr,size_t start_index,size_t number_of_elements);
+ void wonky_arr_shrink(void * _wonky_arr arr,size_t shrink_size);
+ void wonky_arr_delete(void * _wonky_arr arr);
+ size_t wonky_arr_size(void * _wonky_arr arr);
+ size_t wonky_arr_last_index(void * _wonky_arr arr);
+ _Bool wonky_arr_oom(void * _wonky_arr arr);
+ void _wonky_arr * wonky_arr_copy(void * _wonky_arr arr);
+ struct wonky_array_internals* wonky_arr_get_internals(void * _wonky_arr arr);
+
+ #endif
F diff --git a/src/misc/wonky_array.hh b/src/misc/wonky_array.hh new file mode 100644 --- /dev/null +++ b/src/misc/wonky_array.hh
+ #ifndef WONKY_ARRAY_HH
+ #define WONKY_ARRAY_HH WONKY_ARRAY_HH
+
+ struct wonky_array_internals;
+
+ #endif
F diff --git a/src/misc/wonky_malloc.h b/src/misc/wonky_malloc.h --- a/src/misc/wonky_malloc.h +++ b/src/misc/wonky_malloc.h
void delete_memory_segment(struct Memory_Segment *segment);
void* wonky_malloc(size_t size);
+ void* wonky_realloc(void *old_mem,size_t new_size);
void* wonky_calloc(size_t nmemb,size_t size);
struct Map* wonky_malloc_map_node();
struct token* wonky_malloc_token();