[LUAU] hack o' the day: gcode.c

Jim Thompson jim at netgate.com
Fri Dec 14 13:14:06 PST 2007


because its been so long since actual code was posted here...

//
// http://tlrobinson.net/blog/?p=31
//
// GCCalc is a simple command line calculator, much like the common
// bc calculator on many Unix systems. It’s implementation, however,
// is very different than most calculators. While bc is said to have
// “C-like syntax”, GCCalc’s syntax is C. Whatever you enter on the
// command line automatically gets compiled, loaded, and executed, and
// the result is returned (as a double) and printed to the screen.
//
// You can either enter expressions like:
//
// round(46.95886*sqrt(1+2/9.99*sin((21%5)*pow(2,8))))
// or you can enter whole C statements (as long as they’re on one  
line, for now) like:
//
//  int i; for (i=0;i<10;i++) { printf("hello world!\n"); }  
printf("goodbye\n");
//
// Unfortunately variables are scoped to the function that wraps
// them, so they don’t persist across multiple entries. However, you
// can access the last result using the “last” variable (a double).
//
//
// Compile with “gcc -o gccalc gccalc.c” on MacOS X,
// or “gcc -o gccalc gccalc.c -ldl” on Linux.
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <unistd.h>

#ifdef __ELF__
#define GCC_FLAGS "-fPIC -shared"
#define EXTENSION "so"
#else
#define GCC_FLAGS "-dynamiclib"
#define EXTENSION "dylib"
#endif

#define HEADERS "#include <stdio.h>\n#include<math.h>"

typedef double(func_return_double)(double);

unsigned count = 0;
char *cwd;
char tmp_path[1024] = {'\0'};

void *lib = NULL;

int main(int argc, char **argv)
{
     double result = 0.0;
     char input_buffer[1024], code_buffer[2048], function_name[32],  
command_buffer[1024];

     // get out current directory, which we’ll use for tmp files  
(dlopen seems to need absolute paths)
     cwd = getcwd(NULL, 0);

     while (1)
     {
         // for unique function and file names (needed for dlopen/ 
dlsym to work correctly)
         count++;

         // read in the next line
         printf(">> ");
         fgets(input_buffer, sizeof(input_buffer), stdin);

         // format the function name
         sprintf(function_name, "f%d", count);

         // format the code string: if it doesn’t contain a semicolon,  
assume it is just an expression
         if (strchr(input_buffer, ';'))
             sprintf(code_buffer, "%s\ndouble %s(double last) { %s 
\nreturn 0; }", HEADERS, function_name, input_buffer);
         else
             sprintf(code_buffer, "%s\ndouble %s(double last) { return  
(%s); }", HEADERS, function_name, input_buffer);

         // format the filename string, delete the file if it exists
         sprintf(tmp_path, "%s/libtmp%d.%s", cwd, count, EXTENSION);
         unlink(tmp_path);

         // format the gcc command string
         sprintf(command_buffer, "gcc -Wall %s -x c - -o %s",  
GCC_FLAGS, tmp_path);

         // execute gcc command, write out the code
         FILE *fp = popen(command_buffer, "w");
         fwrite(code_buffer, 1, strlen(code_buffer), fp);
         fprintf(fp, "\n");

         // pclose waits for gcc to terminate (fclose/close do NOT  
thus compilation will sometimes not finish prior to the dlopen)
         pclose(fp);

         void *ptr = NULL;

         // open the just-compiled dynamic library
         if ((lib = dlopen(tmp_path, RTLD_NOW|RTLD_LOCAL)) == NULL) {
             puts(dlerror());
         }
         // get the function pointer
         else if ((ptr = dlsym(lib, function_name)) == NULL) {
             puts(dlerror());
         }

         // execute it
         if (ptr != NULL)
         {
             func_return_double *func = (func_return_double*)ptr;
             result = (*func)(result);
             // print the result
             printf("=> %.*lf\n", (result/((int)result)>1.0)?5:0,  
result);
         }

         // clean up: close the library, delete the temp file
         dlclose(lib);
         unlink(tmp_path);
     }

     return 0;
}





More information about the LUAU mailing list