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 - Libraries                                    */
22 /*  File: seed7/src/libpath.c                                       */
23 /*  Changes: 1990 - 1994, 2013  Thomas Mertes                       */
24 /*  Content: Procedures to manage the include library search path.  */
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 "data_rtl.h"
40 #include "os_decls.h"
41 #include "heaputl.h"
42 #include "striutl.h"
43 #include "infile.h"
44 #include "hsh_rtl.h"
45 #include "str_rtl.h"
46 #include "cmd_rtl.h"
47 #include "cmd_drv.h"
48 
49 #undef EXTERN
50 #define EXTERN
51 #include "libpath.h"
52 
53 
54 static rtlArrayType lib_path;
55 
56 intType strCmpGeneric (const genericType value1, const genericType value2);
57 genericType strCreateGeneric (const genericType source);
58 void strDestrGeneric (const genericType old_value);
59 
60 
61 
initIncludeFileHash(void)62 rtlHashType initIncludeFileHash (void)
63 
64   {
65     rtlHashType includeFileHash;
66 
67   /* initIncludeFileHash */
68     logFunction(printf("initIncludeFileHash()\n"););
69     includeFileHash = hshEmpty();
70     logFunction(printf("initIncludeFileHash --> " FMT_U_MEM "\n",
71                        (memSizeType) includeFileHash););
72     return includeFileHash;
73   } /* initIncludeFileHash */
74 
75 
76 
shutIncludeFileHash(const const_rtlHashType includeFileHash)77 void shutIncludeFileHash (const const_rtlHashType includeFileHash)
78 
79   { /* shutIncludeFileHash */
80     logFunction(printf("shutIncludeFileHash(" FMT_U_MEM ")\n",
81                        (memSizeType) includeFileHash););
82     hshDestr(includeFileHash, &strDestrGeneric, &genericDestr);
83     logFunction(printf("shutIncludeFileHash -->\n"););
84   } /* shutIncludeFileHash */
85 
86 
87 
openIncludeFile(const rtlHashType includeFileHash,const_striType includeFileName,errInfoType * err_info)88 static includeResultType openIncludeFile (const rtlHashType includeFileHash,
89     const_striType includeFileName, errInfoType *err_info)
90 
91   {
92     striType absolutePath;
93     includeResultType includeResult = INCLUDE_FAILED;
94 
95   /* openIncludeFile */
96     logFunction(printf("openIncludeFile(" FMT_U_MEM ", \"%s\", %d)\n",
97                        (memSizeType) includeFileHash,
98                        striAsUnquotedCStri(includeFileName),
99                        *err_info););
100     absolutePath = getAbsolutePath(includeFileName);
101     if (unlikely(absolutePath == NULL)) {
102       *err_info = MEMORY_ERROR;
103     } else {
104       if (hshContains(includeFileHash, (genericType) absolutePath,
105                       strHashCode(absolutePath), &strCmpGeneric)) {
106         /* already included */
107         logMessage(printf("already included: \"%s\"\n",
108                           striAsUnquotedCStri(absolutePath)););
109         includeResult = INCLUDE_ALREADY;
110       } else if (openInfile(includeFileName, in_file.write_library_names,
111                             in_file.write_line_numbers, err_info)) {
112         /* add to list of include files */
113         hshIncl(includeFileHash, (genericType) absolutePath,
114                 (genericType) 1, strHashCode(absolutePath),
115                 &strCmpGeneric, &strCreateGeneric,
116                 &genericCreate, &genericCpy);
117         includeResult = INCLUDE_SUCCESS;
118       } /* if */
119       FREE_STRI(absolutePath, absolutePath->size);
120     } /* if */
121     logFunction(printf("openIncludeFile --> %d (err_info=%d)\n",
122                        includeResult, *err_info););
123     return includeResult;
124   } /* openIncludeFile */
125 
126 
127 
128 /**
129  *  Search for an include library and open it, if it was found.
130  *  A library with an absolute path is opened directly.
131  *  For a library with a relative path the directories of the
132  *  include library search path are checked for the library.
133  *  The directories of the search path are checked one after
134  *  another for the requested include library file. As soon as
135  *  the include library is found the search is stopped and the
136  *  include library is opened.
137  */
findIncludeFile(const rtlHashType includeFileHash,const_striType includeFileName,errInfoType * err_info)138 includeResultType findIncludeFile (const rtlHashType includeFileHash,
139     const_striType includeFileName, errInfoType *err_info)
140 
141   {
142     memSizeType lib_path_size;
143     memSizeType position;
144     striType curr_path;
145     memSizeType length;
146     striType stri;
147     includeResultType includeResult = INCLUDE_FAILED;
148 
149   /* findIncludeFile */
150     logFunction(printf("findIncludeFile(" FMT_U_MEM ", \"%s\", %d)\n",
151                        (memSizeType) includeFileHash,
152                        striAsUnquotedCStri(includeFileName),
153                        *err_info););
154     if (*err_info == OKAY_NO_ERROR) {
155       if (includeFileName->size >= 1 && includeFileName->mem[0] == '/') {
156         includeResult = openIncludeFile(includeFileHash, includeFileName, err_info);
157       } else if (unlikely(lib_path == NULL)) {
158         /* This is a compile-time function and it is called at run-time. */
159         *err_info = ACTION_ERROR;
160       } else {
161         lib_path_size = arraySize(lib_path);
162         for (position = 0;
163              includeResult == INCLUDE_FAILED && position < lib_path_size;
164              position++) {
165           curr_path = lib_path->arr[position].value.striValue;
166           if (curr_path->size == 0) {
167             includeResult = openIncludeFile(includeFileHash, includeFileName, err_info);
168           } else {
169             if (curr_path->size > MAX_STRI_LEN - includeFileName->size) {
170               *err_info = MEMORY_ERROR;
171             } else {
172               length = curr_path->size + includeFileName->size;
173               if (!ALLOC_STRI_SIZE_OK(stri, length)) {
174                 *err_info = MEMORY_ERROR;
175               } else {
176                 stri->size = length;
177                 memcpy(stri->mem, curr_path->mem,
178                     (size_t) curr_path->size * sizeof(strElemType));
179                 memcpy(&stri->mem[curr_path->size], includeFileName->mem,
180                     (size_t) includeFileName->size * sizeof(strElemType));
181                 includeResult = openIncludeFile(includeFileHash, stri, err_info);
182                 FREE_STRI(stri, length);
183               } /* if */
184             } /* if */
185           } /* if */
186         } /* for */
187         if (includeResult == INCLUDE_FAILED && *err_info == OKAY_NO_ERROR) {
188           *err_info = FILE_ERROR;
189         } /* if */
190       } /* if */
191     } /* if */
192     logFunction(printf("findIncludeFile --> %d (err_info=%d)\n",
193                        includeResult, *err_info););
194     return includeResult;
195   } /* findIncludeFile */
196 
197 
198 
199 #ifdef OUT_OF_ORDER
print_lib_path(void)200 static void print_lib_path (void)
201 
202   {
203     memSizeType length;
204     memSizeType position;
205     striType stri;
206 
207   /* print_lib_path */
208     length = arraySize(lib_path);
209     for (position = 0; position < length; position++) {
210       stri = lib_path->arr[position].value.striValue;
211       prot_stri(stri);
212       prot_nl();
213     } /* for */
214   } /* print_lib_path */
215 #endif
216 
217 
218 
219 /**
220  *  Add the given directory path to the include library search path.
221  *  The function makes sure that all paths in the include library
222  *  search path end with '/'.
223  */
appendToLibPath(const_striType path,errInfoType * err_info)224 void appendToLibPath (const_striType path, errInfoType *err_info)
225 
226   {
227     memSizeType stri_len;
228     striType stri;
229     rtlArrayType resized_lib_path;
230     memSizeType position;
231 
232   /* appendToLibPath */
233     logFunction(printf("appendToLibPath(\"%s\")\n",
234                        striAsUnquotedCStri(path)););
235     stri_len = path->size;
236     if (stri_len >= 1 && path->mem[stri_len - 1] != '/') {
237       stri_len++;
238     } /* if */
239     if (!ALLOC_STRI_CHECK_SIZE(stri, stri_len)) {
240       *err_info = MEMORY_ERROR;
241     } else {
242       resized_lib_path = REALLOC_RTL_ARRAY(lib_path,
243           (memSizeType) lib_path->max_position,
244           (memSizeType) (lib_path->max_position + 1));
245       if (resized_lib_path == NULL) {
246         FREE_STRI(stri, stri_len);
247         *err_info = MEMORY_ERROR;
248       } else {
249         lib_path = resized_lib_path;
250         COUNT3_RTL_ARRAY((memSizeType) lib_path->max_position,
251             (memSizeType) (lib_path->max_position + 1));
252         stri->size = stri_len;
253         for (position = 0; position < path->size; position++) {
254           if (path->mem[position] == '\\') {
255             stri->mem[position] = '/';
256           } else {
257             stri->mem[position] = path->mem[position];
258           } /* if */
259         } /* for */
260         if (stri_len != path->size) {
261           stri->mem[stri_len - 1] = '/';
262         } /* if */
263         lib_path->arr[lib_path->max_position].value.striValue = stri;
264         lib_path->max_position++;
265       } /* if */
266     } /* if */
267     logFunction(printf("appendToLibPath --> (err_info=%d)\n", *err_info););
268   } /* appendToLibPath */
269 
270 
271 
272 /**
273  *  Initialize the include library search path.
274  *  The initial search path consists of the following directories:
275  *  1. The directory of the program source file.
276  *  2. Directories from the commandline option -l.
277  *  3. The directory containing the predefined Seed7 include libraries.
278  *  4. The directory specified with the SEED7_LIBRARY environment variable.
279  */
initLibPath(const_striType sourceFileName,const const_rtlArrayType seed7_libraries,errInfoType * err_info)280 void initLibPath (const_striType sourceFileName,
281     const const_rtlArrayType seed7_libraries, errInfoType *err_info)
282 
283   {
284     striType path;
285     memSizeType position;
286     memSizeType dir_path_size;
287     static const os_charType seed7_library[] =
288         {'S', 'E', 'E', 'D', '7', '_', 'L', 'I', 'B', 'R', 'A', 'R', 'Y', 0};
289     os_striType library_environment_variable;
290     intType idx;
291 
292   /* initLibPath */
293     logFunction(printf("initLibPath\n"););
294     if (!ALLOC_RTL_ARRAY(lib_path, 0)) {
295       *err_info = MEMORY_ERROR;
296     } else {
297       lib_path->min_position = 1;
298       lib_path->max_position = 0;
299 
300       /* Add directory of the source file to the lib_path. */
301       dir_path_size = 0;
302       for (position = 0; position < sourceFileName->size; position++) {
303         if (sourceFileName->mem[position] == '/') {
304           dir_path_size = position + 1;
305         } /* if */
306       } /* for */
307       if (!ALLOC_STRI_SIZE_OK(path, dir_path_size)) {
308         *err_info = MEMORY_ERROR;
309       } else {
310         path->size = dir_path_size;
311         memcpy(path->mem, sourceFileName->mem, dir_path_size * sizeof(strElemType));
312         appendToLibPath(path, err_info);
313         FREE_STRI(path, path->size);
314       } /* if */
315 
316       /* Add the libraries from the commandline to the lib_path */
317       if (seed7_libraries != NULL) {
318         for (idx = 0;
319              idx <= seed7_libraries->max_position - seed7_libraries->min_position;
320              idx++) {
321           appendToLibPath(seed7_libraries->arr[idx].value.striValue, err_info);
322         } /* for */
323       } /* if */
324 
325       /* Add the hardcoded library of the interpreter to the lib_path. */
326       path = cstri8_or_cstri_to_stri(SEED7_LIBRARY);
327       if (path == NULL) {
328         *err_info = MEMORY_ERROR;
329       } else {
330         appendToLibPath(path, err_info);
331         FREE_STRI(path, path->size);
332       } /* if */
333 
334       /* Add the SEED7_LIBRARY environment variable to the lib_path */
335       library_environment_variable = os_getenv(seed7_library);
336       if (library_environment_variable != NULL) {
337         path = cp_from_os_path(library_environment_variable, err_info);
338         os_getenv_string_free(library_environment_variable);
339         if (path != NULL) {
340           appendToLibPath(path, err_info);
341           FREE_STRI(path, path->size);
342         } /* if */
343       } /* if */
344 
345       /* print_lib_path(); */
346     } /* if */
347     logFunction(printf("initLibPath -->\n"););
348   } /* initLibPath */
349 
350 
351 
freeLibPath(void)352 void freeLibPath (void)
353 
354   {
355     memSizeType length;
356     memSizeType position;
357     striType stri;
358 
359   /* freeLibPath */
360     logFunction(printf("freeLibPath\n"););
361     length = arraySize(lib_path);
362     for (position = 0; position < length; position++) {
363       stri = lib_path->arr[position].value.striValue;
364       FREE_STRI(stri, stri->size);
365     } /* for */
366     FREE_RTL_ARRAY(lib_path, length);
367     lib_path = NULL;
368     logFunction(printf("freeLibPath -->\n"););
369   } /* freeLibPath */
370