6 ex__file_8c
gullradriel edited this page 2026-10-09 00:55:18 +02:00

examples/ex_file.c

Functions

Name
void usage(void )
int test_atomic_file(void )
void process_args(int argc, char ** argv)
int main(int argc, char ** argv)
void inlined_func(void )

Functions Documentation

function usage

void usage(
    void 
)

function test_atomic_file

static int test_atomic_file(
    void 
)

function process_args

void process_args(
    int argc,
    char ** argv
)

function main

int main(
    int argc,
    char ** argv
)

function inlined_func

void inlined_func(
    void 
)

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>

#include "nilorea/n_files.h"
#include "nilorea/n_log.h"
#include "nilorea/n_str.h"

#ifndef __windows__
#include <sys/stat.h>
#include <sys/wait.h>
#endif

void usage(void) {
    fprintf(stderr,
            "     -v version\n"
            "     -V log level: LOG_INFO, LOG_NOTICE, LOG_ERR, LOG_DEBUG\n"
            "     -h help\n");
}

void process_args(int argc, char** argv) {
    int getoptret = 0,
        log_level = LOG_DEBUG; /* default log level */

    /* Arguments optionnels */
    /* -v version
     * -V log level
     * -h help
     */
    while ((getoptret = getopt(argc, argv, "hvV:")) != EOF) {
        switch (getoptret) {
            case 'v':
                fprintf(stderr, "Date de compilation : %s a %s.\n", __DATE__, __TIME__);
                exit(1);
            case 'V':
                if (!strcmp("LOG_NULL", optarg))
                    log_level = LOG_NULL;
                else if (!strcmp("LOG_NOTICE", optarg))
                    log_level = LOG_NOTICE;
                else if (!strcmp("LOG_INFO", optarg))
                    log_level = LOG_INFO;
                else if (!strcmp("LOG_ERR", optarg))
                    log_level = LOG_ERR;
                else if (!strcmp("LOG_DEBUG", optarg))
                    log_level = LOG_DEBUG;
                else {
                    fprintf(stderr, "%s n'est pas un niveau de log valide.\n", optarg);
                    exit(-1);
                }
                break;
            default:
            case '?': {
                if (optopt == 'V') {
                    fprintf(stderr, "\n      Missing log level\n");
                } else if (optopt == 'p') {
                    fprintf(stderr, "\n      Missing port\n");
                } else if (optopt != 's') {
                    fprintf(stderr, "\n      Unknow missing option %c\n", optopt);
                }
                usage();
                exit(1);
            }
            case 'h': {
                usage();
                exit(1);
            }
        }
    }
    set_log_level(log_level);
} /* void process_args( ... ) */

FORCE_INLINE void inlined_func(void) {
    n_log(LOG_DEBUG, "Inlined func");
}

/* Regression for n_file_write_atomic + n_file_read_bounded (n_files.h). */
static int test_atomic_file(void) {
    const char* path = "nilorea_ex_file_atomic.dat";
    const unsigned char payload[] = {0x00, 0x41, 0xff, 0x42, 0x00, 0x7a};
    unsigned char* buf = NULL;
    size_t len = 0;
    int rc = 0;

    if (n_file_write_atomic(path, payload, sizeof(payload), 0600) != TRUE) {
        n_log(LOG_ERR, "n_file_write_atomic failed");
        return 1;
    }
    if (n_file_read_bounded(path, sizeof(payload), &buf, &len) != TRUE) {
        n_log(LOG_ERR, "n_file_read_bounded failed");
        remove(path);
        return 1;
    }
    if (len != sizeof(payload) || memcmp(buf, payload, len) != 0) {
        n_log(LOG_ERR, "atomic write/read round-trip mismatch (len %zu)", len);
        rc = 1;
    }
    Free(buf);

    /* the cap must reject a file larger than max_size */
    if (n_file_read_bounded(path, sizeof(payload) - 1, &buf, &len) != FALSE) {
        n_log(LOG_ERR, "n_file_read_bounded ignored the size cap");
        Free(buf);
        rc = 1;
    }

    /* the requested mode is on the file, not just on the temporary it came from */
#ifndef __windows__
    {
        struct stat st;
        if (stat(path, &st) != 0 || (st.st_mode & 07777) != 0600) {
            n_log(LOG_ERR, "n_file_write_atomic did not apply the 0600 mode");
            rc = 1;
        }
    }
#endif

    /* atomic replace over the existing file, shorter content */
    if (n_file_write_atomic(path, payload, 3, 0600) != TRUE) {
        n_log(LOG_ERR, "n_file_write_atomic overwrite failed");
        rc = 1;
    } else if (n_file_read_bounded(path, 16, &buf, &len) != TRUE || len != 3) {
        n_log(LOG_ERR, "overwrite length wrong (len %zu)", len);
        Free(buf);
        rc = 1;
    } else {
        Free(buf);
    }

    remove(path);
    return rc;
}

int main(int argc, char** argv) {
    /* processing args and set log_level */
    process_args(argc, argv);

    if (test_atomic_file() != 0)
        return 1;

    inlined_func();

    n_log(LOG_INFO, "TRUE,true values: %d,%d / FALSE,false value: %d,%d", TRUE, true, FALSE, false);

    n_log(LOG_INFO, "_str(\"TEST\")=\"%s\" , _str(NULL)=\"%s\"", _str("TEST"), _str(NULL));
    n_log(LOG_INFO, "_strw(\"TEST\")=\"%s\" , _strw(NULL)=\"%s\"", _str("TEST"), _str(NULL));
    N_STR* nstr = char_to_nstr("TEST");
    n_log(LOG_INFO, "_nstr(nstrpointer)=\"%s\"", _nstr(nstr));
    n_log(LOG_INFO, "_nstrp(nstrpointer)=\"%s\"", _nstrp(nstr));
    free_nstr(&nstr);
    n_log(LOG_INFO, "_nstr(nstrpointer_freed)=\"%s\"", _nstr(nstr));
    n_log(LOG_INFO, "_nstrp(nstrpointer_freed)=\"%s\"", _nstrp(nstr));

    char* data = NULL;
    __n_assert(data, n_log(LOG_INFO, "data is NULL"));
    Malloc(data, char, 1024);
    __n_assert(data, n_log(LOG_INFO, "data is NULL"));
    Free(data);
    Malloc(data, char, 1024);
    Realloc(data, char, 2048);
    Free(data);
    Malloc(data, char, 1024);
    Reallocz(data, char, 1024, 2048);
    FreeNoLog(data);
    Alloca(data, 2048);
    // Free( data ); alloca should not be free else it's double freeing on exit

    n_log(LOG_INFO, "next_odd(10):%d  , next_odd(11):%d", next_odd(10), next_odd(11));
    n_log(LOG_INFO, "next_even(10):%d  , next_even(11):%d", next_even(10), next_even(11));

    init_error_check();
    ifzero(0) endif;
    ifzero(1) endif;
    ifnull(data) endif;
    ifnull(NULL) endif;
    iffalse(FALSE) endif;
    iftrue(TRUE) endif;
    checkerror();
error:
    if (get_error()) {
        n_log(LOG_INFO, "got an error while processing test");
    } else {
        n_log(LOG_INFO, "All tests for checkerror() are OK");
    }

    if (file_exist(argv[0])) {
        n_log(LOG_INFO, "%s exists !", argv[0]);
    }

    char *dir = NULL, *name = NULL;
    dir = get_prog_dir();
    name = get_prog_name();
    n_log(LOG_INFO, "From %s/%s", dir, name);
    Free(dir);
    Free(name);

    N_STR* out = NULL;
    int ret = -1;
    if (n_popen("ls -ltr", 2048, (void*)&out, &ret) == TRUE) {
        n_log(LOG_INFO, "ls returned %d : %s", ret, _nstr(out));
    } else {
        n_log(LOG_ERR, "popen s returned an error");
    }
    free_nstr(&out);

    char hidden_str[47] = "";
    N_HIDE_STR(hidden_str, 'T', 'h', 'i', 's', ' ', 's', 't', 'r', 'i', 'n', 'g', ' ', 'w', 'i', 'l', 'l', ' ', 'b', 'e', ' ', 'h', 'i', 'd', 'd', 'e', 'n', ' ', 'i', 'n', ' ', 't', 'h', 'e', ' ', 'f', 'i', 'n', 'a', 'l', ' ', 'b', 'i', 'n', 'a', 'r', 'y', '\0');
    printf("hidden str:%s\n", hidden_str);

    /* test n_scan_dir and n_free_file_info from n_files.h */
    LIST* file_list = new_generic_list(0);
    if (n_scan_dir(".", file_list, 0) == TRUE) {
        n_log(LOG_INFO, "n_scan_dir found %zu files in current directory", file_list->nb_items);
        list_foreach(fnode, file_list) {
            N_FILE_INFO* fi = (N_FILE_INFO*)fnode->ptr;
            if (fi && fi->name) {
                n_log(LOG_DEBUG, "  file: %s (time: %ld)", fi->name, (long)fi->filetime);
            }
        }
    } else {
        n_log(LOG_ERR, "n_scan_dir failed");
    }
    list_destroy(&file_list);

#ifndef __windows__
    n_log(LOG_INFO, "before system_nb( sleep 3 )");
    int pid = system_nb("sleep 3", NULL, NULL);
    n_log(LOG_INFO, "after system_nb( sleep 3 )");
    n_log(LOG_INFO, "wait for nb sys call");
    wait(&pid);
    n_log(LOG_INFO, "done");
    n_daemonize();
#endif
    n_abort("Testing abort before exit");
    n_log(LOG_INFO, "abort done");
    exit(0);
}