[comp.sources.unix] v11i100: Graphics editor for Suns, Part04/06

rsalz@uunet.UU.NET (Rich Salz) (10/07/87)

Submitted-by: steinmetz!sbcs!nyfca1!chan (Douglas Chan)
Posting-number: Volume 11, Issue 100
Archive-name: graphedit/part04

# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Contents:  core.c
 
echo x - core.c
sed 's/^@//' > "core.c" <<'@//E*O*F core.c//'

static char SccsId[] = "@(#)core.c	1.2 6/8/87 Copyright 1987 SBCS-chan";

/*****************************************************************************

          (c) Copyright 1987 

          Lap-Tak Chan
          Computer Science Department
          State University of New York at Stony Brook
          Stony Brook, NY 11794

    This software and its documentation may be used, copied, and
  distributed, provided that this legend appear in all copies and
  that it is not copied or distributed for a profit.

  No representations is made about the suitability of this software
  for any purpose.  It is provided "as is" with no support and no
  express or implied warranty.

*****************************************************************************/

/*****************************************************************************

                        SunCore Interface
                        =================

    This file contains a package of routines used by graphedit as interface
  to SunCore, which is used to maintain the display on the view surface and
  to obtain mouse input from the view surface.

*****************************************************************************/

#include <usercore.h>
#include <math.h>
#include <stdio.h>
#include "display.h"
#include "suntool/sunview.h"
#include "suntool/panel.h"

/* something from demolib.h */
struct	vwsurf	*get_view_surface(/* (struct vwsurf *), argv */);
struct	vwsurf	*get_surface(/* (struct vwsurf *), argv */);
static	struct	vwsurf	Core_vwsurf;
struct	vwsurf	*our_surface = &Core_vwsurf; /* our view surface */

/* pixrect device handlers */
static int cg1dd();
static int gp1dd();
static int cg2dd();
static int cg4dd(); /* only on Sun 3.2 and latter */
static int cgpixwindd();
static int pixwindd();
static int gp1pixwindd();

#define MAPSIZE		256
#define GE_TMPSEG 100000

/* The following two level mapping of colors can actually be reduced to
   one level */
/* entries in colormap used */
static int colortable[] = {   0,  1,  20,  40, 63 , 85, 105,
				127, 147, 167, 191, 253, 254, 255 };

/* mapping between graphedit colors from 0-11 to colors in colortable */
static int clrmap[] =
{ 1,2,3,4,5,6,7,8,9,10,11,13};

/* color table values for b/w screens */
static float redlist[MAPSIZE], grnlist[MAPSIZE], blulist[MAPSIZE];
/*  1     2     3     4     5     6     7     8    9    10    11   12 */
static float redtex[] =
{0.,.7334,.7922,.6667,.7765,.6589,.6589,.2667,.5334,.0314,.0235,.0157,0.,.0};
static float grntex[] =
{0.,.5334,.1922,.5334,.0667,.1922,.0667,.5334,.5334,.0667,.0667,.0667,0.,.2667 };
static float blutex[] =
{0.,.4001,.0000,.4001,.4001,.0000,.4001,.4001,.4001,.4001,.4001,.4001,0.,.3882};

/* color table values for color screens */
static float credtex[]=
{1.,.95,.9,.8,.75,.7,.6,.5,.4,.3,.2,.1,1.,0.};
static float cgrntex[]=
{1.,.95,.9,.8,.75,.7,.6,.5,.4,.3,.2,.1,1.,0.};
static float cblutex[]=
{1.,.95,.9,.8,.75,.7,.6,.5,.4,.3,.2,.1,1.,0.};

/*****************************************************************************

    set_up_core will create the view surface, initialize the input devices,
  and setup the color table.

*****************************************************************************/

set_up_core(argv)
char *argv[];
{
    int colorflag,i;
    float white=1.0;
    static char default_cood[]="301,0,851,650,512,836,64,64,0";
    static char *ptrs[]={default_cood, (char *)0};

    /* start up SunCore */
    if ( initialize_core(DYNAMICC, SYNCHRONOUS, TWOD)) exit(0);

    /* get what device the view surface will be created on */
    get_view_surface(our_surface,argv);

    /* create a new window if view surface will be created in
       suntools */
    if ( (our_surface->dd == pixwindd) ||
         (our_surface->dd == cgpixwindd) ||
         (our_surface->dd == gp1pixwindd) ) {

      our_surface->flags=1;
    }

    /* actually create the view surface */
    our_surface->ptr = ptrs;
    our_surface->cmapsize = MAPSIZE;
    our_surface->cmapname[0] = '\0';
    if (initialize_view_surface( our_surface, FALSE)) exit(0);

    /* initailize the input devices */
    initialize_device( BUTTON, 1);
    initialize_device( BUTTON, 2);
    initialize_device( BUTTON, 3);
    initialize_device( LOCATOR, 1);
    initialize_device( PICK, 1);
    set_echo_position( LOCATOR, 1, 0., 0.);
    set_echo_surface( LOCATOR, 1, our_surface);
    set_echo_surface( PICK, 1, our_surface);
    set_pick(1,0.01);
    set_echo( PICK, 1,1);

    /* initailize view surface */
    set_window(0.,GE_WIN_X,0.,GE_WIN_Y);
    set_viewport_2( 0.,1.,0., .75);	/* init viewing transform */
    set_window_clipping(FALSE);
    set_output_clipping(TRUE);
    select_view_surface(our_surface);
    set_image_transformation_type(XFORM2);
    set_primitive_attributes( &PRIMATTS);
    set_charprecision(CHARACTER);

    /* check whether view surface is on color device */
    if((our_surface->dd == cg1dd) || (our_surface->dd == cgpixwindd) ||
       (our_surface->dd == cg2dd) || (our_surface->dd == gp1dd)      ||
       (our_surface->dd == cg4dd) || (our_surface->dd == gp1pixwindd))
	colorflag=TRUE;
    else
	colorflag=FALSE;

    if(!colorflag) {
        /* colormap for b/w device */
        for (i=0;i<14;i++) {
            redlist[colortable[i]]=redtex[i];
            grnlist[colortable[i]]=grntex[i];
            blulist[colortable[i]]=blutex[i];
        }
     }
     else {
        /* colormap for color device */
        for (i=0;i<14;i++) {
            redlist[colortable[i]]=credtex[i];
            grnlist[colortable[i]]=cgrntex[i];
            blulist[colortable[i]]=cblutex[i];
         }
        set_line_index(colortable[13]);
        set_text_index(colortable[13]);
      } /* if */

    /* setup the color map */
    define_color_indices(our_surface,0,MAPSIZE-1,redlist,grnlist,blulist);

    /* create the crosshair used by ge_locator */
    ge_crosshair();

} /* set_up_core */

/*****************************************************************************

    ge_crosshair will create the crosshair used by ge_locator.

*****************************************************************************/

#define CROSSHAIRSZ 2.5	/* size of crosshair */

ge_crosshair()
{

  create_retained_segment(GE_CROSSHAIR);
  set_segment_visibility(GE_CROSSHAIR,0);
  move_abs_2(0., -CROSSHAIRSZ);
  line_abs_2(0., CROSSHAIRSZ);
  move_abs_2(-CROSSHAIRSZ, 0.);
  line_abs_2(CROSSHAIRSZ, 0.);
  close_retained_segment();

} /* ge_crosshair */

/*****************************************************************************

    do_exit will terminate the SunCore view surface.

*****************************************************************************/

do_exit()
{
   terminate_device( LOCATOR, 1);
   deselect_view_surface(our_surface);
   terminate_view_surface(our_surface);
   terminate_core();
} /* do_exit */

/*****************************************************************************

    ge_locator will read the mouse input within the view surface.  It 
  behaves differently according to echo.

  Input
    echo - if negative, read the current status of the mouse and
           return immediately
           otherwise, return the status of the mouse when any of the
           buttons is hit
           The mouse input will be echoed according to the value
           of abs(echo) as how the locator in Suncore is echoed:
             0 - no echo
             1 - pointing finger
             2 - line connecting from (x,y) to mouse location
             3 - line connecting from (x,y) to x coordinate of mouse
             4 - line connecting from (x,y) to y coordinate of mouse
             5 - line connecting from (x,y) to x or y coordinate of mouse,
                 whichever is further
             6 - a box with (x,y) as one corner and mouse location the other
                 corner

    x,y - world coordinate used by echo

  Output
    butnum - number of button hit, 0 if no button was hit
    x,y - world coordinate of mouse location

*****************************************************************************/

ge_locator(echo, butnum, x, y)
int *butnum, echo;
float *x, *y;
{
  float nx, ny;
  int wait_int; /* how long (in ms) to wait */

  /* decide how long to wait */
  if ( echo<0 ) {
    echo = - echo;
    wait_int=20;
  }
  else wait_int=100000000;

  /* set the echo reference position */
  if ( echo > 1 ) {
    map_world_to_ndc_2( *x, *y, &nx, &ny );
    set_echo_position(LOCATOR, 1, nx, ny);
  }

  if ( (echo == 1) && (wait_int > 1000) ) {

    /* put cross hair at location read because the location may not be the
       position of the pointing finger */
    set_echo(LOCATOR, 1, 0);
    await_any_button_get_locator_2(200,1,butnum, &nx, &ny);
    set_segment_image_transformation_2(GE_CROSSHAIR,1.,1.,0.,nx,ny);
    set_segment_visibility(GE_CROSSHAIR,1);
    while ( !(*butnum) ) {
      await_any_button_get_locator_2(200,1,butnum, &nx, &ny);
      set_segment_image_transformation_2(GE_CROSSHAIR,1.,1.,0.,nx,ny);
    } /* while */
    set_segment_visibility(GE_CROSSHAIR,0);

  }
  else {
    /* specify the echo and read locator input */
    set_echo(LOCATOR, 1, echo);
    await_any_button_get_locator_2(wait_int,1, butnum, &nx, &ny);
  }

  /* map normal device coordinate back to world coordinate */
  map_ndc_to_world_2(nx, ny, x, y);

} /* ge_locator */

/*****************************************************************************

    ge_tmp_new is used to create a temporary segment to echo a number of
  lines drawn.

  Input
    x,y - world coordinate to start at
    attr - attributes of current segment

*****************************************************************************/

ge_tmp_new(x,y,attr)
float x,y;
struct attr attr;
{
  /* set attributes */
  set_linestyle(attr.linestyle);
  set_linewidth((float)attr.linewidth/5.);

  /* create temporary segment */
  create_retained_segment(GE_TMPSEG);

  /* move to starting point */
  move_abs_2(x,y);

} /* ge_tmp_new */

/*****************************************************************************

    ge_tmp_line is used to continue echo of a number of lines.

    Input
      x,y - world coordinate to draw a line to

*****************************************************************************/

ge_tmp_line(x,y)
float x,y;
{

  line_abs_2(x,y);

} /* ge_tmp_line */

/*****************************************************************************

    ge_tmp_delete will delete the temporary segment created.

*****************************************************************************/

ge_tmp_delete()
{

  close_retained_segment(GE_TMPSEG);
  delete_retained_segment(GE_TMPSEG);

} /* ge_tmp_delete */

/*****************************************************************************

    ge_flush will flush all previous mouse input.

*****************************************************************************/

ge_flush()
{
  int butnum;
  float x,y;

  do {
    await_any_button_get_locator_2(0,1, &butnum, &x, &y);
  } while ( butnum );

} /* ge_flush */

/*****************************************************************************

    ge_pick is used to pick a segment.  It will flush previous input and
  wait for the user to pick a segment.

  Output
    Return number of segment picked.

*****************************************************************************/

ge_pick()
{
  int segno;
  int pickid;

  /* flush previous input */
  ge_flush();

  /* pick segment */
  await_pick(1000000000, 1, &segno, &pickid);
  return(segno);

} /* ge_pick */

/*****************************************************************************

    ge_draw will update the display of a segment on the view surface.
  If the segment is marked deleted, the segment will be make invisible on
  the display.  If the segment has been drawn, the old image on the view
  surface will be erased.

    To minimize the time between the old image is erased and the new
  image is drawn, the new image is first drawn in an invisible
  temporary segment.  The old image is then deleted and the new
  temporary segment renamed to be the segment.

  Input
    segno - number of segment to draw

*****************************************************************************/

/* map graphedit linestyle to SunCore linestyle */
static int linestyle_menu[]=
{SOLID,DOTTED,DASHED,DOTDASHED};

/* map graphedit font to SunCore font */
static int font_menu[]=
{STICK,ROMAN,GREEK,SCRIPT,OLDENGLISH};

/* table to adjust width of font in SunCore so that they will have
   proportional width with fonts in PostScript */
static float charwidthfactor[] = { 1.28, 1.54, 1.42, 1.49, 1.48 };
static int segmentfont, segmentcharsize;

/* ge_setchar will set the character size according to the graphedit
   character size and font */
#define ge_setchar(size,font) set_charsize((size)/charwidthfactor[(font)],(size)/1.5)

ge_draw(segno)
int segno;
{
  struct list *seginfo, *ge_display_list();
  struct list_item *ptr;
  static struct list_item closeinstr={GE_CLOSE, 0.,0.,NULL};
  float tx,ty;

  /* abort if the display list of the segment cannot be found or is
     empty */
  if ( !((seginfo=ge_display_list(segno)) &&
         (ptr=seginfo->d_list)) )
    return;

  /* set the initial attributes of the segment */
  segmentfont = seginfo->attr.font;
  segmentcharsize = seginfo->attr.charsize;
  set_fill_index(colortable[clrmap[seginfo->attr.color]]);
  set_linestyle(linestyle_menu[seginfo->attr.linestyle]);
  set_linewidth((float)seginfo->attr.linewidth/5.);
  ge_setchar((float)seginfo->attr.charsize,seginfo->attr.font);
  set_font(font_menu[seginfo->attr.font]);

  /* create an invisible temporary segment*/
  create_retained_segment(GE_TMPSEG);
  set_segment_visibility(GE_TMPSEG,0);

  /* scan the display list of the segment to draw the image */
  ptr=ptr->next;
  do {
    ge_exec(ptr);
    ptr=ptr->next;
  } while ( ptr != seginfo->d_list->next );

  /* close the segment */
  ge_exec(&closeinstr);

  /* make user segments detectable and sample segment undetectable */
  if ( segno >= GE_MIN_SEG ) {
    set_segment_detectability(GE_TMPSEG, segno);
  }
  else {
    set_segment_detectability(GE_TMPSEG, 0);
  }

  /* close the temporary segment */
  close_retained_segment(GE_TMPSEG);

  /* set the transformation of the segment */
  map_world_to_ndc_2(seginfo->attr.tx, seginfo->attr.ty, &tx, &ty);
  set_segment_image_transformation_2(GE_TMPSEG,
    seginfo->attr.sx, seginfo->attr.sy,
    seginfo->attr.ang, tx, ty);

  /* delete the old image if the segment has been drawn before */
  if ( seginfo->attr.drawn )
    delete_retained_segment(segno);

  /* make the temporary segment visible */
  set_segment_visibility(GE_TMPSEG,!seginfo->attr.deleted);

  /* rename the temporary segment to be the segment */
  rename_retained_segment(GE_TMPSEG, segno);

  seginfo->attr.drawn=1;

} /* ge_draw */

/*****************************************************************************

    ge_draw_ellipse will draw a ellipse will a number of lines.  The equation
  of the ellipse is

      2      2
     x      y
    ---  + ---  = 1
      2      2
     a      b

  Input
    a, b - parameter in equation
    fill - how the ellipse should be filled/bordered

*****************************************************************************/

#define LINEPERCIRCLE 20 /* number of lines to form a circle */

ge_draw_ellipse(a,b,fill)
float a,b;
int fill;
{
  float i;
  float oldsin, oldcos;
  float tmpsin, tmpcos;
  float intv;
  float ang;
  int count;
  float xbuff[LINEPERCIRCLE+1], ybuff[LINEPERCIRCLE+1];

  intv=2.*PI/LINEPERCIRCLE;
  ang=0.;
  count=1;

  xbuff[0]=a*(oldcos=cos((double)ang));
  ybuff[0]=b*(oldsin=sin((double)ang));

  for (ang=intv; !(ang>(2.1*PI)); ang+=intv) {
    xbuff[count]=a*(-oldcos+(tmpcos=cos((double)ang)));
    ybuff[count++]=b*(-oldsin+(tmpsin=sin((double)ang)));
    oldcos=tmpcos;  oldsin=tmpsin;
  } /* for */

  if ( (fill==GE_FILLONLY) || (fill==GE_FILLBORDER) ) {
    /* fill region */
    polygon_rel_2(xbuff,ybuff,count);
    move_rel_2(-xbuff[0], -ybuff[0]);
  } /* if */

  if ( (fill==GE_BORDERONLY) || (fill==GE_FILLBORDER) ) {
    /* draw border */
    move_rel_2(xbuff[0],ybuff[0]);
    polyline_rel_2(&(xbuff[1]),&(ybuff[1]),count-1);
  } /* if */
 
} /* ge_draw_ellipse */

/*****************************************************************************

    ge_draw_arc will draw an arc with center at current point, from ang1
  to ang2 with radius radius.

  Input
    ang1 - from angle, 0 <= ang1 <= 2PI
    ang2 - to angle, 0 <= ang2 <= 2PI
    radius - radius of arc

*****************************************************************************/

ge_draw_arc(ang1,ang2,radius)
float ang1,ang2,radius;
{
  float intv, ang;
  float oldsin, oldcos, tmpsin, tmpcos;
  int count;
  float xbuff[LINEPERCIRCLE+1], ybuff[LINEPERCIRCLE+1];

  /* ensure that ang1 < ang2 */
  if ( ang1 > ang2 ) {
    ang1 -= 2*PI;
  }

  /* determine the interval */
  intv=2.*PI/LINEPERCIRCLE;
  if ((ang2-ang1) < (3*intv) ) {
    /* a minimum of three lines are drawn for the arc */
    intv = (ang2-ang1)/3;
  }

  /* the first point */
  ang=ang1;
  count=1;
  xbuff[0]=radius*(oldcos=cos((double)ang));
  ybuff[0]=radius*(oldsin=sin((double)ang));

  /* determine the following points */
  for (ang += intv; ang < ang2; ang+=intv) {
    xbuff[count]=radius*(-oldcos+(tmpcos=cos((double)ang)));
    ybuff[count++]=radius*(-oldsin+(tmpsin=sin((double)ang)));
    oldcos=tmpcos;  oldsin=tmpsin;
  }

  /* the last point */
  xbuff[count]=radius*(-oldcos+(cos((double)ang2)));
  ybuff[count++]=radius*(-oldsin+(sin((double)ang2)));

  /* draw the arc */
  move_rel_2(xbuff[0],ybuff[0]);
  polyline_rel_2(&(xbuff[1]),&(ybuff[1]),count-1);

} /* ge_draw_arc */

/*****************************************************************************

    ge_exec will execute an instruction on a display list.

  Input
    ptr - pointer to the instruction

*****************************************************************************/

ge_exec(ptr)
struct list_item *ptr;
{
  static float xbuff[512], ybuff[512];
  static int lastinstr=0;
  static int n=0;
  static int fill=0;

  /* execute last polyline/polygon instruction if instruction indicates
     end of the last instruction */
  if ( lastinstr && ptr->instr != GE_CONT ) {
    switch ( lastinstr ) {
      case GE_POLYLINE :
        polyline_abs_2(xbuff,ybuff,n);
        break;

      case GE_POLYGON : {

        /* do not draw if there are less than 3 points */
        if ( n < 3 ) {
          fill=0;
          break;
        }

        if ( (fill==GE_FILLONLY) || (fill==GE_FILLBORDER) ) {
          /* fill region */
          polygon_abs_2(xbuff,ybuff,n);
        }

        if ( (fill==GE_BORDERONLY) || (fill==GE_FILLBORDER) ) {
          /* draw border */
          move_abs_2(xbuff[n-1],ybuff[n-1]);
          polyline_abs_2(xbuff,ybuff,n);
        }

        fill=0;
        break;
      } /* GE_POLYGON */

      default: ;
    } /* switch */

    lastinstr = n = 0;

  } /* if */

  /* execute new instruction */
  switch ( ptr->instr) {

    /* instructions with single coordinate */
    case GE_MOVE:
      move_abs_2(ptr->x,ptr->y);
      break;

    case GE_LINE:
      line_abs_2(ptr->x,ptr->y);
      break;

    case GE_PLOT:
      move_abs_2(ptr->x,ptr->y);
      line_rel_2(0.,0.);
      break;

    case GE_TEXT:
      text((char *)((int)ptr->x));
      break;

    case GE_FILL:
      fill=(int)ptr->x;
      break;

    /* instruction with two or more coordinates */
    case GE_POLYLINE:
    case GE_POLYGON:
      lastinstr=ptr->instr; /* store instruction */

    case GE_CONT:
      /* save coordinate of polyline/polygon */
      xbuff[n] = ptr->x;
      ybuff[n++]= ptr->y;
      break;

    case GE_CIRCLE:
      ge_draw_ellipse(ptr->x,ptr->x,fill);
      fill = 0;
      break;

    case GE_ELLIPSE:
      ge_draw_ellipse(ptr->x,ptr->y,fill);
      fill = 0;
      break;

    case GE_ARC:
      /* save the angles */
      xbuff[0]=ptr->x;
      ybuff[0]=ptr->y;
      break;

    case GE_ARCEXT:
      ge_draw_arc(xbuff[0],ybuff[0],ptr->x);
      break;

    /* change the attributes of the segment */
    case GE_SETCOLOR:
      set_fill_index(colortable[clrmap[(int)ptr->x]]);
      break;

    case GE_SETTYPELINE:
      set_linestyle(linestyle_menu[(int)ptr->x]);
      break;

    case GE_SETLINEWIDTH:
      set_linewidth(ptr->x/5.);
      break;

    case GE_SETCHARSIZE:
      ge_setchar(ptr->x,segmentfont);
      segmentcharsize = (int) ptr->x;
      break;

    case GE_SETFONT:
      set_font(font_menu[(int)ptr->x]);
      segmentfont = (int)ptr->x;
      ge_setchar(segmentcharsize, segmentfont);
      break;

    case GE_CLOSE:
      break;

    default :
      /* check that all instructions are handled properly */
      fprintf(stderr,
              "Internal Error-Action for instruction %d missing.\n",
              ptr->instr);
      break;

  } /* switch */

} /* ge_exec */

/*****************************************************************************

    ge_redisplay will redraw the segment will any new transformation.

*****************************************************************************/

ge_redisplay(seginfo)
struct list *seginfo;
{
  float tx, ty;

  /* translation should be in ndc */
  map_world_to_ndc_2(seginfo->attr.tx, seginfo->attr.ty, &tx, &ty);
  /* will redraw the segment */
  set_segment_image_transformation_2(seginfo->segno,
                               seginfo->attr.sx, seginfo->attr.sy,
                               seginfo->attr.ang,tx,ty);

} /* ge_redisplay */

/*****************************************************************************

    core_write will write the pixrect image of a region on the view surface
  as a rasterfile on file.

  Input
    file - opened stream to write to
    xmin, ymin - coordinate of a corner of region in world coordinate
    xmax, ymax - coordinate of diagonal corner of region in world coordinate

*****************************************************************************/

core_write(file, xmin, ymin, xmax, ymax)
FILE *file;
float xmin, ymin, xmax, ymax;
{
  struct suncore_raster raster;
  float nx1, ny1, nx2, ny2, tmp;

  /* empty colormap structure for raster_to_file */
  static struct {
    int type;
    int nbytes;
    char *data;
  } color_map = { 0, 0, 0 };

  /* convert coordinates to ndc coordinates */
  map_world_to_ndc_2(xmin, ymin, &nx1, &ny1);
  map_world_to_ndc_2(xmax, ymax, &nx2, &ny2);

  /* make (nx1,ny1) the lower left corner and (nx2,ny2) the upper right
     corner */
  if ( nx2 < nx1 ) {
    tmp = nx1;
    nx1 = nx2;
    nx2 = tmp;
  }
  if ( ny2 < ny1 ) {
    tmp = ny1;
    ny1 = ny2;
    ny2 = tmp;
  }

  /* allocate memory for the pixrect image */
  size_raster(our_surface, nx1, nx2, ny1, ny2, &raster);
  allocate_raster(&raster);

  /* get the pixrect image */
  get_raster(our_surface, nx1, nx2, ny1, ny2, 0, 0, &raster);

  /* write pixrect image as raster file */
  raster_to_file(&raster, &color_map, file->_file, 1);

  /* free memory */
  free_raster(&raster);

} /* core_write */

/*****************************************************************************

    ge_refresh will refresh the view surface.

*****************************************************************************/

ge_refresh()
{

  new_frame();

} /* ge_refresh */
@//E*O*F core.c//
chmod u=r,g=r,o=r core.c
 
echo Inspecting for damage in transit...
temp=/tmp/shar$$; dtemp=/tmp/.shar$$
trap "rm -f $temp $dtemp; exit" 0 1 2 3 15
cat > $temp <<\!!!
     843    2410   23387 core.c
!!!
wc  core.c | sed 's=[^ ]*/==' | diff -b $temp - >$dtemp
if [ -s $dtemp ]
then echo "Ouch [diff of wc output]:" ; cat $dtemp
else echo "No problems found."
fi
exit 0