diff --git a/graphics/traveler/tools/libwld/Makefile b/graphics/traveler/tools/libwld/Makefile index 3d1dab82c..de639f6b0 100644 --- a/graphics/traveler/tools/libwld/Makefile +++ b/graphics/traveler/tools/libwld/Makefile @@ -35,7 +35,6 @@ WD = ${shell pwd} -APPDIR = $(WD)/../../../.. TRAVELER = $(WD)/../.. NUTTXDIR = $(WD)/../include @@ -52,8 +51,8 @@ PLNSRCS += wld_addplane.c wld_mergeplanelists.c wld_removeplane.c wld_moveplane. PLNSRCS += wld_findplane.c PALSRCS = wld_loadpaltable.c wld_discardpaltable.c CLRSRCS = wld_rgblookup.c wld_rgb2pixel.c wld_pixel2lum.c wld_lum2pixel.c -UTSRCS = wld_readdecimal.c wld_fatalerror.c wld_malloc.c wld_realloc.c -UTSRCS += wld_free.c +UTSRCS = wld_inifile.c wld_readdecimal.c wld_fatalerror.c +UTSRCS += wld_malloc.c wld_realloc.c wld_free.c SRCS = $(WLDSRCS) $(TXTSRCS) $(BMSRCS) $(PLNSRCS) $(PALSRCS) $(CLRSRCS) $(UTSRCS) OBJS = $(SRCS:.c=.o) @@ -62,7 +61,7 @@ AR = ar -rcv DEBUG_LEVEL ?= 0 DEFINES = -DDEBUG_LEVEL=$(DEBUG_LEVEL) -INCLUDES = -I. -I$(APPDIR)/include -I$(TRAVELER)/include -isystem $(NUTTXDIR) +INCLUDES = -I. -I$(TRAVELER)/include -isystem $(NUTTXDIR) WARNINGS = -Wall -Wstrict-prototypes -Wshadow -Wno-trigraphs ifneq ($(DEBUG_LEVEL),0) diff --git a/graphics/traveler/tools/libwld/wld_createworld.c b/graphics/traveler/tools/libwld/wld_createworld.c index a075c7754..1f7ed827c 100644 --- a/graphics/traveler/tools/libwld/wld_createworld.c +++ b/graphics/traveler/tools/libwld/wld_createworld.c @@ -39,7 +39,7 @@ *************************************************************************/ #include "trv_types.h" -#include "fsutils/inifile.h" + #include "wld_paltable.h" #include "wld_color.h" #include "wld_inifile.h" diff --git a/graphics/traveler/tools/libwld/wld_inifile.c b/graphics/traveler/tools/libwld/wld_inifile.c new file mode 100644 index 000000000..8aa2ee01b --- /dev/null +++ b/graphics/traveler/tools/libwld/wld_inifile.c @@ -0,0 +1,607 @@ +/**************************************************************************** + * apps/graphics/traveler/tools/libwld/wld_inifile.c + * + * Copyright (C) 2016 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include "wld_inifile.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* The maximum size of a line in the INI file */ + +#define INFILE_MAXLINE 256 + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/* A structure that describes one entry from the INI file */ + +struct inifile_var_s +{ + char *variable; + char *value; +}; + +/* This structure describes the state of one instance of the INI file parser */ + +struct inifile_state_s +{ + FILE *instream; + int nextch; + char line[INFILE_MAXLINE+1]; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static bool inifile_next_line(struct inifile_state_s *priv); +static int inifile_read_line(struct inifile_state_s *priv); +static int inifile_read_noncomment_line(struct inifile_state_s *priv); +static bool inifile_seek_to_section(struct inifile_state_s *priv, + const char *section); +static bool inifile_read_variable(struct inifile_state_s *priv, + struct inifile_var_s *varinfo); +static char *inifile_find_section_variable(struct inifile_state_s *priv, + const char *variable); +static char *inifile_find_variable(struct inifile_state_s *priv, + const char *section, const char *variable); + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: inifile_next_line + * + * Description: + * Skip to the first character of the next line. Returns true if the end + * of file was not encountered. + * + ****************************************************************************/ + +static bool inifile_next_line(struct inifile_state_s *priv) +{ + /* Search ahead for the end of line mark (or possibly the end of file mark) */ + + while ((priv->nextch != '\n') && (priv->nextch != EOF)) + { + priv->nextch = getc(priv->instream); + } + + /* Re-prime the pump with the first character from the next line. NOTE: + * this logic depends on the fact that getc() will return EOF repeatedly. + */ + + priv->nextch = getc(priv->instream); + return (priv->nextch != EOF); +} + +/**************************************************************************** + * Name: inifile_read_line + * + * Description: + * Read the next line from the INI file into the line buffer and return + * the number of characters read into the buffer. If we hit the end of a + * section (or the end of a file), this function will return a count of + * zero. + * + ****************************************************************************/ + +static int inifile_read_line(struct inifile_state_s *priv) +{ + int nbytes; + + /* Assuming that the file pointer is correctly positioned at the beginning + * of the next line, read until the end of line indication is found (or + * until the line buffer is full). This is basically fgets(). + */ + + nbytes = 0; + while ((nbytes < INFILE_MAXLINE) && + (priv->nextch != EOF) && + (priv->nextch != '\n')) + { + /* Always ignore carriage returns */ + + if (priv->nextch != '\r') + { + /* Ignore any leading whitespace on the line */ + + if (nbytes || (priv->nextch != ' ' && priv->nextch != '\t')) + { + /* Add the new character to the line buffer */ + + priv->line[nbytes] = priv->nextch; + nbytes++; + } + } + + /* Get the next character from the INI file */ + + priv->nextch = getc(priv->instream); + } + + /* NUL terminate the string */ + + priv->line[nbytes] = '\0'; + + /* Skip to the first character of the next line. This should normally + * just amount to skipping over the newline, but could be more involved + * if we had to truncate the line to fit into the line buffer. + */ + + if (priv->nextch != EOF) + { + (void)inifile_next_line(priv); + } + + /* And return the number of bytes read (excluding the NUL terminator and + * leading whitespace). + */ + + return nbytes; +} + +/**************************************************************************** + * Name: inifile_read_noncomment_line + * + * Description: + * Read until either a (1) no further lines are found in the file, or (2) + * a line that does not begin with a semi-colon is found + * + ****************************************************************************/ + +static int inifile_read_noncomment_line(struct inifile_state_s *priv) +{ + int nbytes; + + /* Read until either a (1) no further lines are found in + * the file, or (2) a line that does not begin with a semi-colon + * is found. + */ + + do nbytes = inifile_read_line(priv); + while (nbytes > 0 && priv->line[0] == ';'); + + return nbytes; +} + +/**************************************************************************** + * Name: inifile_seek_to_section + * + * Description: + * Positions the file pointer to the line containing the first variable + * description within the INI file. Returns 1 if the section was found. + * In this case, the file pointer will be positioned at the beginning of + * the first variable line. + * + ****************************************************************************/ + +static bool inifile_seek_to_section(struct inifile_state_s *priv, + const char *section) +{ + int nbytes; + + /* Rewind to the beginning of the INI file and re-prime the pump with the + * first character from the INI file. + */ + + rewind(priv->instream); + priv->nextch = getc(priv->instream); + + /* Loop until either the section is found, or until we hit the end of the + * INI file. + */ + + do + { + /* Read the next line into the input buffer. A returned value of zero + * bytes means nothing special here -- could be EOF or a blank line. + */ + + nbytes = inifile_read_noncomment_line(priv); + + /* It takes at least three bytes of data to be a candidate for a + * section header. + */ + + if (nbytes >= 3) + { + /* A section header must begin with a left bracket */ + + if (priv->line[0] == '[') + { + /* The section name should start with the first character + * after the left bracket. + */ + + char *sectend; + + /* The section name should extend to the right bracket. */ + + sectend = strchr(&priv->line[1], ']'); + + /* Replace the right bracket (if found) with a NULL + * terminator. + */ + + if (sectend) + { + *sectend = '\0'; + } + + /* Then compare the section name to the one we are looking for */ + + if (strcasecmp(&priv->line[1], section) == 0) + { + /* The section names match! Return success */ + + return true; + } + } + } + } + while (priv->nextch != EOF); + + /* If we got here, we search the whole INI file without finding + * the requested section + */ + + return false; +} + +/**************************************************************************** + * Name: inifile_read_variable + * + * Description: + * Obtain variable info from the next line in the section. This assumes + * that the file pointer is pointing to the beginning of the next line. + * If there is no further data in the section, false is returned. + * + ****************************************************************************/ + +static bool inifile_read_variable(struct inifile_state_s *priv, + struct inifile_var_s *varinfo) +{ + char *ptr; + + /* Read until either (1) the end of file is found, (2) the end of + * the section is found, or (3) a valid variable assignment is found. + */ + + for (;;) + { + /* Read the next line in the buffer */ + + int nbytes = inifile_read_noncomment_line(priv); + + /* Make sure that the line is non-NULL and that this is not the + * beginning of a new section + */ + + if (!nbytes || priv->line[0] == '[') + { + return false; + } + + /* Search for the '=' delimiter. NOTE the line is guaranteed to + * be NULL terminated by inifile_read_noncomment_line(). + */ + + ptr = strchr(&priv->line[1], '='); + + /* If the delimiter was found, return success */ + + if (ptr) + { + /* Put NUL termination between the variable name and the + * variable value (replacing the equal sign). + */ + + *ptr = '\0'; + + /* Set up the return structure. NOTE: value may point at + * a NULL string + */ + + varinfo->variable = (char*)priv->line; + varinfo->value = (ptr + 1); + return true; + } + } +} + +/**************************************************************************** + * Name: inifile_find_section_variable + * + * Description: + * Find the value string associated with the variable name. This function + * will return NULL on failure to find the variable. It will return a + * pointer to an empty string is the variable is found, but not assigned a + * value. + * + ****************************************************************************/ + +static char *inifile_find_section_variable(struct inifile_state_s *priv, + const char *variable) +{ + /* Loop until either (1) we hit the end of file, (2) we hit the end + * of the section, or (3) we find the variable that we are looking + * for/ + */ + + for (;;) + { + /* Get the next variable from this section. */ + + struct inifile_var_s varinfo; + bool found = inifile_read_variable(priv, &varinfo); + + /* Is there anything left in the section? */ + + if (!found) + { + return NULL; + } + + /* Does the the variable name match the one we are looking for? */ + + if (strcasecmp(varinfo.variable, variable) == 0) + { + /* Yes... then we have it! */ + + return varinfo.value; + } + } +} + +/**************************************************************************** + * Name: inifile_find_variable + * + * Description: + * Obtains the specified string value for the specified variable name + * within the specified section of the INI file. + * + ****************************************************************************/ + +static char *inifile_find_variable(struct inifile_state_s *priv, + const char *section, + const char *variable) +{ + char *ret = NULL; + + /* Seek to the first variable in the specified section of the INI file */ + + if (priv->instream && inifile_seek_to_section(priv, section)) + { + /* If the seek was successful, then find the value string within + * the section + */ + + char *value = inifile_find_section_variable(priv, variable); + + if (value && *value) + { + ret = value; + } + } + + /* Return the string that we found. */ + + return ret; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: inifile_initialize + * + * Description: + * Initialize for access to the INI file 'inifile_name' + * + ****************************************************************************/ + +INIHANDLE inifile_initialize(const char *inifile_name) +{ + /* Allocate an INI file parser state structure */ + + struct inifile_state_s *priv = + (struct inifile_state_s *)malloc(sizeof(struct inifile_state_s)); + + if (!priv) + { + return (INIHANDLE)NULL; + } + + /* Open the specified INI file for reading */ + + priv->instream = fopen(inifile_name, "r"); + + /* Prime the pump */ + + if (priv->instream) + { + priv->nextch = getc(priv->instream); + return (INIHANDLE)priv; + } + else + { + return (INIHANDLE)NULL; + } +} + +/**************************************************************************** + * Name: inifile_uninitialize + * + * Description: + * Free resources commit to INI file parsing + * + ****************************************************************************/ + +void inifile_uninitialize(INIHANDLE handle) +{ + struct inifile_state_s *priv = (struct inifile_state_s *)handle; + + if (priv) + { + /* Close the INI file stream */ + + if (priv->instream) + { + fclose(priv->instream); + } + + /* Release the state structure */ + + free(priv); + } +} + +/**************************************************************************** + * Name: inifile_read_string + * + * Description: + * Obtains the specified string value for the specified variable name + * within the specified section of the INI file. The receiver of the + * value string should call inifile_free_string when it no longer needs + * the memory held by the value string. + * + ****************************************************************************/ + +char *inifile_read_string(INIHANDLE handle, + const char *section, + const char *variable, + const char *defvalue) +{ + struct inifile_state_s *priv = (struct inifile_state_s *)handle; + char *ret = NULL; + const char *value; + + /* Get a reference to the volatile version of the string */ + + value = inifile_find_variable(priv, section, variable); + + /* If the variable was not found, then use the default value */ + + if (!value) + { + /* Selecting the default string */ + + value = defvalue; + } + + /* If this was successful, create a non-volatile copy of the string + * We do this even if the default value is used because the caller + * will (eventually) deallocate it. + */ + + if (value) + { + ret = strdup(value); + } + + /* Return the string that we found. */ + + return ret; +} + +/**************************************************************************** + * Name: inifile_read_integer + * + * Description: + * Obtains the specified integer value for the specified variable name + * within the specified section of the INI file + * + ****************************************************************************/ + +long inifile_read_integer(INIHANDLE handle, + const char *section, + const char *variable, + long defvalue) +{ + struct inifile_state_s *priv = (struct inifile_state_s *)handle; + char *value; + long ret = defvalue; + + /* Get the value as a string first */ + + value = inifile_find_variable(priv, section, variable); + + /* If this was successful, then convert the string to an integer value. */ + + if (value) + { + /* Then convert the string to an integer value (accept any base, and + * ignore all conversion errors. + */ + + ret = strtol(value, NULL, 0); + } + + /* Return the value that we found. */ + + return ret; +} + +/**************************************************************************** + * Name: inifile_free_string + * + * Description: + * Release resources allocated for the value string previously obtained + * from inifile_read_string. The purpose of this inline function is to + * hide the memory allocator used by this implementation. + * + ****************************************************************************/ + +void inifile_free_string(char *value) +{ + if (value) + { + free(value); + } +} diff --git a/graphics/traveler/tools/libwld/wld_inifile.h b/graphics/traveler/tools/libwld/wld_inifile.h index d1bc589a3..c60b78034 100644 --- a/graphics/traveler/tools/libwld/wld_inifile.h +++ b/graphics/traveler/tools/libwld/wld_inifile.h @@ -37,43 +37,92 @@ #define __APPS_GRAPHICS_TRAVELER_TOOSL_LIBWLD_WLD_INIFILE_H /**************************************************************************** - * Pre-processor Definitions + * Public Types ****************************************************************************/ -/* Everything related to the camera POV is defined in the - * camera section. */ +typedef void *INIHANDLE; -#define CAMERA_SECTION_NAME "camera" +/**************************************************************************** + * Public Data + ****************************************************************************/ -/* These values define the initial camera postion. */ +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif -#define CAMERA_INITIAL_X "initialcamerax" -#define CAMERA_INITIAL_Y "initialcameray" -#define CAMERA_INITIAL_Z "initialcameraz" +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ -/* These values define the orientation of the camera. */ +/**************************************************************************** + * Name: inifile_initialize + * + * Description: + * Initialize for access to the INI file 'inifile_name' + * + ****************************************************************************/ -#define CAMERA_INITIAL_YAW "initialcamerayaw" -#define CAMERA_INITIAL_PITCH "initialcamerayaw" +INIHANDLE inifile_initialize(const char *inifile_name); -/* Everything related to the player is defined in the player section. */ +/**************************************************************************** + * Name: inifile_uninitialize + * + * Description: + * Free resources commit to INI file parsing + * + ****************************************************************************/ -#define PLAYER_SECTION_NAME "player" +void inifile_uninitialize(INIHANDLE handle); -/* These are charwld_erictics of the player. */ +/**************************************************************************** + * Name: inifile_read_string + * + * Description: + * Obtains the specified string value for the specified variable name + * within the specified section of the INI file. The receiver of the + * value string should call inifile_free_string when it no longer needs + * the memory held by the value string. + * + ****************************************************************************/ -#define PLAYER_HEIGHT "playerheight" -#define PLAYER_WALK_STEPHEIGHT "playerwalkstepheight" -#define PLAYER_RUN_STEPHEIGHT "playerrunstepheight" +char *inifile_read_string(INIHANDLE handle, + const char *section, + const char *variable, + const char *defvalue); -/* Everything related to the world is defined in the world section. */ +/**************************************************************************** + * Name: inifile_read_integer + * + * Description: + * Obtains the specified integer value for the specified variable name + * within the specified section of the INI file + * + ****************************************************************************/ -#define WORLD_SECTION_NAME "world" +long inifile_read_integer(INIHANDLE handle, + const char *section, + const char *variable, + long defvalue); -/* Other files: */ +/**************************************************************************** + * Name: inifile_free_string + * + * Description: + * Release resources allocated for the value string previously obtained + * from inifile_read_string. The purpose of this inline function is to + * hide the memory allocator used by this implementation. + * + ****************************************************************************/ -#define WORLD_MAP "worldmap" -#define WORLD_PALETTE "worldpalette" -#define WORLD_IMAGES "worldimages" +void inifile_free_string(char *value); + +#undef EXTERN +#ifdef __cplusplus +} +#endif #endif /* __APPS_GRAPHICS_TRAVELER_TOOSL_LIBWLD_WLD_INIFILE_H */ diff --git a/graphics/traveler/tools/libwld/wld_world.h b/graphics/traveler/tools/libwld/wld_world.h index c05ac228c..f619acd1d 100644 --- a/graphics/traveler/tools/libwld/wld_world.h +++ b/graphics/traveler/tools/libwld/wld_world.h @@ -57,6 +57,44 @@ extern "C" #define FILE_NAME_SIZE 16 +/* World file section/variable names */ + +/* Everything related to the camera POV is defined in the + * camera section. */ + +#define CAMERA_SECTION_NAME "camera" + +/* These values define the initial camera postion. */ + +#define CAMERA_INITIAL_X "initialcamerax" +#define CAMERA_INITIAL_Y "initialcameray" +#define CAMERA_INITIAL_Z "initialcameraz" + +/* These values define the orientation of the camera. */ + +#define CAMERA_INITIAL_YAW "initialcamerayaw" +#define CAMERA_INITIAL_PITCH "initialcamerayaw" + +/* Everything related to the player is defined in the player section. */ + +#define PLAYER_SECTION_NAME "player" + +/* These are charwld_erictics of the player. */ + +#define PLAYER_HEIGHT "playerheight" +#define PLAYER_WALK_STEPHEIGHT "playerwalkstepheight" +#define PLAYER_RUN_STEPHEIGHT "playerrunstepheight" + +/* Everything related to the world is defined in the world section. */ + +#define WORLD_SECTION_NAME "world" + +/* Other files: */ + +#define WORLD_MAP "worldmap" +#define WORLD_PALETTE "worldpalette" +#define WORLD_IMAGES "worldimages" + /************************************************************************* * Public Type Definitions *************************************************************************/