Browse code

Optimise empty lines

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@622 77e5149b-7576-45b1-b177-96237e5ba77b

Nigel Horne authored on 2004/06/22 13:08:02
Showing 4 changed files
... ...
@@ -17,6 +17,9 @@
17 17
  *
18 18
  * Change History:
19 19
  * $Log: mbox.c,v $
20
+ * Revision 1.79  2004/06/22 04:08:01  nigelhorne
21
+ * Optimise empty lines
22
+ *
20 23
  * Revision 1.78  2004/06/21 10:21:19  nigelhorne
21 24
  * Fix crash when a multipart/mixed message contains many parts that need to be scanned as attachments
22 25
  *
... ...
@@ -222,7 +225,7 @@
222 222
  * Compilable under SCO; removed duplicate code with message.c
223 223
  *
224 224
  */
225
-static	char	const	rcsid[] = "$Id: mbox.c,v 1.78 2004/06/21 10:21:19 nigelhorne Exp $";
225
+static	char	const	rcsid[] = "$Id: mbox.c,v 1.79 2004/06/22 04:08:01 nigelhorne Exp $";
226 226
 
227 227
 #if HAVE_CONFIG_H
228 228
 #include "clamav-config.h"
... ...
@@ -266,6 +269,21 @@ static	char	const	rcsid[] = "$Id: mbox.c,v 1.78 2004/06/21 10:21:19 nigelhorne E
266 266
 #include "defaults.h"
267 267
 #include "str.h"
268 268
 
269
+#ifdef	CL_DEBUG
270
+#if __GLIBC__ == 2 && __GLIBC_MINOR__ >= 1
271
+#define HAVE_BACKTRACE
272
+#endif
273
+
274
+#ifdef HAVE_BACKTRACE
275
+#include <execinfo.h>
276
+#include <signal.h>
277
+#include <syslog.h>
278
+#endif
279
+
280
+static	void	sigsegv(int sig);
281
+static	void	print_trace(int use_syslog);
282
+#endif
283
+
269 284
 #if	defined(NO_STRTOK_R) || !defined(CL_THREAD_SAFE)
270 285
 #undef strtok_r
271 286
 #undef __strtok_r
... ...
@@ -395,6 +413,9 @@ cl_mbox(const char *dir, int desc)
395 395
 	message *m, *body;
396 396
 	FILE *fd;
397 397
 	char buffer[LINE_LENGTH];
398
+#ifdef	CL_DEBUG
399
+	void (*segv)(int);
400
+#endif
398 401
 
399 402
 	cli_dbgmsg("in mbox()\n");
400 403
 
... ...
@@ -436,6 +457,10 @@ cl_mbox(const char *dir, int desc)
436 436
 	pthread_mutex_unlock(&tables_mutex);
437 437
 #endif
438 438
 
439
+#ifdef	CL_DEBUG
440
+	segv = signal(SIGSEGV, sigsegv);
441
+#endif
442
+
439 443
 	/*
440 444
 	 * is it a UNIX style mbox with more than one
441 445
 	 * mail message, or just a single mail message?
... ...
@@ -519,6 +544,10 @@ cl_mbox(const char *dir, int desc)
519 519
 
520 520
 	cli_dbgmsg("cli_mbox returning %d\n", retcode);
521 521
 
522
+#ifdef	CL_DEBUG
523
+	signal(SIGSEGV, segv);
524
+#endif
525
+
522 526
 	return retcode;
523 527
 }
524 528
 
... ...
@@ -537,27 +566,33 @@ parseEmailHeaders(const message *m, const table_t *rfc821Table)
537 537
 	const text *t;
538 538
 	message *ret;
539 539
 
540
+	cli_dbgmsg("parseEmailHeaders\n");
541
+
540 542
 	if(m == NULL)
541 543
 		return NULL;
542 544
 
543 545
 	ret = messageCreate();
544 546
 
545 547
 	for(t = messageGetBody(m); t; t = t->t_next) {
546
-		char *buffer = strdup(t->t_text);
548
+		char *buffer;
547 549
 #ifdef CL_THREAD_SAFE
548 550
 		char *strptr;
549 551
 #endif
550 552
 
551
-		if(buffer == NULL)
552
-			break;
553
-
554
-		cli_chomp(buffer);
553
+		if(t->t_text) {
554
+			buffer = strdup(t->t_text);
555
+			if(buffer == NULL)
556
+				break;
557
+			cli_chomp(buffer);
558
+		} else
559
+			buffer = NULL;
555 560
 
556 561
 		/*
557 562
 		 * Section B.2 of RFC822 says TAB or SPACE means
558 563
 		 * a continuation of the previous entry.
559 564
 		 */
560
-		if(inHeader && ((buffer[0] == '\t') || (buffer[0] == ' ')))
565
+		if(inHeader && buffer &&
566
+		  ((buffer[0] == '\t') || (buffer[0] == ' ')))
561 567
 			inContinuationHeader = TRUE;
562 568
 
563 569
 		if(inContinuationHeader) {
... ...
@@ -569,22 +604,23 @@ parseEmailHeaders(const message *m, const table_t *rfc821Table)
569 569
 			/*
570 570
 			 * Add all the arguments on the line
571 571
 			 */
572
-			for(ptr = strtok_r(buffer, ";", &strptr); ptr; ptr = strtok_r(NULL, ":", &strptr))
573
-				messageAddArgument(ret, ptr);
574
-			free(buffer);
572
+			if(buffer) {
573
+				for(ptr = strtok_r(buffer, ";", &strptr); ptr; ptr = strtok_r(NULL, ":", &strptr))
574
+					messageAddArgument(ret, ptr);
575
+				free(buffer);
576
+			}
575 577
 		} else if(inHeader) {
576
-			cli_dbgmsg("Deal with header %s\n", buffer);
577
-
578 578
 			/*
579 579
 			 * A blank line signifies the end of the header and
580 580
 			 * the start of the text
581 581
 			 */
582
-			if(strlen(buffer) == 0) {
582
+			if((buffer == NULL) || (strlen(buffer) == 0)) {
583 583
 				cli_dbgmsg("End of header information\n");
584 584
 				inContinuationHeader = inHeader = FALSE;
585 585
 			} else if(parseEmailHeader(ret, buffer, rfc821Table) == CONTENT_TYPE)
586 586
 				inContinuationHeader = continuationMarker(buffer);
587
-			free(buffer);
587
+			if(buffer)
588
+				free(buffer);
588 589
 		} else {
589 590
 			/*cli_dbgmsg("Add line to body '%s'\n", buffer);*/
590 591
 			messageAddLine(ret, buffer, 0);
... ...
@@ -787,11 +823,12 @@ parseEmailBody(message *messageIn, blob **blobsIn, int nBlobs, text *textIn, con
787 787
 				 * Ignore blank lines. There shouldn't be ANY
788 788
 				 * but some viruses insert them
789 789
 				 */
790
-				while((t_line = t_line->t_next) != NULL) {
791
-					cli_chomp(t_line->t_text);
792
-					if(strlen(t_line->t_text) != 0)
793
-						break;
794
-				}
790
+				while((t_line = t_line->t_next) != NULL)
791
+					if(t_line->t_text) {
792
+						cli_chomp(t_line->t_text);
793
+						if(strlen(t_line->t_text) != 0)
794
+							break;
795
+					}
795 796
 
796 797
 				if(t_line == NULL) {
797 798
 					cli_dbgmsg("Empty part\n");
... ...
@@ -805,6 +842,10 @@ parseEmailBody(message *messageIn, blob **blobsIn, int nBlobs, text *textIn, con
805 805
 						inMimeHead, inhead, boundary, line, t_line->t_next ? t_line->t_next->t_text : "(null)");*/
806 806
 
807 807
 					if(inMimeHead) {
808
+						if(line == NULL) {
809
+							inhead = inMimeHead = 0;
810
+							continue;
811
+						}
808 812
 						/*
809 813
 						 * Handle continuation lines
810 814
 						 * because the previous line
... ...
@@ -836,7 +877,8 @@ parseEmailBody(message *messageIn, blob **blobsIn, int nBlobs, text *textIn, con
836 836
 						inMimeHead = continuationMarker(line);
837 837
 						messageAddArgument(aMessage, line);
838 838
 					} else if(inhead) {
839
-						if(strlen(line) == 0) {
839
+						if(line == NULL) {
840
+							/* empty line */
840 841
 							inhead = 0;
841 842
 							continue;
842 843
 						}
... ...
@@ -872,7 +914,9 @@ parseEmailBody(message *messageIn, blob **blobsIn, int nBlobs, text *textIn, con
872 872
 						 */
873 873
 						inMimeHead = continuationMarker(line);
874 874
 						if(!inMimeHead)
875
-							if(t_line->t_next && ((t_line->t_next->t_text[0] == '\t') || (t_line->t_next->t_text[0] == ' ')))
875
+							if(t_line->t_next &&
876
+							   t_line->t_next->t_text &&
877
+							  ((t_line->t_next->t_text[0] == '\t') || (t_line->t_next->t_text[0] == ' ')))
876 878
 								inMimeHead = TRUE;
877 879
 
878 880
 						parseEmailHeader(aMessage, line, rfc821Table);
... ...
@@ -1540,7 +1584,8 @@ parseEmailBody(message *messageIn, blob **blobsIn, int nBlobs, text *textIn, con
1540 1540
 				 * won't be scanned
1541 1541
 				 */
1542 1542
 				for(t = t_line; t; t = t->t_next)
1543
-					if((strncasecmp(t->t_text, encoding, sizeof(encoding) - 1) == 0) &&
1543
+					if(t->t_text &&
1544
+					   (strncasecmp(t->t_text, encoding, sizeof(encoding) - 1) == 0) &&
1544 1545
 					   (strstr(t->t_text, "7bit") == NULL))
1545 1546
 						break;
1546 1547
 				if(t && ((b = textToBlob(t_line, NULL)) != NULL)) {
... ...
@@ -1646,6 +1691,8 @@ boundaryStart(const char *line, const char *boundary)
1646 1646
 	 * notice the extra '-'
1647 1647
 	 */
1648 1648
 	/*cli_dbgmsg("boundaryStart: line = '%s' boundary = '%s'\n", line, boundary);*/
1649
+	if(line == NULL)
1650
+		return 0;	/* empty line */
1649 1651
 	if(strstr(line, boundary) != NULL) {
1650 1652
 		cli_dbgmsg("found %s in %s\n", boundary, line);
1651 1653
 		return 1;
... ...
@@ -1667,6 +1714,8 @@ endOfMessage(const char *line, const char *boundary)
1667 1667
 {
1668 1668
 	size_t len;
1669 1669
 
1670
+	if(line == NULL)
1671
+		return 0;
1670 1672
 	if(*line++ != '-')
1671 1673
 		return 0;
1672 1674
 	if(*line++ != '-')
... ...
@@ -1789,6 +1838,7 @@ strstrip(char *s)
1789 1789
 {
1790 1790
 	if(s == (char *)NULL)
1791 1791
 		return(0);
1792
+
1792 1793
 	return(strip(s, strlen(s) + 1));
1793 1794
 }
1794 1795
 
... ...
@@ -1804,7 +1854,8 @@ continuationMarker(const char *line)
1804 1804
 {
1805 1805
 	const char *ptr;
1806 1806
 
1807
-	assert(line != NULL);
1807
+	if(line == NULL)
1808
+		return FALSE;
1808 1809
 
1809 1810
 #ifdef	CL_DEBUG
1810 1811
 	cli_dbgmsg("continuationMarker(%s)\n", line);
... ...
@@ -2030,3 +2081,43 @@ saveFile(const blob *b, const char *dir)
2030 2030
 
2031 2031
 	return (close(fd) >= 0);
2032 2032
 }
2033
+
2034
+#ifdef	CL_DEBUG
2035
+static void
2036
+sigsegv(int sig)
2037
+{
2038
+	signal(SIGSEGV, SIG_DFL);
2039
+	print_trace(0);
2040
+	exit(SIGSEGV);
2041
+}
2042
+
2043
+static void
2044
+print_trace(int use_syslog)
2045
+{
2046
+#ifdef HAVE_BACKTRACE
2047
+	void *array[10];
2048
+	size_t size;
2049
+	char **strings;
2050
+	size_t i;
2051
+	pid_t pid = getpid();
2052
+
2053
+	size = backtrace(array, 10);
2054
+	strings = backtrace_symbols(array, size);
2055
+
2056
+	syslog(LOG_ERR, "Backtrace of pid %d:", pid);
2057
+
2058
+	if(use_syslog == 0)
2059
+		cli_dbgmsg("Backtrace of pid %d:\n", pid);
2060
+	else 
2061
+		syslog(LOG_ERR, "Backtrace of pid %d:", pid);
2062
+
2063
+	for(i = 0; i < size; i++)
2064
+		if(use_syslog)
2065
+			syslog(LOG_ERR, "bt[%d]: %s", i, strings[i]);
2066
+		else
2067
+			cli_dbgmsg("%s\n", strings[i]);
2068
+
2069
+	free(strings);
2070
+#endif
2071
+}
2072
+#endif
... ...
@@ -17,6 +17,9 @@
17 17
  *
18 18
  * Change History:
19 19
  * $Log: message.c,v $
20
+ * Revision 1.61  2004/06/22 04:08:02  nigelhorne
21
+ * Optimise empty lines
22
+ *
20 23
  * Revision 1.60  2004/06/16 08:07:39  nigelhorne
21 24
  * Added thread safety
22 25
  *
... ...
@@ -177,7 +180,7 @@
177 177
  * uuencodebegin() no longer static
178 178
  *
179 179
  */
180
-static	char	const	rcsid[] = "$Id: message.c,v 1.60 2004/06/16 08:07:39 nigelhorne Exp $";
180
+static	char	const	rcsid[] = "$Id: message.c,v 1.61 2004/06/22 04:08:02 nigelhorne Exp $";
181 181
 
182 182
 #if HAVE_CONFIG_H
183 183
 #include "clamav-config.h"
... ...
@@ -244,7 +247,7 @@ static	const	struct	encoding_map {
244 244
 	{	"7bit",			NOENCODING	},
245 245
 	{	"text/plain",		NOENCODING	},
246 246
 	{	"quoted-printable",	QUOTEDPRINTABLE	},	/* rfc1522 */
247
-	{	"base64",		BASE64		},
247
+	{	"base64",		BASE64		},	/* rfc2045 */
248 248
 	{	"8bit",			EIGHTBIT	},
249 249
 	{	"8 bit",		EIGHTBIT	},	/* incorrect */
250 250
 	{	"x-uuencode",		UUENCODE	},
... ...
@@ -792,23 +795,21 @@ messageAddLine(message *m, const char *line, int takeCopy)
792 792
 
793 793
 	m->body_last->t_next = NULL;
794 794
 
795
-	if(takeCopy) {
796
-		m->body_last->t_text = strdup((line) ? line : "");
797
-		if(m->body_last->t_text == NULL) {
798
-			cli_errmsg("messageAddLine: out of memory\n");
799
-			return -1;
800
-		}
801
-		assert(m->body_last->t_text != NULL);
802
-	} else {
803
-		assert(line != NULL);
804
-		m->body_last->t_text = (char *)line;
805
-	}
806
-
807
-	/*
808
-	 * See if this line marks the start of a non MIME inclusion that
809
-	 * will need to be scanned
810
-	 */
811 795
 	if(line && *line) {
796
+		if(takeCopy) {
797
+			m->body_last->t_text = strdup(line);
798
+			if(m->body_last->t_text == NULL) {
799
+				cli_errmsg("messageAddLine: out of memory\n");
800
+				return -1;
801
+			}
802
+			// cli_chomp(m->body_last->t_text);
803
+		} else
804
+			m->body_last->t_text = (char *)line;
805
+
806
+		/*
807
+		 * See if this line marks the start of a non MIME inclusion that
808
+		 * will need to be scanned
809
+		 */
812 810
 		if((m->encoding == NULL) &&
813 811
 		   (strncasecmp(line, encoding, sizeof(encoding) - 1) == 0) &&
814 812
 		   (strstr(line, "7bit") == NULL))
... ...
@@ -826,7 +827,9 @@ messageAddLine(message *m, const char *line, int takeCopy)
826 826
 			(isdigit(line[8])) &&
827 827
 			(line[9] == ' ')))
828 828
 				m->uuencode = m->body_last;
829
-	}
829
+	} else
830
+		m->body_last->t_text = NULL;
831
+
830 832
 	return 1;
831 833
 }
832 834
 
... ...
@@ -961,7 +964,8 @@ messageToBlob(message *m)
961 961
 		 * See RFC1741
962 962
 		 */
963 963
 		while((t_line = t_line->t_next) != NULL)
964
-			blobAddData(tmp, (unsigned char *)t_line->t_text, strlen(t_line->t_text));
964
+			if(t_line->t_text)
965
+				blobAddData(tmp, (unsigned char *)t_line->t_text, strlen(t_line->t_text));
965 966
 
966 967
 		data = blobGetData(tmp);
967 968
 
... ...
@@ -1324,13 +1328,12 @@ messageToText(const message *m)
1324 1324
 				last = last->t_next;
1325 1325
 			}
1326 1326
 
1327
-			if(last)
1328
-				last->t_text = strdup((char *)data);
1329
-
1330
-			if((last == NULL) || (last->t_text == NULL))
1327
+			if(last == NULL)
1331 1328
 				break;
1332 1329
 
1333
-			if(messageGetEncoding(m) == BASE64)
1330
+			last->t_text = data[0] ? strdup((char *)data) : NULL;
1331
+
1332
+			if(line && messageGetEncoding(m) == BASE64)
1334 1333
 				if(strchr(line, '='))
1335 1334
 					break;
1336 1335
 		}
... ...
@@ -1471,7 +1474,6 @@ decodeLine(const message *m, const char *line, unsigned char *buf, size_t buflen
1471 1471
 	char *copy;
1472 1472
 
1473 1473
 	assert(m != NULL);
1474
-	assert(line != NULL);
1475 1474
 	assert(buf != NULL);
1476 1475
 
1477 1476
 	switch(messageGetEncoding(m)) {
... ...
@@ -1483,11 +1485,20 @@ decodeLine(const message *m, const char *line, unsigned char *buf, size_t buflen
1483 1483
 		case NOENCODING:
1484 1484
 		case EIGHTBIT:
1485 1485
 		default:	/* unknown encoding type - try our best */
1486
+			if(line == NULL) {	/* empty line */
1487
+				*buf++ = '\n';
1488
+				break;
1489
+			}
1486 1490
 			buf = (unsigned char *)strrcpy((char *)buf, line);
1487 1491
 			/* Put the new line back in */
1488 1492
 			return (unsigned char *)strrcpy((char *)buf, "\n");
1489 1493
 
1490 1494
 		case QUOTEDPRINTABLE:
1495
+			if(line == NULL) {	/* empty line */
1496
+				*buf++ = '\n';
1497
+				break;
1498
+			}
1499
+			
1491 1500
 			softbreak = FALSE;
1492 1501
 			while(*line) {
1493 1502
 				if(*line == '=') {
... ...
@@ -1523,6 +1534,8 @@ decodeLine(const message *m, const char *line, unsigned char *buf, size_t buflen
1523 1523
 			break;
1524 1524
 
1525 1525
 		case BASE64:
1526
+			if(line == NULL)
1527
+				break;
1526 1528
 			/*
1527 1529
 			 * RFC1521 sets the maximum length to 76 bytes
1528 1530
 			 * but many e-mail clients ignore that
... ...
@@ -1537,14 +1550,14 @@ decodeLine(const message *m, const char *line, unsigned char *buf, size_t buflen
1537 1537
 			/*
1538 1538
 			 * Klez doesn't always put "=" on the last line
1539 1539
 			 */
1540
-			/*buf = decode(line, buf, base64, p2 == NULL);*/
1541
-			buf = decode(copy, buf, base64, FALSE);
1540
+			buf = decode(copy, buf, base64, (p2 == NULL) && ((strlen(copy) & 3) == 0));
1541
+			/*buf = decode(copy, buf, base64, FALSE);*/
1542 1542
 
1543 1543
 			free(copy);
1544 1544
 			break;
1545 1545
 
1546 1546
 		case UUENCODE:
1547
-			if(*line == '\0')	/* empty line */
1547
+			if((line == NULL) || (*line == '\0'))	/* empty line */
1548 1548
 				break;
1549 1549
 			if(strncasecmp(line, "begin ", 6) == 0)
1550 1550
 				break;
... ...
@@ -1580,6 +1593,7 @@ decode(const char *in, unsigned char *out, unsigned char (*decoder)(char), bool
1580 1580
 {
1581 1581
 	unsigned char b1, b2, b3, b4;
1582 1582
 
1583
+	/*cli_dbgmsg("decode %s (len %d ifFast %d)\n", in, strlen(in), isFast);*/
1583 1584
 	if(isFast)
1584 1585
 		/* Fast decoding if not last line */
1585 1586
 		while(*in) {
... ...
@@ -1609,23 +1623,17 @@ decode(const char *in, unsigned char *out, unsigned char (*decoder)(char), bool
1609 1609
 				b2 = '\0';
1610 1610
 				nbytes = 1;
1611 1611
 			} else {
1612
-				assert(*in != '\0');
1613
-
1614 1612
 				b2 = (*decoder)(*in++);
1615 1613
 				if(*in == '\0') {
1616 1614
 					b3 = '\0';
1617 1615
 					nbytes = 2;
1618 1616
 				} else {
1619
-					assert(*in != '\0');
1620
-
1621 1617
 					b3 = (*decoder)(*in++);
1622 1618
 
1623 1619
 					if(*in == '\0') {
1624 1620
 						b4 = '\0';
1625 1621
 						nbytes = 3;
1626 1622
 					} else {
1627
-						assert(*in != '\0');
1628
-
1629 1623
 						b4 = (*decoder)(*in++);
1630 1624
 						nbytes = 4;
1631 1625
 					}
... ...
@@ -16,6 +16,9 @@
16 16
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 17
  *
18 18
  * $Log: text.c,v $
19
+ * Revision 1.7  2004/06/22 04:08:02  nigelhorne
20
+ * Optimise empty lines
21
+ *
19 22
  * Revision 1.6  2004/05/05 09:37:52  nigelhorne
20 23
  * Removed textClean - not needed in clamAV
21 24
  *
... ...
@@ -27,7 +30,7 @@
27 27
  *
28 28
  */
29 29
 
30
-static	char	const	rcsid[] = "$Id: text.c,v 1.6 2004/05/05 09:37:52 nigelhorne Exp $";
30
+static	char	const	rcsid[] = "$Id: text.c,v 1.7 2004/06/22 04:08:02 nigelhorne Exp $";
31 31
 
32 32
 #if HAVE_CONFIG_H
33 33
 #include "clamav-config.h"
... ...
@@ -56,7 +59,8 @@ textDestroy(text *t_head)
56 56
 {
57 57
 	while(t_head) {
58 58
 		text *t_next = t_head->t_next;
59
-		free(t_head->t_text);
59
+		if(t_head->t_text)
60
+			free(t_head->t_text);
60 61
 		free(t_head);
61 62
 		t_head = t_next;
62 63
 	}
... ...
@@ -147,9 +151,11 @@ textCopy(const text *t_head)
147 147
 
148 148
 		assert(last != NULL);
149 149
 
150
-		last->t_text = strdup(t_head->t_text);
151
-
152
-		assert(last->t_text != NULL);
150
+		if(t_head->t_text) {
151
+			last->t_text = strdup(t_head->t_text);
152
+			assert(last->t_text != NULL);
153
+		} else
154
+			last->t_text = NULL;
153 155
 
154 156
 		t_head = t_head->t_next;
155 157
 	}
... ...
@@ -183,9 +189,11 @@ textAdd(text *t_head, const text *t)
183 183
 
184 184
 		assert(t_head != NULL);
185 185
 
186
-		t_head->t_text = strdup(t->t_text);
187
-
188
-		assert(t_head->t_text != NULL);
186
+		if(t->t_text) {
187
+			t_head->t_text = strdup(t->t_text);
188
+			assert(t_head->t_text != NULL);
189
+		} else
190
+			t_head->t_text = NULL;
189 191
 
190 192
 		t = t->t_next;
191 193
 	}
... ...
@@ -237,12 +245,16 @@ textToBlob(const text *t, blob *b)
237 237
 	}
238 238
 
239 239
 	for(t1 = t; t1; t1 = t1->t_next)
240
-		s += strlen(t1->t_text) + 1;
240
+		if(t1->t_text)
241
+			s += strlen(t1->t_text) + 1;
242
+		else
243
+			s++;
241 244
 
242 245
 	blobGrow(b, s);
243 246
 
244 247
 	do {
245
-		blobAddData(b, (unsigned char *)t->t_text, strlen(t->t_text));
248
+		if(t->t_text)
249
+			blobAddData(b, (unsigned char *)t->t_text, strlen(t->t_text));
246 250
 		blobAddData(b, (unsigned char *)"\n", 1);
247 251
 	} while((t = t->t_next) != NULL);
248 252
 
... ...
@@ -14,10 +14,15 @@
14 14
  *  You should have received a copy of the GNU General Public License
15 15
  *  along with this program; if not, write to the Free Software
16 16
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
+ *
18
+ * $Log: text.h,v $
19
+ * Revision 1.3  2004/06/22 04:08:02  nigelhorne
20
+ * Optimise empty lines
21
+ *
17 22
  */
18 23
 
19 24
 typedef struct text {
20
-	char	*t_text;
25
+	char	*t_text;	/* NULL if the line is empty */
21 26
 	struct	text	*t_next;
22 27
 } text;
23 28