1 /*
2    miscutil.cpp : This file is part of pstoedit
3    misc utility functions
4 
5    Copyright (C) 1998 Wolfgang Glunz, wglunz@geocities.com
6 
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 #include "miscutil.h"
23 
24 #include I_stdio
25 
26 // #ifdef _MSC_VER
27 // for getcwd ( at least for Visual C++)
28 
29 #if defined(unix) || defined(__unix__) || defined(_unix) || defined(__unix) || defined(__EMX__)
30 #include <unistd.h>
31 #else
32 #include <direct.h>
33 #endif
34 
35 #include I_stdlib
36 
37 #include I_string_h
38 
39 
40 #if defined(_WIN32)
41 	#include <windows.h>
42 #elif defined (__OS2__)
43         #define INCL_DOS
44         #define INCL_WINWINDOWMGR
45         #define INCL_WINSHELLDATA       /* Window Shell functions       */
46         #define INCL_WINERRORS
47         #include <os2.h>
48 #endif
49 
50 
51 #if defined(unix) || defined(__unix__) || defined(_unix) || defined(__unix)
52 //take this out (we may have backslashes w/ EMX(OS/2)):  || defined(__EMX__)
convertBackSlashes(char * string)53 void convertBackSlashes(char* string) { unused(string); }
54 // nothing to do on systems with unix style file names ( / for directories)
55 #else
convertBackSlashes(char * string)56 void convertBackSlashes(char* string) {
57 
58     char* c;
59 
60     while ((c = strchr(string,'\\')) != NULL)
61        *c = '/';
62 }
63 #endif
64 
65 #if defined(__STRICT_ANSI__)
66 // normally this is in stdio.h except if __STRICT_ANSI__ is defined (GNU specific)
67 extern "C" char *tempnam(const char *, const char *pfx);
68 #endif
69 
70 #if defined(riscos)
71 // rcw2: tempnam doesn't seem to be defined in UnixLib 3.7b for RiscOS
tempnam(const char *,const char * pfx)72 char *tempnam(const char *, const char *pfx)
73 {
74 	char tmp[1024];
75 
76 	strcpy(tmp,"<Wimp$ScrapDir>.");
77 	strcat(tmp,pfx);
78 	return strdup(tmp);
79 }
80 #endif
81 
82 #ifdef __WATCOMC__
83 // tempnam doesn't seem to be defined in Watcoms clibs
tempnam(const char *,const char * pfx)84 char *tempnam(const char *, const char *pfx)
85 {
86 	const char* path;
87 	char		tmp[1024];
88 
89 	// simply take c: as temp dir, if environment not defined
90 	if( (path=getenv("TEMP")) == 0L &&
91 		(path=getenv("TMP")) == 0L )
92 	{
93 		strcpy(tmp,"C:\\");
94 	}
95 	else
96 	{
97 		// take temp dir from environment
98 		strcpy(tmp,path);
99 		strcat(tmp,"\\");
100 	}
101 
102 	strcat(tmp,pfx);
103 
104 	// remove all backslashes
105 	convertBackSlashes(tmp);
106 
107 	return strdup(tmp);
108 }
109 #endif
110 
111 // #define BUGGYTEMPNAM
112 
113 #if defined(DJGPP) && defined(BUGGYTEMPNAM)
114 // tempnam under DJGPP behaves different than on all other systems
tempnam(const char *,const char * pfx)115 char *tempnam(const char *, const char *pfx)
116 {
117 	return strdup(tmpnam(0));
118 }
119 #endif
120 
full_qualified_tempnam(const char * pref)121 char * full_qualified_tempnam(const char * pref)
122 {
123 #if defined (__BCPLUSPLUS__) || defined (__TCPLUSPLUS__)
124 /* borland has a prototype that expects a char * as second arg */
125 	char * filename = tempnam(0,(char *) pref);
126 #else
127 	char * filename = tempnam(0,pref);
128 #endif
129 	// W95: Fkt. tempnam() erzeugt Filename+Pfad
130 	// W3.1: es wird nur der Name zurueckgegeben
131 
132 // rcw2: work round weird RiscOS naming conventions
133 #ifdef riscos
134 	return filename;
135 #else
136 	convertBackSlashes(filename);
137 	if ( (strchr(filename,'\\')==0) &&
138 	     (strchr(filename,'/') ==0) ) { // keine Pfadangaben..
139 		char cwd[400];
140 		getcwd(cwd,400);
141 		char * result = new char [strlen(filename) + strlen(cwd) + 2];
142 		strcpy(result,cwd);
143 		strcat(result,"/");
144 		strcat(result,filename);
145 		free(filename);
146 		return result;
147 	} else {
148 		return filename;
149 	}
150 #endif
151 }
152 
153 // a strdup which uses new instead of malloc
cppstrdup(const char * src)154 char * cppstrdup(const char * src)
155 {
156 	char * ret = new char [strlen(src) + 1];
157 	strcpy(ret,src);
158 	return ret;
159 }
160 
161 #if defined(_WIN32)
tryregistry(HKEY hKey,LPCSTR subkeyn,LPCSTR key)162 char * tryregistry(HKEY hKey,LPCSTR subkeyn, LPCSTR key)
163 {
164 	HKEY subkey;
165 	const long ret = RegOpenKeyEx (
166 		hKey, // HKEY_LOCAL_MACHINE, //HKEY hKey,
167 		subkeyn, // LPCSTR lpSubKey,
168 		0L , // DWORD ulOptions,
169 		KEY_READ , // REGSAM samDesired,
170 		&subkey //PHKEY phkResult
171     );
172 	if ( ret !=  ERROR_SUCCESS) {
173 		// errstream << "RegOpenKeyEx failed with error code " << ret << endl;
174 		return 0;
175 	} else {
176 		const int maxvaluelength = 1000;
177 		BYTE value[maxvaluelength];
178 		DWORD bufsize = maxvaluelength;
179 		DWORD valuetype ;
180 		const long retv = RegQueryValueEx (
181 				subkey, // HKEY_LOCAL_MACHINE, //HKEY hKey,
182 				key, // "SOFTWARE\\wglunz\\pstoedit\\plugindir", //LPCSTR lpValueName,
183 				NULL, // LPDWORD lpReserved,
184 				&valuetype, // LPDWORD lpType,
185 				value, // LPBYTE lpData,
186 				&bufsize // LPDWORD lpcbData
187 				);
188 		RegCloseKey(subkey);
189 		if ( retv !=  ERROR_SUCCESS) {
190 //			errstream << "RegQueryValueEx failed with error code " << retv << endl;
191 			return 0;
192 		} else {
193 //			errstream << "result is " << dirname << endl;
194 			return cppstrdup( (const char *) value);
195 		}
196 	}
197 }
198 
199 #endif
200 
201 #ifdef __OS2__
202 #include "getini.c"
203 #endif
204 
getRegistryValue(ostream & errstream,const char * typekey,const char * key)205 char * getRegistryValue(ostream& errstream, const char * typekey, const char * key) {
206 #if defined(_WIN32)
207 
208 //	CString subkey = CString("SOFTWARE\\wglunz\\") + CString(product);
209 	char subkeyn[1000];
210 	subkeyn[0] = '\0';
211 	strcat(subkeyn,"SOFTWARE\\wglunz\\");
212 	strcat(subkeyn,typekey);
213 	char * result = tryregistry(HKEY_CURRENT_USER,subkeyn,key);
214 	if (!result) result = tryregistry(HKEY_LOCAL_MACHINE ,subkeyn,key);
215 	return result;
216 #elif defined (__OS2__)
217 	//query a "real" OS/2 profile pstoedit.ini
218 	HINI  hini;
219 	HAB   hab;
220 	char pszFileName [1000];
221         const char inifilename[] = "pstoedit.ini";
222 	APIRET  rc;
223 	char  buffer[1000];
224 
225 	hab  = WinInitialize( 0 );
226 
227         getini(0,errstream,pszFileName,inifilename,
228  	       (int)sizeof(pszFileName));
229 	hini = PrfOpenProfile( hab, pszFileName);
230 	rc=PrfQueryProfileString( hini, typekey, key,
231 				  NULL, (PVOID)buffer, (LONG)sizeof(buffer));
232 	PrfCloseProfile(hini);
233 	WinTerminate(hab);
234 
235 	if (rc)
236 	  {
237 	    char * r = cppstrdup(buffer);
238 	    return r;
239 	  }
240 	else return 0;
241 #else
242 //
243 // UNIX version
244 // Just ask the environment
245 //
246 #if 0
247 //getenv version
248 	char envname[1000];
249 	envname[0] = '\0';
250 	strcat(envname,typekey);
251 	strcat(envname,"_");
252 	strcat(envname,key);
253 //	cout << "checking " << envname << endl;
254 	char * envvalue = getenv(envname);
255 	if (envvalue != 0) {
256 		char * r = cppstrdup(envvalue);
257 //		cout << "found " << r << endl;
258 		return r;
259 	} else	return 0;
260 #else
261 	char envname[1000];
262 	envname[0] = '\0';
263 	strcat(envname,typekey);
264 	strcat(envname,"/");
265 	strcat(envname,key);
266 //	cout << "checking " << envname << endl;
267 	const char * homedir = getenv("HOME");
268 	if (!homedir) return 0;
269 	const int len = strlen(homedir) + 20;
270 	char * obuf = new char[len ];
271 	strcpy(obuf,homedir);
272 	strcat(obuf,"/.pstoedit.reg");
273 	ifstream regfile(obuf);
274 //	cout << "opened " << obuf << endl;
275 	delete []obuf;
276 	if (!regfile) return 0;
277 	char line [1000];
278 	while (!regfile.eof()) {
279 		regfile.getline(line,1000);
280 //		cout << line << endl;
281 		if (strstr(line,envname)) {
282 			char * r = cppstrdup(line+strlen(envname)+1);
283 			char * cr = strrchr(r,'\r');
284 			if (cr) *cr = 0;
285 //			cout << "found " << r << endl;
286 			return r;
287 		}
288 	}
289 	return 0;
290 #endif
291 #endif
292 }
293 
copy_file(istream & infile,ostream & outfile)294 void copy_file(istream& infile,ostream& outfile)
295 {
296 #if 1
297 	outfile << infile.rdbuf();
298 #else
299 // long version. should do the same as above
300 	unsigned char c;
301 	while (infile.get(c)) {
302 		outfile.put(c);
303 	}
304 #endif
305 }
306 
operator <<(ostream & out,const Argv & a)307 ostream & operator <<(ostream & out, const Argv & a)
308 {
309 	for (unsigned int i = 0; i < (unsigned) a.argc; i++) {
310 		out << a.argv[i]; out << endl;
311 	}
312 	return out;
313 }
314 
315 
TempFile()316 TempFile::TempFile()
317 {
318 	tempFileName = tempnam(0,"pstmp");
319 	// cout << "constructed " << tempFileName << endl;
320 }
321 
~TempFile()322 TempFile::~TempFile()
323 {
324 	// cout << "detructed " << tempFileName << endl;
325 	close();
326 	remove(tempFileName);
327 	free(tempFileName);
328 }
329 
asOutput()330 ofstream & TempFile::asOutput()
331 {
332 	close();
333 	outFileStream.open(tempFileName);
334 	if (outFileStream.fail()) cerr << "openening " << tempFileName << "failed " << endl;
335 	return outFileStream;
336 }
337 
asInput()338 ifstream & TempFile::asInput()
339 {
340 	close();
341 	inFileStream.open(tempFileName);
342 	if (outFileStream.fail()) cerr << "openening " << tempFileName << "failed " << endl;
343 	return  inFileStream;
344 }
345 
close()346 void TempFile::close()
347 {
348 //#ifdef HAVE_IS_OPEN
349 //#define IS_OPEN(file) file.is_open()
350 //#else
351 //#define IS_OPEN(file) file
352 //#endif
353 // commented, since it also works portably if we call clear()
354 
355 //	if (IS_OPEN(inFileStream))  {
356 		inFileStream.close();
357 //		if (inFileStream.fail()) cerr << "closing inFileStream failed " << endl;
358 //	}
359 	inFileStream.clear();
360 //	if (IS_OPEN(outFileStream))  {
361 		outFileStream.close();
362 //		if (outFileStream.fail()) cerr << "closing outFileStream  failed " << endl;
363 //	}
364 	outFileStream.clear();
365 }
366 
367 
368 #if 0
369 void freeconst(const void *ptr)
370 {
371 	free((char *)ptr); // just to have the warning about casting away constness
372 		   // once (here)
373 }
374 #endif
375 
P_GetPathToMyself(const char * name,char * returnbuffer,unsigned long buflen)376 unsigned long P_GetPathToMyself(const char *name,char * returnbuffer, unsigned long buflen)
377 {
378 #if defined(_WIN32)
379 	return	GetModuleFileName(GetModuleHandle(name),returnbuffer,buflen);
380 #elif defined (__OS2__)
381 	PTIB pptib;
382 	PPIB pppib;
383         APIRET rc;
384 	if ( (rc=DosGetInfoBlocks(&pptib, &pppib)) == 0 )
385 	  if ( (rc=DosQueryModuleName(pppib->pib_hmte, buflen,
386 				      returnbuffer)) == 0 )
387 	    return strlen(returnbuffer);
388 	  else
389 	    return 0;
390 	else
391 	  return 0;
392 #else
393 	if (*name == '/' ) { // starts with /
394 		strcpy(returnbuffer,name);
395 		return strlen(returnbuffer);
396 	} else {
397 		const char * EnvPath = getenv("PATH");
398 		if (!EnvPath) return 0;
399 		char * path = cppstrdup(EnvPath);
400 		char * colon = path;
401 		char * lastbegin = path;
402 		while (*colon) {
403 			while (*colon && (*colon !=':')) colon++;
404 			if (*colon) {
405 				*colon='\0';
406 				RSString test(lastbegin);
407 				test+="/";
408 				test+=name;
409 				if (fileExists(test.value())) {
410 					strcpy(returnbuffer,test.value());
411 					delete [] path;
412 					return strlen(returnbuffer);
413 				}
414 			}
415 			colon++;
416 			lastbegin=colon;
417 		}
418 		delete [] path;
419 	}
420 	return 0; // not found
421 #endif
422 }
423 
errorMessage(const char * text)424 void errorMessage(const char * text)
425 {
426 #if defined(_WIN32)
427 	MessageBox(NULL, text, "pstoedit", MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
428 #else
429 	cerr << text << endl;
430 #endif
431 }
432 
433 // a very very simple resizing string
RSString(const char * arg)434 RSString::RSString(const char * arg) :
435 			content(0),
436 			allocatedLength(0) {
437 				if (arg) this->copy(arg);
438 				// cerr << "{ constructed" << (void*) this << endl;
439 		}
RSString(const RSString & s)440 RSString::RSString(const RSString & s) : content(0),allocatedLength(0) {
441 			assert(this != &s);
442 			this->copy(s.value());
443 		}
444 
newContent(unsigned int size)445 char * RSString::newContent(unsigned int size) {
446 	return new char[size];
447 }
448 
clearContent()449 void RSString::clearContent() {
450 	delete [] content;
451 	content = 0;
452 }
453 
~RSString()454 RSString::~RSString() {
455 			// cerr << (void*) this << "deleted }" << endl;
456 			clearContent();
457 			allocatedLength = 0;
458 }
459 
operator +=(const RSString & rs)460 const RSString& RSString::operator+= (const RSString &rs) {
461 	unsigned int newlen = strlen(content)+ strlen(rs.content) + 1;
462 	char * newstring = newContent(newlen);
463 	strcpy(newstring,content);
464 	strcat(newstring,rs.content);
465 	clearContent();;
466 	content = newstring;
467 	allocatedLength = newlen;
468 	return *this;
469 }
470 //		const char * value() const { return content; }
copy(const char * src)471 void RSString::copy(const char *src) {
472 //			cerr << "copy " << src << " to " << (void *) this << endl;
473 			if ( content && ((strlen(src)+1) <= allocatedLength)) {
474 				// we have enough space
475 				::strcpy(content,src);
476 			} else {
477 				// resize
478 //				cerr << "content before delete is " << (void *) content << endl;
479 				clearContent();
480 				allocatedLength = strlen(src) + 1;
481 				content = newContent(allocatedLength);
482 //				cerr << "content after new is " << (void *) content << endl;
483 				::strcpy(content,src);
484 			}
485 		}
486 
fileExists(const char * filename)487 bool fileExists (const char * filename)
488 {
489 #ifdef HAVESTL
490 	std::ifstream test(filename);
491     return test.is_open();
492 #else
493 	ifstream test(filename, ios::in	| ios::nocreate);
494 	// MSVC neede ios::nocreate if used for testing whether file exists
495 	return  test ? true : false;
496 #endif
497 }
498 
499 
500 //FontMapper::~FontMapper() {
501 	// cerr << "destroying FontMapper" << endl;
502 
503 //}
504 
skipws(char * & lineptr)505 static void skipws(char * & lineptr) {
506 	while ((*lineptr != '\0') && (*lineptr == ' ') || (*lineptr == '\t')) lineptr++;
507 	return ;
508 }
509 
readword(char * & lineptr)510 static char * readword( char * & lineptr) {
511 	char * result = 0;
512 	if (*lineptr == '"') {
513 		result = strtok(lineptr,"\"");
514 	} else {
515 		result = strtok(lineptr,"\t ");
516 	}
517 	if (result) {
518 		lineptr = result + strlen(result) + 1;
519 	}
520 	return result;
521 }
522 
readMappingTable(ostream & errstream,const char * filename)523 void FontMapper::readMappingTable(ostream & errstream, const char * filename)
524 {
525 	if (!fileExists(filename)) {
526 		errstream << "Could not open font map file " << filename << endl;
527 		return;
528 	}
529 	ifstream inFile(filename);
530 	const int linesize = 255;
531 	char line[linesize];
532 	char save[linesize];
533 	unsigned int linenr = 0;
534 	while (!inFile.getline(line,linesize).eof()) {
535 		linenr++;
536 		strcpy(save,line);
537 #ifdef HAVESTL
538 		// Notes regarding ANSI C++ version (from KB)
539 		// istream::get( char* pch, int nCount, char delim ) is different in three ways:
540 		// When nothing is read, failbit is set.
541 		// An eos is always stored after characters extracted (this happens regardless of the outcome).
542 		// A value of -1 for nCount is an error.
543 
544 		// If the line contains just a \n then the failbit
545 		// is set in the ANSI version
546 		if (inFile.gcount() == 0) { inFile.clear(); continue; }
547 #endif
548 		if (line[0] == '%') continue;
549 		char * lineptr = line;
550 		//skip initial spaces
551 		skipws(lineptr);
552 		char * original = readword(lineptr);
553 		skipws(lineptr);
554 		char * replacement = readword(lineptr);
555 		if (original && replacement) {
556 			// errstream << "\"" << original << "\" \"" << replacement <<"\""<< endl;
557 			insert(original, replacement);
558 		} else {
559 			errstream << "wrongly formatted line(" << linenr << ") found in fontmap: " << save << endl;
560 		}
561 	}
562 }
563 
mapFont(const RSString & fontname)564 const char * FontMapper::mapFont(const RSString & fontname)
565 {
566 #if 0
567 	FontMapping * curEntry = firstEntry;
568 	// cerr << "Trying to remap font" << fontname << endl;
569 	while (curEntry != 0) {
570 		// cerr << "comparing with" << curEntry->original << endl;
571 		if (curEntry->original == RSString(fontname) ) {
572 			// cerr << "mapped to " << curEntry->replacement.value() << endl;
573 			return curEntry->replacement.value();
574 		}
575 		curEntry=curEntry->nextEntry;
576 	}
577 	return 0;
578 #endif
579 	const RSString * r = getValue(fontname);
580 	if (r) return r->value(); else return 0;
581 }
582 
583 
584