1 #include <stdio.h>
2 #include <sys/stat.h>
3 #include <errno.h>
4 #define __USE_XOPEN_EXTENDED // for strdup() BS glibc now needs
5 #include <string.h>
6 #define __USE_GNU // qsort_r()
7 #include <stdlib.h>
8 #define _POSIX_SOURCE
9 #include <time.h>
10 
11 #include <faup/faup.h>
12 #include <faup/snapshot.h>
13 
rehash(const void * e,void * unused)14 static size_t rehash(const void *e, void *unused)
15 {
16   return hash_string(((faup_snapshot_value_count_t *)e)->value);
17 }
18 
streq(const void * e,void * string)19 static bool streq(const void *e, void *string)
20 {
21   return strcmp(((faup_snapshot_value_count_t *)e)->value, string) == 0;
22 }
23 
faup_snapshot_new(void)24 faup_snapshot_t *faup_snapshot_new(void)
25 {
26   faup_snapshot_t *snapshot;
27   snapshot = malloc(sizeof(*snapshot));
28   snapshot->length = 0;
29   snapshot->items = NULL;
30 
31   return snapshot;
32 }
33 
faup_snapshot_value_count_debug(faup_snapshot_value_count_t * vc)34 void faup_snapshot_value_count_debug(faup_snapshot_value_count_t *vc)
35 {
36   if (!vc) {
37     fprintf(stderr, "%s: No such value_count object\n", __FUNCTION__);
38   }
39   printf("**\t\tvalue:->%s<-\n", vc->value);
40   printf("**\t\tfirst time seen: %s", ctime(&vc->first_time_seen));
41   printf("**\t\tlast time seen: %s", ctime(&vc->last_time_seen));
42   printf("**\t\tcount:%ld\n", vc->count);
43 }
44 
faup_snapshot_item_debug(faup_snapshot_item_t * item)45 void faup_snapshot_item_debug(faup_snapshot_item_t *item)
46 {
47   struct htable_iter iter;
48   faup_snapshot_value_count_t *vc;
49 
50   if (!item) {
51     printf("** item empty, cannot debug!\n");
52     return;
53   }
54 
55   printf("** \titem\n");
56   printf("** \tkey:%s\n", item->key);
57   printf("** \tlength:%ld\n", item->length);
58 
59   if (item->length) {
60     vc = htable_first(&item->values, &iter);
61     while (vc) {
62       faup_snapshot_value_count_debug(vc);
63       vc = htable_next(&item->values, &iter);
64     }
65   }
66 }
67 
faup_snapshot_debug(faup_snapshot_t * snapshot)68 void faup_snapshot_debug(faup_snapshot_t *snapshot)
69 {
70   size_t counter;
71 
72   printf("** Snapshot debug:\n");
73   printf("** Name: %s\n", snapshot->name);
74   printf("** items length: %ld\n", snapshot->length);
75   for (counter = 0; counter < snapshot->length; counter++) {
76     faup_snapshot_item_debug(snapshot->items[counter]);
77   }
78 }
79 
compare_items(const void * p1,const void * p2)80 static int compare_items(const void *p1, const void *p2)
81 {
82   faup_snapshot_item_t ** item1 = (faup_snapshot_item_t **)p1;
83   faup_snapshot_item_t ** item2 = (faup_snapshot_item_t **)p2;
84 
85   printf("compare %s with %s\n", (*item1)->key, (*item2)->key);
86 
87   return strcmp((*item1)->key, (*item2)->key);
88 }
89 
compare_search(const void * key,const void * member)90 static int compare_search(const void *key, const void *member)
91 {
92   faup_snapshot_item_t *k = (faup_snapshot_item_t *)key;
93   faup_snapshot_item_t *m = (faup_snapshot_item_t *)member;
94 
95 
96   return strcmp(k->key, m->key);
97 }
98 
compare_simple(const void * p1,const void * p2)99 static int compare_simple(const void *p1, const void *p2)
100 {
101   const faup_snapshot_item_t *item1 = (faup_snapshot_item_t *)p1;
102   const faup_snapshot_item_t *item2 = (faup_snapshot_item_t *)p2;
103 
104   return strcmp(item1->key, item2->key);
105 }
106 
107 
faup_snapshot_value_count_new(void)108 faup_snapshot_value_count_t *faup_snapshot_value_count_new(void)
109 {
110   faup_snapshot_value_count_t *vc;
111 
112   vc = malloc(sizeof(faup_snapshot_value_count_t));
113 
114   vc->value = NULL;
115   vc->first_time_seen = 0;
116   vc->last_time_seen = 0;
117   vc->count = 0;
118 
119   return vc;
120 }
121 
faup_snapshot_value_count_copy(faup_snapshot_value_count_t * vc)122 faup_snapshot_value_count_t *faup_snapshot_value_count_copy(faup_snapshot_value_count_t *vc)
123 {
124   faup_snapshot_value_count_t *copy;
125 
126   copy = faup_snapshot_value_count_new();
127   if (!copy) {
128     fprintf(stderr, "%s: could not copy object!\n", __FUNCTION__);
129     return NULL;
130   }
131   copy->value = strdup(vc->value);
132   copy->first_time_seen = vc->first_time_seen;
133   copy->last_time_seen = vc->last_time_seen;
134   copy->count = vc->count;
135 
136   return copy;
137 }
138 
faup_snapshot_value_count_free(faup_snapshot_value_count_t * vc)139 void faup_snapshot_value_count_free(faup_snapshot_value_count_t *vc)
140 {
141   free(vc->value);
142   free(vc);
143 }
144 
faup_snapshot_item_new(char * key)145 faup_snapshot_item_t *faup_snapshot_item_new(char *key)
146 {
147   faup_snapshot_item_t *item;
148 
149   item = malloc(sizeof(faup_snapshot_item_t));
150   if (!item) {
151     fprintf(stderr, "Cannot allocatate a snapshot_item item!\n");
152     return NULL;
153   }
154 
155   item->length = 0;
156   item->key = strdup(key);
157   htable_init(&item->values, rehash, NULL);
158 
159   return item;
160 
161 }
162 
faup_snapshot_item_copy(faup_snapshot_item_t * item)163 faup_snapshot_item_t *faup_snapshot_item_copy(faup_snapshot_item_t *item)
164 {
165   faup_snapshot_item_t *copy;
166   size_t counter;
167   struct htable_iter iter;
168   /* faup_snapshot_value_count_t *vc; */
169   /* faup_snapshot_value_count_t *vc_copy; */
170 
171   copy = faup_snapshot_item_new(item->key);
172   memcpy(&copy->values, &item->values, sizeof(item->values));
173   /* vc = htable_first(&copy->values, &iter); */
174   /* while (vc) { */
175   /* /\*   vc_copy = faup_snapshot_value_count_copy(vc); *\/ */
176   /* /\*   faup_snapshot_value_count_append_object(item, vc_copy); *\/ */
177   /*   printf("vc->value:%s\n", vc->value); */
178 
179   /*   vc = htable_next(&copy->values, &iter); */
180   /* } */
181   copy->length = item->length;
182 
183   return copy;
184 }
185 
faup_snapshot_value_count_get(faup_snapshot_item_t * item,char * value)186 faup_snapshot_value_count_t *faup_snapshot_value_count_get(faup_snapshot_item_t *item, char *value)
187 {
188   size_t counter;
189 
190   if (!item) {
191     fprintf(stderr, "Item is empty!\n");
192     return NULL;
193   }
194 
195   return (faup_snapshot_value_count_t *)htable_get(&item->values, hash_string(value), streq, value);
196 }
197 
faup_snapshot_value_count_set_value(faup_snapshot_value_count_t * vc,char * value)198 int faup_snapshot_value_count_set_value(faup_snapshot_value_count_t *vc, char *value)
199 {
200   vc->value = strdup(value);
201 }
202 
faup_snapshot_value_count_set_first_time_seen(faup_snapshot_value_count_t * vc,time_t first_time_seen)203 int faup_snapshot_value_count_set_first_time_seen(faup_snapshot_value_count_t *vc, time_t first_time_seen)
204 {
205   vc->first_time_seen = first_time_seen;
206 }
207 
faup_snapshot_value_count_set_last_time_seen(faup_snapshot_value_count_t * vc,time_t last_time_seen)208 int faup_snapshot_value_count_set_last_time_seen(faup_snapshot_value_count_t *vc, time_t last_time_seen)
209 {
210   vc->last_time_seen = last_time_seen;
211 }
212 
faup_snapshot_value_count_set_count(faup_snapshot_value_count_t * vc,size_t count)213 int faup_snapshot_value_count_set_count(faup_snapshot_value_count_t *vc, size_t count)
214 {
215   vc->count = count;
216 }
217 
faup_snapshot_value_count_append(faup_snapshot_item_t * item,char * value)218 int faup_snapshot_value_count_append(faup_snapshot_item_t *item, char *value)
219 {
220   faup_snapshot_value_count_t *vc;
221 
222   if (!item) {
223     fprintf(stderr, "Cannot append value '%s' to item\n", value);
224     return -1;
225   }
226 
227   /* printf("Adding value '%s' to the item '%s'\n", item->key, value); */
228 
229   vc = faup_snapshot_value_count_get(item, value);
230   if (!vc) {
231     vc = faup_snapshot_value_count_new();
232     vc->value = strdup(value);
233     vc->first_time_seen = vc->last_time_seen = time(NULL);
234     vc->count++;
235 
236     htable_add(&item->values, hash_string(vc->value), vc);
237 
238     item->length++;
239   } else {
240     vc->count++;
241     vc->last_time_seen = time(NULL);
242   }
243 
244   return 0;
245 }
246 
faup_snapshot_value_count_append_object(faup_snapshot_item_t * item,faup_snapshot_value_count_t * vc)247 int faup_snapshot_value_count_append_object(faup_snapshot_item_t *item, faup_snapshot_value_count_t *vc)
248 {
249   htable_add(&item->values, hash_string(vc->value), vc);
250 
251   item->length++;
252 }
253 
faup_snapshot_item_free(faup_snapshot_item_t * item)254 void faup_snapshot_item_free(faup_snapshot_item_t *item)
255 {
256   struct htable_iter iter;
257   faup_snapshot_value_count_t *vc;
258 
259   vc = htable_first(&item->values, &iter);
260   while (vc) {
261     htable_del(&item->values, hash_string(vc->value), vc);
262     faup_snapshot_value_count_free(vc);
263 
264     vc = htable_next(&item->values, &iter);
265   }
266 
267   htable_clear(&item->values);
268 
269   free(item->key);
270   free(item);
271 }
272 
faup_snapshot_item_get(faup_snapshot_t * snapshot,char * item_name)273 faup_snapshot_item_t *faup_snapshot_item_get(faup_snapshot_t *snapshot, char *item_name)
274 {
275   faup_snapshot_item_t *res, key;
276   size_t counter;
277 
278   if (!snapshot) {
279     fprintf(stderr, "Snapshot is NULL!\n");
280     return NULL;
281   }
282 
283   for (counter = 0; counter < snapshot->length; counter++) {
284     if (!strcmp(snapshot->items[counter]->key, item_name)) {
285       return snapshot->items[counter];
286     }
287   }
288 
289   return NULL;
290 }
291 
faup_snapshot_item_append(faup_snapshot_t * snapshot,char * item_name)292 int faup_snapshot_item_append(faup_snapshot_t *snapshot, char *item_name)
293 {
294   faup_snapshot_item_t *item;
295   void *arg;
296 
297   item = faup_snapshot_item_get(snapshot, item_name);
298   if (!item) {
299     snapshot->items = realloc(snapshot->items, sizeof(faup_snapshot_item_t *) * (snapshot->length + 1));
300     if (!snapshot->items) {
301       fprintf(stderr, "Cannot allocatate a snapshot_item!\n");
302       return -1;
303     }
304     snapshot->items[snapshot->length] = faup_snapshot_item_new(item_name);
305     snapshot->length++;
306 
307     qsort(snapshot->items, snapshot->length, sizeof(faup_snapshot_item_t *), compare_simple);
308 
309   }
310 
311   return 0;
312 }
313 
faup_snapshot_free(faup_snapshot_t * snapshot)314 void faup_snapshot_free(faup_snapshot_t *snapshot)
315 {
316   size_t counter;
317   if (!snapshot) {
318     return;
319   }
320 
321   free(snapshot->name);
322   for (counter = 0; counter < snapshot->length; counter++) {
323     faup_snapshot_item_free(snapshot->items[counter]);
324   }
325   free(snapshot->items);
326 
327   free(snapshot);
328 }
329 
faup_snapshot_open(char * name)330 faup_snapshot_t  *faup_snapshot_open(char *name)
331 {
332   faup_snapshot_t *snapshot;
333   int retval;
334 
335   snapshot = faup_snapshot_new();
336   snapshot->name = strdup(name);
337 
338   return snapshot;
339 }
340 
341 
faup_snapshot_close(faup_snapshot_t * snapshot)342 void faup_snapshot_close(faup_snapshot_t *snapshot)
343 {
344   faup_snapshot_free(snapshot);
345 }
346 
faup_snapshot_append(faup_snapshot_t * snapshot,char * key,char * value)347 int faup_snapshot_append(faup_snapshot_t *snapshot, char *key, char *value)
348 {
349   faup_snapshot_item_t *item;
350 
351   faup_snapshot_item_append(snapshot, key);
352   item = faup_snapshot_item_get(snapshot, key);
353   if (item) {
354     faup_snapshot_value_count_append(item, value);
355   } else {
356     fprintf(stderr, "Item does not exists. Cannot append value!\n");
357   }
358 
359   return 0;
360 }
361 
362 // FIXME: Remove this useless function
faup_snapshot_append_item(faup_snapshot_t * snapshot,char * item_name,faup_snapshot_item_t * item)363 int faup_snapshot_append_item(faup_snapshot_t *snapshot, char *item_name, faup_snapshot_item_t *item)
364 {
365   if (!snapshot) {
366     fprintf(stderr, "Cannot append item to an unexisting snapshot!\n");
367     return -1;
368   }
369 
370   snapshot->items = realloc(snapshot->items, sizeof(faup_snapshot_item_t *) * (snapshot->length + 1));
371   if (!snapshot->items) {
372     fprintf(stderr, "Cannot allocatate a snapshot_item!\n");
373     return -1;
374   }
375 
376   snapshot->items[snapshot->length] = faup_snapshot_item_copy(item);
377 
378   snapshot->length++;
379 
380   return 0;
381 
382 }
383 
faup_snapshot_output(faup_handler_t * fh,faup_snapshot_t * snapshot,FILE * fd)384 void faup_snapshot_output(faup_handler_t *fh, faup_snapshot_t *snapshot, FILE *fd)
385 {
386   size_t counter;
387   size_t values_count;
388   faup_snapshot_value_count_t *vc;
389   struct htable_iter iter;
390   char first_timebuf[200];
391   char last_timebuf[200];
392 
393   if (!snapshot) {
394     fprintf(stderr, "Error reading snapshot. Stopping.\n");
395     return;
396   }
397 
398   fprintf(fd, "{\n");
399   fprintf(fd,"\t\"snapshot name\": \"%s\",\n", snapshot->name);
400   if (!snapshot->length) {
401     fprintf(fd,"\t\"snapshot length\": %ld\n", snapshot->length);
402   } else {
403     fprintf(fd,"\t\"snapshot length\": %ld,\n", snapshot->length);
404     fprintf(fd,"\t\"items\":[");
405   for (counter = 0; counter < snapshot->length; counter++) {
406     faup_snapshot_item_t *item = snapshot->items[counter];
407     fprintf(fd,"\t\t{\n");
408     fprintf(fd,"\t\t\"key\": \"%s\",\n", item->key);
409     fprintf(fd,"\t\t\"length\": %ld,\n", item->length);
410     fprintf(fd,"\t\t\"values\": [\n");
411 
412     if (item->length) {
413       values_count = 1;
414       vc = htable_first(&item->values, &iter);
415       while (vc) {
416 	strftime(first_timebuf, sizeof(first_timebuf), "%Y-%m-%d %H:%M:%S %z", localtime(&vc->first_time_seen));
417 	strftime(last_timebuf, sizeof(last_timebuf), "%Y-%m-%d %H:%M:%S %z", localtime(&vc->last_time_seen));
418 	fprintf(fd,"\t\t\t{\"value\": \"%s\", \"count\": %ld, \"first seen\": \"%s\", \"last seen\": \"%s\"}", vc->value, vc->count, first_timebuf, last_timebuf);
419 
420 	if (values_count == item->length) {
421 	  fprintf(fd,"\n");
422 	} else {
423 	  fprintf(fd,",\n");
424 	}
425 
426 	values_count++;
427 	vc = htable_next(&item->values, &iter);
428       }
429     }
430     fprintf(fd,"\t\t]\n\t}");
431     if (counter == snapshot->length - 1) {
432       fprintf(fd,"\n");
433       fprintf(fd, "\t]\n");
434     } else {
435       fprintf(fd,",\n");
436     }
437   }
438   }
439   fprintf(fd, "\n}\n");
440 }
441