Commits

Jason Perkins committed 6ac4b37

Add ability to generate a deterministic UUID from a string value

  • Participants
  • Parent commits a5066b8

Comments (0)

Files changed (4)

File src/host/os_uuid.c

  */
 
 #include "premake.h"
+#include <stdint.h>
+
 #if PLATFORM_WINDOWS
 #include <Objbase.h>
 #endif
 
 int os_uuid(lua_State* L)
 {
-	unsigned char bytes[16];
 	char uuid[38];
+	uint32_t buffer[4];
+	uint8_t* bytes = (uint8_t*)buffer;
+	
+	/* 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)
+	{
+		buffer[0] = do_hash(name, 0);
+		buffer[1] = do_hash(name, 'L');
+		buffer[2] = do_hash(name, 'u');
+		buffer[3] = do_hash(name, 'a');
+	}
 
+	/* If no name is supplied, try to build one properly */	
+	else
+	{
 #if PLATFORM_WINDOWS
-	CoCreateGuid((GUID*)bytes);
+		CoCreateGuid((GUID*)buffer);
 #else
-	int result;
+		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;
+		/* not sure how to get a UUID here, so I fake it */
+		FILE* rnd = fopen("/dev/urandom", "rb");
+		result = fread(buffer, 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],

File src/host/premake.c

 
 static const luaL_Reg string_functions[] = {
 	{ "endswith",  string_endswith },
+	{ "hash", string_hash },
 	{ NULL, NULL }
 };
 

File src/host/premake.h

 
 
 /* Bootstrapping helper functions */
+unsigned long do_hash(const char* str, int seed);
 int do_isfile(const char* filename);
 
 
 int os_stat(lua_State* L);
 int os_uuid(lua_State* L);
 int string_endswith(lua_State* L);
+int string_hash(lua_State* L);
 
 /* Engine interface */
 int premake_init(lua_State* L);

File src/host/string_hash.c

+/**
+ * \file   string_hash.c
+ * \brief  Computes a hash value for a string.
+ * \author Copyright (c) 2012 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);
+	lua_pushnumber(L, do_hash(str, 0));
+	return 1;	
+}
+
+
+unsigned long do_hash(const char* str, int seed)
+{
+	/* DJB2 hashing; see http://www.cse.yorku.ca/~oz/hash.html */
+	
+	unsigned long hash = 5381;
+	
+	if (seed != 0) {
+		hash = hash * 33 + seed;
+	}
+
+	while (*str) {
+		hash = hash * 33 + (*str);
+		str++;
+	}
+
+	return hash;
+}