Written by Urs-Jakob Rüetschi
as part of the pracc project.
Low-level output and
parsing routines for PostScript and PJL.
PostScript-specific code is in the ps.h and ps.c
source files.
PJL-specific code is in the pjl.h and pjl.c
source files.
All these routines return 0 if successful and -1/errno on failure.
void psinit(void); void pjlinit(void);
Initialize global variables in the PS / PJL module and reset the message parser.
int psecho(int fd, int cookie); int pjlecho(int fd, int cookie);
Send a PS print / PJL ECHO statement that prints/echoes the given cookie. Use a random number as the cookie value. The parser stores the cookie, once received back from the printer, in a global variable. Use this routine to synchronise with the printer, so that we do not parse the previous job's page counts...
int pscount(int fd, int cookie); int pjlcount(int fd);
Send a small PS program / PJL INFO PAGECOUNT statement. The parser stores the pagecount, once received back from the printer, in a global variable. For PostScript, a cookie is included in the generated program which can be used to determine if the message received was the one generated by pscount.
int pjluel(int fd); int pjljob(int fd, int jobid, char *personality, char *display); int pjleoj(int fd, int jobid); int pjloff(int fd);
The pjluel routine sends UEL@PJL\r\n to the given file descriptor, where UEL is the Universal Escape Language sequence \033%-12345X. This is useful to get the PJL interpreter's attention. Use it according to HP's PJL specification.
The pjljob and pjleoj routines should be used to frame a print job. They issue the PJL JOB and PJL EOJ commands. Their job argument is the job's "name" (max 80 chars per PJL specification; for simplicity we use the decimal representation of an integer). If personality is null, we hope that the printer auto-detects the print job language, otherwise, pjljob emits an ENTER LANGUAGE statement. The display argument is the string to show on the printer's display while printing the job; if NULL, it defaults to "Job ID printing", where ID is the job argument. Per PJL specification, calls to these routines must be properly nested!
The pjloff routine sends a PJL statement to turn off "unsolicited status" messages. Such messages were requested by pjljob to get messages from the printer about job start and end and even individual pages printed. Note that these status messages cannot be turned off in pjleoj, because at the time pjleoj is invoked we are still interested in getting status messages.
There are two parsers, xxxparse() to parse a PostScript or PJL message, and xxxchar() to find a PostScript or PJL message in a continuous stream of bytes. The latter calls the former if a message is found.
int pschar(char c); int pjlchar(char c);
These routines should be called repeatedly with bytes read from the printer. They look through the buffer provided for a PostScript or a PJL message and call the respective xxxparse() routines if one is found. Messages can span across buffer boundaries but must not exceed MBSIZE bytes (an internal constant) in length or they will not be recognised as messages.
int psparse(const char *buf, unsigned len); int pjlparse(const char *buf, unsigned len);
These routines parse PostScript / PJL messages and set global variables (ps_xxx / pjl_xxx) according to the parsed messages. The return value is an indication of the type of message that was parsed and should be used by the calling function to determine what variables to read and what actions to take (e.g., change state in a FSM).
Messages generated by | Message value | |
---|---|---|
PJL | PS | |
PJL_MSG_COOKIE | PS_MSG_COOKIE | 1 |
PJL_MSG_PAGECOUNT | PS_MSG_PAGECOUNT | 2 |
PJL_MSG_JOBSTART | 3 | |
PJL_MSG_JOBEND | 4 | |
PJL_MSG_PAGE | 5 | |
PS_MSG_PRERROR | 6 | |
PS_MSG_FLUSHING | 7 | |
PJL_MSG_OTHER | PS_MSG_OTHER | 88 |
PS_MSG_MALFORMED | 99 |