Initial community commit
This commit is contained in:
+125
@@ -0,0 +1,125 @@
|
||||
/**
|
||||
* \file buffered_io.c
|
||||
* \brief provide buffered io.
|
||||
* \author Copyright (c) 2014
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "premake.h"
|
||||
#include "buffered_io.h"
|
||||
|
||||
void buffer_init(Buffer* b)
|
||||
{
|
||||
b->capacity = 0;
|
||||
b->length = 0;
|
||||
b->data = NULL;
|
||||
}
|
||||
|
||||
void buffer_destroy(Buffer* b)
|
||||
{
|
||||
free(b->data);
|
||||
b->capacity = 0;
|
||||
b->length = 0;
|
||||
b->data = NULL;
|
||||
}
|
||||
|
||||
void buffer_puts(Buffer* b, const void* ptr, size_t len)
|
||||
{
|
||||
char* data;
|
||||
|
||||
size_t required = b->length + len;
|
||||
if (required > b->capacity)
|
||||
{
|
||||
size_t cap = b->capacity;
|
||||
while (required > cap)
|
||||
{
|
||||
cap = (cap * 3) / 2;
|
||||
if (cap <= 65536)
|
||||
cap = 65536;
|
||||
}
|
||||
|
||||
data = (char*)calloc(cap, 1);
|
||||
if (b->length > 0)
|
||||
{
|
||||
memcpy(data, b->data, b->length);
|
||||
free(b->data);
|
||||
}
|
||||
b->data = data;
|
||||
b->capacity = cap;
|
||||
}
|
||||
|
||||
memcpy(b->data + b->length, ptr, len);
|
||||
b->length += len;
|
||||
}
|
||||
|
||||
void buffer_printf(Buffer* b, const char *fmt, ...)
|
||||
{
|
||||
char text[2048];
|
||||
int len;
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
len = vsnprintf(text, sizeof(text) - 1, fmt, args);
|
||||
va_end(args);
|
||||
buffer_puts(b, text, len);
|
||||
}
|
||||
|
||||
// -- Lua wrappers ----------------------------------------
|
||||
|
||||
int buffered_new(lua_State* L)
|
||||
{
|
||||
Buffer* b = (Buffer*)malloc(sizeof(Buffer));
|
||||
buffer_init(b);
|
||||
lua_pushlightuserdata(L, b);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int buffered_write(lua_State* L)
|
||||
{
|
||||
size_t len;
|
||||
const char *s = luaL_checklstring(L, 2, &len);
|
||||
Buffer* b = (Buffer*)lua_touserdata(L, 1);
|
||||
|
||||
buffer_puts(b, s, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int buffered_writeln(lua_State* L)
|
||||
{
|
||||
size_t len;
|
||||
const char *s = luaL_optlstring(L, 2, NULL, &len);
|
||||
Buffer* b = (Buffer*)lua_touserdata(L, 1);
|
||||
|
||||
if (s != NULL)
|
||||
buffer_puts(b, s, len);
|
||||
buffer_puts(b, "\r\n", 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int buffered_close(lua_State* L)
|
||||
{
|
||||
Buffer* b = (Buffer*)lua_touserdata(L, 1);
|
||||
buffer_destroy(b);
|
||||
free(b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int buffered_tostring(lua_State* L)
|
||||
{
|
||||
Buffer* b = (Buffer*)lua_touserdata(L, 1);
|
||||
size_t len = b->length;
|
||||
|
||||
// trim string for _eol of line at the end.
|
||||
if (len > 0 && b->data[len-1] == '\n')
|
||||
--len;
|
||||
if (len > 0 && b->data[len-1] == '\r')
|
||||
--len;
|
||||
|
||||
if (len > 0)
|
||||
// push data into a string.
|
||||
lua_pushlstring(L, b->data, len);
|
||||
else
|
||||
lua_pushstring(L, "");
|
||||
|
||||
return 1;
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* \file buffered_io.h
|
||||
* \brief provide buffered io.
|
||||
* \author Copyright (c) 2014
|
||||
*/
|
||||
#ifndef buffered_io_h
|
||||
#define buffered_io_h
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
typedef struct struct_Buffer
|
||||
{
|
||||
size_t capacity;
|
||||
size_t length;
|
||||
char* data;
|
||||
} Buffer;
|
||||
|
||||
void buffer_init(Buffer* b);
|
||||
void buffer_destroy(Buffer* b);
|
||||
|
||||
void buffer_puts(Buffer* b, const void* ptr, size_t len);
|
||||
void buffer_printf(Buffer* b, const char* s, ...);
|
||||
|
||||
#endif
|
||||
+310
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* \file criteria_matches.c
|
||||
* \brief Determine if this criteria is met by the provided filter terms.
|
||||
* \author Copyright (c) 2002-2014 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
struct Word {
|
||||
const char* word;
|
||||
const char* prefix;
|
||||
int matchesFiles;
|
||||
int assertion;
|
||||
int wildcard;
|
||||
};
|
||||
|
||||
struct Pattern {
|
||||
int matchesFiles;
|
||||
int n;
|
||||
struct Word* word;
|
||||
};
|
||||
|
||||
struct Patterns {
|
||||
int prefixed;
|
||||
int filePatterns;
|
||||
int n;
|
||||
struct Pattern* pattern;
|
||||
};
|
||||
|
||||
|
||||
static int criteria_compilePattern(lua_State* L, struct Pattern* pattern);
|
||||
|
||||
|
||||
int criteria_compile(lua_State* L)
|
||||
{
|
||||
struct Patterns* patterns;
|
||||
int i, n;
|
||||
|
||||
/* create a Patterns object and userdata; holds a list of Pattern items */
|
||||
patterns = (struct Patterns*)lua_newuserdata(L, sizeof(struct Patterns));
|
||||
patterns->prefixed = 0;
|
||||
patterns->filePatterns = 0;
|
||||
|
||||
if (luaL_newmetatable(L, "premake.criteria")) {
|
||||
lua_pushstring(L, "__gc");
|
||||
lua_pushcfunction(L, criteria_delete);
|
||||
lua_settable(L, -3);
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
|
||||
/* create array to hold the incoming list of patterns */
|
||||
n = (int)lua_rawlen(L, 1);
|
||||
patterns->n = n;
|
||||
patterns->pattern = (struct Pattern*)malloc(sizeof(struct Pattern) * n);
|
||||
|
||||
/* create a new pattern object for each incoming pattern */
|
||||
for (i = 0; i < n; ++i) {
|
||||
struct Pattern* pattern = &patterns->pattern[i];
|
||||
|
||||
lua_rawgeti(L, 1, i + 1);
|
||||
criteria_compilePattern(L, pattern);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (pattern->n > 0 && pattern->word[0].prefix != NULL) {
|
||||
patterns->prefixed = 1;
|
||||
}
|
||||
|
||||
if (pattern->matchesFiles) {
|
||||
++patterns->filePatterns;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int criteria_compilePattern(lua_State* L, struct Pattern* pattern)
|
||||
{
|
||||
int i, n;
|
||||
|
||||
/* create array to hold the incoming list of words */
|
||||
n = (int)lua_rawlen(L, -1);
|
||||
pattern->n = n;
|
||||
pattern->word = (struct Word*)malloc(sizeof(struct Word) * n);
|
||||
pattern->matchesFiles = 0;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
struct Word* word = &pattern->word[i];
|
||||
word->matchesFiles = 0;
|
||||
|
||||
lua_rawgeti(L, -1, i + 1);
|
||||
|
||||
lua_rawgeti(L, -1, 1);
|
||||
word->word = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_rawgeti(L, -1, 2);
|
||||
word->prefix = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_rawgeti(L, -1, 3);
|
||||
word->assertion = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_rawgeti(L, -1, 4);
|
||||
word->wildcard = lua_toboolean(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (word->prefix && strcmp(word->prefix, "files") == 0) {
|
||||
word->matchesFiles = 1;
|
||||
pattern->matchesFiles = 1;
|
||||
}
|
||||
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int criteria_delete(lua_State* L)
|
||||
{
|
||||
int i, n;
|
||||
struct Patterns* patterns = (struct Patterns*)lua_touserdata(L, 1);
|
||||
|
||||
n = patterns->n;
|
||||
for (i = 0; i < n; ++i) {
|
||||
free(patterns->pattern[i].word);
|
||||
}
|
||||
free(patterns->pattern);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int match(lua_State* L, const char* value, struct Word* word)
|
||||
{
|
||||
if (word->wildcard) {
|
||||
/* use string.match() to compare */
|
||||
const char* result;
|
||||
int matched = 0;
|
||||
|
||||
int top = lua_gettop(L);
|
||||
|
||||
lua_pushvalue(L, 4);
|
||||
lua_pushstring(L, value);
|
||||
lua_pushstring(L, word->word);
|
||||
lua_call(L, 2, 1);
|
||||
|
||||
if (lua_isstring(L, -1)) {
|
||||
result = lua_tostring(L, -1);
|
||||
matched = (strcmp(value, result) == 0);
|
||||
}
|
||||
|
||||
lua_settop(L, top);
|
||||
return matched;
|
||||
}
|
||||
else {
|
||||
return (strcmp(value, word->word) == 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Compares the value on the top of the stack to the specified word.
|
||||
*/
|
||||
|
||||
static int testValue(lua_State* L, struct Word* word)
|
||||
{
|
||||
const char* value;
|
||||
size_t i, n;
|
||||
int result;
|
||||
|
||||
if (lua_istable(L, -1)) {
|
||||
n = lua_rawlen(L, -1);
|
||||
for (i = 1; i <= n; ++i) {
|
||||
lua_rawgeti(L, -1, i);
|
||||
result = testValue(L, word);
|
||||
lua_pop(L, 1);
|
||||
if (result) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = lua_tostring(L, -1);
|
||||
if (value) {
|
||||
return match(L, value, word);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int testWithPrefix(lua_State* L, struct Word* word, const char* filename, int* fileMatched)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (word->matchesFiles && !filename) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushstring(L, word->prefix);
|
||||
lua_rawget(L, 2);
|
||||
result = testValue(L, word);
|
||||
lua_pop(L, 1);
|
||||
|
||||
if (word->matchesFiles && result == word->assertion) {
|
||||
(*fileMatched) = 1;
|
||||
}
|
||||
|
||||
if (result) {
|
||||
return word->assertion;
|
||||
}
|
||||
|
||||
return (!word->assertion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int testNoPrefix(lua_State* L, struct Word* word, const char* filename, int* fileMatched)
|
||||
{
|
||||
if (filename && word->assertion && match(L, filename, word)) {
|
||||
(*fileMatched) = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, 2)) {
|
||||
if (testValue(L, word)) {
|
||||
lua_pop(L, 2);
|
||||
return word->assertion;
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
return (!word->assertion);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int criteria_matches(lua_State* L)
|
||||
{
|
||||
/* stack [1] = criteria */
|
||||
/* stack [2] = context */
|
||||
|
||||
struct Patterns* patterns;
|
||||
const char* filename;
|
||||
int i, j, fileMatched;
|
||||
int matched = 1;
|
||||
|
||||
/* filename = context.files */
|
||||
lua_pushstring(L, "files");
|
||||
lua_rawget(L, 2);
|
||||
filename = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
/* fetch the patterns to be tested */
|
||||
lua_pushstring(L, "data");
|
||||
lua_rawget(L, 1);
|
||||
patterns = (struct Patterns*)lua_touserdata(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
/* if a file is being matched, the pattern must be able to match it */
|
||||
if (patterns->prefixed && filename != NULL && patterns->filePatterns == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Cache string.match on the stack (at index 4) to save time in matches() later */
|
||||
|
||||
lua_getglobal(L, "string");
|
||||
lua_getfield(L, -1, "match");
|
||||
|
||||
/* if there is no file to consider, consider it matched */
|
||||
fileMatched = (filename == NULL);
|
||||
|
||||
/* all patterns must match to pass */
|
||||
for (i = 0; matched && i < patterns->n; ++i) {
|
||||
struct Pattern* pattern = &patterns->pattern[i];
|
||||
|
||||
/* only one word needs to match for the pattern to pass */
|
||||
matched = 0;
|
||||
|
||||
for (j = 0; !matched && j < pattern->n; ++j) {
|
||||
struct Word* word = &pattern->word[j];
|
||||
if (word->prefix) {
|
||||
matched = testWithPrefix(L, word, filename, &fileMatched);
|
||||
}
|
||||
else {
|
||||
matched = testNoPrefix(L, word, filename, &fileMatched);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* if a file name was provided in the context, it must be matched */
|
||||
if (filename && !fileMatched) {
|
||||
matched = 0;
|
||||
}
|
||||
|
||||
lua_pushboolean(L, matched);
|
||||
return 1;
|
||||
}
|
||||
+207
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* \file curl_utils.c
|
||||
* \brief curl utilities for the http library.
|
||||
* \author Copyright (c) 2017 Tom van Dijck, João Matos and the Premake project
|
||||
*/
|
||||
#ifdef PREMAKE_CURL
|
||||
|
||||
#include "curl_utils.h"
|
||||
#include "premake.h"
|
||||
#include <string.h>
|
||||
|
||||
int curlProgressCallback(curl_state* state, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
{
|
||||
lua_State* L = state->L;
|
||||
|
||||
(void)ultotal;
|
||||
(void)ulnow;
|
||||
|
||||
if (dltotal == 0) return 0;
|
||||
|
||||
/* retrieve the lua progress callback we saved before */
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, state->RefIndex);
|
||||
lua_pushnumber(L, (lua_Number)dltotal);
|
||||
lua_pushnumber(L, (lua_Number)dlnow);
|
||||
int ret = premake_pcall(L, 2, LUA_MULTRET);
|
||||
if (ret != LUA_OK) {
|
||||
printLastError(L);
|
||||
return -1; // abort download
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
size_t curlWriteCallback(char *ptr, size_t size, size_t nmemb, curl_state* state)
|
||||
{
|
||||
size_t length = size * nmemb;
|
||||
buffer_puts(&state->S, ptr, length);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
static void curl_init()
|
||||
{
|
||||
static int initializedHTTP = 0;
|
||||
|
||||
if (initializedHTTP)
|
||||
return;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
atexit(curl_global_cleanup);
|
||||
initializedHTTP = 1;
|
||||
}
|
||||
|
||||
|
||||
static void get_headers(lua_State* L, int headersIndex, struct curl_slist** headers)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, headersIndex) != 0)
|
||||
{
|
||||
const char *item = luaL_checkstring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
*headers = curl_slist_append(*headers, item);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CURL* curlRequest(lua_State* L, curl_state* state, int optionsIndex, int progressFnIndex, int headersIndex)
|
||||
{
|
||||
char agent[1024];
|
||||
CURL* curl;
|
||||
|
||||
state->L = 0;
|
||||
state->RefIndex = 0;
|
||||
state->errorBuffer[0] = '\0';
|
||||
state->headers = NULL;
|
||||
buffer_init(&state->S);
|
||||
|
||||
curl_init();
|
||||
curl = curl_easy_init();
|
||||
|
||||
if (!curl)
|
||||
return NULL;
|
||||
|
||||
strcpy(agent, "Premake/");
|
||||
strcat(agent, PREMAKE_VERSION);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, luaL_checkstring(L, 1));
|
||||
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, state->errorBuffer);
|
||||
curl_easy_setopt(curl, CURLOPT_USERAGENT, agent);
|
||||
|
||||
// check if the --insecure option was specified on the commandline.
|
||||
lua_getglobal(L, "_OPTIONS");
|
||||
lua_pushstring(L, "insecure");
|
||||
lua_gettable(L, -2);
|
||||
if (!lua_isnil(L, -1))
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
}
|
||||
lua_pop(L, 2);
|
||||
|
||||
// apply all other options.
|
||||
if (optionsIndex && lua_istable(L, optionsIndex))
|
||||
{
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, optionsIndex) != 0)
|
||||
{
|
||||
const char* key = luaL_checkstring(L, -2);
|
||||
|
||||
if (!strcmp(key, "headers") && lua_istable(L, -1))
|
||||
{
|
||||
get_headers(L, lua_gettop(L), &state->headers);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, state->headers);
|
||||
}
|
||||
else if (!strcmp(key, "progress") && lua_isfunction(L, -1))
|
||||
{
|
||||
state->L = L;
|
||||
lua_pushvalue(L, -1);
|
||||
state->RefIndex = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
else if (!strcmp(key, "userpwd") && lua_isstring(L, -1))
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_USERPWD, luaL_checkstring(L, -1));
|
||||
}
|
||||
else if (!strcmp(key, "username") && lua_isstring(L, -1))
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_USERNAME, luaL_checkstring(L, -1));
|
||||
}
|
||||
else if (!strcmp(key, "password") && lua_isstring(L, -1))
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_PASSWORD, luaL_checkstring(L, -1));
|
||||
}
|
||||
else if (!strcmp(key, "timeout") && lua_isnumber(L, -1))
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, (long)luaL_checknumber(L, -1));
|
||||
}
|
||||
else if (!strcmp(key, "timeoutms") && lua_isnumber(L, -1))
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT_MS, (long)luaL_checknumber(L, -1));
|
||||
}
|
||||
else if (!strcmp(key, "sslverifyhost") && lua_isnumber(L, -1))
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, (long)luaL_checknumber(L, -1));
|
||||
}
|
||||
else if (!strcmp(key, "sslverifypeer") && lua_isnumber(L, -1))
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long)luaL_checknumber(L, -1));
|
||||
}
|
||||
else if (!strcmp(key, "proxyurl") && lua_isstring(L, -1))
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_PROXY, luaL_checkstring(L, -1));
|
||||
}
|
||||
|
||||
// pop the value, leave the key for lua_next
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (progressFnIndex && lua_type(L, progressFnIndex) == LUA_TFUNCTION)
|
||||
{
|
||||
state->L = L;
|
||||
lua_pushvalue(L, progressFnIndex);
|
||||
state->RefIndex = luaL_ref(L, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
if (headersIndex && lua_istable(L, headersIndex))
|
||||
{
|
||||
get_headers(L, headersIndex, &state->headers);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, state->headers);
|
||||
}
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, state);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteCallback);
|
||||
|
||||
if (state->L != 0)
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0);
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, state);
|
||||
curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, curlProgressCallback);
|
||||
}
|
||||
|
||||
// clear error buffer.
|
||||
state->errorBuffer[0] = 0;
|
||||
|
||||
return curl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void curlCleanup(CURL* curl, curl_state* state)
|
||||
{
|
||||
if (state->headers)
|
||||
{
|
||||
curl_slist_free_all(state->headers);
|
||||
state->headers = 0;
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* \file curl_utils.h
|
||||
* \brief curl utilities for the http library.
|
||||
* \author Copyright (c) 2017 Tom van Dijck, João Matos and the Premake project
|
||||
*/
|
||||
#ifndef curl_utils_h
|
||||
#define curl_utils_h
|
||||
|
||||
#ifdef PREMAKE_CURL
|
||||
|
||||
#include "buffered_io.h"
|
||||
#include "lua.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use curl functions only */
|
||||
#include <curl/curl.h>
|
||||
#include <curl/mprintf.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
lua_State* L;
|
||||
int RefIndex;
|
||||
Buffer S;
|
||||
char errorBuffer[256];
|
||||
struct curl_slist* headers;
|
||||
} curl_state;
|
||||
|
||||
int curlProgressCallback(curl_state* state, double dltotal, double dlnow, double ultotal, double ulnow);
|
||||
size_t curlWriteCallback(char *ptr, size_t size, size_t nmemb, curl_state* state);
|
||||
|
||||
CURL* curlRequest(lua_State* L, curl_state* state, int optionsIndex, int progressFnIndex, int headersIndex);
|
||||
void curlCleanup(CURL* curl, curl_state* state);
|
||||
|
||||
|
||||
#endif // PREMAKE_CURL
|
||||
|
||||
#endif // curl_utils_h
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* \file debug_prompt.c
|
||||
* \brief Display a prompt and enter interactive REPL mode.
|
||||
* \author Copyright (c) 2014 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
/* Build on the REPL built into Lua already */
|
||||
#define main lua_main
|
||||
#include "lua.c"
|
||||
|
||||
|
||||
/* Based on dotty() in lua.c */
|
||||
int debug_prompt(lua_State* L)
|
||||
{
|
||||
int status;
|
||||
|
||||
const char* oldProgName = progname;
|
||||
progname = NULL;
|
||||
|
||||
while ((status = loadline(L)) != -1) {
|
||||
if (status == 0) {
|
||||
status = docall(L, 0, 0);
|
||||
}
|
||||
|
||||
report(L, status);
|
||||
|
||||
if (status == 0 && lua_gettop(L) > 0) { /* any result to print? */
|
||||
lua_getglobal(L, "print");
|
||||
lua_insert(L, 1);
|
||||
if (lua_pcall(L, lua_gettop(L) - 1, 0, 0) != 0) {
|
||||
l_message(progname, lua_pushfstring(L,
|
||||
"error calling " LUA_QL("print") " (%s)",
|
||||
lua_tostring(L, -1))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lua_settop(L, 0); /* clear stack */
|
||||
fputs("\n", stdout);
|
||||
fflush(stdout);
|
||||
progname = oldProgName;
|
||||
return 0;
|
||||
}
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* \file http_download.c
|
||||
* \brief HTTP download support using libcurl.
|
||||
* \author Copyright (c) 2017 Blizzard Entertainment, João Matos and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include "curl_utils.h"
|
||||
|
||||
#ifdef PREMAKE_CURL
|
||||
|
||||
static size_t curl_file_cb(void *ptr, size_t size, size_t nmemb, FILE *stream)
|
||||
{
|
||||
return fwrite(ptr, size, nmemb, stream);
|
||||
}
|
||||
|
||||
int http_download(lua_State* L)
|
||||
{
|
||||
curl_state state;
|
||||
CURL* curl;
|
||||
CURLcode code = CURLE_FAILED_INIT;
|
||||
long responseCode = 0;
|
||||
|
||||
FILE* fp;
|
||||
const char* file = luaL_checkstring(L, 2);
|
||||
|
||||
fp = fopen(file, "wb");
|
||||
if (!fp)
|
||||
{
|
||||
lua_pushstring(L, "Unable to open file.");
|
||||
lua_pushnumber(L, -1);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (lua_istable(L, 3))
|
||||
{
|
||||
// http.download(source, destination, { options })
|
||||
curl = curlRequest(L, &state, /*optionsIndex=*/3, /*progressFnIndex=*/0, /*headersIndex=*/0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// backward compatible function signature
|
||||
// http.download(source, destination, progressFunction, { headers })
|
||||
curl = curlRequest(L, &state, /*optionsIndex=*/0, /*progressFnIndex=*/3, /*headersIndex=*/4);
|
||||
}
|
||||
|
||||
if (curl)
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curl_file_cb);
|
||||
|
||||
code = curl_easy_perform(curl);
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
|
||||
curlCleanup(curl, &state);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
char errorBuf[1024];
|
||||
snprintf(errorBuf, sizeof(errorBuf) - 1, "%s\n%s\n", curl_easy_strerror(code), state.errorBuffer);
|
||||
lua_pushstring(L, errorBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushstring(L, "OK");
|
||||
}
|
||||
|
||||
buffer_destroy(&state.S);
|
||||
lua_pushnumber(L, (lua_Number)responseCode);
|
||||
return 2;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* \file http_get.c
|
||||
* \brief HTTP get request support using libcurl.
|
||||
* \author Copyright (c) 2017 Blizzard Entertainment, João Matos and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include "curl_utils.h"
|
||||
|
||||
#ifdef PREMAKE_CURL
|
||||
|
||||
int http_get(lua_State* L)
|
||||
{
|
||||
curl_state state;
|
||||
CURL* curl;
|
||||
CURLcode code = CURLE_FAILED_INIT;
|
||||
long responseCode = 0;
|
||||
|
||||
if (lua_istable(L, 2))
|
||||
{
|
||||
// http.get(source, { options })
|
||||
curl = curlRequest(L, &state, /*optionsIndex=*/2, /*progressFnIndex=*/0, /*headersIndex=*/0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// backward compatible function signature
|
||||
// http.get(source, progressFunction, { headers })
|
||||
curl = curlRequest(L, &state, /*optionsIndex=*/0, /*progressFnIndex=*/2, /*headersIndex=*/3);
|
||||
}
|
||||
|
||||
if (curl)
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
|
||||
|
||||
code = curl_easy_perform(curl);
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
|
||||
curlCleanup(curl, &state);
|
||||
}
|
||||
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
char errorBuf[1024];
|
||||
|
||||
lua_pushnil(L);
|
||||
snprintf(errorBuf, sizeof(errorBuf) - 1, "%s\n%s\n", curl_easy_strerror(code), state.errorBuffer);
|
||||
lua_pushstring(L, errorBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushlstring(L, state.S.data, state.S.length);
|
||||
lua_pushstring(L, "OK");
|
||||
}
|
||||
|
||||
buffer_destroy(&state.S);
|
||||
lua_pushnumber(L, (lua_Number)responseCode);
|
||||
return 3;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* \file http_post.c
|
||||
* \brief HTTP post request support using libcurl.
|
||||
* \author Copyright (c) 2017 Blizzard Entertainment, João Matos and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include "curl_utils.h"
|
||||
|
||||
#ifdef PREMAKE_CURL
|
||||
|
||||
int http_post(lua_State* L)
|
||||
{
|
||||
curl_state state;
|
||||
CURL* curl;
|
||||
CURLcode code = CURLE_FAILED_INIT;
|
||||
long responseCode = 0;
|
||||
|
||||
// http.post(source, postdata, { options })
|
||||
curl = curlRequest(L, &state, /*optionsIndex=*/3, /*progressFnIndex=*/0, /*headersIndex=*/0);
|
||||
if (curl)
|
||||
{
|
||||
size_t dataSize;
|
||||
const char* data = luaL_checklstring(L, 2, &dataSize);
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
if (data && dataSize > 0)
|
||||
{
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)dataSize);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
|
||||
}
|
||||
|
||||
code = curl_easy_perform(curl);
|
||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode);
|
||||
curlCleanup(curl, &state);
|
||||
}
|
||||
|
||||
if (code != CURLE_OK)
|
||||
{
|
||||
char errorBuf[1024];
|
||||
|
||||
lua_pushnil(L);
|
||||
snprintf(errorBuf, sizeof(errorBuf) - 1, "%s\n%s\n", curl_easy_strerror(code), state.errorBuffer);
|
||||
lua_pushstring(L, errorBuf);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushlstring(L, state.S.data, state.S.length);
|
||||
lua_pushstring(L, "OK");
|
||||
}
|
||||
|
||||
buffer_destroy(&state.S);
|
||||
lua_pushnumber(L, (lua_Number)responseCode);
|
||||
return 3;
|
||||
}
|
||||
|
||||
#endif
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* \file lua_auxlib.c
|
||||
* \brief Modifications and extensions to Lua's library functions.
|
||||
* \author Copyright (c) 2014-2017 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
|
||||
static int chunk_wrapper(lua_State* L);
|
||||
|
||||
|
||||
|
||||
/* Pull in Lua's aux lib implementation, but rename luaL_loadfilex() so I
|
||||
* can replace it with my own implementation. */
|
||||
|
||||
#define luaL_loadfilex original_luaL_loadfilex
|
||||
#include "lauxlib.c"
|
||||
#undef luaL_loadfilex
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Extend the default implementation of luaL_loadfile() to call my chunk
|
||||
* wrapper, above, before executing any scripts loaded from a file.
|
||||
*/
|
||||
LUALIB_API int luaL_loadfilex (lua_State* L, const char* filename, const char* mode)
|
||||
{
|
||||
const char* script_dir;
|
||||
const char* test_name;
|
||||
|
||||
int bottom = lua_gettop(L);
|
||||
int z = !OKAY;
|
||||
|
||||
/* If filename starts with "$/" then we want to load the version that
|
||||
* was embedded into the executable and skip the local file system */
|
||||
if (filename[0] == '$') {
|
||||
z = premake_load_embedded_script(L, filename + 2); /* Skip over leading "$/" */
|
||||
if (z != OKAY) {
|
||||
return z;
|
||||
}
|
||||
}
|
||||
|
||||
/* If the currently running script was embedded, try to load this file
|
||||
* as it if were embedded too. */
|
||||
if (z != OKAY) {
|
||||
lua_getglobal(L, "_SCRIPT_DIR");
|
||||
script_dir = lua_tostring(L, -1);
|
||||
|
||||
if (script_dir && script_dir[0] == '$') {
|
||||
/* Call `path.getabsolute(filename, _SCRIPT_DIR)` to resolve any
|
||||
* "../" sequences in the filename */
|
||||
lua_pushcfunction(L, path_getabsolute);
|
||||
lua_pushstring(L, filename);
|
||||
lua_pushvalue(L, -3);
|
||||
lua_call(L, 2, 1);
|
||||
test_name = lua_tostring(L, -1);
|
||||
|
||||
/* if successful, filename and chunk will be on top of stack */
|
||||
z = premake_load_embedded_script(L, test_name + 2); /* Skip over leading "$/" */
|
||||
|
||||
/* remove test_name */
|
||||
lua_remove(L, bottom + 1);
|
||||
}
|
||||
|
||||
/* remove _SCRIPT_DIR */
|
||||
lua_remove(L, bottom);
|
||||
}
|
||||
|
||||
/* Try to locate the script on the filesystem */
|
||||
if (z != OKAY) {
|
||||
lua_pushcfunction(L, os_locate);
|
||||
lua_pushstring(L, filename);
|
||||
lua_call(L, 1, 1);
|
||||
|
||||
test_name = lua_tostring(L, -1);
|
||||
|
||||
if (test_name) {
|
||||
z = original_luaL_loadfilex(L, test_name, mode);
|
||||
}
|
||||
|
||||
/* If the file exists but errors, pass that through */
|
||||
if (test_name && z != OKAY && z != LUA_ERRFILE) {
|
||||
return z;
|
||||
}
|
||||
|
||||
/* If the file didn't exist, remove the result and the test
|
||||
* name from the stack before checking embedded scripts */
|
||||
if (z != OKAY) {
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to load from embedded scripts */
|
||||
if (z != OKAY) {
|
||||
z = premake_load_embedded_script(L, filename);
|
||||
}
|
||||
|
||||
/* Either way I should have ended up with the file name followed by the
|
||||
* script chunk on the stack. Turn these into a closure that will call my
|
||||
* wrapper below when the loaded script needs to be executed. */
|
||||
if (z == OKAY) {
|
||||
lua_pushcclosure(L, chunk_wrapper, 2);
|
||||
}
|
||||
else if (z == LUA_ERRFILE) {
|
||||
lua_pushfstring(L, "cannot open %s: No such file or directory", filename);
|
||||
}
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Execute a chunk of code previously loaded by my customized version of
|
||||
* luaL_loadfile(), below. Sets the _SCRIPT global variable to the absolute
|
||||
* path of the loaded chunk, and makes its enclosing directory current so
|
||||
* that relative path references to other files or scripts can be used.
|
||||
*/
|
||||
|
||||
static int chunk_wrapper(lua_State* L)
|
||||
{
|
||||
char cwd[PATH_MAX];
|
||||
const char* filename;
|
||||
char* ptr;
|
||||
int i, args;
|
||||
|
||||
args = lua_gettop(L);
|
||||
|
||||
/* Remember the current _SCRIPT and working directory so I can
|
||||
* restore them after this new chunk has been run. */
|
||||
|
||||
do_getcwd(cwd, PATH_MAX);
|
||||
lua_getglobal(L, "_SCRIPT");
|
||||
lua_getglobal(L, "_SCRIPT_DIR");
|
||||
|
||||
/* Set the new _SCRIPT variable */
|
||||
|
||||
lua_pushvalue(L, lua_upvalueindex(1));
|
||||
lua_setglobal(L, "_SCRIPT");
|
||||
|
||||
/* And the new _SCRIPT_DIR variable (const cheating) */
|
||||
|
||||
filename = lua_tostring(L, lua_upvalueindex(1));
|
||||
ptr = strrchr(filename, '/');
|
||||
if (ptr) *ptr = '\0';
|
||||
lua_pushlstring(L, filename, strlen(filename));
|
||||
lua_setglobal(L, "_SCRIPT_DIR");
|
||||
|
||||
/* And make that the CWD (and fix the const cheat) */
|
||||
|
||||
if (filename[0] != '$') {
|
||||
do_chdir(L, filename);
|
||||
}
|
||||
if (ptr) *ptr = '/';
|
||||
|
||||
/* Move the function's arguments to the top of the stack and
|
||||
* execute the function created by luaL_loadfile() */
|
||||
|
||||
lua_pushvalue(L, lua_upvalueindex(2));
|
||||
for (i = 1; i <= args; ++i) {
|
||||
lua_pushvalue(L, i);
|
||||
}
|
||||
|
||||
lua_call(L, args, LUA_MULTRET);
|
||||
|
||||
/* Finally, restore the previous _SCRIPT variable and working directory
|
||||
* before returning control to the previously executing script. */
|
||||
|
||||
do_chdir(L, cwd);
|
||||
lua_pushvalue(L, args + 1);
|
||||
lua_setglobal(L, "_SCRIPT");
|
||||
lua_pushvalue(L, args + 2);
|
||||
lua_setglobal(L, "_SCRIPT_DIR");
|
||||
|
||||
return lua_gettop(L) - args - 2;
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* \file lua_shimtable.h
|
||||
* \brief Lua shim for premake binary modules.
|
||||
* \author Copyright (c) 2017 Tom van Dijck and the Premake project
|
||||
*/
|
||||
#ifndef HEADER_lua_shimtable_H
|
||||
#define HEADER_lua_shimtable_H
|
||||
|
||||
#include "luashim.h"
|
||||
|
||||
static LuaFunctionTable_t s_shimTable = {
|
||||
&luaL_register,
|
||||
&lua_newstate,
|
||||
&lua_close,
|
||||
&lua_newthread,
|
||||
&lua_atpanic,
|
||||
&lua_version,
|
||||
&lua_absindex,
|
||||
&lua_gettop,
|
||||
&lua_settop,
|
||||
&lua_pushvalue,
|
||||
&lua_rotate,
|
||||
&lua_copy,
|
||||
&lua_checkstack,
|
||||
&lua_xmove,
|
||||
&lua_isnumber,
|
||||
&lua_isstring,
|
||||
&lua_iscfunction,
|
||||
&lua_isinteger,
|
||||
&lua_isuserdata,
|
||||
&lua_type,
|
||||
&lua_typename,
|
||||
&lua_tonumberx,
|
||||
&lua_tointegerx,
|
||||
&lua_toboolean,
|
||||
&lua_tolstring,
|
||||
&lua_rawlen,
|
||||
&lua_tocfunction,
|
||||
&lua_touserdata,
|
||||
&lua_tothread,
|
||||
&lua_topointer,
|
||||
&lua_arith,
|
||||
&lua_rawequal,
|
||||
&lua_compare,
|
||||
&lua_pushnil,
|
||||
&lua_pushnumber,
|
||||
&lua_pushinteger,
|
||||
&lua_pushlstring,
|
||||
&lua_pushstring,
|
||||
&lua_pushvfstring,
|
||||
&lua_pushcclosure,
|
||||
&lua_pushboolean,
|
||||
&lua_pushlightuserdata,
|
||||
&lua_pushthread,
|
||||
&lua_getglobal,
|
||||
&lua_gettable,
|
||||
&lua_getfield,
|
||||
&lua_geti,
|
||||
&lua_rawget,
|
||||
&lua_rawgeti,
|
||||
&lua_rawgetp,
|
||||
&lua_createtable,
|
||||
&lua_newuserdata,
|
||||
&lua_getmetatable,
|
||||
&lua_getuservalue,
|
||||
&lua_setglobal,
|
||||
&lua_settable,
|
||||
&lua_setfield,
|
||||
&lua_seti,
|
||||
&lua_rawset,
|
||||
&lua_rawseti,
|
||||
&lua_rawsetp,
|
||||
&lua_setmetatable,
|
||||
&lua_setuservalue,
|
||||
&lua_callk,
|
||||
&lua_pcallk,
|
||||
&lua_load,
|
||||
&lua_dump,
|
||||
&lua_yieldk,
|
||||
&lua_resume,
|
||||
&lua_status,
|
||||
&lua_isyieldable,
|
||||
&lua_gc,
|
||||
&lua_error,
|
||||
&lua_next,
|
||||
&lua_concat,
|
||||
&lua_len,
|
||||
&lua_stringtonumber,
|
||||
&lua_getallocf,
|
||||
&lua_setallocf,
|
||||
&lua_getstack,
|
||||
&lua_getinfo,
|
||||
&lua_getlocal,
|
||||
&lua_setlocal,
|
||||
&lua_getupvalue,
|
||||
&lua_setupvalue,
|
||||
&lua_upvalueid,
|
||||
&lua_upvaluejoin,
|
||||
&lua_sethook,
|
||||
&lua_gethook,
|
||||
&lua_gethookmask,
|
||||
&lua_gethookcount,
|
||||
&luaL_checkversion_,
|
||||
&luaL_getmetafield,
|
||||
&luaL_callmeta,
|
||||
&luaL_tolstring,
|
||||
&luaL_argerror,
|
||||
&luaL_checklstring,
|
||||
&luaL_optlstring,
|
||||
&luaL_checknumber,
|
||||
&luaL_optnumber,
|
||||
&luaL_checkinteger,
|
||||
&luaL_optinteger,
|
||||
&luaL_checkstack,
|
||||
&luaL_checktype,
|
||||
&luaL_checkany,
|
||||
&luaL_newmetatable,
|
||||
&luaL_setmetatable,
|
||||
&luaL_testudata,
|
||||
&luaL_checkudata,
|
||||
&luaL_where,
|
||||
&luaL_checkoption,
|
||||
&luaL_fileresult,
|
||||
&luaL_execresult,
|
||||
&luaL_ref,
|
||||
&luaL_unref,
|
||||
&luaL_loadfilex,
|
||||
&luaL_loadbufferx,
|
||||
&luaL_loadstring,
|
||||
&luaL_newstate,
|
||||
&luaL_len,
|
||||
&luaL_gsub,
|
||||
&luaL_setfuncs,
|
||||
&luaL_getsubtable,
|
||||
&luaL_traceback,
|
||||
&luaL_requiref,
|
||||
&luaL_buffinit,
|
||||
&luaL_prepbuffsize,
|
||||
&luaL_addlstring,
|
||||
&luaL_addstring,
|
||||
&luaL_addvalue,
|
||||
&luaL_pushresult,
|
||||
&luaL_pushresultsize,
|
||||
&luaL_buffinitsize,
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* \file os_chdir.c
|
||||
* \brief Change the current working directory.
|
||||
* \author Copyright (c) 2002-2014 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
|
||||
int do_chdir(lua_State* L, const char* path)
|
||||
{
|
||||
int z;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t wide_buffer[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_buffer, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode path");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
z = SetCurrentDirectoryW(wide_buffer);
|
||||
#else
|
||||
(void)(L); /* warning: unused parameter */
|
||||
|
||||
z = !chdir(path);
|
||||
#endif
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int os_chdir(lua_State* L)
|
||||
{
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
|
||||
int z = do_chdir(L, path);
|
||||
if (!z)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unable to switch to directory '%s'", path);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* \file os_chmod.c
|
||||
* \brief Change file permissions
|
||||
* \author Copyright (c) 2014 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
int os_chmod(lua_State* L)
|
||||
{
|
||||
int rv;
|
||||
char* endPtr;
|
||||
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
const char* modeStr = luaL_checkstring(L, 2);
|
||||
|
||||
int mode = (int)strtol(modeStr, &endPtr, 8);
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
/* DOS-mode permissions only support the low word */
|
||||
mode = mode & 0x0000ffff;
|
||||
rv = _chmod(path, mode);
|
||||
#else
|
||||
rv = chmod(path, mode);
|
||||
#endif
|
||||
|
||||
if (rv != 0)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unable to set mode %o on '%s', errno %d : %s", mode, path, errno, strerror(errno));
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* \file os_comparefiles.c
|
||||
* \brief Check if two files are identical.
|
||||
* \author Copyright (c) 2015 Jérôme "Lynix" Leclercq and the Premake project
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "premake.h"
|
||||
|
||||
int os_comparefiles(lua_State* L)
|
||||
{
|
||||
FILE* firstFile;
|
||||
FILE* secondFile;
|
||||
size_t firstSize;
|
||||
size_t secondSize;
|
||||
size_t count;
|
||||
size_t read;
|
||||
char firstBuffer[4096];
|
||||
char secondBuffer[4096];
|
||||
const char* firstPath = luaL_checkstring(L, 1);
|
||||
const char* secondPath = luaL_checkstring(L, 2);
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t wide_firstPath[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, firstPath, -1, wide_firstPath, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "unable to encode first path");
|
||||
return 2;
|
||||
}
|
||||
|
||||
wchar_t wide_secondPath[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, secondPath, -1, wide_secondPath, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "unable to encode second path");
|
||||
return 2;
|
||||
}
|
||||
|
||||
firstFile = _wfopen(wide_firstPath, L"rb");
|
||||
secondFile = _wfopen(wide_secondPath, L"rb");
|
||||
#else
|
||||
firstFile = fopen(firstPath, "rb");
|
||||
secondFile = fopen(secondPath, "rb");
|
||||
#endif
|
||||
|
||||
if (!firstFile)
|
||||
{
|
||||
if (secondFile)
|
||||
fclose(secondFile);
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "failed to open first file");
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
if (!secondFile)
|
||||
{
|
||||
fclose(firstFile);
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "failed to open second file");
|
||||
return 2;
|
||||
}
|
||||
|
||||
// check sizes.
|
||||
fseek(firstFile, 0, SEEK_END);
|
||||
firstSize = ftell(firstFile);
|
||||
fseek(firstFile, 0, SEEK_SET);
|
||||
|
||||
fseek(secondFile, 0, SEEK_END);
|
||||
secondSize = ftell(secondFile);
|
||||
fseek(secondFile, 0, SEEK_SET);
|
||||
|
||||
if (firstSize != secondSize)
|
||||
{
|
||||
fclose(firstFile);
|
||||
fclose(secondFile);
|
||||
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// compare file content
|
||||
while (firstSize > 0)
|
||||
{
|
||||
count = firstSize > 4096 ? 4096 : firstSize;
|
||||
|
||||
read = fread(firstBuffer, 1, count, firstFile);
|
||||
if (read != count)
|
||||
{
|
||||
fclose(firstFile);
|
||||
fclose(secondFile);
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "failed to read first file content");
|
||||
return 2;
|
||||
}
|
||||
|
||||
read = fread(secondBuffer, 1, count, secondFile);
|
||||
if (read != count)
|
||||
{
|
||||
fclose(firstFile);
|
||||
fclose(secondFile);
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushstring(L, "failed to read second file content");
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (memcmp(firstBuffer, secondBuffer, count) != 0)
|
||||
{
|
||||
fclose(firstFile);
|
||||
fclose(secondFile);
|
||||
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
firstSize -= count;
|
||||
}
|
||||
|
||||
// File content match
|
||||
fclose(firstFile);
|
||||
fclose(secondFile);
|
||||
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* \file os_compile.c
|
||||
* \brief Compile lua source.
|
||||
* \author Copyright (c) 2002-2012 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include "lundump.h"
|
||||
#include "lstate.h"
|
||||
|
||||
extern int original_luaL_loadfilex(lua_State* L, const char* filename, const char* mode);
|
||||
|
||||
static int writer(lua_State* L, const void* p, size_t size, void* u)
|
||||
{
|
||||
UNUSED(L);
|
||||
return (fwrite(p, size, 1, (FILE*)u) != 1) && (size != 0);
|
||||
}
|
||||
|
||||
int os_compile(lua_State* L)
|
||||
{
|
||||
const char* input = luaL_checkstring(L, 1);
|
||||
const char* output = luaL_checkstring(L, 2);
|
||||
lua_State* P = luaL_newstate();
|
||||
|
||||
if (original_luaL_loadfilex(P, input, NULL) != LUA_OK)
|
||||
{
|
||||
const char* msg = lua_tostring(P, -1);
|
||||
if (msg == NULL)
|
||||
msg = "(error with no message)";
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "Unable to compile '%s': %s", input, msg);
|
||||
|
||||
lua_close(P);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
FILE* outputFile = (output == NULL) ? stdout : fopen(output, "wb");
|
||||
if (outputFile == NULL)
|
||||
{
|
||||
lua_close(P);
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unable to write to '%s'", output);
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_dump(P, writer, outputFile, FALSE);
|
||||
fclose(outputFile);
|
||||
|
||||
lua_close(P);
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* \file os_copyfile.c
|
||||
* \brief Copy a file from one location to another.
|
||||
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "premake.h"
|
||||
|
||||
int os_copyfile(lua_State* L)
|
||||
{
|
||||
int z;
|
||||
const char* src = luaL_checkstring(L, 1);
|
||||
const char* dst = luaL_checkstring(L, 2);
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t wide_src[PATH_MAX];
|
||||
wchar_t wide_dst[PATH_MAX];
|
||||
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, src, -1, wide_src, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode source path");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, dst, -1, wide_dst, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode source path");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
z = CopyFileW(wide_src, wide_dst, FALSE);
|
||||
#else
|
||||
lua_pushfstring(L, "cp \"%s\" \"%s\"", src, dst);
|
||||
z = (system(lua_tostring(L, -1)) == 0);
|
||||
#endif
|
||||
|
||||
if (!z)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t buf[256];
|
||||
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, NULL);
|
||||
|
||||
char bufA[256];
|
||||
WideCharToMultiByte(CP_UTF8, 0, buf, 256, bufA, 256, 0, 0);
|
||||
|
||||
lua_pushfstring(L, "unable to copy file to '%s', reason: '%s'", dst, bufA);
|
||||
#else
|
||||
lua_pushfstring(L, "unable to copy file to '%s'", dst);
|
||||
#endif
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/**
|
||||
* \file os_reg.c
|
||||
* \brief Returns true if the given file exists on the file system.
|
||||
* \author Copyright (c) 2002-2016 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
typedef struct RegKeyInfo
|
||||
{
|
||||
HKEY key;
|
||||
HKEY subkey;
|
||||
char * value;
|
||||
} RegKeyInfo;
|
||||
|
||||
HKEY getRegistryKey(const char **path)
|
||||
{
|
||||
if (_strnicmp(*path, "HKCU:", 5) == 0) {
|
||||
*path += 5;
|
||||
return HKEY_CURRENT_USER;
|
||||
}
|
||||
if (_strnicmp(*path, "HKLM:", 5) == 0) {
|
||||
*path += 5;
|
||||
return HKEY_LOCAL_MACHINE;
|
||||
}
|
||||
if (_strnicmp(*path, "HKCR:", 5) == 0) {
|
||||
*path += 5;
|
||||
return HKEY_CLASSES_ROOT;
|
||||
}
|
||||
if (_strnicmp(*path, "HKU:", 4) == 0) {
|
||||
*path += 4;
|
||||
return HKEY_USERS;
|
||||
}
|
||||
if (_strnicmp(*path, "HKCC:", 5) == 0) {
|
||||
*path += 5;
|
||||
return HKEY_CURRENT_CONFIG;
|
||||
}
|
||||
|
||||
// unsupported or invalid key prefix
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static HKEY getSubkey(HKEY key, const char **path)
|
||||
{
|
||||
HKEY subkey;
|
||||
size_t length;
|
||||
char *subpath;
|
||||
const char *value;
|
||||
char hasValue;
|
||||
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
// skip the initial path separator
|
||||
if ((*path)[0] == '\\')
|
||||
(*path)++;
|
||||
|
||||
// make a copy of the subkey path that excludes the value name (if present)
|
||||
value = strrchr(*path, '\\');
|
||||
hasValue = value ? value[1] : 0;
|
||||
if (hasValue) {
|
||||
length = (size_t)(value - *path);
|
||||
subpath = (char *)malloc(length + 1);
|
||||
strncpy(subpath, *path, length);
|
||||
subpath[length] = 0;
|
||||
}
|
||||
// no value separator means we should check the default value
|
||||
else {
|
||||
subpath = (char *)*path;
|
||||
length = strlen(subpath);
|
||||
}
|
||||
|
||||
// open the key for reading
|
||||
if (RegOpenKeyExA(key, subpath, 0, KEY_READ, &subkey) != ERROR_SUCCESS)
|
||||
subkey = NULL;
|
||||
|
||||
// free the subpath if one was allocated
|
||||
if (hasValue)
|
||||
free(subpath);
|
||||
|
||||
*path += length;
|
||||
return subkey;
|
||||
}
|
||||
|
||||
static char * getValue(HKEY key, const char * name)
|
||||
{
|
||||
DWORD length;
|
||||
char * value;
|
||||
|
||||
if (key == NULL || name == NULL)
|
||||
return NULL;
|
||||
|
||||
// skip the initial path separator
|
||||
if (name[0] == '\\')
|
||||
name++;
|
||||
|
||||
// query length of value
|
||||
if (RegQueryValueExA(key, name, NULL, NULL, NULL, &length) != ERROR_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
// allocate room for the value and fetch it
|
||||
value = (char *)malloc((size_t)length + 1);
|
||||
if (RegQueryValueExA(key, name, NULL, NULL, (LPBYTE)value, &length) != ERROR_SUCCESS) {
|
||||
free(value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
value[length] = 0;
|
||||
return value;
|
||||
}
|
||||
|
||||
static void fetchKeyInfo(struct RegKeyInfo *info, const char *path)
|
||||
{
|
||||
info->key = getRegistryKey(&path);
|
||||
info->subkey = getSubkey(info->key, &path);
|
||||
info->value = getValue(info->subkey, path);
|
||||
}
|
||||
|
||||
static void releaseKeyInfo(struct RegKeyInfo *info)
|
||||
{
|
||||
free(info->value);
|
||||
RegCloseKey(info->subkey);
|
||||
}
|
||||
|
||||
int os_getWindowsRegistry(lua_State *L)
|
||||
{
|
||||
RegKeyInfo info;
|
||||
fetchKeyInfo(&info, luaL_checkstring(L, 1));
|
||||
lua_pushstring(L, info.value);
|
||||
releaseKeyInfo(&info);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int os_getWindowsRegistry(lua_State *L)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* \file os_getcwd.c
|
||||
* \brief Retrieve the current working directory.
|
||||
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
int os_getcwd(lua_State* L)
|
||||
{
|
||||
char buffer[0x4000];
|
||||
if (do_getcwd(buffer, 0x4000)) {
|
||||
lua_pushstring(L, buffer);
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int do_getcwd(char* buffer, size_t size)
|
||||
{
|
||||
int result;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t wbuffer[PATH_MAX];
|
||||
|
||||
result = (GetCurrentDirectoryW(PATH_MAX, wbuffer) != 0);
|
||||
if (result) {
|
||||
WideCharToMultiByte(CP_UTF8, 0, wbuffer, -1, buffer, (int)size, NULL, NULL);
|
||||
|
||||
do_translate(buffer, '/');
|
||||
}
|
||||
#else
|
||||
result = (getcwd(buffer, size) != 0);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* \file os_getpass.c
|
||||
* \brief Prompt and retrieve a password from the user.
|
||||
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
|
||||
int os_getpass(lua_State* L)
|
||||
{
|
||||
const char* prompt = luaL_checkstring(L, 1);
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
HANDLE hstdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
HANDLE hstdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
DWORD read_chars, mode, written_chars;
|
||||
char buffer[1024];
|
||||
const char* newline = "\n";
|
||||
|
||||
WriteConsoleA(hstdout, prompt, (DWORD)strlen(prompt), &written_chars, NULL);
|
||||
|
||||
GetConsoleMode(hstdin, &mode);
|
||||
SetConsoleMode(hstdin, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
|
||||
ReadConsoleA(hstdin, buffer, sizeof (buffer), &read_chars, NULL);
|
||||
SetConsoleMode(hstdin, mode);
|
||||
|
||||
WriteConsoleA(hstdout, newline, (DWORD)strlen(newline), &written_chars, NULL);
|
||||
|
||||
buffer[strcspn(buffer, "\r\n")] = '\0';
|
||||
|
||||
lua_pushstring(L, buffer);
|
||||
return 1;
|
||||
#else
|
||||
lua_pushstring(L, getpass(prompt));
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
/**
|
||||
* \file os_getversioninfo.c
|
||||
* \brief Retrieve operating system version information.
|
||||
* \author Copyright (c) 2011-2012 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
struct OsVersionInfo
|
||||
{
|
||||
int majorversion;
|
||||
int minorversion;
|
||||
int revision;
|
||||
const char* description;
|
||||
int isalloc;
|
||||
};
|
||||
|
||||
static int getversion(struct OsVersionInfo* info);
|
||||
|
||||
int os_getversion(lua_State* L)
|
||||
{
|
||||
struct OsVersionInfo info = {0, 0, 0, NULL, 0};
|
||||
if (!getversion(&info))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushstring(L, "majorversion");
|
||||
lua_pushnumber(L, (lua_Number)info.majorversion);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "minorversion");
|
||||
lua_pushnumber(L, (lua_Number)info.minorversion);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "revision");
|
||||
lua_pushnumber(L, (lua_Number)info.revision);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "description");
|
||||
lua_pushstring(L, info.description);
|
||||
lua_settable(L, -3);
|
||||
|
||||
if (info.isalloc) {
|
||||
free((void*)info.description);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
#if defined(PLATFORM_WINDOWS)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma comment(lib, "version.lib")
|
||||
#endif
|
||||
|
||||
int getKernelVersion(struct OsVersionInfo* info)
|
||||
{
|
||||
DWORD size = GetFileVersionInfoSizeA("kernel32.dll", NULL);
|
||||
if (size > 0)
|
||||
{
|
||||
void* data = malloc(size);
|
||||
if (GetFileVersionInfoA("kernel32.dll", 0, size, data))
|
||||
{
|
||||
void* fixedInfoPtr;
|
||||
UINT fixedInfoSize;
|
||||
if (VerQueryValueA(data, "\\", &fixedInfoPtr, &fixedInfoSize))
|
||||
{
|
||||
VS_FIXEDFILEINFO* fileInfo = (VS_FIXEDFILEINFO*)fixedInfoPtr;
|
||||
info->majorversion = HIWORD(fileInfo->dwProductVersionMS);
|
||||
info->minorversion = LOWORD(fileInfo->dwProductVersionMS);
|
||||
info->revision = HIWORD(fileInfo->dwProductVersionLS);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int getversion(struct OsVersionInfo* info)
|
||||
{
|
||||
HKEY key;
|
||||
info->description = "Windows";
|
||||
|
||||
// First get a friendly product name from the registry.
|
||||
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
char value[512];
|
||||
DWORD value_length = sizeof(value);
|
||||
DWORD type;
|
||||
RegQueryValueExA(key, "productName", NULL, &type, (LPBYTE)value, &value_length);
|
||||
RegCloseKey(key);
|
||||
if (type == REG_SZ)
|
||||
{
|
||||
info->description = strdup(value);
|
||||
info->isalloc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// See if we can get a product version number from kernel32.dll
|
||||
return getKernelVersion(info);
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
#elif defined(PLATFORM_MACOSX)
|
||||
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int getversion(struct OsVersionInfo* info)
|
||||
{
|
||||
const char * propertyListFilePath = "/System/Library/CoreServices/SystemVersion.plist";
|
||||
Boolean fallback = TRUE;
|
||||
|
||||
info->description = "Mac OS";
|
||||
info->majorversion = 10;
|
||||
|
||||
if (access (propertyListFilePath, R_OK) == 0)
|
||||
{
|
||||
CFPropertyListFormat format;
|
||||
CFErrorRef errorDescriptor = NULL;
|
||||
CFStringRef stringRef = NULL;
|
||||
CFURLRef urlRef = NULL;
|
||||
CFReadStreamRef streamRef = NULL;
|
||||
CFPropertyListRef propertyListRef = NULL;
|
||||
CFTypeID typeId = 0;
|
||||
Boolean result = FALSE;
|
||||
|
||||
stringRef = CFStringCreateWithCStringNoCopy(
|
||||
kCFAllocatorDefault,
|
||||
propertyListFilePath,
|
||||
kCFStringEncodingASCII,
|
||||
kCFAllocatorNull);
|
||||
if (stringRef == NULL)
|
||||
{
|
||||
goto getversion_macosx_cleanup;
|
||||
};
|
||||
|
||||
urlRef = CFURLCreateWithFileSystemPath(
|
||||
kCFAllocatorDefault,
|
||||
stringRef,
|
||||
kCFURLPOSIXPathStyle,
|
||||
false);
|
||||
if (urlRef == NULL)
|
||||
{
|
||||
goto getversion_macosx_cleanup;
|
||||
}
|
||||
|
||||
streamRef = CFReadStreamCreateWithFile(
|
||||
kCFAllocatorDefault,
|
||||
urlRef);
|
||||
if (streamRef == NULL)
|
||||
{
|
||||
goto getversion_macosx_cleanup;
|
||||
}
|
||||
|
||||
result = CFReadStreamOpen (streamRef);
|
||||
|
||||
if (result == FALSE)
|
||||
{
|
||||
goto getversion_macosx_cleanup;
|
||||
}
|
||||
|
||||
propertyListRef = CFPropertyListCreateWithStream(
|
||||
kCFAllocatorDefault,
|
||||
streamRef,
|
||||
0,
|
||||
kCFPropertyListImmutable,
|
||||
&format,
|
||||
&errorDescriptor);
|
||||
|
||||
CFReadStreamClose (streamRef);
|
||||
|
||||
if (!(propertyListRef && CFPropertyListIsValid(propertyListRef, format)) || errorDescriptor)
|
||||
{
|
||||
goto getversion_macosx_cleanup;
|
||||
}
|
||||
|
||||
typeId = CFGetTypeID(propertyListRef);
|
||||
if (typeId == CFDictionaryGetTypeID())
|
||||
{
|
||||
const CFDictionaryRef dictionaryRef = (const CFDictionaryRef)propertyListRef;
|
||||
char versionString[128];
|
||||
CFStringRef stringValueRef = NULL;
|
||||
if (CFDictionaryGetValueIfPresent(dictionaryRef, CFSTR("ProductVersion"), (const void **)(&stringValueRef)))
|
||||
{
|
||||
CFStringGetCString(stringValueRef, &versionString[0], (CFIndex)sizeof (versionString), kCFStringEncodingASCII);
|
||||
sscanf (versionString, "%d.%d.%d", &info->majorversion, &info->minorversion, &info->revision);
|
||||
|
||||
fallback = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
getversion_macosx_cleanup:
|
||||
|
||||
if (propertyListRef) CFRelease (propertyListRef);
|
||||
if (streamRef) CFRelease (streamRef);
|
||||
if (urlRef) CFRelease (urlRef);
|
||||
if (stringRef) CFRelease (stringRef);
|
||||
}
|
||||
|
||||
if (fallback == TRUE)
|
||||
{
|
||||
int mib[] = { CTL_KERN, KERN_OSRELEASE };
|
||||
size_t len;
|
||||
sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &len, NULL, 0);
|
||||
|
||||
char kernel_version[len];
|
||||
sysctl(mib, sizeof(mib) / sizeof(mib[0]), kernel_version, &len, NULL, 0);
|
||||
|
||||
int kern_major;
|
||||
int kern_minor;
|
||||
sscanf(kernel_version, "%d.%d.%*d", &kern_major, &kern_minor);
|
||||
|
||||
info->minorversion = kern_major - 4;
|
||||
info->revision = kern_minor;
|
||||
}
|
||||
|
||||
if (info->majorversion == 10)
|
||||
{
|
||||
switch (info->minorversion)
|
||||
{
|
||||
case 4:
|
||||
info->description = "Mac OS X Tiger";
|
||||
break;
|
||||
case 5:
|
||||
info->description = "Mac OS X Leopard";
|
||||
break;
|
||||
case 6:
|
||||
info->description = "Mac OS X Snow Leopard";
|
||||
break;
|
||||
case 7:
|
||||
info->description = "OS X Lion";
|
||||
break;
|
||||
case 8:
|
||||
info->description = "OS X Mountain Lion";
|
||||
break;
|
||||
case 9:
|
||||
info->description = "OS X Mavericks";
|
||||
case 10:
|
||||
info->description = "OS X Yosemite";
|
||||
case 11:
|
||||
info->description = "OS X El Capitan";
|
||||
break;
|
||||
case 12:
|
||||
info->description = "macOS Sierra";
|
||||
break;
|
||||
case 13:
|
||||
info->description = "macOS High Sierra";
|
||||
break;
|
||||
case 14:
|
||||
info->description = "macOS Mojave";
|
||||
break;
|
||||
case 15:
|
||||
info->description = "macOS Catalina";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
#elif defined(PLATFORM_BSD) || defined(PLATFORM_LINUX) || defined(PLATFORM_SOLARIS) || defined(PLATFORM_HURD) || defined(PLATFORM_HAIKU)
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/utsname.h>
|
||||
|
||||
int getversion(struct OsVersionInfo* info)
|
||||
{
|
||||
struct utsname u;
|
||||
char* ver;
|
||||
|
||||
info->majorversion = 0;
|
||||
info->minorversion = 0;
|
||||
info->revision = 0;
|
||||
|
||||
if (uname(&u))
|
||||
{
|
||||
// error
|
||||
info->description = PLATFORM_STRING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if __GLIBC__
|
||||
// When using glibc, info->description gets set to u.sysname,
|
||||
// but it isn't passed out of this function, so we need to copy
|
||||
// the string.
|
||||
info->description = malloc(strlen(u.sysname) + 1);
|
||||
strcpy((char*)info->description, u.sysname);
|
||||
info->isalloc = 1;
|
||||
#else
|
||||
info->description = u.sysname;
|
||||
#endif
|
||||
|
||||
if ((ver = strtok(u.release, ".-")) != NULL)
|
||||
{
|
||||
info->majorversion = atoi(ver);
|
||||
// continue parsing from the previous position
|
||||
if ((ver = strtok(NULL, ".-")) != NULL)
|
||||
{
|
||||
info->minorversion = atoi(ver);
|
||||
if ((ver = strtok(NULL, ".-")) != NULL)
|
||||
info->revision = atoi(ver);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
#else
|
||||
|
||||
int getversion(struct OsVersionInfo* info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* \file os_host.c
|
||||
* \brief Get the current host OS we're executing on.
|
||||
* \author Copyright (c) 2014-2017 Tom van Dijck, Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
int os_host(lua_State* L)
|
||||
{
|
||||
lua_pushstring(L, PLATFORM_STRING);
|
||||
return 1;
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* \file os_is64bit.c
|
||||
* \brief Native code-side checking for a 64-bit architecture.
|
||||
* \author Copyright (c) 2011 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
int os_is64bit(lua_State* L)
|
||||
{
|
||||
// If this code returns true, then the platform is 64-bit. If it
|
||||
// returns false, the platform might still be 64-bit, but more
|
||||
// checking will need to be done on the Lua side of things.
|
||||
#if PLATFORM_WINDOWS
|
||||
typedef BOOL (WINAPI* WowFuncSig)(HANDLE, PBOOL);
|
||||
WowFuncSig func = (WowFuncSig)GetProcAddress(GetModuleHandle(TEXT("kernel32")), "IsWow64Process");
|
||||
if (func)
|
||||
{
|
||||
BOOL isWow = FALSE;
|
||||
if (func(GetCurrentProcess(), &isWow))
|
||||
{
|
||||
lua_pushboolean(L, isWow);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* \file os_isdir.c
|
||||
* \brief Returns true if the specified directory exists.
|
||||
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include "premake.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
int os_isdir(lua_State* L)
|
||||
{
|
||||
struct stat buf;
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
#ifdef _WIN32
|
||||
DWORD attr;
|
||||
|
||||
wchar_t wide_path[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_path, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode path");
|
||||
return lua_error(L);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* empty path is equivalent to ".", must be true */
|
||||
if (strlen(path) == 0)
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
// Use Windows-specific GetFileAttributes since it deals with symbolic links.
|
||||
else if ((attr = GetFileAttributesW(wide_path)) != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
int isdir = (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
lua_pushboolean(L, isdir);
|
||||
}
|
||||
#endif
|
||||
else if (stat(path, &buf) == 0)
|
||||
{
|
||||
int isdir = (buf.st_mode & S_IFDIR) != 0;
|
||||
lua_pushboolean(L, isdir);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushboolean(L, 0);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* \file os_isfile.c
|
||||
* \brief Returns true if the given file exists on the file system.
|
||||
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include "premake.h"
|
||||
|
||||
|
||||
int os_isfile(lua_State* L)
|
||||
{
|
||||
const char* filename = luaL_checkstring(L, 1);
|
||||
lua_pushboolean(L, do_isfile(L, filename));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int do_isfile(lua_State* L, const char* filename)
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t wide_path[PATH_MAX];
|
||||
DWORD attrib;
|
||||
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, wide_path, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode filepath");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
attrib = GetFileAttributesW(wide_path);
|
||||
if (attrib != INVALID_FILE_ATTRIBUTES)
|
||||
{
|
||||
return (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
#else
|
||||
struct stat buf;
|
||||
|
||||
(void)(L); /* warning: unused parameter */
|
||||
|
||||
if (stat(filename, &buf) == 0)
|
||||
{
|
||||
return ((buf.st_mode & S_IFDIR) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* \file os_islink.c
|
||||
* \brief Returns true if the given path is a symbolic link or reparse point.
|
||||
* \author Copyright (c) 2014 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include "premake.h"
|
||||
|
||||
|
||||
int os_islink(lua_State* L)
|
||||
{
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
{
|
||||
wchar_t wide_path[PATH_MAX];
|
||||
DWORD attr;
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_path, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode path");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
attr = GetFileAttributesW(wide_path);
|
||||
if (attr != INVALID_FILE_ATTRIBUTES) {
|
||||
lua_pushboolean(L, (attr & FILE_ATTRIBUTE_REPARSE_POINT) != 0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
{
|
||||
struct stat buf;
|
||||
if (lstat(path, &buf) == 0) {
|
||||
lua_pushboolean(L, S_ISLNK(buf.st_mode));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
lua_pushboolean(L, 0);
|
||||
return 1;
|
||||
}
|
||||
+252
@@ -0,0 +1,252 @@
|
||||
/**
|
||||
* \file os_reg.c
|
||||
* \brief Returns true if the given file exists on the file system.
|
||||
* \author Copyright (c) 2002-2016 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
typedef struct RegNodeInfo
|
||||
{
|
||||
const char * name;
|
||||
const char * value;
|
||||
DWORD valueSize;
|
||||
DWORD type;
|
||||
} RegNodeInfo;
|
||||
|
||||
typedef void (*ListCallback)(const RegNodeInfo * info, void * user);
|
||||
extern HKEY getRegistryKey(const char** path);
|
||||
|
||||
static const char* getTypeString(DWORD type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case REG_NONE: return "REG_NONE";
|
||||
case REG_SZ: return "REG_SZ";
|
||||
case REG_EXPAND_SZ: return "REG_EXPAND_SZ";
|
||||
case REG_BINARY: return "REG_BINARY";
|
||||
case REG_DWORD: return "REG_DWORD";
|
||||
case REG_DWORD_BIG_ENDIAN: return "REG_DWORD_BIG_ENDIAN";
|
||||
case REG_LINK: return "REG_LINK";
|
||||
case REG_MULTI_SZ: return "REG_MULTI_SZ";
|
||||
case REG_RESOURCE_LIST: return "REG_RESOURCE_LIST";
|
||||
case REG_FULL_RESOURCE_DESCRIPTOR: return "REG_FULL_RESOURCE_DESCRIPTOR";
|
||||
case REG_RESOURCE_REQUIREMENTS_LIST: return "REG_RESOURCE_REQUIREMENTS_LIST";
|
||||
case REG_QWORD: return "REG_QWORD";
|
||||
default: return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static HKEY openKey(const char *path)
|
||||
{
|
||||
HKEY key, subkey;
|
||||
|
||||
// check string
|
||||
if (path == NULL)
|
||||
return NULL;
|
||||
|
||||
// get HKEY
|
||||
key = getRegistryKey(&path);
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
// skip the initial path separator
|
||||
if (path[0] == '\\')
|
||||
path++;
|
||||
|
||||
// open the key for reading
|
||||
if (RegOpenKeyExA(key, path, 0, KEY_READ, &subkey) != ERROR_SUCCESS)
|
||||
subkey = NULL;
|
||||
|
||||
return subkey;
|
||||
}
|
||||
|
||||
static int listNodes(HKEY key, ListCallback callback, void * user)
|
||||
{
|
||||
RegNodeInfo node;
|
||||
DWORD maxSubkeyLength;
|
||||
DWORD maxValueLength;
|
||||
DWORD maxNameLength;
|
||||
DWORD numSubkeys;
|
||||
DWORD numValues;
|
||||
DWORD length;
|
||||
DWORD index;
|
||||
char* name;
|
||||
char* value;
|
||||
int ok;
|
||||
|
||||
if (key == NULL || callback == NULL)
|
||||
return 0;
|
||||
|
||||
// Initialize node structure
|
||||
node.value = NULL;
|
||||
node.valueSize = 0;
|
||||
node.type = REG_NONE;
|
||||
|
||||
// Fetch info about key content
|
||||
if (RegQueryInfoKeyA(key, NULL, NULL, NULL, &numSubkeys, &maxSubkeyLength, NULL, &numValues, &maxNameLength, &maxValueLength, NULL, NULL) != ERROR_SUCCESS)
|
||||
return 0;
|
||||
|
||||
// Allocate name and value buffers
|
||||
if (maxSubkeyLength > maxNameLength)
|
||||
maxNameLength = maxSubkeyLength;
|
||||
|
||||
maxNameLength++;
|
||||
maxValueLength++;
|
||||
name = (char*)malloc((size_t)maxNameLength);
|
||||
value = (char*)malloc((size_t)maxValueLength + 1);
|
||||
|
||||
// Iterate over subkeys
|
||||
ok = 1;
|
||||
node.name = name;
|
||||
for (index = 0; index < numSubkeys; index++) {
|
||||
length = maxNameLength;
|
||||
if (RegEnumKeyExA(key, index, name, &length, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) {
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
callback(&node, user);
|
||||
}
|
||||
|
||||
// Iterate over values
|
||||
if (ok) {
|
||||
node.value = value;
|
||||
for (index = 0; index < numValues; index++) {
|
||||
length = maxNameLength;
|
||||
node.valueSize = maxValueLength;
|
||||
if (RegEnumValueA(key, index, name, &length, NULL, &node.type, (LPBYTE)value, &node.valueSize) != ERROR_SUCCESS) {
|
||||
ok = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
// Ensure proper termination of strings (two terminators for the REG_MULTI_SZ)
|
||||
value[node.valueSize] = '\0';
|
||||
value[node.valueSize + 1] = '\0';
|
||||
callback(&node, user);
|
||||
}
|
||||
}
|
||||
|
||||
// Free buffers
|
||||
free(name);
|
||||
free(value);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void listCallback(const RegNodeInfo* info, void* user)
|
||||
{
|
||||
lua_State* L = (lua_State*)user;
|
||||
const char* typeString;
|
||||
|
||||
// Insert key into the result table (keys are represented as empty tables)
|
||||
if (info->value == NULL) {
|
||||
lua_createtable(L, 0, 0);
|
||||
lua_setfield(L, -2, info->name);
|
||||
return;
|
||||
}
|
||||
|
||||
// Values are represented as tables containing "type" and "value" records
|
||||
typeString = getTypeString(info->type);
|
||||
lua_createtable(L, 0, 2);
|
||||
lua_pushstring(L, typeString ? typeString : "Unknown");
|
||||
lua_setfield(L, -2, "type");
|
||||
|
||||
switch (info->type)
|
||||
{
|
||||
// Binary encoded values -> size defined string
|
||||
case REG_NONE:
|
||||
case REG_BINARY:
|
||||
case REG_RESOURCE_LIST:
|
||||
case REG_FULL_RESOURCE_DESCRIPTOR:
|
||||
case REG_RESOURCE_REQUIREMENTS_LIST: {
|
||||
lua_pushlstring(L, info->value, info->valueSize);
|
||||
break;
|
||||
}
|
||||
|
||||
// String encoded values -> zero terminated string
|
||||
case REG_SZ:
|
||||
case REG_EXPAND_SZ:
|
||||
case REG_LINK: {
|
||||
lua_pushstring(L, info->value);
|
||||
break;
|
||||
}
|
||||
|
||||
// Numbers
|
||||
case REG_DWORD: {
|
||||
lua_pushinteger(L, *(DWORD32*)info->value);
|
||||
break;
|
||||
}
|
||||
|
||||
case REG_DWORD_BIG_ENDIAN: {
|
||||
lua_pushinteger(L, (info->value[3] << 0) | (info->value[2] << 8) | (info->value[1] << 16) | (info->value[0] << 24));
|
||||
break;
|
||||
}
|
||||
|
||||
case REG_QWORD: {
|
||||
lua_pushinteger(L, *(DWORD64*)info->value);
|
||||
break;
|
||||
}
|
||||
|
||||
// Multiple strings
|
||||
case REG_MULTI_SZ: {
|
||||
DWORD i, j, k;
|
||||
|
||||
lua_newtable(L);
|
||||
for (i = j = 0, k = 1; i < info->valueSize; i++)
|
||||
{
|
||||
if (info->value[i] != 0)
|
||||
continue;
|
||||
|
||||
if (i == j)
|
||||
break;
|
||||
|
||||
lua_pushlstring(L, &info->value[j], i - j);
|
||||
lua_rawseti(L, -2, k);
|
||||
j = i + 1;
|
||||
k++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Unknown field -> nil
|
||||
default: {
|
||||
lua_pushnil(L);
|
||||
break;
|
||||
}
|
||||
}
|
||||
lua_setfield(L, -2, "value");
|
||||
|
||||
// Complete the value subtable
|
||||
lua_setfield(L, -2, info->name);
|
||||
}
|
||||
|
||||
int os_listWindowsRegistry(lua_State* L)
|
||||
{
|
||||
HKEY key = openKey(luaL_checkstring(L, 1));
|
||||
if (key == NULL) {
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_newtable(L);
|
||||
if (!listNodes(key, listCallback, (void *)L)) {
|
||||
// Discard table in case of fault and push nil instead
|
||||
lua_pop(L, 1);
|
||||
lua_pushnil(L);
|
||||
}
|
||||
|
||||
RegCloseKey(key);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int os_listWindowsRegistry(lua_State* L)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* \file os_locate.c
|
||||
* \brief Locates files along the standard built-in search paths.
|
||||
* \author Copyright (c) 2014-2015 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "premake.h"
|
||||
|
||||
|
||||
int do_locate(lua_State* L, const char* filename, const char* path)
|
||||
{
|
||||
if (do_pathsearch(L, filename, path)) {
|
||||
lua_pushstring(L, "/");
|
||||
lua_pushstring(L, filename);
|
||||
lua_concat(L, 3);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int os_locate(lua_State* L)
|
||||
{
|
||||
const char* path;
|
||||
int i;
|
||||
int nArgs = lua_gettop(L);
|
||||
|
||||
/* Fetch premake.path */
|
||||
lua_getglobal(L, "premake");
|
||||
lua_getfield(L, -1, "path");
|
||||
path = lua_tostring(L, -1);
|
||||
|
||||
for (i = 1; i <= nArgs; ++i) {
|
||||
const char* name = lua_tostring(L, i);
|
||||
|
||||
/* Direct path to an embedded file? */
|
||||
if (name[0] == '$' && name[1] == '/' && premake_find_embedded_script(name + 2)) {
|
||||
lua_pushvalue(L, i);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Direct path to file? Return as absolute path */
|
||||
if (do_isfile(L, name)) {
|
||||
lua_pushcfunction(L, path_getabsolute);
|
||||
lua_pushvalue(L, i);
|
||||
lua_call(L, 1, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* do_locate(arg[i], premake.path) */
|
||||
if (do_locate(L, name, path)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* embedded in the executable? */
|
||||
if (premake_find_embedded_script(name)) {
|
||||
lua_pushstring(L, "$/");
|
||||
lua_pushvalue(L, i);
|
||||
lua_concat(L, 2);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/**
|
||||
* \file os_match.c
|
||||
* \brief Match files and directories.
|
||||
* \author Copyright (c) 2002-2014 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "premake.h"
|
||||
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
typedef struct struct_MatchInfo
|
||||
{
|
||||
HANDLE handle;
|
||||
int is_first;
|
||||
WIN32_FIND_DATAW entry;
|
||||
} MatchInfo;
|
||||
|
||||
int os_matchstart(lua_State* L)
|
||||
{
|
||||
const char* mask = luaL_checkstring(L, 1);
|
||||
MatchInfo* m;
|
||||
|
||||
wchar_t wide_mask[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, mask, -1, wide_mask, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode mask");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
m = (MatchInfo*)malloc(sizeof(MatchInfo));
|
||||
|
||||
m->handle = FindFirstFileW(wide_mask, &m->entry);
|
||||
m->is_first = 1;
|
||||
lua_pushlightuserdata(L, m);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int os_matchdone(lua_State* L)
|
||||
{
|
||||
MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
|
||||
if (m->handle != INVALID_HANDLE_VALUE)
|
||||
FindClose(m->handle);
|
||||
free(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_matchname(lua_State* L)
|
||||
{
|
||||
MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
|
||||
|
||||
char filename[PATH_MAX];
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, m->entry.cFileName, -1, filename, PATH_MAX, NULL, NULL) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to decode filename");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
lua_pushstring(L, filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int os_matchisfile(lua_State* L)
|
||||
{
|
||||
MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
|
||||
lua_pushboolean(L, (m->entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int os_matchnext(lua_State* L)
|
||||
{
|
||||
MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
|
||||
if (m->handle == INVALID_HANDLE_VALUE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (m) /* loop forever */
|
||||
{
|
||||
if (m->is_first)
|
||||
m->is_first = 0;
|
||||
else
|
||||
{
|
||||
if (!FindNextFileW(m->handle, &m->entry))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (wcscmp(m->entry.cFileName, L".") != 0 && wcscmp(m->entry.cFileName, L"..") != 0)
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <dirent.h>
|
||||
#include <fnmatch.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
typedef struct struct_MatchInfo
|
||||
{
|
||||
DIR* handle;
|
||||
struct dirent* entry;
|
||||
char* path;
|
||||
char* mask;
|
||||
} MatchInfo;
|
||||
|
||||
int os_matchstart(lua_State* L)
|
||||
{
|
||||
const char* split;
|
||||
const char* mask = luaL_checkstring(L, 1);
|
||||
MatchInfo* m = (MatchInfo*)malloc(sizeof(MatchInfo));
|
||||
|
||||
/* split the mask into path and filename components */
|
||||
split = strrchr(mask, '/');
|
||||
if (split)
|
||||
{
|
||||
m->path = (char*)malloc(split - mask + 1);
|
||||
strncpy(m->path, mask, split - mask);
|
||||
m->path[split - mask] = '\0';
|
||||
m->mask = (char*)malloc(mask + strlen(mask) - split);
|
||||
strcpy(m->mask, split + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m->path = (char*)malloc(2);
|
||||
strcpy(m->path, ".");
|
||||
m->mask = (char*)malloc(strlen(mask)+1);
|
||||
strcpy(m->mask, mask);
|
||||
}
|
||||
|
||||
m->handle = opendir(m->path);
|
||||
lua_pushlightuserdata(L, m);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int os_matchdone(lua_State* L)
|
||||
{
|
||||
MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
|
||||
if (m->handle != NULL)
|
||||
closedir(m->handle);
|
||||
free(m->path);
|
||||
free(m->mask);
|
||||
free(m);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_matchname(lua_State* L)
|
||||
{
|
||||
MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
|
||||
lua_pushstring(L, m->entry->d_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int os_matchisfile(lua_State* L)
|
||||
{
|
||||
MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
|
||||
#if defined(_DIRENT_HAVE_D_TYPE)
|
||||
// Dirent marks symlinks as DT_LNK, not (DT_LNK|DT_DIR). The fallback handles symlinks using stat.
|
||||
if (m->entry->d_type == DT_DIR)
|
||||
{
|
||||
lua_pushboolean(L, 0);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
const char* fname;
|
||||
lua_pushfstring(L, "%s/%s", m->path, m->entry->d_name);
|
||||
fname = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_pushboolean(L, do_isfile(L, fname));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int os_matchnext(lua_State* L)
|
||||
{
|
||||
MatchInfo* m = (MatchInfo*)lua_touserdata(L, 1);
|
||||
if (m->handle == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
m->entry = readdir(m->handle);
|
||||
while (m->entry != NULL)
|
||||
{
|
||||
const char* name = m->entry->d_name;
|
||||
if (strcmp(name, ".") != 0 && strcmp(name, "..") != 0)
|
||||
{
|
||||
if (fnmatch(m->mask, name, 0) == 0)
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
m->entry = readdir(m->handle);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* \file os_mkdir.c
|
||||
* \brief Create a subdirectory.
|
||||
* \author Copyright (c) 2002-2008 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include <direct.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
int do_mkdir(const char* path)
|
||||
{
|
||||
struct stat sb;
|
||||
char sub_path[1024];
|
||||
int i, length;
|
||||
|
||||
// if it already exists, return.
|
||||
if (stat(path, &sb) == 0)
|
||||
return 1;
|
||||
|
||||
// find the parent folder name.
|
||||
length = (int)strlen(path);
|
||||
for (i = length - 1; i >= 0; --i)
|
||||
{
|
||||
if (path[i] == '/' || path[i] == '\\')
|
||||
break;
|
||||
}
|
||||
|
||||
// if we found one, create it.
|
||||
if (i > 0)
|
||||
{
|
||||
memcpy(sub_path, path, i);
|
||||
sub_path[i] = '\0';
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
if (sub_path[i - 1] == ':')
|
||||
{
|
||||
sub_path[i + 0] = '/';
|
||||
sub_path[i + 1] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!do_mkdir(sub_path))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// now finally create the actual folder we want.
|
||||
#if PLATFORM_WINDOWS
|
||||
return _mkdir(path) == 0;
|
||||
#else
|
||||
return mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int os_mkdir(lua_State* L)
|
||||
{
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
|
||||
int z = do_mkdir(path);
|
||||
if (!z)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unable to create directory '%s'", path);
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* \file os_pathsearch.c
|
||||
* \brief Locates a file, given a set of search paths.
|
||||
* \author Copyright (c) 2002-2015 Jason Perkins and the Premake project
|
||||
*
|
||||
* \note This function is required by the bootstrapping code; it must be
|
||||
* implemented here in the host and not scripted.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "premake.h"
|
||||
|
||||
|
||||
int do_pathsearch(lua_State* L, const char* filename, const char* path)
|
||||
{
|
||||
do
|
||||
{
|
||||
const char* split;
|
||||
|
||||
/* look for the closest path separator ; or : */
|
||||
/* can't use : on windows because it breaks on C:\path */
|
||||
const char* semi = strchr(path, ';');
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
const char* full = strchr(path, ':');
|
||||
#else
|
||||
const char* full = NULL;
|
||||
#endif
|
||||
|
||||
if (!semi)
|
||||
{
|
||||
split = full;
|
||||
}
|
||||
else if (!full)
|
||||
{
|
||||
split = semi;
|
||||
}
|
||||
else
|
||||
{
|
||||
split = (semi < full) ? semi : full;
|
||||
}
|
||||
|
||||
/* push this piece of the full search string onto the stack */
|
||||
if (split)
|
||||
{
|
||||
lua_pushlstring(L, path, split - path);
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushstring(L, path);
|
||||
}
|
||||
|
||||
/* keep an extra copy around, so I can return it if I have a match */
|
||||
lua_pushvalue(L, -1);
|
||||
|
||||
/* append the filename to make the full test path */
|
||||
lua_pushstring(L, "/");
|
||||
lua_pushstring(L, filename);
|
||||
lua_concat(L, 3);
|
||||
|
||||
/* test it - if it exists, return the absolute path */
|
||||
if (do_isfile(L, lua_tostring(L, -1)))
|
||||
{
|
||||
lua_pop(L, 1);
|
||||
lua_pushcfunction(L, path_getabsolute);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_call(L, 1, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* no match, set up the next try */
|
||||
lua_pop(L, 2);
|
||||
path = (split) ? split + 1 : NULL;
|
||||
}
|
||||
while (path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int os_pathsearch(lua_State* L)
|
||||
{
|
||||
int i;
|
||||
|
||||
const char* filename = luaL_checkstring(L, 1);
|
||||
for (i = 2; i <= lua_gettop(L); ++i)
|
||||
{
|
||||
if (lua_isnil(L, i)) continue;
|
||||
if (do_pathsearch(L, filename, luaL_checkstring(L, i))) return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* \file os_realpath.c
|
||||
* \brief Return the canonical absolute version of a given path.
|
||||
* \author Copyright (c) 2014 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
int os_realpath(lua_State* L)
|
||||
{
|
||||
char result[PATH_MAX];
|
||||
int ok;
|
||||
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
|
||||
#if PLATFORM_POSIX
|
||||
ok = (realpath(path, result) != NULL);
|
||||
#elif PLATFORM_WINDOWS
|
||||
ok = (_fullpath(result, path, PATH_MAX) != NULL);
|
||||
#else
|
||||
do_getabsolute(result, path, NULL);
|
||||
ok = 1;
|
||||
#endif
|
||||
|
||||
if (!ok) {
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unable to fetch real path of '%s', errno %d : %s", path, errno, strerror(errno));
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_pushstring(L, result);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* \file os_remove.c
|
||||
* \brief Remove a file on Windows.
|
||||
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
int os_remove(lua_State* L)
|
||||
{
|
||||
const char* filename = luaL_checkstring(L, 1);
|
||||
|
||||
wchar_t wide_path[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, wide_path, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode path");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
if (DeleteFileW(wide_path))
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
|
||||
char unicodeErr[512];
|
||||
|
||||
LPWSTR messageBuffer = NULL;
|
||||
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) &messageBuffer, 0, NULL) != 0)
|
||||
{
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, messageBuffer, -1, unicodeErr, sizeof(unicodeErr), NULL, NULL) == 0)
|
||||
strcpy(unicodeErr, "failed to translate error message");
|
||||
|
||||
LocalFree(messageBuffer);
|
||||
}
|
||||
else
|
||||
strcpy(unicodeErr, "failed to get error message");
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "%s: %s", filename, unicodeErr);
|
||||
lua_pushinteger(L, err);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* \file os_rename.c
|
||||
* \brief Rename a path on Windows.
|
||||
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
int os_rename(lua_State* L)
|
||||
{
|
||||
const char *fromname = luaL_checkstring(L, 1);
|
||||
const char *toname = luaL_checkstring(L, 2);
|
||||
|
||||
wchar_t wide_frompath[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, fromname, -1, wide_frompath, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode source path");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
wchar_t wide_topath[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, toname, -1, wide_topath, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode dest path");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
if (MoveFileExW(wide_frompath, wide_topath, MOVEFILE_COPY_ALLOWED))
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
DWORD err = GetLastError();
|
||||
|
||||
char unicodeErr[512];
|
||||
|
||||
LPWSTR messageBuffer = NULL;
|
||||
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR) &messageBuffer, 0, NULL) != 0)
|
||||
{
|
||||
if (WideCharToMultiByte(CP_UTF8, 0, messageBuffer, -1, unicodeErr, sizeof(unicodeErr), NULL, NULL) == 0)
|
||||
strcpy(unicodeErr, "failed to translate error message");
|
||||
|
||||
LocalFree(messageBuffer);
|
||||
}
|
||||
else
|
||||
strcpy(unicodeErr, "failed to get error message");
|
||||
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "%s: %s", fromname, unicodeErr);
|
||||
lua_pushinteger(L, err);
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* \file os_rmdir.c
|
||||
* \brief Remove a subdirectory.
|
||||
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "premake.h"
|
||||
|
||||
|
||||
int os_rmdir(lua_State* L)
|
||||
{
|
||||
int z;
|
||||
const char* path = luaL_checkstring(L, 1);
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t wide_path[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, path, -1, wide_path, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode path");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
z = RemoveDirectoryW(wide_path);
|
||||
#else
|
||||
z = (0 == rmdir(path));
|
||||
#endif
|
||||
|
||||
if (!z)
|
||||
{
|
||||
lua_pushnil(L);
|
||||
lua_pushfstring(L, "unable to remove directory '%s'", path);
|
||||
return 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushboolean(L, 1);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* \file os_stat.c
|
||||
* \brief Retrieve information about a file.
|
||||
* \author Copyright (c) 2011 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
int os_stat(lua_State* L)
|
||||
{
|
||||
const char* filename = luaL_checkstring(L, 1);
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
struct _stat s;
|
||||
|
||||
wchar_t wide_filename[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, filename, -1, wide_filename, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushstring(L, "unable to encode source path");
|
||||
return lua_error(L);
|
||||
}
|
||||
|
||||
if (_wstat(wide_filename, &s) != 0)
|
||||
#else
|
||||
struct stat s;
|
||||
|
||||
if (stat(filename, &s) != 0)
|
||||
#endif
|
||||
{
|
||||
lua_pushnil(L);
|
||||
switch (errno)
|
||||
{
|
||||
case EACCES:
|
||||
lua_pushfstring(L, "'%s' could not be accessed", filename);
|
||||
break;
|
||||
case ENOENT:
|
||||
lua_pushfstring(L, "'%s' was not found", filename);
|
||||
break;
|
||||
default:
|
||||
lua_pushfstring(L, "An unknown error %d occured while accessing '%s'", errno, filename);
|
||||
break;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
lua_pushstring(L, "mtime");
|
||||
lua_pushinteger(L, (lua_Integer)s.st_mtime);
|
||||
lua_settable(L, -3);
|
||||
|
||||
lua_pushstring(L, "size");
|
||||
lua_pushnumber(L, (lua_Number)s.st_size);
|
||||
lua_settable(L, -3);
|
||||
|
||||
return 1;
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
/**
|
||||
* \file os_touchfile.c
|
||||
* \brief markes a file as modified without changing its contents.
|
||||
* \author Blizzard Entertainment (contact tvandijck@blizzard.com)
|
||||
* \author Copyright (c) 2015 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "premake.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
static int truncate_file(const char* fn)
|
||||
{
|
||||
FILE* file = fopen(fn, "rb");
|
||||
size_t size;
|
||||
file = fopen(fn, "ab");
|
||||
if (file == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
fseek(file, 0, SEEK_END);
|
||||
size = ftell(file);
|
||||
// append a dummy space. There are better ways to do
|
||||
// a touch, however this is a rather simple
|
||||
// multiplatform method
|
||||
if (fwrite(" ", 1, 1, file) != 1)
|
||||
{
|
||||
fclose(file);
|
||||
return FALSE;
|
||||
}
|
||||
#if PLATFORM_WINDOWS
|
||||
if (_chsize(_fileno(file), (long)size) != 0)
|
||||
{
|
||||
fclose(file);
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
fclose(file);
|
||||
#if !PLATFORM_WINDOWS
|
||||
if (truncate(fn, (off_t)size) != 0)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int os_touchfile(lua_State* L)
|
||||
{
|
||||
FILE* file;
|
||||
const char* dst = luaL_checkstring(L, 1);
|
||||
|
||||
// if destination exist, mark the file as modified
|
||||
if (do_isfile(L, dst))
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
SYSTEMTIME systemTime;
|
||||
FILETIME fileTime;
|
||||
HANDLE fileHandle;
|
||||
wchar_t wide_path[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, dst, -1, wide_path, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushinteger(L, -1);
|
||||
lua_pushstring(L, "unable to encode path");
|
||||
return 2;
|
||||
}
|
||||
|
||||
fileHandle = CreateFileW(wide_path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (fileHandle == NULL)
|
||||
{
|
||||
lua_pushinteger(L, -1);
|
||||
lua_pushfstring(L, "unable to touch file '%s'", dst);
|
||||
return 2;
|
||||
}
|
||||
|
||||
GetSystemTime(&systemTime);
|
||||
if (SystemTimeToFileTime(&systemTime, &fileTime) == 0)
|
||||
{
|
||||
lua_pushinteger(L, -1);
|
||||
lua_pushfstring(L, "unable to touch file '%s'", dst);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (SetFileTime(fileHandle, NULL, NULL, &fileTime) == 0)
|
||||
{
|
||||
lua_pushinteger(L, -1);
|
||||
lua_pushfstring(L, "unable to touch file '%s'", dst);
|
||||
return 2;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, 0);
|
||||
return 1;
|
||||
#else
|
||||
if (truncate_file(dst))
|
||||
{
|
||||
lua_pushinteger(L, 0);
|
||||
return 1;
|
||||
} else {
|
||||
lua_pushinteger(L, -1);
|
||||
lua_pushfstring(L, "unable to touch file '%s'", dst);
|
||||
return 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t wide_path[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, dst, -1, wide_path, PATH_MAX) == 0)
|
||||
{
|
||||
lua_pushinteger(L, -1);
|
||||
lua_pushstring(L, "unable to encode path");
|
||||
return 2;
|
||||
}
|
||||
|
||||
file = _wfopen(wide_path, L"wb");
|
||||
#else
|
||||
file = fopen(dst, "wb");
|
||||
#endif
|
||||
|
||||
if (file != NULL)
|
||||
{
|
||||
fclose(file);
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, -1);
|
||||
lua_pushfstring(L, "unable to open file to '%s'", dst);
|
||||
return 2;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* \file os_uuid.c
|
||||
* \brief Create a new UUID.
|
||||
* \author Copyright (c) 2002-2012 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include <objbase.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Pull off the four lowest bytes of a value and add them to my array,
|
||||
* without the help of the determinately sized C99 data types that
|
||||
* are not yet universally supported.
|
||||
*/
|
||||
static void add(unsigned char* bytes, int offset, uint32_t value)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i)
|
||||
{
|
||||
bytes[offset++] = (unsigned char)(value & 0xff);
|
||||
value >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int os_uuid(lua_State* L)
|
||||
{
|
||||
char uuid[38];
|
||||
unsigned char bytes[16];
|
||||
|
||||
/* If a name argument is supplied, build the UUID from that. For speed we
|
||||
* are using a simple DBJ2 hashing function; if this isn't sufficient we
|
||||
* can switch to a full RFC 4122 §4.3 implementation later. */
|
||||
const char* name = luaL_optstring(L, 1, NULL);
|
||||
if (name != NULL)
|
||||
{
|
||||
add(bytes, 0, do_hash(name, 0));
|
||||
add(bytes, 4, do_hash(name, 'L'));
|
||||
add(bytes, 8, do_hash(name, 'u'));
|
||||
add(bytes, 12, do_hash(name, 'a'));
|
||||
}
|
||||
|
||||
/* If no name is supplied, try to build one properly */
|
||||
else
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
CoCreateGuid((GUID*)bytes);
|
||||
#else
|
||||
int result;
|
||||
|
||||
/* not sure how to get a UUID here, so I fake it */
|
||||
FILE* rnd = fopen("/dev/urandom", "rb");
|
||||
result = fread(bytes, 16, 1, rnd);
|
||||
fclose(rnd);
|
||||
if (!result)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
sprintf(uuid, "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
bytes[0], bytes[1], bytes[2], bytes[3],
|
||||
bytes[4], bytes[5],
|
||||
bytes[6], bytes[7],
|
||||
bytes[8], bytes[9],
|
||||
bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]);
|
||||
|
||||
lua_pushstring(L, uuid);
|
||||
return 1;
|
||||
}
|
||||
+109
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* \file os_writefile_ifnotequal.c
|
||||
* \brief Writes a file only if it differs with its current contents.
|
||||
* \author Blizzard Entertainment (contact tvandijck@blizzard.com)
|
||||
* \author Copyright (c) 2015 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "premake.h"
|
||||
|
||||
static int compare_file(const char* content, size_t length, const char* dst)
|
||||
{
|
||||
FILE* file;
|
||||
size_t size;
|
||||
size_t read;
|
||||
char buffer[4096];
|
||||
size_t num;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t wide_path[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, dst, -1, wide_path, PATH_MAX) == 0)
|
||||
return FALSE;
|
||||
|
||||
file = _wfopen(wide_path, L"rb");
|
||||
#else
|
||||
file = fopen(dst, "rb");
|
||||
#endif
|
||||
|
||||
if (file == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// check sizes.
|
||||
fseek(file, 0, SEEK_END);
|
||||
size = ftell(file);
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
if (length != size)
|
||||
{
|
||||
fclose(file);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
num = size > 4096 ? 4096 : size;
|
||||
|
||||
read = fread(buffer, 1, num, file);
|
||||
if (read != num)
|
||||
{
|
||||
fclose (file);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (memcmp(content, buffer, num) != 0)
|
||||
{
|
||||
fclose(file);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
size -= num;
|
||||
content += num;
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
int os_writefile_ifnotequal(lua_State* L)
|
||||
{
|
||||
FILE* file;
|
||||
size_t length;
|
||||
const char* content = luaL_checklstring(L, 1, &length);
|
||||
const char* dst = luaL_checkstring(L, 2);
|
||||
|
||||
// if destination exist, and they are the same, no need to copy.
|
||||
if (do_isfile(L, dst) && compare_file(content, length, dst))
|
||||
{
|
||||
lua_pushinteger(L, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t wide_path[PATH_MAX];
|
||||
if (MultiByteToWideChar(CP_UTF8, 0, dst, -1, wide_path, PATH_MAX) == 0)
|
||||
return FALSE;
|
||||
|
||||
file = _wfopen(wide_path, L"wb");
|
||||
#else
|
||||
file = fopen(dst, "wb");
|
||||
#endif
|
||||
|
||||
if (file != NULL)
|
||||
{
|
||||
fwrite(content, 1, length, file);
|
||||
fclose(file);
|
||||
|
||||
lua_pushinteger(L, 1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lua_pushinteger(L, -1);
|
||||
lua_pushfstring(L, "unable to write file to '%s'", dst);
|
||||
return 2;
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* \file path_getabsolute.c
|
||||
* \brief Returns an absolute version of a relative path.
|
||||
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
void do_getabsolute(char* result, const char* value, const char* relative_to)
|
||||
{
|
||||
int i;
|
||||
char* ch;
|
||||
char* prev;
|
||||
char buffer[0x4000] = { '\0' };
|
||||
|
||||
/* if the path is not already absolute, base it on working dir */
|
||||
if (!do_isabsolute(value)) {
|
||||
if (relative_to) {
|
||||
strcpy(buffer, relative_to);
|
||||
}
|
||||
else {
|
||||
do_getcwd(buffer, 0x4000);
|
||||
}
|
||||
strcat(buffer, "/");
|
||||
}
|
||||
|
||||
/* normalize the path */
|
||||
strcat(buffer, value);
|
||||
do_translate(buffer, '/');
|
||||
|
||||
/* process it part by part */
|
||||
result[0] = '\0';
|
||||
if (buffer[0] == '/') {
|
||||
strcat(result, "/");
|
||||
if (buffer[1] == '/') {
|
||||
strcat(result, "/");
|
||||
}
|
||||
}
|
||||
|
||||
prev = NULL;
|
||||
ch = strtok(buffer, "/");
|
||||
while (ch) {
|
||||
/* remove ".." where I can */
|
||||
if (strcmp(ch, "..") == 0 && (prev == NULL || (prev[0] != '$' && prev[0] != '%' && strcmp(prev, "..") != 0))) {
|
||||
i = (int)strlen(result) - 2;
|
||||
while (i >= 0 && result[i] != '/') {
|
||||
--i;
|
||||
}
|
||||
if (i >= 0) {
|
||||
result[i + 1] = '\0';
|
||||
}
|
||||
ch = NULL;
|
||||
}
|
||||
|
||||
/* allow everything except "." */
|
||||
else if (strcmp(ch, ".") != 0) {
|
||||
strcat(result, ch);
|
||||
strcat(result, "/");
|
||||
}
|
||||
|
||||
prev = ch;
|
||||
ch = strtok(NULL, "/");
|
||||
}
|
||||
|
||||
/* remove trailing slash */
|
||||
i = (int)strlen(result) - 1;
|
||||
if (result[i] == '/') {
|
||||
result[i] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int path_getabsolute(lua_State* L)
|
||||
{
|
||||
const char* relative_to;
|
||||
char buffer[0x4000];
|
||||
|
||||
relative_to = NULL;
|
||||
if (lua_gettop(L) > 1 && !lua_isnil(L,2)) {
|
||||
relative_to = luaL_checkstring(L, 2);
|
||||
}
|
||||
|
||||
if (lua_istable(L, 1)) {
|
||||
int i = 0;
|
||||
lua_newtable(L);
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, 1)) {
|
||||
const char* value = luaL_checkstring(L, -1);
|
||||
do_getabsolute(buffer, value, relative_to);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_pushstring(L, buffer);
|
||||
lua_rawseti(L, -3, ++i);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
const char* value = luaL_checkstring(L, 1);
|
||||
do_getabsolute(buffer, value, relative_to);
|
||||
lua_pushstring(L, buffer);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* \file path_getrelative.c
|
||||
* \brief Returns a path relative to another.
|
||||
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <string.h>
|
||||
#if PLATFORM_WINDOWS
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
|
||||
int path_getrelative(lua_State* L)
|
||||
{
|
||||
int i, last, count;
|
||||
char src[0x4000];
|
||||
char dst[0x4000];
|
||||
|
||||
const char* p1 = luaL_checkstring(L, 1);
|
||||
const char* p2 = luaL_checkstring(L, 2);
|
||||
|
||||
/* normalize the paths */
|
||||
do_normalize(L, src, p1);
|
||||
do_normalize(L, dst, p2);
|
||||
|
||||
/* same directory? */
|
||||
#if PLATFORM_WINDOWS
|
||||
if (_stricmp(src, dst) == 0) {
|
||||
#else
|
||||
if (strcmp(src, dst) == 0) {
|
||||
#endif
|
||||
lua_pushstring(L, ".");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* dollar macro? Can't tell what the real path might be, so treat
|
||||
* as absolute. This enables paths like $(SDK_ROOT)/include to
|
||||
* work as expected. */
|
||||
if (dst[0] == '$') {
|
||||
lua_pushstring(L, dst);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* find the common leading directories */
|
||||
strcat(src, "/");
|
||||
strcat(dst, "/");
|
||||
|
||||
last = -1;
|
||||
i = 0;
|
||||
#if PLATFORM_WINDOWS
|
||||
while (src[i] && dst[i] && tolower(src[i]) == tolower(dst[i])) {
|
||||
#else
|
||||
while (src[i] && dst[i] && src[i] == dst[i]) {
|
||||
#endif
|
||||
if (src[i] == '/') {
|
||||
last = i;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
/* if I end up with just the root of the filesystem, either a single
|
||||
* slash (/) or a drive letter (c:) then return the absolute path. */
|
||||
if (last <= 0 || (last == 2 && src[1] == ':')) {
|
||||
dst[strlen(dst) - 1] = '\0';
|
||||
lua_pushstring(L, dst);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Relative paths within a server can't climb outside the server root.
|
||||
* If the paths don't share server name, return the absolute path. */
|
||||
if (src[0] == '/' && src[1] == '/' && last == 1) {
|
||||
dst[strlen(dst) - 1] = '\0';
|
||||
lua_pushstring(L, dst);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* count remaining levels in src */
|
||||
count = 0;
|
||||
for (i = last + 1; src[i] != '\0'; ++i) {
|
||||
if (src[i] == '/') {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
|
||||
/* start my result by backing out that many levels */
|
||||
src[0] = '\0';
|
||||
for (i = 0; i < count; ++i) {
|
||||
strcat(src, "../");
|
||||
}
|
||||
|
||||
/* append what's left */
|
||||
strcat(src, dst + last + 1);
|
||||
|
||||
/* remove trailing slash and done */
|
||||
src[strlen(src) - 1] = '\0';
|
||||
lua_pushstring(L, src);
|
||||
return 1;
|
||||
}
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* \file path_isabsolute.c
|
||||
* \brief Determines if a path is absolute or relative.
|
||||
* \author Copyright (c) 2002-2016 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include "path_isabsolute.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#define strncasecmp _strnicmp
|
||||
#endif
|
||||
|
||||
int do_absolutetype(const char* path)
|
||||
{
|
||||
char c;
|
||||
const char* closing;
|
||||
size_t length;
|
||||
|
||||
while (path[0] == '"' || path[0] == '!')
|
||||
path++;
|
||||
if (path[0] == '/' || path[0] == '\\')
|
||||
return JOIN_ABSOLUTE;
|
||||
if (isalpha(path[0]) && path[1] == ':')
|
||||
return JOIN_ABSOLUTE;
|
||||
|
||||
// $(foo) and %(foo)
|
||||
if ((path[0] == '%' || path[0] == '$') && path[1] == '(')
|
||||
{
|
||||
char delimiter = path[0];
|
||||
closing = strchr(path + 2, ')');
|
||||
if (closing == NULL)
|
||||
return JOIN_RELATIVE;
|
||||
|
||||
path += 2;
|
||||
// special case VS macros %(filename) and %(extension) as normal text
|
||||
if (delimiter == '%')
|
||||
{
|
||||
length = closing - path;
|
||||
switch (length) {
|
||||
case 8:
|
||||
if (strncasecmp(path, "Filename)", length) == 0)
|
||||
return JOIN_RELATIVE;
|
||||
break;
|
||||
case 9:
|
||||
if (strncasecmp(path, "Extension)", length) == 0)
|
||||
return JOIN_RELATIVE;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// only alpha, digits, _ and . allowed inside $()
|
||||
while (path < closing) {
|
||||
c = *path++;
|
||||
if (!isalpha(c) && !isdigit(c) && c != '_' && c != '.')
|
||||
return JOIN_RELATIVE;
|
||||
}
|
||||
|
||||
return JOIN_ABSOLUTE;
|
||||
}
|
||||
|
||||
// $ORIGIN.
|
||||
if (path[0] == '$')
|
||||
return JOIN_ABSOLUTE;
|
||||
|
||||
// either %ORIGIN% or %{<lua code>}
|
||||
if (path[0] == '%')
|
||||
{
|
||||
if (path[1] == '{') //${foo} need to defer join until after detokenization
|
||||
{
|
||||
closing = strchr(path + 2, '}');
|
||||
if (closing != NULL)
|
||||
return JOIN_MAYBE_ABSOLUTE;
|
||||
}
|
||||
// find the second closing %
|
||||
path += 1;
|
||||
closing = strchr(path, '%');
|
||||
if (closing == NULL)
|
||||
return JOIN_RELATIVE;
|
||||
|
||||
// need at least one character between the %%
|
||||
if (path == closing)
|
||||
return JOIN_RELATIVE;
|
||||
|
||||
// only alpha, digits and _ allowed inside %..%
|
||||
while (path < closing) {
|
||||
c = *path++;
|
||||
if (!isalpha(c) && !isdigit(c) && c != '_')
|
||||
return JOIN_RELATIVE;
|
||||
}
|
||||
return JOIN_ABSOLUTE;
|
||||
}
|
||||
|
||||
return JOIN_RELATIVE;
|
||||
}
|
||||
|
||||
int do_isabsolute(const char* path)
|
||||
{
|
||||
// backwards compatibility
|
||||
return (do_absolutetype(path) == 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
int path_isabsolute(lua_State* L)
|
||||
{
|
||||
const char* path = luaL_checkstring(L, -1);
|
||||
lua_pushboolean(L, do_isabsolute(path));
|
||||
return 1;
|
||||
}
|
||||
|
||||
int path_absolutetype(lua_State* L)
|
||||
{
|
||||
const char* path = luaL_checkstring(L, -1);
|
||||
lua_pushinteger(L, do_absolutetype(path));
|
||||
return 1;
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* \file path_isabsolute.h
|
||||
* \brief Determines if a path is absolute or relative.
|
||||
* \author Copyright (c) 2002-2016 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#define JOIN_RELATIVE 0
|
||||
#define JOIN_ABSOLUTE 1
|
||||
#define JOIN_MAYBE_ABSOLUTE 2
|
||||
+191
@@ -0,0 +1,191 @@
|
||||
/**
|
||||
* \file path_join.c
|
||||
* \brief Join two or more pieces of a file system path.
|
||||
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <string.h>
|
||||
#include "path_isabsolute.h"
|
||||
|
||||
#define DEFERRED_JOIN_DELIMITER '\a'
|
||||
|
||||
char* path_join_single(char* buffer, char* ptr, const char* part, int allowDeferredJoin)
|
||||
{
|
||||
int absoluteType;
|
||||
size_t len = strlen(part);
|
||||
/* remove leading "./" */
|
||||
while (strncmp(part, "./", 2) == 0) {
|
||||
part += 2;
|
||||
len -= 2;
|
||||
}
|
||||
|
||||
/* remove trailing slashes */
|
||||
while (len > 1 && part[len - 1] == '/') {
|
||||
--len;
|
||||
}
|
||||
|
||||
/* ignore empty segments and "." */
|
||||
if (len == 0 || (len == 1 && part[0] == '.')) {
|
||||
return ptr;
|
||||
}
|
||||
|
||||
absoluteType = do_absolutetype(part);
|
||||
if (!allowDeferredJoin && absoluteType == JOIN_MAYBE_ABSOLUTE)
|
||||
absoluteType = JOIN_RELATIVE;
|
||||
|
||||
/* if I encounter an absolute path, restart my result */
|
||||
switch (absoluteType) {
|
||||
case JOIN_ABSOLUTE:
|
||||
ptr = buffer;
|
||||
break;
|
||||
case JOIN_RELATIVE:
|
||||
/* if source has a .. prefix then take off last dest path part
|
||||
note that this doesn't guarantee a normalized result as this
|
||||
code doesn't check for .. in the mid path, however .. occurring
|
||||
mid path are much more likely to occur during path joins
|
||||
and its faster if we handle here as we don't have to remove
|
||||
substrings from the middle of the string. */
|
||||
|
||||
while (ptr != buffer && len >= 2 && part[0] == '.' && part[1] == '.')
|
||||
{
|
||||
/* locate start of previous segment */
|
||||
char* start = strrchr(buffer, '/');
|
||||
if (!start) {
|
||||
start = buffer;
|
||||
}
|
||||
else {
|
||||
++start;
|
||||
}
|
||||
|
||||
/* if I hit a segment I can't trim, bail out */
|
||||
if (strcmp(start, "..") == 0 /* parent dir */
|
||||
|| strcmp(start, ".") == 0 /* current dir */
|
||||
|| strstr(start, "**") != NULL /* recursive wildcard */
|
||||
|| strchr(start, '$') != NULL) /* property expansion */
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* otherwise trim segment and the ".." sequence */
|
||||
if (start != buffer) {
|
||||
--start;
|
||||
}
|
||||
*start = '\0';
|
||||
ptr = start;
|
||||
part += 2;
|
||||
len -= 2;
|
||||
if (len > 0 && part[0] == '/') {
|
||||
++part;
|
||||
--len;
|
||||
}
|
||||
}
|
||||
|
||||
/* if the path is already started, split parts */
|
||||
if (ptr != buffer && *(ptr - 1) != '/') {
|
||||
*(ptr++) = '/';
|
||||
}
|
||||
|
||||
break;
|
||||
case JOIN_MAYBE_ABSOLUTE:
|
||||
*ptr = DEFERRED_JOIN_DELIMITER;
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
|
||||
/* append new part */
|
||||
strncpy(ptr, part, len);
|
||||
ptr += len;
|
||||
*ptr = '\0';
|
||||
return ptr;
|
||||
}
|
||||
|
||||
int path_join_internal(lua_State* L, int allowDeferredJoin)
|
||||
{
|
||||
int i;
|
||||
const char* part;
|
||||
char buffer[0x4000];
|
||||
char* ptr = buffer;
|
||||
|
||||
/* for each argument... */
|
||||
int argc = lua_gettop(L);
|
||||
for (i = 1; i <= argc; ++i) {
|
||||
/* if next argument is nil, skip it */
|
||||
if (lua_isnil(L, i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* grab the next argument */
|
||||
part = luaL_checkstring(L, i);
|
||||
ptr = path_join_single(buffer, ptr, part, allowDeferredJoin);
|
||||
}
|
||||
|
||||
lua_pushstring(L, buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int path_join(lua_State* L)
|
||||
{
|
||||
return path_join_internal(L, 0);
|
||||
}
|
||||
|
||||
|
||||
int path_deferred_join(lua_State* L)
|
||||
{
|
||||
return path_join_internal(L, 1);
|
||||
}
|
||||
|
||||
|
||||
int do_path_has_deferred_join(const char* path)
|
||||
{
|
||||
return (strchr(path, DEFERRED_JOIN_DELIMITER) != NULL);
|
||||
}
|
||||
|
||||
|
||||
int path_has_deferred_join(lua_State* L)
|
||||
{
|
||||
const char* path = luaL_checkstring(L, -1);
|
||||
lua_pushboolean(L, do_path_has_deferred_join(path));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int path_resolve_deferred_join(lua_State* L)
|
||||
{
|
||||
const char* path = luaL_checkstring(L, -1);
|
||||
char inBuffer[0x4000];
|
||||
char outBuffer[0x4000];
|
||||
char* ptr = outBuffer;
|
||||
char* nextPart;
|
||||
size_t len = strlen(path);
|
||||
int i;
|
||||
int numParts = 0;
|
||||
strncpy(inBuffer, path, len);
|
||||
inBuffer[len] = '\0';
|
||||
char *parts[0x200];
|
||||
// break up the string into parts and index the start of each part
|
||||
nextPart = strchr(inBuffer, DEFERRED_JOIN_DELIMITER);
|
||||
if (nextPart == NULL) // nothing to do
|
||||
{
|
||||
lua_pushlstring(L, inBuffer, len);
|
||||
return 1;
|
||||
}
|
||||
parts[numParts++] = inBuffer;
|
||||
while (nextPart != NULL)
|
||||
{
|
||||
*nextPart = '\0';
|
||||
nextPart++;
|
||||
parts[numParts++] = nextPart;
|
||||
nextPart = strchr(nextPart, DEFERRED_JOIN_DELIMITER);
|
||||
}
|
||||
|
||||
/* for each part... */
|
||||
for (i = 0; i < numParts; ++i) {
|
||||
nextPart = parts[i];
|
||||
ptr = path_join_single(outBuffer, ptr, nextPart, 0);
|
||||
}
|
||||
|
||||
lua_pushstring(L, outBuffer);
|
||||
return 1;
|
||||
}
|
||||
+223
@@ -0,0 +1,223 @@
|
||||
/**
|
||||
* \file path_normalize.c
|
||||
* \brief Removes any weirdness from a file system path string.
|
||||
* \author Copyright (c) 2013 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
#define IS_SEP(__c) ((__c) == '/' || (__c) == '\\')
|
||||
#define IS_QUOTE(__c) ((__c) == '\"' || (__c) == '\'')
|
||||
|
||||
#define IS_UPPER_ALPHA(__c) ((__c) >= 'A' && (__c) <= 'Z')
|
||||
#define IS_LOWER_ALPHA(__c) ((__c) >= 'a' && (__c) <= 'z')
|
||||
#define IS_ALPHA(__c) (IS_UPPER_ALPHA(__c) || IS_LOWER_ALPHA(__c))
|
||||
|
||||
#define IS_SPACE(__c) ((__c >= '\t' && __c <= '\r') || __c == ' ')
|
||||
|
||||
#define IS_WIN_ENVVAR_START(__c) (*__c == '%')
|
||||
#define IS_WIN_ENVVAR_END(__c) (*__c == '%')
|
||||
|
||||
#define IS_VS_VAR_START(__c) (*__c == '$' && __c[1] == '(')
|
||||
#define IS_VS_VAR_END(__c) (*__c == ')')
|
||||
|
||||
#define IS_UNIX_ENVVAR_START(__c) (*__c == '$' && __c[1] == '{')
|
||||
#define IS_UNIX_ENVVAR_END(__c) (*__c == '}')
|
||||
|
||||
#define IS_PREMAKE_TOKEN_START(__c) (*__c == '%' && __c[1] == '{')
|
||||
#define IS_PREMAKE_TOKEN_END(__c) (*__c == '}')
|
||||
|
||||
static void* normalize_substring(const char* srcPtr, const char* srcEnd, char* dstPtr)
|
||||
{
|
||||
#define IS_END(__p) (__p >= srcEnd || *__p == '\0')
|
||||
#define IS_SEP_OR_END(__p) (IS_END(__p) || IS_SEP(*__p))
|
||||
|
||||
// Handle Windows absolute paths
|
||||
if (IS_ALPHA(srcPtr[0]) && srcPtr[1] == ':')
|
||||
{
|
||||
*(dstPtr++) = srcPtr[0];
|
||||
*(dstPtr++) = ':';
|
||||
|
||||
srcPtr += 2;
|
||||
}
|
||||
|
||||
// Handle path starting with a sep (C:/ or /)
|
||||
if (IS_SEP(*srcPtr))
|
||||
{
|
||||
++srcPtr;
|
||||
*(dstPtr++) = '/';
|
||||
// Handle path starting with //
|
||||
if (IS_SEP(*srcPtr))
|
||||
{
|
||||
++srcPtr;
|
||||
*(dstPtr++) = '/';
|
||||
}
|
||||
}
|
||||
|
||||
const char * const dstRoot = dstPtr;
|
||||
unsigned int folderDepth = 0;
|
||||
|
||||
while (!IS_END(srcPtr))
|
||||
{
|
||||
// Skip multiple sep and "./" pattern
|
||||
while (IS_SEP(*srcPtr) || (srcPtr[0] == '.' && IS_SEP_OR_END(&srcPtr[1])))
|
||||
++srcPtr;
|
||||
|
||||
if (IS_END(srcPtr))
|
||||
break;
|
||||
|
||||
// Handle "../ pattern"
|
||||
if (srcPtr[0] == '.' && srcPtr[1] == '.' && IS_SEP_OR_END(&srcPtr[2]))
|
||||
{
|
||||
if (folderDepth > 0)
|
||||
{
|
||||
// Here dstPtr[-1] is safe as folderDepth > 0.
|
||||
while (--dstPtr != dstRoot && !IS_SEP(dstPtr[-1]));
|
||||
|
||||
--folderDepth;
|
||||
}
|
||||
else
|
||||
{
|
||||
*(dstPtr++) = '.';
|
||||
*(dstPtr++) = '.';
|
||||
*(dstPtr++) = '/';
|
||||
}
|
||||
srcPtr += 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!IS_SEP_OR_END(srcPtr))
|
||||
*(dstPtr++) = *(srcPtr++);
|
||||
|
||||
if (IS_SEP(*srcPtr))
|
||||
{
|
||||
*(dstPtr++) = '/';
|
||||
++srcPtr;
|
||||
++folderDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove trailing slash except for C:/ or / (root)
|
||||
while (dstPtr != dstRoot && IS_SEP(dstPtr[-1]))
|
||||
--dstPtr;
|
||||
|
||||
return dstPtr;
|
||||
#undef IS_END
|
||||
#undef IS_SEP_OR_END
|
||||
}
|
||||
|
||||
static int skip_tokens(const char *readPtr)
|
||||
{
|
||||
int skipped = 0;
|
||||
|
||||
#define DO_SKIP_FOR(__kind)\
|
||||
if (IS_ ## __kind ## _START(readPtr)) { \
|
||||
do \
|
||||
{ \
|
||||
skipped++; \
|
||||
} while (!IS_ ## __kind ## _END(readPtr++)); \
|
||||
} \
|
||||
// DO_SKIP_FOR
|
||||
|
||||
do
|
||||
{
|
||||
DO_SKIP_FOR(PREMAKE_TOKEN)
|
||||
DO_SKIP_FOR(WIN_ENVVAR)
|
||||
DO_SKIP_FOR(VS_VAR)
|
||||
DO_SKIP_FOR(UNIX_ENVVAR)
|
||||
|
||||
} while (IS_WIN_ENVVAR_START(readPtr) ||
|
||||
IS_VS_VAR_START(readPtr) ||
|
||||
IS_UNIX_ENVVAR_START(readPtr) ||
|
||||
IS_PREMAKE_TOKEN_START(readPtr));
|
||||
|
||||
return skipped;
|
||||
#undef DO_SKIP_FOR
|
||||
}
|
||||
|
||||
int path_normalize(lua_State* L)
|
||||
{
|
||||
const char *path = luaL_checkstring(L, 1);
|
||||
const char *readPtr = path;
|
||||
char buffer[0x4000] = { 0 };
|
||||
char *writePtr = buffer;
|
||||
const char *endPtr;
|
||||
|
||||
// skip leading white spaces
|
||||
while (IS_SPACE(*readPtr))
|
||||
++readPtr;
|
||||
|
||||
endPtr = readPtr;
|
||||
|
||||
while (*endPtr) {
|
||||
|
||||
int skipped = skip_tokens(readPtr);
|
||||
if (skipped > 0) {
|
||||
|
||||
if (readPtr != path && writePtr != buffer &&
|
||||
IS_SEP(readPtr[-1]) && !IS_SEP(writePtr[-1]))
|
||||
{
|
||||
*(writePtr++) = (readPtr[-1]);
|
||||
}
|
||||
|
||||
while (skipped-- > 0)
|
||||
*(writePtr++) = *(readPtr++);
|
||||
|
||||
endPtr = readPtr;
|
||||
}
|
||||
|
||||
// find the end of sub path
|
||||
while (*endPtr && !IS_SPACE(*endPtr) &&
|
||||
!IS_WIN_ENVVAR_START(endPtr) &&
|
||||
!IS_VS_VAR_START(endPtr) &&
|
||||
!IS_UNIX_ENVVAR_START(endPtr) &&
|
||||
!IS_PREMAKE_TOKEN_START(endPtr))
|
||||
{
|
||||
++endPtr;
|
||||
}
|
||||
|
||||
// path is surrounded with quotes
|
||||
if (readPtr != endPtr &&
|
||||
IS_QUOTE(*readPtr))
|
||||
{
|
||||
*(writePtr++) = *(readPtr++);
|
||||
}
|
||||
|
||||
writePtr = normalize_substring(readPtr, endPtr, writePtr);
|
||||
|
||||
// skip any white spaces between sub paths
|
||||
while (IS_SPACE(*endPtr))
|
||||
*(writePtr++) = *(endPtr++);
|
||||
|
||||
readPtr = endPtr;
|
||||
}
|
||||
|
||||
// skip any trailing white spaces
|
||||
while (writePtr != buffer && IS_SPACE(writePtr[-1]))
|
||||
--writePtr;
|
||||
|
||||
*writePtr = 0;
|
||||
|
||||
lua_pushstring(L, buffer);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* Call the scripted path.normalize(), to allow for overrides */
|
||||
void do_normalize(lua_State* L, char* buffer, const char* path)
|
||||
{
|
||||
int top = lua_gettop(L);
|
||||
|
||||
lua_getglobal(L, "path");
|
||||
lua_getfield(L, -1, "normalize");
|
||||
lua_pushstring(L, path);
|
||||
lua_call(L, 1, 1);
|
||||
|
||||
path = luaL_checkstring(L, -1);
|
||||
strcpy(buffer, path);
|
||||
|
||||
lua_settop(L, top);
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* \file path_translate.c
|
||||
* \brief Translates between path separators.
|
||||
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
void do_translate(char* value, const char sep)
|
||||
{
|
||||
char* ch;
|
||||
for (ch = value; *ch != '\0'; ++ch) {
|
||||
if (*ch == '/' || *ch == '\\') {
|
||||
*ch = sep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void translate(char* result, const char* value, const char sep)
|
||||
{
|
||||
strcpy(result, value);
|
||||
do_translate(result, sep);
|
||||
}
|
||||
|
||||
|
||||
int path_translate(lua_State* L)
|
||||
{
|
||||
const char* sep;
|
||||
char buffer[0x4000];
|
||||
|
||||
if (lua_gettop(L) == 1) {
|
||||
lua_getglobal(L, "path");
|
||||
lua_getfield(L, -1, "getDefaultSeparator");
|
||||
lua_call(L, 0, 1);
|
||||
sep = luaL_checkstring(L, -1);
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
else {
|
||||
sep = luaL_checkstring(L, 2);
|
||||
}
|
||||
|
||||
if (lua_istable(L, 1)) {
|
||||
int i = 0;
|
||||
lua_newtable(L);
|
||||
lua_pushnil(L);
|
||||
while (lua_next(L, 1)) {
|
||||
const char* value = luaL_checkstring(L, 4);
|
||||
translate(buffer, value, sep[0]);
|
||||
lua_pop(L, 1);
|
||||
|
||||
lua_pushstring(L, buffer);
|
||||
lua_rawseti(L, -3, ++i);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
const char* value = luaL_checkstring(L, 1);
|
||||
translate(buffer, value, sep[0]);
|
||||
lua_pushstring(L, buffer);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* \file path_wildcards.c
|
||||
* \brief Converts from a simple wildcard syntax to the corresponding Lua pattern.
|
||||
* \author Copyright (c) 2015 Tom van Dijck, Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
--Converts from a simple wildcard syntax, where * is "match any"
|
||||
-- and ** is "match recursive", to the corresponding Lua pattern.
|
||||
--
|
||||
-- @param pattern
|
||||
-- The wildcard pattern to convert.
|
||||
-- @returns
|
||||
-- The corresponding Lua pattern.
|
||||
*/
|
||||
int path_wildcards(lua_State* L)
|
||||
{
|
||||
size_t length, i;
|
||||
const char* input;
|
||||
char buffer[0x4000];
|
||||
char* output;
|
||||
|
||||
input = luaL_checklstring(L, 1, &length);
|
||||
output = buffer;
|
||||
|
||||
for (i = 0; i < length; ++i)
|
||||
{
|
||||
char c = input[i];
|
||||
switch (c)
|
||||
{
|
||||
case '+':
|
||||
case '.':
|
||||
case '-':
|
||||
case '^':
|
||||
case '$':
|
||||
case '(':
|
||||
case ')':
|
||||
case '%':
|
||||
*(output++) = '%';
|
||||
*(output++) = c;
|
||||
break;
|
||||
|
||||
case '*':
|
||||
if ((i + 1) < length && input[i + 1] == '*')
|
||||
{
|
||||
i++; // skip the next character.
|
||||
*(output++) = '.';
|
||||
*(output++) = '*';
|
||||
}
|
||||
else
|
||||
{
|
||||
*(output++) = '[';
|
||||
*(output++) = '^';
|
||||
*(output++) = '/';
|
||||
*(output++) = ']';
|
||||
*(output++) = '*';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
*(output++) = c;
|
||||
break;
|
||||
}
|
||||
|
||||
if (output >= buffer + sizeof(buffer))
|
||||
{
|
||||
lua_pushstring(L, "Wildcards expansion too big.");
|
||||
lua_error(L);
|
||||
}
|
||||
}
|
||||
|
||||
*(output++) = '\0';
|
||||
|
||||
lua_pushstring(L, buffer);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,705 @@
|
||||
/**
|
||||
* \file premake.c
|
||||
* \brief Program entry point.
|
||||
* \author Copyright (c) 2002-2017 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "premake.h"
|
||||
#include "lua_shimtable.h"
|
||||
|
||||
#if PLATFORM_MACOSX
|
||||
#include <CoreFoundation/CFBundle.h>
|
||||
#endif
|
||||
|
||||
#if PLATFORM_BSD
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#define ERROR_MESSAGE "Error: %s\n"
|
||||
|
||||
|
||||
static void build_premake_path(lua_State* L);
|
||||
static int process_arguments(lua_State* L, int argc, const char** argv);
|
||||
static int run_premake_main(lua_State* L, const char* script);
|
||||
|
||||
|
||||
/* A search path for script files */
|
||||
const char* scripts_path = NULL;
|
||||
|
||||
|
||||
/* Built-in functions */
|
||||
static const luaL_Reg criteria_functions[] = {
|
||||
{ "_compile", criteria_compile },
|
||||
{ "_delete", criteria_delete },
|
||||
{ "matches", criteria_matches },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_Reg debug_functions[] = {
|
||||
{ "prompt", debug_prompt },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_Reg path_functions[] = {
|
||||
{ "getabsolute", path_getabsolute },
|
||||
{ "getrelative", path_getrelative },
|
||||
{ "isabsolute", path_isabsolute },
|
||||
{ "join", path_join },
|
||||
{ "deferredjoin", path_deferred_join },
|
||||
{ "hasdeferredjoin", path_has_deferred_join },
|
||||
{ "resolvedeferredjoin", path_resolve_deferred_join },
|
||||
{ "normalize", path_normalize },
|
||||
{ "translate", path_translate },
|
||||
{ "wildcards", path_wildcards },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_Reg os_functions[] = {
|
||||
{ "chdir", os_chdir },
|
||||
{ "chmod", os_chmod },
|
||||
{ "comparefiles", os_comparefiles },
|
||||
{ "copyfile", os_copyfile },
|
||||
{ "_is64bit", os_is64bit },
|
||||
{ "isdir", os_isdir },
|
||||
{ "getcwd", os_getcwd },
|
||||
{ "getpass", os_getpass },
|
||||
{ "getWindowsRegistry", os_getWindowsRegistry },
|
||||
{ "listWindowsRegistry", os_listWindowsRegistry },
|
||||
{ "getversion", os_getversion },
|
||||
{ "host", os_host },
|
||||
{ "isfile", os_isfile },
|
||||
{ "islink", os_islink },
|
||||
{ "locate", os_locate },
|
||||
{ "matchdone", os_matchdone },
|
||||
{ "matchisfile", os_matchisfile },
|
||||
{ "matchname", os_matchname },
|
||||
{ "matchnext", os_matchnext },
|
||||
{ "matchstart", os_matchstart },
|
||||
{ "mkdir", os_mkdir },
|
||||
#if PLATFORM_WINDOWS
|
||||
// utf8 functions for Windows (assuming posix already handle utf8)
|
||||
{"remove", os_remove },
|
||||
{"rename", os_rename },
|
||||
#endif
|
||||
{ "pathsearch", os_pathsearch },
|
||||
{ "realpath", os_realpath },
|
||||
{ "rmdir", os_rmdir },
|
||||
{ "stat", os_stat },
|
||||
{ "uuid", os_uuid },
|
||||
{ "writefile_ifnotequal", os_writefile_ifnotequal },
|
||||
{ "touchfile", os_touchfile },
|
||||
{ "compile", os_compile },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_Reg premake_functions[] = {
|
||||
{ "getEmbeddedResource", premake_getEmbeddedResource },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_Reg string_functions[] = {
|
||||
{ "endswith", string_endswith },
|
||||
{ "hash", string_hash },
|
||||
{ "sha1", string_sha1 },
|
||||
{ "startswith", string_startswith },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_Reg buffered_functions[] = {
|
||||
{ "new", buffered_new },
|
||||
{ "write", buffered_write },
|
||||
{ "writeln", buffered_writeln },
|
||||
{ "tostring", buffered_tostring },
|
||||
{ "close", buffered_close },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
static const luaL_Reg term_functions[] = {
|
||||
{ "getTextColor", term_getTextColor },
|
||||
{ "setTextColor", term_setTextColor },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
||||
#ifdef PREMAKE_CURL
|
||||
static const luaL_Reg http_functions[] = {
|
||||
{ "get", http_get },
|
||||
{ "post", http_post },
|
||||
{ "download", http_download },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef PREMAKE_COMPRESSION
|
||||
static const luaL_Reg zip_functions[] = {
|
||||
{ "extract", zip_extract },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
static void lua_getorcreate_table(lua_State *L, const char *modname)
|
||||
{
|
||||
luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); // get _LOADED table stack = {_LOADED}
|
||||
lua_getfield(L, -1, modname); // get _LOADED[modname] stack = { _LOADED, result }
|
||||
if (!lua_istable(L, -1)) // not found? stack = { _LOADED, result }
|
||||
{
|
||||
lua_pop(L, 1); // remove previous result stack = { _LOADED }
|
||||
lua_pushglobaltable(L); // push _G onto stack stack = { _LOADED, _G }
|
||||
lua_createtable(L, 0, 0); // new table for field stack = { _LOADED, _G, result }
|
||||
lua_pushlstring(L, modname, strlen(modname)); // stack = { _LOADED, _G, result, modname }
|
||||
lua_pushvalue(L, -2); // stack = { _LOADED, _G, result, modname, result }
|
||||
lua_settable(L, -4); // _G[modname] = result stack = { _LOADED, _G, result }
|
||||
lua_remove(L, -2); // remove _G from stack stack = { _LOADED, result }
|
||||
lua_pushvalue(L, -1); // duplicate result stack = { _LOADED, result, result }
|
||||
lua_setfield(L, -3, modname); // _LOADED[modname] = result stack = { _LOADED, result }
|
||||
}
|
||||
|
||||
lua_remove(L, -2); // remove _LOADED from stack stack = { result }
|
||||
}
|
||||
|
||||
|
||||
void luaL_register(lua_State *L, const char *libname, const luaL_Reg *l)
|
||||
{
|
||||
lua_getorcreate_table(L, libname);
|
||||
luaL_setfuncs(L, l, 0);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initialize the Premake Lua environment.
|
||||
*/
|
||||
int premake_init(lua_State* L)
|
||||
{
|
||||
const char* value;
|
||||
|
||||
luaL_register(L, "premake", premake_functions);
|
||||
luaL_register(L, "criteria", criteria_functions);
|
||||
luaL_register(L, "debug", debug_functions);
|
||||
luaL_register(L, "path", path_functions);
|
||||
luaL_register(L, "os", os_functions);
|
||||
luaL_register(L, "string", string_functions);
|
||||
luaL_register(L, "buffered", buffered_functions);
|
||||
luaL_register(L, "term", term_functions);
|
||||
|
||||
#ifdef PREMAKE_CURL
|
||||
luaL_register(L, "http", http_functions);
|
||||
#endif
|
||||
|
||||
#ifdef PREMAKE_COMPRESSION
|
||||
luaL_register(L, "zip", zip_functions);
|
||||
#endif
|
||||
|
||||
lua_pushlightuserdata(L, &s_shimTable);
|
||||
lua_rawseti(L, LUA_REGISTRYINDEX, 0x5348494D); // equal to 'SHIM'
|
||||
|
||||
/* push the application metadata */
|
||||
lua_pushstring(L, LUA_COPYRIGHT);
|
||||
lua_setglobal(L, "_COPYRIGHT");
|
||||
|
||||
lua_pushstring(L, PREMAKE_VERSION);
|
||||
lua_setglobal(L, "_PREMAKE_VERSION");
|
||||
|
||||
lua_pushstring(L, PREMAKE_COPYRIGHT);
|
||||
lua_setglobal(L, "_PREMAKE_COPYRIGHT");
|
||||
|
||||
lua_pushstring(L, PREMAKE_PROJECT_URL);
|
||||
lua_setglobal(L, "_PREMAKE_URL");
|
||||
|
||||
/* set the OS platform variable */
|
||||
lua_pushstring(L, PLATFORM_STRING);
|
||||
lua_setglobal(L, "_TARGET_OS");
|
||||
|
||||
/* find the user's home directory */
|
||||
value = getenv("HOME");
|
||||
if (!value) value = getenv("USERPROFILE");
|
||||
if (!value) value = "~";
|
||||
lua_pushstring(L, value);
|
||||
lua_setglobal(L, "_USER_HOME_DIR");
|
||||
|
||||
/* publish the initial working directory */
|
||||
os_getcwd(L);
|
||||
lua_setglobal(L, "_WORKING_DIR");
|
||||
|
||||
#if !defined(PREMAKE_NO_BUILTIN_SCRIPTS)
|
||||
/* let native modules initialize themselves */
|
||||
registerModules(L);
|
||||
#endif
|
||||
|
||||
return OKAY;
|
||||
}
|
||||
|
||||
|
||||
static void setErrorColor(lua_State* L)
|
||||
{
|
||||
int errorColor = 12;
|
||||
|
||||
lua_getglobal(L, "term");
|
||||
lua_pushstring(L, "errorColor");
|
||||
lua_gettable(L, -2);
|
||||
|
||||
if (!lua_isnil(L, -1))
|
||||
errorColor = (int)luaL_checkinteger(L, -1);
|
||||
|
||||
term_doSetTextColor(errorColor);
|
||||
|
||||
lua_pop(L, 2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void printLastError(lua_State* L)
|
||||
{
|
||||
const char* message = lua_tostring(L, -1);
|
||||
int oldColor = term_doGetTextColor();
|
||||
setErrorColor(L);
|
||||
printf(ERROR_MESSAGE, message);
|
||||
term_doSetTextColor(oldColor);
|
||||
}
|
||||
|
||||
static int lua_error_handler(lua_State* L)
|
||||
{
|
||||
// in debug mode, show full traceback on all errors
|
||||
#if !defined(NDEBUG)
|
||||
lua_getglobal(L, "debug");
|
||||
lua_getfield(L, -1, "traceback");
|
||||
lua_remove(L, -2); // remove debug table
|
||||
lua_insert(L, -2); // insert traceback function before error message
|
||||
lua_pushinteger(L, 3); // push level
|
||||
lua_call(L, 2, 1); // call traceback
|
||||
#else
|
||||
(void) L;
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int premake_pcall(lua_State* L, int nargs, int nresults)
|
||||
{
|
||||
lua_pushcfunction(L, lua_error_handler);
|
||||
|
||||
int error_handler_index = lua_gettop(L) - nargs - 1;
|
||||
lua_insert(L, error_handler_index); // insert lua_error_handler before call parameters
|
||||
int result = lua_pcall(L, nargs, nresults, error_handler_index);
|
||||
lua_remove(L, error_handler_index); // remove lua_error_handler from stack
|
||||
return result;
|
||||
}
|
||||
|
||||
int premake_execute(lua_State* L, int argc, const char** argv, const char* script)
|
||||
{
|
||||
/* push the absolute path to the Premake executable */
|
||||
lua_pushcfunction(L, path_getabsolute);
|
||||
premake_locate_executable(L, argv[0]);
|
||||
lua_call(L, 1, 1);
|
||||
lua_setglobal(L, "_PREMAKE_COMMAND");
|
||||
|
||||
/* Parse the command line arguments */
|
||||
if (process_arguments(L, argc, argv) != OKAY) {
|
||||
return !OKAY;
|
||||
}
|
||||
|
||||
/* Use --scripts and PREMAKE_PATH to populate premake.path */
|
||||
build_premake_path(L);
|
||||
|
||||
/* Find and run the main Premake bootstrapping script */
|
||||
if (run_premake_main(L, script) != OKAY) {
|
||||
printLastError(L);
|
||||
return !OKAY;
|
||||
}
|
||||
|
||||
/* and call the main entry point */
|
||||
lua_getglobal(L, "_premake_main");
|
||||
if (premake_pcall(L, 0, 1) != OKAY) {
|
||||
printLastError(L);
|
||||
return !OKAY;
|
||||
}
|
||||
else {
|
||||
int exitCode = (int)lua_tonumber(L, -1);
|
||||
return exitCode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Locate the Premake executable, and push its full path to the Lua stack.
|
||||
* Based on:
|
||||
* http://sourceforge.net/tracker/index.php?func=detail&aid=3351583&group_id=71616&atid=531880
|
||||
* http://stackoverflow.com/questions/933850/how-to-find-the-location-of-the-executable-in-c
|
||||
* http://stackoverflow.com/questions/1023306/finding-current-executables-path-without-proc-self-exe
|
||||
*/
|
||||
int premake_locate_executable(lua_State* L, const char* argv0)
|
||||
{
|
||||
char buffer[PATH_MAX];
|
||||
const char* path = NULL;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
wchar_t widebuffer[PATH_MAX];
|
||||
|
||||
DWORD len = GetModuleFileNameW(NULL, widebuffer, PATH_MAX);
|
||||
if (len > 0)
|
||||
{
|
||||
WideCharToMultiByte(CP_UTF8, 0, widebuffer, len, buffer, PATH_MAX, NULL, NULL);
|
||||
|
||||
buffer[len] = 0;
|
||||
path = buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PLATFORM_MACOSX
|
||||
CFURLRef bundleURL = CFBundleCopyExecutableURL(CFBundleGetMainBundle());
|
||||
CFStringRef pathRef = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
|
||||
if (CFStringGetCString(pathRef, buffer, PATH_MAX - 1, kCFStringEncodingUTF8))
|
||||
path = buffer;
|
||||
#endif
|
||||
|
||||
#if PLATFORM_LINUX
|
||||
int len = readlink("/proc/self/exe", buffer, PATH_MAX - 1);
|
||||
if (len > 0)
|
||||
{
|
||||
buffer[len] = 0;
|
||||
path = buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PLATFORM_BSD && !defined(__OpenBSD__)
|
||||
int len = readlink("/proc/curproc/file", buffer, PATH_MAX - 1);
|
||||
if (len < 0)
|
||||
len = readlink("/proc/curproc/exe", buffer, PATH_MAX - 1);
|
||||
if (len < 0)
|
||||
{
|
||||
int mib[4];
|
||||
mib[0] = CTL_KERN;
|
||||
mib[1] = KERN_PROC;
|
||||
mib[2] = KERN_PROC_PATHNAME;
|
||||
mib[3] = -1;
|
||||
size_t cb = sizeof(buffer);
|
||||
sysctl(mib, 4, buffer, &cb, NULL, 0);
|
||||
len = (int)cb;
|
||||
}
|
||||
if (len > 0)
|
||||
{
|
||||
buffer[len] = 0;
|
||||
path = buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PLATFORM_SOLARIS
|
||||
int len = readlink("/proc/self/path/a.out", buffer, PATH_MAX - 1);
|
||||
if (len > 0)
|
||||
{
|
||||
buffer[len] = 0;
|
||||
path = buffer;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* As a fallback, search the PATH with argv[0] */
|
||||
if (!path)
|
||||
{
|
||||
lua_pushcfunction(L, os_pathsearch);
|
||||
lua_pushstring(L, argv0);
|
||||
lua_pushstring(L, getenv("PATH"));
|
||||
if (lua_pcall(L, 2, 1, 0) == OKAY && !lua_isnil(L, -1))
|
||||
{
|
||||
lua_pushstring(L, "/");
|
||||
lua_pushstring(L, argv0);
|
||||
lua_concat(L, 3);
|
||||
path = lua_tostring(L, -1);
|
||||
}
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
/* If all else fails, use argv[0] as-is and hope for the best */
|
||||
if (!path)
|
||||
{
|
||||
/* make it absolute, if needed */
|
||||
os_getcwd(L);
|
||||
lua_pushstring(L, "/");
|
||||
lua_pushstring(L, argv0);
|
||||
|
||||
if (!do_isabsolute(argv0)) {
|
||||
lua_concat(L, 3);
|
||||
}
|
||||
else {
|
||||
lua_pop(L, 3);
|
||||
lua_pushstring(L, argv0);
|
||||
}
|
||||
|
||||
path = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
lua_pushstring(L, path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Checks one or more of the standard script search locations to locate the
|
||||
* specified file. If found, returns the discovered path to the script on
|
||||
* the top of the Lua stack.
|
||||
*/
|
||||
int premake_test_file(lua_State* L, const char* filename, int searchMask)
|
||||
{
|
||||
if (searchMask & TEST_LOCAL) {
|
||||
if (do_isfile(L, filename)) {
|
||||
lua_pushcfunction(L, path_getabsolute);
|
||||
lua_pushstring(L, filename);
|
||||
lua_call(L, 1, 1);
|
||||
return OKAY;
|
||||
}
|
||||
}
|
||||
|
||||
if (scripts_path && (searchMask & TEST_SCRIPTS)) {
|
||||
if (do_locate(L, filename, scripts_path)) return OKAY;
|
||||
}
|
||||
|
||||
if (searchMask & TEST_PATH) {
|
||||
const char* path = getenv("PREMAKE_PATH");
|
||||
if (path && do_locate(L, filename, path)) return OKAY;
|
||||
}
|
||||
|
||||
#if !defined(PREMAKE_NO_BUILTIN_SCRIPTS)
|
||||
if ((searchMask & TEST_EMBEDDED) != 0) {
|
||||
/* Try to locate a record matching the filename */
|
||||
if (premake_find_embedded_script(filename) != NULL) {
|
||||
lua_pushstring(L, "$/");
|
||||
lua_pushstring(L, filename);
|
||||
lua_concat(L, 2);
|
||||
return OKAY;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return !OKAY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char* set_scripts_path(const char* relativePath)
|
||||
{
|
||||
char* path = (char*)malloc(PATH_MAX);
|
||||
do_getabsolute(path, relativePath, NULL);
|
||||
scripts_path = path;
|
||||
return scripts_path;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Set the premake.path variable, pulling from the --scripts argument
|
||||
* and PREMAKE_PATH environment variable if present.
|
||||
*/
|
||||
static void build_premake_path(lua_State* L)
|
||||
{
|
||||
int top;
|
||||
const char* value;
|
||||
|
||||
lua_getglobal(L, "premake");
|
||||
top = lua_gettop(L);
|
||||
|
||||
/* Start by searching the current working directory */
|
||||
lua_pushstring(L, ".");
|
||||
|
||||
/* The --scripts argument goes next, if present */
|
||||
if (scripts_path) {
|
||||
lua_pushstring(L, ";");
|
||||
lua_pushstring(L, scripts_path);
|
||||
}
|
||||
|
||||
/* Then the PREMAKE_PATH environment variable */
|
||||
value = getenv("PREMAKE_PATH");
|
||||
if (value) {
|
||||
lua_pushstring(L, ";");
|
||||
lua_pushstring(L, value);
|
||||
}
|
||||
|
||||
/* Then in ~/.premake */
|
||||
lua_pushstring(L, ";");
|
||||
lua_getglobal(L, "_USER_HOME_DIR");
|
||||
lua_pushstring(L, "/.premake");
|
||||
|
||||
/* In the user's Application Support folder */
|
||||
#if defined(PLATFORM_MACOSX)
|
||||
lua_pushstring(L, ";");
|
||||
lua_getglobal(L, "_USER_HOME_DIR");
|
||||
lua_pushstring(L, "/Library/Application Support/Premake");
|
||||
#endif
|
||||
|
||||
/* In the /usr tree */
|
||||
lua_pushstring(L, ";/usr/local/share/premake;/usr/share/premake");
|
||||
|
||||
/* Put it all together */
|
||||
lua_concat(L, lua_gettop(L) - top);
|
||||
|
||||
/* Match Lua's package.path; use semicolon separators */
|
||||
#if !defined(PLATFORM_WINDOWS)
|
||||
lua_getglobal(L, "string");
|
||||
lua_getfield(L, -1, "gsub");
|
||||
lua_pushvalue(L, -3);
|
||||
lua_pushstring(L, ":");
|
||||
lua_pushstring(L, ";");
|
||||
lua_call(L, 3, 1);
|
||||
/* remove the string global table */
|
||||
lua_remove(L, -2);
|
||||
/* remove the previously concatonated result */
|
||||
lua_remove(L, -2);
|
||||
#endif
|
||||
|
||||
/* Store it in premake.path */
|
||||
lua_setfield(L, -2, "path");
|
||||
|
||||
/* Remove the premake namespace table */
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Copy all command line arguments into the script-side _ARGV global, and
|
||||
* check for the presence of a /scripts=<path> argument to help locate
|
||||
* the manifest if needed.
|
||||
* \returns OKAY if successful.
|
||||
*/
|
||||
static int process_arguments(lua_State* L, int argc, const char** argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* Copy all arguments in the _ARGV global */
|
||||
lua_newtable(L);
|
||||
for (i = 1; i < argc; ++i)
|
||||
{
|
||||
lua_pushstring(L, argv[i]);
|
||||
lua_rawseti(L, -2, luaL_len(L, -2) + 1);
|
||||
|
||||
/* The /scripts option gets picked up here; used later to find the
|
||||
* manifest and scripts later if necessary */
|
||||
if (strncmp(argv[i], "/scripts=", 9) == 0)
|
||||
{
|
||||
argv[i] = set_scripts_path(argv[i] + 9);
|
||||
}
|
||||
else if (strncmp(argv[i], "--scripts=", 10) == 0)
|
||||
{
|
||||
argv[i] = set_scripts_path(argv[i] + 10);
|
||||
}
|
||||
}
|
||||
lua_setglobal(L, "_ARGV");
|
||||
|
||||
return OKAY;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Find and run the main Premake bootstrapping script. The loading of the
|
||||
* bootstrap and the other core scripts use a limited set of search paths
|
||||
* to avoid mismatches between the native host code and the scripts
|
||||
* themselves.
|
||||
*/
|
||||
static int run_premake_main(lua_State* L, const char* script)
|
||||
{
|
||||
/* Release builds want to load the embedded scripts, with --scripts
|
||||
* argument allowed as an override. Debug builds will look at the
|
||||
* local file system first, then fall back to embedded. */
|
||||
#if defined(NDEBUG)
|
||||
int z = premake_test_file(L, script,
|
||||
TEST_SCRIPTS | TEST_EMBEDDED);
|
||||
#else
|
||||
int z = premake_test_file(L, script,
|
||||
TEST_LOCAL | TEST_SCRIPTS | TEST_PATH | TEST_EMBEDDED);
|
||||
#endif
|
||||
|
||||
/* If no embedded script can be found, release builds will then
|
||||
* try to fall back to the local file system, just in case */
|
||||
#if defined(NDEBUG)
|
||||
if (z != OKAY) {
|
||||
z = premake_test_file(L, script, TEST_LOCAL | TEST_PATH);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (z == OKAY) {
|
||||
const char* filename = lua_tostring(L, -1);
|
||||
z = luaL_dofile(L, filename);
|
||||
}
|
||||
|
||||
return z;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Locate a file in the embedded script index. If found, returns the
|
||||
* contents of the file's script.
|
||||
*/
|
||||
|
||||
const buildin_mapping* premake_find_embedded_script(const char* filename)
|
||||
{
|
||||
#if !defined(PREMAKE_NO_BUILTIN_SCRIPTS)
|
||||
int i;
|
||||
for (i = 0; builtin_scripts[i].name != NULL; ++i) {
|
||||
if (strcmp(builtin_scripts[i].name, filename) == 0) {
|
||||
return builtin_scripts + i;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Load a script that was previously embedded into the executable. If
|
||||
* successful, a function containing the new script chunk is pushed to
|
||||
* the stack, just like luaL_loadfile would do had the chunk been loaded
|
||||
* from a file.
|
||||
*/
|
||||
|
||||
int premake_load_embedded_script(lua_State* L, const char* filename)
|
||||
{
|
||||
#if !defined(NDEBUG)
|
||||
static int warned = 0;
|
||||
#endif
|
||||
|
||||
const buildin_mapping* chunk = premake_find_embedded_script(filename);
|
||||
if (chunk == NULL) {
|
||||
return LUA_ERRFILE;
|
||||
}
|
||||
|
||||
/* Debug builds probably want to be loading scripts from the disk */
|
||||
#if !defined(NDEBUG)
|
||||
if (!warned) {
|
||||
warned = 1;
|
||||
printf("** warning: using embedded script '%s'; use /scripts argument to load from files\n", filename);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* "Fully qualify" the filename by turning it into the form $/filename */
|
||||
lua_pushstring(L, "$/");
|
||||
lua_pushstring(L, filename);
|
||||
lua_concat(L, 2);
|
||||
|
||||
/* Load the chunk */
|
||||
return luaL_loadbuffer(L, (const char*)chunk->bytecode, chunk->length, filename);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Give the lua runtime raw access to embedded files.
|
||||
*/
|
||||
int premake_getEmbeddedResource(lua_State* L)
|
||||
{
|
||||
const char* filename = luaL_checkstring(L, 1);
|
||||
const buildin_mapping* chunk = premake_find_embedded_script(filename);
|
||||
if (chunk == NULL)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
lua_pushlstring(L, (const char*)chunk->bytecode, chunk->length);
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,201 @@
|
||||
/**
|
||||
* \file premake.h
|
||||
* \brief Program-wide constants and definitions.
|
||||
* \author Copyright (c) 2002-2021 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#define lua_c
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PREMAKE_VERSION "5.0.0-beta1"
|
||||
#define PREMAKE_COPYRIGHT "Copyright (C) 2002-2021 Jason Perkins and the Premake Project"
|
||||
#define PREMAKE_PROJECT_URL "https://github.com/premake/premake-core/wiki"
|
||||
|
||||
/* Identify the current platform I'm not sure how to reliably detect
|
||||
* Windows but since it is the most common I use it as the default */
|
||||
#if defined(__linux__)
|
||||
#define PLATFORM_LINUX (1)
|
||||
#define PLATFORM_STRING "linux"
|
||||
#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
#define PLATFORM_BSD (1)
|
||||
#define PLATFORM_STRING "bsd"
|
||||
#elif defined(__APPLE__) && defined(__MACH__)
|
||||
#define PLATFORM_MACOSX (1)
|
||||
#define PLATFORM_STRING "macosx"
|
||||
#elif defined(__sun__) && defined(__svr4__)
|
||||
#define PLATFORM_SOLARIS (1)
|
||||
#define PLATFORM_STRING "solaris"
|
||||
#elif defined(__HAIKU__)
|
||||
#define PLATFORM_HAIKU (1)
|
||||
#define PLATFORM_STRING "haiku"
|
||||
#elif defined (_AIX)
|
||||
#define PLATFORM_AIX (1)
|
||||
#define PLATFORM_STRING "aix"
|
||||
#elif defined (__GNU__)
|
||||
#define PLATFORM_HURD (1)
|
||||
#define PLATFORM_STRING "hurd"
|
||||
#else
|
||||
#define PLATFORM_WINDOWS (1)
|
||||
#define PLATFORM_STRING "windows"
|
||||
#endif
|
||||
|
||||
#define PLATFORM_POSIX (PLATFORM_LINUX || PLATFORM_BSD || PLATFORM_MACOSX || PLATFORM_SOLARIS || PLATFORM_HAIKU)
|
||||
|
||||
|
||||
/* Pull in platform-specific headers required by built-in functions */
|
||||
#if PLATFORM_WINDOWS
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdint.h>
|
||||
|
||||
/* not all platforms define this */
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
/* Fill in any missing bits */
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX (4096)
|
||||
#endif
|
||||
|
||||
|
||||
/* A success return code */
|
||||
#define OKAY (0)
|
||||
|
||||
|
||||
/* Bitmasks for the different script file search locations */
|
||||
#define TEST_LOCAL (0x01)
|
||||
#define TEST_SCRIPTS (0x02)
|
||||
#define TEST_PATH (0x04)
|
||||
#define TEST_EMBEDDED (0x08)
|
||||
|
||||
|
||||
/* If a /scripts argument is present, its value */
|
||||
extern const char* scripts_path;
|
||||
|
||||
|
||||
/* Bootstrapping helper functions */
|
||||
int do_chdir(lua_State* L, const char* path);
|
||||
uint32_t do_hash(const char* str, int seed);
|
||||
void do_getabsolute(char* result, const char* value, const char* relative_to);
|
||||
int do_getcwd(char* buffer, size_t size);
|
||||
int do_isabsolute(const char* path);
|
||||
int do_absolutetype(const char* path);
|
||||
int do_isfile(lua_State* L, const char* filename);
|
||||
int do_locate(lua_State* L, const char* filename, const char* path);
|
||||
void do_normalize(lua_State* L, char* buffer, const char* path);
|
||||
int do_pathsearch(lua_State* L, const char* filename, const char* path);
|
||||
void do_translate(char* value, const char sep);
|
||||
|
||||
int term_doGetTextColor();
|
||||
void term_doSetTextColor(int color);
|
||||
void printLastError(lua_State* L);
|
||||
|
||||
/* Built-in functions */
|
||||
int criteria_compile(lua_State* L);
|
||||
int criteria_delete(lua_State* L);
|
||||
int criteria_matches(lua_State* L);
|
||||
int debug_prompt(lua_State* L);
|
||||
int path_getabsolute(lua_State* L);
|
||||
int path_getrelative(lua_State* L);
|
||||
int path_isabsolute(lua_State* L);
|
||||
int path_join(lua_State* L);
|
||||
int path_deferred_join(lua_State* L);
|
||||
int path_has_deferred_join(lua_State* L);
|
||||
int path_resolve_deferred_join(lua_State* L);
|
||||
int path_normalize(lua_State* L);
|
||||
int path_translate(lua_State* L);
|
||||
int path_wildcards(lua_State* L);
|
||||
int os_chdir(lua_State* L);
|
||||
int os_chmod(lua_State* L);
|
||||
int os_comparefiles(lua_State* L);
|
||||
int os_copyfile(lua_State* L);
|
||||
int os_getcwd(lua_State* L);
|
||||
int os_getpass(lua_State* L);
|
||||
int os_getWindowsRegistry(lua_State* L);
|
||||
int os_listWindowsRegistry(lua_State* L);
|
||||
int os_getversion(lua_State* L);
|
||||
int os_host(lua_State* L);
|
||||
int os_is64bit(lua_State* L);
|
||||
int os_isdir(lua_State* L);
|
||||
int os_isfile(lua_State* L);
|
||||
int os_islink(lua_State* L);
|
||||
int os_locate(lua_State* L);
|
||||
int os_matchdone(lua_State* L);
|
||||
int os_matchisfile(lua_State* L);
|
||||
int os_matchname(lua_State* L);
|
||||
int os_matchnext(lua_State* L);
|
||||
int os_matchstart(lua_State* L);
|
||||
int os_mkdir(lua_State* L);
|
||||
int os_pathsearch(lua_State* L);
|
||||
int os_realpath(lua_State* L);
|
||||
#if PLATFORM_WINDOWS
|
||||
// utf8 versions
|
||||
int os_remove(lua_State* L);
|
||||
int os_rename(lua_State* L);
|
||||
#endif
|
||||
int os_rmdir(lua_State* L);
|
||||
int os_stat(lua_State* L);
|
||||
int os_uuid(lua_State* L);
|
||||
int os_writefile_ifnotequal(lua_State* L);
|
||||
int os_touchfile(lua_State* L);
|
||||
int os_compile(lua_State* L);
|
||||
int premake_getEmbeddedResource(lua_State* L);
|
||||
int string_endswith(lua_State* L);
|
||||
int string_hash(lua_State* L);
|
||||
int string_sha1(lua_State* L);
|
||||
int string_startswith(lua_State* L);
|
||||
int buffered_new(lua_State* L);
|
||||
int buffered_write(lua_State* L);
|
||||
int buffered_writeln(lua_State* L);
|
||||
int buffered_close(lua_State* L);
|
||||
int buffered_tostring(lua_State* L);
|
||||
int term_getTextColor(lua_State* L);
|
||||
int term_setTextColor(lua_State* L);
|
||||
|
||||
#ifdef PREMAKE_CURL
|
||||
int http_get(lua_State* L);
|
||||
int http_post(lua_State* L);
|
||||
int http_download(lua_State* L);
|
||||
#endif
|
||||
|
||||
#ifdef PREMAKE_COMPRESSION
|
||||
int zip_extract(lua_State* L);
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#ifndef snprintf
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Engine interface */
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const unsigned char* bytecode;
|
||||
size_t length;
|
||||
} buildin_mapping;
|
||||
|
||||
extern const buildin_mapping builtin_scripts[];
|
||||
extern void registerModules(lua_State* L);
|
||||
|
||||
int premake_init(lua_State* L);
|
||||
int premake_pcall(lua_State* L, int nargs, int nresults);
|
||||
int premake_execute(lua_State* L, int argc, const char** argv, const char* script);
|
||||
int premake_load_embedded_script(lua_State* L, const char* filename);
|
||||
const buildin_mapping* premake_find_embedded_script(const char* filename);
|
||||
|
||||
int premake_locate_executable(lua_State* L, const char* argv0);
|
||||
int premake_test_file(lua_State* L, const char* filename, int searchMask);
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* \file premake_main.c
|
||||
* \brief Program entry point.
|
||||
* \author Copyright (c) 2002-2013 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
int main(int argc, const char** argv)
|
||||
{
|
||||
lua_State* L;
|
||||
int z;
|
||||
|
||||
L = luaL_newstate();
|
||||
luaL_openlibs(L);
|
||||
|
||||
z = premake_init(L);
|
||||
if (z == OKAY) {
|
||||
z = premake_execute(L, argc, argv, "src/_premake_main.lua");
|
||||
}
|
||||
|
||||
lua_close(L);
|
||||
return z;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by resource.rc
|
||||
//
|
||||
#define IDI_ICON1 101
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
#include "premake.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "winres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENA)
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""winres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 5,0,0
|
||||
PRODUCTVERSION 5,0,0
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904E4"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Jason Perkins and the Premake Project"
|
||||
VALUE "FileDescription", "Premake5"
|
||||
VALUE "FileVersion", PREMAKE_VERSION
|
||||
VALUE "LegalCopyright", PREMAKE_COPYRIGHT
|
||||
VALUE "OriginalFilename", "premake5.exe"
|
||||
VALUE "ProductName", "Premake5"
|
||||
VALUE "ProductVersion", PREMAKE_VERSION
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x0409, 1200
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon with lowest ID value placed first to ensure application icon
|
||||
// remains consistent on all systems.
|
||||
//IDI_ICON1 ICON ""
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* \file string_endswith.c
|
||||
* \brief Determines if a string ends with the given sequence.
|
||||
* \author Copyright (c) 2002-2009 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
int string_endswith(lua_State* L)
|
||||
{
|
||||
const char* haystack = luaL_optstring(L, 1, NULL);
|
||||
const char* needle = luaL_optstring(L, 2, NULL);
|
||||
|
||||
if (haystack && needle)
|
||||
{
|
||||
size_t hlen = strlen(haystack);
|
||||
size_t nlen = strlen(needle);
|
||||
if (hlen >= nlen)
|
||||
{
|
||||
lua_pushboolean(L, strcmp(haystack + hlen - nlen, needle) == 0);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* \file string_hash.c
|
||||
* \brief Computes a hash value for a string.
|
||||
* \author Copyright (c) 2012-2014 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
int string_hash(lua_State* L)
|
||||
{
|
||||
const char* str = luaL_checkstring(L, 1);
|
||||
int seed = (int)luaL_optinteger(L, 2, 0);
|
||||
lua_pushinteger(L, do_hash(str, seed));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
uint32_t do_hash(const char* str, int seed)
|
||||
{
|
||||
/* DJB2 hashing; see http://www.cse.yorku.ca/~oz/hash.html */
|
||||
|
||||
uint32_t hash = 5381;
|
||||
|
||||
if (seed != 0) {
|
||||
hash = hash * 33 + seed;
|
||||
}
|
||||
|
||||
while (*str) {
|
||||
hash = hash * 33 + (*str);
|
||||
str++;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "premake.h"
|
||||
|
||||
#define HASH_LENGTH 20
|
||||
#define BLOCK_LENGTH 64
|
||||
|
||||
typedef struct sha1nfo {
|
||||
uint32_t buffer[BLOCK_LENGTH / 4];
|
||||
uint32_t state[HASH_LENGTH / 4];
|
||||
uint32_t byteCount;
|
||||
uint8_t bufferOffset;
|
||||
uint8_t keyBuffer[BLOCK_LENGTH];
|
||||
uint8_t innerHash[HASH_LENGTH];
|
||||
} sha1nfo;
|
||||
|
||||
/* public API - prototypes - TODO: doxygen*/
|
||||
void sha1_init(sha1nfo *s);
|
||||
void sha1_writebyte(sha1nfo *s, uint8_t data);
|
||||
void sha1_write(sha1nfo *s, const char *data, size_t len);
|
||||
uint8_t* sha1_result(sha1nfo *s);
|
||||
|
||||
/* code */
|
||||
#define SHA1_K0 0x5a827999
|
||||
#define SHA1_K20 0x6ed9eba1
|
||||
#define SHA1_K40 0x8f1bbcdc
|
||||
#define SHA1_K60 0xca62c1d6
|
||||
|
||||
void sha1_init(sha1nfo *s)
|
||||
{
|
||||
s->state[0] = 0x67452301;
|
||||
s->state[1] = 0xefcdab89;
|
||||
s->state[2] = 0x98badcfe;
|
||||
s->state[3] = 0x10325476;
|
||||
s->state[4] = 0xc3d2e1f0;
|
||||
s->byteCount = 0;
|
||||
s->bufferOffset = 0;
|
||||
}
|
||||
|
||||
uint32_t sha1_rol32(uint32_t number, uint8_t bits)
|
||||
{
|
||||
return ((number << bits) | (number >> (32 - bits)));
|
||||
}
|
||||
|
||||
void sha1_hashBlock(sha1nfo *s)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t a, b, c, d, e, t;
|
||||
|
||||
a = s->state[0];
|
||||
b = s->state[1];
|
||||
c = s->state[2];
|
||||
d = s->state[3];
|
||||
e = s->state[4];
|
||||
for (i = 0; i < 80; i++)
|
||||
{
|
||||
if (i >= 16)
|
||||
{
|
||||
t = s->buffer[(i + 13) & 15] ^ s->buffer[(i + 8) & 15] ^ s->buffer[(i + 2) & 15] ^ s->buffer[i & 15];
|
||||
s->buffer[i & 15] = sha1_rol32(t, 1);
|
||||
}
|
||||
if (i < 20)
|
||||
{
|
||||
t = (d ^ (b & (c ^ d))) + SHA1_K0;
|
||||
}
|
||||
else if (i < 40)
|
||||
{
|
||||
t = (b ^ c ^ d) + SHA1_K20;
|
||||
}
|
||||
else if (i < 60)
|
||||
{
|
||||
t = ((b & c) | (d & (b | c))) + SHA1_K40;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (b ^ c ^ d) + SHA1_K60;
|
||||
}
|
||||
t += sha1_rol32(a, 5) + e + s->buffer[i & 15];
|
||||
e = d;
|
||||
d = c;
|
||||
c = sha1_rol32(b, 30);
|
||||
b = a;
|
||||
a = t;
|
||||
}
|
||||
s->state[0] += a;
|
||||
s->state[1] += b;
|
||||
s->state[2] += c;
|
||||
s->state[3] += d;
|
||||
s->state[4] += e;
|
||||
}
|
||||
|
||||
void sha1_addUncounted(sha1nfo *s, uint8_t data)
|
||||
{
|
||||
uint8_t * const b = (uint8_t*)s->buffer;
|
||||
b[s->bufferOffset ^ 3] = data;
|
||||
s->bufferOffset++;
|
||||
if (s->bufferOffset == BLOCK_LENGTH)
|
||||
{
|
||||
sha1_hashBlock(s);
|
||||
s->bufferOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void sha1_writebyte(sha1nfo *s, uint8_t data)
|
||||
{
|
||||
++s->byteCount;
|
||||
sha1_addUncounted(s, data);
|
||||
}
|
||||
|
||||
void sha1_write(sha1nfo *s, const char *data, size_t len)
|
||||
{
|
||||
for (; len--;) sha1_writebyte(s, (uint8_t)*data++);
|
||||
}
|
||||
|
||||
void sha1_pad(sha1nfo *s)
|
||||
{
|
||||
// Implement SHA-1 padding (fips180-2 §5.1.1)
|
||||
|
||||
// Pad with 0x80 followed by 0x00 until the end of the block
|
||||
sha1_addUncounted(s, 0x80);
|
||||
while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00);
|
||||
|
||||
// Append length in the last 8 bytes
|
||||
sha1_addUncounted(s, 0); // We're only using 32 bit lengths
|
||||
sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
|
||||
sha1_addUncounted(s, 0); // So zero pad the top bits
|
||||
sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
|
||||
sha1_addUncounted(s, (uint8_t)(s->byteCount >> 21)); // as SHA-1 supports bitstreams as well as
|
||||
sha1_addUncounted(s, (uint8_t)(s->byteCount >> 13)); // byte.
|
||||
sha1_addUncounted(s, (uint8_t)(s->byteCount >> 5));
|
||||
sha1_addUncounted(s, (uint8_t)(s->byteCount << 3));
|
||||
}
|
||||
|
||||
uint8_t* sha1_result(sha1nfo *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Pad to complete the last block
|
||||
sha1_pad(s);
|
||||
|
||||
// Swap byte order back
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
s->state[i] =
|
||||
(((s->state[i]) << 24) & 0xff000000)
|
||||
| (((s->state[i]) << 8) & 0x00ff0000)
|
||||
| (((s->state[i]) >> 8) & 0x0000ff00)
|
||||
| (((s->state[i]) >> 24) & 0x000000ff);
|
||||
}
|
||||
|
||||
// Return pointer to hash (20 characters)
|
||||
return (uint8_t*)s->state;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int string_sha1(lua_State* L)
|
||||
{
|
||||
static const char* g_int2hex = "0123456789ABCDEF";
|
||||
uint8_t* result;
|
||||
size_t l;
|
||||
sha1nfo s;
|
||||
int i;
|
||||
char output[41];
|
||||
|
||||
const char *str = luaL_checklstring(L, 1, &l);
|
||||
if (str != NULL)
|
||||
{
|
||||
sha1_init(&s);
|
||||
sha1_write(&s, str, l);
|
||||
result = sha1_result(&s);
|
||||
|
||||
for (i = 0; i < 20; ++i)
|
||||
{
|
||||
output[i * 2 + 0] = g_int2hex[result[i] & 0x0f];
|
||||
output[i * 2 + 1] = g_int2hex[result[i] >> 4];
|
||||
}
|
||||
output[40] = 0;
|
||||
|
||||
lua_pushlstring(L, output, 40);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* \file string_startswith.c
|
||||
* \brief Determines if a string starts with the given sequence.
|
||||
* \author Copyright (c) 2013 Jason Perkins and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
#include <string.h>
|
||||
|
||||
|
||||
int string_startswith(lua_State* L)
|
||||
{
|
||||
const char* haystack = luaL_optstring(L, 1, NULL);
|
||||
const char* needle = luaL_optstring(L, 2, NULL);
|
||||
|
||||
if (haystack && needle)
|
||||
{
|
||||
size_t nlen = strlen(needle);
|
||||
lua_pushboolean(L, strncmp(haystack, needle, nlen) == 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* \file term_textColor.c
|
||||
* \brief Change the foreground color of the terminal output.
|
||||
* \author Copyright (c) 2017 Blizzard Entertainment and the Premake project
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#if PLATFORM_POSIX
|
||||
static int s_currentColor = -1;
|
||||
#endif
|
||||
|
||||
int canUseColors()
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
return _isatty(_fileno(stdout));
|
||||
#else
|
||||
return isatty(1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const char *getenvOrFallback(const char *var, const char *fallback)
|
||||
{
|
||||
const char *value = getenv(var);
|
||||
return (value != NULL) ? value : fallback;
|
||||
}
|
||||
|
||||
static int s_shouldUseColor = -1;
|
||||
static int shouldUseColors()
|
||||
{
|
||||
if (s_shouldUseColor < 0)
|
||||
{
|
||||
// CLICOLOR* documented at: http://bixense.com/clicolors/
|
||||
s_shouldUseColor = ((getenvOrFallback("CLICOLOR", "1")[0] != '0') && canUseColors())
|
||||
|| getenvOrFallback("CLICOLOR_FORCE", "0")[0] != '0';
|
||||
}
|
||||
return s_shouldUseColor;
|
||||
}
|
||||
|
||||
int term_doGetTextColor()
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info))
|
||||
return -1;
|
||||
return (int)info.wAttributes;
|
||||
#else
|
||||
return s_currentColor;
|
||||
#endif
|
||||
}
|
||||
|
||||
void term_doSetTextColor(int color)
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
if (color >= 0 && shouldUseColors())
|
||||
{
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), (WORD)color);
|
||||
SetConsoleTextAttribute(GetStdHandle(STD_ERROR_HANDLE), (WORD)color);
|
||||
}
|
||||
#else
|
||||
|
||||
// Do not output colors e.g. into a pipe, unless forced.
|
||||
if (!shouldUseColors())
|
||||
return;
|
||||
|
||||
s_currentColor = color;
|
||||
|
||||
const char* colorTable[] =
|
||||
{
|
||||
"\x1B[0;30m", // term.black = 0
|
||||
"\x1B[0;34m", // term.blue = 1
|
||||
"\x1B[0;32m", // term.green = 2
|
||||
"\x1B[0;36m", // term.cyan = 3
|
||||
"\x1B[0;31m", // term.red = 4
|
||||
"\x1B[0;35m", // term.purple = 5
|
||||
"\x1B[0;33m", // term.brown = 6
|
||||
"\x1B[0;37m", // term.lightGray = 7
|
||||
"\x1B[1;30m", // term.gray = 8
|
||||
"\x1B[1;34m", // term.lightBlue = 9
|
||||
"\x1B[1;32m", // term.lightGreen = 10
|
||||
"\x1B[1;36m", // term.lightCyan = 11
|
||||
"\x1B[1;31m", // term.lightRed = 12
|
||||
"\x1B[1;35m", // term.magenta = 13
|
||||
"\x1B[1;33m", // term.yellow = 14
|
||||
"\x1B[1;37m", // term.white = 15
|
||||
};
|
||||
if (color >= 0 && color < 16)
|
||||
{
|
||||
fputs(colorTable[color], stdout);
|
||||
} else
|
||||
{
|
||||
fputs("\x1B[0m", stdout);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int term_getTextColor(lua_State* L)
|
||||
{
|
||||
int color = term_doGetTextColor();
|
||||
lua_pushinteger(L, color);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int term_setTextColor(lua_State* L)
|
||||
{
|
||||
term_doSetTextColor((int)luaL_optinteger(L, 1, -1));
|
||||
return 0;
|
||||
}
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
/**
|
||||
* \file os_unzip.c
|
||||
* \brief Unzip file using libzip library.
|
||||
* \author battle.net -- abrunasso.int@blizzard.com
|
||||
*/
|
||||
|
||||
#include "premake.h"
|
||||
|
||||
#ifdef PREMAKE_COMPRESSION
|
||||
|
||||
#include "zip.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <direct.h>
|
||||
#include <io.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
|
||||
// File Attribute for Unix
|
||||
#define FA_IFIFO 0010000 /* named pipe (fifo) */
|
||||
#define FA_IFCHR 0020000 /* character special */
|
||||
#define FA_IFDIR 0040000 /* directory */
|
||||
#define FA_IFBLK 0060000 /* block special */
|
||||
#define FA_IFREG 0100000 /* regular */
|
||||
#define FA_IFLNK 0120000 /* symbolic link */
|
||||
#define FA_IFSOCK 0140000 /* socket */
|
||||
|
||||
#define FA_ISUID 0004000 /* set user id on execution */
|
||||
#define FA_ISGID 0002000 /* set group id on execution */
|
||||
#define FA_ISTXT 0001000 /* sticky bit */
|
||||
#define FA_IRWXU 0000700 /* RWX mask for owner */
|
||||
#define FA_IRUSR 0000400 /* R for owner */
|
||||
#define FA_IWUSR 0000200 /* W for owner */
|
||||
#define FA_IXUSR 0000100 /* X for owner */
|
||||
#define FA_IRWXG 0000070 /* RWX mask for group */
|
||||
#define FA_IRGRP 0000040 /* R for group */
|
||||
#define FA_IWGRP 0000020 /* W for group */
|
||||
#define FA_IXGRP 0000010 /* X for group */
|
||||
#define FA_IRWXO 0000007 /* RWX mask for other */
|
||||
#define FA_IROTH 0000004 /* R for other */
|
||||
#define FA_IWOTH 0000002 /* W for other */
|
||||
#define FA_IXOTH 0000001 /* X for other */
|
||||
#define FA_ISVTX 0001000 /* save swapped text even after use */
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static int is_symlink(zip_uint8_t opsys, zip_uint32_t attrib)
|
||||
{
|
||||
if (opsys == ZIP_OPSYS_DOS)
|
||||
return (attrib & 0x400) == 0x400; // FILE_ATTRIBUTE_REPARSE_POINT
|
||||
|
||||
if (opsys == ZIP_OPSYS_UNIX)
|
||||
return ((attrib >> 16) & FA_IFLNK) == FA_IFLNK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int is_directory(zip_uint8_t opsys, zip_uint32_t attrib)
|
||||
{
|
||||
if (opsys == ZIP_OPSYS_DOS)
|
||||
return (attrib & 0x10) == 0x10; // FILE_ATTRIBUTE_DIRECTORY
|
||||
|
||||
if (opsys == ZIP_OPSYS_UNIX)
|
||||
return ((attrib >> 16) & FA_IFDIR) == FA_IFDIR;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int write_link(const char* filename, const char* bytes, size_t count)
|
||||
{
|
||||
#if PLATFORM_POSIX
|
||||
(void)(count);
|
||||
return symlink(bytes, filename);
|
||||
#else
|
||||
FILE* fp = fopen(filename, "wb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("Error creating file:\n %s\n", filename);
|
||||
return -1;
|
||||
}
|
||||
fwrite(bytes, sizeof(char), count, fp);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
extern int do_mkdir(const char* path);
|
||||
|
||||
static void parse_path(const char* full_name, char* filename, char* directory)
|
||||
{
|
||||
const char *ssc;
|
||||
size_t orig_length = strlen(full_name);
|
||||
size_t l = 0;
|
||||
size_t dir_size;
|
||||
|
||||
ssc = strstr(full_name, "/");
|
||||
do
|
||||
{
|
||||
l = strlen(ssc) + 1;
|
||||
full_name = &full_name[strlen(full_name) - l + 2];
|
||||
ssc = strstr(full_name, "/");
|
||||
} while (ssc);
|
||||
|
||||
// full_name currently pointing to beginning of filename
|
||||
memcpy(filename, full_name, strlen(full_name));
|
||||
filename[strlen(full_name)] = 0; // Null terminate it
|
||||
|
||||
dir_size = orig_length - strlen(filename);
|
||||
// full_name points to beginning of original string(with directory)
|
||||
full_name = &full_name[strlen(full_name) - orig_length];
|
||||
|
||||
// Extract directory from full name by removing filename
|
||||
memcpy(directory, full_name, dir_size);
|
||||
directory[dir_size] = 0;
|
||||
}
|
||||
|
||||
|
||||
static int extract(const char* src, const char* destination)
|
||||
{
|
||||
int err = 0;
|
||||
FILE *fp = NULL;
|
||||
struct zip *z_archive = zip_open(src, 0, &err);
|
||||
int i;
|
||||
zip_int64_t entries;
|
||||
char buffer[4096];
|
||||
char appended_full_name[512];
|
||||
char directory[512];
|
||||
char filename[512];
|
||||
size_t result;
|
||||
zip_int64_t bytes_read;
|
||||
|
||||
if (!z_archive)
|
||||
{
|
||||
printf("%s does not exist\n", src);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0, entries = zip_get_num_entries(z_archive, 0); i < entries; ++i)
|
||||
{
|
||||
zip_uint8_t opsys;
|
||||
zip_uint32_t attrib;
|
||||
const char* full_name;
|
||||
|
||||
struct zip_file* zf = zip_fopen_index(z_archive, i, 0);
|
||||
if (!zf)
|
||||
continue;
|
||||
|
||||
zip_file_get_external_attributes(z_archive, i, 0, &opsys, &attrib);
|
||||
|
||||
full_name = zip_get_name(z_archive, i, 0);
|
||||
|
||||
sprintf(appended_full_name, "%s/%s", destination, full_name);
|
||||
do_translate(appended_full_name, '/');
|
||||
|
||||
parse_path(appended_full_name, filename, directory);
|
||||
do_mkdir(directory);
|
||||
|
||||
// is this a symbolic link?
|
||||
if (is_symlink(opsys, attrib))
|
||||
{
|
||||
bytes_read = zip_fread(zf, buffer, sizeof(buffer));
|
||||
buffer[bytes_read] = '\0';
|
||||
if (write_link(appended_full_name, buffer, (size_t)bytes_read) != 0)
|
||||
{
|
||||
printf(" Failed to create symbolic link [%s->%s]\n", appended_full_name, buffer);
|
||||
return -1;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// If blank filename it's just a directory so create it and move on
|
||||
if (!is_directory(opsys, attrib) && strlen(filename) > 0)
|
||||
{
|
||||
// mark as read-write, so we can overwrite the file if it already exists.
|
||||
chmod(appended_full_name, 0666);
|
||||
|
||||
fp = fopen(appended_full_name, "wb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
printf("Error creating file:\n %s\n", appended_full_name);
|
||||
return -1;
|
||||
}
|
||||
for(;;)
|
||||
{
|
||||
// Read content from zipped file
|
||||
bytes_read = zip_fread(zf, buffer, sizeof(buffer));
|
||||
if (bytes_read == 0) break;
|
||||
// Write that content to file
|
||||
result = fwrite(buffer, sizeof(char), (size_t)bytes_read, fp);
|
||||
// If all bytes read weren't written, report error
|
||||
if (result != (size_t)bytes_read)
|
||||
{
|
||||
printf(" Writing data to %s failed\n %d bytes were written\n %d bytes were attempted to be written\n File may be corrupt\n",
|
||||
appended_full_name, (int)result, (int)bytes_read);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
|
||||
// mark read-only, but maintain the other properties.
|
||||
if (opsys == ZIP_OPSYS_UNIX)
|
||||
chmod(appended_full_name, (attrib >> 16) & ~0222);
|
||||
else
|
||||
chmod(appended_full_name, 0444);
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
zip_fclose(zf);
|
||||
}
|
||||
zip_close(z_archive);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int zip_extract(lua_State* L)
|
||||
{
|
||||
const char* src = luaL_checkstring(L, 1);
|
||||
const char* dst = luaL_checkstring(L, 2);
|
||||
|
||||
int res = extract(src, dst);
|
||||
|
||||
lua_pushnumber(L, (lua_Number)res);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user