MODIFY VARIABLES: Eliminate VAR_NAME_LEN limit on variable names.
[pspp] / src / language / utilities / include.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 1997-9, 2000, 2007, 2010 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include <ctype.h>
20 #include <errno.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #include <data/file-name.h>
26 #include <language/command.h>
27 #include <language/lexer/lexer.h>
28 #include <language/syntax-file.h>
29 #include <libpspp/getl.h>
30 #include <libpspp/message.h>
31 #include <libpspp/str.h>
32
33 #include "dirname.h"
34 #include "xalloc.h"
35
36 #include "gettext.h"
37 #define _(msgid) gettext (msgid)
38
39 static int parse_insert (struct lexer *lexer, char **filename);
40
41
42 int
43 cmd_include (struct lexer *lexer, struct dataset *ds UNUSED)
44 {
45   char *filename = NULL;
46   int status = parse_insert (lexer, &filename);
47
48   if ( CMD_SUCCESS != status)
49     return status;
50
51   lex_get (lexer);
52
53   status = lex_end_of_command (lexer);
54
55   if ( status == CMD_SUCCESS)
56     {
57       struct source_stream *ss = lex_get_source_stream (lexer);
58
59       assert (filename);
60       getl_include_source (ss, create_syntax_file_source (filename),
61                            GETL_BATCH, ERRMODE_STOP);
62       free (filename);
63     }
64
65   return status;
66 }
67
68
69 int
70 cmd_insert (struct lexer *lexer, struct dataset *ds UNUSED)
71 {
72   enum syntax_mode syntax_mode = GETL_INTERACTIVE;
73   enum error_mode error_mode = ERRMODE_CONTINUE;
74   char *filename = NULL;
75   int status = parse_insert (lexer, &filename);
76   bool cd = false;
77
78   if ( CMD_SUCCESS != status)
79     return status;
80
81   lex_get (lexer);
82
83   while ( T_ENDCMD != lex_token (lexer))
84     {
85       if (lex_match_id (lexer, "SYNTAX"))
86         {
87           lex_match (lexer, T_EQUALS);
88           if ( lex_match_id (lexer, "INTERACTIVE") )
89             syntax_mode = GETL_INTERACTIVE;
90           else if ( lex_match_id (lexer, "BATCH"))
91             syntax_mode = GETL_BATCH;
92           else
93             {
94               lex_error (lexer, _("expecting %s or %s after %s"),
95                          "BATCH", "INTERACTIVE", "SYNTAX");
96               return CMD_FAILURE;
97             }
98         }
99       else if (lex_match_id (lexer, "CD"))
100         {
101           lex_match (lexer, T_EQUALS);
102           if ( lex_match_id (lexer, "YES") )
103             {
104               cd = true;
105             }
106           else if ( lex_match_id (lexer, "NO"))
107             {
108               cd = false;
109             }
110           else
111             {
112               lex_error (lexer, _("expecting %s or %s after %s"),
113                          "YES", "NO", "CD");
114               return CMD_FAILURE;
115             }
116         }
117       else if (lex_match_id (lexer, "ERROR"))
118         {
119           lex_match (lexer, T_EQUALS);
120           if ( lex_match_id (lexer, "CONTINUE") )
121             {
122               error_mode = ERRMODE_CONTINUE;
123             }
124           else if ( lex_match_id (lexer, "STOP"))
125             {
126               error_mode = ERRMODE_STOP;
127             }
128           else
129             {
130               lex_error (lexer, _("expecting %s or %s after %s"),
131                          "CONTINUE", "STOP", "ERROR");
132               return CMD_FAILURE;
133             }
134         }
135
136       else
137         {
138           lex_error (lexer, _("Unexpected token: `%s'."),
139                      lex_token_representation (lexer));
140
141           return CMD_FAILURE;
142         }
143     }
144
145   status = lex_end_of_command (lexer);
146
147   if ( status == CMD_SUCCESS)
148     {
149       struct source_stream *ss = lex_get_source_stream (lexer);
150
151       assert (filename);
152       getl_include_source (ss, create_syntax_file_source (filename),
153                            syntax_mode,
154                            error_mode);
155
156       if ( cd )
157         {
158           char *directory = dir_name (filename);
159           chdir (directory);
160           free (directory);
161         }
162
163       free (filename);
164     }
165
166   return status;
167 }
168
169
170 static int
171 parse_insert (struct lexer *lexer, char **filename)
172 {
173   const char *target_fn;
174   char *relative_filename;
175
176   /* Skip optional FILE=. */
177   if (lex_match_id (lexer, "FILE"))
178     lex_match (lexer, T_EQUALS);
179
180   /* File name can be identifier or string. */
181   if (lex_token (lexer) != T_ID && !lex_is_string (lexer))
182     {
183       lex_error (lexer, _("expecting file name"));
184       return CMD_FAILURE;
185     }
186
187   target_fn = lex_tokcstr (lexer);
188
189   relative_filename =
190     fn_search_path (target_fn,
191                     getl_include_path (lex_get_source_stream (lexer)));
192
193   if ( ! relative_filename)
194     {
195       msg (SE, _("Can't find `%s' in include file search path."),
196          target_fn);
197       return CMD_FAILURE;
198     }
199
200   *filename = relative_filename;
201   if (*filename == NULL) 
202     {
203       msg (SE, _("Unable to open `%s': %s."),
204            relative_filename, strerror (errno));
205       free (relative_filename);
206       return CMD_FAILURE;
207     }
208
209   return CMD_SUCCESS;
210 }