Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
strobj.c
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