archie/prospero/lib/ardp/ardp_add2req.c
2024-05-27 16:13:40 +02:00

164 lines
5.6 KiB
C

/*
* Copyright (c) 1993 by the University of Southern California
*
* For copying and distribution information, please see the file
* <usc-copyr.h>.
*
* Written by bcn 2/93 to add text to a request
*/
#include <usc-copyr.h>
#include <string.h>
#include <stdio.h>
#include <ardp.h>
#include <sys/types.h> /* so pmachine.h won't redefine it. */
#include <pmachine.h> /* for bcopy() */
#define max(x,y) (x > y ? x : y)
#define min(x,y) (x < y ? x : y)
/*
* ardp_add2req - add text to request structure
*
* ardp_add2req takes a request structure, flags, a buffer containing text
* to be added to the output queue of the request, and the length of the
* buffer.
*
* If the specified length of the buffer is 0, ardp_add2req calculates
* it using strlen (if the lenght is zero, the assumption is that the
* buffer is null terminated).
* If the buffer is a NULL pointer and the specified length is 0, then
* it treated as a true zero-length buffer.
*
* If the flag ARDP_A2R_NOSPLITB is set, the request will not be split
* across packets. If ARDP_A2R_NOSPLITL, the lines may not be split
* across packets, and text added to a request without a trailing new
* line will be deferred until a newline is added or ardp_add2req is called
* without ARDP_A2R_NOSPLITL set. If ARDP_A2R_COMPLETE is specified, it
* indicates this is the final text to be added to the request structure,
* and no text will remain buffered. If there is still deferred text,
* a newline will be added. If the flag ARDP_A2R_TAGLENGTH is specified,
* the data written to the request will be tagged with a four octet length
* field in network byte order.
*
* NOTE: If you use this function to add text to a request, then you
* should use only this function. If this function is called on
* a request previously constructed by hand, unexpected failures
* may result.
*
* BUGS: ARDP_A2R_NOSPLITL is not currently supported unless
* ARDP_A2R_NOSPLITB is also set.
* ARDP_A2R_TAGLENGTH is not presently supported.
* An ardp_flush_partial_line() is needed to handle some manifestations
* of the ARDP_TOOLONG error. Alternatively, we might specify an
* additional flag to ardp_add2req() to specify the behavior on an
* ARDP_TOOLONG error.
*/
int
ardp_add2req(RREQ req, /* Request to get the text */
int flags, /* Options to add2req */
char *buf, /* New text for request */
int buflen) /* Length of the new text */
{
int remaining; /* Space remaining in pkt */
int written; /* # Octets written */
char *newline; /* last nl in string */
int deflen; /* Length of deferred text */
int extra; /* Extra space needed */
long taglen; /* Length in net byte ord */
PTEXT pkt = NOPKT; /* Current packet */
PTEXT ppkt; /* Previous packet */
/* Note: New text gets written after pkt->ioptr. If */
/* there is text waiting for a newline, then ->ioptr */
/* may be beyond ->start+->length, which will be the */
/* text up to the final newline seen so far */
/* XXX For now if NOSPLITL, must also specify NOSPLITB */
if((flags & ARDP_A2R_NOSPLITL) && !(flags & ARDP_A2R_NOSPLITB))
return(ARDP_FAILURE);
if(buf && !buflen) buflen = strlen(buf);
if(!buf) buf = "";
keep_writing:
/* Find ot allocate last packet in ->outpkt */
if(req->outpkt) pkt = req->outpkt->previous;
if(!pkt) {
if((pkt = ardp_ptalloc()) == NOPKT) return(ARDP_FAILURE);
APPEND_ITEM(pkt,req->outpkt);
}
deflen = pkt->ioptr - (pkt->start + pkt->length);
extra = deflen;
if(flags & ARDP_A2R_NOSPLITL) extra += 1;
if(flags & ARDP_A2R_TAGLENGTH) extra += 4;
if((flags & ARDP_A2R_NOSPLITB) && (buflen + extra > ARDP_PTXT_LEN))
return(ARDP_TOOLONG);
remaining = ARDP_PTXT_LEN - (pkt->ioptr - pkt->start);
if(((flags & ARDP_A2R_NOSPLITB) && (remaining < buflen + 1)) ||
((flags & ARDP_A2R_TAGLENGTH) && (remaining < 4)) ||
(remaining == 0)) {
ppkt = pkt;
if((pkt = ardp_ptalloc()) == NOPKT) return(ARDP_FAILURE);
if(ppkt->start + ppkt->length != ppkt->ioptr) {
/* Must move deferred text to new packet */
bcopy(ppkt->start+ppkt->length, pkt->start, deflen);
ppkt->ioptr = ppkt->start + ppkt->length;
*(ppkt->ioptr) = '\0';
pkt->ioptr += deflen;
}
APPEND_ITEM(pkt,req->outpkt);
remaining = ARDP_PTXT_LEN;
}
if(flags & ARDP_A2R_TAGLENGTH) {
taglen = htonl(buflen);
bcopy4(&buflen,pkt->ioptr);
pkt->ioptr += 4;
remaining -= 4;
}
written = min(remaining,buflen);
bcopy(buf,pkt->ioptr,written);
pkt->ioptr += written;
if(flags & ARDP_A2R_NOSPLITL) {
*(pkt->ioptr) = '\0'; /* To catch runaway strrchar */
/* Find last newline */
newline = strrchr(pkt->start + pkt->length,'\n');
if(newline) pkt->length = newline + 1 - pkt->start;
}
else pkt->length = pkt->ioptr - pkt->start;
/* Always need to stick on trailing NULL for sake of ardp_respond(),
which expects it. */
*pkt->ioptr = '\0';
/* In this case, ARDP_A@R_NOSPLITB was not specified, split it */
if(written != buflen) {
buf += written;
buflen -= written;
goto keep_writing;
}
if(flags & ARDP_A2R_COMPLETE) {
deflen = pkt->ioptr - (pkt->start + pkt->length);
/* If deferred, write a newline */
if(deflen) {
*(pkt->ioptr++) = '\n';
pkt->length = pkt->ioptr - pkt->start;
/* Always need to stick on trailing NULL for sake of
ardp_respond(), which expects it. */
*pkt->ioptr = '\0';
}
}
return ARDP_SUCCESS;
}