Index: pkpgcounter/trunk/pkpgpdls/tiff.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/tiff.py (revision 235)
+++ pkpgcounter/trunk/pkpgpdls/tiff.py (revision 252)
@@ -36,6 +36,5 @@
         bigendian = (chr(0x4d)*2) + chr(0) + chr(0x2a)
         if self.firstblock[:4] in (littleendian, bigendian) :
-            if self.debug :  
-                sys.stderr.write("DEBUG: Input file is in the TIFF format.\n")
+            self.logdebug("DEBUG: Input file is in the TIFF format.")
             return 1
         else :    
Index: pkpgcounter/trunk/pkpgpdls/pdf.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/pdf.py (revision 243)
+++ pkpgcounter/trunk/pkpgpdls/pdf.py (revision 252)
@@ -47,6 +47,5 @@
            ((self.firstblock[:128].find("\033%-12345X") != -1) and (self.firstblock.upper().find("LANGUAGE=PDF") != -1)) or \
            (self.firstblock.find("%PDF-") != -1) :
-            if self.debug :  
-                sys.stderr.write("DEBUG: Input file is in the PDF format.\n")
+            self.logdebug("DEBUG: Input file is in the PDF format.")
             return 1
         else :    
@@ -99,12 +98,11 @@
         colorregexp = re.compile(r"(/ColorSpace) ?(/DeviceRGB|/DeviceCMYK)[/ \t\r\n]", re.I)
         pagecount = 0
-        for object in objects.values() :
-            content = "".join(object.content)
+        for obj in objects.values() :
+            content = "".join(obj.content)
             count = len(newpageregexp.findall(content))
             pagecount += count
             if colorregexp.match(content) :
                 self.iscolor = 1
-                if self.debug :
-                    sys.stderr.write("ColorSpace : %s\n" % content)
+                self.logdebug("ColorSpace : %s" % content)
         return pagecount    
         
Index: pkpgcounter/trunk/pkpgpdls/pcl345.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/pcl345.py (revision 249)
+++ pkpgcounter/trunk/pkpgpdls/pcl345.py (revision 252)
@@ -84,6 +84,5 @@
            self.firstblock.startswith("\033%8\033") or \
            (self.firstblock.find("\033%-12345X") != -1) :
-            if self.debug :  
-                sys.stderr.write("DEBUG: Input file is in the PCL3/4/5 format.\n")
+            self.logdebug("DEBUG: Input file is in the PCL3/4/5 format.")
             return 1
         else :    
@@ -92,6 +91,6 @@
     def setPageDict(self, pages, number, attribute, value) :
         """Initializes a page dictionnary."""
-        dict = pages.setdefault(number, { "copies" : 1, "mediasource" : "Main", "mediasize" : "Default", "mediatype" : "Plain", "orientation" : "Portrait"})
-        dict[attribute] = value
+        dic = pages.setdefault(number, { "copies" : 1, "mediasource" : "Main", "mediasize" : "Default", "mediatype" : "Plain", "orientation" : "Portrait", "escaped" : []})
+        dic[attribute] = value
         
     def getJobSize(self) :     
@@ -137,4 +136,6 @@
         mediasourcecount = mediasizecount = orientationcount = mediatypecount = 0
         tag = None
+        endmark = chr(0x1b) + chr(0x0c) + chr(0x00) 
+        asciilimit = chr(0x80)
         pages = {}
         pos = 0
@@ -145,93 +146,101 @@
                     pagecount += 1
                 elif char == "\033" :    
-                    starb = ampl = 0
-                    #
-                    #     <ESC>*b###y#m###v###w... -> PCL3 raster graphics
-                    #     <ESC>*b###W -> Start of a raster data row/block
-                    #     <ESC>*b###V -> Start of a raster data plane
-                    #     <ESC>*c###W -> Start of a user defined pattern
-                    #     <ESC>*i###W -> Start of a viewing illuminant block
-                    #     <ESC>*l###W -> Start of a color lookup table
-                    #     <ESC>*m###W -> Start of a download dither matrix block
-                    #     <ESC>*v###W -> Start of a configure image data block
-                    #     <ESC>*r1A -> Start Gfx 
-                    #     <ESC>(s###W -> Start of a characters description block
-                    #     <ESC>)s###W -> Start of a fonts description block
-                    #     <ESC>(f###W -> Start of a symbol set block
-                    #     <ESC>&b###W -> Start of configuration data block
-                    #     <ESC>&l###X -> Number of copies for current page
-                    #     <ESC>&n###W -> Starts an alphanumeric string ID block
-                    #     <ESC>&p###X -> Start of a non printable characters block
-                    #     <ESC>&a2G -> Back side when duplex mode as generated by rastertohp
-                    #     <ESC>*g###W -> Needed for planes in PCL3 output
-                    #     <ESC>&l###H (or only 0 ?) -> Eject if NumPlanes > 1, as generated by rastertohp. Also defines mediasource
-                    #     <ESC>&l###A -> mediasize
-                    #     <ESC>&l###O -> orientation
-                    #     <ESC>&l###M -> mediatype
-                    #     <ESC>*t###R -> gfx resolution
-                    #
-                    tagstart = minfile[pos] ; pos += 1
-                    if tagstart in "E9=YZ" : # one byte PCL tag
-                        if tagstart == "E" :
-                            resets += 1
-                        continue             # skip to next tag
-                    tag = tagstart + minfile[pos] ; pos += 1
-                    if tag == "*b" : 
-                        starb = 1
-                        tagend = "VW"
-                    elif tag == "&l" :    
-                        ampl = 1
-                        tagend = "XHAOM"
-                    else :    
-                        try :
-                            tagend = tagsends[tag]
-                        except KeyError :    
-                            continue # Unsupported PCL tag
-                    # Now read the numeric argument
-                    size = 0
-                    while 1 :
-                        char = minfile[pos] ; pos += 1
-                        if not char.isdigit() :
-                            break
-                        size = (size * 10) + int(char)    
-                    if char in tagend :    
-                        if tag == "&l" :
-                            if char == "X" : 
-                                self.setPageDict(pages, pagecount, "copies", size)
-                            elif char == "H" :
-                                self.setPageDict(pages, pagecount, "mediasource", self.mediasources.get(size, str(size)))
-                                mediasourcecount += 1
-                                ejects += 1 
-                            elif char == "A" :
-                                self.setPageDict(pages, pagecount, "mediasize", self.mediasizes.get(size, str(size)))
-                                mediasizecount += 1
-                            elif char == "O" :
-                                self.setPageDict(pages, pagecount, "orientation", self.orientations.get(size, str(size)))
-                                orientationcount += 1
-                            elif char == "M" :
-                                self.setPageDict(pages, pagecount, "mediatype", self.mediatypes.get(size, str(size)))
-                                mediatypecount += 1
-                        elif tag == "*r" :
-                            # Special tests for PCL3
-                            if (char == "s") and size :
-                                while 1 :
-                                    char = minfile[pos] ; pos += 1
-                                    if char == "A" :
-                                        break
-                            elif (char == "b") and (minfile[pos] == "C") and not size :
-                                ispcl3 = 1 # Certainely a PCL3 file
-                            startgfx += (char == "A") and (minfile[pos - 2] in ("0", "1", "2", "3")) # Start Gfx
-                            endgfx += (not size) and (char in ("C", "B")) # End Gfx
-                        elif tag == "*t" :    
-                            escstart += 1
-                        elif (tag == "&a") and (size == 2) :
-                            backsides += 1      # Back side in duplex mode
+                    if minfile[pos : pos+8] == r"%-12345X" :
+                        endpos = pos + 9
+                        while (minfile[endpos] not in endmark) and (minfile[endpos] < asciilimit) :
+                            endpos += 1
+                        self.setPageDict(pages, pagecount, "escaped", minfile[pos : endpos].replace('\r\n', '\n').split('\n'))
+                        self.logdebug("Escaped datas : [%s]" % repr(minfile[pos : endpos]))
+                        pos += (endpos - pos)
+                    else :
+                        starb = ampl = 0
+                        #
+                        #     <ESC>*b###y#m###v###w... -> PCL3 raster graphics
+                        #     <ESC>*b###W -> Start of a raster data row/block
+                        #     <ESC>*b###V -> Start of a raster data plane
+                        #     <ESC>*c###W -> Start of a user defined pattern
+                        #     <ESC>*i###W -> Start of a viewing illuminant block
+                        #     <ESC>*l###W -> Start of a color lookup table
+                        #     <ESC>*m###W -> Start of a download dither matrix block
+                        #     <ESC>*v###W -> Start of a configure image data block
+                        #     <ESC>*r1A -> Start Gfx 
+                        #     <ESC>(s###W -> Start of a characters description block
+                        #     <ESC>)s###W -> Start of a fonts description block
+                        #     <ESC>(f###W -> Start of a symbol set block
+                        #     <ESC>&b###W -> Start of configuration data block
+                        #     <ESC>&l###X -> Number of copies for current page
+                        #     <ESC>&n###W -> Starts an alphanumeric string ID block
+                        #     <ESC>&p###X -> Start of a non printable characters block
+                        #     <ESC>&a2G -> Back side when duplex mode as generated by rastertohp
+                        #     <ESC>*g###W -> Needed for planes in PCL3 output
+                        #     <ESC>&l###H (or only 0 ?) -> Eject if NumPlanes > 1, as generated by rastertohp. Also defines mediasource
+                        #     <ESC>&l###A -> mediasize
+                        #     <ESC>&l###O -> orientation
+                        #     <ESC>&l###M -> mediatype
+                        #     <ESC>*t###R -> gfx resolution
+                        #
+                        tagstart = minfile[pos] ; pos += 1
+                        if tagstart in "E9=YZ" : # one byte PCL tag
+                            if tagstart == "E" :
+                                resets += 1
+                            continue             # skip to next tag
+                        tag = tagstart + minfile[pos] ; pos += 1
+                        if tag == "*b" : 
+                            starb = 1
+                            tagend = "VW"
+                        elif tag == "&l" :    
+                            ampl = 1
+                            tagend = "XHAOM"
                         else :    
-                            # we just ignore the block.
-                            if tag == "&n" : 
-                                # we have to take care of the operation id byte
-                                # which is before the string itself
-                                size += 1
-                            pos += size    
+                            try :
+                                tagend = tagsends[tag]
+                            except KeyError :    
+                                continue # Unsupported PCL tag
+                        # Now read the numeric argument
+                        size = 0
+                        while 1 :
+                            char = minfile[pos] ; pos += 1
+                            if not char.isdigit() :
+                                break
+                            size = (size * 10) + int(char)    
+                        if char in tagend :    
+                            if tag == "&l" :
+                                if char == "X" : 
+                                    self.setPageDict(pages, pagecount, "copies", size)
+                                elif char == "H" :
+                                    self.setPageDict(pages, pagecount, "mediasource", self.mediasources.get(size, str(size)))
+                                    mediasourcecount += 1
+                                    ejects += 1 
+                                elif char == "A" :
+                                    self.setPageDict(pages, pagecount, "mediasize", self.mediasizes.get(size, str(size)))
+                                    mediasizecount += 1
+                                elif char == "O" :
+                                    self.setPageDict(pages, pagecount, "orientation", self.orientations.get(size, str(size)))
+                                    orientationcount += 1
+                                elif char == "M" :
+                                    self.setPageDict(pages, pagecount, "mediatype", self.mediatypes.get(size, str(size)))
+                                    mediatypecount += 1
+                            elif tag == "*r" :
+                                # Special tests for PCL3
+                                if (char == "s") and size :
+                                    while 1 :
+                                        char = minfile[pos] ; pos += 1
+                                        if char == "A" :
+                                            break
+                                elif (char == "b") and (minfile[pos] == "C") and not size :
+                                    ispcl3 = 1 # Certainely a PCL3 file
+                                startgfx += (char == "A") and (minfile[pos - 2] in ("0", "1", "2", "3")) # Start Gfx
+                                endgfx += (not size) and (char in ("C", "B")) # End Gfx
+                            elif tag == "*t" :    
+                                escstart += 1
+                            elif (tag == "&a") and (size == 2) :
+                                backsides += 1      # Back side in duplex mode
+                            else :    
+                                # we just ignore the block.
+                                if tag == "&n" : 
+                                    # we have to take care of the operation id byte
+                                    # which is before the string itself
+                                    size += 1
+                                pos += size    
                 else :                            
                     if starb :
@@ -329,5 +338,6 @@
             pass        # should be OK.
         elif (not startgfx) and (not endgfx) :
-            pagecount = ejects or pagecount
+            if ejects :
+                pagecount = ejects
         elif startgfx == endgfx :    
             pagecount = startgfx
@@ -339,9 +349,38 @@
             pagecount = abs(startgfx - endgfx)
             
-        if self.debug :        
-            for pnum in range(pagecount) :
-                # if no number of copies defined, take the preceding one else the one set before any page else 1.
-                page = pages.get(pnum, pages.get(pnum - 1, pages.get(0, { "copies" : 1, "mediasource" : "Main", "mediasize" : "Default", "mediatype" : "Plain", "orientation" : "Portrait"})))
-                sys.stderr.write("%s*%s*%s*%s*%s\n" % (page["copies"], page["mediatype"], page["mediasize"], page["orientation"], page["mediasource"]))
+        pjlstatements = []
+        for pnum in range(pagecount) :
+            # if no number of copies defined, take the preceding one else the one set before any page else 1.
+            page = pages.get(pnum, pages.get(pnum - 1, pages.get(0, { "copies" : 1, "mediasource" : "Main", "mediasize" : "Default", "mediatype" : "Plain", "orientation" : "Portrait", "escaped" : []})))
+            pjlstuff = page["escaped"]
+            if not pjlstuff :
+                pjlcopies = 1
+            else :    
+                pjlstatements.extend(pjlstuff)
+                newpjl = "\n".join(pjlstatements)
+                copiesstatement = newpjl.rfind("@PJL SET COPIES=")
+                qtystatement = newpjl.rfind("@PJL SET QTY=")
+                if copiesstatement > qtystatement :
+                    # we use the COPIES= statement
+                    try :
+                        pjlcopies = int(newpjl[copiesstatement+16:].split()[0].strip())
+                    except :    
+                        pjlcopies = 1
+                elif qtystatement > copiesstatement :    
+                    # we use the QTY= statement
+                    try :
+                        pjlcopies = int(newpjl[qtystatement+13:].split()[0].strip())
+                    except :    
+                        pjlcopies = 1
+                else :
+                    # both can't be equal unless they both equal -1 (not found)
+                    pjlcopies = 1
+            copies = pjlcopies * page["copies"]        
+            pagecount += (copies - 1)
+            self.logdebug("%s*%s*%s*%s*%s" % (copies, \
+                                              page["mediatype"], \
+                                              page["mediasize"], \
+                                              page["orientation"], \
+                                              page["mediasource"]))
                 
         return pagecount
Index: pkpgcounter/trunk/pkpgpdls/postscript.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/postscript.py (revision 248)
+++ pkpgcounter/trunk/pkpgpdls/postscript.py (revision 252)
@@ -39,6 +39,5 @@
               (self.firstblock.find("LANGUAGE = Postscript") != -1))) or \
               (self.firstblock.find("%!PS-Adobe") != -1) :
-            if self.debug :  
-                sys.stderr.write("DEBUG: Input file is in the PostScript format.\n")
+            self.logdebug("DEBUG: Input file is in the PostScript format.")
             return 1
         else :    
@@ -47,6 +46,5 @@
     def throughGhostScript(self) :
         """Get the count through GhostScript, useful for non-DSC compliant PS files."""
-        if self.debug :
-            sys.stderr.write("Internal parser sucks, using GhostScript instead...\n")
+        self.logdebug("Internal parser sucks, using GhostScript instead...")
         self.infile.seek(0)
         command = 'gs -sDEVICE=bbox -dNOPAUSE -dBATCH -dQUIET - 2>&1 | grep -c "%%HiResBoundingBox:" 2>/dev/null'
@@ -81,4 +79,5 @@
         pages = {}
         pages[0] = { "copies" : 1 }
+        previousline = ""
         for line in self.infile.xreadlines() : 
             if line.startswith(r"%%Page: ") :
@@ -130,6 +129,5 @@
             copies = page["copies"]
             pagecount += (copies - 1)
-            if self.debug :
-                sys.stderr.write("%s * page #%s\n" % (copies, pnum))
+            self.logdebug("%s * page #%s" % (copies, pnum))
         return pagecount
         
Index: pkpgcounter/trunk/pkpgpdls/escp2.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/escp2.py (revision 235)
+++ pkpgcounter/trunk/pkpgpdls/escp2.py (revision 252)
@@ -34,6 +34,5 @@
            self.firstblock.startswith("\n\033@") or \
            self.firstblock.startswith("\0\0\0\033\1@EJL") : # ESC/P Raster ??? Seen on Stylus Photo 1284
-            if self.debug :  
-                sys.stderr.write("DEBUG: Input file is in the ESC/P2 format.\n")
+            self.logdebug("DEBUG: Input file is in the ESC/P2 format.")
             return 1
         else :    
Index: pkpgcounter/trunk/pkpgpdls/ooo.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/ooo.py (revision 235)
+++ pkpgcounter/trunk/pkpgpdls/ooo.py (revision 252)
@@ -23,5 +23,4 @@
 
 import sys
-import os
 import zipfile
 
@@ -40,6 +39,5 @@
                 return 0
             else :
-                if self.debug :  
-                    sys.stderr.write("DEBUG: Input file is in the OpenOffice.org format.\n")
+                self.logdebug("DEBUG: Input file is in the OpenOffice.org format.")
                 return 1
         else :    
Index: pkpgcounter/trunk/pkpgpdls/pdlparser.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/pdlparser.py (revision 247)
+++ pkpgcounter/trunk/pkpgpdls/pdlparser.py (revision 252)
@@ -69,4 +69,9 @@
             psyco.bind(self.getJobSize)
             
+    def logdebug(self, message) :       
+        """Logs a debug message if needed."""
+        if self.debug :
+            sys.stderr.write("%s\n" % message)
+            
     def isValid(self) :    
         """Returns 1 if data is in the expected format, else 0."""
Index: pkpgcounter/trunk/pkpgpdls/dvi.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/dvi.py (revision 235)
+++ pkpgcounter/trunk/pkpgpdls/dvi.py (revision 252)
@@ -35,6 +35,5 @@
         try :
             if (ord(self.firstblock[0]) == 0xf7) and (ord(self.lastblock[-1]) == 0xdf) :
-                if self.debug :  
-                    sys.stderr.write("DEBUG: Input file is in the DVI format.\n")
+                self.logdebug("DEBUG: Input file is in the DVI format.")
                 return 1
             else :    
Index: pkpgcounter/trunk/pkpgpdls/pclxl.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/pclxl.py (revision 248)
+++ pkpgcounter/trunk/pkpgpdls/pclxl.py (revision 252)
@@ -28,4 +28,5 @@
 
 import pdlparser
+import pjl
 
 class Parser(pdlparser.PDLParser) :
@@ -82,6 +83,5 @@
              ((self.firstblock.find("LANGUAGE=PCLXL") != -1) or \
               (self.firstblock.find("LANGUAGE = PCLXL") != -1))) :
-            if self.debug :  
-                sys.stderr.write("DEBUG: Input file is in the PCLXL (aka PCL6) format.\n")
+            self.logdebug("DEBUG: Input file is in the PCLXL (aka PCL6) format.")
             return 1
         else :    
@@ -116,5 +116,5 @@
             elif val == 0x28 :    
                 orientation = ord(minfile[pos - 2])
-                orienationlabel = self.orientations.get(orientation, str(orientation))
+                orientationlabel = self.orientations.get(orientation, str(orientation))
                 pos = pos - 4
             elif val == 0x27 :    
@@ -246,6 +246,5 @@
     def reservedForFutureUse(self) :
         """Outputs something when a reserved byte is encountered."""
-        if self.debug :
-            sys.stderr.write("Byte at %s is out of the PCLXL Protocol Class 2.0 Specification\n" % self.pos)
+        self.logdebug("Byte at %s is out of the PCLXL Protocol Class 2.0 Specification" % self.pos)
         return 0    
         
@@ -255,5 +254,5 @@
         if self.minfile[pos : pos+8] == r"%-12345X" :
             endpos = pos + 9
-            endmark = chr(0x0c) + chr(0x00)
+            endmark = chr(0x0c) + chr(0x00) + chr(0x1b)
             asciilimit = chr(0x80)
             while (self.minfile[endpos] not in endmark) and (self.minfile[endpos] < asciilimit) :
@@ -264,6 +263,5 @@
             stuff = self.escapedStuff.setdefault(self.pagecount, [])
             stuff.append(self.minfile[pos : endpos])
-            if self.debug :
-                sys.stderr.write("Escaped datas : [%s]\n" % repr(self.minfile[pos : endpos]))
+            self.logdebug("Escaped datas : [%s]" % repr(self.minfile[pos : endpos]))
         return endpos - pos
         
@@ -489,4 +487,7 @@
         else :    
             colormode = "Black"
+            
+        defaultpjlcopies = 1    
+        oldpjlcopies = -1
         for pnum in range(1, self.pagecount + 1) :
             # if no number of copies defined, take 1, as explained
@@ -496,13 +497,36 @@
             # to decrease the total number of pages in this case.
             page = self.pages.get(pnum, self.pages.get(1, { "copies" : 1 }))
-            copies = page["copies"]
+            pjlstuff = self.escapedStuff.get(pnum, [])
+            if pjlstuff :
+                pjlparser = pjl.PJLParser("".join(pjlstuff))
+                nbdefaultcopies = int(pjlparser.default_variables.get("COPIES", -1))
+                nbcopies = int(pjlparser.environment_variables.get("COPIES", -1))
+                nbdefaultqty = int(pjlparser.default_variables.get("QTY", -1))
+                nbqty = int(pjlparser.environment_variables.get("QTY", -1))
+                if nbdefaultcopies > -1 :
+                    defaultpjlcopies = nbdefaultcopies
+                if nbdefaultqty > -1 :
+                    defaultpjlcopies = nbdefaultqty
+                if nbcopies > -1 :
+                    oldpjlcopies = pjlcopies = nbcopies
+                elif nbqty > -1 :
+                    oldpjlcopies = pjlcopies = nbqty
+                else :
+                    if oldpjlcopies == -1 :    
+                        oldpjlcopies = defaultpjlcopies
+                    pjlcopies = oldpjlcopies    
+            else :        
+                if oldpjlcopies == -1 :
+                    pjlcopies = defaultpjlcopies
+                else :    
+                    pjlcopies = oldpjlcopies
+            copies = pjlcopies * page["copies"]
             self.pagecount += (copies - 1)
-            if self.debug :
-                sys.stderr.write("%s*%s*%s*%s*%s*%s\n" % (copies, 
-                                                          page["mediatype"], 
-                                                          page["mediasize"], 
-                                                          page["orientation"], 
-                                                          page["mediasource"], 
-                                                          colormode))
+            self.logdebug("%s*%s*%s*%s*%s*%s" % (copies, 
+                                                 page["mediatype"], 
+                                                 page["mediasize"], 
+                                                 page["orientation"], 
+                                                 page["mediasource"], 
+                                                 colormode))
         return self.pagecount
         
Index: pkpgcounter/trunk/pkpgpdls/analyzer.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/analyzer.py (revision 235)
+++ pkpgcounter/trunk/pkpgpdls/analyzer.py (revision 252)
@@ -119,5 +119,5 @@
                            ooo) :
                 try :               
-                    return getattr(module, "Parser")(self.infile, self.debug, firstblock, lastblock)
+                    return module.Parser(self.infile, self.debug, firstblock, lastblock)
                 except pdlparser.PDLParserError :
                     pass # try next parser
Index: pkpgcounter/trunk/pkpgpdls/pjl.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/pjl.py (revision 252)
+++ pkpgcounter/trunk/pkpgpdls/pjl.py (revision 252)
@@ -0,0 +1,131 @@
+#! /usr/bin/env python
+# -*- coding: ISO-8859-15 -*-
+#
+# pkpgcounter : a generic Page Description Language parser
+#
+# (c) 2003, 2004, 2005 Jerome Alet <alet@librelogiciel.com>
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+# 
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# $Id$
+#
+
+import sys
+
+class PJLParserError(Exception):
+    """An exception for PJLParser related stuff."""
+    def __init__(self, message = ""):
+        self.message = message
+        Exception.__init__(self, message)
+    def __repr__(self):
+        return self.message
+    __str__ = __repr__
+        
+class PJLParser :
+    """A parser for PJL documents.
+    
+       Only extracts the PJL SET variables. Ignore other statements.
+    """
+    def __init__(self, pjljob, debug=0) :
+        """Initializes PJL Parser."""
+        self.debug = debug
+        self.statements = pjljob.replace("\r\n", "\n").split("\n")
+        self.default_variables = {}
+        self.environment_variables = {}
+        self.parsed = 0
+        self.parse()
+        
+    def __str__(self) :    
+        """Outputs our variables as a string of text."""
+        if not self.parsed :
+            return ""
+        mybuffer = []
+        if self.default_variables :
+            mybuffer.append("Default variables :")
+            for (k, v) in self.default_variables.items() :
+                mybuffer.append("  %s : %s" % (k, v))
+        if self.environment_variables :        
+            mybuffer.append("Environment variables :")
+            for (k, v) in self.environment_variables.items() :
+                mybuffer.append("  %s : %s" % (k, v))
+        return "\n".join(mybuffer)        
+            
+    def logdebug(self, message) :    
+        """Logs a debug message if needed."""
+        if self.debug :
+            sys.stderr.write("%s\n" % message)
+            
+    def cleanvars(self) :        
+        """Cleans the variables dictionnaries."""
+        for dicname in ("default", "environment") :
+            varsdic = getattr(self, "%s_variables" % dicname)
+            for (k, v) in varsdic.items() :
+                if len(v) == 1 :
+                    varsdic[k] = v[0]
+        
+    def parse(self) :
+        """Parses a PJL job."""
+        for i in range(len(self.statements)) :
+            statement = self.statements[i]
+            if statement.startswith("@PJL") :
+                parts = statement.split()
+                nbparts = len(parts)
+                if parts[0] == "@PJL" :
+                    # this is a valid PJL statement, but we don't
+                    # want to examine all of them...
+                    if (nbparts > 2) and (parts[1].upper() in ("SET", "DEFAULT")) :
+                        # this is what we are interested in !
+                        try :    
+                            (varname, value) = "".join(parts[2:]).split("=", 1)
+                        except :    
+                            self.logdebug("Invalid PJL SET statement [%s]" % repr(statement))
+                        else :    
+                            # all still looks fine...
+                            if parts[1].upper() == "DEFAULT" :
+                                varsdic = self.default_variables
+                            else :    
+                                varsdic = self.environment_variables 
+                            variable = varsdic.setdefault(varname.upper(), [])
+                            variable.append(value)
+                    else :
+                        self.logdebug("Ignored PJL statement [%s]" % repr(statement))
+                else :
+                    self.logdebug("Invalid PJL statement [%s]" % repr(statement))
+            else :
+                self.logdebug("Invalid PJL statement [%s]" % repr(statement))
+        self.cleanvars()
+        self.parsed = 1
+        
+def test() :        
+    """Test function."""
+    if (len(sys.argv) < 2) or ((not sys.stdin.isatty()) and ("-" not in sys.argv[1:])) :
+        sys.argv.append("-")
+    for arg in sys.argv[1:] :
+        if arg == "-" :
+            infile = sys.stdin
+            mustclose = 0
+        else :    
+            infile = open(arg, "rb")
+            mustclose = 1
+        try :
+            parser = PJLParser(infile.read(), debug=1)
+        except PJLParserError, msg :    
+            sys.stderr.write("ERROR: %s\n" % msg)
+            sys.stderr.flush()
+        if mustclose :    
+            infile.close()
+        print str(parser)            
+    
+if __name__ == "__main__" :    
+    test()
Index: pkpgcounter/trunk/pkpgpdls/version.py
===================================================================
--- pkpgcounter/trunk/pkpgpdls/version.py (revision 248)
+++ pkpgcounter/trunk/pkpgpdls/version.py (revision 252)
@@ -20,5 +20,5 @@
 #
 
-__version__ = "1.61"
+__version__ = "1.62"
 
 __doc__ = """pkpgcounter : a generic Page Description Languages parser."""
