Initial community commit

This commit is contained in:
Jef
2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit 20d28e80a5
16810 changed files with 4640254 additions and 2 deletions
@@ -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;
}
@@ -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
@@ -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;
}
@@ -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
@@ -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
@@ -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;
}
@@ -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
@@ -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;
}
@@ -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;
}
}
@@ -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;
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
@@ -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
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
}
@@ -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;
}
@@ -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;
}
@@ -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
@@ -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;
}
@@ -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);
}
@@ -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;
}
}
@@ -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);
@@ -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
@@ -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
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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