--- trunk/jscoverage-server.c 2008/05/31 21:42:36 116 +++ trunk/jscoverage-server.c 2008/06/19 05:53:29 133 @@ -25,7 +25,9 @@ #include #include +#ifdef HAVE_PTHREAD_H #include +#endif #include "http-server.h" #include "instrument-js.h" @@ -64,19 +66,28 @@ static const char ** no_instrument; static size_t num_no_instrument = 0; +#ifdef __MINGW32__ +CRITICAL_SECTION javascript_mutex; +CRITICAL_SECTION source_cache_mutex; +#define LOCK EnterCriticalSection +#define UNLOCK LeaveCriticalSection +#else pthread_mutex_t javascript_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t source_cache_mutex = PTHREAD_MUTEX_INITIALIZER; +#define LOCK pthread_mutex_lock +#define UNLOCK pthread_mutex_unlock +#endif static Stream * find_cached_source(const char * url) { Stream * result = NULL; - pthread_mutex_lock(&source_cache_mutex); + LOCK(&source_cache_mutex); for (SourceCache * p = source_cache; p != NULL; p = p->next) { if (strcmp(url, p->url) == 0) { result = p->source; break; } } - pthread_mutex_unlock(&source_cache_mutex); + UNLOCK(&source_cache_mutex); return result; } @@ -84,10 +95,10 @@ SourceCache * new_source_cache = xmalloc(sizeof(SourceCache)); new_source_cache->url = xstrdup(url); new_source_cache->source = source; - pthread_mutex_lock(&source_cache_mutex); + LOCK(&source_cache_mutex); new_source_cache->next = source_cache; source_cache = new_source_cache; - pthread_mutex_unlock(&source_cache_mutex); + UNLOCK(&source_cache_mutex); } static int get(const char * url, Stream * stream) __attribute__((warn_unused_result)); @@ -338,26 +349,17 @@ return true; } -static int merge(Coverage * coverage, const char * path, size_t size) __attribute__((warn_unused_result)); +static int merge(Coverage * coverage, FILE * f) __attribute__((warn_unused_result)); -static int merge(Coverage * coverage, const char * path, size_t size) { - FILE * f = fopen(path, "r"); - if (f == NULL) { - return -1; - } - uint8_t * buffer = xmalloc(size); - if (fread(buffer, 1, size, f) != size) { - fclose(f); - free(buffer); - return -1; - } - fclose(f); +static int merge(Coverage * coverage, FILE * f) { + Stream * stream = Stream_new(0); + Stream_write_file_contents(stream, f); - pthread_mutex_lock(&javascript_mutex); - int result = jscoverage_parse_json(coverage, buffer, size); - pthread_mutex_unlock(&javascript_mutex); + LOCK(&javascript_mutex); + int result = jscoverage_parse_json(coverage, stream->data, stream->length); + UNLOCK(&javascript_mutex); - free(buffer); + Stream_delete(stream); return result; } @@ -444,7 +446,7 @@ /* check that the path begins with / */ if (file_coverage->id[0] == '/') { char * source_path = make_path(document_root, file_coverage->id + 1); - FILE * source_file = fopen(source_path, "r"); + FILE * source_file = fopen(source_path, "rb"); free(source_path); if (source_file == NULL) { fputs("\"\"", f); @@ -511,9 +513,9 @@ } Coverage * coverage = Coverage_new(); - pthread_mutex_lock(&javascript_mutex); + LOCK(&javascript_mutex); int result = jscoverage_parse_json(coverage, json->data, json->length); - pthread_mutex_unlock(&javascript_mutex); + UNLOCK(&javascript_mutex); Stream_delete(json); if (result != 0) { @@ -524,10 +526,21 @@ mkdir_if_necessary(report_directory); char * path = make_path(report_directory, "jscoverage.json"); + + /* check if the JSON file exists */ struct stat buf; if (stat(path, &buf) == 0) { /* it exists: merge */ - result = merge(coverage, path, buf.st_size); + FILE * f = fopen(path, "r"); + if (f == NULL) { + result = 1; + } + else { + result = merge(coverage, f); + if (fclose(f) == EOF) { + result = 1; + } + } if (result != 0) { free(path); Coverage_delete(coverage); @@ -604,9 +617,9 @@ } static void instrument_js(const char * id, Stream * input_stream, Stream * output_stream) { - pthread_mutex_lock(&javascript_mutex); + LOCK(&javascript_mutex); jscoverage_instrument_js(id, input_stream, output_stream); - pthread_mutex_unlock(&javascript_mutex); + UNLOCK(&javascript_mutex); const struct Resource * resource = get_resource("report.js"); Stream_write(output_stream, resource->data, resource->length); @@ -814,6 +827,11 @@ } filesystem_path = make_path(document_root, abs_path + 1); + size_t filesystem_path_length = strlen(filesystem_path); + if (filesystem_path_length > 0 && filesystem_path[filesystem_path_length - 1] == '/') { + /* stat on Windows doesn't work with trailing slash */ + filesystem_path[filesystem_path_length - 1] = '\0'; + } struct stat buf; if (stat(filesystem_path, &buf) == -1) { @@ -822,7 +840,7 @@ } if (S_ISDIR(buf.st_mode)) { - if (filesystem_path[strlen(filesystem_path) - 1] != '/') { + if (abs_path[strlen(abs_path) - 1] != '/') { const char * request_uri = HTTPExchange_get_request_uri(exchange); char * uri = xmalloc(strlen(request_uri) + 2); strcpy(uri, request_uri); @@ -857,7 +875,7 @@ closedir(d); } else if (S_ISREG(buf.st_mode)) { - FILE * f = fopen(filesystem_path, "r"); + FILE * f = fopen(filesystem_path, "rb"); if (f == NULL) { send_response(exchange, 404, "Not found\n"); goto done; @@ -1021,6 +1039,13 @@ /* is this a shutdown? */ if (shutdown) { +#ifdef __MINGW32__ + WSADATA data; + if (WSAStartup(MAKEWORD(1, 1), &data) != 0) { + fatal("Could not start Winsock"); + } +#endif + /* INADDR_LOOPBACK */ HTTPConnection * connection = HTTPConnection_new_client("127.0.0.1", numeric_port); if (connection == NULL) { @@ -1050,22 +1075,31 @@ jscoverage_init(); +#ifndef __MINGW32__ /* handle broken pipe */ signal(SIGPIPE, SIG_IGN); +#endif + +#ifdef __MINGW32__ +InitializeCriticalSection(&javascript_mutex); +InitializeCriticalSection(&source_cache_mutex); +#endif if (verbose) { printf("Starting HTTP server on %s:%lu\n", ip_address, numeric_port); + fflush(stdout); } HTTPServer_run(ip_address, (uint16_t) numeric_port, handler); if (verbose) { printf("Stopping HTTP server\n"); + fflush(stdout); } jscoverage_cleanup(); free(no_instrument); - pthread_mutex_lock(&source_cache_mutex); + LOCK(&source_cache_mutex); while (source_cache != NULL) { SourceCache * p = source_cache; source_cache = source_cache->next; @@ -1073,7 +1107,7 @@ Stream_delete(p->source); free(p); } - pthread_mutex_unlock(&source_cache_mutex); + UNLOCK(&source_cache_mutex); return 0; }