ui/common/properties.c

Sun, 29 Sep 2024 18:51:03 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sun, 29 Sep 2024 18:51:03 +0200
branch
newapi
changeset 315
144c2b4683cb
parent 254
13997c76859b
child 378
d41b1ffc5f77
permissions
-rw-r--r--

use GtkFileDialog on newer gtk4 versions

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2017 Olaf Wintermann. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   1. Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 *
 *   2. Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

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

#include "properties.h"
#include <cx/string.h>
#include <cx/buffer.h>

#include "ucx_properties.h"

static CxMap *application_properties;
static CxMap *language;

#ifndef UI_COCOA

static char *locales_dir;
static char *pixmaps_dir;

#endif

char* ui_getappdir() {
    if(ui_appname() == NULL) {
        return NULL;
    }
    
    return ui_configfile(NULL);
}

char* ui_configfile(char *name) {
    const char *appname = ui_appname();
    if(!appname) {
        return NULL;
    }
    
    CxBuffer buf;
    cxBufferInit(&buf, NULL, 128, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
    
    // add base dir
    char *homeenv = getenv("HOME");
    if(homeenv == NULL) {
        cxBufferDestroy(&buf);
        return NULL;
    }
    cxstring home = cx_str(homeenv);
    
    cxBufferWrite(home.ptr, 1, home.length, &buf);
    if(home.ptr[home.length-1] != '/') {
        cxBufferPut(&buf, '/');
    }
    
#ifdef UI_COCOA
    // on OS X the app dir is $HOME/Library/Application Support/$APPNAME/
    ucx_buffer_puts(buf, "Library/Application Support/");
#else
    // app dir is $HOME/.$APPNAME/
    cxBufferPut(&buf, '.');
#endif
    cxBufferPutString(&buf, appname);
    cxBufferPut(&buf, '/');
    
    // add file name
    if(name) {
        cxBufferPutString(&buf, name);
    }
    
    cxBufferPut(&buf, 0);
    
    return buf.space;
}

static int ui_mkdir(char *path) {
#ifdef _WIN32
    return mkdir(path);
#else
    return mkdir(path, S_IRWXU);
#endif
} 

void uic_load_app_properties() {
    application_properties = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 128);
    
    if(!ui_appname()) {
        // applications without name cannot load app properties
        return;
    }
    
    char *dir = ui_configfile(NULL);
    if(!dir) {
        return;
    }
    if(ui_mkdir(dir)) {
        if(errno != EEXIST) {
            fprintf(stderr, "Ui Error: Cannot create directory %s\n", dir);
            free(dir);
            return;
        }
    }
    free(dir);
    
    char *path = ui_configfile("application.properties");
    if(!path) {
        return;
    }
    
    FILE *file = fopen(path, "r");
    if(!file) {
        free(path);
        return;
    }
    
    if(ucx_properties_load(application_properties, file)) {
        fprintf(stderr, "Ui Error: Cannot load application properties.\n");
    }
    
    fclose(file);
    free(path);
}

void uic_store_app_properties() {
    char *path = ui_configfile("application.properties");
    if(!path) {
        return;
    }
    
    FILE *file = fopen(path, "w");
    if(!file) {
        fprintf(stderr, "Ui Error: Cannot open properties file: %s\n", path);
        free(path);
        return;
    }
    
    if(ucx_properties_store(application_properties, file)) {
        fprintf(stderr, "Ui Error: Cannot store application properties.\n");
    }
    
    fclose(file);
    free(path);
}


char* ui_get_property(char *name) {
    return cxMapGet(application_properties, name);
}

void ui_set_property(char *name, char *value) {
    cxMapPut(application_properties, name, value);
}

void ui_set_default_property(char *name, char *value) {
    char *v = cxMapGet(application_properties, name);
    if(!v) {
        cxMapPut(application_properties, name, value);
    }
}



static char* uic_concat_path(const char *base, const char *p, const char *ext) {
    size_t baselen = strlen(base);
    
    CxBuffer *buf = cxBufferCreate(NULL, 32, cxDefaultAllocator, CX_BUFFER_FREE_CONTENTS|CX_BUFFER_AUTO_EXTEND);
    if(baselen > 0) {
        cxBufferWrite(base, 1, baselen, buf);
        if(base[baselen - 1] != '/') {
            cxBufferPut(buf, '/');
        }
    }
    cxBufferWrite(p, 1, strlen(p), buf);
    if(ext) {
        cxBufferWrite(ext, 1, strlen(ext), buf);
    }
    
    char *str = buf->space;
    free(buf);
    return str;
}

#ifndef UI_COCOA

void ui_locales_dir(char *path) {
    locales_dir = path;
}

void ui_pixmaps_dir(char *path) {
    pixmaps_dir = path;
}

char* uic_get_image_path(const char *imgfilename) {
    if(pixmaps_dir) {
        return uic_concat_path(pixmaps_dir, imgfilename, NULL);
    } else {
        return NULL;
    }
}

void ui_load_lang(char *locale) {
    if(!locale) {
        locale = "en_EN";
    }
    
    char *path = uic_concat_path(locales_dir, locale, ".properties");
    
    uic_load_language_file(path);
    free(path);
}

void ui_load_lang_def(char *locale, char *default_locale) {
    char tmp[6];
    if(!locale) {
        char *lang = getenv("LANG");
        if(lang && strlen(lang) >= 5) {
            memcpy(tmp, lang, 5);
            tmp[5] = '\0';
            locale = tmp;
        } else {
            locale = default_locale;
        }
    }
    
    char *path = uic_concat_path(locales_dir, locale, ".properties");
    
    if(uic_load_language_file(path)) {
        if(default_locale) {
            ui_load_lang_def(default_locale, NULL);
        } else {
            // cannot find any language file
            fprintf(stderr, "Ui Error: Cannot load language.\n");
            free(path);
            exit(-1);
        }
    }
    free(path);
}

#endif

int uic_load_language_file(const char *path) {
    CxMap *lang = cxHashMapCreate(cxDefaultAllocator, CX_STORE_POINTERS, 256);
    
    FILE *file = fopen(path, "r");
    if(!file) {
        return 1;
    }
    
    if(ucx_properties_load(lang, file)) {
        fprintf(stderr, "Ui Error: Cannot parse language file: %s.\n", path);
    }
    
    fclose(file);
    
    cxMapRehash(lang);
    
    language = lang;
    
    return 0;
}

char* uistr(char *name) {
    char *value = uistr_n(name);
    return value ? value : "missing string";
}

char* uistr_n(char *name) {
    if(!language) {
        return NULL;
    }
    return cxMapGet(language, name);
}

mercurial