winspool: better /etc/printcap parsing
Huw D M Davies
h.davies1 at physics.ox.ac.uk
Mon Nov 10 09:40:51 CST 2003
Huw Davies <huw at codeweavers.com>
Much better parsing of /etc/printcap.
Don't even try to use heuristics to guess whether the printer is
PostScript or not - we're going to get it wrong anyway.
Don't list printer entries that begin with ispunct() - these are used
for 'tc' aliases.
--
Huw Davies
huw at codeweavers.com
Index: dlls/winspool/info.c
===================================================================
RCS file: /home/wine/wine/dlls/winspool/info.c,v
retrieving revision 1.85
diff -u -r1.85 info.c
--- dlls/winspool/info.c 5 Nov 2003 00:36:47 -0000 1.85
+++ dlls/winspool/info.c 10 Nov 2003 15:38:00 -0000
@@ -176,7 +176,6 @@
if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
ERROR_SUCCESS) {
ERR("Can't create Printers key\n");
- SetLastError(ERROR_FILE_NOT_FOUND); /* ?? */
return FALSE;
}
@@ -230,130 +229,160 @@
static BOOL
PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
PRINTER_INFO_2A pinfo2a;
- char *s,*name,*prettyname,*devname;
- BOOL isps = FALSE;
- char *port,*devline;
+ char *e,*s,*name,*prettyname,*devname;
+ BOOL ret = FALSE, set_default = FALSE;
+ char *port,*devline,*env_default;
+ HKEY hkeyPrinter, hkeyPrinters;
while (isspace(*pent)) pent++;
s = strchr(pent,':');
- if (!s) return FALSE;
- *s='\0';
- name = pent;
- pent = s+1;
- TRACE("%s\n",name);
-
- /* Determine whether this is a postscript printer. */
-
- /* 1. Check if name or aliases contain trigger phrases like 'ps' */
- if (strstr(name,"ps") ||
- strstr(name,"pd") || /* postscript double page */
- strstr(name,"postscript") ||
- strstr(name,"PostScript")
- ) {
- TRACE("%s has 'ps' style name, assuming postscript.\n",name);
- isps = TRUE;
- }
- /* 2. Check if this is a remote printer. These usually are postscript
- * capable
- */
- if (strstr(pent,":rm")) {
- isps = TRUE;
- TRACE("%s is remote, assuming postscript.\n",name);
- }
- /* 3. Check if we have an input filter program. If we have one, it
- * most likely is one capable of converting postscript.
- * (Could probably check for occurrence of 'gs' or 'ghostscript'
- * in the if file itself.)
- */
- if (strstr(pent,":if=/")) {
- isps = TRUE;
- TRACE("%s has inputfilter program, assuming postscript.\n",name);
+ if(s) *s='\0';
+ name = HeapAlloc(GetProcessHeap(), 0, strlen(pent) + 1);
+ strcpy(name,pent);
+ if(s) {
+ *s=':';
+ pent = s;
+ } else
+ pent = "";
+
+ TRACE("name=%s entry=%s\n",name, pent);
+
+ if(ispunct(*name)) { /* a tc entry, not a real printer */
+ TRACE("skipping tc entry\n");
+ goto end;
+ }
+
+ if(strstr(pent,":server")) { /* server only version so skip */
+ TRACE("skipping server entry\n");
+ goto end;
}
- /* If it is not a postscript printer, we cannot use it. */
- if (!isps)
- return FALSE;
+ /* Determine whether this is a postscript printer. */
+ ret = TRUE;
+ env_default = getenv("PRINTER");
prettyname = name;
/* Get longest name, usually the one at the right for later display. */
- while ((s=strchr(prettyname,'|'))) prettyname = s+1;
- s=strchr(name,'|');if (s) *s='\0';
+ while((s=strchr(prettyname,'|'))) {
+ *s = '\0';
+ e = s;
+ while(isspace(*--e)) *e = '\0';
+ TRACE("\t%s\n", debugstr_a(prettyname));
+ if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
+ for(prettyname = s+1; isspace(*prettyname); prettyname++)
+ ;
+ }
+ e = prettyname + strlen(prettyname);
+ while(isspace(*--e)) *e = '\0';
+ TRACE("\t%s\n", debugstr_a(prettyname));
+ if(env_default && !strcasecmp(prettyname, env_default)) set_default = TRUE;
/* prettyname must fit into the dmDeviceName member of DEVMODE struct,
* if it is too long, we use it as comment below. */
devname = prettyname;
if (strlen(devname)>=CCHDEVICENAME-1)
devname = name;
- if (strlen(devname)>=CCHDEVICENAME-1)
- return FALSE;
-
- if (isfirst) /* set first entry as default */
- WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
+ if (strlen(devname)>=CCHDEVICENAME-1) {
+ ret = FALSE;
+ goto end;
+ }
- memset(&pinfo2a,0,sizeof(pinfo2a));
- pinfo2a.pPrinterName = devname;
- pinfo2a.pDatatype = "RAW";
- pinfo2a.pPrintProcessor = "WinPrint";
- pinfo2a.pDriverName = "PS Driver";
- pinfo2a.pComment = "WINEPS Printer using LPR";
- pinfo2a.pLocation = prettyname;
port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(name)+1);
sprintf(port,"LPR:%s",name);
- pinfo2a.pPortName = port;
- pinfo2a.pParameters = "<parameters?>";
- pinfo2a.pShareName = "<share name?>";
- pinfo2a.pSepFile = "<sep file?>";
devline=HeapAlloc(GetProcessHeap(),0,strlen("WINEPS,")+strlen(port)+1);
sprintf(devline,"WINEPS,%s",port);
WriteProfileStringA("devices",devname,devline);
HeapFree(GetProcessHeap(),0,devline);
-
- if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
- if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
- ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
+
+ if(RegCreateKeyA(HKEY_LOCAL_MACHINE, Printers, &hkeyPrinters) !=
+ ERROR_SUCCESS) {
+ ERR("Can't create Printers key\n");
+ ret = FALSE;
+ goto end;
+ }
+ if(RegOpenKeyA(hkeyPrinters, devname, &hkeyPrinter) == ERROR_SUCCESS) {
+ /* Printer already in registry, delete the tag added in WINSPOOL_LoadSystemPrinters
+ and continue */
+ TRACE("Printer already exists\n");
+ RegDeleteValueW(hkeyPrinter, May_Delete_Value);
+ RegCloseKey(hkeyPrinter);
+ } else {
+ memset(&pinfo2a,0,sizeof(pinfo2a));
+ pinfo2a.pPrinterName = devname;
+ pinfo2a.pDatatype = "RAW";
+ pinfo2a.pPrintProcessor = "WinPrint";
+ pinfo2a.pDriverName = "PS Driver";
+ pinfo2a.pComment = "WINEPS Printer using LPR";
+ pinfo2a.pLocation = prettyname;
+ pinfo2a.pPortName = port;
+ pinfo2a.pParameters = "<parameters?>";
+ pinfo2a.pShareName = "<share name?>";
+ pinfo2a.pSepFile = "<sep file?>";
+
+ if (!AddPrinterA(NULL,2,(LPBYTE)&pinfo2a)) {
+ if (GetLastError()!=ERROR_PRINTER_ALREADY_EXISTS)
+ ERR("%s not added by AddPrinterA (%ld)\n",name,GetLastError());
+ }
}
- HeapFree(GetProcessHeap(),0,port);
- return TRUE;
+ RegCloseKey(hkeyPrinters);
+
+ if (isfirst || set_default)
+ WINSPOOL_SetDefaultPrinter(devname,name,TRUE);
+
+ HeapFree(GetProcessHeap(), 0, port);
+ end:
+ HeapFree(GetProcessHeap(), 0, name);
+ return ret;
}
static BOOL
PRINTCAP_LoadPrinters(void) {
- BOOL hadprinter = FALSE, isfirst = TRUE;
+ BOOL hadprinter = FALSE;
char buf[200];
FILE *f;
+ char *pent = NULL;
+ BOOL had_bash = FALSE;
f = fopen("/etc/printcap","r");
if (!f)
return FALSE;
- while (fgets(buf,sizeof(buf),f)) {
- char *pent = NULL;
- do {
- char *s;
- s=strchr(buf,'\n'); if (s) *s='\0';
- if ((buf[0]=='#') || (buf[0]=='\0'))
- continue;
-
- if (pent) {
- pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(buf)+2);
- strcat(pent,buf);
- } else {
- pent=HeapAlloc(GetProcessHeap(),0,strlen(buf)+1);
- strcpy(pent,buf);
- }
-
- if (strlen(pent) && (pent[strlen(pent)-1] == '\\'))
- pent[strlen(pent)-1] = '\0';
- else
- break;
- } while (fgets(buf,sizeof(buf),f));
- if (pent)
- hadprinter |= PRINTCAP_ParseEntry(pent,isfirst);
- isfirst = FALSE;
- if (pent) HeapFree(GetProcessHeap(),0,pent);
- pent = NULL;
- if (feof(f)) break;
+ while(fgets(buf,sizeof(buf),f)) {
+ char *start, *end;
+
+ end=strchr(buf,'\n');
+ if (end) *end='\0';
+
+ start = buf;
+ while(isspace(*start)) start++;
+ if(*start == '#' || *start == '\0')
+ continue;
+
+ if(pent && !had_bash && *start != ':' && *start != '|') { /* start of new entry, parse the previous one */
+ hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
+ HeapFree(GetProcessHeap(),0,pent);
+ pent = NULL;
+ }
+
+ if (end && *--end == '\\') {
+ *end = '\0';
+ had_bash = TRUE;
+ } else
+ had_bash = FALSE;
+
+ if (pent) {
+ pent=HeapReAlloc(GetProcessHeap(),0,pent,strlen(pent)+strlen(start)+1);
+ strcat(pent,start);
+ } else {
+ pent=HeapAlloc(GetProcessHeap(),0,strlen(start)+1);
+ strcpy(pent,start);
+ }
+
+ }
+ if(pent) {
+ hadprinter |= PRINTCAP_ParseEntry(pent,!hadprinter);
+ HeapFree(GetProcessHeap(),0,pent);
}
fclose(f);
return hadprinter;
@@ -413,9 +442,10 @@
RegCloseKey(hkeyPrinters);
}
- /* We want to avoid calling AddPrinter on cups printers as much as
- possible, because this will (eventually) lead to a call to
- cupsGetPPD which takes forever. So we'll tag all printers that
+ /* We want to avoid calling AddPrinter on printers as much as
+ possible, because on cups printers this will (eventually) lead
+ to a call to cupsGetPPD which takes forever, even with non-cups
+ printers AddPrinter takes a while. So we'll tag all printers that
were automatically added last time around, if they still exist
we'll leave them be otherwise we'll delete them. */
EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
@@ -440,11 +470,18 @@
#ifdef HAVE_CUPS_CUPS_H
- /* If we have any CUPS based printers, skip looking for printcap printers */
done = CUPS_LoadPrinters();
-
#endif
+ if(!done) { /* If we have any CUPS based printers, skip looking for printcap printers */
+ /* Check for [ppd] section in config file before parsing /etc/printcap */
+ if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
+ &hkey) == ERROR_SUCCESS) {
+ RegCloseKey(hkey);
+ PRINTCAP_LoadPrinters();
+ }
+ }
+
/* Now enumerate the list again and delete any printers that a still tagged */
EnumPrintersA(PRINTER_ENUM_LOCAL, NULL, 5, NULL, 0, &needed, &num);
if(needed) {
@@ -469,18 +506,8 @@
HeapFree(GetProcessHeap(), 0, pi);
}
+ return;
- if(done)
- return;
-
- /* Check for [ppd] section in config file before parsing /etc/printcap */
-
- if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\ppd",
- &hkey) == ERROR_SUCCESS)
- {
- RegCloseKey(hkey);
- PRINTCAP_LoadPrinters();
- }
}
More information about the wine-patches
mailing list