int
main(int argc, char **argv)
{
    static long ncells;

    bu_debug = BU_DEBUG_MEM_CHECK | BU_DEBUG_MEM_LOG;
    bu_debug = 0;

    BU_LIST_INIT(&(gp_locs.l));
    if (! pars_Argv(argc, argv)) {
	prnt_Usage();
	return 1;
    }
    grid = (Cell *) bu_malloc(sizeof(Cell) * maxcells, "grid");
    if (debug_flag & CFB_DBG_MEM)
	bu_log("grid = %p... %ld cells @ %lu bytes/cell\n",
	       (void *)grid, maxcells, sizeof(Cell));
    do {
	struct locrec *lrp;

	init_Globs();
	if ((ncells = read_Cell_Data()) == 0) {
	    bu_log("cell-fb: failed to read view\n");
	    return 1;
	}
	if (BU_LIST_NON_EMPTY(&(gp_locs.l))) {
	    while (BU_LIST_WHILE(lrp, locrec, (&(gp_locs.l)))) {
		BU_LIST_DEQUEUE(&(lrp->l));
		bu_log("%g %g	%d %d\n", lrp->h, lrp->v,
		       (int) H2SCRX(lrp->h), (int) V2SCRY(lrp->v));
		bu_free((char *) lrp, "location record");
	    }
	} else {
	    bu_log("Displaying %ld cells\n", ncells);
	    if (! display_Cells(ncells)) {
		bu_log("cell-fb: failed to display %ld cells\n", ncells);
		return 1;
	    }
	    if (log_flag)
		log_Run();
	}
    } while ((view_flag == 0) && ! feof(filep) && get_OK());

    return 0;
}
Beispiel #2
0
int
main(int argc, char **argv)
{
    int	n;

    if (argc < 2)  {
	fprintf(stderr, "%s", srv_usage);
	return 1;
    }
    while (argv[1][0] == '-')  {
	if (BU_STR_EQUAL(argv[1], "-d"))  {
	    debug++;
	} else if (BU_STR_EQUAL(argv[1], "-x"))  {
	    sscanf(argv[2], "%x", (unsigned int *)&RTG.debug);
	    argc--; argv++;
	} else if (BU_STR_EQUAL(argv[1], "-X"))  {
	    sscanf(argv[2], "%x", (unsigned int *)&rdebug);
	    argc--; argv++;
	} else {
	    fprintf(stderr, "%s", srv_usage);
	    return 3;
	}
	argc--; argv++;
    }
    if (argc != 3 && argc != 4)  {
	fprintf(stderr, "%s", srv_usage);
	return 2;
    }

    control_host = argv[1];
    tcp_port = argv[2];

    /* Note that the LIBPKG error logger can not be
     * "bu_log", as that can cause bu_log to be entered recursively.
     * Given the special version of bu_log in use here,
     * that will result in a deadlock in bu_semaphore_acquire(res_syscall)!
     *  libpkg will default to stderr via pkg_errlog(), which is fine.
     */
    pcsrv = pkg_open(control_host, tcp_port, "tcp", "", "",
		      pkgswitch, NULL);
    if (pcsrv == PKC_ERROR)  {
	fprintf(stderr, "rtsrv: unable to contact %s, port %s\n",
		control_host, tcp_port);
	return 1;
    }

    if (argc == 4)  {
	/* Slip one command to dispatcher */
	(void)pkg_send(MSG_CMD, argv[3], strlen(argv[3])+1, pcsrv);

	/* Prevent chasing the package with an immediate TCP close */
	sleep(1);

	pkg_close(pcsrv);
	return 0;
    }

#ifdef SO_SNDBUF
    /* increase the default send buffer size to 32k since we're
     * sending pixels more than likely.
     */
    {
	int val = 32767;
	n = setsockopt(pcsrv->pkc_fd, SOL_SOCKET, SO_SNDBUF, (const void *)&val, sizeof(val));
	if (n < 0)  perror("setsockopt: SO_SNDBUF");
    }
#endif

    if (!debug)  {
	/* A fresh process */
	if (fork())
	    return 0;

	/* Go into our own process group */
	n = bu_process_id();

#ifdef HAVE_SETPGID
	if (setpgid(n, n) < 0)
	    perror("setpgid");
#else
	/* SysV uses setpgrp with no args and it can't fail,
	 * obsoleted by setpgid.
	 */
	setpgrp();
#endif

	/*
	 *  Unless controller process has specifically said
	 *  that this is an interactive session, e.g., for a demo,
	 *  drop to the lowest sensible priority.
	 */
	if (!interactive)  {
	    bu_nice_set(19);		/* lowest priority */
	}

	/* Close off the world */
	fclose(stdin);
	fclose(stdout);
	fclose(stderr);

	(void)close(0);
	(void)close(1);
	(void)close(2);

	/* For stdio & perror safety, reopen 0, 1, 2 */
	(void)open("/dev/null", 0);	/* to fd 0 */
	n = dup(0);			/* to fd 1 */
	if (n == -1)
	    perror("dup");
	n = dup(0);			/* to fd 2 */
	if (n == -1)
	    perror("dup");

#if defined(HAVE_SYS_IOCTL_H) && defined(TIOCNOTTY)
	n = open("/dev/tty", 2);
	if (n >= 0) {
	    (void)ioctl(n, TIOCNOTTY, 0);
	    (void)close(n);
	}
#endif
    }

    /* Send our version string */
    if (pkg_send(MSG_VERSION,
		   PROTOCOL_VERSION, strlen(PROTOCOL_VERSION)+1, pcsrv) < 0)  {
	fprintf(stderr, "pkg_send MSG_VERSION error\n");
	return 1;
    }
    if (debug)  fprintf(stderr, "PROTOCOL_VERSION='%s'\n", PROTOCOL_VERSION);

    /*
     *  Now that the fork() has been done, it is safe to initialize
     *  the parallel processing support.
     */

    avail_cpus = bu_avail_cpus();

    /* Need to set rtg_parallel non_zero here for RES_INIT to work */
    npsw = avail_cpus;
    if (npsw > 1)  {
	RTG.rtg_parallel = 1;
    } else
	RTG.rtg_parallel = 0;
    bu_semaphore_init(RT_SEM_LAST);

    bu_log("using %d of %d cpus\n",
	   npsw, avail_cpus);

    /*
     *  Initialize the non-parallel memory resource.
     *  The parallel guys are initialized after the rt_dirbuild().
     */
    rt_init_resource(&rt_uniresource, MAX_PSW, NULL);
    bn_rand_init(rt_uniresource.re_randptr, MAX_PSW);

    BU_LIST_INIT(&WorkHead);

    for (;;)  {
	struct pkg_queue	*lp;
	fd_set ifds;
	struct timeval tv;

	/* First, process any packages in library buffers */
	if (pkg_process(pcsrv) < 0)  {
	    bu_log("pkg_get error\n");
	    break;
	}

	/* Second, see if any input to read */
	FD_ZERO(&ifds);
	FD_SET(pcsrv->pkc_fd, &ifds);
	tv.tv_sec = BU_LIST_NON_EMPTY(&WorkHead) ? 0L : 9999L;
	tv.tv_usec = 0L;

	if (select(pcsrv->pkc_fd+1, &ifds, (fd_set *)0, (fd_set *)0,
		    &tv) != 0)  {
	    n = pkg_suckin(pcsrv);
	    if (n < 0)  {
		bu_log("pkg_suckin error\n");
		break;
	    } else if (n == 0)  {
		/* EOF detected */
		break;
	    } else {
		/* All is well */
	    }
	}

	/* Third, process any new packages in library buffers */
	if (pkg_process(pcsrv) < 0)  {
	    bu_log("pkg_get error\n");
	    break;
	}

	/* Finally, more work may have just arrived, check our list */
	if (BU_LIST_NON_EMPTY(&WorkHead))  {
	    lp = BU_LIST_FIRST(pkg_queue, &WorkHead);
	    BU_LIST_DEQUEUE(&lp->l);
	    switch (lp->type)  {
		case MSG_MATRIX:
		    ph_matrix((struct pkg_conn *)0, lp->buf);
		    break;
		case MSG_LINES:
		    ph_lines((struct pkg_conn *)0, lp->buf);
		    break;
		case MSG_OPTIONS:
		    ph_options((struct pkg_conn *)0, lp->buf);
		    break;
		case MSG_GETTREES:
		    ph_gettrees((struct pkg_conn *)0, lp->buf);
		    break;
		default:
		    bu_log("bad list element, type=%d\n", lp->type);
		    return 33;
	    }
	    BU_PUT(lp, struct pkg_queue);
	}
    }

    return 0;		/* bu_exit(0, NULL) */
}
Beispiel #3
0
int
rt_process_uplot_value(register struct bu_list **vhead,
		       struct bn_vlblock *vbp,
		       FILE *fp,
		       register int c,
		       double char_size,
		       int mode)
{
    mat_t mat;
    const struct uplot *up;
#define CARG_LEN 256
#define ARG_LEN 6
    char carg[CARG_LEN];
    fastf_t arg[ARG_LEN];
    vect_t a, b;
    point_t last_pos;
    static point_t lpnt;		/* last point of a move/draw series */
    static int moved = 0;	/* moved since color change */

    memset(carg, 0, sizeof(char)*CARG_LEN);
    memset(arg, 0, sizeof(fastf_t)*ARG_LEN);
#undef ARG_LEN
#undef CARG_LEN


    /* look it up */
    if (c < 'A' || c > 'z') {
	up = &rt_uplot_error;
    } else {
	up = &rt_uplot_letters[ c - 'A' ];
    }

    if (up->targ == TBAD) {
	fprintf(stderr, "Lee : Bad command '%c' (0x%02x)\n", c, c);
	return -1;
    }

    if (up->narg > 0) {
	if (mode == PL_OUTPUT_MODE_BINARY)
	    rt_uplot_get_args(fp, up, carg, arg);
	else
	    rt_uplot_get_text_args(fp, up, carg, arg);
    }

    switch (c) {
	case 's':
	case 'w':
	case 'S':
	case 'W':
	    /* Space commands, do nothing. */
	    break;
	case 'm':
	case 'o':
	    /* 2-D move */
	    arg[Z] = 0;
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, arg, BN_VLIST_LINE_MOVE);
	    VMOVE(lpnt, arg);
	    moved = 1;
	    break;
	case 'M':
	case 'O':
	    /* 3-D move */
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, arg, BN_VLIST_LINE_MOVE);
	    VMOVE(lpnt, arg);
	    moved = 1;
	    break;
	case 'n':
	case 'q':
	    /*
	     * If no move command was issued since the last color
	     * change, insert one now using the last point from a
	     * move/draw.
	     */
	    if (!moved) {
		BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, lpnt, BN_VLIST_LINE_MOVE);
		moved = 1;
	    }

	    /* 2-D draw */
	    arg[Z] = 0;
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, arg, BN_VLIST_LINE_DRAW);
	    VMOVE(lpnt, arg);
	    break;
	case 'N':
	case 'Q':
	    /*
	     * If no move command was issued since the last color
	     * change, insert one now using the last point from a
	     * move/draw.
	     */
	    if (!moved) {
		BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, lpnt, BN_VLIST_LINE_MOVE);
		moved = 1;
	    }

	    /* 3-D draw */
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, arg, BN_VLIST_LINE_DRAW);
	    VMOVE(lpnt, arg);
	    break;
	case 'l':
	case 'v':
	    /* 2-D line */
	    VSET(a, arg[0], arg[1], 0.0);
	    VSET(b, arg[2], arg[3], 0.0);
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, a, BN_VLIST_LINE_MOVE);
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, b, BN_VLIST_LINE_DRAW);
	    break;
	case 'L':
	case 'V':
	    /* 3-D line */
	    VSET(a, arg[0], arg[1], arg[2]);
	    VSET(b, arg[3], arg[4], arg[5]);
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, a, BN_VLIST_LINE_MOVE);
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, b, BN_VLIST_LINE_DRAW);
	    break;
	case 'p':
	case 'x':
	    /* 2-D point */
	    arg[Z] = 0;
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, arg, BN_VLIST_LINE_MOVE);
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, arg, BN_VLIST_LINE_DRAW);
	    break;
	case 'P':
	case 'X':
	    /* 3-D point */
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, arg, BN_VLIST_LINE_MOVE);
	    BN_ADD_VLIST(vbp->free_vlist_hd, *vhead, arg, BN_VLIST_LINE_DRAW);
	    break;
	case 'C':
	    /* Color */
	    *vhead = rt_vlblock_find(vbp,
				     carg[0], carg[1], carg[2]);
	    moved = 0;
	    break;
	case 't':
	    /* Text string */
	    MAT_IDN(mat);
	    if (BU_LIST_NON_EMPTY(*vhead)) {
		struct bn_vlist *vlp;
		/* Use coordinates of last op */
		vlp = BU_LIST_LAST(bn_vlist, *vhead);
		VMOVE(last_pos, vlp->pt[vlp->nused-1]);
	    } else {
		VSETALL(last_pos, 0);
	    }
	    bn_vlist_3string(*vhead, vbp->free_vlist_hd, carg, last_pos, mat, char_size);
	    break;
    }

    return 0;
}
int
ged_draw_guts(struct ged *gedp, int argc, const char *argv[], int kind)
{
    size_t i;
    int drawtrees_retval;
    int flag_A_attr=0;
    int flag_o_nonunique=1;
    int last_opt=0;
    struct bu_vls vls = BU_VLS_INIT_ZERO;
    static const char *usage = "<[-R -C#/#/# -s] objects> | <-o -A attribute name/value pairs>";

/* #define DEBUG_TIMING 1 */

#ifdef DEBUG_TIMING
    int64_t elapsedtime;
#endif

    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
    GED_CHECK_DRAWABLE(gedp, GED_ERROR);
    GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);

    /* initialize result */
    bu_vls_trunc(gedp->ged_result_str, 0);

    /* must be wanting help */
    if (argc == 1) {
	bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
	return GED_HELP;
    }

#ifdef DEBUG_TIMING
    elapsedtime = bu_gettime();
#endif

    /* skip past cmd */
    --argc;
    ++argv;

    /* check args for "-A" (attributes) and "-o" */
    for (i = 0; i < (size_t)argc; i++) {
	char *ptr_A=NULL;
	char *ptr_o=NULL;
	char *c;

	if (*argv[i] != '-') {
	    /* Done checking options. If our display is non-empty,
	     * add -R to keep current view.
	     */
	    if (BU_LIST_NON_EMPTY(gedp->ged_gdp->gd_headDisplay)) {
		bu_vls_strcat(&vls, " -R");
	    }
	    break;
	}

	ptr_A=strchr(argv[i], 'A');
	if (ptr_A)
	    flag_A_attr = 1;

	ptr_o=strchr(argv[i], 'o');
	if (ptr_o)
	    flag_o_nonunique = 2;

	last_opt = i;

	if (!ptr_A && !ptr_o) {
	    bu_vls_putc(&vls, ' ');
	    bu_vls_strcat(&vls, argv[i]);
	    continue;
	}

	if (strlen(argv[i]) == ((size_t)1 + (ptr_A != NULL) + (ptr_o != NULL))) {
	    /* argv[i] is just a "-A" or "-o" */
	    continue;
	}

	/* copy args other than "-A" or "-o" */
	bu_vls_putc(&vls, ' ');
	c = (char *)argv[i];
	while (*c != '\0') {
	    if (*c != 'A' && *c != 'o') {
		bu_vls_putc(&vls, *c);
	    }
	    c++;
	}
    }

    if (flag_A_attr) {
	/* args are attribute name/value pairs */
	struct bu_attribute_value_set avs;
	int max_count=0;
	int remaining_args=0;
	int new_argc=0;
	char **new_argv=NULL;
	struct bu_ptbl *tbl;

	remaining_args = argc - last_opt - 1;
	if (remaining_args < 2 || remaining_args%2) {
	    bu_vls_printf(gedp->ged_result_str, "Error: must have even number of arguments (name/value pairs)\n");
	    bu_vls_free(&vls);
	    return GED_ERROR;
	}

	bu_avs_init(&avs, (argc - last_opt)/2, "ged_draw_guts avs");
	i = 0;
	while (i < (size_t)argc) {
	    if (*argv[i] == '-') {
		i++;
		continue;
	    }

	    /* this is a name/value pair */
	    if (flag_o_nonunique == 2) {
		bu_avs_add_nonunique(&avs, argv[i], argv[i+1]);
	    } else {
		bu_avs_add(&avs, argv[i], argv[i+1]);
	    }
	    i += 2;
	}

	tbl = db_lookup_by_attr(gedp->ged_wdbp->dbip, RT_DIR_REGION | RT_DIR_SOLID | RT_DIR_COMB, &avs, flag_o_nonunique);
	bu_avs_free(&avs);
	if (!tbl) {
	    bu_log("Error: db_lookup_by_attr() failed!!\n");
	    bu_vls_free(&vls);
	    return TCL_ERROR;
	}
	if (BU_PTBL_LEN(tbl) < 1) {
	    /* nothing matched, just return */
	    bu_vls_free(&vls);
	    return TCL_OK;
	}
	for (i = 0; i < BU_PTBL_LEN(tbl); i++) {
	    struct directory *dp;

	    dp = (struct directory *)BU_PTBL_GET(tbl, i);
	    bu_vls_putc(&vls, ' ');
	    bu_vls_strcat(&vls, dp->d_namep);
	}

	max_count = BU_PTBL_LEN(tbl) + last_opt + 1;
	bu_ptbl_free(tbl);
	bu_free((char *)tbl, "ged_draw_guts ptbl");
	new_argv = (char **)bu_calloc(max_count+1, sizeof(char *), "ged_draw_guts new_argv");
	new_argc = bu_argv_from_string(new_argv, max_count, bu_vls_addr(&vls));

	/* First, delete any mention of these objects.
	 * Silently skip any leading options (which start with minus signs).
	 */
	for (i = 0; i < (size_t)new_argc; ++i) {
	    /* Skip any options */
	    if (new_argv[i][0] == '-') {
		/* If this option requires an argument which was
		 * provided separately (e.g. '-C 0/255/0' instead of
		 * '-C0/255/0'), skip the argument too.
		 */
		if (strlen(argv[i]) == 2 && strchr("mxCP", argv[i][1])) {
		    i++;
		}
		continue;
	    }

	    dl_erasePathFromDisplay(gedp->ged_gdp->gd_headDisplay, gedp->ged_wdbp->dbip, gedp->ged_free_vlist_callback, new_argv[i], 0, gedp->freesolid);
	}

	drawtrees_retval = _ged_drawtrees(gedp, new_argc, (const char **)new_argv, kind, (struct _ged_client_data *)0);
	bu_vls_free(&vls);
	bu_free((char *)new_argv, "ged_draw_guts new_argv");
	if (drawtrees_retval) {
	    return GED_ERROR;
	}
    } else {
	int empty_display;
	bu_vls_free(&vls);

	empty_display = 1;
	if (BU_LIST_NON_EMPTY(gedp->ged_gdp->gd_headDisplay)) {
	    empty_display = 0;
	}

	/* First, delete any mention of these objects.
	 * Silently skip any leading options (which start with minus signs).
	 */
	for (i = 0; i < (size_t)argc; ++i) {
	    /* Skip any options */
	    if (argv[i][0] == '-') {
		/* If this option requires an argument which was
		 * provided separately (e.g. '-C 0/255/0' instead of
		 * '-C0/255/0'), skip the argument too.
		 */
		if (strlen(argv[i]) == 2 && strchr("mxCP", argv[i][1])) {
		    i++;
		}
		continue;
	    }

	    dl_erasePathFromDisplay(gedp->ged_gdp->gd_headDisplay, gedp->ged_wdbp->dbip, gedp->ged_free_vlist_callback, argv[i], 0, gedp->freesolid);
	}

	/* if our display is non-empty add -R to keep current view */
	if (!empty_display) {
	    int new_argc;
	    char **new_argv;

	    new_argc = argc + 1;
	    new_argv = (char **)bu_malloc(new_argc * sizeof(char *), "ged_draw_guts new_argv");

	    new_argv[0] = bu_strdup("-R");
	    for (i = 0; i < (size_t)argc; ++i) {
		new_argv[i + 1] = bu_strdup(argv[i]);
	    }

	    drawtrees_retval = _ged_drawtrees(gedp, new_argc, (const char **)new_argv, kind, (struct _ged_client_data *)0);

	    for (i = 0; i < (size_t)new_argc; ++i) {
		bu_free(new_argv[i], "ged_draw_guts new_argv[i] - bu_strdup(argv[i])");
	    }
	    bu_free(new_argv, "ged_draw_guts new_argv");
	} else {
	    drawtrees_retval = _ged_drawtrees(gedp, argc, argv, kind, (struct _ged_client_data *)0);
	}
	if (drawtrees_retval) {
	    return GED_ERROR;
	}
    }

#ifdef DEBUG_TIMING
    elapsedtime = bu_gettime() - elapsedtime;
    {
	int seconds = elapsedtime / 1000000;
	int minutes = seconds / 60;
	int hours = minutes / 60;

	minutes = minutes % 60;
	seconds = seconds %60;

	bu_vls_printf(gedp->ged_result_str, "Elapsed time: %02d:%02d:%02d\n", hours, minutes, seconds);
    }
#endif

    return GED_OK;
}
Beispiel #5
0
int
main(int argc, char **argv)
{
    int c;
    int i;
    struct pshell *psh;
    struct pbar *pbp;
    struct wmember head;
    struct wmember all_head;
    char *nastran_file = "Converted from NASTRAN file (stdin)";

    bu_setprogname(argv[0]);

    fpin = stdin;

    units = INCHES;

    /* FIXME: These need to be improved */
    tol.magic = BN_TOL_MAGIC;
    tol.dist = 0.0005;
    tol.dist_sq = tol.dist * tol.dist;
    tol.perp = 1e-6;
    tol.para = 1 - tol.perp;

    while ((c=bu_getopt(argc, argv, "x:X:t:ni:o:mh?")) != -1) {
	switch (c) {
	    case 'x':
		sscanf(bu_optarg, "%x", (unsigned int *)&RTG.debug);
		bu_printb("librt RT_G_DEBUG", RT_G_DEBUG, DEBUG_FORMAT);
		bu_log("\n");
		break;
	    case 'X':
		sscanf(bu_optarg, "%x", (unsigned int *)&RTG.NMG_debug);
		bu_printb("librt RTG.NMG_debug", RTG.NMG_debug, NMG_DEBUG_FORMAT);
		bu_log("\n");
		break;
	    case 't':		/* calculational tolerance */
		tol.dist = atof(bu_optarg);
		tol.dist_sq = tol.dist * tol.dist;
		break;
	    case 'n':
		polysolids = 0;
		break;
	    case 'm':
		units = MM;
		break;
	    case 'i':
		fpin = fopen(bu_optarg, "rb");
		if (fpin == (FILE *)NULL) {
		    bu_log("Cannot open NASTRAN file (%s) for reading!\n", bu_optarg);
		    bu_exit(1, Usage, argv[0]);
		}
		nastran_file = bu_optarg;
		break;
	    case 'o':
		output_file = bu_optarg;
		break;
	    default:
		bu_exit(1, Usage, argv[0]);
	}
    }

    fpout = wdb_fopen(output_file);
    if (fpout == NULL) {
	bu_log("Cannot open BRL-CAD file (%s) for writing!\n", output_file);
	bu_exit(1, Usage, argv[0]);
    }

    if (!fpin || !fpout) {
	bu_exit(1, Usage, argv[0]);
    }

    line = (char *)bu_malloc(MAX_LINE_SIZE, "line");
    next_line = (char *)bu_malloc(MAX_LINE_SIZE, "next_line");
    prev_line = (char *)bu_malloc(MAX_LINE_SIZE, "prev_line");
    curr_rec = (char **)bu_calloc(NO_OF_FIELDS, sizeof(char *), "curr_rec");
    for (i=0; i<NO_OF_FIELDS; i++)
	curr_rec[i] = (char *)bu_malloc(sizeof(char)*FIELD_LENGTH, "curr_rec[i]");
    prev_rec = (char **)bu_calloc(NO_OF_FIELDS, sizeof(char *), "prev_rec");
    for (i=0; i<NO_OF_FIELDS; i++)
	prev_rec[i] = (char *)bu_malloc(sizeof(char)*FIELD_LENGTH, "prev_rec[i]");

    /* first pass, find start of NASTRAN "bulk data" */
    start_off = (-1);
    bulk_data_start_line = 0;
    while (bu_fgets(line, MAX_LINE_SIZE, fpin)) {
	bulk_data_start_line++;
	if (bu_strncmp(line, "BEGIN BULK", 10))
	    continue;

	start_off = bu_ftell(fpin);
	break;
    }

    if (start_off < 0) {
	bu_log("Cannot find start of bulk data in NASTRAN file!\n");
	bu_exit(1, Usage, argv[0]);
    }

    /* convert BULK data deck into something reasonable */
    fptmp = bu_temp_file(NULL, 0);
    if (fptmp == NULL) {
	perror(argv[0]);
	bu_exit(1, "Cannot open temporary file\n");
    }
    convert_input();

    /* initialize some lists */
    BU_LIST_INIT(&coord_head.l);
    BU_LIST_INIT(&pbar_head.l);
    BU_LIST_INIT(&pshell_head.l);
    BU_LIST_INIT(&all_head.l);

    nmg_model = (struct model *)NULL;

    /* count grid points */
    bu_fseek(fptmp, 0, SEEK_SET);
    while (bu_fgets(line, MAX_LINE_SIZE, fptmp)) {
	if (!bu_strncmp(line, "GRID", 4))
	    grid_count++;
    }
    if (!grid_count) {
	bu_exit(1, "No geometry in this NASTRAN file!\n");
    }

    /* get default values and properties */
    bu_fseek(fptmp, 0, SEEK_SET);
    while (get_next_record(fptmp, 1, 0)) {
	if (!bu_strncmp(curr_rec[0], "BAROR", 5)) {
	    /* get BAR defaults */
	    bar_def_pid = atoi(curr_rec[2]);
	} else if (!bu_strncmp(curr_rec[0], "PBAR", 4)) {
	    struct pbar *pb;

	    BU_ALLOC(pb, struct pbar);

	    pb->pid = atoi(curr_rec[1]);
	    pb->mid = atoi(curr_rec[2]);
	    pb->area = atof(curr_rec[3]);

	    BU_LIST_INIT(&pb->head.l);

	    BU_LIST_INSERT(&pbar_head.l, &pb->l);
	} else if (!bu_strncmp(curr_rec[0], "PSHELL", 6)) {
	    BU_ALLOC(psh, struct pshell);

	    psh->s = (struct shell *)NULL;
	    psh->pid = atoi(curr_rec[1]);
	    psh->mid = atoi(curr_rec[2]);
	    psh->thick = atof(curr_rec[3]);
	    BU_LIST_INSERT(&pshell_head.l, &psh->l);
	    pshell_count++;
	}
    }

    /* allocate storage for grid points */
    g_pts = (struct grid_point *)bu_calloc(grid_count, sizeof(struct grid_point), "grid points");

    /* get all grid points */
    bu_fseek(fptmp, 0, SEEK_SET);
    while (get_next_record(fptmp, 1, 0)) {
	int gid;
	int cid;
	double tmp[3];

	if (bu_strncmp(curr_rec[0], "GRID", 4))
	    continue;

	gid = atoi(curr_rec[1]);
	cid = atoi(curr_rec[2]);

	for (i=0; i<3; i++) {
	    tmp[i] = atof(curr_rec[i+3]);
	}

	g_pts[grid_used].gid = gid;
	g_pts[grid_used].cid = cid;
	g_pts[grid_used].v = (struct vertex **)bu_calloc(pshell_count + 1, sizeof(struct vertex *), "g_pts vertex array");
	VMOVE(g_pts[grid_used].pt, tmp);
	grid_used++;
    }


    /* find coordinate systems */
    bu_fseek(fptmp, 0, SEEK_SET);
    while (get_next_record(fptmp, 1, 0)) {
	if (bu_strncmp(curr_rec[0], "CORD", 4))
	    continue;

	get_coord_sys();
    }
    /* convert everything to BRL-CAD coordinate system */
    i = 0;
    while (convert_all_cs() || convert_all_pts()) {
	i++;
	if (i > 10) {
	    bu_exit(1, "Cannot convert to default coordinate system, check for circular definition\n");
	}
    }

    mk_id(fpout, nastran_file);

    /* get elements */
    bu_fseek(fptmp, 0, SEEK_SET);
    while (get_next_record(fptmp, 1, 0)) {
	if (!bu_strncmp(curr_rec[0], "CBAR", 4))
	    get_cbar();
	else if (!bu_strncmp(curr_rec[0], "CROD", 4))
	    get_cbar();
	else if (!bu_strncmp(curr_rec[0], "CTRIA3", 6))
	    get_ctria3();
	else if (!bu_strncmp(curr_rec[0], "CQUAD4", 6))
	    get_cquad4();
    }

    if (nmg_model) {
	nmg_rebound(nmg_model, &tol);
	if (polysolids)
	    mk_bot_from_nmg(fpout, "pshell.0", nmg_shell);
	else
	    mk_nmg(fpout, "pshell.0", nmg_model);
    }

    BU_LIST_INIT(&head.l);
    for (BU_LIST_FOR(psh, pshell, &pshell_head.l)) {
	struct model *m;
	char name[NAMESIZE+1];

	if (!psh->s)
	    continue;

	m = nmg_find_model(&psh->s->l.magic);
	nmg_rebound(m, &tol);
	nmg_fix_normals(psh->s, &tol);
	if (psh->thick > tol.dist) {
	    nmg_model_face_fuse(m, &tol);
	    nmg_hollow_shell(psh->s, psh->thick*conv[units], 1, &tol);
	}
	sprintf(name, "pshell.%d", psh->pid);
	if (polysolids)
	    mk_bot_from_nmg(fpout, name, psh->s);
	else
	    mk_nmg(fpout, name, m);

	mk_addmember(name, &head.l, NULL, WMOP_UNION);
    }
    if (BU_LIST_NON_EMPTY(&head.l)) {
	mk_lfcomb(fpout, "shells", &head, 0);
	mk_addmember("shells", &all_head.l, NULL, WMOP_UNION);
    }

    BU_LIST_INIT(&head.l);
    for (BU_LIST_FOR(pbp, pbar, &pbar_head.l)) {
	char name[NAMESIZE+1];

	if (BU_LIST_IS_EMPTY(&pbp->head.l))
	    continue;

	sprintf(name, "pbar_group.%d", pbp->pid);
	mk_lfcomb(fpout, name, &pbp->head, 0);

	mk_addmember(name, &head.l, NULL, WMOP_UNION);
    }
    if (BU_LIST_NON_EMPTY(&head.l)) {
	mk_lfcomb(fpout, "pbars", &head, 0);
	mk_addmember("pbars", &all_head.l, NULL, WMOP_UNION);
    }

    if (BU_LIST_NON_EMPTY(&all_head.l)) {
	mk_lfcomb(fpout, "all", &all_head, 0);
    }
    wdb_close(fpout);
    return 0;
}