Home > OS >  C correct usage of getenv("XXX") return string
C correct usage of getenv("XXX") return string

Time:09-20

I am writing a program in C as below

char *msg = "Do you want to overwrite existing data in config file? (Y/n) [n] : ";
// if (!fexists(CONFFILE)) {                                            // Doesnt work if uncommented
//     msg = "Do you want to save data to config file? (Y/n) [n] : ";   // Doesnt work if uncommented
// }                                                                    // Doesnt work if uncommented

struct arguments arguments;

arguments.a = "vala";
arguments.b = "valb";
arguments.c = "valc";

argp_parse (&argp, argc, argv, 0, 0, &arguments);

printf("%s", msg);
char ans = getchar();
if ((ans == 'y') || (ans == 'Y')) {
    CONFIG cfg = {a, b, c};
    create_config(cfg); //The function that stops working
    if (!fexists(CONFFILE)) {
        printf("Saved credentials to config file.\n");
    } else {
        printf("Err: Unable to save " CONFFILE)
    }
} else {
    printf("Not saving credentials to config file.\n");
}

fexists(), create_config() are confirmed to be working as intended.

bool fexists(char *fname) {
    struct stat buffer;   
    return (stat (fname, &buffer) == 0);
}

int create_config(struct config cfg) {
    struct json_object *jsonobj = json_object_new_object();
    json_object_object_add(jsonobj, "api", json_object_new_string(cfg.api));
    json_object_object_add(jsonobj, "key", json_object_new_string(cfg.key));
    json_object_object_add(jsonobj, "domain", json_object_new_string(cfg.domain));
    return json_object_to_file_ext(CONFFILE, jsonobj, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY);
}

create_config() [and the program] works as intended if the above if statement is commented but stops working if uncommented.

Is there any mistake in my code? What is the solution for this?

EDIT: minimal program to reproduce the issue

// Compile with gcc -ljson-c
// libjson-c-dev is required
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <json-c/json.h>
#include <json-c/json_object.h>
#include <json-c/json_util.h>

struct config {
    char *a;
    char *b;
    char *c;
};

#ifdef _WIN32
    #define CONFFILE strcat(getenv("LOCALAPPDATA"), "/.conf.json")
#else
    #define CONFFILE strcat(getenv("HOME"), "/.conf.json")
#endif

int create_config(struct config cfg) {
    struct json_object *jsonobj = json_object_new_object();
    json_object_object_add(jsonobj, "a", json_object_new_string(cfg.a));
    json_object_object_add(jsonobj, "b", json_object_new_string(cfg.b));
    json_object_object_add(jsonobj, "c", json_object_new_string(cfg.c));
    int retval = json_object_to_file_ext(CONFFILE, jsonobj, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY);
    printf("Err: %s\n", json_util_get_last_err());
    return retval;
}

bool fexists(char *fname) {
    struct stat buffer;   
    return (stat (fname, &buffer) == 0);
}


int main(){
    char *msg = "Do you want to create conffile? (y/n) ";
    // if (!fexists(CONFFILE)) {                                   // Comment these to fix
    //     msg = "Do you want to overwrite conffile? (y/n) ";      // Comment these to fix
    // }                                                           // Comment these to fix
    printf("%s", msg);
    if (((a=getchar()) == 'y') || (a == 'Y')){
        char *a = "vala";
        char *b = "valb";
        char *c = "valc";
        struct config cfg = {a, b, c};
        printf("%d", create_config(cfg));
    }
}

libjson-c-dev is required to compile the program

EDIT2: error message is now printed. Err: json_object_to_file: error opening file /home/user/.conf.json/.conf.json: No such file or directory

CodePudding user response:

Caught the issue...

It wasn't related to if loop. Instead it was the incorrect usage of getenv("XXX")

#ifdef _WIN32
    #define CONFFILE strcat(getenv("LOCALAPPDATA"), "/.conf.json")
#else
    #define CONFFILE strcat(getenv("HOME"), "/.conf.json")
#endif

is wrong as the value returned by getenv("XXX") gets modified and further calls to getenv will return incorrect value.

#ifdef _WIN32
    char* confdir = getenv("LOCALAPPDATA");
#else
    char* confdir = getenv("HOME");
#endif
 char* conffile = malloc(sizeof(confdir)   sizeof("/.conf.json")   1);
strcpy(conffile, confdir);
strcat(conffile, "/.conf.json");

// And use conffile variable instead of CONFFILE macro.

So the example code will change to

// Compile with gcc -ljson-c
// libjson-c-dev is required
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <json-c/json.h>
#include <json-c/json_object.h>
#include <json-c/json_util.h>

struct config {
    char *a;
    char *b;
    char *c;
};

int create_config(struct config cfg, char* conffile) {
    struct json_object *jsonobj = json_object_new_object();
    json_object_object_add(jsonobj, "a", json_object_new_string(cfg.a));
    json_object_object_add(jsonobj, "b", json_object_new_string(cfg.b));
    json_object_object_add(jsonobj, "c", json_object_new_string(cfg.c));
    int retval = json_object_to_file_ext(conffile, jsonobj, JSON_C_TO_STRING_SPACED | JSON_C_TO_STRING_PRETTY);
    printf("Err: %s\n", json_util_get_last_err());
    return retval;
}

bool fexists(char *fname) {
    struct stat buffer;   
    return (stat (fname, &buffer) == 0);
}


int main(){
    ifdef _WIN32
        char* confdir = getenv("LOCALAPPDATA");
    #else
        char* confdir = getenv("HOME");
    #endif
    char* conffile = malloc(sizeof(confdir)   sizeof("/.conf.json")   1);
    strcpy(conffile, confdir);
    strcat(conffile, "/.conf.json");

    char *msg = "Do you want to create conffile? (y/n) ";
     if (!fexists(conffile)) {                                   // Now this works
         msg = "Do you want to overwrite conffile? (y/n) ";      // Now this works
     }                                                           // Now this works 

    printf("%s", msg);
    if (((a=getchar()) == 'y') || (a == 'Y')){
        char *a = "vala";
        char *b = "valb";
        char *c = "valc";
        struct config cfg = {a, b, c};
        printf("%d", create_config(cfg, conffile));
    }
}
  • Related