home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / printer / lpr_lpq3.arc / LPQ.C next >
Text File  |  1989-10-14  |  16KB  |  560 lines

  1. /*  LPQ.C -  a utility to list and manipulate the print queue for the DOS    */
  2. /*  PRINT utility                                                             */
  3. /*                                                  R. Brittain  June 12, 1989 */
  4. /*
  5.     This program is
  6.                     Copyright  1989  by Richard Brittain
  7.     Permission is granted to freely use and distribute this program so long as
  8.     this copyright notice is maintained intact.  This software may not be sold.
  9.  
  10.     Revision history:
  11.         Released to usenet as version 1.0   6/18/89
  12.         Version 1.1 7/2/89
  13.         - attempts to find out percentage of current file processed using the
  14.           DOS system file table (undocumented service 52H)
  15.         Version 1.2 9/30/89
  16.         - added printer_status() function.  If I can get this to work, I want
  17.           to store the printer port in the environment, maybe with a command
  18.           line override -d:dev LPTx or COMx.  So far it doesn't return anything
  19.           useful.  Added reset printer to release_suspended_print_queue().
  20. */
  21.  
  22. #include <dos.h>
  23. #include <dir.h>
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <alloc.h>
  27. #include <string.h>
  28. #include <sys\stat.h>
  29. #include <bios.h>
  30.  
  31. #define    DOSPRINT     1
  32. #define MULTIPLEX    0x2F
  33. #define CANCELLED   "JOB_CANCELLED"
  34. #define QELEN        64                /* size in bytes of each queue entry */
  35. #define MAGIC        '*'                /* magic number to signify suspended entry */
  36.  
  37. extern unsigned int _version;
  38.  
  39. /* function prototypes */
  40. int            print_loaded(void);
  41. char far     *print_queue(void);
  42. char        *localcopy2(char far *);
  43. char far    *farcopy2(char far *, char *);
  44. char far     *strcpyfar2(char far *, char far *);
  45. void        release_print_queue(void);
  46. int            print_terminate(void);
  47. int            print_job_cancel(int);
  48. int         print_job_rush(int);
  49. int            print_file_cancel(char *);
  50. void        purge_cancelled_jobs(int);
  51. void        suspend_print_queue(void);
  52. void        release_suspended_print_queue(void);
  53. int            curpos(char *);
  54. void        printer_status(int);
  55.  
  56. static         int        print_port=0;
  57.  
  58. void    _setenvp(){}  /* we don't need this */
  59.  
  60. main(argc, argv)
  61. int        argc;
  62. char    **argv;
  63. {
  64.     int        i=1, verbose=0, suspend=0, job, nc=0, nameonly=0, badargs=0;
  65.     char     far    *ps, far *fp, *p, *s, sjob[4];
  66.     struct stat statbuf;
  67.     char    version[]="1.2";
  68.     char    copyright[]="Copyright  1989  by  Richard Brittain";
  69.     char    usage[]="Usage: lpq [-vhtsr1] [-c n] [-p n]";
  70.     char    helptext[]="Print Queue display:\n\
  71. \tNo argument - display current state of print queue\n\
  72. \t-c n        - cancel job (n) from queue\n\
  73. \t-p n        - rush job (n) to top of queue\n\
  74. \t-t          - terminate printing and cancel all jobs\n\
  75. \t-s          - suspend printing operation after current job completes\n\
  76. \t-r          - resume printing operation\n\
  77. \t-v          - turn on verbose mode\n\
  78. \t-1          - display 1 file per line with no other information\n\
  79. \t-h          - display this help text\n";
  80.     char    permiss[]="\nPermission is granted to freely use and distribute this program";
  81.  
  82.     if (!print_loaded()) {
  83.         printf("lpq: DOS print spooler not loaded\n");
  84.         exit(1);
  85.     }
  86.  
  87. /* process the command line arguments */
  88.     for (i=1; i<argc; i++) {
  89.         p = argv[i];
  90.         if ( *p == '-') {
  91.             do {
  92.                 p++;
  93.                 switch(*p) {
  94.                     case '\0':
  95.                         break;
  96.                     case 'h':  /* display help and quit */
  97.                         printf("LPQ Version %s of %s\n",version,__DATE__);
  98.                         printf("                 %s\n\n",copyright);
  99.                         printf("%s\n",usage);
  100.                         printf("%s\n",helptext);
  101.                         printf("%s\n",permiss);
  102.                         exit(1);
  103.                     case 'v':  /* set verbose mode and continue */
  104.                         verbose = 1;
  105.                         break;
  106.                     case 't':  /* terminate printing and quit */
  107.                         if (*(print_queue()) == NULL ) {
  108.                             if (verbose) printf("lpq: no files in print queue\n");
  109.                         } else {
  110.                             if (print_terminate() < 0) {
  111.                                 perror("lpq");
  112.                             } else {
  113.                                 if (verbose) printf("lpq: all files cancelled\n");
  114.                             }
  115.                         }
  116.                         release_print_queue();
  117.                         exit(0);
  118.                         break;
  119.                     case 's':  /* set suspend flag and continue */
  120.                         suspend = 1;
  121.                         break;
  122.                     case 'r':  /* release queue and continue */
  123.                         suspend = 0;
  124.                         if (verbose) printf("lpq: print queue released\n");
  125.                         release_suspended_print_queue();
  126.                         break;
  127.                     case 'c':  /* cancel job */
  128.                         p++;
  129.                         if (*p != '\0') {
  130.                             strncpy(sjob,p,sizeof(sjob));
  131.                             sjob[sizeof(sjob)-1] = '\0';
  132.                             if ((job=atoi(sjob)) == 0) {
  133.                                 printf("lpq: invalid job number %s\n",sjob);
  134.                                 exit(1);
  135.                             }
  136.                         } else {
  137.                             i++;
  138.                             if (i >= argc) {
  139.                                 printf("lpq: invalid job number\n");
  140.                                 exit(1);
  141.                             }
  142.                             p = argv[i];
  143.                             strncpy(sjob,p,sizeof(sjob));
  144.                             sjob[sizeof(sjob)-1] = '\0';
  145.                             if ((job=atoi(sjob)) == 0) {
  146.                                 printf("lpq: invalid job number %s\n",sjob);
  147.                                 exit(1);
  148.                             }
  149.                         }
  150.                         if (print_job_cancel(job) < 0) {
  151.                             printf("lpq: invalid job number %d\n",job);
  152.                         } else {
  153.                             nc++;
  154.                             if (verbose) printf("lpq: print job %d cancelled\n",job);
  155.                         }
  156.                         while (*p) {p++;};
  157.                         break;
  158.                     case 'p':  /* rush job */
  159.                         p++;
  160.                         if (*p != '\0') {
  161.                             strncpy(sjob,p,sizeof(sjob));
  162.                             sjob[sizeof(sjob)-1] = '\0';
  163.                             if ((job=atoi(sjob)) == 0) {
  164.                                 printf("lpq: invalid job number %s\n",sjob);
  165.                                 exit(1);
  166.                             }
  167.                         } else {
  168.                             i++;
  169.                             if (i >= argc) {
  170.                                 printf("lpq: invalid job number\n");
  171.                                 exit(1);
  172.                             }
  173.                             p = argv[i];
  174.                             strncpy(sjob,p,sizeof(sjob));
  175.                             sjob[sizeof(sjob)-1] = '\0';
  176.                             if ((job=atoi(sjob)) == 0) {
  177.                                 printf("lpq: invalid job number %s\n",sjob);
  178.                                 exit(1);
  179.                             }
  180.                         }
  181.                         if (print_job_rush(job) < 0) {
  182.                             printf("lpq: invalid job number %s\n",sjob);
  183.                         } else {
  184.                             if (verbose)
  185.                               printf("lpq: print job %d moved to head of queue\n",job);
  186.                         }
  187.                         while (*p) {p++;};
  188.                         break;
  189.                     case '1' :  /* filenames only requested */
  190.                         nameonly = 1;
  191.                         break;
  192.                     default:
  193.                         printf("lpq: unrecognised option %c\n",*p);
  194.                         badargs = 1;
  195.                 }
  196.             } while (*p);
  197.         } else {
  198.             printf("lpq: unrecognised argument %s\n",p);
  199.             badargs = 1;
  200.         }
  201.     }
  202.     purge_cancelled_jobs(nc);
  203.  
  204.     if (verbose && badargs) printf("%s\n",usage);
  205.  
  206. /*  we have finished processing options - now display the queue */
  207.     if (*(ps=print_queue()) != NULL) {
  208.         /* we have a file name, print it out */
  209.         i = 1;
  210.         while (*ps != NULL) {
  211.             s = localcopy2(ps);
  212.             if (nameonly) {
  213.                 printf("%s\n",strlwr(s));
  214.             } else {
  215.                 printf("(%2d)   %-38s",i,strlwr(s));
  216.                 if (stat(s,&statbuf) == -1) {
  217.                     printf(" file not found");
  218.                 } else {
  219.                     printf(" (%5ld bytes) ",statbuf.st_size);
  220.                 }
  221.                 if (i==1) {
  222.                     printf("   printing (%d%%)",curpos(s));
  223.                 } else {
  224.                     fp = ps;
  225.                     while (*fp) {fp++;};
  226.                     /* see if there is a time behind the file name */
  227.                     if (*(++fp) == MAGIC) printf("   %Fs",++fp);
  228.                 }
  229.                 printf("\n");
  230.             }
  231.             ps += QELEN;
  232.             i++;
  233.         }
  234.     } else {
  235.         if (verbose) printf("lpq: no files in print queue\n");
  236.     }
  237.     if (suspend) {
  238.         suspend_print_queue();
  239.         printf("lpq: print queue suspended (lpq -r to release)\n");
  240.     }
  241.     release_print_queue();
  242. #if 0
  243. /*  This doesn't return anything useful yet - leave out */
  244.     if (verbose) {
  245.         printer_status(print_port);
  246.     }
  247. #endif
  248.     exit(0);
  249. }
  250.  
  251. char *localcopy2(char far *s)
  252. /* Make a copy of a string pointed to by a far pointer             */
  253. /* Look for magic character and optionally copy second string also */
  254. /* Never copy more than QELEN total characters                       */
  255. {
  256.     char far *p, *l, *r ;
  257.     int         i=0 ;
  258.     p = s;
  259.     while (*p++ != NULL) { i++; }
  260.     if (*(++p) == MAGIC) {
  261.         i++;
  262.         while (*p++ != NULL) { if (i++ >= QELEN-1) break; }
  263.     }
  264.     r = l = (char *)malloc(i+1);
  265.     p = s;
  266.     i = 0;
  267.     while (*p != NULL) { *l++ = *p++; i++;}
  268.     *l = '\0';
  269.     if (*(++p) == MAGIC) {
  270.         l++;
  271.         i++;
  272.         while (*p != NULL) { *l++ = *p++;  if (i++ >= QELEN) break; }
  273.         *l = '\0';
  274.     }
  275.     return(r);
  276. }
  277.  
  278. char far *farcopy2(char far *dest, char *src)
  279. /* Copy a string from a near pointer into a far pointer (already allocated) */
  280. /* If the magic character follows, copy a second string                     */
  281. /* Never copy more than QELEN total characters                                */
  282. {
  283.     char far *p, *s ;
  284.     int     i=0;
  285.     p = dest;
  286.     s = src;
  287.     while (*s != NULL) { *p++ = *s++; if (i++ >= QELEN) break; }
  288.     *p = '\0';
  289.     if (*(++s) == MAGIC) {
  290.         p++;
  291.         while (*s != NULL) { *p++ = *s++; if (i++ >= QELEN) break; }
  292.         *p = '\0';
  293.     }
  294.     return(dest);
  295. }
  296.  
  297. char far *strcpyfar2(char far *dest, char far *src)
  298. /* Copy a string from one far pointer into another      */
  299. /* If the magic character follows, copy a second string */
  300. /* Never copy more than QELEN total characters            */
  301. {
  302.     char far *p, far *s ;
  303.     int     i=0;
  304.     p = dest;
  305.     s = src;
  306.     while (*s != NULL) { *p++ = *s++; if (i++ >= QELEN) break; }
  307.     *p = '\0';
  308.     if (*(++s) == MAGIC) {
  309.         p++;
  310.         while (*s != NULL) { *p++ = *s++; if (i++ >= QELEN) break; }
  311.         *p = '\0';
  312.     }
  313.     return(dest);
  314. }
  315.  
  316. int print_loaded()
  317. {
  318. /* find out if the resident portion of the DOS print spooler is loaded */
  319.     union REGS  regs;
  320.     regs.h.ah = DOSPRINT;
  321.     regs.h.al = 0;
  322.     int86(MULTIPLEX,®s,®s);
  323.     if (regs.h.al == 0xFF)
  324.         return(1);        /* print is installed */
  325.     else
  326.         return(0);        /* print is not installed */
  327. }
  328.  
  329. char far *print_queue()
  330. {
  331. /* Get a far pointer to the start of the list of files in the print queue    */
  332. /* This also freezes the queue (and suspends operation of the print spooler) */
  333. /* until another call is made to any PRINT function.  This does NOT free up  */
  334. /* the printer to other applications, so a special suspend_print_queue() is  */
  335. /* needed for that job */
  336.     union     REGS     regs;
  337.     struct    SREGS     sregs;
  338.     regs.h.ah = DOSPRINT;
  339.     regs.h.al = 4;
  340.     int86x(MULTIPLEX,®s,®s,&sregs);
  341.     return (MK_FP(sregs.ds, regs.x.si));
  342.     /* DS:SI is a far pointer to the queue */
  343. }
  344.  
  345. void release_print_queue()
  346. {
  347. /*  This is a do-nothing print function that serves only to release the */
  348. /*  print queue  from the frozen state caused by print_queue() */
  349.     union     REGS     regs;
  350.     regs.h.ah = DOSPRINT;
  351.     regs.h.al = 5;
  352.     int86(MULTIPLEX,®s,®s);
  353. }
  354.  
  355. int print_terminate()
  356. {
  357. /* cancel all files in print queue */
  358.     union REGS  regs;
  359.     regs.h.ah = DOSPRINT;
  360.     regs.h.al = 3;
  361.     int86(MULTIPLEX,®s,®s);
  362.     if (regs.x.cflag != 0)
  363.         return(-1);        /* error */
  364.     else
  365.         return(regs.h.al);
  366. }
  367.  
  368. int print_job_cancel(job)
  369. int job;
  370. {
  371. /*  Get the print queue, look for entry <job>, and mark it cancelled    */
  372. /*  This method lets us mark several jobs cancelled in one pass */
  373. /*  Return -1 if <job> is invalid, 0 otherwise */
  374.     char far *ps;
  375.     int        i=1;
  376.  
  377.     if (*(ps=print_queue()) != NULL) {
  378.         i = 1;
  379.         while (*ps != NULL) {
  380.             if (i == job) break;
  381.             ps += QELEN;
  382.             i++;
  383.         }
  384.         if (*ps == NULL) return(-1) ;  /* there were not that many jobs in queue */
  385.         farcopy2(ps, CANCELLED);
  386.         return(0);
  387.     } else {
  388.         return(-1);                    /* no jobs in queue */
  389.     }
  390. }
  391.  
  392. int print_job_rush(job)
  393. int job;
  394. {
  395. /*  Get the print queue, look for entry <job>, and place it at the head */
  396. /*  of the queue */
  397. /*  Return -1 if <job> is invalid else return 0 */
  398.     char far *ps, *l;
  399.     int        i;
  400.  
  401.     if (*(ps=print_queue()) != NULL) {
  402.         i = 1;
  403.         while (*ps != NULL) {
  404.             if (i == job) break;
  405.             ps += QELEN;
  406.             i++;
  407.         }
  408.         if (*ps == NULL) return(-1) ;  /* there were not that many jobs in queue */
  409.         if (i <= 2) return(0) ;        /* job is already at head */
  410.         l = localcopy2(ps);               /* make a copy of entry <job> */
  411.         for (i=1; i<=job-2; i++) {     /* copy each job into the following slot */
  412.             strcpyfar2(ps, ps-QELEN);
  413.             ps -= QELEN;
  414.         }
  415.         farcopy2(ps,l);                   /* put the priority job into slot 2 */
  416.         return(0);
  417.     } else {
  418.         return(-1);                    /* no jobs in queue */
  419.     }
  420. }
  421.  
  422. int print_file_cancel(filename)
  423. char *filename;
  424. {
  425. /* submit a filename to PRINT for deletion from the queue */
  426. /* The returned value is the value returned in AL by PRINT */
  427. /*  if the carry flag indicates an error, -1 is returned */
  428.  
  429.     union     REGS      regs;
  430.  
  431.     regs.h.ah = DOSPRINT;
  432.     regs.h.al = 2;                     /* AL=2 means we are cancelling a file */
  433.     regs.x.dx = (char near *)filename; /* put the segment offset into dx      */
  434.     /* NOTE: the above line gives a pointer warning */
  435.     int86(MULTIPLEX,®s,®s);      /* the ds register is set already      */
  436.     if (regs.x.cflag != 0)
  437.         return(-1);                       /* error */
  438.     else
  439.         return (regs.h.al);
  440. }
  441.  
  442. void purge_cancelled_jobs(int n)
  443. {
  444. /*  call the cancel function <n> times */
  445.     while (n > 0) {print_file_cancel(CANCELLED); n--; };
  446. }
  447.  
  448. void suspend_print_queue()
  449. {
  450. /* turn entry 2 into a NULL pointer, thereby making print think the queue is empty */
  451.     char far *ps, *l;
  452.     if (*(ps=print_queue()) == NULL) return;
  453.     ps += QELEN;
  454.     if (*ps != NULL) {
  455.         l = localcopy2(ps);
  456.         farcopy2(ps+2, l);
  457.         *ps = '\0';
  458.         *(ps+1) = MAGIC;
  459.     }
  460.     return;
  461. }
  462.  
  463. void release_suspended_print_queue()
  464. {
  465. /* Turn modified entry back into a real entry */
  466. /* The special entry will be either 1 or 2    */
  467.     char far *ps, *l;
  468.     ps=print_queue();
  469.     if ((*ps == NULL) && (*(ps+1) == MAGIC)) {
  470.         l = localcopy2(ps+2);
  471.         farcopy2(ps, l);
  472.     } else {
  473.         ps += QELEN;
  474.         if ((*ps == NULL) && (*(ps+1) == MAGIC)) {
  475.             l = localcopy2(ps+2);
  476.             farcopy2(ps, l);
  477.         }
  478.     }
  479.     /* send the printer a reset command */
  480.     biosprint(1,0,print_port);
  481.     return;
  482. }
  483.  
  484. int curpos(filename)
  485. char *filename;
  486. {
  487. /* attempt to find out current file offset of <filename>, as a percentage of
  488.    the length, for currently open file <filename>.  This uses the undocumented
  489.    interrupt 52H (DOS "list of lists")
  490. */
  491.     union REGS regs;
  492.     struct SREGS segregs;
  493.     char far *pfiletab, far *pnext, far *name, far *plist, far *entry;
  494.     char file[12], fname[21], fext[8];
  495.     int  nfiles, i, numhandles, entrylen;
  496.     long length, offset;
  497.  
  498.     /* convert filename (a full pathname) to FCB format (11 bytes, no period) */
  499.     fnsplit(filename,NULL,NULL,fname,fext);
  500.     /* name could be 1-8 characters, add 7 blanks to be sure */
  501.     strcat(fname,"       ");
  502.     /* ext could be null, make sure it is blanks */
  503.     strcat(fext,"   ");
  504.     if (fext[0] == '.')
  505.         strcpy(&fname[8],&fext[1]);
  506.     else
  507.         strcpy(&fname[8],&fext[0]);
  508.     fname[11] = '\0';
  509.  
  510.     /* get DOS list of lists */
  511.     regs.h.ah = 0x52;
  512.     intdosx(®s,®s,&segregs);
  513.     /* pointer to start of list */
  514.     plist    = (char far *)MK_FP(segregs.es,regs.x.bx);
  515.      /* pointer to start of file table */
  516.     pfiletab = (char far *)MK_FP(*(int far *)(plist+6), *(int far *)(plist+4));
  517.  
  518.     if ((_version&0xFF) < 4)
  519.         entrylen = 53;
  520.     else
  521.         entrylen = 59;
  522.  
  523.     for (;;) {
  524.         pnext    = (char far *)MK_FP(*(int far *)(pfiletab+2), *(int far *)(pfiletab+0));
  525.         nfiles   = *(int far *)(pfiletab+4);
  526.         for (i=0; i<nfiles; i++) {
  527.             entry = pfiletab + 6 + (i * entrylen);
  528.             name  = entry + 32 ;
  529.             strncpy(file, localcopy2(name), 11);
  530.             file[11] = '\0';
  531.             if (strlen(file) == 0) return(0);
  532.             numhandles = *(int far *)(entry + 0) ;
  533.             if ((stricmp(file,fname) == 0) && (numhandles > 0)) {
  534.                 /* file name matches and open handle */
  535.                 length     = *(long far *)(entry + 17) ;
  536.                 offset     = *(long far *)(entry + 21) ;
  537.                 if (length > 0)
  538.                     return((int)(offset*100L/length));
  539.                 else
  540.                     return(100);
  541.             }
  542.         }
  543.         pfiletab = pnext;
  544.         if (pfiletab == 0L) break;  /* last table pointer isn't normally null */
  545.     }
  546.     return(0);
  547. }
  548.  
  549. void printer_status(port)
  550. int port;
  551. {
  552.     /* display current status of printer port specified */
  553.     int result;
  554.     result = biosprint(2,0,port);
  555.     if (result & 0x01) printf("Port LPT%d Device time out\n",port+1);
  556.     if (result & 0x20) printf("Port LPT%d Out of paper\n",port+1);
  557.     if (result & 0x80) printf("Port LPT%d Not busy\n",port+1);
  558.     if (result & 0x08) printf("Port LPT%d I/O error\n",port+1);
  559. }
  560.