Move opts/
into util/opts/
This commit is contained in:
26
util/opts/control.c
Normal file
26
util/opts/control.c
Normal file
@ -0,0 +1,26 @@
|
||||
#include "control.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int device_option_normalize_name(const char *in, char *outp)
|
||||
{
|
||||
// The output is always shorter, so `outp=in`
|
||||
// colour_correction_matrix => colourcorrectionmatrix
|
||||
// Colour Correction Matrix => colourcorrectionmatrix
|
||||
// ColourCorrectionMatrix => colourcorrectionmatrix
|
||||
|
||||
char *out = outp;
|
||||
|
||||
while (*in) {
|
||||
if (isalnum(*in)) {
|
||||
*out++ = tolower(*in++);
|
||||
} else {
|
||||
in++;
|
||||
}
|
||||
}
|
||||
|
||||
*out++ = 0;
|
||||
return out - outp;
|
||||
}
|
1
util/opts/control.h
Normal file
1
util/opts/control.h
Normal file
@ -0,0 +1 @@
|
||||
int device_option_normalize_name(const char *in, char *out);
|
21
util/opts/fourcc.c
Normal file
21
util/opts/fourcc.c
Normal file
@ -0,0 +1,21 @@
|
||||
#include "fourcc.h"
|
||||
|
||||
fourcc_string fourcc_to_string(unsigned format)
|
||||
{
|
||||
fourcc_string fourcc;
|
||||
char *ptr = fourcc.buf;
|
||||
*ptr++ = format & 0x7F;
|
||||
*ptr++ = (format >> 8) & 0x7F;
|
||||
*ptr++ = (format >> 16) & 0x7F;
|
||||
*ptr++ = (format >> 24) & 0x7F;
|
||||
if (format & ((unsigned)1 << 31)) {
|
||||
*ptr++ = '-';
|
||||
*ptr++ = 'B';
|
||||
*ptr++ = 'E';
|
||||
*ptr++ = '\0';
|
||||
} else {
|
||||
*ptr++ = '\0';
|
||||
}
|
||||
*ptr++ = 0;
|
||||
return fourcc;
|
||||
}
|
10
util/opts/fourcc.h
Normal file
10
util/opts/fourcc.h
Normal file
@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
#include <linux/videodev2.h>
|
||||
|
||||
typedef struct {
|
||||
char buf[10];
|
||||
} fourcc_string;
|
||||
|
||||
fourcc_string fourcc_to_string(unsigned format);
|
103
util/opts/log.c
Normal file
103
util/opts/log.c
Normal file
@ -0,0 +1,103 @@
|
||||
#include "util/opts/log.h"
|
||||
#include "util/opts/opts.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
char *
|
||||
strstrn(const char *s, const char *find, size_t len)
|
||||
{
|
||||
char c, sc;
|
||||
if ((c = *find++) != 0) {
|
||||
len--;
|
||||
|
||||
do {
|
||||
do {
|
||||
if ((sc = *s++) == 0)
|
||||
return (NULL);
|
||||
} while (sc != c);
|
||||
} while (strncmp(s, find, len) != 0);
|
||||
s--;
|
||||
}
|
||||
return ((char *)s);
|
||||
}
|
||||
|
||||
bool filter_log(const char *filename)
|
||||
{
|
||||
if (!log_options.filter[0])
|
||||
return false;
|
||||
|
||||
const char *ptr = log_options.filter;
|
||||
do {
|
||||
const char *next = strchr(ptr, OPTION_VALUE_LIST_SEP[0]);
|
||||
if (!next)
|
||||
next = ptr + strlen(ptr);
|
||||
|
||||
if(strstrn(filename, ptr, next - ptr))
|
||||
return true;
|
||||
|
||||
ptr = next;
|
||||
} while(*ptr++);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int shrink_to_block(int size, int block)
|
||||
{
|
||||
return size / block * block;
|
||||
}
|
||||
|
||||
uint64_t get_time_us(clockid_t clock, struct timespec *ts, struct timeval *tv, int64_t delays_us)
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
if (clock != CLOCK_FROM_PARAMS) {
|
||||
clock_gettime(clock, &now);
|
||||
} else if (ts) {
|
||||
now = *ts;
|
||||
} else if (tv) {
|
||||
now.tv_sec = tv->tv_sec;
|
||||
now.tv_nsec = tv->tv_usec * 1000;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (delays_us > 0) {
|
||||
#define NS_IN_S (1000LL * 1000LL * 1000LL)
|
||||
int64_t nsec = now.tv_nsec + delays_us * 1000LL;
|
||||
now.tv_nsec = nsec % NS_IN_S;
|
||||
now.tv_sec += nsec / NS_IN_S;
|
||||
}
|
||||
|
||||
if (ts) {
|
||||
*ts = now;
|
||||
}
|
||||
if (tv) {
|
||||
tv->tv_sec = now.tv_sec;
|
||||
tv->tv_usec = now.tv_nsec / 1000;
|
||||
}
|
||||
return now.tv_sec * 1000000LL + now.tv_nsec / 1000;
|
||||
}
|
||||
|
||||
uint64_t get_monotonic_time_us(struct timespec *ts, struct timeval *tv)
|
||||
{
|
||||
return get_time_us(CLOCK_MONOTONIC, ts, tv, 0);
|
||||
}
|
||||
|
||||
int ioctl_retried(const char *name, int fd, int request, void *arg)
|
||||
{
|
||||
#define MAX_RETRIES 4
|
||||
|
||||
int retries = 4;
|
||||
int ret = -1;
|
||||
|
||||
while (retries-- > 0) {
|
||||
ret = ioctl(fd, request, arg);
|
||||
if (errno != EINTR && errno != EAGAIN && errno != ETIMEDOUT)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ret && retries <= 0) {
|
||||
LOG_PERROR(NULL, "%s: ioctl(%08x) retried %u times; giving up", name, request, MAX_RETRIES);
|
||||
}
|
||||
return ret;
|
||||
}
|
60
util/opts/log.h
Normal file
60
util/opts/log.h
Normal file
@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#define __FILENAME__ __FILE__
|
||||
|
||||
typedef struct log_options_s {
|
||||
bool debug;
|
||||
bool verbose;
|
||||
char filter[256];
|
||||
} log_options_t;
|
||||
|
||||
extern log_options_t log_options;
|
||||
|
||||
#define MIN(a, b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a, b) ((a) > (b) ? (a) : (b))
|
||||
|
||||
bool filter_log(const char *filename);
|
||||
|
||||
// assumes that name is first item
|
||||
#define dev_name(dev) (dev ? *(const char**)dev : "?")
|
||||
#define LOG_ERROR(dev, _msg, ...) do { fprintf(stderr, "%s: %s: " _msg "\n", __FILENAME__, dev_name(dev), ##__VA_ARGS__); goto error; } while(0)
|
||||
#define LOG_PERROR(dev, _msg, ...) do { fprintf(stderr, "%s: %s: " _msg "\n", __FILENAME__, dev_name(dev), ##__VA_ARGS__); exit(-1); } while(0)
|
||||
#define LOG_INFO(dev, _msg, ...) do { fprintf(stderr, "%s: %s: " _msg "\n", __FILENAME__, dev_name(dev), ##__VA_ARGS__); } while(0)
|
||||
#define LOG_VERBOSE(dev, _msg, ...) do { if (log_options.debug || log_options.verbose || filter_log(__FILENAME__)) { fprintf(stderr, "%s: %s: " _msg "\n", __FILENAME__, dev_name(dev), ##__VA_ARGS__); } } while(0)
|
||||
#define LOG_DEBUG(dev, _msg, ...) do { if (log_options.debug || filter_log(__FILENAME__)) { fprintf(stderr, "%s: %s: " _msg "\n", __FILENAME__, dev_name(dev), ##__VA_ARGS__); } } while(0)
|
||||
|
||||
#define CLOCK_FROM_PARAMS -1
|
||||
|
||||
uint64_t get_monotonic_time_us(struct timespec *ts, struct timeval *tv);
|
||||
uint64_t get_time_us(clockid_t clock, struct timespec *ts, struct timeval *tv, int64_t delays_us);
|
||||
int shrink_to_block(int size, int block);
|
||||
|
||||
int ioctl_retried(const char *name, int fd, int request, void *arg);
|
||||
|
||||
#define ERR_IOCTL(dev, _fd, _request, _value, _msg, ...) do { \
|
||||
int ret; \
|
||||
if ((ret = ioctl_retried(dev_name(dev), _fd, _request, _value)) < 0) { \
|
||||
LOG_ERROR(dev, "ioctl(ret=%d): " _msg, ret, ##__VA_ARGS__); \
|
||||
} \
|
||||
} while(0)
|
179
util/opts/opts.c
Normal file
179
util/opts/opts.c
Normal file
@ -0,0 +1,179 @@
|
||||
#include "opts.h"
|
||||
#include "util/opts/log.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#define OPT_LENGTH 30
|
||||
|
||||
static void print_help(option_t *options, const char *cmd)
|
||||
{
|
||||
printf("Usage:\n");
|
||||
printf("$ %s <options...>\n", cmd);
|
||||
printf("\n");
|
||||
|
||||
printf("Options:\n");
|
||||
for (int i = 0; options[i].name; i++) {
|
||||
option_t *option = &options[i];
|
||||
int len = 0;
|
||||
|
||||
len += printf(" -%s", option->name);
|
||||
if (option->default_value) {
|
||||
len += printf("[=%s]", option->default_value);
|
||||
} else if (option->value_mapping) {
|
||||
len += printf("=arg");
|
||||
} else {
|
||||
len += printf("=%s", option->format);
|
||||
}
|
||||
if (len < OPT_LENGTH) {
|
||||
printf("%*s", OPT_LENGTH-len, " ");
|
||||
}
|
||||
|
||||
printf("- %s", option->description);
|
||||
if (option->value_mapping) {
|
||||
printf(" Values: ");
|
||||
for (int j = 0; option->value_mapping[j].name; j++) {
|
||||
if (j > 0) printf(", ");
|
||||
printf("%s", option->value_mapping[j].name);
|
||||
}
|
||||
printf(".");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
printf("Configuration:\n");
|
||||
for (int i = 0; options[i].name; i++) {
|
||||
option_t *option = &options[i];
|
||||
int len = 0;
|
||||
|
||||
if (option->value_list) {
|
||||
char *string = option->value_list;
|
||||
char *token;
|
||||
|
||||
if (!*string)
|
||||
continue;
|
||||
|
||||
while ((token = strsep(&string, OPTION_VALUE_LIST_SEP)) != NULL) {
|
||||
len = printf(" -%s=", option->name);
|
||||
if (len < OPT_LENGTH) {
|
||||
printf("%*s", OPT_LENGTH-len, " ");
|
||||
}
|
||||
printf("%s\n", token);
|
||||
}
|
||||
} else if (option->value_string) {
|
||||
len += printf(" -%s=", option->name);
|
||||
if (len < OPT_LENGTH) {
|
||||
printf("%*s", OPT_LENGTH-len, " ");
|
||||
}
|
||||
printf(option->format, option->value_string);
|
||||
printf("\n");
|
||||
} else {
|
||||
len += printf(" -%s=", option->name);
|
||||
if (len < OPT_LENGTH) {
|
||||
printf("%*s", OPT_LENGTH-len, " ");
|
||||
}
|
||||
if (option->value_mapping) {
|
||||
for (int j = 0; option->value_mapping[j].name; j++) {
|
||||
if (option->value_mapping[j].value == *option->value) {
|
||||
printf("%s - ", option->value_mapping[j].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned mask = UINT_MAX >> ((sizeof(*option->value) - option->size) * 8);
|
||||
printf(option->format, *option->value & mask);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int parse_opt(option_t *options, const char *key)
|
||||
{
|
||||
option_t *option = NULL;
|
||||
const char *value = strchr(key, '=');
|
||||
|
||||
for (int i = 0; options[i].name; i++) {
|
||||
if (value) {
|
||||
if (!strncmp(key, options[i].name, value - key)) {
|
||||
option = &options[i];
|
||||
value++; // ignore '='
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// require exact match
|
||||
if (!strcmp(key, options[i].name)) {
|
||||
option = &options[i];
|
||||
value = option->default_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG(NULL, "Parsing '%s'. Got value='%s', and option='%s'", key, value, option ? option->name : NULL);
|
||||
|
||||
if (!option || !value) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int ret = 0;
|
||||
if (option->value_list) {
|
||||
char *ptr = option->value_list;
|
||||
|
||||
if (*ptr) {
|
||||
strcat(ptr, OPTION_VALUE_LIST_SEP);
|
||||
ptr += strlen(ptr);
|
||||
}
|
||||
|
||||
ret = sscanf(value, option->format, ptr);
|
||||
} else if (option->value_string) {
|
||||
ret = sscanf(value, option->format, option->value_string);
|
||||
} else if (option->value_mapping) {
|
||||
for (int j = 0; option->value_mapping[j].name; j++) {
|
||||
if (!strcmp(option->value_mapping[j].name, value)) {
|
||||
*option->value_uint = option->value_mapping[j].value;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
ret = sscanf(value, option->format, option->value);
|
||||
} else {
|
||||
ret = sscanf(value, option->format, option->value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int parse_opts(option_t *options, int argc, char *argv[])
|
||||
{
|
||||
int arg;
|
||||
|
||||
for (arg = 1; arg < argc; arg++) {
|
||||
const char *key = argv[arg];
|
||||
|
||||
if (key[0] == '-') {
|
||||
key++;
|
||||
if (key[0] == '-')
|
||||
key++;
|
||||
} else {
|
||||
LOG_ERROR(NULL, "The '%s' is not option (should start with - or --).", key);
|
||||
}
|
||||
|
||||
if (!strcmp(key, "help")) {
|
||||
print_help(options, argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = parse_opt(options, key);
|
||||
if (ret <= 0) {
|
||||
LOG_ERROR(NULL, "Parsing '%s' returned '%d'.", argv[arg], ret);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
76
util/opts/opts.h
Normal file
76
util/opts/opts.h
Normal file
@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef struct option_value_s {
|
||||
const char *name;
|
||||
unsigned value;
|
||||
} option_value_t;
|
||||
|
||||
typedef struct options_s {
|
||||
const char *name;
|
||||
char *value_string;
|
||||
char *value_list;
|
||||
union {
|
||||
unsigned *value;
|
||||
unsigned *value_uint;
|
||||
unsigned *value_hex;
|
||||
bool *value_bool;
|
||||
float *value_float;
|
||||
};
|
||||
const char *format;
|
||||
const char *help;
|
||||
option_value_t *value_mapping;
|
||||
unsigned size;
|
||||
const char *default_value;
|
||||
const char *description;
|
||||
} option_t;
|
||||
|
||||
#define OPTION_VALUE_LIST_SEP ";"
|
||||
|
||||
#define OPTION_FORMAT_uint "%u"
|
||||
#define OPTION_FORMAT_hex "%08x"
|
||||
#define OPTION_FORMAT_bool "%d"
|
||||
#define OPTION_FORMAT_float "%f"
|
||||
#define OPTION_FORMAT_string "%s"
|
||||
#define OPTION_FORMAT_list "%s"
|
||||
|
||||
#define DEFINE_OPTION(_section, _name, _type, _desc) \
|
||||
{ \
|
||||
.name = #_section "-" #_name, \
|
||||
.value_##_type = &_section##_options._name, \
|
||||
.format = OPTION_FORMAT_##_type, \
|
||||
.size = sizeof(_section##_options._name), \
|
||||
.description = _desc, \
|
||||
}
|
||||
|
||||
#define DEFINE_OPTION_DEFAULT(_section, _name, _type, _default_value, _desc) \
|
||||
{ \
|
||||
.name = #_section "-" #_name, \
|
||||
.value_##_type = &_section##_options._name, \
|
||||
.format = OPTION_FORMAT_##_type, \
|
||||
.size = sizeof(_section##_options._name), \
|
||||
.default_value = _default_value, \
|
||||
.description = _desc, \
|
||||
}
|
||||
|
||||
#define DEFINE_OPTION_VALUES(_section, _name, _value_mapping, _desc) \
|
||||
{ \
|
||||
.name = #_section "-" #_name, \
|
||||
.value_hex = &_section##_options._name, \
|
||||
.format = OPTION_FORMAT_hex, \
|
||||
.value_mapping = _value_mapping, \
|
||||
.size = sizeof(_section##_options._name), \
|
||||
.description = _desc, \
|
||||
}
|
||||
|
||||
#define DEFINE_OPTION_PTR(_section, _name, _type, _desc) \
|
||||
{ \
|
||||
.name = #_section "-" #_name, \
|
||||
.value_##_type = _section##_options._name, \
|
||||
.format = OPTION_FORMAT_##_type, \
|
||||
.size = sizeof(_section##_options._name), \
|
||||
.description = _desc, \
|
||||
}
|
||||
|
||||
int parse_opts(option_t *options, int argc, char *argv[]);
|
Reference in New Issue
Block a user