Date: Fri, 24 Jul 2009 20:35:44 +0000 (UTC) From: Garance A Drosehn <gad@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-7@freebsd.org Subject: svn commit: r195855 - in stable/7/usr.sbin/lpr: . common_source Message-ID: <200907242035.n6OKZiNF020486@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: gad Date: Fri Jul 24 20:35:44 2009 New Revision: 195855 URL: http://svn.freebsd.org/changeset/base/195855 Log: MFC: Fix end-of-line issues that can come up when `lpq' reads information about a queue from a remote host. PR: bin/104731 Modified: stable/7/usr.sbin/lpr/ (props changed) stable/7/usr.sbin/lpr/common_source/displayq.c Modified: stable/7/usr.sbin/lpr/common_source/displayq.c ============================================================================== --- stable/7/usr.sbin/lpr/common_source/displayq.c Fri Jul 24 19:35:06 2009 (r195854) +++ stable/7/usr.sbin/lpr/common_source/displayq.c Fri Jul 24 20:35:44 2009 (r195855) @@ -69,6 +69,13 @@ __FBSDID("$FreeBSD$"); #define SIZCOL 62 /* start of Size column in normal */ /* + * isprint() takes a parameter of 'int', but expect values in the range + * of unsigned char. Define a wrapper which takes a value of type 'char', + * whether signed or unsigned, and ensure it ends up in the right range. + */ +#define isprintch(Anychar) isprint((u_char)(Anychar)) + +/* * Stuff for handling job specifications */ extern uid_t uid, euid; @@ -86,6 +93,7 @@ static const char *head0 = "Rank Owne static const char *head1 = "Total Size\n"; static void alarmhandler(int _signo); +static void filtered_write(char *_obuffer, int _wlen, FILE *_wstream); static void warn(const struct printer *_pp); /* @@ -254,12 +262,105 @@ displayq(struct printer *pp, int format) if (write(fd, line, i) != i) fatal(pp, "Lost connection"); while ((i = read(fd, line, sizeof(line))) > 0) - (void) fwrite(line, 1, i, stdout); + filtered_write(line, i, stdout); + filtered_write(NULL, -1, stdout); (void) close(fd); } } /* + * The lpq-info read from remote hosts may contain unprintable characters, + * or carriage-returns instead of line-feeds. Clean those up before echoing + * the lpq-info line(s) to stdout. The info may also be missing any kind of + * end-of-line character. This also turns CRLF and LFCR into a plain LF. + * + * This routine may be called multiple times to process a single set of + * information, and after a set is finished this routine must be called + * one extra time with NULL specified as the buffer address. + */ +static void +filtered_write(char *wbuffer, int wlen, FILE *wstream) +{ + static char lastchar, savedchar; + char *chkptr, *dest_end, *dest_ch, *nxtptr, *w_end; + int destlen; + char destbuf[BUFSIZ]; + + if (wbuffer == NULL) { + if (savedchar != '\0') { + if (savedchar == '\r') + savedchar = '\n'; + fputc(savedchar, wstream); + lastchar = savedchar; + savedchar = '\0'; + } + if (lastchar != '\0' && lastchar != '\n') + fputc('\n', wstream); + lastchar = '\0'; + return; + } + + dest_ch = &destbuf[0]; + dest_end = dest_ch + sizeof(destbuf); + chkptr = wbuffer; + w_end = wbuffer + wlen; + lastchar = '\0'; + if (savedchar != '\0') { + chkptr = &savedchar; + nxtptr = wbuffer; + } else + nxtptr = chkptr + 1; + + while (chkptr < w_end) { + if (nxtptr < w_end) { + if ((*chkptr == '\r' && *nxtptr == '\n') || + (*chkptr == '\n' && *nxtptr == '\r')) { + *dest_ch++ = '\n'; + /* want to skip past that second character */ + nxtptr++; + goto check_next; + } + } else { + /* This is the last byte in the buffer given on this + * call, so check if it could be the first-byte of a + * significant two-byte sequence. If it is, then + * don't write it out now, but save for checking in + * the next call. + */ + savedchar = '\0'; + if (*chkptr == '\r' || *chkptr == '\n') { + savedchar = *chkptr; + break; + } + } + if (*chkptr == '\r') + *dest_ch++ = '\n'; +#if 0 /* XXX - don't translate unprintable characters (yet) */ + else if (*chkptr != '\t' && *chkptr != '\n' && + !isprintch(*chkptr)) + *dest_ch++ = '?'; +#endif + else + *dest_ch++ = *chkptr; + +check_next: + chkptr = nxtptr; + nxtptr = chkptr + 1; + if (dest_ch >= dest_end) { + destlen = dest_ch - &destbuf[0]; + fwrite(destbuf, 1, destlen, wstream); + lastchar = destbuf[destlen - 1]; + dest_ch = &destbuf[0]; + } + } + destlen = dest_ch - &destbuf[0]; + if (destlen > 0) { + fwrite(destbuf, 1, destlen, wstream); + lastchar = destbuf[destlen - 1]; + } +} + +/* * Print a warning message if there is no daemon present. */ static void
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200907242035.n6OKZiNF020486>