1 /* pstotxtd.c */
2 /* OS/2 and Win32 Command line interface to pstotxt[23].dll */
3 /* 8086 MS-DOS command line EXE. */
4 /* Russell Lang */
5 
6 /* derived from main.c */
7 /* Copyright (C) 1995, Digital Equipment Corporation.         */
8 /* All rights reserved.                                       */
9 /* See the file pstotext.txt for a full description.          */
10 /* Last modified on Fri Jan  9 21:11:00 AEST 2004 by rjl      */
11 /*      modified on Sat Mar 11 09:16:00 AEST 2000 by rjl      */
12 /*      modified on Fri Oct 16 16:30:54 PDT 1998 by mcjones   */
13 /*      modified on Thu Nov 16 13:33:13 PST 1995 by deutsch   */
14 
15 /* Modifications by rjl
16  *  Fixed compiler warnings.
17  */
18 
19 #ifndef MSDOS
20 #ifdef _Windows
21 #include <windows.h>
22 #include <io.h>
23 #ifndef __BORLANDC__
24 #define mktemp(t) _mktemp(t)
25 #endif
26 #else
27 #define INCL_DOS
28 #include <os2.h>
29 #endif
30 #endif
31 
32 #include <signal.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
36 
37 #ifdef MSDOS
38 #include <io.h>
39 #include <ctype.h>
40 #include "bundle.h"
41 #include "ocr.h"
42 #include "rot270.h"
43 #include "rot90.h"
44 typedef int HMODULE;
45 #endif
46 
47 #include "ptotdll.h"
48 
49 
50 #define BOOLEAN int
51 #define FALSE 0
52 #define TRUE 1
53 
54 #define LINELEN 2000 /* longest allowable line from gs ocr.ps output */
55 
56 /* resource IDs for pstotxt3.dll */
57 #define OCR_PROLOG 1
58 #define ROT270_PROLOG 2
59 #define ROT90_PROLOG 3
60 
61 static int cleanup(void);
62 static void do_it(char *path);
63 #define strcasecmp stricmp
64 #define MAXPATHLEN 256
65 static int debug = FALSE;
66 static int cork = FALSE;
67 #ifdef MSDOS
68 static char *gscommand = "gs386.exe";
69 #else
70 #ifdef _Windows
71 static char *gscommand = "gswin32c.exe";
72 #else
73 static char *gscommand = "gsos2.exe";
74 #endif
75 #endif
76 static char *outfile = "";
77 
78 static char *cmd; /* = argv[0] */
79 
80 static enum {
81   portrait,
82   landscape,
83   landscapeOther} orientation = portrait;
84 
85 static int bboxes = FALSE;
86 
87 static int explicitFiles = 0; /* count of explicit file arguments */
88 
usage(void)89 void usage(void) {
90   fprintf(stderr, "pstotext 1.8i of 2003-01-08\n");
91   fprintf(stderr, "Copyright (C) 1995-1998, Digital Equipment Corporation.\n");
92   fprintf(stderr, "Modified by Ghostgum Software Pty Ltd for Ghostscript 6.0.\n");
93   fprintf(stderr, "Comments to {mcjones,birrell}@pa.dec.com.\n\n");
94   fprintf(stderr, "Usage: %s [option|file]...\n", cmd);
95   fprintf(stderr, "Options:\n");
96   fprintf(stderr, "  -cork            Assume Cork encoding for dvips output\n");
97   fprintf(stderr, "  -landscape       rotate 270 degrees\n");
98   fprintf(stderr, "  -landscapeOther  rotate 90 degrees\n");
99   fprintf(stderr, "  -portrait        don't rotate (default)\n");
100   fprintf(stderr, "  -bboxes          output one word per line with bounding box\n");
101   fprintf(stderr, "  -debug           show Ghostscript output and error messages\n");
102   fprintf(stderr, "  -gs \042command\042    Ghostscript command\n");
103   fprintf(stderr, "  -output file     output results to \042file\042 (default is stdout)\n");
104   fprintf(stderr, "  -                read from stdin (default if no files specified)\n");
105 }
106 
107 #ifndef _Windows
108 #define WINAPI 		/* nothing for OS/2 or MSDOS */
109 #endif
110 
111 typedef int (WINAPI *PFN_pstotextInit)(void **instance);
112 typedef int (WINAPI *PFN_pstotextFilter)(void *instance, char *instr,
113     char **pre, char **word, char **post,
114     int *llx, int *lly, int *urx, int *ury);
115 typedef int (WINAPI *PFN_pstotextExit)(void *instance);
116 typedef int (WINAPI *PFN_pstotextSetCork)(void *instance, int value);
117 HMODULE pstotextModule;
118 void *pstotextInstance;
119 PFN_pstotextInit dllfn_pstotextInit;
120 PFN_pstotextFilter dllfn_pstotextFilter;
121 PFN_pstotextExit dllfn_pstotextExit;
122 PFN_pstotextSetCork dllfn_pstotextSetCork;
123 
124 #ifdef _Windows
125 int
load_pstotext(void)126 load_pstotext(void)
127 {
128 char dllname[256];
129 char *p;
130     /* get path to EXE */
131     GetModuleFileName(0, dllname, sizeof(dllname));
132     if ((p = strrchr(dllname,'\\')) != (char *)NULL)
133 	p++;
134     else
135 	p = dllname;
136     *p = '\0';
137 #ifdef __WIN32__
138 #ifdef DECALPHA
139     strcat(dllname, "pstotxta.dll");
140 #else
141     strcat(dllname, "pstotxt3.dll");
142 #endif
143 #else
144     strcat(dllname, "pstotxt1.dll");
145 #endif
146     if (debug) {
147 	fputs(dllname, stdout);
148 	fputc('\n', stdout);
149     }
150 
151 
152     /* load pstotext DLL */
153     pstotextModule = LoadLibrary(dllname);
154     if (pstotextModule < (HINSTANCE)HINSTANCE_ERROR) {
155 	fprintf(stderr, "Can't load %s\n", dllname);
156 	return 1;
157     }
158     dllfn_pstotextInit = (PFN_pstotextInit) GetProcAddress(pstotextModule, "pstotextInit");
159     if (dllfn_pstotextInit == (PFN_pstotextInit)NULL) {
160 	fprintf(stderr, "Can't find pstotextInit() in %s\n", dllname);
161 	FreeLibrary(pstotextModule);
162 	return 1;
163     }
164     dllfn_pstotextFilter = (PFN_pstotextFilter) GetProcAddress(pstotextModule, "pstotextFilter");
165     if (dllfn_pstotextFilter == (PFN_pstotextFilter)NULL) {
166 	fprintf(stderr, "Can't find pstotextFilter() in %s\n", dllname);
167 	FreeLibrary(pstotextModule);
168 	return 1;
169     }
170     dllfn_pstotextExit = (PFN_pstotextExit) GetProcAddress(pstotextModule, "pstotextExit");
171     if (dllfn_pstotextExit == (PFN_pstotextExit)NULL) {
172 	fprintf(stderr, "Can't find pstotextExit() in %s\n", dllname);
173 	FreeLibrary(pstotextModule);
174 	return 1;
175     }
176     dllfn_pstotextSetCork = (PFN_pstotextSetCork) GetProcAddress(pstotextModule, "pstotextSetCork");
177     if (dllfn_pstotextSetCork == (PFN_pstotextSetCork)NULL) {
178 	fprintf(stderr, "Can't find pstotextSetCork() in %s\n", dllname);
179 	FreeLibrary(pstotextModule);
180 	return 1;
181     }
182 
183     dllfn_pstotextInit(&pstotextInstance);
184 
185     return 0;
186 }
187 
188 int
unload_pstotext(void)189 unload_pstotext(void)
190 {
191     if (pstotextInstance)
192         dllfn_pstotextExit(pstotextInstance);
193     pstotextInstance = NULL;
194     FreeLibrary(pstotextModule);
195     pstotextModule = NULL;
196     return 0;
197 }
198 
199 void
send_prolog(FILE * f,int resource)200 send_prolog(FILE *f, int resource)
201 {
202     HGLOBAL hglobal;
203     LPSTR prolog;
204     hglobal = LoadResource(pstotextModule,
205 	FindResource(pstotextModule, (LPSTR)resource, RT_RCDATA));
206     if ( (prolog = (LPSTR)LockResource(hglobal)) != (LPSTR)NULL) {
207 	fputs(prolog, f);
208 	FreeResource(hglobal);
209     }
210 }
211 
212 #else /* !_Windows */
213 #ifdef MSDOS
214 int
load_pstotext(void)215 load_pstotext(void)
216 {
217     dllfn_pstotextInit = pstotextInit;
218     dllfn_pstotextFilter = pstotextFilter;
219     dllfn_pstotextExit = pstotextExit;
220     dllfn_pstotextSetCork = pstotextSetCork;
221     dllfn_pstotextInit(&pstotextInstance);
222     return 0;
223 }
224 
225 int
unload_pstotext(void)226 unload_pstotext(void)
227 {
228     return 0;
229 }
230 
231 void
send_prolog(FILE * f,int resource)232 send_prolog(FILE *f, int resource)
233 {
234     switch (resource) {
235 	case OCR_PROLOG:
236 	    putbundle(ocr, f);
237 	    break;
238 	case ROT270_PROLOG:
239 	    putbundle(rot270, f);
240 	    break;
241 	case ROT90_PROLOG:
242 	    putbundle(rot90, f);
243 	    break;
244     }
245 }
246 
247 #else /* !_Windows && !MSDOS */
248 /* OS/2 */
249 int
load_pstotext(void)250 load_pstotext(void)
251 {
252 char dllname[256];
253 char buf[256];
254 char *p;
255 APIRET rc;
256 PTIB pptib;
257 PPIB pppib;
258 
259     if ( (rc = DosGetInfoBlocks(&pptib, &pppib)) != 0 ) {
260 	fprintf(stderr,"Couldn't get pid, rc = \n", rc);
261 	return rc;
262     }
263 
264     /* get path to EXE */
265     if ( (rc = DosQueryModuleName(pppib->pib_hmte, sizeof(dllname), dllname)) != 0 ) {
266 	fprintf(stderr,"Couldn't get module name, rc = %d\n", rc);
267 	return rc;
268     }
269     if ((p = strrchr(dllname,'\\')) != (PCHAR)NULL) {
270 	p++;
271 	*p = '\0';
272     }
273     strcat(dllname, "pstotxt2.dll");
274     if (debug) {
275 	fputs(dllname, stdout);
276 	fputc('\n', stdout);
277     }
278 
279     /* load pstotext DLL */
280     if (DosLoadModule(buf, sizeof(buf), dllname, &pstotextModule)) {
281 	fprintf(stderr, "Can't load %s\n", dllname);
282 	return 1;
283     }
284     if ((rc = DosQueryProcAddr(pstotextModule, 0, "pstotextInit", (PFN *)(&dllfn_pstotextInit))) !=0) {
285 	fprintf(stderr, "Can't find pstotextInit() in %s\n", dllname);
286 	DosFreeModule(pstotextModule);
287 	pstotextModule = (HMODULE)NULL;
288 	return 1;
289     }
290     if ((rc = DosQueryProcAddr(pstotextModule, 0, "pstotextFilter", (PFN *)(&dllfn_pstotextFilter))) !=0) {
291 	fprintf(stderr, "Can't find pstotextFilter() in %s\n", dllname);
292 	DosFreeModule(pstotextModule);
293 	pstotextModule = (HMODULE)NULL;
294 	return 1;
295     }
296     if ((rc = DosQueryProcAddr(pstotextModule, 0, "pstotextExit", (PFN *)(&dllfn_pstotextExit))) !=0) {
297 	fprintf(stderr, "Can't find pstotextExit() in %s\n", dllname);
298 	DosFreeModule(pstotextModule);
299 	pstotextModule = (HMODULE)NULL;
300 	return 1;
301     }
302     if ((rc = DosQueryProcAddr(pstotextModule, 0, "pstotextSetCork", (PFN *)(&dllfn_pstotextSetCork))) !=0) {
303 	fprintf(stderr, "Can't find pstotextSetCork() in %s\n", dllname);
304 	DosFreeModule(pstotextModule);
305 	pstotextModule = (HMODULE)NULL;
306 	return 1;
307     }
308 
309     dllfn_pstotextInit(&pstotextInstance);
310 
311     return 0;
312 }
313 
314 int
unload_pstotext(void)315 unload_pstotext(void)
316 {
317     if (pstotextInstance)
318         dllfn_pstotextExit(pstotextInstance);
319     pstotextInstance = NULL;
320     if (pstotextModule)
321         DosFreeModule(pstotextModule);
322     pstotextModule = (HMODULE)NULL;
323     return 0;
324 }
325 
326 
327 int
send_prolog(FILE * f,int resource)328 send_prolog(FILE *f, int resource)
329 {
330 char *prolog, *p;
331 APIRET rc;
332 int code = -1;
333 	rc = DosGetResource(pstotextModule, RT_RCDATA, resource, (PPVOID)&prolog);
334 	if (!rc && (prolog != (char *)NULL) ) {
335 	    code = 0;
336 	    p = prolog;
337 	    while (*p) {
338 		if (!code)
339 		    fputs(p, f);
340 		p += strlen(p)+1;
341 	    }
342 	    DosFreeResource(prolog);
343 	}
344 	else {
345 	    fprintf(stderr, "Failed to load pstotext resource %d\n", resource);
346 	}
347 	return code;
348 }
349 #endif /* OS/2   (!MSDOS) */
350 #endif /* (!_Windows) */
351 
352 /* create an empty temporary file and return its name */
scratch_file(void)353 static char *scratch_file(void) {
354     FILE *f;
355     char *temp;
356     char *path = malloc(256);
357     if (path == NULL)
358 	return NULL;
359     if ( (temp = getenv("TEMP")) != NULL )
360 	strcpy(path, temp);
361     else if ( (temp = getenv("TMP")) != NULL )
362 	strcpy(path, temp);
363     else
364 	strcpy(path, "c:\\");
365 
366     /* Prevent X's in path from being converted by mktemp. */
367     for ( temp = path; *temp; temp++ ) {
368 	    *temp = (char)tolower(*temp);
369 	    if (*temp == '/')
370 		*temp = '\\';
371     }
372     if ( strlen(path) && (path[strlen(path)-1] != '\\') )
373 	    strcat(path, "\\");
374 
375     strcat(path, "ptXXXXXX");
376     mktemp(path);
377     f = fopen(path, "w");
378     if (f==NULL) {perror(cmd); exit(1);}
379     fclose(f);
380     return path;
381 }
382 
make_temp(int resource)383 static char *make_temp(int resource) {
384   /* Return pathname of temporary file containing prolog from resources.  Caller
385      should unlink file (and, technically, free pathname). */
386     FILE *f;
387     char *path = scratch_file();
388     if (path == NULL) {perror(cmd); cleanup(); exit(1);}
389 
390     f = fopen(path, "w");
391     if (f==NULL) {perror(cmd); cleanup(); exit(1);}
392 
393     send_prolog(f, resource);
394     fclose(f);
395     return path;
396 }
397 
398 
399 static char *ocr_path = NULL, *rotate_path = NULL;
400 static FILE *gs = NULL;
401 char *gstemp = NULL;
402 static void *instance; /* pstotext state */
403 
cleanup(void)404 static int cleanup(void) {
405   int status = 0;
406   unload_pstotext();
407   if (gs!=NULL) {
408 #if defined(_Windows) || defined(MSDOS)
409     fclose(gs);
410 #else
411     pclose(gs);
412 #endif
413   }
414   if (gstemp!=NULL && !debug)
415     unlink(gstemp);
416   if (rotate_path!=NULL && strcmp(rotate_path, "")!=0 && !debug)
417     unlink(rotate_path);
418   if (ocr_path!=NULL && !debug)
419      unlink(ocr_path);
420   return status;
421 }
422 
handler(int code)423 static void handler(int code) {
424   int status = code; /* suppress unreference 'code' warning */
425   status = cleanup();
426   if (status!=0)
427     exit(status);
428   exit(2);
429 }
430 
do_it(char * path)431 static void do_it(char *path) {
432   /* If "path" is NULL, then "stdin" should be processed. */
433   char gs_cmd[2*MAXPATHLEN];
434   char input[MAXPATHLEN];
435   int status;
436   FILE *fileout;
437 #ifdef MSDOS
438   char *gsargtemp;
439   FILE *gsargfile;
440 #endif
441 
442   fileout = stdout;
443   if (strlen(outfile) != 0) {
444     fileout = fopen(outfile, "w");
445     if (fileout == NULL) {perror(cmd); exit(1);}
446   }
447 
448   signal(SIGINT, handler);
449   signal(SIGTERM, handler);
450 
451   status = load_pstotext();
452   if (status!=0) {
453     fprintf(stderr, "%s: internal error %d\n", cmd, status);
454     exit(5);
455   }
456 
457   if (cork) {
458     status = dllfn_pstotextSetCork(pstotextInstance, TRUE);
459     if (status!=0) {
460       fprintf(stderr, "%s: internal error %d\n", cmd, status);
461       exit(5);
462     }
463   }
464 
465   ocr_path = make_temp(OCR_PROLOG);
466 
467   switch (orientation) {
468   case portrait: rotate_path = ""; break;
469   case landscape: rotate_path = make_temp(ROT270_PROLOG); break;
470   case landscapeOther: rotate_path = make_temp(ROT90_PROLOG); break;
471   }
472 
473   if (path==NULL) strcpy(input, "-");
474   else {strcpy(input, "-- "); strcat(input, path);}
475 
476 #if defined(_Windows) || defined(MSDOS)
477   /* don't support pipes, so write gs output to a temporary file */
478   if ( (gstemp = scratch_file()) == NULL) {
479 	cleanup();
480 	exit(1);
481   }
482 #endif
483 
484 #ifdef MSDOS
485   /* MSDOS has command line length problems */
486   if ( (gsargtemp = scratch_file()) == NULL) {
487 	cleanup();
488 	exit(1);
489   }
490   if ( (gsargfile = fopen(gsargtemp, "w")) == (FILE *)NULL) {
491 	cleanup();
492 	exit(1);
493   }
494   fprintf(gsargfile, "-r72 -dNODISPLAY -dFIXEDMEDIA -dDELAYBIND -dWRITESYSTEMDICT %s -dNOPAUSE\n",
495     (debug ? "" : "-q"));
496   fputs(rotate_path, gsargfile);
497   fputs("\n", gsargfile);
498   fputs(ocr_path, gsargfile);
499   fputs("\n", gsargfile);
500   fputs(input, gsargfile);
501   fputs("\n", gsargfile);
502   fclose(gsargfile);
503 
504   sprintf(gs_cmd, "%s @%s %s %s", gscommand, gsargtemp,
505 #if defined(_Windows) || defined(MSDOS)
506     "> ", gstemp
507 #else
508     "", ""
509 #endif
510     );
511 
512 #else   /* !MSDOS */
513   sprintf(gs_cmd, "%s -r72 -dNODISPLAY -dFIXEDMEDIA -dDELAYBIND -dWRITESYSTEMDICT %s -dNOPAUSE %s %s %s %s %s",
514     gscommand,
515     (debug ? "" : "-q"),
516     ocr_path,
517     rotate_path,
518     input,
519 #if defined(_Windows) || defined(MSDOS)
520     "> ", gstemp
521 #else
522     "", ""
523 #endif
524     );
525 #endif
526 
527   if (debug) {
528     fputs(gs_cmd, stdout);
529     fputc('\n', stdout);
530   }
531 
532 #if defined(_Windows) || defined(MSDOS)
533   if (system(gs_cmd)) {
534     fprintf(stderr,"\nCan't run (errno=%d):\n   %s\n", errno, gs_cmd);
535     cleanup();
536     exit(1);
537   }
538 
539   gs = fopen(gstemp, "r");
540 #else
541   gs = popen(gs_cmd, "r");
542 #endif
543 
544 #ifdef MSDOS
545   if (!debug)
546      unlink(gsargtemp);
547   free(gsargtemp);
548 #endif
549 
550   if( gs==NULL ) {perror(cmd); cleanup(); exit(1);}
551 
552   while (gs != NULL) {   /* while TRUE */
553     char line[LINELEN];
554     char *pre, *word, *post;
555     int llx, lly, urx, ury;
556     if (fgets(line, LINELEN, gs)==NULL) break;
557     if (debug)
558 	fputs(line, stdout);
559     status = dllfn_pstotextFilter(
560       pstotextInstance, line, &pre, &word, &post, &llx, &lly, &urx, &ury);
561     if (status!=0) {
562       fprintf(stderr, "%s: internal error %d\n", cmd, status);
563       cleanup();
564       exit(5);
565     }
566     if (word!=NULL)
567       if (!bboxes) {
568         fputs(pre, fileout); fputs(word, fileout); fputs(post, fileout);
569 	if (debug)
570 	    fputc('\n', stdout);
571       }
572       else {
573 	if (pre) {
574 	    if (*pre == ' ')
575 		pre++;
576 	    fputs(pre, fileout);
577 	}
578         fprintf(fileout, "%6d\t%6d\t%6d\t%6d\t%s\n", llx, lly, urx, ury, word);
579 	if (post)
580 	    fputs(post, fileout);
581       }
582   }
583   if (fileout != stdout) fclose(fileout);
584   status = cleanup();
585   if (status!=0) exit(status);
586 }
587 
main(int argc,char * argv[])588 int main(int argc, char *argv[]) {
589   int i;
590   char *arg;
591   cmd = argv[0];
592   for (i = 1; i<argc; i++) {
593     arg = argv[i];
594     if (strcasecmp(arg, "-landscape")==0) orientation = landscape;
595     else if (strcasecmp(arg, "-cork")==0) cork = TRUE;
596     else if (strcasecmp(arg, "-landscapeOther")==0) orientation = landscapeOther;
597     else if (strcasecmp(arg, "-portrait")==0) orientation = portrait;
598     else if (strcasecmp(arg, "-bboxes")==0) bboxes = TRUE;
599     else if (strcasecmp(arg, "-debug")==0) debug = TRUE;
600     else if (strcasecmp(arg, "-gs")==0) {
601 	i++;
602 	if (i<argc)
603 	    gscommand = argv[i];
604     }
605     else if (strcasecmp(arg, "-output") == 0) {
606 	i++;
607 	if (i>=argc) {usage(); exit(1);}
608 	outfile = argv[i];
609     }
610     else if (strcmp(arg, "-")==0) do_it(NULL);
611     else if (arg[0] == '-') {usage(); exit(1);}
612     else /* file */ {
613       explicitFiles++;
614       do_it(arg);
615     }
616   }
617   if (explicitFiles==0) do_it(NULL);
618   return 0;
619 }
620