Embed:
(wiki syntax)
Show/hide line numbers
strobj.c
Go to the documentation of this file.
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