73 // make the array as small as possible |
73 // make the array as small as possible |
74 ucx_array_shrink(result); |
74 ucx_array_shrink(result); |
75 return result; |
75 return result; |
76 } |
76 } |
77 |
77 |
78 /* ... */ |
78 // ... |
79 |
79 |
80 sstr_t* array = /* some standard array of strings */ |
80 sstr_t* array = // some standard array of strings |
81 size_t arrlen = /* the length of the array */ |
81 size_t arrlen = // the length of the array |
82 |
82 |
83 UcxArray* result = create_unique(array,arrlen); |
83 UcxArray* result = create_unique(array,arrlen); |
84 |
84 |
85 /* Iterate over the array and print the elements */ |
85 // Iterate over the array and print the elements |
86 sstr_t* unique = result->data; |
86 sstr_t* unique = result->data; |
87 for (size_t i = 0 ; i < result->size ; i++) { |
87 for (size_t i = 0 ; i < result->size ; i++) { |
88 printf("%" PRIsstr "\n", SFMT(unique[i])); |
88 printf("%" PRIsstr "\n", SFMT(unique[i])); |
89 } |
89 } |
90 |
90 |
91 /* Free the array. */ |
91 // Free the array. |
92 ucx_array_free(result); |
92 ucx_array_free(result); |
93 ``` |
93 ``` |
94 ### Preventing out of bounds writes |
94 ### Preventing out of bounds writes |
95 |
95 |
96 The functions `ucx_array_reserve()`, `ucx_array_resize()`, `ucx_array_grow()`, |
96 The functions `ucx_array_reserve()`, `ucx_array_resize()`, `ucx_array_grow()`, |
126 |
126 |
127 Suppose you have a list of items which contain a `time_t` value and your task |
127 Suppose you have a list of items which contain a `time_t` value and your task |
128 is to find all items within a time window `[t_start, t_end]`. |
128 is to find all items within a time window `[t_start, t_end]`. |
129 With AVL Trees this is easy: |
129 With AVL Trees this is easy: |
130 ```C |
130 ```C |
131 /* --------------------- |
131 // Somewhere in a header |
132 * Somewhere in a header |
|
133 */ |
|
134 typedef struct { |
132 typedef struct { |
135 time_t ts; |
133 time_t ts; |
136 /* other important data */ |
134 // other important data |
137 } MyObject; |
135 } MyObject; |
138 |
136 |
139 /* ----------- |
137 // Source code |
140 * Source code |
|
141 */ |
|
142 |
|
143 UcxAVLTree* tree = ucx_avl_new(ucx_cmp_longint); |
138 UcxAVLTree* tree = ucx_avl_new(ucx_cmp_longint); |
144 /* ... populate tree with objects, use '& MyObject.ts' as key ... */ |
139 // ... populate tree with objects, use '& MyObject.ts' as key ... |
145 |
140 |
146 |
141 |
147 /* Now find every item, with 30 <= ts <= 70 */ |
142 // Now find every item, with 30 <= ts <= 70 |
148 time_t ts_start = 30; |
143 time_t ts_start = 30; |
149 time_t ts_end = 70; |
144 time_t ts_end = 70; |
150 |
145 |
151 printf("Values in range:\n"); |
146 printf("Values in range:\n"); |
152 for ( |
147 for ( |
210 |
205 |
211 const size_t chunksize = 256; |
206 const size_t chunksize = 256; |
212 |
207 |
213 UcxBuffer* linebuf = |
208 UcxBuffer* linebuf = |
214 ucx_buffer_new( |
209 ucx_buffer_new( |
215 NULL, /* the buffer should manage the memory area for us */ |
210 NULL, // the buffer should manage the memory area for us |
216 2*chunksize, /* initial size should be twice the chunk size */ |
211 2*chunksize, // initial size should be twice the chunk size |
217 UCX_BUFFER_AUTOEXTEND); /* the buffer will grow when necessary */ |
212 UCX_BUFFER_AUTOEXTEND); // the buffer will grow when necessary |
218 |
213 |
219 size_t lineno = 1; |
214 size_t lineno = 1; |
220 do { |
215 do { |
221 /* read line chunk */ |
216 // read line chunk |
222 size_t read = ucx_stream_ncopy( |
217 size_t read = ucx_stream_ncopy( |
223 input, linebuf, fread, ucx_buffer_write, chunksize); |
218 input, linebuf, fread, ucx_buffer_write, chunksize); |
224 if (read == 0) break; |
219 if (read == 0) break; |
225 |
220 |
226 /* handle line endings */ |
221 // handle line endings |
227 do { |
222 do { |
228 sstr_t bufstr = ucx_buffer_to_sstr(linebuf); |
223 sstr_t bufstr = ucx_buffer_to_sstr(linebuf); |
229 sstr_t nl = sstrchr(bufstr, '\n'); |
224 sstr_t nl = sstrchr(bufstr, '\n'); |
230 if (nl.length == 0) break; |
225 if (nl.length == 0) break; |
231 |
226 |
232 size_t linelen = bufstr.length - nl.length; |
227 size_t linelen = bufstr.length - nl.length; |
233 sstr_t linestr = sstrsubsl(bufstr, 0, linelen); |
228 sstr_t linestr = sstrsubsl(bufstr, 0, linelen); |
234 |
229 |
235 printf("%zu: %" PRIsstr "\n", lineno++, SFMT(linestr)); |
230 printf("%zu: %" PRIsstr "\n", lineno++, SFMT(linestr)); |
236 |
231 |
237 /* shift the buffer to the next line */ |
232 // shift the buffer to the next line |
238 ucx_buffer_shift_left(linebuf, linelen+1); |
233 ucx_buffer_shift_left(linebuf, linelen+1); |
239 } while(1); |
234 } while(1); |
240 |
235 |
241 } while(1); |
236 } while(1); |
242 |
237 |
243 /* print the 'noeol' line, if any */ |
238 // print the 'noeol' line, if any |
244 sstr_t lastline = ucx_buffer_to_sstr(linebuf); |
239 sstr_t lastline = ucx_buffer_to_sstr(linebuf); |
245 if (lastline.length > 0) { |
240 if (lastline.length > 0) { |
246 printf("%zu: %" PRIsstr, lineno, SFMT(lastline)); |
241 printf("%zu: %" PRIsstr, lineno, SFMT(lastline)); |
247 } |
242 } |
248 |
243 |
284 } |
279 } |
285 } |
280 } |
286 return list; |
281 return list; |
287 } |
282 } |
288 |
283 |
289 /* we will need this function to clean up the list contents later */ |
284 // we will need this function to clean up the list contents later |
290 void free_sstr(void* ptr) { |
285 void free_sstr(void* ptr) { |
291 sstr_t* s = ptr; |
286 sstr_t* s = ptr; |
292 free(s->ptr); |
287 free(s->ptr); |
293 free(s); |
288 free(s); |
294 } |
289 } |
295 |
290 |
296 /* ... */ |
291 // ... |
297 |
292 |
298 sstr_t* array = /* some array of strings */ |
293 sstr_t* array = // some array of strings |
299 size_t arrlen = /* the length of the array */ |
294 size_t arrlen = // the length of the array |
300 |
295 |
301 UcxList* list = remove_duplicates(array,arrlen); |
296 UcxList* list = remove_duplicates(array,arrlen); |
302 |
297 |
303 /* Iterate over the list and print the elements */ |
298 // Iterate over the list and print the elements |
304 UCX_FOREACH(elem, list) { |
299 UCX_FOREACH(elem, list) { |
305 sstr_t s = *((sstr_t*)elem->data); |
300 sstr_t s = *((sstr_t*)elem->data); |
306 printf("%" PRIsstr "\n", SFMT(s)); |
301 printf("%" PRIsstr "\n", SFMT(s)); |
307 } |
302 } |
308 |
303 |
309 /* Use our free function to free the duplicated strings. */ |
304 // Use our free function to free the duplicated strings. |
310 ucx_list_free_content(list, free_sstr); |
305 ucx_list_free_content(list, free_sstr); |
311 ucx_list_free(list); |
306 ucx_list_free(list); |
312 ``` |
307 ``` |
313 |
308 |
314 ## Logging |
309 ## Logging |
461 FILE *f = fopen("test.csv", "r"); |
456 FILE *f = fopen("test.csv", "r"); |
462 if (!f) { |
457 if (!f) { |
463 perror("Cannot open file"); |
458 perror("Cannot open file"); |
464 return 1; |
459 return 1; |
465 } |
460 } |
466 /* close the file automatically at pool destruction*/ |
461 // close the file automatically at pool destruction |
467 ucx_mempool_reg_destr(pool, f, (ucx_destructor) fclose); |
462 ucx_mempool_reg_destr(pool, f, (ucx_destructor) fclose); |
468 |
463 |
469 /* create a buffer and register it at the memory pool for destruction */ |
464 // create a buffer and register it at the memory pool for destruction |
470 UcxBuffer* content = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND); |
465 UcxBuffer* content = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND); |
471 ucx_mempool_reg_destr(pool, content, (ucx_destructor) ucx_buffer_free); |
466 ucx_mempool_reg_destr(pool, content, (ucx_destructor) ucx_buffer_free); |
472 |
467 |
473 /* read the file and split it by lines first */ |
468 // read the file and split it by lines first |
474 ucx_stream_copy(f, content, fread, ucx_buffer_write); |
469 ucx_stream_copy(f, content, fread, ucx_buffer_write); |
475 sstr_t contentstr = ucx_buffer_to_sstr(content); |
470 sstr_t contentstr = ucx_buffer_to_sstr(content); |
476 ssize_t lc = 0; |
471 ssize_t lc = 0; |
477 sstr_t* lines = sstrsplit_a(pool->allocator, contentstr, S("\n"), &lc); |
472 sstr_t* lines = sstrsplit_a(pool->allocator, contentstr, S("\n"), &lc); |
478 |
473 |
479 /* skip the header and parse the remaining data */ |
474 // skip the header and parse the remaining data |
480 UcxList* datalist = NULL; |
475 UcxList* datalist = NULL; |
481 for (size_t i = 1 ; i < lc ; i++) { |
476 for (size_t i = 1 ; i < lc ; i++) { |
482 if (lines[i].length == 0) continue; |
477 if (lines[i].length == 0) continue; |
483 ssize_t fc = 3; |
478 ssize_t fc = 3; |
484 sstr_t* fields = sstrsplit_a(pool->allocator, lines[i], S(";"), &fc); |
479 sstr_t* fields = sstrsplit_a(pool->allocator, lines[i], S(";"), &fc); |
492 data->column_b = fields[1]; |
487 data->column_b = fields[1]; |
493 data->column_c = fields[2]; |
488 data->column_c = fields[2]; |
494 datalist = ucx_list_append_a(pool->allocator, datalist, data); |
489 datalist = ucx_list_append_a(pool->allocator, datalist, data); |
495 } |
490 } |
496 |
491 |
497 /* control output */ |
492 // control output |
498 UCX_FOREACH(elem, datalist) { |
493 UCX_FOREACH(elem, datalist) { |
499 CSVData* data = elem->data; |
494 CSVData* data = elem->data; |
500 printf("Column A: %" PRIsstr " | " |
495 printf("Column A: %" PRIsstr " | " |
501 "Column B: %" PRIsstr " | " |
496 "Column B: %" PRIsstr " | " |
502 "Column C: %" PRIsstr "\n", |
497 "Column C: %" PRIsstr "\n", |
503 SFMT(data->column_a), SFMT(data->column_b), SFMT(data->column_c) |
498 SFMT(data->column_a), SFMT(data->column_b), SFMT(data->column_c) |
504 ); |
499 ); |
505 } |
500 } |
506 |
501 |
507 /* cleanup everything, no manual free() needed */ |
502 // cleanup everything, no manual free() needed |
508 ucx_mempool_destroy(pool); |
503 ucx_mempool_destroy(pool); |
509 |
504 |
510 return 0; |
505 return 0; |
511 } |
506 } |
512 ``` |
507 ``` |
517 memory is not supposed to be freed with a simple call to `free()`. |
512 memory is not supposed to be freed with a simple call to `free()`. |
518 In this case, you can overwrite the default destructor as follows: |
513 In this case, you can overwrite the default destructor as follows: |
519 ```C |
514 ```C |
520 MyObject* obj = ucx_mempool_malloc(pool, sizeof(MyObject)); |
515 MyObject* obj = ucx_mempool_malloc(pool, sizeof(MyObject)); |
521 |
516 |
522 /* some special initialization with own resource management */ |
517 // some special initialization with own resource management |
523 my_object_init(obj); |
518 my_object_init(obj); |
524 |
519 |
525 /* register destructor function */ |
520 // register destructor function |
526 ucx_mempool_set_destr(obj, (ucx_destructor) my_object_destroy); |
521 ucx_mempool_set_destr(obj, (ucx_destructor) my_object_destroy); |
527 ``` |
522 ``` |
528 Be aware, that your destructor function should not free any memory, that is |
523 Be aware, that your destructor function should not free any memory, that is |
529 also managed by the pool. |
524 also managed by the pool. |
530 Otherwise you might be risking a double-free. |
525 Otherwise you might be risking a double-free. |
542 The key/value pairs are stored within an UCX Map. |
537 The key/value pairs are stored within an UCX Map. |
543 |
538 |
544 ### Example: Loading properties from a file |
539 ### Example: Loading properties from a file |
545 |
540 |
546 ```C |
541 ```C |
547 /* Open the file as usual */ |
542 // Open the file as usual |
548 FILE* file = fopen("myprops.properties", "r"); |
543 FILE* file = fopen("myprops.properties", "r"); |
549 if (!file) { |
544 if (!file) { |
550 // error handling |
545 // error handling |
551 return 1; |
546 return 1; |
552 } |
547 } |
553 |
548 |
554 /* Load the properties from the file */ |
549 // Load the properties from the file |
555 UcxMap* myprops = ucx_map_new(16); |
550 UcxMap* myprops = ucx_map_new(16); |
556 if (ucx_properties_load(myprops, file)) { |
551 if (ucx_properties_load(myprops, file)) { |
557 /* ... error handling ... */ |
552 // ... error handling ... |
558 fclose(file); |
553 fclose(file); |
559 ucx_map_free(myprops); |
554 ucx_map_free(myprops); |
560 return 1; |
555 return 1; |
561 } |
556 } |
562 |
557 |
563 /* Print out the key/value pairs */ |
558 // Print out the key/value pairs |
564 char* propval; |
559 char* propval; |
565 UcxMapIterator propiter = ucx_map_iterator(myprops); |
560 UcxMapIterator propiter = ucx_map_iterator(myprops); |
566 UCX_MAP_FOREACH(key, propval, propiter) { |
561 UCX_MAP_FOREACH(key, propval, propiter) { |
567 printf("%s = %s\n", (char*)key.data, propval); |
562 printf("%s = %s\n", (char*)key.data, propval); |
568 } |
563 } |
569 |
564 |
570 /* Don't forget to free the values before freeing the map */ |
565 // Don't forget to free the values before freeing the map |
571 ucx_map_free_content(myprops, NULL); |
566 ucx_map_free_content(myprops, NULL); |
572 ucx_map_free(myprops); |
567 ucx_map_free(myprops); |
573 fclose(file); |
568 fclose(file); |
574 ``` |
569 ``` |
575 |
570 |
597 int i = 42; |
592 int i = 42; |
598 float f = 3.14f; |
593 float f = 3.14f; |
599 const char* str = "Hello!"; |
594 const char* str = "Hello!"; |
600 size_t strn = 7; |
595 size_t strn = 7; |
601 |
596 |
602 /* push the integer */ |
597 // push the integer |
603 ucx_stack_push(&stack, sizeof(int), &i); |
598 ucx_stack_push(&stack, sizeof(int), &i); |
604 |
599 |
605 /* push the float and rember the address */ |
600 // push the float and rember the address |
606 float* remember = ucx_stack_push(&stack, sizeof(float), &f); |
601 float* remember = ucx_stack_push(&stack, sizeof(float), &f); |
607 |
602 |
608 /* push the string with zero terminator */ |
603 // push the string with zero terminator |
609 ucx_stack_push(&stack, strn, str); |
604 ucx_stack_push(&stack, strn, str); |
610 |
605 |
611 /* if we forget, how big an element was, we can ask the stack */ |
606 // if we forget, how big an element was, we can ask the stack |
612 printf("Length of string: %zu\n", ucx_stack_topsize(&stack)-1); |
607 printf("Length of string: %zu\n", ucx_stack_topsize(&stack)-1); |
613 |
608 |
614 /* retrieve the string as sstr_t, without zero terminator! */ |
609 // retrieve the string as sstr_t, without zero terminator! |
615 sstr_t s; |
610 sstr_t s; |
616 s.length = ucx_stack_topsize(&stack)-1; |
611 s.length = ucx_stack_topsize(&stack)-1; |
617 s.ptr = malloc(s.length); |
612 s.ptr = malloc(s.length); |
618 ucx_stack_popn(&stack, s.ptr, s.length); |
613 ucx_stack_popn(&stack, s.ptr, s.length); |
619 printf("%" PRIsstr "\n", SFMT(s)); |
614 printf("%" PRIsstr "\n", SFMT(s)); |
620 |
615 |
621 /* print the float directly from the stack and free it */ |
616 // print the float directly from the stack and free it |
622 printf("Float: %f\n", *remember); |
617 printf("Float: %f\n", *remember); |
623 ucx_stack_free(&stack, remember); |
618 ucx_stack_free(&stack, remember); |
624 |
619 |
625 /* the last element is the integer */ |
620 // the last element is the integer |
626 int j; |
621 int j; |
627 ucx_stack_pop(&stack, &j); |
622 ucx_stack_pop(&stack, &j); |
628 printf("Integer: %d\n", j); |
623 printf("Integer: %d\n", j); |
629 ``` |
624 ``` |
630 |
625 |
645 ### Initialization |
640 ### Initialization |
646 |
641 |
647 There are several ways to create an `sstr_t`: |
642 There are several ways to create an `sstr_t`: |
648 |
643 |
649 ```C |
644 ```C |
650 /* (1) sstr() uses strlen() internally, hence cstr MUST be zero-terminated */ |
645 // (1) sstr() uses strlen() internally, hence cstr MUST be zero-terminated |
651 sstr_t a = sstr(cstr); |
646 sstr_t a = sstr(cstr); |
652 |
647 |
653 /* (2) cstr does not need to be zero-terminated, if length is specified */ |
648 // (2) cstr does not need to be zero-terminated, if length is specified |
654 sstr_t b = sstrn(cstr, len); |
649 sstr_t b = sstrn(cstr, len); |
655 |
650 |
656 /* (3) S() macro creates sstr_t from a string using sizeof() and using sstrn(). |
651 // (3) S() macro creates sstr_t from a string using sizeof() and using sstrn(). |
657 This version is especially useful for function arguments */ |
652 // This version is especially useful for function arguments |
658 sstr_t c = S("hello"); |
653 sstr_t c = S("hello"); |
659 |
654 |
660 /* (4) SC() macro works like S(), but makes the string immutable using scstr_t. |
655 // (4) SC() macro works like S(), but makes the string immutable using scstr_t. |
661 (available since UCX 2.0) */ |
656 // (available since UCX 2.0) |
662 scstr_t d = SC("hello"); |
657 scstr_t d = SC("hello"); |
663 |
658 |
664 /* (5) ST() macro creates sstr_t struct literal using sizeof() */ |
659 // (5) ST() macro creates sstr_t struct literal using sizeof() |
665 sstr_t e = ST("hello"); |
660 sstr_t e = ST("hello"); |
666 ``` |
661 ``` |
667 |
662 |
668 You should not use the `S()`, `SC()`, or `ST()` macro with string of unknown |
663 You should not use the `S()`, `SC()`, or `ST()` macro with string of unknown |
669 origin, since the `sizeof()` call might not coincide with the string length in |
664 origin, since the `sizeof()` call might not coincide with the string length in |
714 |
709 |
715 ```C |
710 ```C |
716 sstr_t test = ST("here::are::some::strings"); |
711 sstr_t test = ST("here::are::some::strings"); |
717 sstr_t delim = ST("::"); |
712 sstr_t delim = ST("::"); |
718 |
713 |
719 ssize_t count = 0; /* no limit */ |
714 ssize_t count = 0; // no limit |
720 UcxMempool* pool = ucx_mempool_new_default(); |
715 UcxMempool* pool = ucx_mempool_new_default(); |
721 |
716 |
722 sstr_t* result = sstrsplit_a(pool->allocator, test, delim, &count); |
717 sstr_t* result = sstrsplit_a(pool->allocator, test, delim, &count); |
723 for (ssize_t i = 0 ; i < count ; i++) { |
718 for (ssize_t i = 0 ; i < count ; i++) { |
724 /* don't forget to specify the length via the %*s format specifier */ |
719 // don't forget to specify the length via the %*s format specifier |
725 printf("%*s\n", result[i].length, result[i].ptr); |
720 printf("%*s\n", result[i].length, result[i].ptr); |
726 } |
721 } |
727 |
722 |
728 ucx_mempool_destroy(pool); |
723 ucx_mempool_destroy(pool); |
729 ``` |
724 ``` |
760 define test subroutines. |
755 define test subroutines. |
761 |
756 |
762 You should declare test cases and subroutines in a header file per test unit |
757 You should declare test cases and subroutines in a header file per test unit |
763 and implement them as you would implement normal functions. |
758 and implement them as you would implement normal functions. |
764 ```C |
759 ```C |
765 /* myunit.h */ |
760 // myunit.h |
766 UCX_TEST(function_name); |
761 UCX_TEST(function_name); |
767 UCX_TEST_SUBROUTINE(subroutine_name, paramlist); /* optional */ |
762 UCX_TEST_SUBROUTINE(subroutine_name, paramlist); // optional |
768 |
763 |
769 |
764 |
770 /* myunit.c */ |
765 // myunit.c |
771 UCX_TEST_SUBROUTINE(subroutine_name, paramlist) { |
766 UCX_TEST_SUBROUTINE(subroutine_name, paramlist) { |
772 /* ... reusable tests with UCX_TEST_ASSERT() ... */ |
767 // ... reusable tests with UCX_TEST_ASSERT() ... |
773 } |
768 } |
774 |
769 |
775 UCX_TEST(function_name) { |
770 UCX_TEST(function_name) { |
776 /* ... resource allocation and other test preparation ... */ |
771 // ... resource allocation and other test preparation ... |
777 |
772 |
778 /* mandatory marker for the start of the tests */ |
773 // mandatory marker for the start of the tests |
779 UCX_TEST_BEGIN |
774 UCX_TEST_BEGIN |
780 |
775 |
781 /* ... verifications with UCX_TEST_ASSERT() ... |
776 // ... verifications with UCX_TEST_ASSERT() ... |
782 * (and/or calls with UCX_TEST_CALL_SUBROUTINE()) |
777 // (and/or calls with UCX_TEST_CALL_SUBROUTINE()) |
783 */ |
778 |
784 |
779 // mandatory marker for the end of the tests |
785 /* mandatory marker for the end of the tests */ |
|
786 UCX_TEST_END |
780 UCX_TEST_END |
787 |
781 |
788 /* ... resource cleanup ... |
782 // ... resource cleanup ... |
789 * (all code after UCX_TEST_END is always executed) |
783 // (all code after UCX_TEST_END is always executed) |
790 */ |
|
791 } |
784 } |
792 ``` |
785 ``` |
793 If you want to use the `UCX_TEST_ASSERT()` macro in a function, you are |
786 If you want to use the `UCX_TEST_ASSERT()` macro in a function, you are |
794 *required* to use a `UCX_TEST_SUBROUTINE`. |
787 *required* to use a `UCX_TEST_SUBROUTINE`. |
795 Otherwise the testing framework does not know where to jump, when the assertion |
788 Otherwise the testing framework does not know where to jump, when the assertion |
798 After implementing the tests, you can easily build a test suite and execute it: |
791 After implementing the tests, you can easily build a test suite and execute it: |
799 ```C |
792 ```C |
800 UcxTestSuite* suite = ucx_test_suite_new(); |
793 UcxTestSuite* suite = ucx_test_suite_new(); |
801 ucx_test_register(suite, testMyTestCase01); |
794 ucx_test_register(suite, testMyTestCase01); |
802 ucx_test_register(suite, testMyTestCase02); |
795 ucx_test_register(suite, testMyTestCase02); |
803 /* ... */ |
796 // ... |
804 ucx_test_run(suite, stdout); /* stdout, or any other FILE stream */ |
797 ucx_test_run(suite, stdout); // stdout, or any other FILE stream |
805 ``` |
798 ``` |
806 |
799 |
807 ## Utilities |
800 ## Utilities |
808 |
801 |
809 *Header file:* [utils.h](api-2.1/utils_8h.html) |
802 *Header file:* [utils.h](api-2.1/utils_8h.html) |
829 if (argc != 3) { |
822 if (argc != 3) { |
830 fprintf(stderr, "Use %s <src> <dest>", argv[0]); |
823 fprintf(stderr, "Use %s <src> <dest>", argv[0]); |
831 return 1; |
824 return 1; |
832 } |
825 } |
833 |
826 |
834 FILE *srcf = fopen(argv[1], "r"); /* insert error handling on your own */ |
827 FILE *srcf = fopen(argv[1], "r"); // insert error handling on your own |
835 FILE *destf = fopen(argv[2], "w"); |
828 FILE *destf = fopen(argv[2], "w"); |
836 |
829 |
837 size_t n = ucx_stream_copy(srcf, destf, fread, fwrite); |
830 size_t n = ucx_stream_copy(srcf, destf, fread, fwrite); |
838 printf("%zu bytes copied.\n", n); |
831 printf("%zu bytes copied.\n", n); |
839 |
832 |
864 for (unsigned int i = 2 ; i < 100 ; i++) { |
857 for (unsigned int i = 2 ; i < 100 ; i++) { |
865 ucx_bprintf(strbuffer, "Integer %d is %s\n", |
858 ucx_bprintf(strbuffer, "Integer %d is %s\n", |
866 i, prime(i) ? "prime" : "not prime"); |
859 i, prime(i) ? "prime" : "not prime"); |
867 } |
860 } |
868 |
861 |
869 /* print the result to stdout */ |
862 // print the result to stdout |
870 printf("%s", (char*)strbuffer->space); |
863 printf("%s", (char*)strbuffer->space); |
871 |
864 |
872 ucx_buffer_free(strbuffer); |
865 ucx_buffer_free(strbuffer); |
873 ``` |
866 ``` |