Example #1
0
/* 7.7.3 <SUFFIX PROGRAM DATA> */
int scpiLex_SuffixProgramData(lex_state_t * state, scpi_token_t * token) {
    token->ptr = state->pos;

    skipChr(state, '/');

    // TODO: strict parsing  : SLASH? (ALPHA+ (MINUS? DIGIT)?) ((SLASH | DOT) (ALPHA+ (MINUS? DIGIT)?))*
    if (skipAlpha(state)) {
        skipChr(state, '-');
        skipDigit(state);

        while (skipSlashDot(state)) {
            skipAlpha(state);
            skipChr(state, '-');
            skipDigit(state);
        }
    }

    token->len = state->pos - token->ptr;
    if ((token->len > 0)) {
        token->type = SCPI_TOKEN_SUFFIX_PROGRAM_DATA;
    } else {
        token->type = SCPI_TOKEN_UNKNOWN;
        state->pos = token->ptr;
        token->len = 0;
    }

    return token->len;
}
/**
 * Parse the planet string and its sub elements
 * @param topLevel Pointer to the string structure to be parsed
 * @return Returns a pointer to a planet structure with associated data. Null on failure
 **/
pPlanet planetTopLevel( pstring topLevel )
{
	int endIndex = 0;
        int temp_index = 0;
        pPlanet newPlanet = NULL;
        element el;
        char *fl = NULL;
        int lastGood = 0;

        if ( topLevel == NULL ) {
                goto end;
        }

        /// Skip any leading spaces
        skipWhiteSpace( topLevel );

	lastGood = topLevel->index;

	if ( topLevel->maxlength < 9 ) {
		goto end;
	}

	char *c = "{Planet}";

	for ( int i = 0; i < 8; i++ ) {
		if ( topLevel->buffer[ topLevel->index + i ] != c[i] ) {
			goto end;
		}
	}

        /// Skip 8 bytes of top level then any whitespace
        topLevel->index += 8;

	skipWhiteSpace( topLevel );

        /// Allocate a new planet structure
        if ( allocate( sizeof(Planet), 0, (void**)&newPlanet) != 0 ) {
                goto end;
        }

        initPlanet( newPlanet );

        /// Extract the next element name
        fl = pullNextElementName( topLevel );

        getIndex( topLevel, &lastGood);

        while ( fl != NULL ) {
                /// Convert the element name
                el = elementNameToEnum( fl );

                /// The name is no longer needed so free it
                deallocate( fl, strlen(fl) + 1 );

                switch (el) {
                        case name:
                                fl = extractName( topLevel );

                                if ( fl == NULL ) {
                                        goto error;
                                }

				bzero( newPlanet->name, 20 );
                                strncpy( newPlanet->name, fl, 19 );

                                deallocate(fl, strlen(fl) + 1 );
                                fl = NULL;

                                break;
                        case population:
                                newPlanet->population = extractPopulation( topLevel );

                                if ( newPlanet->population < 0 ) {
                                        goto error;
                                }

                                break;
                        case period:
                                /// Extract period and check result
                                newPlanet->period = extractPeriod( topLevel );
                                if ( newPlanet->period < 0.0 ) {
                                        goto error;
                                }

                                break;
                        case orbitspeed:
                                newPlanet->orbitspeed = extractOrbitSpeed( topLevel );

                                if ( newPlanet->orbitspeed < 0.0 ) {
                                        goto error;
                                }
                                break;
                        case aphelion:
                                newPlanet->aphelion = extractAphelion( topLevel );

                                if ( newPlanet->aphelion < 0.0 ) {
                                        goto error;
                                }
                                break;
                        case perihelion:
                                newPlanet->perihelion = extractPerihelion( topLevel );

                                if ( newPlanet->perihelion < 0.0 ) {
                                        goto error;
                                }

                                break;
                        case radius:
                                newPlanet->radius = extractRadius( topLevel );

                                if ( newPlanet->radius < 0.0 ) {
                                        goto error;
                                }
                                break;

                        case eradius:
                                newPlanet->eradius = extractERadius( topLevel );

                                if ( newPlanet->eradius < 0.0 ) {
                                        goto error;
                                }
                                break;
                        case mass:
                                newPlanet->mass = extractMass( topLevel );

                                if ( newPlanet->mass < 0.0 ) {
                                        goto error;
                                }

                                break;

                        case gravity:
                                newPlanet->gravity = extractGravity( topLevel );

                                if ( newPlanet->gravity < 0.0 ) {
                                        goto error;
                                }

                                break;
                        case country:
                                if ( newPlanet->country_count >= COUNTRYMAX ) {
                                        printf("!!Only @d countries allowed\n", COUNTRYMAX);
                                        goto error;
                                }

                                newPlanet->countries[ newPlanet->country_count] = countryTopLevel(topLevel);

                                if (newPlanet->countries[ newPlanet->country_count ] == NULL ) {
                                        goto error;
                                }

                                newPlanet->country_count++;
                                break;

                        default:
                                printf("Not allowed under Planet\n", fl);
                                goto error;
                                break;
                };


                getIndex( topLevel, &lastGood );
                fl = pullNextElementName( topLevel );

        }

        /// Since no more valid elements need to be parsed, check the closing element
        skipWhiteSpace( topLevel );

        if ( !atChar( topLevel, '{' ) ) {
                printf("!!Closing value failed for Planet\n");
                goto error;
        }

        /// Skip the open brace
        if ( incChar( topLevel ) < 0 ) {
                goto error;
        }

        skipWhiteSpace( topLevel );

        if ( !atChar( topLevel, '#' ) ) {
                printf("!!Malformed closing element\n");
                goto error;
        }

        /// Skip past #
        if ( incChar( topLevel ) == -1 ) {
                goto error;
        }

        getIndex( topLevel, &temp_index );

        endIndex = skipAlpha( topLevel );

        if ( endIndex == -1 ) {
                endIndex = 0;
                goto error;
        }

        if ( temp_index == endIndex ) {
                goto error;
        }

        fl = copyData( topLevel, temp_index, endIndex );

        if ( fl == NULL ) {
                goto error;
        }

        if ( strcmp( fl, "Planet") != 0 ) {
                printf("!!Closing element malformed\n");
                deallocate( fl, (endIndex-temp_index) + 1 );
                goto error;
        }

        deallocate(fl, (endIndex-temp_index) + 1 );

        skipWhiteSpace( topLevel );

        if ( !atChar( topLevel, '}' ) ) {
                printf("!!Failed to find final closing brace\n");
                goto error;
        }

        incChar(topLevel);
	
        goto end;

error:
        topLevel->index = lastGood;

        printf("!!Error at: @s\n", topLevel->buffer + topLevel->index);

	if ( newPlanet != NULL ) {
		freePlanet( newPlanet );
		newPlanet = NULL;
	}

end:
        return newPlanet;
}
/**
 * Extracts the data from the Name element
 * @param str Pointer to a string structure
 * @return Returns a pointer to the name data or NULL on failure
 *	The calling function must free the name pointer
 **/
char *extractName( pstring str )
{
	char *temp = NULL;
	char *name = NULL;
	int start = 0;
	int end = 0;

	/// These will be used specifically for the name data
	int ns = 0;
	int ne = 0;

	if (str == NULL ) {
		return name;
	}

	skipWhiteSpace(str);

	if ( !atChar( str, '{' ) ) {
		printf("!!Failed to locate opening brace\n");
		return name;
	}

	/// Skip past the curly brace
	if ( skipLength( str, 1 ) == -1 ) {
		printf("!!Failed to skip opening brace\n");
		return name;
	}

	/// Skip any additional whitespace
	skipWhiteSpace(str);

	/// Save the index
	start = str->index;

	/// This should skip any to either whitespace or a closing '}'
	end = skipAlpha( str );

	if ( end == -1 ) {
		printf("!!Failed to locate the end of the element id\n");
		return NULL;
	}

	/// Copy the element id from the string
	temp = copyData( str, start, end );

#ifdef PATCHED
	if ( temp == NULL ) {
		return NULL;
	}
#endif

	if ( temp == NULL ) {
		printf("!!Copy from @d to @d failed\n", start, end);
		return NULL;
	}

	/// If the element id is not "Name" then this is the wrong function
	if ( strcmp( temp, "Name") != 0 ) {
		printf("!!Element id is not \"Name\"\n");
		deallocate( temp, strlen(temp) + 1 );
		temp = NULL;
		return NULL;
	}

	/// The buffer is no longer needed so free it
	deallocate(temp, strlen(temp) + 1);

	/// Skip to the end of the element id
	skipWhiteSpace( str );

	/// If it is not a closing brace then this is improperly formatted.
	if ( !atChar( str, '}' ) ) {
		printf("!!Failed to locate initial closing brace\n");
		return NULL;
	}

	/// Skip the closing brace as well as any whitespace
	if ( skipLength( str, 1 ) == -1 ) {
		printf("!!Failed to skip initial closing brace\n");
		return NULL;
	}

	skipWhiteSpace( str );

	/// Copy the start index to store the data
	ns = str->index;

	/// The name data must be alphanumeric
	ne = skipToNonAlphaNum( str );

	if ( ne == -1 ) {
		printf("!!Failed to locate the end of the name data\n");
		return NULL;
	}

	/// The rest of this code is a check to ensure proper formatting except for the copy data
	skipWhiteSpace( str );

	/// If this is not an opening curly brace then fail
	if ( !atChar( str, '{' ) ) {
		printf("!!Failed to locate the final opening brace\n");
		return NULL;
	}

	/// Skip past the brace
	if ( skipLength( str, 1 ) == -1 ) {
		printf("!!Failed to skip the final opening brace\n");
		return NULL;
	}
	
	skipWhiteSpace(str);

	/// If this is not a # indicating the closing brace then fail
	if ( !atChar( str, '#' ) ) {
		printf("!!Failed to locate the closing mark\n");		
		return NULL;
	}

	/// Skip past the # but save the start
	start = skipLength( str, 1 );

	if ( start == -1 ) {
		printf("!!Failed to skip closing mark\n");
		return NULL;
	}

	end = skipAlpha( str );

	if ( end == -1 ) {
		printf("!!Failed to locate the end of the closing element id\n");
		return NULL;
	}
	
	temp = copyData( str, start, end );

#ifdef PATCHED
	if ( temp == NULL ) {
		return NULL;
	}
#endif

	if ( strcmp( temp, "Name") != 0 ) {
		printf("!!Invalid closing element id: @s\n", temp);
		deallocate(temp, strlen(temp)+1);
		return NULL;
	}

	deallocate(temp, strlen(temp)+1);

	skipWhiteSpace( str );

	/// Check the final curly brace
	if ( !atChar( str, '}' ) ) {
		printf("!!Failed to locate final closing brace\n");
		return NULL;
	}

	/// Skip past the closing brace
	skipLength( str, 1 );
		
	/// Copy the name element data
	name = copyData( str, ns, ne );

	return name;
}
/**
 * Parse the Border element and return a structure containing the data
 * @param str Pointer to a string structure
 * @return Returns a pointer to a border structure or NULL on failure
 **/
Border *extractBorder( pstring str )
{
	char *temp = NULL;
	pBorder bor = NULL;
	int start = 0;
	int end = 0;

	if (str == NULL ) {
		return bor;
	}

	/// Allocate a new border structure
	if ( allocate( sizeof(Border), 0, (void**)&bor) != 0 ) {
		bor = NULL;
		return bor;
	}

	skipWhiteSpace(str);

	/// If it does not open with a '{' then it is invalid.
	if ( !atChar( str, '{' ) ) {
		printf("!!Failed to locate opening brace\n");
		goto error;
	}

	/// Skip past the curly brace
	if ( skipLength( str, 1 ) == -1 ) {
		printf("!!Failed to skip opening brace\n");
		goto error;
	}

	/// Skip any additional whitespace
	skipWhiteSpace(str);

	/// Save the index
	start = str->index;

	/// This should skip any to either whitespace or a closing '}'
	end = skipAlpha( str );

	if ( end == -1 ) {
		printf("!!Failed to locate the end of the element id\n");
		goto error;
	}

	/// If start and end are then same then it is an invalid character
	if ( start == end ) {
		goto error;
	}

	/// Copy the element id from the string
	temp = copyData( str, start, end );

	if ( temp == NULL ) {
		printf("!!Copy from @d to @d failed\n", start, end);
		goto error;
	}

	/// If the element id is not "Border" then this is the wrong function
	if ( strcmp( temp, "Border") != 0 ) {
		printf("!!Element id is not \"Border\"\n");
		deallocate( temp, strlen(temp) + 1 );
		temp = NULL;
		goto error;
	}

	/// The buffer is no longer needed so free it
	deallocate(temp, strlen(temp) + 1);

	/// Skip to the end of the element id
	skipWhiteSpace( str );

	/// If it is not a closing brace then this is improperly formatted.
	if ( !atChar( str, '}' ) ) {
		printf("!!Failed to locate initial closing brace\n");
		goto error;
	}

	/// Skip the closing brace as well as any whitespace
	if ( skipLength( str, 1 ) == -1 ) {
		printf("!!Failed to skip initial closing brace\n");
		goto error;
	}

	start = skipWhiteSpace( str );

	/// The border data must be a float
	end = skipFloat( str );

	if ( start == end ) {
		printf("!!Failed to locate first lat\n");
		goto error;
	}

	if ( end == -1 ) {
		printf("!!Failed to locate the end of the first latitude float\n");
		goto error;
	}

	temp = copyData( str, start, end );

	if (temp == NULL ) {
		printf("!!Failed to copy first latitude float\n");
		goto error;
	}

	/// Convert the first value
	bor->latStart = atof( temp );

	deallocate( temp, (end-start) + 1 );

	/// Skip to the next value
	start = skipWhiteSpace( str );

	end = skipFloat(str);

	if ( start == end ) {
		printf("!!Failed to locate first long\n");
		goto error;
	}

	if ( start == -1 || end == -1 ) {
		printf("!!Failed to locate first longitude float\n");
		goto error;
	}

	temp = copyData( str, start, end );

	if ( temp == NULL ) {
		printf("!!Failed to copy first longitude float\n");
		goto error;
	}

	/// Convert the first long
	bor->lngStart = atof( temp );

	deallocate( temp, (end-start) + 1 );

	/// Skip to the next value
	start = skipWhiteSpace( str );

	end = skipFloat(str);

	if ( start == end ) {
		printf("!!Failed to locate second lat\n");
		goto error;
	}

	if ( start == -1 || end == -1 ) {
		printf("!!Failed to locate second latitude float\n");
		goto error;
	}

	temp = copyData( str, start, end );

	if ( temp == NULL ) {
		printf("!!Failed to copy second latitude float\n");
		goto error;
	}

	/// Convert the second lat
	bor->latEnd = atof( temp );

	deallocate( temp, (end-start) + 1 );

	/// Skip to the next value
	start = skipWhiteSpace( str );

	end = skipFloat(str);

	if ( start == end ) {
		printf("!!Failed to locate second long\n");
		goto error;
	}

	if ( start == -1 || end == -1 ) {
		printf("!!Failed to locate second longitude float\n");
		goto error;
	}

	temp = copyData( str, start, end );

	if ( temp == NULL ) {
		printf("!!Failed to copy second longitude float\n");
		goto error;
	}

	/// Convert the second long
	bor->lngEnd = atof( temp );

	deallocate( temp, (end-start) + 1 );

	skipWhiteSpace( str );

	/// If this is not an opening curly brace then fail
	if ( !atChar( str, '{' ) ) {
		printf("!!Failed to locate the final opening brace\n");
		goto error;
	}

	/// Skip past the brace
	if ( skipLength( str, 1 ) == -1 ) {
		printf("!!Failed to skip the final opening brace\n");
		goto error;
	}
	
	skipWhiteSpace(str);

	/// If this is not a # indicating the closing brace then fail
	if ( !atChar( str, '#' ) ) {
		printf("!!Failed to locate the closing mark\n");		
		goto error;
	}

	/// Skip past the # but save the start
	start = skipLength( str, 1 );

	if ( start == -1 ) {
		printf("!!Failed to skip closing mark\n");
		goto error;
	}

	end = skipAlpha( str );

	if ( end == -1 ) {
		printf("!!Failed to locate the end of the closing element id\n");
		goto error;
	}
	
	temp = copyData( str, start, end );

#ifdef PATCHED
	if ( temp == NULL ) {
		goto error;
	}
#endif

	if ( strcmp( temp, "Border") != 0 ) {
		printf("!!Invalid closing element id: @s\n", temp);
		deallocate(temp, strlen(temp)+1);
		goto error;
	}

	deallocate(temp, strlen(temp)+1);

	skipWhiteSpace( str );

	/// Check the final curly brace
	if ( !atChar( str, '}' ) ) {
		printf("!!Failed to locate final closing brace\n");
		goto error;
	}

	/// Skip past the closing brace
	skipLength( str, 1 );

	/// Everything succeeded, skip error
	goto fin;
		
error:
	deallocate( bor, sizeof(Border) );
	bor = NULL;

fin:
	return bor;
}
Example #5
0
/**
 * Extract the data from the Url element.
 * 	This can be something such as http://www.rome.com
 * @param str Pointer to a string structure
 * @return Returns the element data or NULL on failure
 *	The caller is responsible for freeing the pointer
 **/
char *extractUrl( pstring str ) 
{
	char *url = NULL;
	int startIndex = 0;
	char *temp = NULL;

	if ( str == NULL ) {
		goto end;
	}

	if ( skipOpen( str, 0 ) == 0 ) {
		goto end;
	}

	getIndex( str, &startIndex );

	skipAlpha(str);

	url = copyData( str, startIndex, str->index);

	if ( url == NULL ) {
		goto end;
	}

	if ( strcmp( url, "Url" ) ) {
		freeCharPtr( &url );
		goto end;
	}

	skipWhiteSpace( str );

	if (!atChar( str, '}') ) {
		goto end;
	}

	incChar(str);
	skipWhiteSpace(str);
	getIndex( str, &startIndex);

	skipUrl( str );

	url = copyData( str, startIndex, str->index );

	if ( url == NULL ) {
		goto end;
	}

	skipWhiteSpace(str);
	if ( skipOpen( str, 1 ) == 0 ) {
		goto error;
	}

	getIndex( str, &startIndex );
	skipAlpha(str);
	temp = copyData( str, startIndex, str->index);

	if ( temp == NULL ) {
		goto error;
	}

	if ( strcmp( temp, "Url") != 0 ) {
		freeCharPtr( &temp );
		goto error;
	}

	freeCharPtr( &temp );

	skipWhiteSpace(str);
	if ( !atChar( str, '}') ) {
		goto error;
	}

	incChar(str);

	goto end;
error:
	if ( url ) {
		freeCharPtr( &url );
	}

end:
	return url;
}
Example #6
0
/**
 * Extracts the data from the Mayor element id
 * @param str Pointer to a string structure
 * @return Returns a pointer to the data or NULL on failure
 *	The caller must free the pointer
 **/
char *extractMayor( pstring str )
{
	char *mayor = NULL;
	register int startIndex = 0;
	register int endIndex = 0;
 	char *temp = NULL;

	if ( !str ) {
		return NULL;
	}

	/// This skips any whitespace and opening '{ '
	if (skipOpen(str, 0 ) == 0 ) {
		return NULL;
	}

	startIndex = str->index;
	endIndex = skipAlpha(str);

	if ( endIndex == -1 || startIndex == endIndex ) {
		return NULL;
	}

	mayor = copyData( str, startIndex, endIndex );

	if ( mayor == NULL ) {
		return NULL;
	}

	if ( strcmp( mayor, "Mayor") != 0 ) {
		freeCharPtr( &mayor );
		return NULL;
	}

	freeCharPtr( &mayor );

	skipWhiteSpace( str );

	if (!atChar( str, '}') ) {
		return NULL;
	}

	/// Skip the Closing brace
	incChar( str );

	startIndex = skipWhiteSpace(str);

	/// Using this function allows things like Sir Winston Churchill 3rd
	endIndex = skipToNonAlphaNumSpace( str );

	if ( endIndex < 0 || startIndex == endIndex ) {
		return NULL;
	}

	while ( isspace( str->buffer[endIndex-1] ) ) {
		endIndex--;
	}

	mayor = copyData( str, startIndex, endIndex );

	if ( mayor == NULL ) {
		return NULL;
	}

	skipWhiteSpace(str);

	/// Skip the opening brace and '#'
	if ( skipOpen( str, 1 ) == 0 ) {
		goto error;
	}

	startIndex = str->index;
	endIndex = skipAlpha( str );

	if ( endIndex == -1 || startIndex == endIndex ) {
		goto error;
	}

	temp = copyData( str, startIndex, endIndex );

	if ( temp == NULL ) {
		goto error;
	}

	if ( strcmp( temp, "Mayor") != 0 ) {
		freeCharPtr( &temp );
		goto error;
	}

	skipWhiteSpace(str);

	if ( !atChar( str, '}' ) ) {
		goto error;
	}

	incChar(str);
	
	goto end;
error:
	freeCharPtr( &mayor );
end:
	return mayor; 
}
Example #7
0
/**
 * Top level function for parsing a City PML element
 * @param str Pointer to a string structure
 * @return Returns a pointer to a filled in city structure or NULL on failure
 **/
pCity cityTopLevel( pstring str )
{
	int lastGood = 0;
	pCity newCity = NULL;
	int startIndex = 0;
	int endIndex = 0;
	char *temp = NULL;
	int tempInt = 0;
	element el;

	if ( str == NULL ) {
		goto end;
	}

	/// Skip the opening "{"
	if ( skipOpen( str, 0 ) == 0 ) {
		goto end;
	}

	/// Get the start and end index of the element id
	getIndex( str, &startIndex);
	endIndex = skipAlpha(str);

	if ( endIndex == -1 ) {
		goto end;
	}

	if ( startIndex == endIndex ) {
		goto end;
	}

	temp = copyData( str, startIndex, endIndex );

	if ( temp == NULL ) {
		goto end;
	}

	if ( strcmp( temp, "City") != 0 ) {
		deallocate(temp, cgc_strlen(temp) + 1 );
		goto end;
	}

	deallocate(temp, cgc_strlen(temp) + 1 );

	skipWhiteSpace( str );
	if ( !atChar( str, '}') ) {
		goto end;
	}

	incChar( str );
	skipWhiteSpace(str);

	lastGood = str->index;

	if ( allocate( sizeof(City), 0, (void**)&newCity) != 0 ) {
		newCity = NULL;
		goto error;
	}

	initCity( newCity );

	temp = pullNextElementName( str );

	while ( temp != NULL ) {
		el = elementNameToEnum( temp );

		deallocate(temp, cgc_strlen(temp) + 1 );

		switch (el) {
			case name:
				temp = extractName( str );

				if ( temp == NULL ) {
					goto error;
				}

				/// Clear it out
				bzero( newCity->name, 20 );

				/// Copy the name data. It has already been filtered 
				///	for invalid characters.
				strncpy( newCity->name, temp, 19);

				/// Free the buffer
				deallocate( temp, cgc_strlen(temp) + 1 );
				temp = NULL;
				break;
			case mayor:
				temp = extractMayor( str );

				if ( temp == NULL ) {
					goto error;
				}
			
				bzero( newCity->mayor, 30 );
#ifdef PATCHED
				strncpy( newCity->mayor, temp, 29 );
#else
				strcpy( newCity->mayor, temp );
#endif
				freeCharPtr( &temp );

				break;
			case url:
				temp = extractUrl( str );

				if ( temp == NULL ) {
					goto error;
				}

				bzero( newCity->url, 30 );

				strncpy( newCity->url, temp, 29 );
				freeCharPtr( &temp );
				break;
			case border:
				if ( newCity->border_count >= CITYBORDERMAX) {
					goto error;
				}

				tempInt = newCity->border_count;

				newCity->borders[ tempInt ] = extractBorder(str);

				if ( newCity->borders[ tempInt] == NULL ) {
					goto error;
				}

				newCity->border_count++;
				break;
			case population:
				newCity->population = extractPopulation( str );

				if ( newCity->population < 0 ) {
					goto error;
				}

				break;
			default:
				printf("!!Invalid element ID for City\n");
				goto error;
				break;
		};

		lastGood = str->index;
		temp = pullNextElementName(str);
	}

	if ( skipOpen( str, 1) == 0 ) {
		goto error;
	}

	getIndex( str, &startIndex);
	endIndex = skipAlpha( str );

	if ( endIndex == -1 ) {
		goto error;
	} else if ( startIndex == endIndex ) {
		goto error;
	}

	temp = copyData( str, startIndex, endIndex );

	if ( temp == NULL ) {
		goto error;
	}

	if ( strcmp( temp, "City") != 0 ) {
		deallocate(temp, cgc_strlen(temp) + 1 );
		goto error;
	}

	deallocate( temp, cgc_strlen(temp) + 1 );
	skipWhiteSpace(str);
	if ( !atChar( str, '}') ) {
		goto error;
	}

	incChar(str);
	goto end;
error:
	if ( newCity ) {
		freeCity( newCity );
		newCity = NULL;
	}

	printf("!!Error at: @s\n", str->buffer + lastGood);
	str->index = lastGood;

end:
	return newCity;
}