diff options
| -rw-r--r-- | README.md | 1 | ||||
| -rw-r--r-- | httpd.c | 2 | ||||
| -rw-r--r-- | xs.h | 77 | ||||
| -rw-r--r-- | xs_set.h | 27 | ||||
| -rw-r--r-- | xs_unicode.h | 4 | ||||
| -rw-r--r-- | xs_version.h | 2 |
6 files changed, 93 insertions, 20 deletions
| @@ -111,6 +111,7 @@ This will: | |||
| 111 | - [How to run your own social network with snac (by Giacomo Tesio)](https://encrypted.tesio.it/2024/12/18/how-to-run-your-own-social-network.html). Includes information on how to run snac as a CGI. | 111 | - [How to run your own social network with snac (by Giacomo Tesio)](https://encrypted.tesio.it/2024/12/18/how-to-run-your-own-social-network.html). Includes information on how to run snac as a CGI. |
| 112 | - [Improving snac Performance with Nginx Proxy Cache (by Stefano Marinelli)](https://it-notes.dragas.net/2025/01/29/improving-snac-performance-with-nginx-proxy-cache/). | 112 | - [Improving snac Performance with Nginx Proxy Cache (by Stefano Marinelli)](https://it-notes.dragas.net/2025/01/29/improving-snac-performance-with-nginx-proxy-cache/). |
| 113 | - [Caching Snac Proxied Media With Nginx (by Stefano Marinelli)](https://it-notes.dragas.net/2025/02/08/caching-snac-proxied-media-with-nginx/). | 113 | - [Caching Snac Proxied Media With Nginx (by Stefano Marinelli)](https://it-notes.dragas.net/2025/02/08/caching-snac-proxied-media-with-nginx/). |
| 114 | - [My snac config (activitypub instance) with Caddy (by ffuentes)](https://ffuentes.sdf.org/communication/2025/08/23/my-snac-config-activitypub-instance-with-caddy.html). | ||
| 114 | - [A bit of lore about Susie, snac's default avatar](https://comam.es/snac/grunfink/p/1754553922.333170). | 115 | - [A bit of lore about Susie, snac's default avatar](https://comam.es/snac/grunfink/p/1754553922.333170). |
| 115 | 116 | ||
| 116 | ## Incredibly awesome CSS themes for snac | 117 | ## Incredibly awesome CSS themes for snac |
| @@ -226,7 +226,7 @@ int server_get_handler(xs_dict *req, const char *q_path, | |||
| 226 | const xs_dict *q_vars = xs_dict_get(req, "q_vars"); | 226 | const xs_dict *q_vars = xs_dict_get(req, "q_vars"); |
| 227 | const char *t = NULL; | 227 | const char *t = NULL; |
| 228 | 228 | ||
| 229 | if (xs_type(q_vars) == XSTYPE_DICT && (t = xs_dict_get(q_vars, "t"))) { | 229 | if (xs_type(q_vars) == XSTYPE_DICT && xs_is_string(t = xs_dict_get(q_vars, "t"))) { |
| 230 | /** search by tag **/ | 230 | /** search by tag **/ |
| 231 | int skip = 0; | 231 | int skip = 0; |
| 232 | int show = xs_number_get(xs_dict_get_def(srv_config, "def_timeline_entries", | 232 | int show = xs_number_get(xs_dict_get_def(srv_config, "def_timeline_entries", |
| @@ -134,7 +134,9 @@ xs_dict *xs_dict_set_path_sep(xs_dict *dict, const char *path, const xs_val *val | |||
| 134 | 134 | ||
| 135 | xs_val *xs_val_new(xstype t); | 135 | xs_val *xs_val_new(xstype t); |
| 136 | xs_number *xs_number_new(double f); | 136 | xs_number *xs_number_new(double f); |
| 137 | xs_number *xs_number_new_l(long l); | ||
| 137 | double xs_number_get(const xs_number *v); | 138 | double xs_number_get(const xs_number *v); |
| 139 | long xs_number_get_l(const xs_number *v); | ||
| 138 | const char *xs_number_str(const xs_number *v); | 140 | const char *xs_number_str(const xs_number *v); |
| 139 | 141 | ||
| 140 | xs_data *xs_data_new(const void *data, int size); | 142 | xs_data *xs_data_new(const void *data, int size); |
| @@ -163,6 +165,7 @@ uint64_t xs_hash64_func(const char *data, int size); | |||
| 163 | #define xs_is_string(v) (xs_type((v)) == XSTYPE_STRING) | 165 | #define xs_is_string(v) (xs_type((v)) == XSTYPE_STRING) |
| 164 | #define xs_is_list(v) (xs_type((v)) == XSTYPE_LIST) | 166 | #define xs_is_list(v) (xs_type((v)) == XSTYPE_LIST) |
| 165 | #define xs_is_dict(v) (xs_type((v)) == XSTYPE_DICT) | 167 | #define xs_is_dict(v) (xs_type((v)) == XSTYPE_DICT) |
| 168 | #define xs_is_number(v) (xs_type((v)) == XSTYPE_NUMBER) | ||
| 166 | 169 | ||
| 167 | #define xs_list_foreach(l, v) for (int ct_##__LINE__ = 0; xs_list_next(l, &v, &ct_##__LINE__); ) | 170 | #define xs_list_foreach(l, v) for (int ct_##__LINE__ = 0; xs_list_next(l, &v, &ct_##__LINE__); ) |
| 168 | #define xs_dict_foreach(l, k, v) for (int ct_##__LINE__ = 0; xs_dict_next(l, &k, &v, &ct_##__LINE__); ) | 171 | #define xs_dict_foreach(l, k, v) for (int ct_##__LINE__ = 0; xs_dict_next(l, &k, &v, &ct_##__LINE__); ) |
| @@ -362,9 +365,22 @@ int xs_is_null(const xs_val *data) | |||
| 362 | int xs_cmp(const xs_val *v1, const xs_val *v2) | 365 | int xs_cmp(const xs_val *v1, const xs_val *v2) |
| 363 | /* compares two values */ | 366 | /* compares two values */ |
| 364 | { | 367 | { |
| 365 | if (xs_type(v1) == XSTYPE_STRING && xs_type(v2) == XSTYPE_STRING) | 368 | xstype t1 = xs_type(v1); |
| 369 | xstype t2 = xs_type(v2); | ||
| 370 | |||
| 371 | if (t1 == XSTYPE_NULL || t2 == XSTYPE_NULL) | ||
| 372 | return 0; | ||
| 373 | |||
| 374 | if (t1 == XSTYPE_STRING && t2 == XSTYPE_STRING) | ||
| 366 | return strcmp(v1, v2); | 375 | return strcmp(v1, v2); |
| 367 | 376 | ||
| 377 | if (t1 == XSTYPE_NUMBER && t2 == XSTYPE_NUMBER) { | ||
| 378 | double d1 = xs_number_get(v1); | ||
| 379 | double d2 = xs_number_get(v2); | ||
| 380 | |||
| 381 | return d1 == d2 ? 0 : d1 < d2 ? -1 : 1; | ||
| 382 | } | ||
| 383 | |||
| 368 | int s1 = xs_size(v1); | 384 | int s1 = xs_size(v1); |
| 369 | int s2 = xs_size(v2); | 385 | int s2 = xs_size(v2); |
| 370 | int d = s1 - s2; | 386 | int d = s1 - s2; |
| @@ -975,6 +991,9 @@ xs_str *xs_join(const xs_list *list, const char *sep) | |||
| 975 | 991 | ||
| 976 | xs_list_foreach(list, v) { | 992 | xs_list_foreach(list, v) { |
| 977 | /* refuse to join non-string values */ | 993 | /* refuse to join non-string values */ |
| 994 | if (xs_type(v) == XSTYPE_NUMBER) | ||
| 995 | v = xs_number_str(v); | ||
| 996 | |||
| 978 | if (xs_type(v) == XSTYPE_STRING) { | 997 | if (xs_type(v) == XSTYPE_STRING) { |
| 979 | int sz; | 998 | int sz; |
| 980 | 999 | ||
| @@ -1396,10 +1415,20 @@ xs_val *xs_val_new(xstype t) | |||
| 1396 | 1415 | ||
| 1397 | /** numbers */ | 1416 | /** numbers */ |
| 1398 | 1417 | ||
| 1418 | xs_number *_xs_number_new(const char *str) | ||
| 1419 | { | ||
| 1420 | xs_number *v = xs_realloc(NULL, 1 + xs_size(str)); | ||
| 1421 | |||
| 1422 | v[0] = XSTYPE_NUMBER; | ||
| 1423 | memcpy(&v[1], str, xs_size(str)); | ||
| 1424 | |||
| 1425 | return v; | ||
| 1426 | } | ||
| 1427 | |||
| 1428 | |||
| 1399 | xs_number *xs_number_new(double f) | 1429 | xs_number *xs_number_new(double f) |
| 1400 | /* adds a new number value */ | 1430 | /* creates a new number value from a double */ |
| 1401 | { | 1431 | { |
| 1402 | xs_number *v; | ||
| 1403 | char tmp[64]; | 1432 | char tmp[64]; |
| 1404 | 1433 | ||
| 1405 | snprintf(tmp, sizeof(tmp), "%.15lf", f); | 1434 | snprintf(tmp, sizeof(tmp), "%.15lf", f); |
| @@ -1416,40 +1445,54 @@ xs_number *xs_number_new(double f) | |||
| 1416 | *ptr = '\0'; | 1445 | *ptr = '\0'; |
| 1417 | } | 1446 | } |
| 1418 | 1447 | ||
| 1419 | /* alloc for the marker and the full string */ | 1448 | return _xs_number_new(tmp); |
| 1420 | v = xs_realloc(NULL, _xs_blk_size(1 + xs_size(tmp))); | 1449 | } |
| 1421 | 1450 | ||
| 1422 | v[0] = XSTYPE_NUMBER; | ||
| 1423 | memcpy(&v[1], tmp, xs_size(tmp)); | ||
| 1424 | 1451 | ||
| 1425 | return v; | 1452 | xs_number *xs_number_new_l(long l) |
| 1453 | /* creates a new number value from a long */ | ||
| 1454 | { | ||
| 1455 | char tmp[64]; | ||
| 1456 | |||
| 1457 | snprintf(tmp, sizeof(tmp), "%ld", l); | ||
| 1458 | |||
| 1459 | return _xs_number_new(tmp); | ||
| 1426 | } | 1460 | } |
| 1427 | 1461 | ||
| 1428 | 1462 | ||
| 1429 | double xs_number_get(const xs_number *v) | 1463 | double xs_number_get(const xs_number *v) |
| 1430 | /* gets the number as a double */ | 1464 | /* gets the number as a double */ |
| 1431 | { | 1465 | { |
| 1432 | double f = 0.0; | 1466 | if (xs_type(v) == XSTYPE_NUMBER) |
| 1467 | v++; | ||
| 1468 | |||
| 1469 | if (xs_type(v) == XSTYPE_STRING) | ||
| 1470 | return atof(v); | ||
| 1433 | 1471 | ||
| 1472 | return 0.0; | ||
| 1473 | } | ||
| 1474 | |||
| 1475 | |||
| 1476 | long xs_number_get_l(const xs_number *v) | ||
| 1477 | /* gets the number as a long */ | ||
| 1478 | { | ||
| 1434 | if (xs_type(v) == XSTYPE_NUMBER) | 1479 | if (xs_type(v) == XSTYPE_NUMBER) |
| 1435 | f = atof(&v[1]); | 1480 | v++; |
| 1436 | else | 1481 | |
| 1437 | if (xs_type(v) == XSTYPE_STRING) | 1482 | if (xs_type(v) == XSTYPE_STRING) |
| 1438 | f = atof(v); | 1483 | return atol(v); |
| 1439 | 1484 | ||
| 1440 | return f; | 1485 | return 0; |
| 1441 | } | 1486 | } |
| 1442 | 1487 | ||
| 1443 | 1488 | ||
| 1444 | const char *xs_number_str(const xs_number *v) | 1489 | const char *xs_number_str(const xs_number *v) |
| 1445 | /* gets the number as a string */ | 1490 | /* gets the number as a string */ |
| 1446 | { | 1491 | { |
| 1447 | const char *p = NULL; | ||
| 1448 | |||
| 1449 | if (xs_type(v) == XSTYPE_NUMBER) | 1492 | if (xs_type(v) == XSTYPE_NUMBER) |
| 1450 | p = &v[1]; | 1493 | return v + 1; |
| 1451 | 1494 | ||
| 1452 | return p; | 1495 | return NULL; |
| 1453 | } | 1496 | } |
| 1454 | 1497 | ||
| 1455 | 1498 | ||
| @@ -14,6 +14,7 @@ typedef struct _xs_set { | |||
| 14 | void xs_set_init(xs_set *s); | 14 | void xs_set_init(xs_set *s); |
| 15 | xs_list *xs_set_result(xs_set *s); | 15 | xs_list *xs_set_result(xs_set *s); |
| 16 | void xs_set_free(xs_set *s); | 16 | void xs_set_free(xs_set *s); |
| 17 | int xs_set_in(const xs_set *s, const xs_val *data); | ||
| 17 | int xs_set_add(xs_set *s, const xs_val *data); | 18 | int xs_set_add(xs_set *s, const xs_val *data); |
| 18 | 19 | ||
| 19 | 20 | ||
| @@ -60,7 +61,7 @@ static int _store_hash(xs_set *s, const char *data, int value) | |||
| 60 | 61 | ||
| 61 | while (s->hash[(i = hash % s->elems)]) { | 62 | while (s->hash[(i = hash % s->elems)]) { |
| 62 | /* get the pointer to the stored data */ | 63 | /* get the pointer to the stored data */ |
| 63 | char *p = &s->list[s->hash[i]]; | 64 | const char *p = &s->list[s->hash[i]]; |
| 64 | 65 | ||
| 65 | /* already here? */ | 66 | /* already here? */ |
| 66 | if (memcmp(p, data, sz) == 0) | 67 | if (memcmp(p, data, sz) == 0) |
| @@ -79,6 +80,30 @@ static int _store_hash(xs_set *s, const char *data, int value) | |||
| 79 | } | 80 | } |
| 80 | 81 | ||
| 81 | 82 | ||
| 83 | int xs_set_in(const xs_set *s, const xs_val *data) | ||
| 84 | /* returns 1 if the data is already in the set */ | ||
| 85 | { | ||
| 86 | unsigned int hash, i; | ||
| 87 | int sz = xs_size(data); | ||
| 88 | |||
| 89 | hash = xs_hash_func(data, sz); | ||
| 90 | |||
| 91 | while (s->hash[(i = hash % s->elems)]) { | ||
| 92 | /* get the pointer to the stored data */ | ||
| 93 | const char *p = &s->list[s->hash[i]]; | ||
| 94 | |||
| 95 | /* already here? */ | ||
| 96 | if (memcmp(p, data, sz) == 0) | ||
| 97 | return 1; | ||
| 98 | |||
| 99 | /* try next value */ | ||
| 100 | hash++; | ||
| 101 | } | ||
| 102 | |||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | |||
| 82 | int xs_set_add(xs_set *s, const xs_val *data) | 107 | int xs_set_add(xs_set *s, const xs_val *data) |
| 83 | /* adds the data to the set */ | 108 | /* adds the data to the set */ |
| 84 | /* returns: 1 if added, 0 if already there */ | 109 | /* returns: 1 if added, 0 if already there */ |
diff --git a/xs_unicode.h b/xs_unicode.h index ef18fea..67b3827 100644 --- a/xs_unicode.h +++ b/xs_unicode.h | |||
| @@ -79,6 +79,10 @@ unsigned int xs_utf8_dec(const char **str) | |||
| 79 | /* decodes an utf-8 char inside str and updates the pointer */ | 79 | /* decodes an utf-8 char inside str and updates the pointer */ |
| 80 | { | 80 | { |
| 81 | const char *p = *str; | 81 | const char *p = *str; |
| 82 | |||
| 83 | if (!xs_is_string(p)) | ||
| 84 | return 0; | ||
| 85 | |||
| 82 | unsigned int cpoint = 0; | 86 | unsigned int cpoint = 0; |
| 83 | unsigned char c = *p++; | 87 | unsigned char c = *p++; |
| 84 | int cb = 0; | 88 | int cb = 0; |
diff --git a/xs_version.h b/xs_version.h index 466535b..cd52531 100644 --- a/xs_version.h +++ b/xs_version.h | |||
| @@ -1 +1 @@ | |||
| /* 401d229ffbec89b4a5cf97793926b7afb84a4f26 2025-07-08T15:44:54+02:00 */ | /* ad90abcefd455c0ba0faf155dc2976490dbde0b0 2025-08-23T20:36:11+02:00 */ | ||