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.txtsrc/misc/queue.csrc/misc/stack.csrc/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 0F 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));+ }++ #endifF 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);++ #endifF 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;++ #endifF 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.hvoid 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();