Skip to content
Snippets Groups Projects
parse_split_from_section.c 6.27 KiB
/*
 * parse_split_from_section.c
 *
 * Copyright (c) 2018-2024 Eric Vidal <eric@obarun.org>
 *
 * All rights reserved.
 *
 * This file is part of Obarun. It is subject to the license terms in
 * the LICENSE file found in the top-level directory of this
 * distribution.
 * This file may not be copied, modified, propagated, or distributed
 * except according to the terms contained in the LICENSE file./
 */

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

#include <oblibs/stack.h>
#include <oblibs/log.h>
#include <oblibs/sastr.h>
#include <oblibs/string.h>
#include <oblibs/mill.h>

#include <skalibs/stralloc.h>
#include <skalibs/types.h> //UINT_FMT

#include <66/parse.h>
#include <66/resolve.h>
#include <66/enum.h>

static ssize_t parse_get_previous_element(stralloc *sa, size_t where)
{
    size_t n = sastr_nelement(sa) ;
    n-- ;
    if ((n - where) < n)
        return -1 ;

    return sastr_find_element_byid(sa,n - where) ;
}

/* *
 * For now the ability to comment an entire section when
 * commenting the section name is not available anymore
 * */
int parse_split_from_section(resolve_service_t *res, stralloc *secname, char *str, char const *svname)
{
    log_flow() ;

    int e = 0, r = 0, found = 0 ;

    key_all_t const *list = total_list ;

    // cpos -> current, ipos -> idx pos, tpos -> temporary pos, end -> end the parse process
    size_t len = strlen(str), cpos = 0, ipos = 0, tpos = 0, end = 0 ;
    char tline[len + 1] ;
    char store[len + UINT_FMT + 1] ; // +6 be paranoid
    char *line ;

    memset(store, 0, sizeof(char) * (len + UINT_FMT + 1)) ;

    // find the name of the current section
    ssize_t previous_sec = parse_get_previous_element(secname, 0) ;

    if (previous_sec == -1) {
        log_warn("get previous section") ;
        goto err ;
    }

    int id = get_enum_by_key(secname->s + previous_sec) ;
    if (id < 0) {
        log_warn("invalid section name: ", secname->s + previous_sec, " for service: ", svname) ;
        goto err ;
    }

    log_trace("parsing section: ", secname->s + previous_sec) ;

    if (!strcmp(secname->s + previous_sec, enum_str_section[SECTION_ENV])) {
        str[strlen(str)] = 0 ;

        if (!parse_store_g(res, str, SECTION_ENV, KEY_ENVIRON_ENVAL)) {
            log_warnu("store resolve file of: ", svname) ;
            goto err ;
        }

        goto end ;
    }

    while(cpos < len) {

        ipos = 0 ;
        tpos = 0 ;
        end = 0 ;

        line = (char *)str + cpos ; // (char *) shut up compiler

        /** comment must be the first character found
         * at the begin of the line */
        if (line[tpos] == '#') {
            cpos += get_len_until(line, '\n') + 1 ;
            continue ;
        }

        // empty line or no more key=value?
        while (get_sep_before(line, '=', '\n') < 1){

                // Try to see if it's an empty line.
                r = get_len_until(line, '\n') ;
                if (r < 0) {
                    // end of string
                    end++ ;
                    break ;
                }

                cpos += r + 1 ; // +1 to remove '\n'

                if (cpos >= len) {
                    // end of string
                    end++ ;
                    break ;
                }

                line = (char *)str + cpos ;
        }

        if (end)
            break ;

        // get a cleaned key string
        wild_zero_all(&MILL_GET_KEY) ;
        _init_stack_(stk, strlen(line) + 1) ;
        r = mill_element(&stk, line, &MILL_GET_KEY, &tpos) ;
        if (r < 1) {
            log_warnu("get key at frontend service file of service: ", svname, " from line: ", line, " -- please make a bug report") ;
            goto err ;
        } else if (!r || tpos + cpos >= len) {
                // '=' was not find or end of string?
                break ;
        }
        if (!stack_close(&stk)) {
            log_warnu("stack overflow") ;
            goto err ;
        }

        // copy the string to parse
        auto_strings(tline, line) ;

        tpos = 0 ;

        // loop around all keys from the section
        while (*total_list[id].list[ipos].name) {

            found = 0 ;

            // look for a valid key name
            if (*list[id].list[ipos].name && !strcmp(stk.s, *list[id].list[ipos].name)) {

                found = 1 ;

                log_trace("parsing key: ", get_key_by_key_all(id, ipos)) ;

                switch(list[id].list[ipos].expected) {

                    case EXPECT_QUOTE:

                        r = get_len_until(tline, '\n') ;

                        if (r >= 0)
                            /** user migth forgot to close the double-quotes.
                             * so, only keep the line and not the complete string
                             * +1 for the parse_line_g which search for the '\n' character */
                            tline[r + 1] = 0 ;

                        wild_zero_all(&MILL_GET_DOUBLE_QUOTE) ;
                        if (!parse_line_g(store, &MILL_GET_DOUBLE_QUOTE, tline, &tpos))
                            parse_error_return(0, 6, id, ipos) ;

                        break ;

                    case EXPECT_BRACKET:

                        if (!parse_parentheses(store, tline, &tpos))
                            parse_error_return(0, 6, id, ipos) ;

                        break ;

                    case EXPECT_LINE:
                    case EXPECT_UINT:
                    case EXPECT_SLASH:

                        wild_zero_all(&MILL_GET_VALUE) ;
                        if (!parse_line_g(store, &MILL_GET_VALUE, tline, &tpos))
                            parse_error_return(0, 6, id, ipos) ;

                        break ;

                    default:
                        return 0 ;
                }
            }

            cpos += tpos ;

            if (found) {

                if (!parse_store_g(res, store, id, ipos)) {
                    log_warnu("store resolve file of: ", svname) ;
                    goto err ;
                } ;

                break ;
            }

            ipos++ ;
        }

        if (!found && r >= 0) {
            log_warn("unknown key: ", store," : in section: ",  secname->s + previous_sec, " -- ignoring it") ;
            tpos = get_len_until(line, '\n') ;
            cpos += tpos + 1 ;
        }
    }
    end:

    e = 1 ;

    err:
        return e ;
}