From: Fletcher T. Penney Date: Sat, 13 Jun 2015 18:59:00 +0000 (-0400) Subject: Initialize project X-Git-Tag: 0.1.0a~56 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4ae562d17bbd7df03fc5f6210d3e21a7f5b00a8e;p=multimarkdown Initialize project --- 4ae562d17bbd7df03fc5f6210d3e21a7f5b00a8e diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..0129aa2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,125 @@ +cmake_minimum_required (VERSION 2.6) + + +# ================== +# Define Our Project +# ================== + +set (My_Project_Title "Some Project") +set (My_Project_Author "Somebody") +set (My_Project_Revised_Date "2015-06-05") +set (My_Project_Version_Major 1) +set (My_Project_Version_Minor 0) +set (My_Project_Version_Patch 0) + +set (My_Project_Copyright_Date "2015") +set (My_Project_Copyright "Copyright © ${My_Project_Copyright_Date} ${My_Project_Author}.") + +project (${My_Project_Title}) + + +# Search for included files here +include_directories( ${PROJECT_SOURCE_DIR}/src ) +include_directories( ${PROJECT_SOURCE_DIR}/test ) + + +string(TOUPPER ${My_Project_Title} My_Project_Title_Caps ) +string(REGEX REPLACE " " "_" My_Project_Title_Caps ${My_Project_Title_Caps} ) + + +# ====================== +# Process Template Files +# ====================== + +file(READ ${PROJECT_SOURCE_DIR}/LICENSE.txt My_Project_License) + +string(REGEX REPLACE "\n" "\n\t" My_Project_License_Indent ${My_Project_License}) + +configure_file ( + "${PROJECT_SOURCE_DIR}/templates/template.c.in" + "${PROJECT_BINARY_DIR}/template.c" +) + +configure_file ( + "${PROJECT_SOURCE_DIR}/templates/template.h.in" + "${PROJECT_BINARY_DIR}/template.h" +) + +configure_file ( + "${PROJECT_SOURCE_DIR}/templates/README.md.in" + "${PROJECT_BINARY_DIR}/README.md" +) + + +# ============= +# Build Targets +# ============= + +set(src_files +# src/file.c +) + +set(header_files +# src/file.h +) + +# Create a library? +# add_library(libFOO STATIC +# ${src_files} +# ${header_files} +# ) + +# remove the extra "lib" from "liblibFOO" +# SET_TARGET_PROPERTIES(libFOO PROPERTIES PREFIX "") + +# Create a command-line app? +# if (NOT DEFINED TEST) +# add_executable(main +# src/main.c +# src/GLibFacade.c +# src/GLibFacade.h +# ${header_files} +# ) +# +# Link the library to the app? +# target_link_libraries(main libFOO) +# endif() + + +# =========================================== +# Build Test Suite with CuTest (unit testing) +# =========================================== + +set(test_files + test/CuTest.c + test/CuTest.h + ${PROJECT_BINARY_DIR}/AllTests.c +) + +if (DEFINED TEST) + add_definitions(-DTEST) + + add_executable(run_tests + ${test_files} + ${src_files} + ${header_files} + ) + + # Process source files to look for tests to run + add_custom_command ( + OUTPUT ${PROJECT_BINARY_DIR}/AllTests.c + COMMAND sh ${PROJECT_SOURCE_DIR}/test/make-tests.sh ${PROJECT_SOURCE_DIR}/src/*.c > ${PROJECT_BINARY_DIR}/AllTests.c + ) + + enable_testing() + + add_test( test ${PROJECT_BINARY_DIR}/run_tests) + +endif() + + +# ========================== +# Build Installer with CPack +# ========================== + +# You're on your own here diff --git a/IMPORTANT b/IMPORTANT new file mode 100644 index 0000000..a332193 --- /dev/null +++ b/IMPORTANT @@ -0,0 +1,46 @@ +This project is designed for use with cmake. + +The Makefile controls the overall build: + + make + make release + +Build a version optimized for performance. + + make debug + +Faster compile, but not as high performance. + + make xcode + +Create an Xcode project for use on OS X. + + make windows + +Used for cross-compiling for Windows using MinGW. + + make clean + +Clean up the `build` directory. + +These commands control the `build` directory. Everything in this directory is +auto-generated. You should not manually change these files or put anything +else in there. + + +The setup is designed to support unit testing with CuTest. Functions along +the lines of `void Test*` will be located automatically and used to create the +test suite, which is run by: + + ./run_tests + +Or + + make test + +(The `run_tests` approach will probably give more useful feedback if a test fails.) + + +Integration testing must be handled separately. + +You can configure the `CMakeLists.txt` to support creating installers. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..a89ea09 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,32 @@ +The `new-project` project is released under the MIT License. + +GLibFacade.c and GLibFacade.h are from the MultiMarkdown v4 project: + + https://github.com/fletcher/MultiMarkdown-4/ + +MMD 4 is released under both the MIT License and GPL. + + +CuTest is released under the zlib/libpng license. See CuTest.c for the text +of the license. + + +## The MIT License ## + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c132a5e --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ +BUILD_DIR = build + +$(BUILD_DIR_): + -mkdir $(BUILD_DIR_) 2>/dev/null + -cd $(BUILD_DIR); rm -rf * + +# The release target will perform additional optimization +release: $(BUILD_DIR) + cd $(BUILD_DIR); \ + cmake -DCMAKE_BUILD_TYPE=Release .. + +# Enables CuTest unit testing +debug: $(BUILD_DIR) + cd $(BUILD_DIR); \ + cmake -DTEST=1 .. + +# For Mac only +xcode: $(BUILD_DIR) + cd $(BUILD_DIR); \ + cmake -G Xcode .. + +# Cross-compile for Windows +windows: $(BUILD_DIR) + cd $(BUILD_DIR); \ + cmake -DCMAKE_TOOLCHAIN_FILE=../tools/Toolchain-mingw32.cmake -DCMAKE_BUILD_TYPE=Release .. + +# Clean out the build directory +clean: + rm -rf $(BUILD_DIR)/* diff --git a/README.md b/README.md new file mode 100644 index 0000000..a003f3b --- /dev/null +++ b/README.md @@ -0,0 +1,104 @@ +Title: Some Project +Author: Fletcher T. Penney +Date: 2015-06-05 +Copyright: Copyright © 2015 Fletcher T. Penney. +Version: 1.0.0 + +# Introduction # + +This template was created out of a desire to simplify some of the setup and +configuration that I was doing over and over each time I started a new project. +Additionally, I wanted to try to start encouraging some "better practices" +(though not necessarily "best practices"): + +1. [Test-driven development][tdd] -- My development of MultiMarkdown + focused on integration testing, but really had no unit testing to + speak of. Some newer projects I began working on were a bit math- + heavy, and ensuring that each piece works properly became even more + important. It was also nice to be able to actually develop code that + could do *something* (via the test suite), even though the project as + a whole was nowhere near complete.) To accomplish this, I include the + [CuTest] project to support writing tests for your code. + +2. Use of the [cmake] build system. `cmake` is not perfect by any + means, but it does offer some very useful features and a means for + better integrating the compilation and packaging/installation aspects + of development. Rather than reinventing the wheel each time, this + setup incorporates basic `cmake` functionality to make it easy to + control how your project is compiled, and includes automated generation + of the test command. + +3. Templates -- `cmake` has a reasonable templating system, so that you + can define basic variables (e.g. author, project name, etc.) and allow + `cmake` to combine those elements to ensure consistency across source + code and README files. + + + +[tdd]: https://en.wikipedia.org/wiki/Test-driven_development +[cmake]: http://www.cmake.org/ +[CuTest]: http://cutest.sourceforge.net + + +# How do I use it? # + +You can download the source from [github] and get to work. The file "IMPORTANT" +contains instructions on the various build commands you can use. + + +I recommend using the following script to automatically create a new git repo, +pull in the default project template, and configure git-flow. You simply have +to rename your project from `new-project` to whatever you desire: + + + #!/bin/sh + + git init new-project + + cd new-project + + git remote add "template" https://github.com/fletcher/c-template.git + + git pull template master + + git flow init -d + + git checkout develop + + +Using this approach, you can define your own "origin" remote if you like, but +the "template" remote can be used to update the core project files should any +improvements come about: + + git checkout develop + git merge template master + +**NOTE**: `cmake` is a complex suite of utilities, and if you have trouble you +will need to get support elsewhere. If you find errors in this template, by +all means I want to hear about them and fix them, but this is just a basic +framework to get you started. In all likelihood, all but the most basic +projects will need some customization. + + +# License # + +## The MIT License ## + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 0000000..5e7d273 --- /dev/null +++ b/build/.gitignore @@ -0,0 +1,4 @@ +# Ignore everything in this directory +* +# Except this file +!.gitignore diff --git a/src/GLibFacade.c b/src/GLibFacade.c new file mode 100644 index 0000000..552d066 --- /dev/null +++ b/src/GLibFacade.c @@ -0,0 +1,210 @@ +/* + * GLibFacade.c + * MultiMarkdown + * + * https://github.com/fletcher/MultiMarkdown-4/ + * + * Created by Daniel Jalkut on 7/26/11. + * Modified by Fletcher T. Penney on 9/15/11. + * Modified by Dan Lowe on 1/3/12. + * Copyright 2011 __MyCompanyName__. All rights reserved. + */ + +#include "GLibFacade.h" + +#include +#include +#include +#include + +/* + * The following section came from: + * + * http://lists-archives.org/mingw-users/12649-asprintf-missing-vsnprintf- + * behaving-differently-and-_vsncprintf-undefined.html + * + * and + * + * http://groups.google.com/group/jansson-users/browse_thread/thread/ + * 76a88d63d9519978/041a7d0570de2d48?lnk=raot + */ + +/* Solaris and Windows do not provide vasprintf() or asprintf(). */ +#if defined(__WIN32) || (defined(__SVR4) && defined(__sun)) +int vasprintf( char **sptr, char *fmt, va_list argv ) +{ + int wanted = vsnprintf( *sptr = NULL, 0, fmt, argv ); + if( (wanted > 0) && ((*sptr = malloc( 1 + wanted )) != NULL) ) + return vsprintf( *sptr, fmt, argv ); + + return wanted; +} + +int asprintf( char **sptr, char *fmt, ... ) +{ + int retval; + va_list argv; + va_start( argv, fmt ); + retval = vasprintf( sptr, fmt, argv ); + va_end( argv ); + return retval; +} +#endif + + +/* GString */ + +#define kStringBufferStartingSize 1024 +#define kStringBufferGrowthMultiplier 2 + +GString* g_string_new(char *startingString) +{ + GString* newString = malloc(sizeof(GString)); + + if (startingString == NULL) startingString = ""; + + size_t startingBufferSize = kStringBufferStartingSize; + size_t startingStringSize = strlen(startingString); + while (startingBufferSize < (startingStringSize + 1)) + { + startingBufferSize *= kStringBufferGrowthMultiplier; + } + + newString->str = malloc(startingBufferSize); + newString->currentStringBufferSize = startingBufferSize; + strncpy(newString->str, startingString, startingStringSize); + newString->str[startingStringSize] = '\0'; + newString->currentStringLength = startingStringSize; + + return newString; +} + +char* g_string_free(GString* ripString, bool freeCharacterData) +{ + char* returnedString = ripString->str; + if (freeCharacterData) + { + if (ripString->str != NULL) + { + free(ripString->str); + } + returnedString = NULL; + } + + free(ripString); + + return returnedString; +} + +static void ensureStringBufferCanHold(GString* baseString, size_t newStringSize) +{ + size_t newBufferSizeNeeded = newStringSize + 1; + if (newBufferSizeNeeded > baseString->currentStringBufferSize) + { + size_t newBufferSize = baseString->currentStringBufferSize; + + while (newBufferSizeNeeded > newBufferSize) + { + newBufferSize *= kStringBufferGrowthMultiplier; + } + + baseString->str = realloc(baseString->str, newBufferSize); + baseString->currentStringBufferSize = newBufferSize; + } +} + +void g_string_append(GString* baseString, char* appendedString) +{ + if ((appendedString != NULL) && (strlen(appendedString) > 0)) + { + size_t appendedStringLength = strlen(appendedString); + size_t newStringLength = baseString->currentStringLength + appendedStringLength; + ensureStringBufferCanHold(baseString, newStringLength); + + /* We already know where the current string ends, so pass that as the starting address for strncat */ + strncat(baseString->str + baseString->currentStringLength, appendedString, appendedStringLength); + baseString->currentStringLength = newStringLength; + } +} + +void g_string_append_c(GString* baseString, char appendedCharacter) +{ + size_t newSizeNeeded = baseString->currentStringLength + 1; + ensureStringBufferCanHold(baseString, newSizeNeeded); + + baseString->str[baseString->currentStringLength] = appendedCharacter; + baseString->currentStringLength++; + baseString->str[baseString->currentStringLength] = '\0'; +} + +void g_string_append_printf(GString* baseString, char* format, ...) +{ + va_list args; + va_start(args, format); + + char* formattedString = NULL; + vasprintf(&formattedString, format, args); + if (formattedString != NULL) + { + g_string_append(baseString, formattedString); + free(formattedString); + } + va_end(args); +} + +void g_string_prepend(GString* baseString, char* prependedString) +{ + if ((prependedString != NULL) && (strlen(prependedString) > 0)) + { + size_t prependedStringLength = strlen(prependedString); + size_t newStringLength = baseString->currentStringLength + prependedStringLength; + ensureStringBufferCanHold(baseString, newStringLength); + + memmove(baseString->str + prependedStringLength, baseString->str, baseString->currentStringLength); + strncpy(baseString->str, prependedString, prependedStringLength); + baseString->currentStringLength = newStringLength; + baseString->str[baseString->currentStringLength] = '\0'; + } +} + +/* GSList */ + +void g_slist_free(GSList* ripList) +{ + GSList* thisListItem = ripList; + while (thisListItem != NULL) + { + GSList* nextItem = thisListItem->next; + + /* I guess we don't release the data? Non-retained memory management is hard... let's figure it out later. */ + free(thisListItem); + + thisListItem = nextItem; + } +} + +/* Currently only used for markdown_output.c endnotes printing */ +GSList* g_slist_reverse(GSList* theList) +{ + GSList* lastNodeSeen = NULL; + + /* Iterate the list items, tacking them on to our new reversed List as we find them */ + GSList* listWalker = theList; + while (listWalker != NULL) + { + GSList* nextNode = listWalker->next; + listWalker->next = lastNodeSeen; + lastNodeSeen = listWalker; + listWalker = nextNode; + } + + return lastNodeSeen; +} + +GSList* g_slist_prepend(GSList* targetElement, void* newElementData) +{ + GSList* newElement = malloc(sizeof(GSList)); + newElement->data = newElementData; + newElement->next = targetElement; + return newElement; +} diff --git a/src/GLibFacade.h b/src/GLibFacade.h new file mode 100644 index 0000000..035d97b --- /dev/null +++ b/src/GLibFacade.h @@ -0,0 +1,69 @@ +/* + * GLibFacade.h + * MultiMarkdown + * + * https://github.com/fletcher/MultiMarkdown-4/ + * + * Created by Daniel Jalkut on 7/26/11. + * Copyright 2011 __MyCompanyName__. All rights reserved. + */ + +#ifndef __MARKDOWN_GLIB_FACADE__ +#define __MARKDOWN_GLIB_FACADE__ + +/* peg_markdown uses the link symbol for its own purposes */ +#define link MARKDOWN_LINK_IGNORED +#include +#undef link + +#include +#include + +typedef int gboolean; +typedef char gchar; + +/* This style of bool is used in shared source code */ +#define FALSE false +#define TRUE true + +/* WE implement minimal mirror implementations of GLib's GString and GSList + * sufficient to cover the functionality required by MultiMarkdown. + * + * NOTE: THese are 100% clean, from-scratch implementations using only the + * GLib function prototype as guide for behavior. + */ + +typedef struct +{ + /* Current UTF8 byte stream this string represents */ + char* str; + + /* Where in the str buffer will we add new characters */ + /* or append new strings? */ + int currentStringBufferSize; + int currentStringLength; +} GString; + +GString* g_string_new(char *startingString); +char* g_string_free(GString* ripString, bool freeCharacterData); + +void g_string_append_c(GString* baseString, char appendedCharacter); +void g_string_append(GString* baseString, char *appendedString); + +void g_string_prepend(GString* baseString, char* prependedString); + +void g_string_append_printf(GString* baseString, char* format, ...); + +/* Just implement a very simple singly linked list. */ + +typedef struct _GSList +{ + void* data; + struct _GSList* next; +} GSList; + +void g_slist_free(GSList* ripList); +GSList* g_slist_prepend(GSList* targetElement, void* newElementData); +GSList* g_slist_reverse(GSList* theList); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..22d0ff2 --- /dev/null +++ b/src/main.c @@ -0,0 +1,51 @@ +/* + + main.c -- Template main() + + Copyright © 2015 Fletcher T. Penney. + + + This program is free software you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include +#include + +#include "GLibFacade.h" + +char * stdin_buffer() { + /* Read from stdin and return a char * + `result` will need to be freed elsewhere */ + + GString * buffer = g_string_new(""); + char curchar; + char * result; + + while ((curchar = fgetc(stdin)) != EOF) + g_string_append_c(buffer, curchar); + + fclose(stdin); + + result = buffer->str; + + g_string_free(buffer, false); + + return result; +} + +int main( int argc, char** argv ) { + /* Make your program do whatever you want */ +} diff --git a/templates/README.md.in b/templates/README.md.in new file mode 100644 index 0000000..bf2b25e --- /dev/null +++ b/templates/README.md.in @@ -0,0 +1,13 @@ +Title: @My_Project_Title@ +Author: @My_Project_Author@ +Date: @My_Project_Revised_Date@ +Copyright: @My_Project_Copyright@ +Version: @My_Project_Version_Major@.@My_Project_Version_Minor@.@My_Project_Version_Patch@ + +# Introduction # + + + +# License # + +@My_Project_License@ diff --git a/templates/template.c.in b/templates/template.c.in new file mode 100644 index 0000000..d11d1e6 --- /dev/null +++ b/templates/template.c.in @@ -0,0 +1,24 @@ +/* + + file.c -- @My_Project_Title@ + + @My_Project_Copyright@ + + + @My_Project_License_Indent@ + +*/ + +#include "file.h" + +int void_function(void) { + return 0; +} + +#ifdef TEST +void Test_void_function(CuTest* tc) { + int test = void_function(); + + CuAssertIntEquals(tc, 0, test); +} +#endif diff --git a/templates/template.h.in b/templates/template.h.in new file mode 100644 index 0000000..e135985 --- /dev/null +++ b/templates/template.h.in @@ -0,0 +1,20 @@ +/* + + file.h -- @My_Project_Title@ + + @My_Project_Copyright@ + + + @My_Project_License_Indent@ + +*/ + +#ifndef FILE_@My_Project_Title_Caps@_H +#define FILE_@My_Project_Title_Caps@_H + +#ifdef TEST +#include "CuTest.h" +#endif + + +#endif diff --git a/test/CuTest.c b/test/CuTest.c new file mode 100644 index 0000000..f5e142a --- /dev/null +++ b/test/CuTest.c @@ -0,0 +1,386 @@ +/* + +CuTest + + http://cutest.sourceforge.net/ + +NOTE + +The license is based on the zlib/libpng license. For more details see +http://www.opensource.org/licenses/zlib-license.html. The intent of the +license is to: + +- keep the license as simple as possible +- encourage the use of CuTest in both free and commercial applications + and libraries +- keep the source code together +- give credit to the CuTest contributors for their work + +If you ship CuTest in source form with your source distribution, the +following license document must be included with it in unaltered form. +If you find CuTest useful we would like to hear about it. + +LICENSE + +Copyright (c) 2003 Asim Jalis + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software in +a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not +be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +*/ + +#include +#include +#include +#include +#include +#include + +#include "CuTest.h" + +/*-------------------------------------------------------------------------* + * CuStr + *-------------------------------------------------------------------------*/ + +char* CuStrAlloc(int size) +{ + char* newStr = (char*) malloc( sizeof(char) * (size) ); + return newStr; +} + +char* CuStrCopy(const char* old) +{ + int len = strlen(old); + char* newStr = CuStrAlloc(len + 1); + strcpy(newStr, old); + return newStr; +} + +/*-------------------------------------------------------------------------* + * CuString + *-------------------------------------------------------------------------*/ + +void CuStringInit(CuString* str) +{ + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; +} + +CuString* CuStringNew(void) +{ + CuString* str = (CuString*) malloc(sizeof(CuString)); + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; + return str; +} + +void CuStringDelete(CuString *str) +{ + if (!str) return; + free(str->buffer); + free(str); +} + +void CuStringResize(CuString* str, int newSize) +{ + str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); + str->size = newSize; +} + +void CuStringAppend(CuString* str, const char* text) +{ + int length; + + if (text == NULL) { + text = "NULL"; + } + + length = strlen(text); + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + str->length += length; + strcat(str->buffer, text); +} + +void CuStringAppendChar(CuString* str, char ch) +{ + char text[2]; + text[0] = ch; + text[1] = '\0'; + CuStringAppend(str, text); +} + +void CuStringAppendFormat(CuString* str, const char* format, ...) +{ + va_list argp; + char buf[HUGE_STRING_LEN]; + va_start(argp, format); + vsprintf(buf, format, argp); + va_end(argp); + CuStringAppend(str, buf); +} + +void CuStringInsert(CuString* str, const char* text, int pos) +{ + int length = strlen(text); + if (pos > str->length) + pos = str->length; + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1); + str->length += length; + memcpy(str->buffer + pos, text, length); +} + +/*-------------------------------------------------------------------------* + * CuTest + *-------------------------------------------------------------------------*/ + +void CuTestInit(CuTest* t, const char* name, TestFunction function) +{ + t->name = CuStrCopy(name); + t->failed = 0; + t->ran = 0; + t->message = NULL; + t->function = function; + t->jumpBuf = NULL; +} + +CuTest* CuTestNew(const char* name, TestFunction function) +{ + CuTest* tc = CU_ALLOC(CuTest); + CuTestInit(tc, name, function); + return tc; +} + +void CuTestDelete(CuTest *t) +{ + if (!t) return; + free(t->name); + free(t); +} + +void CuTestRun(CuTest* tc) +{ + jmp_buf buf; + tc->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + tc->ran = 1; + (tc->function)(tc); + } + tc->jumpBuf = 0; +} + +static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) +{ + char buf[HUGE_STRING_LEN]; + + sprintf(buf, "%s:%d: ", file, line); + CuStringInsert(string, buf, 0); + + tc->failed = 1; + tc->message = string->buffer; + if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0); +} + +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) +{ + CuString string; + + CuStringInit(&string); + if (message2 != NULL) + { + CuStringAppend(&string, message2); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, message); + CuFailInternal(tc, file, line, &string); +} + +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) +{ + if (condition) return; + CuFail_Line(tc, file, line, NULL, message); +} + +void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + const char* expected, const char* actual) +{ + CuString string; + if ((expected == NULL && actual == NULL) || + (expected != NULL && actual != NULL && + strcmp(expected, actual) == 0)) + { + return; + } + + CuStringInit(&string); + if (message != NULL) + { + CuStringAppend(&string, message); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, "expected <"); + CuStringAppend(&string, expected); + CuStringAppend(&string, "> but was <"); + CuStringAppend(&string, actual); + CuStringAppend(&string, ">"); + CuFailInternal(tc, file, line, &string); +} + +void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + int expected, int actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected <%d> but was <%d>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + double expected, double actual, double delta) +{ + char buf[STRING_MAX]; + if (fabs(expected - actual) <= delta) return; + sprintf(buf, "expected <%f> but was <%f>", expected, actual); + + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + void* expected, void* actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + + +/*-------------------------------------------------------------------------* + * CuSuite + *-------------------------------------------------------------------------*/ + +void CuSuiteInit(CuSuite* testSuite) +{ + testSuite->count = 0; + testSuite->failCount = 0; + memset(testSuite->list, 0, sizeof(testSuite->list)); +} + +CuSuite* CuSuiteNew(void) +{ + CuSuite* testSuite = CU_ALLOC(CuSuite); + CuSuiteInit(testSuite); + return testSuite; +} + +void CuSuiteDelete(CuSuite *testSuite) +{ + unsigned int n; + for (n=0; n < MAX_TEST_CASES; n++) + { + if (testSuite->list[n]) + { + CuTestDelete(testSuite->list[n]); + } + } + free(testSuite); + +} + +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) +{ + assert(testSuite->count < MAX_TEST_CASES); + testSuite->list[testSuite->count] = testCase; + testSuite->count++; +} + +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) +{ + int i; + for (i = 0 ; i < testSuite2->count ; ++i) + { + CuTest* testCase = testSuite2->list[i]; + CuSuiteAdd(testSuite, testCase); + } +} + +void CuSuiteRun(CuSuite* testSuite) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuTestRun(testCase); + if (testCase->failed) { testSuite->failCount += 1; } + } +} + +void CuSuiteSummary(CuSuite* testSuite, CuString* summary) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuStringAppend(summary, testCase->failed ? "F" : "."); + } + CuStringAppend(summary, "\n\n"); +} + +void CuSuiteDetails(CuSuite* testSuite, CuString* details) +{ + int i; + int failCount = 0; + + if (testSuite->failCount == 0) + { + int passCount = testSuite->count - testSuite->failCount; + const char* testWord = passCount == 1 ? "test" : "tests"; + CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord); + } + else + { + if (testSuite->failCount == 1) + CuStringAppend(details, "There was 1 failure:\n"); + else + CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount); + + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + if (testCase->failed) + { + failCount++; + CuStringAppendFormat(details, "%d) %s: %s\n", + failCount, testCase->name, testCase->message); + } + } + CuStringAppend(details, "\n!!!FAILURES!!!\n"); + + CuStringAppendFormat(details, "Runs: %d ", testSuite->count); + CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount); + CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount); + } +} diff --git a/test/CuTest.h b/test/CuTest.h new file mode 100644 index 0000000..e293fd0 --- /dev/null +++ b/test/CuTest.h @@ -0,0 +1,163 @@ +/* + +CuTest + + http://cutest.sourceforge.net/ + +NOTE + +The license is based on the zlib/libpng license. For more details see +http://www.opensource.org/licenses/zlib-license.html. The intent of the +license is to: + +- keep the license as simple as possible +- encourage the use of CuTest in both free and commercial applications + and libraries +- keep the source code together +- give credit to the CuTest contributors for their work + +If you ship CuTest in source form with your source distribution, the +following license document must be included with it in unaltered form. +If you find CuTest useful we would like to hear about it. + +LICENSE + +Copyright (c) 2003 Asim Jalis + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software in +a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not +be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source +distribution. + +*/ + +#ifndef CU_TEST_H +#define CU_TEST_H + +#include +#include + +#define CUTEST_VERSION "CuTest 1.5" + +/* CuString */ + +char* CuStrAlloc(int size); +char* CuStrCopy(const char* old); + +#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE))) + +#define HUGE_STRING_LEN 8192 +#define STRING_MAX 256 +#define STRING_INC 256 + +typedef struct +{ + int length; + int size; + char* buffer; +} CuString; + +void CuStringInit(CuString* str); +CuString* CuStringNew(void); +void CuStringRead(CuString* str, const char* path); +void CuStringAppend(CuString* str, const char* text); +void CuStringAppendChar(CuString* str, char ch); +void CuStringAppendFormat(CuString* str, const char* format, ...); +void CuStringInsert(CuString* str, const char* text, int pos); +void CuStringResize(CuString* str, int newSize); +void CuStringDelete(CuString* str); + +/* CuTest */ + +typedef struct CuTest CuTest; + +typedef void (*TestFunction)(CuTest *); + +struct CuTest +{ + char* name; + TestFunction function; + int failed; + int ran; + const char* message; + jmp_buf *jumpBuf; +}; + +void CuTestInit(CuTest* t, const char* name, TestFunction function); +CuTest* CuTestNew(const char* name, TestFunction function); +void CuTestRun(CuTest* tc); +void CuTestDelete(CuTest *t); + +/* Internal versions of assert functions -- use the public versions */ +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message); +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition); +void CuAssertStrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + const char* expected, const char* actual); +void CuAssertIntEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + int expected, int actual); +void CuAssertDblEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + double expected, double actual, double delta); +void CuAssertPtrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + void* expected, void* actual); + +/* public assert functions */ + +#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms)) +#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond)) +#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond)) + +#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl)) +#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl)) +#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) + +#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL)) +#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL)) + +/* CuSuite */ + +#define MAX_TEST_CASES 1024 + +#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST)) + +typedef struct +{ + int count; + CuTest* list[MAX_TEST_CASES]; + int failCount; + +} CuSuite; + + +void CuSuiteInit(CuSuite* testSuite); +CuSuite* CuSuiteNew(void); +void CuSuiteDelete(CuSuite *testSuite); +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase); +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2); +void CuSuiteRun(CuSuite* testSuite); +void CuSuiteSummary(CuSuite* testSuite, CuString* summary); +void CuSuiteDetails(CuSuite* testSuite, CuString* details); + +#endif /* CU_TEST_H */ diff --git a/test/make-tests.sh b/test/make-tests.sh new file mode 100644 index 0000000..9d41dab --- /dev/null +++ b/test/make-tests.sh @@ -0,0 +1,55 @@ +#!/usr/bin/env bash + +# Auto generate single AllTests file for CuTest. +# Searches through all *.c files in the current directory. +# Prints to stdout. +# Author: Asim Jalis +# Date: 01/08/2003 + +if test $# -eq 0 ; then FILES=*.c ; else FILES=$* ; fi + +echo ' + +/* This is auto-generated code. Edit at your own peril. */ +#include +#include + +#include "CuTest.h" + +' + +cat $FILES | grep '^void Test' | + sed -e 's/(.*$//' \ + -e 's/$/(CuTest*);/' \ + -e 's/^/extern /' + +echo \ +' + +void RunAllTests(void) +{ + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + +' +cat $FILES | grep '^void Test' | + sed -e 's/^void //' \ + -e 's/(.*$//' \ + -e 's/^/ SUITE_ADD_TEST(suite, /' \ + -e 's/$/);/' + +echo \ +' + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\\n", output->buffer); + CuStringDelete(output); + CuSuiteDelete(suite); +} + +int main(void) +{ + RunAllTests(); +} +' diff --git a/tools/Toolchain-mingw32.cmake b/tools/Toolchain-mingw32.cmake new file mode 100644 index 0000000..f529580 --- /dev/null +++ b/tools/Toolchain-mingw32.cmake @@ -0,0 +1,9 @@ +# Settings for compiling under MinGW32 + +set (CMAKE_SYSTEM_NAME Windows) + +set (CMAKE_C_COMPILER i586-mingw32msvc-gcc) +set (CMAKE_CXX_COMPILER i586-mingw32msvc-g++) +set (CMAKE_RC_COMPILER i586-mingw32msvc-windres) + +set (CMAKE_FIND_ROOT_PATH /usr/bin)