v04i079: xpic -- pic previewer for X11, Part14/15

Dan Heller argv at island.uu.net
Sat Jul 22 17:42:17 AEST 1989


Submitted-by: Mark Moraes <moraes at ai.toronto.edu>
Posting-number: Volume 4, Issue 79
Archive-name: xpic/part14



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 14 (of 15)."
# Contents:  xpic/doc/xpic.doc xpic/xpic.c
# Wrapped by moraes at neat.ai on Thu Jul 13 22:36:12 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'xpic/doc/xpic.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xpic/doc/xpic.doc'\"
else
echo shar: Extracting \"'xpic/doc/xpic.doc'\" \(29158 characters\)
sed "s/^X//" >'xpic/doc/xpic.doc' <<'END_OF_FILE'
X$Header: xpic.doc,v 1.11 89/02/10 04:12:27 xwindows Exp $
X                              Using xpic.
X                              -----------
X
X                             Mark Moraes
X                  Computer Systems Research Institute
X                      (moraes at csri.toronto.edu)
X
XXpic is a drawing package for the X Windows system, inspired
Xstrongly by a similar, much-used package written by Bruno Preiss
Xfor the BitGraph (bgpic).  Xpic was not intended for painting, but
Xdrawing diagrams, and figures. It was intended to produce output
Xfor pic(1) and PostScript(tm), and some of its features stem from
Xthat. But it outputs a simple file of object descriptions, which
Xcan be translated to any device you like, if you write the
Xappropriate filter. At present, filters exist for pic (the troff
Xand TeX versions) and PostScript.
X
XUsage:
Xxpic [host:display] [geometry] [iconGeometry] option ..... file ... 
X
XThe list of options is shown below - either the short form, or the 
Xlong form is valid. The option is followed by a description, and the 
Xdefault.
X
XOption   Resource name    Action                 Default
X
X-grid,   gridOn "off"     Turns grid off         (On)
X+grid,   gridOn "on"      Turns grid on          (On)
X-gs,     gridSpacing      Grid spacing in pixels (8)
X-ph,     pageHeight       PageHeight in 10*in.   (110)
X-pw,     pageWidth        PageWidth in 10*in.    (85)
X-rotate, rotate "on"      swap page height and width
X+rotate, rotate "off"     normal page height and width
X-backup, backup "off"     No backup file on write(On)
X+backup, backup "on"      Make backup file on write(On)
X-cr,     cursorColor      Sets cursor color      (Black)
X-hl,     highlight        Sets highlight color   (Black)
X
XThanks to a sneak trick in the way xpic saves files, *executing* a file
Xsaved by xpic will cause it to start up xpic on itself. This feature
Xmay not be available on all systems.
X
X(Note that we refer to two types of buttons in this document - mouse
Xbuttons, and screen buttons (which are pieces of text on the screen
Xsurrounded by borders, which darken when the mouse cursor moves into
Xthem, and highlight and select when the left mouse button is pressed
Xin them. We will always call a mouse button a 'left button', 'right
Xbutton', or 'middle button' or just a 'mouse button'. Any other use of
Xbutton means a screen button)
X
XThe basic screen consists of three sections: the drawing window, the
Xtext interaction window, and the button area.
X
X The Drawing Window
X ------------------
XThe drawing window has a grid, with crosses every five grid points. Each
Xcross is supposed to be at 0.5 inch spacings - as such, the default page
Xsize is supposed to represent an 8.5x11" page. Changing the size results
Xin the picture window resizing as best as it can, while the menus and
Xthe input window remain constant. (There is a minimum window size, which
Xcan be discovered by experimentation) Resizing assumes the so-called
X'quarter-plane' model - i.e. the upper-left corner of the picture is the
Xorigin, and remains fixed; Increasing the size means that more room is
Xavailable to draw, but the scale does NOT change. If you make the window
Xsmaller, then stuff that may go outside the window boundaries will be
Xclipped, but will still be part of the picture.
X
XThe cross-hairs cursor in the drawing window tracks the mouse. The
Xtracking is done by the X server, and possesses all the disadvantages of
XX tracking. However, the cursor position, as far as xpic is concerned,
Xis "snapped" to the nearest grid point, (or a fraction thereof,
Xdepending on the Snap setting - more on this later.)
X
XAll objects in the drawing window "rubber-band", i.e. they follow the
Xmouse, re-drawing on each mouse movement. This means that hyper-speed
Xmovement of the mouse is very unwise. 
X
XThe mouse button convention is reasonably consistent:
X
XThe Left mouse button selects a point. This is really the action mouse button for
Xmost tasks. (In edit mode, i.e. copy, move, delete, paste, adjust, this
Xmouse button selects the nearest selectable object - 'nearest' means the
Xobject whose bounding-box centre is closest to the mouse)
X
XThe Right mouse button ends lines, and splines at the last point at which the
XLeft mouse button was clicked. i.e. the rubber-banded segment vanishes.
X(In edit mode, this deselects the object that has been selected, and
Xmakes it non-selectable. So a subsequent Left click will select the 
Xnext-nearest object. This selection cycles around)
X
XThe Middle mouse button aborts the operation, and erases the element being
Xdrawn. Use with care - It cannot be undone. (Maybe this should become
XSHIFT-Middle mouse button.) (In edit mode, in addition to aborting whatever
Xoperation was in progress, it also makes all objects selectable again)
X
XSmall fonts are barely readable - they are meant to give an idea of size
Xmore than anything. Using 6 point fonts requires considerable imagination.
XThe fonts are not exact replicas of what you can get on paper, and are
Xlimited to a small subset of fonts which I could scale and generate for
XX.
X
X The Button Area
X ---------------
XThe buttons are grouped in button-boxes. Click the left mouse button on a
Xbutton to select it.  There are three types of buttons - radio-buttons,
Xcommand buttons and updown buttons. The radio-buttons when clicked on, turn
Xon, AND the button in the same button box which was on turns off - i.e. only
Xone radio-button in any button box will be on at any one time. The selected
Xbutton will be in inverse video, and will remain that way till another
Xbutton is selected. The updown buttons have a "+" sign on the left and a "-"
Xsign on the right - clicking the left mouse button will cause the updown
Xbutton to advance to the next selection, which is displayed in the centre of
Xthe button. Clicking the right mouse button will cause the updown button to
Xmove to the previous selection.
X
XIn the command button boxes, no item remains permanantly selected.
XWhen a button is pressed, it executes a command, and unhighlights
Xautomatically.
X
X Button functions:
X -----------------
XThe top button box consists of basic functions - for drawing elements,
Xand for editing them.
X
XThe basic element drawing functions are:
X
XBox:
X	Draws a rectangle. Select the button, and click the left mouse
Xbutton in the drawing window to start the box, (this specifies one
Xcorner) and move the mouse to the other corner of the desired box and
Xclick the left mouse button again to end the box.
X
XLine:
X	This is a continuous "poly-line". To draw the line, select
Xthis button, and go into the drawing window. Each left click puts down
Xa point for the line, and clicking the right button ends the line.
X(Note that the point where you click the right button is not part of
Xthe line)
X
XSpline:
X	Works just like a line, except that it draws a quadratic
XB-spline connecting the points instead of a line.
X
XCircle:
X	The first click of the left mouse button sets the centre, and
Xthe second click sets the radius.
X
XEllipse:
X	The first click sets one corner of the box enclosing the
Xellipse, and the second click sets the other corner.
X
X
XText: 
X	To put text, select the Text button. Then, click the left mouse
Xbutton somewhere in the drawing window. The interaction window will
Xprompt for text with a "?". After inputting the text, (and hitting
Xreturn), move the mouse (which will now have the text string attached)
Xto the place where the text should be and click the left mouse button
Xagain. The way the text string is attached to the mouse depends on the
Xtext positioning attributes (left justified, centred, right-justified,
Xetc).
X
X	Xpic tries to display onscreen text as a reasonable approximation of
Xwhat you will see on the hardcopy output. This is subject to the
Xavailability of reasonable fonts, and xpic's interfaces with the output
Xdevices (the filter programs x2ps, x2pic, and x2tpic, documented below).
XHowever, since the output medium (presently pic for troff, or PostScript) is
Xlikely to have non-ascii characters which xpic cannot display easily on the
Xscreen (not without putting the full pic or PostScript text semantics in
Xxpic) there are bound to be differences. For example, the troff notation for
Xbullet is \(bu - if you put this on screen, it will appear as such. If you
Xprint it with pic and troff, it will come out on paper as a bullet. If you
Xtry printing it with tpic and TeX, it will come out as \(bu. For tpic and
XTeX, you have to say \bullet. For PostScript, you have to say \267.  In all
Xcases, xpic will not understand and will print \(bu, \bullet or \267 on the
Xscreen respectively. The user is expected to understand this. If you want
Xsnazzy effects like special characters or equations on your output device,
Xbe sure you understand the output device - xpic will try not to get it the
Xway - it won't help much either.
X
XObviously, if you want a real honest-to-goodness backslash, you have to
Xescape it with another backslash, for TeX, troff and PostScript. Backslash,
Xin xpic text, like in most other aspects of Unix, is magic - it unleashes
Xspells and incantations that are wondrous to behold if you know what you are
Xdoing, and devastating if you don't. Beware.
X
XThe text interaction window is used whenever text is needed, or
Xfilenames, or such-like. It allows a decent subset of EMACS (actually,
XJOVE) commands to edit the text in the line. The usual concepts of
Xpoint and mark apply, and killing, and yanking back killed text. Note
Xthat there is no kill ring, or mark stack - and C-X performs the
Xfunction of C-X C-X (There are no prefixes!) The keys to which
Xcommands are bound can be changed : the default bindings are:
X
X    /* motion bindings */
X
X    <Ctrl>F:            forward-character
X    <Key>168:           forward-character       /* Cursor -> key */
X    <Ctrl>B:            backward-character
X    <Key>167:           backward-character      /* Cursor <- key */
X    <Ctrl>A:            beginning-of-line
X    <Ctrl>E:            end-of-line
X    <Ctrl>U:            universal-argument      /* Multiplies by four */
X
X    /* delete bindings */
X
X    <Ctrl>D:            delete-next-character
X    <Ctrl>H:            delete-previous-character
X    <Key>113:           delete-previous-character
X    <Key>188:           delete-previous-character
X
X    /* kill bindings */ 
X
X    <Ctrl>X:            exchange-point-and-mark
X    <Ctrl> :            make-this-the-mark
X    <Ctrl>W:            kill-region
X    <Ctrl>K:            kill-to-end-of-line
X    <Meta>D:            kill-to-beginning-of-line
X
X    /* yank bindings */ 
X
X    <Ctrl>Y:            yank-killed-text
X
X    /* exit quit stuff */
X
X    <Ctrl>J:            newline
X    <Key>115:           newline
X    <Ctrl>M:            newline
X    <Key>189:           newline
X    <Ctrl>G:            abort
X    <Ctrl>C:            abort
X
X    /* selection stuff */
X
X    <BtnDown>left:      set-cursor-to-mouse
X    <BtnDown>middle:    set-mark-to-mouse
X    <BtnDown>right:     get-x-buffer
X
XTheir functions should be sort-of obvious - if not, grab a Jove manual.
X(USD-17 in the 4.3 manuals).  vi users have my sympathies. The minibuf
Xbecomes the Focus of input whenever it is required, so you need not move
Xthe mouse into the interaction window to type. When input is over, Focus is
Xgiven to the RootWindow, as it presumably was before the program
Xstarted. (If it wasn't, tough!) Clicking the left mouse button at a point in
Xthe interaction window moves the point there, clicking the middle
Xmouse button sets the mark there, (indicated by the text cursor flashing there
Xbriefly) Clicking the right mouse button extracts the text in the global X cut
Xbuffer and pastes it in at the point.
X
XChanging these bindings can be done by putting a file of bindings in the
Xabove format (without the C style comments) somewhere, and adding the
Xline 
X    xpic.Minibuf.eventBindings:         filename
X
Xin you .Xdefaults file. 'filename' can be an absolute pathname (starting
Xwith a '/') or a pathname relative to your home directory (starting without
Xa '/'. i.e. the ~ character is implicit. ~ does not work, however.) See more
Xon resources below. 
X
XNote that xpic will not go on if it expects input from the input window,
Xunless a newline (RETURN, LINE-FEED) or abort (^G) is input. It does
Xnot, however, stop other applications from continuing.
X
XThe editing operations have two modes, selected in the second button
Xbox - they should be discussed before the editing functions.
X
XElement:
X	This allows editing of individual objects. You select an
Xobject to edit by going into the drawing window and clicking near
Xit (after selecting one of the editing functions in the "Elements"
Xbox) The selected object will highlight - lines, boxes, splines,
Xellipses, circles by being redrawn thicker, and text will get a
Xshaded box over it. If you happen to have selected the wrong
Xobject, simply click the right mouse button (which will deselect
Xthe object, i.e unhighlight it, and mark it rejected) and click the
Xleft mouse button again. This time, it will select the second
Xnearest object, since the first selection is marked as rejected.
XYou can cycle through all objects on the screen without moving the
Xmouse, simply by clicking the left and right button alternately.
X
X	Once selected, you can perform the appropriate editing
Xoperation on the object.
X
XBlock:
X	In this mode, you operate on all objects contained within a
Xbox which you draw in the drawing window - first left mouse button
Xclick sets one corner of the box, and the second mouse click sets the
Xother corner. This will usually highlight all the elements within the
Xbox, and put a box on the mouse cursor, which you can drag around and
Xposition with another left click. The selected objects will be redrawn
Xat the new position, and highlighted. You can keep dragging the box
Xaround and repositioning it as long as you like - when you're
Xsatisfied with the position/shape of the new object, click the right
Xbutton and the objects unhighlight, and the drag box vanishes.
X
XThe editing operations available are:
X
XCopy:
X	This makes a copy of the selected object(s). In element mode, it
Xputs the copy of the object on the mouse cursor and allows you to
Xdrag it around and place it with another click of the mouse. In block
Xmode, you can drag the enclosing box around, which is why you get
Xmultiple chances to place it - since you can't see all the elements
Xmove.
X
XMove: 
X	Similar to copy, except the objects in question themselves
Xmove, instead of making a copy.
X
XDelete:
X	The selected object(s) highlight, and you are prompted to
Xclick again to confirm the delete. The most recently deleted
Xelement/block is stored in a kill-buffer, and can be retrieved with a
XPaste operation.
X
XPaste:
X	A left click in the drawing window puts the element/block most
Xrecently deleted on the mouse cursor and allows it to be dragged
Xaround and positioned. (one try for elements, multiple tries for
Xblocks, as usual)
X
XAdjust:
X	This differs considerably in element and block modes. In
Xelement mode, the selected object can be adjusted depending on the
Xtype of object. For lines and splines, the nearest point in the
Xline/spline is selected and moves with the mouse cursor, the object
Xbeing redrawn appropriately. For boxes, the nearest corner is
Xadjusted. In circles, the radius is changed. For ellipses, like boxes,
Xthe nearest corner (of the enclosing box) is moved. Text is put in the
Xminibuffer and can be edited - hitting return puts it back on the
Xdrawing window.
X
X	In block mode, adjustment is primarily useful for lines and
Xsplines. (But works on other objects). All control points within the
Xblock are moved around. (This is an exception to the strict
Xcontainment rule which applies to all other block operations. Here,
Xeven those elements which have only part of them in the selected block
Xare selected). For lines/splines, the control points are any point,
Xfor a boxes/ellipses, they are any corner enclosed, for circles, the
Xcentres are the control points, and for text, the text origin is the
Xcontrol point moved. This mode is best learnt by experimenting - it is
Xmore easily seen than described.
X
XGet, Put:
X	These work only in block mode (and make loud and persistent
Xcomplaints if selected in element mode). Get will prompt for the name
Xof an xpic file when the left mouse button is cliecked in the drawing
Xwindow, and will read it in, and put the enclosing box on the
Xmouse cursor to be positioned. The elements from the file will be
Xinserted into the figure. 
X
X	Put does exactly the reverse - it prompts for a file name to
Xsave the selected block to. The saved file can be read in with the Get
Xcommand, or used as a full xpic picture (xpicture?)  in its own right.
X
XChange Attributes:
X	This will change the attributes of the selected object(s) to
Xthe current set of attributes. Th eattributes are described below.
X
X Attributes
X ----------
X
XThe following attributes affect all objects excpet Text. (i.e. Line,
XSpline, Box, Circle, Ellipse).
X
XPatterns:
X	The five patterns are Solid, Dotted, Short-Dashed,
XLong-Dashed, and Dot-Dashed.
X
XLine Thickness:
X	Ranges from 0 to 10. A zero line width means a thin line, that
Xis half the width of a line of width 1, but is drawn with the same
Xwidth as a line of width 1 because of screen resolution.
X
X	This attribute affects only lines and splines:
X
XArrows:
X	Whether to draw arrows at the start of a line, the end of a
Xline, both ends of a line, or not at all.
X
X
XThe following attributes apply to only Text objects:
X
XFont:
X	This is an updown button - it will display the current font.  By
Xclicking the right or left button, one can cycle through the available fonts
X- which are determined from the X server.  See the section on fonts (later)
Xfor more on this.
X
XPoint Size:  
X	Also an updown button, which permits cycling through the
Xavailable pointsizes for the current font. 
X
XText Vertical, Horizontal Alignment:
X	These two boxes indicate how the text should be placed at the
Xmouse position. The vertical alignment Top means that the mouse is at
Xthe Top of the text, Middle is for the mouse at the bottom of the
Xtext, and Bottom means that the mouse is below the text.
X
X	The horizontal alignment decides if the mouse if to be to the
XLeft, Centre, or Right of the text.
X
XThe next attribute decides how to round off the mouse position:
X
XSnap:
X	The grid points are 8 pixels apart. There are 10 grid points
Xto every inch. (i.e 80 points per inch). The default snap value makes
Xsure that all points in the diagram are rounded off to the nearest
Xgrid point. This makes drawing precise figures much easier. If you
Xneed more resolution, you can reduce the snap value (snap of 1 means
Xthat there is no real snap) or increase it. Since X Windows does the
Xmouse cursor tracking, you can move the cursor in between the grip
Xpoints even at snap of 8. But the rubber banding of the objects will
Xshow you the effect of snap - objects will not allow you to select a
Xpixel in between two grid points if you have a snap of 8.
X
X Command Boxes
X -------------
X
XThe file operations are:
X
XRead:
X	Reads in a new file and puts it into a new cell. (Eventually,
Xyou should be able to switch between buffers easily. For now, it isn't
Xpossible, so xpic insists you must save a file before reading in
Xanother one).
X
XSave:
X	Saves the current cell in a file. If the cell has no filename
Xassociated with it, it will prompt for a cell in the interaction
Xwindow. When xpic saves a file, it makes a backup of the file before
Xthe save in a file of the form filename~ for the file filename.
X
XSave As:
X	It will prompt for a filename in the interaction window, and
Xsave the cell there. From then on, the new filename is th eone
Xassociated with the cell.
X
X
XThe miscellaneous operations are:
X
XUndo:
X	This extremely handy operation allows one level of undo - it
Xwill exactly undo the last operation performed EXCEPT for File
Xoperations. Also, undo is effective for block operations immediately
Xafter the block operation only. The first edit operation performed
X(even if it is aborted) after a block operation makes the undo
Ximpossible (and strange things will happen if the undo is performed -
Xthis is due to the way undo is implemented; unlikely to change).  If
Xundo is clicked twice, the first undo is undone. 
X
XRedisplay:
X	Refreshes the drawing window, and cleans up internal data structures
Xsomewhat. (xpic will automatically refresh itself if the window is
Xobscured and later exposed)
X
XGrid:
X	Toggles the grid on and off. With th egrid off, you usually
Xget a reasonable idea of what the picture will look when on paper.
XThis wins the least used command sweepstakes hands-down.
X
XStatus:
X	Prints the status of the buffer, in the form
X
XXPIC version.patchlevel   Buffer: buffername   File: filename   [Modified]
X
X	The [Modified] flag indicates that changes have been made to
Xthe picture since it was last saved.
X
XExit:
X	The advanced user will deduce what this is for.
X
X Resources
X ---------
X
XThe buttons and button boxes used by xpic are standard toolkit items, their
Xresources may be set easily. The interaction window and drawing window have
Xthe following resource names:
X
X                            name                class
X    Program:                xpic                XPic
X    Form enclosing it:      form                Form
X    Interaction window:     minibuf             Minibuf
X    Drawing Window:         picture             Window
X    Labels:                 label               StaticText
X    ButtonBoxes:            label.box           RowCol
X    Buttons:                button name         PushButton
X
XProgram level resources are
X    Resource name           Resource class      default
X    name                    Name                xpic
X    iconGeometry            IconGeometry        (none)
X    iconPixmap              IconPixmap          one is provided
X    pageWidth               PageWidth           85
X    pageHeight              PageHeight          105
X    gridSpacing             GridSpacing         8
X    gridOn                  GridOn              True
X    gridColor               GridColor           Black
X    cursorColor             CursorColor         Black
X    highlight               Highlight           Black
X    rotate                  Rotate              False
X    backup                  Backup              True
X    printer                 Printer             PostScript
X    lprcommand              LprCommand          x2ps -w | lpr -P%s
X    
XA sample resource file is: 
X
X	xpic*picture.background:	#80cfdf
X	xpic*picture.foreground:	black
X	xpic*RowCol.background:		MediumTurquoise
X	xpic*RowCol.borderWidth:	0
X	xpic*PushButton.font:		helv10b
X	xpic*PushButton.background:	SkyBlue
X	xpic*PushButton.foreground:	DarkSlateGrey
X	xpic*PushButton.border:		MediumAquamarine
X	xpic*Minibuf.background:	#13e5e5
X	xpic*Minibuf.foreground:	black
X	xpic*Minibuf.font:		9x15
X	xpic*Minibuf.borderWidth:	0
X	xpic*StaticText.background:	white
X	xpic*StaticText.font:		fg-13
X	xpic*StaticText.borderWidth:	0
X	xpic*background:		SkyBlue
X	
X Output
X ------
X	Xpic saves files in an internal, (ascii) easy to read/write
Xformat (easy for xpic and me, that is!) This format can be translated
Xinto PostScript and pic.
X
Xpic:
X    Use the program x2pic - no options etc. Just
X        x2pic [-s scale] [-f numfonts] [filename] ...
X
X-s scale 
Xscales the picture by 'scale', where scale can be a float. It tries to
Xscale the fonts too, unlike pic's scale command, but don't expect
Xmiracles.
X
X-f numfonts
Xsets the maximum number of fonts in the font mapping table. See the
Xsection on fonts below. The default is usually adequate unless the
Xuser has lots of fonts in the ~/.x2pic or ~/.x2tpic file.
X
XEach file becomes a separate .PS/.PE and the pic output is written to
Xstdout. If no filename is given, it is read from stdin.
X
XThen process it normally through pic. Note that the fonts on the screen
Xmatch the output fonts closely, but not perfectly.  So don't try to draw
Xboxes/ellipses/stuff around text with no tolerance - be generous.
X(Remember the old cartoonists adage - draw the bubble AFTER the text,
Xnot before)
X
Xpic cannot do anything other than solid circles/ellipses/splines. It
Xhas a silent limit of 50 points per spline which it enforces by core
Xdump.
X
XThere is a similar program called x2tpic which generates almost
Xexactly the same output, but with font style/size selection commands
Xin TeX. It can be used with tpic.
X
XPostScript:
X	x2ps [-w] [-r] [-x] [-s scale] [-p prologuefile] [-t trailerfile] 
X		[-f numfonts] [-h hoffset] [-v voffset] [filename] ....
X
X-w WYSIWYG mode, prints the figure as it was in the screen without moving the
Xpicture so the picture's lower left corner is at the page lower left corner.
XUseful for sending the picture straight to the printer. (The Print button on
Xxpic uses this by default. If you don't have a PostScript printer, you
Xmay want to change the printing command to use x2pic, pic, and troff)
X
X-r prints the figure in landscape mode, rotated by 90 degrees. It
Xgoes together with the -r option on xpic.
X
X-x suppresses the showpage emitted by x2ps - LaTeX used to need this.
X(Locally, we've fixed LaTeX by defining /showpage to be null in the 
Xspecial header).
X
X-s scale 
Xscales the picture by 'scale', where scale can be a float.
X
X-p prologuefile
X-t trailerfile
Xspecify the prologue and trailer to be used. The defaults are
X/usr/local/lib/xpic/x2ps.pro and x2ps.tra. Use these only if you know
Xwhat you're doing. Typically, you'd take x2ps.{pro,tra} and modify
Xthem to change something you don't like - or you think is buggy. On
Xyour own head be it.
X
X-h hoffset
X-v voffset
Xspecify the horizontal and vertical offset to add to the figure, in
Xinches. hoffset and voffset may be floats.
X
X-f numfonts
Xsets the maximum number of fonts in the font mapping table. See the
Xsection on fonts below. The default is usually adequate unless the
Xuser has lots of fonts in the ~/.x2ps file.
X
X FONTS
X -----
X	xpic reads a font description file to decide what fonts it can use
Xfrom the server, and to deal with differing resolutions of available screen
Xfonts.  The fontdesc file should be something like 
X
X	<Full name(used in label)> <prefix> <fontname-root>
X
XThe actual font name would be prefix.fontname-root.size[.<dots-per-inch>]
Xwhere size is a point size, at the specified dots-per-inch.
X
X(eg)
XItalic	devsun	i
XRoman	devsun	r
XBold	devsun	b
XSpecial	devsun	s
XItalic	xpic	i
XBold	xpic	r
XSpecial	xpic	s
XRoman	xpic	r
X
Xsays that fonts of the form devsun.i.* (where the * is the point
Xsize) are Italic fonts. Xpic will scale font point sizes to the
Xscreen resolution. If more than one font of the same Full name,
Xand effective point size at the current screen resolution exists,
Xthen the first one gets used.
X
XTo set the default, a line of the form 
X	default <Full name> <pointsize>
Xcould be put in. (If it isn't there, the default is the first fontname
Xand the first size of that font.
X
XThe default fontdesc file it reads is XPICLIBDIR/fontdesc/xpic. It also 
Xchecks for a ~/.xpic file, and anything in that overrides the system
Xdefaults.
X
X	x2pic uses a similar fontdesc file, which lists the mapping of
Xxpic font names to pic (or really, troff) font changing commands.
X
X(eg)
XRoman 	\fR
XItalic 	\fI
XBold 	\fB
XSpecial	\fS
XBigBold	\f(BB
X
XThe default x2pic fontdesc is in XPICLIBDIR/fontdesc/x2pic, and it also
Xreads ~/.x2pic.
X
X	x2ps does the same thing to map xpic font names to PostScript names.
X
X(eg)
XRoman Times-Roman
XItalic Times-Italic
XBold Times-Bold
XSpecial Symbol
XBigBold Helvetica-Bold
X
XThe default x2ps fontdesc is in XPICLIBDIR/fontdesc/x2ps, and it also
Xreads ~/.x2ps.
X
X
X	x2tpic has a slightly more complex font description file,
Xwhich has the following fields:
X	<Full xpic name> <pointsize> <tex name> <tex font> <optional tex scale>
X
X(eg)
XRoman 	9		\Xninerm	cmr9
X
X-- maps xpic Roman, 9 pt, to the name \Xninerm, corresponding to cmr9.
X
XRoman 	11		\Xelevenrm	cmr10  \magstephalf
X
X-- maps xpic Roman, 11 pt, to the name \Xelevenrm, corresponding to
Xcmr10, scaled by magstephalf. (See the TeXbook for more in this)
X
XItalic 	6		\Xsixit		cmti7  857
X
X-- maps xpic Italic, 6 pt, to the name \Xsixit, corresponding to cmti7
Xscaled 857.
X
XSpecial 6		\Xsixsp		PS-Symbol pointsize6
X
X-- We store the .tfm file for PostScript(tm) fonts under the names
XPS-postscriptname. (eg) PS-Symbol. Other sites may use different names
X(eg) pssymbol. The above line generates the appropriate scaled at
Xcommand to get 6 point Symbol.
X
Xx2tpic will search this table to find the closest font to the one
Xrequested. It will find the closest size in either the same font style
Xor Roman.
X
XIf you want to add to the table, keep the entries in ~/.x2tpic.
XUsually, your system will have the right map of fonts in the default.
XIf not, ask the person who installed xpic to talk to the person who
Xlooks after TeX.
X
X BUGS
X ----
XPlease report bugs to me, as specifically as you can. Note that if
Xthe system crashes, xpic cannot retrieve work like text editors.
XIf xpic dies due to some unpleasant cause (program error, network
Xerror, a signal), it dumps the current unsaved cell into some
Xtemporary directory - usually /tmp.
X
XIf you make improvements, or think they should be made, tell me. If
Xyou send code, please use context diffs - the -c flag on diff.
X
XGood luck.
X
X-----------
X+ PostScript is a trademark of Adobe, Inc.
END_OF_FILE
if test 29158 -ne `wc -c <'xpic/doc/xpic.doc'`; then
    echo shar: \"'xpic/doc/xpic.doc'\" unpacked with wrong size!
fi
# end of 'xpic/doc/xpic.doc'
fi
if test -f 'xpic/xpic.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xpic/xpic.c'\"
else
echo shar: Extracting \"'xpic/xpic.c'\" \(20476 characters\)
sed "s/^X//" >'xpic/xpic.c' <<'END_OF_FILE'
X/* $Header: xpic.c,v 1.5 89/04/21 03:32:24 xwindows Exp $ */
X/*
X *  This file contains lots of basic routines which manipulate the data
X *  and create/free/read/write various structures
X */
X
X#include <strings.h>
X#include <sys/types.h>
X#include <sys/param.h>
X#ifndef MAXPATHLEN
X# ifdef PATH_MAX
X#  define MAXPATHLEN	PATH_MAX
X# else
X   /* If you haven't got either MAXPATHLEN or PATH_MAX defined, ouch! */
X#  define MAXPATHLEN    256
X# endif
X#endif
X#include <sys/stat.h>
X#include <stdio.h>
X#include <values.h>
X
X#include "xpic.h"
X#include "windows.h"
X#include "input.h"
X#include "gels.h"
X#include "tune.h"
X#include "newfonts.h"
X#include "assert.h"
X
X#define round(x)	((int) ((x) + 0.5))
X#define xfree(x)	if (x) free(x); else
X
X/* 
X *  basic bounding box manipulation routines (may write them later as
X *  macros if I think the speed improvement warrants it.) Note that
X *  'contains' means 'p' lying within or on the bounding box 'clip', hence
X *  'intersects' means 'b' intersecting or touching 'clip'.
X */
X
XBOOL containsXY(x, y, clip)
Xregister int x, y;
Xregister Box *clip;
X{
X	return((x >= clip->ll.x) && (x <= clip->ur.x) &&
X	 (y >= clip->ll.y )&& (y <= clip->ur.y));
X}
X
XBOOL contains(p, clip)
Xregister Point *p;
Xregister Box *clip;
X{
X	return((p->x >= clip->ll.x) && (p->x <= clip->ur.x) &&
X	 (p->y >= clip->ll.y )&& (p->y <= clip->ur.y));
X}
X
X/* 
X *  If two boxes intersect, then the area of intersection must be
X *  positive, i.e. ur.x of the intersection > ll.x AND ur.y > ll.y where
X *  ur.x of the intersection is the minimum of the ur.x of the two
X *  boxes, and the ll.x is the maximum of the ll.x of the two boxes
X *  (similarly for y). (Assuming ll.x < ur.x, ll.y < ur.y ALWAYS for all
X *  boxes.)
X */
XBOOL intersects(b, clip)
Xregister Box *b;
Xregister Box *clip;
X{
X	return ( (MAX(b->ll.x, clip->ll.x) <= MIN(b->ur.x, clip->ur.x)) &&
X		 (MAX(b->ll.y, clip->ll.y) <= MIN(b->ur.y, clip->ur.y)) );
X}
X
X
X/* Returns TRUE if box 'b' lies ENTIRELY within 'clip' */
XBOOL within(b, clip)
Xregister Box *b;
Xregister Box *clip;
X{
X	return(contains(&(b->ll), clip) && contains(&(b->ur), clip));
X}
X
X
X/*
X *  Frees the vertex buffer of a pointlist, and the pointlist itself
X */
Xvoid FreePtList(pt)
Xregister PointList *pt;
X{
X	if (!pt)
X		return;
X	xfree((char *) pt->v);
X	free((char *) pt);
X}
X
X
X/*
X *  Takes a XPoint array, mallocs space for N points, and copies the first
X *  N points from the given XPoint array to the PointList
X */
XPointList *NewPtList(vertices, n)
Xregister XPoint *vertices;
Xint n;
X{
X	PointList *thisPtList;
X	
X	if ((thisPtList = (PointList *) malloc(sizeof(PointList))) == NULL) {
X		message("NewPointList: Can't get memory for new pointlist element");
X		return( (PointList *) NULL);
X	}
X
X	if ((thisPtList->v = (XPoint *) calloc((unsigned) n, sizeof(XPoint)))
X	 == NULL) {
X		message("NewPointList: Can't get memory for new vertex list");
X		free((char *) thisPtList);
X		return( (PointList *) NULL);
X	}
X
X	thisPtList->nVerts = n;
X
X	(void) bcopy((char *) vertices, (char *) (thisPtList->v),
X	 (int) (n * sizeof(XPoint)));
X	 
X	return(thisPtList);
X}
X
X
X/* Reads in a pointlist from the current inFile */
XPointList *ReadPtList(scale, type)
Xdouble scale;
Xint type;
X{
X	PointList *thisPtList;
X	register XPoint *tmp;
X	register int i, n;
X	int x, y;
X	
X	if ((thisPtList = (PointList *) malloc(sizeof(PointList))) == NULL) {
X		message("Can't get memory for new pointlist");
X		return( (PointList *) NULL);
X	}
X
X	if (fscanf(inFile, " %d", &(thisPtList->nVerts)) != 1) {
X		free((char *) thisPtList);
X		return( (PointList *) NULL);
X	}
X
X	if (type == SPLINE)
X		 thisPtList->nVerts += 2;
X
X	n = thisPtList->nVerts;
X
X	if ((thisPtList->v = (XPoint *) calloc((unsigned) n, sizeof(XPoint)))
X	 == NULL) {
X		message("Can't get memory for new vertex list");
X		free((char *) thisPtList);
X		return( (PointList *) NULL);
X	}
X
X	tmp = thisPtList->v;
X	if (type == SPLINE) {
X		tmp++;
X		n -= 2;
X	}
X
X	for (i = 0; i < n; i++, tmp++) {
X		if (fscanf(inFile, " %d %d", &x, &y) != 2) {
X			FreePtList(thisPtList);
X			return((PointList *) NULL);
X		}
X		tmp->x = round(x * scale);
X		tmp->y = round(y * scale);
X	}
X	return(thisPtList);
X}
X
X
X/* writes out a pointlist to the current outFile */
Xvoid WritePtList(pt, type)
XPointList *pt;
Xint type;
X{
X	register int i, j, n;
X	register XPoint *vert;
X	
X	vert = pt->v;
X	n = pt->nVerts;
X	if (type == SPLINE) {
X		vert++;
X		n -= 2;
X	}
X
X	(void) fprintf(outFile, "%d\n", n);
X
X	for (i = 0, j = 1; i < n; i++, vert++, j++) {
X		(void) fprintf(outFile, " %d %d", vert->x, vert->y);
X		if (j == 4) {
X			j = 0;
X			(void) fputc('\n', outFile);
X		}
X	}
X	if (j != 1)
X		(void) fputc('\n', outFile);
X}
X
X
X/*
X *  makes a Gel
X */
XGel *NewGel()
X{
X	Gel *thisGel;
X	
X	if ((thisGel = (Gel *) malloc(sizeof(Gel))) == NULL) {
X		message("NewGel: Can't get memory for new element");
X		return( (Gel *) NULL);
X	}
X
X	/* Null the pointers, and other fields */
X	bzero((char *) thisGel, sizeof(Gel));
X	
X	thisGel->number = GelCounter++;
X	
X	return (thisGel);
X}
X
X
X/*
X *  Traverse the linked list, freeing each gel - for some items like line,
X *  may need to traverse sub-lists i.e ptlist
X */
Xvoid FreeGel(g)
Xregister Gel *g;
X{
X	register Gel *tmp = g;
X
X	while (tmp != NULL) {
X		switch (tmp->type) {
X		case LINE:
X		case SPLINE:
X			FreePtList( (PointList *) tmp->data);
X			break;
X		case TEXT:
X			{
X				TextString *tmp_text = (TextString *) tmp->data;
X				if (tmp_text) xfree(tmp_text->str);
X				xfree( (char *) tmp_text);
X			}
X			break;
X		case CIRCLE:
X		case ELLIPSE:
X			xfree(tmp->data);
X			break;
X		default:
X			break;
X		}
X		tmp = tmp->next;
X		free ((char *) g);
X		g = tmp;
X	}
X}
X
X
X/*
X *  Pushes a list of Gels (g) onto another list of gels (stack). It
X *  returns the number of gels pushed onto the stack.
X */
Xint PushGel(stack, g)
Xregister Gel *g, **stack;
X{
X	register Gel *tmp;
X	register i = 0;
X	
X	while(g != NULL) {
X		tmp = g->next;
X 		g->next = *stack;
X		*stack = g;
X		g = tmp;
X		i++;
X	}
X	return(i);
X}
X
X
X/*
X *  Pushes the list of gels g onto the stack, AFTER popping off N
X *  elements. The N elements are then pushed back on. This is used by
X *  aborts, when a gel needs to be pushed back onto the stack, without
X *  disturbing the top undo elements. Note that the N returned MAY NOT
X *  be used for undo purposes, since it is not from the top of the
X *  stack. Note also that this does not completely solve the problem,
X *  because if you select one of the top undo elements, and then try an
X *  undo, things get confused, In short - don't undo too long after you
X *  do!
X */
Xint PushUnderUndo(stack, g, n)
Xregister Gel **stack;
Xregister Gel *g;
Xregister int n;
X{
X	Gel *tmp;
X
X	tmp = PopGel(stack, n);
X	n = PushGel(stack, g);
X	(void) PushGel(stack, tmp);
X	return(n);
X}
X
X	
X/*
X *  This pops N gels off the stack and returns a pointer to the list
X */
XGel *PopGel(stack, n)
Xregister Gel **stack;
Xint n;
X{
X	register Gel *g, *tmp;
X	register int i;
X
X	for(i = 0, g = NULL; i < n && *stack != NULL; i++) {
X		tmp = (*stack)->next;
X		(*stack)->next = g;
X		g = *stack;
X		*stack = tmp;
X	}
X	return(g);
X}
X
X
X/*
X *  Counts the number of Gels in a gellist
X */
Xint CountGel(gel)
Xregister Gel *gel;
X{
X	register int i = 0;
X	
X	for (; gel != NULL; gel = gel->next, i++)
X		;
X	return(i);
X}
X/* 
X *  This returns the bounding box of a gel list. Since the bounding box is
X *  returned in a static struct, it must not be modified or changed.
X */
XBox *GetBBox(g)
Xregister Gel *g;
X{
X	static Box b;
X
X	b.ur.x = b.ur.y = 0;
X	b.ll.x = b.ll.y = MAXINT;
X	while (g != NULL) {
X		bigger_box(b, g->b_box);
X		g = g->next;
X	}
X	return(&b);
X}
X		
X
X/* 
X *  Just traverse the linked list, writing out all elements in the Gel
X *  list to outFile
X */
Xvoid WriteGel(g)
Xregister Gel *g;
X{
X	Conic *conic;
X	TextString *text;
X	Box *b;
X
X#ifdef MAGIC
X	/* Write out the magic string, using the appropriate invocation */
X	(void) fprintf(outFile, "#! %s\n", PROGRAMNAME);
X#endif MAGIC
X	/* First write out Gel bounding box */
X	CalcBBox(g, MAXINT);
X	b = GetBBox(g);
X	(void) fprintf(outFile, "%d %d %d %d %d\n", b->ll.x, b->ll.y,
X	 b->ur.x, b->ur.y, gridSpacing);
X
X	/* Now write out the Gel list */
X	for (;g != NULL; g = g->next) {
X		(void) fprintf(outFile, "%d %d %d %d %d %d %x %d\n", g->type,
X		 g->number, g->b_box.ll.x, g->b_box.ll.y,
X		 g->b_box.ur.x, g->b_box.ur.y, g->attributes, g->linewidth);
X		switch (g->type) {
X		case BOX:
X			break;
X		case ELLIPSE:
X			conic = (Conic *) g->data;
X			(void) fprintf(outFile, "%d %d %d %d\n", conic->centre.x, 
X			 conic->centre.y, conic->xrad, conic->yrad);
X			break;
X		case CIRCLE:
X			conic = (Conic *) g->data;
X			(void) fprintf(outFile, "%d %d %d\n", conic->centre.x, 
X			 conic->centre.y, conic->xrad);
X			break;
X		case TEXT:
X			text = (TextString *) g->data;
X			(void) fprintf(outFile, "%d %d %d %s %d\n%s\n", text->x, text->y,
X			 text->length, text->fontname, text->fontsize, text->str);
X			break;
X		case LINE:
X		case SPLINE:
X			WritePtList((PointList *) g->data, g->type);
X			break;
X		}
X	}
X}
X
X
Xstatic char *strsave(s)
Xchar *s;
X{
X	char *s1 = XtMalloc((unsigned) (strlen(s) + 1));
X
X	if (s1)
X		(void) strcpy(s1, s);
X	return(s1);
X}
X
X
X/*
X *  Read in and make a linked list of Gel items from inFile
X */
XGel *ReadGel()
X{
X	Gel *g;
X	int type;
X	int xc, yc, xr, yr, len, attr;
X	int size;
X	char font[MAXSTR];
X	int x1, y1, x2, y2, gs;
X	char *s;
X	int c;
X	int err, nf;
X	PointList *ptlist;
X	double scale;
X	int num, thickness;
X	FontFamily *fptr;
X	char *fontname;
X
X#define NOMEM 1
X#define INPERR 2
X#define INPEOF 3
X
X	err = 0;
X	g = NULL;
X	ASSERT(allock(), "test 1");
X#ifdef MAGIC
X	/* Check for the magic header that the new xpic puts out */
X	if ((c = getc(inFile)) == EOF) {
X		message("Incorrect input format");
X		return(NULL);
X	}
X	ASSERT(allock(), "test 2");
X	(void) ungetc(c, inFile);
X	if (c == '#') {
X		/* Magic header - ignore */
X		(void) fscanf(inFile, "%*[^\n]");
X	}
X#endif MAGIC
X	/* Read in (and ignore) the gel bounding box */
X	if (fscanf(inFile, " %d %d %d %d %d", &x1, &y1, &x2, &y2, &gs) != 5) {
X		message("Incorrect input format");
X		return(NULL);
X	}
X	
X	if (gs == 0) {
X		message("Incorrect input.");
X		return(NULL);
X	}
X
X	scale = ((double) gridSpacing) / gs;
X	
X	/* Read in the actual list */
X	do {
X		if ((nf = fscanf(inFile, " %d", &type)) != 1) {
X			err = INPEOF;
X			break;
X		}
X		nf = fscanf(inFile, " %d %d %d %d %d %x %d", &num, &x1, &y1, 
X		 &x2, &y2, &attr, &thickness);
X		if (nf != 7) {
X			err = INPERR;
X			break;
X		}
X		x1 = round(x1 * scale);
X		x2 = round(x2 * scale);
X		y1 = round(y1 * scale);
X		y2 = round(y2 * scale);
X		switch (type) {
X		case BOX:
X			AddBoxGel(&g, x1, y1,x2, y2, attr, thickness);
X			break;
X		case ELLIPSE:
X			nf = fscanf(inFile, " %d %d %d %d", &xc, &yc, &xr, &yr) ;
X			if (nf != 4) {
X				err = INPERR;
X				break;
X			}
X			xc = round(xc * scale);
X			yc = round(yc * scale);
X			xr = round(xr * scale);
X			yr = round(yr * scale);
X			AddConicGel(&g, type, xc, yc, xr, yr, attr, x1, y1, x2, y2, thickness);
X			break;
X		case CIRCLE:
X			nf = fscanf(inFile, " %d %d %d", &xc, &yc, &xr);
X			if (nf != 3) {
X				err = INPERR;
X				break;
X			}
X			xc = round(xc * scale);
X			yc = round(yc * scale);
X			xr = round(xr * scale);
X			AddConicGel(&g, type, xc, yc, xr, xr, attr, x1, y1, x2, y2, thickness);
X			break;
X		case TEXT:
X			nf = fscanf(inFile, " %d %d %d %s %d", &xc, &yc, &len, font, 
X			 &size);
X			if (nf != 5) {
X				err = INPERR;
X				break;
X			}
X			/*
X			 *  For backward compatibility with the bad old days. The
X			 *  old convention of storing font information was really
X			 *  ugly - a font number from 0-3, (corresponding to Roman,
X			 *  Bolld, Italic, Special) and a size from 0-9
X			 *  (corresponding to point sizes 6 - 24)
X			 */
X			if (font[1] == '\0') {
X				int oldfontconvention = TRUE;
X				
X				switch (font[0]) {
X				case '0':
X					(void) strcpy(font, "Roman");
X					break;
X				case '1':
X					(void) strcpy(font, "Bold");
X					break;
X				case '2':
X					(void) strcpy(font, "Italic");
X					break;
X				case '3':
X					(void) strcpy(font, "Special");
X					break;
X				default:
X					/* Must a new font with a one letter name. Eeep! */
X					oldfontconvention = FALSE;
X				}
X				if (oldfontconvention)
X					/* Convert to pointsize */
X					size = size * 2 + 6;
X			}
X			xc = round(xc * scale);
X			yc = round(yc * scale);
X			/* Go to the next line */
X			while ((c = fgetc(inFile)) != '\n' && c != EOF)
X				;
X			if (c == EOF) {
X				err = INPERR;
X				break;
X			}
X			s = XtMalloc((unsigned) (len + 2));
X			if (fgets(s, len + 1, inFile) == NULL) {
X				free(s);
X				err = INPERR;
X				break;
X			}
X			s[len] = '\0';
X			if ((fptr = findfont(font, TRUE)) == NULL) {
X				fontname = strsave(font);
X				fptr = defaultFontFamily;
X			} else {
X				fontname = fptr->name;
X			}
X			AddTextGel(&g, s, len, fptr, findsize(fptr, size), fontname, size, 
X			 attr, xc, yc, x1, y1, x2, y2);
X			break;
X		case LINE:
X		case SPLINE:
X			if ((ptlist = ReadPtList(scale, type)) == NULL) {
X				err = NOMEM;
X				break;
X			}
X			AddLineGel(&g, type, ptlist, attr, x1, y1, x2, y2, thickness);
X			ptlist = NULL;
X			break;
X		}
X	} while (err == 0);
X	if (err == NOMEM)
X		message("No more memory for elements");
X	else if (err == INPERR)
X		message("Incorrect input format");
X
X	CalcBBox(g, MAXINT);
X	return(g);
X#undef NOMEM
X#undef INPERR
X#undef INPEOF
X}
X
X
X/* 
X *  Creates a new cell, with appropriate filename and name, and giving it
X *  all the default values. It does not open the file, nor does it read
X *  anything in - the cell is empty
X */
XCell *NewCell(cellName, fileName)
Xchar *cellName;
Xchar *fileName;
X{
X	register Cell *thisCell;
X	
X	if ((thisCell = (Cell *) malloc(sizeof(Cell))) == NULL) {
X		message("NewCell: Can't create cell");
X		return( (Cell *)NULL);
X	}
X
X	thisCell->name = cellName;
X	thisCell->filename = fileName;
X	thisCell->gelList = NULL;
X	thisCell->saved = NEWFILE;
X	thisCell->undo = 0;
X	thisCell->undoList = NULL;
X	thisCell->next = NULL;
X	thisCell->mtime = 0;
X
X	return(thisCell);
X}
X
X
X/* Frees and destroys a cell */
Xvoid FreeCell(cell)
XCell *cell;
X{
X	if (!cell) 
X		return;
X	xfree(cell->name);
X	xfree(cell->filename);
X	FreeGel(cell->gelList);
X	FreeGel(cell->undoList);
X	free((char *) cell);
X}
X
X
X/*
X *  Prints a cell out to lpr
X */
XLPrintCell(cell)
XCell *cell;
X{
X	static char *cmdbuf = NULL;
X	char *buf;
X	extern char *lprcommand;
X	extern char *lprinter;
X	extern void SetWorkingCursor(), SetWaitCursor();
X	
X	if (cmdbuf == NULL) {
X		/* format default command */
X		cmdbuf = XtMalloc((unsigned)
X		 (strlen(lprcommand) + strlen(lprinter) + 1));
X		(void) sprintf(cmdbuf, lprcommand, lprinter);
X	}
X	/* offer user a chance to change default printing command */
X	if ((buf = get_input("Print command % ", cmdbuf, FALSE)) == NULL)
X		return;
X	/* free default command and make new command from user the default */
X	XtFree(cmdbuf);
X	cmdbuf = buf;
X	/* open the pipe - Then write out the cell Gels. */
X	if ((outFile = popen(buf, "w")) == NULL) {
X		message("Can't open pipe for print");
X	} else {
X		SetWaitCursor();
X		WriteGel(cell->gelList);
X		(void) sprintf(errstring, "Print Complete");
X		message(errstring);
X		(void) pclose(outFile);
X		SetWorkingCursor();
X		outFile = NULL;
X	}
X}
X
X
X/*
X *  Writes a cell out - closely emulates the Jove save about making
X *  backups, checking if the file has been written to, etc
X */
Xint
XWriteCell(cell, backup)
XCell *cell;
X{
X	char *fname;
X	char buf[MAXPATHLEN];
X	struct stat stbuf;
X	int retval = 0;
X	extern void SetWorkingCursor(), SetWaitCursor();
X#ifdef MAGIC
X	int fperms;
X#endif MAGIC
X	
X	
X	if (!(cell->saved & MODIFIED)) {
X		message("No changes need to be written.");
X		return 1;
X	}
X
X	/* If no file name, ask for one - default is buffer name */
X	if (!cell->filename || STREQ(cell->filename, nullfile)) {
X		if ((fname = get_input("Save file name ? ", cell->name, TRUE)) == NULL)
X			return 0;
X		cell->filename = fname;
X		cell->saved |= NEWFILE;
X	}
X
X	/*
X	 *  Check that it's safe to write the file, and make a backup if
X	 *  necessary
X	 */
X	if (!chk_mtime(cell, buf, backup))
X		return 0;
X
X	/* 
X	 *  open the file - Then write out the cell Gels. Should sort the
X	 *  cell gels before doing this
X	 */
X	if ((outFile = fopen(buf, "w")) == NULL) {
X		(void) sprintf(errstring, "Can't open %s for save", buf);
X		message(errstring);
X		retval = 0;
X	} else {
X		SetWaitCursor();
X		WriteGel(cell->gelList);
X		SetWorkingCursor();
X		if (fclose(outFile) == 0) {
X			cell->saved = SAVED;
X			(void) sprintf(errstring, "Wrote %s", buf);
X			retval = 1;
X		} else {
X			(void) sprintf(errstring, "Error writing %s - cell not saved",
X			 buf);
X			retval = 0;
X		}
X		message(errstring);
X		outFile = NULL;
X		if (stat(buf, &stbuf) == -1) {
X			(void) sprintf(errstring, "Cannot stat %s", buf);
X			message(errstring);
X		} else {
X			cell->mtime = stbuf.st_mtime;
X#ifdef MAGIC
X			/*
X			 * Extract permissions - we set it to owner execuatble, and make
X			 * it group/other executable only if it is group/other readable.
X			 * Not sure if it needs to be that elaborate...
X			 */
X			fperms = stbuf.st_mode & 0777;
X			fperms |= 0100;		/* Set owner executable */
X			if (fperms & 0040)
X				fperms |= 0010;	/* Set group executable */
X			if (fperms & 0004)
X				fperms |= 0001;	/* Set user executable */
X			if (chmod(buf, fperms) == -1) {
X				(void) sprintf(errstring, "Cannot chmod %s", buf);
X				message(errstring);
X			}
X#endif MAGIC
X		}
X	}
X	return(retval);
X}
X
X
X/* 
X *  Read Cell routine - when this is done for multiple buffers, it should
X *  check first to see if another buffer already has the file. It takes a
X *  filename as input - if this is NULL, then it asks the user for a
X *  filename.
X */
XCell *ReadCell(prompt, fname)
Xchar *prompt;
Xchar *fname;
X{
X	char *name, *StripName();
X	Cell *cell;
X	char buf[MAXPATHLEN];
X	struct stat	stbuf;
X	extern void SetWorkingCursor(), SetWaitCursor();
X	
X	/* Get filename */
X	if (fname == NULL)
X		if ((fname = get_input(prompt, (char *) NULL, TRUE)) == NULL)
X			return((Cell *) NULL);
X	/*
X	 *  create the cell
X	 */
X	if ((name = StripName(fname)) == NULL) {
X		message("No memory for cell name");
X		return((Cell *) NULL);
X	}
X
X	if ((cell = NewCell(name, fname)) == NULL) {
X		message("No memory for new cell");
X		free(name);
X		free(fname);
X		return((Cell *) NULL);
X	}
X	PathParse(fname, buf);
X	/* if a file exists, then open it and read the Gels */
X	if ((inFile = fopen(buf, "r")) != NULL) {
X		SetWaitCursor();
X		cell->gelList = ReadGel();
X#ifdef DEBUG
X		if (cell->gelList != NULL) {
X			(void) sprintf(errstring, "Read file %s", buf);
X			message(errstring);
X		}
X#endif
X		if (fstat(fileno(inFile), &stbuf) == -1) {
X			(void) sprintf(errstring, "Can't fstat %s", buf);
X			message(errstring);
X		} else {
X			cell->mtime = stbuf.st_mtime;
X		}
X		(void) fclose(inFile);
X		SetWorkingCursor();
X		cell->saved = SAVED;
X		inFile = NULL;
X	} 
X#ifdef DEBUG
X	else {
X		(void) sprintf(errstring, "New file %s", buf);
X		message(errstring);
X	}
X#endif
X
X	return(cell);
X}
X
X
X/*
X *  expands and ~ in the cell filename and returns that in fname, stats
X *  the file, checks with the user if the file has been modified since
X *  it was last saved/read by the program, or if we'll be overwriting a
X *  file, and returns TRUE if things can proceed, FALSE if things can't!
X *  If backup is true, then it makes a backup copy of the file. All in
X *  one stat! This code has been adapted from similar code in JOVE.
X */
X
Xint
Xchk_mtime(cell, fname, backup)
XCell	*cell;
Xchar	*fname;
Xint		backup;
X{
X	struct stat	stbuf;
X	int exists;
X	static char	*badchars = "!$^&*()`{}\"'\\|<>? ";
X	register char *cp = cell->filename;
X	register int c;
X
X	while (c = *cp++)
X		if (c < ' ' || c == '\177' || index(badchars, c)) {
X			(void) sprintf(errstring,
X			 "'%c': bad character in filename \"%s\".", 
X			 c, cell->filename);
X			message(errstring);
X			return(FALSE);
X		}
X	PathParse(cell->filename, fname);
X	stbuf.st_mode = 0;
X	exists = stat(fname, &stbuf);
X	if ((!exists) && (cell->saved & NEWFILE)) {
X		/* We're about to overwrite something */
X		(void) sprintf(errstring,
X		 "\"%s\" already exists; overwrite it (y/n)? ", 
X		 cell->filename);
X		switch (confirm(errstring, "n")) {
X			case ABORT:
X			case NO:
X				return(FALSE);
X			case YES:
X				break;
X		}
X	}
X	if ((cell->mtime != 0) &&				/* if we care ... */
X	 (!exists) &&								/* and it exists */
X	 (stbuf.st_mtime != cell->mtime)) {	/* and there's trouble. */
X	 	(void) sprintf(errstring,
X		 "\"%s\" on disk is not what you last read/saved. Overwrite (y/n)? ",
X		 cell->filename);
X		switch(confirm(errstring, "n")) {
X			case ABORT:
X			case NO:
X				return(FALSE);
X			case YES:
X				break;
X		}
X	}
X	if ((!exists) && backup)
X		/* Create backup file with same mode as input file */
X		if (file_backup(fname, stbuf.st_mode) == -1) {
X			message("Couldn't write backup file - save failed");
X			return(FALSE);
X		}
X		
X	return(TRUE);
X}
END_OF_FILE
if test 20476 -ne `wc -c <'xpic/xpic.c'`; then
    echo shar: \"'xpic/xpic.c'\" unpacked with wrong size!
fi
# end of 'xpic/xpic.c'
fi
echo shar: End of archive 14 \(of 15\).
cp /dev/null ark14isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 15 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0



More information about the Comp.sources.x mailing list