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