home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / comm / xprzedza.lzh / Utils.c < prev    next >
C/C++ Source or Header  |  1992-11-30  |  40KB  |  1,260 lines

  1. /**********************************************************************
  2.  * Utils.c: Miscellaneous support routines for xprzmodem.library;
  3.  * Version 2.10, 12 February 1991, by Rick Huebner.
  4.  * Released to the Public Domain; do as you like with this code.
  5.  *
  6.  * Version 2.50, 15 November 1991, by William M. Perkins.  Added code
  7.  * to update_rate() function in utils.c to avoid the Guru # 80000005
  8.  * you would have gotten if you had decided to adjust the system clock
  9.  * back during an upload or download.
  10.  *
  11.  * Mysprintf() function to replace sprintf() and proto code to use 
  12.  * libinit.o and linent.o library code was supplied by Jim Cooper of SAS.
  13.  *
  14.  **********************************************************************
  15.  * Modified to support ZedZap/ZedZip fidonet protocol by
  16.  * Yves Konighofer and Russel McOrmond.
  17.  *
  18.  * Adapted to xprzmodem Version 2.52 by Andrea Cisternino
  19.  **********************************************************************/
  20.  
  21. #include <proto/all.h>
  22. #include <exec/types.h>
  23. #include <exec/memory.h>
  24. #include <ctype.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <dos.h>
  29. #include "xproto.h"
  30. #include "zmodem.h"
  31. #include "xprzmodem.h"
  32.  
  33. /* Transfer options to use if XProtocolSetup not called */
  34. struct SetupVars Default_Config =
  35. {
  36.    NULL, NULL, 0,
  37.   { "C" }, { "N" }, { "16" }, { "0" }, { "10" }, { "N" }, { "N" },
  38.   { "Y" }, { "N" }, { "Y" }, { "0"}, { "8192" }, { "Y" }, { "" }
  39. };
  40.  
  41. #ifdef DEBUGLOG
  42.    UBYTE DebugName[] = "T:XDebug.Log";
  43.    void *DebugLog = NULL;
  44. #endif
  45.  
  46. LONG KSIZE   = 8192;
  47. LONG USEZERO = TRUE;
  48. LONG NEWBAUD = 0;
  49.  
  50. struct DosLibrary *DOSBase;
  51. struct ExecBase *SysBase;
  52.  
  53. /**********************************************************
  54.  * void _UserLibInit(struct Library *libbase)
  55.  **********************************************************/
  56. void __saveds __asm _UserLibInit(register __a6 struct Library *libbase)
  57. {
  58.    SysBase = (*((struct ExecBase **) 4));
  59.    DOSBase = (struct DosLibrary *) OpenLibrary("dos.library", 0);
  60. }  /* End of void _UserLibInit() */
  61.  
  62. /**********************************************************
  63.  * void _UserLibCleanup(void)
  64.  **********************************************************/
  65. void __saveds _UserLibCleanup(void)
  66. {
  67.    CloseLibrary(DOSBase);
  68. }  /* End of void _UserLibCleanup() */
  69.  
  70. /**********************************************************
  71.  * long XProtocolSetup(struct XPR_IO *xio)
  72.  *
  73.  * Called by comm program to set transfer options
  74.  **********************************************************/
  75. long __saveds __asm XProtocolSetup(register __a0 struct XPR_IO *xio)
  76. {
  77.    struct SetupVars *sv, tempsv;
  78.    struct xpr_option *option_ptrs[15];
  79.    struct xpr_option *optr, xo_hdr, xo_t, xo_o, xo_b, xo_f, xo_e, xo_s,
  80.       xo_r, xo_a, xo_d, xo_k, xo_p, xo_m, xo_n, xo_c;
  81.    UBYTE buf [512], *p;
  82.    long i, len;
  83.  
  84.    /* Allocate memory for transfer options string */
  85.    if (! (sv = (void *) xio->xpr_data))
  86.    {
  87.       xio->xpr_data = AllocMem((long) sizeof(struct SetupVars), MEMF_CLEAR);
  88.       if (! (sv = (void *) xio->xpr_data))
  89.       {
  90.          ioerr(xio,"Not enough memory");
  91.          return XPRS_FAILURE;
  92.       }
  93.       /* Start out with default options; merge user changes into defaults */
  94.       *sv = Default_Config;
  95.    }
  96.  
  97.    /* If options string passed by comm prog, use it; else prompt user */
  98.    if (xio->xpr_filename) strcpy(buf, xio->xpr_filename);
  99.    else
  100.    {
  101.       /* If xpr_options() implemented by comm program, use it */
  102.       if (xio->xpr_extension >= 1 && xio->xpr_options)
  103.       {
  104.          /*
  105.           * Let user edit temp copy of options so we can ignore invalid
  106.           * entries.  Have to init all this crud the hard way 'cause it's
  107.           * got to be on the stack in order to maintain reentrancy
  108.           */
  109.          tempsv = *sv;
  110.          xo_hdr.xpro_description = "ZedZap options:";
  111.          xo_hdr.xpro_type = XPRO_HEADER;
  112.          xo_hdr.xpro_value = NULL;
  113.          xo_hdr.xpro_length = 0;
  114.          option_ptrs[0] = &xo_hdr;
  115.          xo_t.xpro_description = "Text mode (Y,N,?,C):";
  116.          xo_t.xpro_type = XPRO_STRING;
  117.          xo_t.xpro_value = tempsv.option_t;
  118.          xo_t.xpro_length = sizeof(tempsv.option_t);
  119.          option_ptrs[1] = &xo_t;
  120.          xo_o.xpro_description = "Overwrite mode (Y,N,R,S):";
  121.          xo_o.xpro_type = XPRO_STRING;
  122.          xo_o.xpro_value = tempsv.option_o;
  123.          xo_o.xpro_length = sizeof(tempsv.option_o);
  124.          option_ptrs[2] = &xo_o;
  125.          xo_b.xpro_description = "I/O buffer size (KB):";
  126.          xo_b.xpro_type = XPRO_LONG;
  127.          xo_b.xpro_value = tempsv.option_b;
  128.          xo_b.xpro_length = sizeof(tempsv.option_b);
  129.          option_ptrs[3] = &xo_b;
  130.          xo_f.xpro_description = "Frame size (bytes):";
  131.          xo_f.xpro_type = XPRO_LONG;
  132.          xo_f.xpro_value = tempsv.option_f;
  133.          xo_f.xpro_length = sizeof(tempsv.option_f);
  134.          option_ptrs[4] = &xo_f;
  135.          xo_e.xpro_description = "Error limit:";
  136.          xo_e.xpro_type = XPRO_LONG;
  137.          xo_e.xpro_value = tempsv.option_e;
  138.          xo_e.xpro_length = sizeof(tempsv.option_e);
  139.          option_ptrs[5] = &xo_e;
  140.          xo_a.xpro_description = "Auto-activate receiver:";
  141.          xo_a.xpro_type = XPRO_BOOLEAN;
  142.          xo_a.xpro_value = tempsv.option_a;
  143.          xo_a.xpro_length = sizeof(tempsv.option_a);
  144.          option_ptrs[6] = &xo_a;
  145.          xo_d.xpro_description = "Delete after sending:";
  146.          xo_d.xpro_type = XPRO_BOOLEAN;
  147.          xo_d.xpro_value = tempsv.option_d;
  148.          xo_d.xpro_length = sizeof(tempsv.option_d);
  149.          option_ptrs[7] = &xo_d;
  150.          xo_k.xpro_description = "Keep partial files:";
  151.          xo_k.xpro_type = XPRO_BOOLEAN;
  152.          xo_k.xpro_value = tempsv.option_k;
  153.          xo_k.xpro_length = sizeof(tempsv.option_k);
  154.          option_ptrs[8] = &xo_k;
  155.          xo_s.xpro_description = "Send full path:";
  156.          xo_s.xpro_type = XPRO_BOOLEAN;
  157.          xo_s.xpro_value = tempsv.option_s;
  158.          xo_s.xpro_length = sizeof(tempsv.option_s);
  159.          option_ptrs[9] = &xo_s;
  160.          xo_r.xpro_description = "Use received path:";
  161.          xo_r.xpro_type = XPRO_BOOLEAN;
  162.          xo_r.xpro_value = tempsv.option_r;
  163.          xo_r.xpro_length = sizeof(tempsv.option_r);
  164.          option_ptrs[10] = &xo_r;
  165.          xo_p.xpro_description = "Default receive path:";
  166.          xo_p.xpro_type = XPRO_STRING;
  167.          xo_p.xpro_value = tempsv.option_p;
  168.          xo_p.xpro_length = sizeof(tempsv.option_p);
  169.          option_ptrs[11] = &xo_p;
  170.          xo_c.xpro_description = "Connect BPS Rate:";
  171.          xo_c.xpro_type = XPRO_LONG;
  172.          xo_c.xpro_value = tempsv.option_c;
  173.          xo_c.xpro_length = sizeof(tempsv.option_c);
  174.          option_ptrs[12] = &xo_c;
  175.          xo_m.xpro_description = "Maximum Block Size:";
  176.          xo_m.xpro_type = XPRO_LONG;
  177.          xo_m.xpro_value = tempsv.option_m;
  178.          xo_m.xpro_length = sizeof(tempsv.option_m);
  179.          option_ptrs[13] = &xo_m;
  180.          xo_n.xpro_description = "Send If Files = 0:";
  181.          xo_n.xpro_type = XPRO_BOOLEAN;
  182.          xo_n.xpro_value = tempsv.option_n;
  183.          xo_n.xpro_length = sizeof(tempsv.option_n);
  184.          option_ptrs[14] = &xo_n;
  185.  
  186.          /* Convert Y/N used elsewhere into "yes"/"no" required by spec */
  187.          for (i = 6; i <= 10; ++i)
  188.          {
  189.             optr = option_ptrs[i];
  190.             strcpy(optr->xpro_value, (*optr->xpro_value == 'Y') ? "yes" : "no");
  191.          }
  192.          optr = option_ptrs[14];
  193.          strcpy(optr->xpro_value, (*optr->xpro_value == 'Y') ? "yes" : "no");
  194.  
  195.          (*xio->xpr_options)(15L, option_ptrs);
  196.  
  197.          /* Convert "yes"/"no" or "on"/"off" into Y/N */
  198.          for (i = 6; i <= 10; ++i)
  199.          {
  200.             optr = option_ptrs[i];
  201.             strcpy(optr->xpro_value, (! stricmp(optr->xpro_value, "yes")
  202.                         || ! stricmp(optr->xpro_value, "on")) ? "Y" : "N");
  203.          }
  204.  
  205.          /* Convert xpr_options() results into parseable options string */
  206.          mysprintf(buf, "T%s,O%s,B%s,F%s,E%s,A%s,D%s,K%s,S%s,R%s,C%s,N%s,M%s,P%s",
  207.             tempsv.option_t, tempsv.option_o, tempsv.option_b, tempsv.option_f,
  208.             tempsv.option_e, tempsv.option_a, tempsv.option_d, tempsv.option_k,
  209.             tempsv.option_s, tempsv.option_r, tempsv.option_c, tempsv.option_n,
  210.             tempsv.option_m, tempsv.option_p);
  211.          /* If xpr_options() not provided, try xpr_gets() instead */
  212.       }
  213.       else
  214.       {
  215.          /* Start buffer with current settings so user can see/edit them. */
  216.          mysprintf(buf, "T%s,O%s,B%s,F%s,E%s,A%s,D%s,K%s,S%s,R%s,C%s,N%s,M%s,P%s",
  217.                   sv->option_t, sv->option_o, sv->option_b, sv->option_f,
  218.                   sv->option_e, sv->option_a, sv->option_d, sv->option_k,
  219.                   sv->option_s, sv->option_r, sv->option_c, sv->option_n,
  220.                   sv->option_m, sv->option_p);
  221.          if (xio->xpr_gets) (*xio->xpr_gets)("ZedZap options:", buf);
  222.       }
  223.    }
  224.  
  225.    /* Upshift options string for easier parsing */
  226.    strupr(buf);
  227.  
  228.    /*
  229.     * Merge new T(ext) option into current settings if given
  230.     *  "TY" = Force Text mode on,
  231.     *  "TN" = Force Text mode off,
  232.     *  "T?" = Use other end's text mode suggestion (default to binary)
  233.     *  "TC" = Ask Comm program for file type
  234.     */
  235.    if (p = find_option(buf, 'T'))
  236.    {
  237.       if (*p == 'Y' || *p == 'N' || *p == '?' || *p == 'C') *sv->option_t = *p;
  238.       else  ioerr(xio, "Invalid T flag ignored; should be Y, N, ?, or C");
  239.    }
  240.  
  241.    /*
  242.     * Merge new O(verwrite) option into current settings if given
  243.     *  "OY" = Yes, delete old file and replace with new one,
  244.     *  "ON" = No, prevent overwrite by appending ".dup" to avoid name collision,
  245.     *  "OR" = Resume transfer at end of existing file,
  246.     *  "OS" = Skip file if it already exists; go on to next
  247.     */
  248.    if (p = find_option(buf, 'O'))
  249.    {
  250.       if (*p == 'R' && ! xio->xpr_finfo) ioerr(xio, "Can't Resume; xpr_finfo() not supported");
  251.       else if (*p == 'Y' || *p == 'N' || *p == 'R' || *p == 'S') *sv->option_o = *p;
  252.       else ioerr(xio, "Invalid O flag ignored; should be Y, N, R, or S");
  253.    }
  254.  
  255.    /*
  256.     * Merge new B(uffer) setting into current settings if given
  257.     * Size of file I/O buffer in kilobytes
  258.     */
  259.    if (p = find_option(buf, 'B'))
  260.    {
  261.       len = atol(p);
  262.       if (len < 1) len = 1;
  263.       mysprintf(sv->option_b, "%ld", len);
  264.    }
  265.  
  266.    /*
  267.     * Merge new F(ramelength) setting into other settings if given
  268.     * Number of bytes we're willing to send or receive between ACKs.
  269.     * 0 = unlimited; nonstop streaming data
  270.     */
  271.    if (p = find_option(buf, 'F'))
  272.    {
  273.       len = atol(p);
  274.       if (len < 0) len = 0;
  275.       if (len > 0 && len < MINBLOCK) len = MINBLOCK;
  276.       mysprintf(sv->option_f, "%ld", len);
  277.    }
  278.  
  279.    /*
  280.     * Merge new E(rror limit) setting into other settings if given
  281.     * Number of sequential errors which will cause an abort
  282.     */
  283.    if (p = find_option(buf, 'E'))
  284.    {
  285.       len = atol(p);
  286.       if (len < 1) len = 1;
  287.       if (len > 32767) len = 32767;
  288.       mysprintf(sv->option_e, "%ld", len);
  289.    }
  290.  
  291.    /*
  292.     * Merge new A(uto-activate) setting into other settings if given
  293.     *  "AY" = Automatically call XProtocolReceive() if ZRQINIT string received
  294.     *  "AN" = Don't look for ZRQINIT; user will explicitly activate receive
  295.     */
  296.    if (p = find_option(buf, 'A'))
  297.    {
  298.       if (*p == 'Y' || *p == 'N') *sv->option_a = *p;
  299.       else  ioerr(xio, "Invalid A flag ignored; should be Y or N");
  300.    }
  301.  
  302.    /*
  303.     * Merge new D(elete after sending) setting into other options
  304.     *  "DY" = Delete files after successfully sending them
  305.     *  "DN" = Don't delete files after sending
  306.     */
  307.    if (p = find_option(buf, 'D'))
  308.    {
  309.       if (*p == 'Y' && (xio->xpr_extension < 2 || ! xio->xpr_unlink))
  310.       {
  311.          ioerr(xio,"Can't use DY; xpr_unlink() not supported");
  312.       }
  313.       else  if (*p == 'Y' || *p == 'N') *sv->option_d = *p;
  314.       else  ioerr(xio, "Invalid D flag ignored; should be Y or N");
  315.    }
  316.  
  317.    /*
  318.     * Merge new K(eep partial files) setting into other options
  319.     *  "KY" = Keep partially-received file fragments to allow later resumption
  320.     *  "KN" = Delete partially-received file fragments
  321.     */
  322.    if (p = find_option(buf, 'K'))
  323.    {
  324.       if (*p == 'N' && (xio->xpr_extension < 2 || ! xio->xpr_unlink))
  325.       {
  326.          ioerr(xio, "Can't use KN; xpr_unlink() not supported");
  327.       }
  328.       else if (*p == 'Y' || *p == 'N') *sv->option_k = *p;
  329.       else ioerr(xio, "Invalid K flag ignored; should be Y or N");
  330.    }
  331.  
  332.    /*
  333.     * Merge new S(end full path) setting into other options
  334.     *  "SY" = Send full filename including directory path to receiver
  335.     *  "SN" = Send only simple filename portion, not including directory path
  336.     */
  337.    if (p = find_option(buf, 'S'))
  338.    {
  339.       if (*p == 'Y' || *p == 'N') *sv->option_s = *p;
  340.       else ioerr(xio, "Invalid S flag ignored; should be Y or N");
  341.    }
  342.  
  343.    /*
  344.     * Merge new R(eceive path) setting into other options
  345.     *  "RY" = Use full filename exactly as received; don't use P option path
  346.     *  "RN" = Ignore received directory path if any; use path from P option
  347.     */
  348.    if (p = find_option(buf, 'R'))
  349.    {
  350.       if (*p == 'Y' || *p == 'N') *sv->option_r = *p;
  351.       else ioerr(xio, "Invalid R flag ignored; should be Y or N");
  352.    }
  353.  
  354.    /*
  355.     * Modify BPS Rate If We Have The BPS Rate Locked
  356.     *  "Cnnnn" is the real baud rate. It will be used to calculate
  357.     *          the maximum packet size.
  358.     */
  359.    if (p = find_option(buf,'C'))
  360.    {
  361.       len = atol(p);
  362.       if ((len < 300)||(len > 58600)) len = 0;
  363.       NEWBAUD = len;
  364.       mysprintf(sv->option_c,"%ld",len);
  365.    }
  366.  
  367.    /*
  368.     * Can we send '0' files ?
  369.     *  "NY" = we can send a batch of '0' files
  370.     *  "NN" = we can't
  371.     */
  372.    if (p = find_option(buf,'N'))
  373.    {
  374.       if (*p == 'Y' || *p == 'N') *sv->option_n = *p;
  375.       else ioerr(xio,"Invalid N Flag Ignored; Should Be Y Or N");
  376.       if(sv->option_n[0] == 'Y') USEZERO = TRUE;
  377.       else USEZERO = FALSE;
  378.    }
  379.  
  380.    /*
  381.     * Maximum packet size. Must be <=8192
  382.     */
  383.    if (p = find_option(buf,'M'))
  384.    {
  385.       len = atol(p);
  386.       if (len < MINBLOCK) KSIZE = MINBLOCK;
  387.       if ((len >= MINBLOCK) && (len <= 8192)) KSIZE = len;
  388.       if (len > 8192) len = KSIZE;
  389.       mysprintf(sv->option_m,"%ld",len);
  390.    }
  391.  
  392.    /*
  393.     * Merge new P(ath) setting into other options
  394.     *  "Pdir" = Receive files into directory "dir" if RN selected
  395.     *  "dir" can by any valid existing directory, with or without trailing "/"
  396.     */
  397.    if (p = find_option(buf, 'P'))
  398.    {
  399.       strcpy(sv->option_p, p);
  400.       p = sv->option_p + strcspn(sv->option_p, " ,\t\r\n");
  401.       *p = '\0';
  402.    }
  403.  
  404.    return (*sv->option_a == 'Y') ? XPRS_SUCCESS | XPRS_NORECREQ | XPRS_HOSTMON
  405.                                  : XPRS_SUCCESS | XPRS_NORECREQ;
  406.  
  407. }  /* End of long XProtocolSetup() */
  408.  
  409. /**********************************************************
  410.  * long XProtocolCleanup(struct XPR_IO *xio)
  411.  *
  412.  * Called by comm program to give us a chance to clean
  413.  * up before program ends
  414.  **********************************************************/
  415. long __saveds __asm XProtocolCleanup(register __a0 struct XPR_IO *xio)
  416. {
  417.    /* Release option memory, if any */
  418.    if (xio->xpr_data)
  419.    {
  420.       FreeMem(xio->xpr_data, (long) sizeof(struct SetupVars));
  421.       xio->xpr_data = NULL;
  422.    }
  423.  
  424.    return XPRS_SUCCESS;
  425.  
  426. }  /* End of long XProtocolCleanup() */
  427.  
  428. /**********************************************************
  429.  * long XProtocolHostMon(struct XPR_IO *xio,
  430.  *      char *serbuff, long actual, long maxsize)
  431.  *
  432.  * Called by comm program upon our request (XPRS_HOSTMON)
  433.  * to let us monitor the incoming data stream for our
  434.  * receiver auto-activation string (ZRQINIT packet).
  435.  * We only ask for this to be called if option AY is set.
  436.  **********************************************************/
  437. long __saveds __asm XProtocolHostMon(
  438.    register __a0 struct XPR_IO *xio,
  439.    register __a1 char *serbuff,
  440.    register __d0 long actual,
  441.    register __d1 long maxsize)
  442. {
  443.    static UBYTE startrcv[] = { ZPAD, ZDLE, ZHEX, "00" };
  444.    struct SetupVars *sv;
  445.  
  446.    if (! (sv = (void *) xio->xpr_data))
  447.    {
  448.       return actual;    /* XProtocolSetup() never called?! */
  449.    }
  450.  
  451.    if (! sv->matchptr) sv->matchptr = startrcv;
  452.  
  453.    /*
  454.     * Scan through serbuff to see if we can match all bytes in the start
  455.     * string in sequence.
  456.     */
  457.    for (sv->bufpos = serbuff; sv->bufpos < serbuff + actual; ++sv->bufpos)
  458.    {
  459.       if (*sv->bufpos == *sv->matchptr)
  460.       {                    /* if data matches current position in match */
  461.          ++sv->matchptr;   /* string, increment match position */
  462.          if (! *sv->matchptr)
  463.          {                 /* if at end of match string, it all matched */
  464.             sv->buflen = actual - (sv->bufpos - serbuff);
  465.             XProtocolReceive(xio);
  466.             sv->matchptr = startrcv;
  467.             actual = 0;
  468.             break;
  469.          }
  470.       }
  471.       else if (sv->matchptr > startrcv)
  472.       {                    /* mismatch?  Reset to start of match string */
  473.          sv->matchptr = startrcv;
  474.          if (*sv->bufpos == *sv->matchptr) ++sv->matchptr;
  475.       }
  476.    }
  477.  
  478.    sv->bufpos = NULL;
  479.    return actual;
  480.  
  481. }  /* End of long XProtocolHostMon() */
  482.  
  483. /**********************************************************
  484.  * long XProtocolUserMon(struct XPR_IO *xio,
  485.  *      char *serbuff, long actual, long maxsize)
  486.  *
  487.  * Called by comm program to let us monitor user's inputs;
  488.  * we never ask for this to be called, but it's better to
  489.  * recover gracefully than guru the machine.
  490.  **********************************************************/
  491. long __saveds __asm XProtocolUserMon(
  492.    register __a0 struct XPR_IO *xio,
  493.    register __a1 char *serbuff,
  494.    register __d0 long actual,
  495.    register __d1 long maxsize)
  496. {
  497.    return actual;
  498. }
  499.  
  500. /**********************************************************
  501.  * struct Vars *setup(struct XPR_IO *io)
  502.  *
  503.  * Perform setup and initializations common to both Send
  504.  * and Receive routines
  505.  **********************************************************/
  506. struct Vars *setup(struct XPR_IO *io)
  507. {
  508.    static long bauds[] = { 110, 300, 1200, 2400, 4800, 9600, 19200, 31250,
  509.                            38400, 57600, 76800, 115200 };
  510.    struct SetupVars *sv;
  511.    struct Vars *v;
  512.    long origbuf, newstatus;
  513.  
  514. #ifdef DEBUGLOG
  515.    long i, *lng;
  516. #endif
  517.  
  518.    /* Make sure comm program supports the required call-back functions */
  519.    if (! io->xpr_update) return NULL;
  520.  
  521.    if (  ! io->xpr_fopen  || ! io->xpr_fclose || ! io->xpr_fread
  522.       || ! io->xpr_fwrite || ! io->xpr_fseek  || ! io->xpr_sread
  523.       || ! io->xpr_swrite)
  524.    {
  525.       ioerr(io, "Comm prog missing required function(s); see docs");
  526.       return NULL;
  527.    }
  528.  
  529.    /* Hook in default transfer options if XProtocolSetup wasn't called */
  530.    if (! (sv = (void *) io->xpr_data))
  531.    {
  532.       io->xpr_data = AllocMem((long) sizeof(struct SetupVars), MEMF_CLEAR);
  533.       if (! (sv = (void *) io->xpr_data))
  534.       {
  535.          ioerr(io, "Not enough memory");
  536.          return NULL;
  537.       }
  538.       *sv = Default_Config;
  539.    }
  540.  
  541.    /* Allocate memory for our unshared variables, to provide reentrancy */
  542.    if (! (v = AllocMem((long) sizeof(struct Vars), MEMF_CLEAR)))
  543.    {
  544. nomem:
  545.       ioerr(io, "Not enough memory");
  546.       return NULL;
  547.    }
  548.    v->Modemchar = v->Modembuf;
  549.  
  550.    /*
  551.     * Allocate memory for our file I/O buffer; if we can't get as much as
  552.     * requested, keep asking for less until we hit minimum before giving up
  553.     */
  554.    v->Filebufmax = origbuf = atol(sv->option_b) * 1024;
  555.    while (! (v->Filebuf = AllocMem(v->Filebufmax, 0L)))
  556.    {
  557.       if (v->Filebufmax > 1024) v->Filebufmax -= 1024;
  558.       else
  559.       {
  560.          FreeMem(v, (long) sizeof(struct Vars));
  561.          goto nomem;
  562.       }
  563.    }
  564.  
  565.    if((KSIZE * 2) > v->Filebufmax)
  566.    {
  567.       if(v->Filebufmax >=  1024) { KSIZE = 512 ;strcpy(sv->option_m,"512" ); }
  568.       if(v->Filebufmax >=  2048) { KSIZE = 1024;strcpy(sv->option_m,"1024"); }
  569.       if(v->Filebufmax >=  4096) { KSIZE = 2048;strcpy(sv->option_m,"2048"); }
  570.       if(v->Filebufmax >=  8192) { KSIZE = 4096;strcpy(sv->option_m,"4096"); }
  571.       if(v->Filebufmax >= 16384) { KSIZE = 8192;strcpy(sv->option_m,"8192"); }
  572.    }
  573.  
  574.    /* If framelength was intended to match buffer size, stay in sync */
  575.    v->Tframlen = atol(sv->option_f);
  576.    if (v->Tframlen && v->Tframlen == origbuf) v->Tframlen = v->Filebufmax;
  577.  
  578.    v->ErrorLimit = atol(sv->option_e);
  579.  
  580.    /* Copy caller's io struct into our Vars for easier passing */
  581.    v->io = *io;
  582.  
  583. #ifdef DEBUGLOG
  584.    if (! DebugLog) DebugLog = (*v->io.xpr_fopen)(DebugName, "w");
  585.    dlog(v, "XPR_IO struct:\n");
  586.    for (i = 0, lng = (long *) io; i < sizeof(struct XPR_IO) / 4; ++i)
  587.    {
  588.       mysprintf(v->Msgbuf, "  %08lx\n", *lng++);
  589.       dlog(v, v->Msgbuf);
  590.    }
  591. #endif
  592.  
  593.    /* Get baud rate; set serial port mode if necessary (and possible) */
  594.    if (v->io.xpr_setserial)
  595.    {
  596.       v->Oldstatus = (*v->io.xpr_setserial)(-1L);
  597.       if (v->Oldstatus != -1)
  598.       {
  599.          /*
  600.           * ZModem requires 8 data bits, no parity (full transparency),
  601.           *  leave other settings alone
  602.           */
  603.  
  604.          newstatus = v->Oldstatus & 0xFFFFE0BC;
  605.          /*
  606.           * newstatus |= on_flags; Here's where we'd turn bits on if we
  607.           * needed to
  608.           */
  609.          if (newstatus != v->Oldstatus) (*v->io.xpr_setserial)(newstatus);
  610.          v->Baud = bauds[(newstatus >> 16) & 0xFF];
  611.  
  612. #ifdef DEBUGLOG
  613.          mysprintf(v->Msgbuf,"Old serial status = %lx, new = %lx, baud = %ld\n",
  614.                    v->Oldstatus, newstatus, v->Baud);
  615.          dlog(v, v->Msgbuf);
  616. #endif
  617.       }
  618.       else  v->Baud = 2400;
  619.    }  /* End of "if (v->io.xpr_setserial)" */
  620.  
  621.    /* If no xpr_setserial(), muddle along with most likely guess */
  622.    else v->Baud = 2400;
  623.  
  624.    return v;
  625. }  /* End of struct Vars *setup() */
  626.  
  627. /**********************************************************
  628.  * void set_textmode(struct Vars *v)
  629.  *
  630.  * Set text/binary mode flags in accordance with T option
  631.  * setting
  632.  **********************************************************/
  633. void set_textmode(struct Vars *v)
  634. {
  635.    struct SetupVars *sv;
  636.    long i;
  637.  
  638.    sv = (void *) v->io.xpr_data;
  639.    switch(*sv->option_t)
  640.    {
  641.       case 'Y':  /* Force text mode on receive; suggest text mode on send */
  642. TY:
  643.          v->Rxascii = TRUE;
  644.          v->Rxbinary = FALSE;
  645.          v->Lzconv = ZCNL;
  646.          break;
  647.  
  648.       case 'N':  /* Force binary mode on receive; suggest binary mode on send */
  649. TN:
  650.          v->Rxascii = FALSE;
  651.          v->Rxbinary = TRUE;
  652.          v->Lzconv = ZCBIN;
  653.          break;
  654.  
  655.       case 'C':  /* Ask comm program for proper mode for this file */
  656.          if (v->io.xpr_finfo)
  657.          {
  658.             i = (*v->io.xpr_finfo)(v->Filename, 2L);
  659.             if (i == 1)    /* Comm program says use binary mode */
  660.                goto TN;
  661.             if (i == 2)    /* Comm program says use text mode */
  662.                goto TY;
  663.          }
  664.  
  665.       /* xpr_finfo() not provided (or failed); default to T? */
  666.       case '?':
  667.          v->Rxascii = v->Rxbinary = FALSE;
  668.          v->Lzconv = 0;
  669.          break;
  670.  
  671.    }  /* End of "switch(*sv->option_t)" */
  672.  
  673. } /* End of void set_textmode() */
  674.  
  675. /**********************************************************
  676.  * UBYTE *find_option(UBYTE *buf, UBYTE option)
  677.  *
  678.  * Search for specified option setting in string
  679.  **********************************************************/
  680. UBYTE *find_option(UBYTE *buf, UBYTE option)
  681. {
  682.    while (*buf)
  683.    {
  684.       buf += strspn(buf, " ,\t\r\n");
  685.       if (*buf == option) return ++buf;
  686.       buf += strcspn(buf, " ,\t\r\n");
  687.    }
  688.  
  689.    return NULL;
  690. }  /* End of UBYTE *find_option() */
  691.  
  692. /**********************************************************
  693.  * void canit(struct Vars *v)
  694.  *
  695.  * send cancel string to get the other end to shut up
  696.  **********************************************************/
  697. void canit(struct Vars *v)
  698. {
  699.    static char canistr[] = { 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
  700.                               8,  8,  8,  8,  8,  8,  8,  8,  8,  8, 0 };
  701.  
  702.    zmputs(v, canistr);
  703. }  /* End of void canit() */
  704.  
  705. /**********************************************************
  706.  * void zmputs(struct Vars *v, UBYTE *s)
  707.  *
  708.  * Send a string to the modem, with processing for \336 (sleep 1 sec)
  709.  * and \335 (break signal, ignored since XPR spec doesn't support it)
  710.  **********************************************************/
  711. void zmputs(struct Vars *v, UBYTE *s)
  712. {
  713.    UBYTE c;
  714.  
  715.    while (*s)
  716.    {
  717.       switch (c = *s++)
  718.       {
  719.          case '\336':
  720.             Delay(50L);
  721.  
  722.          case '\335':
  723.             break;
  724.  
  725.          default:
  726.             sendline(v,c);
  727.       }
  728.    }
  729.    sendbuf(v);
  730. }  /* End of void zmputs() */
  731.  
  732. /**********************************************************
  733.  * void xsendline(struct Vars *v, UBYTE c)
  734.  *
  735.  * Write one character to the modem
  736.  **********************************************************/
  737. void xsendline(struct Vars *v, UBYTE c)
  738. {
  739.    v->Outbuf[v->Outbuflen++] = c;
  740.    if (v->Outbuflen >= sizeof(v->Outbuf)) sendbuf(v);
  741.  
  742. }  /* End of void xsendline() */
  743.  
  744. /**********************************************************
  745.  * void sendbuf(struct Vars *v)
  746.  *
  747.  * Send any data waiting in modem output buffer
  748.  **********************************************************/
  749. void sendbuf(struct Vars *v)
  750. {
  751.    if (v->Outbuflen)
  752.    {
  753.       (*v->io.xpr_swrite)(v->Outbuf, (long) v->Outbuflen);
  754.       v->Outbuflen = 0;
  755.    }
  756. }  /* End of void sendbuf() */
  757.  
  758. /**********************************************************
  759.  * short readock(struct Vars *v, short tenths)
  760.  *
  761.  * Get a byte from the modem;
  762.  * return TIMEOUT if no read within timeout tenths of a
  763.  * second, return RCDO if carrier lost or other fatal error
  764.  * (sread returns -1).  Added in some buffering so we
  765.  * wouldn't hammer the system with single-byte serial port
  766.  * reads.  Also, the buffering makes char_avail() a lot
  767.  * easier to implement.
  768.  **********************************************************/
  769. short readock(struct Vars *v, short tenths)
  770. {
  771.    long t;
  772.  
  773.    /* If there's data waiting in our buffer, return next byte */
  774.    if (v->Modemcount)
  775.    {
  776. gotdata:
  777.       --v->Modemcount;
  778.       return (short) (*v->Modemchar++);
  779.    }
  780.  
  781.    /*
  782.     * Our buffer is empty; see if there's anything waiting in system buffer.
  783.     * If the caller is in a hurry, don't wait around, but if it can spare
  784.     * a half second, wait a bit and build up some input so we don't do as
  785.     * many sread() calls.
  786.     */
  787.    t = (tenths < 5) ? 0 : 500000;
  788.  
  789. #ifdef DEBUGLOG
  790.    mysprintf(v->Msgbuf,
  791.       "Input buffer empty; calling sread for %ld bytes, %ld usec\n",
  792.       (long) sizeof(v->Modembuf), t);
  793.    dlog(v, v->Msgbuf);
  794. #endif
  795.  
  796.    v->Modemcount = (*v->io.xpr_sread)(v->Modembuf, (long) sizeof(v->Modembuf), t);
  797.  
  798. #ifdef DEBUGLOG
  799.    mysprintf(v->Msgbuf, "   sread returned %ld\n", v->Modemcount);
  800.    dlog(v, v->Msgbuf);
  801. #endif
  802.  
  803.    if (v->Modemcount < 0)   /* Carrier dropped or other fatal error; abort */
  804.    {
  805.       v->Modemcount = 0;
  806.       return RCDO;
  807.    }
  808.    else if (! v->Modemcount)    /* Nothing in system buffer; try waiting */
  809.    {
  810.       t = tenths * 100000L - t;
  811.  
  812. #ifdef DEBUGLOG
  813.       mysprintf(v->Msgbuf, "   calling sread for 1 byte, %ld usec\n", t);
  814.       dlog(v, v->Msgbuf);
  815. #endif
  816.  
  817.       v->Modemcount = (*v->io.xpr_sread)(v->Modembuf, 1L, t);
  818.  
  819. #ifdef DEBUGLOG
  820.       mysprintf(v->Msgbuf, "   sread returned %ld\n", v->Modemcount);
  821.       dlog(v, v->Msgbuf);
  822. #endif
  823.  
  824.       if (v->Modemcount < 0)
  825.       {
  826.          v->Modemcount = 0;
  827.          return RCDO;
  828.       }
  829.       else if (! v->Modemcount)  /* Nothing received in time */
  830.       {
  831.          return TIMEOUT;
  832.       }
  833.    }
  834.  
  835.    v->Modemchar = v->Modembuf;   /* Reset buffer pointer to start of data */
  836.    goto gotdata;
  837.  
  838. }  /* End of short readock() */
  839.  
  840. /**********************************************************
  841.  * char char_avail(struct Vars *v)
  842.  *
  843.  * Check if there's anything available to read from the
  844.  * modem
  845.  **********************************************************/
  846. char char_avail(struct Vars *v)
  847. {
  848.    if (v->Modemcount)
  849.       return TRUE;
  850.  
  851.    /* No data in our buffer; check system's input buffer */
  852.  
  853.    v->Modemcount = (*v->io.xpr_sread) (v->Modembuf, (long) sizeof(v->Modembuf), 0L);
  854.    if (v->Modemcount < 1)     /* Nothing in system buffer either */
  855.    {
  856.       v->Modemcount = 0;
  857.       return FALSE;
  858.    }
  859.    else           /* System buffer had something waiting for us */
  860.    {
  861.       v->Modemchar = v->Modembuf;
  862.       return TRUE;
  863.    }
  864. }  /* End of char char_avail() */
  865.  
  866. /**********************************************************
  867.  * void update_rate(struct Vars *v)
  868.  *
  869.  * Update the elapsed time, expected total time, and
  870.  * effective data transfer rate values for status display
  871.  **********************************************************/
  872. void update_rate(struct Vars *v)
  873. {
  874.    ULONG sent, elapsed, expect;
  875.    short hr, min;
  876.    struct timeval tv;
  877.  
  878.    /* Compute effective data rate so far in characters per second */
  879.    sent = v->xpru.xpru_bytes - v->Strtpos;
  880.    getsystime(&tv);
  881.    elapsed = (tv.tv_secs & 0x7FFFFF) * 128 + tv.tv_micro / 8192;
  882.    elapsed -= (v->Starttime.tv_secs & 0x7FFFFF) * 128 + v->Starttime.tv_micro / 8192;
  883.  
  884.    if (elapsed < 128 || elapsed > 0x7FFFFF)
  885.    /*                   ^^^^^^^^^^^^^^^^^^ Kludge for the GURU!  -WMP- */
  886.       elapsed = 128;
  887.  
  888.    /*
  889.     * If we haven't transferred anything yet (just starting), make reasonable
  890.     * guess (95% throughput); otherwise, compute actual effective transfer
  891.     * rate
  892.     */
  893.    v->xpru.xpru_datarate = (sent) ? (sent * 128 / elapsed) : (v->Baud * 95 / 1000);
  894.  
  895.    /* Compute expected total transfer time based on data rate so far */
  896.    if (v->xpru.xpru_filesize < 0)
  897.    {
  898.       expect = 0;    /* Don't know filesize; display time=0 */
  899.    }
  900.    else  expect = (v->xpru.xpru_filesize - v->Strtpos) / v->xpru.xpru_datarate;
  901.  
  902.    hr = expect / 3600;     /* How many whole hours */
  903.    expect -= hr * 3600;    /* Remainder not counting hours */
  904.    min = expect / 60;      /* How many whole minutes */
  905.    expect -= min * 60;     /* Remaining seconds */
  906.  
  907.    mysprintf(v->Msgbuf, "%02ld:%02ld:%02ld", (long) hr, (long) min, expect);
  908.    v->xpru.xpru_expecttime = (char *) v->Msgbuf;
  909.  
  910.    /* Compute elapsed time for this transfer so far */
  911.    elapsed /= 128;
  912.    hr = elapsed / 3600;
  913.    elapsed -= hr * 3600;
  914.    min = elapsed / 60;
  915.    elapsed -= min * 60;
  916.  
  917.    mysprintf(v->Msgbuf + 20, "%02ld:%02ld:%02ld", (long) hr, (long) min,elapsed);
  918.    v->xpru.xpru_elapsedtime = (char *) v->Msgbuf + 20;
  919.  
  920. }  /* End of void update_rate() */
  921.  
  922. /**********************************************************
  923.  * long bfopen(struct Vars *v, UBYTE *mode)
  924.  *
  925.  * Buffered file I/O fopen() interface routine
  926.  **********************************************************/
  927. long bfopen(struct Vars *v, UBYTE *mode)
  928. {
  929.    if (v->File) bfclose(v);   /* Why was the file still open? ARGH! */
  930.  
  931.    /* Initialize file-handling variables */
  932.    v->Filebufpos = v->Filebuflen = v->Filebufcnt = 0;
  933.    v->Fileflush = FALSE;
  934.    v->Filebufptr = v->Filebuf;
  935.  
  936.    /* Open the file */
  937. #ifdef DEBUGLOG
  938.    mysprintf(v->Msgbuf, "bfopen: %s %s\n", v->Filename, mode);
  939.    dlog(v, v->Msgbuf);
  940. #endif
  941.  
  942.    return (v->File = (*v->io.xpr_fopen)(v->Filename, mode));
  943.  
  944. }  /* End of long bfopen() */
  945.  
  946. /**********************************************************
  947.  * void bfclose(struct Vars *v)
  948.  *
  949.  * Buffered file I/O fclose() interface routine
  950.  **********************************************************/
  951. void bfclose(struct Vars *v)
  952. {
  953.    if (v->File)
  954.    {
  955.       /* If bfwrite() left data in buffer, flush it out before closing */
  956.       if (v->Fileflush)
  957.       {
  958.          (*v->io.xpr_fwrite)(v->Filebuf, 1L, v->Filebufcnt, v->File);
  959.       }
  960.  
  961.       /* Close the file */
  962.       (*v->io.xpr_fclose)(v->File);
  963.       v->File = NULL;
  964.    }
  965. }  /* End of void bfclose() */
  966.  
  967. /**********************************************************
  968.  * void bfseek(struct Vars *v, long pos)
  969.  *
  970.  * Buffered file I/O fseek() interface routine
  971.  **********************************************************/
  972. void bfseek(struct Vars *v, long pos)
  973. {
  974.    long offset;
  975.  
  976.    /* If new file position is within currently buffered section,
  977.       reset pointers */
  978.    if (pos >= v->Filebufpos && pos < v->Filebufpos + v->Filebuflen)
  979.    {
  980.       offset = pos - v->Filebufpos;
  981.       v->Filebufptr = v->Filebuf + offset;
  982.       v->Filebufcnt = v->Filebuflen - offset;
  983.       /* Otherwise, fseek() file & discard buffer contents to force new read */
  984.    }
  985.    else
  986.    {
  987.       (*v->io.xpr_fseek)(v->File, pos, 0L);
  988.       v->Filebuflen = v->Filebufcnt = 0;
  989.       v->Filebufpos = pos;
  990.    }
  991. }  /* End of void bfseek() */
  992.  
  993. /**********************************************************
  994.  * long bfread(struct Vars *v, UBYTE *buf, long length)
  995.  *
  996.  * Buffered file I/O fread() interface routine
  997.  **********************************************************/
  998. long bfread(struct Vars *v, UBYTE *buf, long length)
  999. {
  1000.    long count, total = 0;
  1001.  
  1002.    /* Keep going until entire request completed */
  1003.    while (length > 0)
  1004.    {
  1005.       /* Copy as much of the request as possible from the buffer */
  1006.       count = (length <= v->Filebufcnt) ? length : v->Filebufcnt;
  1007.       CopyMem(v->Filebufptr, buf, count);
  1008.  
  1009. #ifdef DEBUGLOG
  1010.       mysprintf(v->Msgbuf, "bfread got %ld bytes from buffer\n", count);
  1011.       dlog(v, v->Msgbuf);
  1012. #endif
  1013.  
  1014.       buf += count;
  1015.       total += count;
  1016.       length -= count;
  1017.       v->Filebufptr += count;
  1018.       v->Filebufcnt -= count;
  1019.  
  1020.       /* If we've emptied the buffer, read next buffer's worth */
  1021.       if (! v->Filebufcnt)
  1022.       {
  1023.          v->Filebufpos += v->Filebuflen;
  1024.          v->Filebufptr = v->Filebuf;
  1025.          v->Filebufcnt = v->Filebuflen =
  1026.                   (*v->io.xpr_fread)(v->Filebuf, 1L, v->Filebufmax, v->File);
  1027.  
  1028. #ifdef DEBUGLOG
  1029.          mysprintf(v->Msgbuf, "bfread read %ld bytes\n", v->Filebufcnt);
  1030.          dlog(v, v->Msgbuf);
  1031. #endif
  1032.  
  1033.          /* If we hit the EOF, return with however much we read so far */
  1034.          if (! v->Filebufcnt) break;
  1035.       }
  1036.    }  /* End of "while (length > 0)" */
  1037.  
  1038.    return total;
  1039.  
  1040. }  /* End of long bfread() */
  1041.  
  1042. /**********************************************************
  1043.  * long bfwrite(struct Vars *v, UBYTE *buf, long length)
  1044.  *
  1045.  * Buffered file I/O fwrite() interface routine
  1046.  **********************************************************/
  1047. long bfwrite(struct Vars *v, UBYTE *buf, long length)
  1048. {
  1049.    long count, total = 0;
  1050.  
  1051.    /* Keep going until entire request completed */
  1052.    while (length > 0)
  1053.    {
  1054.       /* Copy as much as will fit into the buffer */
  1055.       count = v->Filebufmax - v->Filebufcnt;
  1056.       if (length < count) count = length;
  1057.       CopyMem(buf, v->Filebufptr, count);
  1058.  
  1059. #ifdef DEBUGLOG
  1060.       mysprintf(v->Msgbuf, "bfwrite buffered %ld bytes\n", count);
  1061.       dlog(v, v->Msgbuf);
  1062. #endif
  1063.  
  1064.       buf += count;
  1065.       total += count;
  1066.       length -= count;
  1067.       v->Filebufptr += count;
  1068.       v->Filebufcnt += count;
  1069.       v->Fileflush = TRUE;
  1070.  
  1071.       /* If we've filled the buffer, write it out */
  1072.       if (v->Filebufcnt == v->Filebufmax)
  1073.       {
  1074.          count = (*v->io.xpr_fwrite)(v->Filebuf, 1L, v->Filebufcnt, v->File);
  1075.  
  1076. #ifdef DEBUGLOG
  1077.          mysprintf(v->Msgbuf, "bfwrite wrote %ld bytes\n", count);
  1078.          dlog(v, v->Msgbuf);
  1079. #endif
  1080.          if (count < v->Filebufcnt) return -1;
  1081.          v->Filebufptr = v->Filebuf;
  1082.          v->Filebufcnt = 0;
  1083.          v->Fileflush = FALSE;
  1084.       }
  1085.    }
  1086.  
  1087.    return total;
  1088.  
  1089. }  /* End of long bfwrite() */
  1090.  
  1091. /**********************************************************
  1092.  * void ioerr(struct XPR_IO *io, char *msg)
  1093.  *
  1094.  * Have the comm program display an error message for us,
  1095.  * using a temporary XPR_UPDATE structure; used to display
  1096.  * errors before Vars gets allocated
  1097.  **********************************************************/
  1098. void ioerr(struct XPR_IO *io, char *msg)
  1099. {
  1100.    struct XPR_UPDATE xpru;
  1101.  
  1102.    if (io->xpr_update)
  1103.    {
  1104.       xpru.xpru_updatemask = XPRU_ERRORMSG;
  1105.       xpru.xpru_errormsg = msg;
  1106.       (*io->xpr_update)(&xpru);
  1107.    }
  1108. }  /* End of void ioerr() */
  1109.  
  1110. /**********************************************************
  1111.  * void upderr(struct Vars *v, char *msg)
  1112.  *
  1113.  * Have the comm program display an error message for us, using the
  1114.  * normal XPR_IO structure allocated in Vars
  1115.  **********************************************************/
  1116. void upderr(struct Vars *v, char *msg)
  1117. {
  1118.    v->xpru.xpru_updatemask = XPRU_ERRORMSG;
  1119.    v->xpru.xpru_errormsg = msg;
  1120.  
  1121.    if (msg == v->Msgbuf)
  1122.    {
  1123.       msg[48] = '\0';      /* Ensure message length < 50 */
  1124.    }
  1125.  
  1126.    (*v->io.xpr_update)(&v->xpru);
  1127.  
  1128. #ifdef DEBUGLOG
  1129.    dlog(v, msg);
  1130.    dlog(v, "\n");
  1131. #endif
  1132.  
  1133. }  /* End of void upderr() */
  1134.  
  1135. /**********************************************************
  1136.  * void updmsg(struct Vars *v,char *msg)
  1137.  *
  1138.  * Have the comm program display a normal message for us
  1139.  **********************************************************/
  1140. void updmsg(struct Vars *v,char *msg)
  1141. {
  1142.    v->xpru.xpru_updatemask = XPRU_MSG;
  1143.    v->xpru.xpru_msg = msg;
  1144.  
  1145.    if (msg == v->Msgbuf)
  1146.    {
  1147.       msg[48] = '\0';      /* Ensure message length < 50 */
  1148.    }
  1149.  
  1150.    (*v->io.xpr_update)(&v->xpru);
  1151.  
  1152. #ifdef DEBUGLOG
  1153.    dlog(v, msg);
  1154.    dlog(v, "\n");
  1155. #endif
  1156.  
  1157. }  /* End of void updmsg() */
  1158.  
  1159. /**********************************************************
  1160.  * void updstatus(struct Vars *v,char *filename,long status)
  1161.  *
  1162.  * Set the pass/fail status of this file.
  1163.  **********************************************************/
  1164. void updstatus(struct Vars *v,char *filename,long status)
  1165. {
  1166.    v->xpru.xpru_updatemask = XPRU_FILENAME|XPRU_STATUS;
  1167.    v->xpru.xpru_filename = filename;
  1168.    v->xpru.xpru_status = status;
  1169.    (*v->io.xpr_update)(&v->xpru);
  1170.  
  1171. }  /* End of void updstatus() */
  1172.  
  1173. /**********************************************************
  1174.  * long getfree(void)
  1175.  *
  1176.  * Figure out how many bytes are free on the drive we're uploading to.
  1177.  * Stubbed out for now; not supported by XPR spec.
  1178.  **********************************************************/
  1179. long getfree(void)
  1180. {
  1181.    return 0x7FFFFFFF;
  1182. }  /* End of long getfree() */
  1183.  
  1184. /**********************************************************
  1185.  * char exist(struct Vars *v)
  1186.  *
  1187.  * Check whether file already exists; used to detect
  1188.  * potential overwrites
  1189.  **********************************************************/
  1190. char exist(struct Vars *v)
  1191. {
  1192.    long file;
  1193.  
  1194.    file = (*v->io.xpr_fopen)(v->Filename, "r");
  1195.    if (file)
  1196.    {
  1197.       (*v->io.xpr_fclose)(file);
  1198.       return TRUE;
  1199.    }
  1200.    else return FALSE;
  1201.  
  1202. }  /* End of char exist() */
  1203.  
  1204. /**********************************************************
  1205.  * int mysprintf(char *buffer, char *ctl, ...)
  1206.  **********************************************************/
  1207. void prbuf(char c);
  1208.  
  1209. int mysprintf(char *buffer, char *ctl, ...)
  1210. {
  1211.    long *arg1;
  1212.  
  1213.    arg1 = (long *) (&ctl + 1);
  1214.    RawDoFmt(ctl, (APTR)arg1, prbuf, (APTR)buffer);
  1215.    return(strlen (buffer));
  1216.  
  1217. }  /* End of int mysprintf() */
  1218.  
  1219. /**********************************************************
  1220.  * void prbuf(char c)
  1221.  *
  1222.  * This stub routine is called from the RawDoFmt routine for
  1223.  * each character in the string.  At invocation, we have:
  1224.  *   D0 - next character to be formatted
  1225.  *   A3 - pointer to data buffer
  1226.  **********************************************************/
  1227. #define R_A3 (8 + 3)
  1228.  
  1229. void prbuf(char c)
  1230. {
  1231.    char *p = (char *) __builtin_getreg(R_A3);
  1232.    *p++ = c;
  1233.    __builtin_putreg(R_A3, (long) p);
  1234.  
  1235. }  /* End of void prbuf() */
  1236.  
  1237. #ifdef DEBUGLOG
  1238. /**********************************************************
  1239.  * void dlog(struct Vars *v, UBYTE *s)
  1240.  *
  1241.  * Write a message to the debug log
  1242.  **********************************************************/
  1243. void dlog(struct Vars *v, UBYTE *s)
  1244. {
  1245.    /* Open the debug log if it isn't already open */
  1246.    if (! DebugLog) DebugLog = (*v->io.xpr_fopen)(DebugName, "a");
  1247.    (*v->io.xpr_fwrite)(s, 1L, (long) strlen(s), DebugLog);
  1248.  
  1249.    /*
  1250.     * Close file to flush output buffer; comment these two lines out if
  1251.     * you aren't crashing your system and don't mind waiting until the
  1252.     * transfer finishes to look at your log file.
  1253.     * (*v->io.xpr_fclose)(DebugLog);
  1254.     * DebugLog = NULL;
  1255.     */
  1256. }  /* End of void dlog() */
  1257. #endif
  1258.  
  1259. /* End of Utils.c source */
  1260.