Norimasa Okamoto
/
pymite
python-on-a-chip online compiler
Embed:
(wiki syntax)
Show/hide line numbers
strobj.c
Go to the documentation of this file.
00001 /* 00002 # This file is Copyright 2002 Dean Hall. 00003 # This file is part of the PyMite VM. 00004 # This file is licensed under the MIT License. 00005 # See the LICENSE file for details. 00006 */ 00007 00008 00009 #undef __FILE_ID__ 00010 #define __FILE_ID__ 0x12 00011 00012 00013 /** 00014 * \file 00015 * \brief String Object Type 00016 * 00017 * String object type opeartions. 00018 */ 00019 00020 #include "pm.h" 00021 00022 00023 #if USE_STRING_CACHE 00024 /** String obj cachche: a list of all string objects. */ 00025 static pPmString_t pstrcache = C_NULL; 00026 #endif /* USE_STRING_CACHE */ 00027 00028 00029 /* The following 2 ascii values are used to escape printing to ipm */ 00030 #define REPLY_TERMINATOR 0x04 00031 #define ESCAPE_CHAR 0x1B 00032 00033 00034 /* 00035 * If USE_STRING_CACHE is defined nonzero, the string cache 00036 * will be searched for an existing String object. 00037 * If not found, a new object is created and inserted 00038 * into the cache. 00039 */ 00040 PmReturn_t 00041 string_create(PmMemSpace_t memspace, uint8_t const **paddr, int16_t len, 00042 int16_t n, pPmObj_t *r_pstring) 00043 { 00044 PmReturn_t retval = PM_RET_OK; 00045 pPmString_t pstr = C_NULL; 00046 uint8_t *pdst = C_NULL; 00047 uint8_t const *psrc = C_NULL; 00048 00049 #if USE_STRING_CACHE 00050 pPmString_t pcacheentry = C_NULL; 00051 #endif /* USE_STRING_CACHE */ 00052 uint8_t *pchunk; 00053 00054 /* If loading from an image, get length from the image */ 00055 if (len < 0) 00056 { 00057 len = mem_getWord(memspace, paddr); 00058 } 00059 00060 /* If loading from a C string, get its strlen (first null) */ 00061 else if (len == 0) 00062 { 00063 len = sli_strlen((char const *)*paddr); 00064 } 00065 00066 /* Get space for String obj */ 00067 retval = heap_getChunk(sizeof(PmString_t) + len * n, &pchunk); 00068 PM_RETURN_IF_ERROR(retval); 00069 pstr = (pPmString_t)pchunk; 00070 00071 /* Fill the string obj */ 00072 OBJ_SET_TYPE(pstr, OBJ_TYPE_STR); 00073 pstr->length = len * n; 00074 00075 /* Copy C-string into String obj */ 00076 pdst = (uint8_t *)&(pstr->val); 00077 while (--n >= 0) 00078 { 00079 psrc = *paddr; 00080 mem_copy(memspace, &pdst, &psrc, len); 00081 } 00082 00083 /* Be sure paddr points to one byte past the end of the source string */ 00084 *paddr = psrc; 00085 00086 /* Zero-pad end of string */ 00087 for (; pdst < (uint8_t *)pstr + PM_OBJ_GET_SIZE(pstr); pdst++) 00088 { 00089 *pdst = 0; 00090 } 00091 00092 #if USE_STRING_CACHE 00093 /* Check for twin string in cache */ 00094 for (pcacheentry = pstrcache; 00095 pcacheentry != C_NULL; pcacheentry = pcacheentry->next) 00096 { 00097 /* If string already exists */ 00098 if (string_compare(pcacheentry, pstr) == C_SAME) 00099 { 00100 /* Free the string */ 00101 retval = heap_freeChunk((pPmObj_t)pstr); 00102 00103 /* Return ptr to old */ 00104 *r_pstring = (pPmObj_t)pcacheentry; 00105 return retval; 00106 } 00107 } 00108 00109 /* Insert string obj into cache */ 00110 pstr->next = pstrcache; 00111 pstrcache = pstr; 00112 00113 #endif /* USE_STRING_CACHE */ 00114 00115 *r_pstring = (pPmObj_t)pstr; 00116 return PM_RET_OK; 00117 } 00118 00119 00120 PmReturn_t 00121 string_newFromChar(uint8_t const c, pPmObj_t *r_pstring) 00122 { 00123 PmReturn_t retval; 00124 uint8_t cstr[2]; 00125 uint8_t const *pcstr; 00126 00127 cstr[0] = c; 00128 cstr[1] = '\0'; 00129 pcstr = cstr; 00130 00131 retval = string_new(&pcstr, r_pstring); 00132 00133 /* If c was a null character, force the length to 1 */ 00134 if (c == '\0') 00135 { 00136 ((pPmString_t)*r_pstring)->length = 1; 00137 } 00138 00139 return retval; 00140 } 00141 00142 00143 int8_t 00144 string_compare(pPmString_t pstr1, pPmString_t pstr2) 00145 { 00146 /* Return false if lengths are not equal */ 00147 if (pstr1->length != pstr2->length) 00148 { 00149 return C_DIFFER; 00150 } 00151 00152 /* Compare the strings' contents */ 00153 return sli_strncmp((char const *)&(pstr1->val), 00154 (char const *)&(pstr2->val), 00155 pstr1->length) == 0 ? C_SAME : C_DIFFER; 00156 } 00157 00158 00159 #ifdef HAVE_PRINT 00160 PmReturn_t 00161 string_printFormattedBytes(uint8_t *pb, uint8_t is_escaped, uint16_t n) 00162 { 00163 uint16_t i; 00164 uint8_t ch; 00165 uint8_t nibble; 00166 PmReturn_t retval = PM_RET_OK; 00167 00168 if (is_escaped) 00169 { 00170 retval = plat_putByte('\''); 00171 PM_RETURN_IF_ERROR(retval); 00172 } 00173 00174 for (i = 0; i < n; i++) 00175 { 00176 ch = pb[i]; 00177 if (is_escaped && (ch == '\\')) 00178 { 00179 /* Output an additional backslash to escape it. */ 00180 retval = plat_putByte('\\'); 00181 PM_RETURN_IF_ERROR(retval); 00182 } 00183 00184 /* Print the hex escape code of non-printable characters */ 00185 if (is_escaped 00186 && ((ch < (uint8_t)32) || (ch >= (uint8_t)128) || (ch == '\''))) 00187 { 00188 plat_putByte('\\'); 00189 plat_putByte('x'); 00190 00191 nibble = (ch >> (uint8_t)4) + '0'; 00192 if (nibble > '9') 00193 nibble += ('a' - '0' - (uint8_t)10); 00194 plat_putByte(nibble); 00195 00196 nibble = (ch & (uint8_t)0x0F) + '0'; 00197 if (nibble > '9') 00198 nibble += ('a' - '0' - (uint8_t)10); 00199 plat_putByte(nibble); 00200 } 00201 else 00202 { 00203 /* Escape the escape and reply terminator chars */ 00204 if ((ch == ESCAPE_CHAR) || (ch == REPLY_TERMINATOR)) 00205 { 00206 plat_putByte(ESCAPE_CHAR); 00207 } 00208 00209 /* Output character */ 00210 retval = plat_putByte(ch); 00211 PM_RETURN_IF_ERROR(retval); 00212 } 00213 } 00214 if (is_escaped) 00215 { 00216 retval = plat_putByte('\''); 00217 } 00218 00219 return retval; 00220 } 00221 00222 00223 PmReturn_t 00224 string_print(pPmObj_t pstr, uint8_t is_escaped) 00225 { 00226 PmReturn_t retval = PM_RET_OK; 00227 00228 C_ASSERT(pstr != C_NULL); 00229 00230 /* Ensure string obj */ 00231 if (OBJ_GET_TYPE(pstr) != OBJ_TYPE_STR) 00232 { 00233 PM_RAISE(retval, PM_RET_EX_TYPE); 00234 return retval; 00235 } 00236 00237 retval = string_printFormattedBytes(&(((pPmString_t)pstr)->val[0]), 00238 is_escaped, 00239 ((pPmString_t)pstr)->length); 00240 00241 return retval; 00242 } 00243 #endif /* HAVE_PRINT */ 00244 00245 00246 PmReturn_t 00247 string_cacheInit(void) 00248 { 00249 pstrcache = C_NULL; 00250 00251 return PM_RET_OK; 00252 } 00253 00254 00255 PmReturn_t 00256 string_getCache(pPmString_t **r_ppstrcache) 00257 { 00258 #if USE_STRING_CACHE 00259 *r_ppstrcache = &pstrcache; 00260 #else 00261 *r_ppstrcache = C_NULL; 00262 #endif 00263 return PM_RET_OK; 00264 } 00265 00266 00267 PmReturn_t 00268 string_concat(pPmString_t pstr1, pPmString_t pstr2, pPmObj_t *r_pstring) 00269 { 00270 PmReturn_t retval = PM_RET_OK; 00271 pPmString_t pstr = C_NULL; 00272 uint8_t *pdst = C_NULL; 00273 uint8_t const *psrc = C_NULL; 00274 #if USE_STRING_CACHE 00275 pPmString_t pcacheentry = C_NULL; 00276 #endif /* USE_STRING_CACHE */ 00277 uint8_t *pchunk; 00278 uint16_t len; 00279 00280 /* Create the String obj */ 00281 len = pstr1->length + pstr2->length; 00282 retval = heap_getChunk(sizeof(PmString_t) + len, &pchunk); 00283 PM_RETURN_IF_ERROR(retval); 00284 pstr = (pPmString_t)pchunk; 00285 OBJ_SET_TYPE(pstr, OBJ_TYPE_STR); 00286 pstr->length = len; 00287 00288 /* Concatenate C-strings into String obj and apply null terminator */ 00289 pdst = (uint8_t *)&(pstr->val); 00290 psrc = (uint8_t const *)&(pstr1->val); 00291 mem_copy(MEMSPACE_RAM, &pdst, &psrc, pstr1->length); 00292 psrc = (uint8_t const *)&(pstr2->val); 00293 mem_copy(MEMSPACE_RAM, &pdst, &psrc, pstr2->length); 00294 *pdst = '\0'; 00295 00296 #if USE_STRING_CACHE 00297 /* Check for twin string in cache */ 00298 for (pcacheentry = pstrcache; 00299 pcacheentry != C_NULL; pcacheentry = pcacheentry->next) 00300 { 00301 /* If string already exists */ 00302 if (string_compare(pcacheentry, pstr) == C_SAME) 00303 { 00304 /* Free the string */ 00305 retval = heap_freeChunk((pPmObj_t)pstr); 00306 00307 /* Return ptr to old */ 00308 *r_pstring = (pPmObj_t)pcacheentry; 00309 return retval; 00310 } 00311 } 00312 00313 /* Insert string obj into cache */ 00314 pstr->next = pstrcache; 00315 pstrcache = pstr; 00316 #endif /* USE_STRING_CACHE */ 00317 00318 *r_pstring = (pPmObj_t)pstr; 00319 return PM_RET_OK; 00320 } 00321 00322 00323 #ifdef HAVE_STRING_FORMAT 00324 00325 #define SIZEOF_FMTDBUF 42 00326 #define SIZEOF_SMALLFMT 8 00327 00328 PmReturn_t 00329 string_format(pPmString_t pstr, pPmObj_t parg, pPmObj_t *r_pstring) 00330 { 00331 PmReturn_t retval; 00332 uint16_t strsize = 0; 00333 uint16_t strindex; 00334 uint8_t *fmtcstr; 00335 uint8_t smallfmtcstr[SIZEOF_SMALLFMT]; 00336 uint8_t fmtdbuf[SIZEOF_FMTDBUF]; 00337 uint8_t i; 00338 uint8_t j; 00339 uint8_t argtupleindex = 0; 00340 pPmObj_t pobj; 00341 int fmtretval; 00342 uint8_t expectedargcount = 0; 00343 pPmString_t pnewstr; 00344 uint8_t *pchunk; 00345 #if USE_STRING_CACHE 00346 pPmString_t pcacheentry = C_NULL; 00347 #endif /* USE_STRING_CACHE */ 00348 00349 /* Get the first arg */ 00350 pobj = parg; 00351 00352 /* Calculate the size of the resulting string */ 00353 fmtcstr = pstr->val; 00354 for (i = 0; i < pstr->length; i++) 00355 { 00356 /* Count non-format chars */ 00357 if (fmtcstr[i] != '%') { strsize++; continue; } 00358 00359 /* If double percents, count one percent */ 00360 if (fmtcstr[++i] == '%') { strsize++; continue; } 00361 00362 /* Get arg from the tuple */ 00363 if (OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP) 00364 { 00365 pobj = ((pPmTuple_t)parg)->val[argtupleindex++]; 00366 } 00367 00368 fmtretval = -1; 00369 00370 /* Format one arg to get its length */ 00371 smallfmtcstr[0] = '%'; 00372 for(j = 1; (i < pstr->length) && (j < SIZEOF_SMALLFMT); i++) 00373 { 00374 smallfmtcstr[j] = fmtcstr[i]; 00375 j++; 00376 00377 if ((fmtcstr[i] == 'd') 00378 || (fmtcstr[i] == 'x') 00379 || (fmtcstr[i] == 'X')) 00380 { 00381 if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT) 00382 { 00383 PM_RAISE(retval, PM_RET_EX_TYPE); 00384 return retval; 00385 } 00386 smallfmtcstr[j] = '\0'; 00387 #ifdef HAVE_SNPRINTF_FORMAT 00388 fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF, 00389 (char *)smallfmtcstr, ((pPmInt_t)pobj)->val); 00390 #else 00391 if (fmtcstr[i] == 'd') 00392 { 00393 retval = sli_ltoa10(((pPmInt_t)pobj)->val, 00394 fmtdbuf, 00395 sizeof(fmtdbuf)); 00396 PM_RETURN_IF_ERROR(retval); 00397 } 00398 else 00399 { 00400 sli_ltoa16(((pPmInt_t)pobj)->val, 00401 fmtdbuf, 00402 sizeof(fmtdbuf), 00403 fmtcstr[i] == 'X'); 00404 } 00405 fmtretval = sli_strlen((char *)fmtdbuf); 00406 #endif /* HAVE_SNPRINTF_FORMAT */ 00407 break; 00408 } 00409 00410 #ifdef HAVE_FLOAT 00411 else if ((fmtcstr[i] == 'f') || (fmtcstr[i] == 'F')) 00412 { 00413 if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_FLT) 00414 { 00415 PM_RAISE(retval, PM_RET_EX_TYPE); 00416 return retval; 00417 } 00418 #ifdef HAVE_SNPRINTF_FORMAT 00419 smallfmtcstr[j] = '\0'; 00420 fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF, 00421 (char *)smallfmtcstr, ((pPmFloat_t)pobj)->val); 00422 #else 00423 sli_ftoa(((pPmFloat_t)pobj)->val, fmtdbuf, SIZEOF_FMTDBUF); 00424 fmtretval = sli_strlen((char *)fmtdbuf); 00425 #endif /* HAVE_SNPRINTF_FORMAT */ 00426 break; 00427 } 00428 #endif /* HAVE_FLOAT */ 00429 00430 else if (fmtcstr[i] == 's') 00431 { 00432 if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_STR) 00433 { 00434 PM_RAISE(retval, PM_RET_EX_TYPE); 00435 return retval; 00436 } 00437 00438 /* Skip using snprintf(), just use length of string arg */ 00439 fmtretval = ((pPmString_t)pobj)->length; 00440 break; 00441 } 00442 } 00443 00444 /* Raise ValueError if the format string was bad */ 00445 if (fmtretval < 0) 00446 { 00447 PM_RAISE(retval, PM_RET_EX_VAL); 00448 return retval; 00449 } 00450 00451 expectedargcount++; 00452 strsize += fmtretval; 00453 } 00454 00455 /* TypeError wrong number args */ 00456 if (((OBJ_GET_TYPE(parg) != OBJ_TYPE_TUP) && (expectedargcount != 1)) 00457 || ((OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP) 00458 && (expectedargcount != ((pPmTuple_t)parg)->length))) 00459 { 00460 PM_RAISE(retval, PM_RET_EX_TYPE); 00461 return retval; 00462 } 00463 00464 /* Allocate and initialize String obj */ 00465 retval = heap_getChunk(sizeof(PmString_t) + strsize, &pchunk); 00466 PM_RETURN_IF_ERROR(retval); 00467 pnewstr = (pPmString_t)pchunk; 00468 OBJ_SET_TYPE(pnewstr, OBJ_TYPE_STR); 00469 pnewstr->length = strsize; 00470 00471 /* Fill contents of String obj */ 00472 strindex = 0; 00473 argtupleindex = 0; 00474 pobj = parg; 00475 00476 for (i = 0; i < pstr->length; i++) 00477 { 00478 /* Copy non-format chars */ 00479 if (fmtcstr[i] != '%') 00480 { 00481 pnewstr->val[strindex++] = fmtcstr[i]; 00482 continue; 00483 } 00484 00485 /* If double percents, copy one percent */ 00486 if (fmtcstr[++i] == '%') 00487 { 00488 pnewstr->val[strindex++] = '%'; 00489 continue; 00490 } 00491 00492 /* Get arg from the tuple */ 00493 if (OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP) 00494 { 00495 pobj = ((pPmTuple_t)parg)->val[argtupleindex++]; 00496 } 00497 00498 fmtretval = -1; 00499 00500 /* Format one arg to get its length */ 00501 smallfmtcstr[0] = '%'; 00502 for(j = 1; (i < pstr->length) && (j < SIZEOF_SMALLFMT); i++) 00503 { 00504 smallfmtcstr[j] = fmtcstr[i]; 00505 j++; 00506 00507 if ((fmtcstr[i] == 'd') 00508 || (fmtcstr[i] == 'x') 00509 || (fmtcstr[i] == 'X')) 00510 { 00511 smallfmtcstr[j] = '\0'; 00512 #ifdef HAVE_SNPRINTF_FORMAT 00513 fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF, 00514 (char *)smallfmtcstr, ((pPmInt_t)pobj)->val); 00515 #else 00516 if (fmtcstr[i] == 'd') 00517 { 00518 retval = sli_ltoa10(((pPmInt_t)pobj)->val, 00519 fmtdbuf, 00520 sizeof(fmtdbuf)); 00521 PM_RETURN_IF_ERROR(retval); 00522 } 00523 else 00524 { 00525 sli_ltoa16(((pPmInt_t)pobj)->val, 00526 fmtdbuf, 00527 sizeof(fmtdbuf), 00528 fmtcstr[i] == 'X'); 00529 } 00530 fmtretval = sli_strlen((char *)fmtdbuf); 00531 #endif /* HAVE_SNPRINTF_FORMAT */ 00532 break; 00533 } 00534 00535 #ifdef HAVE_FLOAT 00536 else if ((fmtcstr[i] == 'f') || (fmtcstr[i] == 'F')) 00537 { 00538 #ifdef HAVE_SNPRINTF_FORMAT 00539 smallfmtcstr[j] = '\0'; 00540 fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF, 00541 (char *)smallfmtcstr, ((pPmFloat_t)pobj)->val); 00542 #else 00543 sli_ftoa(((pPmFloat_t)pobj)->val, fmtdbuf, SIZEOF_FMTDBUF); 00544 fmtretval = sli_strlen((char *)fmtdbuf); 00545 #endif /* HAVE_SNPRINTF_FORMAT */ 00546 break; 00547 } 00548 #endif /* HAVE_FLOAT */ 00549 00550 else if (fmtcstr[i] == 's') 00551 { 00552 #ifdef HAVE_SNPRINTF_FORMAT 00553 smallfmtcstr[j] = '\0'; 00554 fmtretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF, 00555 (char *)smallfmtcstr, ((pPmString_t)pobj)->val); 00556 #else 00557 sli_memcpy(fmtdbuf, ((pPmString_t)pobj)->val, 00558 ((pPmString_t)pobj)->length); 00559 fmtretval = ((pPmString_t)pobj)->length; 00560 #endif /* HAVE_SNPRINTF_FORMAT */ 00561 break; 00562 } 00563 } 00564 00565 /* Copy formatted C string into new string object */ 00566 for (j = 0; j < fmtretval; j++) 00567 { 00568 pnewstr->val[strindex++] = fmtdbuf[j]; 00569 } 00570 } 00571 pnewstr->val[strindex] = '\0'; 00572 00573 #if USE_STRING_CACHE 00574 /* Check for twin string in cache */ 00575 for (pcacheentry = pstrcache; 00576 pcacheentry != C_NULL; pcacheentry = pcacheentry->next) 00577 { 00578 /* If string already exists */ 00579 if (string_compare(pcacheentry, pnewstr) == C_SAME) 00580 { 00581 /* Free the string */ 00582 retval = heap_freeChunk((pPmObj_t)pnewstr); 00583 00584 /* Return ptr to old */ 00585 *r_pstring = (pPmObj_t)pcacheentry; 00586 return retval; 00587 } 00588 } 00589 00590 /* Insert string obj into cache */ 00591 pnewstr->next = pstrcache; 00592 pstrcache = pnewstr; 00593 00594 #endif /* USE_STRING_CACHE */ 00595 00596 *r_pstring = (pPmObj_t)pnewstr; 00597 return PM_RET_OK; 00598 } 00599 #endif /* HAVE_STRING_FORMAT */
Generated on Tue Jul 12 2022 23:13:47 by 1.7.2