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 #3 0x409a46c9 in WINSPOOL_LoadSystemPrinters () at info.c:298 #4 0x409aac08 in WINSPOOL_EntryPoint (hInstance=1083838464, reason=1, lpReserved=0x1) at wspool.c:30 #5 0x40082ea7 in PE_InitDLL (module=1083838464, type=1, lpReserved=0x1) at pe_image.c:737 #6 0x4007eb75 in MODULE_InitDLL (wm=0x403a1aa0, type=1, lpReserved=0x1) at module.c:115 #7 0x4007ec92 in MODULE_DllProcessAttach (wm=0x403a1aa0, lpReserved=0x1) at module.c:182 #8 0x4007ec6c in MODULE_DllProcessAttach (wm=0x403a1598, lpReserved=0x1) at module.c:177 #9 0x4007ec6c in MODULE_DllProcessAttach (wm=0x0, lpReserved=0x1) at module.c:177 #10 0x400c83b1 in start_process () at process.c:372 #11 0x400cbeb5 in SYSDEPS_DoCallOnStack ( func=0x400c8270 <start_process>, arg=0x0) at sysdeps.c:173 #12 0x400cbf5f in SYSDEPS_CallOnStack () at sysdeps.c:183 #13 0x400cc002 in SYSDEPS_SwitchToThreadStack ( func=0x400c8270 <start_process>) at sysdeps.c:236 #14 0x400c87fb in PROCESS_InitWine (argc=2, argv=0xbffff8dc, win16_exe_name=0x804d620 "", win16_exe_file=0x804d724) at process.c:525 #15 0x0804c187 in main () at main.c:84 #16 0x40289177 in __libc_start_main (main=0x804c16c <main>, argc=2, ubp_av=0xbffff8dc, init=0x80486f8 <_init>, fini=0x804c1d0 <_fini>, rtld_fini=0x4000e184 <_dl_fini>, stack_end=0xbffff8cc) at ../sysdeps/generic/libc-start.c:129
I'm rebuilding now, with Marcus' LPR printing patch backed out.
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:
Marcus Meissner wrote:
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.
Thanks!