aboutsummaryrefslogtreecommitdiff
path: root/lib/sendf.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2006-04-26 07:40:37 +0000
committerDaniel Stenberg <daniel@haxx.se>2006-04-26 07:40:37 +0000
commit95152aec685c4d11de6cb25802303e4872d51b3e (patch)
tree213409d6a9103d2b2be41474782cdd0ffd3ef28f /lib/sendf.c
parent8ed676236395ef970e7c3b74aebbd1f8eef837ba (diff)
David McCreedy brought line end conversions when doing FTP ASCII
transfers. They are done on non-windows systems and translate CRLF to LF.
Diffstat (limited to 'lib/sendf.c')
-rw-r--r--lib/sendf.c113
1 files changed, 98 insertions, 15 deletions
diff --git a/lib/sendf.c b/lib/sendf.c
index dda70c42b..a9cb58363 100644
--- a/lib/sendf.c
+++ b/lib/sendf.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -139,6 +139,89 @@ void curl_slist_free_all(struct curl_slist *list)
} while (next);
}
+#ifdef CURL_DO_LINEEND_CONV
+/*
+ * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
+ * (\n), with special processing for CRLF sequences that are split between two
+ * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new
+ * size of the data is returned.
+ */
+static size_t convert_lineends(struct SessionHandle *data,
+ char *startPtr, size_t size)
+{
+ char *inPtr, *outPtr;
+
+ /* sanity check */
+ if ((startPtr == NULL) || (size < 1)) {
+ return(size);
+ }
+
+ if (data->state.prev_block_had_trailing_cr == TRUE) {
+ /* The previous block of incoming data
+ had a trailing CR, which was turned into a LF. */
+ if (*startPtr == '\n') {
+ /* This block of incoming data starts with the
+ previous block's LF so get rid of it */
+ memcpy(startPtr, startPtr+1, size-1);
+ size--;
+ /* and it wasn't a bare CR but a CRLF conversion instead */
+ data->state.crlf_conversions++;
+ }
+ data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
+ }
+
+ /* find 1st CR, if any */
+ inPtr = outPtr = memchr(startPtr, '\r', size);
+ if (inPtr) {
+ /* at least one CR, now look for CRLF */
+ while (inPtr < (startPtr+size-1)) {
+ /* note that it's size-1, so we'll never look past the last byte */
+ if (memcmp(inPtr, "\r\n", 2) == 0) {
+ /* CRLF found, bump past the CR and copy the NL */
+ inPtr++;
+ *outPtr = *inPtr;
+ /* keep track of how many CRLFs we converted */
+ data->state.crlf_conversions++;
+ }
+ else {
+ if (*inPtr == '\r') {
+ /* lone CR, move LF instead */
+ *outPtr = '\n';
+ }
+ else {
+ /* not a CRLF nor a CR, just copy whatever it is */
+ *outPtr = *inPtr;
+ }
+ }
+ outPtr++;
+ inPtr++;
+ } /* end of while loop */
+
+ if (inPtr < startPtr+size) {
+ /* handle last byte */
+ if (*inPtr == '\r') {
+ /* deal with a CR at the end of the buffer */
+ *outPtr = '\n'; /* copy a NL instead */
+ /* note that a CRLF might be split across two blocks */
+ data->state.prev_block_had_trailing_cr = TRUE;
+ }
+ else {
+ /* copy last byte */
+ *outPtr = *inPtr;
+ }
+ outPtr++;
+ inPtr++;
+ }
+ if (outPtr < startPtr+size) {
+ /* tidy up by null terminating the now shorter data */
+ *outPtr = '\0';
+ }
+ return(outPtr - startPtr);
+ }
+ return(size);
+}
+#endif /* CURL_DO_LINEEND_CONV */
+
/* Curl_infof() is for info message along the way */
void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
@@ -294,36 +377,36 @@ CURLcode Curl_client_write(struct SessionHandle *data,
if(0 == len)
len = strlen(ptr);
-#ifdef CURL_DOES_CONVERSIONS
if(type & CLIENTWRITE_BODY) {
if(data->ftp_in_ascii_mode) {
+#ifdef CURL_DOES_CONVERSIONS
/* convert from the network encoding */
size_t rc;
rc = Curl_convert_from_network(data, ptr, len);
/* Curl_convert_from_network calls failf if unsuccessful */
- if(rc != CURLE_OK) {
- return(rc);
- }
+ if(rc != CURLE_OK)
+ return rc;
+#endif /* CURL_DOES_CONVERSIONS */
+
+#ifdef CURL_DO_LINEEND_CONV
+ /* convert end-of-line markers */
+ len = convert_lineends(data, ptr, len);
+#endif /* CURL_DO_LINEEND_CONV */
}
+ /* If the previous block of data ended with CR and this block of data is
+ just a NL, then the length might be zero */
if (len) {
wrote = data->set.fwrite(ptr, 1, len, data->set.out);
- } else {
- wrote = len;
}
- if(wrote != len) {
- failf (data, "Failed writing body");
- return CURLE_WRITE_ERROR;
+ else {
+ wrote = len;
}
- }
-#else
- if(type & CLIENTWRITE_BODY) {
- wrote = data->set.fwrite(ptr, 1, len, data->set.out);
+
if(wrote != len) {
failf (data, "Failed writing body");
return CURLE_WRITE_ERROR;
}
}
-#endif /* CURL_DOES_CONVERSIONS */
if((type & CLIENTWRITE_HEADER) &&
(data->set.fwrite_header || data->set.writeheader) ) {