#include #include #include #include #include /************************************************************************/ /* */ /************************************************************************/ static size_t read_body(FILE *fp, char *buf, size_t bufsiz, int *nlines, long *nbytes) { size_t cc; char *cp; while((bufsiz > 0) && (fgets(buf, bufsiz + 2, fp) != NULL)) { cc = strlen(buf); if(cc < bufsiz) bufsiz -= cc; else bufsiz = 0; cp = buf + cc - 1; if(cc > 1 && *(cp - 1) == '\r') { *cp-- = '\0'; *cp = '\n'; cc--; } if(*cp == '\n') { buf += cc; *nbytes += cc; (*nlines)++; } else bufsiz = 0; } return(bufsiz); } /************************************************************************/ /* */ /************************************************************************/ int append_temp(FILE *fp, char *name, char *buf, size_t bufsiz) { int r = 0; int cc; FILE *ft; if((ft = fopen(name, "rb")) != NULL) { while((cc = fread(buf, 1, bufsiz, ft)) != 0) fwrite(buf, 1, cc, fp); fclose(ft); r = 1; } else lperror(name); return(r); } /************************************************************************/ /* copy_body */ /* */ /* Reads an article's body from fpin and counts the number of lines. */ /* Then it writes a last header line "Lines:", an empty line and the */ /* article's body to fpout. */ /* */ /* If the size of the article body fits in the memory buffer, then */ /* this procedures works without a temporary disk file. */ /* */ /************************************************************************/ long copy_body(FILE *fpout, FILE *fpin, long body_size) { long rv = 0; size_t bufsiz = 32767; size_t left = bufsiz; int nlines = 0; char *buf = malloc(bufsiz); char *line = buf; FILE *fp; int cc; char *cp; if(body_size) { if((body_size + 2) < (long)bufsiz) { left = read_body(fpin, buf, (size_t)body_size, &nlines, &rv); rv += fprintf(fpout, "Lines: %u\n\n", nlines); fputs(buf, fpout); } else { char *tempname = tempnam(NULL, "ART"); long left4read = body_size; if((fp = fopen(tempname, "wb")) != NULL) { while(left4read > 0 && fgets(buf, (size_t)min(left4read + 2, (long)bufsiz), fpin)) { cc = strlen(buf); cp = buf + cc - 1; if(cc > 1 && *(cp - 1) == '\r') { *cp-- = '\0'; *cp = '\n'; cc--; } fputs(buf, fp); rv += cc; left4read -= cc; nlines++; } fclose(fp); if(body_size != rv) lprintf("Given %ld bytes, read %ld bytes\n", body_size, rv); rv += fprintf(fpout, "Lines: %u\n\n", nlines); append_temp(fpout, tempname, buf, bufsiz); if(unlink(tempname)) lperror(tempname); } else lperror(tempname); free(tempname); } } else { /* * Try to read the article into memory first */ left = read_body(fpin, buf, bufsiz - 2, &nlines, &rv); /* * If the article doesn't fit into our memory buffer * then create a temporary file. */ if(!left) { char *tempname = tempnam(NULL, "ART"); if((fp = fopen(tempname, "wb")) != NULL) { fputs(buf, fp); while(fgets(buf, bufsiz, fpin)) { cc = strlen(buf); cp = buf + cc - 1; if(cc > 1 && *(cp - 1) == '\r') { *cp-- = '\0'; *cp = '\n'; cc--; } fputs(buf, fp); rv += cc; nlines++; } fclose(fp); rv += fprintf(fpout, "Lines: %u\n\n", nlines); append_temp(fpout, tempname, buf, bufsiz); if(unlink(tempname)) lperror(tempname); } else lperror(tempname); free(tempname); } else { rv += fprintf(fpout, "Lines: %u\n\n", nlines); fputs(buf, fpout); } } free(buf); return(rv); }