home *** CD-ROM | disk | FTP | other *** search
/ The Fred Fish Collection 1.5 / ffcollection-1-5-1992-11.iso / ff_disks / 200-299 / ff226.lzh / Vlt / xprlib / xprotocol.doc < prev    next >
Text File  |  1989-06-25  |  56KB  |  1,624 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 - 4 June 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.
  322.         An error return is indicated when the function returns NULL.
  323.         Note that the arguments must be passed in registers A0 and A1
  324. respectively. See also section 4.
  325.  
  326.  
  327. 3.3     long (*xpr_fclose)();
  328. -----------------------------
  329.  
  330.         The xpr_fclose() call-back function works in most respects identically
  331. to the stdio function fclose(). Calling sequence:
  332.  
  333.         (*xpr_fclose)(long filepointer)
  334.                       A0
  335.  
  336. Note that the argument must be passed in register A0.
  337.  
  338.  
  339. 3.4     long (*xpr_fread)();
  340. ----------------------------
  341.  
  342.         The xpr_fread() call-back function works in most respects identically to
  343. the stdio function fread(). Calling sequence:
  344.  
  345.         long count = (*xpr_fread)(char *buffer, long size, long count,
  346.         D0                        A0            D0         D1
  347.  
  348.                                   long fileptr)
  349.                                   A1
  350.  
  351. The function returns the actual number items read. The size argument is in bytes.
  352. The function returns 0 on error or end of file.
  353.  
  354.  
  355. 3.5     long (*xpr_fwrite)();
  356. -----------------------------
  357.  
  358.         The xpr_fwrite() call-back function works in most respects identically
  359. to the stdio function fwrite(). Calling sequence:
  360.  
  361.         long count = (*xpr_fwrite)(char *buffer, long size, long count,
  362.         D0                         A0            D0         D1
  363.  
  364.                                   long fileptr)
  365.                                   A1
  366.  
  367. The function returns the actual number items written. The size argument is in
  368. bytes. The function returns 0 on failure.
  369.  
  370.  
  371. 3.6     long (*xpr_sread)();
  372. ----------------------------
  373.  
  374.         The xpr_sread() call-back function has the following calling sequence:
  375.  
  376.         long count = (*xpr_sread)(char *buffer, long size, long timeout)
  377.         D0                        A0            D0         D1
  378.  
  379. The first argument is a pointer to a buffer to receive the characters from the
  380. serial port, with a size specified in the second argument. The third item is a
  381. timeout in microseconds. The timeout may be set to 0L if the objective is to
  382. just read any characters that may currently be available. When this argument is
  383. non-zero, the function will not return until either the timeout period has
  384. expired, or the buffer has filled up. The function returns the actual number of
  385. characters put into the buffer, or -1L on error or timeout.
  386.         Note: the value 0L for the timeout argument is a special case. Remember
  387. that AmigaDOS 1.3 may have problems with small non-zero values for timeouts.
  388.  
  389.  
  390. 3.7     long (*xpr_swrite)();
  391. -----------------------------
  392.  
  393.         The xpr_swrite() call-back function has the following calling sequence:
  394.  
  395.         long status = (*xpr_swrite)(char *buffer, long size)
  396.         D0                          A0            D0
  397.  
  398. This function writes a buffer with the given size to the serial port. It returns
  399. 0L on success, non-zero on failure.
  400.  
  401. 3.8     long (*xpr_sflush)();
  402. ----------------------------
  403.  
  404.         The xpr_sflush call-back function has the following calling sequence:
  405.  
  406.         long status = (*xpr_sflush)()
  407.         D0
  408.  
  409. This function flushes all the data in the serial port input buffer.  It is
  410. typically used to recover after a protocol error. The function returns 0L on
  411. success, non-zero on failure.
  412.  
  413. 3.9     long (*xpr_update)();
  414. -----------------------------
  415.  
  416.         The xpr_update() call-back function has the following calling sequence:
  417.  
  418.         (*xpr_update)(struct XPR_UPDATE *updatestruct)
  419.                       A0
  420. where:
  421.  
  422. struct XPR_UPDATE {     long  xpru_updatemask;
  423.                         char *xpru_protocol;
  424.                         char *xpru_filename;
  425.                         long  xpru_filesize;
  426.                         char *xpru_msg;
  427.                         char *xpru_errormsg;
  428.                         long  xpru_blocks;
  429.                         long  xpru_blocksize;
  430.                         long  xpru_bytes;
  431.                         long  xpru_errors;
  432.                         long  xpru_timeouts;
  433.                         long  xpru_packettype;
  434.                         long  xpru_packetdelay;
  435.                         long  xpru_chardelay;
  436.                         char *xpru_blockcheck;
  437.                         char *xpru_expecttime;
  438.                         char *xpru_elapsedtime;
  439.                         long  xpru_datarate;
  440.                         long  xpru_reserved1;
  441.                         long  xpru_reserved2;
  442.                         long  xpru_reserved3;
  443.                         long  xpru_reserved4;
  444.                         long  xpru_reserved5;
  445.                    }
  446.  
  447. This function is intended to communicate a variety of values and strings from
  448. the external protocol to the communications program for display. Hence, the
  449. display format itself (requester, text-I/O) is left to the implementer of the
  450. communications program.
  451.         The mask xpru_updatemask indicates which of the other fields are valid,
  452. i.e. have had their value updated. It is possible to update a single or multiple
  453. values. Values that the external protocol does not use can be indicated by a
  454. NULL for pointers and -1L for longs.
  455.         The possible bit values for the xpru_updatemask are:
  456.  
  457.                 #define XPRU_PROTOCOL           0x00000001L
  458.                 #define XPRU_FILENAME           0x00000002L
  459.                 #define XPRU_FILESIZE           0x00000004L
  460.                 #define XPRU_MSG                0x00000008L
  461.                 #define XPRU_ERRORMSG           0x00000010L
  462.                 #define XPRU_BLOCKS             0x00000020L
  463.                 #define XPRU_BLOCKSIZE          0x00000040L
  464.                 #define XPRU_BYTES              0x00000080L
  465.                 #define XPRU_ERRORS             0x00000100L
  466.                 #define XPRU_TIMEOUTS           0x00000200L
  467.                 #define XPRU_PACKETTYPE         0x00000400L
  468.                 #define XPRU_PACKETDELAY        0x00000800L
  469.                 #define XPRU_CHARDELAY          0x00001000L
  470.                 #define XPRU_BLOCKCHECK         0x00002000L
  471.                 #define XPRU_EXPECTTIME         0x00004000L
  472.                 #define XPRU_ELAPSEDTIME        0x00008000L
  473.                 #define XPRU_DATARATE           0x00010000L
  474.  
  475.         The other fields of the XPR_UPDATE structure have the following
  476. meaning:
  477.  
  478. xpru_protocol    -- a string that indicates the name of the protocol used
  479. xpru_filename    -- the name of the file currently sent or received
  480. xpru_filesize    -- the size of the file
  481. xpru_msg         -- a "generic" message (50 characters or less)
  482. xpru_errormsg    -- an "error" message  (50 characters or less)
  483. xpru_blocks      -- number of transferred blocks
  484. xpru_blocksize   -- size of most recently transferred block (bytes)
  485. xpru_bytes       -- number of transferred bytes
  486. xpru_errors      -- number of errors
  487. xpru_timeouts    -- number of timeouts
  488. xpru_packettype  -- type of packet (e.g. Kermit 'D'-packet)
  489. xpru_packetdelay -- delay between packets in msec
  490. xpru_chardelay   -- delay between characters in msec
  491. xpru_blockcheck  -- block check type (e.g. "Checksum", "CRC-16", "CRC-32")
  492. xpru_expecttime  -- expected transfer time (e.g. "5 min 20 sec", "00:05:30")
  493. xpru_elapsedtime -- elapsed time from start of transfer (see xpru_expecttime)
  494. xpru_datarate    -- rate of data transfer expressed in characters per second.
  495. xpru_reserved1   -- for further expansion
  496.  ...         .   --  ...
  497. xpru_reserved5   -- for further expansion
  498.  
  499.         The communications program is free to ignore any field and to only update
  500. the ones it can handle.
  501.         If xpru_updatemask is equal to -1L, then ALL fields are either valid or 
  502. are unambiguously valued to indicate they are unused: NULL for pointers and -1L
  503. for longs.
  504.         When writing an external protocol, it is advisable to keep any strings
  505. as short as possible, and not longer than about 50 characters. Remember, if your
  506. strings are too long, they may overflow whatever display mechanism the
  507. communications program has chosen. It is also advisable to fill in as many
  508. fields as you can, since the communications program may not choose to display
  509. the ones you favor. When writing a communications program interface to XPR, on
  510. the other hand, remember that strings can be as much as 50 characters long. If
  511. you don't receive your favorite variables, it may be possible to compute them
  512. from those that are given. It is good practice for the external protocol to call
  513. xpr_update before starting the transfer with a message in the xpru_msg field
  514. indicating whether the protocol is sending or receiving a file.
  515.         The XPR_UPDATE structure must be provided by the external protocol, and
  516. must, of course be allocated either on the stack (as a local variable) or using
  517. AllocMem or malloc(). This is needed to ensure reentrancy. In general, it is a
  518. good idea to keep the entire library reentrant, since more than one
  519. communications program may be using the same code simultaneously.
  520.  
  521.  
  522. 3.10     long (*xpr_chkabort)();
  523. -------------------------------
  524.  
  525.         The xpr_chkabort() call-back function has no arguments:
  526.  
  527.         long status = (*xpr_chkabort)()
  528.         D0
  529.  
  530. When it returns non-zero, it means that the user has requested an abort. It is
  531. possible to implement levels of abort by returning 1L, 2L, 3L, etc, depending on
  532. the user's actions. The highest level of abort is -1L, which should be
  533. interpreted to mean stop all actions and return. The chkabort function should be
  534. called reasonably frequently.
  535.  
  536.  
  537. 3.11    long (*xpr_chkmisc)();
  538. ------------------------------
  539.  
  540.         The xpr_chkmisc() call-back function has no arguments and returns
  541. nothing.
  542.  
  543.         (*xpr_chkmisc)()
  544.  
  545. It is intended to give the communications program that is currently executing
  546. the external protocol transfer a chance to service its various message ports and
  547. to respond to user actions. It should be called on a regular basis.
  548.  
  549.  
  550. 3.12    long (*xpr_gets)();
  551. ---------------------------
  552.  
  553.         The xpr_gets() call-back function works somewhat like the stdio function
  554. gets(). Calling sequence:
  555.  
  556.         long status = (*xpr_gets)(char *prompt, char *buffer)
  557.         D0                        A0            A1
  558.  
  559. The first argument is a pointer to a string containing a prompt, to be displayed
  560. by the communications program in any manner it sees fit. The second argument
  561. should be a pointer to a buffer to receive the user's response. It should have a
  562. size of at least 256 bytes. The function returns 0L on failure or user
  563. cancellation, non-zero on success. The buffer has to be supplied by the XPR.
  564.  
  565.  
  566. 3.13    long (*xpr_setserial)();
  567. --------------------------------
  568.  
  569.         The xpr_setserial() call-back function has the following calling
  570. sequence:
  571.  
  572.         long oldstatus = (*xpr_setserial)(long newstatus)
  573.         D0                                D0
  574.  
  575. This function returns the current serial device status in encoded form. If the
  576. newstatus argument is -1L, the serial device status will not be changed.
  577. Otherwise the serial device status will be changed to newstatus. If oldstatus
  578. is returned as -1L, the call failed and the serial status was not changed.
  579.         Note: if the serial device status is changed with this function, the 
  580. external protocol must change the status back to oldstatus before returning.
  581.  
  582.         serial status longword:
  583.         .......................
  584.  
  585.         byte 0:         as the SerFlags field in IOExtSer structure.
  586.                 bit 0:  - parity on if set
  587.                 bit 1:  - parity odd if set
  588.                 bit 2:  - 7-wire protocol enabled if set
  589.                 bit 3:  - queued break if set
  590.                 bit 4:  - rad-boogie if set
  591.                 bit 5:  - shared if set
  592.                 bit 6:  - EOF mode if set
  593.                 bit 7:  - Xon/Xoff disabled if set
  594.         byte 1:         summary of other settings
  595.                 bit 0:  - enable mark/space parity if set
  596.                 bit 1:  - parity mark if set, space otherwise
  597.                 bit 2:  - 2 stop bits if set, 1 otherwise
  598.                 bit 3:  - read wordlength is 7 if set, 8 otherwise
  599.                 bit 4:  - write wordlength is 7 if set, 8 otherwise
  600.                 bit 5:  - not used
  601.                 bit 6:  - not used
  602.                 bit 7:  - not used
  603.         byte 2:         specifies one of a limited set of baud rates, as in
  604.                         preferences.h.
  605.                         -    110 baud =  0
  606.                         -    300 baud =  1
  607.                         -   1200 baud =  2
  608.                         -   2400 baud =  3
  609.                         -   4800 baud =  4
  610.                         -   9600 baud =  5
  611.                         -  19200 baud =  6
  612.                         -   midi      =  7
  613.                         -  38400 baud =  8
  614.                         -  57600 baud =  9
  615.                         -  76800 baud = 10
  616.                         - 115200 baud = 11
  617.         byte 3:         not used
  618.  
  619.  
  620. 3.14    long (*xpr_ffirst)();
  621. -----------------------------
  622.  
  623.         The xpr_ffirst() call-back function has the calling sequence:
  624.  
  625.         long stateinfo = (*xpr_ffirst)(char *buffer, char *pattern)
  626.         D0                             A0            A1
  627.  
  628. The first argument is a buffer to receive the first filename that matches the
  629. pattern in the second argument. The function returns 0L if no file matching the
  630. pattern was found, non-zero otherwise. The buffer should have a size of at least
  631. 256 bytes and is provided by the XPR. See also 3.14.
  632.  
  633.  
  634. 3.15    long (*xpr_fnext)();
  635. ----------------------------
  636.  
  637.         The xpr_fnext() call-back function has the calling sequence:
  638.  
  639.         long stateinfo = (*xpr_fnext)(long oldstate, char *buffer, char *pattern)
  640.         D0                            D0             A0            A1
  641.  
  642. The first argument is a buffer to receive the next filename that matches the
  643. pattern in the second argument. The function returns 0L if no further file
  644. matching the pattern was found, non-zero otherwise. The buffer should have a
  645. size of at least 256 bytes and is provided by the XPR.
  646.         Note: the value returned by xpr_ffirst and xpr_fnext may be used by the
  647. implementing communications program to maintain state information, but the
  648. mechanism is up to the implementer. If reentrancy is not required, state
  649. information may be kept in global variables by the implementer, and the oldstate
  650. argument can be ignored. However, the external protocol implementation must pass
  651. the stateinfo variable returned by ffirst or fnext to the next invocation of
  652. fnext.
  653.  
  654.  
  655. 3.16    long (*xpr_finfo)();
  656. ----------------------------
  657.  
  658.         The xpr_finfo() call-back function has the calling sequence:
  659.  
  660.         long info = (*xpr_finfo)(char *filename, long typeofinfo)
  661.         D0                       A0              D0
  662.  
  663. This function returns information about a file given its name and the type of
  664. information requested.
  665.  
  666.         typeofinfo value:       resulting info:
  667.         .......................................
  668.  
  669.         1L                      file size
  670.         (other values)          (to be determined)
  671.  
  672.  
  673. 3.17    long  *xpr_reserved1;
  674. -----------------------------
  675.  
  676.         This field is reserved for future expansion. It should be initialized to
  677. NULL by the communications program.
  678.  
  679.  
  680. 3.18    long  *xpr_reserved2;
  681. -----------------------------
  682.  
  683.         This field is reserved for future expansion. It should be initialized to
  684. NULL by the communications program.
  685.  
  686.  
  687. 3.19    long  *xpr_data;
  688. ------------------------
  689.  
  690.         This field is for internal use by the external protocol. Typically the
  691. field is initialized to point to a structure containing information extracted
  692. from the initialization string handed to or retrieved by the XProtocolSetup()
  693. function, see section 2. The structure should be deallocated and the field
  694. restored to NULL by the XProtocolCleanup() function. The communications program
  695. should never access this field, except when initializing the XPR_IO structure:
  696. the field should be initialized to NULL.
  697.  
  698.  
  699.  
  700.  
  701. 4. An example protocol.
  702. =======================
  703.  
  704.         The following is an annotated listing of an ascii upload protocol.
  705.  
  706. /** xprascii.c
  707. *
  708. *   These are the protocol transfer routines for a simple ASCII upload.
  709. *
  710. **/
  711. #include <exec/exec.h>
  712. #include <functions.h>
  713. #include <stdio.h>
  714. /*
  715. *   xproto.h is the include file given in Appendix B.
  716. */
  717. #include "xproto.h"
  718. /*
  719. *   The following two strings must exist.
  720. */
  721. char  XPRname[]   = "xprascii.library";
  722. char  XPRid[]     = "xprascii 0.9 (May 89)\r\n";
  723. UWORD XPRrevision = 9;
  724.  
  725. long atol();
  726. /*
  727. *   The callxx...() routines are described later. They provide the 
  728. *   assembler interface from the XPR library to the call-back routines.
  729. */
  730. long calla(), callaa(), callad(), calladd(), calladda();
  731.  
  732. char *malloc();
  733.  
  734.  
  735. /**
  736. *
  737. *   Send a file
  738. *
  739. **/
  740. long XProtocolSend(IO)
  741. struct XPR_IO *IO;
  742. {
  743.    long fp, r, i;
  744.    long brkflag = 0, fl = 0L, sd = 0L;
  745.    long (*xupdate)(), (*xswrite)(), (*xfopen)(), (*xfclose)(), (*xfread)(),
  746.         (*xsread)(),  (*xchkabort)();
  747.    unsigned char *buff = NULL, *serbuff = NULL;
  748.    struct XPR_UPDATE xpru;
  749.  
  750. /*
  751. *   These are the call-backs we need. If any of them isn't provided, quit.
  752. *   Could do some error reporting if at least xupdate is there.
  753. */
  754.    if ((xupdate    = IO->xpr_update)   == NULL) return(0L);
  755.    if ((xswrite    = IO->xpr_swrite)   == NULL) return(0L);
  756.    if ((xfopen     = IO->xpr_fopen)    == NULL) return(0L);
  757.    if ((xfclose    = IO->xpr_fclose)   == NULL) return(0L);
  758.    if ((xfread     = IO->xpr_fread)    == NULL) return(0L);
  759.    if ((xsread     = IO->xpr_sread)    == NULL) return(0L);
  760.    if ((xchkabort  = IO->xpr_chkabort) == NULL) return(0L);
  761. /*
  762. *   Allocate a few buffers.
  763. */
  764.    buff    = (unsigned char *) malloc(80);
  765.    serbuff = (unsigned char *) malloc(80);
  766. /*
  767. *   If we ran out of memory, print a message.
  768. *   The argument needs to go in A0: calla does this for us. 
  769. */
  770.    if (buff == NULL || serbuff == NULL) {
  771.       xpru.xpru_updatemask = XPRU_ERRORMSG;
  772.       xpru.xpru_errormsg   = "Ran out of memory!";
  773.       calla(xupdate, &xpru);
  774.       return(0L);
  775.    }
  776. /*
  777. *   Read the send delay, if a XProtocolSetup() was done before.
  778. *   If send delay is too large, cut it off at 10 seconds.
  779. *   In this example, the xpr_data field contains a null terminated string
  780. *   containing the number of ticks to delay each 80 characters.
  781. */
  782.    if (IO->xpr_data) {
  783.       sd = atol(IO->xpr_data);
  784.       if (sd > 500L) sd == 500L;
  785.    }
  786. /*
  787. *   Open the file. One could do wild card detection here.
  788. *   xfopen requires two arguments, in a0 and a1 respectively.
  789. *   Again, this must be done in assembler, and callaa does it.
  790. */
  791.    fp = callaa(xfopen, IO->xpr_filename, "r");
  792.    if (fp == NULL) {
  793.       free(buff);
  794.       free(serbuff);
  795.       xpru.xpru_updatemask = XPRU_ERRORMSG | XPRU_FILENAME;
  796.       xpru.xpru_errormsg   = "Failed to open input file";
  797.       xpru.xpru_filename   = IO->xpr_filename;
  798.       calla(xupdate, &xpru);
  799.       return(0L);
  800.    }
  801. /*
  802. *   Start the transfer. See 3.8 for a discussion on how to implement
  803. *   xupdate. 
  804. */
  805.    xpru.xpru_updatemask = XPRU_MSG | XPRU_FILENAME;
  806.    xpru.xpru_msg        = "Starting ASCII Send";
  807.    xpru.xpru_filename   = IO->xpr_filename;
  808.    calla(xupdate, &xpru);
  809. /*
  810. *   Now read 80 byte chunks from the file using xfread.
  811. *   xfread requires four arguments, a0, d0, d1 and a1.
  812. */
  813.    xpru.xpru_blocks = 0L;
  814.    while (r = calladda(xfread, buff, 1L, 80L, fp)) {
  815. /*
  816. *   Convert line feeds to carriage returns before sending to host.
  817. *   fl counts the characters. Display how many characters are sent.
  818. */
  819.       for (i = 0L; i < r; i++) if (buff[i] == '\n') buff[i] = '\r';
  820.       fl += r;
  821.       xpru.xpru_updatemask = XPRU_BYTES | XPRU_BLOCKS | XPRU_BLOCKSIZE;
  822.       xpru.xpru_bytes      = fl;
  823.       xpru.xpru_blocks++;
  824.       xpru.xpru_blocksize  = r;
  825.       calla(xupdate, &xpru);
  826.       callad(xswrite, buff, r);
  827. /*
  828. *   Every 80 bytes, put out a message and delay if requested.
  829. */
  830.       xpru.xpru_updatemask  = XPRU_PACKETDELAY;
  831.       xpru.xpru_packetdelay = sd * 20L;  /* msec! */
  832.       calla(xupdate, &xpru);
  833. /*
  834. *   Can't use Delay() here, because Delay() is in dos.library!
  835. *   However writing an equivalent function using the timer.device is
  836. *   trivial.
  837. */
  838.       TimeOut(sd);
  839. /*
  840. *   Eat any characters that might arrive from the serial port.
  841. *   calladd stores arg1 in a0, arg2 in d0, arg3 in d1.
  842. *   We're not really waiting for any characters: use a timeout of 0L.
  843. */
  844.       while (calladd(xsread, serbuff, 80L, 0L) > 0L) ;
  845. /*
  846. *   Check for "abort" here. Perhaps should call chkmisc() as well.
  847. */
  848.       if (brkflag = xchkabort()) break;
  849.    }
  850. /*
  851. *   Close the file
  852. */
  853.    calla(xfclose, fp);
  854.    free(buff);
  855.    free(serbuff);
  856. /*
  857. *   If we got here through chkabort() say Aborted.
  858. */
  859.    xpru.xpru_updatemask       = XPRU_MSG;
  860.    if (brkflag) xpru.xpru_msg = "Aborted";
  861.    else         xpru.xpru_msg = "Done"; 
  862.    calla(xupdate, &xpru);
  863.    if (brkflag) return(0L);
  864.    else         return(1L);
  865. }
  866.  
  867.  
  868. /**
  869. *
  870. *   Receive a file.
  871. *
  872. **/
  873. long XProtocolReceive(IO)
  874. struct XPR_IO *IO;
  875. {
  876.    long (*xupdate)();
  877.    struct XPR_UPDATE xpru;
  878.  
  879.    if (xupdate = IO->xpr_update) {
  880.       xpru.xpru_updatemask = XPRU_MSG;
  881.       xpru.xpru_msg        = "ASCII receive is not implemented. Use capture?";
  882.       calla(xupdate, &xpru);
  883.    }
  884.    return(0L);
  885. }
  886.  
  887.  
  888. /**
  889. *
  890. *   Setup
  891. *
  892. **/
  893. long XProtocolSetup(IO)
  894. struct XPR_IO *IO;
  895. {
  896.    long (*xupdate)(), (*xgets)();
  897.    struct XPR_UPDATE xpru;
  898.  
  899.    if ((xupdate = IO->xpr_update) == NULL) return(0L);
  900.    if ((xgets   = IO->xpr_gets)   == NULL) return(0L);
  901. /*
  902. *   Allocate a bit of memory for a data buffer
  903. */
  904.    if (IO->xpr_data == NULL) {
  905.       if ((IO->xpr_data = (long *) malloc(256)) == NULL) {
  906.          xpru.xpru_updatemask = XPRU_ERRORMSG;
  907.          xpru.xpru_errormsg   = "ASCII - Out of memory!";
  908.          calla(xupdate, &xpru);
  909.          return(0L);
  910.       }
  911.    }
  912. /*
  913. *   If setup string isn't handed to us, ask questions
  914. */
  915.    if (IO->xpr_filename == NULL) {
  916. /*
  917. *   Get the value for the send dealy
  918. */
  919.       callaa(xgets, "Enter ASCII send delay (ticks, 1 tick = 20 msec)",
  920.                   IO->xpr_data);
  921.    }
  922.    else {
  923.       strcpy(IO->xpr_data, IO->xpr_filename);
  924.    }
  925.    
  926.    return(1L);
  927. }
  928.  
  929. /**
  930. *
  931. *   Cleanup
  932. *
  933. **/
  934. long XProtocolCleanup(IO)
  935. struct XPR_IO *IO;
  936. {
  937.    if (IO->xpr_data) free(IO->xpr_data);
  938.    IO->xpr_data = NULL;
  939.  
  940.    return(1L);
  941. }
  942.  
  943. /**
  944. *
  945. *   The following functions setup the proper registers for the call-back 
  946. *   functions.
  947. *
  948. **/
  949. #asm
  950.         public _callad
  951. _callad:
  952.         movea.l 4(sp),a2                ; First  argument is function
  953.         movea.l 8(sp),a0                ; Second argument goes in a0
  954.         move.l  12(sp),d0               ; Third  argument goes in d0
  955.         jsr     (a2)
  956.         rts
  957.  
  958.         public  _calladda
  959. _calladda:
  960.         movea.l 4(sp),a2                ; First  argument is function
  961.         movea.l 8(sp),a0                ; Second argument goes in a0
  962.         move.l  12(sp),d0               ; Third  argument goes in d0
  963.         move.l  16(sp),d1               ; Fourth argument goes in d1
  964.         movea.l 20(sp),a1               ; Fifth  argument goes in a1
  965.         jsr     (a2)
  966.         rts
  967.  
  968.         public  _calla
  969. _calla:
  970.         movea.l 4(sp),a2                ; First  argument is function
  971.         movea.l 8(sp),a0                ; Second argument goes in a0
  972.         jsr     (a2)
  973.         rts
  974.  
  975.         public  _callaa
  976. _callaa:
  977.         movea.l 4(sp),a2                ; First  argument is function
  978.         movea.l 8(sp),a0                ; Second argument goes in a0
  979.         movea.l 12(sp),a1               ; Third  argument goes in a1
  980.         jsr     (a2)
  981.         rts
  982.  
  983.         public  _calladd
  984. _calladd:
  985.         movea.l 4(sp),a2                ; First  argument is function
  986.         move.l  8(sp),a0                ; Second argument goes in a0
  987.         move.l  12(sp),d0               ; Third  argument goes in d0
  988.         move.l  16(sp),d1               ; Fourth argument goes in d1
  989.         jsr     (a2)
  990.         rts
  991.  
  992. #endasm
  993. /*
  994. *   Could have added any other functions needed for other call-backs.
  995. *   Could have written a fancier single one... Could've...
  996. */
  997.                               __                
  998.                              /  \ o    /        
  999.                        -----/----\----/-----
  1000.                            /    o \__/          
  1001.                                                 
  1002.         Clearly it isn't very hard to implement a simple protocol. More
  1003. elaborate protocols are straightforward extensions to the above example. Of
  1004. course, there are a few more standard files needed to make the above example
  1005. into a complete library (like Open, Close and Expunge functions and a ROM-Tag
  1006. structure) but those parts are the same for any library and aren't given here.
  1007.  
  1008.  
  1009.  
  1010. 5. The interface to the communications program.
  1011. ===============================================
  1012.  
  1013.         The following is an annotated listing of a few call-back functions
  1014. as they are implemented in VLT. Also, it is shown how to initialize the
  1015. XPR_IO structure.
  1016.  
  1017. /** xprfuncs.c
  1018. *
  1019. *   Call-back functions for eXternal PRotocol support
  1020. *
  1021. **/
  1022. #include <functions.h>
  1023. #include <exec/exec.h>
  1024. #include <stdio.h>
  1025. /*
  1026. *   xproto.h is given in Appendix B
  1027. */
  1028. #include "xproto.h"
  1029. /*
  1030. *   xfer.h is a VLT private header file containing some information for
  1031. *   file transfer protocols
  1032. */
  1033. #include "xfer.h"
  1034.  
  1035. /*
  1036. *   These are the C versions of the interface
  1037. */
  1038. long        vlt_update(),  vlt_swrite(),  vlt_fread(),  vlt_fopen(),
  1039.             vlt_fclose(),  vlt_gets(),    vlt_sread(),  vlt_chkabort();
  1040. /*
  1041. *   These are the assembly level glue functions, see vltface.asm
  1042. */
  1043. extern long avlt_update(), avlt_swrite(), avlt_fread(), avlt_fopen(),
  1044.             avlt_fclose(), avlt_gets(),   avlt_sread(), avlt_chkabort();
  1045.  
  1046. /**
  1047. *
  1048. *   This function initializes an XPR_IO structure.
  1049. *
  1050. **/
  1051. xpr_setup(IO)
  1052. struct XPR_IO *IO;
  1053. {
  1054. /*
  1055. *   NULL out all the functions we don't do yet.
  1056. *   Fill the other ones with the addresses to the assembler glue version
  1057. *   of the interface routines. See vltface.asm
  1058. */
  1059.    IO->xpr_filename  = NULL;
  1060.    IO->xpr_fopen     = avlt_fopen;
  1061.    IO->xpr_fclose    = avlt_fclose;
  1062.    IO->xpr_fread     = avlt_fread;
  1063.    IO->xpr_fwrite    = NULL;
  1064.    IO->xpr_sread     = avlt_sread;
  1065.    IO->xpr_swrite    = avlt_swrite;
  1066.    IO->xpr_sflush    = NULL;
  1067.    IO->xpr_update    = avlt_update;
  1068.    IO->xpr_chkabort  = avlt_chkabort;
  1069.    IO->xpr_chkmisc   = NULL;
  1070.    IO->xpr_gets      = avlt_gets;
  1071.    IO->xpr_setserial = NULL;
  1072.    IO->xpr_ffirst    = NULL;
  1073.    IO->xpr_fnext     = NULL;
  1074.    IO->xpr_finfo     = NULL;
  1075.    IO->xpr_reserved1 = NULL;
  1076.    IO->xpr_reserved2 = NULL;
  1077. /*
  1078. *   Especially, NULL out the XPR private data field.
  1079. */
  1080.    IO->xpr_data      = NULL;
  1081.  
  1082.    return;
  1083. }
  1084.  
  1085. /**
  1086. *
  1087. *   Interface to VLT's MsgDisplay() function.
  1088. *
  1089. **/
  1090. /*
  1091. *   These are formats for VLT's requester
  1092. */
  1093. static char *xprnamfmt = "%s\n%s\n\n\n\n";
  1094. static char *filnamfmt = "\n\n%s\n\n\n";
  1095. static char *blksizfmt = "\n\n\n\nBlock:  %6ld  --  Block Size:  %6ld\n";
  1096. static char *errtimfmt = "\n\n\n\n\nErrors: %6ld  --  Timeouts:    %6ld";
  1097. static char *delayfmt  = "\n\n\n\n\nPacket delay %ld";
  1098. /*
  1099. *   Below are some VLT globals to orchestrate the display
  1100. */
  1101. long xpr_blocks = 0L, xpr_blocksize = 0L, xpr_errors = 0L, xpr_timeouts = 0L;
  1102. /*
  1103. *   The function
  1104. */
  1105. long vlt_update(x)
  1106. struct XPR_UPDATE *x;
  1107. {
  1108.    extern struct Window *mywindow;
  1109.    extern char *XPR_Name;
  1110. /*
  1111. *   First time, determine the window size (50 chars wide, 5 lines tall).
  1112. */
  1113.    SetMsgWindow(mywindow, 50, 6);
  1114. /*
  1115. *   Use VLT's PostMsg function to display all the information.
  1116. */
  1117.    if (x->xpru_updatemask & XPRU_PROTOCOL) {
  1118.       PostMsg(mywindow, xprnamfmt, XPR_Name, x->xpru_protocol);
  1119.    }
  1120.    if (x->xpru_updatemask & XPRU_MSG) {
  1121.       PostMsg(mywindow, xprnamfmt, XPR_Name, x->xpru_msg);
  1122.    }
  1123.    if (x->xpru_updatemask & XPRU_ERRORMSG) {
  1124.       PostMsg(mywindow, xprnamfmt, XPR_Name, x->xpru_errormsg);
  1125.    }
  1126.    if (x->xpru_updatemask & XPRU_FILENAME) {
  1127.       PostMsg(mywindow, filnamfmt, x->xpru_filename);
  1128.    }
  1129.    if (x->xpru_updatemask & XPRU_PACKETDELAY) {
  1130.       PostMsg(mywindow, delayfmt, x->xpru_packetdelay);
  1131.    }
  1132.    if (x->xpru_updatemask & (XPRU_BLOCKS | XPRU_BLOCKSIZE)) {
  1133.       if (x->xpru_updatemask & XPRU_BLOCKS)    xpr_blocks    = x->xpru_blocks;
  1134.       if (x->xpru_updatemask & XPRU_BLOCKSIZE) xpr_blocksize = x->xpru_blocksize;
  1135.       PostMsg(mywindow, blksizfmt, xpr_blocks, xpr_blocksize);
  1136.    }
  1137.    if (x->xpru_updatemask & (XPRU_ERRORS | XPRU_TIMEOUTS)) {
  1138.       if (x->xpru_updatemask & XPRU_ERRORS)   xpr_errors   = x->xpru_errors;
  1139.       if (x->xpru_updatemask & XPRU_TIMEOUTS) xpr_timeouts = x->xpru_timeouts;
  1140.       PostMsg(mywindow, errtimfmt, xpr_errors, xpr_timeouts);
  1141.    }
  1142.    return(0L);
  1143. }
  1144.  
  1145. /**
  1146. *
  1147. *   Prompt the user for input
  1148. *
  1149. **/
  1150. long vlt_gets(s, t)
  1151. char *s, *t;
  1152. {
  1153. /*
  1154. *   Use VLT's DoRequest() function
  1155. */
  1156.    return((long) DoRequest(mywindow, t, s, NULL, " Cancel "));
  1157. }
  1158.  
  1159. /**
  1160. *
  1161. *   Write a string to the serial port
  1162. *
  1163. **/
  1164. long vlt_swrite(s, n)
  1165. char *s;
  1166. long n;
  1167. {
  1168. /*
  1169. *   Use VLT's SendString() function
  1170. */
  1171.    SendString(s, (int) n);
  1172.    return(0L);
  1173. }
  1174.  
  1175. /**
  1176. *
  1177. *   Read characters from the serial port
  1178. *
  1179. **/
  1180. long vlt_sread(buff, length, micros)
  1181. unsigned char *buff;
  1182. long length, micros;
  1183. {
  1184.    extern int timeout;
  1185.    long secs = 0L;
  1186.  
  1187.    if (buff == NULL) return(-1L);
  1188. /*
  1189. *   Convert timeout to seconds and micros if necessary
  1190. */
  1191.    if (micros) {
  1192.       if (micros > 1000000L) {
  1193.          secs   = micros / 1000000L;
  1194.          micros = micros % 1000000L;
  1195.       }
  1196.    }
  1197. /*
  1198. *   Cheat! Only return a single character since we have such a nice
  1199. *   readchar() function in VLT. One day I'll have to modify this to 
  1200. *   save the odd microsecond...
  1201. */
  1202.    buff[0] = (unsigned char) readchar(secs, micros);
  1203. /*
  1204. *   VLT has a global called timeout. This comes in xfer.h.
  1205. *   If the read was successful, return having read a single character.
  1206. */
  1207.    if (timeout == GOODREAD) return(1L);
  1208. /*
  1209. *   Else return error condition
  1210. */
  1211.    return(-1L);
  1212. }
  1213.  
  1214. /**
  1215. *
  1216. *   Interfaces to stdio
  1217. *
  1218. **/
  1219. long vlt_fopen(s, t)
  1220. char *s, *t;
  1221. {
  1222.    return((long) fopen(s, t));
  1223. }
  1224.  
  1225. long vlt_fclose(fp)
  1226. FILE *fp;
  1227. {
  1228.    return((long) fclose(fp));
  1229. }
  1230.  
  1231. long vlt_fread(buff, size, count, fp)
  1232. char *buff;
  1233. long size, count;
  1234. FILE *fp;
  1235. {
  1236.    int res;
  1237.    res = fread(buff, (int) size, (int) count, fp);
  1238.    return((long) res);
  1239. }
  1240.  
  1241. /**
  1242. *
  1243. *   Check for Abort
  1244. *
  1245. **/
  1246. long vlt_chkabort()
  1247. {
  1248. /*
  1249. *   VLT aborts its protocols when the escape key is pressed.
  1250. *   CheckForKey loops over the UserPort messages looking for an escape.
  1251. */
  1252.    return((long) CheckForKey(69));
  1253. }
  1254.                               __                
  1255.                              /  \ o    /        
  1256.                        -----/----\----/-----
  1257.                            /    o \__/          
  1258.                                                 
  1259.         Clearly, this part of the implementation isn't hard either. The only
  1260. thing left is the assembly level glue on the communications program side. You
  1261. may wonder at this point why all this assembly level stuff is necessary. It is
  1262. necessary because many programs and libraries are written in small code/small
  1263. data. This means that both the communications program and the library address
  1264. their code/data off of some register, in the case of Manx usually A4. The
  1265. problem is that the communications program and the library are loaded in
  1266. different parts of memory, while startup code takes care of setting up the
  1267. proper value for A4. And the values of A4 are different for the the
  1268. communications program and the library! Now, if you just call a library
  1269. function, the assembly level glue does a few things, among which are: (1) saving
  1270. the caller's A4 somewhere safe and (2) retrieving the A4 it stored somewhere
  1271. when the library was loaded. Then the library function is executed, and the
  1272. function returns to the glue. The glue then restores A4 to the state it was in
  1273. before the library call.
  1274.         In the case of these call-back functions, we have to do the reverse.
  1275. After all, when a function like xpr_update is called, the current value of A4 is
  1276. the one that goes with the library's code. If the call-back function tries to
  1277. access any data back in the communications program, we're in big trouble.
  1278.         So what the assembly part of the call-backs has to do is (1) save the
  1279. library's A4 (on the stack) and (2) get the value of A4 appropriate for the
  1280. communications program. Then we can push the various registers onto the stack,
  1281. call the C version of the call-back and then restore the value of A4 to what the
  1282. library wants.
  1283.         For the above call-backs, the assembly level glue is listed below. This
  1284. concludes the documentation on external protocols using Amiga shared libraries.
  1285. If you have any questions, comments or suggestions, contact me on BIX.
  1286.         Meanwhile, have fun!
  1287.  
  1288. ;;; vltface.asm
  1289. ;
  1290. ;   DESCRIPTION:
  1291. ;   ===========
  1292. ;
  1293. ;        This is an interface to VLT callback functions from
  1294. ;        external protocol libraries.
  1295. ;
  1296. ;   AUTHOR/DATE:  W.G.J. Langeveld, March 1989.
  1297. ;   ============
  1298. ;
  1299. ;;;
  1300.  
  1301.         public  _geta4
  1302.  
  1303. setup   macro
  1304.         movem.l d2/d3/d4-d7/a2-a6,-(sp)
  1305.         jsr     _geta4                        ; Get a4.
  1306.         endm
  1307.  
  1308. push    macro
  1309.         move.l  \1,-(sp)
  1310.         endm
  1311.  
  1312. fix     macro
  1313.         ifc     '\1',''
  1314.                 mexit
  1315.         endc
  1316.         ifle    \1-8
  1317.                 addq.l  #\1,sp
  1318.         endc
  1319.         ifgt    \1-8
  1320.                 lea     \1(sp),sp
  1321.         endc
  1322.         endm
  1323.  
  1324. restore macro
  1325.         fix     \1
  1326.         movem.l (sp)+,d2/d3/d4-d7/a2-a6        
  1327.         rts
  1328.         endm
  1329.  
  1330.         public  _avlt_fopen
  1331.         public  _vlt_fopen
  1332.         public  _avlt_fclose
  1333.         public  _vlt_fclose
  1334.         public  _avlt_fread
  1335.         public  _vlt_fread
  1336.         public  _avlt_sread
  1337.         public  _vlt_sread
  1338.         public  _avlt_swrite
  1339.         public  _vlt_swrite
  1340.         public  _avlt_update
  1341.         public  _vlt_update
  1342.         public  _avlt_chkabort
  1343.         public  _vlt_chkabort
  1344.         public  _avlt_gets
  1345.         public  _vlt_gets
  1346.  
  1347. _avlt_fopen:
  1348.         setup
  1349.         push    a1
  1350.         push    a0
  1351.         jsr     _vlt_fopen
  1352.         restore 8
  1353.  
  1354. _avlt_fclose:
  1355.         setup
  1356.         push    a0
  1357.         jsr     _vlt_fclose
  1358.         restore 4
  1359.  
  1360. _avlt_fread:
  1361.         setup
  1362.         push    a1
  1363.         push    d1
  1364.         push    d0
  1365.         push    a0
  1366.         jsr     _vlt_fread
  1367.         restore 16
  1368.  
  1369. _avlt_sread:
  1370.         setup
  1371.         push    d1
  1372.         push    d0
  1373.         push    a0
  1374.         jsr     _vlt_sread
  1375.         restore 12
  1376.  
  1377. _avlt_swrite:
  1378.         setup
  1379.         push    d0
  1380.         push    a0
  1381.         jsr     _vlt_swrite
  1382.         restore 8
  1383.  
  1384. _avlt_update:
  1385.         setup
  1386.         push    a0
  1387.         jsr     _vlt_update
  1388.         restore 4
  1389.  
  1390. _avlt_chkabort:
  1391.         setup
  1392.         jsr     _vlt_chkabort
  1393.         restore
  1394.  
  1395. _avlt_gets:
  1396.         setup
  1397.         push    a1
  1398.         push    a0
  1399.         jsr     _vlt_gets
  1400.         restore 8
  1401.  
  1402.                               __                
  1403.                              /  \ o    /        
  1404.                        -----/----\----/-----
  1405.                            /    o \__/          
  1406.                                                 
  1407.  
  1408.  
  1409.  
  1410.  
  1411.  
  1412.  
  1413.  
  1414. Appendix A: XPR library skeleton.
  1415. =================================
  1416.  
  1417. ;;; libface.asm
  1418. ;
  1419. ;   DESCRIPTION:
  1420. ;   ===========
  1421. ;
  1422. ;        This is the skeleton for an Amiga Exec library.
  1423. ;        This version is written for Aztec C. It is based on the example
  1424. ;        library by Jim Mackraz who got some stuff from Neil Katin.
  1425. ;        This library implements a protocol transfer library.
  1426. ;        All changes and additions by me.
  1427. ;
  1428. ;   AUTHOR/DATE:  W.G.J. Langeveld, February 1989.
  1429. ;   ============
  1430. ;
  1431. ;;;
  1432.  
  1433.         include 'exec/types.i'
  1434.  
  1435. setup   macro
  1436.         movem.l d2/d3/d4-d7/a2-a6,-(sp)
  1437.         jsr     _geta4                        ;set up a4 for small model
  1438.         endm
  1439.  
  1440. push    macro
  1441.         move.l  \1,-(sp)
  1442.         endm
  1443.  
  1444. fix     macro
  1445.         ifc     '\1',''
  1446.                 mexit
  1447.         endc
  1448.         ifle    \1-8
  1449.                 addq.l        #\1,sp
  1450.         endc
  1451.         ifgt    \1-8
  1452.                 lea        \1(sp),sp
  1453.         endc
  1454.         endm
  1455.  
  1456. restore macro
  1457.         fix     \1
  1458.         movem.l (sp)+,d2/d3/d4-d7/a2-a6        
  1459.         rts
  1460.         endm
  1461.  
  1462.         dseg
  1463.  
  1464.         public  _libfunctab
  1465. _libfunctab:
  1466.         dc.l    XPRopen
  1467.         dc.l    XPRclose
  1468.         dc.l    XPRexpunge
  1469.         dc.l    $0000
  1470.         dc.l    XPRXProtocolCleanup
  1471.         dc.l    XPRXProtocolSetup
  1472.         dc.l    XPRXProtocolSend
  1473.         dc.l    XPRXProtocolReceive
  1474.         dc.l    $ffffffff
  1475.  
  1476.         cseg
  1477.  
  1478.         ;=== library functions
  1479.         public  _XPROpen
  1480.         public  _XPRClose
  1481.         public  _XPRExpunge
  1482.         public  _XProtocolCleanup
  1483.         public  _XProtocolSetup
  1484.         public  _XProtocolSend
  1485.         public  _XProtocolReceive
  1486.  
  1487.         public  _geta4
  1488.  
  1489. XPRopen:
  1490.         setup
  1491.         push    a6
  1492.         jsr     _XPROpen
  1493.         restore 4
  1494.  
  1495. XPRclose:
  1496.         setup
  1497.         push    a6
  1498.         jsr     _XPRClose
  1499.         restore 4
  1500.  
  1501. XPRexpunge:
  1502.         setup
  1503.         push    a6
  1504.         jsr     _XPRExpunge
  1505.         restore 4
  1506.  
  1507. XPRXProtocolCleanup:
  1508.         setup
  1509.         push    a0
  1510.         jsr     _XProtocolCleanup
  1511.         restore 4
  1512.  
  1513. XPRXProtocolSetup:
  1514.         setup
  1515.         push    a0
  1516.         jsr     _XProtocolSetup
  1517.         restore 4
  1518.  
  1519. XPRXProtocolSend:
  1520.         setup
  1521.         push    a0
  1522.         jsr     _XProtocolSend
  1523.         restore 4
  1524.  
  1525. XPRXProtocolReceive:
  1526.         setup
  1527.         push    a0
  1528.         jsr     _XProtocolReceive
  1529.         restore 4
  1530.  
  1531.  
  1532.         end
  1533.  
  1534.  
  1535.  
  1536.  
  1537.  
  1538. Appendix B: The xproto.h include file
  1539. =====================================
  1540.  
  1541. /** xproto.h
  1542. *
  1543. *   Include file for External Protocol Handling
  1544. *
  1545. **/
  1546. /*
  1547. *   The structure
  1548. */
  1549. struct XPR_IO {
  1550.                   char  *xpr_filename;      /* File name(s)             */
  1551.                   long (*xpr_fopen)();      /* Open file                */
  1552.                   long (*xpr_fclose)();     /* Close file               */
  1553.                   long (*xpr_fread)();      /* Get char from file       */
  1554.                   long (*xpr_fwrite)();     /* Put string to file       */
  1555.                   long (*xpr_sread)();      /* Get char from serial     */
  1556.                   long (*xpr_swrite)();     /* Put string to serial     */
  1557.                   long (*xpr_sflush)();     /* Flush serial input buffer*/
  1558.                   long (*xpr_update)();     /* Print stuff              */
  1559.                   long (*xpr_chkabort)();   /* Check for abort          */
  1560.                   long (*xpr_chkmisc)();    /* Check misc. stuff        */
  1561.                   long (*xpr_gets)();       /* Get string interactively */
  1562.                   long (*xpr_setserial)();  /* Set and Get serial info  */
  1563.                   long (*xpr_ffirst)();     /* Find first file name     */
  1564.                   long (*xpr_fnext)();      /* Find next file name      */
  1565.                   long (*xpr_finfo)();      /* Return file info         */
  1566.                   long  *xpr_reserved1;     /* Reserved                 */
  1567.                   long  *xpr_reserved2;     /* Reserved                 */
  1568.                   long  *xpr_data;          /* Initialized by Setup.    */
  1569.               };
  1570.  
  1571. /*
  1572. *   The functions
  1573. */
  1574. extern long XProtocolSend(),  XProtocolReceive(),
  1575.             XProtocolSetup(), XProtocolCleanup();
  1576. /*
  1577. *   The update structure
  1578. */
  1579. struct XPR_UPDATE {     long  xpru_updatemask;
  1580.                         char *xpru_protocol;
  1581.                         char *xpru_filename;
  1582.                         long  xpru_filesize;
  1583.                         char *xpru_msg;
  1584.                         char *xpru_errormsg;
  1585.                         long  xpru_blocks;
  1586.                         long  xpru_blocksize;
  1587.                         long  xpru_bytes;
  1588.                         long  xpru_errors;
  1589.                         long  xpru_timeouts;
  1590.                         long  xpru_packettype;
  1591.                         long  xpru_packetdelay;
  1592.                         long  xpru_chardelay;
  1593.                         char *xpru_blockcheck;
  1594.                         char *xpru_expecttime;
  1595.                         char *xpru_elapsedtime;
  1596.                         long  xpru_datarate;
  1597.                         long  xpru_reserved1;
  1598.                         long  xpru_reserved2;
  1599.                         long  xpru_reserved3;
  1600.                         long  xpru_reserved4;
  1601.                         long  xpru_reserved5;
  1602.                    };
  1603. /*
  1604. *   The possible bit values for the xpru_updatemask are:
  1605. */
  1606. #define XPRU_PROTOCOL           0x00000001L
  1607. #define XPRU_FILENAME           0x00000002L
  1608. #define XPRU_FILESIZE           0x00000004L
  1609. #define XPRU_MSG                0x00000008L
  1610. #define XPRU_ERRORMSG           0x00000010L
  1611. #define XPRU_BLOCKS             0x00000020L
  1612. #define XPRU_BLOCKSIZE          0x00000040L
  1613. #define XPRU_BYTES              0x00000080L
  1614. #define XPRU_ERRORS             0x00000100L
  1615. #define XPRU_TIMEOUTS           0x00000200L
  1616. #define XPRU_PACKETTYPE         0x00000400L
  1617. #define XPRU_PACKETDELAY        0x00000800L
  1618. #define XPRU_CHARDELAY          0x00001000L
  1619. #define XPRU_BLOCKCHECK         0x00002000L
  1620. #define XPRU_EXPECTTIME         0x00004000L
  1621. #define XPRU_ELAPSEDTIME        0x00008000L
  1622. #define XPRU_DATARATE           0x00010000L
  1623.  
  1624.