/*
Common library.
It contains some general-purpose low-level functions
useful for other components:
- dynamic-link libraries management,
- settings file support,
- error messages handling.
*/
#include "common.h"
#define KERNEL
#include "corefunc.h"
#include "inter.h"
#undef KERNEL
/********************************/
/* Library-management functions */
/********************************/
/*------------------------------------------*/
/* Implementation of OS-dependent functions */
Local(CharPtr) ErrBufPtr;
#if _WIN
/* !! Declarations of Windows functions must match onse in windows.h !! */
#ifdef WIN32
LibHandle FAR PASCAL LoadLibraryA(CharPtr);
#define LoadLibrary LoadLibraryA
#else
LibHandle FAR PASCAL LoadLibrary(CharPtr);
#endif
void FAR PASCAL FreeLibrary(LibHandle);
void FAR * FAR PASCAL GetProcAddress(LibHandle,CharPtr);
/* !! Declarations of Windows functions must match ones in windows.h !! */
Local(CharPtr) _LibraryError(void) {
return ErrBufPtr;
}
Local(LibHandle) _LibraryLock(CharPtr LibName) {
LibHandle lh;
Char b[sizeof("LIBLOAD")+3];
lh=LoadLibrary(LibName);
if ((unsigned)lh<=32) {
/* LibName is equal to ParBuf! */
StrCat(LibName," ");
GetParamAppend(SFS_KERNELERRORS,"LIBLOAD");
StrCat(LibName," ");
sprintf(b,"LIBLOAD%i",(int)lh);
ErrBufPtr=GetParamAppend(SFS_KERNELERRORS,b);
lh=0;
}
return lh;
}
Local(void) _LibraryUnlock(LibHandle LibHndl) {
FreeLibrary(LibHndl);
}
Local(VoidPtr) _LibraryFuncAddress(LibHandle LibHndl, CharPtr FuncName) {
VoidPtr fp;
fp=GetProcAddress(LibHndl,FuncName);
if (!fp) {
StrCpy(ParBuf,FuncName);
ErrBufPtr=GetParamAppend(SFS_KERNELERRORS,"FUNCADR");
}
return fp;
}
#endif
#if _MAC
#error Interface to Dynamical Libraries management is not defined (dynlib.h)
#endif
#if _UNIX
#ifdef PROC_HPPA /* HP-UX */
#include
#define _LibraryLock(l) shl_load(l,BIND_DEFERRED,0L)
#define _LibraryUnlock(h) shl_unload(h)
Local(VoidPtr) _LibraryFuncAddress(LibHandle h, CharPtr f) {
VoidPtr fp;
if (shl_findsym(&h,f,TYPE_PROCEDURE,&fp)) { /* not found */
StrCpy(ParBuf,f);
ErrBufPtr=GetParamAppend(SFS_KERNELERRORS,"FUNCADR");
fp=NULL;
}
return fp;
}
Local(CharPtr) _LibraryError(void) {
return ErrBufPtr;
}
#else /* PROC_HPPA */
#include
#ifdef _UNIX_R6K /* AIX RS 6000 */
#ifndef RTLD_LAZY
#define RTLD_LAZY 1
#endif
#endif
#define _LibraryLock(l) dlopen(l,RTLD_LAZY)
#define _LibraryFuncAddress(h,f) dlsym(h,f)
#define _LibraryUnlock(h) dlclose(h)
#define _LibraryError() dlerror()
#endif /* PROC_HPPA */
#endif /* if _UNIX */
/* End of implementation of OS-dependent functions */
/*-------------------------------------------------*/
#if DEB_LIB
static ByteStorePtr lbs;
static FILE *ldeb=NULL;
typedef struct {
CharPtr libname;
LibHandle handle;
Int2 lockcount;
} LibBlock;
void _InitDebLib(void) {
LibBlock blk;
MemFill(&blk,0,sizeof(LibBlock));
lbs=BSNew(0);
BSWrite(lbs,&blk,sizeof(LibBlock)); /* BSFree(lbs) will crash without this */
ldeb=fopen("deb_lib","wt");
}
void _TermDebLib(void) {
LibBlock blk;
Int4 n;
n=BSLen(lbs)/sizeof(LibBlock)-1;
BSSeek(lbs,sizeof(LibBlock),SEEK_SET);
if (n) {
Beep();
Message(MSG_OK,"There are %i unlocked libraries (see deb_lib file)",(int)n);
fprintf(ldeb,"\n\n\n==========================\n\n");
fflush(ldeb);
}
for (; n; n--) {
BSRead(lbs,&blk,sizeof(LibBlock));
fprintf(ldeb,"%s with lock count %i\n",blk.libname,(int)blk.lockcount);
fflush(ldeb);
MemFree(blk.libname);
}
BSFree(lbs);
fclose(ldeb);
}
static Boolean _DebLibSearch(CharPtr libname, LibHandle handle, LibBlock PNTR blk) {
Int4 n;
n=BSLen(lbs)/sizeof(LibBlock)-1;
BSSeek(lbs,sizeof(LibBlock),SEEK_SET);
for (; n; n--) {
BSRead(lbs,blk,sizeof(LibBlock));
if (libname ? !StrCmp(blk->libname,libname) : blk->handle==handle) {
BSSeek(lbs,-((int)(sizeof(LibBlock))),SEEK_CUR);
return TRUE;
}
}
return FALSE;
}
static void _DebLibLock(CharPtr libname, LibHandle handle) {
LibBlock blk;
if (_DebLibSearch(libname,0,&blk)) {
blk.lockcount++;
} else {
blk.libname=StringSave(libname);
blk.lockcount=1;
blk.handle=handle;
}
BSWrite(lbs,&blk,sizeof(LibBlock));
fprintf(ldeb,"Lock %s, Count %i, Handle %x\n",libname,(int)blk.lockcount,
(int)handle);
fflush(ldeb);
}
static void _DebLibUnlock(LibHandle handle) {
LibBlock _blk;
if (_DebLibSearch(NULL,handle,&_blk)) {
_blk.lockcount--;
fprintf(ldeb,"Unlock %s, Count %i, Handle %x\n",_blk.libname,(int)_blk.lockcount,
(int)handle);
fflush(ldeb);
if (_blk.lockcount)
BSWrite(lbs,&_blk,sizeof(LibBlock));
else {
MemFree(_blk.libname);
BSDelete(lbs,sizeof(LibBlock));
}
} else
if (handle && Message(MSG_OKC,"%x is not a handle of a library",
(int)handle)==ANS_CANCEL) {
Abend();
}
}
static void _DebLibAddress(LibHandle handle, CharPtr name, VoidPtr addr) {
LibBlock _blk;
if (_DebLibSearch(NULL,handle,&_blk)) {
fprintf(ldeb,"Addr %s(%s)=%p\n",_blk.libname,name,addr);
fflush(ldeb);
} else
if (Message(MSG_OKC,"%x is not a handle of a library",
(int)handle)==ANS_CANCEL) {
Abend();
}
}
#endif
/*
There are three reasons we need to maintain our own list
of loaded shared libraries.
1. Thank you very much, HP!
shl_load and shl_unload don't employ the usage count mechanism:
- load increases the count,
- unload decreases the count,
- library is removed from the memory only when the count reaches 0.
Instead, the first shl_unload(lib) removes the lib
and frees its handle. As a result the following does not
work:
h=shl_load("lib");
h=shl_load("lib"); the same!
shl_unload(h);
... there is no "lib" in the memory any more ...
2. Linux's dlopen contributs also:
h1=dlopen("lib");
h2=dlopen("lib"); the same!
... h1!=h2 ...
3. UnlockRequested and UnlockAll need true value of usage counts.
*/
#define LIBMAX 20
typedef struct {
CharPtr l; /* lib name */
LibHandle h; /* lib handle */
int c; /* usage count */
} LibDesc, PNTR LibDescPtr;
Local(LibDesc) Libs[LIBMAX]; /* it is clean after load (see ANSI C standard) */
Local(LibHandle) my_LibraryLock(CharPtr l) {
Int2 i,j;
for (i=0, j=-1; itermproc=termproc;
urp->lib=hLib;
urp->next=UnlockList;
UnlockList=urp;
Epilog
}
Global(void) LibraryUnlockRequested(void) {
UnlockReqPtr urp;
LibHandle lh;
Int2 i,j;
while (UnlockList) {
lh=UnlockList->lib;
if (UnlockList->termproc) UnlockList->termproc();
for (i=0; inext;
_MemFree(UnlockList);
UnlockList=urp;
}
}
Global(void) LibraryUnlockAll(void) {
LIB_ITERM_FUNC_TYPE ITermFuncPtr;
Int2 i;
for (i=0; i0) {
while (Libs[i].c>1) LibraryUnlock(Libs[i].h);
ITermFuncPtr=(LIB_ITERM_FUNC_TYPE)(LibraryFuncAddressCond(Libs[i].h,LIB_ITERM_FUNC_STR));
if (ITermFuncPtr) ITermFuncPtr();
LibraryUnlock(Libs[i].h);
}
}
/****************************/
/* Settings file management */
/****************************/
Global(Char) ParBuf[PAR_BUF]=""; /* work text buffer */
#if _WIN
Local(Char) ConfigFile[PATH_MAX]="";
#define CONFIG_FILE ConfigFile
Global(Boolean) GetConfigFilePath(void) {
CharPtr p;
StrCpy(ConfigFile,p=CurrentDirectory());
FileBuildPath(ConfigFile,NULL,APP_NAME".ini");
_MemFree(p);
return access(ConfigFile,0)==0;
}
#endif /* _WIN */
#if _UNIX
#define CONFIG_FILE APP_NAME
Global(Boolean) GetConfigFilePath(void) {
return access("."CONFIG_FILE"rc",0)==0;
}
#endif /* _UNIX */
#if _MAC
#error Global(Boolean) GetConfigFilePath(void) is not declared
#endif /* _MAC */
#define ERR_HEAD "Settings file '%s', section '%s', key '%s': "
#define NOT_FOUND "not found"
/* STR_EMPTY -> '' */
Local(void) RemoveEmptyChars(CharPtr p) {
for (; (p=StrStr(p,STR_EMPTY))!=NULL; ) StrCpy(p,p+1);
}
/* Symbolic refernce to the value of a Key under a Section
has the form
$(Section.Key)
It may be used in any value string and will be repalced by
the value of appropriate Key. Avoid recursion!
CHAR_NL are replaced by \n.
*/
#define SYMREF "$(%n%*[^.].%n%*[^)])%n"
Local(Boolean) TranslateRef(CharPtr Buf, CharPtr Section, CharPtr Key) {
CharPtr rp; /* start of ref */
int soff; /* offset of section name */
int koff; /* offset of key name */
int eoff; /* end of ref */
Boolean res=TRUE; /* OK */
Char buf[PAR_BUF];
for (rp=Buf; res && (rp=StrChr(rp,*SYMREF))!=NULL; ) {
soff=koff=eoff=0;
sscanf(rp,SYMREF,&soff,&koff,&eoff);
if (eoff) {
*(rp+koff-1)='\0';
*(rp+eoff-1)='\0';
if (GetAppParam(CONFIG_FILE,rp+soff,rp+koff,"",buf,sizeof(buf))) {
/* STR_EMPTY -> empty */
RemoveEmptyChars(buf);
StrCat(buf,rp+eoff);
StrCpy(rp,buf);
} else {
Warning("TRANSLN",APP_NAME,Section,Key);
res=FALSE;
}
} else { /* format incorrect, don't substitute */
rp++;
}
}
return res;
}
Global(Boolean) Translate(CharPtr Buf, CharPtr Section, CharPtr Key) {
CharPtr rp;
Boolean res; /* TRUE means OK */
/* Substitute $(section,key) */
res=TranslateRef(Buf,Section,Key);
/* CHAR_NL -> \n */
while ((rp=StrChr(Buf,CHAR_NL))!=NULL) *rp='\n';
/* STR_EMPTY -> empty */
RemoveEmptyChars(Buf);
return res;
}
/* Reads a value from the settings file, performs format substitution
and put the result into the buffer */
#ifdef VAR_ARGS
Global(CharPtr) GetParam(Section, Key, va_alist)
CharPtr Section;
CharPtr Key;
va_dcl
#else
Global(CharPtr) GetParam(CharPtr Section, CharPtr Key,...)
#endif
{
va_list valist;
Char buf[PAR_BUF];
if (GetAppParam(CONFIG_FILE,Section,Key,"",buf,PAR_BUF))
if (Translate(buf,Section,Key)) {
#ifdef VAR_ARGS
va_start(valist);
#else
va_start(valist,Key);
#endif
vsprintf(ParBuf,buf,valist);
va_end(valist);
return ParBuf;
} else return NULL;
else {
Message(MSG_OK,ERR_HEAD NOT_FOUND,APP_NAME,Section,Key);
return NULL;
}
}
/* Reads a string from the settings file and put it to the buffer */
Global(CharPtr) GetParamString(CharPtr Section, CharPtr Key) {
if (GetAppParam(CONFIG_FILE,Section,Key,"",ParBuf,PAR_BUF))
return Translate(ParBuf,Section,Key) ? ParBuf : NULL;
else {
Message(MSG_OK,ERR_HEAD NOT_FOUND,APP_NAME,Section,Key);
return NULL;
}
}
/* Reads a value from the settings file and append it to the buffer */
Global(CharPtr) GetParamAppend(CharPtr Section, CharPtr Key) {
Int2 len=(Int2)StrLen(ParBuf);
if (GetAppParam(CONFIG_FILE,Section,Key,"",ParBuf+len,PAR_BUF-len))
return Translate(ParBuf,Section,Key) ? ParBuf : NULL;
else {
Message(MSG_OK,ERR_HEAD NOT_FOUND,APP_NAME,Section,Key);
return NULL;
}
}
/* Writes a string to the settings file */
Global(void) SetParam(CharPtr Section, CharPtr Key, CharPtr Value) {
CharPtr p;
for (; (p=StringChr(Value,'\n'))!=NULL; *p=CHAR_NL);
SetAppParam(CONFIG_FILE,Section,Key,Value);
}
/***************************/
/* Error messages handling */
/***************************/
/* Issues a warning message.
The text of a message is obtained form the SFS_KERNELERRORS
section using the first parameter as a key name.
NOTE: This routine must not be available when it is in DLL.
So, Global is used instead of Entry.
Also it DOES NOT use common input buffer of GetParam family.
*/
#ifdef VAR_ARGS
Global(Int2) Warning(Key, va_alist)
CharPtr Key;
va_dcl
#else
Global(Int2) Warning(CharPtr Key,...)
#endif
{
static Char Buf[PAR_BUF],Format[PAR_BUF];
va_list list;
if (GetAppParam(CONFIG_FILE,SFS_KERNELERRORS,Key,"",Format,PAR_BUF)) {
Translate(Format,SFS_KERNELERRORS,Key);
#ifdef VAR_ARGS
va_start(list);
#else
va_start(list,Key);
#endif
vsprintf(Buf,Format,list);
#if DEB
if (Message(MSG_OKC,Buf)==ANS_CANCEL) Abend();
#else
Message(MSG_OK,Buf);
#endif
va_end(list);
}
return 1;
}
/*************************/
/* Directories and files */
/*************************/
#if _WIN
#include
#endif
#if _MAC
#error ChangeDirectory is not defined
#endif
#if _UNIX
#include
#endif
/* Changes current directory */
Global(void) ChangeDirectory(CharPtr dir) {
#if DEB_LIB
CharPtr p;
int ret;
#endif
if (dir==NULL) return;
#if DEB_LIB
p=CurrentDirectory();
ret=
#endif
#if _WIN
chdir(dir);
#endif
#if _MAC
#error ChangeDirectory is not defined
#endif
#if _UNIX
chdir(dir);
#endif
#if DEB_LIB
fprintf(ldeb,"ChangeDirectory(%s)=%i (errno=%i)\n",dir,ret,errno);
fprintf(ldeb," from directory=%s\n",p);
_MemFree(p);
fflush(ldeb);
#endif
}
/* Gets current directory */
Global(CharPtr) CurrentDirectory(void) {
CharPtr buf;
Int2 len;
len=PATH_MAX;
buf=_MemNew(len);
#if _WIN
getcwd(buf,len);
#endif
#if _MAC
#error CurrentDirectory is not defined
#endif
#if _UNIX
getcwd(buf,len);
#endif
#if DEB_LIB
if (ldeb) { /* is NULL for setup */
fprintf(ldeb,"CurrentDirectory is %s\n",buf);
fflush(ldeb);
}
#endif
return buf;
}
/* Truncates a file */
Global(Boolean) TruncateFile(FILE PNTR stream, long size) {
#if _WIN
return chsize(fileno(stream),size)==0;
#endif
#if _MAC
#error TruncateFile is not defined
#endif
#if _UNIX
return ftruncate(fileno(stream),size)==0;
#endif
}
/* Windows: GetInputFileName&GetOutputFileName change the current directory */
#if _WIN
#pragma argsused
#endif
Global(Boolean) myGetInputFileName(CharPtr fileName, size_t maxsize, CharPtr extType) {
#if _WIN && !defined(WIN32)
Message(MSG_OK,"Sorry, this feature doesn't work under Windows 3.1");
return FALSE;
#else
CharPtr dir;
Boolean res;
dir=CurrentDirectory();
res=GetInputFileName(fileName,maxsize,extType,NULL);
ChangeDirectory(dir);
_MemFree(dir);
return res;
#endif
}
#if _WIN
#pragma argsused
#endif
Global(Boolean) myGetOutputFileName(CharPtr fileName, size_t maxsize, CharPtr dfault) {
#if _WIN && !defined(WIN32)
Message(MSG_OK,"Sorry, this feature doesn't work under Windows 3.1");
return FALSE;
#else
CharPtr dir;
Boolean res;
dir=CurrentDirectory();
res=GetOutputFileName(fileName,maxsize,dfault);
ChangeDirectory(dir);
_MemFree(dir);
return res;
#endif
}
/***************************/
/* Useful string functions */
/***************************/
/* Substitutes all occurences of *what by *with in *source */
Global(CharPtr) StrSubstitute(CharPtr source, CharPtr what, CharPtr with,
Boolean wholeid, Int2Ptr num) {
CharPtr p;
CharPtr n;
Int2 lwhat,lwith,lh;
if (num) *num=0;
lwhat=StrLen(what);
lwith=StrLen(with);
for (p=source; (p=StringStr(p,what),p); ) {
if (wholeid && p!=source && IS_ALPHANUM(*(p-1))) {
p+=lwhat;
continue;
}
n=_MemNew(StrLen(source)+1-lwhat+lwith);
StringNCpy(n,source,lh=(Int2)(p-source));
n[(Int2)(p-source)]='\0';
StringCat(n,with);
StringCat(n,p+lwhat);
_MemFree(source);
source=n;
p=source+lh+lwith;
if (num) (*num)++;
}
return source;
}
/* Inserts *what before charater number position of *source */
Global(CharPtr) StrInsert(CharPtr source, Int2 position, CharPtr what) {
CharPtr p;
p=_MemNew(StrLen(source)+StrLen(what)+1);
StrCat(StrCpy(p+position,what),source+position);
StrNCpy(p,source,position);
_MemFree(source);
return p;
}
/* Removes leading and trailing blanks */
Global(void) StrTrim(CharPtr source) {
Int2 s,e;
#define IGNCHRS " \n\r\t\x1A"
s=(Int2)StrSpn(source,IGNCHRS);
if (source[s]=='\0')
*source='\0';
else {
for (e=(Int2)StrLen(source)-1; e>=s && StrChr(IGNCHRS,source[e]); e--);
e+=1-s; /* e=e+1-s; e is now len of trimmed text */
MemMove(source,source+s,e);
source[e]='\0';
}
#undef IGNCHRS
}
/**************************************/
/* Several file-related aux. routines */
/**************************************/
#define IN 3
Local(FILE PNTR) in[IN];
Local(Int2) inl;
Local(CharPtr) descGetName(CharPtr filename) {
CharPtr p;
if (StrChr(filename,DIRDELIMCHR)) return filename;
p=_StringSave(filename);
GetParam(SFS_PATHS,"KERNEL");
StrCat(ParBuf,p);
_MemFree(p);
return ParBuf;
}
Global(Boolean) DescOpen(CharPtr filename) {
in[inl=0]=FileOpen(descGetName(filename),"rt");
return in[inl]!=NULL;
}
Global(void) DescClose(void) {
Int2 i;
for (i=0; i<=inl; i++)
FileClose(in[i]);
}
Global(Boolean) DescEof(void) {
return inl==0 && feof(in[0]);
}
Global(void) DescRewind(void) {
for ( ; inl; ) FileClose(in[inl--]);
rewind(in[0]);
}
Global(void) DescSeek(DescPtr fp) {
Int2 linl;
linl=(Int2)(fp>>24);
for ( ; inl>linl; ) FileClose(in[inl--]);
fseek(in[linl],fp&0x00ffffffL,SEEK_SET);
}
Local(DescPtr) descTell(void) {
long fpos;
fpos=ftell(in[inl]);
return (inl<<24)|(Int4)fpos;
}
Local(CharPtr) getLine(CharPtr b) {
CharPtr p;
CharPtr q;
read:
p=FileGets(b,BL,in[inl]);
/* remove heading and trailing blanks */
if (p) {
q=StrChr(p,'!');
if (q) *q='\0';
StrTrim(p);
if (*p=='\0') goto read;
Translate(p,NULL,NULL);
}
return p;
}
Global(CharPtr) GetLine(CharPtr b) {
do {
if (getLine(b))
if (b[0]==SECPRF[0] && b[1]==SECPRF[0] && inlmlen) mlen=len;
}
} while (!feof(s));
_MemFree(p);
fclose(s);
}
return mlen;
}
/**********************/
/* Execute OS command */
/**********************/
/*
cmd - commind line.
check - (PC, ignored for UNIX) checks whether the command terminated.
post - post-processing
*/
#if _WIN
/*--------------------------------------------------------------------------*/
/* !! Declarations of Windows functions must be the same as in windows.h !! */
Uint2 FAR PASCAL WinExec(CharPtr cmd, Uint2 show);
Uint2 FAR PASCAL SetTimer(Uint2 hwnd, Uint2 idTimer,Uint2 uTimeout,
void (FAR PASCAL *tmprc)());
Int2 FAR PASCAL KillTimer(Uint2 hwnd, Uint2 idTimer);
#ifdef WIN32
#define Catch setjmp
#define Throw longjmp
#else
int FAR PASCAL Catch(VoidPtr CatchBuf);
void FAR PASCAL Throw(VoidPtr CatchBuf, int RetCode);
#endif
/* */
/*--------------------------------------------------------------------------*/
static Uint2 idTimer;
static Int2 (FAR *_PostProc)(void);
static Boolean (FAR *_CheckProc)(void);
#ifdef WIN32
static jmp_buf CatchBuf;
#else
static CatchBuf[50]; /* Must be at least sizeof(CATCHBUF) bytes long */
#endif
#pragma argsused
static void FAR PASCAL _export WakeupProc(Uint2 hwnd, Uint2 msg,
Uint2 idTimer, Uint4 dwTime) {
if (_CheckProc()) {
KillTimer(NULL,idTimer);
Throw(CatchBuf,_PostProc()+1);
}
}
#define MINH 32 /* Handle<=MINH indicates an error */
Global(Int2) ExecuteCommand(CharPtr cmd, Boolean (FAR *CheckProc)(void),
Int2 (FAR *PostProc)(void)) {
Uint2 h;
Int2 r;
Char b[sizeof("WINEXEC")+3];
h=(cmd && *cmd) ? WinExec(cmd,0) : MINH+1;
if (h>MINH) { /* OK, sheduled */
/*
Windows only scheduled the command but did not execute it yet (unlike Unix).
So we have to wait checking periodically is it completed.
*/
_CheckProc=CheckProc;
_PostProc=PostProc;
idTimer=SetTimer(NULL,0,1000,WakeupProc);
if (!idTimer) {
Warning("WINEXECT");
return 2;
}
r=Catch(CatchBuf);
if (r) { /* Throw */
return r-1;
} else { /* env is copied */
ProcessEvents(); /* !!! */
}
} else { /* error, will not be executed */
/* cmd is equal to Buf! */
StrCat(cmd," ");
GetParamAppend(SFS_KERNELERRORS,"WINEXEC");
sprintf(b,"LIBLOAD%i",(int)h);
if (Message(MSG_OKC,GetParamAppend(SFS_KERNELERRORS,b))==ANS_CANCEL) {
/* The answer is 'Cancel', go for SYSABEND dump */
#if DEB
Abend();
#endif
}
}
return 1;
}
#endif
#if _MAC
#error ExecuteCommand is not defined
#endif
#if _UNIX
Global(Int2) ExecuteCommand(CharPtr cmd, Boolean (*CheckProc)(void),
Int2 (*PostProc)(void)) {
return (system(cmd), PostProc());
}
#endif
/************************/
/* Vibrant-related zaps */
/************************/
#if _UNIX
#undef Boolean
#include
extern XtAppContext Nlm_appContext; /* defined in Vibrant */
/* As ProcessAnEvent except it process timer events also */
Global(void) myProcessAnyEvent(void) {
XEvent event;
if (XtAppPending(Nlm_appContext)&(XtIMXEvent|XtIMTimer)) {
XtAppNextEvent(Nlm_appContext,&event);
XtDispatchEvent(&event);
}
}
#define Boolean Nlm_Boolean
#else
Global(void) myProcessAnyEvent(void) {
ProcessAnEvent();
}
#endif
/*************/
/* More zaps */
/*************/
#if defined(COMP_GNU) && defined(OS_UNIX_SUN)
/* There are no div_t and div in stdlib.h */
Global(div_t) div (int numer, int denom) {
div_t d;
d.quot=numer/denom;
d.rem=numer%denom;
return d;
}
#endif
/*********/
/* Debug */
/*********/
#if DEB
void PrintRect(RectPtr pr, CharPtr t) {
#if _UNIX
printf(
#endif
#if _WIN
Message(MSG_OK,
#endif
#if MAC
Message(MSG_OK,
#endif
"%s: (%i,%i)-(%i,%i), dx=%i dy=%i\n",
t,pr->left,pr->top,pr->right,pr->bottom,
pr->right-pr->left,pr->bottom-pr->top);
}
void Abend(void) {
#if _WIN
Int1 i=0;
i=1/i;
#endif
#if _UNIX
abort();
#endif
}
#endif
/***************************/
/* Debug memory management */
/***************************/
#if DEB_MEM
Local(Boolean) MemTrace=TRUE;
#if _WIN
#pragma argsused
#endif
Global(void) Debug_MemTrace(Int2 index) {
MemTrace^=TRUE;
}
#if _WIN
#pragma argsused
#endif
Global(Boolean) Debug_MemTrace_Status(Int2 index) {
return MemTrace;
}
#define DEB_MEM_FAST 1 /* use 32 ByteStores, one per each possible last byte */
#define FILES_TAB 50
static CharPtr FileTab[FILES_TAB];
static Int2 FileTabN=1;
static Int2 DebInsertFileName(CharPtr filename) {
Int2 i;
for (i=1; i=FILES_TAB) return 0;
FileTab[FileTabN]=StringSave(filename);
return FileTabN++;
}
typedef struct {
Pointer ptr;
size_t size;
Int2 line;
Int2 filename;
} Block;
#if DEB_MEM_FAST
static ByteStorePtr Bs[32];
#define bs(p) Bs[(((int)p)&0xff)>>3]
#else
static ByteStorePtr Bs[1];
#define bs(p) Bs[0]
#endif
static FILE *deb;
static void DoubleFault(int line) {
if (Message(MSG_OKC,"Double fault in line %i",line)==ANS_CANCEL)
Abend();
}
#define Check(cond) if (!(cond)) DoubleFault(__LINE__)
void _InitDebMem(void) {
Block blk;
Int4 l;
Int2 i;
MemFill(&blk,0,sizeof(Block));
deb=fopen("deb_mem","wt");
Check(deb);
FileTab[0]=StringSave("???");
for (i=1; i=0);
s=BSSeek(bs(ptr),sizeof(Block),SEEK_SET);
Check(s==0);
for (; n; n--) {
l=BSRead(bs(ptr),&blk,sizeof(blk));
Check(l==sizeof(blk));
if (blk.ptr==ptr) {
s=BSSeek(bs(ptr),-((int)(sizeof(blk))),SEEK_CUR);
Check(s==0);
return TRUE;
}
}
return FALSE;
}
Pointer __MemNew(size_t size, CharPtr FileName, int Line) {
Block _blk;
Int4 _l;
Int2 _s;
if (!size) return NULL;
_blk.ptr=MemNew(size);
if (!MemTrace) return _blk.ptr;
_blk.size=size;
_blk.line=Line;
_blk.filename=DebInsertFileName(FileName);
if (_blk.ptr) {
_s=BSSeek(bs(_blk.ptr),0,SEEK_END);
Check(_s==0);
_l=BSWrite(bs(_blk.ptr),&_blk,sizeof(_blk));
Check(_l==sizeof(_blk));
} else {
if (Message(MSG_OKC,"MemNew cannot allocate %i bytes\nFile %s, line %i",
(int)size,FileName,Line)==ANS_CANCEL) {
Abend();
}
}
fprintf(deb,"%s(%i): New(%i)=%p\n",FileName,Line,(int)size,_blk.ptr);
fflush(deb);
return _blk.ptr;
}
Pointer __MemGet(size_t size, unsigned int clear, CharPtr FileName, int Line) {
Block _blk;
Int4 _l;
Int2 _s;
if (!size) return NULL;
_blk.ptr=MemGet(size,clear);
if (!MemTrace) return _blk.ptr;
_blk.size=size;
_blk.line=Line;
_blk.filename=DebInsertFileName(FileName);
if (_blk.ptr) {
_s=BSSeek(bs(_blk.ptr),0,SEEK_END);
Check(_s==0);
_l=BSWrite(bs(_blk.ptr),&_blk,sizeof(_blk));
Check(_l==sizeof(_blk));
} else {
if (Message(MSG_OKC,"MemGet cannot allocate %i bytes\nFile %s, line %i",
(int)size,FileName,Line)==ANS_CANCEL) {
Abend();
}
}
fprintf(deb,"%s(%i): Get(%i)=%p\n",FileName,Line,(int)size,_blk.ptr);
fflush(deb);
return _blk.ptr;
}
Pointer LIBCALL __MemFree(Pointer ptr, CharPtr FileName, int Line) {
Int4 _l;
if (!ptr) return NULL;
if (!MemTrace) { MemFree(ptr); return NULL;}
if (Search(ptr)) {
_l=BSDelete(bs(ptr),sizeof(Block));
Check(_l==sizeof(Block));
MemFree(ptr);
} else {
if (Message(MSG_OKC,"MemFree cannot free block %p\nFile %s, line %i",
ptr,FileName,Line)==ANS_CANCEL) {
Abend();
}
_TermDebMem();
}
fprintf(deb,"%s(%i): Free(%p)\n",FileName,Line,ptr);
fflush(deb);
return NULL;
}
Pointer LIBCALL __MemMore(Pointer ptr, size_t size, CharPtr FileName, int Line) {
Block _blk;
Int4 _l;
Int2 _s;
if (!MemTrace) {_blk.ptr=MemMore(ptr,size); return _blk.ptr;}
_blk.size=size;
_blk.ptr=ptr;
_blk.line=Line;
_blk.filename=DebInsertFileName(FileName);
if (Search(_blk.ptr)) {
_l=BSDelete(bs(_blk.ptr),sizeof(Block));
Check(_l==sizeof(Block));
fprintf(deb,"%s(%i): More(%p,%i)=",FileName,Line,_blk.ptr,(int)size);
_blk.ptr=MemMore(_blk.ptr,size);
fprintf(deb,"%p\n",_blk.ptr);
fflush(deb);
if (_blk.ptr) {
_s=BSSeek(bs(_blk.ptr),0,SEEK_END);
Check(_s==0);
_l=BSWrite(bs(_blk.ptr),&_blk,sizeof(_blk));
Check(_l==sizeof(_blk));
} else {
if (Message(MSG_OKC,"MemMore cannot allocate %i bytes\nFile %s, Line %i",
(int)size,FileName,Line)==ANS_CANCEL) {
Abend();
}
}
} else {
if (Message(MSG_OKC,"MemMore cannot free block %p\nFile %s, line %i",
_blk.ptr,FileName,Line)==ANS_CANCEL) {
Abend();
}
}
return _blk.ptr;
}
Pointer LIBCALL __MemExtend(Pointer ptr, size_t size, size_t oldsize, CharPtr FileName, int Line) {
Block _blk;
Int4 _l;
Int2 _s;
if (!MemTrace) {_blk.ptr=MemExtend(ptr,size,oldsize); return _blk.ptr;}
_blk.size=size;
_blk.ptr=ptr;
_blk.line=Line;
_blk.filename=DebInsertFileName(FileName);
if (Search(_blk.ptr)) {
_l=BSDelete(bs(_blk.ptr),sizeof(Block));
Check(_l==sizeof(Block));
fprintf(deb,"%s(%i): Extend(%p,%i,%i)=",FileName,Line,_blk.ptr,(int)size,(int)oldsize);
_blk.ptr=MemExtend(_blk.ptr,size,oldsize);
fprintf(deb,"%p\n",_blk.ptr);
fflush(deb);
if (_blk.ptr) {
_s=BSSeek(bs(_blk.ptr),0,SEEK_END);
Check(_s==0);
_l=BSWrite(bs(_blk.ptr),&_blk,sizeof(_blk));
Check(_l==sizeof(_blk));
} else {
if (Message(MSG_OKC,"MemExtend cannot allocate %i bytes\nFile %s, Line %i",
(int)size,FileName,Line)==ANS_CANCEL) {
Abend();
}
}
} else {
if (Message(MSG_OKC,"MemExtend cannot free block %p\nFile %s, line %i",
_blk.ptr,FileName,Line)==ANS_CANCEL) {
Abend();
}
}
return _blk.ptr;
}
CharPtr LIBCALL __StringSave(const char FAR *ptr, CharPtr FileName, int Line) {
Block _blk;
Int4 _l;
Int2 _s;
if (!ptr) return NULL;
_blk.ptr=StringSave(ptr);
if (!MemTrace) return _blk.ptr;
_blk.size=StrLen(ptr)+1;
_blk.line=Line;
_blk.filename=DebInsertFileName(FileName);
if (_blk.ptr) {
_s=BSSeek(bs(_blk.ptr),0,SEEK_END);
Check(_s==0);
_l=BSWrite(bs(_blk.ptr),&_blk,sizeof(_blk));
Check(_l==sizeof(_blk));
} else {
if (Message(MSG_OKC,"StringSave cannot save string '%s'\nFile %s, line %i",
ptr,FileName,Line)==ANS_CANCEL) {
Abend();
}
}
fprintf(deb,"%s(%i): Save(%s)=%p\n",FileName,Line,ptr,_blk.ptr);
fflush(deb);
return _blk.ptr;
}
Pointer LIBCALL __BSMerge(ByteStorePtr bsp, Pointer buffer, CharPtr FileName, int Line) {
Int4 _l;
Int2 _s;
Block _blk;
_blk.ptr=BSMerge(bsp,buffer);
if (!MemTrace) return _blk.ptr;
_blk.line=Line;
_blk.filename=DebInsertFileName(FileName);
if (_blk.ptr) {
if (!buffer) {
_blk.size=(size_t)BSLen(bsp);
_s=BSSeek(bs(_blk.ptr),0,SEEK_END);
Check(_s==0);
_l=BSWrite(bs(_blk.ptr),&_blk,sizeof(_blk));
Check(_l==sizeof(_blk));
}
} else {
if (Message(MSG_OKC,"BSMegre cannot allocate buffer\nFile %s, line %i",
FileName,Line)==ANS_CANCEL) {
Abend();
}
}
fprintf(deb,"%s(%i): Merge()=%p\n",FileName,Line,_blk.ptr);
fflush(deb);
return _blk.ptr;
}
#ifdef VAR_ARGS
Global(void) DebugMsg(format, va_list) {
CharPtr format;
va_dcl
#else
Global(void) DebugMsg(CharPtr format,...) {
#endif
va_list valist;
#ifdef VAR_ARGS
va_start(valist);
#else
va_start(valist,format);
#endif
vfprintf(deb,format,valist);
fflush(deb);
}
#endif