Platon Technologies
neprihlásený Prihlásiť Registrácia
SlovakEnglish
open source software development oslavujeme 10 rokov vývoja otvoreného softvéru! Štvrtok, 28. marec 2024

Súbor: [Platon] / ep / src / conf.c (stiahnutie)

Revízia 1.41, Fri Nov 28 17:35:11 2003 UTC (20 years, 4 months ago) by nepto


Zmeny od 1.40: +3 -3 [lines]

Changed URL from www.platon.sk to platon.sk.

/*
 * ep - extended pipelining
 *
 * conf.c - command line and config file parsing implementation
 * ____________________________________________________________
 *
 * Developed by Ondrej Jombik <nepto@platon.sk>
 *          and Lubomir Host <rajo@platon.sk>
 * Copyright (c) 2000-2003 Platon SDG, http://platon.sk/
 * All rights reserved.
 *
 * See README file for more information about this software.
 * See COPYING file for license information.
 *
 * Download the latest version from
 * http://platon.sk/projects/ep/
 */

/* $Platon: ep/src/conf.c,v 1.40 2003/05/03 09:58:19 nepto Exp $ */

/* Includes {{{ */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

#include <platon/cfg+.h>
#include "platon-str.h"

#include "fd.h"
#include "proctable.h"
#include "proclink.h"
#include "message.h"
#include "conf.h"
/* }}} */

/* Static variables {{{ */
static char *section_boundaries[2]       = {"[", "]"};
static char *name_vs_stream_separator[4] = {".", "..", "-", NULL};
static char *global_str                  = "Global";
static char *process_str                 = "Process";
/* }}} */

/* Options structures (used only with libcfg+ context) {{{ */
static struct conf_struct_global global_cfg;
static struct conf_struct_process process_cfg;
/* }}} */

/* Options contexts {{{ */
static CFG_CONTEXT global_context = NULL;
static CFG_CONTEXT process_context = NULL;
/* }}} */

/* Global options {{{ */
static struct cfg_option global_options[] = { /* } */
{ "help", 'h', NULL, CFG_BOOLEAN + CFG_MULTI, (void *) &(global_cfg.help), 0 },
{"quiet", 'q', "quiet", CFG_BOOLEAN, (void *) &(global_cfg.quiet), 0},
{"verbose", 'v', "verbose", CFG_BOOLEAN + CFG_MULTI, (void *) &(global_cfg.verbose), 0},
{"config-file", 'f', NULL, CFG_STRING + CFG_MULTI, (void *) &(global_cfg.config_file), 0},
{"disable-global-config",'\0',NULL,CFG_BOOLEAN,(void*)&(global_cfg.disable_global_config),0},
{"disable-user-config",'\0',NULL,CFG_BOOLEAN,(void*)&(global_cfg.disable_user_config),0},
{"case-insensitive-names",'\0',NULL,CFG_BOOLEAN,(void*)&(global_cfg.case_insensitive_names),0},
{"fast-data-transfer",'F',"fast data transfer",CFG_BOOLEAN,(void*)&(global_cfg.fast_data_transfer),0},
    CFG_END_OF_LIST
    }; /* }}} */

/* Process options {{{ */
static struct cfg_option process_options[] = { /* } */
{"nice", 'N', "nice", CFG_INT, (void *) &(process_cfg.nice), 0},
{"name", 'n', "name", CFG_STRING+CFG_MULTI_SEPARATED, (void *) &(process_cfg.name), 0},
{"input", 'i', "input", CFG_STRING+CFG_MULTI_SEPARATED, (void *) &(process_cfg.fd_str[0]), 0},
{"output", 'o', "output", CFG_STRING+CFG_MULTI_SEPARATED, (void *)&(process_cfg.fd_str[1]),0},
{"errput", 'e', "errput", CFG_STRING+CFG_MULTI_SEPARATED, (void *)&(process_cfg.fd_str[2]),0},
{NULL, '\0', "command", CFG_LEFTOVER_ARGS+CFG_STRING+CFG_MULTI_SEPARATED,
    (void *)&(process_cfg.argv),0},
    CFG_END_OF_LIST
    }; /* }}} */

/* Static function declarations {{{ */
static void print_cfg_error(const CFG_CONTEXT con);
static int test_process_cfg_argv(const char *config_filename);
static char *get_user_config_filename(void);
static void clear_global_cfg(void);
static void clear_process_cfg(void);
static int check_context(CFG_CONTEXT *context, struct cfg_option options[]);
static int is_cfgfile_section(char *section_str);
static void free_global(struct conf_struct_global **global);
static void free_processes(struct conf_struct_process ***processes);
static int get_processes_index_by_name(
        struct conf_struct_process **processes, char *name);
static int add_global_cfg_to_global(struct conf_struct_global **global);
static int add_process_cfg_to_processes(
        struct conf_struct_process ***processes,
        int *size);
static int add_processes_to_processes(
        struct conf_struct_process ***dest_processes,
        struct conf_struct_process **src_processes);
static int add_processes_to_proctable(
        PROCTABLE *p_ptbl,
        struct conf_struct_process **processes,
        int start_idx_size, int *start_idx);
/* }}} */

/*
 * Function definitions
 */

/*    PARSING SCHEME (do not delete) {{{
 *    ------------------------------
 *
 *    conf_cmdline_parse_process();
 *    if (error) {
 *        conf_cmdline_parse_global();
 *        if (err) {
 *            fail;
 *        }
 *
 *        if (config_file) {
 *            conf_cfgfile_parse_all();
 *        }
 *    }
 *
 *    while(1) {
 *
 *        conf_cmdline_parse_process();
 *
 *        if (error) {
 *            fail;
 *        }
 *    }
 */ /* }}} */

    int
conf_init(void)
{/* {{{ */
    return check_context(&global_context, global_options)
        && check_context(&process_context, process_options);
} /* }}} */

    void
conf_destroy(void)
{ /* {{{ */
    if (global_context != NULL)
        cfg_free_context(global_context);
    if (process_context != NULL)
        cfg_free_context(process_context);
} /* }}} */

    PROCTABLE
conf_parse_all(argc, argv)
    int    argc;
    char   **argv;
{ /* {{{ */
    register int ret, i;
    struct conf_struct_global *global;
    struct conf_struct_global *global_work;
    struct conf_struct_process **processes;
    struct conf_struct_process **processes_work;

    PROCTABLE ptbl;

    int *start_idx;
    int start_idx_size;

    global    = NULL;
    processes = NULL;
    ret = conf_cmdline_parse(argc - 1, argv + 1, &global, &processes);

    if (ret != CFG_OK) {
        /* TODO: better error information */
        /* print_cfg_error(con, ret); */
        if (ret == CFG_ERR_NOMEM)
            msg_error_print("not enough memory for command line parsing\n");
        /* XXX: free structures */
        free_global(&global);
        free_processes(&processes);
        return NULL;
    }

    if (global->help) {
        msg_usage_print();
        free_global(&global);
        free_processes(&processes);
        return NULL;
    }

    for (start_idx_size = 0; global->config_file != NULL
            && global->config_file[start_idx_size] != NULL;
            start_idx_size++)
        ;

    start_idx_size += 3; /* command line, global config, homedir config */
    start_idx = (int *) malloc(start_idx_size * sizeof(int));

    if (start_idx == NULL) {
        msg_error_print("not enough memory for parsing indexes\n");
        /* XXX: free structures */
        free_global(&global);
        free_processes(&processes);
        return NULL;
    }

    start_idx[0] = 0;

    for (i = 0; i < start_idx_size - 1; i++) {

        register char *filename;

        if ((i == 0 && global->disable_global_config)
                || (i == 1 && global->disable_user_config))
            continue;

        filename = i <= 0 ? conf_global_filename
            : i == 1 ? get_user_config_filename()
            : global->config_file[i - 2];

        if (/* i == 1 && */ filename == NULL) {
            msg_error_print("not enough memory for filename buffer\n");
            /* XXX: free structures */
            free(start_idx);
            free_global(&global);
            free_processes(&processes);
            return NULL;
        }

#if DEBUG
        msg_debug_print("conf_parse_all(): parsing file '%s'\n", filename);
#endif

        global_work    = NULL;
        processes_work = NULL;
        ret = conf_cfgfile_parse(filename, &global_work, &processes_work);

        /* TODO: Progressive config file type reporting in error messages.
           There are three types: global, local/user, user defined. */

        if (ret != CFG_OK
                && (i >= 2 || (i < 2 && ret != CFG_ERR_FILE_NOT_FOUND))) {
            /* TODO: better error information */
            /* print_cfg_error(con, ret); */
            if (ret == CFG_ERR_NOMEM)
                msg_error_print("not enough memory for config file parsing\n");
            if (ret == CFG_ERR_FILE_NOT_FOUND)
                msg_error_print("file '%s' not found\n", filename);
            /* msg_error_print("config file '%s' parsing error %d\n",
               filename, ret); */
            /* XXX: free structures */
            if (i == 1)
                free(filename);
            free(start_idx);
            free_global(&global_work);
            free_processes(&processes_work);
            free_global(&global);
            free_processes(&processes);
            return NULL;
        }

        for (start_idx[i + 1] = 0; processes_work != NULL
                && processes_work[start_idx[i + 1]] != NULL;
                start_idx[i + 1]++)
            ;
        start_idx[i + 1] += start_idx[i];

        if (! add_processes_to_processes(&processes, processes_work)) {
            msg_error_print("not enough memory for config file '%s'"
                    "process table merging\n", filename);
            /* XXX: free structures */
            if (i == 1)
                free(filename);
            free(start_idx);
            free_global(&global_work);
            free_processes(&processes_work);
            free_global(&global);
            free_processes(&processes);
            return NULL;
        }

        if (i == 1)
            free(filename);

        free(global_work);
        free(processes_work);
    }

#if DEBUG
    {
        register int dbg_i;
        register char *names;
        register char *argvs;

        msg_debug_print("conf_parse_all(): ret = %d\n", ret);

        msg_debug_print("verbose = %d\n", global->verbose);

        for (dbg_i = 0; processes != NULL && processes[dbg_i] != NULL;
                dbg_i++) {

            if (processes[dbg_i]->name != NULL)
                names = PLATON_FUNC(strdyn_implode_str)
                    (processes[dbg_i]->name, ", ");
            else
                names = strdup("-- N/A --");

            if (processes[dbg_i]->argv != NULL)
                argvs = PLATON_FUNC(strdyn_implode_str)
                    (processes[dbg_i]->argv, " ");
            else
                argvs = strdup("-- N/A --");

            msg_debug_print("Process %d\n", dbg_i);
            msg_debug_print("  NAMES: %s\n", names);
            msg_debug_print("  ARGVS: %s\n", argvs);

            free(names);
            free(argvs);
        }

        msg_debug_print("Indexes:\n");
        for (dbg_i = 0; dbg_i < start_idx_size; dbg_i++)
            msg_debug_print("  %d -> %d\n", dbg_i, start_idx[dbg_i]);
    }
#endif

    /*
     * Here are proccesses going to be added into new PROCTABLE.
     */

    if ((ptbl = proctable_create(0)) == NULL ||
            proctable_add_std_process(&ptbl) < 0) {
        msg_error_print("not enough memory\n");
        /* XXX: free structures */
        free(start_idx);
        free_global(&global);
        free_processes(&processes);
        return NULL;
    }

    if (add_processes_to_proctable(&ptbl, processes,
                start_idx_size, start_idx) < 0) {
        /* msg_error_print("not enough memory\n"); */
        /* XXX: free structures */
        proctable_destroy(&ptbl);
        free(start_idx);
        free_global(&global);
        free_processes(&processes);
        return NULL;
    }

    cfg = *global;

    free(start_idx);
    free_global(&global);
    free_processes(&processes);

    return ptbl;
} /* }}} */

    int
conf_cfgfile_parse(filename, global, processes)
    char                       *filename;
    struct conf_struct_global  **global;
    struct conf_struct_process ***processes;
{ /* {{{ */
    register int ret;
    int processes_size;
    CFG_CONTEXT cur_context;

    *processes = NULL;
    processes_size = 0;

    clear_global_cfg();
    clear_process_cfg();

    cfg_reset_context(global_context);
    cfg_reset_context(process_context);

    /* Start at first line (0) and parse to end (-1) */
    cfg_set_cfgfile_context(global_context, 0, -1, filename);
    cfg_set_cfgfile_context(process_context, 0, -1, filename);

    for (cur_context = global_context; ; ) {

        ret = cfg_parse(cur_context);

        if (ret != CFG_ERR_STOP_STR) {
#if DEBUG
            msg_debug_print("detected %s error %d in <%s>\n",
                    cur_context == process_context ? "process" : "global",
                    ret, cfg_get_cur_opt(cur_context));
#endif
            break;
        }
        else { /* Section boundaries detected */
            register int   section_no;
            register char *section_str;

            section_str = cfg_get_cur_opt(cur_context);
            section_no  = is_cfgfile_section(section_str);

            if (section_no > 0) {
                if (cur_context == process_context) {
                    if (! test_process_cfg_argv(filename)) {
                        ret = CFG_ERROR_STOP_STR;
                        cur_context = NULL;
                        break;
                    }
                    /* Adding to processes array */
                    if (! add_process_cfg_to_processes(processes,
                                &processes_size))
                        return CFG_ERR_NOMEM;

                    clear_process_cfg();
                }

                /* If section name is correct, set appropriate context and
                   continue with parsing on next line (it is that '+ 1'). */

                if (section_no == 1) { /* [Global] section */
                    cfg_set_cfgfile_context(global_context,
                            cfg_get_cur_idx(cur_context) + 1, -1, NULL);
                    cur_context = global_context;
                }
                else { /* [Process] section */
                    cfg_set_cfgfile_context(process_context,
                            cfg_get_cur_idx(cur_context) + 1, -1, NULL);
                    cur_context = process_context;
                }
            }
            else {
                msg_error_print("unknown section '%s' in config file '%s'\n",
                        section_str, filename);
                ret = CFG_ERROR_STOP_STR;
                cur_context = NULL;
                break;
            }
        }
    }

    /* Set returning parameters. */
    if (ret == CFG_OK) {
        if (cur_context == process_context) {
            if (! test_process_cfg_argv(filename))
                ret = CFG_ERROR_STOP_STR;
            else if (! add_process_cfg_to_processes(processes, &processes_size))
                return CFG_ERR_NOMEM;
        }
    }

    if (! add_global_cfg_to_global(global))
        return CFG_ERR_NOMEM;

    switch (ret) {
        case CFG_OK:
        case CFG_ERR_NOMEM:
        case CFG_ERR_FILE_NOT_FOUND:
        case CFG_ERR_STOP_STR_FOUND:
            break;
        default:
            print_cfg_error(cur_context);
            break;
    };

    return ret;
} /* }}} */

    int
conf_cmdline_parse(argc, argv, global, processes)
    int                        argc;
    char                       **argv;
    struct conf_struct_global  **global;
    struct conf_struct_process ***processes;
{ /* {{{ */
    register int ret = CFG_OK, first_loop, index;
    int processes_size;
    CFG_CONTEXT cur_context;

    *processes = NULL;
    processes_size = 0;

    clear_global_cfg();
    clear_process_cfg();

    cfg_reset_context(global_context);
    cfg_reset_context(process_context);

    cfg_set_cmdline_context(global_context, 0, argc, argv);
    cfg_set_cmdline_context(process_context, 0, argc, argv);

    /*
     * Yokotasi intelligent parser. :-)
     */

    for (cur_context = process_context, first_loop = 1, index = 0;
            index < argc; first_loop = 0) {

        ret = cfg_parse(cur_context);

        if (ret < 0 && ret != CFG_ERR_STOP_STR_FOUND) {
            if (! first_loop)
                break;

            cur_context = global_context;
            /* not needed:
               cfg_set_cmdline_context_by_argc(cur_context, argc, argv); */
            continue;
        }
        else if (ret == CFG_ERR_STOP_STR_FOUND) {
            register int cur_idx = cfg_get_cur_idx(cur_context);

            if (cur_idx - index < 1 && ! first_loop) {
                msg_error_print("double process separator '--'"
                        " on command line\n");
                break;
            }

            if (cur_idx + 1 >= argc) {
                msg_error_print("misplaced process separator '--'"
                        " at the end of command line\n");
                break;
            }

            if (cur_context == process_context) {
                if (first_loop && process_cfg.argv == NULL) {
                    /* empty global options (./ep -- ...) are allowed */
                }
                else {
                    if (! test_process_cfg_argv(NULL)) {
                        ret = CFG_ERROR_STOP_STR;
                        break;
                    }

                    /* Adding to processes array */
                    if (! add_process_cfg_to_processes(processes,
                                &processes_size))
                        return CFG_ERR_NOMEM;

                }

                clear_process_cfg();
            }

            index = cur_idx + 1;
            cur_context = process_context;
            cfg_set_cmdline_context(cur_context, index, argc - index, argv);
        }
        else { /* ret == CFG_OK */
            break;
        }
    }

    /* Set returning parameters. */
    if (cur_context == process_context
            && ret == CFG_OK
            && cfg_get_cur_idx(cur_context) > 0) {
        if (! test_process_cfg_argv(NULL))
            ret = CFG_ERROR_STOP_STR;
        else if (! add_process_cfg_to_processes(processes, &processes_size))
            return CFG_ERR_NOMEM;
    }

    if (! add_global_cfg_to_global(global))
        return CFG_ERR_NOMEM;

    switch (ret) {
        case CFG_OK:
        case CFG_ERR_NOMEM:
        case CFG_ERR_STOP_STR_FOUND:
            break;
        default:
            print_cfg_error(cur_context);
            break;
    };

    return ret;
} /* }}} */

/*
 * Static function definitions
 */

    static void
print_cfg_error(con)
    const CFG_CONTEXT con;
{ /* {{{ */
    register char *s;

    if ((s = cfg_get_error_str(con)) == NULL) {
        msg_error_print("not enough memory for error message creating\n");
        return;
    }

    msg_error_print("%s\n", s);
    free(s);

    return;
} /* }}} */

/* Test if argv was specified */
    static int
test_process_cfg_argv(config_filename)
    const char *config_filename;
{ /* {{{ */
    if (process_cfg.argv == NULL) {

        if (process_cfg.name != NULL && process_cfg.name[0]) {
            /* At least one process name is defined in this case */
            if (config_filename != NULL)
                msg_error_print("process '%s' has not"
                        " 'command' clausule in config file '%s'\n",
                        process_cfg.name[0],
                        config_filename);
            else
                msg_error_print("process '%s' has not specified"
                        " what to run on command line\n",
                        process_cfg.name[0]);
        }
        else {
            /* No process name is defined in this case */
            if (config_filename != NULL)
                msg_error_print("some process has not"
                        " 'command' clausule in config file '%s'\n",
                        config_filename);
            else
                msg_error_print("some process has not specified"
                        " what to run on command line\n");
        }

        return 0;
    }

    return 1;
} /* }}} */

    static char *
get_user_config_filename(void)
{ /* {{{ */
    register char *homedir, *filename;

    if ((homedir = getenv("HOME")) == NULL)
        return strdup(conf_user_filename);

    filename = (char *) malloc((strlen(homedir)
                + strlen(conf_user_filename) + 2) * sizeof(char));
    if (filename == NULL)
        return NULL;

    strcpy(filename, homedir);
    if (strlen(filename) > 0 && filename[strlen(filename) - 1] != '/')
        strcpy(filename + strlen(filename), "/");

    strcpy(filename + strlen(filename), conf_user_filename);

    return filename;
} /* }}} */

    static void
clear_global_cfg(void)
{ /* {{{ */
    memset((void *) &global_cfg, '\0',
            sizeof(struct conf_struct_global));
} /* }}} */

    static void
clear_process_cfg(void)
{ /* {{{ */
    memset((void *) &process_cfg, '\0',
            sizeof(struct conf_struct_process));
} /* }}} */

    static int
check_context(context, options)
    CFG_CONTEXT       *context;
    struct cfg_option options[];
{ /* {{{ */
    if (*context == NULL) {
        if ((*context = cfg_get_context(options)) == NULL)
            return 0;

        cfg_set_context_flag(*context, CFG_PROCESS_FIRST);
        cfg_clear_context_flag(*context, CFG_SKIP_FIRST);
        cfg_set_context_flag(*context, CFG_FILE_LINE_POS_USAGE);

        /* TODO: one call for multi vals properties */
        cfg_clear_property(*context, CFG_LINE_STOP_STRING);
        cfg_clear_property(*context, CFG_MULTI_VALS_SEPARATOR);
        cfg_clear_property(*context, CFG_FILE_STOP_PREFIX);

        if (! cfg_add_property(*context, CFG_LINE_STOP_STRING, "--")
                || ! cfg_add_property(*context,
                    CFG_NORMAL_MULTI_VALS_SEPARATOR, ",")
                || ! cfg_add_property(*context,
                    CFG_FILE_LEFTOVER_MULTI_VALS_SEPARATOR, " ")
                || ! cfg_add_property(*context,
                    CFG_FILE_STOP_PREFIX, section_boundaries[0]))
            return 0;
    }

    return 1;
} /* }}} */

    static int
is_cfgfile_section(section_str)
    char *section_str;
{ /* {{{ */
    register int secstr_size = strlen(section_str);
    register int secb0_size  = strlen(section_boundaries[0]);
    register int secb1_size  = strlen(section_boundaries[1]);

    register int ret = 0;

    if (secstr_size > secb0_size + secb1_size
            && ! strncmp(section_str, section_boundaries[0], secb0_size)
            && ! strncmp(section_str + secstr_size - secb1_size,
                section_boundaries[1], secb1_size))
    {
        register char *pos = section_str + secb0_size;

        while (isspace(*pos))
            pos++;

        if (! strncasecmp(global_str, pos, strlen(global_str))) {
            pos += strlen(global_str);
            ret = 1;
        }
        else if (! strncasecmp(process_str, pos, strlen(process_str))) {
            pos += strlen(process_str);
            ret = 2;
        }

        while (ret > 0 && pos < section_str + secstr_size - secb1_size)
            if (isspace(*pos))
                pos++;
            else
                ret = 0;
    }

    return ret;
} /* }}} */

    static void
free_global(global)
    struct conf_struct_global **global;
{ /* {{{ */
    if (*global == NULL)
        return;

    PLATON_FUNC(strdyn_safe_free)((*global)->config_file);

    free(*global);
    *global = NULL;
} /* }}} */

    static void
free_processes(processes)
    struct conf_struct_process ***processes;
{ /* {{{ */
    register int i, j;

    if (*processes == NULL)
        return;

    for (i = 0; (*processes)[i] != NULL; i++) {
        PLATON_FUNC(strdyn_safe_free)((*processes)[i]->name);
        PLATON_FUNC(strdyn_safe_free)((*processes)[i]->argv);

        for (j = 0; j < N_FD; j++)
            PLATON_FUNC(strdyn_safe_free)((*processes)[i]->fd_str[j]);

        free((*processes)[i]);
    }

    free(*processes);
    *processes = NULL;
} /* }}} */

    static int
get_processes_index_by_name(processes, name)
    struct conf_struct_process **processes;
    char                       *name;
{ /* {{{ */
    register int i;

    for (i = 0; processes != NULL && processes[i] != NULL; i++)
        if (processes[i]->name != NULL
                && ! PLATON_FUNC(strdyn_casecmp)(processes[i]->name, name))
            return i;

    return -1;
} /* }}} */

    static int
add_global_cfg_to_global(global)
    struct conf_struct_global **global;
{ /* {{{ */
    *global = (struct conf_struct_global *)
        malloc(sizeof(struct conf_struct_global));
    if (*global == NULL)
        return 0;

    **global = global_cfg;

    return 1;
} /* }}} */

    static int
add_process_cfg_to_processes(processes, size)
    struct conf_struct_process ***processes;
    int                        *size;
{ /* {{{ */
    register int items;

    for (items = 0; *processes != NULL && (*processes)[items] != NULL; items++)
        ;

    if (items + 1 >= *size) {

#if DEBUG /* minimum increment value is 2 */
        *size += 2;
#else
        *size += 10;
#endif
        *processes = (struct conf_struct_process **)
            realloc(*processes, sizeof(struct conf_struct_process*) * (*size));

        if (*processes == NULL)
            return 0;
    }

    (*processes)[items] = (struct conf_struct_process *)
        malloc(sizeof(struct conf_struct_process));
    if ((*processes)[items] == NULL)
        return 0;

    *((*processes)[items]) = process_cfg;
    (*processes)[items + 1] = NULL;

    return 1;
} /* }}} */

    static int
add_processes_to_processes(dest_processes, src_processes)
    struct conf_struct_process ***dest_processes;
    struct conf_struct_process **src_processes;
{ /* {{{ */
    register int i, dest_size, src_size;

    if (dest_processes == NULL)
        return 0;

    for (i = 0; *dest_processes != NULL && (*dest_processes)[i] != NULL; i++)
        ;
    dest_size = i;

    for (i = 0; src_processes != NULL && src_processes[i] != NULL; i++)
        ;
    src_size = i;

    *dest_processes = (struct conf_struct_process **) realloc(*dest_processes,
            sizeof(struct conf_struct_process*) * (dest_size + src_size + 1));
    if (*dest_processes == NULL)
        return 0;

    for (i = 0; i < src_size; i++)
        (*dest_processes)[dest_size + i] = src_processes[i];

    (*dest_processes)[dest_size + src_size] = NULL;

    return 1;
} /* }}} */

/*
 * XXX: TODO: FIXME: reindexing proctable! remove +1 above too
 */

    static int
add_processes_to_proctable(p_ptbl, processes, start_idx_size, start_idx)
    PROCTABLE                  *p_ptbl;
    struct conf_struct_process **processes;
    int                        start_idx_size;
    int                        *start_idx;
{ /* {{{ */
    register int i, j, k, idx;
    register int resource_idx = 0;
    register int ptbl_size, new_ptbl_size;
    PROCTABLE new_ptbl;

    ptbl_size = proctable_get_size(*p_ptbl);

    for (new_ptbl_size = 0; processes != NULL
            && processes[new_ptbl_size] != NULL; new_ptbl_size++)
        ;
#if DEBUG
    msg_debug_print("add_processes_to_proctable():"
            " ptbl_size = %d, new_ptbl_size = %d\n",
            ptbl_size, new_ptbl_size);
#endif

    if ((new_ptbl = proctable_create(new_ptbl_size)) == NULL) {
        msg_error_print("not enough memory for process table creation\n");
        return -1;
    }

    for (i = 0; i < new_ptbl_size; i++) {

        /* Counting resource_idx. */
        while (resource_idx < start_idx_size - 1
                && start_idx[resource_idx + 1] <= i)
            resource_idx++;

        /* Checking processes names. */
        for (j = 0; processes[i]->name != NULL
                && processes[i]->name[j] != NULL; j++) {
            idx = proctable_get_process_index_by_name(
                    *p_ptbl, processes[i]->name[j]);
            if (idx >= 0) {
                msg_error_print("process %d from resource %d (%s) already"
                        " exists in process table with index %d\n",
                        j - start_idx[resource_idx], resource_idx,
                        processes[i]->name[j], idx);
                return -1;
            }
        }

        new_ptbl[i]->pid  = 0;
        new_ptbl[i]->nice = processes[i]->nice;
        new_ptbl[i]->name = PLATON_FUNC(strdyn_safe_duplicate)
            (processes[i]->name);
        new_ptbl[i]->argv = PLATON_FUNC(strdyn_safe_duplicate)
            (processes[i]->argv);

        /* Converting filedescriptors strings to indexes. */
        for (j = 0; j < N_FD; j++) {
            register int size = processes[i]->fd_str[j] == NULL
                ? 0 : PLATON_FUNC(strdyn_get_size)(processes[i]->fd_str[j]);

            new_ptbl[i]->fd[j].n_link  = 0;
            new_ptbl[i]->fd[j].pipe[0] = 0;
            new_ptbl[i]->fd[j].pipe[1] = 0;

            for (k = 0; k < size; k++) {
                struct proclink link;
                char **ar;
                register char *fd_str = NULL, *char_in_name;

                if (strlen(processes[i]->fd_str[j][k]) <= 0)
                    continue;

                ar = PLATON_FUNC(strdyn_explode2_ar)(processes[i]->fd_str[j][k],
                        name_vs_stream_separator);

                if (ar == NULL) {
                    msg_error_print("not enough memory"
                            " for link argument exploding\n");
                    proctable_destroy(&new_ptbl);
                    return -1;
                }

                switch (PLATON_FUNC(strdyn_get_size)(ar)) {
                    case 1:
                        link.proc_id = 0;
                        fd_str = ar[0];
                        break;

                    case 2:

                        for (char_in_name = ar[0];
                                isdigit(*char_in_name);
                                char_in_name++)
                            ;

                        fd_str = ar[1];

                        /*
                         * Process link initialization by local number
                         */

                        if (*char_in_name == '\0') {
                            char *end;
                            link.proc_id = (int) strtol(ar[0], &end, 0);

                            if ((end && *end == '\0') && link.proc_id >= 0) {
                                if (link.proc_id == 0) /* 0 is always valid */
                                    break;

                                if (link.proc_id > 0) {
                                    link.proc_id--; /* make real index */

                                    if (link.proc_id <=
                                            start_idx[resource_idx + 1]
                                            - start_idx[resource_idx] - 1) {

                                        link.proc_id += ptbl_size;
                                        link.proc_id += start_idx[resource_idx];
                                        break;
                                    }
                                }
                            }

                            msg_error_print("bad process number '%s'\n", ar[0]);
                            proctable_destroy(&new_ptbl);
                            PLATON_FUNC(strdyn_free)(ar);
                            return -1;
                        }

                        /*
                         * Process link initialization by name
                         */

                        /* Searching name in original (old) proctable. */
                        link.proc_id = proctable_get_process_index_by_name(
                                *p_ptbl, ar[0]);

                        if (link.proc_id >= 0)
                            break;

                        /* Searching name in existing new proctable.
                         * THIS IS ABSOLUTELY WRONG!
                         * You cannot search proctable which is not already
                         * built!

                         link.proc_id = proctable_get_process_index_by_name(
                         new_ptbl, ar[0]);

                         if (link.proc_id >= 0) {
                         link.proc_id += ptbl_size;
                         break;
                         }
                         */

                        /* Searching name in processes. */
                        link.proc_id = get_processes_index_by_name(
                                processes, ar[0]);

                        if (link.proc_id >= 0) {
                            link.proc_id += ptbl_size;
                            /* link.proc_id += start_idx[resource_idx]; */
                            break;
                        }

                        msg_error_print("bad process name '%s'\n", ar[0]);
                        proctable_destroy(&new_ptbl);
                        PLATON_FUNC(strdyn_free)(ar);
                        return -1;

                    default:
                        msg_error_print("bad link specification: %s\n",
                                processes[i]->fd_str[j][k]);
                        proctable_destroy(&new_ptbl);
                        PLATON_FUNC(strdyn_free)(ar);
                        return -1;
                }

                link.fd_id = fd_str_to_fd_id(fd_str);
                PLATON_FUNC(strdyn_free)(ar); /* fd_str points to ar[] */
                if (link.fd_id < 0) {
                    msg_error_print("bad stream specification '%s'\n", fd_str);
                    proctable_destroy(&new_ptbl);
                    return -1;
                }

                if (! fd_add_proclink(&(new_ptbl[i]->fd[j]), &link)) {
                    msg_error_print("not enought memory for"
                            " process link addition\n");
                    proctable_destroy(&new_ptbl);
                    return -1;
                }
            }
        }
    }

    if (! proctable_join(p_ptbl, new_ptbl)) {
        msg_error_print("not enought memory for process table resize\n");
        proctable_destroy(&new_ptbl);
        return -1;
    }

    return 0;
} /* }}} */

/* Modeline for ViM {{{
 * vim:set ts=4:
 * vim600:fdm=marker fdl=0 fdc=0:
 * }}} */


Platon Group <platon@platon.sk> http://platon.sk/
Copyright © 2002-2006 Platon Group
Stránka používa redakčný systém Metafox
Na začiatok