OSDN Git Service

branch: yandytex with kpathsea.
[putex/putex.git] / src / texsourc / openinou.c
1 /* Copyright 1992 Karl Berry
2    Copyright 2007 TeX Users Group
3    Copyright 2014 Clerk Ma
4
5    This program is free software; you can redistribute it and/or modify
6    it under the terms of the GNU General Public License as published by
7    the Free Software Foundation; either version 2 of the License, or
8    (at your option) any later version.
9
10    This program is distributed in the hope that it will be useful, but
11    WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    General Public License for more details.
14
15    You should have received a copy of the GNU General Public License
16    along with this program; if not, write to the Free Software
17    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18    02110-1301 USA.  */
19
20 #ifdef _WINDOWS
21   #define NOCOMM
22   #define NOSOUND
23   #define NODRIVERS
24   #define STRICT
25   #pragma warning(disable:4115) // kill rpcasync.h complaint
26   #include <windows.h>
27   #define MYLIBAPI __declspec(dllexport)
28 #endif
29
30 #include "texwin.h"
31
32 #pragma warning(disable:4996)
33 #pragma warning(disable:4131) // old style declarator
34 #pragma warning(disable:4135) // conversion between different integral types
35 #pragma warning(disable:4127) // conditional expression is constant
36
37 #include <setjmp.h>
38
39 #include <direct.h>           /* for _getcwd() */
40
41 #define EXTERN extern
42
43 #include "texd.h"
44
45 #define PATH_SEP        '/'
46 #define PATH_SEP_STRING "/"
47
48 /* openinout.c: open input and output files. */
49
50 #define BUILDNAMEDIRECT         /* avoid malloc for string concat */
51
52 bool test_read_access (unsigned char *, int);   /* in ourpaths.c - bkph */
53
54 extern char *unixify (char *);      /* in pathsrch.c bkph */
55
56 extern void try_and_open (char *);    /* in local.c bkph */
57
58 extern int shorten_file_name;       /* in local.c bkph */
59
60 #ifdef FUNNY_CORE_DUMP
61 /* This is defined in ./texmf.c.  */
62 extern void funny_core_dump();
63 #endif /* FUNNY_CORE_DUMP */
64
65 #ifdef MSDOS
66
67 #ifdef BUILDNAMEDIRECT
68 /* kpathsea/concat.c */
69 /* kpathsea/concat3.c */
70 /* similar to concat, but AVOIDS using malloc, pass in place to put result */
71 char *xconcat (char *buffer, char *s1, char *s2)
72 {
73   int n1 = strlen(s1);
74   int n2 = strlen(s2);
75
76   if (buffer == s2)
77   {     /* treat special case of overlap */
78     memmove (buffer + n1, buffer, n2 + 1); /* trailing null ! */
79     strncpy (buffer, s1, n1);
80   }
81   else
82   {
83     strcpy(buffer, s1);
84     strcat(buffer + n1, s2);
85   }
86
87   return buffer;
88 }
89 /* similar to concat3, but avoids using malloc, pass in place to put result */
90 char *xconcat3 (char *buffer, char *s1, char *s2, char *s3)
91 {
92   int n1 = strlen(s1);
93   int n2 = strlen(s2);
94   int n3 = strlen(s3);
95
96   if (buffer == s3)
97   {     /* treat special case of overlap */
98     memmove (buffer + n1 + n2, buffer, n3 + 1); /* trailing null ! */
99     strncpy (buffer, s1, n1);
100     strncpy (buffer + n1, s2, n2);
101   }
102   else
103   {
104     strcpy(buffer, s1);
105     strcat(buffer + n1, s2);
106     strcat(buffer + n1 + n2, s3);
107   }
108   return buffer;
109 }
110 #endif /* end of BUILDNAMEDIRECT  */
111
112 #endif  /* end of ifdef MSDOS ??? */
113
114 #ifdef MSDOS
115 /* separated out 1996/Jan/20 to make easier to read */
116 /* assumes path does not end in PATH_SEP */
117 void patch_in_path (unsigned char *buffer, unsigned char *name, unsigned char *path)
118 {
119 #ifdef BUILDNAMEDIRECT
120   if (*path == '\0')
121     strcpy((char *) buffer, (char *) name);
122   else
123     xconcat3((char *) buffer, (char *) path, PATH_SEP_STRING, (char *) name);
124 #else
125   string temp_name;
126   temp_name = concat3 (path, PATH_SEP_STRING, name);
127   strcpy (buffer, temp_name);
128   free (temp_name);
129 #endif
130 }
131
132 int qualified (unsigned char * name)
133 {
134   if (strchr((char *) name, PATH_SEP) != NULL ||
135       strchr((char *) name, '\\') != NULL ||
136       strchr((char *) name, ':') != NULL)
137     return 1;
138   else
139     return 0;
140 }
141 /* patch path if 
142     (i)   path not empty
143     (ii)  name not qualified
144     (iii) ext match
145 */
146 int prepend_path_if (unsigned char *buffer, unsigned char *name, char *ext, unsigned char *path)
147 {
148   if (path == NULL)
149     return 0;
150
151   if (*path == '\0')
152     return 0;
153
154   if (qualified(name))
155     return 0;
156
157   if (strstr((char *)name, ext) == NULL)
158     return 0;
159
160   patch_in_path(buffer, name, path);
161
162   return 1;
163 }
164 #endif      /* end of MSDOS */
165
166 /*  Following works on null-terminated strings */
167
168 void check_short_name (unsigned char *s)
169 {
170   unsigned char *star, *sdot;
171   int n;
172
173   if ((star = (unsigned char *) strrchr((char *) s, '\\')) != NULL)
174     star++;
175   else if ((star = (unsigned char *) strrchr((char *) s, '/')) != NULL)
176     star++;
177   else if ((star = (unsigned char *) strchr((char *) s, ':')) != NULL)
178     star++;
179   else
180     star = s;
181
182   if ((sdot = (unsigned char *) strchr((char *) star, '.')) != NULL)
183     n = sdot - star;
184   else
185     n = strlen((char *) star);
186
187   if (n > 8)
188     strcpy((char *) star + 8, (char *) star + n);
189
190   if ((sdot = (unsigned char *) strchr((char *) star, '.')) != NULL)
191   {
192     star = sdot + 1;
193
194     n = strlen((char *) star);
195
196     if (n > 3)
197       *(star + 3) = '\0';
198   }
199 }
200
201 /* Following works on both null-terminated names */
202 /* reconvert 254 to '~' in file name 95/Sep/26 */
203 /* reconvert 255 to ' ' in file name 95/Sep/26 */
204 /* we do this in tex3.c start_input() -> scan_file_name() now 95/Sep/26 */
205 /* kpathsea/tilde.c */
206 void retwiddle (unsigned char *s)
207 {
208 /* assumes null terminated - 97/June/5 */
209 /*  while (*s != '\0' && *s != ' ') { */
210   while (*s != '\0')
211   {
212     if (*s == (unsigned char) pseudo_tilde)
213       *s = '~';
214     else if (*s == (unsigned char) pseudo_space)
215       *s = ' ';
216     s++;
217   }
218 }
219
220 /* #endif */ /* ??? */
221
222 /* Open an input file F, using the path PATHSPEC and passing
223    FOPEN_MODE to fopen.  The filename is in `name_of_file', as a Pascal
224    string. We return whether or not the open succeeded.  If it did, we
225    also set `name_length' to the length of the full pathname that we
226    opened.  */
227 /* in lib/openclose.c */
228 bool open_input (FILE **f, path_constant_type path_index, char *fopen_mode)
229 {
230   bool openable = false;
231
232 #if defined (FUNNY_CORE_DUMP) && !defined (BibTeX)
233   if (path_index == TEXINPUTPATH &&
234       strncmp (name_of_file + 1, "HackyInputFileNameForCoreDump.tex", 33) == 0)
235     funny_core_dump();
236 #endif /* FUNNY_CORE_DUMP and not BibTeX */
237
238 #ifdef MSDOS
239   if (return_flag)
240   {
241     if (strcmp(fopen_mode, "r") == 0)
242       fopen_mode = "rb";    /* so can catch `return' bkph */
243   }
244 #endif /* MSDOS */
245
246   name_of_file[name_length + 1] = '\0'; /* null terminate */
247
248 /* reinsert '~' and ' ' in file names -  95/June/5 */
249 /* done late to prevent problems with  null_terminate / space_terminate */  
250   if (pseudo_tilde != 0 || pseudo_space != 0)
251     retwiddle(name_of_file + 1);
252
253 #ifdef MSDOS
254 /* 8 + 3 file names on Windows NT 95/Feb/20 */
255   if (shorten_file_name)
256   {
257     check_short_name(name_of_file + 1);
258   }
259 #endif  /* MSDOS */
260   
261   if (open_trace_flag)
262   {
263     sprintf(log_line, " Open `%s' for input ", name_of_file + 1); /* Pascal */
264     show_line(log_line, 0);
265   }
266
267   if (test_read_access(name_of_file + 1, path_index))
268   {
269 /*  if (test_read_access(name_of_file, name_length, path_index)) */
270
271 /*    We can assume `name_of_file' is openable, */
272 /*    since `test_read_access' just returned true.  */
273 /*    *f = xfopen_pas (name_of_file, fopen_mode); */
274     *f = xfopen((char *) name_of_file + 1, fopen_mode);
275
276 //    should we check *f == NULL ??? (should be OK because of test_read_access)
277
278 /*    If we found the file in the current directory, don't leave the
279         `./' at the beginning of `name_of_file', since it looks dumb when
280         TeX says `(./foo.tex ...)', and analogously for Metafont.  */
281 #ifdef MSDOS
282     if (name_of_file[1] == '.' &&         /* 1994/Mar/1 */
283       (name_of_file[2] == PATH_SEP || name_of_file[2] == '\\'))
284 #else
285     if (name_of_file[1] == '.' && name_of_file[2] == PATH_SEP) 
286 #endif
287     {
288       unsigned i = 1;
289 /*        while (name_of_file[i + 2] != ' ') */
290       while (name_of_file[i + 2] != '\0')
291       {
292         name_of_file[i] = name_of_file[i + 2];
293         i++;
294       }
295 /*      name_of_file[i] = ' '; */
296       name_of_file[i] = '\0';
297       name_length = i - 1;
298     }
299     else
300 /*      name_length = strchr(name_of_file + 1, ' ') - (name_of_file + 1); */
301       name_length = strlen((char *) name_of_file + 1);
302       
303 #ifdef TeX
304 /*    If we just opened a TFM file, we have to read the first byte,
305         since TeX wants to look at it.  What a kludge.  */
306 /*    See comments in ctex.ch for why we need this.  */
307     if (path_index == TFMFILEPATH)
308     {
309       tfm_temp = getc (*f);
310     }
311 #endif /* TeX */  
312
313 #ifdef MSDOS
314 /*    code added 94/June/21 to show 'fmt' file opening in log */
315     if (strstr((char *) name_of_file + 1, ".fmt") != NULL)
316     {
317       if (format_file == NULL)
318       {
319         format_file = xstrdup((char *) name_of_file + 1);
320       }
321     } /* remember full format file name with path */
322     else if (strstr((char *)name_of_file+1, ".poo") != NULL)
323     {
324       if (string_file == NULL)
325       {
326         string_file = xstrdup((char *) name_of_file + 1);
327       }
328     } /* remember full pool file name with path */
329     else if (strstr((char *)name_of_file+1, ".tfm") != NULL)
330     {
331       if (show_tfm_flag && log_opened)
332       {
333 #ifdef WRAPLINES
334         int old_setting = selector;
335         char *s = name_of_file + 1;
336         selector = log_only;
337         print_char(' ');
338         print_char('(');
339
340         while (*s != '\0')
341           print_char (*s++);
342
343         print_char(')');
344         selector = old_setting;
345 #else
346         int n; 
347         n = strlen((char *) name_of_file + 1);
348
349         if (file_offset + n > max_print_line)
350         {
351           putc('\n', log_file);
352           file_offset = 0;
353         } /* somewhat risky ? */
354         else
355           putc(' ', log_file);
356
357         fprintf(log_file, "(%s)", name_of_file + 1);
358         file_offset += n+3;
359 /*        space_terminate (name_of_file + 1);  */
360 #endif  /*  end of WRAPLINES */
361       }
362     }
363 /*    code added 98/Sep/29 to catch first file input */
364 /*    is there a problem if this file bombs ? */
365     else if (source_direct == NULL) /* 98/Sep/29 */
366     {
367       char *s;
368
369       source_direct = xstrdup((char *) name_of_file + 1);
370
371       if (trace_flag)
372       {
373         sprintf(log_line, "Methinks the source %s is `%s'\n", "file", source_direct);
374         show_line(log_line, 0);
375       }
376
377       if ((s = strrchr(source_direct, '/')) == NULL)
378         *source_direct = '\0';
379       else
380         *(s+1) = '\0';
381
382       if (trace_flag)
383       {
384         sprintf(log_line, "Methinks the source %s is `%s'\n", "directory", source_direct);
385         show_line(log_line, 0);
386       }
387     }
388 #endif  /* end of MSDOS */
389     openable = true;
390   }
391 /*  space_terminate (name_of_file + 1); */
392   {
393     unsigned temp_length = strlen((char *) name_of_file + 1);
394     name_of_file[temp_length + 1] = ' ';  /* space terminate */
395 /*    set up name_length ??? */
396   }
397
398   return openable;
399 }
400
401 /* Call the external program PROGRAM, passing it `name_of_file'.  */
402 /* This nonsense probably only works for Unix anyway. bkph */
403 /* For one thing, MakeTeXTFM etc is more than 8 characters ! */
404
405 #ifdef MSDOS
406   #define NO_MAKETEX
407 #endif
408
409 #define TEXONLY
410
411 char *get_env_shroud (char *);    /* defined in texmf.c */
412
413 /* char outputdirectory[PATH_MAX]; */       /* defined in local.c */
414
415 extern char * dvi_directory; /* defined in local.c */
416 extern char * log_directory; /* defined in local.c */
417 extern char * aux_directory; /* defined in local.c */
418 extern char * fmt_directory; /* defined in local.c */
419 extern char * pdf_directory; /* defined in local.c */
420
421 /* At least check for I/O error (such as disk full) when closing */
422 /* Would be better to check while writing - but this is better than nothing */
423 /* This is used for both input and output files, but never mind ... */
424
425 /* now a_close returns -1 on error --- which could be used by caller */
426 /* probably want to ignore on input files ... */
427
428 void perrormod (char *s);       /* in local.c */
429
430 // check_fclose not used by anything
431 /* 1993/Nov/20 - bkph */
432 int check_fclose (FILE * f)
433 {
434   if (f == NULL)
435     return 0;      // sanity check
436
437   if (ferror(f) || fclose (f))
438   {
439     perrormod("\n! I/O Error");
440     uexit (1);    // ???
441   }
442
443   return 0;
444 }
445
446 /* open_output moved down here to avoid potential pragma problem */
447
448 bool open_output (FILE **f, char *fopen_mode)
449 {
450   unsigned temp_length;
451
452   name_of_file[name_length + 1] = '\0'; /* null terminate */
453
454   if (pseudo_tilde != 0 || pseudo_space !=  0)
455   {
456     retwiddle(name_of_file + 1);
457   }
458
459 #ifdef MSDOS
460 /* 8 + 3 file names on Windows NT 95/Feb/20 */
461   if (shorten_file_name)
462   {
463     check_short_name(name_of_file + 1);
464   }
465 #endif
466
467 #ifdef MSDOS
468
469   if (prepend_path_if (name_of_file + 1, name_of_file + 1, ".dvi", (unsigned char *) dvi_directory) ||
470       prepend_path_if (name_of_file + 1, name_of_file + 1, ".log", (unsigned char *) log_directory) ||
471       prepend_path_if (name_of_file + 1, name_of_file + 1, ".aux", (unsigned char *) aux_directory) ||
472       prepend_path_if (name_of_file + 1, name_of_file + 1, ".fmt", (unsigned char *) fmt_directory) ||
473       prepend_path_if (name_of_file + 1, name_of_file + 1, ".pdf", (unsigned char *) pdf_directory))
474   {
475     if (open_trace_flag)
476     {
477       sprintf(log_line, "After prepend %s\n", name_of_file+1);
478       show_line(log_line, 0);
479     }
480   }
481 #endif
482
483   if (open_trace_flag)
484   {
485     sprintf(log_line, " Open `%s' for output ", name_of_file + 1);
486     show_line(log_line, 0);
487   }
488
489 /* Is the filename openable as given?  */
490
491 /*  if share_flag is non-zero and we are opening for reading use fsopen */
492 /*  but we can assume this is opening here for *output* */
493   *f = fopen((char *) name_of_file + 1, fopen_mode);
494
495 /* Can't open as given.  Try the envvar.  */
496   if (*f == NULL)
497   {
498     string temp_dir = get_env_shroud ("UFYNGPVU");
499
500 /*    if (deslash) unixify(temp_dir); */    /* deslashify 93/Dec/28 */
501
502     if (temp_dir != NULL)
503     {
504 #ifdef BUILDNAMEDIRECT
505       unsigned char temp_name[PATH_MAX];
506       xconcat3((char *) temp_name, temp_dir, PATH_SEP_STRING, (char *) name_of_file + 1);
507 #else
508 /*    string temp_name = concat3 (temp_dir, "/", name_of_file + 1); */
509       string temp_name = concat3 (temp_dir, PATH_SEP_STRING, name_of_file + 1);
510 #endif
511       if (deslash)
512         unixify((char *) temp_name);     /* deslashify 93/Dec/28 */
513 /*  If share_flag is non-zero and we are opening for reading use fsopen */
514 /*  but we can assume this is opening here for *output* */
515       *f = fopen((char*)temp_name, fopen_mode);
516 /*  If this succeeded, change name_of_file accordingly.  */
517       if (*f)
518         strcpy((char*) name_of_file + 1, (char *) temp_name);
519 #ifndef BUILDNAMEDIRECT
520       free (temp_name);
521 #endif
522     }
523   }
524
525   if (strstr((char *) name_of_file + 1, ".dvi") != NULL)
526   {
527     if (qualified(name_of_file + 1))
528       *log_line = '\0';
529     else
530     {
531       (void) _getcwd(log_line, sizeof(log_line));
532       strcat(log_line, PATH_SEP_STRING);
533     }
534
535     strcat(log_line, (char*) name_of_file + 1);
536     unixify(log_line);
537     dvi_file_name = xstrdup(log_line);
538   }
539   else if (strstr((char *)name_of_file + 1, ".log") != NULL)
540   {
541     if (qualified(name_of_file + 1))
542       *log_line = '\0';
543     else
544     {
545       (void) _getcwd(log_line, sizeof(log_line));
546       strcat(log_line, PATH_SEP_STRING);
547     }
548
549     strcat(log_line, (char *) name_of_file + 1);
550     unixify(log_line);
551     log_file_name = xstrdup(log_line);
552   }
553
554   temp_length = strlen ((char *)name_of_file + 1);
555   name_of_file[temp_length+1] = ' ';
556
557   if (*f)
558     name_length = temp_length;
559   
560   return *f != NULL;
561 }