Пример #1
0
static size_t
recv_header(void *ptr, size_t size, size_t nmem, void *data)
{
    CurlState* state = (CurlState*) data;
    char code[4];
    char* header = (char*) ptr;
    size_t length = size * nmem;
    size_t index = 0;
    JSString* hdr = NULL;
    jsuint hdrlen;
    jsval hdrval;

    if(length > 7 && strncasecmp(header, "HTTP/1.", 7) == 0)
    {
        if(length < 12)
        {
            return CURLE_WRITE_ERROR;
        }

        memcpy(code, header+9, 3*sizeof(char));
        code[3] = '\0';
        state->http->last_status = atoi(code);

        state->resp_headers = JS_NewArrayObject(state->cx, 0, NULL);
        if(!state->resp_headers)
        {
            return CURLE_WRITE_ERROR;
        }

        return length;
    }

    // We get a notice at the \r\n\r\n after headers.
    if(length <= 2)
    {
        return length;
    }

    // Append the new header to our array.
    hdr = dec_string(state->cx, header, length);
    if(!hdr)
    {
        return CURLE_WRITE_ERROR;
    }

    if(!JS_GetArrayLength(state->cx, state->resp_headers, &hdrlen))
    {
        return CURLE_WRITE_ERROR;
    }

    hdrval = STRING_TO_JSVAL(hdr);
    if(!JS_SetElement(state->cx, state->resp_headers, hdrlen, &hdrval))
    {
        return CURLE_WRITE_ERROR;
    }

    return length;
}
Пример #2
0
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;
}
Пример #3
0
int
main(int argc, const char* argv[])
{
    JSRuntime* rt = NULL;
    JSContext* cx = NULL;
    JSObject* global = NULL;
    JSObject* klass = NULL;
    JSScript* script;
    JSString* scriptsrc;
    jschar* schars;
    size_t slen;
    jsval sroot;
    jsval result;

    couch_args* args = couch_parse_args(argc, argv);

    rt = JS_NewRuntime(64L * 1024L * 1024L);
    if(rt == NULL)
        return 1;

    cx = JS_NewContext(rt, args->stack_size);
    if(cx == NULL)
        return 1;

    JS_SetErrorReporter(cx, couch_error);
    JS_ToggleOptions(cx, JSOPTION_XML);

    SETUP_REQUEST(cx);

    global = JS_NewObject(cx, &global_class, NULL, NULL);
    if(global == NULL)
        return 1;

    JS_SetGlobalObject(cx, global);

    if(!JS_InitStandardClasses(cx, global))
        return 1;

    if(couch_load_funcs(cx, global, global_functions) != JS_TRUE)
        return 1;

    if(args->use_http) {
        http_check_enabled();

        klass = JS_InitClass(
            cx, global,
            NULL,
            &CouchHTTPClass, req_ctor,
            0,
            CouchHTTPProperties, CouchHTTPFunctions,
            NULL, NULL
        );

        if(!klass)
        {
            fprintf(stderr, "Failed to initialize CouchHTTP class.\n");
            exit(2);
        }
    }

    // Convert script source to jschars.
    scriptsrc = dec_string(cx, args->script, strlen(args->script));
    if(!scriptsrc)
        return 1;

    schars = JS_GetStringChars(scriptsrc);
    slen = JS_GetStringLength(scriptsrc);

    // Root it so GC doesn't collect it.
    sroot = STRING_TO_JSVAL(scriptsrc);
    if(JS_AddRoot(cx, &sroot) != JS_TRUE) {
        fprintf(stderr, "Internal root error.\n");
        return 1;
    }

    // Compile and run
    script = JS_CompileUCScript(cx, global, schars, slen, args->script_name, 1);
    if(!script) {
        fprintf(stderr, "Failed to compile script.\n");
        return 1;
    }

    JS_ExecuteScript(cx, global, script, &result);

    // Warning message if we don't remove it.
    JS_RemoveRoot(cx, &sroot);

    FINISH_REQUEST(cx);
    JS_DestroyContext(cx);
    JS_DestroyRuntime(rt);
    JS_ShutDown();

    return 0;
}
Пример #4
0
static JSBool
go(JSContext* cx, JSObject* obj, HTTPData* http, char* body, size_t bodylen)
{
    CurlState state;
    char* referer;
    JSString* jsbody;
    JSBool ret = JS_FALSE;
    jsval tmp;
    
    state.cx = cx;
    state.http = http;
    
    state.sendbuf = body;
    state.sendlen = bodylen;
    state.sent = 0;
    state.sent_once = 0;

    state.recvbuf = NULL;
    state.recvlen = 0;
    state.read = 0;

    if(HTTP_HANDLE == NULL) {
        HTTP_HANDLE = curl_easy_init();
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_READFUNCTION, send_body);
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_SEEKFUNCTION,
                                        (curl_seek_callback) seek_body);
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_HEADERFUNCTION, recv_header);
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEFUNCTION, recv_body);
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_NOPROGRESS, 1);
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_ERRORBUFFER, ERRBUF);
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_COOKIEFILE, "");
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_USERAGENT,
                                            "CouchHTTP Client - Relax");
    }
    
    if(!HTTP_HANDLE) {
        JS_ReportError(cx, "Failed to initialize cURL handle.");
        goto done;
    }

    if(!JS_GetReservedSlot(cx, obj, 0, &tmp)) {
      JS_ReportError(cx, "Failed to readreserved slot.");
      goto done;
    }

    if(!(referer = enc_string(cx, tmp, NULL))) {
      JS_ReportError(cx, "Failed to encode referer.");
      goto done;
    }
    curl_easy_setopt(HTTP_HANDLE, CURLOPT_REFERER, referer);
    free(referer);

    if(http->method < 0 || http->method > OPTIONS) {
        JS_ReportError(cx, "INTERNAL: Unknown method.");
        goto done;
    }

    curl_easy_setopt(HTTP_HANDLE, CURLOPT_CUSTOMREQUEST, METHODS[http->method]);
    curl_easy_setopt(HTTP_HANDLE, CURLOPT_NOBODY, 0);
    curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 1);
    curl_easy_setopt(HTTP_HANDLE, CURLOPT_UPLOAD, 0);
    
    if(http->method == HEAD) {
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_NOBODY, 1);
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 0);
    } else if(http->method == POST || http->method == PUT) {
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_UPLOAD, 1);
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_FOLLOWLOCATION, 0);
    }
    
    if(body && bodylen) {
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, bodylen);        
    } else {
        curl_easy_setopt(HTTP_HANDLE, CURLOPT_INFILESIZE, 0);
    }

    // curl_easy_setopt(HTTP_HANDLE, CURLOPT_VERBOSE, 1);

    curl_easy_setopt(HTTP_HANDLE, CURLOPT_URL, http->url);
    curl_easy_setopt(HTTP_HANDLE, CURLOPT_HTTPHEADER, http->req_headers);
    curl_easy_setopt(HTTP_HANDLE, CURLOPT_READDATA, &state);
    curl_easy_setopt(HTTP_HANDLE, CURLOPT_SEEKDATA, &state);
    curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEHEADER, &state);
    curl_easy_setopt(HTTP_HANDLE, CURLOPT_WRITEDATA, &state);

    if(curl_easy_perform(HTTP_HANDLE) != 0) {
        JS_ReportError(cx, "Failed to execute HTTP request: %s", ERRBUF);
        goto done;
    }
    
    if(!state.resp_headers) {
        JS_ReportError(cx, "Failed to recieve HTTP headers.");
        goto done;
    }

    tmp = OBJECT_TO_JSVAL(state.resp_headers);
    if(!JS_DefineProperty(
        cx, obj,
        "_headers",
        tmp,
        NULL, NULL,
        JSPROP_READONLY
    )) {
        JS_ReportError(cx, "INTERNAL: Failed to set response headers.");
        goto done;
    }
    
    if(state.recvbuf) {
        state.recvbuf[state.read] = '\0';
        jsbody = dec_string(cx, state.recvbuf, state.read+1);
        if(!jsbody) {
            // If we can't decode the body as UTF-8 we forcefully
            // convert it to a string by just forcing each byte
            // to a jschar.
            jsbody = str_from_binary(cx, state.recvbuf, state.read);
            if(!jsbody) {
                if(!JS_IsExceptionPending(cx)) {
                    JS_ReportError(cx, "INTERNAL: Failed to decode body.");
                }
                goto done;
            }
        }
        tmp = STRING_TO_JSVAL(jsbody);
    } else {
        tmp = JS_GetEmptyStringValue(cx);
    }
    
    if(!JS_DefineProperty(
        cx, obj,
        "responseText",
        tmp,
        NULL, NULL,
        JSPROP_READONLY
    )) {
        JS_ReportError(cx, "INTERNAL: Failed to set responseText.");
        goto done;
    }
    
    ret = JS_TRUE;

done:
    if(state.recvbuf) JS_free(cx, state.recvbuf);
    return ret;
}
Пример #5
0
ERL_NIF_TERM
decode_iter(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{
    Decoder* d;
    jiffy_st* st = (jiffy_st*) enif_priv_data(env);

    ErlNifBinary bin;

    ERL_NIF_TERM objs;
    ERL_NIF_TERM curr;
    ERL_NIF_TERM val = argv[2];
    ERL_NIF_TERM trailer;
    ERL_NIF_TERM ret;
    size_t bytes_read = 0;

    if(argc != 5) {
        return enif_make_badarg(env);
    } else if(!enif_inspect_binary(env, argv[0], &bin)) {
        return enif_make_badarg(env);
    } else if(!enif_get_resource(env, argv[1], st->res_dec, (void**) &d)) {
        return enif_make_badarg(env);
    } else if(!enif_is_list(env, argv[3])) {
        return enif_make_badarg(env);
    } else if(!enif_is_list(env, argv[4])) {
        return enif_make_badarg(env);
    }

    dec_init(d, env, argv[0], &bin);
    objs = argv[3];
    curr = argv[4];

    while(d->i < bin.size) {
        if(should_yield(env, &bytes_read, d->bytes_per_red)) {
            return enif_make_tuple5(
                    env,
                    st->atom_iter,
                    argv[1],
                    val,
                    objs,
                    curr
                );
        }

        bytes_read += 1;

        switch(dec_curr(d)) {
            case st_value:
                switch(d->p[d->i]) {
                    case ' ':
                    case '\n':
                    case '\r':
                    case '\t':
                        d->i++;
                        break;
                    case 'n':
                        if(d->i + 3 >= d->len) {
                            ret = dec_error(d, "invalid_literal");
                            goto done;
                        }
                        if(memcmp(&(d->p[d->i]), "null", 4) != 0) {
                            ret = dec_error(d, "invalid_literal");
                            goto done;
                        }
                        val = d->null_term;
                        dec_pop(d, st_value);
                        d->i += 4;
                        break;
                    case 't':
                        if(d->i + 3 >= d->len) {
                            ret = dec_error(d, "invalid_literal");
                            goto done;
                        }
                        if(memcmp(&(d->p[d->i]), "true", 4) != 0) {
                            ret = dec_error(d, "invalid_literal");
                            goto done;
                        }
                        val = d->atoms->atom_true;
                        dec_pop(d, st_value);
                        d->i += 4;
                        break;
                    case 'f':
                        if(d->i + 4 >= bin.size) {
                            ret = dec_error(d, "invalid_literal");
                            goto done;
                        }
                        if(memcmp(&(d->p[d->i]), "false", 5) != 0) {
                            ret = dec_error(d, "invalid_literal");
                            goto done;
                        }
                        val = d->atoms->atom_false;
                        dec_pop(d, st_value);
                        d->i += 5;
                        break;
                    case '\"':
                        if(!dec_string(d, &val)) {
                            ret = dec_error(d, "invalid_string");
                            goto done;
                        }
                        dec_pop(d, st_value);
                        break;
                    case '-':
                    case '0':
                    case '1':
                    case '2':
                    case '3':
                    case '4':
                    case '5':
                    case '6':
                    case '7':
                    case '8':
                    case '9':
                        if(!dec_number(d, &val)) {
                            ret = dec_error(d, "invalid_number");
                            goto done;
                        }
                        dec_pop(d, st_value);
                        break;
                    case '{':
                        dec_push(d, st_object);
                        dec_push(d, st_key);
                        objs = enif_make_list_cell(env, curr, objs);
                        curr = enif_make_list(env, 0);
                        d->i++;
                        break;
                    case '[':
                        dec_push(d, st_array);
                        dec_push(d, st_value);
                        objs = enif_make_list_cell(env, curr, objs);
                        curr = enif_make_list(env, 0);
                        d->i++;
                        break;
                    case ']':
                        if(!enif_is_empty_list(env, curr)) {
                            ret = dec_error(d, "invalid_json");
                            goto done;
                        }
                        dec_pop(d, st_value);
                        if(dec_curr(d) != st_array) {
                            ret = dec_error(d, "invalid_json");
                            goto done;
                        }
                        dec_pop(d, st_array);
                        dec_pop(d, st_value);
                        val = curr; // curr is []
                        if(!enif_get_list_cell(env, objs, &curr, &objs)) {
                            ret = dec_error(d, "internal_error");
                            goto done;
                        }
                        d->i++;
                        break;
                    default:
                        ret = dec_error(d, "invalid_json");
                        goto done;
                }
                if(dec_top(d) == 0) {
                    dec_push(d, st_done);
                } else if(dec_curr(d) != st_value && dec_curr(d) != st_key) {
                    dec_push(d, st_comma);
                    curr = enif_make_list_cell(env, val, curr);
                }
                break;

            case st_key:
                switch(d->p[d->i]) {
                    case ' ':
                    case '\n':
                    case '\r':
                    case '\t':
                        d->i++;
                        break;
                    case '\"':
                        if(!dec_string(d, &val)) {
                            ret = dec_error(d, "invalid_string");
                            goto done;
                        }
                        dec_pop(d, st_key);
                        dec_push(d, st_colon);
                        curr = enif_make_list_cell(env, val, curr);
                        break;
                    case '}':
                        if(!enif_is_empty_list(env, curr)) {
                            ret = dec_error(d, "invalid_json");
                            goto done;
                        }
                        dec_pop(d, st_key);
                        dec_pop(d, st_object);
                        dec_pop(d, st_value);
                        val = make_empty_object(env, d->return_maps);
                        if(!enif_get_list_cell(env, objs, &curr, &objs)) {
                            ret = dec_error(d, "internal_error");
                            goto done;
                        }
                        if(dec_top(d) == 0) {
                            dec_push(d, st_done);
                        } else {
                            dec_push(d, st_comma);
                            curr = enif_make_list_cell(env, val, curr);
                        }
                        d->i++;
                        break;
                    default:
                        ret = dec_error(d, "invalid_json");
                        goto done;
                }
                break;

            case st_colon:
                switch(d->p[d->i]) {
                    case ' ':
                    case '\n':
                    case '\r':
                    case '\t':
                        d->i++;
                        break;
                    case ':':
                        dec_pop(d, st_colon);
                        dec_push(d, st_value);
                        d->i++;
                        break;
                    default:
                        ret = dec_error(d, "invalid_json");
                        goto done;
                }
                break;

            case st_comma:
                switch(d->p[d->i]) {
                    case ' ':
                    case '\n':
                    case '\r':
                    case '\t':
                        d->i++;
                        break;
                    case ',':
                        dec_pop(d, st_comma);
                        switch(dec_curr(d)) {
                            case st_object:
                                dec_push(d, st_key);
                                break;
                            case st_array:
                                dec_push(d, st_value);
                                break;
                            default:
                                ret = dec_error(d, "internal_error");
                                goto done;
                        }
                        d->i++;
                        break;
                    case '}':
                        dec_pop(d, st_comma);
                        if(dec_curr(d) != st_object) {
                            ret = dec_error(d, "invalid_json");
                            goto done;
                        }
                        dec_pop(d, st_object);
                        dec_pop(d, st_value);
                        if(!make_object(env, curr, &val,
                                d->return_maps, d->dedupe_keys)) {
                            ret = dec_error(d, "internal_object_error");
                            goto done;
                        }
                        if(!enif_get_list_cell(env, objs, &curr, &objs)) {
                            ret = dec_error(d, "internal_error");
                            goto done;
                        }
                        if(dec_top(d) > 0) {
                            dec_push(d, st_comma);
                            curr = enif_make_list_cell(env, val, curr);
                        } else {
                            dec_push(d, st_done);
                        }
                        d->i++;
                        break;
                    case ']':
                        dec_pop(d, st_comma);
                        if(dec_curr(d) != st_array) {
                            ret = dec_error(d, "invalid_json");
                            goto done;
                        }
                        dec_pop(d, st_array);
                        dec_pop(d, st_value);
                        val = make_array(env, curr);
                        if(!enif_get_list_cell(env, objs, &curr, &objs)) {
                            ret = dec_error(d, "internal_error");
                            goto done;
                        }
                        if(dec_top(d) > 0) {
                            dec_push(d, st_comma);
                            curr = enif_make_list_cell(env, val, curr);
                        } else {
                            dec_push(d, st_done);
                        }
                        d->i++;
                        break;
                    default:
                        ret = dec_error(d, "invalid_json");
                        goto done;
                }
                break;

            case st_done:
                switch(d->p[d->i]) {
                    case ' ':
                    case '\n':
                    case '\r':
                    case '\t':
                        d->i++;
                        break;
                    default:
                        goto decode_done;
                }
                break;

            default:
                ret = dec_error(d, "invalid_internal_state");
                goto done;
        }
    }

decode_done:

    if(d->i < bin.size && d->return_trailer) {
        trailer = enif_make_sub_binary(env, argv[0], d->i, bin.size - d->i);
        val = enif_make_tuple3(env, d->atoms->atom_has_trailer, val, trailer);
    } else if(d->i < bin.size) {
        ret = dec_error(d, "invalid_trailing_data");
        goto done;
    }

    if(dec_curr(d) != st_done) {
        ret = dec_error(d, "truncated_json");
    } else if(d->is_partial) {
        ret = enif_make_tuple2(env, d->atoms->atom_partial, val);
    } else {
        ret = val;
    }

done:
    return ret;
}
Пример #6
0
int get_header(fitsfile *fptr, struct uvf_header *header)
{
  int status = 0;
  int error;
  int i, k, hdunum, hdutype, bitpix, naxis, group;
  long pcount, gcount, naxes[MAX_DIM];
  char extname[68];
  int extver;
  char object[FLEN_VALUE];
  char telescop[FLEN_VALUE];
  char instrume[FLEN_VALUE];
  char ctype[FLEN_VALUE];
  char datobs[FLEN_VALUE], bunit[FLEN_VALUE], radecsys[FLEN_VALUE];
  char keyctype[FLEN_KEYWORD], keycrval[FLEN_KEYWORD];
  char keycdelt[FLEN_KEYWORD], keycrpix[FLEN_KEYWORD];
  char observer[FLEN_KEYWORD];
  double crval, cdelt, crpix;
  double equinox, obsra, obsdec, ra, dec, freq, bw;
  double min_date, max_date;
  int stokes[MAX_STOKES], nstokes, delta_stokes;
  int nc, nif, nval;
  struct uvf_sample sample;

  /* Read the standard header keywords */

  fits_read_imghdr(fptr, MAX_DIM, NULL, &bitpix, &naxis,
		   naxes, &pcount, &gcount, NULL, &status);
  fprintf(stderr, "  bitpix = %d, gcount=%ld\n", bitpix, gcount);
  fits_report_error(stderr, status);

  /* Check for UVF */

  if (status || gcount <= 1  || naxes[0] != 0) {
    fprintf(stderr, "This is not UV-FITS file\n");
    return 1;
  }

  /* Look for the keywords that we know about */

  fits_read_key(fptr, TSTRING, "OBJECT",   object,   NULL, &status);
  if (status == 202) {status = 0; object[0] = '\0';}
  fits_read_key(fptr, TSTRING, "TELESCOP", telescop, NULL, &status);
  if (status == 202) {status = 0; telescop[0] = '\0';}
  fits_read_key(fptr, TSTRING, "INSTRUME", instrume, NULL, &status);
  if (status == 202) {status = 0; instrume[0] = '\0';}
  fits_read_key(fptr, TSTRING, "DATE-OBS", datobs,   NULL, &status);
  if (status == 202) {status = 0; datobs[0] = '\0';}
  fits_read_key(fptr, TSTRING, "BUNIT",    bunit,    NULL, &status);
  if (status == 202) {status = 0; bunit[0] = '\0';}
  fits_read_key(fptr, TSTRING, "RADECSYS", radecsys, NULL, &status);
  if (status == 202) {status = 0; radecsys[0] = '\0';}
  fits_read_key(fptr, TSTRING, "OBSERVER", observer, NULL, &status);
  if (status == 202) {status = 0; observer[0] = '\0';}
  fits_read_key(fptr, TDOUBLE, "EQUINOX",  &equinox, NULL, &status);
  if (status == 202) { /* EQUINOX not found; use EPOCH */
    status = 0;
    /* fprintf(stderr, "Warning: EQUINOX keyword missing\n"); */
    fits_read_key(fptr, TDOUBLE, "EPOCH",  &equinox, NULL, &status);
  }
  fits_read_key(fptr, TDOUBLE, "OBSRA",  &obsra, NULL, &status);
  if (status == 202) {status = 0; obsra = 0.0;}
  fits_read_key(fptr, TDOUBLE, "OBSDEC", &obsdec, NULL, &status);
  if (status == 202) {status = 0; obsdec = 0.0;}
  fprintf(stderr, "  %s,%s,%s,%s,%s,%s,%s,%.2f,%s,%s\n", 
	  object, telescop, instrume, observer, datobs, bunit, radecsys,
	  equinox, ra_string(obsra*RPDEG), dec_string(obsdec*RPDEG));

  /* Look at the axis descriptions */

  error = 0;
  nc = 0;
  nstokes = 0;
  nif = 0;
  ra = dec = freq = bw = 0.0;
  stokes[0] = 0;
  delta_stokes = 0;
  fprintf(stderr, "  Axes (%d): ", naxis-1);
  for (i=1; i<naxis; i++) {
    status = 0;
    fits_make_keyn("CTYPE", i+1, keyctype, &status);
    fits_make_keyn("CRVAL", i+1, keycrval, &status);
    fits_make_keyn("CDELT", i+1, keycdelt, &status);
    fits_make_keyn("CRPIX", i+1, keycrpix, &status);
    fits_read_key(fptr, TSTRING, keyctype, ctype, NULL, &status);
    fits_read_key(fptr, TDOUBLE, keycrval, &crval, NULL, &status);
    fits_read_key(fptr, TDOUBLE, keycdelt, &cdelt, NULL, &status);
    fits_read_key(fptr, TDOUBLE, keycrpix, &crpix, NULL, &status);
    if (status)
      fits_report_error(stderr, status);
    if (i>1) fprintf(stderr, ",");
    fprintf(stderr, "%s(%ld)", ctype, naxes[i]);
    if (strcmp(ctype, "RA") == 0) {
      ra = crval;
      error += (naxes[i] != 1);
    } else if (strcmp(ctype, "DEC") == 0) {
      dec = crval;
      error += (naxes[i] != 1);
    } else if (strcmp(ctype, "COMPLEX") == 0) {
      nc = naxes[i];
      error += (nc != 3);
      error += (crval != 1.0);
    } else if (strcmp(ctype, "STOKES") == 0) {
      nstokes = naxes[i];
      error += (nstokes < 1 || nstokes > MAX_STOKES);
      delta_stokes = cdelt;
      for (k=0; k < MAX_STOKES; k++) {
	stokes[k] = crval + (1+k-crpix)*cdelt;
      }
      error += (nc == 0); /* COMPLEX must be an earlier axis than STOKES */
    } else if (strcmp(ctype, "FREQ") == 0) {
      freq = crval;
      bw = cdelt;
      error += (naxes[i] != 1);
    } else if (strcmp(ctype, "IF") == 0) {
      nif = naxes[i];
      error += (nif < 1);
      error += (crval != 1.0);
      error += (nstokes == 0); /* STOKES must be an earlier axis than IF */
      error += (nc == 0); /* COMPLEX must be an earlier axis than IF */
    } else {
      error += 1;
    }
  }
  fprintf(stderr, "\n");
  if (error > 0) {
    fprintf(stderr, "This is not an acceptable UV-FITS file\n");
    return 1;
  }
  fprintf(stderr, "  RA=%s, Dec=%s, Stokes=",
	  ra_string(ra*RPDEG), dec_string(dec*RPDEG));
  for (k = 0; k < nstokes; k++)
    fprintf(stderr,"%s,", stokes_label(stokes[k]));
  fprintf(stderr, " Freq=%.6g, BW=%.6g\n", freq, bw);
  nval = nc*nif; /* Number of data values at each uv point */

  /* Look at the parameter descriptions */

  header->index_u = -1;
  header->index_v = -1;
  header->index_w = -1;
  header->index_baseline = -1;
  header->index_date1 = -1;
  header->index_date2 = -1;
  header->index_inttim = -1;
  fprintf(stderr, "  Parameters (%ld): ", pcount);
  for (i=0; i<pcount; i++) {
    status = 0;
    fits_make_keyn("PTYPE", i+1, keyctype, &status);
    fits_read_key(fptr, TSTRING, keyctype, ctype, NULL, &status);
    fits_make_keyn("PSCAL", i+1, keyctype, &status);
    fits_read_key(fptr, TDOUBLE, keyctype, &header->pscal[i], NULL, &status);
    fits_make_keyn("PZERO", i+1, keyctype, &status);
    fits_read_key(fptr, TDOUBLE, keyctype, &header->pzero[i], NULL, &status);
    if (status)
      fits_report_error(stderr, status);
    if (i>0) fprintf(stderr, ",");
    fprintf(stderr, "%s", ctype);
    if (strcmp("UU---SIN", ctype) == 0 ||
	strcmp("UU",       ctype) == 0)
      header->index_u = i;
    else if (strcmp("VV---SIN", ctype) == 0 ||
	     strcmp("VV",       ctype) == 0)
      header->index_v = i;
    else if (strcmp("WW---SIN", ctype) == 0 ||
	     strcmp("WW",       ctype) == 0)
      header->index_w = i;
    else if (strcmp("BASELINE", ctype) == 0)
      header->index_baseline = i;
    else if (strcmp("INTTIM", ctype) == 0)
      header->index_inttim = i; /* optional */
    else if (strcmp("DATE", ctype) == 0) {
      if (header->index_date1 == -1)
	header->index_date1 = i;
      else
	header->index_date2 = i;
    } else {
      fprintf(stderr, "\nIgnoring unknown parameter \"%s\"\n", ctype);
    }      
  }
  fprintf(stderr, "\n");

  if (header->index_u < 0 || header->index_v < 0 || header->index_w < 0 ||
      header->index_baseline < 0 || header->index_date1 < 0) {
    fprintf(stderr, "A required parameter is missing\n");
    return 1;
  }

  if (pcount > MAX_PAR) {
    fprintf(stderr, "Too many group parameters in UVF file\n");
    return 1;
  }
  if (DEBUG) {
    for (i=0; i < pcount; i++)
      fprintf(stderr,"%g %g\n", header->pscal[i], header->pzero[i]);
  }

  /* Save header */

  strcpy(header->object, object);
  strcpy(header->telescop, telescop);
  strcpy(header->instrume, instrume);
  strcpy(header->bunit, bunit);
  strcpy(header->radecsys, radecsys);
  strcpy(header->observer, observer);
  header->equinox = equinox;
  header->obsra = obsra;
  header->obsdec = obsdec;
  header->ra = ra;
  header->dec = dec;
  header->freq = freq;
  header->bw = bw;
  header->nstokes = nstokes;
  header->delta_stokes = delta_stokes;
  for (k = 0; k < nstokes; k++)
    header->stokes[k] = stokes[k];
  header->nif = nif;
  header->nchan = nif*nstokes;
  header->nsamp = gcount;
  header->pcount = pcount;
  header->n_antennas = 0;

  /* Read the data to find the time range */

  max_date = 0.0;
  min_date = 1e20;
  for (group=1; group <= gcount; group++) {
    get_sample(fptr, header, group, &sample); 
    if (sample.date < min_date) min_date = sample.date;
    if (sample.date > max_date) max_date = sample.date;
  }
  header->start_jd = min_date;
  header->end_jd = max_date;
  fprintf(stderr, "  Time range: MJD %.8f to %.8f\n", min_date, max_date);

  /* Find the extensions */

  fits_get_num_hdus(fptr, &hdunum, &status);
  for (i=1; i < hdunum; i++) {
    fits_movabs_hdu(fptr, i+1, &hdutype, &status);
    if (hdutype == BINARY_TBL || hdutype == ASCII_TBL) {
      fits_read_key(fptr, TSTRING, "EXTNAME", extname, NULL, &status);
      fits_read_key(fptr, TINT, "EXTVER", &extver, NULL, &status);
      fprintf(stderr, "  Extension %d is %s version %d (%s table)\n", i,
	      extname, extver, hdutype == BINARY_TBL ? "binary" : "ascii");
      if (hdutype == BINARY_TBL && strcmp(extname, "AIPS AN") == 0)
	get_antable(fptr, i+1, header);
      if (hdutype == BINARY_TBL && strcmp(extname, "AIPS FQ") == 0)
	get_fqtable(fptr, i+1, header);
    } else {
      fprintf(stderr, "  Skipping unknown extension of type %d\n", hdutype);
    }
  }

  return status ? 1 : 0;
}