1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-30 08:24:11 +01:00
LibrePilot/flight/Libraries/PyMite/vm/strobj.c

546 lines
14 KiB
C

/*
# This file is Copyright 2003, 2006, 2007, 2009, 2010 Dean Hall.
#
# This file is part of the PyMite VM.
# The PyMite VM is free software: you can redistribute it and/or modify
# it under the terms of the GNU GENERAL PUBLIC LICENSE Version 2.
#
# The PyMite VM is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# A copy of the GNU GENERAL PUBLIC LICENSE Version 2
# is seen in the file COPYING in this directory.
*/
#undef __FILE_ID__
#define __FILE_ID__ 0x12
/**
* \file
* \brief String Object Type
*
* String object type opeartions.
*/
#include "pm.h"
#if USE_STRING_CACHE
/** String obj cachche: a list of all string objects. */
static pPmString_t pstrcache = C_NULL;
#endif /* USE_STRING_CACHE */
/*
* If USE_STRING_CACHE is defined nonzero, the string cache
* will be searched for an existing String object.
* If not found, a new object is created and inserted
* into the cache.
*/
PmReturn_t
string_create(PmMemSpace_t memspace, uint8_t const **paddr, int16_t len,
int16_t n, pPmObj_t *r_pstring)
{
PmReturn_t retval = PM_RET_OK;
pPmString_t pstr = C_NULL;
uint8_t *pdst = C_NULL;
uint8_t const *psrc = C_NULL;
#if USE_STRING_CACHE
pPmString_t pcacheentry = C_NULL;
#endif /* USE_STRING_CACHE */
uint8_t *pchunk;
/* If loading from an image, get length from the image */
if (len < 0)
{
len = mem_getWord(memspace, paddr);
}
/* If loading from a C string, get its strlen (first null) */
else if (len == 0)
{
len = sli_strlen((char const *)*paddr);
}
/* Get space for String obj */
retval = heap_getChunk(sizeof(PmString_t) + len * n, &pchunk);
PM_RETURN_IF_ERROR(retval);
pstr = (pPmString_t)pchunk;
/* Fill the string obj */
OBJ_SET_TYPE(pstr, OBJ_TYPE_STR);
pstr->length = len * n;
/* Copy C-string into String obj */
pdst = (uint8_t *)&(pstr->val);
while (--n >= 0)
{
psrc = *paddr;
mem_copy(memspace, &pdst, &psrc, len);
}
/* Be sure paddr points to one byte past the end of the source string */
*paddr = psrc;
/* Zero-pad end of string */
for (; pdst < (uint8_t *)pstr + OBJ_GET_SIZE(pstr); pdst++)
{
*pdst = 0;
}
#if USE_STRING_CACHE
/* Check for twin string in cache */
for (pcacheentry = pstrcache;
pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
{
/* If string already exists */
if (string_compare(pcacheentry, pstr) == C_SAME)
{
/* Free the string */
retval = heap_freeChunk((pPmObj_t)pstr);
/* Return ptr to old */
*r_pstring = (pPmObj_t)pcacheentry;
return retval;
}
}
/* Insert string obj into cache */
pstr->next = pstrcache;
pstrcache = pstr;
#endif /* USE_STRING_CACHE */
*r_pstring = (pPmObj_t)pstr;
return PM_RET_OK;
}
PmReturn_t
string_newFromChar(uint8_t const c, pPmObj_t *r_pstring)
{
PmReturn_t retval;
uint8_t cstr[2];
uint8_t const *pcstr;
cstr[0] = c;
cstr[1] = '\0';
pcstr = cstr;
retval = string_new(&pcstr, r_pstring);
/* If c was a null character, force the length to 1 */
if (c == '\0')
{
((pPmString_t)*r_pstring)->length = 1;
}
return retval;
}
int8_t
string_compare(pPmString_t pstr1, pPmString_t pstr2)
{
/* Return false if lengths are not equal */
if (pstr1->length != pstr2->length)
{
return C_DIFFER;
}
/* Compare the strings' contents */
return sli_strncmp((char const *)&(pstr1->val),
(char const *)&(pstr2->val),
pstr1->length) == 0 ? C_SAME : C_DIFFER;
}
#ifdef HAVE_PRINT
PmReturn_t
string_printFormattedBytes(uint8_t *pb, uint8_t is_escaped, uint16_t n)
{
uint16_t i;
uint8_t ch;
uint8_t nibble;
PmReturn_t retval = PM_RET_OK;
if (is_escaped)
{
retval = plat_putByte('\'');
PM_RETURN_IF_ERROR(retval);
}
for (i = 0; i < n; i++)
{
ch = pb[i];
if (is_escaped && (ch == '\\'))
{
/* Output an additional backslash to escape it. */
retval = plat_putByte('\\');
PM_RETURN_IF_ERROR(retval);
}
/* Print the hex escape code of non-printable characters */
if (is_escaped
&& ((ch < (uint8_t)32) || (ch >= (uint8_t)128) || (ch == '\'')))
{
plat_putByte('\\');
plat_putByte('x');
nibble = (ch >> (uint8_t)4) + '0';
if (nibble > '9')
nibble += ('a' - '0' - (uint8_t)10);
plat_putByte(nibble);
nibble = (ch & (uint8_t)0x0F) + '0';
if (nibble > '9')
nibble += ('a' - '0' - (uint8_t)10);
plat_putByte(nibble);
}
else
{
/* Simply output character */
retval = plat_putByte(ch);
PM_RETURN_IF_ERROR(retval);
}
}
if (is_escaped)
{
retval = plat_putByte('\'');
}
return retval;
}
PmReturn_t
string_print(pPmObj_t pstr, uint8_t is_escaped)
{
PmReturn_t retval = PM_RET_OK;
C_ASSERT(pstr != C_NULL);
/* Ensure string obj */
if (OBJ_GET_TYPE(pstr) != OBJ_TYPE_STR)
{
PM_RAISE(retval, PM_RET_EX_TYPE);
return retval;
}
retval = string_printFormattedBytes(&(((pPmString_t)pstr)->val[0]),
is_escaped,
((pPmString_t)pstr)->length);
return retval;
}
#endif /* HAVE_PRINT */
PmReturn_t
string_cacheInit(void)
{
#if USE_STRING_CACHE
pstrcache = C_NULL;
#endif
return PM_RET_OK;
}
PmReturn_t
string_getCache(pPmString_t **r_ppstrcache)
{
#if USE_STRING_CACHE
*r_ppstrcache = &pstrcache;
#else
*r_ppstrcache = C_NULL;
#endif
return PM_RET_OK;
}
PmReturn_t
string_concat(pPmString_t pstr1, pPmString_t pstr2, pPmObj_t *r_pstring)
{
PmReturn_t retval = PM_RET_OK;
pPmString_t pstr = C_NULL;
uint8_t *pdst = C_NULL;
uint8_t const *psrc = C_NULL;
#if USE_STRING_CACHE
pPmString_t pcacheentry = C_NULL;
#endif /* USE_STRING_CACHE */
uint8_t *pchunk;
uint16_t len;
/* Create the String obj */
len = pstr1->length + pstr2->length;
retval = heap_getChunk(sizeof(PmString_t) + len, &pchunk);
PM_RETURN_IF_ERROR(retval);
pstr = (pPmString_t)pchunk;
OBJ_SET_TYPE(pstr, OBJ_TYPE_STR);
pstr->length = len;
/* Concatenate C-strings into String obj and apply null terminator */
pdst = (uint8_t *)&(pstr->val);
psrc = (uint8_t const *)&(pstr1->val);
mem_copy(MEMSPACE_RAM, &pdst, &psrc, pstr1->length);
psrc = (uint8_t const *)&(pstr2->val);
mem_copy(MEMSPACE_RAM, &pdst, &psrc, pstr2->length);
*pdst = '\0';
#if USE_STRING_CACHE
/* Check for twin string in cache */
for (pcacheentry = pstrcache;
pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
{
/* If string already exists */
if (string_compare(pcacheentry, pstr) == C_SAME)
{
/* Free the string */
retval = heap_freeChunk((pPmObj_t)pstr);
/* Return ptr to old */
*r_pstring = (pPmObj_t)pcacheentry;
return retval;
}
}
/* Insert string obj into cache */
pstr->next = pstrcache;
pstrcache = pstr;
#endif /* USE_STRING_CACHE */
*r_pstring = (pPmObj_t)pstr;
return PM_RET_OK;
}
#ifdef HAVE_STRING_FORMAT
#define SIZEOF_FMTDBUF 42
#define SIZEOF_SMALLFMT 8
PmReturn_t
string_format(pPmString_t pstr, pPmObj_t parg, pPmObj_t *r_pstring)
{
PmReturn_t retval;
uint16_t strsize = 0;
uint16_t strindex;
uint8_t *fmtcstr;
uint8_t smallfmtcstr[SIZEOF_SMALLFMT];
uint8_t fmtdbuf[SIZEOF_FMTDBUF];
uint8_t i;
uint8_t j;
uint8_t argtupleindex = 0;
pPmObj_t pobj;
int snprintretval;
uint8_t expectedargcount = 0;
pPmString_t pnewstr;
uint8_t *pchunk;
#if USE_STRING_CACHE
pPmString_t pcacheentry = C_NULL;
#endif /* USE_STRING_CACHE */
/* Get the first arg */
pobj = parg;
/* Calculate the size of the resulting string */
fmtcstr = pstr->val;
for (i = 0; i < pstr->length; i++)
{
/* Count non-format chars */
if (fmtcstr[i] != '%') { strsize++; continue; }
/* If double percents, count one percent */
if (fmtcstr[++i] == '%') { strsize++; continue; }
/* Get arg from the tuple */
if (OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
{
pobj = ((pPmTuple_t)parg)->val[argtupleindex++];
}
snprintretval = -1;
/* Format one arg to get its length */
smallfmtcstr[0] = '%';
for(j = 1; (i < pstr->length) && (j < SIZEOF_SMALLFMT); i++)
{
smallfmtcstr[j] = fmtcstr[i];
j++;
if ((fmtcstr[i] == 'd')
|| (fmtcstr[i] == 'x')
|| (fmtcstr[i] == 'X'))
{
if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT)
{
PM_RAISE(retval, PM_RET_EX_TYPE);
return retval;
}
smallfmtcstr[j] = '\0';
snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
(char *)smallfmtcstr, ((pPmInt_t)pobj)->val);
break;
}
#ifdef HAVE_FLOAT
else if (fmtcstr[i] == 'f')
{
if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_FLT)
{
PM_RAISE(retval, PM_RET_EX_TYPE);
return retval;
}
smallfmtcstr[j] = '\0';
snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
(char *)smallfmtcstr, ((pPmFloat_t)pobj)->val);
break;
}
#endif /* HAVE_FLOAT */
else if (fmtcstr[i] == 's')
{
if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_STR)
{
PM_RAISE(retval, PM_RET_EX_TYPE);
return retval;
}
smallfmtcstr[j] = '\0';
snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
(char *)smallfmtcstr, ((pPmString_t)pobj)->val);
break;
}
}
/* Raise ValueError if the format string was bad */
if (snprintretval < 0)
{
PM_RAISE(retval, PM_RET_EX_VAL);
return retval;
}
expectedargcount++;
strsize += snprintretval;
}
/* TypeError wrong number args */
if (((OBJ_GET_TYPE(parg) != OBJ_TYPE_TUP) && (expectedargcount != 1))
|| ((OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
&& (expectedargcount != ((pPmTuple_t)parg)->length)))
{
PM_RAISE(retval, PM_RET_EX_TYPE);
return retval;
}
/* Allocate and initialize String obj */
retval = heap_getChunk(sizeof(PmString_t) + strsize, &pchunk);
PM_RETURN_IF_ERROR(retval);
pnewstr = (pPmString_t)pchunk;
OBJ_SET_TYPE(pnewstr, OBJ_TYPE_STR);
pnewstr->length = strsize;
/* Fill contents of String obj */
strindex = 0;
argtupleindex = 0;
pobj = parg;
for (i = 0; i < pstr->length; i++)
{
/* Copy non-format chars */
if (fmtcstr[i] != '%')
{
pnewstr->val[strindex++] = fmtcstr[i];
continue;
}
/* If double percents, copy one percent */
if (fmtcstr[++i] == '%')
{
pnewstr->val[strindex++] = '%';
continue;
}
/* Get arg from the tuple */
if (OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
{
pobj = ((pPmTuple_t)parg)->val[argtupleindex++];
}
snprintretval = -1;
/* Format one arg to get its length */
smallfmtcstr[0] = '%';
for(j = 1; (i < pstr->length) && (j < SIZEOF_SMALLFMT); i++)
{
smallfmtcstr[j] = fmtcstr[i];
j++;
if ((fmtcstr[i] == 'd')
|| (fmtcstr[i] == 'x')
|| (fmtcstr[i] == 'X'))
{
smallfmtcstr[j] = '\0';
snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
(char *)smallfmtcstr, ((pPmInt_t)pobj)->val);
break;
}
#ifdef HAVE_FLOAT
else if (fmtcstr[i] == 'f')
{
smallfmtcstr[j] = '\0';
snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
(char *)smallfmtcstr, ((pPmFloat_t)pobj)->val);
break;
}
#endif /* HAVE_FLOAT */
else if (fmtcstr[i] == 's')
{
smallfmtcstr[j] = '\0';
snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
(char *)smallfmtcstr, ((pPmString_t)pobj)->val);
break;
}
}
/* Copy formatted C string into new string object */
for (j = 0; j < snprintretval; j++)
{
pnewstr->val[strindex++] = fmtdbuf[j];
}
}
pnewstr->val[strindex] = '\0';
#if USE_STRING_CACHE
/* Check for twin string in cache */
for (pcacheentry = pstrcache;
pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
{
/* If string already exists */
if (string_compare(pcacheentry, pnewstr) == C_SAME)
{
/* Free the string */
retval = heap_freeChunk((pPmObj_t)pnewstr);
/* Return ptr to old */
*r_pstring = (pPmObj_t)pcacheentry;
return retval;
}
}
/* Insert string obj into cache */
pnewstr->next = pstrcache;
pstrcache = pnewstr;
#endif /* USE_STRING_CACHE */
*r_pstring = (pPmObj_t)pnewstr;
return PM_RET_OK;
}
#endif /* HAVE_STRING_FORMAT */