File notation_plpath.c
File List > note-plpath > src > notation_plpath.c
Go to the documentation of this file
#include "notation_plpath.h"
#include "notation_defs.h"
#include "tang_defs.h"
#include <stdio.h>
#include <float.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdbool.h>
/******************************************************************************/
/************************** Private Typedef ***********************************/
/******************************************************************************/
/******************************************************************************/
/************************** Defines *******************************************/
/******************************************************************************/
/******************************************************************************/
/************************** Private Function Declarations *********************/
/******************************************************************************/
STATIC_INLINE_UINT8 note_plpath_dp_process_str(char *str, note_plpath_t *path);
STATIC_INLINE char * note_plpath_dp_strip_lws(char *str, const char *str_end);
STATIC_INLINE char * note_plpath_dp_move_nl(char *str, const char *str_end);
STATIC_INLINE char * note_plpath_dp_strip_com(char *str, const char *str_end);
STATIC_INLINE char * note_plpath_dp_build_pt(char *str, note_plpath_point_t *point,
const char *str_end);
STATIC_INLINE char *note_plpath_ep_insert_double(double new_double,
char *str,
const char *str_end);
STATIC_INLINE char * note_plpath_ep_writeseg(note_plpath_point_t *active_point,
char *str,
const char *str_end);
/******************************************************************************/
/************************** Local Variables ***********************************/
/******************************************************************************/
/******************************************************************************/
/************************** Public Function Definitions ***********************/
/******************************************************************************/
/*
* Documentation in header
*/
/* cppcheck-suppress constParameterPointer */
uint8_t note_plpath_decode(char *str, note_plpath_t *path)
{
uint8_t retval = NOTE_DEFS_DECODE_SUCCESS;
if (NULL == str)
{
retval |= NOTE_STATUS_BLDR(NOTE_DEFS_DECODE_FAIL, NOTE_PLPATH_DECODE_EMPTY_STR);
}
else if (NULL == path)
{
retval |= NOTE_STATUS_BLDR(NOTE_DEFS_DECODE_FAIL, NOTE_PLPATH_DECODE_NULL_DEST);
}
else
{
retval |= note_plpath_dp_process_str(str, path);
}
return retval;
}
/*
* Documentation in header
*/
/* cppcheck-suppress constParameterPointer */
uint8_t note_plpath_encode(note_plpath_t path, char *str, size_t buffer_size)
{
uint8_t retval = NOTE_DEFS_ENCODE_SUCCESS;
if (NULL == str)
{
retval |= NOTE_STATUS_BLDR(NOTE_DEFS_ENCODE_FAIL, NOTE_PLPATH_ENCODE_STR_BUF);
}
else
{
size_t i;
const char *str_end = str + buffer_size;
retval = NOTE_DEFS_ENCODE_SUCCESS;
for (i = 0; i < buffer_size; i++)
{
char *ptr = str + i;
*ptr = '\0';
}
for (i = 0; i < path.segment_count; i++)
{
/* if the segment exists write it to a string*/
if (NULL != path.segments[i])
{
str = note_plpath_ep_writeseg(path.segments[i],
str,
str_end);
if (NULL == str)
{
retval |= NOTE_STATUS_BLDR(NOTE_DEFS_ENCODE_FAIL,
NOTE_PLPATH_ENCODE_OVRUNDR_ERROR);
break;
}
}
/* Except for the last segment write two new lines*/
if (i + 1 < path.segment_count)
{
if (str < str_end - 1)
{
*str = '\n';
str++;
*str = '\n';
str++;
}
else
{
retval |= NOTE_STATUS_BLDR(NOTE_DEFS_ENCODE_FAIL,
NOTE_PLPATH_ENCODE_OVRUNDR_ERROR);
break;
}
}
}
}
return retval;
}
/******************************************************************************/
/************************** Private Function Definitions **********************/
/******************************************************************************/
/************************** Decode Path ***************************************/
STATIC_INLINE char * note_plpath_dp_build_pt(char *str,
note_plpath_point_t *point,
const char *str_end)
{
char * str_offset;
double val = strtod(str, &str_offset);
/*Build x*/
str = str_offset;
if ((0 != errno) || (str == str_end) || (',' != *str) ||
!((('0' <= *(str + 1) && (*(str + 1) <= '9')) || ('-' == *(str + 1)))))
{
errno = 0;
return NULL;
}
point->x = val;
str++;
/*Build y*/
val = strtod(str, &str_offset);
str = str_offset;
if ((0 != errno) || (str == str_end) || (',' != *str) ||
!((('0' <= *(str + 1)) && (*(str + 1) <= '9')) || ('-' == *(str + 1))))
{
errno = 0;
return NULL;
}
point->y = val;
str++;
/*Build y*/
val = strtod(str, &str_offset);
str = str_offset;
if (0 != errno)
{
errno = 0;
return NULL;
}
point->z = val;
return str;
}
STATIC_INLINE char * note_plpath_dp_strip_com(char *str, const char *str_end)
{
while (('\n' != *str) && (str < str_end))
{
str++;
}
return str;
}
STATIC_INLINE char * note_plpath_dp_move_nl(char *str, const char *str_end)
{
while (('\n' == *str) && (str < str_end))
{
str++;
}
return str;
}
STATIC_INLINE char * note_plpath_dp_strip_lws(char *str, const char *str_end)
{
while (((' ' == *str) || ('\t' == *str)) && (str < str_end))
{
str++;
}
return str;
}
STATIC_INLINE_UINT8 note_plpath_dp_process_str(char *str, note_plpath_t *path)
{
uint8_t retval = NOTE_DEFS_DECODE_SUCCESS;
const char * str_end = str + strlen(str);
note_plpath_point_t *active_point = NULL;
/* while the string is not exhausted */
while ((NOTE_DEFS_DECODE_SUCCESS == retval) && (str < str_end))
{
str = note_plpath_dp_strip_lws(str, str_end);
if ('\n' == *str)
{
if (('\n' == *(str + 1)) && (NULL != path->segments[path->segment_count - 1]))
{
path->segment_count++;
path->segments[path->segment_count - 1] = NULL;
}
str = note_plpath_dp_move_nl(str, str_end);
}
else if (('/' == *str) && ('/' == *(str + 1)))
{
str = note_plpath_dp_strip_com(str, str_end);
}
else if ((('0' <= *str) && (*str <= '9')) || ('-' == *str))
{
/* If there are no segments add one*/
if (0 == path->segment_count)
{
path->segment_count++;
path->segments[path->segment_count - 1] = NULL;
}
if (path->buffer->idx < path->buffer->size)
{
note_plpath_point_t *new_point = &(path->buffer->buffer[path->buffer->idx]);
path->buffer->idx++;
str = note_plpath_dp_build_pt(str, new_point, str_end);
if (NULL != str)
{
/* If the segement has no points add this one`.*/
if (NULL == path->segments[path->segment_count - 1])
{
path->segments[path->segment_count - 1] = new_point;
}
else
{
/* Otherwise, add this the next point in the chain active_point.*/
active_point->next_point = new_point;
}
active_point = new_point;
}
else
{
retval |= NOTE_STATUS_BLDR(NOTE_DEFS_DECODE_FAIL, NOTE_PLPATH_DECODE_BAD_STR);
break;
}
}
else
{
retval |= NOTE_STATUS_BLDR(NOTE_DEFS_DECODE_FAIL, NOTE_PLPATH_DECODE_BUFFER_ERROR);
break;
}
}
else
{
retval |= NOTE_STATUS_BLDR(NOTE_DEFS_DECODE_FAIL, NOTE_PLPATH_DECODE_BAD_STR);
break;
}
}
return retval;
}
/************************** Encode Path ***************************************/
STATIC_INLINE char * note_plpath_ep_insert_double(double new_double,
char *str,
const char *str_end)
{
size_t local_offset = 0;
char local_str[4 + DBL_DIG + -DBL_MIN_10_EXP];
sprintf(local_str, "%f", new_double);
local_offset = strlen(local_str);
if ((str + local_offset) < str_end)
{
strcpy(str, local_str);
str += local_offset;
}
else
{
return NULL;
}
return str;
}
STATIC_INLINE char * note_plpath_ep_writeseg(note_plpath_point_t *active_point,
char *str,
const char *str_end)
{
const note_plpath_point_t *first_pt = active_point;
while ((NULL != str) && (NULL != active_point))
{
if (str < str_end)
{
str = note_plpath_ep_insert_double(active_point->x, str, str_end);
}
else
{
return NULL;
}
if (str < str_end)
{
*str = ',';
str++;
}
else
{
return NULL;
}
if (str < str_end)
{
str = note_plpath_ep_insert_double(active_point->y, str, str_end);
}
else
{
return NULL;
}
if (str < str_end)
{
*str = ',';
str++;
}
else
{
return NULL;
}
if (str < str_end)
{
str = note_plpath_ep_insert_double(active_point->z, str, str_end);
}
else
{
return NULL;
}
/*Only add a new line if we're not at the end of a segment. */
if (NULL != active_point->next_point)
{
if (str < str_end)
{
*str = '\n';
str++;
}
else
{
return NULL;
}
}
active_point = active_point->next_point;
if (active_point == first_pt)
{
return NULL;
}
}
return str;
}