argv@island.uu.net (Dan Heller) (07/22/89)
Submitted-by: Mark Moraes <moraes@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@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@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