koliseo 0.4.8
Loading...
Searching...
No Matches
kls_gulp.h
Go to the documentation of this file.
1// jgabaut @ github.com/jgabaut
2// SPDX-License-Identifier: GPL-3.0-only
3/*
4 Copyright (C) 2023-2024 jgabaut
5
6 This program is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, version 3 of the License.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <https://www.gnu.org/licenses/>.
17*/
18
19#ifndef KLS_GULP_H_
20#define KLS_GULP_H_
21#ifndef KOLISEO_H_
22#include "koliseo.h"
23#endif // KOLISEO_H_
24
25#include "ctype.h" // Needed for isspace()...
26
27typedef struct Kstr {
28 const char* data;
29 size_t len;
31
32Kstr kstr_new(const char* str, size_t len);
33Kstr kstr_from_c_lit(const char* c_lit);
34bool kstr_eq(Kstr left, Kstr right);
35bool kstr_eq_ignorecase(Kstr left, Kstr right);
36Kstr kstr_cut_l(Kstr *k, size_t n);
37Kstr kstr_cut_r(Kstr *k, size_t n);
40Kstr kstr_trim(Kstr kstr);
41bool kstr_indexof(Kstr k, char c, int* idx);
42Kstr kstr_token(Kstr* k, char delim);
43bool kstr_try_token(Kstr* k, char delim, Kstr* part);
44Kstr kstr_token_kstr(Kstr* k, Kstr delim);
45
46#define KSTR(c_lit) kstr_new(c_lit, sizeof(c_lit) - 1)
47#define KSTR_NULL kstr_new(NULL, 0)
48
52#define Kstr_Fmt "%.*s"
56#define Kstr_Arg(kstr) (int) (kstr.len), (kstr.data)
57
65#define ONEGB_DEC_INT 1073741824
66
71#define GULP_MAX_FILE_SIZE ONEGB_DEC_INT
72
86
90#define Gulp_Res_Fmt "%s"
94#define Gulp_Res_Arg(gr) (string_from_Gulp_Res((gr)))
95
100extern const char* gulp_res_names[TOT_GULP_RES+1];
101const char* string_from_Gulp_Res(Gulp_Res g);
102
103//static char * kls_read_file(Koliseo* kls, const char * f_name, Gulp_Res * err, size_t * f_size, ...);
104char * kls_gulp_file_sized(Koliseo* kls, const char * filepath, Gulp_Res * err, size_t max_size);
105char * try_kls_gulp_file(Koliseo* kls, const char * filepath, size_t max_size);
106#define KLS_GULP_FILE(kls, filepath) try_kls_gulp_file((kls),(filepath), GULP_MAX_FILE_SIZE)
107//Kstr * kls_read_file_to_kstr(Koliseo* kls, const char * f_name, Gulp_Res * err, size_t * f_size, ...);
108Kstr * kls_gulp_file_sized_to_kstr(Koliseo* kls, const char * filepath, Gulp_Res * err, size_t max_size, bool allow_nullchar);
109Kstr * try_kls_gulp_file_to_kstr(Koliseo* kls, const char * filepath, size_t max_size, bool allow_nullchar);
110#define KLS_GULP_FILE_KSTR(kls, filepath) try_kls_gulp_file_to_kstr((kls),(filepath), GULP_MAX_FILE_SIZE, false)
111
112#endif // KLS_GULP_H_
113
114#ifdef KLS_GULP_IMPLEMENTATION
115
120const char* gulp_res_names[TOT_GULP_RES+1] = {
121 [GULP_FILE_OK] = "Success",
122 [GULP_FILE_NOT_EXIST] = "File does not exist",
123 [GULP_FILE_TOO_LARGE] = "File is too large",
124 [GULP_FILE_READ_ERROR] = "File could not be read",
125 [GULP_FILE_CONTAINS_NULLCHAR] = "File contains nullchar",
126 [GULP_FILE_KLS_NULL] = "Koliseo was NULL",
127 [TOT_GULP_RES] = "Total of Gulp_Res values",
128};
129
137const char* string_from_Gulp_Res(Gulp_Res g)
138{
139 assert(g >= 0 && g < TOT_GULP_RES && "Unexpected Gulp_Res value");
140 return gulp_res_names[g];
141}
142
150Kstr kstr_new(const char* data, size_t len)
151{
152 return (Kstr) {
153 .data = data,
154 .len = len,
155 };
156}
157
164Kstr kstr_from_c_lit(const char* c_lit)
165{
166 return kstr_new(c_lit, strlen(c_lit));
167}
168
176bool kstr_eq(Kstr left, Kstr right)
177{
178 if (left.len != right.len) {
179 return false;
180 }
181
182 for (size_t i=0; i < left.len; i++) {
183 if (left.data[i] != right.data[i]) return false;
184 }
185 return true;
186}
187
195bool kstr_eq_ignorecase(Kstr left, Kstr right)
196{
197 if (left.len != right.len) {
198 return false;
199 }
200
201 char l, r;
202 for (size_t i=0; i < left.len; i++) {
203 l = 'A' <= left.data[i] && 'Z' >= left.data[i]
204 ? left.data[i] + 32
205 : left.data[i];
206 r = 'A' <= right.data[i] && 'Z' >= right.data[i]
207 ? right.data[i] + 32
208 : right.data[i];
209 if (l != r) return false;
210 }
211 return true;
212}
213
221Kstr kstr_cut_l(Kstr *k, size_t n)
222{
223 if (n > k->len) {
224 n = k->len;
225 }
226 Kstr res = kstr_new(k->data, n);
227 k->data += n;
228 k->len -= n;
229
230 return res;
231}
232
240Kstr kstr_cut_r(Kstr *k, size_t n)
241{
242 if (n > k->len) {
243 n = k->len;
244 }
245 Kstr res = kstr_new(k->data + k->len - n, n);
246 k->len -= n;
247
248 return res;
249}
250
258{
259 size_t i = 0;
260 while ( i < kstr.len && isspace(kstr.data[i])) {
261 i++;
262 }
263 return kstr_new(kstr.data + i, kstr.len - i);
264}
265
273{
274 size_t i = 0;
275 while ( i < kstr.len && isspace(kstr.data[kstr.len - i - 1])) {
276 i++;
277 }
278 return kstr_new(kstr.data, kstr.len - i);
279}
280
289Kstr kstr_trim(Kstr kstr)
290{
291 return kstr_trim_left(kstr_trim_right(kstr));
292}
293
302bool kstr_indexof(Kstr k, char c, int* idx)
303{
304 if (k.len == 0) {
305 return false;
306 } else {
307 size_t i = 0;
308 while (i < k.len) {
309 if (k.data[i] == c) {
310 *idx = i;
311 return true;
312 }
313
314 i++;
315 }
316 return false;
317 }
318}
319
328bool kstr_try_token(Kstr *k, char delim, Kstr* part)
329{
330 size_t i = 0;
331 while (i < k->len && k->data[i] != delim) {
332 i++;
333 }
334
335 Kstr res = kstr_new(k->data,i);
336
337 if (i < k->len) {
338 k->len -= i +1;
339 k->data += i +1;
340 if (part) {
341 *part = res;
342 }
343 return true;
344 }
345
346 return false;
347}
348
356Kstr kstr_token(Kstr *k, char delim)
357{
358 size_t i = 0;
359 while (i < k->len && k->data[i] != delim) {
360 i++;
361 }
362
363 Kstr res = kstr_new(k->data,i);
364
365 if (i < k->len) {
366 k->len -= i +1;
367 k->data += i +1;
368 } else {
369 k->len -= i;
370 k->data += i;
371 }
372
373 return res;
374}
375
376Kstr kstr_token_kstr(Kstr* k, Kstr delim)
377{
378
379 //Kstr to scroll k data, sized as the delimiter
380 Kstr win = kstr_new(k->data, delim.len);
381
382 size_t i = 0;
383
384 //Loop checking if k data can still be scrolled and if current window is equal to the delimiter
385 while (i + delim.len < k->len &&
386 !(kstr_eq(win, delim))) {
387 i++;
388 win.data++;
389 }
390
391 //New Kstr just up to the delimiter position
392 Kstr res = kstr_new(k->data, i);
393
394 //If we don't cleanly empty k, we increase result len so that it holds the remaining chars
395 if (i + delim.len == k->len) {
396 res.len += delim.len;
397 }
398
399 //Advance k by the delimiter size, plus its starting position
400 k->data += i + delim.len;
401 k->len += i + delim.len;
402
403 return res;
404}
405
406static char * kls_read_file(Koliseo* kls, const char * f_name, Gulp_Res * err, size_t * f_size, ...)
407{
408 if (!kls) {
409 *err = GULP_FILE_KLS_NULL;
410 return NULL;
411 }
412 char * buffer;
413 size_t length = 0;
414 FILE * f = fopen(f_name, "rb");
415 size_t read_length;
416
417 if (f) {
418 fseek(f, 0, SEEK_END);
419 length = ftell(f);
420 fseek(f, 0, SEEK_SET);
421
422 va_list args;
423 va_start(args, f_size);
424 size_t max_size = va_arg(args, size_t);
425 if (length > max_size) {
426 *err = GULP_FILE_TOO_LARGE;
427
428 return NULL;
429 }
430 va_end(args);
431
432 buffer = KLS_PUSH_ARR_NAMED(kls,char,length + 1,"char*","Buffer for file gulp");
433
434 if (buffer == NULL) {
435 assert(0 && "KLS_PUSH_NAMED() failed\n");
436 }
437
438 if (length) {
439 read_length = fread(buffer, 1, length, f);
440
441 if (length != read_length) {
443 return NULL;
444 }
445 }
446
447 fclose(f);
448
449 *err = GULP_FILE_OK;
450 buffer[length] = '\0';
451 *f_size = length;
452 } else {
453 *err = GULP_FILE_NOT_EXIST;
454
455 return NULL;
456 }
457
458 if (strlen(buffer) == length) {
459 return buffer;
460 } else {
462 return buffer;
463 }
464}
465
475char * kls_gulp_file_sized(Koliseo* kls, const char * filepath, Gulp_Res * err, size_t max_size)
476{
477 static_assert(TOT_GULP_RES == 6, "Number of Gulp_Res changed");
478 size_t f_size;
479 char * data = NULL;
480 data = kls_read_file(kls, filepath, err, &f_size, max_size);
481 if (*err != GULP_FILE_OK) {
482 switch (*err) {
487 case GULP_FILE_KLS_NULL: {
488 fprintf(stderr,"[ERROR] %s(): {" Gulp_Res_Fmt "}.\n",__func__, Gulp_Res_Arg(*err));
489 }
490 break;
491 default: {
492 fprintf(stderr,"[ERROR] %s(): Unexpected error {%i}.\n",__func__, *err);
493 }
494 break;
495 }
496 if (*err != GULP_FILE_CONTAINS_NULLCHAR) return NULL;
497 } else {
498 assert(strlen(data) == f_size && "data len should be equal to f_size here!");
499 if (!data) {
500 assert(0 && "kls_read_file() failed\n");
501 }
502 //printf("%s\n\n",data);
503 //printf("SIZE: {%i}\n",f_size);
504 }
505 return data;
506}
507
516char * try_kls_gulp_file(Koliseo* kls, const char * filepath, size_t max_size)
517{
518 Gulp_Res err = -1;
519
520 char* res = kls_gulp_file_sized(kls, filepath, &err, max_size);
521
522 if (err != GULP_FILE_OK && err != GULP_FILE_CONTAINS_NULLCHAR) {
523 fprintf(stderr, "%s(): kls_gulp_file_sized() failed with err {%s}.\n",__func__,string_from_Gulp_Res(err));
524 }
525
526 return res;
527}
528
529static Kstr * kls_read_file_to_kstr(Koliseo* kls, const char * f_name, Gulp_Res * err, size_t * f_size, ...)
530{
531 if (!kls) {
532 *err = GULP_FILE_KLS_NULL;
533 return NULL;
534 }
535 char * buffer = NULL;
536 size_t length = 0;
537 FILE * f = fopen(f_name, "rb");
538 size_t read_length;
539 bool allow_nullchar = false;
540
541 if (f) {
542 fseek(f, 0, SEEK_END);
543 length = ftell(f);
544 fseek(f, 0, SEEK_SET);
545
546 va_list args;
547 va_start(args, f_size);
548 size_t max_size = va_arg(args, size_t);
549 if (length > max_size) {
550 *err = GULP_FILE_TOO_LARGE;
551
552 return NULL;
553 }
554 bool allow_nulls = va_arg(args, int);
555 allow_nullchar = allow_nulls;
556 va_end(args);
557
558 buffer = KLS_PUSH_ARR_NAMED(kls,char,length + 1,"char*","Buffer for file gulp");
559
560 if (buffer == NULL) {
561 assert(0 && "KLS_PUSH_NAMED() failed\n");
562 }
563
564 if (length) {
565 read_length = fread(buffer, 1, length, f);
566
567 if (length != read_length) {
569 return NULL;
570 }
571 }
572
573 fclose(f);
574
575 *err = GULP_FILE_OK;
576 buffer[length] = '\0';
577 *f_size = length;
578 } else {
579 *err = GULP_FILE_NOT_EXIST;
580
581 return NULL;
582 }
583
584 if (strlen(buffer) == length) {
585 } else {
587 if (!allow_nullchar) {
588 return NULL;
589 }
590 }
591 Kstr * res = KLS_PUSH_NAMED(kls,Kstr,"Kstr","Kstr for file gulp");
592 if (res == NULL) {
593 assert(0 && "KLS_PUSH_NAMED() failed\n");
594 }
595 res->data = buffer;
596 if (*err == GULP_FILE_CONTAINS_NULLCHAR) {
597 res->len = length;
598 } else {
599 res->len = strlen(buffer);
600 }
601 return res;
602}
603
615Kstr * kls_gulp_file_sized_to_kstr(Koliseo* kls, const char * filepath, Gulp_Res * err, size_t max_size, bool allow_nullchar)
616{
617 static_assert(TOT_GULP_RES == 6, "Number of Gulp_Res changed");
618 size_t f_size;
619 Kstr * data = NULL;
620 data = kls_read_file_to_kstr(kls, filepath, err, &f_size, max_size, allow_nullchar);
621 if (*err != GULP_FILE_OK) {
622 switch (*err) {
627 case GULP_FILE_KLS_NULL: {
628 fprintf(stderr,"[ERROR] %s(): {" Gulp_Res_Fmt "}.\n",__func__, Gulp_Res_Arg(*err));
629 }
630 break;
631 default: {
632 fprintf(stderr,"[ERROR] %s(): Unexpected error {%i}.\n",__func__, *err);
633 }
634 break;
635 }
636 return data;
637 } else {
638 assert(data->len == f_size && "data len should be equal to f_size here!");
639 if (!data) {
640 assert(0 && "kls_read_file_to_kstr() failed\n");
641 }
642 //printf("%s\n\n",data->data);
643 //printf("SIZE: {%i}\n",f_size);
644 }
645 return data;
646}
647
657Kstr * try_kls_gulp_file_to_kstr(Koliseo* kls, const char * filepath, size_t max_size, bool allow_nullchar)
658{
659 Gulp_Res err = -1;
660
661 Kstr * res = NULL;
662 res = kls_gulp_file_sized_to_kstr(kls, filepath, &err, max_size, allow_nullchar);
663
664 if (err != GULP_FILE_OK) {
665 fprintf(stderr, "%s(): kls_gulp_file_sized_to_kstr() failed with err {%s}.\n",__func__,string_from_Gulp_Res(err));
666 }
667
668 return res;
669}
670
671#endif // KLS_GULP_IMPLEMENTATION
const char * string_from_Gulp_Res(Gulp_Res g)
Return a constant string for the passed Gulp_Res.
Definition koliseo.c:3285
Kstr * kls_gulp_file_sized_to_kstr(Koliseo *kls, const char *filepath, Gulp_Res *err, size_t max_size, bool allow_nullchar)
Tries mapping the passed file on the Koliseo.
Definition koliseo.c:3763
bool kstr_try_token(Kstr *k, char delim, Kstr *part)
Scans the first passed Kstr and if the passed char is present, the old Kstr is set to second pointer ...
Definition koliseo.c:3476
Kstr kstr_trim_left(Kstr kstr)
Returns a new Kstr after removing heading spaces from the passed one.
Definition koliseo.c:3405
bool kstr_eq_ignorecase(Kstr left, Kstr right)
Checks if the two passed Kstr have equal data, ignoring case.
Definition koliseo.c:3343
char * kls_gulp_file_sized(Koliseo *kls, const char *filepath, Gulp_Res *err, size_t max_size)
Tries mapping the passed file on the Koliseo.
Definition koliseo.c:3623
Kstr kstr_trim_right(Kstr kstr)
Returns a new Kstr after removing trailing spaces from the passed one.
Definition koliseo.c:3420
Kstr * try_kls_gulp_file_to_kstr(Koliseo *kls, const char *filepath, size_t max_size, bool allow_nullchar)
Tries mapping the passed file on the Koliseo.
Definition koliseo.c:3805
char * try_kls_gulp_file(Koliseo *kls, const char *filepath, size_t max_size)
Tries mapping the passed file on the Koliseo.
Definition koliseo.c:3664
Kstr kstr_cut_r(Kstr *k, size_t n)
Cuts the passed Kstr by up to n chars, from the right.
Definition koliseo.c:3388
Kstr kstr_from_c_lit(const char *c_lit)
Returns a new Kstr from the passed null-terminated string.
Definition koliseo.c:3312
Kstr kstr_cut_l(Kstr *k, size_t n)
Cuts the passed Kstr by up to n chars, from the left.
Definition koliseo.c:3369
Kstr kstr_new(const char *str, size_t len)
Returns a new Kstr with the passed args set.
Definition koliseo.c:3298
#define Gulp_Res_Fmt
Format macro for a Gulp_Res.
Definition kls_gulp.h:90
#define Gulp_Res_Arg(gr)
Format matching macro for a Gulp_Res.
Definition kls_gulp.h:94
Kstr kstr_token(Kstr *k, char delim)
Scans the passed Kstr and cuts it up to the first occurrence of passed char, even if it is not presen...
Definition koliseo.c:3504
Kstr kstr_trim(Kstr kstr)
Returns a new Kstr after removing heading and trailing spaces from the passed one.
Definition koliseo.c:3437
Kstr kstr_token_kstr(Kstr *k, Kstr delim)
Definition koliseo.c:3524
Gulp_Res
Defines possible results for kls_gulp_file_sized().
Definition kls_gulp.h:77
@ TOT_GULP_RES
Definition kls_gulp.h:84
@ GULP_FILE_KLS_NULL
Definition kls_gulp.h:83
@ GULP_FILE_CONTAINS_NULLCHAR
Definition kls_gulp.h:82
@ GULP_FILE_NOT_EXIST
Definition kls_gulp.h:79
@ GULP_FILE_TOO_LARGE
Definition kls_gulp.h:80
@ GULP_FILE_OK
Definition kls_gulp.h:78
@ GULP_FILE_READ_ERROR
Definition kls_gulp.h:81
bool kstr_indexof(Kstr k, char c, int *idx)
Checks if passed Kstr contains the passed char, and if so, sets the value pointed by idx to the first...
Definition koliseo.c:3450
const char * gulp_res_names[TOT_GULP_RES+1]
String array for representations of Gulp_Res.
Definition koliseo.c:3268
bool kstr_eq(Kstr left, Kstr right)
Checks if the two passed Kstr have exactly equal data.
Definition koliseo.c:3324
Definition kls_gulp.h:27
size_t len
Definition kls_gulp.h:29
const char * data
Definition kls_gulp.h:28