1/* VMS DEC C wrapper.
2   Copyright (C) 2001, 2003 Free Software Foundation, Inc.
3   Contributed by Douglas B. Rupp (rupp@gnat.com).
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2, or (at your option)
10any later version.
11
12GCC is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING.  If not, write to
19the Free Software Foundation, 51 Franklin Street, Fifth Floor,
20Boston, MA 02110-1301, USA.  */
21
22/* This program is a wrapper around the VMS DEC C compiler.
23   It translates Unix style command line options into corresponding
24   VMS style qualifiers and then spawns the DEC C compiler.  */
25
26#include "config.h"
27#include "system.h"
28#include "coretypes.h"
29#include "tm.h"
30
31#undef PATH_SEPARATOR
32#undef PATH_SEPARATOR_STR
33#define PATH_SEPARATOR ','
34#define PATH_SEPARATOR_STR ","
35
36/* These can be set by command line arguments */
37static int verbose = 0;
38static int save_temps = 0;
39
40static int comp_arg_max = -1;
41static const char **comp_args = 0;
42static int comp_arg_index = -1;
43static char *objfilename = 0;
44
45static char *system_search_dirs = (char *) "";
46static char *search_dirs;
47
48static char *default_defines = (char *) "";
49static char *defines;
50
51/* Translate a Unix syntax directory specification into VMS syntax.
52   If indicators of VMS syntax found, return input string.  */
53static char *to_host_dir_spec (char *);
54
55/* Translate a Unix syntax file specification into VMS syntax.
56   If indicators of VMS syntax found, return input string.  */
57static char *to_host_file_spec (char *);
58
59/* Add a translated arg to the list to be passed to DEC CC.  */
60static void addarg (const char *);
61
62/* Preprocess the number of args in P_ARGC and contained in ARGV.
63   Look for special flags, etc. that must be handled first.  */
64static void preprocess_args (int *, char **);
65
66/* Process the number of args in P_ARGC and contained in ARGV. Look
67   for special flags, etc. that must be handled for the VMS compiler.  */
68static void process_args (int *, char **);
69
70/* Action routine called by decc$to_vms */
71static int translate_unix (char *, int);
72
73/* Add the argument contained in STR to the list of arguments to pass to the
74   compiler.  */
75
76static void
77addarg (const char *str)
78{
79  int i;
80
81  if (++comp_arg_index >= comp_arg_max)
82    {
83      const char **new_comp_args
84	= (const char **) xcalloc (comp_arg_max + 1000, sizeof (char *));
85
86      for (i = 0; i <= comp_arg_max; i++)
87	new_comp_args [i] = comp_args [i];
88
89      if (comp_args)
90	free (comp_args);
91
92      comp_arg_max += 1000;
93      comp_args = new_comp_args;
94    }
95
96  comp_args [comp_arg_index] = str;
97}
98
99static void
100preprocess_args (int *p_argc, char *argv[])
101{
102  int i;
103
104  for (i = 1; i < *p_argc; i++)
105    {
106      if (strcmp (argv[i], "-o") == 0)
107	{
108	  char *buff, *ptr;
109
110	  i++;
111	  ptr = to_host_file_spec (argv[i]);
112	  objfilename = xstrdup (ptr);
113	  buff = concat ("/obj=", ptr, NULL);
114	  addarg (buff);
115	}
116    }
117}
118
119static void
120process_args (int *p_argc, char *argv[])
121{
122  int i;
123
124  for (i = 1; i < *p_argc; i++)
125    {
126      if (strlen (argv[i]) < 2)
127	continue;
128
129      if (strncmp (argv[i], "-I", 2) == 0)
130	{
131	  char *ptr;
132	  int new_len, search_dirs_len;
133
134	  ptr = to_host_dir_spec (&argv[i][2]);
135	  new_len = strlen (ptr);
136	  search_dirs_len = strlen (search_dirs);
137
138	  search_dirs = xrealloc (search_dirs, search_dirs_len + new_len + 2);
139	  if (search_dirs_len > 0)
140	    strcat (search_dirs, PATH_SEPARATOR_STR);
141	  strcat (search_dirs, ptr);
142	}
143      else if (strncmp (argv[i], "-D", 2) == 0)
144	{
145	  char *ptr;
146	  int new_len, defines_len;
147
148	  ptr = &argv[i][2];
149	  new_len = strlen (ptr);
150	  defines_len = strlen (defines);
151
152	  defines = xrealloc (defines, defines_len + new_len + 4);
153	  if (defines_len > 0)
154	    strcat (defines, ",");
155
156	  strcat (defines, "\"");
157	  strcat (defines, ptr);
158	  strcat (defines, "\"");
159	}
160      else if (strcmp (argv[i], "-v") == 0)
161	verbose = 1;
162      else if (strcmp (argv[i], "-g0") == 0)
163	addarg ("/nodebug");
164      else if (strcmp (argv[i], "-O0") == 0)
165	addarg ("/noopt");
166      else if (strncmp (argv[i], "-g", 2) == 0)
167	addarg ("/debug");
168      else if (strcmp (argv[i], "-E") == 0)
169	addarg ("/preprocess");
170      else if (strcmp (argv[i], "-save-temps") == 0)
171	save_temps = 1;
172    }
173}
174
175/* The main program.  Spawn the VMS DEC C compiler after fixing up the
176   Unix-like flags and args to be what VMS DEC C wants.  */
177
178typedef struct dsc {unsigned short len, mbz; char *adr; } Descr;
179
180int
181main (int argc, char **argv)
182{
183  int i;
184  char cwdev [128], *devptr;
185  int devlen;
186  char *cwd = getcwd (0, 1024);
187
188  devptr = strchr (cwd, ':');
189  devlen = (devptr - cwd) + 1;
190  strncpy (cwdev, cwd, devlen);
191  cwdev [devlen] = '\0';
192
193  search_dirs = xstrdup (system_search_dirs);
194  defines = xstrdup (default_defines);
195
196  addarg ("cc");
197  preprocess_args (&argc , argv);
198  process_args (&argc , argv);
199
200  if (strlen (search_dirs) > 0)
201    {
202      addarg ("/include=(");
203      addarg (search_dirs);
204      addarg (")");
205    }
206
207  if (strlen (defines) > 0)
208    {
209      addarg ("/define=(");
210      addarg (defines);
211      addarg (")");
212    }
213
214  for (i = 1; i < argc; i++)
215    {
216      int arg_len = strlen (argv[i]);
217
218      if (strcmp (argv[i], "-o") == 0)
219	i++;
220      else if (strcmp (argv[i], "-v" ) == 0
221	       || strcmp (argv[i], "-E") == 0
222	       || strcmp (argv[i], "-c") == 0
223	       || strncmp (argv[i], "-g", 2 ) == 0
224	       || strncmp (argv[i], "-O", 2 ) == 0
225	       || strcmp (argv[i], "-save-temps") == 0
226	       || (arg_len > 2 && strncmp (argv[i], "-I", 2) == 0)
227	       || (arg_len > 2 && strncmp (argv[i], "-D", 2) == 0))
228	;
229
230      /* Unix style file specs and VMS style switches look alike, so assume
231	 an arg consisting of one and only one slash, and that being first, is
232	 really a switch.  */
233      else if ((argv[i][0] == '/') && (strchr (&argv[i][1], '/') == 0))
234	addarg (argv[i]);
235      else
236	{
237	  /* Assume filename arg */
238	  char buff [256], *ptr;
239
240	  ptr = to_host_file_spec (argv[i]);
241	  arg_len = strlen (ptr);
242
243	  if (ptr[0] == '[')
244	    sprintf (buff, "%s%s", cwdev, ptr);
245	  else if (strchr (ptr, ':'))
246	    sprintf (buff, "%s", ptr);
247	  else
248	    sprintf (buff, "%s%s", cwd, ptr);
249
250	  ptr = xstrdup (buff);
251	  addarg (ptr);
252	}
253    }
254
255  addarg (NULL);
256
257  if (verbose)
258    {
259      int i;
260
261      for (i = 0; i < comp_arg_index; i++)
262	printf ("%s ", comp_args [i]);
263
264      putchar ('\n');
265    }
266
267  {
268    int i;
269    int len = 0;
270
271    for (i = 0; comp_args[i]; i++)
272      len = len + strlen (comp_args[i]) + 1;
273
274    {
275      char *allargs = (char *) alloca (len + 1);
276      Descr cmd;
277      int status;
278      int status1 = 1;
279
280      for (i = 0; i < len + 1; i++)
281	allargs [i] = 0;
282
283      for (i = 0; comp_args [i]; i++)
284	{
285	  strcat (allargs, comp_args [i]);
286	  strcat (allargs, " ");
287	}
288
289      cmd.adr = allargs;
290      cmd.len = len;
291      cmd.mbz = 0;
292
293      i = LIB$SPAWN (&cmd, 0, 0, 0, 0, 0, &status);
294
295      if ((i & 1) != 1)
296	{
297	  LIB$SIGNAL (i);
298	  exit (1);
299	}
300
301      if ((status & 1) == 1 && (status1 & 1) == 1)
302	exit (0);
303
304      exit (1);
305    }
306  }
307}
308
309static char new_host_filespec [255];
310static char new_host_dirspec [255];
311static char filename_buff [256];
312
313static int
314translate_unix (char *name, int type ATTRIBUTE_UNUSED)
315{
316  strcpy (filename_buff, name);
317  return 0;
318}
319
320static char *
321to_host_dir_spec (char *dirspec)
322{
323  int len = strlen (dirspec);
324
325  strcpy (new_host_dirspec, dirspec);
326
327  if (strchr (new_host_dirspec, ']') || strchr (new_host_dirspec, ':'))
328    return new_host_dirspec;
329
330  while (len > 1 && new_host_dirspec [len-1] == '/')
331    {
332      new_host_dirspec [len-1] = 0;
333      len--;
334    }
335
336  decc$to_vms (new_host_dirspec, translate_unix, 1, 2);
337  strcpy (new_host_dirspec, filename_buff);
338
339  return new_host_dirspec;
340
341}
342
343static char *
344to_host_file_spec (char *filespec)
345{
346  strcpy (new_host_filespec, "");
347  if (strchr (filespec, ']') || strchr (filespec, ':'))
348    strcpy (new_host_filespec, filespec);
349  else
350    {
351      decc$to_vms (filespec, translate_unix, 1, 1);
352      strcpy (new_host_filespec, filename_buff);
353    }
354
355  return new_host_filespec;
356}
357