libdc/src/field-cache.c
Linus Torvalds e9129ff45a Add generic dc_field_get() helper
This generic helper just gets everything from the field cache.

Dive computers can do their own things for any field they handle
differently, and then at the end fall back to this for all of the common
cases that are purely described by the field cache structure.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2020-06-22 14:56:55 -07:00

103 lines
2.7 KiB
C

#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "parser-private.h"
#include "field-cache.h"
/*
* The field cache 'string' interface has some simple rules:
* the "descriptor" part is assumed to be a static allocation,
* while the "value" is something that this interface will
* alway sallocate with 'strdup()', so you can generate it
* dynamically on the stack or whatever without having to
* worry about it.
*/
dc_status_t dc_field_add_string(dc_field_cache_t *cache, const char *desc, const char *value)
{
int i;
cache->initialized |= 1 << DC_FIELD_STRING;
for (i = 0; i < MAXSTRINGS; i++) {
dc_field_string_t *str = cache->strings+i;
if (str->desc)
continue;
str->value = strdup(value);
if (!str->value)
return DC_STATUS_NOMEMORY;
str->desc = desc;
return DC_STATUS_SUCCESS;
}
return DC_STATUS_INVALIDARGS;
}
dc_status_t dc_field_add_string_fmt(dc_field_cache_t *cache, const char *desc, const char *fmt, ...)
{
char buffer[256];
va_list ap;
/*
* We ignore the return value from vsnprintf, and we
* always NUL-terminate the destination buffer ourselves.
*
* That way we don't have to worry about random bad legacy
* implementations.
*/
va_start(ap, fmt);
buffer[sizeof(buffer)-1] = 0;
(void) vsnprintf(buffer, sizeof(buffer)-1, fmt, ap);
va_end(ap);
return dc_field_add_string(cache, desc, buffer);
}
dc_status_t dc_field_get_string(dc_field_cache_t *cache, unsigned idx, dc_field_string_t *value)
{
if (idx < MAXSTRINGS) {
dc_field_string_t *res = cache->strings+idx;
if (res->desc && res->value) {
*value = *res;
return DC_STATUS_SUCCESS;
}
}
return DC_STATUS_UNSUPPORTED;
}
/*
* Use this generic "pick fields from the field cache" helper
* after you've handled all the ones you do differently
*/
dc_status_t
dc_field_get(dc_field_cache_t *cache, dc_field_type_t type, unsigned int flags, void* value)
{
if (!(cache->initialized & (1 << type)))
return DC_STATUS_UNSUPPORTED;
switch (type) {
case DC_FIELD_DIVETIME:
return DC_FIELD_VALUE(*cache, value, DIVETIME);
case DC_FIELD_MAXDEPTH:
return DC_FIELD_VALUE(*cache, value, MAXDEPTH);
case DC_FIELD_AVGDEPTH:
return DC_FIELD_VALUE(*cache, value, AVGDEPTH);
case DC_FIELD_GASMIX_COUNT:
case DC_FIELD_TANK_COUNT:
return DC_FIELD_VALUE(*cache, value, GASMIX_COUNT);
case DC_FIELD_GASMIX:
if (flags >= MAXGASES)
break;
return DC_FIELD_INDEX(*cache, value, GASMIX, flags);
case DC_FIELD_SALINITY:
return DC_FIELD_VALUE(*cache, value, SALINITY);
case DC_FIELD_DIVEMODE:
return DC_FIELD_VALUE(*cache, value, DIVEMODE);
case DC_FIELD_STRING:
return dc_field_get_string(cache, flags, (dc_field_string_t *)value);
default:
break;
}
return DC_STATUS_UNSUPPORTED;
}