OSDN Git Service

fixed call_edit().
[putex/putex.git] / src / texsourc / yandytex.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 #define EXTERN
21
22 #include "yandytex.h"
23
24 #define dump_ext_length     4
25 #define edit_value          tex_edit_value
26
27 extern char * replacement[];
28 int    gargc;
29 char **gargv;
30
31 int jump_used = 0;
32
33 jmp_buf jumpbuffer;
34
35 int main (int ac, char *av[])
36 {
37   int flag = 0, ret = 0;
38
39   gargc = ac;
40   gargv = av;
41
42   if (main_init(gargc, gargv))
43     return -1;
44
45   TEX_format_default = " plain.fmt";
46   format_default_length = strlen(TEX_format_default + 1);
47
48   jump_used = 0;
49
50   ret = setjmp(jumpbuffer);
51
52   if (ret == 0)
53   {
54     flag = main_program();
55
56     if (trace_flag)
57       printf("EXITING at %s: flag = %d, ret = %d, jump_used = %d\n", "main", flag, ret, jump_used);
58   }
59   else
60   {
61     if (trace_flag)
62       printf("EXITING at %s: flag = %d, ret = %d, jump_used =  %d\n", "jump_out", flag, ret, jump_used);
63   }
64
65   if (endit(flag) != 0)
66     flag = 1; /* do final clean up in local.c */
67
68   if (flag == 0)
69     return 0;
70   else
71     exit (flag);
72 }
73
74 /* texk/web2c/lib/texmfmp.c */
75 void t_open_in (void)
76 {
77   int i;
78
79   buffer[first] = 0;
80
81   if (gargc > optind && optind > 0)
82   {
83     for (i = optind; i < gargc; i++)
84     {
85       if (allow_quoted_names && strchr(gargv[i], ' ') != NULL)
86       {
87         (void) strcat ((char *) &buffer[first], "\"");
88         (void) strcat ((char *) &buffer[first], gargv[i]);
89         (void) strcat ((char *) &buffer[first], "\"");
90       }
91       else
92         (void) strcat ((char *) &buffer[first], gargv[i]);
93
94       (void) strcat ((char *) &buffer[first], " ");
95     }
96     
97     gargc = 0;
98   }
99
100   /* Find the end of the buffer.  */
101   for (last = first; buffer[last]; ++last)
102     do_nothing();
103
104   for (--last; last >= first && ISBLANK (buffer[last]) && buffer[last] != '\r'; --last)
105     do_nothing();
106
107   last++;
108
109 /* One more time, this time converting to TeX's internal character
110    representation.  */ /* for command line input in this case */
111   if (non_ascii)
112   {
113     for (i = first; i < last; i++)
114       buffer[i] = xord[buffer[i]];
115   }
116 }
117
118 static void catch_interrupt (int err)
119 {
120   (void) err;
121   (void) signal(SIGINT, SIG_IGN);
122
123   if (interrupt++ >= 3)
124     exit(1);
125
126   (void) signal(SIGINT, catch_interrupt);
127 }
128
129 void fix_date_and_time (void)
130 {
131   time_t clock;
132   struct tm *tmptr;
133
134   (void) time(&clock);
135
136   if (trace_flag)
137     printf("The time is %lld\n", (long long)clock);
138
139   if (clock < 0)
140     puts("Time not available!");
141
142   tmptr = localtime (&clock);
143
144   if (tmptr == NULL)
145   {
146     printf("Cannot convert time (%0lld)!\n", (long long)clock);
147     year     = 2038;
148     month    = 1;
149     day      = 18;
150     tex_time = 22 * 60 + 14;
151   }
152   else
153   {
154     tex_time = tmptr->tm_hour * 60 + tmptr->tm_min;
155     day      = tmptr->tm_mday;
156     month    = tmptr->tm_mon + 1;
157     year     = tmptr->tm_year + 1900;
158
159     if (trace_flag)
160       printf("%d-%d-%d %d:%d\n",
161         tmptr->tm_year + 1900,
162         tmptr->tm_mon + 1,
163         tmptr->tm_mday,
164         tmptr->tm_hour,
165         tmptr->tm_min);
166   }
167
168   {
169 #ifdef _WIN32
170     if (signal(SIGINT, catch_interrupt) == SIG_ERR)
171     {
172       puts(" CTRL-C handler not installed");
173       uexit(EXIT_FAILURE);
174     }
175 #else
176     void (*old_handler)();
177
178     old_handler = signal(SIGINT, catch_interrupt);
179
180     if (old_handler != SIG_DFL)
181       (void) signal(SIGINT, old_handler);
182 #endif
183   }
184 }
185
186 /* I/O for TeX and Metafont. */
187 void complain_line (FILE * output)
188 {
189   show_line("\n", 0);
190
191 #ifdef ALLOCATEBUFFER
192   sprintf(log_line, "! Unable to read an entire line---buf_size=%d.\n", current_buf_size);
193 #else
194   sprintf(log_line, "! Unable to read an entire line---buf_size=%d.\n", buf_size);
195 #endif
196
197   fputs(log_line, output);
198   puts("  (File may have a line termination problem.)");
199 }
200
201 void show_bad_line (FILE * output, int first, int last)
202 {
203   int i, c, d, ch;
204   char *s = log_line;
205
206   for (i = first; i <= last; i++)
207   {
208     ch = buffer[i];
209
210     if (show_in_hex && (ch > 127))
211     {
212       c = ch >> 4;
213       d = ch & 15;
214
215       if (c > 9)
216         c = c + 'a' - 10;
217       else
218         c = c + '0';
219
220       if (d > 9)
221         d = d + 'a' - 10;
222       else
223         d = d + '0';
224
225       *s++ = '^';
226       *s++ = '^';
227
228       *s++ = (char) c;
229       *s++ = (char) d;
230     }
231     else if (ch < 32)
232     {
233       *s++ = '^';
234       *s++ = '^';
235       *s++ = (char) (ch + 64);
236     }
237     else if (ch == 127)
238     {
239       *s++ = '^';
240       *s++ = '^';
241       *s++ = (char) (ch - 64);
242     }
243     else
244     {
245       *s++ = (char) ch;
246     }
247   }
248
249   *s++ = ' ';
250   *s++ = '\0';
251
252   fputs(log_line, output);   // log_file
253 }
254
255 boolean input_line_finish (void)
256 {
257   int i = '\0';
258   int ch, flag;
259
260   buffer[last] = ' ';
261
262   if (last >= max_buf_stack)
263     max_buf_stack = last;
264
265   while (last > first)
266   {
267     i = buffer[last - 1];
268
269     if (i == ' ' || i == '\t')
270       --last;
271     else
272       break;
273   }
274
275   if (restrict_to_ascii)
276   {
277     flag = 0;
278
279     for (i = first; i <= last; i++)
280     {
281       ch = buffer[i];
282
283       if (ch > 126 ||  (ch < ' ' && ch != '\t' && ch != '\f' && ch != '\r' && ch != '\n'))
284       {
285         sprintf(log_line, "\n! non ASCII char (%d) in line: ", ch);
286         show_line(log_line, 1);
287
288         if (log_opened)
289           fprintf(log_file, "\n! non ASCII char (%d) in line: ", ch);
290
291         flag = 1;
292         break;
293       }
294     }
295
296     if (flag)
297     {
298       show_bad_line(errout, first, last);
299
300       if (log_opened)
301         show_bad_line(log_file, first, last);
302     }
303   }
304
305   if (non_ascii)
306   {
307     for (i = first; i <= last; i++)
308       buffer[i] = xord[buffer[i]];
309   }
310
311   return true;
312 }
313
314 /* Read a line of input into buffer as efficiently as possible (ha ha)
315    while still looking like Pascal.
316    We set `last' to `first' and return `false' if we get to eof.
317    Otherwise, we return `true' and set last = first +
318    length(line except trailing whitespace).  */
319
320 boolean input_line (FILE * f)
321 {
322   char * u;        /* 1994/July/3 for key_replace */
323   int i = '\0';
324
325   last = first;
326 /*  following is new version with tab expansion and key replacement */
327 /*  may want to expand out separately for speed 1994/July/3 */
328 /*  different versions depending on return_flag / tabexpand / key_replace */
329 /*  while (last < buf_size && (i = getc (f)) != EOF)  */
330 #ifdef ALLOCATEBUFFER
331   for ( ; ; ) 
332 #else
333   while (last < buf_size) 
334 #endif
335   {
336     i = getc(f);
337
338     if (i < ' ')
339     {
340       if (i == EOF || i == '\n' || (i == '\r' && return_flag))
341         break;
342       else if (i == '\t' && tab_step != 0)
343       {
344         buffer[last++] = (ASCII_code) ' ';
345
346 #ifdef ALLOCATEBUFFER
347         if (last >= current_buf_size)
348         {
349           buffer = realloc_buffer(increment_buf_size);  
350
351           if (last >= current_buf_size)
352             break;
353         }
354 #endif
355
356 #ifdef ALLOCATEBUFFER
357         while ((last - first) % tab_step != 0) 
358 #else
359         while (last < buf_size && (last - first) % tab_step != 0)
360 #endif
361         {
362
363           buffer[last++] = (ASCII_code) ' ';
364
365 #ifdef ALLOCATEBUFFER
366           if (last >= current_buf_size)
367           {
368             buffer = realloc_buffer(increment_buf_size);
369
370             if (last >= current_buf_size)
371               break;
372           }
373 #endif
374         }
375
376         continue;
377       }
378     }
379
380     if (key_replace && (u = replacement[i]) != NULL)
381     {
382 #ifdef ALLOCATEBUFFER
383       while (*u != '\0') 
384 #else
385       while (last < buf_size && *u != '\0')  
386 #endif
387       {
388         buffer[last++] = (ASCII_code) *u++;
389
390 #ifdef ALLOCATEBUFFER
391         if (last >= current_buf_size)
392         {
393           buffer = realloc_buffer(increment_buf_size);
394
395           if (last >= current_buf_size)
396             break;
397         }
398 #endif
399       }
400     }
401     else       /* normal case */
402     {
403       buffer[last++] = (ASCII_code) i;
404
405 #ifdef ALLOCATEBUFFER
406       if (last >= current_buf_size)
407       {
408         buffer = realloc_buffer(increment_buf_size);
409
410         if (last >= current_buf_size)
411           break;
412       }
413 #endif
414     }
415   }
416
417   if (return_flag)    /* let return terminate line as well as newline */
418   {
419     if (i == '\r')      /* see whether return followed by newline */
420     {
421       i = getc (f);       /* in which case throw away the newline */
422
423       if (i != '\n')
424       {
425         ungetc (i, f);
426         i = '\r';
427       }
428 /*      else  buffer[last-1] = (ASCII_code) i; */
429     }
430   }
431
432   //  Turn Ctrl-Z at end of file into newline 2000 June 22
433   if (i == EOF && trimeof && buffer[last - 1] == 26)
434   {
435     last--;
436   }
437
438   if (i == EOF && last == first)
439     return false;
440
441 /*  Didn't get the whole line because buffer was too small?  */
442 /*  This shouldn't happen anymore 99/Jan/23 */
443   if (i != EOF && i != '\n' && i != '\r')
444   {
445     complain_line(errout);
446
447     if (log_opened)
448       complain_line(log_file);
449
450     /* This may no longer be needed ... now that we grow it */
451     if (truncate_long_lines)
452     {
453       while (i != EOF && i != '\n' && i != '\r')
454       {
455         i = getc (f);     // discard rest of line
456       }
457
458       last--;       /* just in case */
459     }
460     else
461       uexit(EXIT_FAILURE);      /* line too long */
462   }
463
464   return input_line_finish();
465 }
466
467 /* This string specifies what the `e' option does in response to an
468    error message.  */
469
470 static char * edit_value = "c:\\yandy\\WinEdt\\WinEdt.exe [Open('%s');SelLine(%d,7)]";
471
472 static int Isspace (char c)
473 {
474   return (c == ' ' || c == '\t');
475 }
476
477 void call_edit (ASCII_code * filename, pool_pointer fnstart, integer fnlength, integer linenumber)
478 {
479   char *temp, *command, *fullcmd;
480   char c;
481   int sdone, ddone, i;
482
483 #ifdef WIN32
484   char *fp, *ffp, *env, editorname[256], buffer[256];
485   int cnt = 0;
486   int dontchange = 0;
487 #endif
488
489   sdone = ddone = 0;
490   filename += fnstart;
491
492   /* Close any open input files, since we're going to kill the job.  */
493   for (i = 1; i <= in_open; i++)
494 #ifdef XeTeX
495     xfclose (input_file[i]->f, "inputfile");
496 #else
497     xfclose (input_file[i], "inputfile");
498 #endif
499
500   /* Replace the default with the value of the appropriate environment
501      variable or config file value, if it's set.  */
502   temp = kpse_var_value("TEXEDIT");
503
504   if (temp != NULL)
505     edit_value = temp;
506
507   /* Construct the command string.  The `11' is the maximum length an
508      integer might be.  */
509   command = (char *) xmalloc (strlen (edit_value) + fnlength + 11);
510
511   /* So we can construct it as we go.  */
512   temp = command;
513
514 #ifdef WIN32
515   fp = editorname;
516   if ((isalpha(*edit_value) && *(edit_value + 1) == ':'
517         && IS_DIR_SEP (*(edit_value + 2)))
518       || (*edit_value == '"' && isalpha(*(edit_value + 1))
519         && *(edit_value + 2) == ':'
520         && IS_DIR_SEP (*(edit_value + 3)))
521      )
522     dontchange = 1;
523 #endif
524
525   while ((c = *edit_value++) != 0)
526   {
527     if (c == '%')
528     {
529       switch (c = *edit_value++)
530       {
531         case 'd':
532           if (ddone)
533             FATAL ("call_edit: `%%d' appears twice in editor command");
534           sprintf (temp, "%ld", (long int)linenumber);
535           while (*temp != '\0')
536             temp++;
537           ddone = 1;
538           break;
539         
540         case 's':
541           if (sdone)
542             FATAL ("call_edit: `%%s' appears twice in editor command");
543           for (i = 0; i < fnlength; i++)
544             *temp++ = xchr[(filename[i])];
545           sdone = 1;
546           break;
547         
548         case '\0':
549           *temp++ = '%';
550           /* Back up to the null to force termination.  */
551           edit_value--;
552           break;
553         
554         default:
555           *temp++ = '%';
556           *temp++ = c;
557           break;
558       }
559     }
560     else
561     {
562 #ifdef WIN32
563       if (dontchange)
564         *temp++ = c;
565       else 
566       { 
567         if(Isspace(c) && cnt == 0)
568         {
569           cnt++;
570           temp = command;
571           *temp++ = c;
572           *fp = '\0';
573         }
574         else if(!Isspace(c) && cnt == 0)
575         {
576           *fp++ = c;
577         }
578         else
579         {
580           *temp++ = c;
581         }
582       }
583 #else
584       *temp++ = c;
585 #endif
586     }
587   }
588
589   *temp = 0;
590
591 #ifdef WIN32
592   if (dontchange == 0) {
593     if(editorname[0] == '.' ||
594        editorname[0] == '/' ||
595        editorname[0] == '\\') {
596       fprintf(stderr, "%s is not allowed to execute.\n", editorname);
597       uexit(1);
598     }
599     env = (char *)getenv("PATH");
600     if(SearchPath(env, editorname, ".exe", 256, buffer, &ffp)==0) {
601       if(SearchPath(env, editorname, ".bat", 256, buffer, &ffp)==0) {
602         fprintf(stderr, "I cannot find %s in the PATH.\n", editorname);
603         uexit(1);
604       }
605     }
606     fullcmd = (char *)xmalloc(strlen(buffer)+strlen(command)+5);
607     strcpy(fullcmd, "\"");
608     strcat(fullcmd, buffer);
609     strcat(fullcmd, "\"");
610     strcat(fullcmd, command);
611   } else
612 #endif
613   fullcmd = command;
614
615   /* Execute the command.  */
616   if (system (fullcmd) != 0)
617     fprintf(stderr, "! Trouble executing `%s'.\n", command);
618
619   /* Quit, since we found an error.  */
620   uexit(1);
621 }
622
623
624 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
625
626 /* We don't REALLY care what `endian' the machine is after all ! */
627
628 // #ifdef MYDEBUG
629 // char swapmarkerstring="ERROR: SWAPPING - NOT BigEndian AND NOT NoFmtBaseSwap";
630 // #endif
631
632 /* This macro is always invoked as a statement.  It assumes a variable
633    `temp'.  */
634    
635 #define SWAP(x, y) temp = (x); (x) = (y); (y) = temp;
636
637
638 /* Make the NITEMS items pointed at by P, each of size SIZE, be the
639    opposite-endianness of whatever they are now.  */
640
641 static int swap_items (char *p, int nitems, int size)
642 {
643   char temp;
644
645   /* Since `size' does not change, we can write a while loop for each
646      case, and avoid testing `size' for each time.  */
647   switch (size)
648   {
649     case 8:
650       while (nitems--)
651       {
652         SWAP (p[0], p[7]);
653         SWAP (p[1], p[6]);
654         SWAP (p[2], p[5]);
655         SWAP (p[3], p[4]);
656         p += size;
657       }
658       break;
659
660     case 4:
661       while (nitems--)
662       {
663         SWAP (p[0], p[3]);
664         SWAP (p[1], p[2]);
665         p += size;
666       }
667       break;
668
669     case 2:
670       while (nitems--)
671       {
672         SWAP (p[0], p[1]);
673         p += size;
674       }
675       break;
676
677     case 1:
678     /* Nothing to do.  */
679       break;
680
681     default:
682       show_line("\n", 0);
683       sprintf(log_line, "! I can't (un)dump a %d byte item.\n", size);
684       show_line(log_line, 1);
685       uexit(EXIT_FAILURE);
686   }
687   return 0;
688 }
689 #endif /* not WORDS_BIGENDIAN and not NO_FMTBASE_SWAP */
690
691 #ifdef COMPACTFORMAT
692 int do_dump (char *p, int item_size, int nitems, gzFile out_file)
693 #else
694 int do_dump (char *p, int item_size, int nitems, FILE *out_file)
695 #endif
696 {
697 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
698   swap_items (p, nitems, item_size);
699 #endif
700
701 #ifdef COMPACTFORMAT
702   if (gzwrite(out_file, p, (item_size * nitems)) != (item_size * nitems))
703 #else
704   if ((int) fwrite(p, item_size, nitems, out_file) != nitems)
705 #endif
706   {
707     printf("\n! Could not write %d %d-byte item%s.\n",
708                nitems, item_size, (nitems > 1) ? "s" : "");
709     uexit(EXIT_FAILURE);
710   }
711
712 /* Have to restore the old contents of memory, since some of it might get used again.  */
713 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
714   swap_items (p, nitems, item_size);
715 #endif
716
717   return 0;
718 }
719
720 #ifdef COMPACTFORMAT
721 int do_undump (char *p, int item_size, int nitems, gzFile in_file)
722 #else
723 int do_undump (char *p, int item_size, int nitems, FILE *in_file)
724 #endif
725 {
726 #ifdef COMPACTFORMAT
727   if (gzread(in_file, (void *) p, (unsigned int) (item_size * nitems)) <= 0)
728 #else
729   if ((int) fread((void *) p, item_size, nitems, in_file) != nitems)
730 #endif
731   {
732     printf("\n! Could not read %d %d-byte item%s.\n",
733                nitems, item_size, (nitems > 1) ? "s" : "");
734     uexit(EXIT_FAILURE);
735   }
736
737 #if !defined (WORDS_BIGENDIAN) && !defined (NO_FMTBASE_SWAP)
738   swap_items (p, nitems, item_size);
739 #endif
740
741   return 0;
742 }
743
744 #ifdef FUNNY_CORE_DUMP
745
746 void funny_core_dump (void)
747 {
748   int pid, w;
749   union wait status;
750
751   switch (pid = vfork ())
752   {
753     case -1:
754       perrormod ("vfork");
755       exit (-1);
756
757     case 0:
758        (void) signal (SIGQUIT, SIG_DFL);
759        (void) kill (getpid (), SIGQUIT);
760        (void) write (2, "how did we get here?\n", 21);
761        exit (1);
762
763     default:
764       while ((w = wait (&status)) != pid && w != -1)
765         ;
766
767       if (status.w_coredump)
768         exit (0);
769
770       (void) write (2, "attempt to dump core failed\n", 28);
771       exit (1);
772   }
773 }
774 #endif /* FUNNY_CORE_DUMP */