Mon, 16 Jul 2012 16:15:16 +0300
- The output cmd-line argument is now optional - one is generated from the input file if not given.
- All data is now buffered before being written into the file. This way, no incomplete data is written in case an error occurrs.
common.h | file | annotate | diff | comparison | revisions | |
databuffer.h | file | annotate | diff | comparison | revisions | |
main.cxx | file | annotate | diff | comparison | revisions | |
objwriter.cxx | file | annotate | diff | comparison | revisions | |
objwriter.h | file | annotate | diff | comparison | revisions | |
str.cxx | file | annotate | diff | comparison | revisions | |
variables.cxx | file | annotate | diff | comparison | revisions |
--- a/common.h Mon Jul 16 04:33:09 2012 +0300 +++ b/common.h Mon Jul 16 16:15:16 2012 +0300 @@ -52,6 +52,11 @@ #define VERSION_MINOR 0 #define VERSION_REVISION 999 +// On Windows, files are case-insensitive +#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__) + #define FILE_CASEINSENSITIVE 0 +#endif + // Where is the parser at? enum parsermode { MODE_TOPLEVEL, // at top level @@ -76,6 +81,8 @@ #define PLURAL(n) (n != 1) ? "s" : "" void error (const char* text, ...); +char* ObjectFileName (str s); +bool fexists (char* path); #ifndef __PARSER_CXX__ extern int g_NumStates;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/databuffer.h Mon Jul 16 16:15:16 2012 +0300 @@ -0,0 +1,125 @@ +/* + * botc source code + * Copyright (C) 2012 Santeri `Dusk` Piippo + * All rights reserved. + * + * 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 of the developer nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * 4. Redistributions in any form must be accompanied by information on how to + * obtain complete source code for the software and any accompanying + * software that uses the software. The source code must either be included + * in the distribution or be available for no more than the cost of + * distribution plus a nominal fee, and must be freely redistributable + * under reasonable conditions. For an executable file, complete source + * code means the source code for all modules it contains. It does not + * include source code for modules or files that typically accompany the + * major components of the operating system on which the executable file + * runs. + * + * 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 HOLDER 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. + */ + +#ifndef __DATABUFFER_H__ +#define __DATABUFFER_H__ +#include <stdio.h> +#include <string.h> +#include "common.h" + +// ============================================================================ +// DataBuffer: A dynamic data buffer. +class DataBuffer { +public: + // The actual buffer + unsigned char* buffer; + + // Allocated size of the buffer + unsigned int allocsize; + + // Written size of the buffer + unsigned int writesize; + + // METHODS + DataBuffer (unsigned int size=128) { + writesize = 0; + + buffer = new unsigned char[size]; + allocsize = size; + } + + ~DataBuffer () { + delete buffer; + } + + template<class T> void Write(T stuff) { + if (sizeof (char) != 1) { + error ("DataBuffer: sizeof(char) must be 1!\n"); + } + + // Out of space, must resize + if (writesize + sizeof(T) >= allocsize) { + // First, store the old buffer temporarily + char* copy = new char[allocsize]; + memcpy (copy, buffer, allocsize); + + // Remake the buffer with the new size. + // Have a bit of leeway so we don't have to + // resize immediately again. + size_t newsize = allocsize + sizeof (T) + 128; + delete buffer; + buffer = new unsigned char[newsize]; + allocsize = newsize; + + // Now, copy the new stuff over. + memcpy (buffer, copy, allocsize); + + // Nuke the copy now as it's no longer needed + delete copy; + } + + // Write the new stuff one byte at a time + for (unsigned int x = 0; x < sizeof (T); x++) { + if (writesize >= allocsize) + error ("DataBuffer: written size exceeds allocated size!\n"); + buffer[writesize] = CharByte<T> (stuff, x); + writesize++; + } + } + +private: + template <class T> unsigned char CharByte (T a, unsigned int b) { + if (b >= sizeof (T)) + error ("CharByte: tried to get byte %u out of a %u-byte %s\n", + b, sizeof (T), typeid(T).name()); + + unsigned long p1 = pow<unsigned long> (256, b); + unsigned long p2 = pow<unsigned long> (256, b+1); + unsigned long r = (a % p2) / p1; + + if (r > 256) + error ("result %lu too big!", r); + + unsigned char ur = static_cast<unsigned char> (r); + return ur; + } +}; + +#endif // __DATABUFFER_H__ \ No newline at end of file
--- a/main.cxx Mon Jul 16 04:33:09 2012 +0300 +++ b/main.cxx Mon Jul 16 16:15:16 2012 +0300 @@ -54,6 +54,14 @@ #include "bots.h" #include "botcommands.h" +bool fexists (char* path) { + if (FILE* test = fopen (path, "r")) { + fclose (test); + return true; + } + return false; +} + int main (int argc, char** argv) { // Intepret command-line parameters: // -l: list commands @@ -79,11 +87,42 @@ headerline += '-'; printf ("%s\n%s\n", header.chars(), headerline.chars()); - if (argc != 3) { - fprintf (stderr, "usage: %s: <infile> <outFile>\n", argv[0]); + if (argc < 2) { + fprintf (stderr, "usage: %s: <infile> [outfile]\n", argv[0]); exit (1); } + str outfile; + if (argc < 3) + outfile = ObjectFileName (argv[1]); + else + outfile = argv[2]; + + // If we'd end up writing into an existing file, + // ask the user if we want to overwrite it + if (fexists (outfile)) { + // Additional warning if the paths are the same + str warning; +#ifdef FILE_CASEINSENSITIVE + if (!outfile.icompare (argv[1])) +#else + if (!outfile.compare (argv[1])) +#endif + { + warning = "\nWARNING: Output file is the same as the input file. "; + warning += "Answering yes here will destroy the source!\n"; + warning += "Continue nevertheless?"; + } + printf ("output file `%s` already exists! overwrite?%s (y/n) ", outfile.chars(), warning.chars()); + + char ans; + fgets (&ans, 2, stdin); + if (ans != 'y') { + printf ("abort\n"); + exit (1); + } + } + // Read definitions printf ("Reading definitions...\n"); ReadEvents (); @@ -95,18 +134,18 @@ // Prepare reader and writer ScriptReader *r = new ScriptReader (argv[1]); - ObjWriter *w = new ObjWriter (argv[2]); + ObjWriter *w = new ObjWriter (outfile); // We're set, begin parsing :) printf ("Parsing script..\n"); r->BeginParse (w); - // Parse done, print statistics + // Parse done, print statistics and write to file unsigned int globalcount = CountGlobalVars (); printf ("%u global variable%s\n", globalcount, PLURAL (globalcount)); printf ("%d state%s written\n", g_NumStates, PLURAL (g_NumStates)); printf ("%d event%s written\n", g_NumEvents, PLURAL (g_NumEvents)); - printf ("-- %u byte%s written to %s\n", w->numWrittenBytes, PLURAL (w->numWrittenBytes), argv[2]); + w->WriteToFile (); // Clear out the junk delete r; @@ -117,4 +156,16 @@ PERFORM_FORMAT (text, c); fprintf (stderr, "error: %s", c); exit (1); +} + +char* ObjectFileName (str s) { + // Locate the extension and chop it out + unsigned int extdot = s.last ("."); + if (extdot != s.len() && extdot >= s.len()-4) + s.trim (s.len() - extdot); + + // Add new ".o" extension + s += ".o"; + + return s.chars(); } \ No newline at end of file
--- a/objwriter.cxx Mon Jul 16 04:33:09 2012 +0300 +++ b/objwriter.cxx Mon Jul 16 16:15:16 2012 +0300 @@ -51,16 +51,15 @@ extern bool g_GotMainLoop; ObjWriter::ObjWriter (str path) { + MainBuffer = new DataBuffer; MainLoopBuffer = new DataBuffer; OnEnterBuffer = new DataBuffer; - numWrittenBytes = 0; - fp = fopen (path, "w"); - CHECK_FILE (fp, path, "writing"); + filepath = path; } ObjWriter::~ObjWriter () { - fclose (fp); + delete MainBuffer; delete MainLoopBuffer; delete OnEnterBuffer; } @@ -89,7 +88,7 @@ // Write the onenter and mainloop buffers, IN THAT ORDER for (int i = 0; i < 2; i++) { DataBuffer* buf = (!i) ? OnEnterBuffer : MainLoopBuffer; - for (unsigned int x = 0; x < buf->writepos; x++) { + for (unsigned int x = 0; x < buf->writesize; x++) { unsigned char c = *(buf->buffer+x); Write<unsigned char> (c); } @@ -101,4 +100,22 @@ // Next state definitely has no mainloop yet g_GotMainLoop = false; +} + +// Write main buffer to file +void ObjWriter::WriteToFile () { + fp = fopen (filepath, "w"); + CHECK_FILE (fp, filepath, "writing"); + + if (sizeof (unsigned char) != 1) + error ("size of unsigned char isn't 1, but %d!\n", sizeof (unsigned char)); + + for (unsigned int x = 0; x < MainBuffer->writesize; x++) { + unsigned char c = *(MainBuffer->buffer+x); + fwrite (&c, 1, 1, fp); + numWrittenBytes ++; + } + + printf ("-- %u byte%s written to %s\n", numWrittenBytes, PLURAL (numWrittenBytes), filepath.chars()); + fclose (fp); } \ No newline at end of file
--- a/objwriter.h Mon Jul 16 04:33:09 2012 +0300 +++ b/objwriter.h Mon Jul 16 16:15:16 2012 +0300 @@ -45,100 +45,18 @@ #include <typeinfo> #include <string.h> #include "common.h" +#include "databuffer.h" #include "str.h" extern int g_CurMode; -// ============================================================================ -// DataBuffer: A dynamic data buffer. -class DataBuffer { -public: - // The actual buffer - unsigned char* buffer; - - // How big is the buffer? - unsigned int bufsize; - - // Position in the buffer - unsigned int writepos; - unsigned int readpos; - - // METHODS - DataBuffer (unsigned int size=128) { - writepos = 0; - readpos = 0; - - buffer = new unsigned char[size]; - bufsize = size; - } - - ~DataBuffer () { - delete buffer; - } - - template<class T> void Write(T stuff) { - if (sizeof (char) != 1) { - error ("DataBuffer: sizeof(char) must be 1!\n"); - } - - // Out of space, must resize - if (writepos + sizeof(T) >= bufsize) { - // First, store the old buffer temporarily - char* copy = new char[bufsize]; - printf ("Resizing buffer: copy buffer to safety. %u bytes to copy\n", bufsize); - memcpy (copy, buffer, bufsize); - - // Remake the buffer with the new size. - // Have a bit of leeway so we don't have to - // resize immediately again. - size_t newsize = bufsize + sizeof (T) + 128; - delete buffer; - buffer = new unsigned char[newsize]; - bufsize = newsize; - - // Now, copy the new stuff over. - memcpy (buffer, copy, bufsize); - - // Nuke the copy now as it's no longer needed - delete copy; - } - - // Write the new stuff one byte at a time - for (unsigned int x = 0; x < sizeof (T); x++) { - buffer[writepos] = CharByte<T> (stuff, x); - writepos++; - } - } - - template<class T> T Read() { - T result = buffer[readpos]; - readpos += sizeof (T); - return result; - } - -private: - template <class T> unsigned char CharByte (T a, unsigned int b) { - if (b >= sizeof (T)) - error ("CharByte: tried to get byte %u out of a %u-byte %s\n", - b, sizeof (T), typeid(T).name()); - - unsigned long p1 = pow<unsigned long> (256, b); - unsigned long p2 = pow<unsigned long> (256, b+1); - unsigned long r = (a % p2) / p1; - - if (r > 256) - error ("result %lu too big!", r); - - unsigned char ur = static_cast<unsigned char> (r); - return ur; - } -}; - class ObjWriter { public: // ==================================================================== // MEMBERS FILE* fp; + str filepath; + DataBuffer* MainBuffer; DataBuffer* OnEnterBuffer; DataBuffer* MainLoopBuffer; unsigned int numWrittenBytes; @@ -151,18 +69,16 @@ void WriteString (const char* s); void WriteString (str s); void WriteBuffers (); + void WriteToFile (); template <class T> void Write (T stuff) { - // Mainloop and onenter are written into a separate buffer. - if (g_CurMode == MODE_MAINLOOP || g_CurMode == MODE_ONENTER) { - DataBuffer* buffer = (g_CurMode == MODE_MAINLOOP) ? MainLoopBuffer : OnEnterBuffer; - buffer->Write<T> (stuff); - return; - } - - fwrite (&stuff, sizeof (T), 1, fp); - numWrittenBytes += sizeof (T); + DataBuffer* buffer = (g_CurMode == MODE_MAINLOOP) ? MainLoopBuffer : + (g_CurMode == MODE_ONENTER) ? OnEnterBuffer : + MainBuffer; + buffer->Write<T> (stuff); + return; } + // Cannot use default arguments in function templates.. void Write (long stuff) {Write<long> (stuff);} };
--- a/str.cxx Mon Jul 16 04:33:09 2012 +0300 +++ b/str.cxx Mon Jul 16 16:15:16 2012 +0300 @@ -250,16 +250,16 @@ if (!dellen) return; - str s; - // If dellen is positive, trim from the end, - // if negative, trim from beginning. - if (dellen > 0) - s = substr (0, len()-dellen); - else - s = substr (-dellen, len()); - - clear(); - append (s); + unsigned int delpos; + if (dellen > 0) { + delpos = len()-dellen; + text[delpos] = 0; + curs -= dellen; + } else { + str s = substr (-dellen, len()); + clear(); + append (s); + } } // ============================================================================ @@ -311,10 +311,8 @@ bool str::isnumber () { ITERATE_STRING (u) { // Minus sign as the first character is allowed for negatives - if (!u && text[u] == '-') { - printf ("%u was minus sign\n", u); + if (!u && text[u] == '-') continue; - } if (text[u] < '0' || text[u] > '9') return false;
--- a/variables.cxx Mon Jul 16 04:33:09 2012 +0300 +++ b/variables.cxx Mon Jul 16 16:15:16 2012 +0300 @@ -88,11 +88,13 @@ return g; } -/*void AssignScriptVariable (ScriptReader* r, str name, str value) { +/* +void AssignScriptVariable (ScriptReader* r, str name, str value) { ScriptVar* g = FindScriptVariable (name); if (!g) r->ParserError ("global variable %s not declared", name.chars()); -}*/ +} +*/ // Find a global variable by name ScriptVar* FindGlobalVariable (str name) {