From 09303625fb05747a766601f68e3224da619541ea Mon Sep 17 00:00:00 2001 From: Arkshine Date: Tue, 12 Aug 2014 23:49:41 +0200 Subject: [PATCH] Compiler: Generate .scp files as part of the build process. Stolen from SM (https://github.com/alliedmodders/sourcemod/pull/112). --- compiler/libpc300/AMBuilder | 43 ++- compiler/libpc300/{sc5.scp => sc5-in.scp} | 0 compiler/libpc300/sc5.c | 2 +- compiler/libpc300/{sc7.scp => sc7-in.scp} | 0 compiler/libpc300/sc7.c | 2 +- compiler/libpc300/scpack.c | 450 ++++++++++++++++++++++ 6 files changed, 494 insertions(+), 3 deletions(-) rename compiler/libpc300/{sc5.scp => sc5-in.scp} (100%) mode change 100755 => 100644 rename compiler/libpc300/{sc7.scp => sc7-in.scp} (100%) mode change 100755 => 100644 create mode 100644 compiler/libpc300/scpack.c diff --git a/compiler/libpc300/AMBuilder b/compiler/libpc300/AMBuilder index 3776948c..69c0a028 100644 --- a/compiler/libpc300/AMBuilder +++ b/compiler/libpc300/AMBuilder @@ -1,9 +1,50 @@ # vim: set sts=2 ts=8 sw=2 tw=99 et ft=python: import os.path +# Build the packing binary garbage. +scpack = AMXX.Program(builder, 'scpack') +if builder.target_platform == 'windows': + scpack.compiler.linkflags.remove('/SUBSYSTEM:WINDOWS') + scpack.compiler.linkflags.append('/SUBSYSTEM:CONSOLE') +scpack.sources = ['scpack.c'] +scpack = builder.Add(scpack) + +# Generate pack files. +packed_files = ['sc5', 'sc7'] +packed_includes = [] +for packed_file in packed_files: + # The absolute path to sc5-in.scp etc. + in_path = os.path.join(builder.currentSourcePath, '{0}-in.scp'.format(packed_file)) + + # The output file relative to the output folder, i.e. sourcepawn/compiler/sc5.scp. + out_path = os.path.join(builder.buildFolder, '{0}.scp'.format(packed_file)) + + # The absolute path to the build folder, i.e. /Users/.../sourcepawn/compiler. + build_folder = os.path.join(builder.buildPath, builder.buildFolder) + + # scpack runs in ./sourcepawn/compiler/scpack/ so we build relative paths + # from there. + scpack_argv = [ + os.path.join(builder.buildPath, scpack.binary.path), + os.path.relpath(in_path, build_folder), + os.path.relpath(os.path.join(builder.buildPath, out_path), build_folder), + ] + + _, (entry,) = builder.AddCommand( + inputs = [scpack.binary, in_path], + argv = scpack_argv, + outputs = ['{0}.scp'.format(packed_file)], + ) + packed_includes += [entry] + binary = AMXX.Library(builder, 'amxxpc32') -binary.compiler.includes += [builder.currentSourcePath] +binary.compiler.includes += [ + builder.currentSourcePath, + os.path.join(builder.buildPath, builder.buildFolder), +] + +binary.compiler.sourcedeps += packed_includes if builder.target_platform in ['mac', 'linux']: binary.compiler.defines += ['ENABLE_BINRELOC'] diff --git a/compiler/libpc300/sc5.scp b/compiler/libpc300/sc5-in.scp old mode 100755 new mode 100644 similarity index 100% rename from compiler/libpc300/sc5.scp rename to compiler/libpc300/sc5-in.scp diff --git a/compiler/libpc300/sc5.c b/compiler/libpc300/sc5.c index d5ae68b4..05bd9088 100755 --- a/compiler/libpc300/sc5.c +++ b/compiler/libpc300/sc5.c @@ -41,7 +41,7 @@ #pragma warning(disable:4125) /* decimal digit terminates octal escape sequence */ #endif -#include "sc5.scp" +#include #if defined _MSC_VER #pragma warning(pop) diff --git a/compiler/libpc300/sc7.scp b/compiler/libpc300/sc7-in.scp old mode 100755 new mode 100644 similarity index 100% rename from compiler/libpc300/sc7.scp rename to compiler/libpc300/sc7-in.scp diff --git a/compiler/libpc300/sc7.c b/compiler/libpc300/sc7.c index 0037328c..37f18b88 100755 --- a/compiler/libpc300/sc7.c +++ b/compiler/libpc300/sc7.c @@ -51,7 +51,7 @@ #pragma warning(disable:4125) /* decimal digit terminates octal escape sequence */ #endif -#include "sc7.scp" +#include #if defined _MSC_VER #pragma warning(pop) diff --git a/compiler/libpc300/scpack.c b/compiler/libpc300/scpack.c new file mode 100644 index 00000000..459532b7 --- /dev/null +++ b/compiler/libpc300/scpack.c @@ -0,0 +1,450 @@ +/* compress.c -- Byte Pair Encoding compression */ +/* Copyright 1996 Philip Gage */ + +/* This program appeared in the September 1997 issue of + * C/C++ Users Journal. The original source code may still + * be found at the web site of the magazine (www.cuj.com). + * + * It has been modified by me (Thiadmer Riemersma) to + * compress only a section of the input file and to store + * the compressed output along with the input as "C" strings. + * + * Compiling instructions: + * Borland C++ 16-bit (large memory model is required): + * bcc -ml scpack.c + * + * Watcom C/C++ 32-bit: + * wcl386 scpack.c + * + * GNU C (Linux), 32-bit: + * gcc scpack.c -o scpack + */ + +#include +#include +#include +#include +#include + +#if UINT_MAX > 0xFFFFU + #define MAXSIZE 1024*1024L +#else + #define MAXSIZE UINT_MAX /* Input file buffer size */ +#endif +#define HASHSIZE 8192 /* Hash table size, power of 2 */ +#define THRESHOLD 3 /* Increase for speed, min 3 */ + +#define START_TOKEN "#ifdef SCPACK" /* start reading the buffer here */ +#define NAME_TOKEN "#define SCPACK_TABLE" +#define SEP_TOKEN "#define SCPACK_SEPARATOR" +#define TERM_TOKEN "#define SCPACK_TERMINATOR" +#define TEMPFILE "~SCPACK.TMP" +static char tablename[32+1] = "scpack_table"; +static char separator[16]=","; +static char terminator[16]=""; + +int compress(unsigned char *buffer, unsigned buffersize, unsigned char pairtable[128][2]) +{ + unsigned char *left, *right, *count; + unsigned char a, b, bestcount; + unsigned i, j, index, bestindex, code=128; + + /* Dynamically allocate buffers and check for errors */ + left = (unsigned char *)malloc(HASHSIZE); + right = (unsigned char *)malloc(HASHSIZE); + count = (unsigned char *)malloc(HASHSIZE); + if (left==NULL || right==NULL || count==NULL) { + printf("Error allocating memory\n"); + exit(1); + } + + /* Check for errors */ + for (i=0; i 127) { + printf("This program works only on text files (7-bit ASCII)\n"); + exit(1); + } + + memset(pairtable, 0, 128*2*sizeof(char)); + + do { /* Replace frequent pairs with bytes 128..255 */ + + /* Enter counts of all byte pairs into hash table */ + memset(count,0,HASHSIZE); + for (i=0; i bestcount) { + bestcount = count[i]; + bestindex = i; + } + } + + /* Compress if enough occurrences of pair */ + if (bestcount >= THRESHOLD) { + + /* Add pair to table using code as index */ + a = pairtable[code-128][0] = left[bestindex]; + b = pairtable[code-128][1] = right[bestindex]; + + /* Replace all pair occurrences with unused byte */ + for (i=0, j=0; i= 128 || *bufptr == '"' || *bufptr == '\\') + fprintf(output, "\\%03o", *bufptr); + else + fprintf(output, "%c", *bufptr); + bufptr++; + } /* while */ + fprintf(output, "\""); + needseparator = 1; + bufptr++; /* skip '\0' */ + } /* while */ + fprintf(output, "%s\n",terminator); + bufptr++; + + /* skip the input file until the #endif section */ + while (fgets(str,sizeof str,input)!=NULL) { + if (strmatch(str,"#endif",NULL)) { + fprintf(output,"%s",str); + break; /* done */ + } /* if */ + } /* while */ + } /* while - !feof(input) */ +} + +static void usage(void) +{ + printf("Usage: scpack [output file]\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + FILE *in, *out; + unsigned char *buffer; + unsigned buffersize, orgbuffersize; + unsigned char pairtable[128][2]; + + if (argc < 2 || argc > 3) + usage(); + if ((in=fopen(argv[1],"rt"))==NULL) { + printf("SCPACK: error opening input %s\n",argv[1]); + usage(); + } /* if */ + if (argc == 2) { + if ((out=fopen(TEMPFILE,"wt"))==NULL) { + printf("SCPACK: error opening temporary file %s\n",TEMPFILE); + usage(); + } /* if */ + } else { + if ((out=fopen(argv[2],"wt"))==NULL) { + printf("SCPACK: error opening output file %s\n",argv[2]); + usage(); + } /* if */ + } /* if */ + + buffer = (unsigned char *)malloc(MAXSIZE); + if (buffer == NULL) { + printf("SCPACK: error allocating memory\n"); + return 1; + } /* if */ + /* 1. read the buffer + * 2. compress the buffer + * 3. copy the file, insert the compressed buffer + */ + buffersize = readbuffer(in, buffer); + orgbuffersize = buffersize; + if (buffersize > 0) { + buffersize = compress(buffer, buffersize, pairtable); + writefile(in, out, buffer, buffersize, pairtable); + printf("SCPACK: compression ratio: %ld%% (%d -> %d)\n", + 100L-(100L*buffersize)/orgbuffersize, orgbuffersize, buffersize); + } else { + printf("SCPACK: no SCPACK section found, nothing to do\n"); + } /* if */ + fclose(out); + fclose(in); + /* let the new file replace the old file */ + if (buffersize == 0) { + if (argc == 2) + remove(TEMPFILE); + else + remove(argv[2]); + } else if (argc == 2) { + remove(argv[1]); + rename(TEMPFILE,argv[1]); + } /* if */ + return 0; +}