[comp.sources.x] v08i058: tgif

william@CS.UCLA.EDU (William Cheng) (08/04/90)

Submitted-by: william@CS.UCLA.EDU (William Cheng)
Posting-number: Volume 8, Issue 58
Archive-name: tgif/patch2.01
Patch-To: tgif: Volume 7, Issue 56-76 (original: tgif-1.2)
Patch-To: tgif: Volume 8, Issue 46-48 (Patch1: tgif-1.2 => tgif-1.9)

Patch2 of tgif takes tgif-1.9 to tgif-1.12.  Below is a list of
added features/bug fixes, followed by the actual patch.

tgif-1.9 => tgif-1.10

1) Fix bugs reported by Michael Webb regarding reading very long polygline.
2) Disallow stretching of zero width or zero height objects.
3) Add feature:  Add points and delete points to poly and splines.
4) In case of emergency, save working file in EmergencySave.obj or
   EmergencySave.sym.  (Thanks to Stephen Doyle and Christos Zoulas.)
5) Add XDefault "Tgif*Synchronize" call XSynchronize ().
6) Add -p command line option to prtgif to print encapsulated PostScript
   file.  (Thanks to Stephen Doyle.)

tgif-1.10 => tgif-1.11

1) Fix bugs reported by Christos Zoulas regarding prtgif bounding box.
   Text objects was generating wrong boudning boxes.
2) When text objects are saved, its bounding boxes are also saved now.
   This fixes the problem in 1).  File version is bumped to 7!
3) Fix bugs in select.c (change calls to DelObj () to FreeObj ()).
   This caused segmentation faults when tgif is dbx-ed, it caused
   XError when not dbx-ed.
4) Prtgif is cleaned up to share functions with the tgif code.  (Turned
   out to be a lot of changes.)
5) Add double-clicking in selecting file names.  New Xdefaults
   Tgif*DoubleClickInterval (in milli-seconds) is added.

tgif-1.11 => tgif-1.12

1) Fix bugs related to stretching boxes and ovals.  It used to complain
   that object width or height is ZERO while it's not.
2) Fix a minor bug related to a seg fault when exiting tgif.  This doesn't
   really cause problem before.

---------------------------------> cut here <---------------------------------
*** attr.c.orig	Thu Aug  2 09:42:50 1990
--- attr.c	Thu Aug  2 09:42:52 1990
***************
*** 6,10 ****
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/attr.c,v 1.4 90/06/26 00:03:55 william Exp $";
  #endif
  
--- 6,10 ----
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/attr.c,v 1.6 90/07/30 11:09:21 william Exp $";
  #endif
  
***************
*** 484,488 ****
  static
  char * ReadAttrString (Str)
!    char *	Str;
  {
     register char	* s = Str;
--- 484,488 ----
  static
  char * ReadAttrString (Str)
!    char	* Str;
  {
     register char	* s = Str;
***************
*** 496,502 ****
  }
  
! int  ReadAttr (FP, AttrPtr)
     FILE			* FP;
     struct AttrRec	* * AttrPtr;
  {
     struct ObjRec	* TextObj;
--- 496,503 ----
  }
  
! int ReadAttr (FP, AttrPtr, PRTGIF)
     FILE			* FP;
     struct AttrRec	* * AttrPtr;
+    int			PRTGIF;
  {
     struct ObjRec	* TextObj;
***************
*** 505,509 ****
     int			len, shown, nameshown, inherited;
   
!    fgets (inbuf, 255, FP); 
  
     if (inbuf[0] == ']')  return (FALSE);
--- 506,510 ----
     int			len, shown, nameshown, inherited;
   
!    fgets (inbuf, MAXSTRING, FP); 
  
     if (inbuf[0] == ']')  return (FALSE);
***************
*** 533,537 ****
     (*AttrPtr)->inherited = inherited;
  
!    ReadObj (FP, &TextObj);
     TextObj->detail.t->attr = *AttrPtr;
     (*AttrPtr)->obj = TextObj;
--- 534,538 ----
     (*AttrPtr)->inherited = inherited;
  
!    ReadObj (FP, &TextObj, PRTGIF);
     TextObj->detail.t->attr = *AttrPtr;
     (*AttrPtr)->obj = TextObj;
***************
*** 1015,1019 ****
     int			* fore_colors, * pixel_ptr, * valid, * flag_ptr;
     int			len1, len2;
!    char			* * attrStrs, * s, buf[256], msg[80];
     unsigned int		button;
  
--- 1016,1020 ----
     int			* fore_colors, * pixel_ptr, * valid, * flag_ptr;
     int			len1, len2;
!    char			* * attrStrs, * s, buf[MAXSTRING], msg[80];
     unsigned int		button;
  
*** box.c.orig	Thu Aug  2 09:43:01 1990
--- box.c	Thu Aug  2 09:43:02 1990
***************
*** 6,10 ****
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/box.c,v 1.4 90/06/26 00:04:27 william Exp $";
  #endif
  
--- 6,10 ----
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/box.c,v 1.5 90/07/16 10:29:15 william Exp $";
  #endif
  
***************
*** 19,24 ****
  #include "grid.e"
  #include "obj.e"
- #include "poly.e"
  #include "pattern.e"
  #include "raster.e"
  #include "ruler.e"
--- 19,24 ----
  #include "grid.e"
  #include "obj.e"
  #include "pattern.e"
+ #include "poly.e"
  #include "raster.e"
  #include "ruler.e"
*** color.c.orig	Thu Aug  2 09:43:08 1990
--- color.c	Thu Aug  2 09:43:10 1990
***************
*** 6,10 ****
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/color.c,v 1.9 90/06/26 00:04:37 william Exp $";
  #endif
  
--- 6,10 ----
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/color.c,v 1.11 90/07/31 15:11:08 william Exp $";
  #endif
  
***************
*** 368,370 ****
--- 368,384 ----
     if (index != INVALID) ChangeAllSelColor (index);
     cfree (pixmap);
+ }
+ 
+ void CleanUpColors ()
+ {
+    register int	i;
+ 
+    cfree (colorPixels);
+    cfree (xorColorPixels);
+    if (colorDisplay) for (i = 0; i < maxColors; i++) cfree (colorMenuItems[i]);
+    cfree (colorMenuItems);
+ 
+    maxColors = MAXCOLORS;
+    defaultColorIndex = 4;
+    colorIndex = 0;
  }
*** cursor.c.orig	Thu Aug  2 09:43:16 1990
--- cursor.c	Thu Aug  2 09:43:17 1990
***************
*** 6,10 ****
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/cursor.c,v 1.2 90/05/22 14:08:44 william Exp $";
  #endif
  
--- 6,10 ----
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/cursor.c,v 1.5 90/07/16 10:31:01 william Exp $";
  #endif
  
***************
*** 11,16 ****
  #include <X11/Xlib.h>
  #include <X11/cursorfont.h>
- #include "types.h"
  #include "const.h"
  
  #include "choice.e"
--- 11,16 ----
  #include <X11/Xlib.h>
  #include <X11/cursorfont.h>
  #include "const.h"
+ #include "types.h"
  
  #include "choice.e"
*** dialog.c.orig	Thu Aug  2 09:43:24 1990
--- dialog.c	Thu Aug  2 09:43:25 1990
***************
*** 6,10 ****
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/dialog.c,v 1.4 90/05/25 13:36:58 william Exp $";
  #endif
  
--- 6,10 ----
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/dialog.c,v 1.5 90/07/12 09:01:47 william Exp $";
  #endif
  
***************
*** 117,121 ****
           key_code = key_ev->keycode;
           XLookupString (key_ev, buf, 80, &key_sym, &c_stat);
!          if ((buf[0]=='\r' && (key_sym & 0xff)=='\r') ||
                 (buf[0]=='\n' && (key_sym & 0xff)=='\n') ||
                 (buf[0]=='\b' && (key_sym & 0xff)=='\b') ||
--- 117,122 ----
           key_code = key_ev->keycode;
           XLookupString (key_ev, buf, 80, &key_sym, &c_stat);
!          if ((buf[0]=='\033' && (key_sym & 0xff)=='\033') ||
!                (buf[0]=='\r' && (key_sym & 0xff)=='\r') ||
                 (buf[0]=='\n' && (key_sym & 0xff)=='\n') ||
                 (buf[0]=='\b' && (key_sym & 0xff)=='\b') ||
***************
*** 127,130 ****
--- 128,135 ----
              switch (buf[0])
              {
+                case '\033':
+                   ReturnStr[0] = '\0';
+                   dialoging = FALSE;
+                   break;
                 case '\r':
                 case '\n':
*** drawing.c.orig	Thu Aug  2 09:43:40 1990
--- drawing.c	Thu Aug  2 09:43:42 1990
***************
*** 6,10 ****
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/drawing.c,v 1.3 90/05/22 14:10:35 william Exp $";
  #endif
  
--- 6,10 ----
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/drawing.c,v 1.8 90/07/29 15:34:38 william Exp $";
  #endif
  
***************
*** 30,35 ****
  #include "menu.e"
  #include "msg.e"
- #include "oval.e"
  #include "obj.e"
  #include "pattern.e"
  #include "poly.e"
--- 30,35 ----
  #include "menu.e"
  #include "msg.e"
  #include "obj.e"
+ #include "oval.e"
  #include "pattern.e"
  #include "poly.e"
***************
*** 471,475 ****
              case '\016': /*^N*/ NewProc (); break;
              case '\017': /*^O*/ OpenProc (); break;
!             case '\020': /*^P*/ Dump (); break;
              case '\021': /*^Q*/ return (QuitProc ());
              case '\022': /*^R*/ ClearAndRedrawDrawWindow (); break;
--- 471,475 ----
              case '\016': /*^N*/ NewProc (); break;
              case '\017': /*^O*/ OpenProc (); break;
!             case '\020': /*^P*/ Dump (FALSE, ""); break;
              case '\021': /*^Q*/ return (QuitProc ());
              case '\022': /*^R*/ ClearAndRedrawDrawWindow (); break;
***************
*** 530,537 ****
           switch (buf[0])
           {
!             case '\001': /*^#A*/ break;
              case '\002': /*^#B*/ ChangeFontStyle (STYLE_BR); break;
              case '\003': /*^#C*/ ChangeFontJust (JUST_C); break;
!             case '\004': /*^#D*/ break;
              case '\005': /*^#E*/ break;
              case '\006': /*^#F*/ break;
--- 530,537 ----
           switch (buf[0])
           {
!             case '\001': /*^#A*/ AddPoint (); break;
              case '\002': /*^#B*/ ChangeFontStyle (STYLE_BR); break;
              case '\003': /*^#C*/ ChangeFontJust (JUST_C); break;
!             case '\004': /*^#D*/ DeletePoint (); break;
              case '\005': /*^#E*/ break;
              case '\006': /*^#F*/ break;
***************
*** 552,556 ****
              case '\025': /*^#U*/ break;
              case '\026': /*^#V*/ SetCurChoice (DRAWCIRCLE); break;
!             case '\027': /*^#W*/ break;
              case '\030': /*^#X*/ break;
              case '\031': /*^#Y*/ break;
--- 552,556 ----
              case '\025': /*^#U*/ break;
              case '\026': /*^#V*/ SetCurChoice (DRAWCIRCLE); break;
!             case '\027': /*^#W*/ ToggleAllSelLineType (); break;
              case '\030': /*^#X*/ break;
              case '\031': /*^#Y*/ break;
*** dup.c.orig	Thu Aug  2 09:43:49 1990
--- dup.c	Thu Aug  2 09:43:51 1990
***************
*** 6,10 ****
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/dup.c,v 1.2 90/06/26 00:04:49 william Exp $";
  #endif
  
--- 6,10 ----
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/dup.c,v 1.3 90/07/08 00:29:43 william Exp $";
  #endif
  
***************
*** 306,308 ****
--- 306,342 ----
     HighLightForward ();
     SetFileModified (TRUE);
+ }
+ 
+ void JustDupSelObj (NewTopSel, NewBotSel)
+    struct SelRec	* * NewTopSel, * * NewBotSel;
+ {
+    struct SelRec	* sel_ptr, * new_sel_ptr;
+    struct ObjRec	* obj_ptr, * top_obj, * bot_obj;
+ 
+    *NewTopSel = *NewBotSel = NULL;
+    if (topSel == NULL) return;
+ 
+    top_obj = bot_obj = NULL;
+    for (sel_ptr = botSel; sel_ptr != NULL; sel_ptr = sel_ptr->prev)
+    {
+       obj_ptr = DupObj (sel_ptr->obj);
+       obj_ptr->next = top_obj;
+       new_sel_ptr = (struct SelRec *) calloc (1, sizeof (struct SelRec));
+       new_sel_ptr->next = *NewTopSel;
+       new_sel_ptr->obj = obj_ptr;
+       if (top_obj == NULL)
+       {
+          bot_obj = obj_ptr;
+          *NewBotSel = new_sel_ptr;
+       }
+       else
+       {
+          top_obj->prev = obj_ptr;
+          (*NewTopSel)->prev = new_sel_ptr;
+       }
+       top_obj = obj_ptr;
+       *NewTopSel = new_sel_ptr;
+    }
+    top_obj->prev = NULL;
+    (*NewTopSel)->prev = NULL;
  }
*** edit.c.orig	Thu Aug  2 09:43:59 1990
--- edit.c	Thu Aug  2 09:44:01 1990
***************
*** 6,13 ****
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/edit.c,v 1.2 90/06/26 00:04:59 william Exp $";
  #endif
  
  #include <stdio.h>
  #include <X11/Xlib.h>
  #include "const.h"
--- 6,14 ----
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/edit.c,v 1.6 90/07/13 12:51:58 william Exp $";
  #endif
  
  #include <stdio.h>
+ #include <math.h>
  #include <X11/Xlib.h>
  #include "const.h"
***************
*** 16,29 ****
--- 17,41 ----
  #include "align.e"
  #include "color.e"
+ #include "cursor.e"
  #include "drawing.e"
  #include "dup.e"
+ #include "font.e"
  #include "group.e"
  #include "mark.e"
  #include "obj.e"
+ #include "poly.e"
  #include "raster.e"
  #include "select.e"
  #include "setup.e"
+ #include "spline.e"
  #include "stretch.e"
  
+ #define OFFSET_X(x) (((x) - drawOrigX) >> zoomScale)
+ #define OFFSET_Y(y) (((y) - drawOrigY) >> zoomScale)
+ #define MARK(X,Y) \
+       XFillRectangle(mainDisplay,drawWindow,revDefaultGC,(X)-2,(Y)-2,5,5)
+ #define MyDashedLine(W,GC,V,N) XDrawLines (mainDisplay, W, GC, V, N, \
+       CoordModeOrigin)
+ 
  #define EDIT_REDRAW 0
  #define EDIT_DUP 1
***************
*** 31,44 ****
  #define EDIT_SELALL 3
  #define EDIT_UNDODEL 4
! #define MAXEDITMENUS 5
  
  static char * editMenuStr[] =
!       { "Redraw     ^R",
!         "Duplicate  ^D",
!         "Delete     ^X",
!         "SelectAll  ^A",
!         "UndoDelete #U"
        };
  
  void EditMenu (X, Y)
     int	X, Y;
--- 43,664 ----
  #define EDIT_SELALL 3
  #define EDIT_UNDODEL 4
! #define EDIT_DEL_POINT 5
! #define EDIT_ADD_POINT 6
  
+ #define MAXEDITMENUS 7
+ 
  static char * editMenuStr[] =
!       { "Redraw       ^R",
!         "Duplicate    ^D",
!         "Delete       ^X",
!         "SelectAll    ^A",
!         "UndoDelete   #U",
!         "DeletePoint ^#D",
!         "AddPoint    ^#A"
        };
  
+ void DeletePoint ()
+ {
+    register int			i;
+    register struct ObjRec	* obj_ptr;
+    struct PolyRec		* poly_ptr;
+    struct PolygonRec		* polygon_ptr;
+    int				index, n, point_deleted, deleting = TRUE;
+    int				root_x, root_y, old_x, old_y;
+    unsigned int			status;
+    Window			root_win, child_win;
+    XEvent			input;
+ 
+    if (!(topSel != NULL && topSel == botSel &&
+          (topSel->obj->type == OBJ_POLY || topSel->obj->type == OBJ_POLYGON)))
+    {
+       Msg ("Please select only one POLY or POLYGON object.");
+       return;
+    }
+ 
+    obj_ptr = topSel->obj;
+    switch (obj_ptr->type)
+    {
+       case OBJ_POLY: poly_ptr = obj_ptr->detail.p; break;
+       case OBJ_POLYGON: polygon_ptr = obj_ptr->detail.g; break;
+    }
+    TwoLineMsg ("Click left mouse button to DELETE points.",
+          "Click other buttons to quit.");
+ 
+    XGrabPointer (mainDisplay, drawWindow, False,
+          PointerMotionMask | ButtonPressMask,
+          GrabModeAsync, GrabModeAsync, None, defaultCursor, CurrentTime);
+    XQueryPointer (mainDisplay, drawWindow, &root_win, &child_win,
+          &root_x, &root_y, &old_x, &old_y, &status);
+    XDrawString (mainDisplay, drawWindow, revDefaultGC,
+          old_x+4, old_y+defaultFontAsc, "DEL", 3);
+    MarkRulers (old_x, old_y);
+ 
+    while (deleting)
+    {
+       XNextEvent (mainDisplay, &input);
+       if (input.type == ButtonPress)
+       {
+          if (input.xbutton.button == Button1)
+          {
+             point_deleted = FALSE;
+             if (obj_ptr->type == OBJ_POLY &&
+                   PtInPolyMark (input.xbutton.x, input.xbutton.y,
+                   poly_ptr->n, poly_ptr->vlist, &index) ||
+                   obj_ptr->type == OBJ_POLYGON &&
+                   PtInPolyMark (input.xbutton.x, input.xbutton.y,
+                   polygon_ptr->n-1, polygon_ptr->vlist, &index))
+             {
+                point_deleted = TRUE;
+                HighLightReverse ();
+                if (obj_ptr->type == OBJ_POLY && poly_ptr->n == 2 ||
+                      obj_ptr->type == OBJ_POLYGON && polygon_ptr->n == 4)
+                {
+                   CopySelToCut ();
+                   DelObj (obj_ptr);
+                   deleting = FALSE;
+                   obj_ptr = NULL;
+                   cfree (topSel);
+                   topSel = botSel = NULL;
+                }
+                else
+                {
+                   switch (obj_ptr->type)
+                   {
+                      case OBJ_POLY:
+                         n = poly_ptr->n;
+                         for (i = index+1; i < n; i++)
+                            poly_ptr->vlist[i-1] = poly_ptr->vlist[i];
+                         poly_ptr->n--;
+                         if (poly_ptr->curved)
+                         {
+                            cfree (poly_ptr->svlist);
+                            poly_ptr->svlist = MakeSplinePolyVertex (
+                                  &(poly_ptr->sn), drawOrigX, drawOrigY,
+                                  poly_ptr->n, poly_ptr->vlist);
+                         }
+                         UpdPolyBBox (obj_ptr, poly_ptr->n, poly_ptr->vlist);
+                         break;
+                      case OBJ_POLYGON:
+                         n = polygon_ptr->n;
+                         for (i = index+1; i < n; i++)
+                            polygon_ptr->vlist[i-1] = polygon_ptr->vlist[i];
+                         polygon_ptr->n--;
+                         n--;
+                         if (index == 0)
+                            polygon_ptr->vlist[n-1] = polygon_ptr->vlist[0];
+                         if (polygon_ptr->curved)
+                         {
+                            cfree (polygon_ptr->svlist);
+                            polygon_ptr->svlist = MakeSplinePolygonVertex (
+                                  &(polygon_ptr->sn), drawOrigX, drawOrigY,
+                                  polygon_ptr->n, polygon_ptr->vlist);
+                         }
+                         UpdPolyBBox (obj_ptr, polygon_ptr->n,
+                               polygon_ptr->vlist);
+                         break;
+                   }
+                   AdjObjBBox (obj_ptr);
+                }
+             }
+             if (point_deleted)
+             {
+                XDrawString (mainDisplay, drawWindow, revDefaultGC, old_x+4,
+                      old_y+defaultFontAsc, "DEL", 3);
+                old_x = input.xbutton.x;
+                old_y = input.xbutton.y;
+                RedrawAnArea (botObj,
+                      selLtX-(1<<zoomScale), selLtY-(1<<zoomScale),
+                      selRbX+(1<<zoomScale), selRbY+(1<<zoomScale));
+                HighLightForward ();
+                if (obj_ptr != NULL)
+                   XDrawString (mainDisplay, drawWindow, revDefaultGC, old_x+4,
+                         old_y+defaultFontAsc, "DEL", 3);
+                UpdSelBBox ();
+                SetFileModified (TRUE);
+             }
+          }
+          else
+          {
+             deleting = FALSE;
+             XDrawString (mainDisplay, drawWindow, revDefaultGC,
+                   old_x+4, old_y+defaultFontAsc, "DEL", 3);
+          }
+       }
+       else if (input.type == MotionNotify)
+       {
+          XDrawString (mainDisplay, drawWindow, revDefaultGC,
+                old_x+4, old_y+defaultFontAsc, "DEL", 3);
+          old_x = input.xmotion.x;
+          old_y = input.xmotion.y;
+          XDrawString (mainDisplay, drawWindow, revDefaultGC,
+                old_x+4, old_y+defaultFontAsc, "DEL", 3);
+          MarkRulers (old_x, old_y);
+       }
+    }
+    XUngrabPointer (mainDisplay, CurrentTime);
+    Msg ("");
+ }
+ 
+ static
+ void ContinueAddPolyPoint (ObjPtr, MouseX, MouseY, Index, PolyPtr,
+       LastMouseX, LastMouseY)
+    struct ObjRec	* ObjPtr;
+    int			MouseX, MouseY, Index;
+    struct PolyRec	* PolyPtr;
+    int			* LastMouseX, * LastMouseY;
+    /* (MouseX,MouseY) is the mouse's origin in screen offsets */
+ {
+    int		n = PolyPtr->n, already_moved=FALSE, done=FALSE, before;
+    XPoint	* vs = PolyPtr->vlist, v[3];
+    int		prev_x, prev_y, x, y, next_x, next_y, new_x, new_y, dx, dy;
+    int		orig_x, orig_y, grid_x, grid_y, new_mouse_x, new_mouse_y;
+ /* int		prev_dist, next_dist, new_prev_dist, new_next_dist; */
+    int		sel_ltx, sel_lty, sel_rbx, sel_rby, num, i;
+    double	prev_angle, next_angle, new_angle, theta_1, theta_2;
+    XEvent	input;
+ 
+    MARK(OFFSET_X(vs[Index].x), OFFSET_Y(vs[Index].y));
+ 
+    sel_ltx =  selLtX; sel_lty = selLtY;
+    sel_rbx =  selRbX; sel_rby = selRbY;
+ 
+    x = vs[Index].x;
+    y = vs[Index].y;
+ 
+    if (Index == 0)
+    {
+       next_x = vs[1].x;    next_y = vs[1].y;
+       prev_x = 2*x-next_x; prev_y = 2*y-next_y;
+ /*    prev_dist = next_dist = (x-prev_x)*(x-prev_x) + (y-prev_y)*(y-prev_y); */
+    }
+    else if (Index == n-1)
+    {
+       prev_x = vs[n-2].x;  prev_y = vs[n-2].y;
+       next_x = 2*x-prev_x; next_y = 2*y-prev_y;
+ /*    prev_dist = next_dist = (x-prev_x)*(x-prev_x) + (y-prev_y)*(y-prev_y); */
+    }
+    else
+    {
+       prev_x = vs[Index-1].x; prev_y = vs[Index-1].y;
+       next_x = vs[Index+1].x; next_y = vs[Index+1].y;
+ /*    prev_dist = (x-prev_x)*(x-prev_x) + (y-prev_y)*(y-prev_y); */
+ /*    next_dist = (x-next_x)*(x-next_x) + (y-next_y)*(y-next_y); */
+    }
+    prev_angle = atan2 ((double)(prev_y-y), (double)(prev_x-x));
+    next_angle = atan2 ((double)(next_y-y), (double)(next_x-x));
+ 
+    GridXY (MouseX, MouseY, &orig_x, &orig_y);
+    new_mouse_x = MouseX; new_mouse_y = MouseY;
+    XDrawString (mainDisplay, drawWindow, revDefaultGC, new_mouse_x+4,
+          new_mouse_y+defaultFontAsc, "ADD", 3);
+ 
+    while (!done)
+    {
+       XNextEvent (mainDisplay, &input);
+       if (input.type == MotionNotify)
+       {
+          XDrawString (mainDisplay, drawWindow, revDefaultGC, new_mouse_x+4,
+                new_mouse_y+defaultFontAsc, "ADD", 3);
+          new_mouse_x = input.xmotion.x;
+          new_mouse_y = input.xmotion.y;
+          XDrawString (mainDisplay, drawWindow, revDefaultGC, new_mouse_x+4,
+                new_mouse_y+defaultFontAsc, "ADD", 3);
+ 
+          GridXY (new_mouse_x, new_mouse_y, &grid_x, &grid_y);
+          new_x = ((new_mouse_x-MouseX)<<zoomScale) + x;
+          new_y = ((new_mouse_y-MouseY)<<zoomScale) + y;
+          if (!already_moved)
+          {
+             already_moved = TRUE;
+ 
+             new_angle = atan2 ((double)(new_y-y), (double)(new_x-x));
+             theta_1 = fabs (prev_angle - new_angle);
+             theta_2 = fabs (next_angle - new_angle);
+             if (theta_1 > M_PI) theta_1 = 2*M_PI-theta_1;
+             if (theta_2 > M_PI) theta_2 = 2*M_PI-theta_2;
+             before = (theta_1 <= theta_2);
+ 
+ /*          new_prev_dist = (new_x-prev_x)*(new_x-prev_x) + */
+ /*                (new_y-prev_y)*(new_y-prev_y); */
+ /*          new_next_dist = (new_x-next_x)*(new_x-next_x) + */
+ /*                (new_y-next_y)*(new_y-next_y); */
+ 
+ /*          if ((new_prev_dist-prev_dist)*(new_next_dist-next_dist) < 0) */
+ /*             before = (new_prev_dist < prev_dist); */
+ /*          else */
+ /*             before = (abs (new_prev_dist-prev_dist) < */
+ /*                   abs (new_next_dist-next_dist)); */
+ 
+             if (before)
+             {  /* Add a point between the current and the previous point */
+                if (Index == 0)
+                {
+                   num = 2;
+                   v[0].x = OFFSET_X(x); v[0].y = OFFSET_Y(y);
+                   v[1].x = OFFSET_X(x); v[1].y = OFFSET_Y(y);
+                }
+                else
+                {
+                   num = 3;
+                   v[0].x = OFFSET_X(prev_x); v[0].y = OFFSET_Y(prev_y);
+                   v[1].x = OFFSET_X(x);      v[1].y = OFFSET_Y(y);
+                   v[2].x = OFFSET_X(x);      v[2].y = OFFSET_Y(y);
+                }
+             }
+             else
+             {  /* Add a point between the current and the next point */
+                if (Index == n-1)
+                {
+                   num = 2;
+                   v[0].x = OFFSET_X(x);      v[0].y = OFFSET_Y(y);
+                   v[1].x = OFFSET_X(x);      v[1].y = OFFSET_Y(y);
+                }
+                else
+                {
+                   num = 3;
+                   v[0].x = OFFSET_X(x);      v[0].y = OFFSET_Y(y);
+                   v[1].x = OFFSET_X(x);      v[1].y = OFFSET_Y(y);
+                   v[2].x = OFFSET_X(next_x); v[2].y = OFFSET_Y(next_y);
+                }
+             }
+             MyDashedLine (drawWindow, revDefaultGC, v, num);
+          }
+          else
+          {
+             MyDashedLine (drawWindow, revDefaultGC, v, num);
+             v[1].x = OFFSET_X(x) + grid_x - orig_x;
+             v[1].y = OFFSET_Y(y) + grid_y - orig_y;
+             MyDashedLine (drawWindow, revDefaultGC, v, num);
+             MarkRulers (grid_x, grid_y);
+          }
+       }
+       else if (input.type == ButtonRelease)
+       {
+          done = TRUE;
+          *LastMouseX = new_mouse_x; *LastMouseY = new_mouse_y;
+          MARK(OFFSET_X(vs[Index].x), OFFSET_Y(vs[Index].y));
+          XDrawString (mainDisplay, drawWindow, revDefaultGC, new_mouse_x+4,
+                new_mouse_y+defaultFontAsc, "ADD", 3);
+ 
+          if (!already_moved)
+             continue;
+          else
+          {
+             MyDashedLine (drawWindow, revDefaultGC, v, num);
+             if (grid_x == orig_x && grid_y == orig_y)
+                continue;
+          }
+ 
+          HighLightReverse ();
+          vs = (XPoint *) realloc (vs, (n+2)*sizeof(XPoint));
+          if (vs == NULL)
+          {
+             printf ("Can not realloc () in ContinueAddPolyPoint ().\n");
+             exit (-1);
+          }
+          PolyPtr->vlist = vs;
+          if (before)
+          {
+             for (i = n-1; i >= Index; i--) vs[i+1] = vs[i];
+             vs[Index].x = x + ((grid_x-orig_x)<<zoomScale);
+             vs[Index].y = y + ((grid_y-orig_y)<<zoomScale);
+          }
+          else
+          {
+             for (i = n-1; i > Index; i--) vs[i+1] = vs[i];
+             vs[Index+1].x = x + ((grid_x-orig_x)<<zoomScale);
+             vs[Index+1].y = y + ((grid_y-orig_y)<<zoomScale);
+          }
+          PolyPtr->n++;
+          n++;
+          if (PolyPtr->curved)
+          {
+             cfree (PolyPtr->svlist);
+             PolyPtr->svlist = MakeSplinePolyVertex (&(PolyPtr->sn),
+                   drawOrigX, drawOrigY, PolyPtr->n, PolyPtr->vlist);
+          }
+          UpdPolyBBox (ObjPtr, PolyPtr->n, PolyPtr->vlist);
+          AdjObjBBox (ObjPtr);
+ 
+          UpdSelBBox ();
+          RedrawAreas (botObj,
+                sel_ltx-(1<<zoomScale), sel_lty-(1<<zoomScale),
+                sel_rbx+(1<<zoomScale), sel_rby+(1<<zoomScale),
+                selLtX-(1<<zoomScale), selLtY-(1<<zoomScale),
+                selRbX+(1<<zoomScale), selRbY+(1<<zoomScale));
+          HighLightForward ();
+          SetFileModified (TRUE);
+       }
+    }
+ }
+ 
+ static
+ void ContinueAddPolygonPoint (ObjPtr, MouseX, MouseY, Index, PolygonPtr,
+       LastMouseX, LastMouseY)
+    struct ObjRec	* ObjPtr;
+    int			MouseX, MouseY, Index;
+    struct PolygonRec	* PolygonPtr;
+    int			* LastMouseX, * LastMouseY;
+    /* (MouseX,MouseY) is the mouse's origin in screen offsets */
+ {
+    int		n = PolygonPtr->n, already_moved=FALSE, done=FALSE, before;
+    XPoint	* vs = PolygonPtr->vlist, v[3];
+    int		prev_x, prev_y, x, y, next_x, next_y, new_x, new_y, dx, dy;
+    int		orig_x, orig_y, grid_x, grid_y, new_mouse_x, new_mouse_y;
+ /* int		prev_dist, next_dist, new_prev_dist, new_next_dist; */
+    int		sel_ltx, sel_lty, sel_rbx, sel_rby, i;
+    double	prev_angle, next_angle, new_angle, theta_1, theta_2;
+    XEvent	input;
+ 
+    MARK(OFFSET_X(vs[Index].x), OFFSET_Y(vs[Index].y));
+ 
+    sel_ltx =  selLtX; sel_lty = selLtY;
+    sel_rbx =  selRbX; sel_rby = selRbY;
+ 
+    x = vs[Index].x;
+    y = vs[Index].y;
+ 
+    if (Index == 0 || Index == n-1)
+    {
+       next_x = vs[1].x;   next_y = vs[1].y;
+       prev_x = vs[n-2].x; prev_y = vs[n-2].y;
+    }
+    else
+    {
+       prev_x = vs[Index-1].x; prev_y = vs[Index-1].y;
+       next_x = vs[Index+1].x; next_y = vs[Index+1].y;
+    }
+    prev_angle = atan2 ((double)(prev_y-y), (double)(prev_x-x));
+    next_angle = atan2 ((double)(next_y-y), (double)(next_x-x));
+ 
+ /* prev_dist = (x-prev_x)*(x-prev_x) + (y-prev_y)*(y-prev_y); */
+ /* next_dist = (x-next_x)*(x-next_x) + (y-next_y)*(y-next_y); */
+ 
+    GridXY (MouseX, MouseY, &orig_x, &orig_y);
+    new_mouse_x = MouseX; new_mouse_y = MouseY;
+    XDrawString (mainDisplay, drawWindow, revDefaultGC, new_mouse_x+4,
+          new_mouse_y+defaultFontAsc, "ADD", 3);
+ 
+    while (!done)
+    {
+       XNextEvent (mainDisplay, &input);
+       if (input.type == MotionNotify)
+       {
+          XDrawString (mainDisplay, drawWindow, revDefaultGC, new_mouse_x+4,
+                new_mouse_y+defaultFontAsc, "ADD", 3);
+          new_mouse_x = input.xmotion.x;
+          new_mouse_y = input.xmotion.y;
+          XDrawString (mainDisplay, drawWindow, revDefaultGC, new_mouse_x+4,
+                new_mouse_y+defaultFontAsc, "ADD", 3);
+ 
+          GridXY (new_mouse_x, new_mouse_y, &grid_x, &grid_y);
+          new_x = ((new_mouse_x-MouseX)<<zoomScale) + x;
+          new_y = ((new_mouse_y-MouseY)<<zoomScale) + y;
+          if (!already_moved)
+          {
+             already_moved = TRUE;
+ 
+             new_angle = atan2 ((double)(new_y-y), (double)(new_x-x));
+             theta_1 = fabs (prev_angle - new_angle);
+             theta_2 = fabs (next_angle - new_angle);
+             if (theta_1 > M_PI) theta_1 = 2*M_PI-theta_1;
+             if (theta_2 > M_PI) theta_2 = 2*M_PI-theta_2;
+             before = (theta_1 <= theta_2);
+ 
+ /*          new_prev_dist = (new_x-prev_x)*(new_x-prev_x) + */
+ /*                (new_y-prev_y)*(new_y-prev_y); */
+ /*          new_next_dist = (new_x-next_x)*(new_x-next_x) + */
+ /*                (new_y-next_y)*(new_y-next_y); */
+ 
+ /*          if ((new_prev_dist-prev_dist)*(new_next_dist-next_dist) < 0) */
+ /*             before = (new_prev_dist < prev_dist); */
+ /*          else */
+ /*             before = (abs (new_prev_dist-prev_dist) < */
+ /*                   abs (new_next_dist-next_dist)); */
+ 
+             if (before)
+             {  /* Add a point between the current and the previous point */
+                v[0].x = OFFSET_X(prev_x); v[0].y = OFFSET_Y(prev_y);
+                v[1].x = OFFSET_X(x);      v[1].y = OFFSET_Y(y);
+                v[2].x = OFFSET_X(x);      v[2].y = OFFSET_Y(y);
+             }
+             else
+             {  /* Add a point between the current and the next point */
+                v[0].x = OFFSET_X(x);      v[0].y = OFFSET_Y(y);
+                v[1].x = OFFSET_X(x);      v[1].y = OFFSET_Y(y);
+                v[2].x = OFFSET_X(next_x); v[2].y = OFFSET_Y(next_y);
+             }
+             MyDashedLine (drawWindow, revDefaultGC, v, 3);
+          }
+          else
+          {
+             MyDashedLine (drawWindow, revDefaultGC, v, 3);
+             v[1].x = OFFSET_X(x) + grid_x - orig_x;
+             v[1].y = OFFSET_Y(y) + grid_y - orig_y;
+             MyDashedLine (drawWindow, revDefaultGC, v, 3);
+             MarkRulers (grid_x, grid_y);
+          }
+       }
+       else if (input.type == ButtonRelease)
+       {
+          done = TRUE;
+          *LastMouseX = new_mouse_x; *LastMouseY = new_mouse_y;
+          MARK(OFFSET_X(vs[Index].x), OFFSET_Y(vs[Index].y));
+          XDrawString (mainDisplay, drawWindow, revDefaultGC, new_mouse_x+4,
+                new_mouse_y+defaultFontAsc, "ADD", 3);
+ 
+          if (!already_moved)
+             continue;
+          else
+          {
+             MyDashedLine (drawWindow, revDefaultGC, v, 3);
+             if (grid_x == orig_x && grid_y == orig_y)
+                continue;
+          }
+ 
+          HighLightReverse ();
+          vs = (XPoint *) realloc (vs, (n+2)*sizeof(XPoint));
+          if (vs == NULL)
+          {
+             printf ("Can not realloc () in ContinueAddPolygonPoint ().\n");
+             exit (-1);
+          }
+          PolygonPtr->vlist = vs;
+          if (Index == 0 || Index == n-1)
+          {
+             if (before)
+             {
+                vs[n].x = vs[n-1].x;
+                vs[n].y = vs[n-1].y;
+                vs[n-1].x = x + ((grid_x-orig_x)<<zoomScale);
+                vs[n-1].y = y + ((grid_y-orig_y)<<zoomScale);
+             }
+             else
+             {
+                for (i = n-1; i > 0; i--) vs[i+1] = vs[i];
+                vs[1].x = x + ((grid_x-orig_x)<<zoomScale);
+                vs[1].y = y + ((grid_y-orig_y)<<zoomScale);
+             }
+          }
+          else
+          {
+             if (before)
+             {
+                for (i = n-1; i >= Index; i--) vs[i+1] = vs[i];
+                vs[Index].x = x + ((grid_x-orig_x)<<zoomScale);
+                vs[Index].y = y + ((grid_y-orig_y)<<zoomScale);
+             }
+             else
+             {
+                for (i = n-1; i > Index; i--) vs[i+1] = vs[i];
+                vs[Index+1].x = x + ((grid_x-orig_x)<<zoomScale);
+                vs[Index+1].y = y + ((grid_y-orig_y)<<zoomScale);
+             }
+          }
+          PolygonPtr->n++;
+          n++;
+          if (PolygonPtr->curved)
+          {
+             cfree (PolygonPtr->svlist);
+             PolygonPtr->svlist = MakeSplinePolygonVertex (&(PolygonPtr->sn),
+                   drawOrigX, drawOrigY, PolygonPtr->n, PolygonPtr->vlist);
+          }
+          UpdPolyBBox (ObjPtr, PolygonPtr->n, PolygonPtr->vlist);
+          AdjObjBBox (ObjPtr);
+ 
+          UpdSelBBox ();
+          RedrawAreas (botObj,
+                sel_ltx-(1<<zoomScale), sel_lty-(1<<zoomScale),
+                sel_rbx+(1<<zoomScale), sel_rby+(1<<zoomScale),
+                selLtX-(1<<zoomScale), selLtY-(1<<zoomScale),
+                selRbX+(1<<zoomScale), selRbY+(1<<zoomScale));
+          HighLightForward ();
+          SetFileModified (TRUE);
+       }
+    }
+ }
+ 
+ void AddPoint ()
+ {
+    register int			i;
+    register struct ObjRec	* obj_ptr;
+    struct PolyRec		* poly_ptr;
+    struct PolygonRec		* polygon_ptr;
+    int				index, n, point_deleted, adding = TRUE;
+    int				root_x, root_y, old_x, old_y;
+    unsigned int			status;
+    Window			root_win, child_win;
+    XEvent			input;
+ 
+    if (!(topSel != NULL && topSel == botSel &&
+          (topSel->obj->type == OBJ_POLY || topSel->obj->type == OBJ_POLYGON)))
+    {
+       Msg ("Please select only one POLY or POLYGON object.");
+       return;
+    }
+ 
+    obj_ptr = topSel->obj;
+    switch (obj_ptr->type)
+    {
+       case OBJ_POLY: poly_ptr = obj_ptr->detail.p; break;
+       case OBJ_POLYGON: polygon_ptr = obj_ptr->detail.g; break;
+    }
+    TwoLineMsg ("Drag left mouse button to ADD points.",
+          "Click other buttons to quit.");
+ 
+    XGrabPointer (mainDisplay, drawWindow, False,
+          PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
+          GrabModeAsync, GrabModeAsync, None, defaultCursor, CurrentTime);
+    XQueryPointer (mainDisplay, drawWindow, &root_win, &child_win,
+          &root_x, &root_y, &old_x, &old_y, &status);
+    XDrawString (mainDisplay, drawWindow, revDefaultGC,
+          old_x+4, old_y+defaultFontAsc, "ADD", 3);
+    MarkRulers (old_x, old_y);
+ 
+    while (adding)
+    {
+       XNextEvent (mainDisplay, &input);
+       if (input.type == ButtonPress)
+       {
+          if (input.xbutton.button == Button1)
+          {
+             XDrawString (mainDisplay, drawWindow, revDefaultGC,
+                   old_x+4, old_y+defaultFontAsc, "ADD", 3);
+             if (obj_ptr->type == OBJ_POLY &&
+                   PtInPolyMark (input.xbutton.x, input.xbutton.y,
+                   poly_ptr->n, poly_ptr->vlist, &index))
+                ContinueAddPolyPoint (obj_ptr, input.xbutton.x, input.xbutton.y,
+                      index, poly_ptr, &old_x, &old_y);
+             else if (obj_ptr->type == OBJ_POLYGON &&
+                   PtInPolyMark (input.xbutton.x, input.xbutton.y,
+                   polygon_ptr->n-1, polygon_ptr->vlist, &index))
+                ContinueAddPolygonPoint (obj_ptr, input.xbutton.x,
+                      input.xbutton.y, index, polygon_ptr, &old_x, &old_y);
+             XDrawString (mainDisplay, drawWindow, revDefaultGC,
+                   old_x+4, old_y+defaultFontAsc, "ADD", 3);
+          }
+          else
+          {
+             adding = FALSE;
+             XDrawString (mainDisplay, drawWindow, revDefaultGC,
+                   old_x+4, old_y+defaultFontAsc, "ADD", 3);
+          }
+       }
+       else if (input.type == MotionNotify)
+       {
+          XDrawString (mainDisplay, drawWindow, revDefaultGC,
+                old_x+4, old_y+defaultFontAsc, "ADD", 3);
+          old_x = input.xmotion.x;
+          old_y = input.xmotion.y;
+          XDrawString (mainDisplay, drawWindow, revDefaultGC,
+                old_x+4, old_y+defaultFontAsc, "ADD", 3);
+          MarkRulers (old_x, old_y);
+       }
+    }
+    XUngrabPointer (mainDisplay, CurrentTime);
+    Msg ("");
+ }
+ 
  void EditMenu (X, Y)
     int	X, Y;
***************
*** 57,60 ****
--- 677,682 ----
        case EDIT_SELALL: SelAllObj (); break;
        case EDIT_UNDODEL: UndoDelete (); break;
+       case EDIT_DEL_POINT: DeletePoint (); break;
+       case EDIT_ADD_POINT: AddPoint (); break;
     }
  }
*** file.c.orig	Thu Aug  2 09:44:28 1990
--- file.c	Thu Aug  2 09:44:31 1990
***************
*** 6,10 ****
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/file.c,v 1.15 90/06/26 13:03:47 william Exp $";
  #endif
  
--- 6,10 ----
  #ifndef lint
  static char RCSid[] =
!       "@(#)$Header: /n/kona/u/tangram/u/william/X11/TGIF/RCS/file.c,v 1.28 90/07/30 16:08:30 william Exp $";
  #endif
  
***************
*** 12,15 ****
--- 12,16 ----
  #include <sys/file.h>
  #include <stdio.h>
+ #include <signal.h>
  #include <X11/Xlib.h>
  #include "const.h"
***************
*** 27,38 ****
  #include "grid.e"
  #include "group.e"
  #include "menu.e"
  #include "msg.e"
  #include "names.e"
  #include "poly.e"
  #include "polygon.e"
  #include "obj.e"
  #include "oval.e"
- #include "pattern.e"
  #include "rect.e"
  #include "ruler.e"
--- 28,41 ----
  #include "grid.e"
  #include "group.e"
+ #include "mainloop.e"
  #include "menu.e"
  #include "msg.e"
  #include "names.e"
+ #include "pattern.e"
  #include "poly.e"
  #include "polygon.e"
+ #include "prtgif.e"
  #include "obj.e"
  #include "oval.e"
  #include "rect.e"
  #include "ruler.e"
***************
*** 43,47 ****
  #include "text.e"
  
! #define CUR_VERSION 6
  
  char	curFileName[MAXPATHLENGTH];
--- 46,50 ----
  #include "text.e"
  
! #define CUR_VERSION 7
  
  char	curFileName[MAXPATHLENGTH];
***************
*** 134,138 ****
  
  static
! int SaveTmpFile ()
     /* return TRUE if file successfully saved */
  {
--- 137,142 ----
  
  static
! int SaveTmpFile (NewFileName)
!    char	* NewFileName;
     /* return TRUE if file successfully saved */
  {
***************
*** 142,146 ****
     struct ObjRec	* obj_ptr;
  
!    strcpy (new_file_name, "tmpmodel");
  
     for (obj_ptr = topObj; obj_ptr != NULL; obj_ptr = obj_ptr->next)
--- 146,150 ----
     struct ObjRec	* obj_ptr;
  
!    strcpy (new_file_name, NewFileName);
  
     for (obj_ptr = topObj; obj_ptr != NULL; obj_ptr = obj_ptr->next)
***************
*** 355,360 ****
  }
  
! void ReadState (Inbuf)
     char	* Inbuf;
  {
     char	* s;
--- 359,365 ----
  }
  
! void ReadState (Inbuf, PRTGIF)
     char	* Inbuf;
+    int	PRTGIF;
  {
     char	* s;
***************
*** 369,372 ****
--- 374,379 ----
        sscanf (s, "%d", &fileVersion);
  
+    if (PRTGIF) return;
+ 
     if (!importingFile)
     {
***************
*** 419,433 ****
  }
  
! int ReadObj (FP, ObjPtr)
     FILE			* FP;
     struct ObjRec	* * ObjPtr;
  {
     char			inbuf[MAXSTRING+1], obj_name[10], tmp_str[MAXSTRING+1];
     char			* line = NULL, * c_ptr, * s, * s1;
!    int			len, id, old_len, cur_size, done = FALSE;
!    int			allocated = FALSE;
!    struct ObjRec	* tmp_obj_ptr;
!    struct ObjRec	* tmp_top_obj = NULL, * tmp_bot_obj = NULL;
!    struct AttrRec       * top_attr = NULL, * bot_attr = NULL, * attr_ptr;
  
     while (fgets (inbuf, MAXSTRING, FP) != NULL)
--- 426,438 ----
  }
  
! int ReadObj (FP, ObjPtr, PRTGIF)
     FILE			* FP;
     struct ObjRec	* * ObjPtr;
+    int			PRTGIF;
  {
     char			inbuf[MAXSTRING+1], obj_name[10], tmp_str[MAXSTRING+1];
     char			* line = NULL, * c_ptr, * s, * s1;
!    int			len, id, cur_size, done = FALSE, allocated = FALSE;
!    struct AttrRec	* top_attr = NULL, * bot_attr = NULL, * attr_ptr;
  
     while (fgets (inbuf, MAXSTRING, FP) != NULL)
***************
*** 444,448 ****
           strcpy (line, inbuf);
           c_ptr = &(line[MAXSTRING-1]);
!          while (fgets (inbuf, MAXSTRING, FP) != NULL && !done)
           {
              len = strlen(inbuf);
--- 449,453 ----
           strcpy (line, inbuf);
           c_ptr = &(line[MAXSTRING-1]);
!          while (!done && fgets (inbuf, MAXSTRING, FP) != NULL)
           {
              len = strlen(inbuf);
***************
*** 478,482 ****
           ReadPolyObj (line, ObjPtr);
           if (fileVersion != INVALID)
!             while (ReadAttr (FP, &attr_ptr))
              {
                 attr_ptr->owner = *ObjPtr;
--- 483,487 ----
           ReadPolyObj (line, ObjPtr);
           if (fileVersion != INVALID)
!             while (ReadAttr (FP, &attr_ptr, PRTGIF))
              {
                 attr_ptr->owner = *ObjPtr;
***************
*** 510,514 ****
        else if (strcmp (obj_name, "text") == 0)
        {
!          ReadTextObj (FP, line, ObjPtr);
           if (allocated) cfree (line);
           return (TRUE);
--- 515,519 ----
        else if (strcmp (obj_name, "text") == 0)
        {
!          ReadTextObj (FP, line, ObjPtr, PRTGIF);
           if (allocated) cfree (line);
           return (TRUE);
***************
*** 522,528 ****
        else if (strcmp (obj_name, "group") == 0)
        {
!          ReadGroupObj (FP, ObjPtr);
           if (fileVersion != INVALID)
!             while (ReadAttr (FP, &attr_ptr))
              {
                 attr_ptr->owner = *ObjPtr;
--- 527,533 ----
        else if (strcmp (obj_name, "group") == 0)
        {
!          ReadGroupObj (FP, ObjPtr, PRTGIF);
           if (fileVersion != INVALID)
!             while (ReadAttr (FP, &attr_ptr, PRTGIF))
              {
                 attr_ptr->owner = *ObjPtr;
***************
*** 544,551 ****
        else if (strcmp (obj_name, "sym") == 0)
        {
!          ReadGroupObj (FP, ObjPtr);
           (*ObjPtr)->type = OBJ_SYM;
           if (fileVersion != INVALID)
!             while (ReadAttr (FP, &attr_ptr))
              {
                 attr_ptr->owner = *ObjPtr;
--- 549,556 ----
        else if (strcmp (obj_name, "sym") == 0)
        {
!          ReadGroupObj (FP, ObjPtr, PRTGIF);
           (*ObjPtr)->type = OBJ_SYM;
           if (fileVersion != INVALID)
!             while (ReadAttr (FP, &attr_ptr, PRTGIF))
              {
                 attr_ptr->owner = *ObjPtr;
***************
*** 567,571 ****
        else if (strcmp (obj_name, "icon") == 0)
        {
!          ReadGroupObj (FP, ObjPtr);
           (*ObjPtr)->type = OBJ_ICON;
           if (fgets (line, MAXSTRING, FP) == NULL)
--- 572,576 ----
        else if (strcmp (obj_name, "icon") == 0)
        {
!          ReadGroupObj (FP, ObjPtr, PRTGIF);
           (*ObjPtr)->type = OBJ_ICON;
           if (fgets (line, MAXSTRING, FP) == NULL)
***************
*** 588,592 ****
           strcpy ((*ObjPtr)->detail.r->s, tmp_str);
           if (fileVersion != INVALID)
!             while (ReadAttr (FP, &attr_ptr))
              {
                 attr_ptr->owner = *ObjPtr;
--- 593,597 ----
           strcpy ((*ObjPtr)->detail.r->s, tmp_str);
           if (fileVersion != INVALID)
!             while (ReadAttr (FP, &attr_ptr, PRTGIF))
              {
                 attr_ptr->owner = *ObjPtr;
***************
*** 608,612 ****
        else if (strcmp (obj_name, "state") == 0)
        {
!          ReadState (line);
           *ObjPtr = NULL;
           if (allocated) cfree (line);
--- 613,617 ----
        else if (strcmp (obj_name, "state") == 0)
        {
!          ReadState (line, PRTGIF);
           *ObjPtr = NULL;
           if (allocated) cfree (line);
***************
*** 692,696 ****
     Msg (s);
  
!    while (ReadObj (fp, &obj_ptr))
        if (obj_ptr != NULL)
           AddObj (NULL, topObj, obj_ptr);
--- 697,701 ----
     Msg (s);
  
!    while (ReadObj (fp, &obj_ptr, FALSE))
        if (obj_ptr != NULL)
           AddObj (NULL, topObj, obj_ptr);
***************
*** 747,751 ****
     XClearWindow (mainDisplay, drawWindow);
  
!    while (ReadObj (fp, &obj_ptr))
        if (obj_ptr != NULL)
        {
--- 752,756 ----
     XClearWindow (mainDisplay, drawWindow);
  
!    while (ReadObj (fp, &obj_ptr, FALSE))
        if (obj_ptr != NULL)
        {
***************
*** 794,809 ****
  }
  
! void DumpAttrs (FP, AttrPtr)
     FILE				* FP;
     register struct AttrRec	* AttrPtr;
  {
     for ( ; AttrPtr != NULL; AttrPtr = AttrPtr->prev)
        if (AttrPtr->shown)
!          DumpTextObj (FP, AttrPtr->obj);
  }
  
! void DumpAllObj (FP, ObjPtr)
     FILE				* FP;
     register struct ObjRec	* ObjPtr;
  {
     register struct ObjRec	* obj_ptr;
--- 799,816 ----
  }
  
! void DumpAttrs (FP, AttrPtr, PRTGIF)
     FILE				* FP;
     register struct AttrRec	* AttrPtr;
+    int				PRTGIF;
  {
     for ( ; AttrPtr != NULL; AttrPtr = AttrPtr->prev)
        if (AttrPtr->shown)
!          DumpTextObj (FP, AttrPtr->obj, PRTGIF);
  }
  
! void DumpAllObj (FP, ObjPtr, PRTGIF)
     FILE				* FP;
     register struct ObjRec	* ObjPtr;
+    int				PRTGIF;
  {
     register struct ObjRec	* obj_ptr;
***************
*** 813,821 ****
        case OBJ_POLY:
           DumpPolyObj (FP, ObjPtr);
!          DumpAttrs (FP, ObjPtr->detail.p->lattr);
           break;
        case OBJ_BOX: DumpBoxObj (FP, ObjPtr); break;
        case OBJ_OVAL: DumpOvalObj (FP, ObjPtr); break;
!       case OBJ_TEXT: DumpTextObj (FP, ObjPtr); break;
        case OBJ_POLYGON: DumpPolygonObj (FP, ObjPtr); break;
        case OBJ_SYM:
--- 820,828 ----
        case OBJ_POLY:
           DumpPolyObj (FP, ObjPtr);
!          DumpAttrs (FP, ObjPtr->detail.p->lattr, PRTGIF);
           break;
        case OBJ_BOX: DumpBoxObj (FP, ObjPtr); break;
        case OBJ_OVAL: DumpOvalObj (FP, ObjPtr); break;
!       case OBJ_TEXT: DumpTextObj (FP, ObjPtr, PRTGIF); break;
        case OBJ_POLYGON: DumpPolygonObj (FP, ObjPtr); break;
        case OBJ_SYM:
***************
*** 824,829 ****
           obj_ptr = ObjPtr->detail.r->last;
           for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->prev)
!             DumpAllObj (FP, obj_ptr);
!          DumpAttrs (FP, ObjPtr->detail.r->lattr);
           if (ObjPtr->type == OBJ_SYM) DumpSymOutline (FP, ObjPtr);
           break;
--- 831,836 ----
           obj_ptr = ObjPtr->detail.r->last;
           for ( ; obj_ptr != NULL; obj_ptr = obj_ptr->prev)
!             DumpAllObj (FP, obj_ptr, PRTGIF);
!          DumpAttrs (FP, ObjPtr->detail.r->lattr, PRTGIF);
           if (ObjPtr->type == OBJ_SYM) DumpSymOutline (FP, ObjPtr);
           break;
***************
*** 875,879 ****
  }
  
! void Dump ()
  {
     register struct ObjRec	* obj_ptr;
--- 882,888 ----
  }
  
! void Dump (PRTGIF, FileName)
!    int	PRTGIF;
!    char	* FileName;
  {
     register struct ObjRec	* obj_ptr;
***************
*** 886,890 ****
     if (botObj == NULL) { Msg ("No object to print."); return; }
  
!    Msg ("Generating print file ...");
     strcpy (tmp_file, "/tmp/TgifXXXXXX");
     mktemp (tmp_file);
--- 895,900 ----
     if (botObj == NULL) { Msg ("No object to print."); return; }
  
!    if (!PRTGIF) Msg ("Generating print file ...");
! 
     strcpy (tmp_file, "/tmp/TgifXXXXXX");
     mktemp (tmp_file);
***************
*** 893,901 ****
     if ((fp = fopen (tmp_file, "w")) == NULL)
     {
!       sprintf (tmp_str, "Can not create %s, print aborted.", tmp_file);
!       Msg (tmp_str);
        return;
     }
  
     fprintf (fp, "%%!\n");
     DumpBBox (fp);
--- 903,918 ----
     if ((fp = fopen (tmp_file, "w")) == NULL)
     {
!       if (PRTGIF)
!          printf ("Can not create $s, print aborted.", tmp_file);
!       else
!       {
!          sprintf (tmp_str, "Can not create %s, print aborted.", tmp_file);
!          Msg (tmp_str);
!       }
        return;
     }
  
+    if (PRTGIF) printf ("Writing to %s ...\n", tmp_file);
+ 
     fprintf (fp, "%%!\n");
     DumpBBox (fp);
***************
*** 903,908 ****
     if ((fps = fopen (ps_file, "r")) == NULL) 
     {
!       sprintf (message, "Can not find %s, print aborted.", ps_file);
!       Msg (message);
        fclose (fp);
        unlink (tmp_file);
--- 920,930 ----
     if ((fps = fopen (ps_file, "r")) == NULL) 
     {
!       if (PRTGIF)
!          printf ("Can not find %s, print aborted.\n", ps_file);
!       else
!       {
!          sprintf (message, "Can not find %s, print aborted.", ps_file);
!          Msg (message);
!       }
        fclose (fp);
        unlink (tmp_file);
***************
*** 925,929 ****
  
     for (obj_ptr = botObj; obj_ptr != NULL; obj_ptr = obj_ptr->prev)
!       DumpAllObj (fp, obj_ptr);
  
     fprintf (fp, "grestore\n\n");
--- 947,951 ----
  
     for (obj_ptr = botObj; obj_ptr != NULL; obj_ptr = obj_ptr->prev)
!       DumpAllObj (fp, obj_ptr, PRTGIF);
  
     fprintf (fp, "grestore\n\n");
***************
*** 934,946 ****
     {
        case PRINTER:
!          if ((c_ptr = XGetDefault (mainDisplay,"Tgif","PrintCommand")) != NULL)
!             sprintf (cmd, "%s %s 2>&1", c_ptr, tmp_file);
           else
!             sprintf (cmd, "lpr %s 2>&1", tmp_file);
  
           if ((fp = popen (cmd, "r")) == NULL)
           {
!             sprintf (message, "Can not execute '%s', print aborted.", cmd);
!             Msg (message);
              unlink (tmp_file);
              return;
--- 956,991 ----
     {
        case PRINTER:
!          if (PRTGIF)
!          {
!             if (lastFile)
!                sprintf (cmd, "lpr %s 2>&1", tmp_file);
!             else
!                sprintf (cmd, "lpr -h %s 2>&1", tmp_file);
!          }
           else
!          {
!             if ((c_ptr = XGetDefault (mainDisplay,"Tgif","PrintCommand")) !=
!                   NULL)
!             {
!                sprintf (cmd, "%s %s 2>&1", c_ptr, tmp_file);
!                sprintf (message, "Printing with '%s' command.", c_ptr);
!             }
!             else
!             {
!                sprintf (cmd, "lpr %s 2>&1", tmp_file);
!                sprintf (message, "Printing with 'lpr' command.");
!             }
!             Msg (message);
!          }
  
           if ((fp = popen (cmd, "r")) == NULL)
           {
!             if (PRTGIF)
!                printf ("Can not execute '%s', print aborted.\n", cmd);
!             else
!             {
!                sprintf (message, "Can not execute '%s', print aborted.", cmd);
!                Msg (message);
!             }
              unlink (tmp_file);
              return;
***************
*** 948,978 ****
           while (fgets (tmp_str, MAXSTRING, fp) != NULL)
           {
!             Msg (tmp_str);
              sleep (5);
           }
!          pclose (fp);
           break;
        case LATEX_FIG:
!          if (!curFileDefined)
           {
!             Dialog ("No current file.  Can not generate LaTeX output!", cmd);
!             unlink (tmp_file);
!             return;
           }
  
-          strcpy (ps_file, curDomainName);
-          if (*curDomainName != '\0') strcat (ps_file, "/");
-          strcat (ps_file, curFileName);
-          len = strlen (ps_file);
-          for (i = len-1; ps_file[i] != '.'; i--) ;
-          strcpy (&ps_file[i], ".ps");
-          sprintf (cmd, "Printing into '%s'.", ps_file);
-          Msg (cmd);
           sprintf (cmd, "tgif2ps < %s 1> %s 2>&1; chmod %s %s", tmp_file,
                 ps_file, PSFILE_MOD, ps_file);
           if ((fp = popen (cmd, "r")) == NULL)
           {
!             sprintf (message, "Can not execute '%s', file not saved.", cmd);
!             Msg (message);
              unlink (tmp_file);
              return;
--- 993,1038 ----
           while (fgets (tmp_str, MAXSTRING, fp) != NULL)
           {
!             if (PRTGIF)
!                printf ("%s", tmp_str);
!             else
!                Msg (tmp_str);
              sleep (5);
           }
!          if (PRTGIF) printf ("%s printed.\n\n", tmp_file);
           break;
        case LATEX_FIG:
!          if (PRTGIF)
!             sprintf (ps_file, "%s.ps", FileName);
!          else
           {
!             if (!curFileDefined)
!             {
!                Dialog ("No current file.  Can not generate LaTeX output!", cmd);
!                unlink (tmp_file);
!                return;
!             }
! 
!             strcpy (ps_file, curDomainName);
!             if (*curDomainName != '\0') strcat (ps_file, "/");
!             strcat (ps_file, curFileName);
!             len = strlen (ps_file);
!             for (i = len-1; ps_file[i] != '.'; i--) ;
!             strcpy (&ps_file[i], ".ps");
!             sprintf (cmd, "Printing into '%s'.", ps_file);
!             Msg (cmd);
           }
  
           sprintf (cmd, "tgif2ps < %s 1> %s 2>&1; chmod %s %s", tmp_file,
                 ps_file, PSFILE_MOD, ps_file);
+ 
           if ((fp = popen (cmd, "r")) == NULL)
           {
!             if (PRTGIF)
!                printf ("Can not execute '%s', print aborted.\n", cmd);
!             else
!             {
!                sprintf (message, "Can not execute '%s', file not saved.", cmd);
!                Msg (message);
!             }
              unlink (tmp_file);
              return;
***************
*** 980,989 ****
           while (fgets(tmp_str, MAXSTRING, fp) != NULL)
           {
!             Msg (tmp_str);
              sleep (5);
           }
!          pclose (fp);
           break;
     }
     unlink (tmp_file);
  }
--- 1040,1059 ----
           while (fgets(tmp_str, MAXSTRING, fp) != NULL)
           {
!             if (PRTGIF)
!                printf ("%s", tmp_str);
!             else
!                Msg (tmp_str);
              sleep (5);
           }
!          if (PRTGIF)
!             printf ("LaTeX figure printed into '%s'.\n\n", ps_file);
!          else
!          {
!             sprintf (message, "LaTeX figure printed into '%s'.\n\n", ps_file);
!             Msg (message);
!          }
           break;
     }
+    pclose (fp);
     unlink (tmp_file);
  }
***************
*** 1082,1086 ****
  int SolveProc ()
  {
!    switch (SaveTmpFile ())
     {
        case OBJ_FILE_SAVED: return (FILE_SOLVE);
--- 1152,1156 ----
  int SolveProc ()
  {
!    switch (SaveTmpFile ("tmpmodel"))
     {
        case OBJ_FILE_SAVED: return (FILE_SOLVE);
***************
*** 1092,1096 ****
  int SimulateProc ()
  {
!    switch (SaveTmpFile ())
     {
        case OBJ_FILE_SAVED: return (FILE_SIMULATE);
--- 1162,1166 ----
  int SimulateProc ()
  {
!    switch (SaveTmpFile ("tmpmodel"))
     {
        case OBJ_FILE_SAVED: return (FILE_SIMULATE);
***************
*** 1102,1106 ****
  int ProbeProc ()
  {
!    switch (SaveTmpFile ())
     {
        case OBJ_FILE_SAVED: return (FILE_PROBE);
--- 1172,1176 ----
  int ProbeProc ()
  {
!    switch (SaveTmpFile ("tmpmodel"))
     {
        case OBJ_FILE_SAVED: return (FILE_PROBE);
***************
*** 1112,1116 ****
  int AnimateProc ()
  {
!    switch (SaveTmpFile ())
     {
        case OBJ_FILE_SAVED: return (FILE_ANIMATE);
--- 1182,1186 ----
  int AnimateProc ()
  {
!    switch (SaveTmpFile ("tmpmodel"))
     {
        case OBJ_FILE_SAVED: return (FILE_ANIMATE);
***************
*** 1142,1146 ****
        case FILE_IMPORT: ImportFile (); break;
        case FILE_DOMAIN: ChangeDomain (); break;
!       case FILE_DUMP: Dump (); break;
        case FILE_SOLVE: return (SolveProc ()); break;
        case FILE_SIMULATE: return (SimulateProc ()); break;
--- 1212,1216 ----
        case FILE_IMPORT: ImportFile (); break;
        case FILE_DOMAIN: ChangeDomain (); break;
!       case FILE_DUMP: Dump (FALSE, ""); break;
        case FILE_SOLVE: return (SolveProc ()); break;
        case FILE_SIMULATE: return (SimulateProc ()); break;
***************
*** 1151,1153 ****
--- 1221,1254 ----
     }
     return (INVALID);
+ }
+ 
+ void CleanUpFiles ()
+ {
+    ClearFileInfo ();
+    fileModified = FALSE;
+ }
+ 
+ void EmergencySave ()
+ {
+    if (exitNormally) return;
+ 
+    signal (SIGHUP, SIG_DFL);
+    signal (SIGFPE, SIG_DFL);
+    signal (SIGBUS, SIG_DFL);
+    signal (SIGSEGV, SIG_DFL);
+ 
+    switch (SaveTmpFile ("EmergencySave"))
+    {
+       case OBJ_FILE_SAVED:
+          fprintf (stderr, "Saved to EmergencySave.obj.\n");
+          break;
+       case SYM_FILE_SAVED:
+          fprintf (stderr, "Saved to EmergencySave.sym.\n");
+          break;
+       case INVALID:
+          fprintf (stderr, "Unable to save working file.\n");
+          break;
+    }
+    exitNormally = TRUE;
+    exit (0);
  }
---------------------------------> cut here <---------------------------------
--
Bill Cheng // UCLA Computer Science Department // (213) 206-7135
3277 Boelter Hall // Los Angeles, California 90024 // USA
william@CS.UCLA.EDU      ...!{uunet|ucbvax}!cs.ucla.edu!william

dan
----------------------------------------------------
O'Reilly && Associates   argv@sun.com / argv@ora.com
Opinions expressed reflect those of the author only.