486 lines
11 KiB
C
486 lines
11 KiB
C
/*
|
|
* $XConsortium: util.c /main/42 1996/01/14 16:51:55 kaleb $
|
|
* $XFree86: xc/programs/xmh/util.c,v 3.7 2002/04/05 21:06:29 dickey Exp $
|
|
*
|
|
*
|
|
* COPYRIGHT 1987
|
|
* DIGITAL EQUIPMENT CORPORATION
|
|
* MAYNARD, MASSACHUSETTS
|
|
* ALL RIGHTS RESERVED.
|
|
*
|
|
* THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
|
|
* SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
|
|
* DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
|
|
* ANY PURPOSE. IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
*
|
|
* IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT
|
|
* RIGHTS, APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN
|
|
* ADDITION TO THAT SET FORTH ABOVE.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this software and its
|
|
* documentation for any purpose and without fee is hereby granted, provided
|
|
* that the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the name of Digital Equipment Corporation not be
|
|
* used in advertising or publicity pertaining to distribution of the software
|
|
* without specific, written prior permission.
|
|
*/
|
|
|
|
/* util.c -- little miscellaneous utilities. */
|
|
|
|
#include "xmh.h"
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <X11/cursorfont.h>
|
|
#include <X11/Xos.h>
|
|
|
|
#ifndef abs
|
|
#define abs(x) ((x) < 0 ? (-(x)) : (x))
|
|
#endif
|
|
|
|
static char *SysErrorMsg (int n)
|
|
{
|
|
char *s = strerror(n);
|
|
|
|
return (s ? s : "no such error");
|
|
}
|
|
|
|
/* Something went wrong; panic and quit. */
|
|
|
|
void Punt(char *str)
|
|
{
|
|
(void) fprintf( stderr, "%s: %s\nerrno = %d; %s\007\n",
|
|
progName, str, errno, SysErrorMsg(errno) );
|
|
if (app_resources.debug) {
|
|
(void)fprintf(stderr, "forcing core dump.\n");
|
|
(void) fflush(stderr);
|
|
abort();
|
|
}
|
|
else {
|
|
(void)fprintf(stderr, "exiting.\n");
|
|
(void)fflush(stderr);
|
|
_exit(-1);
|
|
}
|
|
}
|
|
|
|
|
|
int myopen(char *path, int flags, int mode)
|
|
{
|
|
int fid;
|
|
fid = open(path, flags, mode);
|
|
if (fid >= 0) DEBUG2("# %d : %s\n", fid, path)
|
|
return fid;
|
|
}
|
|
|
|
|
|
FILE *myfopen(char *path, char *mode)
|
|
{
|
|
FILE *result;
|
|
result = fopen(path, mode);
|
|
if (result) DEBUG2("# %d : %s\n", fileno(result), path)
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
void myclose(int fid)
|
|
{
|
|
if (close(fid) < 0) Punt("Error in myclose!");
|
|
DEBUG1( "# %d : <Closed>\n", fid)
|
|
}
|
|
|
|
|
|
void myfclose(FILE *file)
|
|
{
|
|
int fid = fileno(file);
|
|
if (fclose(file) < 0) Punt("Error in myfclose!");
|
|
DEBUG1("# %d : <Closed>\n", fid)
|
|
}
|
|
|
|
|
|
|
|
/* Return a unique file name. */
|
|
|
|
char *MakeNewTempFileName(void)
|
|
{
|
|
static char name[60];
|
|
static int uniqueid = 0;
|
|
do {
|
|
(void) sprintf(name, "%s/xmh_%ld_%d", app_resources.temp_dir,
|
|
(long)getpid(), uniqueid++);
|
|
} while (FileExists(name));
|
|
return name;
|
|
}
|
|
|
|
|
|
/* Make an array of string pointers big enough to hold n+1 entries. */
|
|
|
|
char **MakeArgv(int n)
|
|
{
|
|
char **result;
|
|
result = ((char **) XtMalloc((unsigned) (n+1) * sizeof(char *)));
|
|
result[n] = 0;
|
|
return result;
|
|
}
|
|
|
|
|
|
char **ResizeArgv(char **argv, int n)
|
|
{
|
|
argv = ((char **) XtRealloc((char *) argv, (unsigned) (n+1) * sizeof(char *)));
|
|
argv[n] = 0;
|
|
return argv;
|
|
}
|
|
|
|
/* Open a file, and punt if we can't. */
|
|
|
|
FILEPTR FOpenAndCheck(char *name, char *mode)
|
|
{
|
|
FILEPTR result;
|
|
result = myfopen(name, mode);
|
|
if (result == NULL) {
|
|
char str[500];
|
|
perror(progName);
|
|
(void)sprintf(str, "Error in FOpenAndCheck(%s, %s)", name, mode);
|
|
Punt(str);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
/* Read one line from a file. */
|
|
|
|
static char *DoReadLine(FILEPTR fid, char lastchar)
|
|
{
|
|
static char *buf;
|
|
static int maxlength = 0;
|
|
char *ptr, c;
|
|
int length = 0;
|
|
ptr = buf;
|
|
c = ' ';
|
|
while (c != '\n' && !feof(fid)) {
|
|
c = getc(fid);
|
|
if (length++ > maxlength - 5) {
|
|
if (maxlength)
|
|
buf = XtRealloc(buf, (unsigned) (maxlength *= 2));
|
|
else
|
|
buf = XtMalloc((unsigned) (maxlength = 512));
|
|
ptr = buf + length - 1;
|
|
}
|
|
*ptr++ = c;
|
|
}
|
|
if (!feof(fid) || length > 1) {
|
|
*ptr = 0;
|
|
*--ptr = lastchar;
|
|
return buf;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
char *ReadLine(FILEPTR fid)
|
|
{
|
|
return DoReadLine(fid, 0);
|
|
}
|
|
|
|
|
|
/* Read a line, and keep the CR at the end. */
|
|
|
|
char *ReadLineWithCR(FILEPTR fid)
|
|
{
|
|
return DoReadLine(fid, '\n');
|
|
}
|
|
|
|
|
|
|
|
/* Delete a file, and Punt if it fails. */
|
|
|
|
void DeleteFileAndCheck(char *name)
|
|
{
|
|
if (strcmp(name, "/dev/null") != 0 && unlink(name) == -1) {
|
|
char str[500];
|
|
perror(progName);
|
|
(void)sprintf(str, "DeleteFileAndCheck(%s) failed!", name);
|
|
Punt(str);
|
|
}
|
|
}
|
|
|
|
void CopyFileAndCheck(char *from, char *to)
|
|
{
|
|
int fromfid, tofid, n;
|
|
char buf[512];
|
|
fromfid = myopen(from, O_RDONLY, 0666);
|
|
tofid = myopen(to, O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
|
if (fromfid < 0 || tofid < 0) {
|
|
perror(progName);
|
|
(void)sprintf(buf, "CopyFileAndCheck(%s->%s) failed!", from, to);
|
|
Punt(buf);
|
|
}
|
|
do {
|
|
n = read(fromfid, buf, 512);
|
|
if (n) (void) write(tofid, buf, n);
|
|
} while (n);
|
|
myclose(fromfid);
|
|
myclose(tofid);
|
|
}
|
|
|
|
|
|
void RenameAndCheck(char *from, char *to)
|
|
{
|
|
if (rename(from, to) == -1) {
|
|
if (errno != EXDEV) {
|
|
char str[500];
|
|
perror(progName);
|
|
(void)sprintf(str, "RenameAndCheck(%s->%s) failed!", from, to);
|
|
Punt(str);
|
|
}
|
|
CopyFileAndCheck(from, to);
|
|
DeleteFileAndCheck(from);
|
|
}
|
|
}
|
|
|
|
|
|
char *CreateGeometry(int gbits, int x, int y, int width, int height)
|
|
{
|
|
char *result, str1[10], str2[10], str3[10], str4[10];
|
|
if (gbits & WidthValue)
|
|
(void) sprintf(str1, "=%d", width);
|
|
else
|
|
(void) strcpy(str1, "=");
|
|
if (gbits & HeightValue)
|
|
(void) sprintf(str2, "x%d", height);
|
|
else
|
|
(void) strcpy(str2, "x");
|
|
if (gbits & XValue)
|
|
(void) sprintf(str3, "%c%d", (gbits & XNegative) ? '-' : '+', abs(x));
|
|
else
|
|
(void) strcpy(str3, "");
|
|
if (gbits & YValue)
|
|
(void) sprintf(str4, "%c%d", (gbits & YNegative) ? '-' : '+', abs(y));
|
|
else
|
|
(void) strcpy(str4, "");
|
|
result = XtMalloc((unsigned) 22);
|
|
(void) sprintf(result, "%s%s%s%s", str1, str2, str3, str4);
|
|
return result;
|
|
}
|
|
|
|
int FileExists(char *file)
|
|
{
|
|
return (access(file, F_OK) == 0);
|
|
}
|
|
|
|
long LastModifyDate(char *file)
|
|
{
|
|
struct stat buf;
|
|
if (stat(file, &buf)) return -1;
|
|
return buf.st_mtime;
|
|
}
|
|
|
|
int GetFileLength(char *file)
|
|
{
|
|
struct stat buf;
|
|
if (stat(file, &buf)) return -1;
|
|
return buf.st_size;
|
|
}
|
|
|
|
Boolean IsSubfolder(char *foldername)
|
|
{
|
|
return (strchr(foldername, '/')) ? True : False;
|
|
}
|
|
|
|
void SetCurrentFolderName(Scrn scrn, char *foldername)
|
|
{
|
|
scrn->curfolder = foldername;
|
|
ChangeLabel((Widget) scrn->folderlabel, foldername);
|
|
}
|
|
|
|
|
|
void ChangeLabel(Widget widget, char *str)
|
|
{
|
|
static Arg arglist[] = {{XtNlabel, (XtArgVal)NULL}};
|
|
arglist[0].value = (XtArgVal) str;
|
|
XtSetValues(widget, arglist, XtNumber(arglist));
|
|
}
|
|
|
|
|
|
Widget CreateTextSW(
|
|
Scrn scrn,
|
|
char *name,
|
|
ArgList args,
|
|
Cardinal num_args)
|
|
{
|
|
/* most text widget options are set in the application defaults file */
|
|
|
|
return XtCreateManagedWidget( name, asciiTextWidgetClass, scrn->widget,
|
|
args, num_args);
|
|
}
|
|
|
|
|
|
Widget CreateTitleBar(Scrn scrn, char *name)
|
|
{
|
|
Widget result;
|
|
int height;
|
|
static Arg arglist[] = {
|
|
{XtNlabel, (XtArgVal)NULL},
|
|
};
|
|
arglist[0].value = (XtArgVal) app_resources.banner; /* xmh version */
|
|
result = XtCreateManagedWidget( name, labelWidgetClass, scrn->widget,
|
|
arglist, XtNumber(arglist) );
|
|
height = GetHeight(result);
|
|
XawPanedSetMinMax(result, height, height);
|
|
return result;
|
|
}
|
|
|
|
void Feep(int type, int volume, Window win)
|
|
{
|
|
#ifdef XKB
|
|
XkbStdBell(theDisplay, win, volume, type);
|
|
#else
|
|
XBell(theDisplay, volume);
|
|
#endif
|
|
}
|
|
|
|
|
|
MsgList CurMsgListOrCurMsg(Toc toc)
|
|
{
|
|
MsgList result;
|
|
Msg curmsg;
|
|
result = TocCurMsgList(toc);
|
|
if (result->nummsgs == 0 && (curmsg = TocGetCurMsg(toc))) {
|
|
FreeMsgList(result);
|
|
result = MakeSingleMsgList(curmsg);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
int GetHeight(Widget w)
|
|
{
|
|
Dimension height;
|
|
Arg args[1];
|
|
|
|
XtSetArg(args[0], XtNheight, &height);
|
|
XtGetValues( w, args, (Cardinal)1 );
|
|
return (int)height;
|
|
}
|
|
|
|
|
|
int GetWidth(Widget w)
|
|
{
|
|
Dimension width;
|
|
Arg args[1];
|
|
|
|
XtSetArg(args[0], XtNwidth, &width);
|
|
XtGetValues( w, args, (Cardinal)1 );
|
|
return (int)width;
|
|
}
|
|
|
|
|
|
Toc SelectedToc(Scrn scrn)
|
|
{
|
|
Toc toc;
|
|
|
|
/* tocs of subfolders are created upon the first reference */
|
|
|
|
if ((toc = TocGetNamed(scrn->curfolder)) == NULL)
|
|
toc = TocCreate(scrn->curfolder);
|
|
return toc;
|
|
}
|
|
|
|
|
|
Toc CurrentToc(Scrn scrn)
|
|
{
|
|
/* return the toc currently being viewed */
|
|
|
|
return scrn->toc;
|
|
}
|
|
|
|
|
|
int strncmpIgnoringCase(char *str1, char *str2, int length)
|
|
{
|
|
int i, diff;
|
|
for (i=0 ; i<length ; i++, str1++, str2++) {
|
|
diff = ((*str1 >= 'A' && *str1 <= 'Z') ? (*str1 + 'a' - 'A') : *str1) -
|
|
((*str2 >= 'A' && *str2 <= 'Z') ? (*str2 + 'a' - 'A') : *str2);
|
|
if (diff) return diff;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
void StoreWindowName(Scrn scrn, char *str)
|
|
{
|
|
static Arg arglist[] = {
|
|
{XtNiconName, (XtArgVal) NULL},
|
|
{XtNtitle, (XtArgVal) NULL},
|
|
};
|
|
arglist[0].value = arglist[1].value = (XtArgVal) str;
|
|
XtSetValues(scrn->parent, arglist, XtNumber(arglist));
|
|
}
|
|
|
|
|
|
/* Create an input-only window with a busy-wait cursor. */
|
|
|
|
void InitBusyCursor(Scrn scrn)
|
|
{
|
|
unsigned long valuemask;
|
|
XSetWindowAttributes attributes;
|
|
|
|
/* the second condition is for the pick scrn */
|
|
if (! app_resources.block_events_on_busy || scrn->wait_window)
|
|
return;
|
|
|
|
/* Ignore device events while the busy cursor is displayed. */
|
|
|
|
valuemask = CWDontPropagate | CWCursor;
|
|
attributes.do_not_propagate_mask = (KeyPressMask | KeyReleaseMask |
|
|
ButtonPressMask | ButtonReleaseMask |
|
|
PointerMotionMask);
|
|
attributes.cursor = app_resources.busy_cursor;
|
|
|
|
/* The window will be as big as the display screen, and clipped by
|
|
* it's own parent window, so we never have to worry about resizing.
|
|
*/
|
|
|
|
scrn->wait_window =
|
|
XCreateWindow(XtDisplay(scrn->parent), XtWindow(scrn->parent), 0, 0,
|
|
rootwidth, rootheight, (unsigned int) 0, CopyFromParent,
|
|
InputOnly, CopyFromParent, valuemask, &attributes);
|
|
}
|
|
|
|
void ShowBusyCursor(void)
|
|
{
|
|
register int i;
|
|
|
|
for (i=0; i < numScrns; i++)
|
|
if (scrnList[i]->mapped)
|
|
XMapWindow(theDisplay, scrnList[i]->wait_window);
|
|
}
|
|
|
|
void UnshowBusyCursor(void)
|
|
{
|
|
register int i;
|
|
|
|
for (i=0; i < numScrns; i++)
|
|
if (scrnList[i]->mapped)
|
|
XUnmapWindow(theDisplay, scrnList[i]->wait_window);
|
|
}
|
|
|
|
|
|
void SetCursorColor(
|
|
Widget widget,
|
|
Cursor cursor,
|
|
unsigned long foreground)
|
|
{
|
|
XColor colors[2];
|
|
Arg args[2];
|
|
Colormap cmap;
|
|
|
|
colors[0].pixel = foreground;
|
|
XtSetArg(args[0], XtNbackground, &(colors[1].pixel));
|
|
XtSetArg(args[1], XtNcolormap, &cmap);
|
|
XtGetValues(widget, args, (Cardinal) 2);
|
|
XQueryColors(XtDisplay(widget), cmap, colors, 2);
|
|
XRecolorCursor(XtDisplay(widget), cursor, &colors[0], &colors[1]);
|
|
}
|