4
\$\begingroup\$

I'd just like to get some pointers on my newbie-ish C here. The intention is to have an environment variable provide the "prefix" for any paths this app needs.

For example, APP_PREFIX could be /opt/app, a path the app wanted to get could be /etc/app.conf, and so app_path("/etc/app.conf") should return /opt/app/etc/app.conf.

I realise this is currently sensitive to leading/trailing slashes; I just wanted to make sure I'm on the right track with this basic stuff. Be as pedantic as you like – from outright bugs down to style and convention.

It compiles with no warnings on Mac OS X with gcc -Wall -pedantic ..., and does what I expect it to. On Linux, I had to compile with libbsd, and #include <bsd/string.h> for strlcpy() and strlcat().

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define APP_PREFIX_ENV_VAR "APP_PREFIX"

const char * app_path_prefix() {
    char * env_prefix = getenv(APP_PREFIX_ENV_VAR);
    if (env_prefix == NULL) {
        return "";
    } else {
        return env_prefix;
    }
}

char * app_path(char * in_path) {
    const char * prefix = app_path_prefix();
    size_t prefix_len = strlen(prefix);
    size_t out_size = prefix_len + strlen(in_path) + 1;
    char * out = malloc(out_size);

    strlcpy(out, prefix, prefix_len + 1);
    strlcat(out, in_path, out_size);
    return out;
}

int main(int argc, char ** argv) {
    char * path = app_path(argv[1]);
    printf("result: '%s'\n", path);
    free(path);
    return EXIT_SUCCESS;
}
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

All seems good.

As you mentioned it is sensitive to trailing slash being missing. I would just force that issue and always append one between the prefix and the path. An extra slash will not hurt but a missing one will.

Apart from not using C in the first place :-) all my other issues are simple stylistic ones that only 30% of people would agree (I always divide stylistic camps as 30% Side A, 30% side ~A, 40% don't care).

A tiny bit more white space to make it easier to read. But let me just say your code is not bad in that regards (just slightly less than I would use).

I don't want to recommend any particular style. But I can show you how I would have written it:

// Keep you includes sorted in alphabetical order
// Here it is not such a big deal but with big projects the list can get big
// and alphabetical order helps you find things in large lists.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define APP_PREFIX_ENV_VAR "APP_PREFIX"

const char * app_path_prefix()
{
    char * env_prefix = getenv(APP_PREFIX_ENV_VAR);
    return (env_prefix == NULL)
               ? ""
               : env_prefix;
}

char * app_path(char * in_path)
{
    /*
     * Some people really hate this.
     *
     * Others like myself really like lining up the '=' sign
     * Just do it locally with a set of calculations. I find it easier to see
     * both the lhs and the rhs of expression quickly.
     */
    char const* prefix     = app_path_prefix();
    size_t      prefix_len = strlen(prefix);
    size_t      out_size   = prefix_len + strlen(in_path) + 1;

    /* 
     * Dynamically allocated. Released to outside world it is the
     * responsibility of the caller to free this memory
     */
    char *      out        = malloc(out_size);

    strlcpy(out, prefix, prefix_len + 1);
    strlcat(out, in_path, out_size);
    return out;
}

int main(int argc, char ** argv)
{
    /* test */
    char * path = app_path(argv[1]);
    printf("result: '%s'\n", path);
    free(path);

    return EXIT_SUCCESS;
}
\$\endgroup\$
3
  • \$\begingroup\$ Thanks! Do feel free to expand on the style points more if you like though, with reasons. Then I can form my own opinions :) Whitespace: blank lines between variable defs and the rest of the function? \$\endgroup\$
    – Dan B
    Commented Feb 17, 2012 at 10:23
  • \$\begingroup\$ @DanB: Added more comments. \$\endgroup\$ Commented Feb 18, 2012 at 15:24
  • \$\begingroup\$ The conditional in app_path_prefix can be simplified to env_prefix ? env_prefix : "". Don't hesitate to exploit C's generalized Boolean conditionals. \$\endgroup\$
    – Anonymous
    Commented May 14, 2014 at 17:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.