-/*
- * Copyright (C) 2012, 2013
- * Dale Weiler
- * Wolfgang Bumiller
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#define GMQCC_PLATFORM_HEADER
+#include <stdlib.h>
+#include <string.h>
#include "gmqcc.h"
-#include "platform.h"
-/*
- * Initially this was handled with a table in the gmqcc.h header, but
- * much to my surprise the contents of the table was duplicated for
- * each translation unit, causing all these strings to be duplicated
- * for every .c file it was included into. This method culls back on
- * it. This is a 'utility' function because the executor also depends
- * on this for disassembled byte-code.
- */
const char *util_instr_str[VINSTR_END] = {
"DONE", "MUL_F", "MUL_V", "MUL_FV",
"MUL_VF", "DIV_F", "ADD_F", "ADD_V",
* only required if big endian .. otherwise no need to swap
* data.
*/
-#if PLATFORM_BYTE_ORDER == GMQCC_BYTE_ORDER_BIG
+#if PLATFORM_BYTE_ORDER == GMQCC_BYTE_ORDER_BIG || PLATFORM_BYTE_ORDER == -1
static GMQCC_INLINE void util_swap16(uint16_t *d, size_t l) {
while (l--) {
d[l] = (d[l] << 8) | (d[l] >> 8);
* so let's go the safe way
*/
static GMQCC_INLINE void util_swap64(uint32_t *d, size_t l) {
- /*
while (l--) {
uint64_t v;
v = ((d[l] << 8) & 0xFF00FF00FF00FF00) | ((d[l] >> 8) & 0x00FF00FF00FF00FF);
v = ((v << 16) & 0xFFFF0000FFFF0000) | ((v >> 16) & 0x0000FFFF0000FFFF);
d[l] = (v << 32) | (v >> 32);
}
- */
- size_t i;
- for (i = 0; i < l; i += 2) {
- uint32_t v1 = d[i];
- d[i] = d[i+1];
- d[i+1] = v1;
- util_swap32(d+i, 2);
- }
}
#endif
-void util_endianswap(void *_data, size_t length, unsigned int typesize) {
+void util_endianswap(void *_data, size_t count, unsigned int typesize) {
# if PLATFORM_BYTE_ORDER == -1 /* runtime check */
if (*((char*)&typesize))
return;
#else
- /* prevent unused warnings */
- (void) _data;
- (void) length;
- (void) typesize;
# if PLATFORM_BYTE_ORDER == GMQCC_BYTE_ORDER_LITTLE
+ /* prevent unused warnings */
+ (void) _data;
+ (void) count;
+ (void) typesize;
return;
# else
switch (typesize) {
case 1: return;
case 2:
- util_swap16((uint16_t*)_data, length>>1);
+ util_swap16((uint16_t*)_data, count);
return;
case 4:
- util_swap32((uint32_t*)_data, length>>2);
+ util_swap32((uint32_t*)_data, count);
return;
case 8:
- util_swap64((uint32_t*)_data, length>>3);
+ util_swap64((uint32_t*)_data, count);
return;
- default: exit(EXIT_FAILURE); /* please blow the fuck up! */
+ default:
+ con_err ("util_endianswap: I don't know how to swap a %u byte structure!\n", typesize);
+ exit(EXIT_FAILURE); /* please blow the fuck up! */
}
# endif
#endif
}
+void util_swap_header(prog_header_t *code_header) {
+ util_endianswap(&code_header->version, 1, sizeof(code_header->version));
+ util_endianswap(&code_header->crc16, 1, sizeof(code_header->crc16));
+ util_endianswap(&code_header->statements.offset, 1, sizeof(code_header->statements.offset));
+ util_endianswap(&code_header->statements.length, 1, sizeof(code_header->statements.length));
+ util_endianswap(&code_header->defs.offset, 1, sizeof(code_header->defs.offset));
+ util_endianswap(&code_header->defs.length, 1, sizeof(code_header->defs.length));
+ util_endianswap(&code_header->fields.offset, 1, sizeof(code_header->fields.offset));
+ util_endianswap(&code_header->fields.length, 1, sizeof(code_header->fields.length));
+ util_endianswap(&code_header->functions.offset, 1, sizeof(code_header->functions.offset));
+ util_endianswap(&code_header->functions.length, 1, sizeof(code_header->functions.length));
+ util_endianswap(&code_header->strings.offset, 1, sizeof(code_header->strings.offset));
+ util_endianswap(&code_header->strings.length, 1, sizeof(code_header->strings.length));
+ util_endianswap(&code_header->globals.offset, 1, sizeof(code_header->globals.offset));
+ util_endianswap(&code_header->globals.length, 1, sizeof(code_header->globals.length));
+ util_endianswap(&code_header->entfield, 1, sizeof(code_header->entfield));
+}
+
+void util_swap_statements(prog_section_statement_t *statements) {
+ size_t i;
+
+ for (i = 0; i < vec_size(statements); ++i) {
+ util_endianswap(&statements[i].opcode, 1, sizeof(statements[i].opcode));
+ util_endianswap(&statements[i].o1, 1, sizeof(statements[i].o1));
+ util_endianswap(&statements[i].o2, 1, sizeof(statements[i].o2));
+ util_endianswap(&statements[i].o3, 1, sizeof(statements[i].o3));
+ }
+}
+
+void util_swap_defs_fields(prog_section_both_t *section) {
+ size_t i;
+
+ for (i = 0; i < vec_size(section); ++i) {
+ util_endianswap(§ion[i].type, 1, sizeof(section[i].type));
+ util_endianswap(§ion[i].offset, 1, sizeof(section[i].offset));
+ util_endianswap(§ion[i].name, 1, sizeof(section[i].name));
+ }
+}
+
+void util_swap_functions(prog_section_function_t *functions) {
+ size_t i;
+
+ for (i = 0; i < vec_size(functions); ++i) {
+ util_endianswap(&functions[i].entry, 1, sizeof(functions[i].entry));
+ util_endianswap(&functions[i].firstlocal, 1, sizeof(functions[i].firstlocal));
+ util_endianswap(&functions[i].locals, 1, sizeof(functions[i].locals));
+ util_endianswap(&functions[i].profile, 1, sizeof(functions[i].profile));
+ util_endianswap(&functions[i].name, 1, sizeof(functions[i].name));
+ util_endianswap(&functions[i].file, 1, sizeof(functions[i].file));
+ util_endianswap(&functions[i].nargs, 1, sizeof(functions[i].nargs));
+ /* Don't swap argsize[] - it's just a byte array, which Quake uses only as such. */
+ }
+}
+
+void util_swap_globals(int32_t *globals) {
+ util_endianswap(globals, vec_size(globals), sizeof(int32_t));
+}
+
/*
-* CRC algorithms vary in the width of the polynomial, the value of said polynomial,
-* the initial value used for the register, weather the bits of each byte are reflected
-* before being processed, weather the algorithm itself feeds input bytes through the
-* register or XORs them with a byte from one end and then straight into the table, as
-* well as (but not limited to the idea of reflected versions) where the final register
-* value becomes reversed, and finally weather the value itself is used to XOR the final
-* register value. AS such you can already imagine how painfully annoying CRCs are,
-* of course we stand to target Quake, which expects it's certain set of rules for proper
-* calculation of a CRC.
+* Based On:
+* Slicing-by-8 algorithms by Michael E.
+* Kounavis and Frank L. Berry from Intel Corp.
+* http://www.intel.com/technology/comms/perfnet/download/CRC_generators.pdf
+*
+* This code was made to be slightly less confusing with macros, which
+* I suppose is somewhat ironic.
+*
+* The code had to be changed for non reflected on the output register
+* since that's the method Quake uses.
*
-* In most traditional CRC algorithms on uses a reflected table driven method where a value
-* or register is reflected if it's bits are swapped around it's center. For example:
-* take the bits 0101 is the 4-bit reflection of 1010, and respectfully 0011 would be the
-* reflection of 1100. Quake however expects a NON-Reflected CRC on the output, but still
-* requires a final XOR on the values (0xFFFF and 0x0000) this is a standard CCITT CRC-16
-* which I respectfully as a programmer don't agree with.
+* The code also had to be changed for CRC16, which is slightly harder
+* since the CRC32 method in the original Intel paper used a different
+* bit order convention.
*
-* So now you know what we target, and why we target it, despite how unsettling it may seem
-* but those are what Quake seems to request.
+* Notes about the table:
+* - It's exactly 4K in size
+* - 64 elements fit in a cache line
+* - can do 8 iterations unrolled 8 times for free
+* - The first 256 elements of the table are standard CRC16 table
+*
+* Table can be generated with the following utility:
*/
+#if 0
+#include <stdio.h>
+#include <stdint.h>
+int main(void) {
+ for (unsigned i = 0; i < 0x100; ++i) {
+ uint16_t x = i << 8;
+ for (int j = 0; j < 8; ++j)
+ x = (x << 1) ^ ((x & 0x8000) ? 0x1021 : 0);
+ tab[0][i] = x;
+ }
+ for (unsigned i = 0; i < 0x100; ++i) {
+ uint16_t c = tab[0][i];
+ for (unsigned j = 1; j < 8; ++j) {
+ c = tab[0][c >> 8] ^ (c << 8);
+ tab[j][i] = c;
+ }
+ }
+ printf("static const uint16_t util_crc16_table[8][256] = {");
+ for (int i = 0; i < 8; ++i) {
+ printf("{\n");
+ for (int j = 0; j < 0x100; ++j) {
+ printf((j & 7) ? " " : " ");
+ printf((j != 0x100-1) ? "0x%04X," : "0x%04X", tab[i][j]);
+ if ((j & 7) == 7)
+ printf("\n");
+ }
+ printf((i != 7) ? "}," : "}");
+ }
+ printf("};\n");
+ return 0;
+}
+#endif
+/*
+ * Non-Reflective version is present as well as a reference.
+ *
+ * TODO:
+ * combine the crc16 into u32s and mask off low high for byte order
+ * to make the arrays smaller.
+ */
static const uint16_t util_crc16_table[8][256] = {{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
}};
/* Non - Reflected */
-uint16_t util_crc16(uint16_t current, const char *k, size_t len) {
- register uint16_t h = current;
+uint16_t util_crc16(uint16_t current, const char *GMQCC_RESTRICT k, size_t len) {
+ uint16_t h = current;
/* don't load twice */
- uint8_t *GMQCC_RESTRICT data = (uint8_t *GMQCC_RESTRICT)k;
+ const uint8_t *GMQCC_RESTRICT data = (const uint8_t *GMQCC_RESTRICT)k;
size_t n;
/* deal with the first bytes as bytes until we reach an 8 byte boundary */
SELECT_DATA(1) ^
SELECT_DATA(0);
data += 8;
+ len -= 8;
}
+ #undef SELECT_BULK
+ #undef SELECT_DATA
+
/* deal with the rest with the byte method */
for (n = len & 7; n; --n)
h = (uint16_t)(h << 8) ^ (*util_crc16_table)[(h >> 8) ^ *data++];
* modifier is the match to make and the transposition from it, while add is the upper-value that determines the
* transposition from uppercase to lower case.
*/
-static GMQCC_INLINE size_t util_strtransform(const char *in, char *out, size_t outsz, const char *mod, int add) {
+static size_t util_strtransform(const char *in, char *out, size_t outsz, const char *mod, int add) {
size_t sz = 1;
for (; *in && sz < outsz; ++in, ++out, ++sz) {
*out = (*in == mod[0])
return util_strtransform(in, out, outsz, "_ ", 'a'-'A');
}
+static int util_vasprintf(char **dat, const char *fmt, va_list args) {
+ int ret;
+ int len;
+ char *tmp = NULL;
+ char buf[128];
+ va_list cpy;
+
+ va_copy(cpy, args);
+ len = vsnprintf(buf, sizeof(buf), fmt, cpy);
+ va_end (cpy);
+
+ if (len < 0)
+ return len;
+
+ if (len < (int)sizeof(buf)) {
+ *dat = util_strdup(buf);
+ return len;
+ }
+
+ tmp = (char*)mem_a(len + 1);
+ if ((ret = vsnprintf(tmp, len + 1, fmt, args)) != len) {
+ mem_d(tmp);
+ *dat = NULL;
+ return -1;
+ }
+
+ *dat = tmp;
+ return len;
+}
+
int util_snprintf(char *str, size_t size, const char *fmt, ...) {
va_list arg;
- int ret;
-
+ int ret;
va_start(arg, fmt);
- ret = platform_vsnprintf(str, size, fmt, arg);
+ ret = vsnprintf(str, size, fmt, arg);
va_end(arg);
-
return ret;
}
int util_asprintf(char **ret, const char *fmt, ...) {
va_list args;
- int read;
-
+ int read;
va_start(args, fmt);
- read = platform_vasprintf(ret, fmt, args);
- va_end (args);
-
+ read = util_vasprintf(ret, fmt, args);
+ va_end(args);
return read;
}
int util_sscanf(const char *str, const char *format, ...) {
va_list args;
- int read;
-
+ int read;
va_start(args, format);
- read = platform_vsscanf(str, format, args);
+ read = vsscanf(str, format, args);
va_end(args);
-
return read;
}
char *util_strncpy(char *dest, const char *src, size_t n) {
- return platform_strncpy(dest, src, n);
+ return strncpy(dest, src, n);
}
+
char *util_strncat(char *dest, const char *src, size_t n) {
- return platform_strncat(dest, src, n);
+ return strncat(dest, src, n);
}
+
char *util_strcat(char *dest, const char *src) {
- return platform_strcat(dest, src);
+ return strcat(dest, src);
}
+
const char *util_strerror(int err) {
- return platform_strerror(err);
+ return strerror(err);
}
const struct tm *util_localtime(const time_t *timer) {
- return platform_localtime(timer);
+ return localtime(timer);
}
+
const char *util_ctime(const time_t *timer) {
- return platform_ctime(timer);
+ return ctime(timer);
}
-bool util_isatty(fs_file_t *file) {
- if (file == (fs_file_t*)stdout) return !!platform_isatty(STDOUT_FILENO);
- if (file == (fs_file_t*)stderr) return !!platform_isatty(STDERR_FILENO);
+int util_getline(char **lineptr, size_t *n, FILE *stream) {
+ int chr;
+ int ret;
+ char *pos;
+
+ if (!lineptr || !n || !stream)
+ return -1;
+ if (!*lineptr) {
+ if (!(*lineptr = (char*)mem_a((*n=64))))
+ return -1;
+ }
+
+ chr = *n;
+ pos = *lineptr;
+
+ for (;;) {
+ int c = getc(stream);
+
+ if (chr < 2) {
+ *n += (*n > 16) ? *n : 64;
+ chr = *n + *lineptr - pos;
+ if (!(*lineptr = (char*)mem_r(*lineptr,*n)))
+ return -1;
+ pos = *n - chr + *lineptr;
+ }
+
+ if (ferror(stream))
+ return -1;
+ if (c == EOF) {
+ if (pos == *lineptr)
+ return -1;
+ else
+ break;
+ }
+
+ *pos++ = c;
+ chr--;
+ if (c == '\n')
+ break;
+ }
+ *pos = '\0';
+ return (ret = pos - *lineptr);
+}
+
+#ifndef _WIN32
+#include <unistd.h>
+bool util_isatty(FILE *file) {
+ if (file == stdout) return !!isatty(STDOUT_FILENO);
+ if (file == stderr) return !!isatty(STDERR_FILENO);
+ return false;
+}
+#else
+bool util_isatty(FILE *file) {
return false;
}
+#endif
+
/*
* A small noncryptographic PRNG based on:
* http://burtleburtle.net/bob/rand/smallprng.html
(void)util_rand();
}
+size_t hash(const char *string) {
+ size_t hash = 0;
+ for(; *string; ++string) {
+ hash += *string;
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+ hash += hash << 3;
+ hash ^= hash >> 11;
+ hash += hash << 15;
+ return hash;
+}
+