コード例 #1
0
ファイル: zend_printf.cpp プロジェクト: vincentbdb/hiphop-php
/**
 * New sprintf implementation for PHP.
 *
 * Modifiers:
 *
 *  " "   pad integers with spaces
 *  "-"   left adjusted field
 *   n    field size
 *  "."n  precision (floats only)
 *  "+"   Always place a sign (+ or -) in front of a number
 *
 * Type specifiers:
 *
 *  "%"   literal "%", modifiers are ignored.
 *  "b"   integer argument is printed as binary
 *  "c"   integer argument is printed as a single character
 *  "d"   argument is an integer
 *  "f"   the argument is a float
 *  "o"   integer argument is printed as octal
 *  "s"   argument is a string
 *  "x"   integer argument is printed as lowercase hexadecimal
 *  "X"   integer argument is printed as uppercase hexadecimal
 */
char *string_printf(const char *format, int len, CArrRef args, int *outlen) {
  Array vargs = args;
  if (!vargs.isNull() && !vargs->isVectorData()) {
    vargs = Array::Create();
    for (ArrayIter iter(args); iter; ++iter) {
      vargs.append(iter.second());
    }
  }

  if (len == 0) {
    return strdup("");
  }

  int size = 240;
  char *result = (char *)malloc(size);
  int outpos = 0;

  int argnum = 0, currarg = 1;
  for (int inpos = 0; inpos < len; ++inpos) {
    char ch = format[inpos];

    int expprec = 0;
    if (ch != '%') {
      appendchar(&result, &outpos, &size, ch);
      continue;
    }

    if (format[inpos + 1] == '%') {
      appendchar(&result, &outpos, &size, '%');
      inpos++;
      continue;
    }

    /* starting a new format specifier, reset variables */
    int alignment = ALIGN_RIGHT;
    int adjusting = 0;
    char padding = ' ';
    int always_sign = 0;
    int width, precision;
    inpos++;      /* skip the '%' */
    ch = format[inpos];

    if (isascii(ch) && !isalpha(ch)) {
      /* first look for argnum */
      int temppos = inpos;
      while (isdigit((int)format[temppos])) temppos++;
      if (format[temppos] == '$') {
        argnum = getnumber(format, &inpos);
        if (argnum <= 0) {
          free(result);
          throw_invalid_argument("argnum: must be greater than zero");
          return nullptr;
        }
        inpos++;  /* skip the '$' */
      } else {
        argnum = currarg++;
      }

      /* after argnum comes modifiers */
      for (;; inpos++) {
        ch = format[inpos];

        if (ch == ' ' || ch == '0') {
          padding = ch;
        } else if (ch == '-') {
          alignment = ALIGN_LEFT;
          /* space padding, the default */
        } else if (ch == '+') {
          always_sign = 1;
        } else if (ch == '\'') {
          padding = format[++inpos];
        } else {
          break;
        }
      }
      ch = format[inpos];

      /* after modifiers comes width */
      if (isdigit(ch)) {
        if ((width = getnumber(format, &inpos)) < 0) {
          free(result);
          throw_invalid_argument("width: must be greater than zero "
                                 "and less than %d", INT_MAX);
          return nullptr;
        }
        adjusting |= ADJ_WIDTH;
      } else {
        width = 0;
      }
      ch = format[inpos];

      /* after width and argnum comes precision */
      if (ch == '.') {
        ch = format[++inpos];
        if (isdigit((int)ch)) {
          if ((precision = getnumber(format, &inpos)) < 0) {
            free(result);
            throw_invalid_argument("precision: must be greater than zero "
                                   "and less than %d", INT_MAX);
            return nullptr;
          }
          ch = format[inpos];
          adjusting |= ADJ_PRECISION;
          expprec = 1;
        } else {
          precision = 0;
        }
      } else {
        precision = 0;
      }
    } else {
      width = precision = 0;
      argnum = currarg++;
    }

    if (argnum > vargs.size()) {
      free(result);
      throw_invalid_argument("arguments: (too few)");
      return nullptr;
    }

    if (ch == 'l') {
      ch = format[++inpos];
    }
    /* now we expect to find a type specifier */
    Variant tmp = vargs[argnum-1];

    switch (ch) {
    case 's': {
      String s = tmp.toString();
      appendstring(&result, &outpos, &size, s.c_str(),
                   width, precision, padding, alignment, s.size(),
                   0, expprec, 0);
      break;
    }
    case 'd':
      appendint(&result, &outpos, &size, tmp.toInt64(),
                width, padding, alignment, always_sign);
      break;
    case 'u':
      appenduint(&result, &outpos, &size, tmp.toInt64(),
                 width, padding, alignment);
      break;

    case 'g':
    case 'G':
    case 'e':
    case 'E':
    case 'f':
    case 'F':
      appenddouble(&result, &outpos, &size, tmp.toDouble(),
                   width, padding, alignment, precision, adjusting,
                   ch, always_sign);
      break;

    case 'c':
      appendchar(&result, &outpos, &size, tmp.toByte());
      break;

    case 'o':
      append2n(&result, &outpos, &size, tmp.toInt64(),
               width, padding, alignment, 3, hexchars, expprec);
      break;

    case 'x':
      append2n(&result, &outpos, &size, tmp.toInt64(),
               width, padding, alignment, 4, hexchars, expprec);
      break;

    case 'X':
      append2n(&result, &outpos, &size, tmp.toInt64(),
               width, padding, alignment, 4, HEXCHARS, expprec);
      break;

    case 'b':
      append2n(&result, &outpos, &size, tmp.toInt64(),
               width, padding, alignment, 1, hexchars, expprec);
      break;

    case '%':
      appendchar(&result, &outpos, &size, '%');

      break;
    default:
      break;
    }
  }

  /* possibly, we have to make sure we have room for the terminating null? */
  result[outpos]=0;
  if (outlen) *outlen = outpos;
  return result;
}
コード例 #2
0
ファイル: plmap.c プロジェクト: FreeScienceCommunity/PLPlot
//--------------------------------------------------------------------------
//This is a function called by the front end map functions to do the map drawing. Its
//parameters are:
//mapform: The transform used to convert the data in raw coordinates to x, y positions
//on the plot
//name: either one of the plplot provided lat/lon maps or the path/file name of a
//shapefile
//dx/dy: the gradient of text/symbols drawn if text is non-null
//shapetype: one of ARC, SHPT_ARCZ, SHPT_ARCM, SHPT_POLYGON, SHPT_POLYGONZ,
//SHPT_POLYGONM, SHPT_POINT, SHPT_POINTM, SHPT_POINTZ. See drawmapdata() for the
//how each type is rendered. But Basically the ARC options are lines, the POLYGON
//options are filled polygons, the POINT options are points/text. Options beginning
//SHPT will only be defined if HAVE_SHAPELIB is true
//text: The text (which can be actual text or a unicode symbol) to be drawn at
//each point
//minx/maxx: The min/max longitude when using a plplot provided map or x value if
//using a shapefile
//miny/maxy: The min/max latitude when using a plplot provided map or y value if
//using a shapefile
//plotentries: used only for shapefiles, as one shapefile contains multiple vectors
//each representing a different item (e.g. multiple boundaries, multiple height
//contours etc. plotentries is an array containing the indices of the
//entries within the shapefile that you wish to plot. if plotentries is null all
//entries are plotted
//nplotentries: the number of elements in plotentries. Ignored if plplot was not built
//with shapefile support or if plotentries is null
//--------------------------------------------------------------------------
void
drawmap( void ( *mapform )( PLINT, PLFLT *, PLFLT * ), const char *name,
         PLFLT dx, PLFLT dy, int shapetype, PLFLT just, const char *text,
         PLFLT minx, PLFLT maxx, PLFLT miny, PLFLT maxy, const PLINT *plotentries, PLINT nplotentries )
{
#if defined ( HAVE_SHAPELIB ) || defined ( PL_DEPRECATED )
    int   i, j;
    char  *filename = NULL;
    char  truncatedfilename[900];
    char  warning[1024];
    int   nVertices = 200;
    PLFLT minsectlon, maxsectlon, minsectlat, maxsectlat;
    PLFLT *bufx   = NULL, *bufy = NULL;
    int   bufsize = 0;
    int   filenamelen;
    PLFLT **splitx             = NULL;
    PLFLT **splity             = NULL;
    int   *splitsectionlengths = NULL;
    int   nsplitsections;
    PLFLT lastsplitpointx;
    PLFLT lastsplitpointy;
    PLFLT penultimatesplitpointx;
    PLFLT penultimatesplitpointy;
    char  islatlon = 1;


#ifdef HAVE_SHAPELIB
    SHPHandle in;
    int       nentries;
    int       entryindex = 0;
    // Unnecessarily set nparts to quiet -O3 -Wuninitialized warnings.
    //int              nparts      = 0;
    int           entrynumber = 0;
    int           partnumber  = 0;
    double        mins[4];
    double        maxs[4];
    SHPObject     *object = NULL;
    double        *bufxraw;
    double        *bufyraw;
    char          *prjfilename = NULL;
    PDFstrm       *prjfile;
    char          prjtype[]    = { 0, 0, 0, 0, 0, 0, 0 };
    int           appendresult = 0;
#else
    PDFstrm       *in;
    //PLFLT            bufx[ncopies][200], bufy[ncopies][200];
    unsigned char n_buff[2], buff[800];
    long int      t;
#endif

    //
    // read map outline
    //

    //strip the .shp extension if a shapefile has been provided and add
    //the needed map file extension if we are not using shapefile
    if ( strstr( name, ".shp" ) )
        filenamelen = (int) ( name - strstr( name, ".shp" ) );
    else
        filenamelen = (int) strlen( name );
    filename = (char *) malloc( filenamelen + strlen( MAP_FILE ) + 1 );
    if ( !filename )
    {
        plabort( "Could not allocate memory for concatenating map filename" );
        return;
    }
    strncpy( filename, name, filenamelen );
    filename[ filenamelen ] = '\0';
    strcat( filename, MAP_FILE );

    //copy the filename to a fixed length array in case it is needed for warning messages
    if ( strlen( filename ) < 899 )
        strcpy( truncatedfilename, filename );
    else
    {
        memcpy( truncatedfilename, filename, 896 );
        truncatedfilename[896] = '.';
        truncatedfilename[897] = '.';
        truncatedfilename[898] = '.';
        truncatedfilename[899] = '\0';
    }

    strcpy( warning, "Could not find " );
    strcat( warning, filename );
    strcat( warning, " file." );
#ifdef HAVE_SHAPELIB
    //Open the shp and shx file using shapelib
    if ( ( in = OpenShapeFile( filename ) ) == NULL )
    {
        plabort( warning );
        free( filename );
        return;
    }
    SHPGetInfo( in, &nentries, &shapetype, mins, maxs );
    //also check for a prj file which will tell us if the data is lat/lon or projected
    //if it is projected then set ncopies to 1 - i.e. don't wrap round longitudes
    prjfilename = (char *) malloc( filenamelen + 5 );
    if ( !prjfilename )
    {
        free( filename );
        plabort( "Could not allocate memory for generating map projection filename" );
        return;
    }
    strncpy( prjfilename, name, filenamelen );
    prjfilename[ filenamelen ] = '\0';
    strcat( prjfilename, ".prj" );
    prjfile = plLibOpenPdfstrm( prjfilename );
    if ( prjfile && prjfile->file )
    {
        fread( prjtype, 1, 6, prjfile->file );
        if ( strcmp( prjtype, "PROJCS" ) == 0 )
            islatlon = 0;
        pdf_close( prjfile );
    }
    free( prjfilename );
    prjfilename = NULL;
#else
    if ( ( in = plLibOpenPdfstrm( filename ) ) == NULL )
    {
        plwarn( warning );
        return;
    }
#endif

    bufx = NULL;
    bufy = NULL;

    for (;; )
    {
#ifdef HAVE_SHAPELIB
        //each object in the shapefile is split into parts.
        //If we are need to plot the first part of an object then read in a new object
        //and check how many parts it has. Otherwise use the object->panPartStart vector
        //to check the offset of this part and the next part and allocate memory. Copy
        //the data to this memory converting it to PLFLT and draw it.
        //finally increment the part number or if we have finished with the object reset the
        //part numberand increment the object.

        //break condition if we've reached the end of the file
        if ( ( !plotentries && ( entrynumber == nentries ) ) || ( plotentries && ( entryindex == nplotentries ) ) )
            break;

        //if partnumber == 0 then we need to load the next object
        if ( partnumber == 0 )
        {
            if ( plotentries )
                object = SHPReadObject( in, plotentries[entryindex] );
            else
                object = SHPReadObject( in, entrynumber );
        }
        //if the object could not be read, increment the object index to read and
        //return to the top of the loop to try the next object.
        if ( object == NULL )
        {
            entrynumber++;
            entryindex++;
            partnumber = 0;
            continue;
        }

        //work out how many points are in the current part
        if ( object->nParts == 0 )
            nVertices = object->nVertices;                                                       //if object->nParts==0, we can still have 1 vertex. A bit odd but it's the way it goes
        else if ( partnumber == ( object->nParts - 1 ) )
            nVertices = object->nVertices - object->panPartStart[partnumber];                    //panPartStart holds the offset for each part
        else
            nVertices = object->panPartStart[partnumber + 1] - object->panPartStart[partnumber]; //panPartStart holds the offset for each part
#endif
        //allocate memory for the data
        if ( nVertices > bufsize )
        {
            bufsize = nVertices;
            free( bufx );
            free( bufy );
            bufx = (PLFLT *) malloc( (size_t) bufsize * sizeof ( PLFLT ) );
            bufy = (PLFLT *) malloc( (size_t) bufsize * sizeof ( PLFLT ) );
            if ( !bufx || !bufy )
            {
                plabort( "Could not allocate memory for map data" );
                free( filename );
                free( bufx );
                free( bufy );
                return;
            }
        }

#ifdef HAVE_SHAPELIB
        //point the plot buffer to the correct starting vertex
        //and copy it to the PLFLT arrays. If we had object->nParts == 0
        //then panPartStart will be NULL
        if ( object->nParts > 0 )
        {
            bufxraw = object->padfX + object->panPartStart[partnumber];
            bufyraw = object->padfY + object->panPartStart[partnumber];
        }
        else
        {
            bufxraw = object->padfX;
            bufyraw = object->padfY;
        }

        for ( i = 0; i < nVertices; i++ )
        {
            bufx[i] = (PLFLT) bufxraw[i];
            bufy[i] = (PLFLT) bufyraw[i];
        }

        //set the min x/y of the object
        minsectlon = object->dfXMin;
        maxsectlon = object->dfXMax;
        minsectlat = object->dfYMin;
        maxsectlat = object->dfYMax;

        //increment the partnumber or if we've reached the end of
        //an entry increment the entrynumber and set partnumber to 0
        if ( partnumber == object->nParts - 1 || object->nParts == 0 )
        {
            entrynumber++;
            entryindex++;
            partnumber = 0;
            SHPDestroyObject( object );
            object = NULL;
        }
        else
            partnumber++;

        if ( nVertices == 0 )
            continue;
#else
        // read in # points in segment
        if ( pdf_rdx( n_buff, (long) sizeof ( unsigned char ) * 2, in ) == 0 )
            break;
        nVertices = ( n_buff[0] << 8 ) + n_buff[1];
        if ( nVertices == 0 )
            break;

        pdf_rdx( buff, (long) sizeof ( unsigned char ) * 4 * nVertices, in );
        if ( nVertices == 1 )
            continue;

        for ( j = i = 0; i < nVertices; i++, j += 2 )
        {
            t       = ( buff[j] << 8 ) + buff[j + 1];
            bufx[i] = ( (PLFLT) t - OFFSET ) / SCALE;
        }
        for ( i = 0; i < nVertices; i++, j += 2 )
        {
            t       = ( buff[j] << 8 ) + buff[j + 1];
            bufy[i] = ( (PLFLT) t - OFFSET ) / SCALE;
        }
        //set the min/max section lat/lon with extreme values
        //to be overwritten later
        minsectlon = 1000.;
        maxsectlon = -1000.;
        minsectlat = 1000.;
        maxsectlat = -1000.;

#endif

        if ( islatlon )
        {
            //two obvious issues exist here with plotting longitudes:
            //
            //1) wraparound causing lines which go the wrong way round
            //   the globe
            //2) some people plot lon from 0-360 deg, others from -180 - +180
            //
            //we can cure these problems by conditionally adding/subtracting
            //360 degrees to each data point in order to ensure that the
            //distance between adgacent points is always less than 180
            //degrees, then plotting up to 2 out of 5 copies of the data
            //each separated by 360 degrees.

            //arrays of pointers to the starts of each section of data that
            //has been split due to longitude wrapping, and an array of ints
            //to hold their lengths. Start with splitx and splity having one
            //element pointing to the beginning of bufx and bufy
            splitx = (PLFLT **) malloc( sizeof ( PLFLT* ) );
            splity = (PLFLT **) malloc( sizeof ( PLFLT* ) );
            //lengths of the split sections
            splitsectionlengths = (int *) malloc( sizeof ( size_t ) );
            if ( !splitx || !splity || !splitsectionlengths )
            {
                plabort( "Could not allocate memory for longitudinally split map data" );
                free( filename );
                free( bufx );
                free( bufy );
                free( splitx );
                free( splity );
                free( splitsectionlengths );
                return;
            }
            splitsectionlengths[0] = nVertices;
            nsplitsections         = 1;
            splitx[0] = bufx;
            splity[0] = bufy;

            //set the min/max lats/lons
            minsectlon = MIN( minsectlon, bufx[0] );
            maxsectlon = MAX( minsectlon, bufx[0] );
            minsectlat = MIN( minsectlat, bufy[0] );
            maxsectlat = MAX( maxsectlat, bufy[0] );
            //ensure our lat and lon are on 0-360 grid and split the
            //data where it wraps.
            rebaselon( &bufx[0], ( minx + maxx ) / 2.0 );
            for ( i = 1; i < nVertices; i++ )
            {
                //put lon into 0-360 degree range
                rebaselon( &bufx[i], ( minx + maxx ) / 2.0 );

                //check if the previous point is more than 180 degrees away
                if ( bufx[i - 1] - bufx[i] > 180. || bufx[i - 1] - bufx[i] < -180. )
                {
                    //check if the map transform deals with wrapping itself, e.g. in a polar projection
                    //in this case give one point overlap to the sections so that lines are contiguous
                    if ( checkwrap( mapform, bufx[i], bufy[i] ) )
                    {
                        appendresult += appendfltptr( &splitx, nsplitsections, bufx + i );
                        appendresult += appendfltptr( &splity, nsplitsections, bufy + i );
                        appendresult += appendint( &splitsectionlengths, nsplitsections, nVertices - i );
                        splitsectionlengths[nsplitsections - 1] -= splitsectionlengths[nsplitsections] - 1;
                        nsplitsections++;
                    }
                    //if the transform doesn't deal with wrapping then allow 2 points overlap to fill in the
                    //edges
                    else
                    {
                        appendresult += appendfltptr( &splitx, nsplitsections, bufx + i - 1 );
                        appendresult += appendfltptr( &splity, nsplitsections, bufy + i - 1 );
                        appendresult += appendint( &splitsectionlengths, nsplitsections, nVertices - i + 1 );
                        splitsectionlengths[nsplitsections - 1] -= splitsectionlengths[nsplitsections] - 2;
                        nsplitsections++;
                    }
                    if ( appendresult > 0 )
                    {
                        plabort( "Could not allocate memory for appending to longitudinally split map data" );
                        free( filename );
                        free( bufx );
                        free( bufy );
                        free( splitx );
                        free( splity );
                        free( splitsectionlengths );
                        return;
                    }
                }

                //update the mins and maxs
                minsectlon = MIN( minsectlon, bufx[i] );
                maxsectlon = MAX( minsectlon, bufx[i] );
                minsectlat = MIN( minsectlat, bufy[i] );
                maxsectlat = MAX( maxsectlat, bufy[i] );
            }

            //check if the latitude and longitude range means we need to plot this section
            if ( ( maxsectlat > miny ) && ( minsectlat < maxy )
                 && ( maxsectlon > minx ) && ( minsectlon < maxx ) )
            {
                //plot each split in turn, now is where we deal with the end points to
                //ensure we draw to the edge of the map
                for ( i = 0; i < nsplitsections; ++i )
                {
                    //check if the first 2 or last 1 points of the split section need
                    //wrapping and add or subtract 360 from them. Note that when the next
                    //section is drawn the code below will undo this if needed
                    if ( splitsectionlengths[i] > 2 )
                    {
                        if ( splitx[i][1] - splitx[i][2] > 180. )
                            splitx[i][1] -= 360.0;
                        else if ( splitx[i][1] - splitx[i][2] < -180. )
                            splitx[i][1] += 360.0;
                    }

                    if ( splitx[i][0] - splitx[i][1] > 180. )
                        splitx[i][0] -= 360.0;
                    else if ( splitx[i][0] - splitx[i][1] < -180. )
                        splitx[i][0] += 360.0;

                    if ( splitx[i][splitsectionlengths[i] - 2] - splitx[i][splitsectionlengths[i] - 1] > 180. )
                        splitx[i][splitsectionlengths[i] - 1] += 360.0;
                    else if ( splitx[i][splitsectionlengths[i] - 2] - splitx[i][splitsectionlengths[i] - 1] < -180. )
                        splitx[i][splitsectionlengths[i] - 1] -= 360.0;

                    //save the last 2 points - they will be needed by the next
                    //split section and will be overwritten by the mapform
                    lastsplitpointx        = splitx[i][splitsectionlengths[i] - 1];
                    lastsplitpointy        = splity[i][splitsectionlengths[i] - 1];
                    penultimatesplitpointx = splitx[i][splitsectionlengths[i] - 2];
                    penultimatesplitpointy = splity[i][splitsectionlengths[i] - 2];

                    //draw the split section
                    drawmapdata( mapform, shapetype, splitsectionlengths[i], splitx[i], splity[i], dx, dy, just, text );

                    for ( j = 1; j < splitsectionlengths[i]; ++j )
                    {
                        if ( ( splitx[i][j] < 200.0 && splitx[i][j - 1] > 260.0 ) || ( splitx[i][j - 1] < 200.0 && splitx[i][j] > 260.0 ) )
                            plwarn( "wrapping error" );
                    }

                    //restore the last 2 points
                    splitx[i][splitsectionlengths[i] - 1] = lastsplitpointx;
                    splity[i][splitsectionlengths[i] - 1] = lastsplitpointy;
                    splitx[i][splitsectionlengths[i] - 2] = penultimatesplitpointx;
                    splity[i][splitsectionlengths[i] - 2] = penultimatesplitpointy;
                }
            }
        }
        else
        {
            drawmapdata( mapform, shapetype, nVertices, bufx, bufy, dx, dy, just, text );
        }

        free( splitx );
        free( splity );
        free( splitsectionlengths );
    }
    // Close map file
#ifdef HAVE_SHAPELIB
    SHPClose( in );
#else
    pdf_close( in );
#endif

    //free memory
    free( bufx );
    free( bufy );
    free( filename );
#else   // defined (HAVE_SHAPELIB) || defined (PL_DEPRECATED)
    plwarn( "Use of the old plplot map file format is deprecated.\nIt is recommended that the shapelib library be used to provide map support.\n" );
#endif  // defined (HAVE_SHAPELIB) || defined (PL_DEPRECATED)
}