home *** CD-ROM | disk | FTP | other *** search
- /* 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);
- }