| // 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" |
| |
| |
| char* |
| slurp_file(char* buf, const char* file) |
| { |
| FILE* fp; |
| char fbuf[16384]; |
| 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) { |
| buflen = nread; |
| buf = (char*) malloc(nread + 1); |
| if(buf == NULL) { |
| fprintf(stderr, "Out of memory.\n"); |
| exit(3); |
| } |
| memcpy(buf, fbuf, buflen); |
| buf[buflen] = '\0'; |
| } else { |
| buflen = strlen(buf); |
| 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); |
| tmp[buflen+nread] = '\0'; |
| free(buf); |
| buf = tmp; |
| } |
| } |
| return buf; |
| } |
| |
| 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 = 8L * 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("-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("--", argv[i]) == 0) { |
| i++; |
| break; |
| } else { |
| break; |
| } |
| i++; |
| } |
| |
| while(i < argc) { |
| args->script = slurp_file(args->script, argv[i]); |
| if(args->script_name == NULL) { |
| if(strcmp(argv[i], "-") == 0) { |
| args->script_name = "<stdin>"; |
| } else { |
| args->script_name = argv[i]; |
| } |
| } else { |
| args->script_name = "<multiple_files>"; |
| } |
| i++; |
| } |
| |
| if(args->script_name == NULL || args->script == NULL) { |
| DISPLAY_USAGE; |
| exit(3); |
| } |
| |
| 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; |
| } |
| |
| |
| JSObject* |
| couch_readfile(JSContext* cx, FILE* fp) |
| { |
| return NULL; |
| } |
| |
| |
| void |
| couch_print(JSContext* cx, uintN argc, jsval* argv) |
| { |
| char *bytes; |
| uintN i; |
| |
| for(i = 0; i < argc; i++) |
| { |
| bytes = enc_string(cx, argv[i], NULL); |
| if(!bytes) return; |
| |
| fprintf(stdout, "%s%s", i ? " " : "", bytes); |
| JS_free(cx, bytes); |
| } |
| |
| fputc('\n', stdout); |
| fflush(stdout); |
| } |
| |
| |
| void |
| couch_error(JSContext* cx, const char* mesg, JSErrorReport* report) |
| { |
| if(!report || !JSREPORT_IS_WARNING(report->flags)) |
| { |
| fprintf(stderr, "[couchjs] %s\n", mesg); |
| } |
| } |
| |
| |
| 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; |
| } |
| |