summaryrefslogtreecommitdiffstats
path: root/src/structs.c
blob: f23e52f96a4a51c29114ff0b76f4d2de0e034afb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#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) */
/* _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_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_STR(x) #x
enum sc_opt {
	SC_ENGINE_GOOGLE =	1 << 0,
	SC_LOG_ERROR	 =	1 << 1,
	SC_LOG_WARNING	 =	1 << 2,
	SC_LOG_INFO	 =	1 << 3,
	SC_LOG_DEBUG	 =	1 << 4,
	SC_OPT_IMAGE 	 =	1 << 5
};
#define SC_LOG_MASK (SC_LOG_ERROR | SC_LOG_WARNING | SC_LOG_INFO | SC_LOG_DEBUG)
#define SC_OPT_TYPE enum sc_opt
#define SC_OPT_INIT 0
#define SC_OPT_COMPAR /* mask */ (/* SC_ENGINE_GOOGLE | */ /* any engine is okay */ SC_OPT_IMAGE)
#define SC_COMPAR_CAST (int (*)(const void *, const void *))
#ifdef SC_LOGMEM
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 */
#endif
struct sc_cache {
#ifdef SC_OLD_STORAGE
	SC_IN_STRUCT_ARRAY(struct sc_query, queries); /* yesfree */
#else
	void * qrp; /* queries root pointer-tsearch(3) */
#endif
	pthread_rwlock_t * queries_lock;
#ifdef SC_LOGMEM
	SC_IN_STRUCT_ARRAY(struct sc_logentry, logentries); /* yesfree */
	pthread_rwlock_t * logentries_lock;
#endif
};
int sc_push_log (SC_OPT_TYPE t, struct sc_cache * c, const char * ca, char * f, size_t l, unsigned short int isf, char * m, ...);
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 */
	char * suggested; /* yesfree - suggested search query (did you mean) */
	bool redirect; /* true if client is encouraged to be redirected to suggested (showing results for) */
	SC_OPT_TYPE opt; /* some options including engines */
};
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;
	q->suggested = NULL;
	q->opt = SC_OPT_INIT;
	return q;
}
#ifdef SC_OLD_STORAGE
int
#else
void 
#endif
sc_query_free (
#ifdef SC_OLD_STORAGE
		struct sc_query
#else
		void
#endif
		* i) {
	struct sc_query * q =
#ifndef SC_OLD_STORAGE
		(struct sc_query *)
#endif
		i;
	if (!q)
		return
#ifdef SC_OLD_STORAGE
			-1
#endif
			;
	if (q->cache)
		SC_LOG(SC_LOG_DEBUG, q->cache, "sc_query_free: %s (sugg: %s)", q->string ? q->string : "NULL", q->suggested ? q->suggested : "NULL");
	free(q->string); /* if they were not alloced, they are NULL, if they were free'd somewhere else, they are also set to NULL */
	free(q->suggested);
	for (size_t i = 0; i < q->results_sizeof; i++)
		sc_result_free(q->results[i]);
	free(q->results);
	free(q);
	return
#ifdef SC_OLD_STORAGE
		1
#endif
		;
}
int sc_query_compar (const struct sc_query * a, const struct sc_query * b) {
#define SC_QUERY_COMPAR_OPT ->opt & SC_OPT_COMPAR
	int r = (a SC_QUERY_COMPAR_OPT) < (b SC_QUERY_COMPAR_OPT) ? -1
		: (a SC_QUERY_COMPAR_OPT) > (b SC_QUERY_COMPAR_OPT) ? 1 : 0;
	if (r) /* first we compare options, because it should be faster than query strings */
		return r; /* yeah, I know, useless optimizations */
	return strcmp(a->string, b->string);
}
struct sc_cache * sc_cache_init() {
#define SC_CILI(name) do { name##_lock = malloc(sizeof(pthread_rwlock_t)); pthread_rwlock_init(name##_lock, NULL); } while (0)
	struct sc_cache * c = calloc(1, sizeof(struct sc_cache));
#ifdef SC_OLD_STORAGE
	c->queries_sizeof = SC_ALLOC_CHUNK;
	c->queries = calloc(c->queries_sizeof, sizeof(struct sc_query *));
#endif
#ifdef SC_LOGMEM
	c->logentries_sizeof = SC_ALLOC_CHUNK;
	c->logentries = calloc(c->logentries_sizeof, sizeof(struct sc_logentry *));
	for (size_t i = 0; i < c->logentries_sizeof; i++)
		c->logentries[i] = sc_logentry_init();
	SC_CILI(c->logentries);
#endif
	SC_CILI(c->queries);
	return c;
}
int sc_cache_free(struct sc_cache * c) {
	#define SC_CFLD(name) do { pthread_rwlock_destroy(name##_lock); free(name##_lock); } while(0)
	if (!c)
		return -1;
#ifdef SC_OLD_STORAGE
	fprintf(stderr, "c->queries_sizeof = %zu\n", c->queries_sizeof);
	for (size_t i = 0; i < c->queries_sizeof; i++)
		sc_query_free(c->queries[i]);
	free(c->queries);
#else
	tdestroy(c->qrp, sc_query_free);
#endif
#ifdef SC_LOGMEM
	for (size_t i = 0; i < c->logentries_sizeof; i++)
		sc_logentry_free(c->logentries[i]);
	SC_CFLD(c->logentries);
	free(c->logentries);
#endif
	SC_CFLD(c->queries);
	free(c);
	return 1;
}