PATCH: Re: Aargh! Wine won't run anything

Marcus Meissner marcus at jet.franken.de
Tue May 8 02:01:58 CDT 2001


On Tue, May 08, 2001 at 01:14:41AM -0500, Ian Pilcher wrote:
> I hate following up to my own messages.  I sent the previous note after
> I couldn't get anything useful out of winedbg.  Then I had the idea of
> just running Wine under gdb, and I got the following:
> 
> Program received signal SIGSEGV, Segmentation fault.
> 0x402f1b93 in strchr () from /lib/i686/libc.so.6
> (gdb) bt
> #0  0x402f1b93 in strchr () from /lib/i686/libc.so.6
> #1  0x405f6c78 in ?? ()
> #2  0x409a459e in PRINTCAP_LoadPrinters () at info.c:265

Oh.

This would happen if you have a comment/empty line at your last line
of your printcap.

I added a "if (pent) " at the place where it is needed.

Ciao, Marcus

Changelog:
	Implemented /etc/printcap based printing support.
	Changed 'CUPS:printername' to 'LPR:printername'.
	Some fixes in AddPrinterW().

Index: dlls/gdi/printdrv.c
===================================================================
RCS file: /home/wine/wine/dlls/gdi/printdrv.c,v
retrieving revision 1.9
diff -u -r1.9 printdrv.c
--- dlls/gdi/printdrv.c	2001/04/27 18:02:46	1.9
+++ dlls/gdi/printdrv.c	2001/05/05 23:54:24
@@ -456,8 +456,8 @@
     if (pszOutput == NULL || *pszOutput == '\0')
       return -1;
 
-    if (!strncmp("CUPS:",pszOutput,5))
-      sprintf(psCmd,"|lpr -P%s",pszOutput+5);
+    if (!strncmp("LPR:",pszOutput,4))
+      sprintf(psCmd,"|lpr -P%s",pszOutput+4);
     else
       PROFILE_GetWineIniString("spooler",pszOutput,"",psCmd,sizeof(psCmd));
     TRACE("Got printerSpoolCommand '%s' for output device '%s'\n",
Index: dlls/wineps/init.c
===================================================================
RCS file: /home/wine/wine/dlls/wineps/init.c,v
retrieving revision 1.15
diff -u -r1.15 init.c
--- dlls/wineps/init.c	2001/05/03 18:34:27	1.15
+++ dlls/wineps/init.c	2001/05/05 23:54:43
@@ -523,10 +523,10 @@
 	    strncpy(ppdFileName, ppd, sizeof(ppdFileName));
 	    res = ERROR_SUCCESS;
 	    /* we should unlink() that file later */
+	} else {
+	    res = ERROR_FILE_NOT_FOUND;
+	    WARN("Did not find ppd for %s\n",name);
 	}
-	else {
-		ERR("Did not find ppd for %s\n",name);
-	}
     }
 #endif
 
@@ -534,7 +534,17 @@
         res = GetPrinterDataA (hPrinter, "PPD File", NULL, ppdFileName,
 	    	sizeof(ppdFileName), &needed);
     }
-    
+    /* Look for a ppd file for this printer in the config file.
+     * First look for the names of the printer, then for 'generic'
+     */
+    if ((res!=ERROR_SUCCESS) &&
+	!PROFILE_GetWineIniString("ppd",name,"",ppdFileName,sizeof(ppdFileName))	&&
+    	!PROFILE_GetWineIniString("ppd","generic","",ppdFileName,sizeof(ppdFileName))
+    )
+	res = ERROR_FILE_NOT_FOUND;
+    else 
+	res = ERROR_SUCCESS;
+
     if (res != ERROR_SUCCESS) {
 	ERR ("Error %li getting PPD file name for printer '%s'\n", res, name);
 	goto closeprinter;
Index: dlls/winspool/info.c
===================================================================
RCS file: /home/wine/wine/dlls/winspool/info.c,v
retrieving revision 1.35
diff -u -r1.35 info.c
--- dlls/winspool/info.c	2001/04/27 18:02:46	1.35
+++ dlls/winspool/info.c	2001/05/08 07:48:12
@@ -76,46 +76,37 @@
 static WCHAR WinPrintW[] = {'W','i','n','P','r','i','n','t',0};
 
 static HKEY WINSPOOL_OpenDriverReg( LPVOID pEnvironment, BOOL unicode);
+static BOOL WINSPOOL_GetPrinterDriver(HANDLE hPrinter, LPWSTR pEnvironment,
+				      DWORD Level, LPBYTE pDriverInfo,
+				      DWORD cbBuf, LPDWORD pcbNeeded,
+				      BOOL unicode);
 
 #ifdef HAVE_CUPS
-void
+BOOL
 CUPS_LoadPrinters(void) {
     cups_dest_t		*dests;
-    int			i,nrofdests;
+    int			i,nrofdests,hadprinter = FALSE;
     PRINTER_INFO_2A	pinfo2a;
-    DRIVER_INFO_3A	di3a;
     const char*		def = cupsGetDefault();
 
     nrofdests = cupsGetDests(&dests);
 
-    di3a.cVersion = 0x400;
-    di3a.pName = "PS Driver";
-    di3a.pEnvironment = NULL;	/* NULL means auto */
-    di3a.pDriverPath = "wineps.drv";
-    di3a.pDataFile = "<datafile?>";
-    di3a.pConfigFile = "wineps.drv";
-    di3a.pHelpFile = "<helpfile?>";
-    di3a.pDependentFiles = "<dependend files?>";
-    di3a.pMonitorName = "<monitor name?>";
-    di3a.pDefaultDataType = "RAW";
-
-
-    if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
-	ERR("Failed adding PS Driver (%ld)\n",GetLastError());
-        return;
-    }
     for (i=0;i<nrofdests;i++) {
 	const char *ppd = cupsGetPPD(dests[i].name);
 	char	*port,*devline;
 
-	if (!ppd)
-		continue;
+	if (!ppd) {
+	    WARN("No ppd file for %s.\n",dests[i].name);
+	    continue;
+	}
 	unlink(ppd);
 
+	hadprinter = TRUE;
+
 	if (!strcmp(def,dests[i].name)) {
-		char	*buf = HeapAlloc(GetProcessHeap(),0,2*strlen(dests[i].name)+strlen(",WINEPS,CUPS:")+1);
+		char	*buf = HeapAlloc(GetProcessHeap(),0,2*strlen(dests[i].name)+strlen(",WINEPS,LPR:")+1);
 
-		sprintf(buf,"%s,WINEPS,CUPS:%s",dests[i].name,dests[i].name);
+		sprintf(buf,"%s,WINEPS,LPR:%s",dests[i].name,dests[i].name);
 		WriteProfileStringA("windows","device",buf);
 		HeapFree(GetProcessHeap(),0,buf);
 	}
@@ -126,8 +117,8 @@
 	pinfo2a.pDriverName	= "PS Driver";
 	pinfo2a.pComment	= "WINEPS Printer using CUPS";
 	pinfo2a.pLocation	= "<physical location of printer>";
-	port = HeapAlloc(GetProcessHeap(),0,strlen("CUPS:")+strlen(dests[i].name)+1);
-	sprintf(port,"CUPS:%s",dests[i].name);
+	port = HeapAlloc(GetProcessHeap(),0,strlen("LPR:")+strlen(dests[i].name)+1);
+	sprintf(port,"LPR:%s",dests[i].name);
 	pinfo2a.pPortName	= port;
 	pinfo2a.pParameters	= "<parameters?>";
 	pinfo2a.pShareName	= "<share name?>";
@@ -144,10 +135,171 @@
 	}
 	HeapFree(GetProcessHeap(),0,port);
     }
+    return hadprinter;
 }
 #endif
 
+static BOOL
+PRINTCAP_ParseEntry(char *pent,BOOL isfirst) {
+    PRINTER_INFO_2A	pinfo2a;
+    char		*s,*name,*prettyname,*devname;
+    BOOL		isps = FALSE;
+    char		*port,*devline;
+
+    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 occurence 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 it is not a postscript printer, we cannot use it. */
+    if (!isps)
+	return FALSE;
+
+    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';
+
+    /* 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) {
+	    char	*buf = HeapAlloc(GetProcessHeap(),0,strlen(name)+strlen(devname)+strlen(",WINEPS,LPR:")+1);
+
+	    sprintf(buf,"%s,WINEPS,LPR:%s",devname,name);
+	    WriteProfileStringA("windows","device",buf);
+	    HeapFree(GetProcessHeap(),0,buf);
+    }
+    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());
+    }
+    HeapFree(GetProcessHeap(),0,port);
+    return TRUE;
+}
+
+static BOOL
+PRINTCAP_LoadPrinters(void) {
+    BOOL		hadprinter = FALSE, isfirst = TRUE;
+    char		buf[200];
+    FILE		*f;
 
+    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;
+    }
+    fclose(f);
+    return hadprinter;
+}
+
+void
+WINSPOOL_LoadSystemPrinters() {
+    DRIVER_INFO_3A	di3a;
+    di3a.cVersion = 0x400;
+    di3a.pName = "PS Driver";
+    di3a.pEnvironment = NULL;	/* NULL means auto */
+    di3a.pDriverPath = "wineps.drv";
+    di3a.pDataFile = "<datafile?>";
+    di3a.pConfigFile = "wineps.drv";
+    di3a.pHelpFile = "<helpfile?>";
+    di3a.pDependentFiles = "<dependend files?>";
+    di3a.pMonitorName = "<monitor name?>";
+    di3a.pDefaultDataType = "RAW";
+
+    if (!AddPrinterDriverA(NULL,3,(LPBYTE)&di3a)) {
+	ERR("Failed adding PS Driver (%ld)\n",GetLastError());
+        return;
+    }
+#ifdef HAVE_CUPS
+    /* If we have any CUPS based printers, skip looking for printcap printers */
+    if (CUPS_LoadPrinters())
+	return;
+#endif
+    PRINTCAP_LoadPrinters();
+}
+
+
 /******************************************************************
  *  WINSPOOL_GetOpenedPrinterEntry
  *  Get the first place empty in the opened printer table
@@ -792,6 +952,13 @@
 	SetLastError(ERROR_INVALID_LEVEL);
 	return 0;
     }
+    if (strlenW(pi->pPrinterName) >= CCHDEVICENAME) {
+	ERR("Printername %s must not exceed length of DEVMODE.dmDeviceName !\n",
+		debugstr_w(pi->pPrinterName)
+	);
+	SetLastError(ERROR_INVALID_LEVEL);
+	return 0;
+    }
     if(!pPrinter) {
         SetLastError(ERROR_INVALID_PARAMETER);
 	return 0;
@@ -801,12 +968,14 @@
         ERR("Can't create Printers key\n");
 	return 0;
     }
-    if(RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) ==
-       ERROR_SUCCESS) {
-        SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
+    if(!RegOpenKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter)) {
+	if (!RegQueryValueA(hkeyPrinter,"Attributes",NULL,NULL)) {
+	    SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
+	    RegCloseKey(hkeyPrinter);
+	    RegCloseKey(hkeyPrinters);
+	    return 0;
+	}
 	RegCloseKey(hkeyPrinter);
-	RegCloseKey(hkeyPrinters);
-	return 0;
     }
     hkeyDrivers = WINSPOOL_OpenDriverReg( NULL, TRUE);
     if(!hkeyDrivers) {
@@ -832,34 +1001,44 @@
 	return 0;
     }
 
+    if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
+       ERROR_SUCCESS) {
+        FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
+	SetLastError(ERROR_INVALID_PRINTER_NAME);
+	RegCloseKey(hkeyPrinters);
+	return 0;
+    }
+    RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
+		   (LPBYTE)&pi->Attributes, sizeof(DWORD));
+    RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
+		   0);
+
     /* See if we can load the driver.  We may need the devmode structure anyway
+     *
+     * FIXME:
+     * Note that DocumentPropertiesW will briefly try to open the printer we
+     * just create to find a DEVMODEA struct (it will use the WINEPS default
+     * one in case it is not there, so we are ok).
      */
     size = DocumentPropertiesW(0, -1, pi->pPrinterName, NULL, NULL, 0);
     if(size < 0) {
         FIXME("DocumentProperties fails\n");
 	size = sizeof(DEVMODEW);
     }
-    if(pi->pDevMode) {
+    if(pi->pDevMode)
         dmW = pi->pDevMode;
-    } else {
+    else {
 	dmW = HeapAlloc(GetProcessHeap(), 0, size);
 	dmW->dmSize = size;
-	DocumentPropertiesW(0, -1, pi->pPrinterName, dmW, NULL, DM_OUT_BUFFER);
+	if (0>DocumentPropertiesW(0,-1,pi->pPrinterName,dmW,NULL,DM_OUT_BUFFER)) {
+	    ERR("DocumentPropertiesW failed!\n");
+	    SetLastError(ERROR_UNKNOWN_PRINTER_DRIVER);
+	    return 0;
+	}
+	/* set devmode to printer name */
+	strcpyW(dmW->dmDeviceName,pi->pPrinterName);
     }
 
-    if(RegCreateKeyW(hkeyPrinters, pi->pPrinterName, &hkeyPrinter) !=
-       ERROR_SUCCESS) {
-        FIXME("Can't create printer %s\n", debugstr_w(pi->pPrinterName));
-	SetLastError(ERROR_INVALID_PRINTER_NAME);
-	RegCloseKey(hkeyPrinters);
-	if(!pi->pDevMode)
-	    HeapFree(GetProcessHeap(), 0, dmW);
-	return 0;
-    }
-    RegSetValueExA(hkeyPrinter, "Attributes", 0, REG_DWORD,
-		   (LPBYTE)&pi->Attributes, sizeof(DWORD));
-    RegSetValueExW(hkeyPrinter, DatatypeW, 0, REG_SZ, (LPBYTE)pi->pDatatype,
-		   0);
     /* Write DEVMODEA not DEVMODEW into reg.  This is what win9x does
        and we support these drivers.  NT writes DEVMODEW so somehow
        we'll need to distinguish between these when we support NT
@@ -1165,7 +1344,7 @@
     if (sz < sizeof(DEVMODEA))
     {
         ERR("corrupted registry for %s ( size %ld)\n",debugstr_w(ValueName),sz);
-        sz = sizeof(DEVMODEA);
+	return FALSE;
     }
     /* ensures that dmSize is not erratically bogus if registry is invalid */
     if (ptr && ((DEVMODEA*)ptr)->dmSize < sizeof(DEVMODEA))
Index: dlls/winspool/wspool.c
===================================================================
RCS file: /home/wine/wine/dlls/winspool/wspool.c,v
retrieving revision 1.5
diff -u -r1.5 wspool.c
--- dlls/winspool/wspool.c	2001/04/27 18:02:46	1.5
+++ dlls/winspool/wspool.c	2001/05/05 23:56:13
@@ -26,10 +26,8 @@
   switch (reason)
   {
     case DLL_PROCESS_ATTACH: {
-#ifdef HAVE_CUPS
-      extern void CUPS_LoadPrinters();
-      CUPS_LoadPrinters();
-#endif
+      extern void WINSPOOL_LoadSystemPrinters();
+      WINSPOOL_LoadSystemPrinters();
       break;
     }
     case DLL_PROCESS_DETACH:




More information about the wine-devel mailing list