Initial implementation of files() with Visual Studio support (r359:369)

This commit is contained in:
starkos 2008-05-09 15:19:56 +00:00
parent e238e847b1
commit b3bb81cfd0
28 changed files with 624 additions and 231 deletions

View File

@ -4,9 +4,11 @@
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
*/
#include <string.h>
#include "premake.h"
#include "action/action.h"
#include "base/buffers.h"
#include "base/cstr.h"
SessionAction Actions[] =
{
@ -17,3 +19,97 @@ SessionAction Actions[] =
{ "vs2008", "Microsoft Visual Studio 2008 (includes Express editions)", vs2008_action },
{ 0, 0, 0 }
};
static int action_source_tree_do(Session sess, Project prj, Stream strm, ActionSourceCallback handler, const char* group);
/**
* Walk a list of source files and pass them off, in nesting order, to
* the specified callback. Handles the grouping of related files info
* groups (by directory currently).
* \param sess The current execution session context.
* \param prj The project containing the files to enumerate.
* \param strm The active output stream.
* \param handler The per-file handler function.
* \returns OKAY on success.
*/
int action_source_tree(Session sess, Project prj, Stream strm, ActionSourceCallback handler)
{
return action_source_tree_do(sess, prj, strm, handler, "");
}
static int action_source_tree_do(Session sess, Project prj, Stream strm, ActionSourceCallback handler, const char* group)
{
int i, n, group_len;
Strings files;
char* buffer = buffers_next();
/* open an enclosing group */
group_len = strlen(group);
strcpy(buffer, group);
if (cstr_ends_with(buffer, "/")) /* Trim off trailing path separator */
{
buffer[strlen(buffer)-1] = '\0';
}
handler(sess, prj, strm, buffer, GroupStart);
/* scan all files in this group and process any subdirectories (subgroups) */
files = project_get_files(prj);
n = strings_size(files);
for (i = 0; i < n; ++i)
{
const char* filename = strings_item(files, i);
/* is this file in the group that I am currently processing? */
if (cstr_starts_with(filename, group))
{
/* see if this file contains an additional directory level (a new group) */
const char* ptr = strchr(filename + group_len, '/');
if (ptr)
{
int j;
/* pull out the name of this new group */
size_t len = ptr - filename + 1;
strncpy(buffer, filename, len);
buffer[len] = '\0';
/* have I processed this subdirectory already? See if it appears earlier in the list */
for (j = 0; j < i; ++j)
{
if (cstr_starts_with(strings_item(files, j), buffer))
break;
}
if (i == j)
{
/* a new group, process it now */
if (action_source_tree_do(sess, prj, strm, handler, buffer) != OKAY)
return !OKAY;
}
}
}
}
/* now process all files that belong to this current group (and not a subgroup) */
for (i = 0; i < n; ++i)
{
const char* filename = strings_item(files, i);
if (!strchr(filename + group_len, '/'))
{
if (handler(sess, prj, strm, filename, SourceFile) != OKAY)
return !OKAY;
}
}
/* close the group */
strcpy(buffer, group);
if (cstr_ends_with(buffer, "/")) /* Trim off trailing path separator */
{
buffer[strlen(buffer)-1] = '\0';
}
handler(sess, prj, strm, buffer, GroupEnd);
return OKAY;
}

View File

@ -8,6 +8,31 @@
#include "session/session.h"
/**
* State values for the source tree enumeration functions.
*/
enum ActionSourceState
{
GroupStart,
GroupEnd,
SourceFile
};
/**
* Per-file callback signature for action_source_tree.
* \param sess The current execution state context.
* \param prj The current project; contains the file being enumerated.
* \param strm The active output stream; for writing the file markup.
* \param filename The name of the file to process.
* \param state One of the ActionSourceStates, enabling file grouping.
* \returns OKAY if successful.
*/
typedef int (*ActionSourceCallback)(Session sess, Project prj, Stream strm, const char* filename, int state);
/* the list of built-in Premake actions */
extern SessionAction Actions[];
int gmake_action(Session sess);
@ -16,4 +41,9 @@ int vs2003_action(Session sess);
int vs2005_action(Session sess);
int vs2008_action(Session sess);
/* support functions */
int action_source_tree(Session sess, Project prj, Stream strm, ActionSourceCallback handler);
#endif

View File

@ -48,4 +48,16 @@ struct FxAction
stream_destroy(strm);
session_destroy(sess);
}
void SetField(Project prj, enum ProjectField index, char** values)
{
Strings strs = strings_create();
for (char** value = values; (*value) != NULL; ++value)
{
strings_add(strs, *value);
}
project_set_values(prj, index, strs);
}
};

View File

@ -23,7 +23,7 @@ SUITE(action)
{
TEST_FIXTURE(Fx2002Config, CharacterSet_Default)
{
vs200x_config_character_set(sess);
vs200x_config_character_set(sess, strm);
CHECK_EQUAL("\n\t\t\tCharacterSet=\"2\"", buffer);
}
}

View File

@ -23,7 +23,7 @@ SUITE(action)
{
TEST_FIXTURE(Fx2003Config, CharacterSet_Default)
{
vs200x_config_character_set(sess);
vs200x_config_character_set(sess, strm);
CHECK_EQUAL("\n\t\t\tCharacterSet=\"2\"", buffer);
}
}

View File

@ -23,7 +23,7 @@ SUITE(action)
{
TEST_FIXTURE(Fx2005Config, CharacterSet_Default)
{
vs200x_config_character_set(sess);
vs200x_config_character_set(sess, strm);
CHECK_EQUAL("\n\t\t\tCharacterSet=\"1\"", buffer);
}
}

View File

@ -23,7 +23,7 @@ SUITE(action)
{
TEST_FIXTURE(Fx2008Config, CharacterSet_Default)
{
vs200x_config_character_set(sess);
vs200x_config_character_set(sess, strm);
CHECK_EQUAL("\n\t\t\tCharacterSet=\"1\"", buffer);
}
}

View File

@ -222,7 +222,7 @@ SUITE(action)
* Files section tests
**********************************************************************/
TEST_FIXTURE(FxVsProject, Vs200x_Files)
TEST_FIXTURE(FxVsProject, Vs200x_Files_OnNoFiles)
{
vs200x_project_files(sess, prj, strm);
CHECK_EQUAL(
@ -231,6 +231,52 @@ SUITE(action)
buffer);
}
TEST_FIXTURE(FxVsProject, Vs200x_Files_OnSingleCppFile)
{
char* values[] = { "Hello.cpp", 0 };
SetField(prj, ProjectFiles, values);
vs200x_project_files(sess, prj, strm);
CHECK_EQUAL(
"\t<Files>\n"
"\t\t<File\n"
"\t\t\tRelativePath=\".\\Hello.cpp\">\n"
"\t\t</File>\n"
"\t</Files>\n",
buffer);
}
TEST_FIXTURE(FxVsProject, Vs200x_Files_OnUpperDirectory)
{
char* values[] = { "../../Hello.cpp", 0 };
SetField(prj, ProjectFiles, values);
vs200x_project_files(sess, prj, strm);
CHECK_EQUAL(
"\t<Files>\n"
"\t\t<File\n"
"\t\t\tRelativePath=\"..\\..\\Hello.cpp\">\n"
"\t\t</File>\n"
"\t</Files>\n",
buffer);
}
TEST_FIXTURE(FxVsProject, Vs200x_Files_OnGroupedCppFile)
{
char* values[] = { "Src/Hello.cpp", 0 };
SetField(prj, ProjectFiles, values);
vs200x_project_files(sess, prj, strm);
CHECK_EQUAL(
"\t<Files>\n"
"\t\t<Filter\n"
"\t\t\tName=\"Src\"\n"
"\t\t\tFilter=\"\">\n"
"\t\t\t<File\n"
"\t\t\t\tRelativePath=\".\\Src\\Hello.cpp\">\n"
"\t\t\t</File>\n"
"\t\t</Filter>\n"
"\t</Files>\n",
buffer);
}
/**********************************************************************
* Globals section tests
@ -245,5 +291,4 @@ SUITE(action)
"</VisualStudioProject>\n",
buffer);
}
}

View File

@ -13,43 +13,6 @@ extern "C" {
SUITE(action)
{
/**********************************************************************
* Element tests
**********************************************************************/
TEST_FIXTURE(FxAction, Element_OnLevel0)
{
session_set_action(sess, "vs2002");
vs200x_element(sess, 0, "VisualStudioProject");
CHECK_EQUAL("<VisualStudioProject>\n", buffer);
}
TEST_FIXTURE(FxAction, Element_OnLevel1)
{
session_set_action(sess, "vs2002");
vs200x_element(sess, 1, "VisualStudioProject");
CHECK_EQUAL("\t<VisualStudioProject>\n", buffer);
}
/**********************************************************************
* Element start tests
**********************************************************************/
TEST_FIXTURE(FxAction, ElementStart_OnLevel0)
{
session_set_action(sess, "vs2002");
vs200x_element_start(sess, 0, "VisualStudioProject");
CHECK_EQUAL("<VisualStudioProject", buffer);
}
TEST_FIXTURE(FxAction, ElementStart_OnLevel1)
{
session_set_action(sess, "vs2002");
vs200x_element_start(sess, 1, "VisualStudioProject");
CHECK_EQUAL("\t<VisualStudioProject", buffer);
}
/**********************************************************************
* Element end tests
**********************************************************************/
@ -57,56 +20,56 @@ SUITE(action)
TEST_FIXTURE(FxAction, ElementEnd_SlashBracket_Vs2002)
{
session_set_action(sess, "vs2002");
vs200x_element_end(sess, 0, "/>");
vs200x_element_end(sess, strm, 0, "/>");
CHECK_EQUAL("/>\n", buffer);
}
TEST_FIXTURE(FxAction, ElementEnd_SlashBracket_Vs2003)
{
session_set_action(sess, "vs2003");
vs200x_element_end(sess, 0, "/>");
vs200x_element_end(sess, strm, 0, "/>");
CHECK_EQUAL("/>\n", buffer);
}
TEST_FIXTURE(FxAction, ElementEnd_SlashBracket_Vs2005)
{
session_set_action(sess, "vs2005");
vs200x_element_end(sess, 0, "/>");
vs200x_element_end(sess, strm, 0, "/>");
CHECK_EQUAL("\n/>\n", buffer);
}
TEST_FIXTURE(FxAction, ElementEnd_SlashBracket_Vs2008)
{
session_set_action(sess, "vs2008");
vs200x_element_end(sess, 0, "/>");
vs200x_element_end(sess, strm, 0, "/>");
CHECK_EQUAL("\n/>\n", buffer);
}
TEST_FIXTURE(FxAction, ElementEnd_Bracket_Vs2002)
{
session_set_action(sess, "vs2002");
vs200x_element_end(sess, 0, ">");
vs200x_element_end(sess, strm, 0, ">");
CHECK_EQUAL(">\n", buffer);
}
TEST_FIXTURE(FxAction, ElementEnd_Bracket_Vs2003)
{
session_set_action(sess, "vs2003");
vs200x_element_end(sess, 0, ">");
vs200x_element_end(sess, strm, 0, ">");
CHECK_EQUAL(">\n", buffer);
}
TEST_FIXTURE(FxAction, ElementEnd_Bracket_Vs2005)
{
session_set_action(sess, "vs2005");
vs200x_element_end(sess, 0, ">");
vs200x_element_end(sess, strm, 0, ">");
CHECK_EQUAL("\n\t>\n", buffer);
}
TEST_FIXTURE(FxAction, ElementEnd_Bracket_Vs2008)
{
session_set_action(sess, "vs2008");
vs200x_element_end(sess, 0, ">");
vs200x_element_end(sess, strm, 0, ">");
CHECK_EQUAL("\n\t>\n", buffer);
}
@ -118,42 +81,14 @@ SUITE(action)
TEST_FIXTURE(FxAction, Attribute_OnLevel0)
{
session_set_action(sess, "vs2002");
vs200x_attribute(sess, 0, "ProjectType", "Visual C++");
CHECK_EQUAL("\n\tProjectType=\"Visual C++\"", buffer);
vs200x_attribute(strm, 0, "ProjectType", "Visual C++");
CHECK_EQUAL("\nProjectType=\"Visual C++\"", buffer);
}
TEST_FIXTURE(FxAction, Attribute_OnLevel1)
TEST_FIXTURE(FxAction, Attribute_OnLevel3)
{
session_set_action(sess, "vs2002");
vs200x_attribute(sess, 1, "ProjectType", "Visual C++");
CHECK_EQUAL("\n\t\tProjectType=\"Visual C++\"", buffer);
}
TEST_FIXTURE(FxAction, Attribute_BooleanValue_OnVs2002)
{
session_set_action(sess, "vs2002");
vs200x_attribute(sess, 0, "RuntimeTypeInfo", "true");
CHECK_EQUAL("\n\tRuntimeTypeInfo=\"TRUE\"", buffer);
}
TEST_FIXTURE(FxAction, Attribute_BooleanValue_OnVs2003)
{
session_set_action(sess, "vs2003");
vs200x_attribute(sess, 0, "RuntimeTypeInfo", "true");
CHECK_EQUAL("\n\tRuntimeTypeInfo=\"TRUE\"", buffer);
}
TEST_FIXTURE(FxAction, Attribute_BooleanValue_OnVs2005)
{
session_set_action(sess, "vs2005");
vs200x_attribute(sess, 0, "RuntimeTypeInfo", "true");
CHECK_EQUAL("\n\tRuntimeTypeInfo=\"true\"", buffer);
}
TEST_FIXTURE(FxAction, Attribute_BooleanValue_OnVs2008)
{
session_set_action(sess, "vs2008");
vs200x_attribute(sess, 0, "RuntimeTypeInfo", "true");
CHECK_EQUAL("\n\tRuntimeTypeInfo=\"true\"", buffer);
vs200x_attribute(strm, 3, "ProjectType", "Visual C++");
CHECK_EQUAL("\n\t\t\tProjectType=\"Visual C++\"", buffer);
}
}

View File

@ -14,33 +14,20 @@
/**
* Write an XML attribute, adjusting for the differing Visual Studio formats.
* \param sess The current execution session.
* \param level The XML element nesting level.
* \param strm The output stream, the attribute will be written here.
* \param indent_size How far to indent (with tabs) the attribute.
* \param name The attribute name.
* \param value The attribute value.
* \param value The attribute value; may contain printf-style formatting codes.
* \returns OKAY if successful.
*/
int vs200x_attribute(Session sess, int level, const char* name, const char* value, ...)
int vs200x_attribute(Stream strm, int indent_size, const char* name, const char* value, ...)
{
int z;
va_list args;
Stream strm = session_get_active_stream(sess);
if (vs200x_get_target_version(sess) < 2005)
{
if (cstr_eq(value, "true"))
{
value = "TRUE";
}
else if (cstr_eq(value, "false"))
{
value = "FALSE";
}
}
int z = OKAY;
va_start(args, value);
z = stream_writeline(strm, "");
z |= stream_write_n(strm, "\t", level + 1);
z |= stream_writeline(strm, "");
z |= stream_write_n(strm, "\t", indent_size);
z |= stream_write(strm, "%s=\"", name);
z |= stream_vprintf(strm, value, args);
z |= stream_write(strm, "\"");
@ -49,34 +36,17 @@ int vs200x_attribute(Session sess, int level, const char* name, const char* valu
}
/**
* Write out an element tag.
* \param sess The current execution session.
* \param level The XML element nesting level.
* \param name The element name.
* \returns OKAY if successful.
*/
int vs200x_element(Session sess, int level, const char* name)
{
int z;
Stream strm = session_get_active_stream(sess);
z = stream_write_n(strm, "\t", level);
z |= stream_writeline(strm, "<%s>", name);
return z;
}
/**
* Write the ending part of an XML tag, adjust for the differing Visual Studio formats.
* \param sess The current execution session.
* \param strm The output stream.
* \param level The XML element nesting level.
* \param markup The end tag markup.
* \returns OKAY if successful.
*/
int vs200x_element_end(Session sess, int level, const char* markup)
int vs200x_element_end(Session sess, Stream strm, int level, const char* markup)
{
int z;
Stream strm = session_get_active_stream(sess);
int version = vs200x_get_target_version(sess);
if (version >= 2005)
{
@ -97,19 +67,13 @@ int vs200x_element_end(Session sess, int level, const char* markup)
/**
* Write out the starting part of an XML element tag: "<MyElement".
* \param sess The current execution session.
* \param level The XML element nesting level.
* \param name The element name.
* \returns OKAY if successful.
* Return the Visual Studio version appropriate version of the string for a false
* value. Before 2005 this was "FALSE", after it is "false".
*/
int vs200x_element_start(Session sess, int level, const char* name)
const char* vs200x_false(Session sess)
{
int z;
Stream strm = session_get_active_stream(sess);
z = stream_write_n(strm, "\t", level);
z |= stream_write(strm, "<%s", name);
return z;
int version = vs200x_get_target_version(sess);
return (version < 2005) ? "FALSE" : "false";
}
@ -188,6 +152,17 @@ const char* vs200x_tool_guid(const char* language)
}
/**
* Return the Visual Studio version appropriate version of the string for a true
* value. Before 2005 this was "TRUE", after it is "true".
*/
const char* vs200x_true(Session sess)
{
int version = vs200x_get_target_version(sess);
return (version < 2005) ? "TRUE" : "true";
}
/**
* Make sure all of the features described in the sesson are supported
* by the Visual Studio actions.

View File

@ -8,13 +8,13 @@
#include "session/session.h"
int vs200x_attribute(Session sess, int level, const char* name, const char* value, ...);
int vs200x_element(Session sess, int level, const char* name);
int vs200x_element_end(Session sess, int level, const char* markup);
int vs200x_element_start(Session sess, int level, const char* name);
int vs200x_attribute(Stream strm, int indent_size, const char* name, const char* value, ...);
int vs200x_element_end(Session sess, Stream strm, int level, const char* markup);
const char* vs200x_false(Session sess);
int vs200x_get_target_version(Session sess);
const char* vs200x_project_file_extension(Project prj);
const char* vs200x_tool_guid(const char* language);
const char* vs200x_true(Session sess);
int vs200x_validate_session(Session sess);
#endif

View File

@ -9,40 +9,40 @@
#include "vs200x_config.h"
int vs200x_config_character_set(Session sess)
int vs200x_config_character_set(Session sess, Stream strm)
{
int version = vs200x_get_target_version(sess);
return vs200x_attribute(sess, 2, "CharacterSet", version > 2003 ? "1" : "2");
return vs200x_attribute(strm, 3, "CharacterSet", version > 2003 ? "1" : "2");
}
int vs200x_config_detect_64bit_portability(Session sess, Project prj)
int vs200x_config_detect_64bit_portability(Session sess, Stream strm, Project prj)
{
int version = vs200x_get_target_version(sess);
UNUSED(prj);
if (version < 2008)
{
return vs200x_attribute(sess, 3, "Detect64BitPortabilityProblems", "true");
return vs200x_attribute(strm, 4, "Detect64BitPortabilityProblems", vs200x_true(sess));
}
return OKAY;
}
int vs200x_config_runtime_type_info(Session sess, Project prj)
int vs200x_config_runtime_type_info(Session sess, Stream strm, Project prj)
{
int version = vs200x_get_target_version(sess);
UNUSED(prj);
if (version < 2005)
{
return vs200x_attribute(sess, 3, "RuntimeTypeInfo", "true");
return vs200x_attribute(strm, 4, "RuntimeTypeInfo", vs200x_true(sess));
}
return OKAY;
}
int vs200x_config_use_precompiled_header(Session sess, Project prj)
int vs200x_config_use_precompiled_header(Session sess, Stream strm, Project prj)
{
int version = vs200x_get_target_version(sess);
UNUSED(prj);
return vs200x_attribute(sess, 3, "UsePrecompiledHeader", (version > 2003) ? "0" : "2");
return vs200x_attribute(strm, 4, "UsePrecompiledHeader", (version > 2003) ? "0" : "2");
}

View File

@ -8,9 +8,9 @@
#include "session/session.h"
int vs200x_config_character_set(Session sess);
int vs200x_config_detect_64bit_portability(Session sess, Project prj);
int vs200x_config_runtime_type_info(Session sess, Project prj);
int vs200x_config_use_precompiled_header(Session sess, Project prj);
int vs200x_config_character_set(Session sess, Stream strm);
int vs200x_config_detect_64bit_portability(Session sess, Stream strm, Project prj);
int vs200x_config_runtime_type_info(Session sess, Stream strm, Project prj);
int vs200x_config_use_precompiled_header(Session sess, Stream strm, Project prj);
#endif

View File

@ -5,10 +5,14 @@
*/
#include <stdlib.h>
#include <string.h>
#include "premake.h"
#include "action/action.h"
#include "vs200x.h"
#include "vs200x_project.h"
#include "vs200x_config.h"
#include "base/cstr.h"
#include "base/path.h"
/**
@ -16,16 +20,15 @@
*/
int vs200x_project_config_element(Session sess, Project prj, Stream strm)
{
int z;
int z = OKAY;
const char* cfg_name = project_get_configuration_filter(prj);
UNUSED(strm);
z = vs200x_element_start(sess, 2, "Configuration");
z |= vs200x_attribute(sess, 2, "Name", "%s|Win32", cfg_name);
z |= vs200x_attribute(sess, 2, "OutputDirectory", "$(SolutionDir)$(ConfigurationName)");
z |= vs200x_attribute(sess, 2, "IntermediateDirectory", "$(ConfigurationName)");
z |= vs200x_attribute(sess, 2, "ConfigurationType", "1");
z |= vs200x_config_character_set(sess);
z |= vs200x_element_end(sess, 2, ">");
z |= stream_write(strm, "\t\t<Configuration");
z |= vs200x_attribute(strm, 3, "Name", "%s|Win32", cfg_name);
z |= vs200x_attribute(strm, 3, "OutputDirectory", "$(SolutionDir)$(ConfigurationName)");
z |= vs200x_attribute(strm, 3, "IntermediateDirectory", "$(ConfigurationName)");
z |= vs200x_attribute(strm, 3, "ConfigurationType", "1");
z |= vs200x_config_character_set(sess, strm);
z |= vs200x_element_end(sess, strm, 2, ">");
return z;
}
@ -35,9 +38,9 @@ int vs200x_project_config_element(Session sess, Project prj, Stream strm)
*/
int vs200x_project_config_end(Session sess, Project prj, Stream strm)
{
UNUSED(sess);
UNUSED(prj);
UNUSED(strm);
return vs200x_element(sess, 2, "/Configuration");
return stream_writeline(strm, "\t\t</Configuration>");
}
@ -71,8 +74,6 @@ int vs200x_project_element(Session sess, Project prj, Stream strm)
const char* prj_name = project_get_name(prj);
const char* prj_guid = project_get_guid(prj);
UNUSED(strm);
version = vs200x_get_target_version(sess);
switch (version)
{
@ -86,21 +87,21 @@ int vs200x_project_element(Session sess, Project prj, Stream strm)
prj_ver = "9.00"; break;
}
z = vs200x_element_start(sess, 0, "VisualStudioProject");
z |= vs200x_attribute(sess, 0, "ProjectType", "Visual C++");
z |= vs200x_attribute(sess, 0, "Version", prj_ver);
z |= vs200x_attribute(sess, 0, "Name", prj_name);
z |= vs200x_attribute(sess, 0, "ProjectGUID", "{%s}", prj_guid);
z = stream_write(strm, "<VisualStudioProject");
z |= vs200x_attribute(strm, 1, "ProjectType", "Visual C++");
z |= vs200x_attribute(strm, 1, "Version", prj_ver);
z |= vs200x_attribute(strm, 1, "Name", prj_name);
z |= vs200x_attribute(strm, 1, "ProjectGUID", "{%s}", prj_guid);
if (version > 2003)
{
z |= vs200x_attribute(sess, 0, "RootNamespace", prj_name);
z |= vs200x_attribute(strm, 1, "RootNamespace", prj_name);
}
z |= vs200x_attribute(sess, 0, "Keyword", "Win32Proj");
z |= vs200x_attribute(strm, 1, "Keyword", "Win32Proj");
if (version > 2005)
{
z |= vs200x_attribute(sess, 0, "TargetFrameworkVersion", "196613");
z |= vs200x_attribute(strm, 1, "TargetFrameworkVersion", "196613");
}
z |= vs200x_element_end(sess, 0, ">");
z |= vs200x_element_end(sess, strm, 0, ">");
return z;
}
@ -117,16 +118,89 @@ int vs200x_project_encoding(Session sess, Project prj, Stream strm)
}
/**
* Write an individual file entry to the project file; callback for action_source_tree().
* \param sess The current execution session context.
* \param prj The current project; contains the file being enumerated.
* \param strm The active output stream; for writing the file markup.
* \param filename The name of the file to process.
* \param state One of the ActionSourceStates, enabling file grouping.
* \returns OKAY if successful.
*/
int vs200x_project_file(Session sess, Project prj, Stream strm, const char* filename, int state)
{
const char* name;
const char* ptr;
int depth, z = OKAY;
/* figure out the grouping depth, skipping over any leading dot directories */
depth = 2;
ptr = filename;
while (cstr_starts_with(ptr, "../"))
{
ptr += 3;
}
ptr = strchr(ptr, '/');
while (ptr != NULL)
{
depth++;
ptr = strchr(ptr + 1, '/');
}
/* group name is just the last bit of the path */
name = path_filename(filename);
/* use the Windows path separator */
filename = path_translate(filename, "\\");
switch (state)
{
case GroupStart:
if (strlen(filename) > 0 && !cstr_eq(name, ".."))
{
z |= stream_write_n(strm, "\t", depth);
z |= stream_write(strm, "<Filter");
z |= vs200x_attribute(strm, depth + 1, "Name", name);
z |= vs200x_attribute(strm, depth + 1, "Filter", "");
z |= vs200x_element_end(sess, strm, depth, ">");
}
break;
case GroupEnd:
if (strlen(filename) > 0 && !cstr_eq(name, ".."))
{
z |= stream_write_n(strm, "\t", depth);
z |= stream_writeline(strm, "</Filter>");
}
break;
case SourceFile:
z |= stream_write_n(strm, "\t", depth);
z |= stream_write(strm, "<File");
ptr = (filename[0] == '.') ? "" : ".\\";
z |= vs200x_attribute(strm, depth + 1, "RelativePath", "%s%s", ptr, filename);
z |= vs200x_element_end(sess, strm, depth, ">");
z |= stream_write_n(strm, "\t", depth);
z |= stream_writeline(strm, "</File>");
break;
}
UNUSED(prj);
return z;
}
/**
* Write out the [Files] element.
*/
int vs200x_project_files(Session sess, Project prj, Stream strm)
{
int z;
UNUSED(prj);
UNUSED(strm);
z = vs200x_element(sess, 1, "Files");
z |= vs200x_element(sess, 1, "/Files");
int z = OKAY;
z |= stream_writeline(strm, "\t<Files>");
z |= action_source_tree(sess, prj, strm, vs200x_project_file);
z |= stream_writeline(strm, "\t</Files>");
return z;
}
@ -136,12 +210,12 @@ int vs200x_project_files(Session sess, Project prj, Stream strm)
*/
int vs200x_project_globals(Session sess, Project prj, Stream strm)
{
int z;
int z = OKAY;
UNUSED(sess);
UNUSED(prj);
UNUSED(strm);
z = vs200x_element(sess, 1, "Globals");
z |= vs200x_element(sess, 1, "/Globals");
z |= vs200x_element(sess, 0, "/VisualStudioProject");
z |= stream_writeline(strm, "\t<Globals>");
z |= stream_writeline(strm, "\t</Globals>");
z |= stream_writeline(strm, "</VisualStudioProject>");
return z;
}
@ -151,14 +225,13 @@ int vs200x_project_globals(Session sess, Project prj, Stream strm)
*/
int vs200x_project_platforms(Session sess, Project prj, Stream strm)
{
int z;
int z = OKAY;
UNUSED(prj);
UNUSED(strm);
z = vs200x_element(sess, 1, "Platforms");
z |= vs200x_element_start(sess, 2, "Platform");
z |= vs200x_attribute(sess, 2, "Name", "Win32");
z |= vs200x_element_end(sess, 2, "/>");
z |= vs200x_element(sess, 1, "/Platforms");
z |= stream_writeline(strm, "\t<Platforms>");
z |= stream_write(strm, "\t\t<Platform");
z |= vs200x_attribute(strm, 3, "Name", "Win32");
z |= vs200x_element_end(sess, strm, 2, "/>");
z |= stream_writeline(strm, "\t</Platforms>");
return OKAY;
}
@ -170,12 +243,11 @@ int vs200x_project_references(Session sess, Project prj, Stream strm)
{
int z;
UNUSED(prj);
UNUSED(strm);
z = vs200x_element(sess, 1, "/Configurations");
z = stream_writeline(strm, "\t</Configurations>");
if (vs200x_get_target_version(sess) > 2002)
{
z |= vs200x_element(sess, 1, "References");
z |= vs200x_element(sess, 1, "/References");
z |= stream_writeline(strm, "\t<References>");
z |= stream_writeline(strm, "\t</References>");
}
return z;
}
@ -188,15 +260,14 @@ int vs200x_project_tool_files(Session sess, Project prj, Stream strm)
{
int version, z = OKAY;
UNUSED(prj);
UNUSED(strm);
version = vs200x_get_target_version(sess);
if (version > 2003)
{
z |= vs200x_element(sess, 1, "ToolFiles");
z |= vs200x_element(sess, 1, "/ToolFiles");
z |= stream_writeline(strm, "\t<ToolFiles>");
z |= stream_writeline(strm, "\t</ToolFiles>");
}
z |= vs200x_element(sess, 1, "Configurations");
z |= stream_writeline(strm, "\t<Configurations>");
return z;
}
@ -208,10 +279,9 @@ static int vs200x_project_vc_empty_tool(Session sess, Project prj, Stream strm,
{
int z;
UNUSED(prj);
UNUSED(strm);
z = vs200x_element_start(sess, 3, "Tool");
z |= vs200x_attribute(sess, 3, "Name", name);
z |= vs200x_element_end(sess, 3, "/>");
z = stream_write(strm, "\t\t\t<Tool");
z |= vs200x_attribute(strm, 4, "Name", name);
z |= vs200x_element_end(sess, strm, 3, "/>");
return z;
}
@ -250,20 +320,19 @@ int vs200x_project_vc_cl_compiler_tool(Session sess, Project prj, Stream strm)
{
int version, z;
UNUSED(prj);
UNUSED(strm);
version = vs200x_get_target_version(sess);
z = vs200x_element_start(sess, 3, "Tool");
z |= vs200x_attribute(sess, 3, "Name", "VCCLCompilerTool");
z |= vs200x_attribute(sess, 3, "Optimization", "0");
z |= vs200x_attribute(sess, 3, "MinimalRebuild", "true");
z |= vs200x_attribute(sess, 3, "BasicRuntimeChecks", "3");
z |= vs200x_attribute(sess, 3, "RuntimeLibrary", "3");
z |= vs200x_config_runtime_type_info(sess, prj);
z |= vs200x_config_use_precompiled_header(sess, prj);
z |= vs200x_attribute(sess, 3, "WarningLevel", "3");
z |= vs200x_config_detect_64bit_portability(sess, prj);
z |= vs200x_attribute(sess, 3, "DebugInformationFormat", "4");
z |= vs200x_element_end(sess, 3, "/>");
z = stream_write(strm, "\t\t\t<Tool");
z |= vs200x_attribute(strm, 4, "Name", "VCCLCompilerTool");
z |= vs200x_attribute(strm, 4, "Optimization", "0");
z |= vs200x_attribute(strm, 4, "MinimalRebuild", vs200x_true(sess));
z |= vs200x_attribute(strm, 4, "BasicRuntimeChecks", "3");
z |= vs200x_attribute(strm, 4, "RuntimeLibrary", "3");
z |= vs200x_config_runtime_type_info(sess, strm, prj);
z |= vs200x_config_use_precompiled_header(sess, strm, prj);
z |= vs200x_attribute(strm, 4, "WarningLevel", "3");
z |= vs200x_config_detect_64bit_portability(sess, strm, prj);
z |= vs200x_attribute(strm, 4, "DebugInformationFormat", "4");
z |= vs200x_element_end(sess, strm, 3, "/>");
return z;
}
@ -293,15 +362,14 @@ int vs200x_project_vc_linker_tool(Session sess, Project prj, Stream strm)
{
int z;
UNUSED(prj);
UNUSED(strm);
z = vs200x_element_start(sess, 3, "Tool");
z |= vs200x_attribute(sess, 3, "Name", "VCLinkerTool");
z |= vs200x_attribute(sess, 3, "LinkIncremental", "2");
z |= vs200x_attribute(sess, 3, "GenerateDebugInformation", "true");
z |= vs200x_attribute(sess, 3, "SubSystem", "1");
z |= vs200x_attribute(sess, 3, "EntryPointSymbol", "mainCRTStartup");
z |= vs200x_attribute(sess, 3, "TargetMachine", "1");
z |= vs200x_element_end(sess, 3, "/>");
z = stream_write(strm, "\t\t\t<Tool");
z |= vs200x_attribute(strm, 4, "Name", "VCLinkerTool");
z |= vs200x_attribute(strm, 4, "LinkIncremental", "2");
z |= vs200x_attribute(strm, 4, "GenerateDebugInformation", vs200x_true(sess));
z |= vs200x_attribute(strm, 4, "SubSystem", "1");
z |= vs200x_attribute(strm, 4, "EntryPointSymbol", "mainCRTStartup");
z |= vs200x_attribute(strm, 4, "TargetMachine", "1");
z |= vs200x_element_end(sess, strm, 3, "/>");
return z;
}

View File

@ -13,6 +13,7 @@ int vs200x_project_config_end(Session sess, Project prj, Stream strm);
int vs200x_project_create(Session sess, Project prj, Stream strm);
int vs200x_project_element(Session sess, Project prj, Stream strm);
int vs200x_project_encoding(Session sess, Project prj, Stream strm);
int vs200x_project_file(Session sess, Project prj, Stream strm, const char* filename, int state);
int vs200x_project_files(Session sess, Project prj, Stream strm);
int vs200x_project_globals(Session sess, Project prj, Stream strm);
int vs200x_project_platforms(Session sess, Project prj, Stream strm);

View File

@ -75,7 +75,6 @@ void fields_destroy(Fields fields)
const char* fields_get_value(Fields fields, int index)
{
Strings values;
assert(fields);
assert(index >= 0 && index < fields->count);
@ -91,6 +90,20 @@ const char* fields_get_value(Fields fields, int index)
}
/**
* Retrieve the list of values for a field.
* \param fields The collection of fields.
* \index index The index of fields to query.
* \returns The list of values stored in the field.
*/
Strings fields_get_values(Fields fields, int index)
{
assert(fields);
assert(index >= 0 && index < fields->count);
return fields->values[index];
}
/**
* Sets the value of a string (single value) field.
* \param fields The collection of fields.
@ -115,3 +128,25 @@ void fields_set_value(Fields fields, int index, const char* value)
strings_set(values, 0, value);
}
}
/**
* Sets the list of values associated with a field. The field will subsequently
* "own" the list, and take responsibility to destroying it with the field set.
* \param fields The collection of fields.
* \param index The index of the field to set.
* \param values The list of new values for the field.
*/
void fields_set_values(Fields fields, int index, Strings values)
{
assert(fields);
assert(index >= 0 && index < fields->count);
assert(values);
if (fields->values[index] != NULL)
{
strings_destroy(fields->values[index]);
}
fields->values[index] = values;
}

View File

@ -6,6 +6,8 @@
#if !defined(PREMAKE_FIELDS_H)
#define PREMAKE_FIELDS_H
#include "base/strings.h"
/**
* Field types.
@ -43,6 +45,8 @@ Fields fields_create(struct FieldInfo* info);
void fields_destroy(Fields fields);
const char* fields_get_value(Fields fields, int index);
Strings fields_get_values(Fields fields, int index);
void fields_set_value(Fields fields, int index, const char* value);
void fields_set_values(Fields fields, int index, Strings values);
#endif

View File

@ -17,6 +17,7 @@
struct FieldInfo ProjectFieldInfo[] =
{
{ "basedir", StringField, NULL },
{ "files", ListField, NULL },
{ "guid", StringField, guid_is_valid },
{ "language", StringField, project_is_valid_language },
{ "location", StringField, NULL },
@ -118,13 +119,22 @@ const char* project_get_filename(Project prj, const char* basename, const char*
}
/**
* Retrieve the list of source files associated with a project.
*/
Strings project_get_files(Project prj)
{
assert(prj);
return fields_get_values(prj->fields, ProjectFiles);
}
/**
* Retrieve the GUID associated with a project.
* \param prj The project to query.
* \returns The GUID associated with the project, or NULL if the GUID has not been set.
*/
const char* project_get_guid(Project prj)
{
assert(prj);
return project_get_value(prj, ProjectGuid);
}
@ -270,3 +280,17 @@ void project_set_value(Project prj, enum ProjectField field, const char* value)
assert(prj);
fields_set_value(prj->fields, field, value);
}
/**
* Sets the list of values associated with a field. The field will subsequently
* "own" the list, and take responsibility to destroying it with the field set.
* \param prj The project object.
* \param index The index of the field to set.
* \param values The list of new values for the field.
*/
void project_set_values(Project prj, enum ProjectField field, Strings values)
{
assert(prj);
fields_set_values(prj->fields, field, values);
}

View File

@ -16,6 +16,7 @@
enum ProjectField
{
ProjectBaseDirectory,
ProjectFiles,
ProjectGuid,
ProjectLanguage,
ProjectLocation,
@ -34,6 +35,7 @@ void project_destroy(Project prj);
const char* project_get_base_dir(Project prj);
const char* project_get_configuration_filter(Project prj);
const char* project_get_filename(Project prj, const char* basename, const char* ext);
Strings project_get_files(Project prj);
const char* project_get_guid(Project prj);
const char* project_get_language(Project prj);
const char* project_get_location(Project prj);
@ -47,6 +49,7 @@ void project_set_language(Project prj, const char* language);
void project_set_location(Project prj, const char* location);
void project_set_name(Project prj, const char* name);
void project_set_value(Project prj, enum ProjectField field, const char* value);
void project_set_values(Project prj, enum ProjectField field, Strings values);
int project_tests(void);
#endif

View File

@ -54,4 +54,11 @@ SUITE(fields)
const char* result = fields_get_value(fields, TestStringValue);
CHECK_EQUAL("String Value", result);
}
TEST_FIXTURE(FxFields, SetValues_CanRoundtrip)
{
Strings values = strings_create();
fields_set_values(fields, TestListValue, values);
CHECK(values == fields_get_values(fields, TestListValue));
}
}

View File

@ -10,11 +10,13 @@
#include "base/error.h"
static int fn_accessor(lua_State* L);
static int fn_accessor_object_has_field(struct FieldInfo* fields, const char* field_name);
static int fn_accessor_register(lua_State* L, struct FieldInfo* fields);
static int fn_accessor_register_field(lua_State* L, struct FieldInfo* field);
static int fn_accessor_set_string_value(lua_State* L, struct FieldInfo* field);
static int fn_accessor(lua_State* L);
static int fn_accessor_set_list_value(lua_State* L, struct FieldInfo* field);
static void fn_accessor_append_values(lua_State* L, int destIndex, int srcIndex);
/**
@ -119,7 +121,14 @@ static int fn_accessor(lua_State* L)
/* if a value is provided, set the field */
if (lua_gettop(L) > 1)
{
fn_accessor_set_string_value(L, field);
if (field->kind == StringField)
{
fn_accessor_set_string_value(L, field);
}
else
{
fn_accessor_set_list_value(L, field);
}
}
/* return the current value of the field */
@ -129,7 +138,7 @@ static int fn_accessor(lua_State* L)
/**
* Sets a string field to the value on the top of the Lua stack.
* Sets a string field to the value on the bottom of the Lua stack.
* \returns OKAY if successful.
*/
static int fn_accessor_set_string_value(lua_State* L, struct FieldInfo* field)
@ -157,3 +166,56 @@ static int fn_accessor_set_string_value(lua_State* L, struct FieldInfo* field)
lua_setfield(L, -2, field->name);
return OKAY;
}
/**
* Appends the value or list at the bottom of the Lua stack to the specified list field.
* \returns OKAY if successful.
*/
static int fn_accessor_set_list_value(lua_State* L, struct FieldInfo* field)
{
/* get the current value of the field */
lua_getfield(L, -1, field->name);
/* if the value passed in is a table, append all of its contents to the current
* field value. If the value passed in is a single string, add it at the end */
if (lua_istable(L, 1))
{
fn_accessor_append_values(L, lua_gettop(L), 1);
}
else
{
lua_pushvalue(L, 1);
lua_rawseti(L, -2, luaL_getn(L, -2) + 1);
}
/* remove the field value from the stack */
lua_pop(L, 1);
return OKAY;
}
/**
* Copy values from one table to the end of another table.
* \param destIndex The absolute stack index of the destination table.
* \param srcIndex The absolute stack index of the source table.
*/
static void fn_accessor_append_values(lua_State* L, int destIndex, int srcIndex)
{
int i;
int src_n = luaL_getn(L, srcIndex);
int dst_n = luaL_getn(L, destIndex);
for (i = 1; i <= src_n; ++i)
{
lua_rawgeti(L, srcIndex, i);
if (lua_istable(L, -1))
{
fn_accessor_append_values(L, destIndex, lua_gettop(L));
dst_n = luaL_getn(L, destIndex);
}
else
{
lua_rawseti(L, destIndex, ++dst_n);
}
}
}

View File

@ -11,6 +11,11 @@
#include "base/string.h"
/**
* Replacement implementation for Lua's dofile() function; manages Premake specific
* features like the _FILE variable, and makes sure the directory containing the
* running script is kept current.
*/
int fn_dofile(lua_State* L)
{
const char *filename;

View File

@ -9,6 +9,10 @@
#include "base/error.h"
/**
* Handler for errors reported out the script; copies the error message to
* Premake's global error state.
*/
int fn_error(lua_State* L)
{
const char* message = lua_tostring(L, 1);

View File

@ -8,6 +8,10 @@
#include "script_internal.h"
#include "base/dir.h"
/**
* Implementation of os.getcwd(): returns the current working directory.
*/
int fn_getcwd(lua_State* L)
{
const char* cwd = dir_get_current();

View File

@ -242,7 +242,8 @@ void script_set_action(Script script, const char* action)
/**
* Copy project information out of the scripting environment and into C objects that
* can be more easily manipulated by the action code.
* \param slns An array to hold the list of unloaded solutions.
* \param script The project scripting engine instance.
* \param slns An array to hold the list of unloaded solutions.
* \returns OKAY if successful.
*/
int script_unload(Script script, Array slns)

View File

@ -64,4 +64,57 @@ SUITE(script)
CHECK_EQUAL("MyLocation", result);
}
/**************************************************************************
* List field tests
**************************************************************************/
TEST_FIXTURE(FxAccessor, Accessor_ReturnsEmptyTable_OnEmptyListValue)
{
const char* result = script_run_string(script,
"return (#files() == 0)");
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Accessor_Appends_OnStringValue)
{
const char* result = script_run_string(script,
"files { 'Hello.c' };"
"return (prj.files[1] == 'Hello.c')" );
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Accessor_Appends_OnListValue)
{
const char* result = script_run_string(script,
"files { 'Hello.c', 'Goodbye.c' };"
"return (prj.files[1] == 'Hello.c' and prj.files[2] == 'Goodbye.c')" );
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Accessor_Appends_OnTwoCalls)
{
const char* result = script_run_string(script,
"files { 'Hello.c' };"
"files { 'Goodbye.c' };"
"return (prj.files[1] == 'Hello.c' and prj.files[2] == 'Goodbye.c')" );
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Accessor_ReturnsList_OnNoArgs)
{
const char* result = script_run_string(script,
"files { 'Hello.c', 'Goodbye.c' };"
"lst = files();"
"return (lst[1] == 'Hello.c' and lst[2] == 'Goodbye.c')" );
CHECK_EQUAL("true", result);
}
TEST_FIXTURE(FxAccessor, Accessor_FlattensTables_OnNestedLists)
{
const char* result = script_run_string(script,
"files { {'Hello.c'}, {'Goodbye.c'} };"
"return (prj.files[1] == 'Hello.c' and prj.files[2] == 'Goodbye.c')" );
CHECK_EQUAL("true", result);
}
}

View File

@ -0,0 +1,19 @@
/**
* \file fn_files_tests.cpp
* \brief Automated tests for the files() function.
* \author Copyright (c) 2007-2008 Jason Perkins and the Premake project
*/
#include "premake.h"
#include "script_tests.h"
SUITE(script)
{
TEST_FIXTURE(FxAccessor, Files_Exists_OnStartup)
{
const char* result = script_run_string(script,
"return (files ~= nil)");
CHECK_EQUAL("true", result);
}
}

View File

@ -2,6 +2,14 @@
* \file session.h
* \brief Context for a program execution session.
* \author Copyright (c) 2008 Jason Perkins and the Premake project
*
* \defgroup session Session
*
* Premake is essentially a long chain of sequential actions; the Session object
* tracks the application state through this chain, and provides the context
* necessary for actions to do their work. It's a glorified global, essentially.
*
* @{
*/
#if !defined(PREMAKE_SESSION_H)
#define PREMAKE_SESSION_H
@ -74,3 +82,5 @@ int session_unload(Session sess);
int session_validate(Session sess);
#endif
/** @} */