1 /********************************************************************/
2 /*                                                                  */
3 /*  s7   Seed7 interpreter                                          */
4 /*  Copyright (C) 1990 - 2013  Thomas Mertes                        */
5 /*                                                                  */
6 /*  This program is free software; you can redistribute it and/or   */
7 /*  modify it under the terms of the GNU General Public License as  */
8 /*  published by the Free Software Foundation; either version 2 of  */
9 /*  the License, or (at your option) any later version.             */
10 /*                                                                  */
11 /*  This program is distributed in the hope that it will be useful, */
12 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of  */
13 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   */
14 /*  GNU General Public License for more details.                    */
15 /*                                                                  */
16 /*  You should have received a copy of the GNU General Public       */
17 /*  License along with this program; if not, write to the           */
18 /*  Free Software Foundation, Inc., 51 Franklin Street,             */
19 /*  Fifth Floor, Boston, MA  02110-1301, USA.                       */
20 /*                                                                  */
21 /*  Module: Analyzer - Infile                                       */
22 /*  File: seed7/src/infile.c                                        */
23 /*  Changes: 1990 - 1994, 2013  Thomas Mertes                       */
24 /*  Content: Procedures to open, close and read the source file.    */
25 /*                                                                  */
26 /********************************************************************/
27 
28 #define LOG_FUNCTIONS 0
29 #define VERBOSE_EXCEPTIONS 0
30 
31 #include "version.h"
32 
33 #include "stdlib.h"
34 #include "stdio.h"
35 #include "string.h"
36 
37 #include "common.h"
38 #include "data.h"
39 #include "os_decls.h"
40 #include "heaputl.h"
41 #include "flistutl.h"
42 #include "striutl.h"
43 #include "info.h"
44 #include "stat.h"
45 #include "errno.h"
46 
47 #if HAS_MMAP
48 #include "sys/types.h"
49 #include "sys/stat.h"
50 #include "sys/mman.h"
51 #include "stat_drv.h"
52 #endif
53 
54 #undef EXTERN
55 #define EXTERN
56 #define DO_INIT
57 #include "infile.h"
58 
59 
60 #define GET_INFILE_BUFFER TRUE
61 #define SIZE_IN_BUFFER 32768
62 
63 
64 static inFileType file_pointer = NULL;
65 static fileNumType file_counter = 0;
66 
67 
68 
69 #if USE_ALTERNATE_NEXT_CHARACTER
fill_buf(void)70 int fill_buf (void)
71 
72   {
73 #if !HAS_MMAP
74     memSizeType chars_read;
75 #endif
76     int ch;
77 
78   /* fill_buf */
79     logFunction(printf("fill_buf\n"););
80 #if HAS_MMAP
81     ch = EOF;
82 #else
83     if (in_file.fil != NULL &&
84         (chars_read = fread(in_file.start, 1,
85         (size_t) in_file.buffer_size, in_file.fil)) != 0) {
86       in_file.nextch = in_file.start;
87       in_file.beyond = in_file.start + chars_read;
88       ch = next_character();
89     } else {
90       ch = EOF;
91     } /* if */
92 #endif
93     logFunction(printf("fill_buf --> %d\n", ch););
94     return ch;
95   } /* fill_buf */
96 #endif
97 
98 
99 
speedup(void)100 static inline boolType speedup (void)
101 
102   {
103     boolType okay;
104 #if HAS_MMAP
105     int file_no;
106     os_fstat_struct file_stat;
107     memSizeType file_length;
108 #endif
109 
110   /* speedup */
111     logFunction(printf("speedup\n"););
112     okay = TRUE;
113 #if USE_ALTERNATE_NEXT_CHARACTER
114 #if HAS_MMAP
115     file_no = fileno(in_file.fil);
116     if (file_no != -1 && os_fstat(file_no, &file_stat) == 0) {
117       if (file_stat.st_size >= 0 && (unsigned_os_off_t) file_stat.st_size < MAX_MEMSIZETYPE) {
118         file_length = (memSizeType) file_stat.st_size;
119         if ((in_file.start = (ustriType) mmap(NULL, file_length,
120             PROT_READ, MAP_PRIVATE, file_no, 0)) != (ustriType) -1) {
121           in_file.nextch = in_file.start;
122           in_file.beyond = in_file.start + file_length;
123           in_file.buffer_size = 0;
124         } else {
125           if (ALLOC_UBYTES(in_file.start, file_length)) {
126             if (fread(in_file.start, 1, file_length, in_file.fil) ==
127                 file_length) {
128               in_file.nextch = in_file.start;
129               in_file.beyond = in_file.start + file_length;
130               in_file.buffer_size = file_length;
131               fseek(in_file.fil, 0, SEEK_SET);
132             } else {
133               FREE_BYTES(in_file.start, file_length);
134               okay = FALSE;
135             } /* if */
136           } else {
137             okay = FALSE;
138           } /* if */
139         } /* if */
140       } else {
141         okay = FALSE;
142       } /* if */
143     } else {
144       okay = FALSE;
145     } /* if */
146 #else
147     if (GET_INFILE_BUFFER) {
148       in_file.buffer_size = SIZE_IN_BUFFER;
149     } else {
150       in_file.buffer_size = 512;
151     } /* if */
152     if (ALLOC_UBYTES(in_file.start, in_file.buffer_size)) {
153       in_file.nextch = in_file.start + in_file.buffer_size;
154       in_file.beyond = in_file.start;
155     } else {
156       in_file.buffer_size = 512;
157       if (ALLOC_UBYTES(in_file.start, in_file.buffer_size)) {
158         in_file.nextch = in_file.start + in_file.buffer_size;
159         in_file.beyond = in_file.start;
160       } else {
161         okay = FALSE;
162       } /* if */
163     } /* if */
164 #endif
165 #else
166 #if USE_INFILE_BUFFER
167     if (GET_INFILE_BUFFER) {
168       if (ALLOC_UBYTES(in_file.buffer, SIZE_IN_BUFFER)) {
169         setvbuf(in_file.fil, in_file.buffer, _IOFBF,
170             (size_t) SIZE_IN_BUFFER);
171       } /* if */
172     } else {
173       in_file.buffer = NULL;
174     } /* if */
175 #endif
176 #endif
177     logFunction(printf("speedup --> %d\n", okay););
178     return okay;
179   } /* speedup */
180 
181 
182 
openInfile(const_striType sourceFileName,boolType write_library_names,boolType write_line_numbers,errInfoType * err_info)183 boolType openInfile (const_striType sourceFileName, boolType write_library_names,
184     boolType write_line_numbers, errInfoType *err_info)
185 
186   {
187     os_striType os_path;
188     inFileType new_file;
189     FILE *in_fil;
190     ustriType name_ustri;
191     memSizeType name_length;
192     striType in_name;
193     int path_info = PATH_IS_NORMAL;
194     boolType isOpen = FALSE;
195 
196   /* openInfile */
197     logFunction(printf("openInfile(\"%s\", %d, %d, err_info=%d)\n",
198                        striAsUnquotedCStri(sourceFileName),
199                        write_library_names, write_line_numbers,
200                        *err_info););
201     os_path = cp_to_os_path(sourceFileName, &path_info, err_info);
202     if (likely(os_path != NULL)) {
203       in_fil = os_fopen(os_path, os_mode_rb);
204       /* printf("fopen(\"" FMT_S_OS "\") --> " FMT_U_MEM "\n",
205              os_path, (memSizeType) in_fil); */
206       if (in_fil == NULL) {
207         logError(printf("openInfile: "
208                         "fopen(\"" FMT_S_OS "\", \"" FMT_S_OS "\") failed:\n"
209                         "errno=%d\nerror: %s\n",
210                         os_path, os_mode_rb, errno, strerror(errno)););
211         *err_info = FILE_ERROR;
212       } else {
213         if (!ALLOC_FILE(new_file)) {
214           fclose(in_fil);
215           *err_info = MEMORY_ERROR;
216         } else {
217           name_ustri = (ustriType) stri_to_cstri8(sourceFileName, err_info);
218           if (name_ustri != NULL) {
219             /* printf("name_ustri: \"%s\"\n", name_ustri); */
220             name_length = strlen((cstriType) name_ustri);
221             name_ustri = REALLOC_USTRI(name_ustri, max_utf8_size(sourceFileName->size), name_length);
222             if (name_ustri == NULL) {
223               *err_info = MEMORY_ERROR;
224             } /* if */
225           } /* if */
226           if (name_ustri == NULL) {
227             fclose(in_fil);
228           } else if (!ALLOC_STRI_CHECK_SIZE(in_name, sourceFileName->size)) {
229             free_cstri8(name_ustri, sourceFileName);
230             fclose(in_fil);
231             *err_info = MEMORY_ERROR;
232           } else {
233             in_name->size = sourceFileName->size;
234             memcpy(in_name->mem, sourceFileName->mem, sourceFileName->size * sizeof(strElemType));
235             if (in_file.curr_infile != NULL) {
236               memcpy(in_file.curr_infile, &in_file, sizeof(inFileRecord));
237             } /* if */
238             in_file.fil = in_fil;
239             if (!speedup()) {
240               fclose(in_file.fil);
241               free_cstri8(name_ustri, sourceFileName);
242               FREE_STRI(in_name, sourceFileName->size);
243               if (in_file.curr_infile != NULL) {
244                 memcpy(&in_file, in_file.curr_infile, sizeof(inFileRecord));
245               } else {
246                 in_file.fil = NULL;
247               } /* if */
248               logError(printf("openInfile: speedup() failed.\n"
249                               "os_path: \"" FMT_S_OS "\"\n", os_path););
250               *err_info = FILE_ERROR;
251             } else {
252               COUNT_USTRI(name_length, count.fnam, count.fnam_bytes);
253               in_file.name_ustri = name_ustri;
254               in_file.name = in_name;
255               in_file.character = next_character();
256               in_file.line = 1;
257               file_counter++;
258               in_file.file_number = file_counter;
259               if (in_file.curr_infile != NULL) {
260                 in_file.owningProg = in_file.curr_infile->owningProg;
261               } else {
262                 in_file.owningProg = NULL; /* Is set in analyze_prog() */
263               } /* if */
264               open_compilation_info(write_library_names, write_line_numbers);
265               in_file.end_of_file = FALSE;
266               in_file.up_infile = in_file.curr_infile;
267               in_file.curr_infile = new_file;
268               in_file.next = file_pointer;
269               file_pointer = new_file;
270               memcpy(new_file, &in_file, sizeof(inFileRecord));
271               isOpen = TRUE;
272             } /* if */
273           } /* if */
274         } /* if */
275       } /* if */
276       os_stri_free(os_path);
277     } /* if */
278     logFunction(printf("openInfile --> %d (err_info=%d)\n", isOpen, *err_info););
279     return isOpen;
280   } /* openInfile */
281 
282 
283 
closeInfile(void)284 void closeInfile (void)
285 
286   { /* closeInfile */
287     logFunction(printf("closeInfile\n"););
288     /* printf("\nclose(\"%s\");\n", in_file.name); */
289 #if WITH_COMPILATION_INFO
290     if (in_file.write_line_numbers) {
291       NL_LIN_INFO();
292     } else {
293       if (in_file.write_library_names) {
294         NL_FIL_LIN_INFO();
295       } /* if */
296     } /* if */
297     total_lines = total_lines + ((unsigned long) in_file.line);
298 #endif
299 #if USE_ALTERNATE_NEXT_CHARACTER
300     if (in_file.start != NULL) {
301       if (in_file.buffer_size == 0) {
302 #if HAS_MMAP
303         if (in_file.fil != NULL) {
304           munmap(in_file.start, (size_t) (in_file.beyond - in_file.start));
305         } /* if */
306 #endif
307       } else {
308         FREE_BYTES(in_file.start, in_file.buffer_size);
309       } /* if */
310     } /* if */
311 #endif
312     if (in_file.fil != NULL) {
313       fclose(in_file.fil);
314       in_file.fil = NULL;
315     } /* if */
316 #if !USE_ALTERNATE_NEXT_CHARACTER
317 #if USE_INFILE_BUFFER
318     if (in_file.BUFFER != NULL) {
319       FREE_BYTES(in_file.buffer, SIZE_IN_BUFFER);
320     } /* if */
321 #endif
322 #endif
323     if (in_file.curr_infile != NULL) {
324       memcpy(in_file.curr_infile, &in_file, sizeof(inFileRecord));
325     } /* if */
326     if (in_file.up_infile != NULL) {
327       memcpy(&in_file, in_file.up_infile, sizeof(inFileRecord));
328       display_compilation_info();
329     } else {
330       in_file.curr_infile = NULL;
331     } /* if */
332     in_file.next_msg_line = in_file.line + in_file.incr_message_line;
333     logFunction(printf("END closeInfile\n"););
334   } /* closeInfile */
335 
336 
337 
openString(bstriType inputString,boolType write_library_names,boolType write_line_numbers,errInfoType * err_info)338 boolType openString (bstriType inputString, boolType write_library_names,
339     boolType write_line_numbers, errInfoType *err_info)
340 
341   {
342     const char sourceFileName[] = "STRING";
343     inFileType new_file;
344     memSizeType name_length;
345     ustriType name_ustri;
346     striType in_name;
347     boolType isOpen = FALSE;
348 
349   /* openString */
350     logFunction(printf("openString(\"%s\", %d, %d, err_info=%d)\n",
351                        bstriAsUnquotedCStri(inputString),
352                        write_library_names, write_line_numbers,
353                        *err_info););
354 #if USE_ALTERNATE_NEXT_CHARACTER
355     if (*err_info == OKAY_NO_ERROR) {
356       if (!ALLOC_FILE(new_file)) {
357         *err_info = MEMORY_ERROR;
358       } else {
359         name_length = STRLEN(sourceFileName);
360         if (!ALLOC_USTRI(name_ustri, name_length)) {
361           *err_info = MEMORY_ERROR;
362         } else if (!ALLOC_STRI_SIZE_OK(in_name, name_length)) {
363           UNALLOC_USTRI(name_ustri, name_length);
364           *err_info = MEMORY_ERROR;
365         } else {
366           COUNT_USTRI(name_length, count.fnam, count.fnam_bytes);
367           strcpy((cstriType) name_ustri, sourceFileName);
368           in_name->size = name_length;
369           memcpy_to_strelem(in_name->mem, name_ustri, name_length);
370           if (in_file.curr_infile != NULL) {
371             memcpy(in_file.curr_infile, &in_file, sizeof(inFileRecord));
372           } /* if */
373           in_file.fil = NULL;
374           in_file.name_ustri = name_ustri;
375           in_file.name = in_name;
376           in_file.start = inputString->mem;
377           in_file.nextch = in_file.start;
378           in_file.beyond = in_file.start + inputString->size;
379           in_file.buffer_size = 0;
380           in_file.character = next_character();
381           in_file.line = 1;
382           file_counter++;
383           in_file.file_number = file_counter;
384           in_file.owningProg = NULL; /* Is set in analyze_prog() */
385           open_compilation_info(write_library_names, write_line_numbers);
386           in_file.end_of_file = FALSE;
387           in_file.up_infile = in_file.curr_infile;
388           in_file.curr_infile = new_file;
389           in_file.next = file_pointer;
390           file_pointer = new_file;
391           memcpy(new_file, &in_file, sizeof(inFileRecord));
392           isOpen = TRUE;
393         } /* if */
394       } /* if */
395     } /* if */
396 #endif
397     logFunction(printf("openString --> %d (err_info=%d)\n", isOpen, *err_info););
398     return isOpen;
399   } /* openString */
400 
401 
402 
freeFile(inFileType old_file)403 static void freeFile (inFileType old_file)
404 
405   {
406     memSizeType name_length;
407 
408   /* freeFile */
409     logFunction(printf("freeFile\n"););
410     name_length = strlen((cstriType) old_file->name_ustri);
411     FREE_USTRI(old_file->name_ustri, name_length, count.fnam, count.fnam_bytes);
412     FREE_STRI(old_file->name, old_file->name->size);
413     FREE_FILE(old_file);
414     logFunction(printf("freeFile -->\n"););
415   } /* freeFile */
416 
417 
418 
removeProgFiles(progType currentProg)419 void removeProgFiles (progType currentProg)
420 
421   {
422     inFileType aFile;
423     inFileType *fileAddr;
424     inFileType currFile;
425 
426   /* removeProgFiles */
427     logFunction(printf("removeProgFiles\n"););
428     aFile = file_pointer;
429     fileAddr = &file_pointer;
430     while (aFile != NULL) {
431       currFile = aFile;
432       aFile = aFile->next;
433       /* printf("removeProgFiles: %s %lx %lx\n", currFile->name_ustri,
434          (unsigned long) currFile->owningProg, (unsigned long) currentProg); */
435       if (currFile->owningProg == currentProg) {
436         freeFile(currFile);
437         *fileAddr = aFile;
438       } else {
439         fileAddr = &currFile->next;
440       } /* if */
441     } /* if */
442     logFunction(printf("removeProgFiles -->\n"););
443   } /* removeProgFiles */
444 
445 
446 
next_file(void)447 void next_file (void)
448 
449   { /* next_file */
450     logFunction(printf("next_file\n"););
451     in_file.line--;
452     if (in_file.up_infile != NULL) {
453       closeInfile();
454     } else {
455       in_file.end_of_file = TRUE;
456     } /* if */
457     logFunction(printf("next_file -->\n"););
458   } /* next_file */
459 
460 
461 
462 #ifdef OUT_OF_ORDER
next_line(void)463 int next_line (void)
464 
465   {
466     register int character;
467 
468   /* next_line */
469     logFunction(printf("next_line\n"););
470     SKIP_CR_SP(character);
471     INCR_LINE_COUNT(in_file.line);
472     logFunction(printf("next_line -->\n"););
473     return character;
474   } /* next_line */
475 #endif
476 
477 
478 
get_file_name(fileNumType file_num)479 striType get_file_name (fileNumType file_num)
480 
481   {
482     static striType question_mark = NULL;
483     register inFileType help_file;
484     striType file_name;
485 
486   /* get_file_name */
487     logFunction(printf("get_file_name(%u)\n", file_num););
488     help_file = file_pointer;
489     while (help_file != NULL && help_file->file_number != file_num) {
490       help_file = help_file->next;
491     } /* while */
492     if (help_file != NULL) {
493       file_name = help_file->name;
494     } else {
495       if (question_mark == NULL) {
496         question_mark = CSTRI_LITERAL_TO_STRI("?");
497       } /* if */
498       file_name = question_mark;
499     } /* if */
500     logFunction(printf("get_file_name --> \"%s\"\n",
501                        striAsUnquotedCStri(file_name)););
502     return file_name;
503   } /* get_file_name */
504 
505 
506 
get_file_name_ustri(fileNumType file_num)507 const_ustriType get_file_name_ustri (fileNumType file_num)
508 
509   {
510     inFileType help_file;
511     const_ustriType file_name;
512 
513   /* get_file_name_ustri */
514     logFunction(printf("get_file_name_ustri\n"););
515     help_file = file_pointer;
516     while (help_file != NULL && help_file->file_number != file_num) {
517       help_file = help_file->next;
518     } /* while */
519     if (help_file != NULL) {
520       file_name = help_file->name_ustri;
521     } else {
522       file_name = (const_ustriType) "?";
523     } /* if */
524     logFunction(printf("get_file_name_ustri -->\n"););
525     return file_name;
526   } /* get_file_name_ustri */
527