#define SC_ALLOC_CHUNK 1 /* how many x to alloc when allocing (for performance so we don't call malloc over and over again) */
#define SC_IN_STRUCT_ARRAY(type, name) _Atomic(type **) name; _Atomic(size_t) name##_sizeof; _Atomic(size_t) name##_length
#define SC_CWLE(c, name) (pthread_rwlock_wrlock(name) ? (SC_LOG(SC_LOG_ERROR,c,SC_I18N_LOCKING " " #name " " SC_I18N_FAILED)||1) :0)
#define SC_CRLE(c, name) (pthread_rwlock_rdlock(name) ? (SC_LOG(SC_LOG_ERROR,c,SC_I18N_LOCKING " " #name " " SC_I18N_FAILED)||1) :0)
#define SC_CUE(c, name) (pthread_rwlock_unlock(name) ? (SC_LOG(SC_LOG_ERROR,c,SC_I18N_UNLOCKING " " #name " " SC_I18N_FAILED)||1):0)
#define SC_REALLOC_K 1.5 /* constant to dynamically realloc large arrays (new size = current size * K) */
#define SC_ENGINE_GOOGLE (1 << 0)
/* _Atomic(size_t) sc_mem_max = 100e6; */ /* the really soft memory limit of the program: 100MB - NOT IMPLEMENTED */
#define SC_LOG(t, c, m, ...) sc_push_log(t, c, __func__, __FILE__, __LINE__, 0##__VA_OPT__(1), m __VA_OPT__(,) __VA_ARGS__)
#define SC_LOG_ERROR (1 << 0)
#define SC_LOG_WARNING (1 << 1)
#define SC_LOG_INFO (1 << 2)
#define SC_LOG_DEBUG (1 << 3)
#define SC_BIGGER_ARRAY(name, type, shallinit) do { \
name = realloc(name, sizeof(name[0])*ceil(name##_sizeof*SC_REALLOC_K)); \
for (size_t i = name##_sizeof; shallinit && (i < ceil(name##_sizeof*SC_REALLOC_K)); i++) \
name[i] = type##_init(); \
name##_sizeof = ceil(name##_sizeof*SC_REALLOC_K); /* ceil je ZELO pomemben, če je chunk 1 recimo */ \
} while (0);
#define SC_OPT_TYPE unsigned char
#define SC_OPT_IMAGE (1 << 0)
struct sc_logentry {
unsigned char type; /* SC_LOG_ERROR, SC_LOG_WARNING, SC_LOG_INFO, SC_LOG_DEBUG */
size_t line;
const char * function; /* nofree */
char * file; /* nofree */
char * message; /* yesfree */
time_t time;
};
int sc_logentry_free (struct sc_logentry * l); /* defined in log.c */
struct sc_logentry * sc_logentry_init (); /* defined in log.c */
struct sc_result {
struct sc_query * query; /* nofree - free from sc_cache */
char * url; /* yesfree - url of referer page when image searching */
char * desc; /* yesfree - url of image when image searching */
char * title; /* yesfree */
time_t date; /* some search engines like to extract a date from a website, store that here - not implemented */
unsigned short int rating; /* some search engines like to extract a rating from a website, store that here */ /* not implementd */
unsigned short int rating_max; /* max rating when above is used /\ */ /* not implemented yet */
char * breadcrumbs; /* yesfree - google has nice breadcrumbs, when hovering over the URL requires too much time (: */
};
struct sc_result * sc_result_init () {
struct sc_result * r = calloc(1, sizeof(struct sc_result));
r->url = NULL;
r->desc = NULL;
r->title = NULL;
r->breadcrumbs = NULL;
return r;
}
int sc_result_free (struct sc_result * r) {
if (!r)
return -1;
free(r->url);
free(r->desc);
free(r->title);
free(r->breadcrumbs);
free(r);
return 1;
}
struct sc_query {
struct sc_cache * cache; /* nofree - what cache owns this query */
SC_IN_STRUCT_ARRAY(struct sc_result, results); /* yesfree */
char * string; /* yesfree - query string, stripped of any excess characters that should be excluded from indexing */
time_t lookup_time; /* time of last lookup */
unsigned char engines; /* with what engine(s) was the query done - bitmask - if there are results from multiple engines */
SC_OPT_TYPE opt; /* some options */
};
struct sc_query * sc_query_init () {
struct sc_query * q = calloc(1, sizeof(struct sc_query));
q->results_sizeof = SC_ALLOC_CHUNK;
q->results = calloc(q->results_sizeof, sizeof(struct sc_result *));
for (size_t i = 0; i < q->results_sizeof; i++) {
q->results[i] = sc_result_init();
q->results[i]->query = q;
}
q->string = NULL;
return q;
}
int sc_query_free (struct sc_query * q) {
if (!q)
return -1;
free(q->string); /* if they were not alloced, they are NULL, if they were free'd somewhere else, they are also set to NULL */
for (size_t i = 0; i < q->results_sizeof; i++)
sc_result_free(q->results[i]);
free(q->results);
free(q);
return 1;
}
struct sc_cache {
SC_IN_STRUCT_ARRAY(struct sc_query, queries); /* yesfree */
pthread_rwlock_t * queries_lock;
SC_IN_STRUCT_ARRAY(struct sc_logentry, logentries); /* yesfree */
pthread_rwlock_t * logentries_lock;
};
struct sc_cache * sc_cache_init() {
struct sc_cache * c = calloc(1, sizeof(struct sc_cache));
c->queries_sizeof = SC_ALLOC_CHUNK;
c->logentries_sizeof = SC_ALLOC_CHUNK;
c->queries = calloc(c->queries_sizeof, sizeof(struct sc_query *));
c->logentries = calloc(c->logentries_sizeof, sizeof(struct sc_logentry *));
for (size_t i = 0; i < c->logentries_sizeof; i++) {
/* c->queries[i] = sc_query_init(); */ /* queries are not inited for performance reasons, they are inited by query function */
/* c->queries[i]->cache = c; */
c->logentries[i] = sc_logentry_init();
}
#define SC_CILI(name) do { name##_lock = malloc(sizeof(pthread_rwlock_t)); pthread_rwlock_init(name##_lock, NULL); } while (0)
SC_CILI(c->queries);
SC_CILI(c->logentries);
return c;
}
int sc_cache_free(struct sc_cache * c) {
if (!c)
return -1;
fprintf(stderr, "c->queries_sizeof = %lu\n", c->queries_sizeof);
for (size_t i = 0; i < c->queries_sizeof; i++)
sc_query_free(c->queries[i]);
free(c->queries);
for (size_t i = 0; i < c->logentries_sizeof; i++)
sc_logentry_free(c->logentries[i]);
free(c->logentries);
#define SC_CFLD(name) do { pthread_rwlock_destroy(name##_lock); free(name##_lock); } while(0)
SC_CFLD(c->queries);
SC_CFLD(c->logentries);
free(c);
return 1;
}