/** * b u _ v l s _ s t r n c m p * * Lexicographically compare two vls strings up to n characters. * Returns an integer greater than, equal to, or less than 0, * according as the string s1 is greater than, equal to, or less than * the string s2. */ int bu_vls_strncmp(struct bu_vls *s1, struct bu_vls *s2, size_t n) { BU_CK_VLS(s1); BU_CK_VLS(s2); if (n <= 0) { /* they match at zero chars */ return 0; } /* A zero-length VLS is a null string, account for it */ if ( s1->vls_max == 0 || s1->vls_str == (char *)NULL ) { /* s1 is empty */ /* ensure first-time allocation for null-termination */ bu_vls_extend(s1, 1); } if ( s2->vls_max == 0 || s2->vls_str == (char *)NULL ) { /* s2 is empty */ /* ensure first-time allocation for null-termination */ bu_vls_extend(s2, 1); } return strncmp(s1->vls_str+s1->vls_offset, s2->vls_str+s2->vls_offset, n); }
/** * b u _ v l s _ r e a d * * Read the remainder of a UNIX file onto the end of a vls. * * Returns - * nread number of characters read * 0 if EOF encountered immediately * -1 read error */ int bu_vls_read( struct bu_vls *vp, int fd ) { size_t todo; int got; int ret = 0; BU_CK_VLS(vp); for (;;) { bu_vls_extend( vp, _VLS_ALLOC_READ ); todo = (size_t)vp->vls_max - vp->vls_len - vp->vls_offset - 1; bu_semaphore_acquire(BU_SEM_SYSCALL); got = read(fd, vp->vls_str+vp->vls_offset+vp->vls_len, todo ); bu_semaphore_release(BU_SEM_SYSCALL); if ( got < 0 ) { /* Read error, abandon the read */ return -1; } if (got == 0) break; vp->vls_len += got; ret += got; } /* force null termination */ vp->vls_str[vp->vls_len+vp->vls_offset] = '\0'; return ret; }
/** * b u _ v l s _ s t r n c p y * * Empty the vls string, and copy in a regular string, up to N bytes * long. */ void bu_vls_strncpy(register struct bu_vls *vp, const char *s, size_t n) { register size_t len; BU_CK_VLS(vp); if ( s == (const char *)NULL ) return; len = strlen(s); if ( len > n ) len = n; if ( len <= 0 ) { vp->vls_len = 0; /* ensure string is empty */ return; } /* cancel offset before extending */ vp->vls_offset = 0; if ( len+1 >= (size_t)vp->vls_max ) bu_vls_extend( vp, len+1 ); memcpy(vp->vls_str, s, len); vp->vls_str[len] = '\0'; /* force null termination */ vp->vls_len = len; }
/** * b u _ v l s _ s t r c p y * * Empty the vls string, and copy in a regular string. */ void bu_vls_strcpy(register struct bu_vls *vp, const char *s) { register size_t len; BU_CK_VLS(vp); if ( s == (const char *)NULL ) return; if ( (len = strlen(s)) <= 0 ) { vp->vls_len = 0; vp->vls_offset = 0; if (vp->vls_max > 0) vp->vls_str[0] = '\0'; return; } /* cancel offset before extending */ vp->vls_offset = 0; if ( len+1 >= (size_t)vp->vls_max ) bu_vls_extend( vp, len+1 ); memcpy(vp->vls_str, s, len+1); /* include null */ vp->vls_len = len; }
void random_hex_or_binary_string(struct bu_vls *v, const hex_bin_enum_t typ, const int nbytes) { const char hex_chars[] = "0123456789abcdef"; const char bin_chars[] = "01"; const int nstrchars = (typ & HEX) ? nbytes * HEXCHARS_PER_BYTE : nbytes * BITS_PER_BYTE; const char *chars = (typ & HEX) ? hex_chars : bin_chars; const int nchars = (typ & HEX) ? sizeof(hex_chars)/sizeof(char) : sizeof(bin_chars)/sizeof(char); int i; long int seed; /* get a random seed from system entropy to seed "random()" */ seed = bu_get_urandom_number(); srand(seed); bu_vls_trunc(v, 0); bu_vls_extend(v, nchars); for (i = 0; i < nstrchars; ++i) { long int r = rand(); int n = r ? (int)(r % (nchars - 1)) : 0; char c = chars[n]; bu_vls_putc(v, c); } if (typ == HEX) { bu_vls_prepend(v, "0x"); } else if (typ == BINARY) { bu_vls_prepend(v, "0b"); } }
/** * b u _ v l s _ v p r i n t f * * Format a string into a vls. This version should work on * practically any machine, but it serves to highlight the the * grossness of the varargs package requiring the size of a parameter * to be known at compile time. * * %s continues to be a regular 'C' string, null terminated. * %S is a pointer to a (struct bu_vls *) string. * * This routine appends to the given vls similar to how vprintf * appends to stdout (see bu_vls_vsprintf for overwriting the vls). */ void bu_vls_vprintf(struct bu_vls *vls, const char *fmt, va_list ap) { register const char *sp; /* start pointer */ register const char *ep; /* end pointer */ register int len; #define LONGINT 0x001 #define FIELDLEN 0x002 #define SHORTINT 0x003 int flags; int fieldlen=-1; char fbuf[64] = {0}; /* % format buffer */ char buf[BUFSIZ] = {0}; if (!vls || !fmt || fmt[0] == '\0') { /* nothing to print to or from */ return; } BU_CK_VLS(vls); bu_vls_extend(vls, _VLS_ALLOC_STEP); sp = fmt; while ( *sp ) { /* Initial state: just printing chars */ fmt = sp; while (*sp != '%' && *sp) sp++; if (sp != fmt) bu_vls_strncat(vls, fmt, (size_t)(sp-fmt)); if (*sp == '\0') break; /* Saw a percent sign, find end of fmt specifier */ flags = 0; ep = sp; while ( *ep ) { ++ep; if (*ep == ' ' || *ep == '#' || *ep == '-' || *ep == '+' || *ep == '.' || isdigit(*ep)) continue; else if (*ep == 'l' || *ep == 'U' || *ep == 'O') flags |= LONGINT; else if (*ep == '*') { fieldlen = va_arg(ap, int); flags |= FIELDLEN; } else if (*ep == 'h') { flags |= SHORTINT; } else /* Anything else must be the end of the fmt specifier */ break; }
/** * b u _ v l s _ p u t c * * Append the given character to the vls. */ void bu_vls_putc(register struct bu_vls *vp, int c) { BU_CK_VLS(vp); if ( vp->vls_offset + vp->vls_len+1 >= vp->vls_max ) bu_vls_extend( vp, _VLS_ALLOC_STEP ); vp->vls_str[vp->vls_offset + vp->vls_len++] = (char)c; vp->vls_str[vp->vls_offset + vp->vls_len] = '\0'; /* force null termination */ }
/** * b u _ v l s _ s e t l e n * * Ensure that the vls has a length of at least 'newlen', and make * that the current length. * * Useful for subroutines that are planning on mucking with the data * array themselves. Not advisable, but occasionally useful. * * Does not change the offset from the front of the buffer, if any. * Does not initialize the value of any of the new bytes. */ void bu_vls_setlen(struct bu_vls *vp, int newlen) { BU_CK_VLS(vp); if ( vp->vls_len >= newlen ) return; bu_vls_extend( vp, (unsigned)newlen - vp->vls_len ); vp->vls_len = newlen; }
/** * b u _ v l s _ s t r c m p * * Lexicographically compare to vls strings. Returns an integer * greater than, equal to, or less than 0, according as the string s1 * is greater than, equal to, or less than the string s2. */ int bu_vls_strcmp(struct bu_vls *s1, struct bu_vls *s2) { BU_CK_VLS(s1); BU_CK_VLS(s2); /* A zero-length VLS is a null string, account for it */ if ( s1->vls_max == 0 || s1->vls_str == (char *)NULL ) { /* s1 is empty */ /* ensure first-time allocation for null-termination */ bu_vls_extend(s1, 1); } if ( s2->vls_max == 0 || s2->vls_str == (char *)NULL ) { /* s2 is empty */ /* ensure first-time allocation for null-termination */ bu_vls_extend(s2, 1); } /* neither empty, straight up comparison */ return strcmp(s1->vls_str+s1->vls_offset, s2->vls_str+s2->vls_offset); }
/** * b u _ v l s _ v l s c a t * * Concatenate a new vls string onto the end of an existing vls * string. The storage of the source string is not affected. */ void bu_vls_vlscat(register struct bu_vls *dest, register const struct bu_vls *src) { BU_CK_VLS(src); BU_CK_VLS(dest); if ( src->vls_len <= 0 ) return; if ( dest->vls_offset + dest->vls_len + src->vls_len+1 >= dest->vls_max ) bu_vls_extend( dest, (unsigned)src->vls_len+1 ); /* copy source string, including null */ memcpy(dest->vls_str +dest->vls_offset + dest->vls_len, src->vls_str+src->vls_offset, (size_t)src->vls_len+1); dest->vls_len += src->vls_len; }
/** * b u _ v l s _ s t r c a t * * Concatenate a new string onto the end of the existing vls string. */ void bu_vls_strcat(register struct bu_vls *vp, const char *s) { register size_t len; BU_CK_VLS(vp); if ( s == (const char *)NULL ) return; if ( (len = strlen(s)) <= 0 ) return; if ( (size_t)vp->vls_offset + (size_t)vp->vls_len + len+1 >= (size_t)vp->vls_max ) bu_vls_extend( vp, len+1 ); memcpy(vp->vls_str +vp->vls_offset + vp->vls_len, s, len+1); /* include null */ vp->vls_len += len; }
/** * b n _ p r _ p o l y * * Print out the polynomial. */ void bn_pr_poly(const char *title, register const struct bn_poly *eqn) { register int n; register int exp; struct bu_vls str; char buf[48]; bu_vls_init( &str ); bu_vls_extend( &str, 196 ); bu_vls_strcat( &str, title ); snprintf(buf, 48, " polynomial, degree = %d\n", eqn->dgr); bu_vls_strcat( &str, buf ); exp = eqn->dgr; for ( n=0; n<=eqn->dgr; n++, exp-- ) { register double coeff = eqn->cf[n]; if ( n > 0 ) { if ( coeff < 0 ) { bu_vls_strcat( &str, " - " ); coeff = -coeff; } else { bu_vls_strcat( &str, " + " ); } } bu_vls_printf( &str, "%g", coeff ); if ( exp > 1 ) { bu_vls_printf( &str, " *X^%d", exp ); } else if ( exp == 1 ) { bu_vls_strcat( &str, " *X" ); } else { /* For constant term, add nothing */ } } bu_vls_strcat( &str, "\n" ); bu_log( "%s", bu_vls_addr(&str) ); bu_vls_free( &str ); }
/** * b u _ v l s _ s t r n c a t * * Concatenate a new string onto the end of the existing vls string. */ void bu_vls_strncat(register struct bu_vls *vp, const char *s, size_t n) { register size_t len; BU_CK_VLS(vp); if ( s == (const char *)NULL ) return; len = strlen(s); if ( len > n ) len = n; if ( len <= 0 ) return; if ( (size_t)vp->vls_offset + (size_t)vp->vls_len + len+1 >= (size_t)vp->vls_max ) bu_vls_extend( vp, len+1 ); memcpy(vp->vls_str + vp->vls_offset + vp->vls_len, s, len); vp->vls_len += len; vp->vls_str[vp->vls_offset + vp->vls_len] = '\0'; /* force null termination */ }
/* * R A Y H I T * * Rayhit() is called by rt_shootray() when the ray hits one or more objects. * A per-shotline header record is written, followed by information about * each object hit. * * Note that the GIFT-3 format uses a different convention for the "zero" * distance along the ray. RT has zero at the ray origin (emanation plain), * while GIFT has zero at the screen plain translated so that it contains * the model origin. This difference is compensated for by adding the * 'dcorrection' distance correction factor. * * Also note that the GIFT-3 format requires information about the start * point of the ray in two formats. First, the h, v coordinates of the * grid cell CENTERS (in screen space coordinates) are needed. * Second, the ACTUAL h, v coordinates fired from are needed. * * An optional rtg3.pl UnixPlot file is written, permitting a * color vector display of ray-model intersections. */ int rayhit(struct application *ap, register struct partition *PartHeadp, struct seg *segp) { register struct partition *pp = PartHeadp->pt_forw; int comp_count; /* component count */ fastf_t dfirst, dlast; /* ray distances */ static fastf_t dcorrection = 0; /* RT to GIFT dist corr */ int card_count; /* # comp. on this card */ const char *fmt; /* printf() format string */ struct bu_vls str; char buf[128]; /* temp. sprintf() buffer */ point_t hv; /* GIFT h, v coords, in inches */ point_t hvcen; int prev_id=-1; point_t first_hit; int first; if ( pp == PartHeadp ) return(0); /* nothing was actually hit?? */ if ( ap->a_rt_i->rti_save_overlaps ) rt_rebuild_overlaps( PartHeadp, ap, 1 ); part_compact(ap, PartHeadp, TOL); /* count components in partitions */ comp_count = 0; for ( pp=PartHeadp->pt_forw; pp!=PartHeadp; pp=pp->pt_forw ) { if ( pp->pt_regionp->reg_regionid > 0 ) { prev_id = pp->pt_regionp->reg_regionid; comp_count++; } else if ( prev_id <= 0 ) { /* normally air would be output along with a solid partition, but this will require a '111' partition */ prev_id = pp->pt_regionp->reg_regionid; comp_count++; } else prev_id = pp->pt_regionp->reg_regionid; } pp = PartHeadp->pt_back; if ( pp!=PartHeadp && pp->pt_regionp->reg_regionid <= 0 ) comp_count++; /* a trailing '111' ident */ if ( comp_count == 0 ) return( 0 ); /* Set up variable length string, to buffer this shotline in. * Note that there is one component per card, and that each card * (line) is 80 characters long. Hence the parameters given to * rt-vls-extend(). */ bu_vls_init( &str ); bu_vls_extend( &str, 80 * (comp_count+1) ); /* * Find the H, V coordinates of the grid cell center. * RT uses the lower left corner of each cell. */ { point_t center; fastf_t dx; fastf_t dy; dx = ap->a_x + 0.5; dy = ap->a_y + 0.5; VJOIN2( center, viewbase_model, dx, dx_model, dy, dy_model ); MAT4X3PNT( hvcen, model2hv, center ); } /* * Find exact h, v coordinates of actual ray start by * projecting start point into GIFT h, v coordinates. */ MAT4X3PNT( hv, model2hv, ap->a_ray.r_pt ); /* * In RT, rays are launched from the plane of the screen, * and ray distances are relative to the start point. * In GIFT-3 output files, ray distances are relative to * the (H, V) plane translated so that it contains the origin. * A distance correction is required to convert between the two. * Since this really should be computed only once, not every time, * the trip_count flag was added. */ { static int trip_count; vect_t tmp; vect_t viewZdir; if ( trip_count == 0) { VSET( tmp, 0, 0, -1 ); /* viewing direction */ MAT4X3VEC( viewZdir, view2model, tmp ); VUNITIZE( viewZdir ); /* dcorrection will typically be negative */ dcorrection = VDOT( ap->a_ray.r_pt, viewZdir ); trip_count = 1; } } /* This code is for diagnostics. * bu_log("dcorrection=%g\n", dcorrection); */ /* dfirst and dlast have been made negative to account for GIFT looking * in the opposite direction of RT. */ dfirst = -(PartHeadp->pt_forw->pt_inhit->hit_dist + dcorrection); dlast = -(PartHeadp->pt_back->pt_outhit->hit_dist + dcorrection); #if 0 /* This code is to note any occurances of negative distances. */ if ( PartHeadp->pt_forw->pt_inhit->hit_dist < 0) { bu_log("ERROR: dfirst=%g at partition x%x\n", dfirst, PartHeadp->pt_forw ); bu_log("\tdcorrection = %f\n", dcorrection ); bu_log("\tray start point is ( %f %f %f ) in direction ( %f %f %f )\n", V3ARGS( ap->a_ray.r_pt ), V3ARGS( ap->a_ray.r_dir ) ); VJOIN1( PartHeadp->pt_forw->pt_inhit->hit_point, ap->a_ray.r_pt, PartHeadp->pt_forw->pt_inhit->hit_dist, ap->a_ray.r_dir ); VJOIN1( PartHeadp->pt_back->pt_outhit->hit_point, ap->a_ray.r_pt, PartHeadp->pt_forw->pt_outhit->hit_dist, ap->a_ray.r_dir ); rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); } /* End of bug trap. */ #endif /* * Output the ray header. The GIFT statements that * would have generated this are: * 410 write(1, 411) hcen, vcen, h, v, ncomp, dfirst, dlast, a, e * 411 format(2f7.1, 2f9.3, i3, 2f8.2,' A', f6.1,' E', f6.1) */ #define SHOT_FMT "%7.1f%7.1f%9.3f%9.3f%3d%8.2f%8.2f A%6.1f E%6.1f" if ( rt_perspective > 0 ) { bn_ae_vec( &azimuth, &elevation, ap->a_ray.r_dir ); } bu_vls_printf( &str, SHOT_FMT, hvcen[0], hvcen[1], hv[0], hv[1], comp_count, dfirst * MM2IN, dlast * MM2IN, azimuth, elevation ); /* * As an aid to debugging, take advantage of the fact that * there are more than 80 columns on UNIX "cards", and * add debugging information to the end of the line to * allow this shotline to be reproduced offline. * -b gives the shotline x, y coordinates when re-running RTG3, * -p and -d are used with RTSHOT * The easy way to activate this is with the harmless -!1 option * when running RTG3. */ if ( R_DEBUG || bu_debug || RT_G_DEBUG ) { bu_vls_printf( &str, " -b%d,%d -p %26.20e %26.20e %26.20e -d %26.20e %26.20e %26.20e\n", ap->a_x, ap->a_y, V3ARGS(ap->a_ray.r_pt), V3ARGS(ap->a_ray.r_dir) ); } else { bu_vls_putc( &str, '\n' ); } /* loop here to deal with individual components */ card_count = 0; prev_id = -1; first = 1; for ( pp=PartHeadp->pt_forw; pp!=PartHeadp; pp=pp->pt_forw ) { /* * The GIFT statements that would have produced * this output are: * do 632 i=icomp, iend * if (clos(icomp).gt.999.99.or.slos(i).gt.999.9) goto 635 * 632 continue * write(1, 633)(item(i), clos(i), cangi(i), cango(i), * & kspac(i), slos(i), i=icomp, iend) * 633 format(1x, 3(i4, f6.2, 2f5.1, i1, f5.1)) * goto 670 * 635 write(1, 636)(item(i), clos(i), cangi(i), cango(i), * & kspac(i), slos(i), i=icomp, iend) * 636 format(1x, 3(i4, f6.1, 2f5.1, i1, f5.0)) */ fastf_t comp_thickness; /* component line of sight thickness */ fastf_t in_obliq; /* in obliquity angle */ fastf_t out_obliq; /* out obliquity angle */ int region_id; /* solid region's id */ int air_id; /* air id */ fastf_t dot_prod; /* dot product of normal and ray dir */ fastf_t air_thickness; /* air line of sight thickness */ vect_t normal; /* surface normal */ register struct partition *nextpp = pp->pt_forw; region_id = pp->pt_regionp->reg_regionid; if ( region_id <= 0 && prev_id > 0 ) { /* air region output with previous partition */ prev_id = region_id; continue; } comp_thickness = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist; /* The below code is meant to catch components with zero or * negative thicknesses. This is not supposed to be possible, * but the condition has been seen. */ #if 0 if ( comp_thickness <= 0 ) { VJOIN1( pp->pt_inhit->hit_point, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir ); VJOIN1( pp->pt_outhit->hit_point, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir ); bu_log("ERROR: comp_thickness=%g for region id = %d at h=%g, v=%g (x=%d, y=%d), partition at x%x\n", comp_thickness, region_id, hv[0], hv[1], ap->a_x, ap->a_y, pp ); rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); bu_log("Send this output to the BRL-CAD Developers ([email protected])\n"); if ( ! (RT_G_DEBUG & DEBUG_ARB8)) { rt_g.debug |= DEBUG_ARB8; rt_shootray(ap); rt_g.debug &= ~DEBUG_ARB8; } } #endif if ( nextpp == PartHeadp ) { if ( region_id <= 0 ) { /* last partition is air, need a 111 'phantom armor' before AND after */ bu_log( "WARNING: adding 'phantom armor' (id=111) with zero thickness before and after air region %s\n", pp->pt_regionp->reg_name ); region_id = 111; air_id = pp->pt_regionp->reg_aircode; air_thickness = comp_thickness; comp_thickness = 0.0; } else { /* Last partition, no air follows, use code 9 */ air_id = 9; air_thickness = 0.0; } } else if ( region_id <= 0 ) { /* air region, need a 111 'phantom armor' */ bu_log( "WARNING: adding 'phantom armor' (id=111) with zero thickness before air region %s\n", pp->pt_regionp->reg_name ); prev_id = region_id; region_id = 111; air_id = pp->pt_regionp->reg_aircode; air_thickness = comp_thickness; comp_thickness = 0.0; } else if ( nextpp->pt_regionp->reg_regionid <= 0 && nextpp->pt_regionp->reg_aircode != 0 ) { /* Next partition is air region */ air_id = nextpp->pt_regionp->reg_aircode; air_thickness = nextpp->pt_outhit->hit_dist - nextpp->pt_inhit->hit_dist; prev_id = air_id; } else { /* 2 solid regions, maybe with gap */ air_id = 0; air_thickness = nextpp->pt_inhit->hit_dist - pp->pt_outhit->hit_dist; if ( air_thickness < 0.0 ) air_thickness = 0.0; if ( !NEAR_ZERO( air_thickness, 0.1 ) ) { air_id = 1; /* air gap */ if ( R_DEBUG & RDEBUG_HITS ) bu_log("air gap added\n"); } else { air_thickness = 0.0; } prev_id = region_id; } /* * Compute the obliquity angles in degrees, ie, * the "declension" angle down off the normal vector. * RT normals always point outwards; * the "inhit" normal points opposite the ray direction, * the "outhit" normal points along the ray direction. * Hence the one sign change. * XXX this should probably be done with atan2() */ if ( first ) { first = 0; VJOIN1( first_hit, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir ); } out: RT_HIT_NORMAL( normal, pp->pt_inhit, pp->pt_inseg->seg_stp, &(ap->a_ray), pp->pt_inflip ); dot_prod = VDOT( ap->a_ray.r_dir, normal ); if ( dot_prod > 1.0 ) dot_prod = 1.0; if ( dot_prod < -1.0 ) dot_prod = (-1.0); in_obliq = acos( -dot_prod ) * bn_radtodeg; RT_HIT_NORMAL( normal, pp->pt_outhit, pp->pt_outseg->seg_stp, &(ap->a_ray), pp->pt_outflip ); dot_prod = VDOT( ap->a_ray.r_dir, normal ); if ( dot_prod > 1.0 ) dot_prod = 1.0; if ( dot_prod < -1.0 ) dot_prod = (-1.0); out_obliq = acos( dot_prod ) * bn_radtodeg; /* Check for exit obliquties greater than 90 degrees. */ #if 0 if ( in_obliq > 90 || in_obliq < 0 ) { bu_log("ERROR: in_obliquity=%g\n", in_obliq); rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); } if ( out_obliq > 90 || out_obliq < 0 ) { bu_log("ERROR: out_obliquity=%g\n", out_obliq); VPRINT(" r_dir", ap->a_ray.r_dir); VPRINT("normal", normal); bu_log("dot=%g, acos(dot)=%g\n", VDOT( ap->a_ray.r_dir, normal ), acos( VDOT( ap->a_ray.r_dir, normal ) ) ); /* Print the defective one */ rt_pr_pt( ap->a_rt_i, pp ); /* Print the whole ray's partition list */ rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:"); } #endif if ( in_obliq > 90.0 ) in_obliq = 90.0; if ( in_obliq < 0.0 ) in_obliq = 0.0; if ( out_obliq > 90.0 ) out_obliq = 90.0; if ( out_obliq < 0.0 ) out_obliq = 0.0; /* * Handle 3-components per card output format, with * a leading space in front of the first component. */ if ( card_count == 0 ) { bu_vls_strcat( &str, " " ); } comp_thickness *= MM2IN; /* Check thickness fields for format overflow */ if ( comp_thickness > 999.99 || air_thickness*MM2IN > 999.9 ) fmt = "%4d%6.1f%5.1f%5.1f%1d%5.0f"; else fmt = "%4d%6.2f%5.1f%5.1f%1d%5.1f"; #ifdef SPRINTF_NOT_PARALLEL bu_semaphore_acquire( BU_SEM_SYSCALL ); #endif snprintf(buf, 128, fmt, region_id, comp_thickness, in_obliq, out_obliq, air_id, air_thickness*MM2IN ); #ifdef SPRINTF_NOT_PARALLEL bu_semaphore_release( BU_SEM_SYSCALL ); #endif bu_vls_strcat( &str, buf ); card_count++; if ( card_count >= 3 ) { bu_vls_strcat( &str, "\n" ); card_count = 0; } /* A color rtg3.pl UnixPlot file of output commands * is generated. This is processed by plot(1) * plotting filters such as pl-fb or pl-sgi. * Portions of a ray passing through air within the * model are represented in blue, while portions * passing through a solid are assigned green. * This will always be done single CPU, * to prevent output garbling. (See view_init). */ if (R_DEBUG & RDEBUG_RAYPLOT) { vect_t inpt; vect_t outpt; VJOIN1(inpt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir); VJOIN1(outpt, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir); pl_color(plotfp, 0, 255, 0); /* green */ pdv_3line(plotfp, inpt, outpt); if (air_thickness > 0) { vect_t air_end; VJOIN1(air_end, ap->a_ray.r_pt, pp->pt_outhit->hit_dist + air_thickness, ap->a_ray.r_dir); pl_color(plotfp, 0, 0, 255); /* blue */ pdv_3cont(plotfp, air_end); } } if ( nextpp == PartHeadp && air_id != 9 ) { /* need to output a 111 'phantom armor' at end of shotline */ air_id = 9; air_thickness = 0.0; region_id = 111; comp_thickness = 0.0; goto out; } } /* If partway through building the line, add a newline */ if ( card_count > 0 ) { /* * Note that GIFT zero-fills the unused component slots, * but neither COVART II nor COVART III require it, * so just end the line here. */ bu_vls_strcat( &str, "\n" ); } /* Single-thread through file output. * COVART will accept non-sequential ray data provided the * ray header and its associated data are not separated. CAVEAT: * COVART will not accept headers out of sequence. */ bu_semaphore_acquire( BU_SEM_SYSCALL ); fputs( bu_vls_addr( &str ), outfp ); if ( shot_fp ) { fprintf( shot_fp, "%.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %ld %.5f %.5f %.5f\n", azimuth, elevation, V3ARGS( ap->a_ray.r_pt ), V3ARGS( ap->a_ray.r_dir ), line_num, V3ARGS( first_hit) ); line_num += 1 + (comp_count / 3 ); if ( comp_count % 3 ) line_num++; } /* End of single-thread region */ bu_semaphore_release( BU_SEM_SYSCALL ); /* Release vls storage */ bu_vls_free( &str ); return(0); }
/* The bu_vls_vprintf function aims to adhere to the following specifications: 1. First, follow the POSIX man page at "http://www.unix.com/man-page/POSIX/3/printf/" regarding the definition of a format specifier. 2. Then modify [1] to accommodate a compatible subset of parts applicable to a wide range of standard C libraries including GNU/Linux, Windows, FreeBSD, and others as differences are brought to our attention. 3. The subset [2] shall be the "valid" flags, length modifiers, and conversion specifiers ("parts") accepted by this function. Those are defined in the following local function: format_part_status 4. Parts known to be defined outside subset [3] shall generate a message stating such invalidity and giving a suitable alternative if possible (such parts will be called "obsolete"); otherwise, the part shall be said to be "unsupported." 5. Parts seen by this function but not defined above shall be deemed "unknown" and result in a suitable message. 6. Library users of this function receiving "unknown" messages while attempting to use valid parts according to their O/S and compiler need to contact the BRL-CAD developers to resolve the issue. Resolution should normally result in assigning the "unknown" part to one of the categories described in [4]. */ void bu_vls_vprintf(struct bu_vls *vls, const char *fmt, va_list ap) { const char *sp; /* start pointer */ const char *ep; /* end pointer */ int len; /* flag variables are reset for each fmt specifier */ vflags_t f; char buf[BUFSIZ] = {0}; int c; struct bu_vls fbuf = BU_VLS_INIT_ZERO; /* % format buffer */ char *fbufp = NULL; if (UNLIKELY(!vls || !fmt || fmt[0] == '\0')) { /* nothing to print to or from */ return; } BU_CK_VLS(vls); bu_vls_extend(vls, (unsigned int)_VLS_ALLOC_STEP); sp = fmt; while (*sp) { /* Initial state: just printing chars */ fmt = sp; while (*sp != '%' && *sp) sp++; if (sp != fmt) bu_vls_strncat(vls, fmt, (size_t)(sp - fmt)); if (*sp == '\0') break; /* Saw a percent sign, now need to find end of fmt specifier */ /* All flags get reset for this fmt specifier */ reset_vflags(&f); ep = sp; while ((c = *(++ep))) { if (c == ' ' || c == '#' || c == '+' || c == '\'' ) { /* skip */ } else if (c == '.') { f.have_dot = 1; } else if (isdigit(c)) { /* skip */ } else if (c == '-') { /* the first occurrence before a dot is the left-justify flag, but the occurrence AFTER a dot is taken to be zero precision */ if (f.have_dot) { f.precision = 0; f.have_digit = 0; } else if (f.have_digit) { /* FIXME: ERROR condition?: invalid format string (e.g., '%7.8-f') */ /* seems as if the fprintf man page is indefinite here, looks like the '-' is passed through and appears in output */ ; } else { f.left_justify = 1; } } else if (c == '*') { /* the first occurrence is the field width, but the second occurrence is the precision specifier */ if (!f.have_dot) { f.fieldlen = va_arg(ap, int); f.flags |= FIELDLEN; } else { f.precision = va_arg(ap, int); f.flags |= PRECISION; } /* all length modifiers below here */ } else if (format_part_status(c) == (VP_VALID | VP_LENGTH_MOD)) {