/***************************************************************************** * ReadSect0() -- Review 12/2002 * * Arthur Taylor / MDL * * PURPOSE * Looks for the next GRIB message, by looking for the keyword "GRIB". It * expects the message in "expect" bytes from the start, but could find the * message in "expect2" bytes or 0 bytes from the start. Returns -1 if it * can't find "GRIB", 1 if "GRIB" is not 0, "expect", or "expect2" bytes from * the start. * It stores the bytes it reads (a max of "expect") upto but not including * the 'G' in "GRIB" in wmo. * * After it finds section 0, it then parses the 16 bytes that make up * section 0 so that it can return the length of the entire GRIB message. * * When done, it sets fp to point to the end of Sect0. * * The reason for this procedure is so that we can read in the size of the * grib message, and thus allocate enough memory to read the message in before * making it Big endian, and passing it to the library for unpacking. * * ARGUMENTS * fp = A pointer to an opened file in which to read. * When done, this points to the start of section 1. (Input/Output) * buff = The data between messages. (Input/Output) * buffLen = The length of buff (Output) * limit = How many bytes to read before giving up and stating it is not * a proper message. (-1 means no limit). (Input) * sect0 = The read in Section 0 (as seen on disk). (Output) * gribLen = Length of this GRIB message. (Output) * version = 1 if GRIB1 message, 2 if GRIB2 message, -1 if TDLP message. * (Output) * expect = The expected number of bytes to find "GRIB" in. (Input) * expect2 = The second possible number of bytes to find "GRIB" in. (Input) * wmo = Assumed allocated to be at least size "expect". * Holds the bytes before the first "GRIB" message. * expect should be > expect2, but is up to caller (Output) * wmoLen = Length of wmo (total number of bytes read - SECT0LEN_WORD * 4). * (Output) * * FILES/DATABASES: * An already opened "GRIB2" File * * RETURNS: int (could use errSprintf()) * 1 = Length of wmo was != 0 and was != expect * 0 = OK * -1 = Couldn't find "GRIB" part of message. * -2 = Ran out of file while reading this section. * -3 = Grib version was not 1 or 2. * -4 = Most significant sInt4 of GRIB length was not 0 * -5 = Grib message length was <= 16 (can't be smaller than just sect 0) * * HISTORY * 9/2002 Arthur Taylor (MDL/RSIS): Created. * 11/2002 AAT: Combined with ReadWMOHeader * 12/2002 (TK,AC,TB,&MS): Code Review. * 1/2003 AAT: Bug found. wmo access out of bounds of expect when setting * the /0 element, if wmoLen > expect. * 4/2003 AAT: Added ability to handle GRIB version 1. * 5/2003 AAT: Added limit option. * 8/2003 AAT: Removed dependence on offset, and fileLen. * 10/2004 AAT: Modified to allow for TDLP files * * NOTES * 1a) 1196575042L == ASCII representation of "GRIB" (GRIB in MSB) * 1b) 1112101447L == ASCII representation of "BIRG" (GRIB in LSB) * 1c) 1413762128L == ASCII representation of "TDLP" (TDLP in MSB) * 1d) 1347175508L == ASCII representation of "PLDT" (TDLP in LSB) * 2) Takes advantage of the wordType to check that the edition is correct. * 3) May want to return prodType. * 4) WMO_HEADER_ORIG_LEN was added for backward compatibility... should be * removed when we no longer use old format. (say in a year from 11/2002) * ***************************************************************************** */ int ReadSECT0 (DataSource &fp, char **buff, uInt4 *buffLen, sInt4 limit, sInt4 sect0[SECT0LEN_WORD], uInt4 *gribLen, int *version) { typedef union { sInt4 li; unsigned char buffer[4]; } wordType; uChar gribMatch = 0; /* Counts how many letters in GRIB we've matched. */ uChar tdlpMatch = 0; /* Counts how many letters in TDLP we've matched. */ wordType word; /* Used to check that the edition is correct. */ uInt4 curLen; /* Where we currently are in buff. */ uInt4 i; /* Used to loop over the first few char's */ uInt4 stillNeed; /* Number of bytes still needed to get 1st 8 bytes of * message into memory. */ /* Get first 8 bytes. If GRIB we don't care. If TDLP, this is the length * of record. Read at least 1 record (length + 2 * 8) + 8 (next record * length) + 8 bytes before giving up. */ curLen = 8; if (*buffLen < curLen) { *buffLen = curLen; *buff = (char *) realloc ((void *) *buff, *buffLen * sizeof (char)); } if (fp.DataSourceFread(*buff, sizeof (char), curLen) != curLen) { errSprintf ("ERROR: Couldn't find 'GRIB' or 'TDLP'\n"); return -1; } /* Can't do the following because we don't know if the file is a GRIB file or not, or if it was a FORTRAN file. if (limit > 0) { MEMCPY_BIG (&recLen, *buff, 4); limit = (limit > recLen + 32) ? limit : recLen + 32; } */ while ((tdlpMatch != 4) && (gribMatch != 4)) { for (i = curLen - 8; i + 3 < curLen; i++) { if ((*buff)[i] == 'G') { if (((*buff)[i + 1] == 'R') && ((*buff)[i + 2] == 'I') && ((*buff)[i + 3] == 'B')) { gribMatch = 4; break; } } else if ((*buff)[i] == 'T') { if (((*buff)[i + 1] == 'D') && ((*buff)[i + 2] == 'L') && ((*buff)[i + 3] == 'P')) { tdlpMatch = 4; break; } } } stillNeed = i - (curLen - 8); /* Read enough of message to have the first 8 bytes (including ID). */ if (stillNeed != 0) { curLen += stillNeed; if ((limit >= 0) && (curLen > (size_t) limit)) { errSprintf ("ERROR: Couldn't find type in %ld bytes\n", limit); return -1; } if (*buffLen < curLen) { *buffLen = curLen; *buff = (char *) realloc ((void *) *buff, *buffLen * sizeof (char)); } if (fp.DataSourceFread((*buff) + (curLen - stillNeed), sizeof (char), stillNeed) != stillNeed) { errSprintf ("ERROR: Ran out of file reading SECT0\n"); return -1; } } } /* curLen and (*buff) hold 8 bytes of section 0. */ curLen -= 8; memcpy (&(sect0[0]), (*buff) + curLen, 4); #ifdef DEBUG #ifdef LITTLE_ENDIAN myAssert ((sect0[0] == 1112101447L) || (sect0[0] == 1347175508L)); #else myAssert ((sect0[0] == 1196575042L) || (sect0[0] == 1413762128L)); #endif #endif memcpy (&(sect0[1]), *buff + curLen + 4, 4); /* Make sure we don't pass back part of "GRIB" in the buffer. */ (*buff)[curLen] = '\0'; *buffLen = curLen; word.li = sect0[1]; if (tdlpMatch == 4) { if (word.buffer[3] != 0) { errSprintf ("ERROR: unexpected version of TDLP in SECT0\n"); return -2; } *version = -1; /* Find out the GRIB Message Length */ *gribLen = GRIB_UNSIGN_INT3 (word.buffer[0], word.buffer[1], word.buffer[2]); /* Min message size: GRIB1=52, TDLP=59, GRIB2=86. */ if (*gribLen < 59) { errSprintf ("TDLP length %ld was < 59?\n", *gribLen); return -5; } } else if (word.buffer[3] == 1) { *version = 1; /* Find out the GRIB Message Length */ *gribLen = GRIB_UNSIGN_INT3 (word.buffer[0], word.buffer[1], word.buffer[2]); /* Min message size: GRIB1=52, TDLP=59, GRIB2=86. */ if (*gribLen < 52) { errSprintf ("GRIB1 length %ld was < 52?\n", *gribLen); return -5; } } else if (word.buffer[3] == 2) { *version = 2; /* Make sure we still have enough file for the rest of section 0. */ if (fp.DataSourceFread(sect0 + 2, sizeof (sInt4), 2) != 2) { errSprintf ("ERROR: Ran out of file reading SECT0\n"); return -2; } if (sect0[2] != 0) { errSprintf ("Most significant sInt4 of GRIB length was not 0?\n"); errSprintf ("This is either an error, or we have a single GRIB " "message which is larger than 2^31 = 2,147,283,648 " "bytes.\n"); return -4; } #ifdef LITTLE_ENDIAN revmemcpy (gribLen, &(sect0[3]), sizeof (sInt4)); #else *gribLen = sect0[3]; #endif } else { errSprintf ("ERROR: Not TDLPack, and Grib edition is not 1 or 2\n"); return -3; } return 0; }
/***************************************************************************** * AllocSprintf() -- Arthur Taylor / MDL (Review 12/2002) * * PURPOSE * Based on minprintf (see K&R C book (2nd edition) page 156. This code * tries to provide some of the functionality of sprintf, while at the same * time it handles the memory allocation. * In addition, it provides a %S option, which allows one to pass in an * array of strings, and get back a comma delimited string. * * ARGUMENTS * Ptr = An array of data that is of size LenBuff. (Input/Output) * LenBuff = The allocated length of Ptr. (Input/Output) * fmt = Format similar to the one used by sprintf to define how to * print the message (Input) * ap = argument list initialized by a call to va_start. Contains the * data needed by fmt. (Input) * * RETURNS: void * * 9/2002 Arthur Taylor (MDL/RSIS): Created. * 12/2002 (RY,FC,MA,&TB): Code Review. * 12/2002 AAT: Fixed the mallocSprintf ("") error. * 2/2003 AAT: increased bufpart[80] to bufpart[330] because the largest * 64 bit double is: +1.7E+308, and I want 20 "slots" for stuff * after the decimal place. There is the possibility of "Long * doubles" (80 bits) which would have a max of: +3.4E+4932, but * that is excessive for now. * 2/2004 AAT: if lenBuff != 0, switch from ipos-- to strlen (buffer); * 3/2004 AAT: Added %c option. * 11/2005 AAT: Added %e option. * 1/2006 AAT: Found a bug with multiple errSprintf. Doesn't seem to be * able to handle lenBuff > strlen(buffer) when procedure is * first called. Something like format = "aaa%s", lenBuff = 3, * buff = 'n' would result in 'naaa__<string>', instead of * 'naaa<string>'. Simple solution set lenBuff = strlen (buff). * better solution: Maybe calculate correct place for ipos * before switch. * * NOTES * Supported formats: * %0.4f => float, double * %03d %ld %10ld => int, sInt4. * %s => Null terminated char string. (no range specification) * %S => take a char ** and turn it into a comma delimited string. * * Assumes that no individual float or int will be more than 80 characters * Assumes that no % option is more than 20 char. ***************************************************************************** */ static void AllocSprintf (char **Ptr, size_t *LenBuff, const char *fmt, va_list ap) { char *buffer = *Ptr; /* Local copy of Ptr. */ size_t lenBuff = *LenBuff; /* Local copy of LenBuff. */ const char *p; /* Points to % char in % option. */ const char *p1; /* Points to end of % option. */ char bufpart[330]; /* Used for formating the int / float options. */ char format[20]; /* Used to store the % option. */ char *sval; /* For pulling strings off va_list. */ char **Sval; /* For pulling lists of strings off va_list. */ size_t slen; /* Length of used part of temp. */ char f_inLoop; /* Flag to state whether we got into %S , loop. */ char flag; /* If they have a l,L,h in string. */ /* size_t ipos = *LenBuff; *//* The current index to start storing data. */ size_t ipos; /* The current index to start storing data. */ int c_type; /* Used when handling %c option. */ myAssert (sizeof (char) == 1); if ((fmt == NULL) || (strlen (fmt) == 0)) { return; } p = fmt; /* If lenBuff = 0, then make room for the '\0' character. */ if (lenBuff == 0) { lenBuff++; buffer = (char *) realloc ((void *) buffer, lenBuff); /* Added following 1 line on 1/2006 */ ipos = 0; } else { /* Added following 3 lines on 1/2006 */ myAssert (lenBuff >= strlen (buffer) + 1); lenBuff = strlen (buffer) + 1; ipos = lenBuff - 1; /* ipos = strlen (buffer); */ } while (p < fmt + strlen (fmt)) { p1 = p; p = strchr (p1, '%'); /* Handle simple case when no more % in format string. */ if (p == NULL) { /* No more format strings; copy rest of format and return */ lenBuff += strlen (p1); buffer = (char *) realloc ((void *) buffer, lenBuff); strcpy (buffer + ipos, p1); goto done; } /* Handle data up to the current % in format string. */ lenBuff += p - p1; buffer = (char *) realloc ((void *) buffer, lenBuff); strncpy (buffer + ipos, p1, p - p1); ipos = lenBuff - 1; /* Start dealing with % of format. */ p1 = p + strspn (p + 1, "0123456789."); p1++; /* p1 points to first letter after %. */ switch (*p1) { case 'h': case 'l': case 'L': flag = *p1; p1++; break; case '\0': /* Handle improper use of '%' for example: '%##' */ lenBuff += p1 - p - 1; buffer = (char *) realloc ((void *) buffer, lenBuff); strncpy (buffer + ipos, p + 1, p1 - p - 1); goto done; default: flag = ' '; } if ((p1 - p + 1) > (int) (sizeof (format)) - 1) { /* Protect against overflow of format string. */ lenBuff += p1 - p + 1; buffer = (char *) realloc ((void *) buffer, lenBuff); strncpy (buffer + ipos, p, p1 - p + 1); ipos = lenBuff - 1; } else { strncpy (format, p, p1 - p + 1); format[p1 - p + 1] = '\0'; switch (*p1) { case 'd': switch (flag) { case 'l': case 'L': sprintf (bufpart, format, va_arg (ap, sInt4)); break; /* * gcc warning for 'h': "..." promotes short int to * int. Could get rid of 'h' option but decided to * leave it in since we might have a different * compiler. */ /* case 'h': sprintf (bufpart, format, va_arg(ap, short int)); break; */ default: sprintf (bufpart, format, va_arg (ap, int)); } slen = strlen (bufpart); lenBuff += slen; buffer = (char *) realloc ((void *) buffer, lenBuff); strncpy (buffer + ipos, bufpart, slen); ipos = lenBuff - 1; break; case 'f': sprintf (bufpart, format, va_arg (ap, double)); slen = strlen (bufpart); lenBuff += slen; buffer = (char *) realloc ((void *) buffer, lenBuff); strncpy (buffer + ipos, bufpart, slen); ipos = lenBuff - 1; break; case 'e': sprintf (bufpart, format, va_arg (ap, double)); slen = strlen (bufpart); lenBuff += slen; buffer = (char *) realloc ((void *) buffer, lenBuff); strncpy (buffer + ipos, bufpart, slen); ipos = lenBuff - 1; break; case 'g': sprintf (bufpart, format, va_arg (ap, double)); slen = strlen (bufpart); lenBuff += slen; buffer = (char *) realloc ((void *) buffer, lenBuff); strncpy (buffer + ipos, bufpart, slen); ipos = lenBuff - 1; break; case 'c': c_type = va_arg (ap, int); lenBuff += 1; buffer = (char *) realloc ((void *) buffer, lenBuff); buffer[ipos] = (char) c_type; buffer[ipos + 1] = '\0'; ipos = lenBuff - 1; break; case 's': if ((p1 - p) == 1) { sval = va_arg (ap, char *); /* printf (":: sval :: '%s'\n", sval);*/ slen = strlen (sval); lenBuff += slen; buffer = (char *) realloc ((void *) buffer, lenBuff); strncpy (buffer + ipos, sval, slen); ipos = lenBuff - 1; break; } /* Intentionally fall through. */ case 'S': if ((p1 - p) == 1) { f_inLoop = 0; for (Sval = va_arg (ap, char **); *Sval; Sval++) { slen = strlen (*Sval); lenBuff += slen + 1; buffer = (char *) realloc ((void *) buffer, lenBuff); strcpy (buffer + ipos, *Sval); strcat (buffer + ipos + slen, ","); ipos = lenBuff - 1; f_inLoop = 1; } if (f_inLoop) { lenBuff--; buffer[lenBuff] = '\0'; ipos = lenBuff - 1; } break; } /* Intentionally fall through. */ default: lenBuff += p1 - p; buffer = (char *) realloc ((void *) buffer, lenBuff); strncpy (buffer + ipos, p + 1, p1 - p); ipos = lenBuff - 1; } }
//Testing mine int main() { int i, j, r, passes, choice1, choice2; int k[10] = {adventurer, gardens, embargo, village, minion, mine, cutpurse, sea_hag, tribute, smithy}; int supply[16] = {0,1,2,3,4,5,6,7,10,11,13,14,17,19,21,22}; struct gameState G; r = initializeGame(2, k, 2, &G); assert(r == 0); //Try upgrading to every card for (i = 1; i < 4; i++) { for (j = 0; j < 16; j++) { r = initializeGame(2, k, 2, &G); assert(r == 0); G.hand[0][0] = mine; G.hand[0][1] = copper; G.hand[0][2] = silver; G.hand[0][3] = gold; G.hand[0][4] = smithy; G.handCount[0] = 5; G.numActions = 1; choice1 = i; choice2 = supply[j]; //Only allow to upgrade the treasure card r = playCard(0, choice1, choice2, 0, &G); passes = 1; if (choice1 == copper && (choice2 != copper || choice2 != silver) && r == 0) { printf("Illegal move %d: traded in %d for %d. -- ", r, choice1, supply[j]); printf("Cost of copper is %d, and cost of %d is %d\n", getCost(copper), i, getCost(i)); passes = 0; } if (choice1 == silver && (choice2 != silver || choice2 != gold) && r == 0) { printf("Illegal move %d: traded in %d for %d. -- ", r, choice1, supply[j]); printf("Cost of copper is %d, and cost of %d is %d\n", getCost(silver), i, getCost(G.hand[0][i])); passes = 0; } if (choice1 == silver && (choice2 != silver || choice2 != gold) && r == 0) { printf("Illegal move %d: traded in %d for %d. -- ", r, choice1, supply[j]); printf("Cost of copper is %d, and cost of %d is %d\n", getCost(silver), i, getCost(G.hand[0][i])); passes = 0; } if (choice1 == gold && choice2 != gold && r == 0) { printf("Illegal move %d: traded in %d for %d. -- ", r, choice1, supply[j]); printf("Cost of copper is %d, and cost of %d is %d\n", getCost(silver), i, getCost(G.hand[0][i])); passes = 0; } } } myAssert(passes); return 0; }