wdbGopherLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:25k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* wdbGopherLib.c - info gathering interpreter for the agent */
  2. /* Copyright 1994-2001 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01l,14sep01,jhw Fixed warnings from compiling with gnu -pedantic flag
  7. 01k,09sep97,elp added global variable to prevent taskLock() calls (SPR# 7653)
  8. + replaced hardcoded value by macro.
  9. 01j,10dec96,elp gopherWriteString() cleanup.
  10. 01i,09dec96,elp fixed null length string error (gopher type was not written).
  11. 01h,30apr96,elp Merged with the host version written by bss (SPR# 6497).
  12. + enabled transfer of larger strings (SPR #6277)
  13. + fix SPR #6403.
  14. 01g,20mar96,s_w modify the gopherWriteString to cope with strings near memory
  15. boundaries (SPR 6218).
  16. 01f,31oct95,ms  changed a couple of strtol's to strtoul's.
  17. 01e,14sep95,c_s added more syntax checking, bug fixes, and memory protection.
  18. (SPRs 4659, 4462).
  19. 01d,23jun95,tpr replaced memcpy() by bcopy()
  20. 01c,20jun95,ms added static buffer back in to make DSA easier
  21. 01b,01jun95,ms added interlocking in task mode, removed static buffer.
  22. 01a,01nov94,c_s written.
  23. */
  24. /*
  25. DESCRIPTION
  26. */
  27. #ifdef HOST
  28. #include <limits.h>
  29. #include <string.h>
  30. #include <ctype.h>
  31. #include <stdlib.h>
  32. #if 0   /* omitted because host.h redefines memset () and memchr () */
  33. #include <memory.h>
  34. #else   /* which breaks the declaration of memcpy () ... */
  35. extern "C" void * memcpy (void * s1, const void * s2, size_t n);
  36. #endif
  37. #include "host.h"
  38. #include "wdb.h"
  39. #include "backend.h"
  40. #else /* #ifdef HOST */
  41. #include "wdb/wdb.h"
  42. #include "wdb/wdbRtIfLib.h"
  43. #include "wdb/wdbLibP.h"
  44. #include "wdb/wdbSvcLib.h"
  45. #include "limits.h"
  46. #include "string.h"
  47. #include "ctype.h"
  48. #include "stdlib.h"
  49. #endif  /* #ifdef HOST */
  50. typedef struct
  51.     {
  52.     char * program; /* where to start executing */
  53.     UINT32 p; /* initial value of pointer */
  54.     char * pTape; /* tape array */
  55.     int tapeIx; /* index in tape to write next cell */
  56.     int tapeLen; /* total length of tape */
  57.     int execute; /* whether to execute, or just parse */
  58.     unsigned int status; /* error code */
  59.     } wdbGopherCtx_t;
  60. /* The Gopher Byte Stream Format
  61.  * 
  62.  * The first byte of an item is the type code, one of GOPHER_UINT32, 
  63.  * GOPHER_UINT16, GOPHER_FLOAT64, etc.  This code determines the number
  64.  * of bytes that immediately follow and represent the tape cell value.
  65.  * These data bytes will be in the target byte order.  If the type code
  66.  * is GOPHER_STRING, all following bytes are part of the string up to 
  67.  * a trailing NUL character.
  68.  */
  69. #define MAX_TAPE_LEN 1400
  70. #ifdef HOST
  71. /*
  72. * XXX - because some emulator back ends only provide low-bandwidth
  73. * memory read capabilities, the host implementation assumes that
  74. * the maximum size of a string in target memory is 32 bytes.
  75. * This is necessary for performance.  However, gopherWriteString()
  76. * should be modified to make several small reads until it finds
  77. * the end of a string.
  78. */
  79. const int       MaxTgtStrLen    = 32;   /* XXX - Maximum length of a string */
  80. #else
  81. #define ADD_TAPE_NB 10
  82. BOOL wdbGopherLock = TRUE;   /* lock during gopher evaluation */
  83. static char * pAddTape [ADD_TAPE_NB];   /* additional tape pointers */
  84. static int pAddTapeIx [ADD_TAPE_NB]; /* additional tape fill indexes */
  85. static int tapeIndex;   /* current tape number */
  86. #endif /* #ifdef HOST */
  87. static char  tape [MAX_TAPE_LEN]; /* XXX should be passed to
  88.  * wdbGopherLib(), but that would
  89.  * make the host based DSA harder
  90.  * to implement */
  91. static int tapeLen = MAX_TAPE_LEN;
  92. #define WDB_REPLY_HDR_SZ 24
  93. #define WDB_WRAPPER_HDR_SZ 12
  94. #define WDB_MEM_XFER_HDR_SZ 8
  95. #define WDB_OPAQUE_HDR_SZ 4
  96. /* it is required to reserve space for headers (WDB + XDR + IP) */
  97. #define WDB_GOPHER_MTU_OFFSET  (WDB_REPLY_HDR_SZ + WDB_WRAPPER_HDR_SZ + 
  98. WDB_MEM_XFER_HDR_SZ + WDB_OPAQUE_HDR_SZ + 8)
  99. /* forward declarations */
  100. #ifdef HOST
  101. /*
  102.  * Note:  although this is a '.c' file, it must be
  103.  * compiled with the '-x c++' option.
  104.  */
  105. extern "C" UINT32 wdbEvaluateGopher (WDB_STRING_T *program,
  106.                                      WDB_MEM_XFER *pTape);
  107. static STATUS gopherWriteP (wdbGopherCtx_t *gc);
  108. #else
  109. static UINT32 wdbEvaluateGopher (WDB_STRING_T *program, WDB_MEM_XFER *pTape);
  110. static STATUS wdbTransferGopher (WDB_MEM_XFER *pTape);
  111. static STATUS gopherNewTapeAllocate (wdbGopherCtx_t *gc);
  112. #endif /* #ifdef HOST */
  113. static STATUS gopher (wdbGopherCtx_t *gc);
  114. static STATUS gopherWriteScalar (wdbGopherCtx_t *gc, UINT8 *src, int type);
  115. static STATUS gopherWriteString (wdbGopherCtx_t *gc, char *string);
  116. /******************************************************************************
  117. *
  118. * gopher -
  119. */
  120. static STATUS gopher 
  121.     (
  122.     wdbGopherCtx_t * gc /* gopher execution context */
  123.     )
  124.     {
  125.     while (*gc->program)
  126. {
  127. /* skip whitespace */
  128. while (*gc->program && isspace ((int) *gc->program))
  129.     ++gc->program;
  130. if (isxdigit ((int) *gc->program)) /* unsigned constants replace p */
  131.     {
  132.     char *newPc;
  133. #ifdef HOST
  134.             /* XXX - this is a work around for the bug in GNU's strtoul (). */
  135.             unsigned int newP = (unsigned int) strtol (gc->program, &newPc, 0);
  136. #else
  137.     unsigned int newP = (unsigned int) strtoul (gc->program, &newPc, 0);
  138. #endif /* #ifdef HOST */
  139.     
  140.     if (gc->program == newPc)
  141. {
  142. gc->status = WDB_ERR_GOPHER_SYNTAX;
  143. return ERROR;
  144. }
  145.     if (gc->execute)
  146. {
  147. gc->p = newP;
  148. }
  149.     
  150.     gc->program = newPc;
  151.     }
  152. else if (*gc->program == '+' /* signed constants increment p */
  153.  || *gc->program == '-')
  154.     {
  155.     char *newPc;
  156.     int minus = *gc->program == '-';
  157.     int delta = strtol (++gc->program, &newPc, 0);
  158.     if (gc->program == newPc)
  159. {
  160. gc->status = WDB_ERR_GOPHER_SYNTAX;
  161. return ERROR;
  162. }
  163.     if (gc->execute)
  164. {
  165. gc->p += minus ? -delta : delta;
  166. }
  167.     gc->program = newPc;
  168.     }
  169. else if (*gc->program == '*') /* * replaces p with *p */
  170.     {
  171.     if (gc->execute)
  172. {
  173. UINT32 newP;
  174. #ifdef HOST
  175.                 if (Backend_T::memProbe_s ((TGT_ADDR_T) gc->p, VX_READ,
  176.                                         sizeof (UINT32), (char *) &newP) != OK)
  177. #else
  178. if ((*pWdbRtIf->memProbe) ((INT8 *) gc->p, VX_READ,
  179. sizeof (UINT32), (char *) &newP) != OK)
  180. #endif /* #ifdef HOST */
  181.     {
  182.     gc->status = WDB_ERR_GOPHER_FAULT;
  183.     return ERROR;
  184.     }
  185. gc->p = newP;
  186. }
  187.     ++gc->program;
  188.     }
  189. else if (*gc->program == '!') /* ! writes p on the tape */
  190.     {
  191.     if (gc->execute)
  192. {
  193. #ifdef HOST
  194.                 if (gopherWriteP (gc) != OK)
  195.                     return ERROR;
  196. #else
  197. if (gopherWriteScalar (gc, (UINT8 *) &gc->p, GOPHER_UINT32)
  198.     != OK)
  199.     return ERROR;
  200. #endif /* #ifdef HOST */
  201. }
  202.     ++gc->program;
  203.     }
  204. else if (*gc->program == '@') /* @ writes *p on the tape, advance p */
  205.     {
  206.     int size = 4;
  207.     int type = GOPHER_UINT32;
  208.     /* If the next character is in [bwlfdx] then modify
  209.      * the size of the transfer. Otherwise pick up 32 bits.
  210.      */
  211.     
  212.     switch (gc->program [1])
  213. {
  214. case 'b':
  215.     size = 1; 
  216.     type = GOPHER_UINT8;
  217.     ++gc->program;
  218.     break;
  219. case 'w':
  220.     size = 2; 
  221.     type = GOPHER_UINT16;
  222.     ++gc->program;
  223.     break;
  224. case 'f':
  225.     size = 4; 
  226.     type = GOPHER_FLOAT32;
  227.     ++gc->program;
  228.     break;
  229. case 'd':
  230.     size = 8; 
  231.     type = GOPHER_FLOAT64;
  232.     ++gc->program;
  233.     break;
  234. case 'x':
  235.     size = 10; 
  236.     type = GOPHER_FLOAT80;
  237.     ++gc->program;
  238.     break;
  239. case 'l':
  240.     size = 4; 
  241.     type = GOPHER_UINT32;
  242.     ++gc->program;
  243.     break;
  244. }
  245.     
  246.     if (gc->execute)
  247. {
  248. if (gopherWriteScalar (gc, (UINT8 *) gc->p, type) != OK)
  249.     return ERROR;
  250. gc->p += size;
  251. }
  252.     ++gc->program;
  253.     }
  254. else if (*gc->program == '$') /* $ writes string at p on tape */
  255.     {
  256.     if (gc->execute)
  257. {
  258. if (gopherWriteString (gc, (char *) gc->p) != OK)
  259.     return ERROR;
  260. }
  261.     ++gc->program;
  262.     }
  263. else if (*gc->program == '{') /* { saves p and repeats contents */
  264.     { /* while p is not NULL.           */
  265.     wdbGopherCtx_t subGc;
  266.     char *progStart = gc->program+1;
  267.     UINT32 oldP = gc->p;
  268.     int oldX = gc->execute;
  269.     int result = OK;
  270.     subGc = *gc; /* set up initial context */
  271.     ++subGc.program; /* skip the initial left-brace */
  272.     /* We set the execute flag to zero if the pointer value 
  273.        is currently zero in our context.  This is because if
  274.        p == 0 upon encountering an open-brace, we should not execute 
  275.        the contents of the brace construct, but we still need
  276.        to know where to resume execution, so we must parse
  277.        in a subcontext. */
  278.     if (gc->p == 0)
  279. {
  280. subGc.execute = 0;
  281. result = gopher (&subGc);
  282. }
  283.     else
  284. {
  285. while (result == OK && subGc.p != 0)
  286.     {
  287.     subGc.program = progStart;
  288.     result = gopher (&subGc);
  289.     }
  290. }
  291.     /* Now set our program pointer to the character after the 
  292.        execution of the subprogram. */
  293.     *gc = subGc;
  294.     if (result != OK)
  295. {
  296. return result;
  297. }
  298.     
  299.     /* restore p, execute. */
  300.     gc->p = oldP;
  301.     gc->execute = oldX;
  302.     }
  303. else if (*gc->program == '}') /* } ends the loop opened by {. */
  304.     {
  305.     ++gc->program;
  306.     return OK;
  307.     }
  308. else if (*gc->program == '<') /* < saves p and executes body once. */
  309.     {
  310.     wdbGopherCtx_t subGc;
  311.     UINT32 oldP = gc->p;
  312.     int result;
  313.     subGc = *gc; /* set up initial context */
  314.     ++subGc.program; /* skip the initial left-bracket */
  315.     result = gopher (&subGc);
  316.     if (result != OK)  
  317. {
  318. *gc = subGc;
  319. return result;
  320. }
  321.     /* Now set our program pointer to the character after the 
  322.        execution of the subprogram. */
  323.     *gc = subGc;
  324.     gc->p = oldP;
  325.     }
  326. else if (*gc->program == '>') /* > closes the block opened by <. */
  327.     {
  328.     ++gc->program;
  329.     return OK;
  330.     }
  331. else if (*gc->program == '(') /* perform "n" times, where n follows */
  332.     {
  333.     char *newPc;
  334.     UINT32 oldP = gc->p;
  335.     wdbGopherCtx_t subGc;
  336. #ifdef HOST
  337.             /* XXX - fix for GNU's bug in strtoul (). */
  338.             unsigned int count = (unsigned int) strtol (gc->program + 1,
  339.                                                         &newPc, 0);
  340. #else
  341.     unsigned int count = (unsigned int) strtoul (gc->program + 1,
  342. &newPc, 0);
  343. #endif /* #ifdef HOST */
  344.     int ix;
  345.     
  346.     if (gc->program+1 == newPc || count <= 0)
  347. {
  348. gc->status = WDB_ERR_GOPHER_SYNTAX;
  349. return ERROR;
  350. }
  351.     /* if we're not executing, just execute the loop once, so we 
  352.        can find the end of the nesting. */
  353.     if (! gc->execute) count = 1;
  354.     gc->program = newPc;
  355.     subGc = *gc;
  356.     for (ix = 0; ix < count; ++ix)
  357. {
  358. /* start the program at the beginning: after the (# part. */
  359. subGc.program = newPc;
  360. if (gopher (&subGc) != OK)
  361.     {
  362.     *gc = subGc;
  363.     return ERROR;
  364.     }
  365. }
  366.     
  367.     *gc = subGc;
  368.     gc->p = oldP;
  369.     }
  370. else if (*gc->program == ')')
  371.     {
  372.     ++gc->program;
  373.     return OK;
  374.     }
  375. else if (*gc->program == '_')
  376.     {
  377.     /* _ is ignored.  It can be used to separate two numbers
  378.        in a generated gopher program. */
  379.     ++gc->program;
  380.     }
  381. else if (*gc->program)
  382.     {
  383.     /* unknown character: syntax error. */
  384.     gc->status = WDB_ERR_GOPHER_SYNTAX;
  385.     return ERROR;
  386.     }
  387. }
  388.     
  389.     return OK;
  390.     }
  391. #ifdef HOST
  392. /******************************************************************************
  393. *
  394. * wdbEvaluateGopher -
  395. */
  396. UINT32 wdbEvaluateGopher
  397.     (
  398.     WDB_STRING_T *      pProgram,
  399.     WDB_MEM_XFER *      pValueTape
  400.     )
  401.     {
  402.     wdbGopherCtx_t      gc;
  403.     gc.program  = *pProgram;
  404.     gc.p        = 0;
  405.     gc.pTape    = tape;
  406.     gc.tapeIx   = 0;
  407.     gc.tapeLen  = tapeLen;
  408.     gc.execute  = 1;
  409.     gc.status   = OK;
  410.     gopher (&gc);
  411.     pValueTape->source          = gc.pTape;
  412.     pValueTape->numBytes        = gc.tapeIx;
  413.     return (gc.status);
  414.     }
  415. /******************************************************************************
  416. *
  417. * gopherWriteScalar -
  418. */
  419. static STATUS gopherWriteScalar
  420.     (
  421.     wdbGopherCtx_t *    gc,                     /* gopher context */
  422.     UINT8 *             src,                    /* source address */
  423.     int                 type                    /* GOPHER_UINT32, etc. */
  424.     )
  425.     {
  426.     int                 nbytes = 4;             /* UINT32 is most common */
  427.     int status;
  428.     if (type == GOPHER_UINT16)   nbytes = 2;    /* fix nbytes if size != 4 */
  429.     if (type == GOPHER_UINT8)    nbytes = 1;
  430.     if (type == GOPHER_FLOAT64)  nbytes = 8;
  431.     if (type == GOPHER_FLOAT80)  nbytes = 10;
  432.     /* We must have at least nbytes+1 bytes left: one for type marker,
  433.        nbytes for the scalar itself. */
  434.     if (gc->tapeLen - gc->tapeIx < nbytes+1)
  435.         {
  436.         gc->status = WDB_ERR_GOPHER_TRUNCATED;
  437.         return ERROR;
  438.         }
  439.     /* Write the scalar type. */
  440.     gc->pTape [gc->tapeIx++] = type;
  441.     status = Backend_T::tgtRead_s ((TGT_ADDR_T) src,
  442.    (void *) (gc->pTape + gc->tapeIx),
  443.    nbytes);
  444.     if (status != OK)
  445. {
  446. gc->status = WDB_ERR_MEM_ACCES;
  447. return ERROR;
  448. }
  449.     
  450.     gc->tapeIx += nbytes;
  451.     return OK;
  452.     }
  453. /******************************************************************************
  454. *
  455. * gopherWriteString -
  456. *
  457. */
  458. static STATUS gopherWriteString
  459.     (
  460.     wdbGopherCtx_t *    gc,
  461.     char *                              string
  462.     )
  463.     {
  464.     int                 maxlen;                 /* how much we can carry */
  465.     if (string == 0)
  466.         {
  467.         if (gc->tapeLen - gc->tapeIx < 2)
  468.             {
  469.             gc->status = WDB_ERR_GOPHER_TRUNCATED;
  470.             return ERROR;
  471.             }
  472.         gc->pTape [gc->tapeIx++] = GOPHER_STRING;
  473.         gc->pTape [gc->tapeIx++] = EOS;
  474.         return OK;
  475.         }
  476.     /* we can write no more than the size of the remaining buffer minus 1
  477.        (we have to save a byte for the null terminator). */
  478.     maxlen = gc->tapeLen - gc->tapeIx;
  479.         {
  480.         int     status;
  481.         char *  pEnd;
  482.         int     nRead;
  483.         int     numToRead = min (maxlen, MaxTgtStrLen);
  484.         char *  pReadBuf =  new char [maxlen];
  485.         /* Get a chunk of memory which is of size numToRead */
  486.         status = Backend_T::tgtRead_s ((TGT_ADDR_T) string,
  487.                                        pReadBuf, numToRead);
  488.         if (status != OK)
  489.             {
  490.             gc->status = WDB_ERR_MEM_ACCES;
  491.             return ERROR;
  492.             }
  493.         /* Null terminate the chunk */
  494.         pReadBuf [numToRead - 1] = EOS;
  495.         /* Find the real end of the string */
  496.         pEnd = strchr (pReadBuf, EOS);
  497.         if (pEnd == NULL)
  498.             {
  499.             memcpy (gc->pTape + gc->tapeIx, pReadBuf, numToRead - 1);
  500.             gc->tapeIx += numToRead - 1;
  501.             gc->status = WDB_ERR_GOPHER_TRUNCATED;
  502.             return ERROR;
  503.             }
  504.         nRead = (UINT32) pEnd - (UINT32) pReadBuf;
  505.         nRead++;        /* account for EOS character ('') */
  506.         memcpy (gc->pTape + gc->tapeIx, pReadBuf, nRead);
  507.         gc->tapeIx += nRead;
  508.         delete [] pReadBuf;
  509.         return OK;
  510.         }
  511.     }
  512. /******************************************************************************
  513. *
  514. * gopherWriteP - write the pointer to the tape
  515. *
  516. * NOMANUAL
  517. */
  518. STATUS gopherWriteP
  519.     (
  520.     wdbGopherCtx_t *    gc              /* gopher context */
  521.     )
  522.     {
  523.     int                 nbytes = 4;             /* p is a UINT32 */
  524.     /* We must have at least nbytes+1 bytes left: one for type marker,
  525.        nbytes for the scalar itself. */
  526.     if (gc->tapeLen - gc->tapeIx < nbytes+1)
  527.         {
  528.         gc->status = WDB_ERR_GOPHER_TRUNCATED;
  529.         return ERROR;
  530.         }
  531.     /* Write the scalar type. */
  532.     gc->pTape [gc->tapeIx++] = GOPHER_UINT32;
  533.     /* Write the scalar itself. */
  534.     memcpy ((gc->pTape + gc->tapeIx), (char *) &gc->p, nbytes);
  535.     gc->tapeIx += nbytes;
  536.     return OK;
  537.     }
  538. #else
  539. /******************************************************************************
  540. *
  541. * wdbGopherLibInit -
  542. */
  543. void wdbGopherLibInit (void)
  544.     {
  545.     pAddTape [0] = tape;
  546.     wdbSvcAdd (WDB_EVALUATE_GOPHER, wdbEvaluateGopher, xdr_WDB_STRING_T,
  547. xdr_WDB_MEM_XFER);
  548.     }
  549. /******************************************************************************
  550. *
  551. * wdbEvaluateGopher -
  552. */
  553. static UINT32 wdbEvaluateGopher
  554.     (
  555.     WDB_STRING_T *  pProgram,
  556.     WDB_MEM_XFER *  pValueTape
  557.     )
  558.     {
  559.     wdbGopherCtx_t gc;
  560.     int ix;
  561.     gc.status = OK;
  562.     pAddTape [0] = tape;
  563.     if (*pProgram != NULL)
  564. {
  565. /* starting a new evaluation */
  566. tapeIndex = 0;
  567. gc.program = *pProgram;
  568. gc.p = 0;
  569. gc.tapeLen = tapeLen;
  570. gc.execute = 1;
  571. if (wdbIsNowTasking() && (pWdbRtIf->taskLock != NULL))
  572.     {
  573.     /* we check that no info is stored */
  574.     for (ix = 0; (ix < ADD_TAPE_NB); ix++)
  575. {
  576. if ((pAddTape[ix]) && ix && (pWdbRtIf->free != NULL))
  577.     {
  578.     (*pWdbRtIf->free) (pAddTape[ix]);
  579.     pAddTape [ix] = NULL;
  580.     }
  581. pAddTapeIx[ix] = 0;
  582. }
  583.     gc.pTape = pAddTape[0];
  584.     gc.tapeIx = 0;
  585.     if (wdbGopherLock)
  586. {
  587. (*pWdbRtIf->taskLock)();
  588. gopher (&gc); 
  589. (*pWdbRtIf->taskUnlock)();
  590. }
  591.     else
  592. gopher (&gc);
  593.     pAddTapeIx[tapeIndex] = gc.tapeIx;
  594.     }
  595. else
  596.     {
  597.     /*
  598.      * system mode : malloc is forbidden we can only store result
  599.      * in pAddTape[0]
  600.      */
  601.     gc.pTape = pAddTape[0];
  602.     gc.tapeIx = 0;
  603.     gopher (&gc); 
  604.     pAddTapeIx [0] = gc.tapeIx;
  605.     }
  606. /* prepare transfer by resetting tapeIndex */
  607. tapeIndex = 0;
  608. }
  609.     if (gc.status == OK)
  610. gc.status = wdbTransferGopher (pValueTape);
  611.     else
  612. {
  613. /* delete additional tapes if some were allocated */
  614. for (ix = 0; (ix < ADD_TAPE_NB) && (pWdbRtIf->free != NULL); ix++)
  615.     if ((pAddTape[ix]) && ix)
  616. {
  617. (*pWdbRtIf->free) (pAddTape[ix]);
  618. pAddTape[ix] = NULL;
  619. }
  620. }
  621.     return (gc.status);
  622.     }
  623. /******************************************************************************
  624. *
  625. * wdbTransferGopher - answer to a gopher request using stored results
  626. *
  627. * This routine also frees tapes when they become out of date (ie when we are
  628. * transfering the next one).
  629. *
  630. */
  631. static STATUS wdbTransferGopher
  632.     (
  633.     WDB_MEM_XFER *  pValueTape
  634.     )
  635.     {
  636.     int offset = 0;
  637.     int tIndex = 0;
  638.     int ix;
  639.     /* 
  640.      * from the index of the request we computed the start address of the
  641.      * result string
  642.      */
  643. #ifdef DEBUG
  644.     printErr ("tapeIndex = %dn", tapeIndex);
  645. #endif
  646.     for (ix = 0; (ix < tapeIndex); ix++)
  647. {
  648. offset += min (wdbCommMtu - WDB_GOPHER_MTU_OFFSET, tapeLen);
  649. if (offset >= pAddTapeIx[tIndex])
  650.     {
  651.     offset = 0;
  652.     tIndex++;
  653.     }
  654. }
  655.     tapeIndex ++;
  656.     /* free the last used tape if necessary */
  657.     if ((tIndex > 1) && (pAddTape[tIndex - 1]) && (pWdbRtIf->free != NULL))
  658. {
  659. (*pWdbRtIf->free) (pAddTape[tIndex - 1]);
  660. pAddTape[tIndex - 1] = NULL;
  661. }
  662.     /* check if every thing is transfered or if we should send another tape */
  663.     if ((tIndex == ADD_TAPE_NB) || (pAddTapeIx[tIndex] == 0))
  664. {
  665. pValueTape->numBytes = 0;
  666. return OK;
  667. }
  668.     pValueTape->source = (char *)((int)pAddTape[tIndex] + offset);
  669.     pValueTape->numBytes = min (pAddTapeIx[tIndex] - offset,
  670. wdbCommMtu - WDB_GOPHER_MTU_OFFSET);
  671. #ifdef DEBUG
  672.     printErr ("pAddTapeIx[%d]= %d, offset = %d, numbytes = %dn", tIndex,
  673.       pAddTapeIx[tIndex], offset, pValueTape->numBytes);
  674. #endif
  675.     /*
  676.      * what about status to return
  677.      * the only case to return OK is no tapes were allocated and the current
  678.      * tape is transfered
  679.      */
  680.     if (tIndex == 0)
  681. {
  682. if ((pValueTape->numBytes + offset >= pAddTapeIx[tIndex]) &&
  683.     (pAddTape[tIndex + 1] == NULL))
  684.     /* tape 0 is finished and there is no other one */
  685.     return OK;
  686. }
  687.     
  688.     return (OK | WDB_TO_BE_CONTINUED);
  689.     }
  690. /*****************************************************************************
  691. *
  692. * gopherNewTapeAllocate - when possible allocate a buffer to store a longer
  693. *   gopher string
  694. *
  695. */
  696. static STATUS gopherNewTapeAllocate
  697.     (
  698.     wdbGopherCtx_t *    gc
  699.     )
  700.     {
  701.     pAddTapeIx[tapeIndex] = gc->tapeIx;
  702.     if (wdbIsNowTasking ())
  703. {
  704. /* try to allocate a new tape if possible */
  705. if ((pWdbRtIf->malloc == NULL) ||
  706.     (++tapeIndex >= ADD_TAPE_NB) ||
  707.     ((pAddTape[tapeIndex] = (*pWdbRtIf->malloc) (gc->tapeLen))
  708.      == NULL))
  709.     {
  710.     gc->status = WDB_ERR_GOPHER_TRUNCATED;
  711.     return ERROR;
  712.     }
  713. gc->pTape = pAddTape[tapeIndex];
  714. gc->tapeIx = 0;
  715. }
  716.     else
  717. {
  718. /* system mode: we can't allocate more than the static buffer */
  719. gc->status = WDB_ERR_GOPHER_TRUNCATED;
  720. return ERROR;
  721. }
  722.     return OK;
  723.     }
  724. /*****************************************************************************
  725. * gopherWriteScalar - write a scalar value on a gopher tape
  726. *
  727. */
  728. static STATUS gopherWriteScalar
  729.     (
  730.     wdbGopherCtx_t * gc, /* gopher context */
  731.     UINT8 * src, /* source address */
  732.     int type /* GOPHER_UINT32, etc. */
  733.     )
  734.     {
  735.     int  nbytes = 4; /* UINT32 is most common */
  736.     int r1; /* memProbe result */
  737.     int r2; /* memProbe result */
  738.     INT8 dummy [4]; /* dummy memProbe buf */
  739.     if (type == GOPHER_UINT16)   nbytes = 2; /* fix nbytes if size != 4 */
  740.     if (type == GOPHER_UINT8)    nbytes = 1;
  741.     if (type == GOPHER_FLOAT64)  nbytes = 8;
  742.     if (type == GOPHER_FLOAT80)  nbytes = 10;
  743.     /* We must have at least nbytes+1 bytes left: one for type marker,
  744.        nbytes for the scalar itself. */
  745.     if (gc->tapeLen - gc->tapeIx < nbytes+1)
  746. {
  747. if (gopherNewTapeAllocate (gc) == ERROR)
  748.     return ERROR;
  749. }
  750.     /* Write the scalar type. */
  751.     gc->pTape [gc->tapeIx++] = type;
  752.     /* Write the scalar itself--probe the two endpoints. */
  753.     if (nbytes <= 4)
  754. {
  755. r1 = r2 = (*pWdbRtIf->memProbe) ((char *) src, VX_READ, nbytes, dummy); 
  756. }
  757.     else
  758. {
  759. r1 = (*pWdbRtIf->memProbe) ((char *) src, VX_READ, 1, dummy); 
  760. r2 = (*pWdbRtIf->memProbe) ((char *) src + nbytes - 1, VX_READ, 1,
  761.     dummy);
  762. }
  763.     if (r1 == OK && r2 == OK)
  764. {
  765. bcopy ((char *) src, gc->pTape + gc->tapeIx, nbytes);
  766. gc->tapeIx += nbytes;
  767. return OK;
  768. }
  769.     else
  770. {
  771. gc->status = WDB_ERR_GOPHER_FAULT;
  772. return ERROR;
  773. }
  774.     }
  775. /*****************************************************************************
  776. *
  777. * gopherWriteString - write a string to a gopher tape
  778. *
  779. */
  780. static STATUS gopherWriteString
  781.     (
  782.     wdbGopherCtx_t * gc,
  783.     char * string
  784.     )
  785.     {
  786.     int r1; /* memProbe result */
  787.     int r2; /* memProbe result */
  788.     int r3 = 0; /* memProbe result */
  789.     char dummy; /* memProbe read value */
  790.     int maxlen; /* how much we can carry */
  791.     char * p = string;
  792.     int  ix;
  793.     if (string == 0)
  794. {
  795. if (gc->tapeLen - gc->tapeIx < 1)
  796.     {
  797.     if (gopherNewTapeAllocate (gc) == ERROR)
  798. return ERROR;
  799.     }
  800. gc->pTape [gc->tapeIx++] = GOPHER_STRING;
  801. if (gc->tapeLen - gc->tapeIx < 1)
  802.     {
  803.     if (gopherNewTapeAllocate (gc) == ERROR)
  804. return ERROR;
  805.     }
  806. gc->pTape [gc->tapeIx++] = EOS;
  807. return OK;
  808. }
  809.     /* if possible, write the gopher type on the tape */
  810.     if (gc->tapeLen - gc->tapeIx < 1)
  811. {
  812. if (gopherNewTapeAllocate (gc) == ERROR)
  813.     return ERROR;
  814. }
  815.     gc->pTape [gc->tapeIx++] = GOPHER_STRING;
  816.     /* write the string itself */
  817.     while (1)
  818. {
  819. /* We can write no more than the size of the remaining buffer */
  820. maxlen = gc->tapeLen - gc->tapeIx;
  821. /* probe the two endpoints.  Note there's a weakness here; it may
  822.    be that a short string lies near the boundary of a memory
  823.    accessibility region and we're about to probe past the end of
  824.    it, which may give a false result.  But we can't call strlen on
  825.    the string without some hope that it is bounded by real
  826.    memory. */
  827. r1 = (*pWdbRtIf->memProbe) (p, VX_READ, 1, &dummy);
  828. r2 = (*pWdbRtIf->memProbe) (p + maxlen, VX_READ, 1, &dummy);
  829. if (r1 == OK && r2 != OK)
  830.     {
  831.     /* If the start endpoint probe was okay, but not the end one then
  832.      * we assume we have tried to read outside the memory boundary.
  833.      * Given that the boundary is probably at the very least 2K byte
  834.      * aligned (more likely 64k or more), we modify the top 
  835.      * address to account for this and repeat the probe just for good 
  836.      * measure. 
  837.      */
  838.     maxlen = ((((long) (p + maxlen)) & ~0x7ff) - 1) - (long) p;
  839.     r3 = (*pWdbRtIf->memProbe) (p + maxlen, VX_READ, 1, &dummy);
  840.     }
  841. if (r1 != OK || r3 != OK)
  842.     break; /* exit loop: there is an error */
  843. for (ix = 0;
  844.      *p && ix < maxlen;
  845.      p++, ix++)
  846.     {
  847.     /*
  848.      * Do not need to test if there is place for each character.
  849.      * We can't write more than <maxlen> character (i.e. fill the 
  850.      * current tape ).
  851.      */
  852.     gc->pTape [gc->tapeIx++] = *p;
  853.     }
  854. #if DEBUG
  855. printf ("maxlen=%d, r1=%d, r2=%d, r3=%d, ix=%d, *p=%#xn",
  856. maxlen, r1, r2, r3, ix, *p);
  857. #endif
  858. if (*p == EOS)
  859.     {
  860.     /* EOS found : write null terminator and return OK */
  861.     if (gc->tapeLen - gc->tapeIx < 1)
  862. {
  863. if (gopherNewTapeAllocate (gc) == ERROR)
  864.     return ERROR;
  865. }
  866.     gc->pTape [gc->tapeIx++] = *p;
  867.     return OK;
  868.     }
  869. else if (r2 != OK)
  870.     {
  871.     /* we reached maxlen (hardware limitation) : return ERROR */
  872.     gc->status = WDB_ERR_GOPHER_TRUNCATED;
  873.     return (ERROR);
  874.     }
  875. else
  876.     {
  877.     /*
  878.      * we finished the probed zone so re-probe before continuing
  879.      * we allocate a new tape (if needed) to update maxlen computation
  880.      */
  881.     if (gc->tapeLen - gc->tapeIx < 1)
  882. {
  883. if (gopherNewTapeAllocate (gc) == ERROR)
  884.     return (ERROR);
  885. }
  886.     }
  887. }
  888.     /* one of the endpoints was bogus.  Can't write the string. */
  889.     gc->status = WDB_ERR_GOPHER_FAULT;
  890.     return ERROR;
  891.     }
  892. #endif /* #ifdef HOST */