home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
vsiftp.vmssoftware.com
/
VSIPUBLIC@vsiftp.vmssoftware.com.tar
/
FREEWARE
/
FREEWARE40.ZIP
/
xv310a
/
xvdir_vaxc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-11-06
|
57KB
|
2,074 lines
/*
* xvdir.c - Directory changin', file i/o dialog box
*
* callable functions:
*
* CreateDirW(geom,bwidth)- creates the dirW window. Doesn't map it.
* DirBox(vis) - random processing based on value of 'vis'
* maps/unmaps window, etc.
* ClickDirW() - handles mouse clicks in DirW
* LoadCurrentDirectory() - loads up current dir information for dirW
* GetDirPath() - returns path that 'dirW' is looking at
* DoSave() - calls appropriate save routines
* SetDirFName() - sets the 'load/save-as' filename and default
* GetDirFName() - gets the 'load/save-as' filename (no path)
* SetDirSaveMode() - sets default format/color settings
*
* InitPoll() - called whenever a file is first loaded
* CheckPoll(int) - checks to see whether we should reload
*/
#include "copyright.h"
#define NEEDSTIME /* for CheckPoll */
#define NEEDSDIR
#include "xv.h"
#include "bits/d_load"
#include "bits/d_save"
#ifndef VMS
#include <pwd.h> /* for getpwnam() prototype and passwd struct */
#endif
#define DIRWIDE 350 /* (fixed) size of directory window */
#define DIRHIGH 400
#define NLINES 15 /* # of lines in list control (keep odd) */
#define LISTWIDE 237 /* width of list window */
#define BUTTW 60 /* width of buttons */
#define BUTTH 24 /* height of buttons */
#define DDWIDE (LISTWIDE-80+15) /* max width of dirMB */
#define DNAMWIDE 252 /* width of 'file name' entry window */
#define MAXDEEP 30 /* max num of directories in cwd path */
#define MAXFNLEN 256 /* max len of filename being entered */
#define FMTLABEL "Format:" /* label shown next to fmtMB */
#define COLLABEL "Colors:" /* label shown next to colMB */
#define FMTWIDE 150 /* width of fmtMB */
#define COLWIDE 150 /* width of colMB */
/* NOTE: make sure these match up with F_* definitions in xv.h */
static char *saveColors[] = { "Full Color",
"Greyscale",
"B/W Dithered",
"Reduced Color" };
static char *saveFormats[] = { "GIF",
#ifdef HAVE_JPEG
"JPEG",
#endif
#ifdef HAVE_TIFF
"TIFF",
#endif
"PostScript",
"PBM/PGM/PPM (raw)",
"PBM/PGM/PPM (ascii)",
"X11 Bitmap",
"XPM",
"BMP",
"Sun Rasterfile",
"IRIS RGB",
"Targa (24-bit)",
"FITS",
"PM",
MBSEP,
"Filename List"};
static void arrangeButts PARM((int));
static void RedrawDList PARM((int, SCRL *));
static void changedDirMB PARM((int));
static int dnamcmp PARM((const void *, const void *));
static int FNameCdable PARM((void));
static void loadCWD PARM((void));
static int cd_able PARM((char *));
static void scrollToFileName PARM((void));
static void setFName PARM((char *));
static void showFName PARM((void));
static void changeSuffix PARM((void));
static int autoComplete PARM((void));
static byte *handleBWandReduced PARM((byte *, int,int,int, int, int *,
byte **, byte **, byte **));
static byte *handleNormSel PARM((int *, int *, int *, int *));
static char *fnames[MAXNAMES];
static int numfnames = 0, ndirs = 0;
static char path[MAXPATHLEN+1]; /* '/' terminated */
static char loadpath[MAXPATHLEN+1]; /* '/' terminated */
static char savepath[MAXPATHLEN+1]; /* '/' terminated */
static char *dirs[MAXDEEP]; /* list of directory names */
static char *dirMBlist[MAXDEEP]; /* list of dir names in right order */
static char *lastdir; /* name of the directory we're in */
static char filename[MAXFNLEN+100]; /* filename being entered */
static char deffname[MAXFNLEN+100]; /* default filename */
static int savemode; /* if 0 'load box', if 1 'save box' */
static int curPos, stPos, enPos; /* filename textedit stuff */
static MBUTT dirMB; /* popup path menu */
static MBUTT fmtMB; /* 'format' menu button (Save only) */
static MBUTT colMB; /* 'colors' menu button (Save only) */
static Pixmap d_loadPix, d_savePix;
static int haveoldinfo = 0;
static int oldformat, oldcolors;
static char oldfname[MAXFNLEN+100];
/* the name of the file actually opened. (the temp file if we are piping) */
static char outFName[256];
static int dopipe;
/***************************************************/
void CreateDirW(geom)
char *geom;
{
int w, y;
path[0] = '\0';
xv_getwd(loadpath, sizeof(loadpath));
xv_getwd(savepath, sizeof(savepath));
dirW = CreateWindow("","XVdir", geom, DIRWIDE, DIRHIGH, infofg, infobg, 0);
if (!dirW) FatalError("couldn't create 'directory' window!");
LSCreate(&dList, dirW, 10, 5 + 3*(6+LINEHIGH) + 6, LISTWIDE,
LINEHIGH*NLINES, NLINES, fnames, numfnames, infofg, infobg,
hicol, locol, RedrawDList, 1, 0);
dnamW = XCreateSimpleWindow(theDisp, dirW, 80, dList.y + (int) dList.h + 30,
(u_int) DNAMWIDE+6, (u_int) LINEHIGH+5,
1, infofg, infobg);
if (!dnamW) FatalError("can't create name window");
XSelectInput(theDisp, dnamW, ExposureMask);
CBCreate(&browseCB, dirW, DIRWIDE/2, dList.y + (int) dList.h + 6,
"Browse", infofg, infobg, hicol,locol);
CBCreate(&savenormCB, dirW, 220, dList.y + (int) dList.h + 6,
"Normal Size", infofg, infobg,hicol,locol);
CBCreate(&saveselCB, dirW, 80, dList.y + (int) dList.h + 6,
"Selected Area", infofg, infobg,hicol,locol);
/* y-coordinates get filled in when window is opened */
BTCreate(&dbut[S_BOK], dirW, 259, 0, 80, BUTTH,
"Ok", infofg, infobg,hicol,locol);
BTCreate(&dbut[S_BCANC], dirW, 259, 0, 80, BUTTH,
"Cancel", infofg,infobg,hicol,locol);
BTCreate(&dbut[S_BRESCAN], dirW, 259, 0, 80, BUTTH,
"Rescan", infofg,infobg,hicol,locol);
BTCreate(&dbut[S_BOLDSET], dirW, 259, 0, 80, BUTTH,
"Prev Set", infofg,infobg,hicol,locol);
BTCreate(&dbut[S_BOLDNAM], dirW, 259, 0, 80, BUTTH,
"Prev Name", infofg,infobg,hicol,locol);
SetDirFName("");
XMapSubwindows(theDisp, dirW);
numfnames = 0;
/*
* create MBUTTs *after* calling XMapSubWindows() to keep popup unmapped
*/
MBCreate(&dirMB, dirW, 50, dList.y -(LINEHIGH+6),
(u_int) DDWIDE, (u_int) LINEHIGH, NULL, NULL, 0,
infofg,infobg,hicol,locol);
MBCreate(&fmtMB, dirW, DIRWIDE-FMTWIDE-10, 5,
(u_int) FMTWIDE, (u_int) LINEHIGH, NULL, saveFormats, F_MAXFMTS,
infofg,infobg,hicol,locol);
fmtMB.hascheck = 1;
MBSelect(&fmtMB, 0);
MBCreate(&colMB, dirW, DIRWIDE-COLWIDE-10, 5+LINEHIGH+6,
(u_int) COLWIDE, (u_int) LINEHIGH, NULL, saveColors, F_MAXCOLORS,
infofg,infobg,hicol,locol);
colMB.hascheck = 1;
MBSelect(&colMB, 0);
d_loadPix = XCreatePixmapFromBitmapData(theDisp, dirW,
(char *) d_load_bits, d_load_width, d_load_height,
infofg, infobg, dispDEEP);
d_savePix = XCreatePixmapFromBitmapData(theDisp, dirW,
(char *) d_save_bits, d_save_width, d_save_height,
infofg, infobg, dispDEEP);
}
/***************************************************/
void DirBox(mode)
int mode;
{
static int firstclose = 1;
if (!mode) {
if (savemode) strcpy(savepath, path);
else strcpy(loadpath, path);
if (firstclose) {
strcpy(loadpath, path);
strcpy(savepath, path);
firstclose = 0;
}
XUnmapWindow(theDisp, dirW); /* close */
}
else if (mode == BLOAD) {
strcpy(path, loadpath);
WaitCursor(); LoadCurrentDirectory(); SetCursors(-1);
XStoreName(theDisp, dirW, "xv load");
XSetIconName(theDisp, dirW, "xv load");
dbut[S_BLOADALL].str = "Load All";
BTSetActive(&dbut[S_BLOADALL], 1);
arrangeButts(mode);
MBSetActive(&fmtMB, 0);
MBSetActive(&colMB, 0);
CenterMapWindow(dirW, dbut[S_BOK].x+30, dbut[S_BOK].y + BUTTH/2,
DIRWIDE, DIRHIGH);
savemode = 0;
}
else if (mode == BSAVE) {
strcpy(path, savepath);
WaitCursor(); LoadCurrentDirectory(); SetCursors(-1);
XStoreName(theDisp, dirW, "xv save");
XSetIconName(theDisp, dirW, "xv save");
dbut[S_BOLDSET].str = "Prev Set";
arrangeButts(mode);
BTSetActive(&dbut[S_BOLDSET], haveoldinfo);
BTSetActive(&dbut[S_BOLDNAM], haveoldinfo);
CBSetActive(&saveselCB, HaveSelection());
MBSetActive(&fmtMB, 1);
if (MBWhich(&fmtMB) == F_FILELIST) {
MBSetActive(&colMB, 0);
CBSetActive(&savenormCB, 0);
}
else {
MBSetActive(&colMB, 1);
CBSetActive(&savenormCB, 1);
}
CenterMapWindow(dirW, dbut[S_BOK].x+30, dbut[S_BOK].y + BUTTH/2,
DIRWIDE, DIRHIGH);
savemode = 1;
}
scrollToFileName();
dirUp = mode;
BTSetActive(&but[BLOAD], !dirUp);
BTSetActive(&but[BSAVE], !dirUp);
}
/***************************************************/
static void arrangeButts(mode)
int mode;
{
int i, nbts, ngaps, szdiff, top, gap;
nbts = (mode==BLOAD) ? S_LOAD_NBUTTS : S_NBUTTS;
ngaps = nbts-1;
szdiff = dList.h - (nbts * BUTTH);
gap = szdiff / ngaps;
if (gap>16) {
gap = 16;
top = dList.y + (dList.h - (nbts*BUTTH) - (ngaps*gap))/2;
for (i=0; i<nbts; i++) dbut[i].y = top + i*(BUTTH+gap);
}
else {
for (i=0; i<nbts; i++)
dbut[i].y = dList.y + ((dList.h-BUTTH)*i) / ngaps;
}
}
/***************************************************/
void RedrawDirW(x,y,w,h)
int x,y,w,h;
{
int i, ypos, txtw;
char foo[30], *str;
XRectangle xr;
if (dList.nstr==1) strcpy(foo,"1 file");
else sprintf(foo,"%d files",dList.nstr);
ypos = dList.y + dList.h + 8 + ASCENT;
XSetForeground(theDisp, theGC, infobg);
XFillRectangle(theDisp, dirW, theGC, 10, ypos-ASCENT,
(u_int) DIRWIDE, (u_int) CHIGH);
XSetForeground(theDisp, theGC, infofg);
DrawString(dirW, 10, ypos, foo);
if (dirUp == BLOAD) str = "Load file:";
else str = "Save file:";
DrawString(dirW, 10, dList.y + (int) dList.h + 30 + 4 + ASCENT, str);
/* draw dividing line */
XSetForeground(theDisp, theGC, infofg);
XDrawLine(theDisp, dirW, theGC, 0, dirMB.y-6, DIRWIDE, dirMB.y-6);
if (ctrlColor) {
XSetForeground(theDisp, theGC, locol);
XDrawLine(theDisp, dirW, theGC, 0, dirMB.y-5, DIRWIDE, dirMB.y-5);
XSetForeground(theDisp, theGC, hicol);
}
XDrawLine(theDisp, dirW, theGC, 0, dirMB.y-4, DIRWIDE, dirMB.y-4);
for (i=0; i<(savemode ? S_NBUTTS : S_LOAD_NBUTTS); i++) BTRedraw(&dbut[i]);
MBRedraw(&dirMB);
MBRedraw(&fmtMB);
MBRedraw(&colMB);
XSetForeground(theDisp, theGC, infofg);
XSetBackground(theDisp, theGC, infobg);
txtw = StringWidth(FMTLABEL);
if (StringWidth(COLLABEL) > txtw) txtw = StringWidth(COLLABEL);
if (!savemode) {
XCopyArea(theDisp, d_loadPix, dirW, theGC, 0,0,d_load_width,d_load_height,
10, (dirMB.y-6)/2 - d_load_height/2);
XSetFillStyle(theDisp, theGC, FillStippled);
XSetStipple(theDisp, theGC, dimStip);
DrawString(dirW, fmtMB.x-6-txtw, 5+3+ASCENT, FMTLABEL);
DrawString(dirW, fmtMB.x-6-txtw, 5+3+ASCENT + (LINEHIGH+6), COLLABEL);
XSetFillStyle(theDisp,theGC,FillSolid);
CBRedraw(&browseCB);
}
else {
XCopyArea(theDisp, d_savePix, dirW, theGC, 0,0,d_save_width,d_save_height,
10, (dirMB.y-6)/2 - d_save_height/2);
XSetForeground(theDisp, theGC, infofg);
DrawString(dirW, fmtMB.x-6-txtw, 5+3+ASCENT, FMTLABEL);
DrawString(dirW, fmtMB.x-6-txtw, 5+3+ASCENT + (LINEHIGH+6), COLLABEL);
CBRedraw(&savenormCB);
CBRedraw(&saveselCB);
}
}
/***************************************************/
int ClickDirW(x,y)
int x,y;
{
BUTT *bp;
int bnum,i,maxbut,v;
char buf[1024];
if (savemode) { /* check format/colors MBUTTS */
i = v = 0;
if (MBClick(&fmtMB, x,y) && (v=MBTrack(&fmtMB))>=0) i=1;
else if (MBClick(&colMB, x,y) && (v=MBTrack(&colMB))>=0) i=2;
if (i) { /* changed one of them */
if (i==1) SetDirSaveMode(F_FORMAT, v);
else SetDirSaveMode(F_COLORS, v);
changeSuffix();
}
}
if (!savemode) { /* LOAD */
if (CBClick(&browseCB,x,y)) CBTrack(&browseCB);
}
else { /* SAVE */
if (CBClick(&savenormCB,x,y)) CBTrack(&savenormCB);
else if (CBClick(&saveselCB,x,y)) CBTrack(&saveselCB);
}
maxbut = (savemode) ? S_NBUTTS : S_LOAD_NBUTTS;
for (bnum=0; bnum<maxbut; bnum++) {
bp = &dbut[bnum];
if (PTINRECT(x, y, bp->x, bp->y, bp->w, bp->h)) break;
}
if (bnum<maxbut && BTTrack(bp)) { /* found one */
if (bnum<S_BOLDSET) return bnum; /* do Ok,Cancel,Rescan in xvevent.c */
if (bnum == S_BOLDSET && savemode && haveoldinfo) {
MBSelect(&fmtMB, oldformat);
MBSelect(&colMB, oldcolors);
changeSuffix();
}
else if (bnum == S_BOLDNAM && savemode && haveoldinfo) {
setFName(oldfname);
}
else if (bnum == S_BLOADALL && !savemode) {
int j, oldnumnames;
char *dname;
oldnumnames = numnames;
for (i=0; i<numfnames && numnames<MAXNAMES; i++) {
if (fnames[i][0] == C_REG || fnames[i][0] == C_EXE) {
sprintf(buf,"%s%s", path, fnames[i]+1);
/* check for dups. Don't add it if it is. */
for (j=0; j<numnames && strcmp(buf,namelist[j]); j++);
if (j==numnames) { /* add to list */
namelist[numnames] = (char *) malloc(strlen(buf)+1);
if (!namelist[numnames]) FatalError("out of memory!\n");
strcpy(namelist[numnames],buf);
dname = namelist[numnames];
/* figure out how much of name can be shown */
if (StringWidth(dname) > (nList.w-10-16)) { /* truncate */
char *tmp;
int prelen = 0;
tmp = dname;
while (1) {
tmp = (char *) index(tmp,'/'); /* find next '/' in buf */
if (!tmp) break;
tmp++; /* move to char following the '/' */
prelen = tmp - dname;
if (StringWidth(tmp) <= (nList.w-10-16)) break; /* cool now */
}
dispnames[numnames] = dname + prelen;
}
else dispnames[numnames] = dname;
numnames++;
}
}
}
if (oldnumnames != numnames) { /* added some */
if (numnames>0) BTSetActive(&but[BDELETE],1);
windowMB.dim[WMB_TEXTVIEW] = (numnames==0);
LSNewData(&nList, dispnames, numnames);
nList.selected = oldnumnames;
curname = oldnumnames - 1;
ActivePrevNext();
ScrollToCurrent(&nList);
DrawCtrlNumFiles();
if (!browseCB.val) DirBox(0);
}
}
}
if (MBClick(&dirMB, x, y)) {
i = MBTrack(&dirMB);
if (i >= 0) changedDirMB(i);
}
return -1;
}
/***************************************************/
void SelectDir(n)
int n;
{
/* called when entry #n in the dir list was selected/double-clicked */
/* if n<0, nothing was double-clicked, but perhaps the selection
has changed. Copy the selection to the filename if a) we're in
the 'load' box, and b) it's not a directory name */
if (n<0) {
if (dList.selected>=0)
setFName(dList.str[dList.selected]+1);
return;
}
/* can just pretend 'enter' was hit on a double click, as the original
click would've copied the string to filename */
if (!DirCheckCD()) FakeButtonPress(&dbut[S_BOK]);
}
/***************************************************/
static void changedDirMB(sel)
int sel;
{
if (sel != 0) { /* changed directories */
char tmppath[MAXPATHLEN+1], *trunc_point;
/* end 'path' by changing trailing '/' (of dir name) to a '\0' */
trunc_point = (dirs[(ndirs-1)-sel + 1] - 1);
*trunc_point = '\0';
if (path[0] == '\0') {
/* special case: if cd to '/', fix path (it's currently "") */
#ifdef apollo /*** Apollo DomainOS uses // as the network root ***/
strcpy(tmppath,"//");
#else
strcpy(tmppath,"/");
#endif
}
else strcpy(tmppath, path);
#ifdef VMS
/*
* The VMS chdir always needs 2 components (device and directory),
* so convert "/device" to "/device/000000" and convert
* "/" to "/XV_Root_Device/000000" (XV_Root_Device will need to be
* a special concealed device setup to provide a list of available
* disks).
*/
if ( ((ndirs-sel) == 2) && (strlen(tmppath) > 1) )
strcat ( tmppath, "/000000" ); /* add root dir for device */
else if ((ndirs-sel) == 1 ) {
strcpy ( tmppath, "/XV_Root_Device/000000" ); /* fake top level */
}
#endif
if (chdir(tmppath)) {
char str[512];
sprintf(str,"Unable to cd to '%s'\n", tmppath);
*trunc_point = '/'; /* restore the path */
MBRedraw(&dirMB);
ErrPopUp(str, "\nWhatever");
}
else {
loadCWD();
}
}
}
/***************************************************/
static void RedrawDList(delta, sptr)
int delta;
SCRL *sptr;
{
LSRedraw(&dList,delta);
}
/***************************************************/
static void loadCWD()
{
/* loads up current-working-directory into load/save list */
xv_getwd(path, sizeof(path));
LoadCurrentDirectory();
}
/***************************************************/
void LoadCurrentDirectory()
{
/* rescans current load/save directory */
DIR *dirp;
int i, j, ftype, mode, changedDir;
struct stat st;
char *dbeg, *dend;
static char oldpath[MAXPATHLEN + 2] = { '\0' };
#ifdef NODIRENT
struct direct *dp;
#else
struct dirent *dp;
#endif
/* get rid of previous file names */
for (i=0; i<numfnames; i++) free(fnames[i]);
numfnames = 0;
/* get rid of old dirMBlist */
for (i=0; i<ndirs; i++) free(dirMBlist[i]);
#ifndef VMS
if (strlen(path) == 0) xv_getwd(path, sizeof(path)); /* no dir, use cwd */
#else
xv_getwd(path, sizeof(path));
#endif
if (chdir(path)) {
ErrPopUp("Current load/save directory seems to have gone away!",
"\nYikes!");
#ifdef apollo
strcpy(path,"//");
#else
strcpy(path,"/");
#endif
chdir(path);
}
changedDir = strcmp(path, oldpath);
strcpy(oldpath, path);
if ((strlen(path) > (size_t) 1) && path[strlen(path)-1] != '/')
strcat(path,"/"); /* tack on a trailing '/' to make path consistent */
/* path will be something like: "/u3/bradley/src/weiner/whatever/" */
/* parse path into individual directory names */
dbeg = dend = path;
for (i=0; i<MAXDEEP && dend; i++) {
dend = (char *) index(dbeg,'/'); /* find next '/' char */
#ifdef apollo
/** On apollos the path will be something like //machine/users/foo/ **/
/** handle the initial // **/
if ((dend == dbeg ) && (dbeg[0] == '/') && (dbeg[1] == '/')) dend += 1;
#endif
dirs[i] = dbeg;
dbeg = dend+1;
}
ndirs = i-1;
/* build dirMBlist */
for (i=ndirs-1,j=0; i>=0; i--,j++) {
size_t stlen = (i<(ndirs-1)) ? dirs[i+1] - dirs[i] : strlen(dirs[i]);
dirMBlist[j] = (char *) malloc(stlen+1);
if (!dirMBlist[j]) FatalError("unable to malloc dirMBlist[]");
strncpy(dirMBlist[j], dirs[i], stlen);
dirMBlist[j][stlen] = '\0';
}
lastdir = dirs[ndirs-1];
dirMB.list = dirMBlist;
dirMB.nlist = ndirs;
XClearArea(theDisp, dirMB.win, dirMB.x, dirMB.y,
(u_int) dirMB.w+3, (u_int) dirMB.h+3, False);
i = StringWidth(dirMBlist[0]) + 10;
dirMB.x = dirMB.x + dirMB.w/2 - i/2;
dirMB.w = i;
MBRedraw(&dirMB);
dirp = opendir(".");
if (!dirp) {
LSNewData(&dList, fnames, 0);
RedrawDirW(0,0,DIRWIDE,DIRHIGH);
return;
}
WaitCursor();
i=0;
while ( (dp = readdir(dirp)) != NULL) {
if (strcmp(dp->d_name, ".")==0 ||
(strcmp(dp->d_name, "..")==0 &&
(strcmp(path,"/")==0 || strcmp(path,"//")==0)) ||
strcmp(dp->d_name, THUMBDIR)==0) {
/* skip over '.' and '..' and THUMBDIR */
}
else {
if (i == MAXNAMES) {
fprintf(stderr,
"%s: too many directory entries. Only using first %d.\n",
cmd, MAXNAMES);
break;
}
if ((i&31)==0) WaitCursor();
fnames[i] = (char *) malloc(strlen(dp->d_name)+2); /* +2=ftype + '\0' */
if (!fnames[i]) FatalError("malloc error while reading directory");
strcpy(fnames[i]+1, dp->d_name);
/* figure out what type of file the beastie is */
fnames[i][0] = C_REG; /* default to normal file, if stat fails */
#ifdef VMS
/* For VMS we will default all files EXCEPT directories to avoid
the high cost of the VAX C implementation of the stat function.
Suggested by Kevin Oberman (OBERMAN@icdc.llnl.gov) */
if (xv_strstr (fnames[i]+1, ".DIR") != NULL) fnames[i][0] = C_DIR;
if (xv_strstr (fnames[i]+1, ".EXE") != NULL) fnames[i][0] = C_EXE;
if (xv_strstr (fnames[i]+1, ".OBJ") != NULL) fnames[i][0] = C_BLK;
#else
if (!nostat && (stat(fnames[i]+1, &st)==0)) {
mode = st.st_mode & 0777; /* rwx modes */
ftype = st.st_mode;
if (S_ISDIR(ftype)) fnames[i][0] = C_DIR;
else if (S_ISCHR(ftype)) fnames[i][0] = C_CHR;
else if (S_ISBLK(ftype)) fnames[i][0] = C_BLK;
else if (S_ISLINK(ftype)) fnames[i][0] = C_LNK;
else if (S_ISFIFO(ftype)) fnames[i][0] = C_FIFO;
else if (S_ISSOCK(ftype)) fnames[i][0] = C_SOCK;
else if (fnames[i][0] == C_REG && (mode&0111)) fnames[i][0] = C_EXE;
}
else {
/* fprintf(stderr,"problems 'stat-ing' files\n");*/
fnames[i][0] = C_REG;
}
#endif /* VMS */
i++;
}
}
closedir(dirp);
numfnames = i;
qsort((char *) fnames, (size_t) numfnames, sizeof(char *), dnamcmp);
if (changedDir) LSNewData(&dList, fnames, numfnames);
else LSChangeData(&dList, fnames, numfnames);
RedrawDirW(0,0,DIRWIDE,DIRHIGH);
SetCursors(-1);
}
/***************************************************/
void GetDirPath(buf)
char *buf;
{
/* returns current 'dirW' path. buf should be MAXPATHLEN long */
strcpy(buf, path);
}
/***************************************************/
static int cd_able(str)
char *str;
{
return ((str[0] == C_DIR || str[0] == C_LNK));
}
/***************************************************/
static int dnamcmp(p1,p2)
const void *p1, *p2;
{
char **s1, **s2;
s1 = (char **) p1;
s2 = (char **) p2;
#ifdef FOO
/* sort so that directories are at beginning of list */
/* if both dir/lnk or both NOT dir/lnk, sort on name */
if ( ( cd_able(*s1) && cd_able(*s2)) ||
(!cd_able(*s1) && !cd_able(*s2)))
return (strcmp((*s1)+1, (*s2)+1));
else if (cd_able(*s1)) return -1; /* s1 is first */
else return 1; /* s2 is first */
#else
/* sort in pure alpha order */
return(strcmp((*s1)+1, (*s2)+1));
#endif
}
/***************************************************/
int DirKey(c)
int c;
{
/* got keypress in dirW. stick on end of filename */
int len;
len = strlen(filename);
if (c>=' ' && c<'\177') { /* printable characters */
/* note: only allow 'piped commands' in savemode... */
/* only allow spaces in 'piped commands', not filenames */
if (c==' ' && (!ISPIPE(filename[0]) || curPos==0)) return (-1);
/* only allow vertbars in 'piped commands', not filenames */
if (c=='|' && curPos!=0 && !ISPIPE(filename[0])) return(-1);
if (len >= MAXFNLEN-1) return(-1); /* max length of string */
xvbcopy(&filename[curPos], &filename[curPos+1], (size_t) (len-curPos+1));
filename[curPos]=c; curPos++;
scrollToFileName();
}
else if (c=='\010' || c=='\177') { /* BS or DEL */
if (curPos==0) return(-1); /* at beginning of str */
xvbcopy(&filename[curPos], &filename[curPos-1], (size_t) (len-curPos+1));
curPos--;
if (strlen(filename) > (size_t) 0) scrollToFileName();
}
else if (c=='\025') { /* ^U: clear entire line */
filename[0] = '\0';
curPos = 0;
}
else if (c=='\013') { /* ^K: clear to end of line */
filename[curPos] = '\0';
}
else if (c=='\001') { /* ^A: move to beginning */
curPos = 0;
}
else if (c=='\005') { /* ^E: move to end */
curPos = len;
}
else if (c=='\004') { /* ^D: delete character at curPos */
if (curPos==len) return(-1);
xvbcopy(&filename[curPos+1], &filename[curPos], (size_t) (len-curPos));
}
else if (c=='\002') { /* ^B: move backwards char */
if (curPos==0) return(-1);
curPos--;
}
else if (c=='\006') { /* ^F: move forwards char */
if (curPos==len) return(-1);
curPos++;
}
else if (c=='\012' || c=='\015') { /* CR or LF */
if (!DirCheckCD()) FakeButtonPress(&dbut[S_BOK]);
}
else if (c=='\033') { /* ESC = Cancel */
FakeButtonPress(&dbut[S_BCANC]);
}
else if (c=='\011') { /* tab = filename expansion */
if (!autoComplete()) XBell(theDisp, 0);
else {
curPos = strlen(filename);
scrollToFileName();
}
}
else return(-1); /* unhandled character */
showFName();
/* if we cleared out filename, clear out deffname as well */
if (!filename[0]) deffname[0] = '\0';
return(0);
}
/***************************************************/
static int autoComplete()
{
/* called to 'auto complete' a filename being entered. If the name that
has been entered so far is anything but a simple filename (ie, has
spaces, pipe char, '/', etc) fails. If it is a simple filename,
looks through the name list to find something that matches what's already
been typed. If nothing matches, it fails. If more than one thing
matches, it sets the name to the longest string that the multiple
matches have in common, and succeeds (and beeps).
If only one matches, sets the string to the match and succeeds.
returns zero on failure, non-zero on success */
int i, firstmatch, slen, nummatch, cnt;
/* is filename a simple filename? */
if (strlen(filename)==0 ||
ISPIPE(filename[0]) ||
index(filename, '/') ||
filename[0]=='~' ) return 0;
slen = strlen(filename);
for (i=0; i<dList.nstr; i++) {
if (strncmp(filename, dList.str[i]+1, (size_t) slen) <= 0) break;
}
if (i==dList.nstr) return 0;
if (strncmp(filename, dList.str[i]+1, (size_t) slen) < 0) return 0;
/* there's a match of some sort... */
firstmatch = i;
/* count # of matches */
for (i=firstmatch, nummatch=0;
i<dList.nstr && strncmp(filename, dList.str[i]+1, (size_t) slen)==0;
i++, nummatch++);
if (nummatch == 1) { /* only one match */
strcpy(filename, dList.str[firstmatch]+1);
return 1;
}
/* compute longest common prefix among the matches */
while (dList.str[firstmatch][slen+1]!='\0') {
filename[slen] = dList.str[firstmatch][slen+1];
slen++; filename[slen] = '\0';
for (i=firstmatch, cnt=0;
i<dList.nstr && strncmp(filename, dList.str[i]+1, (size_t) slen)==0;
i++, cnt++);
if (cnt != nummatch) { slen--; filename[slen] = '\0'; break; }
}
XBell(theDisp, 0);
return 1;
}
/***************************************************/
static void scrollToFileName()
{
int i, hi, lo, pos, cmp;
/* called when 'fname' changes. Tries to scroll the directory list
so that fname would be centered in it */
/* nothing to do if scrlbar not enabled ( <= NLINES names in list) */
if (dList.scrl.max <= 0) return;
/* find the position in the namelist that the current name should be at
(binary search) */
pos = 0; lo = 0; hi = dList.nstr-1;
i = strlen(filename);
if (!i) { SCSetVal(&dList.scrl, 0); return; }
while ((hi-lo)>=0) {
pos = lo + (hi-lo)/2;
cmp = strcmp(filename, dList.str[pos]+1);
if (cmp<0) hi = pos-1;
else if (cmp>0) lo = pos+1;
else break; /* found it! */
}
/* set scroll position so that 'pos' will be centered in the list */
i = pos - (NLINES/2);
SCSetVal(&dList.scrl, i);
}
/***************************************************/
void RedrawDNamW()
{
int cpos;
/* draw substring filename[stPos:enPos] and cursor */
Draw3dRect(dnamW, 0, 0, (u_int) DNAMWIDE+5, (u_int) LINEHIGH+4, R3D_IN, 2,
hicol, locol, infobg);
XSetForeground(theDisp, theGC, infofg);
if (stPos>0) { /* draw a "there's more over here" doowah */
XDrawLine(theDisp, dnamW, theGC, 0,0,0,LINEHIGH+5);
XDrawLine(theDisp, dnamW, theGC, 1,0,1,LINEHIGH+5);
XDrawLine(theDisp, dnamW, theGC, 2,0,2,LINEHIGH+5);
}
if ((size_t) enPos < strlen(filename)) {
/* draw a "there's more over here" doowah */
XDrawLine(theDisp, dnamW, theGC, DNAMWIDE+5,0,DNAMWIDE+5,LINEHIGH+5);
XDrawLine(theDisp, dnamW, theGC, DNAMWIDE+4,0,DNAMWIDE+4,LINEHIGH+5);
XDrawLine(theDisp, dnamW, theGC, DNAMWIDE+3,0,DNAMWIDE+3,LINEHIGH+5);
}
XDrawString(theDisp, dnamW, theGC,3,ASCENT+3,filename+stPos, enPos-stPos);
cpos = XTextWidth(mfinfo, &filename[stPos], curPos-stPos);
XDrawLine(theDisp, dnamW, theGC, 3+cpos, 2, 3+cpos, 2+CHIGH+1);
XDrawLine(theDisp, dnamW, theGC, 3+cpos, 2+CHIGH+1, 5+cpos, 2+CHIGH+3);
XDrawLine(theDisp, dnamW, theGC, 3+cpos, 2+CHIGH+1, 1+cpos, 2+CHIGH+3);
}
/***************************************************/
int DoSave()
{
FILE *fp;
byte *thepic, *rp, *gp, *bp;
int i, w, h, rv, fmt, col, nc, ptype, pfree;
char *fullname;
/* opens file, does appropriate color pre-processing, calls save routine
based on chosen format. Returns '0' if successful */
dbut[S_BOK].lit = 1; BTRedraw(&dbut[S_BOK]);
fullname = GetDirFullName();
fmt = MBWhich(&fmtMB);
col = MBWhich(&colMB);
if (fmt<0 || col<0)
FatalError("xv: no 'checked' format or color. shouldn't happen!\n");
if (fmt == F_FILELIST) { /* write filename list */
fp = OpenOutFile(fullname);
if (!fp) {
SetCursors(-1);
dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
return -1;
}
for (i=0; i<numnames; i++) {
if ((i&0x3f)==0) WaitCursor();
if (namelist[i][0] != '/') fprintf(fp, "%s/%s\n", initdir, namelist[i]);
else fprintf(fp, "%s\n", namelist[i]);
}
i = (ferror(fp)) ? 1 : 0;
if (CloseOutFile(fp, fullname, i) == 0) {
DirBox(0);
XVCreatedFile(fullname);
}
SetCursors(-1);
dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
return i;
} /* FILELIST */
/* handle formats that pop up 'how do you want to save this' boxes */
if (fmt == F_PS) { /* PostScript */
PSSaveParams(fullname, col);
PSDialog(1); /* open PSDialog box */
dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
return 0; /* always 'succeeds' */
}
#ifdef HAVE_JPEG
else if (fmt == F_JPEG) { /* JPEG */
JPEGSaveParams(fullname, col);
JPEGDialog(1); /* open JPEGDialog box */
dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
return 0; /* always 'succeeds' */
}
#endif
#ifdef HAVE_TIFF
else if (fmt == F_TIFF) { /* TIFF */
TIFFSaveParams(fullname, col);
TIFFDialog(1); /* open TIFF Dialog box */
dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
return 0; /* always 'succeeds' */
}
#endif
WaitCursor();
thepic = GenSavePic(&ptype, &w, &h, &pfree, &nc, &rp, &gp, &bp);
fp = OpenOutFile(fullname);
if (!fp) {
if (pfree) free(thepic);
SetCursors(-1);
dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
return -1;
}
if (col == F_REDUCED) col = F_FULLCOLOR;
rv = 0;
switch (fmt) {
case F_GIF:
rv = WriteGIF (fp, thepic, ptype, w, h, rp,gp,bp, nc,col,picComments);
break;
case F_PM:
rv = WritePM (fp, thepic, ptype, w, h, rp,gp,bp, nc,col,picComments);
break;
case F_PBMRAW:
rv = WritePBM (fp, thepic, ptype, w, h, rp,gp,bp, nc,col,1,picComments);
break;
case F_PBMASCII:
rv = WritePBM (fp, thepic, ptype, w, h, rp,gp,bp, nc,col,0,picComments);
break;
case F_XBM:
rv = WriteXBM (fp, thepic, w, h, rp, gp, bp, fullname); break;
case F_SUNRAS:
rv = WriteSunRas(fp, thepic, ptype, w, h, rp, gp, bp, nc, col,0); break;
case F_BMP:
rv = WriteBMP (fp, thepic, ptype, w, h, rp, gp, bp, nc, col); break;
case F_IRIS:
rv = WriteIRIS (fp, thepic, ptype, w, h, rp, gp, bp, nc, col); break;
case F_TARGA:
rv = WriteTarga (fp, thepic, ptype, w, h, rp, gp, bp, nc, col); break;
case F_XPM:
rv = WriteXPM (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
fullname, picComments);
case F_FITS:
rv = WriteFITS (fp, thepic, ptype, w, h, rp, gp, bp, nc, col,
picComments);
break;
}
if (CloseOutFile(fp, fullname, rv) == 0) {
DirBox(0);
if (!dopipe) {
XVCreatedFile(fullname);
StickInCtrlList(0);
}
}
if (pfree) free(thepic);
SetCursors(-1);
dbut[S_BOK].lit = 0; BTRedraw(&dbut[S_BOK]);
return rv;
}
/***************************************************/
void SetDirFName(st)
char *st;
{
strncpy(deffname, st, (size_t) MAXFNLEN-1);
setFName(st);
}
/***************************************************/
static void setFName(st)
char *st;
{
strncpy(filename, st, (size_t) MAXFNLEN-1);
filename[MAXFNLEN-1] = '\0'; /* make sure it's terminated */
curPos = strlen(st);
stPos = 0; enPos = curPos;
showFName();
}
/***************************************************/
static void showFName()
{
int len;
len = strlen(filename);
if (curPos<stPos) stPos = curPos;
if (curPos>enPos) enPos = curPos;
if (stPos>len) stPos = (len>0) ? len-1 : 0;
if (enPos>len) enPos = (len>0) ? len-1 : 0;
/* while substring is shorter than window, inc enPos */
while (XTextWidth(mfinfo, &filename[stPos], enPos-stPos) < DNAMWIDE
&& enPos<len) { enPos++; }
/* while substring is longer than window, dec enpos, unless enpos==curpos,
in which case, inc stpos */
while (XTextWidth(mfinfo, &filename[stPos], enPos-stPos) > DNAMWIDE) {
if (enPos != curPos) enPos--;
else stPos++;
}
if (ctrlColor) XClearArea(theDisp, dnamW, 2,2, (u_int) DNAMWIDE+5-3,
(u_int) LINEHIGH+4-3, False);
else XClearWindow(theDisp, dnamW);
RedrawDNamW();
BTSetActive(&dbut[S_BOK], strlen(filename)!=0);
}
/***************************************************/
char *GetDirFName()
{
return (filename);
}
/***************************************************/
char *GetDirFullName()
{
static char globname[MAXFNLEN+100]; /* the +100 is for ~ expansion */
static char fullname[MAXPATHLEN+2];
if (ISPIPE(filename[0])) strcpy(fullname, filename);
else {
strcpy(globname, filename);
if (globname[0] == '~') Globify(globname);
if (globname[0] != '/') sprintf(fullname, "%s%s", path, globname);
else strcpy(fullname, globname);
}
return (fullname);
}
/***************************************************/
void SetDirSaveMode(group, bnum)
int group, bnum;
{
if (group == F_COLORS) {
if (picType == PIC24) { /* disable REDUCED COLOR */
colMB.dim[F_REDUCED] = 1;
if (MBWhich(&colMB) == F_REDUCED) MBSelect(&colMB, F_FULLCOLOR);
}
else { /* PIC8 - turn on REDUCED COLOR, if not XBM */
if (MBWhich(&fmtMB) != F_XBM) {
colMB.dim[F_REDUCED] = 0;
MBRedraw(&fmtMB);
}
}
if (bnum>=0) MBSelect(&colMB, bnum);
}
else if (group == F_FORMAT) {
MBSelect(&fmtMB, bnum);
if (MBWhich(&fmtMB) == F_XBM) { /* turn off all but B/W */
colMB.dim[F_FULLCOLOR] = 1;
colMB.dim[F_GREYSCALE] = 1;
colMB.dim[F_BWDITHER] = 0;
colMB.dim[F_REDUCED] = 1;
MBSelect(&colMB, F_BWDITHER);
}
else if (MBWhich(&fmtMB) == F_FITS) { /* turn off 'color' modes */
colMB.dim[F_FULLCOLOR] = 1;
colMB.dim[F_GREYSCALE] = 0;
colMB.dim[F_BWDITHER] = 0;
colMB.dim[F_REDUCED] = 1;
MBSelect(&colMB, F_GREYSCALE);
}
else { /* turn on all */
colMB.dim[F_FULLCOLOR] = 0;
colMB.dim[F_GREYSCALE] = 0;
colMB.dim[F_BWDITHER] = 0;
colMB.dim[F_REDUCED] = (picType==PIC8) ? 0 : 1;
if (picType!=PIC8 && MBWhich(&colMB)==F_REDUCED)
MBSelect(&colMB, F_FULLCOLOR);
}
if (MBWhich(&fmtMB) == F_FILELIST) {
MBSetActive(&colMB, 0);
CBSetActive(&savenormCB, 0);
}
else {
MBSetActive(&colMB, 1);
CBSetActive(&savenormCB, 1);
}
}
}
/***************************************/
static void changeSuffix()
{
/* see if there's a common suffix at the end of the filename.
if there is, remember what case it was (all caps or all lower), lop
it off, and replace it with a new appropriate suffix, in the
same case */
int allcaps;
char *suffix, *sp, *dp, lowsuf[512];
/* find the last '.' in the filename */
suffix = (char *) rindex(filename, '.');
if (!suffix) return;
suffix++; /* point to first letter of the suffix */
/* check for all-caposity */
for (sp = suffix, allcaps=1; *sp; sp++)
if (islower(*sp)) allcaps = 0;
/* copy the suffix into an all-lower-case buffer */
for (sp=suffix, dp=lowsuf; *sp; sp++, dp++) {
*dp = (isupper(*sp)) ? tolower(*sp) : *sp;
}
*dp = '\0';
/* compare for common suffixes */
if ((strcmp(lowsuf,"gif" )==0) ||
(strcmp(lowsuf,"pm" )==0) ||
(strcmp(lowsuf,"pbm" )==0) ||
(strcmp(lowsuf,"pgm" )==0) ||
(strcmp(lowsuf,"ppm" )==0) ||
(strcmp(lowsuf,"pnm" )==0) ||
(strcmp(lowsuf,"bm" )==0) ||
(strcmp(lowsuf,"xbm" )==0) ||
(strcmp(lowsuf,"ras" )==0) ||
(strcmp(lowsuf,"bmp" )==0) ||
(strcmp(lowsuf,"ps" )==0) ||
(strcmp(lowsuf,"eps" )==0) ||
(strcmp(lowsuf,"rgb" )==0) ||
(strcmp(lowsuf,"tga" )==0) ||
(strcmp(lowsuf,"xpm" )==0) ||
(strcmp(lowsuf,"fits")==0) ||
(strcmp(lowsuf,"fts" )==0) ||
(strcmp(lowsuf,"jpg" )==0) ||
(strcmp(lowsuf,"jpeg")==0) ||
(strcmp(lowsuf,"jfif")==0) ||
(strcmp(lowsuf,"tif" )==0) ||
(strcmp(lowsuf,"tiff")==0)) {
/* found one. set lowsuf = to the new suffix, and tack on to filename */
int fmt, col;
fmt = MBWhich(&fmtMB);
col = MBWhich(&colMB);
if (fmt<0 || col<0) return; /* shouldn't happen */
switch (fmt) {
case F_GIF: strcpy(lowsuf,"gif"); break;
case F_PM: strcpy(lowsuf,"pm"); break;
case F_PBMRAW:
case F_PBMASCII: if (col == F_FULLCOLOR || col == F_REDUCED)
strcpy(lowsuf,"ppm");
else if (col == F_GREYSCALE) strcpy(lowsuf,"pgm");
else if (col == F_BWDITHER) strcpy(lowsuf,"pbm");
break;
case F_XBM: strcpy(lowsuf,"xbm"); break;
case F_SUNRAS: strcpy(lowsuf,"ras"); break;
case F_BMP: strcpy(lowsuf,"bmp"); break;
case F_PS: strcpy(lowsuf,"ps"); break;
case F_IRIS: strcpy(lowsuf,"rgb"); break;
case F_TARGA: strcpy(lowsuf,"tga"); break;
case F_XPM: strcpy(lowsuf,"xpm"); break;
case F_FITS: strcpy(lowsuf,"fts"); break;
#ifdef HAVE_JPEG
case F_JPEG: strcpy(lowsuf,"jpg"); break;
#endif
#ifdef HAVE_TIFF
case F_TIFF: strcpy(lowsuf,"tif"); break;
#endif
}
if (allcaps) { /* upper-caseify lowsuf */
for (sp=lowsuf; *sp; sp++)
*sp = (islower(*sp)) ? toupper(*sp) : *sp;
}
/* one other case: if the original suffix started with a single
capital letter, make the new suffix start with a single cap */
if (isupper(suffix[0])) lowsuf[0] = toupper(lowsuf[0]);
strcpy(suffix, lowsuf); /* tack onto filename */
SetDirFName(filename);
}
}
/***************************************************/
int DirCheckCD()
{
/* checks if the current filename is a directory. If so,
cd's there, resets the filename to 'deffname', and returns '1'
otherwise, does nothing and returns '0' */
if (FNameCdable()) {
setFName(deffname);
return 1;
}
return 0;
}
/***************************************************/
static int FNameCdable()
{
/* returns '1' if filename is a directory, and goes there */
char newpath[1024];
struct stat st;
int retval = 0;
newpath[0] = '\0'; /* start out empty */
if (ISPIPE(filename[0]) || strlen(filename)==0) return 0;
if (filename[0] == '/' || filename[0] == '~') { /* absolute path */
strcpy(newpath, filename);
}
else { /* not an absolute pathname */
strcpy(newpath,path);
strcat(newpath,filename);
}
if (newpath[0]=='~') { /* handle globbing */
Globify(newpath);
}
#ifdef VMS
/* Convert names of form "/device.dir" to "/device/000000.DIR" */
if ( rindex ( newpath, '/' ) == newpath ) {
strcpy ( rindex ( newpath, '.' ), "/000000.DIR" );
}
#endif
if (stat(newpath, &st)==0) {
int isdir;
isdir = S_ISDIR(st.st_mode);
if (isdir) {
#ifdef VMS
/* remove .DIR from the path so that false 000000 directories work */
char *dirext;
dirext = rindex ( newpath, '/' );
if ( dirext == NULL ) dirext = newpath; else dirext++;
dirext = xv_strstr ( dirext, "." );
*dirext = '\0';
#endif
if (chdir(newpath)==0) {
loadCWD(); /* success! */
}
else {
char str[512];
sprintf(str,"Can't chdir to '%s'.\n\n %s.",filename, ERRSTR(errno));
ErrPopUp(str, "\nPity");
}
retval = 1;
}
}
return retval;
}
/**************************************************************************/
int Globify(fname)
char *fname;
{
/* expands ~s in file names. Returns the name inplace 'name'.
returns 0 if okay, 1 if error occurred (user name not found) */
struct passwd *entry;
char *cp, *sp, *up, uname[64], tmp[MAXFNLEN+100];
#ifdef VMS
return 1;
#else
if (*fname != '~') return 0; /* doesn't start with a tilde, don't expand */
/* look for the first '/' after the tilde */
sp = (char *) index(fname,'/');
if (sp == 0) { /* no '/' after the tilde */
sp = fname+strlen(fname); /* sp = end of string */
}
/* uname equals the string between the ~ and the / */
for (cp=fname+1,up=uname; cp<sp; *up++ = *cp++);
*up='\0';
if (*uname=='\0') { /* no name. substitute ~ with $HOME */
char *homedir;
homedir = (char *) getenv("HOME");
if (homedir == NULL) homedir = ".";
strcpy(tmp,homedir);
strcat(tmp,sp);
}
else { /* get password entry for uname */
entry = getpwnam(uname);
if (entry==0) return 1; /* name not found */
strcpy(tmp,entry->pw_dir);
strcat(tmp,sp);
endpwent();
}
strcpy(fname,tmp); /* return expanded file name */
return 0;
#endif /* !VMS */
}
/***************************************/
FILE *OpenOutFile(filename)
char *filename;
{
/* opens file for output. does various error handling bits. Returns
an open file pointer if success, NULL if failure */
FILE *fp;
struct stat st;
if (!filename || filename[0] == '\0') return NULL;
strcpy(outFName, filename);
dopipe = 0;
/* make sure we're in the correct directory */
if (strlen(path)) chdir(path);
if (ISPIPE(filename[0])) { /* do piping */
/* make up some bogus temp file to put this in */
#ifndef VMS
sprintf(outFName, "%s/xvXXXXXX", tmpdir);
#else
strcpy(outFName, "[]xvXXXXXX.lis");
#endif
mktemp(outFName);
dopipe = 1;
}
#ifndef VMS
/*
** On OpenVMS, unless a user has set a version limit within a directory
** writing a new file will not overwrite the existing file. Don't put out
** the warning.
** If a version limit is set, well that person should be shot :-)
** BJM
*/
/* see if file exists (ie, we're overwriting) */
if (stat(outFName, &st)==0) { /* stat succeeded, file must exist */
static char *foo[] = { "\nOk", "\033Cancel" };
char str[512];
sprintf(str,"Overwrite existing file '%s'?", outFName);
if (PopUp(str, foo, 2)) return NULL;
}
#endif
/* Open file */
fp = fopen(outFName, "w");
if (!fp) {
char str[512];
sprintf(str,"Can't write file '%s'\n\n %s.",outFName, ERRSTR(errno));
ErrPopUp(str, "\nBummer");
return NULL;
}
return fp;
}
/***************************************/
int CloseOutFile(fp, filename, failed)
FILE *fp;
char *filename;
int failed;
{
char buf[64];
/* close output file, and if piping, deal... Returns '0' if everything OK */
if (failed) { /* failure during format-specific output routine */
char str[512];
sprintf(str,"Couldn't write file '%s'.", outFName);
ErrPopUp(str, "\nBummer!");
unlink(outFName); /* couldn't properly write file: delete it */
return 1;
}
if (fclose(fp) == EOF) {
static char *foo[] = { "\nWeird!" };
char str[512];
sprintf(str,"Can't close file '%s'\n\n %s.",outFName, ERRSTR(errno));
ErrPopUp(str, "\nWeird!");
return 1;
}
buf[0]= '\0'; /* empty buffer */
{ /* compute size of written file */
FILE *fp;
long filesize;
fp = fopen(outFName,"r");
if (fp) {
fseek(fp, 0L, 2);
filesize = ftell(fp);
fclose(fp);
sprintf(buf," (%ld bytes)", filesize);
}
}
SetISTR(ISTR_INFO,"Successfully wrote '%s'%s", outFName, buf);
if (dopipe) {
char cmd[512], str[1024];
int i;
#ifndef VMS
sprintf(cmd, "cat %s |%s", outFName, filename+1); /* lose pipe char */
#else
sprintf(cmd, "Print /Queue = XV_Queue /Delete %s", outFName);
#endif
sprintf(str,"Doing command: '%s'", cmd);
OpenAlert(str);
i = system(cmd);
#ifdef VMS
i = !i;
#endif
if (i) {
sprintf(str, "Unable to complete command:\n %s", cmd);
CloseAlert();
ErrPopUp(str, "\nThat Sucks!");
unlink(outFName);
return 1;
}
else {
CloseAlert();
SetISTR(ISTR_INFO,"Successfully completed command.");
#ifndef VMS
unlink(outFName);
#endif
}
}
/* save old info */
haveoldinfo = 1;
oldformat = MBWhich(&fmtMB);
oldcolors = MBWhich(&colMB);
strcpy(oldfname, filename);
return 0;
}
static byte rBW[2], gBW[2], bBW[2];
static byte gray[256];
/***************************************/
static byte *handleBWandReduced(pic, ptype, pw, ph, color, nc, rpp, gpp, bpp)
byte *pic;
int ptype, pw, ph, color, *nc;
byte **rpp, **gpp, **bpp;
{
/* given 'color mode' (F_FULLCOLOR, etc.), we may have to dither
and/or use different colormaps. Returns 'nc', rpp, gpp, bpp (the
colormap to use). Also, if the function returns non-NULL, it generated
a new (dithered) image to use. */
int i;
byte *bwpic;
bwpic = (byte *) NULL;
*nc = numcols; *rpp = rMap; *gpp = gMap; *bpp = bMap;
/* quick check: if we're saving a 24-bit image, then none of this
complicated 'reduced'/dithered/smoothed business comes into play.
'reduced' is disabled, for semi-obvious reasons, in 24-bit mode,
as is 'dithered'. If 'smoothed', and we're saving at current
size, no problem. Otherwise, if we're saving at original size,
smoothing should have no effect, so there's no reason to smooth
the original pic...
In any event: in 24-bit mode, all we have to do here is determine
if we're saving B/W DITHERED, and deal accordingly */
if (ptype == PIC24) {
if (color != F_BWDITHER) return NULL;
else { /* generate a bw-dithered version */
byte *p24, *thepic;
thepic = pic;
p24 = GammifyPic24(thepic, pw, ph);
if (p24) thepic = p24;
/* generate a FSDithered 1-byte per pixel image */
bwpic = FSDither(thepic, PIC24, pw, ph, NULL,NULL,NULL, 0, 1);
if (!bwpic) FatalError("unable to malloc dithered picture (DoSave)");
if (p24) free(p24); /* won't need it any more */
/* build a BW colormap */
rBW[0] = gBW[0] = bBW[0] = 0;
rBW[1] = gBW[1] = bBW[1] = 255;
*rpp = rBW; *gpp = gBW; *bpp = bBW;
*nc = 2;
return bwpic;
}
}
/* ptype == PIC8 ... */
*nc = numcols; *rpp = rMap; *gpp = gMap; *bpp = bMap;
if (color==F_REDUCED) { *rpp = rdisp; *gpp = gdisp; *bpp = bdisp; }
/* if DITHER or SMOOTH, and color==FULLCOLOR or GREY,
make color=REDUCED, so it will be written with the correct colortable */
if ((epicMode == EM_DITH || epicMode == EM_SMOOTH) && color != F_REDUCED) {
if (color == F_FULLCOLOR) {
*rpp = rdisp; *gpp = gdisp; *bpp = bdisp;
}
else if (color == F_GREYSCALE) {
for (i=0; i<256; i++) gray[i] = MONO(rdisp[i], gdisp[i], bdisp[i]);
*rpp = gray; *gpp = gray; *bpp = gray;
}
}
if (color==F_BWDITHER || (ncols==0 && color==F_REDUCED) ) {
/* if we're saving as 'dithered', or we're viewing as dithered
and we're saving 'reduced' then generate a dithered image */
if (numcols==2) return NULL; /* already dithered */
/* generate a dithered 1-byte per pixel image */
bwpic = FSDither(pic, PIC8, pw, ph, rMap,gMap,bMap, 0, 1);
if (!bwpic) FatalError("unable to malloc dithered picture (DoSave)");
/* put a BW colormap */
rBW[0] = (blkRGB>>16)&0xff; rBW[1] = (whtRGB>>16)&0xff;
gBW[0] = (blkRGB>>8)&0xff; gBW[1] = (whtRGB>>8)&0xff;
bBW[0] = blkRGB&0xff; bBW[1] = whtRGB&0xff;
*rpp = rBW; *gpp = gBW; *bpp = bBW;
*nc = 2;
}
return bwpic;
}
/***************************************/
static byte *handleNormSel(pptype, pwide, phigh, pfree)
int *pptype, *pwide, *phigh, *pfree;
{
/* called to return a pointer to a 'pic', its type, its width & height,
* and whether or not it should be freed when we're done with it. The 'pic'
* returned is the desired portion of 'cpic' or 'epic' if there is a
* selection, and the saveselCB is enabled, or alternately, it's the
* whole cpic or epic.
*
* if selection does not intersect cpic/epic, returns cpic/epic
* NEVER RETURNS NULL
*/
byte *thepic;
int pw, ph, slx, sly, slw, slh;
*pfree = 0; *pptype = picType;
if (savenormCB.val) { thepic = cpic; pw = cWIDE; ph = cHIGH; }
else { thepic = epic; pw = eWIDE; ph = eHIGH; }
*pwide = pw; *phigh = ph;
if (saveselCB.active && saveselCB.val && HaveSelection()) {
GetSelRCoords(&slx, &sly, &slw, &slh); /* in 'pic' coords */
if (savenormCB.val) {
CropRect2Rect(&slx, &sly, &slw, &slh, 0,0,pWIDE,pHIGH);
if (slw<1 || slh<1) { slx = sly = 0; slw=pWIDE; slh=pHIGH; }
if (slx==0 && sly==0 && slw==pWIDE && slh==pHIGH) thepic = pic;
else {
thepic = XVGetSubImage(pic, *pptype, pWIDE,pHIGH, slx, sly, slw, slh);
*pfree = 1;
}
}
else { /* convert sel -> epic coords */
int x1,x2,y1,y2;
x1 = slx; y1 = sly;
x2 = slx + slw; y2 = sly + slh;
CoordP2E(x1,y1, &x1, &y1);
CoordP2E(x2,y2, &x2, &y2);
slx = x1; sly = y1; slw = x2-x1; slh = y2-y1;
CropRect2Rect(&slx, &sly, &slw, &slh, 0,0,pw,ph);
if (slw<1 || slh<1) { slx = sly = 0; slw=pw; slh=ph; }
if (slx!=0 || sly!=0 || slw!=pw || slh!=ph) {
thepic = XVGetSubImage(thepic, *pptype, pw, ph, slx, sly, slw, slh);
*pfree = 1;
}
}
*pwide = slw; *phigh = slh;
}
return thepic;
}
/***************************************/
byte *GenSavePic(ptypeP, wP, hP, freeP, ncP, rmapP, gmapP, bmapP)
int *ptypeP, *wP, *hP, *freeP, *ncP;
byte **rmapP, **gmapP, **bmapP;
{
/* handles the whole ugly mess of the various save options.
* returns an image, of type 'ptypeP', size 'wP,hP'.
* if (*ptypeP == PIC8), also returns numcols 'ncP', and the r,g,b map
* to use rmapP, gmapP, bmapP.
*
* if freeP is set, image can safely be freed after it is saved
*/
byte *pic1, *pic2;
int ptype, w, h, pfree;
pic1 = handleNormSel(&ptype, &w, &h, &pfree);
pic2 = handleBWandReduced(pic1, ptype, w,h, MBWhich(&colMB),
ncP, rmapP, gmapP, bmapP);
if (pic2) {
if (pfree) free(pic1);
pic1 = pic2;
pfree = 1;
ptype = PIC8;
}
if (ptype == PIC24) {
pic2 = GammifyPic24(pic1, w, h);
if (pic2) {
if (pfree) free(pic1);
pic1 = pic2;
pfree = 1;
}
}
*ptypeP = ptype; *wP = w; *hP = h; *freeP = pfree;
return pic1;
}
/***************************************/
void GetSaveSize(wP, hP)
int *wP, *hP;
{
/* returns the size (in pixels) of the save image. Takes 'normal size'
and 'save selection' checkboxes into account */
int slx,sly,slw,slh;
if (savenormCB.val) { slw = cWIDE; slh = cHIGH; }
else { slw = eWIDE; slh = eHIGH; }
if (saveselCB.active && saveselCB.val && HaveSelection()) {
GetSelRCoords(&slx, &sly, &slw, &slh); /* pic coord */
if (savenormCB.val) {
CropRect2Rect(&slx, &sly, &slw, &slh, 0,0,pWIDE,pHIGH);
if (slw<1 || slh<1) { slx = sly = 0; slw=pWIDE; slh=pHIGH; }
}
else { /* -> epic coord */
int x1,x2,y1,y2;
x1 = slx; y1 = sly;
x2 = slx + slw; y2 = sly + slh;
CoordP2E(x1,y1, &x1, &y1);
CoordP2E(x2,y2, &x2, &y2);
slx = x1; sly = y1; slw = x2-x1; slh = y2-y1;
CropRect2Rect(&slx, &sly, &slw, &slh, 0,0,eWIDE,eHIGH);
if (slw<1 || slh<1) { slx = sly = 0; slw=eWIDE; slh=eHIGH; }
}
}
*wP = slw; *hP = slh;
}
/*************************************************************/
/* POLLING ROUTINES */
/*************************************************************/
static struct stat origStat, lastStat;
static int haveStat = 0, haveLastStat = 0;
static time_t lastchgtime;
/****************************/
void InitPoll()
{
/* called whenever a file is initially loaded. stat's the file and puts
the results in origStat */
haveStat = haveLastStat = 0;
lastchgtime = (time_t) 0;
/* only do stat() if curname is a valid index, and it's not '<stdin>' */
if (curname>=0 && curname<numnames &&
(strcmp(namelist[curname], STDINSTR)!=0)) {
if (stat(namelist[curname], &origStat)==0) {
haveStat = 1;
if (DEBUG) fprintf(stderr," origStat.size=%ld, origStat.mtime=%d\n",
origStat.st_size, origStat.st_mtime);
}
}
}
/****************************/
int CheckPoll(del)
int del;
{
/* returns '1' if the file has been modified, and either
A) the file has stabilized (st = lastStat), or
B) 'del' seconds have gone by since the file last changed size
*/
struct stat st;
time_t nowT;
time(&nowT);
if (haveStat && curname>=0 && curname<numnames &&
(strcmp(namelist[curname], STDINSTR)!=0)) {
if (stat(namelist[curname], &st)==0) {
if (DEBUG) fprintf(stderr," st.size=%ld, st.mtime=%d\n",
st.st_size, st.st_mtime);
if ((st.st_size == origStat.st_size) &&
(st.st_mtime == origStat.st_mtime)) return 0; /* no change */
/* if it's changed since last looked ... */
if (!haveLastStat ||
st.st_size != lastStat.st_size ||
st.st_mtime != lastStat.st_mtime) {
xvbcopy((char *) &st, (char *) &lastStat, sizeof(struct stat));
haveLastStat = 1;
lastchgtime = nowT;
return 0;
}
/* if it hasn't changed in a while... */
if (haveLastStat && st.st_size > 0 && (nowT - lastchgtime) > del) {
xvbcopy((char *) &st, (char *) &origStat, sizeof(struct stat));
haveLastStat = 0; lastchgtime = 0;
return 1;
}
}
}
return 0;
}
/***************************************************************/
void DIRDeletedFile(name)
char *name;
{
/* called when file 'name' has been deleted. If any of the browsers
were showing the directory that the file was in, does a rescan() */
int i;
char buf[MAXPATHLEN + 2], *tmp;
strcpy(buf, name);
tmp = BaseName(buf);
*tmp = '\0'; /* truncate after last '/' */
if (strcmp(path, buf)==0) LoadCurrentDirectory();
}
/***************************************************************/
void DIRCreatedFile(name)
char *name;
{
DIRDeletedFile(name);
}