La seguente soluzione non è esattamente quello che hai chiesto, ma spero che, nonostante non sia una semplice risposta C, coprirà le tue esigenze. Reinventare la ruota non è un modo per andare, quindi usiamo date.js in C eseguendolo con SpiderMonkey, il motore JavaScript di Mozilla.
Ecco come l'ho fatto. Ho iniziato a scaricare date.js e a tradurlo in const char*
denominato code
definito in date.js.h
.
(\
echo 'const char *code =' ; \
curl https://datejs.googlecode.com/files/date.js | \
sed -e 's/\\/\\\\/g; s/"/\\"/g; s/^/"/; s/\r\?$/\\n"/'; \
echo ';' \
) > date.js.h
Quindi ho preso il JSAPI's Hello, World! come punto di partenza.
#include "jsapi.h"
#include "date.js.h"
static JSClass global_class = { "global", JSCLASS_GLOBAL_FLAGS,
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
JSCLASS_NO_OPTIONAL_MEMBERS };
void reportError(JSContext *cx, const char *message, JSErrorReport *report) {
fprintf(stderr, "%s:%u:%s\n",
report->filename ? report->filename : "<no filename>",
(unsigned int) report->lineno, message);
}
int main(int argc, const char *argv[]) {
JSRuntime *rt;
JSContext *cx;
JSObject *global;
rt = JS_NewRuntime(8L * 1024L * 1024L);
if (rt == NULL) return 1;
cx = JS_NewContext(rt, 8192);
if (cx == NULL) return 1;
JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT | JSOPTION_METHODJIT);
JS_SetVersion(cx, JSVERSION_LATEST);
JS_SetErrorReporter(cx, reportError);
global = JS_NewCompartmentAndGlobalObject(cx, &global_class, NULL);
if (global == NULL) return 1;
if (!JS_InitStandardClasses(cx, global)) return 1;
/* Here's where the interesting stuff is starting to take place.
* Begin by evaluating sources of date.js */
jsval out;
if (!JS_EvaluateScript(cx, global, code, strlen(code), "code", 1, &out))
return 1;
/* Now create a call to Date.parse and evaluate it. The return value should
* be a timestamp of a given date. If no errors occur convert the timestamp
* to a double and print it. */
const int buflen = 1024;
char parse[buflen + 1];
snprintf(parse, buflen, "Date.parse(\"%s\").getTime();", argv[1]);
if (!JS_EvaluateScript(cx, global, parse, strlen(parse), "parse", 1, &out))
return 1;
double val;
JS_ValueToNumber(cx, out, &val);
printf("%i\n", (int) (val/1000));
/* Finally, clean everything up. */
JS_DestroyContext(cx);
JS_DestroyRuntime(rt);
JS_ShutDown();
return 0;
}
Ecco come funziona in pratica.
$ time ./parse "week ago"
1331938800
0.01user 0.00system 0:00.02elapsed 92%CPU (0avgtext+0avgdata 6168maxresident)k
0inputs+0outputs (0major+1651minor)pagefaults 0swaps
$ time ./parse yesterday
1332457200
0.01user 0.00system 0:00.02elapsed 84%CPU (0avgtext+0avgdata 6168maxresident)k
0inputs+0outputs (0major+1653minor)pagefaults 0swaps
Come si può vedere è abbastanza veloce e si potrebbe aumentare in modo significativo le sue prestazioni riutilizzando contesto inizialmente creata per tutte le chiamate successive a Date.parse
.
Parlando di problemi di licenza, date.js è disponibile in base al MIT e SpiderMonkey è disponibile in MPL 1.1, GPL 2.0 o LGPL 2.1. Il collegamento soddisfa in modo dinamico il requisito non GPL.
TL; DR:git clone https://gist.github.com/2180739.git && cd 2180739 && make && ./parse yesterday
Per quel che vale, date.js è concesso in licenza MIT. Quindi se l'obiettivo qui è quello di ottenere qualcosa che puoi collegare con il codice proprietario, dovresti essere in grado di utilizzare date.js come punto di partenza sicuro se devi eseguire il rollover. Anche se una riscrittura javascript-to-C potrebbe non essere una passeggiata nel parco. –
Questo è esattamente il motivo per cui sto facendo questa domanda invece di andare avanti per scrivere il codice :-) –
Se sei preoccupato della complessità della sorgente per scrivere il tuo parser, puoi usare gli strumenti lex/yacc? – Jerry