Norimasa Okamoto
/
pymite
python-on-a-chip online compiler
- http://pymbed.appspot.com/
- https://code.google.com/p/python-on-a-chip/
- http://www.youtube.com/watch?v=Oyqc2bFRW9I
- https://bitbucket.org/va009039/pymbed/
more info: python-on-a-chip
Diff: vm/strobj.c
- Revision:
- 0:65f1469d6bfb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vm/strobj.c Sat Mar 02 11:54:20 2013 +0000 @@ -0,0 +1,599 @@ +/* +# This file is Copyright 2002 Dean Hall. +# This file is part of the PyMite VM. +# This file is licensed under the MIT License. +# See the LICENSE file for details. +*/ + + +#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 */ + + +/* The following 2 ascii values are used to escape printing to ipm */ +#define REPLY_TERMINATOR 0x04 +#define ESCAPE_CHAR 0x1B + + +/* + * 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 + PM_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 + { + /* Escape the escape and reply terminator chars */ + if ((ch == ESCAPE_CHAR) || (ch == REPLY_TERMINATOR)) + { + plat_putByte(ESCAPE_CHAR); + } + + /* 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) +{ + pstrcache = C_NULL; + + 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 fmtretval; + 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++]; + } + + fmtretval = -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'; +#ifdef HAVE_SNPRINTF_FORMAT + fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF, + (char *)smallfmtcstr, ((pPmInt_t)pobj)->val); +#else + if (fmtcstr[i] == 'd') + { + retval = sli_ltoa10(((pPmInt_t)pobj)->val, + fmtdbuf, + sizeof(fmtdbuf)); + PM_RETURN_IF_ERROR(retval); + } + else + { + sli_ltoa16(((pPmInt_t)pobj)->val, + fmtdbuf, + sizeof(fmtdbuf), + fmtcstr[i] == 'X'); + } + fmtretval = sli_strlen((char *)fmtdbuf); +#endif /* HAVE_SNPRINTF_FORMAT */ + break; + } + +#ifdef HAVE_FLOAT + else if ((fmtcstr[i] == 'f') || (fmtcstr[i] == 'F')) + { + if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_FLT) + { + PM_RAISE(retval, PM_RET_EX_TYPE); + return retval; + } +#ifdef HAVE_SNPRINTF_FORMAT + smallfmtcstr[j] = '\0'; + fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF, + (char *)smallfmtcstr, ((pPmFloat_t)pobj)->val); +#else + sli_ftoa(((pPmFloat_t)pobj)->val, fmtdbuf, SIZEOF_FMTDBUF); + fmtretval = sli_strlen((char *)fmtdbuf); +#endif /* HAVE_SNPRINTF_FORMAT */ + 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; + } + + /* Skip using snprintf(), just use length of string arg */ + fmtretval = ((pPmString_t)pobj)->length; + break; + } + } + + /* Raise ValueError if the format string was bad */ + if (fmtretval < 0) + { + PM_RAISE(retval, PM_RET_EX_VAL); + return retval; + } + + expectedargcount++; + strsize += fmtretval; + } + + /* 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++]; + } + + fmtretval = -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'; +#ifdef HAVE_SNPRINTF_FORMAT + fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF, + (char *)smallfmtcstr, ((pPmInt_t)pobj)->val); +#else + if (fmtcstr[i] == 'd') + { + retval = sli_ltoa10(((pPmInt_t)pobj)->val, + fmtdbuf, + sizeof(fmtdbuf)); + PM_RETURN_IF_ERROR(retval); + } + else + { + sli_ltoa16(((pPmInt_t)pobj)->val, + fmtdbuf, + sizeof(fmtdbuf), + fmtcstr[i] == 'X'); + } + fmtretval = sli_strlen((char *)fmtdbuf); +#endif /* HAVE_SNPRINTF_FORMAT */ + break; + } + +#ifdef HAVE_FLOAT + else if ((fmtcstr[i] == 'f') || (fmtcstr[i] == 'F')) + { +#ifdef HAVE_SNPRINTF_FORMAT + smallfmtcstr[j] = '\0'; + fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF, + (char *)smallfmtcstr, ((pPmFloat_t)pobj)->val); +#else + sli_ftoa(((pPmFloat_t)pobj)->val, fmtdbuf, SIZEOF_FMTDBUF); + fmtretval = sli_strlen((char *)fmtdbuf); +#endif /* HAVE_SNPRINTF_FORMAT */ + break; + } +#endif /* HAVE_FLOAT */ + + else if (fmtcstr[i] == 's') + { +#ifdef HAVE_SNPRINTF_FORMAT + smallfmtcstr[j] = '\0'; + fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF, + (char *)smallfmtcstr, ((pPmString_t)pobj)->val); +#else + sli_memcpy(fmtdbuf, ((pPmString_t)pobj)->val, + ((pPmString_t)pobj)->length); + fmtretval = ((pPmString_t)pobj)->length; +#endif /* HAVE_SNPRINTF_FORMAT */ + break; + } + } + + /* Copy formatted C string into new string object */ + for (j = 0; j < fmtretval; 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 */