home *** CD-ROM | disk | FTP | other *** search
/ Gold Fish 1 / GoldFishApril1994_CD1.img / d2xx / d240 / xprlib / xprotocol.doc < prev    next >
Text File  |  1989-08-28  |  66KB  |  1,838 lines

  1. +----------------------------------------------------------------------+
  2. |                                                                      |
  3. |                  D I S C L A I M E R   N O T I C E                   |
  4. |                                                                      |
  5. |  This document and/or  portions of the material and  data furnished  |
  6. |  herewith,  was developed under sponsorship of the U.S. Government.  |
  7. |  Neither the U.S.  nor  the U.S.D.O.E.,  nor  the  Leland  Stanford  |
  8. |  Junior University, nor their employees,  nor their respective con-  |
  9. |  tractors, subcontractors, or their employees, makes  any warranty,  |
  10. |  express or implied, or assumes any liability or responsibility for  |
  11. |  accuracy,  completeness or  usefulness of any information, appara-  |
  12. |  tus, product or process disclosed, or represents that its use will  |
  13. |  not infringe privately-owned rights.  Mention of any product,  its  |
  14. |  manufacturer, or suppliers shall not, nor is it intended to, imply  |
  15. |  approval, disapproval, or fitness for any particular use. The U.S.  |
  16. |  and  the University at all times  retain the right to use and dis-  |
  17. |  seminate same for any purpose whatsoever.                           |
  18. |                                                                      |
  19. +----------------------------------------------------------------------+
  20.  
  21.  
  22.  
  23.         XPR: External File Transfer Protocols as Amiga Libraries.
  24.         =========================================================
  25.  
  26.                        Version - 16 July 1989
  27.  
  28.                        (C) Copyright 1989 by
  29.  
  30.                          W.G.J. Langeveld
  31.  
  32.                  Stanford Linear Accelerator Center
  33.  
  34.  
  35.                               ABSTRACT
  36.                               ========
  37.  
  38.                 This document describes a standard method
  39.                 of using Amiga shared libraries  for  the
  40.                 implementation of  external file transfer
  41.                 protocols, as (partially) implemented  in
  42.                 the Amiga terminal emulator VLT.
  43.  
  44.  
  45. 1. Introduction.
  46. ================
  47.  
  48.         One of the most frequently asked questions of the author of a
  49. communications program is "Why don't you implement this wonderful file transfer
  50. protocol in addition to the 25 you already have?". Clearly, implementing more
  51. FTP's leads to larger code size and to increased product development time and
  52. customer support requirements, unless there is a way to have the additional
  53. protocols available as separate entities. One obvious way is to put the
  54. additional FTP's in overlays, but that only mitigates the code size problem and
  55. does not allow protocols to be used with communications programs of different
  56. vendors. Better is to open the serial device as a shared port and to have a
  57. completely separate program access it at the same time. However, this method has
  58. the disadvantage that shared use of a single serial port can lead to
  59. unpredictable results unless there is a well-established priority system
  60. enforcing which program is allowed to write to the device at which time. The
  61. advantage is that the FTP can now be developed separately and even by someone
  62. other than the author of the communications program. There are variations
  63. involving inter-process communication to add access control to the latter
  64. system, but I will not go into further detail.
  65.         The system described here is based on Amiga shared libraries. The
  66. library implements a small number of primary functions, such as "Send File(s)"
  67. and "Receive File(s)". These functions are called with a single argument, a
  68. pointer to an XPR_IO structure. This structure contains a number of things, the
  69. more obvious one being a pointer to a null terminated string indicating which
  70. files are to be sent or received and addresses of "call-back" functions inside
  71. the code of the communications program to access the serial device, which is
  72. opened typically in exclusive access. The scheme described here opens the
  73. possibility for the Amiga community to write a multitude of file transfer
  74. protocols, all rather small in size because they don't contain any overhead,
  75. that work with any communications program following the rules outlined in this
  76. document.
  77.         Possible problems with shared libraries are that they should be
  78. reentrant and that they should, if possible, not open dos.library [1]. On the
  79. other hand, these problems can easily be turned into advantages: for one,
  80. reentrancy is not hard to accomplish and in addition when there are multiple
  81. serial ports in use all of them can use the FTP with a single copy of the code.
  82. Not having to open dos.library can be accomplished by having call-back functions
  83. that provide all the DOS access needed in the original communications program.
  84. Typically these DOS functions are already linked into the original code anyway,
  85. and call-backs have to be provided for serial port access in any case.
  86.         For the sake of reentrancy across calls to the external protocol library
  87. (XPR), a field for storing a pointer to a data area is added for use by the XPR
  88. internally.
  89.  
  90.         Section 2 explains the library structure itself. Section 3 covers the
  91. XPR_IO structure and defines all the call-back functions. Section 4 describes an
  92. example library for a simple ASCII transfer without bells or whistles and will
  93. show how to code the library part of the call-backs. Section 5 shows how to set
  94. up the interface on the communications program side.
  95.  
  96.         Note: the examples are all for Manx C and assembler but should be easily
  97. modifyable for Lattice or any other language. Not all source files are given in
  98. this document. This archive, however, contains the example library plus all
  99. files needed to link it and interface to it, for Manx. Specifically, the
  100. routines that interface to XPR from VLT are in the "comm-program" subdirectory,
  101. and the sources to the library are in the "library" subdirectory.
  102.  
  103.         I would like to thank Marco Papa of Felsina Software for his help in
  104. working out some of the details of the XPR standard.
  105.  
  106.         Neither this document, nor the XPR standard, nor the other files in this
  107. archive are in the public domain, but they may be freely distributed and used
  108. for any purpose bearing in mind the stipulations given in the disclaimer above,
  109. and with the proviso that in case of further distribution all files of this
  110. archive must remain together and unchanged.
  111.  
  112.  
  113. Reference:
  114. [1] Jim Mackraz says that opening dos.library inside a library is not a good
  115.     idea.
  116.  
  117.  
  118. 2. XPR libraries.
  119. =================
  120.  
  121.         Each external FTP is implemented as a separate library which lives in
  122. the libs: directory. It is mandatory that the names of XPR libraries start with
  123. the three letters "xpr" so that they are easily identified. The template for the
  124. name is xpr<protocol-name>.library, where <protocol-name> is a descriptive name
  125. of the protocol that is implemented. Obvious examples would be xprkermit.library
  126. and xprxmodem.library, but xprmykermit.library would be fine for a
  127. user-customized kermit implementation. When thinking of a name, the  implementer
  128. of an XPR library should keep in mind that communication programs will likely
  129. use the <protocol-name> part in their XPR requester.
  130.         Each XPR library in turn has four public functions. The functions are:
  131.  
  132.         XProtocolCleanup()
  133.         XprotocolSetup()
  134.         XprotocolSend()    and
  135.         XprotocolReceive()
  136.  
  137. in addition to the usual open, close expunge and reserved vectors. The library
  138. skeleton is given in Appendix A.
  139.         Typically, a session with a terminal emulator using external protocols
  140. would consist of
  141.  
  142.         1. Selecting an external protocol (Using e.g. a file requester
  143.            showing only those files in libs: starting with "xpr").
  144.         2. Retrieving the library base XProtocolBase of the selected protocol
  145.            using OpenLibrary().
  146.         3. (Allocating and) initializing an XPR_IO structure.
  147.         4. Optionally calling XProtocolSetup() with the initialized structure.
  148.         5. Optionally Calling XProtocolSend() and/or XprotocolReceive() once or
  149.            multiple times to transfer files.
  150.         6. Optionally calling XProtocolSetup() to change parameters or to send
  151.            special commands. Perhaps repeat 5.
  152.         7. Calling XprotocolCleanup() to deallocate any resources allocated by
  153.            XProtocolSetup(). (Deallocate the XPR_IO structure if needed).
  154.         8. Closing the library using CloseLibrary().
  155.         9. Repeat the process, or
  156.        10. Exit.
  157.  
  158.         All four XPR functions take a single argument, a pointer to an XPR_IO
  159. structure, properly initialized as described in section 5. After
  160. XProtocolSetup() has been called, the same XPR_IO structure should be used for
  161. calls to any of the other functions. Only the xpr_filename field is allowed to
  162. be changed between  calls. In particular, the xpr_data field is for internal use
  163. by the XPR library only! It should be initialized to NULL before calling
  164. XProtocolSetup() and should not be changed by the communications program.
  165. XProtocolSetup() should only be called at the request of the user.
  166. XProtocolCleanup() should always be called before the library is closed.
  167.         In the form of a sample program, the rules above look like this:
  168.  
  169. /** MyWonderFullCommProgram.c
  170. *
  171. *   Just an example. An actual implementation would likely look different.
  172. *
  173. **/
  174. #include <stdio.h>
  175. #include <functions.h>
  176. #include "xproto.h"
  177.  
  178. struct Library *XProtocolBase = NULL;
  179.  
  180. #define SEND 1
  181. #define RECEIVE 2
  182. #define INITIALIZE 3
  183.  
  184. main()
  185. {
  186.    struct XPR_IO io;
  187.    int user_said, Waiting_for_user_input();
  188.  
  189.    XProtocolBase = OpenLibrary("xprascii.library", 0L);
  190.    if (XProtocolBase == NULL) {
  191.       printf("protocol not found\n");
  192.       exit(10);
  193.    }
  194.  
  195. /*
  196. *   Initialize structure (see later).
  197. */
  198.    xpr_setup(io);
  199. /*
  200. *   Retrieve the initalization string
  201. */
  202.    Get_init_string_from_user_or_wherever(buffer);
  203.    io->xpr_filename = buffer;
  204.    XProtocolSetup(io);
  205.  
  206.    while (user_said = Waiting_for_user_input(filename)) {
  207.       if (user_said == SEND) {
  208.          io->xpr_filename = filename;
  209.          XProtocolSend(io);
  210.       }
  211.       else if (user_said == RECEIVE) {
  212.          io->xpr_filename = filename;
  213.          XProtocolReceive(io);
  214.       }
  215.       else if (user_said == INITIALIZE) {
  216.          io->xpr_filename = NULL;
  217.          XProtocolSetup(io);
  218.       }
  219.    }
  220.  
  221.    XProtocolCleanup(io);
  222.  
  223.    CloseLibrary(XProtocolBase);
  224.  
  225.    exit(0);
  226. }
  227.  
  228.         Clearly, only one FTP can be active at any particular instant in the
  229. life of the session of the communications program. However, this is not really a
  230. limitation in practice, and can be worked around at the cost of some amount of
  231. programming effort.
  232.         XProtocolSetup(), XProtocolSend(), XProtocolReceive() and
  233. XProtocolCleanup() return 0L on failure, non-zero on success.
  234.  
  235.  
  236.  
  237.  
  238. 3. The XPR_IO structure.
  239. ========================
  240.  
  241.         The XPR_IO structure definition is given in Appendix B. The reader
  242. should keep in mind that the callback functions are to be implemented by the
  243. author of the communications program, not by the author of the external
  244. protocol. However, most communications programs already have functions that
  245. perform the operations listed here, so the implementation should not be too
  246. difficult. Also, the communications program author is not required, strictly
  247. speaking, to implement any of the functions: functions that are not implemented
  248. should be indicated by initializing the corresponding XPR_IO field to NULL.
  249. Obviously, a minimum set of functions must be implemented in order to be useful.
  250. On the other hand, it is up to the implementer of the external protocol to
  251. determine if the given set of functions is sufficient to perform the protocol
  252. transfer. In case of missing functions (indicated by NULL fields in the XPR_IO
  253. structure) suitable default actions should be taken.
  254.  
  255.         We will now examine all the fields of XPR_IO in detail. 
  256.  
  257.  
  258. 3.1     char  *xpr_filename;
  259. ----------------------------
  260.  
  261.         The xpr_filename field is used primarily to pass null-terminated strings
  262. containing a file name (or file names specified by wild cards) to the functions
  263. XProtocolSend() or XProtocolReceive(). The XPR implementer may elect to support
  264. wild cards in the file name. Call-backs for finding the first and next filename
  265. matching the pattern are provided in the XPR_IO structure, but on the other hand
  266. XPR implementers should take care to check that these call-backs are implemented
  267. by the communications program by testing the corresponding XPR_IO fields for
  268. NULL. Never assume that all call-backs are implemented! If a particular
  269. call-back without which the XPR cannot function is not implemented, the XPR
  270. should fail gracefully.
  271.  
  272.         The xpr_filename field can also be used to pass an initialization string
  273. to XProtocolSetup(). Typically, if this field is left NULL in a call to
  274. XProtocolSetup(), it would be the duty of XProtocolSetup() to query the user for
  275. initialization information, using the xpr_gets function (see later). If an
  276. initialization string is present, XProtocolSetup() should NOT query the user,
  277. but this is left to the discretion of the implementer of the protocol, as is the
  278. precise form of the initialization string. It is the duty of the communications
  279. program to determine any default initialization strings for the protocol in
  280. question. Suggested is the use of environment variables named for the protocols
  281. they refer to, containing the initialization string. For the simple Ascii
  282. protocol shown later, the user might have a statement like
  283.  
  284.         set xprascii=50
  285.  
  286. in his startup sequence, or with AmigaDOS 1.3, a file called xprascii in his
  287. env: directory containing the letters "50" (50 referring here to the number of
  288. ticks delay between 80-character packets - obviously more extensive
  289. initialization might be needed).
  290.         Given the presence of such default information, XProtocolSetup() should
  291. always be called using the default initialization string right after opening the
  292. library. Conversely, a mechanism (menu option) should be present in the
  293. communications program to change the settings by calling XProtocolSetup() with a
  294. NULL value for this field. On the other hand, if no default initialization
  295. string is present, the legal situation can arise that XProtocolSetup() is never
  296. called.
  297.         It should be noted that XProtocolSetup() can be used to implement any
  298. commands not directly related to sending or receiving files. Examples that come
  299. to mind are Kermit Bye and Finish. One should keep in mind, that typically the
  300. communications program does not know what protocol it is running, much less what
  301. commands that protocol might support. When the user asks to "setup" the external
  302. protocol, XProtocolSetup() should be called with a NULL xpr_filename field,
  303. and the external protocol should request a command, as stated before. In the
  304. case of an external Kermit protocol, the user might type a Bye or Finish, and
  305. the external protocol could act accordingly.
  306.  
  307.         The xpr_filename field is ignored by the XProtocolCleanup() function.
  308.  
  309.  
  310. 3.2    long (*xpr_fopen)();
  311. ---------------------------
  312.  
  313.         The xpr_fopen() call-back function works in most respects identically to
  314. the stdio function fopen(). Calling sequence:
  315.  
  316.         long fp = (*xpr_fopen)(char *filename, char *accessmode)
  317.         D0                     A0              A1
  318.  
  319. The result is a FILE structure, but one should not count on it being a
  320. particular one, since it may be compiler dependent. The return value should only
  321. be used in calls to other stdio functions. The only accesmodes available are
  322. "r"  (read-only)
  323. "w"  (write-only, create new file if none exists, truncate existing file)
  324. "a"  (write-only, create new file if none exists, append to existing file)
  325. "r+" (same as "r", but may also write)
  326. "w+" (same as "w", but may also read)
  327. "a+" (same as "a", but may also read).
  328.         An error return is indicated when the function returns NULL.
  329.         Note that the arguments must be passed in registers A0 and A1
  330. respectively. See also section 4.
  331.  
  332.  
  333. 3.3     long (*xpr_fclose)();
  334. -----------------------------
  335.  
  336.         The xpr_fclose() call-back function works in most respects identically
  337. to the stdio function fclose(). Calling sequence:
  338.  
  339.         (*xpr_fclose)(long filepointer)
  340.                       A0
  341.  
  342. Note that the argument must be passed in register A0.
  343.  
  344.  
  345. 3.4     long (*xpr_fread)();
  346. ----------------------------
  347.  
  348.         The xpr_fread() call-back function works in most respects identically to
  349. the stdio function fread(). Calling sequence:
  350.  
  351.         long count = (*xpr_fread)(char *buffer, long size, long count,
  352.         D0                        A0            D0         D1
  353.  
  354.                                   long fileptr)
  355.                                   A1
  356.  
  357. The function returns the actual number items read. The size argument is in bytes.
  358. The function returns 0 on error or end of file.
  359.  
  360.  
  361. 3.5     long (*xpr_fwrite)();
  362. -----------------------------
  363.  
  364.         The xpr_fwrite() call-back function works in most respects identically
  365. to the stdio function fwrite(). Calling sequence:
  366.  
  367.         long count = (*xpr_fwrite)(char *buffer, long size, long count,
  368.         D0                         A0            D0         D1
  369.  
  370.                                   long fileptr)
  371.                                   A1
  372.  
  373. The function returns the actual number items written. The size argument is in
  374. bytes. The function returns 0 on failure.
  375.  
  376.  
  377. 3.6     long (*xpr_sread)();
  378. ----------------------------
  379.  
  380.         The xpr_sread() call-back function has the following calling sequence:
  381.  
  382.         long count = (*xpr_sread)(char *buffer, long size, long timeout)
  383.         D0                        A0            D0         D1
  384.  
  385. The first argument is a pointer to a buffer to receive the characters from the
  386. serial port, with a size specified in the second argument. The third item is a
  387. timeout in microseconds. The timeout may be set to 0L if the objective is to
  388. just read any characters that may currently be available. When this argument is
  389. non-zero, the function will not return until either the timeout period has
  390. expired, or the buffer has filled up. The function returns the actual number of
  391. characters put into the buffer, or -1L on error or timeout.
  392.         Note: the value 0L for the timeout argument is a special case. Remember
  393. that AmigaDOS 1.3 may have problems with small non-zero values for timeouts.
  394.  
  395.  
  396. 3.7     long (*xpr_swrite)();
  397. -----------------------------
  398.  
  399.         The xpr_swrite() call-back function has the following calling sequence:
  400.  
  401.         long status = (*xpr_swrite)(char *buffer, long size)
  402.         D0                          A0            D0
  403.  
  404. This function writes a buffer with the given size to the serial port. It returns
  405. 0L on success, non-zero on failure.
  406.  
  407. 3.8     long (*xpr_sflush)();
  408. ----------------------------
  409.  
  410.         The xpr_sflush call-back function has the following calling sequence:
  411.  
  412.         long status = (*xpr_sflush)()
  413.         D0
  414.  
  415. This function flushes all the data in the serial port input buffer.  It is
  416. typically used to recover after a protocol error. The function returns 0L on
  417. success, non-zero on failure.
  418.  
  419. 3.9     long (*xpr_update)();
  420. -----------------------------
  421.  
  422.         The xpr_update() call-back function has the following calling sequence:
  423.  
  424.         (*xpr_update)(struct XPR_UPDATE *updatestruct)
  425.                       A0
  426. where:
  427.  
  428. struct XPR_UPDATE {     long  xpru_updatemask;
  429.                         char *xpru_protocol;
  430.                         char *xpru_filename;
  431.                         long  xpru_filesize;
  432.                         char *xpru_msg;
  433.                         char *xpru_errormsg;
  434.                         long  xpru_blocks;
  435.                         long  xpru_blocksize;
  436.                         long  xpru_bytes;
  437.                         long  xpru_errors;
  438.                         long  xpru_timeouts;
  439.                         long  xpru_packettype;
  440.                         long  xpru_packetdelay;
  441.                         long  xpru_chardelay;
  442.                         char *xpru_blockcheck;
  443.                         char *xpru_expecttime;
  444.                         char *xpru_elapsedtime;
  445.                         long  xpru_datarate;
  446.                         long  xpru_reserved1;
  447.                         long  xpru_reserved2;
  448.                         long  xpru_reserved3;
  449.                         long  xpru_reserved4;
  450.                         long  xpru_reserved5;
  451.                    }
  452.  
  453. This function is intended to communicate a variety of values and strings from
  454. the external protocol to the communications program for display. Hence, the
  455. display format itself (requester, text-I/O) is left to the implementer of the
  456. communications program.
  457.         The mask xpru_updatemask indicates which of the other fields are valid,
  458. i.e. have had their value updated. It is possible to update a single or multiple
  459. values. Values that the external protocol does not use can be indicated by a
  460. NULL for pointers and -1L for longs.
  461.         The possible bit values for the xpru_updatemask are:
  462.  
  463.                 #define XPRU_PROTOCOL           0x00000001L
  464.                 #define XPRU_FILENAME           0x00000002L
  465.                 #define XPRU_FILESIZE           0x00000004L
  466.                 #define XPRU_MSG                0x00000008L
  467.                 #define XPRU_ERRORMSG           0x00000010L
  468.                 #define XPRU_BLOCKS             0x00000020L
  469.                 #define XPRU_BLOCKSIZE          0x00000040L
  470.                 #define XPRU_BYTES              0x00000080L
  471.                 #define XPRU_ERRORS             0x00000100L
  472.                 #define XPRU_TIMEOUTS           0x00000200L
  473.                 #define XPRU_PACKETTYPE         0x00000400L
  474.                 #define XPRU_PACKETDELAY        0x00000800L
  475.                 #define XPRU_CHARDELAY          0x00001000L
  476.                 #define XPRU_BLOCKCHECK         0x00002000L
  477.                 #define XPRU_EXPECTTIME         0x00004000L
  478.                 #define XPRU_ELAPSEDTIME        0x00008000L
  479.                 #define XPRU_DATARATE           0x00010000L
  480.  
  481.         The other fields of the XPR_UPDATE structure have the following
  482. meaning:
  483.  
  484. xpru_protocol    -- a string that indicates the name of the protocol used
  485. xpru_filename    -- the name of the file currently sent or received
  486. xpru_filesize    -- the size of the file
  487. xpru_msg         -- a "generic" message (50 characters or less)
  488. xpru_errormsg    -- an "error" message  (50 characters or less)
  489. xpru_blocks      -- number of transferred blocks
  490. xpru_blocksize   -- size of most recently transferred block (bytes)
  491. xpru_bytes       -- number of transferred bytes
  492. xpru_errors      -- number of errors
  493. xpru_timeouts    -- number of timeouts
  494. xpru_packettype  -- type of packet (e.g. Kermit 'D'-packet)
  495. xpru_packetdelay -- delay between packets in msec
  496. xpru_chardelay   -- delay between characters in msec
  497. xpru_blockcheck  -- block check type (e.g. "Checksum", "CRC-16", "CRC-32")
  498. xpru_expecttime  -- expected transfer time (e.g. "5 min 20 sec", "00:05:30")
  499. xpru_elapsedtime -- elapsed time from start of transfer (see xpru_expecttime)
  500. xpru_datarate    -- rate of data transfer expressed in characters per second.
  501. xpru_reserved1   -- for further expansion
  502.  ...         .   --  ...
  503. xpru_reserved5   -- for further expansion
  504.  
  505.         The communications program is free to ignore any field and to only update
  506. the ones it can handle.
  507.         If xpru_updatemask is equal to -1L, then ALL fields are either valid or 
  508. are unambiguously valued to indicate they are unused: NULL for pointers and -1L
  509. for longs.
  510.         When writing an external protocol, it is advisable to keep any strings
  511. as short as possible, and not longer than about 50 characters. Remember, if your
  512. strings are too long, they may overflow whatever display mechanism the
  513. communications program has chosen. It is also advisable to fill in as many
  514. fields as you can, since the communications program may not choose to display
  515. the ones you favor. When writing a communications program interface to XPR, on
  516. the other hand, remember that strings can be as much as 50 characters long. If
  517. you don't receive your favorite variables, it may be possible to compute them
  518. from those that are given. It is good practice for the external protocol to call
  519. xpr_update before starting the transfer with a message in the xpru_msg field
  520. indicating whether the protocol is sending or receiving a file.
  521.         The XPR_UPDATE structure must be provided by the external protocol, and
  522. must, of course be allocated either on the stack (as a local variable) or using
  523. AllocMem or malloc(). This is needed to ensure reentrancy. In general, it is a
  524. good idea to keep the entire library reentrant, since more than one
  525. communications program may be using the same code simultaneously.
  526.  
  527.  
  528. 3.10     long (*xpr_chkabort)();
  529. -------------------------------
  530.  
  531.         The xpr_chkabort() call-back function has no arguments:
  532.  
  533.         long status = (*xpr_chkabort)()
  534.         D0
  535.  
  536. When it returns non-zero, it means that the user has requested an abort. It is
  537. possible to implement levels of abort by returning 1L, 2L, 3L, etc, depending on
  538. the user's actions. The highest level of abort is -1L, which should be
  539. interpreted to mean stop all actions and return. The chkabort function should be
  540. called reasonably frequently.
  541.  
  542.  
  543. 3.11    long (*xpr_chkmisc)();
  544. ------------------------------
  545.  
  546.         The xpr_chkmisc() call-back function has no arguments and returns
  547. nothing.
  548.  
  549.         (*xpr_chkmisc)()
  550.  
  551. It is intended to give the communications program that is currently executing
  552. the external protocol transfer a chance to service its various message ports and
  553. to respond to user actions. It should be called on a regular basis.
  554.  
  555.  
  556. 3.12    long (*xpr_gets)();
  557. ---------------------------
  558.  
  559.         The xpr_gets() call-back function works somewhat like the stdio function
  560. gets(). Calling sequence:
  561.  
  562.         long status = (*xpr_gets)(char *prompt, char *buffer)
  563.         D0                        A0            A1
  564.  
  565. The first argument is a pointer to a string containing a prompt, to be displayed
  566. by the communications program in any manner it sees fit. The second argument
  567. should be a pointer to a buffer to receive the user's response. It should have a
  568. size of at least 256 bytes. The function returns 0L on failure or user
  569. cancellation, non-zero on success. The buffer has to be supplied by the XPR.
  570.  
  571.  
  572. 3.13    long (*xpr_setserial)();
  573. --------------------------------
  574.  
  575.         The xpr_setserial() call-back function has the following calling
  576. sequence:
  577.  
  578.         long oldstatus = (*xpr_setserial)(long newstatus)
  579.         D0                                D0
  580.  
  581. This function returns the current serial device status in encoded form. If the
  582. newstatus argument is -1L, the serial device status will not be changed.
  583. Otherwise the serial device status will be changed to newstatus. If oldstatus
  584. is returned as -1L, the call failed and the serial status was not changed.
  585.         Note: if the serial device status is changed with this function, the 
  586. external protocol must change the status back to oldstatus before returning.
  587.  
  588.         serial status longword:
  589.         .......................
  590.  
  591.         byte 0:         as the SerFlags field in IOExtSer structure.
  592.                 bit 0:  - parity on if set
  593.                 bit 1:  - parity odd if set
  594.                 bit 2:  - 7-wire protocol enabled if set
  595.                 bit 3:  - queued break if set
  596.                 bit 4:  - rad-boogie if set
  597.                 bit 5:  - shared if set
  598.                 bit 6:  - EOF mode if set
  599.                 bit 7:  - Xon/Xoff disabled if set
  600.         byte 1:         summary of other settings
  601.                 bit 0:  - enable mark/space parity if set
  602.                 bit 1:  - parity mark if set, space otherwise
  603.                 bit 2:  - 2 stop bits if set, 1 otherwise
  604.                 bit 3:  - read wordlength is 7 if set, 8 otherwise
  605.                 bit 4:  - write wordlength is 7 if set, 8 otherwise
  606.                 bit 5:  - not used
  607.                 bit 6:  - not used
  608.                 bit 7:  - not used
  609.         byte 2:         specifies one of a limited set of baud rates, as in
  610.                         preferences.h.
  611.                         -    110 baud =  0
  612.                         -    300 baud =  1
  613.                         -   1200 baud =  2
  614.                         -   2400 baud =  3
  615.                         -   4800 baud =  4
  616.                         -   9600 baud =  5
  617.                         -  19200 baud =  6
  618.                         -   midi      =  7
  619.                         -  38400 baud =  8
  620.                         -  57600 baud =  9
  621.                         -  76800 baud = 10
  622.                         - 115200 baud = 11
  623.         byte 3:         not used
  624.  
  625.  
  626. 3.14    long (*xpr_ffirst)();
  627. -----------------------------
  628.  
  629.         The xpr_ffirst() call-back function has the calling sequence:
  630.  
  631.         long stateinfo = (*xpr_ffirst)(char *buffer, char *pattern)
  632.         D0                             A0            A1
  633.  
  634. The first argument is a buffer to receive the first filename that matches the
  635. pattern in the second argument. The function returns 0L if no file matching the
  636. pattern was found, non-zero otherwise. The buffer should have a size of at least
  637. 256 bytes and is provided by the XPR. See also 3.14.
  638.  
  639.  
  640. 3.15    long (*xpr_fnext)();
  641. ----------------------------
  642.  
  643.         The xpr_fnext() call-back function has the calling sequence:
  644.  
  645.         long stateinfo = (*xpr_fnext)(long oldstate, char *buffer, char *pattern)
  646.         D0                            D0             A0            A1
  647.  
  648. The first argument is a buffer to receive the next filename that matches the
  649. pattern in the second argument. The function returns 0L if no further file
  650. matching the pattern was found, non-zero otherwise. The buffer should have a
  651. size of at least 256 bytes and is provided by the XPR.
  652.         Note: the value returned by xpr_ffirst and xpr_fnext may be used by the
  653. implementing communications program to maintain state information, but the
  654. mechanism is up to the implementer. If reentrancy is not required, state
  655. information may be kept in global variables by the implementer, and the oldstate
  656. argument can be ignored. However, the external protocol implementation must pass
  657. the stateinfo variable returned by ffirst or fnext to the next invocation of
  658. fnext.
  659.  
  660.  
  661. 3.16    long (*xpr_finfo)();
  662. ----------------------------
  663.  
  664.         The xpr_finfo() call-back function has the calling sequence:
  665.  
  666.         long info = (*xpr_finfo)(char *filename, long typeofinfo)
  667.         D0                       A0              D0
  668.  
  669. This function returns information about a file given its name and the type of
  670. information requested. Notice that some information may not be accessible if
  671. the file is already write locked. Therefore, you should call this function
  672. (where appropriate) before opening the file.
  673.  
  674.         typeofinfo value:       resulting info:              on failure:
  675.         ..................................................................
  676.  
  677.         1L                      file size (bytes)            0L
  678.  
  679.         2L                      file type: 1L is binary,     0L
  680.                                            2L is text.
  681.  
  682.         (other values)          (to be determined)
  683.  
  684.  
  685. 3.17    long  *xpr_fseek();
  686. ---------------------------
  687.  
  688.         The xpr_fseek() call-back function works in most respects identically to
  689. the stdio function fseek(). Calling sequence:
  690.  
  691.         long status = (*xpr_fseek)(long fileptr, long offset, long origin)
  692.         D0                         A0            D0           D1
  693.  
  694. This function sets the current position of a file to "offset" from the 
  695. beginning (origin = 0), current position (origin = 1) or end (origin = 2) of
  696. the file.
  697. The function returns 0 on success.
  698.  
  699.  
  700. 3.18    long  *xpr_extension;
  701. -----------------------------
  702.  
  703.         This field indicates how many extension fields follow this structure.
  704. Before using any functions or fields defined in section 3.20 and later, the
  705. XPR must check that the desired function is indeed present by ensuring that
  706. xpr_extension is larger than the position of the function beyond the xpr_data
  707. field.
  708.  
  709.  
  710. 3.19    long  *xpr_data;
  711. ------------------------
  712.  
  713.         This field is for internal use by the external protocol. Typically the
  714. field is initialized to point to a structure containing information extracted
  715. from the initialization string handed to or retrieved by the XProtocolSetup()
  716. function, see section 2. The structure should be deallocated and the field
  717. restored to NULL by the XProtocolCleanup() function. The communications program
  718. should never access this field, except when initializing the XPR_IO structure:
  719. the field should be initialized to NULL.
  720.  
  721.  
  722. 3.20    long  *xpr_options();
  723. -----------------------------
  724.  
  725.         This function is in the first extension field of the XPR_IO structure.
  726. Only use this function if the value of the xpr_extension field is 1L or larger.
  727. The calling sequence is:
  728.  
  729.         long status = (*xpr_options)(long n, struct xpr_option *opt[])
  730.         D0                           D0      A0
  731.  
  732. The function passes to the comm program a pointer to an array of n pointers to
  733. xpr_option structures, where n is limited to 31. The xpr_option structures are
  734. defined as follows:
  735.  
  736. struct xpr_option {
  737.    char *xpro_description;      /* description of the option                  */
  738.    long  xpro_type;             /* type of option                             */
  739.    char *xpro_value;            /* pointer to a buffer with the current value */
  740.    long  xpro_length;           /* buffer size                                */
  741. }
  742.  
  743. Valid values for xpro_type are:
  744.  
  745. #define XPRO_BOOLEAN 1L         /* xpro_value is "yes", "no", "on" or "off"   */
  746. #define XPRO_LONG    2L         /* xpro_value is string representing a number */
  747. #define XPRO_STRING  3L         /* xpro_value is a string                     */
  748.  
  749.         The array is allocated and initialized by the XPR to default values. If
  750. the comm program implements this function, it should display the description of
  751. the option and its current value to the user and allow him/her to change them.
  752. This could be accomplished either by dynamically building a requester or by
  753. displaying each line one at a time and allow the user to enter new values or
  754. accept the default. Options that have boolean values could be implemented by the
  755. comm program as boolean gadgets, but the new value must be returned as "yes" or
  756. "on" for logical 1 or "no" or "off" for logical 0 in the xpro_value buffer, and
  757. that long values must be converted to a string and copied to the xpro_value
  758. buffer. Note, that the XPR, if it uses this function must recognize both "yes"
  759. and "on" for logical 1 and "no" and "off" for logical 0. For options that have
  760. string values, the comm program must ensure that the new string selected by the
  761. user fits in the value buffer as determined by the xpro_length field. The buffer
  762. is supplied by the XPR, and must be large enough to be able to hold the '\0'
  763. termination.
  764.         For example, when selecting a ZMODEM based XPR the following array of
  765. xpr_option structures could be passed to the comm program:
  766.  
  767. xpro_description                xpro_value    xpro_type
  768. --------------------------------------------------------------
  769. Convert NL to NL/CR             no            XPRO_BOOLEAN
  770. Escape only CTRL chars          yes           XPRO_BOOLEAN
  771. Escape ALL chars                no            XPRO_BOOLEAN
  772. Send full pathname              yes           XPRO_BOOLEAN
  773. Send 1K blocks                  no            XPRO_BOOLEAN
  774. Subpacket length                512           XPRO_LONG
  775. Disable 32-bit CRC              no            XPRO_BOOLEAN
  776. Protect destination file        no            XPRO_BOOLEAN
  777. Timeout value (sec)             10            XPRO_LONG
  778. Delete after transmission       no            XPRO_BOOLEAN
  779. Overwrite existing file         no            XPRO_BOOLEAN
  780.  
  781. Notice again, that the COMM program still knows nothing about the individual
  782. option items (and in fact there is no way for it to find out, in keeping with
  783. the philosophy of XPR). Also notice that a cheap way to implement this function
  784. is to loop over the n supplied xpr_option's and to call the likely already
  785. implemented xpr_gets function with the option description and the value buffer.
  786.         It is important to follow a few rules when calling this function: the
  787. description strings should be 25 characters or less. The value strings can be
  788. any length up to 255 characters, but be aware that in a typical situation only
  789. about 10 to 15 of them will be displayed in a string requester.
  790.         The return value, status, reflects which options have changed by having
  791. the corresponding bit set. The first option in the xpr_option array corresponds
  792. to  bit 0 (low-order), etc. If the comm program decides to not detect whether
  793. the options changed or not, 0x07FFFFFFL may be returned, in effect specifying
  794. that all options have changed. If nothing changed, 0L is returned. If an error
  795. occurred, the function returns -1L.
  796.  
  797.  
  798.  
  799.  
  800. 4. An example protocol.
  801. =======================
  802.  
  803.         The following is an annotated listing of an ascii upload protocol.
  804. Notice that the files supplied in this archive are likely more up to date and
  805. more extensive than the example given here.
  806.  
  807. /** xprascii.c
  808. *
  809. *   These are the protocol transfer routines for a simple ASCII upload.
  810. *
  811. **/
  812. #include <exec/exec.h>
  813. #include <functions.h>
  814. #include <stdio.h>
  815. /*
  816. *   xproto.h is the include file given in Appendix B.
  817. */
  818. #include "xproto.h"
  819. /*
  820. *   The following two strings must exist.
  821. */
  822. char  XPRname[]   = "xprascii.library";
  823. char  XPRid[]     = "xprascii 0.9 (May 89)\r\n";
  824. UWORD XPRrevision = 9;
  825.  
  826. long atol();
  827. /*
  828. *   The callxx...() routines are described later. They provide the 
  829. *   assembler interface from the XPR library to the call-back routines.
  830. */
  831. long calla(), callaa(), callad(), calladd(), calladda();
  832.  
  833. char *malloc();
  834.  
  835.  
  836. /**
  837. *
  838. *   Send a file
  839. *
  840. **/
  841. long XProtocolSend(IO)
  842. struct XPR_IO *IO;
  843. {
  844.    long fp, r, i;
  845.    long brkflag = 0, fl = 0L, sd = 0L;
  846.    long (*xupdate)(), (*xswrite)(), (*xfopen)(), (*xfclose)(), (*xfread)(),
  847.         (*xsread)(),  (*xchkabort)();
  848.    unsigned char *buff = NULL, *serbuff = NULL;
  849.    struct XPR_UPDATE xpru;
  850.  
  851. /*
  852. *   These are the call-backs we need. If any of them isn't provided, quit.
  853. *   Could do some error reporting if at least xupdate is there.
  854. */
  855.    if ((xupdate    = IO->xpr_update)   == NULL) return(0L);
  856.    if ((xswrite    = IO->xpr_swrite)   == NULL) return(0L);
  857.    if ((xfopen     = IO->xpr_fopen)    == NULL) return(0L);
  858.    if ((xfclose    = IO->xpr_fclose)   == NULL) return(0L);
  859.    if ((xfread     = IO->xpr_fread)    == NULL) return(0L);
  860.    if ((xsread     = IO->xpr_sread)    == NULL) return(0L);
  861.    if ((xchkabort  = IO->xpr_chkabort) == NULL) return(0L);
  862. /*
  863. *   Allocate a few buffers.
  864. */
  865.    buff    = (unsigned char *) malloc(80);
  866.    serbuff = (unsigned char *) malloc(80);
  867. /*
  868. *   If we ran out of memory, print a message.
  869. *   The argument needs to go in A0: calla does this for us. 
  870. */
  871.    if (buff == NULL || serbuff == NULL) {
  872.       xpru.xpru_updatemask = XPRU_ERRORMSG;
  873.       xpru.xpru_errormsg   = "Ran out of memory!";
  874.       calla(xupdate, &xpru);
  875.       return(0L);
  876.    }
  877. /*
  878. *   Read the send delay, if a XProtocolSetup() was done before.
  879. *   If send delay is too large, cut it off at 10 seconds.
  880. *   In this example, the xpr_data field contains a null terminated string
  881. *   containing the number of ticks to delay each 80 characters.
  882. */
  883.    if (IO->xpr_data) {
  884.       sd = atol(IO->xpr_data);
  885.       if (sd > 500L) sd = 500L;
  886.    }
  887. /*
  888. *   Open the file. One could do wild card detection here.
  889. *   xfopen requires two arguments, in a0 and a1 respectively.
  890. *   Again, this must be done in assembler, and callaa does it.
  891. */
  892.    fp = callaa(xfopen, IO->xpr_filename, "r");
  893.    if (fp == NULL) {
  894.       free(buff);
  895.       free(serbuff);
  896.       xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_FILENAME;
  897.       xpru.xpru_errormsg   = "Failed to open input file";
  898.       xpru.xpru_filename   = IO->xpr_filename;
  899.       calla(xupdate, &xpru);
  900.       return(0L);
  901.    }
  902. /*
  903. *   Start the transfer. See 3.8 for a discussion on how to implement
  904. *   xupdate. 
  905. */
  906.    xpru.xpru_updatemask = XPRU_MSG | XPRU_FILENAME;
  907.    xpru.xpru_msg        = "Starting ASCII Send";
  908.    xpru.xpru_filename   = IO->xpr_filename;
  909.    calla(xupdate, &xpru);
  910. /*
  911. *   Now read 80 byte chunks from the file using xfread.
  912. *   xfread requires four arguments, a0, d0, d1 and a1.
  913. */
  914.    xpru.xpru_blocks = 0L;
  915.    while (r = calladda(xfread, buff, 1L, 80L, fp)) {
  916. /*
  917. *   Convert line feeds to carriage returns before sending to host.
  918. *   fl counts the characters. Display how many characters are sent.
  919. */
  920.       for (i = 0L; i < r; i++) if (buff[i] == '\n') buff[i] = '\r';
  921.       fl += r;
  922.       xpru.xpru_updatemask = XPRU_BYTES | XPRU_BLOCKS | XPRU_BLOCKSIZE;
  923.       xpru.xpru_bytes      = fl;
  924.       xpru.xpru_blocks++;
  925.       xpru.xpru_blocksize  = r;
  926.       calla(xupdate, &xpru);
  927.       callad(xswrite, buff, r);
  928. /*
  929. *   Every 80 bytes, put out a message and delay if requested.
  930. */
  931.       xpru.xpru_updatemask  = XPRU_PACKETDELAY;
  932.       xpru.xpru_packetdelay = sd * 20L;  /* msec! */
  933.       calla(xupdate, &xpru);
  934. /*
  935. *   Can't use Delay() here, because Delay() is in dos.library!
  936. *   However writing an equivalent function using the timer.device is
  937. *   trivial.
  938. */
  939.       TimeOut(sd);
  940. /*
  941. *   Eat any characters that might arrive from the serial port.
  942. *   calladd stores arg1 in a0, arg2 in d0, arg3 in d1.
  943. *   We're not really waiting for any characters: use a timeout of 0L.
  944. */
  945.       while (calladd(xsread, serbuff, 80L, 0L) > 0L) ;
  946. /*
  947. *   Check for "abort" here. Perhaps should call chkmisc() as well.
  948. */
  949.       if (brkflag = xchkabort()) break;
  950.    }
  951. /*
  952. *   Close the file
  953. */
  954.    calla(xfclose, fp);
  955.    free(buff);
  956.    free(serbuff);
  957. /*
  958. *   If we got here through chkabort() say Aborted.
  959. */
  960.    xpru.xpru_updatemask       = XPRU_MSG;
  961.    if (brkflag) xpru.xpru_msg = "Aborted";
  962.    else         xpru.xpru_msg = "Done"; 
  963.    calla(xupdate, &xpru);
  964.    if (brkflag) return(0L);
  965.    else         return(1L);
  966. }
  967.  
  968.  
  969. /**
  970. *
  971. *   Receive a file.
  972. *
  973. **/
  974. long XProtocolReceive(IO)
  975. struct XPR_IO *IO;
  976. {
  977.    long fp, r, i;
  978.    long brkflag = 0, fl = 0L, sd = 0L;
  979.    long (*xupdate)(), (*xswrite)(), (*xfopen)(), (*xfclose)(), (*xfwrite)(),
  980.         (*xsread)(),  (*xchkabort)();
  981.    unsigned char *serbuff = NULL;
  982.    struct XPR_UPDATE xpru;
  983.  
  984. /*
  985. *   These are the call-backs we need. If any of them isn't provided, quit.
  986. *   Could do some error reporting if at least xupdate is there.
  987. */
  988.    if ((xupdate    = IO->xpr_update)   == NULL) return(0L);
  989.    if ((xswrite    = IO->xpr_swrite)   == NULL) return(0L);
  990.    if ((xfopen     = IO->xpr_fopen)    == NULL) return(0L);
  991.    if ((xfclose    = IO->xpr_fclose)   == NULL) return(0L);
  992.    if ((xfwrite    = IO->xpr_fwrite)   == NULL) return(0L);
  993.    if ((xsread     = IO->xpr_sread)    == NULL) return(0L);
  994.    if ((xchkabort  = IO->xpr_chkabort) == NULL) return(0L);
  995. /*
  996. *   Allocate a buffer.
  997. */
  998.    serbuff = (unsigned char *) malloc(80);
  999. /*
  1000. *   If we ran out of memory, print a message.
  1001. *   The argument needs to go in A0: calla does this for us. 
  1002. */
  1003.    if (serbuff == NULL) {
  1004.       xpru.xpru_updatemask = XPRU_ERRORMSG;
  1005.       xpru.xpru_errormsg   = "Ran out of memory!";
  1006.       calla(xupdate, &xpru);
  1007.       return(0L);
  1008.    }
  1009. /*
  1010. *   Open the file.
  1011. *   xfopen requires two arguments, in a0 and a1 respectively.
  1012. *   Again, this must be done in assembler, and callaa does it.
  1013. */
  1014.    fp = callaa(xfopen, IO->xpr_filename, "w");
  1015.    if (fp == NULL) {
  1016.       free(serbuff);
  1017.       xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_FILENAME;
  1018.       xpru.xpru_errormsg   = "Failed to open output file";
  1019.       xpru.xpru_filename   = IO->xpr_filename;
  1020.       calla(xupdate, &xpru);
  1021.       return(0L);
  1022.    }
  1023. /*
  1024. *   Start the transfer. See 3.8 for a discussion on how to implement
  1025. *   xupdate. 
  1026. */
  1027.    xpru.xpru_updatemask = XPRU_MSG | XPRU_FILENAME;
  1028.    xpru.xpru_msg        = "Starting ASCII Receive";
  1029.    xpru.xpru_filename   = IO->xpr_filename;
  1030.    calla(xupdate, &xpru);
  1031. /*
  1032. *   Now read 80 byte chunks from the serial port using xsread. Stop
  1033. *   when no characters arrive for 5 sec.
  1034. */
  1035.    xpru.xpru_blocks = 0L;
  1036.    while ((r = calladd(xsread, serbuff, 80L, 5000000L)) > 0L)  {
  1037. /*
  1038. *   Strip high-bit before storing in file.
  1039. *   fl counts the characters. Display how many characters are received.
  1040. */
  1041.       for (i = 0L; i < r; i++) serbuff[i] &= 0177;
  1042.       fl += r;
  1043.       xpru.xpru_updatemask = XPRU_BYTES | XPRU_BLOCKS | XPRU_BLOCKSIZE;
  1044.       xpru.xpru_bytes      = fl;
  1045.       xpru.xpru_blocks++;
  1046.       xpru.xpru_blocksize  = r;
  1047.       calla(xupdate, &xpru);
  1048. /* 
  1049. *   Write 80 byte chunks to the file using xwrite
  1050. */
  1051.       calladda(xfwrite, serbuff, 1L, r, fp);
  1052.  
  1053. /*
  1054. *   Check for "abort" here. Perhaps should call chkmisc() as well.
  1055. */
  1056.       if (brkflag = xchkabort()) break;
  1057.    }
  1058. /*
  1059. *   Close the file
  1060. */
  1061.    calla(xfclose, fp);
  1062.    free(serbuff);
  1063. /*
  1064. *   If we got here through chkabort() say Aborted.
  1065. */
  1066.    xpru.xpru_updatemask       = XPRU_MSG;
  1067.    if (brkflag) xpru.xpru_msg = "Aborted";
  1068.    else         xpru.xpru_msg = "Done"; 
  1069.    calla(xupdate, &xpru);
  1070.    if (brkflag) return(0L);
  1071.    else         return(1L);
  1072. }
  1073.  
  1074.  
  1075. /**
  1076. *
  1077. *   Setup
  1078. *
  1079. **/
  1080. long XProtocolSetup(IO)
  1081. struct XPR_IO *IO;
  1082. {
  1083.    long (*xupdate)(), (*xgets)();
  1084.    struct XPR_UPDATE xpru;
  1085.  
  1086.    if ((xupdate = IO->xpr_update) == NULL) return(0L);
  1087.    if ((xgets   = IO->xpr_gets)   == NULL) return(0L);
  1088. /*
  1089. *   Allocate a bit of memory for a data buffer
  1090. */
  1091.    if (IO->xpr_data == NULL) {
  1092.       if ((IO->xpr_data = (long *) malloc(256)) == NULL) {
  1093.          xpru.xpru_updatemask = XPRU_ERRORMSG;
  1094.          xpru.xpru_errormsg   = "ASCII - Out of memory!";
  1095.          calla(xupdate, &xpru);
  1096.          return(0L);
  1097.       }
  1098.    }
  1099. /*
  1100. *   If setup string isn't handed to us, ask questions
  1101. */
  1102.    if (IO->xpr_filename == NULL) {
  1103. /*
  1104. *   Get the value for the send dealy
  1105. */
  1106.       callaa(xgets, "Enter ASCII send delay (ticks, 1 tick = 20 msec)",
  1107.                   IO->xpr_data);
  1108.    }
  1109.    else {
  1110.       strcpy(IO->xpr_data, IO->xpr_filename);
  1111.    }
  1112.    
  1113.    return(1L);
  1114. }
  1115.  
  1116. /**
  1117. *
  1118. *   Cleanup
  1119. *
  1120. **/
  1121. long XProtocolCleanup(IO)
  1122. struct XPR_IO *IO;
  1123. {
  1124.    if (IO->xpr_data) free(IO->xpr_data);
  1125.    IO->xpr_data = NULL;
  1126.  
  1127.    return(1L);
  1128. }
  1129.  
  1130. /**
  1131. *
  1132. *   The following functions setup the proper registers for the call-back 
  1133. *   functions.
  1134. *
  1135. **/
  1136. #asm
  1137.         public _callad
  1138. _callad:
  1139.         movea.l 8(sp),a0                ; Second argument goes in a0
  1140.         move.l  12(sp),d0               ; Third  argument goes in d0
  1141. /*
  1142. *   Now this is a trick to avoid using another register.
  1143. *   Charlie taught me this...
  1144. */
  1145.         move.l  4(sp),-(sp)             ; First  argument is function
  1146.         rts
  1147.  
  1148.         public  _calladda
  1149. _calladda:
  1150.         movea.l 8(sp),a0                ; Second argument goes in a0
  1151.         move.l  12(sp),d0               ; Third  argument goes in d0
  1152.         move.l  16(sp),d1               ; Fourth argument goes in d1
  1153.         movea.l 20(sp),a1               ; Fifth  argument goes in a1
  1154.         move.l  4(sp),-(sp)             ; First  argument is function
  1155.         rts
  1156.  
  1157.         public  _calla
  1158. _calla:
  1159.         movea.l 8(sp),a0                ; Second argument goes in a0
  1160.         move.l  4(sp),-(sp)             ; First  argument is function
  1161.         rts
  1162.  
  1163.         public  _callaa
  1164. _callaa:
  1165.         movea.l 8(sp),a0                ; Second argument goes in a0
  1166.         movea.l 12(sp),a1               ; Third  argument goes in a1
  1167.         move.l  4(sp),-(sp)             ; First  argument is function
  1168.         rts
  1169.  
  1170.         public  _calladd
  1171. _calladd:
  1172.         move.l  8(sp),a0                ; Second argument goes in a0
  1173.         move.l  12(sp),d0               ; Third  argument goes in d0
  1174.         move.l  16(sp),d1               ; Fourth argument goes in d1
  1175.         move.l  4(sp),-(sp)             ; First  argument is function
  1176.         rts
  1177.  
  1178. #endasm
  1179. /*
  1180. *   Could have added any other functions needed for other call-backs.
  1181. *   Could have written a fancier single one... Could've...
  1182. */
  1183.                               __                
  1184.                              /  \ o    /        
  1185.                        -----/----\----/-----
  1186.                            /    o \__/          
  1187.                                                 
  1188.         Clearly it isn't very hard to implement a simple protocol. More
  1189. elaborate protocols are straightforward extensions to the above example. Of
  1190. course, there are a few more standard files needed to make the above example
  1191. into a complete library (like Open, Close and Expunge functions and a ROM-Tag
  1192. structure) but those parts are the same for any library and aren't given here.
  1193.  
  1194.  
  1195.  
  1196. 5. The interface to the communications program.
  1197. ===============================================
  1198.  
  1199.         The following is an annotated listing of a few call-back functions as
  1200. they are implemented in VLT. Also, it is shown how to initialize the XPR_IO
  1201. structure. Notice that the files supplied in this archive are likely more up to
  1202. date and more extensive than the minimal example given here.
  1203.  
  1204. /** xprfuncs.c
  1205. *
  1206. *   Call-back functions for eXternal PRotocol support
  1207. *
  1208. **/
  1209. #include <functions.h>
  1210. #include <exec/exec.h>
  1211. #include <stdio.h>
  1212. /*
  1213. *   xproto.h is given in Appendix B
  1214. */
  1215. #include "xproto.h"
  1216. /*
  1217. *   xfer.h is a VLT private header file containing some information for
  1218. *   file transfer protocols
  1219. */
  1220. #include "xfer.h"
  1221.  
  1222. /*
  1223. *   These are the C versions of the interface
  1224. */
  1225. long        vlt_update(),  vlt_swrite(),  vlt_fread(),  vlt_fopen(),
  1226.             vlt_fclose(),  vlt_gets(),    vlt_sread(),  vlt_chkabort();
  1227. /*
  1228. *   These are the assembly level glue functions, see vltface.asm
  1229. */
  1230. extern long avlt_update(), avlt_swrite(), avlt_fread(), avlt_fopen(),
  1231.             avlt_fclose(), avlt_gets(),   avlt_sread(), avlt_chkabort();
  1232.  
  1233. /**
  1234. *
  1235. *   This function initializes an XPR_IO structure.
  1236. *
  1237. **/
  1238. xpr_setup(IO)
  1239. struct XPR_IO *IO;
  1240. {
  1241. /*
  1242. *   NULL out all the functions we don't do yet.
  1243. *   Fill the other ones with the addresses to the assembler glue version
  1244. *   of the interface routines. See vltface.asm
  1245. */
  1246.    IO->xpr_filename  = NULL;
  1247.    IO->xpr_fopen     = avlt_fopen;
  1248.    IO->xpr_fclose    = avlt_fclose;
  1249.    IO->xpr_fread     = avlt_fread;
  1250.    IO->xpr_fwrite    = NULL;
  1251.    IO->xpr_sread     = avlt_sread;
  1252.    IO->xpr_swrite    = avlt_swrite;
  1253.    IO->xpr_sflush    = NULL;
  1254.    IO->xpr_update    = avlt_update;
  1255.    IO->xpr_chkabort  = avlt_chkabort;
  1256.    IO->xpr_chkmisc   = NULL;
  1257.    IO->xpr_gets      = avlt_gets;
  1258.    IO->xpr_setserial = NULL;
  1259.    IO->xpr_ffirst    = NULL;
  1260.    IO->xpr_fnext     = NULL;
  1261.    IO->xpr_finfo     = NULL;
  1262.    IO->xpr_fseek     = NULL;
  1263. /*
  1264. *   Support the 1 defined extension
  1265. */
  1266.    IO->xpr_extension = 1L;
  1267. /*
  1268. *   But don't actually implement it yet.
  1269. */
  1270.    IO->xpr_options   = NULL
  1271. /*
  1272. *   Especially, NULL out the XPR private data field.
  1273. */
  1274.    IO->xpr_data      = NULL;
  1275.  
  1276.    return;
  1277. }
  1278.  
  1279. /**
  1280. *
  1281. *   Interface to VLT's MsgDisplay() function.
  1282. *
  1283. **/
  1284. /*
  1285. *   These are formats for VLT's requester
  1286. */
  1287. static char *xprnamfmt = "%s\n%s\n\n\n\n";
  1288. static char *filnamfmt = "\n\n%s\n\n\n";
  1289. static char *blksizfmt = "\n\n\n\nBlock:  %6ld  --  Block Size:  %6ld\n";
  1290. static char *errtimfmt = "\n\n\n\n\nErrors: %6ld  --  Timeouts:    %6ld";
  1291. static char *delayfmt  = "\n\n\n\n\nPacket delay %ld";
  1292. /*
  1293. *   Below are some VLT globals to orchestrate the display
  1294. */
  1295. long xpr_blocks = 0L, xpr_blocksize = 0L, xpr_errors = 0L, xpr_timeouts = 0L;
  1296. /*
  1297. *   The function
  1298. */
  1299. long vlt_update(x)
  1300. struct XPR_UPDATE *x;
  1301. {
  1302.    extern struct Window *mywindow;
  1303.    extern char *XPR_Name;
  1304. /*
  1305. *   First time, determine the window size (50 chars wide, 5 lines tall).
  1306. */
  1307.    SetMsgWindow(mywindow, 50, 6);
  1308. /*
  1309. *   Use VLT's PostMsg function to display all the information.
  1310. */
  1311.    if (x->xpru_updatemask & XPRU_PROTOCOL) {
  1312.       PostMsg(mywindow, xprnamfmt, XPR_Name, x->xpru_protocol);
  1313.    }
  1314.    if (x->xpru_updatemask & XPRU_MSG) {
  1315.       PostMsg(mywindow, xprnamfmt, XPR_Name, x->xpru_msg);
  1316.    }
  1317.    if (x->xpru_updatemask & XPRU_ERRORMSG) {
  1318.       PostMsg(mywindow, xprnamfmt, XPR_Name, x->xpru_errormsg);
  1319.    }
  1320.    if (x->xpru_updatemask & XPRU_FILENAME) {
  1321.       PostMsg(mywindow, filnamfmt, x->xpru_filename);
  1322.    }
  1323.    if (x->xpru_updatemask & XPRU_PACKETDELAY) {
  1324.       PostMsg(mywindow, delayfmt, x->xpru_packetdelay);
  1325.    }
  1326.    if (x->xpru_updatemask & (XPRU_BLOCKS | XPRU_BLOCKSIZE)) {
  1327.       if (x->xpru_updatemask & XPRU_BLOCKS)    xpr_blocks    = x->xpru_blocks;
  1328.       if (x->xpru_updatemask & XPRU_BLOCKSIZE) xpr_blocksize = x->xpru_blocksize;
  1329.       PostMsg(mywindow, blksizfmt, xpr_blocks, xpr_blocksize);
  1330.    }
  1331.    if (x->xpru_updatemask & (XPRU_ERRORS | XPRU_TIMEOUTS)) {
  1332.       if (x->xpru_updatemask & XPRU_ERRORS)   xpr_errors   = x->xpru_errors;
  1333.       if (x->xpru_updatemask & XPRU_TIMEOUTS) xpr_timeouts = x->xpru_timeouts;
  1334.       PostMsg(mywindow, errtimfmt, xpr_errors, xpr_timeouts);
  1335.    }
  1336.    return(0L);
  1337. }
  1338.  
  1339. /**
  1340. *
  1341. *   Prompt the user for input
  1342. *
  1343. **/
  1344. long vlt_gets(s, t)
  1345. char *s, *t;
  1346. {
  1347. /*
  1348. *   Use VLT's DoRequest() function
  1349. */
  1350.    return((long) DoRequest(mywindow, t, s, NULL, " Cancel "));
  1351. }
  1352.  
  1353. /**
  1354. *
  1355. *   Write a string to the serial port
  1356. *
  1357. **/
  1358. long vlt_swrite(s, n)
  1359. char *s;
  1360. long n;
  1361. {
  1362. /*
  1363. *   Use VLT's SendString() function
  1364. */
  1365.    SendString(s, (int) n);
  1366.    return(0L);
  1367. }
  1368.  
  1369. /**
  1370. *
  1371. *   Read characters from the serial port
  1372. *
  1373. **/
  1374. long vlt_sread(buff, length, micros)
  1375. unsigned char *buff;
  1376. long length, micros;
  1377. {
  1378.    extern int timeout;
  1379.    long secs = 0L;
  1380.  
  1381.    if (buff == NULL) return(-1L);
  1382. /*
  1383. *   Convert timeout to seconds and micros if necessary
  1384. */
  1385.    if (micros) {
  1386.       if (micros > 1000000L) {
  1387.          secs   = micros / 1000000L;
  1388.          micros = micros % 1000000L;
  1389.       }
  1390.    }
  1391. /*
  1392. *   Cheat! Only return a single character since we have such a nice
  1393. *   readchar() function in VLT. One day I'll have to modify this to 
  1394. *   save the odd microsecond...
  1395. */
  1396.    buff[0] = (unsigned char) readchar(secs, micros);
  1397. /*
  1398. *   VLT has a global called timeout. This comes in xfer.h.
  1399. *   If the read was successful, return having read a single character.
  1400. */
  1401.    if (timeout == GOODREAD) return(1L);
  1402. /*
  1403. *   Else return error condition
  1404. */
  1405.    return(-1L);
  1406. }
  1407.  
  1408. /**
  1409. *
  1410. *   Interfaces to stdio
  1411. *
  1412. **/
  1413. long vlt_fopen(s, t)
  1414. char *s, *t;
  1415. {
  1416.    return((long) fopen(s, t));
  1417. }
  1418.  
  1419. long vlt_fclose(fp)
  1420. FILE *fp;
  1421. {
  1422.    return((long) fclose(fp));
  1423. }
  1424.  
  1425. long vlt_fread(buff, size, count, fp)
  1426. char *buff;
  1427. long size, count;
  1428. FILE *fp;
  1429. {
  1430.    int res;
  1431.    res = fread(buff, (int) size, (int) count, fp);
  1432.    return((long) res);
  1433. }
  1434.  
  1435. /**
  1436. *
  1437. *   Check for Abort
  1438. *
  1439. **/
  1440. long vlt_chkabort()
  1441. {
  1442. /*
  1443. *   VLT aborts its protocols when the escape key is pressed.
  1444. *   CheckForKey loops over the UserPort messages looking for an escape.
  1445. */
  1446.    return((long) CheckForKey(69));
  1447. }
  1448.                               __                
  1449.                              /  \ o    /        
  1450.                        -----/----\----/-----
  1451.                            /    o \__/          
  1452.                                                 
  1453.         Clearly, this part of the implementation isn't hard either. The only
  1454. thing left is the assembly level glue on the communications program side. You
  1455. may wonder at this point why all this assembly level stuff is necessary. It is
  1456. necessary because many programs and libraries are written in small code/small
  1457. data. This means that both the communications program and the library address
  1458. their code/data off of some register, in the case of Manx usually A4. The
  1459. problem is that the communications program and the library are loaded in
  1460. different parts of memory, while startup code takes care of setting up the
  1461. proper value for A4. And the values of A4 are different for the the
  1462. communications program and the library! Now, if you just call a library
  1463. function, the assembly level glue does a few things, among which are: (1) saving
  1464. the caller's A4 somewhere safe and (2) retrieving the A4 it stored somewhere
  1465. when the library was loaded. Then the library function is executed, and the
  1466. function returns to the glue. The glue then restores A4 to the state it was in
  1467. before the library call.
  1468.         In the case of these call-back functions, we have to do the reverse.
  1469. After all, when a function like xpr_update is called, the current value of A4 is
  1470. the one that goes with the library's code. If the call-back function tries to
  1471. access any data back in the communications program, we're in big trouble.
  1472.         So what the assembly part of the call-backs has to do is (1) save the
  1473. library's A4 (on the stack) and (2) get the value of A4 appropriate for the
  1474. communications program. Then we can push the various registers onto the stack,
  1475. call the C version of the call-back and then restore the value of A4 to what the
  1476. library wants.
  1477.         For the above call-backs, the assembly level glue is listed below. This
  1478. concludes the documentation on external protocols using Amiga shared libraries.
  1479. If you have any questions, comments or suggestions, contact me on BIX.
  1480.         Meanwhile, have fun!
  1481.  
  1482. ;;; vltface.asm
  1483. ;
  1484. ;   DESCRIPTION:
  1485. ;   ===========
  1486. ;
  1487. ;        This is an interface to VLT callback functions from
  1488. ;        external protocol libraries.
  1489. ;
  1490. ;   AUTHOR/DATE:  W.G.J. Langeveld, March 1989.
  1491. ;   ============
  1492. ;
  1493. ;;;
  1494.  
  1495.         public  _geta4
  1496.  
  1497. setup   macro
  1498.         movem.l d2/d3/d4-d7/a2-a6,-(sp)
  1499.         jsr     _geta4                        ; Get a4.
  1500.         endm
  1501.  
  1502. push    macro
  1503.         move.l  \1,-(sp)
  1504.         endm
  1505.  
  1506. fix     macro
  1507.         ifc     '\1',''
  1508.                 mexit
  1509.         endc
  1510.         ifle    \1-8
  1511.                 addq.l  #\1,sp
  1512.         endc
  1513.         ifgt    \1-8
  1514.                 lea     \1(sp),sp
  1515.         endc
  1516.         endm
  1517.  
  1518. restore macro
  1519.         fix     \1
  1520.         movem.l (sp)+,d2/d3/d4-d7/a2-a6        
  1521.         rts
  1522.         endm
  1523.  
  1524.         public  _avlt_fopen
  1525.         public  _vlt_fopen
  1526.         public  _avlt_fclose
  1527.         public  _vlt_fclose
  1528.         public  _avlt_fread
  1529.         public  _vlt_fread
  1530.         public  _avlt_sread
  1531.         public  _vlt_sread
  1532.         public  _avlt_swrite
  1533.         public  _vlt_swrite
  1534.         public  _avlt_update
  1535.         public  _vlt_update
  1536.         public  _avlt_chkabort
  1537.         public  _vlt_chkabort
  1538.         public  _avlt_gets
  1539.         public  _vlt_gets
  1540.  
  1541. _avlt_fopen:
  1542.         setup
  1543.         push    a1
  1544.         push    a0
  1545.         jsr     _vlt_fopen
  1546.         restore 8
  1547.  
  1548. _avlt_fclose:
  1549.         setup
  1550.         push    a0
  1551.         jsr     _vlt_fclose
  1552.         restore 4
  1553.  
  1554. _avlt_fread:
  1555.         setup
  1556.         push    a1
  1557.         push    d1
  1558.         push    d0
  1559.         push    a0
  1560.         jsr     _vlt_fread
  1561.         restore 16
  1562.  
  1563. _avlt_sread:
  1564.         setup
  1565.         push    d1
  1566.         push    d0
  1567.         push    a0
  1568.         jsr     _vlt_sread
  1569.         restore 12
  1570.  
  1571. _avlt_swrite:
  1572.         setup
  1573.         push    d0
  1574.         push    a0
  1575.         jsr     _vlt_swrite
  1576.         restore 8
  1577.  
  1578. _avlt_update:
  1579.         setup
  1580.         push    a0
  1581.         jsr     _vlt_update
  1582.         restore 4
  1583.  
  1584. _avlt_chkabort:
  1585.         setup
  1586.         jsr     _vlt_chkabort
  1587.         restore
  1588.  
  1589. _avlt_gets:
  1590.         setup
  1591.         push    a1
  1592.         push    a0
  1593.         jsr     _vlt_gets
  1594.         restore 8
  1595.  
  1596.                               __                
  1597.                              /  \ o    /        
  1598.                        -----/----\----/-----
  1599.                            /    o \__/          
  1600.                                                 
  1601.  
  1602.  
  1603.  
  1604.  
  1605.  
  1606.  
  1607.  
  1608. Appendix A: XPR library skeleton.
  1609. =================================
  1610.  
  1611. ;;; libface.asm
  1612. ;
  1613. ;   DESCRIPTION:
  1614. ;   ===========
  1615. ;
  1616. ;        This is the skeleton for an Amiga Exec library.
  1617. ;        This version is written for Aztec C. It is based on the example
  1618. ;        library by Jim Mackraz who got some stuff from Neil Katin.
  1619. ;        This library implements a protocol transfer library.
  1620. ;        All changes and additions by me.
  1621. ;
  1622. ;   AUTHOR/DATE:  W.G.J. Langeveld, February 1989.
  1623. ;   ============
  1624. ;
  1625. ;;;
  1626.  
  1627.         include 'exec/types.i'
  1628.  
  1629. setup   macro
  1630.         movem.l d2/d3/d4-d7/a2-a6,-(sp)
  1631.         jsr     _geta4                        ;set up a4 for small model
  1632.         endm
  1633.  
  1634. push    macro
  1635.         move.l  \1,-(sp)
  1636.         endm
  1637.  
  1638. fix     macro
  1639.         ifc     '\1',''
  1640.                 mexit
  1641.         endc
  1642.         ifle    \1-8
  1643.                 addq.l        #\1,sp
  1644.         endc
  1645.         ifgt    \1-8
  1646.                 lea        \1(sp),sp
  1647.         endc
  1648.         endm
  1649.  
  1650. restore macro
  1651.         fix     \1
  1652.         movem.l (sp)+,d2/d3/d4-d7/a2-a6        
  1653.         rts
  1654.         endm
  1655.  
  1656.         dseg
  1657.  
  1658.         public  _libfunctab
  1659. _libfunctab:
  1660.         dc.l    XPRopen
  1661.         dc.l    XPRclose
  1662.         dc.l    XPRexpunge
  1663.         dc.l    $0000
  1664.         dc.l    XPRXProtocolCleanup
  1665.         dc.l    XPRXProtocolSetup
  1666.         dc.l    XPRXProtocolSend
  1667.         dc.l    XPRXProtocolReceive
  1668.         dc.l    $ffffffff
  1669.  
  1670.         cseg
  1671.  
  1672.         ;=== library functions
  1673.         public  _XPROpen
  1674.         public  _XPRClose
  1675.         public  _XPRExpunge
  1676.         public  _XProtocolCleanup
  1677.         public  _XProtocolSetup
  1678.         public  _XProtocolSend
  1679.         public  _XProtocolReceive
  1680.  
  1681.         public  _geta4
  1682.  
  1683. XPRopen:
  1684.         setup
  1685.         push    a6
  1686.         jsr     _XPROpen
  1687.         restore 4
  1688.  
  1689. XPRclose:
  1690.         setup
  1691.         push    a6
  1692.         jsr     _XPRClose
  1693.         restore 4
  1694.  
  1695. XPRexpunge:
  1696.         setup
  1697.         push    a6
  1698.         jsr     _XPRExpunge
  1699.         restore 4
  1700.  
  1701. XPRXProtocolCleanup:
  1702.         setup
  1703.         push    a0
  1704.         jsr     _XProtocolCleanup
  1705.         restore 4
  1706.  
  1707. XPRXProtocolSetup:
  1708.         setup
  1709.         push    a0
  1710.         jsr     _XProtocolSetup
  1711.         restore 4
  1712.  
  1713. XPRXProtocolSend:
  1714.         setup
  1715.         push    a0
  1716.         jsr     _XProtocolSend
  1717.         restore 4
  1718.  
  1719. XPRXProtocolReceive:
  1720.         setup
  1721.         push    a0
  1722.         jsr     _XProtocolReceive
  1723.         restore 4
  1724.  
  1725.  
  1726.         end
  1727.  
  1728.  
  1729.  
  1730.  
  1731.  
  1732. Appendix B: The xproto.h include file
  1733. =====================================
  1734.  
  1735. /** xproto.h
  1736. *
  1737. *   Include file for External Protocol Handling
  1738. *
  1739. **/
  1740. /*
  1741. *   The structure
  1742. */
  1743. struct XPR_IO {
  1744.                   char  *xpr_filename;      /* File name(s)             */
  1745.                   long (*xpr_fopen)();      /* Open file                */
  1746.                   long (*xpr_fclose)();     /* Close file               */
  1747.                   long (*xpr_fread)();      /* Get char from file       */
  1748.                   long (*xpr_fwrite)();     /* Put string to file       */
  1749.                   long (*xpr_sread)();      /* Get char from serial     */
  1750.                   long (*xpr_swrite)();     /* Put string to serial     */
  1751.                   long (*xpr_sflush)();     /* Flush serial input buffer*/
  1752.                   long (*xpr_update)();     /* Print stuff              */
  1753.                   long (*xpr_chkabort)();   /* Check for abort          */
  1754.                   long (*xpr_chkmisc)();    /* Check misc. stuff        */
  1755.                   long (*xpr_gets)();       /* Get string interactively */
  1756.                   long (*xpr_setserial)();  /* Set and Get serial info  */
  1757.                   long (*xpr_ffirst)();     /* Find first file name     */
  1758.                   long (*xpr_fnext)();      /* Find next file name      */
  1759.                   long (*xpr_finfo)();      /* Return file info         */
  1760.                   long (*xpr_fseek)();      /* Seek in a file           */
  1761.                   long  *xpr_extension;     /* Number of extensions     */
  1762.                   long  *xpr_data;          /* Initialized by Setup.    */
  1763.                   long (*xpr_options)();    /* Multiple XPR options.    */
  1764.               };
  1765. /*
  1766. *   Number of defined extensions
  1767. */
  1768. #define XPR_EXTENSION 1L
  1769.  
  1770. /*
  1771. *   The functions
  1772. */
  1773. extern long XProtocolSend(),  XProtocolReceive(),
  1774.             XProtocolSetup(), XProtocolCleanup();
  1775. /*
  1776. *   The update structure
  1777. */
  1778. struct XPR_UPDATE {     long  xpru_updatemask;
  1779.                         char *xpru_protocol;
  1780.                         char *xpru_filename;
  1781.                         long  xpru_filesize;
  1782.                         char *xpru_msg;
  1783.                         char *xpru_errormsg;
  1784.                         long  xpru_blocks;
  1785.                         long  xpru_blocksize;
  1786.                         long  xpru_bytes;
  1787.                         long  xpru_errors;
  1788.                         long  xpru_timeouts;
  1789.                         long  xpru_packettype;
  1790.                         long  xpru_packetdelay;
  1791.                         long  xpru_chardelay;
  1792.                         char *xpru_blockcheck;
  1793.                         char *xpru_expecttime;
  1794.                         char *xpru_elapsedtime;
  1795.                         long  xpru_datarate;
  1796.                         long  xpru_reserved1;
  1797.                         long  xpru_reserved2;
  1798.                         long  xpru_reserved3;
  1799.                         long  xpru_reserved4;
  1800.                         long  xpru_reserved5;
  1801.                    };
  1802. /*
  1803. *   The possible bit values for the xpru_updatemask are:
  1804. */
  1805. #define XPRU_PROTOCOL           0x00000001L
  1806. #define XPRU_FILENAME           0x00000002L
  1807. #define XPRU_FILESIZE           0x00000004L
  1808. #define XPRU_MSG                0x00000008L
  1809. #define XPRU_ERRORMSG           0x00000010L
  1810. #define XPRU_BLOCKS             0x00000020L
  1811. #define XPRU_BLOCKSIZE          0x00000040L
  1812. #define XPRU_BYTES              0x00000080L
  1813. #define XPRU_ERRORS             0x00000100L
  1814. #define XPRU_TIMEOUTS           0x00000200L
  1815. #define XPRU_PACKETTYPE         0x00000400L
  1816. #define XPRU_PACKETDELAY        0x00000800L
  1817. #define XPRU_CHARDELAY          0x00001000L
  1818. #define XPRU_BLOCKCHECK         0x00002000L
  1819. #define XPRU_EXPECTTIME         0x00004000L
  1820. #define XPRU_ELAPSEDTIME        0x00008000L
  1821. #define XPRU_DATARATE           0x00010000L
  1822. /*
  1823. *   The xpro_option structure
  1824. */
  1825. struct xpr_option {
  1826.    char *xpro_description;      /* description of the option                  */
  1827.    long  xpro_type;             /* type of option                             */
  1828.    char *xpro_value;            /* pointer to a buffer with the current value */
  1829.    long  xpro_length;           /* buffer size                                */
  1830. }
  1831. /*
  1832. *   Valid values for xpro_type are:
  1833. */
  1834. #define XPRO_BOOLEAN 1L         /* xpro_value is "yes", "no", "on" or "off"   */
  1835. #define XPRO_LONG    2L         /* xpro_value is string representing a number */
  1836. #define XPRO_STRING  3L         /* xpro_value is a string                     */
  1837.  
  1838.