Library for managing CLI flags

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
3
down vote

favorite












I'm pretty new to C, started learning it less than a month ago, the only language I had previous experience was Javascript.



Anyways, I wrote a library for dealing with CLI flags. It's not a serious project by any means, I wrote it for practice and fun.



It's composed of a source file and a header file (with declarations etc..). I'll list these functions then I'll try to describe them briefly. I didn't use array subscripting as I'm trying to gain a serious understanding of how pointers work etc...



libflagutil.c:



#include "../flagutil.h" //make sure definitions match declarations and protos etc..
#include "../butil.h" //terminal text styling
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

bool flag_present(int argc, char **argv, const char *flag)
/* a single flag is defined as present IF:
- an arg that exactly matches the provided `flag` string is found
- an arg that exactly matches the provided `flag` string BUT includes an `=` (and optionally somed data)
after it is found
*/
bool present = false;
for(char **cur_flag = argv; cur_flag < argv + argc; cur_flag++)

return present;


const Flag *flag_get(int argc, char **argv, const char *flag) !(*(flag + 1)))
printf("Invalid flag structure for flag " bold("%s") " passed to get_flag.n", flag);
return NULL;


static Flag internal; //static buffer of last-fetched flag

for(char **cur_flag = argv; cur_flag < argv + argc; cur_flag++)
if(strncmp(flag, *cur_flag, strlen(flag)) == 0)
char *char_after_flag = *cur_flag + strlen(flag);
if(*char_after_flag == '=' && *(char_after_flag + 1) != '')
internal.data = char_after_flag + 1;
internal.location = (const char **) cur_flag;
strncpy(internal.name, flag, strlen(flag) + 1);
else if(cur_flag + 1 && **(cur_flag + 1) != '-')
internal.data = *(cur_flag + 1);
internal.location = (const char **) cur_flag;
strncpy(internal.name, flag, strlen(flag) + 1);




return &internal;



void flag_startswith(int argc, char **argv, const char *start_string, Flag *storage)
/* assumes that storage is large enough to accomodate all valid flags */
//TODO: handle `=` within flag_string, for now function doesn't work with those flags
for(char **flag = argv; flag < argv + argc; flag++)
if(**flag != '-')
continue;
//First char isn't a `-`, skip arg


if(*(*flag + 1) == '-')
if(strncmp(*flag + 2, start_string, strlen(start_string)) == 0)
char flag_string[2 + strlen(*flag + 2) + 1];
strcpy(flag_string, "--");
strcpy(flag_string + 2, *flag + 2);

*storage = *f_get(flag_string);

else
if(strncmp(*flag + 1, start_string, strlen(start_string)) == 0)
char flag_string[1 + strlen(*flag + 1) + 1];
strcpy(flag_string, "-");
strcpy(flag_string + 1, *flag + 1);

*storage = *f_get(flag_string);



storage++;



char *flag_nextarg(signed int argc, char **argv)
//oversimplify fetching args from argv... (kinda useless)
static size_t counter = 0;
return *(argv + (counter++));



flagutil.h:



#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "./butil.h"

#pragma once

/*define these yourself if you'd like to use short version but use non-"standard"
names for main's 2 args
*/
#ifndef FLAGUTIL_ARGC_NAME
#define FLAGUTIL_ARGC_NAME argc
#endif

#ifndef FLAGUTIL_ARGV_NAME
#define FLAGUTIL_ARGV_NAME argv
#endif

/* expose functions as short versions taking less arguments, for easier usage */

#define f_present(s) flag_present(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s)
#define f_get(s) flag_get(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s)
#define f_startswith(s, g) flag_startswith(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s, g);
#define f_nextarg() flag_nextarg(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME)

struct flag
char name[100];
const char *data;
const char **location; //actual pointer within argv
;

typedef struct flag Flag;

//prototypes:
bool flag_present(int, char **, const char *);
const Flag *flag_get(int, char **, const char *);
void flag_startswith(int, char **, const char *, Flag *);
char *flag_easyArg(int, char **);


Currently all of the functions accept argc and argv as their first 2 arguments, but flagutil.h exposes these functions as macros with shorter names taking only the necessary arguments, and automatically feeding argc and argv (also defined as macros for compatibility in case of non-standard parameter names inside main).



All of the functions (except flag_startswith) take flag names in the form -flagName or --flagName.



Data is passed to flags in the form of -flagName=DATA or -flagName DATA.



bool flag_present(...): Returns true if provided flag exists within argv, false otherwise.



const Flag *flag_get(...): Returns a pointer to an internal static struct which holds data about a certain flag. The actual struct is defined in flagutil.h and holds the name of the flag, its data (if it has any) and a pointer to its location inside of argv.



void flag_startswith(...): Stores struct representations of all flags that start with start_string inside of provided array.



char *flag_nextarg(...): Pretty pointless, wrote it for fun.



I realize some of these functions are unsafe, sometimes broken etc.. but so far they get the job done and I'll be looking to improve them further. I'm looking for general advice, best practices, stuff to avoid, etc... I've tested it only with GCC and linux64 and it compiles without any warnings (-Wall, -Wextra).



Please disregard the use of bil() and bold(), they're macros for styling text inside the terminal..







share|improve this question

















  • 1




    Few more things but something eye catching is that static field. Imagine you're writing a curl clone and you have struct flag* method = flag_get(argc, argv, "X"); struct flag* body = flag_get(argc, argv, "d"); Now you want to check if user is trying to do a GET with a body: if (strncmp(method->data, "GET"...) && strlen(body->data))...it fails because both method and body points to the same data. Here I'd happily accept to return newly allocated memory (leaving the caller with its ownership unless you want to accept a struct flag* flag parameter).
    – Adriano Repetti
    Jul 30 at 11:59










  • @Adriano Repetti Thanks. I usually dereference the pointer returned by flag_get and store the data in a new struct: const struct flag method = *f_get(...). Iniyially I got the idea for using a static buffer from the gmtime function in time.h. Don't know if it's good practice tho. Thanks for the advice!
    – Bogdan M.
    Jul 30 at 12:12










  • It's not a bad practice but it's error-prone. You force the caller to be aware it has to make a copy and the function is not reentrant nor thread-safe (not that it matters in this case). More than that you're returning flag* which is not const and anyway, even if it was, it's a const pointer to variable data. Unless strongly required (and for a cli parser you shouldn't have any strict performance requirement) it's usually better to be on the safe side (a quick search of gmtime() on SO wil give you tons of questions related to this issue...)
    – Adriano Repetti
    Jul 30 at 12:33










  • Yeah I posted a question about gmtime on SO which is how I learned about it's behavior in the first place.
    – Bogdan M.
    Jul 30 at 12:36
















up vote
3
down vote

favorite












I'm pretty new to C, started learning it less than a month ago, the only language I had previous experience was Javascript.



Anyways, I wrote a library for dealing with CLI flags. It's not a serious project by any means, I wrote it for practice and fun.



It's composed of a source file and a header file (with declarations etc..). I'll list these functions then I'll try to describe them briefly. I didn't use array subscripting as I'm trying to gain a serious understanding of how pointers work etc...



libflagutil.c:



#include "../flagutil.h" //make sure definitions match declarations and protos etc..
#include "../butil.h" //terminal text styling
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

bool flag_present(int argc, char **argv, const char *flag)
/* a single flag is defined as present IF:
- an arg that exactly matches the provided `flag` string is found
- an arg that exactly matches the provided `flag` string BUT includes an `=` (and optionally somed data)
after it is found
*/
bool present = false;
for(char **cur_flag = argv; cur_flag < argv + argc; cur_flag++)

return present;


const Flag *flag_get(int argc, char **argv, const char *flag) !(*(flag + 1)))
printf("Invalid flag structure for flag " bold("%s") " passed to get_flag.n", flag);
return NULL;


static Flag internal; //static buffer of last-fetched flag

for(char **cur_flag = argv; cur_flag < argv + argc; cur_flag++)
if(strncmp(flag, *cur_flag, strlen(flag)) == 0)
char *char_after_flag = *cur_flag + strlen(flag);
if(*char_after_flag == '=' && *(char_after_flag + 1) != '')
internal.data = char_after_flag + 1;
internal.location = (const char **) cur_flag;
strncpy(internal.name, flag, strlen(flag) + 1);
else if(cur_flag + 1 && **(cur_flag + 1) != '-')
internal.data = *(cur_flag + 1);
internal.location = (const char **) cur_flag;
strncpy(internal.name, flag, strlen(flag) + 1);




return &internal;



void flag_startswith(int argc, char **argv, const char *start_string, Flag *storage)
/* assumes that storage is large enough to accomodate all valid flags */
//TODO: handle `=` within flag_string, for now function doesn't work with those flags
for(char **flag = argv; flag < argv + argc; flag++)
if(**flag != '-')
continue;
//First char isn't a `-`, skip arg


if(*(*flag + 1) == '-')
if(strncmp(*flag + 2, start_string, strlen(start_string)) == 0)
char flag_string[2 + strlen(*flag + 2) + 1];
strcpy(flag_string, "--");
strcpy(flag_string + 2, *flag + 2);

*storage = *f_get(flag_string);

else
if(strncmp(*flag + 1, start_string, strlen(start_string)) == 0)
char flag_string[1 + strlen(*flag + 1) + 1];
strcpy(flag_string, "-");
strcpy(flag_string + 1, *flag + 1);

*storage = *f_get(flag_string);



storage++;



char *flag_nextarg(signed int argc, char **argv)
//oversimplify fetching args from argv... (kinda useless)
static size_t counter = 0;
return *(argv + (counter++));



flagutil.h:



#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "./butil.h"

#pragma once

/*define these yourself if you'd like to use short version but use non-"standard"
names for main's 2 args
*/
#ifndef FLAGUTIL_ARGC_NAME
#define FLAGUTIL_ARGC_NAME argc
#endif

#ifndef FLAGUTIL_ARGV_NAME
#define FLAGUTIL_ARGV_NAME argv
#endif

/* expose functions as short versions taking less arguments, for easier usage */

#define f_present(s) flag_present(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s)
#define f_get(s) flag_get(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s)
#define f_startswith(s, g) flag_startswith(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s, g);
#define f_nextarg() flag_nextarg(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME)

struct flag
char name[100];
const char *data;
const char **location; //actual pointer within argv
;

typedef struct flag Flag;

//prototypes:
bool flag_present(int, char **, const char *);
const Flag *flag_get(int, char **, const char *);
void flag_startswith(int, char **, const char *, Flag *);
char *flag_easyArg(int, char **);


Currently all of the functions accept argc and argv as their first 2 arguments, but flagutil.h exposes these functions as macros with shorter names taking only the necessary arguments, and automatically feeding argc and argv (also defined as macros for compatibility in case of non-standard parameter names inside main).



All of the functions (except flag_startswith) take flag names in the form -flagName or --flagName.



Data is passed to flags in the form of -flagName=DATA or -flagName DATA.



bool flag_present(...): Returns true if provided flag exists within argv, false otherwise.



const Flag *flag_get(...): Returns a pointer to an internal static struct which holds data about a certain flag. The actual struct is defined in flagutil.h and holds the name of the flag, its data (if it has any) and a pointer to its location inside of argv.



void flag_startswith(...): Stores struct representations of all flags that start with start_string inside of provided array.



char *flag_nextarg(...): Pretty pointless, wrote it for fun.



I realize some of these functions are unsafe, sometimes broken etc.. but so far they get the job done and I'll be looking to improve them further. I'm looking for general advice, best practices, stuff to avoid, etc... I've tested it only with GCC and linux64 and it compiles without any warnings (-Wall, -Wextra).



Please disregard the use of bil() and bold(), they're macros for styling text inside the terminal..







share|improve this question

















  • 1




    Few more things but something eye catching is that static field. Imagine you're writing a curl clone and you have struct flag* method = flag_get(argc, argv, "X"); struct flag* body = flag_get(argc, argv, "d"); Now you want to check if user is trying to do a GET with a body: if (strncmp(method->data, "GET"...) && strlen(body->data))...it fails because both method and body points to the same data. Here I'd happily accept to return newly allocated memory (leaving the caller with its ownership unless you want to accept a struct flag* flag parameter).
    – Adriano Repetti
    Jul 30 at 11:59










  • @Adriano Repetti Thanks. I usually dereference the pointer returned by flag_get and store the data in a new struct: const struct flag method = *f_get(...). Iniyially I got the idea for using a static buffer from the gmtime function in time.h. Don't know if it's good practice tho. Thanks for the advice!
    – Bogdan M.
    Jul 30 at 12:12










  • It's not a bad practice but it's error-prone. You force the caller to be aware it has to make a copy and the function is not reentrant nor thread-safe (not that it matters in this case). More than that you're returning flag* which is not const and anyway, even if it was, it's a const pointer to variable data. Unless strongly required (and for a cli parser you shouldn't have any strict performance requirement) it's usually better to be on the safe side (a quick search of gmtime() on SO wil give you tons of questions related to this issue...)
    – Adriano Repetti
    Jul 30 at 12:33










  • Yeah I posted a question about gmtime on SO which is how I learned about it's behavior in the first place.
    – Bogdan M.
    Jul 30 at 12:36












up vote
3
down vote

favorite









up vote
3
down vote

favorite











I'm pretty new to C, started learning it less than a month ago, the only language I had previous experience was Javascript.



Anyways, I wrote a library for dealing with CLI flags. It's not a serious project by any means, I wrote it for practice and fun.



It's composed of a source file and a header file (with declarations etc..). I'll list these functions then I'll try to describe them briefly. I didn't use array subscripting as I'm trying to gain a serious understanding of how pointers work etc...



libflagutil.c:



#include "../flagutil.h" //make sure definitions match declarations and protos etc..
#include "../butil.h" //terminal text styling
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

bool flag_present(int argc, char **argv, const char *flag)
/* a single flag is defined as present IF:
- an arg that exactly matches the provided `flag` string is found
- an arg that exactly matches the provided `flag` string BUT includes an `=` (and optionally somed data)
after it is found
*/
bool present = false;
for(char **cur_flag = argv; cur_flag < argv + argc; cur_flag++)

return present;


const Flag *flag_get(int argc, char **argv, const char *flag) !(*(flag + 1)))
printf("Invalid flag structure for flag " bold("%s") " passed to get_flag.n", flag);
return NULL;


static Flag internal; //static buffer of last-fetched flag

for(char **cur_flag = argv; cur_flag < argv + argc; cur_flag++)
if(strncmp(flag, *cur_flag, strlen(flag)) == 0)
char *char_after_flag = *cur_flag + strlen(flag);
if(*char_after_flag == '=' && *(char_after_flag + 1) != '')
internal.data = char_after_flag + 1;
internal.location = (const char **) cur_flag;
strncpy(internal.name, flag, strlen(flag) + 1);
else if(cur_flag + 1 && **(cur_flag + 1) != '-')
internal.data = *(cur_flag + 1);
internal.location = (const char **) cur_flag;
strncpy(internal.name, flag, strlen(flag) + 1);




return &internal;



void flag_startswith(int argc, char **argv, const char *start_string, Flag *storage)
/* assumes that storage is large enough to accomodate all valid flags */
//TODO: handle `=` within flag_string, for now function doesn't work with those flags
for(char **flag = argv; flag < argv + argc; flag++)
if(**flag != '-')
continue;
//First char isn't a `-`, skip arg


if(*(*flag + 1) == '-')
if(strncmp(*flag + 2, start_string, strlen(start_string)) == 0)
char flag_string[2 + strlen(*flag + 2) + 1];
strcpy(flag_string, "--");
strcpy(flag_string + 2, *flag + 2);

*storage = *f_get(flag_string);

else
if(strncmp(*flag + 1, start_string, strlen(start_string)) == 0)
char flag_string[1 + strlen(*flag + 1) + 1];
strcpy(flag_string, "-");
strcpy(flag_string + 1, *flag + 1);

*storage = *f_get(flag_string);



storage++;



char *flag_nextarg(signed int argc, char **argv)
//oversimplify fetching args from argv... (kinda useless)
static size_t counter = 0;
return *(argv + (counter++));



flagutil.h:



#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "./butil.h"

#pragma once

/*define these yourself if you'd like to use short version but use non-"standard"
names for main's 2 args
*/
#ifndef FLAGUTIL_ARGC_NAME
#define FLAGUTIL_ARGC_NAME argc
#endif

#ifndef FLAGUTIL_ARGV_NAME
#define FLAGUTIL_ARGV_NAME argv
#endif

/* expose functions as short versions taking less arguments, for easier usage */

#define f_present(s) flag_present(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s)
#define f_get(s) flag_get(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s)
#define f_startswith(s, g) flag_startswith(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s, g);
#define f_nextarg() flag_nextarg(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME)

struct flag
char name[100];
const char *data;
const char **location; //actual pointer within argv
;

typedef struct flag Flag;

//prototypes:
bool flag_present(int, char **, const char *);
const Flag *flag_get(int, char **, const char *);
void flag_startswith(int, char **, const char *, Flag *);
char *flag_easyArg(int, char **);


Currently all of the functions accept argc and argv as their first 2 arguments, but flagutil.h exposes these functions as macros with shorter names taking only the necessary arguments, and automatically feeding argc and argv (also defined as macros for compatibility in case of non-standard parameter names inside main).



All of the functions (except flag_startswith) take flag names in the form -flagName or --flagName.



Data is passed to flags in the form of -flagName=DATA or -flagName DATA.



bool flag_present(...): Returns true if provided flag exists within argv, false otherwise.



const Flag *flag_get(...): Returns a pointer to an internal static struct which holds data about a certain flag. The actual struct is defined in flagutil.h and holds the name of the flag, its data (if it has any) and a pointer to its location inside of argv.



void flag_startswith(...): Stores struct representations of all flags that start with start_string inside of provided array.



char *flag_nextarg(...): Pretty pointless, wrote it for fun.



I realize some of these functions are unsafe, sometimes broken etc.. but so far they get the job done and I'll be looking to improve them further. I'm looking for general advice, best practices, stuff to avoid, etc... I've tested it only with GCC and linux64 and it compiles without any warnings (-Wall, -Wextra).



Please disregard the use of bil() and bold(), they're macros for styling text inside the terminal..







share|improve this question













I'm pretty new to C, started learning it less than a month ago, the only language I had previous experience was Javascript.



Anyways, I wrote a library for dealing with CLI flags. It's not a serious project by any means, I wrote it for practice and fun.



It's composed of a source file and a header file (with declarations etc..). I'll list these functions then I'll try to describe them briefly. I didn't use array subscripting as I'm trying to gain a serious understanding of how pointers work etc...



libflagutil.c:



#include "../flagutil.h" //make sure definitions match declarations and protos etc..
#include "../butil.h" //terminal text styling
#include <stdio.h>
#include <stdbool.h>
#include <string.h>

bool flag_present(int argc, char **argv, const char *flag)
/* a single flag is defined as present IF:
- an arg that exactly matches the provided `flag` string is found
- an arg that exactly matches the provided `flag` string BUT includes an `=` (and optionally somed data)
after it is found
*/
bool present = false;
for(char **cur_flag = argv; cur_flag < argv + argc; cur_flag++)

return present;


const Flag *flag_get(int argc, char **argv, const char *flag) !(*(flag + 1)))
printf("Invalid flag structure for flag " bold("%s") " passed to get_flag.n", flag);
return NULL;


static Flag internal; //static buffer of last-fetched flag

for(char **cur_flag = argv; cur_flag < argv + argc; cur_flag++)
if(strncmp(flag, *cur_flag, strlen(flag)) == 0)
char *char_after_flag = *cur_flag + strlen(flag);
if(*char_after_flag == '=' && *(char_after_flag + 1) != '')
internal.data = char_after_flag + 1;
internal.location = (const char **) cur_flag;
strncpy(internal.name, flag, strlen(flag) + 1);
else if(cur_flag + 1 && **(cur_flag + 1) != '-')
internal.data = *(cur_flag + 1);
internal.location = (const char **) cur_flag;
strncpy(internal.name, flag, strlen(flag) + 1);




return &internal;



void flag_startswith(int argc, char **argv, const char *start_string, Flag *storage)
/* assumes that storage is large enough to accomodate all valid flags */
//TODO: handle `=` within flag_string, for now function doesn't work with those flags
for(char **flag = argv; flag < argv + argc; flag++)
if(**flag != '-')
continue;
//First char isn't a `-`, skip arg


if(*(*flag + 1) == '-')
if(strncmp(*flag + 2, start_string, strlen(start_string)) == 0)
char flag_string[2 + strlen(*flag + 2) + 1];
strcpy(flag_string, "--");
strcpy(flag_string + 2, *flag + 2);

*storage = *f_get(flag_string);

else
if(strncmp(*flag + 1, start_string, strlen(start_string)) == 0)
char flag_string[1 + strlen(*flag + 1) + 1];
strcpy(flag_string, "-");
strcpy(flag_string + 1, *flag + 1);

*storage = *f_get(flag_string);



storage++;



char *flag_nextarg(signed int argc, char **argv)
//oversimplify fetching args from argv... (kinda useless)
static size_t counter = 0;
return *(argv + (counter++));



flagutil.h:



#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include "./butil.h"

#pragma once

/*define these yourself if you'd like to use short version but use non-"standard"
names for main's 2 args
*/
#ifndef FLAGUTIL_ARGC_NAME
#define FLAGUTIL_ARGC_NAME argc
#endif

#ifndef FLAGUTIL_ARGV_NAME
#define FLAGUTIL_ARGV_NAME argv
#endif

/* expose functions as short versions taking less arguments, for easier usage */

#define f_present(s) flag_present(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s)
#define f_get(s) flag_get(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s)
#define f_startswith(s, g) flag_startswith(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME, s, g);
#define f_nextarg() flag_nextarg(FLAGUTIL_ARGC_NAME, FLAGUTIL_ARGV_NAME)

struct flag
char name[100];
const char *data;
const char **location; //actual pointer within argv
;

typedef struct flag Flag;

//prototypes:
bool flag_present(int, char **, const char *);
const Flag *flag_get(int, char **, const char *);
void flag_startswith(int, char **, const char *, Flag *);
char *flag_easyArg(int, char **);


Currently all of the functions accept argc and argv as their first 2 arguments, but flagutil.h exposes these functions as macros with shorter names taking only the necessary arguments, and automatically feeding argc and argv (also defined as macros for compatibility in case of non-standard parameter names inside main).



All of the functions (except flag_startswith) take flag names in the form -flagName or --flagName.



Data is passed to flags in the form of -flagName=DATA or -flagName DATA.



bool flag_present(...): Returns true if provided flag exists within argv, false otherwise.



const Flag *flag_get(...): Returns a pointer to an internal static struct which holds data about a certain flag. The actual struct is defined in flagutil.h and holds the name of the flag, its data (if it has any) and a pointer to its location inside of argv.



void flag_startswith(...): Stores struct representations of all flags that start with start_string inside of provided array.



char *flag_nextarg(...): Pretty pointless, wrote it for fun.



I realize some of these functions are unsafe, sometimes broken etc.. but so far they get the job done and I'll be looking to improve them further. I'm looking for general advice, best practices, stuff to avoid, etc... I've tested it only with GCC and linux64 and it compiles without any warnings (-Wall, -Wextra).



Please disregard the use of bil() and bold(), they're macros for styling text inside the terminal..









share|improve this question












share|improve this question




share|improve this question








edited Jul 30 at 5:32









200_success

123k14143398




123k14143398









asked Jul 29 at 21:55









Bogdan M.

1425




1425







  • 1




    Few more things but something eye catching is that static field. Imagine you're writing a curl clone and you have struct flag* method = flag_get(argc, argv, "X"); struct flag* body = flag_get(argc, argv, "d"); Now you want to check if user is trying to do a GET with a body: if (strncmp(method->data, "GET"...) && strlen(body->data))...it fails because both method and body points to the same data. Here I'd happily accept to return newly allocated memory (leaving the caller with its ownership unless you want to accept a struct flag* flag parameter).
    – Adriano Repetti
    Jul 30 at 11:59










  • @Adriano Repetti Thanks. I usually dereference the pointer returned by flag_get and store the data in a new struct: const struct flag method = *f_get(...). Iniyially I got the idea for using a static buffer from the gmtime function in time.h. Don't know if it's good practice tho. Thanks for the advice!
    – Bogdan M.
    Jul 30 at 12:12










  • It's not a bad practice but it's error-prone. You force the caller to be aware it has to make a copy and the function is not reentrant nor thread-safe (not that it matters in this case). More than that you're returning flag* which is not const and anyway, even if it was, it's a const pointer to variable data. Unless strongly required (and for a cli parser you shouldn't have any strict performance requirement) it's usually better to be on the safe side (a quick search of gmtime() on SO wil give you tons of questions related to this issue...)
    – Adriano Repetti
    Jul 30 at 12:33










  • Yeah I posted a question about gmtime on SO which is how I learned about it's behavior in the first place.
    – Bogdan M.
    Jul 30 at 12:36












  • 1




    Few more things but something eye catching is that static field. Imagine you're writing a curl clone and you have struct flag* method = flag_get(argc, argv, "X"); struct flag* body = flag_get(argc, argv, "d"); Now you want to check if user is trying to do a GET with a body: if (strncmp(method->data, "GET"...) && strlen(body->data))...it fails because both method and body points to the same data. Here I'd happily accept to return newly allocated memory (leaving the caller with its ownership unless you want to accept a struct flag* flag parameter).
    – Adriano Repetti
    Jul 30 at 11:59










  • @Adriano Repetti Thanks. I usually dereference the pointer returned by flag_get and store the data in a new struct: const struct flag method = *f_get(...). Iniyially I got the idea for using a static buffer from the gmtime function in time.h. Don't know if it's good practice tho. Thanks for the advice!
    – Bogdan M.
    Jul 30 at 12:12










  • It's not a bad practice but it's error-prone. You force the caller to be aware it has to make a copy and the function is not reentrant nor thread-safe (not that it matters in this case). More than that you're returning flag* which is not const and anyway, even if it was, it's a const pointer to variable data. Unless strongly required (and for a cli parser you shouldn't have any strict performance requirement) it's usually better to be on the safe side (a quick search of gmtime() on SO wil give you tons of questions related to this issue...)
    – Adriano Repetti
    Jul 30 at 12:33










  • Yeah I posted a question about gmtime on SO which is how I learned about it's behavior in the first place.
    – Bogdan M.
    Jul 30 at 12:36







1




1




Few more things but something eye catching is that static field. Imagine you're writing a curl clone and you have struct flag* method = flag_get(argc, argv, "X"); struct flag* body = flag_get(argc, argv, "d"); Now you want to check if user is trying to do a GET with a body: if (strncmp(method->data, "GET"...) && strlen(body->data))...it fails because both method and body points to the same data. Here I'd happily accept to return newly allocated memory (leaving the caller with its ownership unless you want to accept a struct flag* flag parameter).
– Adriano Repetti
Jul 30 at 11:59




Few more things but something eye catching is that static field. Imagine you're writing a curl clone and you have struct flag* method = flag_get(argc, argv, "X"); struct flag* body = flag_get(argc, argv, "d"); Now you want to check if user is trying to do a GET with a body: if (strncmp(method->data, "GET"...) && strlen(body->data))...it fails because both method and body points to the same data. Here I'd happily accept to return newly allocated memory (leaving the caller with its ownership unless you want to accept a struct flag* flag parameter).
– Adriano Repetti
Jul 30 at 11:59












@Adriano Repetti Thanks. I usually dereference the pointer returned by flag_get and store the data in a new struct: const struct flag method = *f_get(...). Iniyially I got the idea for using a static buffer from the gmtime function in time.h. Don't know if it's good practice tho. Thanks for the advice!
– Bogdan M.
Jul 30 at 12:12




@Adriano Repetti Thanks. I usually dereference the pointer returned by flag_get and store the data in a new struct: const struct flag method = *f_get(...). Iniyially I got the idea for using a static buffer from the gmtime function in time.h. Don't know if it's good practice tho. Thanks for the advice!
– Bogdan M.
Jul 30 at 12:12












It's not a bad practice but it's error-prone. You force the caller to be aware it has to make a copy and the function is not reentrant nor thread-safe (not that it matters in this case). More than that you're returning flag* which is not const and anyway, even if it was, it's a const pointer to variable data. Unless strongly required (and for a cli parser you shouldn't have any strict performance requirement) it's usually better to be on the safe side (a quick search of gmtime() on SO wil give you tons of questions related to this issue...)
– Adriano Repetti
Jul 30 at 12:33




It's not a bad practice but it's error-prone. You force the caller to be aware it has to make a copy and the function is not reentrant nor thread-safe (not that it matters in this case). More than that you're returning flag* which is not const and anyway, even if it was, it's a const pointer to variable data. Unless strongly required (and for a cli parser you shouldn't have any strict performance requirement) it's usually better to be on the safe side (a quick search of gmtime() on SO wil give you tons of questions related to this issue...)
– Adriano Repetti
Jul 30 at 12:33












Yeah I posted a question about gmtime on SO which is how I learned about it's behavior in the first place.
– Bogdan M.
Jul 30 at 12:36




Yeah I posted a question about gmtime on SO which is how I learned about it's behavior in the first place.
– Bogdan M.
Jul 30 at 12:36















active

oldest

votes











Your Answer




StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");

StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f200556%2flibrary-for-managing-cli-flags%23new-answer', 'question_page');

);

Post as a guest



































active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes










 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f200556%2flibrary-for-managing-cli-flags%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

Greedy Best First Search implementation in Rust

Function to Return a JSON Like Objects Using VBA Collections and Arrays

C++11 CLH Lock Implementation