blob: 6110629aa1631f52f90fd312b348375327ee9f45 [file] [log] [blame]
#include "ckcsym.h"
int xcmdsrc = 0;
#ifdef NOICP
int cmdsrc() { return(0); }
#endif /* NOICP */
/* C K U U S 5 -- "User Interface" for C-Kermit, part 5 */
/*
Authors:
Frank da Cruz <fdc@columbia.edu>,
The Kermit Project, Columbia University, New York City
Jeffrey E Altman <jaltman@secure-endpoints.com>
Secure Endpoints Inc., New York City
Copyright (C) 1985, 2004,
Trustees of Columbia University in the City of New York.
All rights reserved. See the C-Kermit COPYING.TXT file or the
copyright text in the ckcmai.c module for disclaimer and permissions.
*/
/* Includes */
#include "ckcdeb.h"
#include "ckcasc.h"
#include "ckcker.h"
#include "ckuusr.h"
#ifdef DCMDBUF
char *line; /* Character buffer for anything */
char *tmpbuf;
#else
char line[LINBUFSIZ+1];
char tmpbuf[TMPBUFSIZ+1]; /* Temporary buffer */
#endif /* DCMDBUF */
#ifndef NOICP
#include "ckcnet.h"
#ifndef NOCSETS
#include "ckcxla.h"
#endif /* NOCSETS */
#ifdef MAC
#include "ckmasm.h"
#endif /* MAC */
#ifdef CK_SSL
#include "ck_ssl.h"
#endif /* CK_SSL */
#ifdef OS2
#include "ckoetc.h"
#ifndef NT
#define INCL_NOPM
#define INCL_VIO /* Needed for ckocon.h */
#include <os2.h>
#undef COMMENT
#else /* NT */
#include <windows.h>
#define TAPI_CURRENT_VERSION 0x00010004
#include <tapi.h>
#include <mcx.h>
#include "ckntap.h"
#define APIRET ULONG
extern int DialerHandle;
extern int StartedFromDialer;
#endif /* NT */
#include "ckocon.h"
#include "ckokey.h"
#ifdef KUI
#include "ikui.h"
#endif /* KUI */
#ifdef putchar
#undef putchar
#endif /* putchar */
#define putchar(x) conoc(x)
extern int cursor_save ;
extern bool cursorena[] ;
#endif /* OS2 */
/* For formatted screens, "more?" prompting, etc. */
#ifdef FT18
#define isxdigit(c) isdigit(c)
#endif /* FT18 */
#ifdef STRATUS /* Stratus Computer, Inc. VOS */
#ifdef putchar
#undef putchar
#endif /* putchar */
#define putchar(x) conoc(x)
#ifdef getchar
#undef getchar
#endif /* getchar */
#define getchar(x) coninc(0)
#endif /* STRATUS */
/* External variables */
extern int carrier, cdtimo, local, quiet, backgrd, bgset, sosi, xsuspend,
binary, escape, xargs, flow, cmdmsk, duplex, ckxech, seslog, what,
inserver, diractive, tlevel, cwdf, nfuncs, msgflg, remappd, hints, mdmtyp,
zincnt, cmask, rcflag, success, xitsta, pflag, tnlm, tn_nlm, xitwarn,
debses, xaskmore, parity, saveask, wasclosed, whyclosed, cdactive,
rcdactive, keepallchars;
#ifdef LOCUS
extern int locus, autolocus;
#endif /* LOCUS */
#ifndef NOMSEND
extern int addlist;
#endif /* NOMSEND */
#ifdef CK_SPEED
extern int prefixing;
#endif /* CK_SPEED */
extern int g_matchdot;
#ifdef RECURSIVE
extern int recursive;
#endif /* RECURSIVE */
extern int xfiletype;
#ifdef IKSDCONF
extern char * iksdconf;
extern int iksdcf;
#endif /* IKSDCONF */
#ifdef CK_RECALL
extern int on_recall;
#endif /* CK_RECALL */
extern int ngetpath, exitonclose;
extern char * getpath[];
extern CHAR * epktmsg;
extern char * snd_move;
extern char * snd_rename;
extern char * rcv_move;
extern char * rcv_rename;
extern char * g_snd_move;
extern char * g_snd_rename;
extern char * g_rcv_move;
extern char * g_rcv_rename;
extern char * nm[];
#ifdef CK_UTSNAME
extern char unm_mch[];
extern char unm_mod[];
extern char unm_nam[];
extern char unm_rel[];
extern char unm_ver[];
#endif /* CK_UTSNAME */
#ifndef NOPUSH
#ifndef NOFRILLS
extern char editor[];
extern char editfile[];
extern char editopts[];
#ifdef BROWSER
extern char browser[];
extern char browsopts[];
extern char browsurl[];
#endif /* BROWSER */
#endif /* NOFRILLS */
#endif /* NOPUSH */
#ifndef NOSERVER
extern char * x_user, * x_passwd, * x_acct;
#endif /* NOSERVER */
#ifdef CKLOGDIAL
extern int dialog;
extern char diafil[];
#endif /* CKLOGDIAL */
#ifdef CKROOT
extern int ckrooterr;
#endif /* CKROOT */
#ifndef NOSPL
extern int cfilef, xxdot;
extern char cmdfil[];
struct localvar * localhead[CMDSTKL];
struct localvar * localtail = NULL;
struct localvar * localnext = NULL;
_PROTOTYP( VOID shosexp, (void) );
_PROTOTYP( static VOID shoinput, (void) );
_PROTOTYP( static char gettok, (void) );
_PROTOTYP( static VOID factor, (void) );
_PROTOTYP( static VOID term, (void) );
_PROTOTYP( static VOID termp, (void) );
_PROTOTYP( static VOID exprp, (void) );
_PROTOTYP( static VOID expr, (void) );
_PROTOTYP( static VOID simple, (void) );
_PROTOTYP( static VOID simpler, (void) );
_PROTOTYP( static VOID simplest, (void) );
_PROTOTYP( static long xparse, (void) );
#endif /* NOSPL */
#ifndef NOSHOW
_PROTOTYP( int sho_iks, (void) );
#endif /* NOSHOW */
#ifdef MAC
char * ckprompt = "Mac-Kermit>"; /* Default prompt for Macintosh */
char * ikprompt = "IKSD>";
#else /* Not MAC */
#ifdef NOSPL
#ifdef OS2
char * ckprompt = "K-95> "; /* Default prompt for Win32 */
char * ikprompt = "IKSD> ";
#else
char * ckprompt = "C-Kermit>";
char * ikprompt = "IKSD>";
#endif /* NT */
#else /* NOSPL */
#ifdef OS2
/* Default prompt for OS/2 and Win32 */
#ifdef NT
char * ckprompt = "[\\freplace(\\flongpath(\\v(dir)),/,\\\\)] K-95> ";
char * ikprompt = "[\\freplace(\\flongpath(\\v(dir)),/,\\\\)] IKSD> ";
#else /* NT */
char * ckprompt = "[\\freplace(\\v(dir),/,\\\\)] K-95> ";
char * ikprompt = "[\\freplace(\\v(dir),/,\\\\)] IKSD> ";
#endif /* NT */
#else /* OS2 */
#ifdef VMS
char * ckprompt = "\\v(dir) C-Kermit>"; /* Default prompt VMS */
char * ikprompt = "\\v(dir) IKSD>";
#else
char * ckprompt = "(\\v(dir)) C-Kermit>"; /* Default prompt for others */
char * ikprompt = "(\\v(dir)) IKSD>";
#endif /* VMS */
#endif /* NT */
#endif /* NOSPL */
#endif /* MAC */
#ifndef CCHMAXPATH
#define CCHMAXPATH 257
#endif /* CCHMAXPATH */
char inidir[CCHMAXPATH] = { NUL, NUL }; /* Directory INI file executed from */
#ifdef TNCODE
extern int tn_b_nlm; /* TELNET BINARY newline mode */
#endif /* TNCODE */
#ifndef NOKVERBS
extern struct keytab kverbs[]; /* Table of \Kverbs */
extern int nkverbs; /* Number of \Kverbs */
#endif /* NOKVERBS */
#ifndef NOPUSH
extern int nopush;
#endif /* NOPUSH */
#ifdef CK_RECALL
extern int cm_recall;
#endif /* CK_RECALL */
extern char *ccntab[];
/* Printer stuff */
extern char *printername;
extern int printpipe;
#ifdef BPRINT
extern int printbidi, pportparity, pportflow;
extern long pportspeed;
#endif /* BPRINT */
#ifdef OS2
_PROTOTYP (int os2getcp, (void) );
_PROTOTYP (int os2getcplist, (int *, int) );
#ifdef OS2MOUSE
extern int tt_mouse;
#endif /* OS2MOUSE */
extern int tt_update, tt_updmode, updmode, tt_utf8;
#ifndef IKSDONLY
extern int tt_status[];
#endif /* IKSDONLY */
#ifdef PCFONTS
extern struct keytab term_font[];
#else
#ifdef KUI
extern struct keytab * term_font;
#endif /* KUI */
#endif /* PCFONTS */
extern int ntermfont, tt_font, tt_font_size;
extern unsigned char colornormal, colorunderline, colorstatus,
colorhelp, colorselect, colorborder, colorgraphic, colordebug,
colorreverse, colorcmd, coloritalic;
extern int priority;
extern struct keytab prtytab[];
extern int nprty;
char * cmdmac = NULL;
#endif /* OS2 */
#ifdef VMS
_PROTOTYP (int zkermini, (char *, int, char *) );
#endif /* VMS */
extern long vernum;
extern int inecho, insilence, inbufsize, nvars, inintr;
extern char *protv, *fnsv, *cmdv, *userv, *ckxv, *ckzv, *ckzsys, *xlav,
*cknetv, *clcmds;
#ifdef OS2
extern char *ckyv;
#endif /* OS2 */
#ifdef CK_AUTHENTICATION
extern char * ckathv;
#endif /* CK_AUTHENTICATION */
#ifdef CK_SSL
extern char * cksslv;
#endif /* CK_SSL */
#ifdef CK_ENCRYPTION
#ifndef CRYPT_DLL
extern char * ckcrpv;
#endif /* CRYPT_DLL */
#endif /* CK_ENCRYPTION */
#ifdef SSHBUILTIN
extern char *cksshv;
#ifdef SFTP_BUILTIN
extern char *cksftpv;
#endif /* SFTP_BUILTIN */
#endif /* SSHBUILTIN */
#ifdef TNCODE
extern char *cktelv;
#endif /* TNCODE */
#ifndef NOFTP
#ifndef SYSFTP
extern char * ckftpv;
#endif /* SYSFTP */
#endif /* NOFTP */
extern int srvidl;
#ifdef OS2
extern char *ckonetv;
extern int interm;
#ifdef CK_NETBIOS
extern char *ckonbiv;
#endif /* CK_NETBIOS */
#ifdef OS2MOUSE
extern char *ckomouv;
#endif /* OS2MOUSE */
#endif /* OS2 */
#ifndef NOLOCAL
extern char *connv;
#endif /* NOLOCAL */
#ifndef NODIAL
extern char *dialv;
#endif /* NODIAL */
#ifndef NOSCRIPT
extern char *loginv;
extern int secho;
#endif /* NOSCRIPT */
#ifndef NODIAL
extern int nmdm, dirline;
extern struct keytab mdmtab[];
#endif /* NODIAL */
extern int network, nettype, ttnproto;
#ifdef OS2
#ifndef NOTERM
/* SET TERMINAL items... */
extern int tt_type, tt_arrow, tt_keypad, tt_wrap, tt_answer, tt_scrsize[];
extern int tt_bell, tt_roll[], tt_ctstmo, tt_cursor, tt_pacing, tt_type_mode;
extern char answerback[];
extern struct tt_info_rec tt_info[]; /* Indexed by terminal type */
extern int max_tt;
#endif /* NOTERM */
#endif /* OS2 */
_PROTOTYP( VOID shotrm, (void) );
_PROTOTYP( int shofea, (void) );
#ifdef OS2
extern int tt_rows[], tt_cols[];
#else /* OS2 */
extern int tt_rows, tt_cols;
#endif /* OS2 */
extern int cmd_rows, cmd_cols;
#ifdef CK_TMPDIR
extern int f_tmpdir; /* Directory changed temporarily */
extern char savdir[]; /* Temporary directory */
#endif /* CK_TMPDIR */
#ifndef NOLOCAL
extern int tt_crd, tt_escape;
#endif /* NOLOCAL */
#ifndef NOCSETS
extern int language, nfilc, tcsr, tcsl, tcs_transp, fcharset;
extern struct keytab fcstab[];
extern struct csinfo fcsinfo[];
#ifndef MAC
extern struct keytab ttcstab[];
#endif /* MAC */
#endif /* NOCSETS */
extern long speed;
#ifndef NOXMIT
extern int xmitf, xmitl, xmitp, xmitx, xmits, xmitw, xmitt;
extern char xmitbuf[];
#endif /* NOXMIT */
extern char **xargv, *versio, *ckxsys, *dftty, *lp;
#ifdef DCMDBUF
extern char *cmdbuf, *atmbuf; /* Command buffers */
#ifndef NOSPL
extern char *savbuf; /* Command buffers */
#endif /* NOSPL */
#else
extern char cmdbuf[], atmbuf[]; /* Command buffers */
#ifndef NOSPL
extern char savbuf[]; /* Command buffers */
#endif /* NOSPL */
#endif /* DCMDBUF */
extern char toktab[], ttname[], psave[];
extern CHAR sstate, feol;
extern int cmflgs, techo, repars, ncmd;
extern struct keytab cmdtab[];
#ifndef NOSETKEY
KEY *keymap;
#ifndef OS2
#define mapkey(x) keymap[x]
#endif /* OS2 */
MACRO *macrotab;
_PROTOTYP( VOID shostrdef, (CHAR *) );
#endif /* NOSETKEY */
extern int cmdlvl;
#ifndef NOSPL
extern struct mtab *mactab;
extern struct keytab mackey[];
extern struct keytab vartab[], fnctab[], iftab[];
extern int maclvl, nmac, mecho, fndiags, fnerror, fnsuccess, nif;
#endif /* NOSPL */
FILE *tfile[MAXTAKE]; /* TAKE file stack */
char *tfnam[MAXTAKE];
int tfline[MAXTAKE];
int topcmd = -1; /* cmdtab index of current command */
int havetoken = 0;
extern int dblquo; /* Doublequoting enabled */
#ifdef DCMDBUF /* Initialization filespec */
char *kermrc = NULL;
#else
char kermrcb[KERMRCL];
char *kermrc = kermrcb;
#endif /* DCMDBUF */
int noherald = 0;
int cm_retry = 1; /* Command retry enabled */
xx_strp xxstring = zzstring;
#ifndef NOXFER
extern int displa, bye_active, protocol, pktlog, remfile, rempipe, unkcs,
keep, lf_opts, fncnv, pktpaus, autodl, xfrcan, xfrchr, xfrnum, srvtim,
srvdis, query, retrans, streamed, reliable, crunched, timeouts,
fnrpath, autopath, rpackets, spackets, epktrcvd, srvping;
#ifdef CK_AUTODL
extern int inautodl, cmdadl;
#endif /* CK_AUTODL */
#ifndef NOSERVER
extern int en_asg, en_cwd, en_cpy, en_del, en_dir, en_fin, en_bye, en_ret,
en_get, en_hos, en_que, en_ren, en_sen, en_set, en_spa, en_typ, en_who,
en_mai, en_pri, en_mkd, en_rmd, en_xit, en_ena;
#endif /* NOSERVER */
extern int atcapr,
atenci, atenco, atdati, atdato, atleni, atleno, atblki, atblko,
attypi, attypo, atsidi, atsido, atsysi, atsyso, atdisi, atdiso;
#ifdef STRATUS
extern int atfrmi, atfrmo, atcrei, atcreo, atacti, atacto;
#endif /* STRATUS */
#ifdef CK_PERMS
extern int atlpri, atlpro, atgpri, atgpro;
#endif /* CK_PERMS */
#ifdef CK_LOGIN
extern char * anonfile; /* Anonymous login init file */
extern char * anonroot; /* Anonymous file-system root */
extern char * userfile; /* Forbidden user file */
extern int isguest; /* Flag for anonymous user */
#endif /* CK_LOGIN */
#endif /* NOXFER */
#ifdef DCMDBUF
int *xquiet = NULL;
#else
int xquiet[CMDSTKL];
#endif /* DCMDBUF */
char * prstring[CMDSTKL];
#ifndef NOSPL
extern long ck_alarm;
extern char alrm_date[], alrm_time[];
/* Local declarations */
static int nulcmd = 0; /* Flag for next cmd to be ignored */
/* Definitions for predefined macros */
/* First, the single-line macros, installed with addmac()... */
/* IBM-LINEMODE macro */
char *m_ibm = "set parity mark, set dupl half, set handsh xon, set flow none";
/* FATAL macro */
char *m_fat = "if def \\%1 echo \\%1, if not = \\v(local) 0 hangup, stop 1";
#ifdef CK_SPEED
#ifdef IRIX65
char *m_fast = "set win 30, set rec pack 4000, set prefix cautious";
#else
#ifdef IRIX
/* Because of bug in telnet server */
char *m_fast = "set window 30, set rec pack 4000, set send pack 4000,\
set pref cautious";
#else
#ifdef pdp11
char *m_fast = "set win 3, set rec pack 1024, set prefix cautious";
#else
#ifdef BIGBUFOK
char *m_fast = "set win 30, set rec pack 4000, set prefix cautious";
#else
char *m_fast = "set win 4, set rec pack 2200, set prefix cautious";
#endif /* BIGBUFOK */
#endif /* IRIX */
#endif /* IRIX65 */
#endif /* pdp11 */
#ifdef pdp11
char *m_cautious = "set win 2, set rec pack 512, set prefixing cautious";
#else
char *m_cautious = "set win 4, set rec pack 1000, set prefixing cautious";
#endif /* pdp11 */
char *m_robust = "set win 1, set rec pack 90, set prefixing all, \
set reliable off, set clearchannel off";
#else
#ifdef BIGBUFOK
#ifdef IRIX65
char *m_fast = "set win 30, set rec pack 4000";
#else
#ifdef IRIX
char *m_fast = "set win 30, set rec pack 4000, set send pack 4000";
#else
char *m_fast = "set win 30, set rec pack 4000";
#endif /* IRIX */
#endif /* IRIX65 */
#else /* Not BIGBUFOK */
char *m_fast = "set win 4, set rec pack 2200";
#endif /* BIGBUFOK */
char *m_cautious = "set win 4, set rec pack 1000";
char *m_robust = "set win 1, set rec pack 90, set reliable off";
#endif /* CK_SPEED */
#ifdef VMS
char *m_purge = "run purge \\%*";
#endif /* VMS */
#ifdef OS2
char *m_manual = "browse \\v(exedir)docs/manual/kermit95.htm";
#endif /* OS2 */
/* Now the multiline macros, defined with addmmac()... */
/* FOR macro for \%i-style loop variables (see dofor()...) */
char *for_def[] = { "_assign _for\\v(cmdlevel) { _getargs,",
"def \\\\\\%1 \\feval(\\%2),:_..top,if \\%5 \\\\\\%1 \\%3 goto _..bot,",
"\\%6,:_..inc,incr \\\\\\%1 \\%4,goto _..top,:_..bot,_putargs},",
"def break goto _..bot, def continue goto _..inc,",
"do _for\\v(cmdlevel) \\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)",
""};
/* This is the FOR macro when the loop variable is itself a macro */
char *foz_def[] = { "_assign _for\\v(cmdlevel) { _getargs,",
"def \\%1 \\feval(\\%2),:_..top,if \\%5 \\%1 \\%3 goto _..bot,",
"\\%6,:_..inc,incr \\%1 \\%4,goto _..top,:_..bot,_putargs},",
"def break goto _..bot, def continue goto _..inc,",
"do _for\\v(cmdlevel) \\%1 \\%2 \\%3 \\%4 { \\%5 },_assign _for\\v(cmdlevel)",
""};
/* WHILE macro */
char *whil_def[] = { "_assign _whi\\v(cmdlevel) {_getargs,",
":_..inc,\\%1,\\%2,goto _..inc,:_..bot,_putargs},",
"_def break goto _..bot, _def continue goto _..inc,",
"do _whi\\v(cmdlevel),_assign _whi\\v(cmdlevel)",
""};
/* SWITCH macro */
char *sw_def[] = { "_assign _sw_\\v(cmdlevel) {_getargs,",
"_forward {\\%1},\\%2,:default,:_..bot,_putargs},_def break goto _..bot,",
"do _sw_\\v(cmdlevel),_assign _sw_\\v(cmdlevel)",
""};
/* XIF macro */
char *xif_def[] = {
"_assign _if\\v(cmdlevel) {_getargs,\\%1,_putargs},",
"do _if\\v(cmdlevel),_assign _if\\v(cmdlevel)",
""};
/*
Variables declared here for use by other ckuus*.c modules.
Space is allocated here to save room in ckuusr.c.
*/
#ifdef DCMDBUF
struct cmdptr *cmdstk;
int
*ifcmd = NULL,
*count = NULL,
*iftest = NULL,
*intime = NULL,
*inpcas = NULL,
*takerr = NULL,
*merror = NULL;
#else
struct cmdptr cmdstk[CMDSTKL];
int ifcmd[CMDSTKL], count[CMDSTKL], iftest[CMDSTKL], intime[CMDSTKL],
inpcas[CMDSTKL], takerr[CMDSTKL], merror[CMDSTKL];
#endif /* DCMDBUF */
/* Macro stack */
#ifdef COMMENT
char *topline = NULL; /* Program invocation arg line */
char *m_line[MACLEVEL] = { NULL, NULL }; /* Stack of macro invocation lines */
#endif /* COMMENT */
char **m_xarg[MACLEVEL]; /* Pointers to arg vector arrays */
int n_xarg[MACLEVEL]; /* Sizes of arg vector arrays */
char *m_arg[MACLEVEL][NARGS]; /* Args of each level */
int macargc[MACLEVEL]; /* Argc of each level */
char *macp[MACLEVEL]; /* Current position in each macro */
char *macx[MACLEVEL]; /* Beginning of each macro def */
char *mrval[MACLEVEL]; /* RETURN value at each level */
int lastcmd[MACLEVEL]; /* Last command at each level */
int topargc = 0; /* Argc at top level */
char **topxarg = NULL; /* Argv at top level */
char *toparg[MAXARGLIST+2];
/* Global Variables */
char *g_var[GVARS+1]; /* Global \%a..z pointers */
extern char varnam[]; /* \%x variable name buffer */
/* Arrays -- Dimension must be 'z' - ARRAYBASE + 1 */
/* Note: a_link[x] < 0 means no link; >= 0 is a link */
char **a_ptr[32]; /* Array pointers, for arrays a-z */
int a_dim[32]; /* Dimensions for each array */
int a_link[32]; /* Link (index of linked-to-array) */
char **aa_ptr[CMDSTKL][32]; /* Array stack for automatic arrays */
int aa_dim[CMDSTKL][32]; /* Dimensions for each array */
/* INPUT command buffers and variables */
char * inpbuf = NULL; /* Buffer for INPUT and REINPUT */
extern char * inpbp; /* Global/static pointer to it */
char inchar[2] = { NUL, NUL }; /* Last character that was INPUT */
int incount = 0; /* INPUT character count */
extern int instatus; /* INPUT status */
static char * i_text[] = { /* INPUT status text */
"success", "timeout", "interrupted", "internal error", "i/o error"
};
char lblbuf[LBLSIZ]; /* Buffer for labels */
#else /* NOSPL */
int takerr[MAXTAKE];
#endif /* NOSPL */
static char *prevdir = NULL;
int pacing = 0; /* OUTPUT pacing */
char *tp; /* Temporary buffer pointer */
int timelimit = 0, asktimer = 0; /* Timers for time-limited commands */
#ifdef CK_APC /* Application Program Command (APC) */
int apcactive = APC_INACTIVE;
int apcstatus = APC_OFF; /* OFF by default everywhere */
#ifdef DCMDBUF
char *apcbuf;
#else
char apcbuf[APCBUFLEN];
#endif /* DCMDBUF */
#endif /* CK_APC */
extern char pktfil[],
#ifdef DEBUG
debfil[],
#endif /* DEBUG */
#ifdef TLOG
trafil[],
#endif /* TLOG */
sesfil[];
#ifndef NOFRILLS
extern int rmailf, rprintf; /* REMOTE MAIL & PRINT items */
extern char optbuf[];
#endif /* NOFRILLS */
extern int noinit; /* Flat to skip init file */
#ifndef NOSPL
static struct keytab kcdtab[] = { /* Symbolic directory names */
#ifdef NT
{ "appdata", VN_APPDATA, 0 },
{ "common", VN_COMMON, 0 },
{ "desktop", VN_DESKTOP, 0 },
#endif /* NT */
{ "download", VN_DLDIR, 0 },
#ifdef OS2ORUNIX
{ "exedir", VN_EXEDIR, 0 },
#endif /* OS2ORUNIX */
{ "home", VN_HOME, 0 },
{ "inidir", VN_INI, 0 },
#ifdef UNIX
{ "lockdir", VN_LCKDIR, 0 },
#endif /* UNIX */
#ifdef NT
{ "personal", VN_PERSONAL, 0 },
#endif /* NT */
{ "startup", VN_STAR, 0 },
{ "textdir", VN_TXTDIR, 0 },
{ "tmpdir", VN_TEMP, 0 }
};
static int nkcdtab = (sizeof(kcdtab) / sizeof(struct keytab));
#endif /* NOSPL */
#ifndef NOSPL
_PROTOTYP( VOID freelocal, (int) );
_PROTOTYP( static long expon, (long, long) );
_PROTOTYP( static long gcd, (long, long) );
_PROTOTYP( static long fact, (long) );
int /* Initialize macro data structures. */
macini() { /* Allocate mactab and preset the first element. */
int i;
if (!(mactab = (struct mtab *) malloc(sizeof(struct mtab) * MAC_MAX)))
return(-1);
mactab[0].kwd = NULL;
mactab[0].mval = NULL;
mactab[0].flgs = 0;
for (i = 0; i < MACLEVEL; i++)
localhead[i] = NULL;
return(0);
}
#endif /* NOSPL */
/* C M D S R C -- Returns current command source */
/* 0 = top level, 1 = file, 2 = macro, -1 = error (shouldn't happen) */
/*
As of 19 Aug 2000 this routine is obsolete. The scalar global variable
xcmdsrc can be checked instead to save the overhead of a function call.
*/
int
cmdsrc() {
#ifdef COMMENT
return(xcmdsrc);
#else
#ifndef NOSPL
if (cmdlvl == 0)
return(0);
else if (cmdstk[cmdlvl].src == CMD_MD)
return(2);
else if (cmdstk[cmdlvl].src == CMD_TF)
return(1);
else
return(-1);
#else
if (tlevel < 0)
return(0);
else
return(1);
#endif /* NOSPL */
#endif /* COMMENT */
}
/* C M D I N I -- Initialize the interactive command parser */
static int cmdinited = 0; /* Command parser initialized */
extern int cmdint; /* Interrupts are allowed */
#ifdef CK_AUTODL
int cmdadl = 1; /* Autodownload */
#else
int cmdadl = 0;
#endif /* CK_AUTODL */
char * k_info_dir = NULL; /* Where to find text files */
#ifdef UNIX
static char * txtdir[] = {
"/usr/local/doc/", /* Linux, SunOS, ... */
"/usr/share/lib/", /* HP-UX 10.xx... */
"/usr/share/doc/", /* Other possibilities... */
"/usr/local/lib/", /* NOTE: Each of these is tried */
"/usr/local/share/", /* as is, and also with a kermit */
"/usr/local/share/doc/", /* subdirectory. */
"/usr/local/share/lib/",
"/opt/kermit/", /* Solaris */
"/opt/kermit/doc/",
"/opt/",
"/usr/doc/",
"/doc/",
""
};
#endif /* UNIX */
/*
lookup() cache to speed up script execution.
This is a static cache. Items are stored in decreasing frequency of
reference based on statistics from a range of scripts. This gives
better performance than a dynamic cache, which would require a lot more
code and also would require system-dependent elements including system
calls (e.g. to get subsecond times for entry aging).
*/
#ifdef USE_LUCACHE /* Set in ckuusr.h */
#define LUCACHE 32 /* Change this to reduce cache size */
int lusize = 0;
char * lucmd[LUCACHE];
int luval[LUCACHE];
int luidx[LUCACHE];
struct keytab * lutab[LUCACHE];
#endif /* USE_LUCACHE */
static VOID
luinit() { /* Initialize lookup() cache */
int x, y;
#ifdef USE_LUCACHE
x = lookup(cmdtab,"if",ncmd,&y);
lucmd[lusize] = "if";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
if (++lusize > LUCACHE) return;
x = lookup(iftab,"not",nif,&y);
lucmd[lusize] = "not";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = iftab;
if (++lusize > LUCACHE) return;
x = lookup(vartab,"cmdlevel",nvars,&y);
lucmd[lusize] = "cmdlevel";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = vartab;
if (++lusize > LUCACHE) return;
x = lookup(cmdtab,"goto",ncmd,&y);
lucmd[lusize] = "goto";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
if (++lusize > LUCACHE) return;
x = lookup(iftab,">",nif,&y);
lucmd[lusize] = ">";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = iftab;
if (++lusize > LUCACHE) return;
x = lookup(cmdtab,"incr",ncmd,&y);
lucmd[lusize] = "incr";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
if (++lusize > LUCACHE) return;
x = lookup(cmdtab,"def",ncmd,&y);
lucmd[lusize] = "def";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
if (++lusize > LUCACHE) return;
x = lookup(cmdtab,"_assign",ncmd,&y);
lucmd[lusize] = "_assign";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
if (++lusize > LUCACHE) return;
x = lookup(cmdtab,"echo",ncmd,&y);
lucmd[lusize] = "echo";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
if (++lusize > LUCACHE) return;
x = lookup(fnctab,"eval",nfuncs,&y);
lucmd[lusize] = "eval";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = fnctab;
if (++lusize > LUCACHE) return;
x = lookup(fnctab,"lit",nfuncs,&y);
lucmd[lusize] = "lit";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = fnctab;
if (++lusize > LUCACHE) return;
x = lookup(cmdtab,"do",ncmd,&y);
lucmd[lusize] = "do";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
if (++lusize > LUCACHE) return;
x = lookup(cmdtab,"_getargs",ncmd,&y);
lucmd[lusize] = "_getargs";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
if (++lusize > LUCACHE) return;
x = lookup(iftab,"<",nif,&y);
lucmd[lusize] = "<";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = iftab;
if (++lusize > LUCACHE) return;
x = lookup(cmdtab,"_putargs",ncmd,&y);
lucmd[lusize] = "_putargs";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
if (++lusize > LUCACHE) return;
x = lookup(cmdtab,"asg",ncmd,&y);
lucmd[lusize] = "asg";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
if (++lusize > LUCACHE) return;
x = lookup(cmdtab,"else",ncmd,&y);
lucmd[lusize] = "else";
luval[lusize] = x;
luidx[lusize] = y;
lutab[lusize] = cmdtab;
#endif /* USE_LUCACHE */
}
VOID
cmdini() {
int i = 0, x = 0, y = 0, z = 0, skip = 0;
char * p;
#ifdef TTSPDLIST
long * ss = NULL;
extern int nspd;
extern struct keytab * spdtab;
#endif /* TTSPDLIST */
#ifndef NOSPL
/*
On stack to allow recursion!
*/
char vnambuf[VNAML]; /* Buffer for variable names */
#endif /* NOSPL */
if (cmdinited) /* Already initialized */
return; /* Don't do it again */
for (i = 0; i < CMDSTKL; i++) /* Prompt strings for each */
prstring[i] = NULL; /* command level */
#ifndef NOCSETS
p = getenv("K_CHARSET"); /* Set default file character set */
if (p) { /* from environment */
x = lookup(fcstab,p,nfilc,&y);
if (x > -1)
fcharset = x;
}
#endif /* NOCSETS */
p = getenv("K_INFO_DIRECTORY"); /* Find Kermit info directory */
if (p && *p && strlen(p) <= CKMAXPATH)
makestr(&k_info_dir,p);
if (!k_info_dir) {
p = getenv("K_INFO_DIR");
if (p && *p && strlen(p) <= CKMAXPATH)
makestr(&k_info_dir,p);
}
#ifdef UNIX
if (k_info_dir) { /* Look for Kermit docs directory */
if (zchki(k_info_dir) == -2) {
char xbuf[CKMAXPATH+32], *s = "";
if (ckrchar(k_info_dir) != '/')
s = "/";
ckmakmsg(xbuf,CKMAXPATH+32,k_info_dir,s,"ckubwr.txt",NULL);
if (zchki(xbuf) < 0)
makestr(&k_info_dir,NULL);
}
}
if (!k_info_dir) {
char xbuf[CKMAXPATH+32];
int i;
for (i = 0; *(txtdir[i]); i++) {
ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"ckubwr.txt",NULL,NULL);
if (zchki(xbuf) > 0) {
makestr(&k_info_dir,txtdir[i]);
debug(F110,"k_info_dir 1",k_info_dir,0);
break;
}
ckmakmsg(xbuf,CKMAXPATH+32,
txtdir[i],"kermit/","ckubwr.txt",NULL);
if (zchki(xbuf) > 0) {
ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"kermit/",NULL,NULL);
makestr(&k_info_dir,xbuf);
debug(F110,"k_info_dir 2",k_info_dir,0);
break;
}
ckmakmsg(xbuf,CKMAXPATH+32,
txtdir[i],"ckermit/","ckubwr.txt",NULL);
if (zchki(xbuf) > 0) {
ckmakmsg(xbuf,CKMAXPATH+32,txtdir[i],"ckermit/",NULL,NULL);
makestr(&k_info_dir,xbuf);
debug(F110,"k_info_dir 3",k_info_dir,0);
break;
}
}
if (k_info_dir) { /* Make sure it ends with "/" */
if (ckrchar(k_info_dir) != '/') {
char xbuf[CKMAXPATH+32];
ckmakmsg(xbuf,CKMAXPATH+32,k_info_dir,"/",NULL,NULL);
makestr(&k_info_dir,xbuf);
}
}
}
#else
#ifdef OS2
{
char xdir[CKMAXPATH+8], *s = "";
extern char startupdir[];
xdir[0] = NUL;
if (ckrchar(startupdir) != '/')
s = "/";
if (strlen(s) + strlen(startupdir) + 5 < CKMAXPATH + 8 )
ckmakmsg(xdir,CKMAXPATH+8,s,startupdir,"DOC/",NULL);
makestr(&k_info_dir,xdir);
}
#endif /* OS2 */
#endif /* UNIX */
#ifdef TTSPDLIST
if (!spdtab && (ss = ttspdlist())) { /* Get speed list if necessary */
int j, k, m = 0, n; /* Create sorted keyword table */
char buf[16];
char * p;
if ((spdtab =
(struct keytab *) malloc(sizeof(struct keytab) * ss[0]))) {
for (i = 1; i <= ss[0]; i++) { /* ss[0] = number of elements */
if (ss[i] < 1L) break; /* Shouldn't happen */
buf[0] = NUL; /* Make string */
sprintf(buf,"%ld",ss[i]); /* SAFE */
if (ss[i] == 8880L)
ckstrncpy(buf,"75/1200",sizeof(buf));
if (ss[i] == 134L)
ckstrncat(buf,".5",16);
n = strlen(buf);
if ((n > 0) && (p = (char *)malloc(n+1))) {
if (m > 0) { /* Have at least one in list */
for (j = 0; /* Find slot */
j < m && strcmp(buf,spdtab[j].kwd) > 0;
j++
)
;
if (j < m) { /* Must insert */
for (k = m-1; k >= j; k--) { /* Move others down */
spdtab[k+1].kwd = spdtab[k].kwd;
spdtab[k+1].flgs = spdtab[k].flgs;
spdtab[k+1].kwval = spdtab[k].kwval;
}
}
} else /* First one */
j = 0;
ckstrncpy(p,buf,n+1); /* Add new speed */
spdtab[j].kwd = p;
spdtab[j].flgs = 0;
spdtab[j].kwval = (int) ss[i] / 10;
m++; /* Count this one */
}
}
}
nspd = m;
}
#endif /* TTSPDLIST */
#ifndef NOSPL
/* Allocate INPUT command buffer */
if (!inpbuf) {
if (!(inpbuf = (char *) malloc(INPBUFSIZ+1)))
fatal("cmdini: no memory for INPUT buffer");
}
for (x = 0; x < INPBUFSIZ; x++) /* Initialize it */
inpbuf[x] = NUL;
inpbp = inpbuf; /* Initialize pointer */
inbufsize = INPBUFSIZ; /* and size. */
#endif /* NOSPL */
#ifdef DCMDBUF
if (cmsetup() < 0) fatal("Can't allocate command buffers!");
#ifndef NOSPL
/* Allocate command stack allowing command parser to call itself */
if (!(cmdstk = (struct cmdptr *) malloc(sizeof(struct cmdptr)*CMDSTKL)))
fatal("cmdini: no memory for cmdstk");
if (!(ifcmd = (int *) malloc(sizeof(int)*CMDSTKL)))
fatal("cmdini: no memory for ifcmd");
if (!(count = (int *) malloc(sizeof(int)*CMDSTKL)))
fatal("cmdini: no memory for count");
if (!(iftest = (int *) malloc(sizeof(int)*CMDSTKL)))
fatal("cmdini: no memory for iftest");
if (!(intime = (int *) malloc(sizeof(int)*CMDSTKL)))
fatal("cmdini: no memory for intime");
if (!(inpcas = (int *) malloc(sizeof(int)*CMDSTKL)))
fatal("cmdini: no memory for inpcas");
if (!(takerr = (int *) malloc(sizeof(int)*CMDSTKL)))
fatal("cmdini: no memory for takerr");
if (!(merror = (int *) malloc(sizeof(int)*CMDSTKL)))
fatal("cmdini: no memory for merror");
if (!(xquiet = (int *) malloc(sizeof(int)*CMDSTKL)))
fatal("cmdini: no memory for xquiet");
if (!kermrc)
if (!(kermrc = (char *) malloc(KERMRCL+1)))
fatal("cmdini: no memory for kermrc");
#ifdef CK_APC
/* Application Program Command buffer */
if (!(apcbuf = malloc(APCBUFLEN + 1)))
fatal("cmdini: no memory for apcbuf");
#endif /* CK_APC */
#endif /* NOSPL */
/* line[] and tmpbuf[] are the two string buffers used by the command parser */
if (!(line = malloc(LINBUFSIZ + 1)))
fatal("cmdini: no memory for line");
if (!(tmpbuf = malloc(LINBUFSIZ + 1)))
fatal("cmdini: no memory for tmpbuf");
#endif /* DCMDBUF */
#ifndef NOSPL
#ifdef CK_MINPUT
{ /* Initialize MINPUT pointers */
int i;
extern char *ms[];
for (i = 0; i < MINPMAX; i++)
ms[i] = NULL;
}
#endif /* CK_MINPUT */
if (macini() < 0) /* Allocate macro buffers */
fatal("Can't allocate macro buffers!");
ifcmd[0] = 0; /* Command-level related variables. */
iftest[0] = 0; /* Initialize variables at top level */
count[0] = 0; /* of stack... */
intime[0] = 0;
inpcas[0] = 0;
takerr[0] = 0;
merror[0] = 0;
xquiet[0] = quiet;
#endif /* NOSPL */
#ifndef NOSPL
cmdlvl = 0; /* Initialize the command stack */
xcmdsrc = CMD_KB;
cmdstk[cmdlvl].src = CMD_KB; /* Source is console */
cmdstk[cmdlvl].lvl = 0; /* Level is 0 */
cmdstk[cmdlvl].ccflgs = 0; /* No flags */
#endif /* NOSPL */
tlevel = -1; /* Take file level = keyboard */
for (i = 0; i < MAXTAKE; i++) /* Initialize command file names */
tfnam[i] = NULL;
cmsetp(ckprompt); /* Set up C-Kermit's prompt */
/* Can't set IKSD prompt here since */
/* we do not yet know if we are IKSD */
#ifndef NOSPL
initmac(); /* Initialize macro table */
/* Predefine built-in one-line macros */
addmac("ibm-linemode",m_ibm); /* IBM-LINEMODE */
addmac("fatal",m_fat); /* FATAL macro */
y = addmac("fast",m_fast); /* FAST macro */
addmac("cautious",m_cautious); /* CAUTIOUS macro */
addmac("robust",m_robust); /* ROBUST macro */
#ifdef OS2
addmac("manual",m_manual); /* MANUAL macro */
#endif /* OS2 */
#ifdef VMS
addmac("purge",m_purge); /* PURGE macro */
#endif /* VMS */
/*
Predefine built-in multiline macros; these are top-level commands
that are implemented internally as macros. NOTE: When adding a new
one of these, remember to update the END and RETURN commands to
account for it, or else END and RETURN from within it won't work right.
*/
x = addmmac("_forx",for_def); /* FOR macro */
if (x > -1) mactab[x].flgs = CM_INV;
x = addmmac("_forz",foz_def); /* Other FOR macro */
if (x > -1) mactab[x].flgs = CM_INV;
x = addmmac("_xif",xif_def); /* XIF macro */
if (x > -1) mactab[x].flgs = CM_INV;
x = addmmac("_while",whil_def); /* WHILE macro */
if (x > -1) mactab[x].flgs = CM_INV;
x = addmmac("_switx",sw_def); /* SWITCH macro */
if (x > -1) mactab[x].flgs = CM_INV;
/* Fill in command-line argument vector */
sprintf(vnambuf,"\\&@[%d]",xargs); /* SAFE */
if (inserver) { /* But hidden in IKSD */
y = -1;
xargs = 0;
} else
y = arraynam(vnambuf,&x,&z); /* goes in array \&@[] */
tmpbuf[0] = NUL;
if (y > -1) {
int j = -1;
int yy = 0;
dclarray((char)x,z); /* Declare the array */
#ifndef NOTAKEARGS
/* Macro argument vector */
sprintf(vnambuf,"\\&_[%d]",z); /* SAFE */
yy = arraynam(vnambuf,&x,&z); /* goes in array \&_[] */
if (yy > -1) /* Name is OK */
dclarray((char)x,z); /* Declare the array */
#endif /* NOTAKEARGS */
skip = 0;
for (i = 0; i < xargs; i++) { /* Fill the arrays */
sprintf(vnambuf,"\\&@[%d]",i); /* SAFE */
addmac(vnambuf,xargv[i]);
if (cfilef && i == 0)
continue;
#ifdef KERBANG
if (skip) {
j = 0;
skip = 0;
continue;
}
#endif /* KERBANG */
if (j < 0 && /* Assign items after "=" or "--"*/
(!strcmp(xargv[i],"=") || !strcmp(xargv[i],"--"))
) {
j = 0; /* to \%1..\%9 */
#ifdef KERBANG
} else if (j < 0 &&
(!strcmp(xargv[i],"+") ||
!strncmp(xargv[i],"+ ",2) ||
!strncmp(xargv[i],"+\t",2))
) {
skip = 1;
continue;
#endif /* KERBANG */
} else if (j > -1) {
j++;
if (j <= 9) {
vnambuf[0] = '\\';
vnambuf[1] = '%';
vnambuf[2] = (char)(j+'0');
vnambuf[3] = NUL;
addmac(vnambuf,xargv[i]);
}
if (yy > -1) {
char c, * p;
int flag = 0;
p = xargv[i];
makestr(&(toparg[j]),p);
while ((c = *p++)) { if (c == SP) { flag++; break; } }
if (flag)
ckstrncat(tmpbuf,"\"",TMPBUFSIZ);
ckstrncat(tmpbuf,xargv[i],TMPBUFSIZ);
if (flag)
ckstrncat(tmpbuf,"\"",TMPBUFSIZ);
ckstrncat(tmpbuf," ",TMPBUFSIZ);
}
}
}
if (cfilef) {
addmac("\\%0",cmdfil);
if (yy > -1)
makestr(&(toparg[0]),cmdfil);
} else {
addmac("\\%0",xargv[0]);
if (yy > -1)
makestr(&(toparg[0]),xargv[0]);
}
if (yy > -1) {
topargc = (j < 0) ? 1 : j + 1;
topxarg = toparg;
#ifdef COMMENT
/* This needs work */
if (!cfilef)
makestr(&topline,tmpbuf);
#endif /* COMMENT */
} else {
topargc = 0;
topxarg = NULL;
}
a_dim[0] = topargc - 1;
a_ptr[0] = topxarg;
debug(F111,"a_dim[0]","A",a_dim[0]);
}
*vnambuf = NUL;
#endif /* NOSPL */
luinit(); /* Initialize lookup() cache */
/* Get our home directory now. This needed in lots of places. */
cmdinited = 1;
}
#ifdef NT
_PROTOTYP(char * GetAppData,(int));
#endif /* NT */
VOID
doinit() {
#ifdef CKROOT
extern int ckrooterr;
#endif /* CKROOT */
int x = 0, ok = 0;
#ifdef OS2
char * ptr = 0;
#endif /* OS2 */
if (!cmdinited)
cmdini();
#ifdef MAC
return; /* Mac Kermit has no init file */
#else /* !MAC */
/* If skipping init file ('-Y' on Kermit command line), return now. */
if (noinit) {
kermrc[0] = '\0';
inidir[0] = '\0';
/*
But returning from here results in inidir[] never being set to anything.
Instead it should be set to wherever the init file *would* have been
executed from. So this bit of code should be removed, and then we should
sprinkle "if (noinit)" tests throughout the following code until we have
set inidir[], and then return without actually taking the init file.
*/
return;
}
#ifdef OS2
/*
The -y init file must be fully specified or in the current directory.
KERMRC is looked for via INIT, DPATH and PATH in that order. Finally, our
own executable file path is taken and the .EXE suffix is replaced by .INI
and this is tried as the initialization file.
*/
#ifdef CK_LOGIN
debug(F101,"doinit inserver","",inserver);
debug(F101,"doinit isguest","",isguest);
debug(F110,"doinit anonfile",anonfile,0);
if (isguest && anonfile) {
ckstrncpy(line, anonfile, LINBUFSIZ+1);
} else
#endif /* CK_LOGIN */
if (rcflag) {
ckstrncpy(line,kermrc,LINBUFSIZ+1);
#ifdef CK_LOGIN
} else if (inserver) {
char * appdata = NULL;
#ifdef NT
appdata = GetAppData(1);
if ( appdata ) {
ckmakmsg(line,LINBUFSIZ+1,appdata,
"Kermit 95/k95.ini",NULL,NULL);
if ( zchki(line) < 0 )
line[0] = '\0';
}
if (line[0] == 0) {
appdata = GetAppData(0);
if ( appdata ) {
ckmakmsg(line,LINBUFSIZ+1,appdata,
"Kermit 95/k95.ini",NULL,NULL);
if ( zchki(line) < 0 )
line[0] = '\0';
}
}
#endif /* NT */
if (line[0] == 0) {
appdata = zhome();
if ( appdata ) {
ckmakmsg(line,LINBUFSIZ+1,appdata,
#ifdef NT
"k95.ini",
#else /* NT */
"k2.ini",
#endif /* NT */
NULL,NULL);
if ( zchki(line) < 0 )
line[0] = '\0';
}
}
debug(F110,"doinit inserver inifile",line,0);
#endif /* CK_LOGIN */
} else {
char * env = 0;
#ifdef NT
env = getenv("K95.KSC");
#else
env = getenv("K2.KSC");
#endif /* NT */
if (!env) {
#ifdef NT
env = getenv("K95.INI");
#else
env = getenv("K2.INI");
#endif /* NT */
}
if (!env)
env = getenv("CKERMIT.INI");
if (!env)
env = getenv("CKERMIT_INI");
line[0] = '\0';
debug(F110,"doinit env",env,0);
if (env)
ckstrncpy(line,env,LINBUFSIZ+1);
#ifdef NT
if (line[0] == 0) {
env = GetAppData(1);
if ( env ) {
ckmakmsg(line,LINBUFSIZ+1,env,"Kermit 95/k95.ini",NULL,NULL);
if ( zchki(line) < 0 )
line[0] = '\0';
}
}
if (line[0] == 0) {
env = GetAppData(0);
if ( env ) {
ckmakmsg(line,LINBUFSIZ+1,env,"Kermit 95/k95.ini",NULL,NULL);
if ( zchki(line) < 0 )
line[0] = '\0';
}
}
#endif /* NT */
if (line[0] == 0) {
env = zhome();
if ( env ) {
ckmakmsg(line,LINBUFSIZ+1,env,
#ifdef NT
"k95.ini",
#else /* NT */
"k2.ini",
#endif /* NT */
NULL,NULL);
if ( zchki(line) < 0 )
line[0] = '\0';
}
}
if (line[0] == 0)
_searchenv(kermrc,"INIT",line);
if (line[0] == 0)
_searchenv(kermrc,"DPATH",line);
if (line[0] == 0)
_searchenv(kermrc,"PATH",line);
if (line[0] == 0) {
char *pgmptr = GetLoadPath();
if (pgmptr && strlen(pgmptr) < LINBUFSIZ-8) {
lp = strrchr(pgmptr, '\\');
if (lp) {
strncpy(line, pgmptr, lp - pgmptr);
#ifdef NT
strcpy(line + (lp - pgmptr), "/k95.ini");
#else /* NT */
strcpy(line + (lp - pgmptr), "/k2.ini");
#endif /* NT */
} else {
lp = strrchr(pgmptr, '.');
if (lp) {
strncpy(line, pgmptr, lp - pgmptr);
strcpy(line + (lp - pgmptr), ".ini");
}
}
}
}
}
#ifdef CKROOT
if (!zinroot(line)) {
debug(F110,"doinit setroot violation",line,0);
return;
}
#endif /* CKROOT */
debug(F110,"doinit fopen()",line,0);
if ((tfile[0] = fopen(line,"r")) != NULL) {
ok = 1;
tlevel = 0;
tfline[tlevel] = 0;
if (tfnam[tlevel] = malloc(strlen(line)+1))
strcpy(tfnam[tlevel],line); /* safe */
#ifndef NOSPL
cmdlvl++;
xcmdsrc = CMD_TF;
cmdstk[cmdlvl].src = CMD_TF;
cmdstk[cmdlvl].lvl = tlevel;
cmdstk[cmdlvl].ccflgs = 0;
ifcmd[cmdlvl] = 0;
iftest[cmdlvl] = 0;
count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */
intime[cmdlvl] = intime[cmdlvl-1];
inpcas[cmdlvl] = inpcas[cmdlvl-1];
takerr[cmdlvl] = takerr[cmdlvl-1];
merror[cmdlvl] = merror[cmdlvl-1];
xquiet[cmdlvl] = quiet;
#endif /* NOSPL */
debug(F110,"doinit init file",line,0);
} else {
debug(F100,"doinit no init file","",0);
}
ckstrncpy(kermrc,line,KERMRCL);
for (ptr = kermrc; *ptr; ptr++) /* Convert backslashes to slashes */
if (*ptr == '\\')
*ptr = '/';
#else /* not OS2 */
lp = line;
lp[0] = '\0';
debug(F101,"doinit rcflag","",rcflag);
#ifdef GEMDOS
zkermini(line, rcflag, kermrc);
#else
#ifdef VMS
{
int x;
x = zkermini(line,LINBUFSIZ,kermrc);
debug(F111,"CUSTOM zkermini",line,x);
if (x == 0)
line[0] = NUL;
}
#else /* not VMS */
#ifdef CK_LOGIN
debug(F101,"doinit isguest","",isguest);
if (isguest)
ckstrncpy(lp, anonfile ? anonfile : kermrc, LINBUFSIZ);
else
#endif /* CK_LOGIN */
if (rcflag) { /* If init file name from cmd line */
ckstrncpy(lp,kermrc,LINBUFSIZ); /* use it, */
} else { /* otherwise... */
#ifdef CK_INI_A /* If we've a system-wide init file */
/* And it takes precedence over the user's... */
ckstrncpy(lp,CK_SYSINI,KERMRCL); /* Use it */
if (zchki(lp) < 0) { /* (if it exists...) */
#endif /* CK_INI_A */
char * homdir;
char * env = 0;
line[0] = NUL;
/* Add support for environment variable */
env = getenv("CKERMIT.INI");
if (!env)
env = getenv("CKERMIT_INI");
if (env)
ckstrncpy(lp,env,KERMRCL);
if (lp[0] == 0) {
homdir = zhome();
if (homdir) { /* Home directory for init file. */
ckstrncpy(lp,homdir,KERMRCL);
#ifdef STRATUS
ckstrncat(lp,">",KERMRCL);/* VOS dirsep */
#else
if (lp[0] == '/') ckstrncat(lp,"/",KERMRCL);
#endif /* STRATUS */
}
ckstrncat(lp,kermrc,KERMRCL);/* Append default file name */
}
#ifdef CK_INI_A
}
#endif /* CK_INI_A */
#ifdef CK_INI_B /* System-wide init defined? */
/* But user's ini file takes precedence */
if (zchki(lp) < 0) /* If user doesn't have her own, */
ckstrncpy(lp,CK_SYSINI,KERMRCL); /* use system-wide one. */
#endif /* CK_INI_B */
}
#endif /* VMS */
#endif /* GEMDOS */
#ifdef AMIGA
reqoff(); /* Disable requestors */
#endif /* AMIGA */
#ifdef USE_CUSTOM
/* If no init file was found, execute the customization file */
debug(F110,"CUSTOM 1",line,0);
if (!line[0] || zchki(line) < 0) {
int x;
#ifdef OS2
x = ckmakestr(line,LINBUFSIZ,GetAppData(1),"/","K95CUSTOM.INI",NULL);
debug(F111,"CUSTOM 2",line,x);
if (zchki(line) < 0) {
x = ckmakestr(line,LINBUFSIZ,GetAppData(0),"/","K95USER.INI",NULL);
debug(F111,"CUSTOM 3",line,x);
}
#else /* OS2 */
x = ckstrncpy(line,zhome(),LINBUFSIZ);
#ifndef VMS
/* VMS zhome() returns "SYS$LOGIN:" */
if (line[x-1] != DIRSEP) {
line[x++] = DIRSEP;
line[x] = NUL;
}
#endif /* VMS */
x = ckstrncat(line,MYCUSTOM,LINBUFSIZ);
debug(F111,"CUSTOM 4",line,x);
#endif /* OS2 */
}
debug(F110,"CUSTOM 5",line,0);
#endif /* USE_CUSTOM */
#ifdef CKROOT
if (!zinroot(line)) {
debug(F110,"doinit setroot violation",line,0);
return;
}
#endif /* CKROOT */
debug(F110,"doinit ini file is",line,0);
if ((tfile[0] = fopen(line,"r")) != NULL) { /* Try to open init file. */
ok = 1;
tlevel = 0;
tfline[tlevel] = 0;
if ((tfnam[tlevel] = malloc(strlen(line)+1)))
strcpy(tfnam[tlevel],line); /* safe */
ckstrncpy(kermrc,line,KERMRCL);
#ifndef NOSPL
cmdlvl++;
ifcmd[cmdlvl] = 0;
iftest[cmdlvl] = 0;
count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */
intime[cmdlvl] = intime[cmdlvl-1];
inpcas[cmdlvl] = inpcas[cmdlvl-1];
takerr[cmdlvl] = takerr[cmdlvl-1];
merror[cmdlvl] = merror[cmdlvl-1];
xquiet[cmdlvl] = quiet;
debug(F101,"doinit open ok","",cmdlvl);
xcmdsrc = CMD_TF;
cmdstk[cmdlvl].src = CMD_TF;
cmdstk[cmdlvl].lvl = tlevel;
cmdstk[cmdlvl].ccflgs = 0;
#endif /* NOSPL */
} else if (rcflag) {
/* Print an error message only if a specific file was asked for. */
printf("?%s - %s\n", ck_errstr(), line);
}
#ifdef datageneral
/* If CKERMIT.INI not found in home directory, look in searchlist */
if (/* homdir && */ (tlevel < 0)) {
ckstrncpy(lp,kermrc,LINBUFSIZ);
if ((tfile[0] = fopen(line,"r")) != NULL) {
ok = 1;
tlevel = 0;
tfline[tlevel] = 0;
if (tfnam[tlevel] = malloc(strlen(line)+1))
strcpy(tfnam[tlevel],line); /* safe */
#ifndef NOSPL
cmdlvl++;
xcmdsrc = CMD_TF;
cmdstk[cmdlvl].src = CMD_TF;
cmdstk[cmdlvl].lvl = tlevel;
cmdstk[cmdlvl].ccflgs = 0;
ifcmd[cmdlvl] = 0;
iftest[cmdlvl] = 0;
count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */
intime[cmdlvl] = intime[cmdlvl-1];
inpcas[cmdlvl] = inpcas[cmdlvl-1];
takerr[cmdlvl] = takerr[cmdlvl-1];
merror[cmdlvl] = merror[cmdlvl-1];
xquiet[cmdlvl] = quiet;
#endif /* NOSPL */
}
}
#endif /* datageneral */
#ifdef AMIGA /* Amiga... */
reqpop(); /* Restore requestors */
#endif /* AMIGA */
#endif /* OS2 */
#endif /* MAC */
/* Assign value to inidir */
if (!ok) {
inidir[0] = NUL;
} else {
ckstrncpy(inidir, kermrc, CCHMAXPATH);
x = strlen(inidir);
if (x > 0) {
int i;
for (i = x - 1; i > 0; i-- ) {
if (ISDIRSEP(inidir[i])) {
inidir[i+1] = NUL;
break;
}
}
}
#ifdef NT
GetShortPathName(inidir,inidir,CCHMAXPATH);
#endif /* NT */
}
}
VOID
doiksdinit() {
#ifdef CK_SSL
/* IKSD doesn't request client certs */
ssl_verify_flag = SSL_VERIFY_NONE;
#endif /* CK_SSL */
if (!cmdinited)
cmdini();
#ifdef IKSDCONF
#ifdef OS2
line[0] = '\0';
_searchenv(iksdconf,"INIT",line);
if (line[0] == 0)
_searchenv(iksdconf,"DPATH",line);
if (line[0] == 0)
_searchenv(iksdconf,"PATH",line);
if (line[0] == 0) {
char *pgmptr = GetLoadPath();
if (pgmptr && strlen(pgmptr) < LINBUFSIZ-8) {
lp = strrchr(pgmptr, '\\');
if (lp) {
strncpy(line, pgmptr, lp - pgmptr);
strcpy(line + (lp - pgmptr), "\\");
strcpy(line + (lp - pgmptr + 1), iksdconf);
} else {
lp = strrchr(pgmptr, '.');
if (lp) {
strncpy(line, pgmptr, lp - pgmptr);
strcpy(line + (lp - pgmptr), ".ksc");
}
}
}
}
debug(F110,"doiksdinit() line",line,0);
tfile[0] = fopen(line,"r");
#else /* OS2 */
tfile[0] = fopen(iksdconf,"r");
#endif /* OS2 */
if (tfile[0] != NULL) {
tlevel = 0;
tfline[tlevel] = 0;
#ifdef OS2
if (tfnam[tlevel] = malloc(strlen(line)+1))
strcpy(tfnam[tlevel],line);
#else /* OS2 */
if ((tfnam[tlevel] = malloc(strlen(iksdconf)+1)))
strcpy(tfnam[tlevel],iksdconf);
#endif /* OS2 */
#ifndef NOSPL
cmdlvl++;
xcmdsrc = CMD_TF;
cmdstk[cmdlvl].src = CMD_TF;
cmdstk[cmdlvl].lvl = tlevel;
cmdstk[cmdlvl].ccflgs = 0;
ifcmd[cmdlvl] = 0;
iftest[cmdlvl] = 0;
count[cmdlvl] = count[cmdlvl-1]; /* Inherit from previous level */
intime[cmdlvl] = intime[cmdlvl-1];
inpcas[cmdlvl] = inpcas[cmdlvl-1];
takerr[cmdlvl] = takerr[cmdlvl-1];
merror[cmdlvl] = merror[cmdlvl-1];
xquiet[cmdlvl] = quiet;
#endif /* NOSPL */
debug(F110,"doiksdinit file ok",tfnam[tlevel],0);
} else {
debug(F110,"doiksdinit open failed",tfnam[tlevel],0);
}
#endif /* IKSDCONF */
}
#ifndef NOSPL
/*
G E T N C M
Get next command from current macro definition. Command is copied
into string pointed to by argument s, max length n. Returns:
0 if a string was copied;
-1 if there was no string to copy.
*/
int
getncm(s,n) char *s; int n; {
int y = 0; /* Character counter */
int quote = 0;
int kp = 0; /* Brace up-down counter */
int pp = 0; /* Parenthesis up-down counter */
#ifndef NODQMACRO
int dq = 0; /* Doublequote counter */
#endif /* NODQMACRO */
char *s2; /* Copy of destination pointer */
s2 = s; /* Initialize string pointers */
*s = NUL; /* and destination buffer */
/* debug(F010,"getncm entry",macp[maclvl],0); */
for (y = 0; /* Loop for n bytes max */
macp[maclvl] && *macp[maclvl] && y < n;
y++, s++, macp[maclvl]++) {
*s = *macp[maclvl]; /* Get next char from macro def */
#ifndef COMMENT
/*
This is to allow quoting of parentheses, commas, etc, in function
arguments, but it breaks just about everything else. DON'T REMOVE THIS
COMMENT! (Otherwise you'll wind up adding the same code again and breaking
everything again.) <-- The preceding warning should be obsolete since the
statements below have been fixed, but in case of fire, remove the "n" from
the <#>ifndef above. NEW WARNING: code added 12 Apr 2002 to exempt the
opening brace in \{nnn} from being treated as a quoted brace.
*/
if (!quote && *s == CMDQ) {
quote = 1;
continue;
}
if (quote) {
int notquote = 0;
quote = 0;
if (*s == '{') { /* Check for \{nnn} (8.0.203) */
char c, * p;
p = macp[maclvl] + 1;
while ((c = *p++)) {
if (isdigit(c))
continue;
else if (c == '}') {
notquote++;
break;
} else {
break;
}
}
}
if (notquote == 0)
continue;
}
#endif /* COMMENT */
/*
Allow braces around macro definition to prevent commas from being turned to
end-of-lines and also treat any commas within parens as text so that
multiple-argument functions won't cause the command to break prematurely.
19 Oct 2001: Similar treatment was added for doublequotes, so
define foo { echo "one, two, three" }
would work as expected. This doesn't seem to have broken anything but
if something comes up later, rebuild with NODQMACRO defined.
*/
if (*s == '{') kp++; /* Count braces */
if (*s == '}' && kp > 0) kp--;
if (*s == '(') pp++; /* Count parentheses. */
if (*s == ')' && pp > 0) pp--;
#ifndef NODQMACRO
#ifndef COMMENT
/* Too many false positives */
/* No, not really -- this is indeed the best we can do */
/* Reverted to this method Sun May 11 18:43:45 2003 */
if (*s == '"') dq = 1 - dq; /* Account for doublequotes */
#else /* Fri Apr 4 13:21:29 2003 */
/* The code below breaks the SWITCH statement */
/* There is no way to make this work -- it would require */
/* building in all the knowledge of command parser. */
if (dblquo && (*s == '"')) { /* Have doublequote */
if (dq == 1) { /* Close quote only if... */
if ((*(macp[maclvl]+1) == SP) || /* followed by space or... */
(!*(macp[maclvl]+1)) || /* at end or ... */
/* Next char is command separator... */
/* Sun May 11 17:24:12 2003 */
(kp < 1 && pp < 1 && (*(macp[maclvl]+1) == ','))
)
dq = 0; /* Close the quote */
} else if (dq == 0) {
/* Open quote only if at beginning or preceded by space */
if (s > s2) {
if (*(s-1) == SP)
dq = 1;
} else if (s == s2) {
dq = 1;
}
}
}
#endif /* COMMENT */
#endif /* NODQMACRO */
if (*s == ',' && pp <= 0 && kp <= 0
#ifndef NODQMACRO
&& dq == 0
#endif /* NODQMACRO */
) {
macp[maclvl]++; /* Comma not in {} or () */
/* debug(F110,"next cmd",s,0); */
kp = pp = 0; /* so we have the next command */
break;
}
} /* Reached end. */
#ifdef COMMENT
/* DON'T DO THIS - IT BREAKS EVERYTHING */
*s = NUL;
#endif /* COMMENT */
if (*s2 == NUL) { /* If nothing was copied, */
/* debug(F100,"XXX getncm eom","",0); */
popclvl(); /* pop command level. */
return(-1);
} else { /* otherwise, tack CR onto end */
*s++ = CR;
*s = '\0';
/* debug(F110,"XXX getncm OK",s,0); */
if (mecho && pflag) /* If MACRO ECHO ON, echo the cmd */
printf("%s\n",s2);
}
return(0);
}
/* D O M A C -- Define and then execute a macro */
int
domac(name, def, flags) char *name, *def; int flags; {
int x, m;
#ifndef NOLOCAL
#ifdef OS2
extern int term_io;
int term_io_sav = term_io;
term_io = 0; /* Disable Terminal Emulator I/O */
#endif /* OS2 */
#endif /* NOLOCAL */
m = maclvl; /* Current macro stack level */
x = addmac(name, def); /* Define a new macro */
if (x > -1) { /* If successful, */
dodo(x,NULL,flags); /* start it (increments maclvl). */
while (maclvl > m) { /* Keep going till done with it, */
debug(F101,"domac loop maclvl 1","",maclvl);
sstate = (CHAR) parser(1); /* parsing & executing each command, */
debug(F101,"domac loop maclvl 2","",maclvl);
if (sstate) proto(); /* including protocol commands. */
}
debug(F101,"domac loop exit maclvl","",maclvl);
}
#ifndef NOLOCAL
#ifdef OS2
term_io = term_io_sav;
#endif /* OS2 */
#endif /* NOLOCAL */
return(success);
}
#endif /* NOSPL */
/*
G E T N C T
Get next command from TAKE (command) file.
Call with:
s Pointer to buffer to read into
n Length of buffer
f File descriptor of file to read from
flag 0 == keep line terminator on and allow continuation
1 == discard line terminator and don't allow continuation
Call with flag == 0 to read a command from a TAKE file;
Call with flag != 0 to read a line from a dialing or network directory.
In both cases, trailing comments and/or trailing whitespace is/are stripped.
If flag == 0, continued lines are combined into one line. A continued line
is one that ends in hypen, or any line in a "block", which starts with "{"
at the end of a line and ends with a matching "}" at the beginning of a
subsequent line; blocks may be nested.
Returns:
0 if a string was copied,
-1 on EOF,
-2 on malloc failure
-3 if line is not properly terminated
-4 if (possibly continued) line is too long.
*/
static int lpxlen = 0;
int
getnct(s,n,f,flag) char *s; int n; FILE *f; int flag; {
int i = 0, len = 0, buflen = 0;
char c = NUL, cc = NUL, ccl = NUL, ccx = NUL, *s2 = NULL;
char *lp = NULL, *lpx = NULL, *lp2 = NULL, *lp3 = NULL, *lastcomma = NULL;
char * prev = NULL;
int bc = 0; /* Block counter */
s2 = s; /* Remember original pointer */
prev = s2;
buflen = n; /* Remember original buffer length */
if (n < 0)
return(-2);
/* Allocate a line buffer only if we don't have one that's big enough */
debug(F111,"getnct",ckitoa(lpxlen),n);
if (lpx && (n > lpxlen)) { /* Have one already */
debug(F101,"getnct new buffer","",lpxlen);
free(lpx); /* But it's not big enough */
lpx = NULL; /* Free current one */
lpxlen = 0;
}
if (!lpx) { /* Get new one */
if (!(lpx = (char *) malloc(n))) {
debug(F101,"getnct malloc failure","",0);
printf("?Memory allocation failure [getnct]\n");
return(-2);
}
lpxlen = n;
}
lp2 = lpx;
#ifdef KLUDGE
/* NOTE: No longer used as of 14 Aug 2000 */
lp2++;
#endif /* KLUDGE */
while (1) { /* Loop to read lines from file */
debug(F101,"getnct while (1)","",n);
if (fgets(lp2,n,f) == NULL) { /* Read a line into lp2 */
debug(F110,"getnct EOF",s2,0); /* EOF */
free(lpx); /* Free temporary storage */
lpx = NULL;
*s = NUL; /* Make destination be empty */
return(-1); /* Return failure code */
}
#ifndef NODIAL
if (flag) /* Count this line */
dirline++;
else
#endif /* NODIAL */
tfline[tlevel]++;
len = strlen(lp2) - 1; /* Position of line terminator */
if (len == 0 && lp2[0] != '\n') { /* Last line in file has one char */
lp2[++len] = '\n'; /* that is not a newline */
lp2[len] = NUL;
}
debug(F010,"getnct",lp2,0);
if (len < 0)
len = 0;
if (techo && pflag) /* If TAKE ECHO ON, */
printf("%3d. %s", /* echo it this line. */
#ifndef NODIAL
flag ? dirline :
#endif /* NODIAL */
tfline[tlevel],
lp2
);
lp3 = lp2; /* Working pointer */
i = len; /* Get first nonwhitespace character */
while (i > 0 && (*lp3 == SP || *lp3 == HT)) {
i--;
lp3++;
}
if (i == 0 && bc > 0) /* Blank line in {...} block */
continue;
/* Isolate, remove, and check terminator */
c = lp2[len]; /* Value of line terminator */
/* debug(F101,"getnct terminator","",c); */
if (c < LF || c > CR) { /* It's not a terminator */
/* debug(F111,"getnct bad line",lp2,c); */
if (feof(f) && len > 0 && len < n) {
/* Kludge Alert... */
if (!quiet)
printf("WARNING: Last line of %s lacks terminator\n",
s2 == cmdbuf ? "command file" : "directory file");
c = lp2[++len] = '\n'; /* No big deal - supply one. */
} else { /* Something's wrong, fail. */
free(lpx);
lpx = NULL;
return(-3);
}
}
/* Trim trailing whitespace */
for (i = len - 1; i > -1 && lp2[i] <= SP; i--) /* Trim */
;
/* debug(F101,"getnct i","",i); */
lp2[i+1] = NUL; /* Terminate the string */
/* debug(F110,"getnct lp2",lp2,0); */
lp = lp2; /* Make a working pointer */
/* Remove trailing or full-line comment */
while ((cc = *lp)) {
if (cc == ';' || cc == '#') { /* Comment introducer? */
if (lp == lp2) { /* First char on line */
*lp = NUL;
break;
} else if (*(lp - 1) == SP || *(lp - 1) == HT) {
lp--;
*lp = NUL; /* Or preceded by whitespace */
break;
}
}
lp++;
}
if (lp > lp2)
lp--; /* Back up over the NUL */
/* Now trim any space that preceded the comment */
while ((*lp == SP || *lp == HT) && lp >= lp2) {
*lp = NUL;
if (lp <= lp2)
break;
lp--;
}
/* debug(F110,"getnct comment trimmed",lp2,0); */
len = strlen(lp2); /* Length after trimming */
if (n - len < 2) { /* Check remaining space */
debug(F111,"getnct command too long",s2,buflen);
printf("?Line too long, maximum length: %d.\n",buflen);
free(lpx);
return(-4);
}
ccl = (len > 0) ? lp2[len-1] : 0; /* Last character in line */
ccx = (len > 1) ? lp2[len-2] : 0; /* Penultimate char in line */
#ifdef COMMENT
/* Line containing only whitespace and ,- */
if ((len > 1) && (lp3 == lp2+len-2) && (ccl == '-') && (ccx == ','))
continue;
#endif /* COMMENT */
#ifdef KLUDGE
/*
If it is a command and it begins with a token (like ! or .) that is not
followed by a space, insert a space now; otherwise cmkey() can get mighty
confused.
*/
if (s == s2 && !flag) {
char *p = toktab;
while (*p) {
if (*p == *lp3 && *(p+1) != SP) {
debug(F110,"getnct token",p,0);
*lp3-- = SP;
*lp3 = *p;
if (lp3 < lp2) {
lp2--;
len++;
}
break;
} else
p++;
}
}
#endif /* KLUDGE */
lp = lp2;
while ((*s++ = *lp++)) /* Copy result to target buffer */
n--; /* accounting for length */
s--; /* Back up over the NUL */
/* Check whether this line is continued */
if (flag) /* No line continuation when flag=1 */
break; /* So break out of read-lines loop */
#ifdef COMMENT
debug(F000,"getnct first char","",*lp3);
debug(F000,"getnct last char","",ccl);
debug(F000,"getnct next-to-last char","",ccx);
#endif /* COMMENT */
if (bc > 0 && *lp3 == '}') { /* First char on line is '}' */
bc--; /* Decrement block counter */
}
if (bc == 0 && /* Line is continued if bc > 0 */
#ifdef COMMENT
/* Not supported as of C-Kermit 6.0 */
ccl != CMDQ && /* or line ends with CMDQ */
#endif /* COMMENT */
ccl != '-' && /* or line ends with dash */
ccl != '{') /* or line ends with opening brace */
break; /* None of those, we're done. */
if (ccl == '-' || ccl == '{') /* Continuation character */
if (ccx == CMDQ) /* But it's quoted */
break; /* so ignore it */
if (ccl == '{') { /* Last char on line is '{'? */
bc++; /* Count the block opener. */
} else if (ccl == '-') { /* Explicit continue? */
char c, * ss;
int state = 0, nn;
s--; /* Yes, back up over terminators */
n++; /* and over continuation character */
nn = n; /* Save current count */
ss = s; /* and pointer */
s--; /* Back up over dash */
n++;
while (state < 2 && s >= prev) { /* Check for "{,-" */
n++;
c = *s--;
if (c <= SP)
continue;
if (c != ',' && c != '{')
break;
switch (state) {
case 0: /* Looking for comma */
if (c == ',')
state = 1;
break;
case 1: /* Looking for left brace */
if (c == '{') {
state = 2;
s += 2;
*s = NUL;
bc++;
}
break;
}
}
if (state != 2) { s = ss; n = nn; }
*s = NUL;
} else { /* None of those but (bc > 0) */
lastcomma = s;
*s++ = ','; /* and insert a comma */
n--;
}
#ifdef COMMENT
debug(F101,"getnct bc","",bc);
debug(F100,"getnct continued","",0);
#endif /* COMMENT */
*s = NUL;
prev = s;
} /* read-lines while loop */
if (lastcomma)
*lastcomma = SP;
if (!flag) /* Tack line terminator back on */
*s++ = c;
*s++ = NUL; /* Terminate the string */
untab(s2); /* Done, convert tabs to spaces */
#ifdef DEBUG
if (!flag) {
debug(F010,"CMD(F)",s2,0);
}
#endif /* DEBUG */
free(lpx); /* Free temporary storage */
return(0); /* Return success */
}
VOID
shostack() { /* Dump the command stack */
int i;
char *p;
#ifndef NOSPL
for (i = cmdlvl; i > 0; i--) {
if (cmdstk[i].src == CMD_TF) {
p = tfnam[cmdstk[i].lvl];
if (zfnqfp(p,TMPBUFSIZ,tmpbuf))
p = tmpbuf;
printf(" %2d. File : %s (line %d)\n",
i,
p,
tfline[cmdstk[i].lvl]
);
} else if (cmdstk[i].src == CMD_MD) {
char * m;
m = m_arg[cmdstk[i].lvl][0]; /* Name of this macro */
if (i > 0) { /* Special handling for 2-level */
char *s; /* built-in macros... */
s = m_arg[cmdstk[i-1].lvl][0]; /* Name next level up */
if (s && cmdstk[i-1].src == CMD_MD) {
if (!strcmp(s,"_forx"))
m = "FOR";
else if (!strcmp(s,"_xif"))
m = "XIF";
else if (!strcmp(s,"_while"))
m = "WHILE";
else if (!strcmp(s,"_switx"))
m = "SWITCH";
}
}
printf(" %2d. Macro : %s\n",i,m);
} else if (cmdstk[i].src == CMD_KB) {
printf(" %2d. Prompt:\n",i);
} else {
printf(" %2d. ERROR : Command source unknown\n",i);
}
}
#else
for (i = tlevel; i > -1; i--) {
p = tfnam[i];
if (zfnqfp(p,TMPBUFSIZ,tmpbuf))
p = tmpbuf;
printf(" %2d. File : %s (line %d)\n",
i,
p,
tfline[i]
);
}
#endif /* NOSPL */
if (i == 0)
printf(" %2d. Prompt: (top level)\n",0);
}
/* P A R S E R -- Top-level interactive command parser. */
/*
Call with:
m = 0 for normal behavior: keep parsing and executing commands
until an action command is parsed, then return with a
Kermit start-state as the value of this function.
m = 1 to parse only one command, can also be used to call parser()
recursively.
m = 2 to read but do not execute one command.
In all cases, parser() returns:
0 if no Kermit protocol action required
> 0 with a Kermit protocol start-state.
< 0 upon error.
*/
int
parser(m) int m; {
int tfcode, xx, yy, zz; /* Workers */
int is_tn = 0;
int cdlost = 0;
#ifndef NOSPL
int inlevel; /* Level we were called at */
extern int askflag;
#endif /* NOSPL */
char *cbp; /* Command buffer pointer */
#ifdef MAC
extern char *lfiles; /* Fake extern cast */
#endif /* MAC */
extern int interrupted;
#ifndef NOXFER
extern int sndcmd, getcmd, fatalio, clearrq;
#endif /* NOXFER */
debok = 1; /* Undisable debugging */
#ifdef AMIGA
reqres(); /* Restore AmigaDOS requestors */
#endif /* AMIGA */
#ifdef OS2
if (cursor_save > -1) { /* Restore cursor if it was */
cursorena[VCMD] = cursor_save; /* turned off during file transfer */
cursor_save = -1;
}
#endif /* OS2 */
#ifdef IKSDB
if (ikdbopen) slotstate(what,"COMMAND PROMPT","",""); /* IKSD database */
#endif /* IKSDB */
is_tn = (local && network && IS_TELNET()) ||
(!local && sstelnet);
if (!xcmdsrc) /* If at top (interactive) level ... */
concb((char)escape); /* put console in 'cbreak' mode. */
#ifdef CK_TMPDIR
/* If we were cd'd temporarily to another device or directory ... */
if (f_tmpdir) {
int x;
x = zchdir((char *) savdir); /* ... restore previous directory */
f_tmpdir = 0; /* and remember we did it. */
debug(F111,"parser tmpdir restoring",savdir,x);
}
#endif /* CK_TMPDIR */
#ifndef NOSPL
inlevel = cmdlvl; /* Current macro level */
#ifdef DEBUG
if (deblog) {
debug(F101,"&parser entry maclvl","",maclvl);
debug(F101,"&parser entry inlevel","",inlevel);
debug(F101,"&parser entry tlevel","",tlevel);
debug(F101,"&parser entry cmdlvl","",cmdlvl);
debug(F101,"&parser entry m","",m);
}
#endif /* DEBUG */
#endif /* NOSPL */
#ifndef NOXFER
ftreset(); /* Reset global file settings */
#endif /* NOXFER */
/*
sstate becomes nonzero when a command has been parsed that requires some
action from the protocol module. Any non-protocol actions, such as local
directory listing or terminal emulation, are invoked directly from below.
*/
sstate = 0; /* Start with no start state. */
#ifndef NOXFER
#ifndef NOSPL
query = 0; /* QUERY not active */
#endif /* NOSPL */
#ifndef NOHINTS
if (!success) {
if (local && !network && carrier != CAR_OFF) {
int x; /* Serial connection */
x = ttgmdm(); /* with carrier checking */
if (x > -1) {
if (!(x & BM_DCD)) {
cdlost = 1;
fatalio = 1;
}
}
}
}
#ifdef DEBUG
if (deblog) {
debug(F101,"parser top what","",what);
debug(F101,"parser top interrupted","",interrupted);
debug(F101,"parser top cdlost","",cdlost);
debug(F101,"parser top sndcmd","",sndcmd);
debug(F101,"parser top getcmd","",getcmd);
}
#endif /* DEBUG */
if (cdlost && !interrupted && (sndcmd || getcmd)) {
printf("?Connection broken (carrier signal lost)\n");
}
if (sndcmd && !success && hints && !interrupted && !fatalio && !xcmdsrc) {
int x = 0, n = 0;
printf("\n*************************\n");
printf("SEND-class command failed.\n");
printf(" Packets sent: %d\n", spackets);
printf(" Retransmissions: %d\n",retrans);
printf(" Timeouts: %d\n", timeouts);
printf(" Damaged packets: %d\n", crunched);
if (epktrcvd) {
printf(" Transfer canceled by receiver.\n");
printf(" Receiver's message: \"%s\"\n",(char *)epktmsg);
n++;
} else {
if (epktmsg) if (*epktmsg) {
printf(" Fatal Kermit Protocol Error: %s\n",epktmsg);
n++;
}
}
if (local && !network && carrier != CAR_OFF) {
int xx; /* Serial connection */
xx = ttgmdm(); /* with carrier checking */
if (xx > -1) {
if (!(xx & BM_DCD))
cdlost = 1;
}
}
#ifdef UNIX
if (errno != 0)
#endif /* UNIX */
{
printf(" Most recent local OS error: \"%s\"\n",ck_errstr());
n++;
}
printf(
"\nHINTS... If the preceding error message%s not explain the failure:\n",
(n > 1) ? "s do" : " does"
);
#ifndef NOLOCAL
if (local) {
if (rpackets == 0) {
printf(" . Did you start a Kermit receiver on the far end?\n");
} else {
printf(
" . Try changing the remote Kermit's FLOW-CONTROL setting.\n");
if (!network && mdmtyp > 0)
if ((3 * crunched) > spackets)
printf(
" . Try placing a new call to get a cleaner connection.\n");
}
} else if (rpackets > 0) {
if (flow == FLO_NONE)
printf(" . Give me a SET FLOW XON/XOFF command and try again.\n");
else
printf(" . Give me a SET FLOW NONE command and try again.\n");
}
x++;
#endif /* NOLOCAL */
if ((3 * timeouts) > spackets)
printf(" . Adjust the timeout method (see HELP SET SEND).\n");
if ((3 * retrans) > spackets)
printf(" . Increase the retry limit (see HELP SET RETRY).\n");
#ifdef CK_SPEED
if (prefixing != PX_ALL && rpackets > 2) {
printf(" . Try it again with SET PREFIXING ALL.\n");
x++;
}
#endif /* CK_SPEED */
#ifdef STREAMING
if (streamed) {
printf(" . Try it again with SET STREAMING OFF.\n");
x++;
} else if (reliable) {
printf(" . Try it again with SET RELIABLE OFF.\n");
x++;
}
#endif /* STREAMING */
#ifdef CK_SPEED
if (clearrq > 0 && prefixing == PX_NON) {
printf(" . Try it again with SET CLEAR-CHANNEL OFF.\n");
x++;
}
#endif /* CK_SPEED */
if (!parity) {
printf(" . Try it again with SET PARITY SPACE.\n");
x++;
}
printf(" . %sive a ROBUST command and try again.\n",
(x > 0) ? "As a last resort, g" : "G"
);
printf("Also:\n");
printf(" . Be sure the source file has read permission.\n");
printf(" . Be sure the target directory has write permission.\n");
printf("(Use SET HINTS OFF to suppress hints.)\n");
printf("*************************\n\n");
}
debug(F101,"topcmd","",topcmd);
if (getcmd && !success && hints && !interrupted && !fatalio && !xcmdsrc) {
int x = 0;
extern int urpsiz, wslotr;
printf("\n*************************\n");
printf("RECEIVE- or GET-class command failed.\n");
printf(" Packets received: %d\n", rpackets);
printf(" Damaged packets: %d\n", crunched);
printf(" Timeouts: %d\n", timeouts);
if (rpackets > 0)
printf(" Packet length: %d\n", urpsiz);
if (epktrcvd) {
printf(" Transfer canceled by sender.\n");
printf(" Sender's message: \"%s\"\n",(char *)epktmsg);
}
#ifdef UNIX
if (errno != 0)
#endif /* UNIX */
printf(" Most recent local error: \"%s\"\n",ck_errstr());
printf(
"\nHINTS... If the preceding error message%s not explain the failure:\n",
epktrcvd ? "s do" : " does"
);
#ifndef NOLOCAL
if (local) {
if (topcmd == XXGET)
printf(" . Did you start a Kermit SERVER on the far end?\n");
if (rpackets == 0) {
if (topcmd != XXGET)
printf(" . Did you start a Kermit SENDer on the far end?\n");
} else {
printf(
" . Choose a different FLOW-CONTROL setting and try again.\n");
}
} else if (topcmd == XXGET)
printf(" . Is the other Kermit in (or does it have) SERVER mode?\n");
if (rpackets > 0 && urpsiz > 90)
printf(" . Try smaller packets (SET RECEIVE PACKET-LENGTH).\n");
if (rpackets > 0 && wslotr > 1 && !streamed)
printf(" . Try a smaller window size (SET WINDOW).\n");
if (!local && rpackets > 0) {
if (flow == FLO_NONE)
printf(" . Give me a SET FLOW XON/XOFF command and try again.\n");
else
printf(" . Give me a SET FLOW NONE command and try again.\n");
}
x++;
#endif /* NOLOCAL */
#ifdef STREAMING
if (streamed) {
printf(" . Try it again with SET STREAMING OFF.\n");
x++;
} else if (reliable && local) {
printf(" . Try it again with SET RELIABLE OFF.\n");
x++;
} else
#endif /* STREAMING */
if (!parity) {
printf(" . Try it again with SET PARITY SPACE.\n");
x++;
}
printf((x > 0) ?
" . As a last resort, give a ROBUST command and try again.\n" :
" . Give a ROBUST command and try again.\n"
);
printf("Also:\n");
printf(" . Be sure the target directory has write permission.\n");
printf(" . Try telling the %s to SET PREFIXING ALL.\n",
topcmd == XXGET ? "server" : "sender"
);
printf(" . Try giving a ROBUST command to the %s.\n",
topcmd == XXGET ? "server" : "sender"
);
printf("(Use SET HINTS OFF to suppress hints.)\n");
printf("*************************\n\n");
}
#endif /* NOHINTS */
getcmd = 0;
sndcmd = 0;
interrupted = 0;
#endif /* NOXFER */
while (sstate == 0) { /* Parse cmds until action requested */
debug(F100,"parse top","",0);
what = W_COMMAND; /* Now we're parsing commands. */
rcdactive = 0; /* REMOTE CD not active */
keepallchars = 0; /* MINPUT not active */
#ifdef OS2
if (apcactive == APC_INACTIVE)
WaitCommandModeSem(-1);
#endif /* OS2 */
#ifdef IKS_OPTION
if ((local &&
!xcmdsrc &&
is_tn &&
TELOPT_ME(TELOPT_KERMIT) &&
TELOPT_SB(TELOPT_KERMIT).kermit.me_start) ||
(!local &&
!cmdadl &&
TELOPT_ME(TELOPT_KERMIT) &&
TELOPT_SB(TELOPT_KERMIT).kermit.me_start)
) {
tn_siks(KERMIT_STOP);
}
#endif /* IKS_OPTION */
#ifndef NOXFER
if (autopath) {
fnrpath = PATH_AUTO;
autopath = 0;
}
remfile = 0; /* Clear these in case REMOTE */
remappd = 0; /* command was interrupted... */
rempipe = 0;
makestr(&snd_move,g_snd_move); /* Restore these */
makestr(&rcv_move,g_rcv_move);
makestr(&snd_rename,g_snd_rename);
makestr(&rcv_rename,g_rcv_rename);
#endif /* NOXFER */
xaskmore = saveask; /* Restore global more-prompting */
diractive = 0;
cdactive = 0;
#ifndef NOSPL
askflag = 0;
#endif /* NOSPL */
/* Take requested action if there was an error in the previous command */
setint();
debug(F101,"parser tlevel","",tlevel);
debug(F101,"parser cmd_rows","",cmd_rows);
#ifndef NOLOCAL
debug(F101,"parser wasclosed","",wasclosed);
if (wasclosed) { /* If connection was just closed */
#ifndef NOSPL
int k;
k = mlook(mactab,"on_close",nmac); /* Look up "on_close" */
if (k >= 0) { /* If found, */
/* printf("ON_CLOSE CMD LOOP\n"); */
dodo(k,ckitoa(whyclosed),0); /* Set it up */
}
#endif /* NOSPL */
whyclosed = WC_REMO;
wasclosed = 0;
}
#endif /* NOLOCAL */
#ifndef NOSPL
xxdot = 0; /* Clear this... */
debug(F101,"parser success","",success);
if (success == 0) {
if (cmdstk[cmdlvl].src == CMD_TF && takerr[cmdlvl]) {
printf("Command file terminated by error.\n");
popclvl();
if (cmdlvl == 0) return(0);
}
if (cmdstk[cmdlvl].src == CMD_MD && merror[cmdlvl]) {
printf("Command error: macro terminated.\n");
popclvl();
if (m && (cmdlvl < inlevel))
return((int) sstate);
}
}
nulcmd = (m == 2);
debug(F101,"parser nulcmd","",nulcmd);
#else
if (success == 0 && tlevel > -1 && takerr[tlevel]) {
printf("Command file terminated by error.\n");
popclvl();
cmini(ckxech); /* Clear the cmd buffer. */
if (tlevel < 0) /* Just popped out of cmd files? */
return(0); /* End of init file or whatever. */
}
#endif /* NOSPL */
#ifdef MAC
/* Check for TAKE initiated by menu. */
if ((tlevel == -1) && lfiles)
startlfile();
#endif /* MAC */
/* If in TAKE file, check for EOF */
#ifndef NOSPL
#ifdef MAC
if
#else
while
#endif /* MAC */
((cmdstk[cmdlvl].src == CMD_TF) /* If end of take file */
&& (tlevel > -1)
&& feof(tfile[tlevel])) {
popclvl(); /* pop command level */
cmini(ckxech); /* and clear the cmd buffer. */
if (cmdlvl == 0) { /* Just popped out of all cmd files? */
return(0); /* End of init file or whatever. */
}
}
#ifdef MAC
miniparser(1);
if (sstate == 'a') { /* if cmd-. cancel */
debug(F100, "parser: cancel take due to sstate", "", sstate);
sstate = '\0';
dostop();
return(0); /* End of init file or whatever. */
}
#endif /* MAC */
#else /* NOSPL */
if ((tlevel > -1) && feof(tfile[tlevel])) { /* If end of take */
popclvl(); /* Pop up one level. */
cmini(ckxech); /* and clear the cmd buffer. */
if (tlevel < 0) /* Just popped out of cmd files? */
return(0); /* End of init file or whatever. */
}
#endif /* NOSPL */
#ifndef NOSPL
debug(F101,"parser cmdlvl","",cmdlvl);
debug(F101,"parser cmdsrc","",cmdstk[cmdlvl].src);
if (cmdstk[cmdlvl].src == CMD_MD) { /* Executing a macro? */
debug(F100,"parser macro","",0);
maclvl = cmdstk[cmdlvl].lvl; /* Get current level */
debug(F101,"parser maclvl","",maclvl);
cbp = cmdbuf; /* Copy next cmd to command buffer. */
*cbp = NUL;
if (*savbuf) { /* In case then-part of 'if' command */
ckstrncpy(cbp,savbuf,CMDBL); /* was saved, restore it. */
*savbuf = '\0';
} else { /* Else get next cmd from macro def */
if (getncm(cbp,CMDBL) < 0) {
#ifdef DEBUG
if (deblog) {
debug(F101,"parser end of macro m","",m);
debug(F101,"parser end of macro cmdlvl","",cmdlvl);
debug(F101,"parser end of macro inlevel","",inlevel);
}
#endif /* DEBUG */
if (m && (cmdlvl < inlevel))
return((int) sstate);
else /* if (!m) */ continue;
}
}
debug(F010,"CMD(M)",cmdbuf,0);
} else if (cmdstk[cmdlvl].src == CMD_TF)
#else
if (tlevel > -1)
#endif /* NOSPL */
{
#ifndef NOSPL
debug(F111,"parser savbuf",savbuf,tlevel);
if (*savbuf) { /* In case THEN-part of IF command */
ckstrncpy(cmdbuf,savbuf,CMDBL); /* was saved, restore it. */
*savbuf = '\0';
} else
#endif /* NOSPL */
/* Get next line from TAKE file */
if ((tfcode = getnct(cmdbuf,CMDBL,tfile[tlevel],0)) < 0) {
debug(F111,"parser tfcode",tfile[tlevel],tfcode);
if (tfcode < -1) { /* Error */
printf("?Error in TAKE command file: %s\n",
(tfcode == -2) ? "Memory allocation failure" :
"Line too long or contains NUL characters"
);
dostop();
}
continue; /* -1 means EOF */
}
/* If interactive, get next command from user. */
} else { /* User types it in. */
if (pflag) prompt(xxstring);
cmini(ckxech);
}
/* Now we know where next command is coming from. Parse and execute it. */