python-on-a-chip online compiler

Dependencies:   mbed TSI

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers strobj.c Source File

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 */