1713 lines
34 KiB
Plaintext
1713 lines
34 KiB
Plaintext
/*
|
|
* $Id: os2 13636 2004-05-05 22:01:21Z hubert $
|
|
*
|
|
* Program: Operating system dependent routines - OS/2 Text mode
|
|
*
|
|
*
|
|
* Michael Seibel
|
|
* Networks and Distributed Computing
|
|
* Computing and Communications
|
|
* University of Washington
|
|
* Administration Builiding, AG-44
|
|
* Seattle, Washington, 98195, USA
|
|
* Internet: mikes@cac.washington.edu
|
|
*
|
|
* Please address all bugs and comments to "pine-bugs@cac.washington.edu"
|
|
*
|
|
*
|
|
* Pine and Pico are registered trademarks of the University of Washington.
|
|
* No commercial use of these trademarks may be made without prior written
|
|
* permission of the University of Washington.
|
|
*
|
|
* Pine, Pico, and Pilot software and its included text are Copyright
|
|
* 1989-2001 by the University of Washington.
|
|
*
|
|
* The full text of our legal notices is contained in the file called
|
|
* CPYRIGHT, included with this distribution.
|
|
*
|
|
*
|
|
* Notes:
|
|
* - mouse support added (mss, 921215)
|
|
*
|
|
* Portions of this code derived from MicroEMACS 3.10:
|
|
*
|
|
* OS2.C: Operating specific I/O and Spawning functions
|
|
* under the OS/2 operating system
|
|
* for MicroEMACS 3.10
|
|
* (C)opyright 1988 by Daniel M. Lawrence
|
|
*
|
|
*/
|
|
|
|
|
|
#include <process.h>
|
|
|
|
|
|
/*
|
|
* Internal functions...
|
|
*/
|
|
int checkmouse PROTO((unsigned *, int, int, int));
|
|
void invert_label PROTO((int, MENUITEM *));
|
|
int enhanced_keybrd PROTO((void));
|
|
int dont_interrupt PROTO((void));
|
|
int interrupt_ok PROTO((void));
|
|
int kbseq PROTO((int *));
|
|
int specialkey PROTO((unsigned int));
|
|
void do_alarm_signal PROTO((void));
|
|
void do_hup_signal PROTO((int sig));
|
|
char *pfnexpand PROTO((char *, size_t));
|
|
int ssleep PROTO((long));
|
|
void mouseon PROTO((void));
|
|
void mouseoff PROTO((void));
|
|
void turnmouseoff PROTO((void));
|
|
|
|
/*
|
|
* Useful global def's
|
|
*/
|
|
|
|
int timeo = 0;
|
|
time_t time_of_last_input;
|
|
int (*pcollator)();
|
|
static int oldbut; /* Previous state of mouse buttons */
|
|
static int enhncd; /* Enhanced keyboard */
|
|
static KBDINFO initialKbdInfo;
|
|
|
|
#ifdef MOUSE
|
|
/*
|
|
* Useful definitions...
|
|
*/
|
|
static int mexist = 0; /* is the mouse driver installed? */
|
|
static int nbuttons; /* number of buttons on the mouse */
|
|
static unsigned mnoop;
|
|
static unsigned char okinfname[32] = {
|
|
0, 0, /* ^@ - ^G, ^H - ^O */
|
|
0, 0, /* ^P - ^W, ^X - ^_ */
|
|
0, 0x17, /* SP - ' , ( - / */
|
|
0xff, 0xe4, /* 0 - 7 , 8 - ? */
|
|
0x7f, 0xff, /* @ - G , H - O */
|
|
0xff, 0xe9, /* P - W , X - _ */
|
|
0x7f, 0xff, /* ` - g , h - o */
|
|
0xff, 0xf6, /* p - w , x - DEL */
|
|
0, 0, /* > DEL */
|
|
0, 0, /* > DEL */
|
|
0, 0, /* > DEL */
|
|
0, 0, /* > DEL */
|
|
0, 0 /* > DEL */
|
|
};
|
|
#endif
|
|
|
|
|
|
static void set_kbd(int state)
|
|
{
|
|
KBDINFO kbdInfo = initialKbdInfo;
|
|
if (state)
|
|
{
|
|
kbdInfo.fsMask &= ~(0x0001|0x0008|0x0100); /* echo,cooked */
|
|
kbdInfo.fsMask |= (0x0002|0x0004|0x0100); /* noecho,raw,shift-rpt on */
|
|
}
|
|
KbdSetStatus(&kbdInfo, 0);
|
|
}
|
|
|
|
/*
|
|
* DISable ctrl-break interruption
|
|
*/
|
|
dont_interrupt()
|
|
{
|
|
signal (SIGINT, SIG_IGN);
|
|
signal (SIGBREAK, SIG_IGN);
|
|
set_kbd(1);
|
|
}
|
|
|
|
/*
|
|
* re-enable ctrl-break interruption
|
|
*/
|
|
interrupt_ok()
|
|
{
|
|
set_kbd(0);
|
|
signal (SIGINT, SIG_DFL);
|
|
signal (SIGBREAK, SIG_DFL);
|
|
}
|
|
|
|
|
|
/*
|
|
* return true if an enhanced keyboard is present
|
|
*/
|
|
enhanced_keybrd()
|
|
{
|
|
return(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* This function is called once to set up the terminal device streams.
|
|
*/
|
|
ttopen()
|
|
{
|
|
initialKbdInfo.cb = sizeof(initialKbdInfo);
|
|
KbdGetStatus(&initialKbdInfo, 0);
|
|
dont_interrupt(); /* don't allow interrupt */
|
|
enhncd = enhanced_keybrd(); /* check for extra keys */
|
|
#if MOUSE
|
|
init_mouse();
|
|
#else /* !MOUSE */
|
|
mexist = 0;
|
|
#endif /* MOUSE */
|
|
return(1);
|
|
}
|
|
|
|
#ifdef MOUSE
|
|
HMOU Mouse_Handle =(HMOU)-1;
|
|
#ifdef FASTVIO
|
|
int mouse_state =0;
|
|
#endif
|
|
|
|
/*
|
|
* init_mouse - check for and initialize mouse driver...
|
|
*/
|
|
init_mouse()
|
|
{
|
|
if (Mouse_Handle==(HMOU)-1) {
|
|
int rc = MouOpen(NULL, &Mouse_Handle);
|
|
mexist=0;
|
|
if (rc)
|
|
return(FALSE);
|
|
mexist=1;
|
|
nbuttons=2;
|
|
MouFlushQue(Mouse_Handle);
|
|
turnmouseoff();
|
|
}
|
|
return(TRUE);
|
|
}
|
|
|
|
static int mouchk()
|
|
{
|
|
if (mexist)
|
|
return (Mouse_Handle==(HMOU)-1) ? init_mouse() : TRUE;
|
|
return FALSE;
|
|
}
|
|
|
|
deinit_mouse()
|
|
{
|
|
turnmouseoff();
|
|
}
|
|
|
|
|
|
/*
|
|
* mouseon - call made available for programs calling pico to turn ON the
|
|
* mouse cursor.
|
|
*/
|
|
void
|
|
mouseon()
|
|
{
|
|
/* Show Cursor */
|
|
if (mouchk() && !mouse_state) {
|
|
#ifdef FASTVIO
|
|
mouse_state=TRUE;
|
|
vidUpdate();
|
|
#else
|
|
MouDrawPtr(Mouse_Handle);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void
|
|
turnmouseoff()
|
|
{
|
|
static NOPTRRECT r = { 0, 0, (USHORT)-1, (USHORT)-1 };
|
|
if (r.cRow == (USHORT)-1) {
|
|
VIOMODEINFO mi;
|
|
mi.cb = sizeof mi;
|
|
VioGetMode(&mi, 0);
|
|
r.cRow = mi.row-1;
|
|
r.cCol = mi.col-1;
|
|
}
|
|
/* Hide Cursor */
|
|
MouRemovePtr(&r, Mouse_Handle);
|
|
mouse_state=FALSE;
|
|
}
|
|
|
|
/*
|
|
* mouseon - call made available for programs calling pico to turn OFF the
|
|
* mouse cursor.
|
|
*/
|
|
void
|
|
mouseoff()
|
|
{
|
|
#ifdef FASTVIO
|
|
/* This is ignored if in FASTVIO mode */
|
|
#else
|
|
if (mouchk()) {
|
|
turnmouseoff();
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* This function gets called just before we go back home to the command
|
|
* interpreter.
|
|
*/
|
|
ttclose()
|
|
{
|
|
if(!Pmaster)
|
|
interrupt_ok();
|
|
#ifdef MOUSE
|
|
deinit_mouse();
|
|
#endif
|
|
return(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* Flush terminal buffer. Does real work where the terminal output is buffered
|
|
* up. A no-operation on systems where byte at a time terminal I/O is done.
|
|
*/
|
|
ttflush()
|
|
{
|
|
return(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* specialkey - return special key definition
|
|
*/
|
|
specialkey(kc)
|
|
unsigned kc;
|
|
{
|
|
switch(kc){
|
|
case 0x3b00 : return(F1);
|
|
case 0x3c00 : return(F2);
|
|
case 0x3d00 : return(F3);
|
|
case 0x3e00 : return(F4);
|
|
case 0x3f00 : return(F5);
|
|
case 0x4000 : return(F6);
|
|
case 0x4100 : return(F7);
|
|
case 0x4200 : return(F8);
|
|
case 0x4300 : return(F9);
|
|
case 0x4400 : return(F10);
|
|
case 0x8500 : return(F11);
|
|
case 0x8600 : return(F12);
|
|
case 0x4800 : return(KEY_UP);
|
|
case 0x5000 : return(KEY_DOWN);
|
|
case 0x4b00 : return(KEY_LEFT);
|
|
case 0x4d00 : return(KEY_RIGHT);
|
|
case 0x4700 : return(KEY_HOME);
|
|
case 0x4f00 : return(KEY_END);
|
|
case 0x4900 : return(KEY_PGUP);
|
|
case 0x5100 : return(KEY_PGDN);
|
|
case 0x5300 : return(KEY_DEL);
|
|
case 0x48e0 : return(KEY_UP); /* grey key version */
|
|
case 0x50e0 : return(KEY_DOWN); /* grey key version */
|
|
case 0x4be0 : return(KEY_LEFT); /* grey key version */
|
|
case 0x4de0 : return(KEY_RIGHT); /* grey key version */
|
|
case 0x47e0 : return(KEY_HOME); /* grey key version */
|
|
case 0x4fe0 : return(KEY_END); /* grey key version */
|
|
case 0x49e0 : return(KEY_PGUP); /* grey key version */
|
|
case 0x51e0 : return(KEY_PGDN); /* grey key version */
|
|
case 0x53e0 : return(KEY_DEL); /* grey key version */
|
|
default : return(NODATA);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Read a character from the terminal, performing no editing and doing no echo
|
|
* at all. Also mouse events are forced into the input stream here.
|
|
*/
|
|
ttgetc(return_on_intr, recorder, bail_handler)
|
|
int return_on_intr;
|
|
int (*recorder)();
|
|
int (*bail_handler)();
|
|
{
|
|
int key = kbd_getkey();
|
|
return key ? key : NODATA;
|
|
}
|
|
|
|
|
|
/*
|
|
* ctrlkey - used to check if the key hit was a control key.
|
|
*/
|
|
ctrlkey()
|
|
{
|
|
return !!(kbd_shift() & KBDSTF_CONTROL);
|
|
}
|
|
|
|
|
|
/*
|
|
* win_multiplex - give OS/2 a shot at the CPU
|
|
*/
|
|
win_multiplex()
|
|
{
|
|
DosSleep(32);
|
|
}
|
|
|
|
|
|
/*
|
|
* Read in a key.
|
|
* Do the standard keyboard preprocessing. Convert the keys to the internal
|
|
* character set. Resolves escape sequences and returns no-op if global
|
|
* timeout value exceeded.
|
|
*/
|
|
GetKey()
|
|
{
|
|
unsigned ch = 0, lch, intrupt = 0;
|
|
long timein;
|
|
|
|
vidUpdate();
|
|
if(mexist || timeo) {
|
|
timein = time(0L);
|
|
#ifdef MOUSE
|
|
mouseon(); /* Show Cursor */
|
|
#endif
|
|
while(!kbd_ready()) {
|
|
#if MOUSE
|
|
if(timeo && time(0L) >= timein+timeo){
|
|
mouseoff(); /* Hide Cursor */
|
|
return(NODATA);
|
|
}
|
|
|
|
if(checkmouse(&ch,0,0,0)){ /* something happen ?? */
|
|
mouseoff(); /* Hide Cursor */
|
|
curwp->w_flag |= WFHARD;
|
|
return(ch);
|
|
}
|
|
#else
|
|
if(time(0L) >= timein+timeo) {
|
|
mouseoff(); /* Hide Cursor */
|
|
return(NODATA);
|
|
}
|
|
#endif /* MOUSE */
|
|
|
|
/*
|
|
* Surrender the CPU...
|
|
*/
|
|
win_multiplex();
|
|
}
|
|
#ifdef MOUSE
|
|
mouseoff(); /* Hide Cursor */
|
|
#endif /* MOUSE */
|
|
}
|
|
|
|
ch = (*term.t_getchar)(0, NULL, NULL);
|
|
lch = (ch&0xff);
|
|
|
|
if(lch & 0x80 && Pmaster && Pmaster->hibit_entered)
|
|
*Pmaster->hibit_entered = 1;
|
|
|
|
return((lch && (lch != 0xe0 || !(ch & 0xff00)))
|
|
? (lch < ' ') ? (CTRL|(lch + '@'))
|
|
: (lch == ' ' && ctrlkey()) ? (CTRL|'@') : lch
|
|
: specialkey(ch));
|
|
}
|
|
|
|
|
|
#if MOUSE
|
|
/*
|
|
* checkmouse - look for mouse events in key menu and return
|
|
* appropriate value.
|
|
*/
|
|
int
|
|
checkmouse(ch, down, xxx, yyy)
|
|
unsigned *ch;
|
|
int down, xxx, yyy;
|
|
{
|
|
MOUQUEINFO qi;
|
|
|
|
if(!mouchk())
|
|
return(FALSE);
|
|
|
|
if (MouGetNumQueEl(&qi, Mouse_Handle)==0 && qi.cEvents)
|
|
{
|
|
MOUEVENTINFO m;
|
|
USHORT w = MOU_NOWAIT;
|
|
|
|
/* check to see if any mouse buttons are different */
|
|
if (MouReadEventQue(&m, &w, Mouse_Handle)==0)
|
|
{
|
|
int k;
|
|
int rv = 0;
|
|
int button = M_BUTTON_LEFT;
|
|
int newbut = ((m.fs & 4)?1:0) | ((m.fs & 16)?2:0) | ((m.fs & 64)?4:0);
|
|
|
|
/* only notice button changes */
|
|
if (oldbut == newbut)
|
|
return(FALSE);
|
|
|
|
for (k=1; k != (1 << nbuttons); k <<= 1) {
|
|
/* For each button on the mouse */
|
|
if ((oldbut&k) != (newbut&k)) {
|
|
if(k == 1){
|
|
static int oindex;
|
|
int i = 0;
|
|
MENUITEM *mp;
|
|
|
|
if(newbut&k) /* button down */
|
|
oindex = -1;
|
|
|
|
for(mp = mfunc; mp; mp = mp->next)
|
|
if(mp->action && M_ACTIVE(m.row, m.col, mp))
|
|
break;
|
|
|
|
if(mp){
|
|
unsigned long r;
|
|
|
|
r = (*mp->action)((newbut&k) ? M_EVENT_DOWN : M_EVENT_UP,
|
|
m.row, m.col, button, 0);
|
|
if(r & 0xffff){
|
|
*ch = (unsigned)((r>>16)&0xffff);
|
|
rv = TRUE;
|
|
}
|
|
}
|
|
else{
|
|
while(1){ /* see if we understand event */
|
|
if(i >= 12){
|
|
i = -1;
|
|
break;
|
|
}
|
|
|
|
if(M_ACTIVE(m.row, m.col, &menuitems[i]))
|
|
break;
|
|
|
|
i++;
|
|
}
|
|
|
|
if(newbut&k){ /* button down */
|
|
oindex = i; /* remember where */
|
|
if(i != -1) { /* invert label */
|
|
invert_label(1, &menuitems[i]);
|
|
}
|
|
}
|
|
else{ /* button up */
|
|
if(oindex != -1){
|
|
if(i == oindex){
|
|
*ch = menuitems[i].val;
|
|
rv = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(!(newbut&k) && oindex != -1) {
|
|
invert_label(0, &menuitems[oindex]); /* restore label */
|
|
}
|
|
}
|
|
|
|
oldbut = newbut;
|
|
return(rv);
|
|
}
|
|
++button;
|
|
}
|
|
}
|
|
}
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* invert_label - highlight the label of the given menu item.
|
|
*/
|
|
void
|
|
invert_label(state, m)
|
|
int state;
|
|
MENUITEM *m;
|
|
{
|
|
USHORT r, c;
|
|
VIOCURSORINFO oldInfo, newInfo;
|
|
int i, j, p;
|
|
char *lp;
|
|
int old_state = getrevstate();
|
|
|
|
if(m->val == mnoop)
|
|
return;
|
|
|
|
VioGetCurPos(&r, &c, 0);
|
|
VioGetCurType(&oldInfo, 0);
|
|
newInfo = oldInfo;
|
|
newInfo.attr = (USHORT)-1;
|
|
VioSetCurType(&newInfo, 0); /* Hide Cursor */
|
|
(*term.t_move)(m->tl.r, m->tl.c);
|
|
(*term.t_rev)(state);
|
|
for(i = m->tl.r; i <= m->br.r; i++)
|
|
for(j = m->tl.c; j <= m->br.c; j++)
|
|
if(i == m->lbl.r && j == m->lbl.c){ /* show label?? */
|
|
lp = m->label;
|
|
while(*lp && j++ < m->br.c)
|
|
(*term.t_putchar)(*lp++);
|
|
continue;
|
|
}
|
|
else (*term.t_putchar)(' ');
|
|
|
|
(*term.t_rev)(old_state);
|
|
VioSetCurPos(r, c, 0); /* restore old position */
|
|
VioSetCurType(&oldInfo, 0); /* Show Cursor */
|
|
vidUpdate();
|
|
}
|
|
#endif /* MOUSE */
|
|
|
|
|
|
/*
|
|
* alt_editor - fork off an alternate editor for mail message composition
|
|
*/
|
|
#define MAXARGS 10
|
|
alt_editor(f, n)
|
|
int f, n;
|
|
{
|
|
char *fn; /* tmp holder for file name */
|
|
char *cp;
|
|
int child, rc, i, done = 0;
|
|
long l;
|
|
int stat;
|
|
FILE *p;
|
|
|
|
char *args[MAXARGS]; /* ptrs into edit command */
|
|
char eb[NLINE];
|
|
|
|
if(Pmaster == NULL)
|
|
return(-1);
|
|
|
|
if(gmode&MDSCUR){
|
|
emlwrite("Alternate editor not available in restricted mode", NULL);
|
|
return(-1);
|
|
}
|
|
|
|
if(Pmaster->alt_ed == NULL){
|
|
if (!(gmode&MDADVN)) {
|
|
emlwrite("\007Unknown Command",NULL);
|
|
return(-1);
|
|
}
|
|
|
|
if((cp=getenv("VISUAL"))!=0 || (cp=getenv("EDITOR"))!=0)
|
|
strcpy(eb, (char *)getenv("EDITOR"));
|
|
else *eb = '\0';
|
|
|
|
while(!done) {
|
|
rc = mlreplyd("Which alternate editor ? ",eb,NLINE,QDEFLT,NULL);
|
|
|
|
switch(rc) {
|
|
case ABORT:
|
|
return(-1);
|
|
case HELPCH:
|
|
emlwrite("no alternate editor help yet", NULL);
|
|
|
|
/* take sleep and break out after there's help */
|
|
sleep(3);
|
|
break;
|
|
case (CTRL|'L'):
|
|
sgarbf = TRUE;
|
|
update();
|
|
break;
|
|
case TRUE:
|
|
case FALSE: /* does editor exist ? */
|
|
if(*eb == '\0'){ /* leave silently? */
|
|
mlerase();
|
|
curwp->w_flag |= WFMODE;
|
|
return(-1);
|
|
}
|
|
|
|
done++;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
strcpy(eb, Pmaster->alt_ed);
|
|
|
|
if((fn=writetmp(1, NULL)) == NULL){ /* get temp file */
|
|
emlwrite("Problem writing temp file for alt editor", NULL);
|
|
return(-1);
|
|
}
|
|
|
|
strcat(eb, " ");
|
|
strcat(eb, fn);
|
|
|
|
cp = eb;
|
|
for(i=0; *cp != '\0';i++) { /* build args array */
|
|
if(i < MAXARGS) {
|
|
args[i] = NULL; /* in case we break out */
|
|
}
|
|
else{
|
|
emlwrite("Too many args for command!", NULL);
|
|
return(-1);
|
|
}
|
|
|
|
while(isspace((unsigned char)(*cp)))
|
|
if(*cp != '\0')
|
|
cp++;
|
|
else break;
|
|
|
|
args[i] = cp;
|
|
while(!isspace((unsigned char)(*cp)))
|
|
if(*cp != '\0')
|
|
cp++;
|
|
else
|
|
break;
|
|
|
|
if(*cp != '\0')
|
|
*cp++ = '\0';
|
|
}
|
|
|
|
args[i] = NULL;
|
|
|
|
(*Pmaster->tty_fix)(0);
|
|
|
|
emlwrite("Invoking alternate editor...", NULL);
|
|
|
|
{
|
|
void (*ohup)() = signal(SIGHUP, SIG_IGN); /* ignore signals for now */
|
|
void (*oint)() = signal(SIGINT, SIG_IGN);
|
|
cp=args[0];
|
|
rc = spawnvp(P_WAIT, cp, args);
|
|
signal(SIGHUP, ohup); /* restore signals */
|
|
signal(SIGINT, oint);
|
|
}
|
|
|
|
(*Pmaster->tty_fix)(1);
|
|
|
|
/*
|
|
* Editor may have set a hibit, we don't know. Assume it did.
|
|
*/
|
|
if(!f && Pmaster && Pmaster->hibit_entered)
|
|
*Pmaster->hibit_entered = 1;
|
|
|
|
dont_interrupt();
|
|
|
|
if (rc==-1) { /* Can't run it */
|
|
emlwrite("error attempting to run alt editor", NULL);
|
|
}
|
|
/*
|
|
* replace edited text with new text
|
|
*/
|
|
else{
|
|
rc = 0;
|
|
curbp->b_flag &= ~BFCHG; /* make sure old text gets blasted */
|
|
readin(fn, 0, 0); /* read new text overwriting old */
|
|
curbp->b_flag |= BFCHG; /* mark dirty for packbuf() */
|
|
}
|
|
unlink(fn); /* blast temp file */
|
|
|
|
ttopen(); /* reset the signals */
|
|
pico_refresh(0, 1); /* redraw */
|
|
return(rc);
|
|
}
|
|
|
|
|
|
/*
|
|
* bktoshell - suspend and wait to be woken up
|
|
*/
|
|
int
|
|
bktoshell() /* suspend MicroEMACS and wait to wake up */
|
|
{
|
|
int i;
|
|
static char * shell = NULL;
|
|
|
|
if (shell == NULL) {
|
|
char *p;
|
|
shell=getenv("SHELL");
|
|
if (!shell && !(shell=getenv("COMSPEC")))
|
|
shell="CMD.EXE";
|
|
if ((p = strdup(shell)) > 0) {
|
|
for (shell = p; (p = strchr(shell, '/')) != 0; )
|
|
*p = '\\';
|
|
}
|
|
}
|
|
|
|
(*term.t_move)(term.t_nrow, 0);
|
|
(*term.t_eeol)();
|
|
exit_text_mode(NULL);
|
|
interrupt_ok();
|
|
if (system(shell) == -1)
|
|
emlwrite("Error loading %s", shell);
|
|
else pico_refresh(0, 1); /* redraw */
|
|
enter_text_mode(NULL);
|
|
dont_interrupt();
|
|
return(1);
|
|
}
|
|
|
|
|
|
/*
|
|
* P_open - run the given command in a sub-shell returning a file pointer
|
|
* from which to read the output
|
|
*
|
|
* note:
|
|
* For OS's other than unix, you will have to rewrite this function.
|
|
* Hopefully it'll be easy to exec the command into a temporary file,
|
|
* and return a file pointer to that opened file or something.
|
|
*/
|
|
FILE *P_open(c)
|
|
char *c;
|
|
{
|
|
return(popen(c,"r"));
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* P_close - close the given descriptor
|
|
*
|
|
*/
|
|
void
|
|
P_close(fp)
|
|
FILE *fp;
|
|
{
|
|
(void)pclose(fp);
|
|
}
|
|
|
|
/*
|
|
* A replacement for fflush
|
|
* relies on #define fflush os2_fflush
|
|
*/
|
|
#undef fflush
|
|
int
|
|
os2_fflush (FILE *f)
|
|
{
|
|
if (f == stdout) {
|
|
vidUpdate();
|
|
}
|
|
else
|
|
fflush (f);
|
|
}
|
|
|
|
/*
|
|
* ttresize - recompute the screen dimensions if necessary, and then
|
|
* adjust pico's internal buffers accordingly
|
|
*/
|
|
void
|
|
ttresize ()
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* picosigs - Install any handlers for the signals we're interested
|
|
* in catching.
|
|
*/
|
|
void
|
|
picosigs()
|
|
{
|
|
signal(SIGHUP, do_hup_signal); /* deal with SIGHUP */
|
|
signal(SIGTERM, do_hup_signal); /* deal with SIGTERM */
|
|
}
|
|
|
|
/*
|
|
* do_hup_signal - jump back in the stack to where we can handle this
|
|
*/
|
|
void
|
|
do_hup_signal(int sig)
|
|
{
|
|
sig=sig;
|
|
signal(SIGHUP, SIG_IGN); /* ignore further SIGHUP's */
|
|
signal(SIGTERM, SIG_IGN); /* ignore further SIGTERM's */
|
|
if(Pmaster){
|
|
extern jmp_buf finstate;
|
|
|
|
longjmp(finstate, COMP_GOTHUP);
|
|
}
|
|
else{
|
|
/*
|
|
* if we've been interrupted and the buffer is changed,
|
|
* save it...
|
|
*/
|
|
if(anycb() == TRUE){ /* time to save */
|
|
if(curbp->b_fname[0] == '\0'){ /* name it */
|
|
strcpy(curbp->b_fname, "pico.sav");
|
|
}
|
|
else{
|
|
strcat(curbp->b_fname, ".sav");
|
|
}
|
|
writeout(curbp->b_fname, TRUE);
|
|
}
|
|
vttidy();
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#ifdef MOUSE
|
|
|
|
/*
|
|
* end_mouse - a no-op on DOS/Windows
|
|
*/
|
|
void
|
|
end_mouse()
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* mouseexist - function to let outsiders know if mouse is turned on
|
|
* or not.
|
|
*/
|
|
mouseexist()
|
|
{
|
|
return(mexist);
|
|
}
|
|
#endif /* MOUSE */
|
|
|
|
|
|
/*
|
|
* fallowc - returns TRUE if c is allowable in filenames, FALSE otw
|
|
*/
|
|
fallowc(c)
|
|
int c;
|
|
{
|
|
return(okinfname[c>>3] & 0x80>>(c&7));
|
|
}
|
|
|
|
|
|
/*
|
|
* fexist - returns TRUE if the file exists, FALSE otherwise
|
|
*/
|
|
fexist(file, m, l)
|
|
char *file, *m;
|
|
off_t *l;
|
|
{
|
|
struct stat sbuf;
|
|
|
|
if(l != NULL)
|
|
*l = (off_t)0;
|
|
|
|
if(stat(file, &sbuf) < 0){
|
|
if(ENOENT) /* File not found */
|
|
return(FIOFNF);
|
|
else
|
|
return(FIOERR);
|
|
}
|
|
|
|
if(l != NULL)
|
|
*l = (off_t)sbuf.st_size;
|
|
|
|
if(sbuf.st_mode & S_IFDIR)
|
|
return(FIODIR);
|
|
|
|
if(m[0] == 'r') /* read access? */
|
|
return((S_IREAD & sbuf.st_mode) ? FIOSUC : FIONRD);
|
|
else if(m[0] == 'w') /* write access? */
|
|
return((S_IWRITE & sbuf.st_mode) ? FIOSUC : FIONWT);
|
|
else if(m[0] == 'x') /* execute access? */
|
|
return((S_IEXEC & sbuf.st_mode) ? FIOSUC : FIONEX);
|
|
return(FIOERR); /* what? */
|
|
}
|
|
|
|
|
|
/*
|
|
* isdir - returns true if fn is a readable directory, false otherwise
|
|
* silent on errors (we'll let someone else notice the problem;)).
|
|
*/
|
|
isdir(fn, l, d)
|
|
char *fn;
|
|
long *l;
|
|
time_t *d;
|
|
{
|
|
struct stat sbuf;
|
|
|
|
if(l)
|
|
*l = 0;
|
|
|
|
if(stat(fn, &sbuf) < 0)
|
|
return(0);
|
|
|
|
if(l)
|
|
*l = sbuf.st_size;
|
|
|
|
if(d)
|
|
*d = sbuf.st_mtime;
|
|
|
|
return(sbuf.st_mode & S_IFDIR);
|
|
}
|
|
|
|
|
|
/*
|
|
* gethomedir - returns the users home directory
|
|
* Note: home is malloc'd for life of pico
|
|
*/
|
|
char *gethomedir(l)
|
|
int *l;
|
|
{
|
|
static char *home = NULL;
|
|
static short hlen = 0;
|
|
|
|
if(home == NULL){
|
|
char *p, buf[NLINE];
|
|
|
|
if (home=getenv("PINEHOME")) /* Overrides all others */
|
|
strcpy(buf, home);
|
|
else if (home=getenv("HOME")) /* Convenient group placement */
|
|
strcpy(buf, home);
|
|
else if (home=getenv("ETC")) /* IBM TCPIP */
|
|
strcpy(buf, home);
|
|
else sprintf(buf, "%c:\\", _getdrive());
|
|
hlen = strlen(buf);
|
|
if ((home=(char *)malloc(hlen + 1)) == NULL) {
|
|
emlwrite("Problem allocating space for home dir", NULL);
|
|
return(0);
|
|
}
|
|
strcpy(home, buf);
|
|
while ((p=strchr(home,'/')) != NULL) /* Normalise, just in case */
|
|
*p = '\\';
|
|
}
|
|
|
|
if(l)
|
|
*l = hlen;
|
|
|
|
return(home);
|
|
}
|
|
|
|
|
|
/*
|
|
* homeless - returns true if given file does not reside in the current
|
|
* user's home directory tree.
|
|
*/
|
|
homeless(f)
|
|
char *f;
|
|
{
|
|
char *home;
|
|
int len;
|
|
|
|
home = gethomedir(&len);
|
|
return(strncmp(home, f, len));
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* errstr - return system error string corresponding to given errno
|
|
* Note: strerror() is not provided on all systems, so it's
|
|
* done here once and for all.
|
|
*/
|
|
char *errstr(err)
|
|
int err;
|
|
{
|
|
return((err >= 0 && err < sys_nerr) ? (char*)sys_errlist[err] : NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* getfnames - return all file names in the given directory in a single
|
|
* malloc'd string. n contains the number of names
|
|
*/
|
|
char *getfnames(dn, pat, n, e)
|
|
char *dn, *pat, *e;
|
|
int *n;
|
|
{
|
|
int status;
|
|
long l;
|
|
size_t avail, alloced, incr = 1024;
|
|
char *names, *np, *p;
|
|
char buf[NLINE];
|
|
struct stat sbuf;
|
|
ULONG count=1;
|
|
FILEFINDBUF3 findbuf;
|
|
HDIR hdir=HDIR_CREATE;
|
|
|
|
*n = 0;
|
|
|
|
while ((p = strchr(dn, '/')) != NULL)
|
|
*p = '\\';
|
|
|
|
if(stat(dn, &sbuf) < 0){
|
|
if(e)
|
|
sprintf(e, "\007Dir \"%s\": %s", dn, strerror(errno));
|
|
|
|
return(NULL);
|
|
}
|
|
else{
|
|
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
|
avail = alloced = MAX(sbuf.st_size, incr);
|
|
if(!(sbuf.st_mode & S_IFDIR)){
|
|
if(e)
|
|
sprintf(e, "\007Not a directory: \"%s\"", dn);
|
|
|
|
return(NULL);
|
|
}
|
|
}
|
|
|
|
if((names=(char *)malloc(alloced * sizeof(char))) == NULL){
|
|
if(e)
|
|
sprintf(e, "\007Can't malloc space for file names");
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
np = names;
|
|
|
|
strcpy(buf, dn);
|
|
if (*buf && buf[strlen(buf)-1] != '\\')
|
|
strcat(buf, "\\");
|
|
if (pat && *pat)
|
|
strcat(buf, pat);
|
|
if (!pat || !*pat || strchr(pat, '.')==NULL)
|
|
strcat(buf, "*");
|
|
|
|
if (DosFindFirst(buf, &hdir, FILE_NORMAL|FILE_DIRECTORY, &findbuf,
|
|
sizeof findbuf, &count, FIL_STANDARD) != 0) {
|
|
if(e)
|
|
sprintf(e, "Can't find first file in \"%s\"", dn);
|
|
|
|
free((char *) names);
|
|
return(NULL);
|
|
}
|
|
|
|
do{
|
|
(*n)++;
|
|
p = findbuf.achName;
|
|
l = strlen(p);
|
|
while(avail < l+1){
|
|
char *oldnames;
|
|
|
|
alloced += incr;
|
|
avail += incr;
|
|
oldnames = names;
|
|
if((names = (char *)realloc((void *)names, alloced * sizeof(char)))
|
|
== NULL){
|
|
if(e)
|
|
sprintf(e, "\007Can't malloc enough space for file names");
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
np = names + (np-oldnames);
|
|
}
|
|
|
|
avail -= (l+1);
|
|
|
|
while((*np++ = *p++) != '\0')
|
|
;
|
|
}
|
|
while(DosFindNext(hdir, &findbuf, sizeof findbuf, &count) == 0);
|
|
|
|
return(names);
|
|
}
|
|
|
|
|
|
/*
|
|
* fioperr - given the error number and file name, display error
|
|
*/
|
|
void
|
|
fioperr(e, f)
|
|
int e;
|
|
char *f;
|
|
{
|
|
switch(e){
|
|
case FIOFNF: /* File not found */
|
|
emlwrite("\007File \"%s\" not found", f);
|
|
break;
|
|
case FIOEOF: /* end of file */
|
|
emlwrite("\007End of file \"%s\" reached", f);
|
|
break;
|
|
case FIOLNG: /* name too long */
|
|
emlwrite("\007File name \"%s\" too long", f);
|
|
break;
|
|
case FIODIR: /* file is a directory */
|
|
emlwrite("\007File \"%s\" is a directory", f);
|
|
break;
|
|
case FIONWT:
|
|
emlwrite("\007Write permission denied: %s", f);
|
|
break;
|
|
case FIONRD:
|
|
emlwrite("\007Read permission denied: %s", f);
|
|
break;
|
|
case FIONEX:
|
|
emlwrite("\007Execute permission denied: %s", f);
|
|
break;
|
|
default:
|
|
emlwrite("\007File I/O error: %s", f);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* pfnexpand - pico's function to expand the given file name if there is
|
|
* a leading '~'
|
|
*/
|
|
char *pfnexpand(fn, len)
|
|
char *fn;
|
|
size_t len;
|
|
{
|
|
register char *x, *y, *z;
|
|
char *home = gethomedir(NULL);
|
|
char name[20];
|
|
|
|
if(*fn == '~') {
|
|
for(x = fn+1, y = name;
|
|
*x != '/' && *x != '\\' && *x != '\0' && y-name < sizeof(name)-1;
|
|
*y++ = *x++);
|
|
*y = '\0';
|
|
if(strlen(home) + strlen(fn) >= len) {
|
|
return(NULL);
|
|
}
|
|
/* make room for expanded path */
|
|
for(z=x+strlen(x),y=fn+strlen(x)+strlen(home);
|
|
z >= x;
|
|
*y-- = *z--);
|
|
/* and insert the expanded address */
|
|
for(x=fn,y=home; *y != '\0'; *x++ = *y++);
|
|
}
|
|
|
|
return(fn);
|
|
}
|
|
|
|
getcurdir(drv, buf)
|
|
int drv;
|
|
char *buf;
|
|
{
|
|
LONG ml = _MAX_PATH;
|
|
drv = drv ? toupper(drv) : _getdrive();
|
|
buf[0] = (char)drv;
|
|
buf[1] = ':';
|
|
buf[2] = '\\';
|
|
return DosQueryCurrentDir(drv-'A'+1, buf + 3, &ml) == 0;
|
|
}
|
|
|
|
/*
|
|
* fixpath - make the given pathname into an absolute path
|
|
*/
|
|
void
|
|
fixpath(name, len)
|
|
char *name;
|
|
size_t len;
|
|
{
|
|
char *p;
|
|
char file[_MAX_PATH];
|
|
int dr;
|
|
|
|
if(!len)
|
|
return;
|
|
|
|
/* normalize: xlate any '/' into '\\' */
|
|
while ((p=strchr(name,'/'))!=NULL)
|
|
*p='\\';
|
|
|
|
/* return the full path of given file */
|
|
if(isalpha((unsigned char)name[0]) && name[1] == ':'){ /* have drive spec? */
|
|
if(name[2] == '\\') /* including path? */
|
|
return;
|
|
if (!getcurdir(name[0], file))
|
|
return;
|
|
name += 2;
|
|
}
|
|
else if(name[0] == '.' && (!name[1] || name[1] == '\\')) {
|
|
getcurdir(0, file);
|
|
name += (1 + name[1] == '\\');
|
|
}
|
|
else if(name[0] == '\\') { /* no drive spec! */
|
|
file[0] = (char)_getdrive();
|
|
file[1] = ':';
|
|
file[2] = '\0';
|
|
}
|
|
else getcurdir(0, file); /* no qualification */
|
|
|
|
if(*name) { /* if name, append it */
|
|
p = NULL;
|
|
if (name[0] == '.' && name[1] == '.' && (!name[2] || name[2] == '\\')) {
|
|
if ((p = strrchr(name,'\\'))!=NULL) {
|
|
*p++ = '\0';
|
|
if (!*p && (p=strrchr(name,'\\'))!=NULL)
|
|
*p = '\0';
|
|
}
|
|
name += (2 & name[2] == '\\');
|
|
}
|
|
if (*name) {
|
|
if (name[0] == '.' && (!name[1] || name[1] == '\\'))
|
|
name += (1 + name[1] == '\\');
|
|
if (*name) {
|
|
if (*file && file[strlen(file)-1] != '\\' && *name != '\\')
|
|
strcat(file, "\\");
|
|
strcat(file, name);
|
|
}
|
|
}
|
|
}
|
|
|
|
strncpy(name, file, len-1); /* copy back to real buffer */
|
|
name[len-1] = '\0'; /* tie off just in case */
|
|
}
|
|
|
|
|
|
/*
|
|
* compresspath - given a base path and an additional directory, collapse
|
|
* ".." and "." elements and return absolute path (appending
|
|
* base if necessary).
|
|
*
|
|
* returns 1 if OK,
|
|
* 0 if there's a problem
|
|
* new path, by side effect, if things went OK
|
|
*/
|
|
compresspath(base, path, len)
|
|
char *base, *path;
|
|
int len;
|
|
{
|
|
register int i;
|
|
int depth = 0;
|
|
char *p;
|
|
char *stack[32];
|
|
char pathbuf[NLINE];
|
|
|
|
#define PUSHD(X) (stack[depth++] = X)
|
|
#define POPD() ((depth > 0) ? stack[--depth] : "")
|
|
|
|
strcpy(pathbuf, path);
|
|
fixpath(pathbuf, len);
|
|
|
|
p = pathbuf;
|
|
for(i=0; pathbuf[i] != '\0'; i++){ /* pass thru path name */
|
|
if(pathbuf[i] == C_FILESEP){
|
|
if(p != pathbuf)
|
|
PUSHD(p); /* push dir entry */
|
|
p = &pathbuf[i+1]; /* advance p */
|
|
pathbuf[i] = '\0'; /* cap old p off */
|
|
continue;
|
|
}
|
|
|
|
if(pathbuf[i] == '.'){ /* special cases! */
|
|
if(pathbuf[i+1] == '.' /* parent */
|
|
&& (pathbuf[i+2] == C_FILESEP || pathbuf[i+2] == '\0')){
|
|
if(!strcmp(POPD(),"")) /* bad news! */
|
|
return(0);
|
|
|
|
i += 2;
|
|
p = (pathbuf[i] == '\0') ? "" : &pathbuf[i+1];
|
|
}
|
|
else if(pathbuf[i+1] == C_FILESEP || pathbuf[i+1] == '\0'){
|
|
i++;
|
|
p = (pathbuf[i] == '\0') ? "" : &pathbuf[i+1];
|
|
}
|
|
}
|
|
}
|
|
|
|
if(*p != '\0')
|
|
PUSHD(p); /* get last element */
|
|
|
|
path[0] = '\0';
|
|
for(i = 0; i < depth; i++){
|
|
strcat(path, S_FILESEP);
|
|
strcat(path, stack[i]);
|
|
}
|
|
|
|
return(1); /* everything's ok */
|
|
}
|
|
|
|
|
|
/*
|
|
* tmpname - return a temporary file name in the given buffer
|
|
*/
|
|
void
|
|
tmpname(dir, name)
|
|
char *dir;
|
|
char *name;
|
|
{
|
|
static int counter = 0;
|
|
static char *tmpdir = NULL;
|
|
char * p;
|
|
|
|
if(dir && *dir)
|
|
tmpdir = dir;
|
|
|
|
if(!tmpdir && (tmpdir=getenv("TEMP"))==NULL && (tmpdir = getenv("TMP"))==NULL)
|
|
tmpdir=".";
|
|
p = strchr(strcpy(name, tmpdir), '/');
|
|
while (p != NULL)
|
|
{
|
|
*p++ = '\\';
|
|
p = strchr(p, '/');
|
|
}
|
|
p = strrchr(name, '\\');
|
|
if (p == 0)
|
|
p = name + strlen(name);
|
|
else if (*++p != 0)
|
|
{
|
|
p = name + strlen(name);
|
|
*p++ = '\\';
|
|
}
|
|
sprintf(p, "pn%d%d", getpid(), ++counter);
|
|
|
|
if(dir && *dir)
|
|
tmpdir = NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Take a file name, and from it
|
|
* fabricate a buffer name. This routine knows
|
|
* about the syntax of file names on the target system.
|
|
* I suppose that this information could be put in
|
|
* a better place than a line of code.
|
|
*/
|
|
void
|
|
makename(bname, fname)
|
|
char bname[];
|
|
char fname[];
|
|
{
|
|
register char *cp1;
|
|
register char *cp2;
|
|
|
|
cp1 = &fname[0];
|
|
while (*cp1 != 0)
|
|
++cp1;
|
|
|
|
while (cp1!=&fname[0] && cp1[-1]!='\\')
|
|
--cp1;
|
|
cp2 = &bname[0];
|
|
while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
|
|
*cp2++ = *cp1++;
|
|
*cp2 = 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* copy - copy contents of file 'a' into a file named 'b'. Return error
|
|
* if either isn't accessible or is a directory
|
|
*/
|
|
copy(a, b)
|
|
char *a, *b;
|
|
{
|
|
int n, rv = 0;
|
|
struct stat tsb, fsb;
|
|
|
|
if(stat(a, &fsb) < 0){ /* get source file info */
|
|
emlwrite("Can't Copy: %s", errstr(errno));
|
|
return(-1);
|
|
}
|
|
|
|
if(!(fsb.st_mode&S_IREAD)){ /* can we read it? */
|
|
emlwrite("\007Read permission denied: %s", a);
|
|
return(-1);
|
|
}
|
|
|
|
if((fsb.st_mode&S_IFMT) == S_IFDIR){ /* is it a directory? */
|
|
emlwrite("\007Can't copy: %s is a directory", a);
|
|
return(-1);
|
|
}
|
|
|
|
if(stat(b, &tsb) < 0){ /* get dest file's mode */
|
|
switch(errno){
|
|
case ENOENT:
|
|
break; /* these are OK */
|
|
default:
|
|
emlwrite("\007Can't Copy: %s", errstr(errno));
|
|
return(-1);
|
|
}
|
|
}
|
|
else{
|
|
if(!(tsb.st_mode&S_IWRITE)){ /* can we write it? */
|
|
emlwrite("\007Write permission denied: %s", b);
|
|
return(-1);
|
|
}
|
|
|
|
if((tsb.st_mode&S_IFMT) == S_IFDIR){ /* is it directory? */
|
|
emlwrite("\007Can't copy: %s is a directory", b);
|
|
return(-1);
|
|
}
|
|
|
|
if(fsb.st_dev == tsb.st_dev && fsb.st_ino == tsb.st_ino){
|
|
emlwrite("\007Identical files. File not copied", NULL);
|
|
return(-1);
|
|
}
|
|
}
|
|
|
|
rv=DosCopy(a, b, DCPY_EXISTING);
|
|
|
|
if(rv != 0 < 0){
|
|
emlwrite("Copy Failed: DosCopy() error %d", rv);
|
|
return(-1);
|
|
}
|
|
return(rv);
|
|
}
|
|
|
|
|
|
/*
|
|
* Open a file for writing. Return TRUE if all is well, and FALSE on error
|
|
* (cannot create).
|
|
*/
|
|
ffwopen(fn, readonly)
|
|
char *fn;
|
|
int readonly;
|
|
{
|
|
extern FIOINFO g_pico_fio;
|
|
|
|
g_pico_fio.flags = FIOINFO_WRITE;
|
|
if ((g_pico_fio.fp = fopen(gf_pico_fio.name = fn, "w")) == NULL) {
|
|
emlwrite("Cannot open file for writing", NULL);
|
|
return (FIOERR);
|
|
}
|
|
|
|
if(readonly)
|
|
chmod(fn, MODE_READONLY); /* fix access rights */
|
|
|
|
return (FIOSUC);
|
|
}
|
|
|
|
|
|
/*
|
|
* Close a file. Should look at the status in all systems.
|
|
*/
|
|
ffclose()
|
|
{
|
|
extern FIOINFO g_pico_fio;
|
|
|
|
if (fclose(g_pico_fio.fp) != FALSE) {
|
|
emlwrite("Error closing file", NULL);
|
|
return(FIOERR);
|
|
}
|
|
|
|
return(FIOSUC);
|
|
}
|
|
|
|
|
|
/*
|
|
* ffelbowroom - make sure the destination's got enough room to receive
|
|
* what we're about to write...
|
|
*/
|
|
ffelbowroom(fn, readonly)
|
|
char *fn;
|
|
int readonly;
|
|
{
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
/*
|
|
* worthit - generic sort of test to roughly gage usefulness of using
|
|
* optimized scrolling.
|
|
*
|
|
* note:
|
|
* returns the line on the screen, l, that the dot is currently on
|
|
*/
|
|
worthit(l)
|
|
int *l;
|
|
{
|
|
int i; /* l is current line */
|
|
unsigned below; /* below is avg # of ch/line under . */
|
|
|
|
*l = doton(&i, &below);
|
|
below = (i > 0) ? below/(unsigned)i : 0;
|
|
|
|
return(below > 3);
|
|
}
|
|
|
|
|
|
/*
|
|
* o_insert - optimize screen insert of char c
|
|
*/
|
|
o_insert(c)
|
|
char c;
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* o_delete - optimized character deletion
|
|
*/
|
|
o_delete()
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
|
|
/*
|
|
* pico_new_mail - just checks mtime and atime of mail file and notifies user
|
|
* if it's possible that they have new mail.
|
|
*/
|
|
pico_new_mail()
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* time_to_check - checks the current time against the last time called
|
|
* and returns true if the elapsed time is > below.
|
|
* Newmail won't necessarily check, but we want to give it
|
|
* a chance to check or do a keepalive.
|
|
*/
|
|
time_to_check()
|
|
{
|
|
static time_t lasttime = 0L;
|
|
|
|
if(!timeo)
|
|
return(FALSE);
|
|
|
|
if(time((time_t *) 0) - lasttime > (Pmaster ? (time_t)(FUDGE-10) : timeo)){
|
|
lasttime = time((time_t *) 0);
|
|
return(TRUE);
|
|
}
|
|
else
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
/*
|
|
* sstrcasecmp - compare two pointers to strings case independently
|
|
*/
|
|
sstrcasecmp(s1, s2)
|
|
QcompType *s1, *s2;
|
|
{
|
|
return((*pcollator)(*(char **)s1, *(char **)s2));
|
|
}
|
|
|
|
|
|
int
|
|
strucmp(o, r)
|
|
char *o, *r;
|
|
{
|
|
return(o ? (r ? stricmp(o, r) : 1) : (r ? -1 : 0));
|
|
}
|
|
|
|
|
|
int
|
|
struncmp(o, r, n)
|
|
char *o, *r;
|
|
int n;
|
|
{
|
|
return(o ? (r ? strnicmp(o, r, n) : 1) : (r ? -1 : 0));
|
|
}
|
|
|
|
|
|
/*
|
|
* sleep the given number of microseconds
|
|
*/
|
|
ssleep(s)
|
|
clock_t s;
|
|
{
|
|
s += clock();
|
|
while(s > clock())
|
|
;
|
|
}
|
|
|
|
|
|
/*
|
|
* chkptinit -- initialize anything we need to support composer
|
|
* checkpointing
|
|
*/
|
|
void
|
|
chkptinit(file, n)
|
|
char *file;
|
|
int n;
|
|
{
|
|
if(!file[0]){
|
|
long gmode_save = gmode;
|
|
|
|
if(gmode&MDCURDIR)
|
|
gmode &= ~MDCURDIR; /* so fixpath will use home dir */
|
|
|
|
strcpy(file, "#picoTM0.txt");
|
|
fixpath(file, NLINE);
|
|
gmode = gmode_save;
|
|
}
|
|
else{
|
|
int l = strlen(file);
|
|
|
|
if(file[l-1] != '\\'){
|
|
file[l++] = '\\';
|
|
file[l] = '\0';
|
|
}
|
|
|
|
strcpy(file + l, "#picoTM0.txt");
|
|
}
|
|
|
|
if(fexist(file, "r", (off_t *)NULL) == FIOSUC){ /* does file exist? */
|
|
char copy[NLINE];
|
|
|
|
strcpy(copy, "#picoTM1.txt");
|
|
fixpath(copy, NLINE);
|
|
rename(file, copy); /* save so we don't overwrite it */
|
|
}
|
|
|
|
unlink(file);
|
|
}
|
|
|
|
|
|
void
|
|
set_collation(collation, ctype)
|
|
int collation;
|
|
int ctype;
|
|
{
|
|
extern int collator(); /* strcoll isn't declared on all systems */
|
|
#ifdef LC_COLLATE
|
|
char *status = NULL;
|
|
#endif
|
|
|
|
pcollator = strucmp;
|
|
|
|
#ifdef LC_COLLATE
|
|
if(collation){
|
|
/*
|
|
* This may not have the desired effect, if collator is not
|
|
* defined to be strcoll in os.h and strcmp and friends
|
|
* don't know about locales. If your system does have strcoll
|
|
* but we haven't defined collator to be strcoll in os.h, let us know.
|
|
*/
|
|
status = setlocale(LC_COLLATE, "");
|
|
|
|
/*
|
|
* If there is an error or if the locale is the "C" locale, then we
|
|
* don't want to use strcoll because in the default "C" locale strcoll
|
|
* uses strcmp ordering and we want strucmp ordering.
|
|
*
|
|
* The test for "C" isn't really correct, since status does not have to
|
|
* be "C" even if we're in the "C" locale. But this works on some systems.
|
|
*/
|
|
if(status && !(status[0] == 'C' && status[1] == '\0'))
|
|
pcollator = collator;
|
|
}
|
|
#endif
|
|
#ifdef LC_CTYPE
|
|
if(ctype){
|
|
(void)setlocale(LC_CTYPE, "");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
static USHORT myShift = 0;
|
|
|
|
int kbd_ready()
|
|
{
|
|
KBDKEYINFO ki;
|
|
|
|
if (KbdPeek(&ki, 0)==0)
|
|
{
|
|
if (ki.fbStatus & 0x40) {
|
|
int key = (USHORT)((ki.chScan << 8) | ki.chChar);
|
|
myShift = ki.fsState;
|
|
if (!key && ki.fbStatus & 0x01) {
|
|
KbdCharIn(&ki, IO_WAIT, 0);
|
|
}
|
|
return key;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int kbd_getkey()
|
|
{
|
|
KBDKEYINFO ki;
|
|
|
|
while (KbdCharIn(&ki, IO_WAIT, 0)==0) {
|
|
if (ki.fbStatus & 0x40) {
|
|
myShift = ki.fsState;
|
|
return (USHORT)((ki.chScan << 8) | ki.chChar);
|
|
}
|
|
if (ki.fbStatus & 0x01) {
|
|
myShift = ki.fsState;
|
|
}
|
|
}
|
|
|
|
return NODATA;
|
|
}
|
|
|
|
void kbd_flush()
|
|
{
|
|
KbdFlushBuffer(0);
|
|
}
|
|
|
|
int kbd_shift()
|
|
{
|
|
return myShift;
|
|
}
|
|
|
|
|