Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
- devel

env:
BUILD_TYPE: Release
BUILD_TYPE: Debug

jobs:
build:
Expand All @@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@v3

- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -S . -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install
run: cmake -B ${{github.workspace}}/build -S . -L -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install

- name: Build
run: cmake --build ${{github.workspace}}/build --target install --config ${{env.BUILD_TYPE}}
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
All changes to the repository will be reported here

## [0.2.0]
### Changed
- Debug build type in CI
### Added
- Struct for opt and arg

## [0.1.2]
### Changed
- Move static variables in header
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Author Marco M. Mosca, email: marcomichele.mosca@gmail.com
]]

cmake_minimum_required(VERSION 3.5.0)
project(cmd-api VERSION 0.1.2 LANGUAGES C)
project(cmd-api VERSION 0.2.0 LANGUAGES C)

include(CTest)

Expand Down
73 changes: 60 additions & 13 deletions cmd-api/include/cmd-api.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,72 @@ Author Marco M. Mosca, email: marcomichele.mosca@gmail.com
#ifndef CMD_H_
#define CMD_H_

#ifdef DEBUG
#define PRINT_DATA() printf("CURRENT ---- OPTIND: %d ---- ARGVIND: %d ---- OPTION: %c ---- OPTARG: %s\n", optind, argvind, argv[optind][1], myoptarg);
#define PRINT_DATAW() printf("CURRENT ---- OPTIND: %d ---- ARGVIND: %d ---- OPTION: %s ---- OPTARG: %s\n", optind, argvind, argv[optind], myoptarg);
#else
#define PRINT_DATA() {};
#define PRINT_DATAW() {};
#endif

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

static int optind = 1, argvind = 2, formatind = -1, argformatind = 0;
static char *optargW = NULL, *curr_option;
/**
* Struct for command line parser
* - opt -- Current option detected
* - arg -- Current option's argument
*/
typedef struct optarg {
char *opt;
char *arg;
} optarg_t;

/**
* Set of variables for cmd-api-c
* - optind -- Index of the option.
* Starts with the first word after the executable.
*/
static int optind = 1;

int isCharInString(char c, char* str);
/**
* Find the shortest string among s1 and s2 in the other.
\param s1 string 1
\param s2 string 2
\param from index of the longest string where to start
comparing the shortest string.

\retval 1 -- both strings are equal or the shortest is contained in the longest
\retval 0 -- the shortest string is not contained in the longest*/
int AreStringsEqualFrom(const char* s1, const char* s2, int from);

/**
\param sub substring to search for in str
\param str string that is searched for substring sub

\retval i -- index of str where sub substring starts
\retval -1 -- no substring found in str*/
int isSubstring(char* sub, char* str);
char* strsep(char** elem_pointer, char* pattern);
char* getoptW(int argc, char** argv, char* format);

/** Cycles on the command line parameters and arguments
and returns the current option and its argument.
This function should be used in a while loop and
the returned struct should be freed after each call.
Usage:
while ((optarg = getoptW(argc, argv, "opt1:|opt2:|")) != NULL) {
if (strcmp(optarg->opt, "opt1") == 0) {
printf("%s\n", optarg->arg);
continue;
}
if (strcmp(optarg->opt, "opt2") == 0) {
printf("%s\n", optarg->arg);
continue;
}
free(optarg);
}
\param argc number of command line items (related to main argc)
\param argv array of command line words (related to main argv)
\param format format string, which contains the option name
followed by special characters to specify whether...:
':' -> ...the option expects an argument
'|' -> ...the end of the option

\retval optarg -- struct with current option and argument.
Needs deallocation after each getoptW call.
\retval NULL -- end of command line */
optarg_t* getoptW(int argc, char** argv, char* format);

#endif /* CMD_H_ */
174 changes: 50 additions & 124 deletions cmd-api/src/cmd-api.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,9 @@ Author Marco M. Mosca, email: marcomichele.mosca@gmail.com
*/
#include "cmd-api.h"


int isCharInString(char c, char* str) {
int i = 0, len=strlen(str);
while (i < len) {
if (str[i] == c) return i;/* return the index */
i++;
}
return -1; /*not found*/
}

int AreStringsEqualFrom(const char* s1, const char* s2,int from) {
int len1, len2, i=0, lensub, lenbig;
const char* bigger, *smaller;
const char *bigger, *smaller;

if ((s1 == NULL) || (s2 == NULL)) return 0;

Expand Down Expand Up @@ -63,7 +53,7 @@ int isSubstring(char* sub, char* str) {
int sublen= strlen(sub), len = strlen(str), i=0;

while (i <= len-sublen) {
if (AreStringsEqualFrom(sub, str,0)) {
if (AreStringsEqualFrom(sub, str, 0)) {
return i;
}
i++;
Expand All @@ -73,130 +63,66 @@ int isSubstring(char* sub, char* str) {
return -1;
}

char* strsep(char** elem_pointer, char* pattern) {
char* current_tkn, *p;
int i = 0, j, len;

if (*elem_pointer == NULL || pattern == NULL) exit(EXIT_FAILURE);
len = strlen(*elem_pointer); /*len of the entire string*/
p = *elem_pointer;
while ((isCharInString(p[i], pattern) == -1) && (i < len)) {
i++;
}
len = i; /*len of the first token*/
current_tkn = (char*) malloc(len * sizeof(char)+1);

j = 0;
for (i = 0; i < len; i++) {
if (p[i] != ' ') {
current_tkn[j] = p[i];
j++;
}
}
current_tkn[j] = '\0';
optarg_t* getoptW(int argc, char** argv, char* format) {
/**
* - argvind -- Index of the option's argument.
* Start with the second word after the executable.
* - formatind -- Index of the option in the format string
* - argformatind -- Starting index of the argument types in the format string
*/
int argvind, formatind, argformatind;
optarg_t* optarg = (optarg_t*)malloc(sizeof(optarg_t));

*elem_pointer += (len+1);
return current_tkn;
}

char* getoptW(int argc, char** argv, char* format) {

/*if optind is one means that there are no more options*/
if (optind == -1) {
return NULL;
}

/*if optind goes over the number of argument commandline*/
if (optind > argc - 1) {
PRINT_DATAW();
puts("Error in parameters number!");
return NULL;
exit(EXIT_FAILURE);
}
if (argv[optind][0] != '-') {
PRINT_DATAW();
puts("It is not an option!");
puts("It is not an option: missing dash");
exit(EXIT_FAILURE);
}
optarg->opt = ++argv[optind];
if ((formatind = isSubstring(optarg->opt, format)) == -1) {
optarg->arg = NULL;
puts("Unknown option!");
exit(EXIT_FAILURE);
}

curr_option = ++argv[optind];
if ((formatind = isSubstring(argv[optind], format)) >= 0) {
argformatind = formatind + strlen(argv[optind]);
/*Format substring is not at the end of the format line*/
if (argformatind < (int)strlen(format)) {
argvind = optind + 1;
/*if the argument index (argvind) in the array is not out of bounds*/
if (argvind <= argc - 1) {
/*if there is a ':' in format string, argument is expected after*/
if (format[argformatind] == ':') {
/*argument expected, update the optargW*/
if (argv[argvind][0] != '-') {
optargW = argv[argvind];
PRINT_DATAW();
optind += 2;
}
/*there is '-' in the argument*/
else
{
optargW = argv[argvind];
PRINT_DATAW();
puts("This option should have a parameter!");
exit(EXIT_FAILURE);
}
}
/*No argument expected for optind option*/
else {

/*check forward if there is no option*/
if (argv[argvind][0] != '-') {
optargW = argv[argvind];
PRINT_DATAW();
puts("This option must not have a parameter!");
exit(EXIT_FAILURE);
}

if (format[argformatind] != '|') {
PRINT_DATAW();
puts("Format and input are not valid!");
exit(EXIT_FAILURE);
}
optargW = NULL;
PRINT_DATAW();
optind++;
}
}
/*if the argument index (argvind) in the array is out of bounds*/
else {
/*No arguments expected in format*/
if (format[argformatind] != '|') {
PRINT_DATAW();
puts("Format and input are not valid!");
exit(EXIT_FAILURE);
}
optargW = NULL;
PRINT_DATAW();
optind++;
}

}
/*Format substring is at the end of the format line*/
else {
if (format[argformatind] != '|') {
PRINT_DATAW();
puts("Format and input are not valid!");
exit(EXIT_FAILURE);
}
optargW = NULL;
PRINT_DATAW();
optind++;
}

if (optind > argc - 1) optind = -1;
return curr_option;
argvind = optind + 1;
argformatind = formatind + strlen(optarg->opt);
if ((argvind > argc - 1) && (format[argformatind] != '|')) {
puts("Missing end bar for the last option in format string");
exit(EXIT_FAILURE);
}
else {
optargW = NULL;
PRINT_DATAW();
puts("Unknown option!");
if (argformatind >= (int)strlen(format)) {
puts("Format string is wrong at the end");
exit(EXIT_FAILURE);
}
if ((format[argformatind] == ':') && (argv[argvind][0] == '-')) {
puts("Argument expected when : is in format string");
exit(EXIT_FAILURE);
}
if ((format[argformatind] != ':') && (argv[argvind][0] != '-')) {
puts("Argument not expected when : is not in format string");
exit(EXIT_FAILURE);
}
if (format[argformatind] == ':') {
optarg->arg = argv[argvind];
optind += 2;
++argformatind;
} else {
optarg->arg = NULL;
++optind;
}

if (format[argformatind] != '|') {
puts("Missing end bar in option format");
exit(EXIT_FAILURE);
}

if (optind > argc - 1) optind = -1;
return optarg;
}
16 changes: 8 additions & 8 deletions tests/longopt_basic.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,24 @@ along with this program. If not, see https://www.gnu.org/licenses/.
Author Marco M. Mosca, email: marcomichele.mosca@gmail.com
*/
#include "cmd-api.h"
#include "string.h"
#include "assert.h"


void test_longopt_basic()
{
char* arr[] = {"exe", "-opt1", "val1", "-opt2", "val2"};
char* w;
char* arr[] = {"exe", "-opt1", "val1", "-opt2", "val2"};
optarg_t* optarg;

while ((w = getoptW(5, arr, "opt1:|opt2:|")) != NULL) {
if (strcmp(w, "opt1") == 0) {
assert(strcmp(optargW, "val1") == 0);
while ((optarg = getoptW(5, arr, "opt1:|opt2:|")) != NULL) {
if (strcmp(optarg->opt, "opt1") == 0) {
assert(strcmp(optarg->arg, "val1") == 0);
continue;
}
if (strcmp(w, "opt2") == 0) {
assert(strcmp(optargW, "val2") == 0);
if (strcmp(optarg->opt, "opt2") == 0) {
assert(strcmp(optarg->arg, "val2") == 0);
continue;
}
free(optarg);
}
}

Expand Down
4 changes: 2 additions & 2 deletions tests/longopt_format_missedbar_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ Author Marco M. Mosca, email: marcomichele.mosca@gmail.com
void test_longopt_format_missedbar_error()
{
char* arr[] = {"exe", "-opt1", "-opt2", "val2"};
char* w;
optarg_t* optarg;

while ((w = getoptW(5, arr, "opt1opt2:|")) != NULL);
while ((optarg = getoptW(5, arr, "opt1opt2:|")) != NULL);
}

int main()
Expand Down
4 changes: 2 additions & 2 deletions tests/longopt_format_missedendbar_error.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ Author Marco M. Mosca, email: marcomichele.mosca@gmail.com
void test_longopt_format_missedendbar_error()
{
char* arr[] = {"exe", "-opt1", "val1", "-opt2"};
char* w;
optarg_t* optarg;

while ((w = getoptW(4, arr, "opt1:|opt2")) != NULL);
while ((optarg = getoptW(4, arr, "opt1:|opt2")) != NULL);
}

int main()
Expand Down
Loading