Saturday, July 9, 2016

Writing C

I have written a number of small C programs for generating cCode for LinuxCNC.  I have followed the typical Unix application model of command line arguments.  Of course for different programs you want different command line arguments, but writing fresh code each time to do this is annoying.  My solution is to pass a list of flags and pointers to the values:

/*
 * parseargs2.c
 *
 *  Created on: Jul 3, 2016
 *      Author: clayton
 */
#include
#include
#include "parseargs2.h"
#define TRUE 1
#define FALSE 0
typedef int boolean;


int parseArgs2(flagsStructType* flags, int flagsCount, char* flagBfr[])
{
boolean match;
const char* valueString;
int argvIndex; // index into flags array
int exitCode = 0;
int flagsIndex;

argvIndex = 1;
for(; flagBfr[argvIndex] != NULL; )
{
if (*flagBfr[argvIndex] == '-') // is this a flag?
{
match = FALSE; // have we matched an entry in flags?
for (flagsIndex = 0; !match && flagsIndex < flagsCount;
flagsIndex++)
{
if (0 == strcmp(flagBfr[argvIndex]+1, flags[flagsIndex].flag))
{
match = TRUE;
// get pointer to following value
int flagLength = 1+strlen(flags[flagsIndex].flag);
valueString = flagBfr[argvIndex+1];
sscanf(valueString, "%f", flags[flagsIndex].valueAddr);
argvIndex += 2;
}
}
}
else
{
fprintf(stderr, "invalid flag: %s\n", flagBfr[argvIndex]);
// Skip to next flag
argvIndex++;
}
}
return(exitCode);
};

The include file shared with the calling application:

/*
 * parseArgs2.h
 *
 *  Created on: Jul 3, 2016
 *      Author: clayton
 */

#ifndef PARSEARGS2_H_
#define PARSEARGS2_H_

typedef struct flagsTag
{
char* flag; // flag to match
float* valueAddr; // where the matching value goes
} flagsStructType;

#define _CountOf_(A) ((sizeof(A))/(sizeof(A[0])))
#endif /* PARSEARGS2_H_ */

An example caller:

/*
 * testparseArgs2.c
 *
 *  Created on: Jul 3, 2016
 *      Author: clayton
 */
#include
#include "parseargs2.h"
extern int parseArgs2(flagsStructType* flags, int flagsCount, char* flagBfr[]);


float xStart;
float xEnd;
flagsStructType flags[] =
{
{"xs", &xStart},
{"xe", &xEnd}
};

int main(int argc, char *argv[])
{
int exitCode;
int i;
for (i=0; i printf("argv[%d]=%s ", i, argv[i]);
printf ("\n");
printf("&xStart=%x\n", &xStart);
printf("&xEnd=%x\n", &xEnd);
exitCode = parseArgs2(flags, _CountOf_(flags), argv);
}


This is limited to float arguments, but adding an object type to the flagsStructType declaration would give more flexibility.

3 comments:

StormCchaser said...

Why not use getopt() ?

It is standard, easy to use and does a lot of the work for you.

Rick C said...

There's a library, getopt, for parsing command-line arguments, that might be userful to you.

Clayton Cramer said...

Forgot it existed.