src/couch/priv/couch_js/1.8.5/util.c (229 lines of code) (raw):

// Licensed under the Apache License, Version 2.0 (the "License"); you may not // use this file except in compliance with the License. You may obtain a copy of // the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations under // the License. #include <stdlib.h> #include <string.h> #include <jsapi.h> #include "help.h" #include "util.h" #include "utf8.h" size_t slurp_file(const char* file, char** outbuf_p) { FILE* fp; char fbuf[16384]; char *buf = NULL; char* tmp; size_t nread = 0; size_t buflen = 0; if(strcmp(file, "-") == 0) { fp = stdin; } else { fp = fopen(file, "r"); if(fp == NULL) { fprintf(stderr, "Failed to read file: %s\n", file); exit(3); } } while((nread = fread(fbuf, 1, 16384, fp)) > 0) { if(buf == NULL) { buf = (char*) malloc(nread + 1); if(buf == NULL) { fprintf(stderr, "Out of memory.\n"); exit(3); } memcpy(buf, fbuf, nread); } else { tmp = (char*) malloc(buflen + nread + 1); if(tmp == NULL) { fprintf(stderr, "Out of memory.\n"); exit(3); } memcpy(tmp, buf, buflen); memcpy(tmp+buflen, fbuf, nread); free(buf); buf = tmp; } buflen += nread; buf[buflen] = '\0'; } *outbuf_p = buf; return buflen + 1; } couch_args* couch_parse_args(int argc, const char* argv[]) { couch_args* args; int i = 1; args = (couch_args*) malloc(sizeof(couch_args)); if(args == NULL) return NULL; memset(args, '\0', sizeof(couch_args)); args->stack_size = 64L * 1024L * 1024L; while(i < argc) { if(strcmp("-h", argv[i]) == 0) { DISPLAY_USAGE; exit(0); } else if(strcmp("-V", argv[i]) == 0) { DISPLAY_VERSION; exit(0); } else if(strcmp("-H", argv[i]) == 0) { args->use_http = 1; } else if(strcmp("-T", argv[i]) == 0) { args->use_test_funs = 1; } else if(strcmp("-S", argv[i]) == 0) { args->stack_size = atoi(argv[++i]); if(args->stack_size <= 0) { fprintf(stderr, "Invalid stack size.\n"); exit(2); } } else if(strcmp("--eval", argv[i]) == 0) { args->eval = 1; } else if(strcmp("--", argv[i]) == 0) { i++; break; } else { break; } i++; } if(i >= argc) { DISPLAY_USAGE; exit(3); } args->scripts = argv + i; return args; } int couch_fgets(char* buf, int size, FILE* fp) { int n, i, c; if(size <= 0) return -1; n = size - 1; for(i = 0; i < n && (c = getc(fp)) != EOF; i++) { buf[i] = c; if(c == '\n') { i++; break; } } buf[i] = '\0'; return i; } JSString* couch_readline(JSContext* cx, FILE* fp) { JSString* str; char* bytes = NULL; char* tmp = NULL; size_t used = 0; size_t byteslen = 256; size_t readlen = 0; bytes = JS_malloc(cx, byteslen); if(bytes == NULL) return NULL; while((readlen = couch_fgets(bytes+used, byteslen-used, fp)) > 0) { used += readlen; if(bytes[used-1] == '\n') { bytes[used-1] = '\0'; break; } // Double our buffer and read more. byteslen *= 2; tmp = JS_realloc(cx, bytes, byteslen); if(!tmp) { JS_free(cx, bytes); return NULL; } bytes = tmp; } // Treat empty strings specially if(used == 0) { JS_free(cx, bytes); return JSVAL_TO_STRING(JS_GetEmptyStringValue(cx)); } // Shring the buffer to the actual data size tmp = JS_realloc(cx, bytes, used); if(!tmp) { JS_free(cx, bytes); return NULL; } bytes = tmp; byteslen = used; str = dec_string(cx, bytes, byteslen); JS_free(cx, bytes); return str; } JSString* couch_readfile(JSContext* cx, const char* filename) { JSString *string; size_t byteslen; char *bytes; if((byteslen = slurp_file(filename, &bytes))) { string = dec_string(cx, bytes, byteslen); free(bytes); return string; } return NULL; } void couch_print(JSContext* cx, uintN argc, jsval* argv) { char *bytes = NULL; FILE *stream = stdout; if (argc) { if (argc > 1 && argv[1] == JSVAL_TRUE) { stream = stderr; } bytes = enc_string(cx, argv[0], NULL); if(!bytes) return; fprintf(stream, "%s", bytes); JS_free(cx, bytes); } fputc('\n', stream); fflush(stream); } void couch_error(JSContext* cx, const char* mesg, JSErrorReport* report) { jsval v, replace; char* bytes; JSObject* regexp, *stack; jsval re_args[2]; if(!report || !JSREPORT_IS_WARNING(report->flags)) { fprintf(stderr, "%s\n", mesg); // Print a stack trace, if available. if (JSREPORT_IS_EXCEPTION(report->flags) && JS_GetPendingException(cx, &v)) { // Clear the exception before an JS method calls or the result is // infinite, recursive error report generation. JS_ClearPendingException(cx); // Use JS regexp to indent the stack trace. // If the regexp can't be created, don't JS_ReportError since it is // probably not productive to wind up here again. #ifdef SM185 if(JS_GetProperty(cx, JSVAL_TO_OBJECT(v), "stack", &v) && (regexp = JS_NewRegExpObjectNoStatics( cx, "^(?=.)", 6, JSREG_GLOB | JSREG_MULTILINE))) #else if(JS_GetProperty(cx, JSVAL_TO_OBJECT(v), "stack", &v) && (regexp = JS_NewRegExpObject( cx, "^(?=.)", 6, JSREG_GLOB | JSREG_MULTILINE))) #endif { // Set up the arguments to ``String.replace()`` re_args[0] = OBJECT_TO_JSVAL(regexp); re_args[1] = STRING_TO_JSVAL(JS_InternString(cx, "\t")); // Perform the replacement if(JS_ValueToObject(cx, v, &stack) && JS_GetProperty(cx, stack, "replace", &replace) && JS_CallFunctionValue(cx, stack, replace, 2, re_args, &v)) { // Print the result bytes = enc_string(cx, v, NULL); fprintf(stderr, "Stacktrace:\n%s", bytes); JS_free(cx, bytes); } } } } } JSBool couch_load_funcs(JSContext* cx, JSObject* obj, JSFunctionSpec* funcs) { JSFunctionSpec* f; for(f = funcs; f->name != NULL; f++) { if(!JS_DefineFunction(cx, obj, f->name, f->call, f->nargs, f->flags)) { fprintf(stderr, "Failed to create function: %s\n", f->name); return JS_FALSE; } } return JS_TRUE; }