Index: pykota/trunk/conf/pykota.conf.sample
===================================================================
--- pykota/trunk/conf/pykota.conf.sample (revision 2066)
+++ pykota/trunk/conf/pykota.conf.sample (revision 2074)
@@ -364,5 +364,15 @@
 #                 this way :
 #
+#                   accounter: software()
+#
+#                 which uses PyKota's internal parser to compute
+#                 the size of the job.
+#
+#                 You could obtain exactly the same result with :
+#
 #                   accounter: software(/usr/bin/pkpgcounter)
+#
+#                 But in this case the job would be passed through
+#                 PyKota's internal parser a second time.
 #
 #                 pkpgcounter is a command line tool which is
@@ -372,9 +382,9 @@
 #                 in the future, as time permits.
 #
-#                 while pkpgcounter is the recommended value
-#                 you can use whatever command you want provided
-#                 that your command accepts the job's data on its
-#                 standard input and prints the job's size in pages
-#                 as a single integer on its standard output.
+#                 while pkpgcounter is the recommended value if you want
+#                 to use an external command here, you can use whatever 
+#                 command you want provided your command accepts the job's
+#                 data on its standard input and prints the job's size in 
+#                 pages as a single integer on its standard output.
 # 
 # This value can be set either globally or on a per printer basis
@@ -384,5 +394,8 @@
 # accounter: hardware(snmp)
 # accounter: hardware(pjl)
-accounter: software(/usr/bin/pkpgcounter)
+# accounter: software(/usr/bin/pkpgcounter)
+#
+# The following is only allowed since PyKota 1.21 
+accounter: software()
 
 # What should we do if the accounter's subprocess doesn't return
Index: pykota/trunk/NEWS
===================================================================
--- pykota/trunk/NEWS (revision 2073)
+++ pykota/trunk/NEWS (revision 2074)
@@ -24,4 +24,9 @@
     - 1.21alpha27 :
     
+        - Allows software() (no arguments) to the software accounting
+          directive. This saves a lot of CPU since the job is not
+          parsed again : the precomputed size is used directly in this
+          case.
+          
         - epykota's --prototype option now works fine with accounts
           limited by balance.
Index: pykota/trunk/pykota/config.py
===================================================================
--- pykota/trunk/pykota/config.py (revision 2066)
+++ pykota/trunk/pykota/config.py (revision 2074)
@@ -22,4 +22,9 @@
 #
 # $Log$
+# Revision 1.62  2005/02/19 18:16:06  jalet
+# Optimize print job parsing by avoiding to pass the job's datas through
+# PyKota's internal parser if the special construct "software()" is used
+# with no argument in the 'accounter' directive.
+#
 # Revision 1.61  2005/02/16 00:29:33  jalet
 # Fixed the maxdenybanners directive.
@@ -393,6 +398,6 @@
                 raise PyKotaConfigError, _("Invalid accounter %s for printer %s") % (fullaccounter, printername)
             if args.endswith(')') :
-                args = args[:-1]
-            if not args :
+                args = args[:-1].strip()
+            if (accounter == "hardware") and not args :
                 raise PyKotaConfigError, _("Invalid accounter %s for printer %s") % (fullaccounter, printername)
             return (accounter.lower(), args)    
Index: pykota/trunk/pykota/accounters/software.py
===================================================================
--- pykota/trunk/pykota/accounters/software.py (revision 1743)
+++ pykota/trunk/pykota/accounters/software.py (revision 2074)
@@ -22,4 +22,9 @@
 #
 # $Log$
+# Revision 1.12  2005/02/19 18:16:06  jalet
+# Optimize print job parsing by avoiding to pass the job's datas through
+# PyKota's internal parser if the special construct "software()" is used
+# with no argument in the 'accounter' directive.
+#
 # Revision 1.11  2004/09/24 21:19:48  jalet
 # Did a pass of PyChecker
@@ -75,51 +80,55 @@
         """Feeds an external command with our datas to let it compute the job size, and return its value."""
         self.filter.printInfo(_("Launching SOFTWARE(%s)...") % self.arguments)
-        MEGABYTE = 1024*1024
-        self.filter.jobdatastream.seek(0)
-        child = popen2.Popen4(self.arguments)
-        try :
-            data = self.filter.jobdatastream.read(MEGABYTE)    
-            while data :
-                child.tochild.write(data)
-                data = self.filter.jobdatastream.read(MEGABYTE)
-            child.tochild.flush()
-            child.tochild.close()    
-        except (IOError, OSError), msg :    
-            msg = "%s : %s" % (self.arguments, msg) 
-            self.filter.printInfo(_("Unable to compute job size with accounter %s") % msg)
-        
-        pagecounter = None
-        try :
-            answer = child.fromchild.read()
-        except (IOError, OSError), msg :    
-            msg = "%s : %s" % (self.arguments, msg) 
-            self.filter.printInfo(_("Unable to compute job size with accounter %s") % msg)
-        else :    
-            lines = [l.strip() for l in answer.split("\n")]
-            for i in range(len(lines)) : 
-                try :
-                    pagecounter = int(lines[i])
-                except (AttributeError, ValueError) :
-                    self.filter.printInfo(_("Line [%s] skipped in accounter's output. Trying again...") % lines[i])
-                else :    
-                    break
-        child.fromchild.close()
-        
-        try :
-            status = child.wait()
-        except OSError, msg :    
-            self.filter.printInfo(_("Problem while waiting for software accounter pid %s to exit : %s") % (child.pid, msg))
-        else :    
-            if os.WIFEXITED(status) :
-                status = os.WEXITSTATUS(status)
-            self.filter.printInfo(_("Software accounter %s exit code is %s") % (self.arguments, str(status)))
+        if not self.arguments :
+            pagecounter = self.filter.softwareJobSize   # Optimize : already computed !
+            self.filter.logdebug("Internal software accounter said job is %s pages long." % repr(pagecounter))
+        else :
+            MEGABYTE = 1024*1024
+            self.filter.jobdatastream.seek(0)
+            child = popen2.Popen4(self.arguments)
+            try :
+                data = self.filter.jobdatastream.read(MEGABYTE)    
+                while data :
+                    child.tochild.write(data)
+                    data = self.filter.jobdatastream.read(MEGABYTE)
+                child.tochild.flush()
+                child.tochild.close()    
+            except (IOError, OSError), msg :    
+                msg = "%s : %s" % (self.arguments, msg) 
+                self.filter.printInfo(_("Unable to compute job size with accounter %s") % msg)
             
-        if pagecounter is None :    
-            message = _("Unable to compute job size with accounter %s") % self.arguments
-            if self.onerror == "CONTINUE" :
-                self.filter.printInfo(message, "error")
-            else :
-                raise PyKotaAccounterError, message
+            pagecounter = None
+            try :
+                answer = child.fromchild.read()
+            except (IOError, OSError), msg :    
+                msg = "%s : %s" % (self.arguments, msg) 
+                self.filter.printInfo(_("Unable to compute job size with accounter %s") % msg)
+            else :    
+                lines = [l.strip() for l in answer.split("\n")]
+                for i in range(len(lines)) : 
+                    try :
+                        pagecounter = int(lines[i])
+                    except (AttributeError, ValueError) :
+                        self.filter.printInfo(_("Line [%s] skipped in accounter's output. Trying again...") % lines[i])
+                    else :    
+                        break
+            child.fromchild.close()
             
-        self.filter.logdebug("Software accounter %s said job is %s pages long." % (self.arguments, repr(pagecounter)))
+            try :
+                status = child.wait()
+            except OSError, msg :    
+                self.filter.printInfo(_("Problem while waiting for software accounter pid %s to exit : %s") % (child.pid, msg))
+            else :    
+                if os.WIFEXITED(status) :
+                    status = os.WEXITSTATUS(status)
+                self.filter.printInfo(_("Software accounter %s exit code is %s") % (self.arguments, str(status)))
+                
+            if pagecounter is None :    
+                message = _("Unable to compute job size with accounter %s") % self.arguments
+                if self.onerror == "CONTINUE" :
+                    self.filter.printInfo(message, "error")
+                else :
+                    raise PyKotaAccounterError, message
+            self.filter.logdebug("Software accounter %s said job is %s pages long." % (self.arguments, repr(pagecounter)))
+            
         return pagecounter or 0
