⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 postio.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * * postio - RS-232 serial interface for PostScript printers * * A simple program that manages input and output for PostScript printers. Much * has been added and changed from early versions of the program, but the basic * philosophy is still the same. Don't send real data until we're certain we've * connected to a PostScript printer that's in the idle state and try to hold the * connection until the job is completely done. It's more work than you might * expect is necessary, but should provide a reasonably reliable spooler interface * that can return error indications to the caller via the program's exit status. * * I've added code that will let you split the program into separate read/write * processes. Although it's not the default it should be useful if you have a file * that will be returning useful data from the printer. The two process stuff was * laid down on top of the single process code and both methods still work. The * implementation isn't as good as it could be, but didn't require many changes * to the original program (despite the fact that there are now many differences). * * By default the program still runs as a single process. The -R2 option forces * separate read and write processes after the intial connection is made. If you * want that as the default initialize splitme (below) to TRUE. In addition the * -t option that's used to force stuff not recognized as status reports to stdout * also tries to run as two processes (by setting splitme to TRUE). It will only * work if the required code (ie. resetline() in ifdef.c) has been implemented * for your Unix system. I've only tested the System V code. * * Code needed to support interactive mode has also been added, although again it's * not as efficient as it could be. It depends on the system dependent procedures * resetline() and setupstdin() (file ifdef.c) and for now is only guaranteed to * work on System V. Can be requested using the -i option. * * Quiet mode (-q option) is also new, but was needed for some printers connected * to RADIAN. If you're running in quiet mode no status requests will be sent to * the printer while files are being transmitted (ie. in send()). * * The program expects to receive printer status lines that look like, * *	%%[ status: idle; source: serial 25 ]%% *	%%[ status: waiting; source: serial 25 ]%% *	%%[ status: initializing; source: serial 25 ]%% *	%%[ status: busy; source: serial 25 ]%% *	%%[ status: printing; source: serial 25 ]%% *	%%[ status: PrinterError: out of paper; source: serial 25 ]%% *	%%[ status: PrinterError: no paper tray; source: serial 25 ]%% * * although this list isn't complete. Sending a '\024' (control T) character forces * the return of a status report. PostScript errors detected on the printer result * in the immediate transmission of special error messages that look like, * *	%%[ Error: undefined; OffendingCommand: xxx ]%% *	%%[ Flushing: rest of job (to end-of-file) will be ignored ]%% * * although we only use the Error and Flushing keywords. Finally conditions, like * being out of paper, result in other messages being sent back from the printer * over the communications line. Typical PrinterError messages look like, * *	%%[ PrinterError: out of paper; source: serial 25 ]%% *	%%[ PrinterError: paper jam; source: serial 25 ]%% * * although we only use the PrinterError keyword rather than trying to recognize * all possible printer errors. * * The implications of using one process and only flow controlling data going to * the printer are obvious. Job transmission should be reliable, but there can be * data loss in stuff sent back from the printer. Usually that only caused problems * with jobs designed to run on the printer and return useful data back over the * communications line. If that's the kind of job you're sending call postio with * the -t option. That should force the program to split into separate read and * write processes and everything not bracketed by "%%[ " and " ]%%" strings goes * to stdout. In otherwords the data you're expecting should be separated from the * status stuff that goes to the log file (or stderr). The -R2 option does almost * the same thing (ie. separate read and write processes), but everything that * comes back from the printer goes to the log file (stderr by default) and you'll * have to separate your data from any printer messages. * * A typical command line might be, * *	postio -l /dev/tty01 -b 9600 -L log file1 file2 * * where -l selects the line, -b sets the baud rate, and -L selects the printer * log file. Since there's no default line, at least not right now, you'll always * need to use the -l option, and if you don't choose a log file stderr will be * used. If you have a program that will be returning data the command line might * look like, * *	postio -t -l/dev/tty01 -b9600 -Llog file >results * * Status stuff goes to file log while the data you're expecting back from the * printer gets put in file results. * */#include <stdio.h>#include <ctype.h>#include <fcntl.h>#include <signal.h>#include <sys/types.h>#include <errno.h>#include "ifdef.h"			/* conditional compilation stuff */#include "gen.h"			/* general purpose definitions */#include "postio.h"			/* some special definitions */char	**argv;				/* global so everyone can use them */int	argc;char	*prog_name = "";		/* really just for error messages */int	x_stat = 0;			/* program exit status */int	debug = OFF;			/* debug flag */int	ignore = OFF;			/* what's done for FATAL errors */char	*line = NULL;			/* printer is on this tty line */short	baudrate = BAUDRATE;		/* and running at this baud rate */Baud	baudtable[] = BAUDTABLE;	/* converts strings to termio values */int	stopbits = 1;			/* number of stop bits */int	tostdout = FALSE;		/* non-status stuff goes to stdout? */int	quiet = FALSE;			/* no status queries in send() if TRUE */int	interactive = FALSE;		/* interactive mode */char	*postbegin = POSTBEGIN;		/* preceeds all the input files */int	useslowsend = FALSE;		/* not recommended! */int	sendctrlC = TRUE;		/* interrupt with ctrl-C when BUSY */int	window_size = -1;		/* for Datakit - use -w */char	*block = NULL;			/* input file buffer */int	blocksize = BLOCKSIZE;		/* and its size in bytes */int	head = 0;			/* block[head] is the next character */int	tail = 0;			/* one past the last byte in block[] */int	splitme = FALSE;		/* into READ and WRITE processes if TRUE */int	whatami = READWRITE;		/* a READ or WRITE process - or both */int	canread = TRUE;			/* allow reads */int	canwrite = TRUE;		/* and writes if TRUE */int	otherpid = -1;			/* who gets signals if greater than 1 */int	joinsig = SIGTRAP;		/* reader gets this when writing is done */int	writedone = FALSE;		/* and then sets this to TRUE */char	mesg[MESGSIZE];			/* exactly what came back on ttyi */char	sbuf[MESGSIZE];			/* for parsing the message */int	next = 0;			/* next character goes in mesg[next] */char	*mesgptr = NULL;		/* printer message starts here in mesg[] */char	*endmesg = NULL;		/* as far as readline() can go in mesg[] */Status	status[] = STATUS;		/* for converting status strings */int	nostatus = NOSTATUS;		/* default getstatus() return value */int	currentstate = NOTCONNECTED;	/* what's happening START, SEND, or DONE */int	ttyi = 0;			/* input */int	ttyo = 2;			/* and output file descriptors */FILE	*fp_log = stderr;		/* log file for stuff from the printer *//*****************************************************************************/main(agc, agv)    int		agc;    char	*agv[];{/* * * A simple program that manages input and output for PostScript printers. Can run * as a single process or as separate read/write processes. What's done depends on * the value assigned to splitme when split() is called. * */    argc = agc;				/* other routines may want them */    argv = agv;    prog_name = argv[0];		/* really just for error messages */    init_signals();			/* sets up interrupt handling */    options();				/* get command line options */    initialize();			/* must be done after options() */    start();				/* make sure the printer is ready */    split();				/* into read/write processes - maybe */    arguments();			/* then send each input file */    done();				/* wait until the printer is finished */    cleanup();				/* make sure the write process stops */    exit(x_stat);			/* everything probably went OK */}   /* End of main *//*****************************************************************************/init_signals(){    void	interrupt();		/* handles them if we catch signals *//* * * Makes sure we handle interrupts. The proper way to kill the program, if * necessary, is to do a kill -15. That forces a call to interrupt(), which in * turn tries to reset the printer and then exits with a non-zero status. If the * program is running as two processes, sending SIGTERM to either the parent or * child should clean things up. * */    if ( signal(SIGINT, interrupt) == SIG_IGN )  {	signal(SIGINT, SIG_IGN);	signal(SIGQUIT, SIG_IGN);	signal(SIGHUP, SIG_IGN);    } else {	signal(SIGHUP, interrupt);	signal(SIGQUIT, interrupt);    }	/* End else */    signal(SIGTERM, interrupt);}   /* End of init_sig *//*****************************************************************************/options(){    int		ch;			/* return value from getopt() */    char	*optnames = "b:cil:qs:tw:B:L:P:R:SDI";    extern char	*optarg;		/* used by getopt() */    extern int	optind;/* * * Reads and processes the command line options. The -R2, -t, and -i options all * force separate read and write processes by eventually setting splitme to TRUE * (check initialize()). The -S option is not recommended and should only be used * as a last resort! * */    while ( (ch = getopt(argc, argv, optnames)) != EOF )  {	switch ( ch )  {	    case 'b':			/* baud rate string */		    baudrate = getbaud(optarg);		    break;	    case 'c':			/* no ctrl-C's */		    sendctrlC = FALSE;		    break;	    case 'i':			/* interactive mode */		    interactive = TRUE;		    break;	    case 'l':			/* printer line */		    line = optarg;		    break;	    case 'q':			/* no status queries - for RADIAN? */		    quiet = TRUE;		    break;	    case 's':			/* use 2 stop bits - for UNISON? */		    if ( (stopbits = atoi(optarg)) < 1 || stopbits > 2 )			stopbits = 1;		    break;	    case 't':			/* non-status stuff goes to stdout */		    tostdout = TRUE;		    break;	    case 'w':			/* Datakit window size */		    window_size = atoi(optarg);		    break;	    case 'B':			/* set the job buffer size */		    if ( (blocksize = atoi(optarg)) <= 0 )			blocksize = BLOCKSIZE;		    break;	    case 'L':			/* printer log file */		    if ( (fp_log = fopen(optarg, "w")) == NULL )  {			fp_log = stderr;			error(NON_FATAL, "can't open log file %s", optarg);		    }	/* End if */		    break;	    case 'P':			/* initial PostScript code */		    postbegin = optarg;		    break;	    case 'R':			/* run as one or two processes */		    if ( atoi(optarg) == 2 )			splitme = TRUE;		    else splitme = FALSE;		    break;	    case 'S':			/* slow and kludged up version of send */		    useslowsend = TRUE;		    break;	    case 'D':			/* debug flag */		    debug = ON;		    break;	    case 'I':			/* ignore FATAL errors */		    ignore = ON;		    break;	    case '?':			/* don't understand the option */		    error(FATAL, "");		    break;	    default:			/* don't know what to do for ch */		    error(FATAL, "missing case for option %c\n", ch);		    break;	}   /* End switch */    }   /* End while */    argc -= optind;			/* get ready for non-option args */    argv += optind;}   /* End of options *//*****************************************************************************/getbaud(rate)    char	*rate;			/* string representing the baud rate */{    int		i;			/* for looking through baudtable[] *//* * * Called from options() to convert a baud rate string into an appropriate termio * value. *rate is looked up in baudtable[] and if it's found, the corresponding * value is returned to the caller. * */    for ( i = 0; baudtable[i].rate != NULL; i++ )	if ( strcmp(rate, baudtable[i].rate) == 0 )	    return(baudtable[i].val);    error(FATAL, "don't recognize baud rate %s", rate);}   /* End of getbaud *//*****************************************************************************/initialize(){/* * * Initialization, a few checks, and a call to setupline() (file ifdef.c) to open * and configure the communications line. Settings for interactive mode always * take precedence. The setupstdin() call with an argument of 0 saves the current * terminal settings if interactive mode has been requested - otherwise nothing's * done. Unbuffering stdout (via the setbuf() call) isn't really needed on System V * since it's flushed whenever terminal input is requested. It's more efficient if * we buffer the stdout (on System V) but safer (for other versions of Unix) if we * include the setbuf() call. * */    whatami = READWRITE;		/* always run start() as one process */    canread = canwrite = TRUE;    if ( tostdout == TRUE )		/* force separate read/write processes */	splitme = TRUE;    if ( interactive == TRUE )  {	/* interactive mode settings always win */	quiet = FALSE;	tostdout = FALSE;	splitme = TRUE;	blocksize = 1;	postbegin = NULL;	useslowsend = FALSE;	nostatus = INTERACTIVE;	setbuf(stdout, NULL);    }	/* End if */    if ( useslowsend == TRUE )  {	/* last resort only - not recommended */	quiet = FALSE;	splitme = FALSE;	if ( blocksize > 1024 )		/* don't send too much all at once */	    blocksize = 1024;    }	/* End if */    if ( tostdout == TRUE && fp_log == stderr )	fp_log = NULL;    if ( line == NULL && (interactive == TRUE || tostdout == TRUE) )	error(FATAL, "a printer line must be supplied - use the -l option");    if ( (block = malloc(blocksize)) == NULL )	error(FATAL, "no memory");    endmesg = mesg + sizeof mesg - 2;	/* one byte from last position in mesg */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -