thecloud
/SimpleSpooler
/amendments
/7
more FilterData compatibility tweaks
- fix bug that failed to remove a filtered byte if it was the last byte
in the buffer being processed
- strip extra linefeeds generated by a reverse feed
- modify filter to remove a subset of 1B5A and 1B44 commands in IW1 mode,
to hopefully improve Scribe compatibility
- reset printer to defaults before starting each print job
thecloud made amendment 7 15 days ago
--- PrintQueue.c Thu Jul 30 16:46:25 2026
+++ PrintQueue.c Wed Aug 5 22:18:36 2026
@@ -4,7 +4,7 @@
* Routines for processing and printing spool files.
*
* Written by: Ken McLeod, 2026-01-16
- * Last update: 2026-02-03
+ * Last update: 2026-08-05
*
* This software is provided as-is, with no warranties expressed or implied,
* under the terms of the BSD 2-Clause License. See separate "LICENSE" file.
@@ -41,7 +41,10 @@ short gSerialRefNum = 0;
long gBytesWritten = 0L;
long gJobsPrinted = 0L;
Boolean gProcessingEscape = false;
+Boolean gReverseFeedMode = false;
+Boolean gGraphicLineMode = false;
short gBytesToRemove = 0;
+short gLinefeedsToRemove = 0;
void FilterData(long *count, void *data)
@@ -54,18 +57,21 @@ void FilterData(long *count, void *data)
* In IW1 mode, we filter the following IW II-only control sequences:
* 1B48xxxxxxxx (page length command, plus 4 parameter bytes)
* 1BF8xxxxxxxx (same as 1B48, but for testing the filter on IW II)
- * 1B4Cxxxxxx (page left margin command, plus 3 parameter bytes)
* 1B4Bxx (select color command, plus 1 parameter byte)
* 1B61xx (print quality command, plus 1 parameter byte)
+ * 1B5A[01-0F]xx (set switch OFF, plus 2 parameter bytes)
+ * 1B44[01-0F]xx (set switch ON, plus 2 parameter bytes)
*
* We can also optionally filter the command that backs up the paper:
* 1B72 (set reverse line feeding)
+ * and keep track of how many linefeeds are made in reverse mode,
+ * so we can subsequently remove the same number of forward linefeeds.
*
* Since control sequences can span data blocks, the 1B might have been
* sent out before we get the command code. Our filter changes the
* command code to FF which will be ignored, and removes the parameter
* bytes which follow. (There is no need to filter IW II-only control
- * sequences that have no parameters.)
+ * sequences that have no parameters, since an IW1 just ignores them.)
*/
char *p;
long length, index;
@@ -86,25 +92,55 @@ void FilterData(long *count, void *data)
switch (p[index]) {
case 0xF8:
case 0x48:
- p[index] = nopCmd; gBytesToRemove = 4; break;
- case 0x4C:
- p[index] = nopCmd; gBytesToRemove = 3; break;
+ p[index] = nopCmd; gBytesToRemove = 4;
+ break;
+ case 0x5A:
+ case 0x44:
+ if (index+1 >= length) {
+ break; /* can't peek at next byte, oh well */
+ }
+ if (p[index+1] > 0x00 && p[index+1] < 0x10) {
+ p[index] = nopCmd; gBytesToRemove = 2;
+ }
+ break;
case 0x4B:
case 0x61:
- p[index] = nopCmd; gBytesToRemove = 1; break;
+ p[index] = nopCmd; gBytesToRemove = 1;
+ break;
default:
break;
}
}
- if (noReverse && p[index] == 0x72) {
- p[index] = nopCmd;
+ if (noReverse) {
+ gGraphicLineMode = false;
+ if (p[index] == 0x72) {
+ p[index] = nopCmd;
+ gReverseFeedMode = true;
+ } else if (p[index] == 0x66) {
+ gReverseFeedMode = false;
+ } else if (p[index] == 0x47 || p[index] == 0x67) {
+ gGraphicLineMode = true;
+ }
}
gProcessingEscape = false;
continue;
}
- if (gBytesToRemove > 0 && length > (index+1)) {
- /* remove one byte by shifting remaining bytes left */
- BlockMove(&p[index+1],&p[index],(length-index)-1);
+ if (noReverse && !gGraphicLineMode && p[index] == 0x0A) {
+ /* this is an actual linefeed and not part of a graphic */
+ if (gReverseFeedMode) {
+ gBytesToRemove = 1;
+ gLinefeedsToRemove += 1;
+ } else if (gLinefeedsToRemove > 0) {
+ gBytesToRemove = 1;
+ gLinefeedsToRemove -= 1;
+ }
+ }
+ if (gBytesToRemove > 0) {
+ if (length > index+1) {
+ /* shift remaining bytes left */
+ BlockMove(&p[index+1],&p[index],(length-index)-1);
+ }
+ /* remove this byte */
index -= 1;
length -= 1;
gBytesToRemove -= 1;
@@ -163,7 +199,9 @@ void PrintCurrentJob(void)
return;
}
gProcessingEscape = false;
+ gReverseFeedMode = false;
gBytesToRemove = 0;
+ gLinefeedsToRemove = 0;
}
/* keep reading more of the current file and sending
* to serial port until done, then close the file.
@@ -171,6 +209,16 @@ void PrintCurrentJob(void)
if (gPrintFileRefNum != 0) {
char buf[256];
Boolean readEOF = false;
+ /* %%% TODO: handshake to make sure printer is actually there! */
+ if (gBytesWritten == 0) {
+ /* reset the printer to defaults before starting job */
+ buf[0] = 0x1B; buf[1] = 0x63; count = 2;
+ err = FSWrite(gSerialRefNum,&count,buf);
+ if (err != noErr) {
+ MessageWithIntValue(LOG_ERR_X,"\pUnable to initialize printer:",err);
+ readEOF = true; /* cannot continue */
+ }
+ }
while (!err) {
count = sizeof(buf);
err = FSRead(gPrintFileRefNum,&count,buf);