Update of /cvsroot/alsa/alsa-tools/envy24control
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv30112

Added Files:
        README.profiles new_process.c profiles.c profiles.h 
Log Message:
Added missing files for profile patch


--- NEW FILE: README.profiles ---
                Profiles management as part of alsa
                2004-05-16 Dirk Kalis <[EMAIL PROTECTED]>

General
=======

Profiles management can be used from all applications like mixers or hardware control 
programs.
It uses always alsactl and if directorys for the profiles file doesn't exists - mkdir.
profiles file means the file in which the profiles will be stored.
For other application the following files are needed:
profiles.h - header file with the exported functions
profiles.c - profiles implementation
new_process.c - used to start external programs (alsactl and mkdir)
strstr_icase_blank.c - string search function with ignoring case sensitivity, number 
of blanks, empty and
                        comment lines (first non blank character '#')
Profile numbers beginning with number 1 not 0 !

Introduction
============

Profiles management stores and restores alsactl settings in a profiles file.
Every card is stored in the profiles and every card profile can have a profile name.
The profiles file has the following structure:

[ profile <profile number> ]
< Card <card number> >
{ /<profile name/ }
***************************
***   alsactl settings  ***
***************************
< /CARD <card number> >
-----next card or next profile or end of file-----

The header for profile name and card footer are optional.
The functions in profile.c write always a card footer.

DO NOT EDIT THIS FILE MANUALLY BECAUSE EVERY WRITE ACCESS MAKE A REORGANIZATION AND 
COMMENTS NOT WRITTEN IN
THE ALSACTL SECTION WILL BE REMOVED! ALSO THE STRUCTURE OF THE FILE WILL BE MODIFIED!

With the environment variables ALACTL_PROG and MKDIR_PROG can the compiled defaults 
for this
programs be overwritten.
e.g.:
export ALSACTL_PROG=<path and name from alsactl>;export MKDIR_PROG=<path and name from 
mkdir>;<mixer program with profiles management>

This pathes must not be a link !

The profiles file name and path can explicit given.
If is not given (by value NULL) two defined defaults will be used.
Two variables can be set in the profiles header file for the default profiles file and 
for the system profiles file.
The default for DEFAULT_PROFILERC is ~/<program name>/profiles.conf.
The default for SYS_PROFILERC is /etc/<program name>/profiles.conf

The profiles management search for profiles file if no profiles file name is given.
Search order for restore:
<given profiles file> if not -> <DEFAULT_PROFILERC> if doesn't exists -> 
<SYS_PROFILERC>

Search order for save:
<given profiles file> if not -> <DEFAULT_PROFILERC>

The SYS_PROFILERC can only be written as root by explicit given profiles file name or
you make a copy as root from one of the DEFAULT_PROFILERC.

This files must not be a link!

The delete_card function can be used to remove card profiles from profiles file if a 
card is removed from your pc.

Miscellaneous cards can have same profile names - thats no problem.
One card with equal profile names is also no problem if you use profile number for 
searching.
If you use profile name for searching you will allways get the least profile number 
with this profile name.

Profiles management in envy24control
====================================

In envy24control you can find a new map named "Profiles".
In this map you can store 8 profiles for every envy24 card.
You can change/give name by activating this profile and then click in the name entry.
You can only change the name for the active profile.
If all settings in the active profile are done you can save settings by clicking 
button "Save active profile".
Error messages will only displayed on stderr in the text window if you start 
envy24control from xterm.

To activate a profile click only the profile button.

You can start envy24control with given profiles file and a default profile. if a 
default profile is given
after initialisation of envy24control this profile will be activated.
Default profile can be given by profile number or profile name.
The accuracy of discrimination works in the following way:
        - if the given default profile contains a letter -> profile name
        - if the given default profile has a number outside the range [1 ... 
MAX_PROFILES] -> profile name
        - the given default profile is interpreted as profile number.

Profile names should have at least one letter.

For "Delete card from profiles" and equal profile names read above.
One card with equal names is only a problem if you start envy24control with default 
profile name. You activate
allways the profile with the least profile number with this profile name.

Copyright
=========

Copyright Dirk Kalis<[EMAIL PROTECTED]>
This is free and can be distributed under GPL.

--- NEW FILE: new_process.c ---
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#ifndef MAX_PARAM
#define MAX_PARAM 10
#endif

/*
 * start child process
 */
int new_process(char * const cmd_line[MAX_PARAM])
{
        int proc_status;
        pid_t pid;
        pid_t w;
        struct stat file_status;

        /* memory for storage of function pointers from the signal handling routines */
        void (*int_stat)();
        void (*quit_stat)();
        void (*usr2_stat)();

        /*
         * check command file
         */

        /* search file */
        if (stat(cmd_line[0], &file_status) < 0) {
                fprintf(stderr, "Cannot find program '%s'.\n", cmd_line[0]);
                fprintf(stderr, "You must specify path for '%s'.\n", cmd_line[0]);
                return -errno;
        }

        proc_status = 0;
        /* check file status and permissions */
        if (file_status.st_mode & S_IFREG) {
                if (!(file_status.st_mode & S_IXOTH)) {
                        if (!(file_status.st_mode & S_IXGRP)) {
                                if (!(file_status.st_mode & S_IXUSR)) {
                                        proc_status = -EACCES;
                                } else if (file_status.st_uid != getuid()) {
                                        proc_status = -EACCES;
                                }
                        } else if ((file_status.st_gid != getgid()) && 
(file_status.st_uid != getuid())) {
                                proc_status = -EACCES;
                        }
                }
        } else {
                proc_status = -EACCES;
        }
                
        if (proc_status != 0) {
                fprintf(stderr, "No permissions to execute program '%s'.\n", 
cmd_line[0]);
                return proc_status;
        }

        if ( (pid = fork() ) == 0) {
                execv(cmd_line[0], cmd_line);
        }

        /* for waiting ingnoring special interrupts */

        int_stat = signal(SIGINT, SIG_IGN);
        quit_stat = signal(SIGQUIT, SIG_IGN);
        usr2_stat = signal(SIGUSR2, SIG_IGN);

        /* waiting for the end of the child process */

        while ( ( (w = wait(&proc_status)) != pid ) && (w != -1) )
                ;
        if (w == -1) {
                proc_status = -errno;
        }

        /* restore pointers from signal handling routines */

        signal(SIGINT, int_stat);
        signal(SIGQUIT, quit_stat);
        signal(SIGUSR2, usr2_stat);

        return proc_status;
}

--- NEW FILE: profiles.c ---
/*
 *  Advanced Linux Sound Architecture part of envy24control
 *  handle profiles for envy24control using alsactl
 * 
 *  Copyright (c) by Dirk Kalis <[EMAIL PROTECTED]>
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

#define __PROFILES_C__
#include "envy24control.h"
#undef __PROFILES_C__

/* include string search function */
#include "strstr_icase_blank.c"

/* include forking process function */
#include "new_process.c"

/* replace tilde with home directory */
static char filename_without_tilde[MAX_FILE_NAME_LENGTH];

static char profile_name[PROFILE_NAME_FIELD_LENGTH];

/*
 * check the environment and use the set variables
 */
char *check_environment(const char * const env_var, char * const var)
{
        if ( (char *)getenv(env_var) == NULL )
                return var;
        return (char *)getenv(env_var);
}

/* replace tilde with home directory by checking HOME environment variable */
void subst_tilde_in_filename(char * const filename)
{
        char new_filename[MAX_FILE_NAME_LENGTH];
        char *pos_after_tilde;

        if ((pos_after_tilde = strchr(filename, '~')) != NULL) {
                pos_after_tilde++;
                strncpy(new_filename, getenv("HOME"), MAX_FILE_NAME_LENGTH);
                strncpy(new_filename + strlen(new_filename), pos_after_tilde, 
MAX_FILE_NAME_LENGTH - strlen(new_filename));
                new_filename[MAX_FILE_NAME_LENGTH - 1] = '\0';
                strncpy(filename, new_filename, MAX_FILE_NAME_LENGTH);
        }
}


int which_cfgfile(char ** const cfgfile)
{
        int res;
        FILE *inputFile;

        strncpy(filename_without_tilde, *cfgfile, MAX_FILE_NAME_LENGTH);
        filename_without_tilde[MAX_FILE_NAME_LENGTH - 1] = '\0';
        subst_tilde_in_filename(filename_without_tilde);
        if ((inputFile = fopen(filename_without_tilde, "r")) == NULL) {
                if ((*cfgfile != DEFAULT_PROFILERC) && (*cfgfile != SYS_PROFILERC)) {
                        res = -ENOENT;
                } else if ((*cfgfile == DEFAULT_PROFILERC) && ((inputFile = 
fopen(SYS_PROFILERC, "r")) == NULL)) {
                        res = -ENOENT;
                } else {
                        fclose(inputFile);
                        *cfgfile = SYS_PROFILERC;
                        res = EXIT_SUCCESS;
                }
        } else {
                fclose(inputFile);
                *cfgfile = filename_without_tilde;
                res = EXIT_SUCCESS;
        }
        return res;
}

int get_file_size(const char * const filename)
{
        struct stat file_status;

        strncpy(filename_without_tilde, filename, MAX_FILE_NAME_LENGTH);
        filename_without_tilde[MAX_FILE_NAME_LENGTH - 1] = '\0';
        subst_tilde_in_filename(filename_without_tilde);
        if (stat(filename_without_tilde, &file_status) < 0) {
                fprintf(stderr, "Cannot find file '%s'.\n", filename);
                return -errno;
        }

        return (int)file_status.st_size;
}

int read_profiles_in_buffer(const char * const cfgfile, void * const buffer, const 
size_t max_length)
{
        int res;
        int inputFile;

        if ((inputFile = open(cfgfile, O_RDONLY)) < 0) {
                fprintf(stderr, "warning: can't open profiles file '%s' for 
reading.\n", cfgfile);
                return -errno;
        }
        res = read(inputFile, buffer, max_length);
        close(inputFile);
        *(char *)(buffer + max_length - 1) = '\0';
        if (res == max_length) {
                fprintf(stderr, "warning: profiles file '%s' has maximum size 
reached.\n", cfgfile);
                fprintf(stderr, "\tThe defined value for MAX_PROFILE_SIZE must be 
increased in 'profiles.h'.\n");
                fprintf(stderr, "\tThen you must recompile the '%s' tool.\n", 
PROGRAM_NAME);
                fprintf(stderr, "\tThe current value is %d.\n", MAX_PROFILE_SIZE);
        }

        return res;
}

/*
 * write buffer with max_length to cfgfile
 * with introduction if with_intro != 0
 */
int write_profiles_from_buffer(const char * const cfgfile, const void * const buffer, 
const size_t max_length, const int with_intro)
{
        int res, length;
        time_t date_time[MAX_NUM_STR_LENGTH];
        char introduction_part[MAX_SEARCH_FIELD_LENGTH];
        int outputFile;

        if ((outputFile = open(cfgfile, O_WRONLY | O_CREAT | O_TRUNC | 0400000 /* 
O_NOFOLLOW */, FILE_CREA_MODE)) < 0) {
                fprintf(stderr, "warning: can't open profiles file '%s' for 
writing.\n", cfgfile);
                return -errno;
        }
        length = max_length > strlen(buffer) ? strlen(buffer) : max_length;
        time(date_time);
        snprintf(introduction_part, MAX_SEARCH_FIELD_LENGTH, 
"%s'%s'%s%s%s'%s'%s%s%s%s%s%s%s%s%s\n", \
                                                        "#\n" \
                                                        "# This file is automatically 
generated by ", PROGRAM_NAME, " at ", \
                                                                                       
 (char *) asctime(localtime(date_time)), \
                                                        "# Do not edit this file 
manually. This file will be permanently overwritten.\n" \
                                                        "# Use ", PROGRAM_NAME, " to 
modify and store settings.\n" \
                                                        "#\n" \
                                                        "# File-Structure:\n" \
                                                        "# ", PROFILE_HEADER_TEMPL, 
"\t\t- profile header\n" \
                                                        "#\t", CARD_HEADER_TEMPL, "\t- 
card header\n" \
                                                        "#\t", PROFILE_NAME_TEMPL, 
"\t\t- profile name - optional\n" \
                                                        
"#\t\t***********************************\n" \
                                                        "#\t\t***** ALSA code for this 
card *****\n" \
                                                        
"#\t\t***********************************\n" \
                                                        "#\t", CARD_FOOTER_TEMPL, "\t- 
card footer\n" \
                                                        "#\n");

        introduction_part[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        if (with_intro)
                res = write(outputFile, introduction_part, strlen(introduction_part));
        res = write(outputFile, buffer, length);
        close(outputFile);
        if (res < 0) {
                fprintf(stderr, "warning: can't write profiles file '%s'.\n", cfgfile);
        }

        return res;
}

int create_dir_from_filename(const char * const filename)
{
        int res;
        char pathname[MAX_FILE_NAME_LENGTH];
        char * parameter[MAX_PARAM];
        char *mkdir;

        mkdir = check_environment("MKDIR_PROG", MKDIR);

        strncpy(pathname, filename, MAX_FILE_NAME_LENGTH);
        pathname[MAX_FILE_NAME_LENGTH - 1] = '\0';

        *strrchr(pathname, '/') = '\0';
        subst_tilde_in_filename(pathname);
        
        parameter[0] = mkdir;
        parameter[1] = "-p";
        parameter[2] = "-m";
        parameter[3] = DIR_CREA_MODE;
        parameter[4] = pathname;
        parameter[5] = NULL;
        
        res = new_process(parameter);
        
        return res;
}

int compose_search_string(char * const search_string, const char * const templ, const 
char * const value, const char place_holder, const int max_length)
{
        int res;
        char *pos_place_holder;

        memset(search_string, '\0', max_length);
        strncpy(search_string, templ, max_length);
        search_string[max_length - 1] = '\0';
        if ((pos_place_holder = strchr(search_string, place_holder)) == NULL) {
                res = NOTFOUND;
                return res;
        }
        strncpy(pos_place_holder, value, max_length - strlen(search_string));
        strncpy(pos_place_holder + strlen(value), \
                        strchr(templ, place_holder) \
                                + sizeof(char), \
                        max_length - strlen(search_string));
        search_string[max_length - 1] = '\0';
        res = EXIT_SUCCESS;
        
        return res;
}

/* search backwards first newline - start of line is position after newline */
int get_start_of_line(const char * const buffer, const int offset)
{
        int begin_of_line;

        for (begin_of_line = offset; begin_of_line >= 0; begin_of_line--)
        {
                if (buffer[begin_of_line] == '\n')
                        break;
        }
        begin_of_line++;

        return begin_of_line;
}

/*
 * search tokens sequential for the furthest token backwards from section_end
 * tokens should be specified from nearest token to the furthest
 */
int get_begin_of_section(const char * const buffer, char * const section_tokens, const 
char * const token_sep, const int section_end)
{
        char *search_token;
        int pos_start_of_section, pos_end_of_section, pos_end_of_search;

        search_token = strtok(section_tokens, token_sep);

        pos_end_of_search = section_end;
        do
        {
                pos_start_of_section = 0;
                pos_end_of_section = 0;
                while ((pos_start_of_section = strstr_icase_blank(buffer + 
pos_end_of_section, search_token)) < pos_end_of_search - pos_end_of_section)
                {
                        if (pos_start_of_section < 0)
                                break;
                        pos_end_of_section += pos_start_of_section;
                        pos_end_of_section++;
                }
                pos_end_of_section--;
                pos_start_of_section = pos_end_of_section;
                pos_end_of_search = pos_end_of_section;
                if (pos_start_of_section < 0) {
                        pos_start_of_section = NOTFOUND;
                        // fprintf(stderr, "Begin of section for '%s' can't be 
found\n", search_token);
                        return pos_start_of_section;
                }
        } while ((search_token = strtok(NULL, token_sep)) != NULL);

        return pos_start_of_section;
}

/*
 * search tokens sequential for the nearest token from section_begin
 * tokens should be specified from furthest token to the nearest
 */
int get_end_of_section(const char * const buffer, char * const section_tokens, const 
char * const token_sep, const int section_begin)
{
        char *search_token;
        int pos_end_of_section, pos_end_of_search;

        search_token = strtok(section_tokens, token_sep);

        pos_end_of_section = strlen(buffer);
        do
        {
                pos_end_of_search = strstr_icase_blank(buffer + section_begin, 
search_token);
                if (!((pos_end_of_search < 0) || (pos_end_of_search > 
pos_end_of_section))) {
                        pos_end_of_section = pos_end_of_search;
                }
        } while ((search_token = strtok(NULL, token_sep)) != NULL);

        return pos_end_of_section == strlen(buffer) ? pos_end_of_section : 
pos_end_of_section + section_begin;
}

int get_profile_begin(const char * const buffer, const int profile_number)
{
        char header[MAX_SEARCH_FIELD_LENGTH], 
profile_or_card_number_as_str[MAX_NUM_STR_LENGTH];
        char place_holder;

        /* compose profile header */
        place_holder = PLACE_HOLDER_NUM;
        snprintf(profile_or_card_number_as_str, MAX_NUM_STR_LENGTH, "%d", 
profile_number);
        profile_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';
        compose_search_string(header, PROFILE_HEADER_TEMPL, 
profile_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        return strstr_icase_blank(buffer, header);
}

int get_profile_end(const char * const buffer, const int profile_number)
{
        char header[MAX_SEARCH_FIELD_LENGTH];
        char place_holder;
        int pos_profile_begin;

        if ((pos_profile_begin = get_profile_begin(buffer, profile_number)) < 0)
                return pos_profile_begin;
        place_holder = PLACE_HOLDER_NUM;
        strncpy(header, PROFILE_HEADER_TEMPL, MAX_SEARCH_FIELD_LENGTH);
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        *strchr(header, place_holder) = '\0';
        return get_end_of_section(buffer, header, TOKEN_SEP, pos_profile_begin + 
sizeof(char));
}

int get_card_begin(const char * const buffer, const int profile_number, const int 
card_number)
{
        char header[MAX_SEARCH_FIELD_LENGTH], 
profile_or_card_number_as_str[MAX_NUM_STR_LENGTH];
        char place_holder;
        int pos_profile_begin, pos_profile_end, pos_card_begin;

        if ((pos_profile_begin = get_profile_begin(buffer, profile_number)) < 0)
                return pos_profile_begin;
        pos_profile_end = get_profile_end(buffer, profile_number);

        /* compose card header */
        place_holder = PLACE_HOLDER_NUM;
        snprintf(profile_or_card_number_as_str, MAX_NUM_STR_LENGTH, "%d", card_number);
        profile_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';
        compose_search_string(header, CARD_HEADER_TEMPL, 
profile_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        if ((pos_card_begin = strstr_icase_blank(buffer + pos_profile_begin, header)) 
< 0)
                return pos_card_begin;
        if ((pos_card_begin += pos_profile_begin) > pos_profile_end)
                return NOTFOUND;
        return pos_card_begin;
}

int get_card_end(const char * const buffer, const int profile_number, const int 
card_number)
{
        char header[MAX_SEARCH_FIELD_LENGTH], 
profile_or_card_number_as_str[MAX_NUM_STR_LENGTH];
        char place_holder;
        int pos_card_begin;

        if ((pos_card_begin = get_card_begin(buffer, profile_number, card_number)) < 0)
                return pos_card_begin;
        /* searching "[ profile | < card | < /card # >" */
        /* add "[ profile |" to search_field */
        place_holder = PLACE_HOLDER_NUM;
        snprintf(profile_or_card_number_as_str, MAX_NUM_STR_LENGTH, "%d", card_number);
        profile_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';
        strncpy(header, PROFILE_HEADER_TEMPL, MAX_SEARCH_FIELD_LENGTH);
        *strchr(header, place_holder) = '\0';
        strncpy(header + strlen(header), TOKEN_SEP, MAX_SEARCH_FIELD_LENGTH - 
strlen(header));
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        /* add "< card |" to header */
        strncpy(header + strlen(header), CARD_HEADER_TEMPL, MAX_SEARCH_FIELD_LENGTH - 
strlen(header));
        *strchr(header, place_holder) = '\0';
        strncpy(header + strlen(header), TOKEN_SEP, MAX_SEARCH_FIELD_LENGTH - 
strlen(header));
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        /* add "< /card # >" to header */
        compose_search_string(header + strlen(header), CARD_FOOTER_TEMPL, 
profile_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH - strlen(header));
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        return get_end_of_section(buffer, header, TOKEN_SEP, pos_card_begin + 
sizeof(char));
}

int get_pos_for_next_card(const char * const buffer, const int profile_number, const 
int card_number)
{
        char header[MAX_SEARCH_FIELD_LENGTH], 
profile_or_card_number_as_str[MAX_NUM_STR_LENGTH];
        char place_holder;
        int pos_next_card;

        if ((pos_next_card = get_card_end(buffer, profile_number, card_number)) < 0)
                return pos_next_card;
        /* add "< /card # >" to header */
        place_holder = PLACE_HOLDER_NUM;
        snprintf(profile_or_card_number_as_str, MAX_NUM_STR_LENGTH, "%d", card_number);
        profile_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';
        compose_search_string(header, CARD_FOOTER_TEMPL, 
profile_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        if (strstr_icase_blank(buffer + pos_next_card, header) == 0) {
                while((buffer[pos_next_card] != '\n') && (buffer[pos_next_card] != 
'\0'))
                        pos_next_card++;
                if (buffer[pos_next_card] == '\n')
                        pos_next_card++;
        }
        return pos_next_card;
}

int get_number_from_header(const char * const header_string)
{
        char string[MAX_SEARCH_FIELD_LENGTH];
        char number_string[MAX_NUM_STR_LENGTH];
        char *pos_number;

        strncpy(string, header_string, MAX_SEARCH_FIELD_LENGTH);
        string[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';

        if ((pos_number = strpbrk(string, "0123456789")) == NULL) {
                return -EINVAL;
        } else {
                strncpy(number_string, pos_number, MAX_NUM_STR_LENGTH);
                number_string[MAX_NUM_STR_LENGTH - 1] = '\0';
        }

        return atoi(number_string);
}

char *get_profile_name_from_header(const char * const header_string)
{
        char string[MAX_SEARCH_FIELD_LENGTH];
        char header_templ[MAX_SEARCH_FIELD_LENGTH];
        char left_name_border;

        memset(profile_name, '\0', PROFILE_NAME_FIELD_LENGTH);
        strncpy(string, header_string, MAX_SEARCH_FIELD_LENGTH);
        string[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        strncpy(header_templ, PROFILE_NAME_TEMPL, MAX_SEARCH_FIELD_LENGTH);
        header_templ[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        string[strstr_icase_blank(string, strchr(header_templ, PLACE_HOLDER_STR) + 
sizeof(char))] = '\0';
        left_name_border = *(strchr(header_templ, PLACE_HOLDER_STR) - sizeof(char));
        strncpy(profile_name, strchr(string + sizeof(char), left_name_border) + 
sizeof(char), PROFILE_NAME_FIELD_LENGTH);
        profile_name[PROFILE_NAME_FIELD_LENGTH - 1] = '\0';

        return profile_name;
}

/* search max card number in profile */
int get_max_card_number_in_profile(const char * const buffer, const int profile_number)
{
        char header[MAX_SEARCH_FIELD_LENGTH];
        char place_holder;
        int pos_card_next, pos_profile_end, pos_card_begin, card_number, 
card_number_max;

        place_holder = PLACE_HOLDER_NUM;
        card_number_max = NOTFOUND;
        strncpy(header, CARD_HEADER_TEMPL, MAX_SEARCH_FIELD_LENGTH);
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        *strchr(header, place_holder) = '\0';
        pos_card_next = get_profile_begin(buffer, profile_number);
        pos_profile_end = get_profile_end(buffer, profile_number);
        while ((pos_card_begin = strstr_icase_blank(buffer + pos_card_next, header)) 
>= 0)
        {
                if ((pos_card_begin += pos_card_next) > pos_profile_end)
                        break;
                pos_card_next = pos_card_begin + sizeof(char);
                card_number = get_number_from_header(buffer + pos_card_begin);
                if (card_number > card_number_max)
                        card_number_max = card_number;
        }
        return card_number_max;
}

int get_pos_name_header_from_card(const char * const buffer, const int profile_number, 
const int card_number)
{
        char header[MAX_SEARCH_FIELD_LENGTH];
        char place_holder;
        int pos_card_begin, pos_card_end, pos_name_header;

        pos_card_begin = get_card_begin(buffer, profile_number, card_number);
        pos_card_end = get_card_end(buffer, profile_number, card_number);
        place_holder = PLACE_HOLDER_STR;
        strncpy(header, PROFILE_NAME_TEMPL, MAX_SEARCH_FIELD_LENGTH);
        *strchr(header, place_holder) = '\0';
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        if ((pos_name_header = strstr_icase_blank(buffer + pos_card_begin, header)) >= 
0) {
                if ((pos_name_header += pos_card_begin) < pos_card_end) {
                        return pos_name_header;
                }
        }
        return NOTFOUND;
}

int get_begin_of_alsa_section(const char * const buffer, const int profile_number, 
const int card_number)
{
        char search_string[MAX_SEARCH_FIELD_LENGTH];
        int card_section_begin, card_section_end;
        int begin_of_alsa_section, pos_after_alsa_section;

        if ((card_section_begin = get_card_begin(buffer, profile_number, card_number)) 
< 0)
                return card_section_begin;
        card_section_end = get_card_end(buffer, profile_number, card_number);
        strncpy(search_string, PROFILE_NAME_TEMPL, MAX_SEARCH_FIELD_LENGTH);
        search_string[MAX_SEARCH_FIELD_LENGTH -1] = '\0';
        *strchr(search_string, PLACE_HOLDER_STR) = '\0';

        pos_after_alsa_section = get_start_of_line(buffer, card_section_end);

        begin_of_alsa_section = strstr_icase_blank(buffer + card_section_begin, 
search_string);
        begin_of_alsa_section = begin_of_alsa_section < 0 ? card_section_begin : 
begin_of_alsa_section + card_section_begin;
        if (begin_of_alsa_section > pos_after_alsa_section)
                begin_of_alsa_section = card_section_begin;
        while (begin_of_alsa_section < pos_after_alsa_section)
        {
                if (buffer[begin_of_alsa_section] == '\n') {
                        begin_of_alsa_section++;
                        break;
                }
                begin_of_alsa_section++;
        }

        if (begin_of_alsa_section >= pos_after_alsa_section)
                begin_of_alsa_section = NOTFOUND;

        return begin_of_alsa_section;
}

int reorganize_profiles(char * const buffer, const int max_length)
{
        int profile_number, card_number, card_number_max;
        int res;
        int pos_profile_begin, pos_profile_end, pos_card_begin, pos_card_end, 
pos_name_header;
        int pos_alsa_section_begin, pos_after_alsa_section;
        char header[MAX_SEARCH_FIELD_LENGTH];
        void *buffer_copy = NULL;
        char profile_or_card_number_as_str[MAX_NUM_STR_LENGTH];
        char place_holder;

        if ((buffer_copy = malloc(max_length)) == NULL) {
                res = -ENOBUFS;
                profile_number = res;
                fprintf(stderr, "Cannot allocate memory for reorganize profiles.\n");
                return res;
        }
        memset(buffer_copy, '\0', max_length);
        for (profile_number = 1; profile_number <= MAX_PROFILES; profile_number++)
        {
                if ((pos_profile_begin = get_profile_begin(buffer, profile_number)) < 
0)
                        continue;
                /* write profile header */
                place_holder = PLACE_HOLDER_NUM;
                snprintf(profile_or_card_number_as_str, MAX_NUM_STR_LENGTH, "%d", 
profile_number);
                profile_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';
                compose_search_string(header, PROFILE_HEADER_TEMPL, 
profile_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
                header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
                snprintf(buffer_copy + strlen(buffer_copy), max_length - 
strlen(buffer_copy), "%s\n", header);
                pos_profile_end = get_profile_end(buffer, profile_number);
                /* search max card number in profile */
                card_number_max = get_max_card_number_in_profile(buffer, 
profile_number);
                for (card_number = 0; card_number <= card_number_max; card_number++)
                {
                        if ((pos_card_begin = get_card_begin(buffer, profile_number, 
card_number)) < 0)
                                continue;
                        /* write card header */
                        place_holder = PLACE_HOLDER_NUM;
                        snprintf(profile_or_card_number_as_str, MAX_NUM_STR_LENGTH, 
"%d", card_number);
                        profile_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';
                        compose_search_string(header, CARD_HEADER_TEMPL, 
profile_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
                        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
                        snprintf(buffer_copy + strlen(buffer_copy), max_length - 
strlen(buffer_copy), "%s\n", header);
                        pos_card_end = get_card_end(buffer, profile_number, 
card_number);
                        /* write profile name */
                        place_holder = PLACE_HOLDER_STR;
                        if ((pos_name_header = get_pos_name_header_from_card(buffer, 
profile_number, card_number)) >= 0) {
                                compose_search_string(header, PROFILE_NAME_TEMPL, 
get_profile_name_from_header(buffer + pos_name_header), place_holder, \
                                                MAX_SEARCH_FIELD_LENGTH);
                                snprintf(buffer_copy + strlen(buffer_copy), max_length 
- strlen(buffer_copy), "%s\n", header);
                        }
                        /* copy alsa section if exists */
                        if ((pos_alsa_section_begin = 
get_begin_of_alsa_section(buffer, profile_number, card_number)) >= 0) {
                                pos_after_alsa_section = get_start_of_line(buffer, 
pos_card_end);
                                strncpy(buffer_copy + strlen(buffer_copy), buffer + 
pos_alsa_section_begin, pos_after_alsa_section - pos_alsa_section_begin);
                        }
                        /* write card footer */
                        place_holder = PLACE_HOLDER_NUM;
                        snprintf(profile_or_card_number_as_str, MAX_NUM_STR_LENGTH, 
"%d", card_number);
                        profile_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';
                        compose_search_string(header, CARD_FOOTER_TEMPL, 
profile_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
                        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
                        snprintf(buffer_copy + strlen(buffer_copy), max_length - 
strlen(buffer_copy), "%s\n", header);
                }
        }
        memset(buffer, '\0', max_length);
        strncpy(buffer, buffer_copy, max_length);
        buffer[max_length - 1] = '\0';
        free(buffer_copy);
        buffer_copy = NULL;
        return EXIT_SUCCESS;
}

int delete_card_from_profile(char * const buffer, const int profile_number, const int 
card_number, const int max_length)
{
        int pos_card_begin, pos_next_card;
        char *buffer_copy = NULL;

        if ((pos_card_begin = get_card_begin(buffer, profile_number, card_number)) < 0)
                return pos_card_begin;
        if ((buffer_copy = malloc(max_length)) == NULL) {
                fprintf(stderr, "Cannot allocate memory for reading profiles.\n");
                fprintf(stderr, "Cannot delete card '%d' from profile '%d'.\n", 
card_number, profile_number);
                return -ENOBUFS;
        }
        memset(buffer_copy, '\0', max_length);
        pos_next_card = get_pos_for_next_card(buffer, profile_number, card_number);
        strncpy(buffer_copy, buffer, pos_card_begin);
        strncpy(buffer_copy + pos_card_begin, buffer + pos_next_card, max_length - 
pos_card_begin);
        buffer_copy[max_length - 1] = '\0';
        memset(buffer, '\0', max_length);
        strncpy(buffer, buffer_copy, max_length);
        buffer[max_length - 1] = '\0';
        free(buffer_copy);
        buffer_copy = NULL;
        return EXIT_SUCCESS;
}

int save_restore_alsactl_settings(char * const tmpfile, const int card_number, char * 
const operation)
{
        int res;
        char * parameter[MAX_PARAM];
        char *alsactl;
        char profile_number_or_card_number_as_str[MAX_NUM_STR_LENGTH];

        alsactl = check_environment("ALSACTL_PROG", ALSACTL);
        snprintf(profile_number_or_card_number_as_str, MAX_NUM_STR_LENGTH, "%d", 
card_number);
        profile_number_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';

        parameter[0] = alsactl;
        parameter[1] = "-f";
        parameter[2] = tmpfile;
        parameter[3] = operation;
        parameter[4] = profile_number_or_card_number_as_str;
        parameter[5] = NULL;
        
        res = new_process(parameter);
        
        return res;
}

void compose_tmpfile_name(char * const tmpfile, const char * const cfgfile)
{
        strncpy(tmpfile, cfgfile, MAX_FILE_NAME_LENGTH);
        tmpfile[MAX_FILE_NAME_LENGTH - 1] = '\0';
        strncpy(tmpfile + strlen(tmpfile), "_alsactl_tmp", MAX_FILE_NAME_LENGTH - 
strlen(tmpfile));
        tmpfile[MAX_FILE_NAME_LENGTH - 1] = '\0';
}

/*
 * restore card settings
 * if profile_number < 0 profile_name must be given
 * if booth is given profile_number will be used profile_name will be ignored
 */
int restore_profile(const int profile_number, const int card_number, const char * 
profile_name, char * cfgfile)
{
        int res, max_length;
        int begin_of_alsa_section, pos_after_alsa_section, profile_nr;
        char *buffer = NULL;
        char tmpfile[MAX_FILE_NAME_LENGTH];
        int get_profile_number(const char * const profile_name_given, const int 
card_number, char * cfgfile);

        if ((profile_number < 0) && (profile_name == NULL)) {
                fprintf(stderr, "Without profile number - profile name for card '%d' 
must given.\n", card_number);
                return -EINVAL;
        }
        if ((max_length = get_file_size(cfgfile)) < 0) {
                fprintf(stderr, "Cannot get file size from '%s'.\n", cfgfile);
                return max_length;
        }
        max_length++;
        if ((buffer = malloc(max_length)) == NULL) {
                fprintf(stderr, "Cannot allocate memory for reading profiles.\n");
                fprintf(stderr, "Cannot read settings for card '%d' in profile 
'%d'.\n", card_number, profile_number);
                return -ENOBUFS;
        }
        memset(buffer, '\0', max_length);
        if ((res = read_profiles_in_buffer(cfgfile, buffer, max_length)) <= 0) {
                if (profile_number < 0) {
                        fprintf(stderr, "Cannot read settings for card '%d' in profile 
'%s'.\n", card_number, profile_name);
                } else {
                        fprintf(stderr, "Cannot read settings for card '%d' in profile 
'%d'.\n", card_number, profile_number);
                }
                free(buffer);
                buffer = NULL;
                return -EINVAL;
        }
        profile_nr = profile_number;
        if (profile_number < 0) {
                if ((profile_nr = get_profile_number(profile_name, card_number, 
cfgfile)) < 0) {
                        fprintf(stderr, "Cannot find profile '%s' for card '%d'.\n", 
profile_name, card_number);
                        free(buffer);
                        buffer = NULL;
                        return profile_nr;
                }
        }
        if ((begin_of_alsa_section = get_begin_of_alsa_section(buffer, profile_nr, 
card_number)) < 0) {
                fprintf(stderr, "Cannot find alsa section for card '%d' in profile 
'%d'.\n", card_number, profile_nr);
                free(buffer);
                buffer = NULL;
                return begin_of_alsa_section;
        }
        pos_after_alsa_section = get_start_of_line(buffer, get_card_end(buffer, 
profile_nr, card_number));
        compose_tmpfile_name(tmpfile, cfgfile);
        if ((res = write_profiles_from_buffer(tmpfile, buffer + begin_of_alsa_section, 
pos_after_alsa_section - begin_of_alsa_section, 0)) >= 0) {
                res = save_restore_alsactl_settings(tmpfile, card_number, 
ALSACTL_OP_RESTORE);
                unlink(tmpfile);
        }
        free(buffer);
        buffer = NULL;

        if (res > 0)
                res = EXIT_SUCCESS;

        return res;
}

int append_alsactl_settings(const char * const tmpfile, char * const buffer_position, 
const int max_length)
{
        int res;

        res = read_profiles_in_buffer(tmpfile, buffer_position, max_length);
        if (res >= 0)
                return EXIT_SUCCESS;
        return res;
}

/*
 * insert entry for card in profile with alsactl settings
 * if profile_number < 0 no profile header is needed
 * if pos_end < 0 the new entry will be appended
 * if profile_name == NULL the profile name header will not be written
 */
int insert_card(char * const buffer, const int profile_number, const int card_number, 
const char * const profile_name, const int pos_begin, \
                const int pos_end, char * const tmpfile, const int max_length)
{
        int res;
        char *buffer_copy = NULL;
        char header[MAX_SEARCH_FIELD_LENGTH];
        char profile_number_or_card_number_as_str[MAX_NUM_STR_LENGTH];
        char profile_name_copy[PROFILE_NAME_FIELD_LENGTH];
        char place_holder;

        if ((res = save_restore_alsactl_settings(tmpfile, card_number, 
ALSACTL_OP_STORE)) < 0)
                return res;
        if (pos_end >= 0) {
                if ((buffer_copy = malloc(max_length)) == NULL) {
                        fprintf(stderr, "Cannot allocate memory for reading 
profiles.\n");
                        fprintf(stderr, "Cannot save settings for card '%d' in profile 
'%d'.\n", card_number, profile_number);
                        unlink(tmpfile);
                        return -ENOBUFS;
                }
                memset(buffer_copy, '\0', max_length);
                strncpy(buffer_copy, buffer, max_length);
                buffer_copy[max_length - 1] = '\0';
                memset(buffer + pos_begin, '\0', max_length - pos_begin);
        }
        if (profile_number >= 0) {
                place_holder = PLACE_HOLDER_NUM;
                snprintf(profile_number_or_card_number_as_str, MAX_NUM_STR_LENGTH, 
"%d", profile_number);
                profile_number_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';
                compose_search_string(header, PROFILE_HEADER_TEMPL, 
profile_number_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
                header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
                snprintf(buffer + strlen(buffer), max_length - strlen(buffer), "%s\n", 
header);
                buffer[max_length - 1] = '\0';
        }
        /* compose card header */
        place_holder = PLACE_HOLDER_NUM;
        snprintf(profile_number_or_card_number_as_str, MAX_NUM_STR_LENGTH, "%d", 
card_number);
        profile_number_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';
        compose_search_string(header, CARD_HEADER_TEMPL, 
profile_number_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        snprintf(buffer + strlen(buffer), max_length - strlen(buffer), "%s\n", header);
        buffer[max_length - 1] = '\0';
        /* compose profile name header if needed */
        if (profile_name != NULL) {
                strncpy(profile_name_copy, profile_name, PROFILE_NAME_FIELD_LENGTH);
                profile_name_copy[PROFILE_NAME_FIELD_LENGTH - 1] = '\0';
                place_holder = PLACE_HOLDER_STR;
                compose_search_string(header, PROFILE_NAME_TEMPL, profile_name_copy, 
place_holder, MAX_SEARCH_FIELD_LENGTH);
                header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
                snprintf(buffer + strlen(buffer), max_length - strlen(buffer), "%s\n", 
header);
                buffer[max_length - 1] = '\0';
        }
        res = append_alsactl_settings(tmpfile, buffer + strlen(buffer), max_length - 
strlen(buffer));
        buffer[max_length - 1] = '\0';
        unlink(tmpfile);
        /* compose card footer */
        place_holder = PLACE_HOLDER_NUM;
        snprintf(profile_number_or_card_number_as_str, MAX_NUM_STR_LENGTH, "%d", 
card_number);
        profile_number_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] = '\0';
        compose_search_string(header, CARD_FOOTER_TEMPL, 
profile_number_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
        header[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
        snprintf(buffer + strlen(buffer), max_length - strlen(buffer), "%s\n", header);
        buffer[max_length - 1] = '\0';
        if (pos_end >= 0) {
                strncpy(buffer + strlen(buffer), buffer_copy + pos_end, max_length - 
strlen(buffer));
                free(buffer_copy);
                buffer_copy = NULL;
        }
        if (res >= 0)
                res = EXIT_SUCCESS;
                
        return res;
}

int save_profile(const int profile_number, const int card_number, const char * const 
profile_name, char *cfgfile)
{
        int res, profile_begin, profile_end, profile_nr;
        int card_begin, pos_next_card, card_nr, card_number_max;
        const int no_profile_header = -1;
        const int append = -1;
        char *buffer = NULL;
        char tmpfile[MAX_FILE_NAME_LENGTH];
        int max_length;

        if ((max_length = get_file_size(cfgfile)) < 0) {
                fprintf(stderr, "This operation will create a new profiles file 
'%s'.\n", cfgfile);
                max_length = 0;
        }
        max_length += MAX_PROFILE_SIZE;
        if ((buffer = malloc(max_length)) == NULL) {
                fprintf(stderr, "Cannot allocate memory for reading profiles.\n");
                fprintf(stderr, "Cannot save settings for card '%d' in profile 
'%d'.\n", card_number, profile_number);
                return -ENOBUFS;
        }
        memset(buffer, '\0', max_length);
        compose_tmpfile_name(tmpfile, cfgfile);
        /* file found */
        if ((res = open(cfgfile, O_RDONLY | 0400000 /* NOFOLLOW */)) >= 0) {
                close(res);
                res = read_profiles_in_buffer(cfgfile, buffer, max_length);
                if (res > 0)
                        res = reorganize_profiles(buffer, max_length);
        }
        res = strlen(buffer);
        if (res > 0) {
                if ((profile_begin = get_profile_begin(buffer, profile_number)) < 0) {
                        if (profile_number < MAX_PROFILES) {
                                for (profile_nr = 0; profile_nr <= MAX_PROFILES; 
profile_nr++)
                                {
                                        if (profile_nr > profile_number) {
                                                if ((profile_begin = 
get_profile_begin(buffer, profile_nr)) >= 0)
                                                        break;
                                        }
                                }
                                if (profile_begin < 0)
                                        profile_begin = strlen(buffer);
                        } else {
                                profile_begin = strlen(buffer);
                        }
                        if (profile_begin < strlen(buffer)) {
                                res = insert_card(buffer, profile_number, card_number, 
profile_name, profile_begin, profile_begin, tmpfile, max_length);
                        } else {
                                res = insert_card(buffer, profile_number, card_number, 
profile_name, profile_begin, append, tmpfile, max_length);
                        }
                } else {
                        if ((card_begin = get_card_begin(buffer, profile_number, 
card_number)) < 0) {
                                card_number_max = 
get_max_card_number_in_profile(buffer, profile_number);
                                profile_end = get_profile_end(buffer, profile_number);
                                if (card_number_max > card_number) {
                                        for (card_nr = 0; card_nr <= card_number_max; 
card_nr++)
                                        {
                                                if (card_nr > card_number) {
                                                        if ((card_begin = 
get_card_begin(buffer, profile_number, card_number)) >= 0)
                                                                break;
                                                }
                                        }
                                        if (card_begin < 0)
                                                card_begin = profile_end;
                                } else {
                                        card_begin = profile_end;
                                }
                                if (card_begin < strlen(buffer)) {
                                        res = insert_card(buffer, no_profile_header, 
card_number, profile_name, card_begin, card_begin, tmpfile, max_length);
                                } else {
                                        res = insert_card(buffer, no_profile_header, 
card_number, profile_name, strlen(buffer), append, tmpfile, max_length);
                                }
                        } else {
                                pos_next_card = get_pos_for_next_card(buffer, 
profile_number, card_number);
                                res = insert_card(buffer, no_profile_header, 
card_number, profile_name, card_begin, pos_next_card, tmpfile, max_length);
                        }
                }
        } else {
                res = insert_card(buffer, profile_number, card_number, profile_name, 
0, -1, tmpfile, max_length);
        }
        if (res < 0) {
                fprintf(stderr, "Cannot store profile '%d' for card '%d'.\n", 
profile_number, card_number);
        } else {
                res = write_profiles_from_buffer(cfgfile, buffer, max_length, 1);
        }
        free(buffer);
        buffer = NULL;

        if (res > 0)
                res = EXIT_SUCCESS;

        return res;
}

int delete_card(const int card_number, char * cfgfile)
{
        int res, profile_number, max_length;
        void *buffer = NULL;

        if (cfgfile == NULL)
                cfgfile = DEFAULT_PROFILERC;
        strncpy(filename_without_tilde, cfgfile, MAX_FILE_NAME_LENGTH);
        filename_without_tilde[MAX_FILE_NAME_LENGTH - 1] = '\0';
        subst_tilde_in_filename(filename_without_tilde);
        cfgfile = filename_without_tilde;
        if ((res = open(cfgfile, O_RDWR | 0400000 /* O_NOFOLLOW */, FILE_CREA_MODE)) < 
0) {
                fprintf(stderr, "Cannot open configuration file '%s' for writing.\n", 
cfgfile);
                fprintf(stderr, "Cannot save settings for card '%d'.\n", card_number);
                return -errno;
        }
        close(res);
        if (res >= 0) {
                if ((max_length = get_file_size(cfgfile)) < 0) {
                        fprintf(stderr, "Cannot get file size for '%s'.\n", cfgfile);
                        return max_length;
                }
                max_length++;
                if ((buffer = malloc(max_length)) == NULL) {
                        fprintf(stderr, "Cannot allocate memory for reading 
profiles.\n");
                        fprintf(stderr, "Cannot delete card '%d'.\n", card_number);
                        return -ENOBUFS;
                }
                memset(buffer, '\0', max_length);
                res = read_profiles_in_buffer(cfgfile, buffer, max_length);
                if (res > 0) {
                        for (profile_number = 1; profile_number <= MAX_PROFILES; 
profile_number++)
                                delete_card_from_profile(buffer, profile_number, 
card_number, max_length);
                        res = EXIT_SUCCESS;
                } else {
                        res = NOTFOUND;
                }
                res = write_profiles_from_buffer(cfgfile, buffer, max_length, 1);
                free(buffer);
                buffer = NULL;
        } else {
                res = NOTFOUND;
        }
        return res;
}

/*
 * First search profile name. if profile name is found look that this profile
 * name is from the specified card number.
 * if not search next occurence from given profile name.
 */
int get_profile_number(const char * const profile_name_given, const int card_number, 
char * cfgfile)
{
        int res, pos_name, pos_name_offset, pos_begin, pos_end, found;
        int profile_number, pos_profile;
        void *buffer = NULL;
        char search_field[MAX_SEARCH_FIELD_LENGTH];
        char header_templ[MAX_SEARCH_FIELD_LENGTH];
        char profile_or_card_number_as_str[MAX_NUM_STR_LENGTH];
        char place_holder;
        int max_length;

        if (strlen(profile_name_given) == 0) {
                fprintf(stderr, "Profile name for card '%d' must be given.\n", 
card_number);
                return -EINVAL;
        }
        /* cut profile name to MAX_PROFILE_NAME_LENGTH */
        strncpy(profile_name, profile_name_given, PROFILE_NAME_FIELD_LENGTH);
        profile_name[PROFILE_NAME_FIELD_LENGTH - 1] = '\0';
        if (cfgfile == NULL)
                cfgfile = DEFAULT_PROFILERC;
        res = which_cfgfile(&cfgfile);
        if (res < 0) {
                profile_number = res;
        } else {
                if ((max_length = get_file_size(cfgfile)) < 0) {
                        fprintf(stderr, "Cannot get file size from '%s'.\n", cfgfile);
                        return max_length;
                }
                max_length++;
                if ((buffer = malloc(max_length)) == NULL) {
                        res = -ENOBUFS;
                        profile_number = res;
                        fprintf(stderr, "Cannot allocate memory for reading 
profiles.\n");
                        return profile_number;
                }
                memset(buffer, '\0', max_length);
                res = read_profiles_in_buffer(cfgfile, buffer, max_length);
                if (res > 0) {
                        /* insert profile name in PROFILE_NAME_TEMPL */
                        place_holder = PLACE_HOLDER_STR;
                        compose_search_string(search_field, PROFILE_NAME_TEMPL, 
profile_name, place_holder, MAX_SEARCH_FIELD_LENGTH);
                        pos_name = 0;
                        pos_name_offset = 0;
                        pos_begin = NOTFOUND;
                        found = 0;
                        while ((pos_name = strstr_icase_blank(buffer + 
pos_name_offset, search_field)) >= 0)
                        {
                                pos_name += pos_name_offset;
                                /* search begin of section for the given card
                                   from profile name pointer backward */
                                /* insert card number in CARD_HEADER_TEMPL */
                                place_holder = PLACE_HOLDER_NUM;
                                snprintf(profile_or_card_number_as_str, 
MAX_NUM_STR_LENGTH, "%d", card_number);
                                profile_or_card_number_as_str[MAX_NUM_STR_LENGTH - 1] 
= '\0';
                                compose_search_string(search_field, CARD_HEADER_TEMPL, 
profile_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
                                search_field[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
                                if ((pos_begin = get_begin_of_section(buffer, 
search_field, TOKEN_SEP, pos_name)) < 0)
                                        break;
                                /* searching "[ profile | < card | < /card # >" */
                                /* add "[ profile |" to search_field */
                                strncpy(header_templ, PROFILE_HEADER_TEMPL, 
MAX_SEARCH_FIELD_LENGTH);
                                *strchr(header_templ, place_holder) = '\0';
                                strncpy(search_field, header_templ, 
MAX_SEARCH_FIELD_LENGTH);
                                strncpy(search_field + strlen(search_field), 
TOKEN_SEP, MAX_SEARCH_FIELD_LENGTH - strlen(search_field));
                                /* add "< card |" to search_field */
                                strncpy(header_templ, CARD_HEADER_TEMPL, 
MAX_SEARCH_FIELD_LENGTH);
                                *strchr(header_templ, place_holder) = '\0';
                                strncpy(search_field + strlen(search_field), 
header_templ, MAX_SEARCH_FIELD_LENGTH - strlen(search_field));
                                strncpy(search_field + strlen(search_field), 
TOKEN_SEP, MAX_SEARCH_FIELD_LENGTH - strlen(search_field));
                                search_field[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
                                /* add "< card # >" to search_field */
                                compose_search_string(header_templ, CARD_FOOTER_TEMPL, 
profile_or_card_number_as_str, place_holder, MAX_SEARCH_FIELD_LENGTH);
                                header_templ[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
                                strncpy(search_field + strlen(search_field), 
header_templ, MAX_SEARCH_FIELD_LENGTH - strlen(search_field));
                                search_field[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
                                pos_end = get_end_of_section(buffer, search_field, 
TOKEN_SEP, pos_begin + sizeof(char));
                                if ((pos_name > pos_begin) && (pos_name < pos_end) && 
(pos_begin >= 0) && (pos_end >= 0)) {
                                        found = 1;
                                        break;
                                }
                                pos_name_offset = pos_name + sizeof(char);
                                place_holder = PLACE_HOLDER_STR;
                                compose_search_string(search_field, 
PROFILE_NAME_TEMPL, profile_name, place_holder, MAX_SEARCH_FIELD_LENGTH);
                        }
                        if (found) {
                                place_holder = PLACE_HOLDER_NUM;
                                strncpy(search_field, PROFILE_HEADER_TEMPL, 
MAX_SEARCH_FIELD_LENGTH);
                                search_field[MAX_SEARCH_FIELD_LENGTH - 1] = '\0';
                                *strchr(search_field, place_holder) = '\0';
                                if ((pos_profile = get_begin_of_section(buffer, 
search_field, TOKEN_SEP, pos_begin)) < 0) {
                                        profile_number = NOTFOUND;
                                } else {
                                        profile_number = get_number_from_header(buffer 
+ pos_profile);
                                        /* check profile header syntax */
                                        if (get_profile_begin(buffer, profile_number) 
!= pos_profile) {
                                                profile_number = -EINVAL;
                                                /* only the profile line */
                                                strncpy(search_field, buffer + 
pos_profile, MAX_SEARCH_FIELD_LENGTH);
                                                search_field[MAX_SEARCH_FIELD_LENGTH - 
1] = '\0';
                                                *strchr(search_field, '\n') = '\0';
                                                fprintf(stderr, "profile header '%s' 
has incorrect syntax.\n", search_field);
                                                fprintf(stderr, "profile header syntax 
is '%s'\n" \
                                                                        "by replacing 
place holder '%c' with profile number.\n", \
                                                                        
PROFILE_HEADER_TEMPL, PLACE_HOLDER_NUM);
                                                /* check profile number */
                                        } else if (profile_number > MAX_PROFILES) {
                                                fprintf(stderr, "profile number '%d' 
is incorrect. the maximum profile number will be '%d'.\n", \
                                                                        
profile_number, MAX_PROFILES);
                                                profile_number = -EINVAL;
                                        }
                                }
                        } else {
                                profile_number = NOTFOUND;
                        }
                } else {
                        profile_number = NOTFOUND;
                }
                free(buffer);
                buffer = NULL;
        }
        return profile_number;
}

char *get_profile_name(const int profile_number, const int card_number, char * cfgfile)
{
        int res, max_length;
        void *buffer = NULL;

        if (cfgfile == NULL)
                cfgfile = DEFAULT_PROFILERC;
        res = which_cfgfile(&cfgfile);
        if (res < 0) {
                snprintf(profile_name, PROFILE_NAME_FIELD_LENGTH, "%d", 
profile_number);
        } else {
                if ((max_length = get_file_size(cfgfile)) < 0) {
                        fprintf(stderr, "Cannot get file size from '%s'.\n", cfgfile);
                        snprintf(profile_name, PROFILE_NAME_FIELD_LENGTH, "%d", 
profile_number);
                        return profile_name;
                }
                max_length++;
                if ((buffer = malloc(max_length)) == NULL) {
                        res = -ENOBUFS;
                        snprintf(profile_name, PROFILE_NAME_FIELD_LENGTH, "%d", 
profile_number);
                        fprintf(stderr, "Cannot allocate memory for reading 
profiles.\n");
                        return profile_name;
                }
                memset(buffer, '\0', max_length);
                memset(profile_name, '\0', PROFILE_NAME_FIELD_LENGTH);
                res = read_profiles_in_buffer(cfgfile, buffer, max_length);
                if (res > 0) {
                        if ((res = get_pos_name_header_from_card(buffer, 
profile_number, card_number)) >= 0) {
                                get_profile_name_from_header(buffer + (res * 
sizeof(char)));
                                profile_name[PROFILE_NAME_FIELD_LENGTH - 1] = '\0';
                        }
                }
                free(buffer);
                buffer = NULL;
                if (strlen(profile_name) == 0) {
                        snprintf(profile_name, PROFILE_NAME_FIELD_LENGTH, "%d", 
profile_number);
                }
        }
        return profile_name;
}

int save_restore(const char * const operation, const int profile_number, const int 
card_number, char * cfgfile, const char * const profile_name)
{
        int res;

        if (cfgfile == NULL)
                cfgfile = DEFAULT_PROFILERC;
        if (!strcmp(operation, ALSACTL_OP_STORE)) {
                strncpy(filename_without_tilde, cfgfile, MAX_FILE_NAME_LENGTH);
                filename_without_tilde[MAX_FILE_NAME_LENGTH - 1] = '\0';
                subst_tilde_in_filename(filename_without_tilde);
                cfgfile = filename_without_tilde;
                if ((res = open(cfgfile, O_RDONLY | 0400000 /* O_NOFOLLOW */)) < 0) {
                        if ((res = create_dir_from_filename(cfgfile)) < 0) {
                                fprintf(stderr, "Cannot open configuration file '%s' 
for writing.\n", cfgfile);
                                fprintf(stderr, "Cannot save settings for card '%d' in 
profile '%d'.\n", card_number, profile_number);
                                return -EACCES;
                        }
                        if ((res = open(cfgfile, O_RDWR | O_CREAT | 0400000 /* 
O_NOFOLLOW */, FILE_CREA_MODE)) < 0) {
                                fprintf(stderr, "Cannot open configuration file '%s' 
for writing.\n", cfgfile);
                                fprintf(stderr, "Cannot save settings for card '%d' in 
profile '%d'.\n", card_number, profile_number);
                                return -errno;
                        }
                        unlink(cfgfile);
                } else {
                        if ((res = open(cfgfile, O_RDWR | 0400000 /* O_NOFOLLOW */, 
FILE_CREA_MODE)) < 0) {
                                fprintf(stderr, "Cannot open configuration file '%s' 
for writing.\n", cfgfile);
                                fprintf(stderr, "Cannot save settings for card '%d' in 
profile '%d'.\n", card_number, profile_number);
                                return -errno;
                        }
                }
                res =  save_profile(profile_number, card_number, profile_name, 
cfgfile);
        } else if (!strcmp(operation, ALSACTL_OP_RESTORE)) {
                res = which_cfgfile(&cfgfile);
                if (res < 0) {
                        fprintf(stderr, "Cannot open profiles file '%s' ...\n", 
cfgfile);
                        fprintf(stderr, "Use current settings.\n");
                        fprintf(stderr, "You can store this settings to profile no. %d 
in file '%s' by pressing save button.\n",
                                                profile_number, cfgfile);
                } else { 
                        if ((res = restore_profile(profile_number, card_number, 
profile_name, cfgfile)) < 0) {
                                fprintf(stderr, "Cannot restore settings for card '%d' 
in profile '%d'.\n", card_number, profile_number); 
                                fprintf(stderr, "Use current settings.\n");
                        }
                }
        } else {
                fprintf(stderr, "%s: Unknown command '%s'...\n", 
                        PROGRAM_NAME, operation);
                res = -ENODEV;
        }

        return res < 0 ? -EXIT_FAILURE : EXIT_SUCCESS;
}

--- NEW FILE: profiles.h ---
#ifndef __PROFILES_H__
#define __PROFILES_H__

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/stat.h>
#include <errno.h>
#include <assert.h>
#include <time.h>

#ifndef PROGRAM_NAME
#define PROGRAM_NAME "envy24control"
#endif

#ifndef MAX_PROFILES
#define MAX_PROFILES 4
#endif

#ifndef MAX_PROFILE_NAME_LENGTH
#define MAX_PROFILE_NAME_LENGTH 20
#endif

#ifndef DEFAULT_PROFILERC
#define DEFAULT_PROFILERC "~/"PROGRAM_NAME"/profiles.conf"
#endif

#ifndef SYS_PROFILERC
#define SYS_PROFILERC "/etc/"PROGRAM_NAME"/profiles.conf"
#endif

#define PROFILE_NAME_FIELD_LENGTH MAX_PROFILE_NAME_LENGTH + 1

#define PROFILE_HEADER_TEMPL "[ Profile # ]"
#define CARD_HEADER_TEMPL "< Card # >"
#define CARD_FOOTER_TEMPL "< /CARD # >"
#define PROFILE_NAME_TEMPL "{ /$/ }"

#define PLACE_HOLDER_NUM '#'
#define PLACE_HOLDER_STR '$'

/* max 32k for every profile */
#define MAX_PROFILE_SIZE 32768
#define MAX_SEARCH_FIELD_LENGTH 1024
#define MAX_FILE_NAME_LENGTH 1024
#define MAX_NUM_STR_LENGTH 10
#define TOKEN_SEP "|"
#define SEP_CHAR ' '

#ifndef NOTFOUND
#define NOTFOUND -1
#endif

#define ALSACTL_OP_STORE "store"
#define ALSACTL_OP_RESTORE "restore"

#define DIR_CREA_MODE "0755"    // this must be a string
#define FILE_CREA_MODE 0644     // this must be a octal number

/* max count of parameters for new_process
 * !first parameter will be the name of the external programm
 * - last parameter will be NULL
 */
#define MAX_PARAM 10

/* the place from mkdir */
#ifndef MKDIR
#define MKDIR "/bin/mkdir"
#endif

/* the place from alsactl */
#ifndef ALSACTL
#define ALSACTL "/usr/sbin/alsactl"
#endif

#ifndef __PROFILES_C__
extern int save_restore(const char * const operation, const int profile_number, const 
int card_number, char * cfgfile, const char * const profile_name);
extern char *get_profile_name(const int profile_number, const int card_number, char * 
cfgfile);
extern int get_profile_number(const char * const profile_name, const int card_number, 
char * cfgfile);
extern int delete_card(const int card_number, char * const cfgfile);
#endif

#endif /* __PROFILES_H__ */



-------------------------------------------------------
This SF.Net email is sponsored by: SourceForge.net Broadband
Sign-up now for SourceForge Broadband and get the fastest
6.0/768 connection for only $19.95/mo for the first 3 months!
http://ads.osdn.com/?ad_id=2562&alloc_id=6184&op=click
_______________________________________________
Alsa-cvslog mailing list
[EMAIL PROTECTED]
https://lists.sourceforge.net/lists/listinfo/alsa-cvslog

Reply via email to