home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
printer
/
lpr_lpq3.arc
/
LPQ.C
next >
Wrap
Text File
|
1989-10-14
|
16KB
|
560 lines
/* LPQ.C - a utility to list and manipulate the print queue for the DOS */
/* PRINT utility */
/* R. Brittain June 12, 1989 */
/*
This program is
Copyright 1989 by Richard Brittain
Permission is granted to freely use and distribute this program so long as
this copyright notice is maintained intact. This software may not be sold.
Revision history:
Released to usenet as version 1.0 6/18/89
Version 1.1 7/2/89
- attempts to find out percentage of current file processed using the
DOS system file table (undocumented service 52H)
Version 1.2 9/30/89
- added printer_status() function. If I can get this to work, I want
to store the printer port in the environment, maybe with a command
line override -d:dev LPTx or COMx. So far it doesn't return anything
useful. Added reset printer to release_suspended_print_queue().
*/
#include <dos.h>
#include <dir.h>
#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
#include <string.h>
#include <sys\stat.h>
#include <bios.h>
#define DOSPRINT 1
#define MULTIPLEX 0x2F
#define CANCELLED "JOB_CANCELLED"
#define QELEN 64 /* size in bytes of each queue entry */
#define MAGIC '*' /* magic number to signify suspended entry */
extern unsigned int _version;
/* function prototypes */
int print_loaded(void);
char far *print_queue(void);
char *localcopy2(char far *);
char far *farcopy2(char far *, char *);
char far *strcpyfar2(char far *, char far *);
void release_print_queue(void);
int print_terminate(void);
int print_job_cancel(int);
int print_job_rush(int);
int print_file_cancel(char *);
void purge_cancelled_jobs(int);
void suspend_print_queue(void);
void release_suspended_print_queue(void);
int curpos(char *);
void printer_status(int);
static int print_port=0;
void _setenvp(){} /* we don't need this */
main(argc, argv)
int argc;
char **argv;
{
int i=1, verbose=0, suspend=0, job, nc=0, nameonly=0, badargs=0;
char far *ps, far *fp, *p, *s, sjob[4];
struct stat statbuf;
char version[]="1.2";
char copyright[]="Copyright 1989 by Richard Brittain";
char usage[]="Usage: lpq [-vhtsr1] [-c n] [-p n]";
char helptext[]="Print Queue display:\n\
\tNo argument - display current state of print queue\n\
\t-c n - cancel job (n) from queue\n\
\t-p n - rush job (n) to top of queue\n\
\t-t - terminate printing and cancel all jobs\n\
\t-s - suspend printing operation after current job completes\n\
\t-r - resume printing operation\n\
\t-v - turn on verbose mode\n\
\t-1 - display 1 file per line with no other information\n\
\t-h - display this help text\n";
char permiss[]="\nPermission is granted to freely use and distribute this program";
if (!print_loaded()) {
printf("lpq: DOS print spooler not loaded\n");
exit(1);
}
/* process the command line arguments */
for (i=1; i<argc; i++) {
p = argv[i];
if ( *p == '-') {
do {
p++;
switch(*p) {
case '\0':
break;
case 'h': /* display help and quit */
printf("LPQ Version %s of %s\n",version,__DATE__);
printf(" %s\n\n",copyright);
printf("%s\n",usage);
printf("%s\n",helptext);
printf("%s\n",permiss);
exit(1);
case 'v': /* set verbose mode and continue */
verbose = 1;
break;
case 't': /* terminate printing and quit */
if (*(print_queue()) == NULL ) {
if (verbose) printf("lpq: no files in print queue\n");
} else {
if (print_terminate() < 0) {
perror("lpq");
} else {
if (verbose) printf("lpq: all files cancelled\n");
}
}
release_print_queue();
exit(0);
break;
case 's': /* set suspend flag and continue */
suspend = 1;
break;
case 'r': /* release queue and continue */
suspend = 0;
if (verbose) printf("lpq: print queue released\n");
release_suspended_print_queue();
break;
case 'c': /* cancel job */
p++;
if (*p != '\0') {
strncpy(sjob,p,sizeof(sjob));
sjob[sizeof(sjob)-1] = '\0';
if ((job=atoi(sjob)) == 0) {
printf("lpq: invalid job number %s\n",sjob);
exit(1);
}
} else {
i++;
if (i >= argc) {
printf("lpq: invalid job number\n");
exit(1);
}
p = argv[i];
strncpy(sjob,p,sizeof(sjob));
sjob[sizeof(sjob)-1] = '\0';
if ((job=atoi(sjob)) == 0) {
printf("lpq: invalid job number %s\n",sjob);
exit(1);
}
}
if (print_job_cancel(job) < 0) {
printf("lpq: invalid job number %d\n",job);
} else {
nc++;
if (verbose) printf("lpq: print job %d cancelled\n",job);
}
while (*p) {p++;};
break;
case 'p': /* rush job */
p++;
if (*p != '\0') {
strncpy(sjob,p,sizeof(sjob));
sjob[sizeof(sjob)-1] = '\0';
if ((job=atoi(sjob)) == 0) {
printf("lpq: invalid job number %s\n",sjob);
exit(1);
}
} else {
i++;
if (i >= argc) {
printf("lpq: invalid job number\n");
exit(1);
}
p = argv[i];
strncpy(sjob,p,sizeof(sjob));
sjob[sizeof(sjob)-1] = '\0';
if ((job=atoi(sjob)) == 0) {
printf("lpq: invalid job number %s\n",sjob);
exit(1);
}
}
if (print_job_rush(job) < 0) {
printf("lpq: invalid job number %s\n",sjob);
} else {
if (verbose)
printf("lpq: print job %d moved to head of queue\n",job);
}
while (*p) {p++;};
break;
case '1' : /* filenames only requested */
nameonly = 1;
break;
default:
printf("lpq: unrecognised option %c\n",*p);
badargs = 1;
}
} while (*p);
} else {
printf("lpq: unrecognised argument %s\n",p);
badargs = 1;
}
}
purge_cancelled_jobs(nc);
if (verbose && badargs) printf("%s\n",usage);
/* we have finished processing options - now display the queue */
if (*(ps=print_queue()) != NULL) {
/* we have a file name, print it out */
i = 1;
while (*ps != NULL) {
s = localcopy2(ps);
if (nameonly) {
printf("%s\n",strlwr(s));
} else {
printf("(%2d) %-38s",i,strlwr(s));
if (stat(s,&statbuf) == -1) {
printf(" file not found");
} else {
printf(" (%5ld bytes) ",statbuf.st_size);
}
if (i==1) {
printf(" printing (%d%%)",curpos(s));
} else {
fp = ps;
while (*fp) {fp++;};
/* see if there is a time behind the file name */
if (*(++fp) == MAGIC) printf(" %Fs",++fp);
}
printf("\n");
}
ps += QELEN;
i++;
}
} else {
if (verbose) printf("lpq: no files in print queue\n");
}
if (suspend) {
suspend_print_queue();
printf("lpq: print queue suspended (lpq -r to release)\n");
}
release_print_queue();
#if 0
/* This doesn't return anything useful yet - leave out */
if (verbose) {
printer_status(print_port);
}
#endif
exit(0);
}
char *localcopy2(char far *s)
/* Make a copy of a string pointed to by a far pointer */
/* Look for magic character and optionally copy second string also */
/* Never copy more than QELEN total characters */
{
char far *p, *l, *r ;
int i=0 ;
p = s;
while (*p++ != NULL) { i++; }
if (*(++p) == MAGIC) {
i++;
while (*p++ != NULL) { if (i++ >= QELEN-1) break; }
}
r = l = (char *)malloc(i+1);
p = s;
i = 0;
while (*p != NULL) { *l++ = *p++; i++;}
*l = '\0';
if (*(++p) == MAGIC) {
l++;
i++;
while (*p != NULL) { *l++ = *p++; if (i++ >= QELEN) break; }
*l = '\0';
}
return(r);
}
char far *farcopy2(char far *dest, char *src)
/* Copy a string from a near pointer into a far pointer (already allocated) */
/* If the magic character follows, copy a second string */
/* Never copy more than QELEN total characters */
{
char far *p, *s ;
int i=0;
p = dest;
s = src;
while (*s != NULL) { *p++ = *s++; if (i++ >= QELEN) break; }
*p = '\0';
if (*(++s) == MAGIC) {
p++;
while (*s != NULL) { *p++ = *s++; if (i++ >= QELEN) break; }
*p = '\0';
}
return(dest);
}
char far *strcpyfar2(char far *dest, char far *src)
/* Copy a string from one far pointer into another */
/* If the magic character follows, copy a second string */
/* Never copy more than QELEN total characters */
{
char far *p, far *s ;
int i=0;
p = dest;
s = src;
while (*s != NULL) { *p++ = *s++; if (i++ >= QELEN) break; }
*p = '\0';
if (*(++s) == MAGIC) {
p++;
while (*s != NULL) { *p++ = *s++; if (i++ >= QELEN) break; }
*p = '\0';
}
return(dest);
}
int print_loaded()
{
/* find out if the resident portion of the DOS print spooler is loaded */
union REGS regs;
regs.h.ah = DOSPRINT;
regs.h.al = 0;
int86(MULTIPLEX,®s,®s);
if (regs.h.al == 0xFF)
return(1); /* print is installed */
else
return(0); /* print is not installed */
}
char far *print_queue()
{
/* Get a far pointer to the start of the list of files in the print queue */
/* This also freezes the queue (and suspends operation of the print spooler) */
/* until another call is made to any PRINT function. This does NOT free up */
/* the printer to other applications, so a special suspend_print_queue() is */
/* needed for that job */
union REGS regs;
struct SREGS sregs;
regs.h.ah = DOSPRINT;
regs.h.al = 4;
int86x(MULTIPLEX,®s,®s,&sregs);
return (MK_FP(sregs.ds, regs.x.si));
/* DS:SI is a far pointer to the queue */
}
void release_print_queue()
{
/* This is a do-nothing print function that serves only to release the */
/* print queue from the frozen state caused by print_queue() */
union REGS regs;
regs.h.ah = DOSPRINT;
regs.h.al = 5;
int86(MULTIPLEX,®s,®s);
}
int print_terminate()
{
/* cancel all files in print queue */
union REGS regs;
regs.h.ah = DOSPRINT;
regs.h.al = 3;
int86(MULTIPLEX,®s,®s);
if (regs.x.cflag != 0)
return(-1); /* error */
else
return(regs.h.al);
}
int print_job_cancel(job)
int job;
{
/* Get the print queue, look for entry <job>, and mark it cancelled */
/* This method lets us mark several jobs cancelled in one pass */
/* Return -1 if <job> is invalid, 0 otherwise */
char far *ps;
int i=1;
if (*(ps=print_queue()) != NULL) {
i = 1;
while (*ps != NULL) {
if (i == job) break;
ps += QELEN;
i++;
}
if (*ps == NULL) return(-1) ; /* there were not that many jobs in queue */
farcopy2(ps, CANCELLED);
return(0);
} else {
return(-1); /* no jobs in queue */
}
}
int print_job_rush(job)
int job;
{
/* Get the print queue, look for entry <job>, and place it at the head */
/* of the queue */
/* Return -1 if <job> is invalid else return 0 */
char far *ps, *l;
int i;
if (*(ps=print_queue()) != NULL) {
i = 1;
while (*ps != NULL) {
if (i == job) break;
ps += QELEN;
i++;
}
if (*ps == NULL) return(-1) ; /* there were not that many jobs in queue */
if (i <= 2) return(0) ; /* job is already at head */
l = localcopy2(ps); /* make a copy of entry <job> */
for (i=1; i<=job-2; i++) { /* copy each job into the following slot */
strcpyfar2(ps, ps-QELEN);
ps -= QELEN;
}
farcopy2(ps,l); /* put the priority job into slot 2 */
return(0);
} else {
return(-1); /* no jobs in queue */
}
}
int print_file_cancel(filename)
char *filename;
{
/* submit a filename to PRINT for deletion from the queue */
/* The returned value is the value returned in AL by PRINT */
/* if the carry flag indicates an error, -1 is returned */
union REGS regs;
regs.h.ah = DOSPRINT;
regs.h.al = 2; /* AL=2 means we are cancelling a file */
regs.x.dx = (char near *)filename; /* put the segment offset into dx */
/* NOTE: the above line gives a pointer warning */
int86(MULTIPLEX,®s,®s); /* the ds register is set already */
if (regs.x.cflag != 0)
return(-1); /* error */
else
return (regs.h.al);
}
void purge_cancelled_jobs(int n)
{
/* call the cancel function <n> times */
while (n > 0) {print_file_cancel(CANCELLED); n--; };
}
void suspend_print_queue()
{
/* turn entry 2 into a NULL pointer, thereby making print think the queue is empty */
char far *ps, *l;
if (*(ps=print_queue()) == NULL) return;
ps += QELEN;
if (*ps != NULL) {
l = localcopy2(ps);
farcopy2(ps+2, l);
*ps = '\0';
*(ps+1) = MAGIC;
}
return;
}
void release_suspended_print_queue()
{
/* Turn modified entry back into a real entry */
/* The special entry will be either 1 or 2 */
char far *ps, *l;
ps=print_queue();
if ((*ps == NULL) && (*(ps+1) == MAGIC)) {
l = localcopy2(ps+2);
farcopy2(ps, l);
} else {
ps += QELEN;
if ((*ps == NULL) && (*(ps+1) == MAGIC)) {
l = localcopy2(ps+2);
farcopy2(ps, l);
}
}
/* send the printer a reset command */
biosprint(1,0,print_port);
return;
}
int curpos(filename)
char *filename;
{
/* attempt to find out current file offset of <filename>, as a percentage of
the length, for currently open file <filename>. This uses the undocumented
interrupt 52H (DOS "list of lists")
*/
union REGS regs;
struct SREGS segregs;
char far *pfiletab, far *pnext, far *name, far *plist, far *entry;
char file[12], fname[21], fext[8];
int nfiles, i, numhandles, entrylen;
long length, offset;
/* convert filename (a full pathname) to FCB format (11 bytes, no period) */
fnsplit(filename,NULL,NULL,fname,fext);
/* name could be 1-8 characters, add 7 blanks to be sure */
strcat(fname," ");
/* ext could be null, make sure it is blanks */
strcat(fext," ");
if (fext[0] == '.')
strcpy(&fname[8],&fext[1]);
else
strcpy(&fname[8],&fext[0]);
fname[11] = '\0';
/* get DOS list of lists */
regs.h.ah = 0x52;
intdosx(®s,®s,&segregs);
/* pointer to start of list */
plist = (char far *)MK_FP(segregs.es,regs.x.bx);
/* pointer to start of file table */
pfiletab = (char far *)MK_FP(*(int far *)(plist+6), *(int far *)(plist+4));
if ((_version&0xFF) < 4)
entrylen = 53;
else
entrylen = 59;
for (;;) {
pnext = (char far *)MK_FP(*(int far *)(pfiletab+2), *(int far *)(pfiletab+0));
nfiles = *(int far *)(pfiletab+4);
for (i=0; i<nfiles; i++) {
entry = pfiletab + 6 + (i * entrylen);
name = entry + 32 ;
strncpy(file, localcopy2(name), 11);
file[11] = '\0';
if (strlen(file) == 0) return(0);
numhandles = *(int far *)(entry + 0) ;
if ((stricmp(file,fname) == 0) && (numhandles > 0)) {
/* file name matches and open handle */
length = *(long far *)(entry + 17) ;
offset = *(long far *)(entry + 21) ;
if (length > 0)
return((int)(offset*100L/length));
else
return(100);
}
}
pfiletab = pnext;
if (pfiletab == 0L) break; /* last table pointer isn't normally null */
}
return(0);
}
void printer_status(port)
int port;
{
/* display current status of printer port specified */
int result;
result = biosprint(2,0,port);
if (result & 0x01) printf("Port LPT%d Device time out\n",port+1);
if (result & 0x20) printf("Port LPT%d Out of paper\n",port+1);
if (result & 0x80) printf("Port LPT%d Not busy\n",port+1);
if (result & 0x08) printf("Port LPT%d I/O error\n",port+1);
}