strobj.c

Go to the documentation of this file.
00001 /*
00002 # This file is Copyright 2003, 2006, 2007, 2009, 2010 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 
00027 #include "pm.h"
00028 
00029 
00030 #if USE_STRING_CACHE
00031 
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 is_escaped, 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 (is_escaped)
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 (is_escaped && (ch == '\\'))
00180         {
00181             /* Output an additional backslash to escape it. */
00182             retval = plat_putByte('\\');
00183             PM_RETURN_IF_ERROR(retval);
00184         }
00185 
00186         /* Print the hex escape code of non-printable characters */
00187         if (is_escaped
00188             && ((ch < (uint8_t)32) || (ch >= (uint8_t)128) || (ch == '\'')))
00189         {
00190             plat_putByte('\\');
00191             plat_putByte('x');
00192 
00193             nibble = (ch >> (uint8_t)4) + '0';
00194             if (nibble > '9')
00195                 nibble += ('a' - '0' - (uint8_t)10);
00196             plat_putByte(nibble);
00197 
00198             nibble = (ch & (uint8_t)0x0F) + '0';
00199             if (nibble > '9')
00200                 nibble += ('a' - '0' - (uint8_t)10);
00201             plat_putByte(nibble);
00202         }
00203         else
00204         {
00205             /* Simply output character */
00206             retval = plat_putByte(ch);
00207             PM_RETURN_IF_ERROR(retval);
00208         }
00209     }
00210     if (is_escaped)
00211     {
00212         retval = plat_putByte('\'');
00213     }
00214 
00215     return retval;
00216 }
00217 
00218 
00219 PmReturn_t
00220 string_print(pPmObj_t pstr, uint8_t is_escaped)
00221 {
00222     PmReturn_t retval = PM_RET_OK;
00223 
00224     C_ASSERT(pstr != C_NULL);
00225 
00226     /* Ensure string obj */
00227     if (OBJ_GET_TYPE(pstr) != OBJ_TYPE_STR)
00228     {
00229         PM_RAISE(retval, PM_RET_EX_TYPE);
00230         return retval;
00231     }
00232 
00233     retval = string_printFormattedBytes(&(((pPmString_t)pstr)->val[0]),
00234                                         is_escaped,
00235                                         ((pPmString_t)pstr)->length);
00236 
00237     return retval;
00238 }
00239 #endif /* HAVE_PRINT */
00240 
00241 
00242 PmReturn_t
00243 string_cacheInit(void)
00244 {
00245 #if USE_STRING_CACHE
00246     pstrcache = C_NULL;
00247 #endif
00248     return PM_RET_OK;
00249 }
00250 
00251 
00252 PmReturn_t
00253 string_getCache(pPmString_t **r_ppstrcache)
00254 {
00255 #if USE_STRING_CACHE
00256     *r_ppstrcache = &pstrcache;
00257 #else
00258     *r_ppstrcache = C_NULL;
00259 #endif
00260     return PM_RET_OK;
00261 }
00262 
00263 
00264 PmReturn_t
00265 string_concat(pPmString_t pstr1, pPmString_t pstr2, pPmObj_t *r_pstring)
00266 {
00267     PmReturn_t retval = PM_RET_OK;
00268     pPmString_t pstr = C_NULL;
00269     uint8_t *pdst = C_NULL;
00270     uint8_t const *psrc = C_NULL;
00271 #if USE_STRING_CACHE
00272     pPmString_t pcacheentry = C_NULL;
00273 #endif /* USE_STRING_CACHE */
00274     uint8_t *pchunk;
00275     uint16_t len;
00276 
00277     /* Create the String obj */
00278     len = pstr1->length + pstr2->length;
00279     retval = heap_getChunk(sizeof(PmString_t) + len, &pchunk);
00280     PM_RETURN_IF_ERROR(retval);
00281     pstr = (pPmString_t)pchunk;
00282     OBJ_SET_TYPE(pstr, OBJ_TYPE_STR);
00283     pstr->length = len;
00284 
00285     /* Concatenate C-strings into String obj and apply null terminator */
00286     pdst = (uint8_t *)&(pstr->val);
00287     psrc = (uint8_t const *)&(pstr1->val);
00288     mem_copy(MEMSPACE_RAM, &pdst, &psrc, pstr1->length);
00289     psrc = (uint8_t const *)&(pstr2->val);
00290     mem_copy(MEMSPACE_RAM, &pdst, &psrc, pstr2->length);
00291     *pdst = '\0';
00292 
00293 #if USE_STRING_CACHE
00294     /* Check for twin string in cache */
00295     for (pcacheentry = pstrcache;
00296          pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
00297     {
00298         /* If string already exists */
00299         if (string_compare(pcacheentry, pstr) == C_SAME)
00300         {
00301             /* Free the string */
00302             retval = heap_freeChunk((pPmObj_t)pstr);
00303 
00304             /* Return ptr to old */
00305             *r_pstring = (pPmObj_t)pcacheentry;
00306             return retval;
00307         }
00308     }
00309 
00310     /* Insert string obj into cache */
00311     pstr->next = pstrcache;
00312     pstrcache = pstr;
00313 #endif /* USE_STRING_CACHE */
00314 
00315     *r_pstring = (pPmObj_t)pstr;
00316     return PM_RET_OK;
00317 }
00318 
00319 
00320 #ifdef HAVE_STRING_FORMAT
00321 
00322 #define SIZEOF_FMTDBUF 42
00323 #define SIZEOF_SMALLFMT 8
00324 
00325 PmReturn_t
00326 string_format(pPmString_t pstr, pPmObj_t parg, pPmObj_t *r_pstring)
00327 {
00328     PmReturn_t retval;
00329     uint16_t strsize = 0;
00330     uint16_t strindex;
00331     uint8_t *fmtcstr;
00332     uint8_t smallfmtcstr[SIZEOF_SMALLFMT];
00333     uint8_t fmtdbuf[SIZEOF_FMTDBUF];
00334     uint8_t i;
00335     uint8_t j;
00336     uint8_t argtupleindex = 0;
00337     pPmObj_t pobj;
00338     int snprintretval;
00339     uint8_t expectedargcount = 0;
00340     pPmString_t pnewstr;
00341     uint8_t *pchunk;
00342 #if USE_STRING_CACHE
00343     pPmString_t pcacheentry = C_NULL;
00344 #endif /* USE_STRING_CACHE */
00345 
00346     /* Get the first arg */
00347     pobj = parg;
00348 
00349     /* Calculate the size of the resulting string */
00350     fmtcstr = pstr->val;
00351     for (i = 0; i < pstr->length; i++)
00352     {
00353         /* Count non-format chars */
00354         if (fmtcstr[i] != '%') { strsize++; continue; }
00355 
00356         /* If double percents, count one percent */
00357         if (fmtcstr[++i] == '%') { strsize++; continue; }
00358 
00359         /* Get arg from the tuple */
00360         if (OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
00361         {
00362             pobj = ((pPmTuple_t)parg)->val[argtupleindex++];
00363         }
00364 
00365         snprintretval = -1;
00366 
00367         /* Format one arg to get its length */
00368         smallfmtcstr[0] = '%';
00369         for(j = 1; (i < pstr->length) && (j < SIZEOF_SMALLFMT); i++)
00370         {
00371             smallfmtcstr[j] = fmtcstr[i];
00372             j++;
00373 
00374             if ((fmtcstr[i] == 'd')
00375                 || (fmtcstr[i] == 'x')
00376                 || (fmtcstr[i] == 'X'))
00377             {
00378                 if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_INT)
00379                 {
00380                     PM_RAISE(retval, PM_RET_EX_TYPE);
00381                     return retval;
00382                 }
00383                 smallfmtcstr[j] = '\0';
00384                 snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
00385                     (char *)smallfmtcstr, ((pPmInt_t)pobj)->val);
00386                 break;
00387             }
00388 
00389 #ifdef HAVE_FLOAT
00390             else if (fmtcstr[i] == 'f')
00391             {
00392                 if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_FLT)
00393                 {
00394                     PM_RAISE(retval, PM_RET_EX_TYPE);
00395                     return retval;
00396                 }
00397                 smallfmtcstr[j] = '\0';
00398                 snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
00399                     (char *)smallfmtcstr, ((pPmFloat_t)pobj)->val);
00400                 break;
00401             }
00402 #endif /* HAVE_FLOAT */
00403 
00404             else if (fmtcstr[i] == 's')
00405             {
00406                 if (OBJ_GET_TYPE(pobj) != OBJ_TYPE_STR)
00407                 {
00408                     PM_RAISE(retval, PM_RET_EX_TYPE);
00409                     return retval;
00410                 }
00411                 smallfmtcstr[j] = '\0';
00412                 snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
00413                     (char *)smallfmtcstr, ((pPmString_t)pobj)->val);
00414                 break;
00415             }
00416         }
00417 
00418         /* Raise ValueError if the format string was bad */
00419         if (snprintretval < 0)
00420         {
00421             PM_RAISE(retval, PM_RET_EX_VAL);
00422             return retval;
00423         }
00424 
00425         expectedargcount++;
00426         strsize += snprintretval;
00427     }
00428 
00429     /* TypeError wrong number args */
00430     if (((OBJ_GET_TYPE(parg) != OBJ_TYPE_TUP) && (expectedargcount != 1))
00431         || ((OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
00432             && (expectedargcount != ((pPmTuple_t)parg)->length)))
00433     {
00434         PM_RAISE(retval, PM_RET_EX_TYPE);
00435         return retval;
00436     }
00437 
00438     /* Allocate and initialize String obj */
00439     retval = heap_getChunk(sizeof(PmString_t) + strsize, &pchunk);
00440     PM_RETURN_IF_ERROR(retval);
00441     pnewstr = (pPmString_t)pchunk;
00442     OBJ_SET_TYPE(pnewstr, OBJ_TYPE_STR);
00443     pnewstr->length = strsize;
00444 
00445 
00446     /* Fill contents of String obj */
00447     strindex = 0;
00448     argtupleindex = 0;
00449     pobj = parg;
00450 
00451     for (i = 0; i < pstr->length; i++)
00452     {
00453         /* Copy non-format chars */
00454         if (fmtcstr[i] != '%')
00455         {
00456             pnewstr->val[strindex++] = fmtcstr[i];
00457             continue;
00458         }
00459 
00460         /* If double percents, copy one percent */
00461         if (fmtcstr[++i] == '%')
00462         {
00463             pnewstr->val[strindex++] = '%';
00464             continue;
00465         }
00466 
00467         /* Get arg from the tuple */
00468         if (OBJ_GET_TYPE(parg) == OBJ_TYPE_TUP)
00469         {
00470             pobj = ((pPmTuple_t)parg)->val[argtupleindex++];
00471         }
00472 
00473         snprintretval = -1;
00474 
00475         /* Format one arg to get its length */
00476         smallfmtcstr[0] = '%';
00477         for(j = 1; (i < pstr->length) && (j < SIZEOF_SMALLFMT); i++)
00478         {
00479             smallfmtcstr[j] = fmtcstr[i];
00480             j++;
00481 
00482             if ((fmtcstr[i] == 'd')
00483                 || (fmtcstr[i] == 'x')
00484                 || (fmtcstr[i] == 'X'))
00485             {
00486                 smallfmtcstr[j] = '\0';
00487                 snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
00488                     (char *)smallfmtcstr, ((pPmInt_t)pobj)->val);
00489                 break;
00490             }
00491 
00492 #ifdef HAVE_FLOAT
00493             else if (fmtcstr[i] == 'f')
00494             {
00495                 smallfmtcstr[j] = '\0';
00496                 snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
00497                     (char *)smallfmtcstr, ((pPmFloat_t)pobj)->val);
00498                 break;
00499             }
00500 #endif /* HAVE_FLOAT */
00501 
00502             else if (fmtcstr[i] == 's')
00503             {
00504                 smallfmtcstr[j] = '\0';
00505                 snprintretval = snprintf((char *)fmtdbuf, SIZEOF_FMTDBUF,
00506                     (char *)smallfmtcstr, ((pPmString_t)pobj)->val);
00507                 break;
00508             }
00509         }
00510 
00511         /* Copy formatted C string into new string object */
00512         for (j = 0; j < snprintretval; j++)
00513         {
00514             pnewstr->val[strindex++] = fmtdbuf[j];
00515         }
00516     }
00517     pnewstr->val[strindex] = '\0';
00518 
00519 #if USE_STRING_CACHE
00520     /* Check for twin string in cache */
00521     for (pcacheentry = pstrcache;
00522          pcacheentry != C_NULL; pcacheentry = pcacheentry->next)
00523     {
00524         /* If string already exists */
00525         if (string_compare(pcacheentry, pnewstr) == C_SAME)
00526         {
00527             /* Free the string */
00528             retval = heap_freeChunk((pPmObj_t)pnewstr);
00529 
00530             /* Return ptr to old */
00531             *r_pstring = (pPmObj_t)pcacheentry;
00532             return retval;
00533         }
00534     }
00535 
00536     /* Insert string obj into cache */
00537     pnewstr->next = pstrcache;
00538     pstrcache = pnewstr;
00539 
00540 #endif /* USE_STRING_CACHE */
00541 
00542     *r_pstring = (pPmObj_t)pnewstr;
00543     return PM_RET_OK;
00544 }
00545 #endif /* HAVE_STRING_FORMAT */

Generated on Mon Oct 18 07:40:48 2010 for Python-on-a-chip by  doxygen 1.5.9