home *** CD-ROM | disk | FTP | other *** search
- /** xprkermit.c
- *
- * $Log: xprkermit.c,v $
- * Revision 1.3 91/11/09 06:53:22 swalton
- * Added support for re-entrant library, by cloning the data segment on entrance
- * to the protocol. This is something of a trick which depends heavily on
- * the particular way Aztec C organizes small model segments, but it seems
- * to work fine.
- *
- *
- * These are the protocol transfer routines for a simple Kermit upload/dnload
- *
- * Version 0.9--by Marco Papa.
- *
- * Version 1.0--updated by Stephen Walton.
- * Added several more user selections to XPRotocolSetup():
- * bctr (block check type to request), limit (retry-limit), and
- * rtimo (timeout for me). "Real" C Kermit makes many of the
- * things declared as local to kermitproto.w user-settable,
- * such as the send packet size.
- * Also fixed several problems in kermitproto.w.
- *
- * Version 1.5--more features
- * Extensive changes.
- * (1) Created a SetupVars variable to hold setting-up information
- * in the XPR_IO structure. This will allow re-entrancy when and if
- * it comes. Right now, it mainly gives a way to set up defaults with
- * one assignment.
- * (2) Added the generic Kermit server functions FINISH, BYE, and CD.
- * (3) Added the ability to set options and execute the server functions
- * from a setup string (sent as IO->xpr_filename to XPRotocolSetup()).
- *
- * Version 1.6
- * Some changes to the chkint() code in kermitproto.w to allow better
- * file cancellations. In particular, -1 is returned if the user
- * does the maximum XPR abort.
- *
- * Bug fixed in malloc() in this module: it wasn't saving the correct
- * number of allocated characters.
- *
- * Version 1.61
- * More mucking with chkint(). Irrelevant to VLT at present.
- *
- * Version 1.62
- * "Final" version of interrupt code. Based on C Kermit, if chkint()
- * returns a negative number, I both put "User cancelled." on the
- * display and send it in an error packet to the other end.
- *
- * Version 1.63
- * gnchar() in kermitproto.w wasn't counting nulls! Fixed.
- *
- * This code is copyright 1990 by Stephen Walton and Marco Papa. It may
- * be freely distributed in its original or in modified form, provided
- * this copyright notice is kept intact. It may not be sold for profit,
- * but may be included as part of a commercial program provided that
- * said inclusion does not increase the cost of that program beyond a
- * modest handling fee.
- **/
-
- #ifndef _lint
- static char rcsid[] = "$Header: Work:src/xprkermit/RCS/xprkermit.c,v 1.3 91/11/09 06:53:22 swalton Exp Locker: swalton $";
- #endif
-
- #include <exec/memory.h>
- #include <functions.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- /*
- * xproto.h is the include file given in Appendix B. It is included
- * in xprkermit.h
- */
-
- #include "xprkermit.h"
- #include "kermitproto.h"
- #include "timer.h"
- #include "version.h"
-
- long (*xupdate) (), (*xswrite) (), (*xfopen) (), (*xfclose) (), (*xfread) (),
- (*xsread) (), (*xchkabort) (), (*xfnext) (), (*xffirst) (), (*xsflush) (),
- (*xfwrite) (), (*xgets) (), (*xfinfo) (), (*xunlink)() ,
- (*xsquery) (), (*xchkmisc) ();
-
- extern CHAR start; /* The start state for the protocol. */
-
- /*
- * Forward declarations
- */
- static SetupVars *setup(struct XPR_IO *IO);
-
- /*
- * The flags for the kermitproto.w module.
- */
- char *p_pattern; /* wildcard pattern */
- int parity; /* parity on? 0 for no parity--need for
- * proper 8th-bit quote */
- int text; /* Text or binary mode? Flag 1 for text file,
- * 0 for binary file */
- int convert; /* Convert file names to lower case? 0 for
- * literal files (no), 1 for translate (yes) */
- int urpsiz; /* Kermit maximum packet size. Maximum
- * receive packet size user wants. */
- char *cmarg; /* Character string containing Kermit server
- * cmd */
-
- extern int bctr; /* Block check type to request. */
- extern int limit; /* Retry limit. May increase on very noisy
- * lines. */
- extern int rtimo; /* Timeout to request. */
- extern int keep; /* Keep incomplete files? */
-
- int getfile; /* Host server. 0 = Receive (no) ; 1 = Get
- * (yes) */
- long brkflag;
-
- static SetupVars Defaults = {
- 0L, /* Data segment--to be filled in later */
- {""}, /* No default file name. */
- 0, /* Parity defaults to off. */
- 1, /* Text file defaults to on. */
- 1, /* Convert file names by default. */
- 94, /* Default maximum packet length. */
- 1, /* Default block check type. */
- 5, /* Retry limit */
- 10, /* Timeout (seconds) */
- 0, /* Don't keep incomplete files */
- 0, /* Host is server? No by default. */
- };
-
- /*
- * Local prototypes.
- */
- static KermitCd(struct XPR_IO *IO, char *dir);
- static KermitFinish(struct XPR_IO *IO);
- static KermitBye(struct XPR_IO *IO);
- static DoGeneric(struct XPR_IO *IO, char *s);
-
-
- /**
- *
- * Send a file
- *
- **/
- long
- XProtocolSend(IO)
- struct XPR_IO *IO;
- {
- struct XPR_UPDATE xpru;
- SetupVars *sv;
-
- if ((sv = setup(IO)) == NULL)
- return 0L; /* Initialize parameters. */
-
- brkflag = 0;
-
- /*
- * Read the text/binary set using xpr_finfo if present. Else use the
- * value chosen in XPRotocolSetup.
- */
- if (xfinfo) {
- /*
- * Use feature that calling xpr_finfo with a zero-length filename
- * returns setting of internal comm program Text/Binary flag.
- */
- text = (callad(xfinfo, IO->xpr_filename, 2L) == 1 ? 0 : 1);
- }
- /*
- * Start the transfer. See 3.8 for a discussion on how to implement
- * xupdate.
- */
- tchar('#');
-
- /*
- * Copy filename, and put pointer in external Kermit variable.
- */
- strcpy(sv->FileName, IO->xpr_filename);
- p_pattern = sv->FileName;
- /*
- * */
- start = 's';
- proto();
-
- /*
- * If we got here through chkabort() say Aborted.
- */
- xpru.xpru_updatemask = XPRU_MSG;
- if (brkflag)
- xpru.xpru_msg = "Aborted";
- else
- xpru.xpru_msg = "Done";
- (void) calla(xupdate, &xpru);
- if (brkflag)
- return (0L);
- else
- return (1L);
- }
-
-
- /**
- *
- * Receive a file.
- *
- **/
- long
- XProtocolReceive(IO)
- struct XPR_IO *IO;
- {
- struct XPR_UPDATE xpru;
- long status;
- SetupVars *sv;
-
- if ((sv = setup(IO)) == NULL)
- return 0L; /* Initialize parameters. */
-
- brkflag = 0;
-
- /*
- * Read the text/binary set using xpr_finfo if present. Else use the
- * value chosen in XPRotocolSetup.
- */
- if (xfinfo) {
- /*
- * Use feature th at calling xpr_finfo with a zero-length filename
- * returns setting of internal comm program Text/Binary flag.
- */
- text = (callad(xfinfo, "", 2L) == 1 ? 0 : 1);
- }
- /*
- * Start the transfer. See 3.8 for a discussion on how to implement
- * xupdate.
- */
- tchar('#');
-
- if (getfile) {
- /*
- * Copy filename, and put pointer in external Kermit variable.
- */
- cmarg = sv->FileName;
- start = 'r';
- status = callaa(xgets, "Host Filename", cmarg);
- if (!status)
- return (0L);
- } else
- start = 'v';
- proto();
-
- /*
- * If we got here through chkabort() say Aborted.
- */
- xpru.xpru_updatemask = XPRU_MSG;
- if (brkflag)
- xpru.xpru_msg = "Aborted";
- else
- xpru.xpru_msg = "Done";
- (void) calla(xupdate, &xpru);
- if (brkflag)
- return (0L);
- else
- return (1L);
- }
-
- /*
- * Perform a generic Kermit server command.
- */
- static
- DoGeneric(IO, s)
- struct XPR_IO *IO;
- char *s;
- {
- if (setup(IO) == NULL)
- return 0; /* Set up transfer characteristics. */
- brkflag = 0;
- start = 'g';
- cmarg = s;
- proto();
- if (brkflag)
- return (0);
- else
- return (1);
- }
-
- /*
- * Execute a Kermit FINISH command.
- */
- static
- KermitFinish(IO)
- struct XPR_IO *IO;
- {
- return (DoGeneric(IO, "F"));
- }
-
- /*
- * Execute a Kermit BYE command.
- */
- static
- KermitBye(IO)
- struct XPR_IO *IO;
- {
- return (DoGeneric(IO, "L"));
- }
-
- /*
- * Change directory on remote server. We need to return an error if the CD
- * fails on the remote end.
- */
- static
- KermitCd(IO, dir)
- struct XPR_IO *IO;
- char *dir;
- {
- char CdCommand[100];
- int retval;
-
- CdCommand[0] = 'C';
- CdCommand[1] = (char) tochar(strlen(dir));
- strcpy(CdCommand + 2, dir);
- retval = DoGeneric(IO, CdCommand);
- return retval;
- }
-
- /**
- *
- * Setup
- *
- * First, a general-purpose comparison for either of the two possible returns
- * indicating a Yes push on a Boolean gadget.
- **/
-
- #define XprBoolTrue(s) ((stricmp(s, "yes") == 0) || (stricmp(s, "on") == 0))
-
- /*
- * Then, a small set of code to initialize a string based on a value.
- */
-
- #define XprSet(value, string) ((value) ? \
- (void) strcpy(string, YesString) : \
- (void) strcpy(string, NoString)) \
-
- static char YesString[] = "yes";
- static char NoString[] = "no";
-
- /*
- * If Setup() succeeds, flag same. Also, we don't need a file requester
- * on receive.
- */
- #define SUCCESS (XPRS_SUCCESS | XPRS_NORECREQ)
-
- extern char _H1_org, _H1_end, _H2_org, _H2_end; /* Data segment pointers */
- static void NewDataSeg(void *);
-
- #pragma regcall(NewDataSeg(a0))
-
- static SetupVars *
- InitData(struct XPR_IO *IO) {
- SetupVars *sv;
-
- /*
- * Allocate memory for file name buffer and options if first call. Also
- * allocate user's data segment and point us at it.
- */
- if ((sv = IO->xpr_data) == NULL) {
- if ((sv = (SetupVars *) malloc(sizeof(SetupVars))) == NULL)
- return NULL;
- *sv = Defaults;
- if ((sv->DataSeg = malloc(&_H2_end - &_H1_org + 4)) == NULL) {
- free(sv);
- return NULL;
- }
- memcpy(sv->DataSeg, &_H1_org, &_H2_end - &_H1_org + 4);
- IO->xpr_data = sv;
- }
- NewDataSeg(sv->DataSeg);
- return(sv);
- }
-
- long
- XProtocolSetup(IO)
- struct XPR_IO *IO;
- {
- long (*xoptions) ();
- #define NOPTS 10
- struct xpr_option opt[NOPTS], *popt[NOPTS];
- #define MAXSTRING 6
- char ValueStrings[NOPTS][MAXSTRING];
- long status;
- int i, j;
- char buf[256];
- SetupVars *sv, tempvar;
-
- if ((sv = InitData(IO)) == NULL)
- return (XPRS_FAILURE);
-
- if ((xupdate = IO->xpr_update) == NULL)
- return (XPRS_FAILURE);
- if ((xgets = IO->xpr_gets) == NULL)
- return (XPRS_FAILURE);
-
- tempvar = *sv;
- /*
- * In order to use xpr_options, we must have all of the three conditions
- * which follow true. Otherwise, either IO->xpr_filename is non-NULL, in
- * which case we assume it contains a setup string, or there is no
- * xpr_options, in which case we use xpr_gets to retrieve a setup string.
- */
- if (IO->xpr_filename == NULL &&
- IO->xpr_extension >= 1 &&
- (xoptions = IO->xpr_options) != NULL) {
-
- /*
- * I use a counter, i, here, so that I can stick in more options
- * without needing to change a lot of numbers. I can also skip
- * options dynamically, as in Text below.
- */
- i = 0;
- /* Announce us. */
- opt[i].xpro_description = "Kermit Commands " VSTRING;
- opt[i].xpro_type = XPRO_HEADER;
- opt[i].xpro_value = NULL;
- opt[i].xpro_length = 0;
- i++;
- /*
- * First, do the Kermit server command items.
- */
- opt[i].xpro_description = "Kermit FINISH";
- opt[i].xpro_type = XPRO_COMMAND;
- opt[i].xpro_value = NULL;
- opt[i].xpro_length = 0;
- i++;
- opt[i].xpro_description = "Kermit BYE";
- opt[i].xpro_type = XPRO_COMMAND;
- opt[i].xpro_value = NULL;
- opt[i].xpro_length = 0;
- i++;
- opt[i].xpro_description = "Kermit CD";
- opt[i].xpro_type = XPRO_COMMPAR;
- buf[0] = '\0';
- opt[i].xpro_value = buf; /* Use buf to hold dir name. */
- opt[i].xpro_length = sizeof(buf) - 1;
- i++;
- opt[i].xpro_description = "Kermit Options";
- opt[i].xpro_type = XPRO_COMMAND;
- opt[i].xpro_value = NULL;
- opt[i].xpro_length = 0;
- i++;
- /* show requester after loading pointers */
- for (j = 0; j < i; j++)
- popt[j] = &opt[j];
- status = callda(xoptions, (long) i, popt);
- /* check returned value */
- if (status == -1L)
- return XPRS_FAILURE;
- /* Check returned value to see what we are to do. */
- i = 1;
- if (status & (1L << i))
- return (KermitFinish(IO) ? SUCCESS : XPRS_FAILURE);
- i++;
- if (status & (1L << i))
- return (KermitBye(IO) ? SUCCESS : XPRS_FAILURE);
- i++;
- if (status & (1L << i))
- return (KermitCd(IO, opt[i].xpro_value) ? SUCCESS : XPRS_FAILURE);
- /* If we get to this point, we are to set options. */
- i = 0; /* Start over. */
- opt[i].xpro_description = "Kermit Options " VSTRING;
- opt[i].xpro_type = XPRO_HEADER;
- opt[i].xpro_value = NULL;
- opt[i].xpro_length = 0;
- i++;
- /* Convert filename */
- opt[i].xpro_description = "Convert Filename";
- opt[i].xpro_type = XPRO_BOOLEAN;
- XprSet(tempvar.ConvertFlag, ValueStrings[i]);
- opt[i].xpro_value = ValueStrings[i];
- opt[i].xpro_length = MAXSTRING;
- i++;
- /* Partial file keep */
- opt[i].xpro_description = "Keep Incomplete";
- opt[i].xpro_type = XPRO_BOOLEAN;
- XprSet(tempvar.KeepFlag, ValueStrings[i]);
- opt[i].xpro_value = ValueStrings[i];
- opt[i].xpro_length = MAXSTRING;
- i++;
- /* host is server */
- opt[i].xpro_description = "Host Server";
- opt[i].xpro_type = XPRO_BOOLEAN;
- XprSet(tempvar.GetFlag, ValueStrings[i]);
- opt[i].xpro_value = ValueStrings[i];
- opt[i].xpro_length = MAXSTRING;
- i++;
- /*
- * file type -- only show this if xpr_finfo not present, or returns
- * error when we try to get the file type.
- */
- if ((xfinfo = IO->xpr_finfo) == NULL ||
- (tempvar.TextFlag = (int) (callad(xfinfo, "", 2L))) == 0) {
- tempvar.TextFlag = -1; /* Flag xfinfo failed. */
- opt[i].xpro_description = "Text File";
- opt[i].xpro_type = XPRO_BOOLEAN;
- XprSet(tempvar.TextFlag, ValueStrings[i]);
- opt[i].xpro_value = ValueStrings[i];
- opt[i].xpro_length = MAXSTRING;
- i++;
- } else
- /*
- * Switch to 0 for binary, 1 for text; xpr_finfo returns 1 for
- * binary, 2 for text.
- */
- tempvar.TextFlag -= 1;
- /* Packet size */
- opt[i].xpro_description = "Packet Size";
- opt[i].xpro_type = XPRO_LONG;
- (void) sprintf(ValueStrings[i], "%-d", tempvar.MaxPacket);
- opt[i].xpro_value = ValueStrings[i];
- opt[i].xpro_length = MAXSTRING;
- i++;
- /* Block Check type */
- opt[i].xpro_description = "Block Check (1, 2, 3)";
- opt[i].xpro_type = XPRO_LONG;
- (void) sprintf(ValueStrings[i], "%-d", tempvar.BlockCheckType);
- opt[i].xpro_value = ValueStrings[i];
- opt[i].xpro_length = MAXSTRING;
- i++;
- /* Retry Limit */
- opt[i].xpro_description = "Maximum Retries";
- opt[i].xpro_type = XPRO_LONG;
- (void) sprintf(ValueStrings[i], "%-d", tempvar.RetryLimit);
- opt[i].xpro_value = ValueStrings[i];
- opt[i].xpro_length = MAXSTRING;
- i++;
- /* Timeout */
- opt[i].xpro_description = "Timeout (seconds)";
- opt[i].xpro_type = XPRO_LONG;
- (void) sprintf(ValueStrings[i], "%-d", tempvar.Timeout);
- opt[i].xpro_value = ValueStrings[i];
- opt[i].xpro_length = MAXSTRING;
- i++;
- /* show requester after loading pointers */
- for (j = 0; j < i; j++)
- popt[j] = &opt[j];
- /* show requester */
- status = callda(xoptions, (long) i, popt);
- /* check returned value */
- if (status == -1L)
- return XPRS_FAILURE;
- i = 1; /* Skip header */
- if (status & (1L << i))
- tempvar.ConvertFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
- i++;
- if (status & (1L << i))
- tempvar.KeepFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
- i++;
- if (status & (1L << i))
- tempvar.GetFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
- i++;
- if (xfinfo == NULL || tempvar.TextFlag == -1) {
- if (status & (1L << i))
- tempvar.TextFlag = XprBoolTrue(opt[i].xpro_value) ? 1 : 0;
- i++;
- }
- if (status & (1L << i))
- tempvar.MaxPacket = atoi(opt[i].xpro_value);
- i++;
- if (status & (1L << i))
- tempvar.BlockCheckType = atoi(opt[i].xpro_value);
- i++;
- if (status & (1L << i))
- tempvar.RetryLimit = atoi(opt[i].xpro_value);
- i++;
- if (status & (1L << i))
- tempvar.Timeout = atoi(opt[i].xpro_value);
- } else {
- if (IO->xpr_filename != NULL)
- strcpy(buf, IO->xpr_filename); /* Save setup string */
- else { /* Prompt for command/options string */
- sprintf(buf, "OC%c,G%c,K%c,T%c,P%d,B%d,R%d,O%d",
- tempvar.ConvertFlag ? 'Y' : 'N',
- tempvar.GetFlag ? 'Y' : 'N', tempvar.KeepFlag ? 'Y' : 'N',
- tempvar.TextFlag ? 'Y' : 'N', tempvar.MaxPacket,
- tempvar.BlockCheckType, tempvar.RetryLimit, tempvar.Timeout);
- if (callaa(xgets, "Kermit Options", buf) == 0)
- return XPRS_FAILURE; /* Failed to set up? */
- }
- (void) strupr(buf);
- switch (buf[0]) {
- case 'F':
- return (KermitFinish(IO) ? SUCCESS : XPRS_FAILURE);
- case 'B':
- return (KermitBye(IO) ? SUCCESS : XPRS_FAILURE);
- case 'C':
- return (KermitCd(IO, buf + 1) ? SUCCESS : XPRS_FAILURE);
- case 'O':
- if (SetupFromString(IO, buf, &tempvar) == 0)
- return XPRS_FAILURE;
- break;
- case '\0':
- break;
- default:
- ioerr(IO, "Unrecognized XPR Kermit setup string");
- break;
- }
- }
- *sv = tempvar; /* Copy setups into safe place. */
- /*
- * Return success and inform caller that we don't need a requester for
- * receive.
- */
- return SUCCESS;
- }
-
- static char Delimiters[] = " \t\r\n,";
-
- int
- SetupFromString(IO, s, sv)
- struct XPR_IO *IO;
- char *s;
- SetupVars *sv;
- {
- char *p;
- char errbuf[50];
-
- if (*s != 'O')
- return 0; /* Options string must start with O. */
- s++; /* Skip leading O. */
- /*
- * Hunt for options with strtok. We allow whitespace and commas to
- * separate options.
- */
- for (p = strtok(s, Delimiters); p != NULL; p = strtok(NULL, Delimiters)) {
- switch (*p++) { /* Auto-increment to option */
- case 'C': /* Case conversion. */
- if (*p == 'Y' || *p == 'N')
- sv->ConvertFlag = (*p == 'Y');
- else
- ioerr(IO, "Illegal C option format (must be Y or N)");
- break;
- case 'G': /* Get files (Host server) */
- if (*p == 'Y' || *p == 'N')
- sv->GetFlag = (*p == 'Y');
- else
- ioerr(IO, "Illegal G option format (must be Y or N)");
- break;
- case 'K': /* Keep incomplete file */
- if (*p == 'Y' || *p == 'N')
- sv->KeepFlag = (*p == 'Y');
- else
- ioerr(IO, "Illegal K option format (must be Y or N)");
- break;
- case 'T': /* Text file */
- if (*p == 'Y' || *p == 'N')
- sv->TextFlag = (*p == 'Y');
- else
- ioerr(IO, "Illegal T option format (must be Y or N)");
- break;
- case 'P': /* Maximum packet length */
- sv->MaxPacket = atoi(p);
- break;
- case 'B': /* Block check type. */
- sv->BlockCheckType = atoi(p);
- break;
- case 'R': /* Retry limit */
- sv->RetryLimit = atoi(p);
- break;
- case 'O': /* Timeout */
- sv->Timeout = atoi(p);
- break;
- default:
- sprintf(errbuf, "Illegal XPR Kermit option: %c", p[-1]);
- ioerr(IO, errbuf);
- break;
- }
- }
- return 1;
- }
-
- /**
- *
- * Cleanup
- *
- **/
- long
- XProtocolCleanup(IO)
- struct XPR_IO *IO;
- {
- if (((SetupVars *)IO->xpr_data)->DataSeg)
- free(((SetupVars *)IO->xpr_data)->DataSeg);
- if (IO->xpr_data)
- free(IO->xpr_data);
- IO->xpr_data = NULL;
-
- return (1L);
- }
-
- int
- XPRParity(IO)
- struct XPR_IO *IO;
- {
- long (*xsetserial) ();
- long status;
-
- /* check out parity */
- if ((xsetserial = IO->xpr_setserial) != NULL) {
- status = calld(xsetserial, -1L);
- if (status & 0x00000001L)
- return 1;
- else
- return 0;
- } else
- return 0; /* Assume no parity if can't tell. */
- }
-
- void
- XPRLong(IO, i)
- struct XPR_IO *IO;
- long i;
- {
- struct XPR_UPDATE xpru;
- char locbuf[80];
-
- if ((xupdate = IO->xpr_update) == NULL)
- return;
- /* debug: show long value */
- xpru.xpru_updatemask = XPRU_MSG;
- sprintf(locbuf, "%lx", i);
- xpru.xpru_msg = &locbuf[0];
- (void) calla(xupdate, &xpru);
- }
-
- /*
- * Copy setup variables into the local copies. If there are none, then
- * simply copy the defaults.
- */
- static SetupVars *
- setup(IO)
- struct XPR_IO *IO;
- {
- register SetupVars *Current;
-
- if ((Current = InitData(IO)) == NULL)
- return NULL;
- /*
- * These are the call-backs we need. If any of them isn't provided, quit.
- * Could do some error reporting if at least xupdate is there.
- */
- if ((xupdate = IO->xpr_update) == NULL)
- return (0L);
- if ((xswrite = IO->xpr_swrite) == NULL)
- return (0L);
- if ((xfopen = IO->xpr_fopen) == NULL)
- return (0L);
- if ((xfclose = IO->xpr_fclose) == NULL)
- return (0L);
- if ((xfread = IO->xpr_fread) == NULL)
- return (0L);
- if ((xsread = IO->xpr_sread) == NULL)
- return (0L);
- if ((xchkabort = IO->xpr_chkabort) == NULL)
- return (0L);
- if ((xfnext = IO->xpr_fnext) == NULL)
- return (0L);
- if ((xffirst = IO->xpr_ffirst) == NULL)
- return (0L);
- if ((xsflush = IO->xpr_sflush) == NULL)
- return (0L);
- if ((xfwrite = IO->xpr_fwrite) == NULL)
- return (0L);
- if ((xgets = IO->xpr_gets) == NULL)
- return (0L);
- /*
- * Here are callbacks we can do without.
- */
- xchkmisc = IO->xpr_chkmisc;
- if (IO->xpr_extension >= 2)
- xunlink = IO->xpr_unlink;
- else
- xunlink = NULL;
- if (IO->xpr_extension >= 3)
- xsquery = IO->xpr_squery;
- else
- xsquery = NULL;
- xfinfo = IO->xpr_finfo;
-
- parity = Current->ParityFlag = XPRParity(IO);
- text = Current->TextFlag;
- convert = Current->ConvertFlag;
- urpsiz = Current->MaxPacket;
- bctr = Current->BlockCheckType;
- limit = Current->RetryLimit;
- rtimo = Current->Timeout;
- getfile = Current->GetFlag;
- keep = Current->KeepFlag;
- return Current;
- }
-
- /*
- * Set the current context's data segment (small model) to the value
- * in DataSeg. Uses (undocumented) feature of compiler which allows
- * access to variables by name between #asm ... #endasm if preceded
- * by double percent sign.
- */
- void
- NewDataSeg(void *DataSeg) {
- #ifndef _lint
-
- ;
- #asm
- movea.l %%DataSeg,a4
- add.l #32766,a4
- #endasm
-
- #endif
- }
-
- /*
- * Have the comm program display an error message for us, using a temporary
- * XPR_UPDATE structure; used to display errors before Vars gets allocated
- */
- void
- ioerr(IO, msg)
- struct XPR_IO *IO;
- char *msg;
- {
- struct XPR_UPDATE xpru;
-
- if ((xupdate = IO->xpr_update) != NULL) {
- xpru.xpru_updatemask = XPRU_ERRORMSG;
- xpru.xpru_errormsg = msg;
- (void) calla(xupdate, &xpru);
- }
- }
-
- /*
- * Simple, re-entrant versions of malloc() and free to replace the ones in
- * the Aztec C libraries. The only reason to use these instead of AllocMem()
- * is that these remember the size of the stuff allocated, and we don't
- * have to rewrite the system-independent Kermit code in terms of AllocMem().
- */
-
- void *malloc(size_t n)
- {
- long *p;
-
- if ((p = AllocMem((long)(n + sizeof(size_t)), MEMF_PUBLIC | MEMF_CLEAR)) == NULL)
- return NULL;
- p[0] = (long)(n + sizeof(size_t));
- return (&p[1]);
- }
-
- void free(void *p)
- {
- long *s = p;
-
- FreeMem(&s[-1], s[-1]);
- }
-
- /**
- *
- * The following functions setup the proper registers for the call-back
- * functions.
- *
- **/
-
- #ifndef _lint
-
- #asm
- public _callad
- _callad:
- movea.l 8(sp),a0 ; Second argument goes in a0
- move.l 12(sp),d0 ; Third argument goes in d0
- /*
- * Now this is a trick to avoid using another register.
- * Charlie taught me this...
- */
- move.l 4(sp),-(sp) ; First argument is function
- rts
-
- public _calladda
- _calladda:
- movea.l 8(sp),a0 ; Second argument goes in a0
- move.l 12(sp),d0 ; Third argument goes in d0
- move.l 16(sp),d1 ; Fourth argument goes in d1
- movea.l 20(sp),a1 ; Fifth argument goes in a1
- move.l 4(sp),-(sp) ; First argument is function
- rts
-
- public _calldaa
- _calldaa:
- move.l 8(sp),d0 ; Second argument goes in d0
- movea.l 12(sp),a0 ; Third argument goes in a0
- movea.l 16(sp),a1 ; Fourth argument goes in a1
- move.l 4(sp),-(sp) ; First argument is function
- rts
-
- public _calla
- _calla:
- movea.l 8(sp),a0 ; Second argument goes in a0
- move.l 4(sp),-(sp) ; First argument is function
- rts
-
- public _calld
- _calld:
- move.l 8(sp),d0 ; Second argument goes in d0
- move.l 4(sp),-(sp) ; First argument is function
- rts
-
- public _callaa
- _callaa:
- movea.l 8(sp),a0 ; Second argument goes in a0
- movea.l 12(sp),a1 ; Third argument goes in a1
- move.l 4(sp),-(sp) ; First argument is function
- rts
-
- public _callda
- _callda:
- move.l 8(sp),d0 ; Second argument goes in d0
- movea.l 12(sp),a0 ; Third argument goes in a0
- move.l 4(sp),-(sp) ; First argument is function
- rts
-
- public _calladd
- _calladd:
- movea.l 8(sp),a0 ; Second argument goes in a0
- move.l 12(sp),d0 ; Third argument goes in d0
- move.l 16(sp),d1 ; Fourth argument goes in d1
- move.l 4(sp),-(sp) ; First argument is function
- rts
-
- #endasm
- /*
- * Could have added any other functions needed for other call-backs.
- * Could have written a fancier single one... Could've...
- */
- #endif
-