~rdoering/ubuntu/intrepid/erlang/fix-535090

« back to all changes in this revision

Viewing changes to erts/etc/common/escript.c

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2007-05-01 16:57:10 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: james.westby@ubuntu.com-20070501165710-2sapk0hp2gf3o0ip
Tags: 1:11.b.4-2ubuntu1
* Merge with Debian Unstable. Remaining changes:
  - Add -fno-stack-protector to fix broken crypto_drv.
* DebianMaintainerField update.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* ``The contents of this file are subject to the Erlang Public License,
 
2
 * Version 1.1, (the "License"); you may not use this file except in
 
3
 * compliance with the License. You should have received a copy of the
 
4
 * Erlang Public License along with this software. If not, it can be
 
5
 * retrieved via the world wide web at http://www.erlang.org/.
 
6
 * 
 
7
 * Software distributed under the License is distributed on an "AS IS"
 
8
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 
9
 * the License for the specific language governing rights and limitations
 
10
 * under the License.
 
11
 * 
 
12
 * The Initial Developer of the Original Code is Ericsson Utvecklings AB.
 
13
 * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
 
14
 * AB. All Rights Reserved.''
 
15
 * 
 
16
 *     $Id$
 
17
 */
 
18
/*
 
19
 * Purpose: escript front-end.
 
20
 */
 
21
#ifdef HAVE_CONFIG_H
 
22
#  include "config.h"
 
23
#endif
 
24
 
 
25
#include "sys.h"
 
26
#ifdef __WIN32__
 
27
#include <winbase.h>
 
28
#endif
 
29
 
 
30
#include <ctype.h>
 
31
 
 
32
#define NO 0
 
33
#define YES 1
 
34
 
 
35
#define ASIZE(a) (sizeof(a)/sizeof(a[0]))
 
36
 
 
37
static int debug = 0;           /* Bit flags for debug printouts. */
 
38
 
 
39
static char** eargv_base;       /* Base of vector. */
 
40
static char** eargv;            /* First argument for erl. */
 
41
 
 
42
static int eargc;               /* Number of arguments in eargv. */
 
43
 
 
44
#ifdef __WIN32__
 
45
#  define QUOTE(s) possibly_quote(s)
 
46
#  define IS_DIRSEP(c) ((c) == '/' || (c) == '\\')
 
47
#  define ERL_NAME "erl.exe"
 
48
#else
 
49
#  define QUOTE(s) s
 
50
#  define IS_DIRSEP(c) ((c) == '/')
 
51
#  define ERL_NAME "erl"
 
52
#endif
 
53
 
 
54
#define UNSHIFT(s) eargc++, eargv--; eargv[0] = QUOTE(s)
 
55
#define UNSHIFT3(s, t, u) UNSHIFT(u); UNSHIFT(t); UNSHIFT(s)
 
56
#define PUSH(s) eargv[eargc++] = QUOTE(s)
 
57
#define PUSH2(s, t) PUSH(s); PUSH(t)
 
58
#define PUSH3(s, t, u) PUSH2(s, t); PUSH(u)
 
59
 
 
60
/*
 
61
 * Local functions.
 
62
 */
 
63
 
 
64
static void error(char* format, ...);
 
65
static char* emalloc(size_t size);
 
66
static char* strsave(char* string);
 
67
static void push_words(char* src);
 
68
static int run_erlang(char* name, char** argv);
 
69
static char* get_default_emulator(char* progname);
 
70
#ifdef __WIN32__
 
71
static char* possibly_quote(char* arg);
 
72
#endif
 
73
 
 
74
/*
 
75
 * Supply a strerror() function if libc doesn't.
 
76
 */
 
77
#ifndef HAVE_STRERROR
 
78
 
 
79
extern int sys_nerr;
 
80
 
 
81
#ifndef SYS_ERRLIST_DECLARED
 
82
extern const char * const sys_errlist[];
 
83
#endif /* !SYS_ERRLIST_DECLARED */
 
84
 
 
85
char *strerror(int errnum)
 
86
{
 
87
  static char *emsg[1024];
 
88
 
 
89
  if (errnum != 0) {
 
90
    if (errnum > 0 && errnum < sys_nerr) 
 
91
      sprintf((char *) &emsg[0], "(%s)", sys_errlist[errnum]);
 
92
    else 
 
93
      sprintf((char *) &emsg[0], "errnum = %d ", errnum);
 
94
  }
 
95
  else {
 
96
    emsg[0] = '\0';
 
97
  }
 
98
  return (char *) &emsg[0];
 
99
}
 
100
#endif /* !HAVE_STRERROR */
 
101
 
 
102
int
 
103
main(int argc, char** argv)
 
104
{
 
105
    int eargv_size;
 
106
    int eargc_base;             /* How many arguments in the base of eargv. */
 
107
    char* emulator;
 
108
 
 
109
    emulator = getenv("ESCRIPT_EMULATOR");
 
110
    if (emulator == NULL) {
 
111
        emulator = get_default_emulator(argv[0]);
 
112
    }
 
113
 
 
114
    /*
 
115
     * Allocate the argv vector to be used for arguments to Erlang.
 
116
     * Arrange for starting to pushing information in the middle of
 
117
     * the array, to allow easy addition of commands in the beginning.
 
118
     */
 
119
 
 
120
    eargv_size = argc*4+100;
 
121
    eargv_base = (char **) emalloc(eargv_size*sizeof(char*));
 
122
    eargv = eargv_base;
 
123
    eargc = 0;
 
124
    push_words(emulator);
 
125
    eargc_base = eargc;
 
126
    eargv = eargv + eargv_size/2;
 
127
    eargc = 0;
 
128
 
 
129
    /*
 
130
     * Push initial arguments.
 
131
     */
 
132
 
 
133
    PUSH("+B");
 
134
    PUSH2("-boot", "start_clean");
 
135
    PUSH("-noshell");
 
136
    PUSH3("-run", "escript", "start");
 
137
 
 
138
    /*
 
139
     * Push all options (without the hyphen) before the script name.
 
140
     */
 
141
 
 
142
    while(argc > 1 && argv[1][0] == '-') {
 
143
        PUSH(argv[1]+1);
 
144
        argc--, argv++;
 
145
    }
 
146
 
 
147
    /*
 
148
     * Push the script name and everything following it as extra arguments.
 
149
     */
 
150
 
 
151
    PUSH("-extra");
 
152
    while (argc > 1) {
 
153
        PUSH(argv[1]);
 
154
        argc--, argv++;
 
155
    }
 
156
 
 
157
    /*
 
158
     * Move up the commands for invoking the emulator and adjust eargv
 
159
     * accordingly.
 
160
     */
 
161
 
 
162
    while (--eargc_base >= 0) {
 
163
        UNSHIFT(eargv_base[eargc_base]);
 
164
    }
 
165
    
 
166
    /*
 
167
     * Invoke Erlang with the collected options.
 
168
     */
 
169
 
 
170
    PUSH(NULL);
 
171
    return run_erlang(eargv[0], eargv);
 
172
}
 
173
 
 
174
static void
 
175
push_words(char* src)
 
176
{
 
177
    char sbuf[1024];
 
178
    char* dst;
 
179
 
 
180
    dst = sbuf;
 
181
    while ((*dst++ = *src++) != '\0') {
 
182
        if (isspace((int)*src)) {
 
183
            *dst = '\0';
 
184
            PUSH(strsave(sbuf));
 
185
            dst = sbuf;
 
186
            do {
 
187
                src++;
 
188
            } while (isspace((int)*src));
 
189
        }
 
190
    }
 
191
    if (sbuf[0])
 
192
        PUSH(strsave(sbuf));
 
193
}
 
194
#ifdef __WIN32__
 
195
char *make_commandline(char **argv)
 
196
{
 
197
    static char *buff = NULL;
 
198
    static int siz = 0;
 
199
    int num = 0;
 
200
    char **arg, *p;
 
201
 
 
202
    if (*argv == NULL) { 
 
203
        return "";
 
204
    }
 
205
    for (arg = argv; *arg != NULL; ++arg) {
 
206
        num += strlen(*arg)+1;
 
207
    }
 
208
    if (!siz) {
 
209
        siz = num;
 
210
        buff = malloc(siz*sizeof(char));
 
211
    } else if (siz < num) {
 
212
        siz = num;
 
213
        buff = realloc(buff,siz*sizeof(char));
 
214
    }
 
215
    p = buff;
 
216
    for (arg = argv; *arg != NULL; ++arg) {
 
217
        strcpy(p,*arg);
 
218
        p+=strlen(*arg);
 
219
        *p++=' ';
 
220
    }
 
221
    *(--p) = '\0';
 
222
 
 
223
    if (debug) {
 
224
        printf("Processed commandline:%s\n",buff);
 
225
    }
 
226
    return buff;
 
227
}
 
228
 
 
229
int my_spawnvp(char **argv)
 
230
{
 
231
    STARTUPINFO siStartInfo;
 
232
    PROCESS_INFORMATION piProcInfo;
 
233
    DWORD ec;
 
234
 
 
235
    memset(&siStartInfo,0,sizeof(STARTUPINFO));
 
236
    siStartInfo.cb = sizeof(STARTUPINFO); 
 
237
    siStartInfo.dwFlags = STARTF_USESTDHANDLES;
 
238
    siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
 
239
    siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
 
240
    siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
 
241
    siStartInfo.wShowWindow = SW_HIDE;
 
242
    siStartInfo.dwFlags |= STARTF_USESHOWWINDOW;
 
243
 
 
244
 
 
245
    if (!CreateProcess(NULL, 
 
246
                       make_commandline(argv),
 
247
                       NULL, 
 
248
                       NULL, 
 
249
                       TRUE, 
 
250
                       0,
 
251
                       NULL, 
 
252
                       NULL, 
 
253
                       &siStartInfo, 
 
254
                       &piProcInfo)) {
 
255
        return -1;
 
256
    }
 
257
    CloseHandle(piProcInfo.hThread);
 
258
 
 
259
    WaitForSingleObject(piProcInfo.hProcess,INFINITE);
 
260
    if (!GetExitCodeProcess(piProcInfo.hProcess,&ec)) {
 
261
        return 0;
 
262
    }
 
263
    return (int) ec;
 
264
}    
 
265
#endif /* __WIN32__ */
 
266
 
 
267
 
 
268
static int
 
269
run_erlang(char* progname, char** argv)
 
270
{
 
271
#ifdef __WIN32__
 
272
    int status;
 
273
#endif
 
274
 
 
275
    if (debug) {
 
276
        int i = 0;
 
277
        while (argv[i] != NULL)
 
278
            printf(" %s", argv[i++]);
 
279
        printf("\n");
 
280
    }
 
281
 
 
282
#ifdef __WIN32__
 
283
    /*
 
284
     * Alas, we must wait here for the program to finish.
 
285
     * Otherwise, the shell from which we was executed will think
 
286
     * we are finished and print a prompt and read keyboard input.
 
287
     */
 
288
 
 
289
    status = my_spawnvp(argv)/*_spawnvp(_P_WAIT,progname,argv)*/;
 
290
    if (status == -1) {
 
291
        fprintf(stderr, "erlc: Error executing '%s': %d", progname, 
 
292
                GetLastError());
 
293
    }
 
294
    return status;
 
295
#else
 
296
    execvp(progname, argv);
 
297
    error("Error %d executing \'%s\'.", errno, progname);
 
298
    return 2;
 
299
#endif
 
300
}
 
301
 
 
302
static void
 
303
error(char* format, ...)
 
304
{
 
305
    char sbuf[1024];
 
306
    va_list ap;
 
307
    
 
308
    va_start(ap, format);
 
309
    vsprintf(sbuf, format, ap);
 
310
    va_end(ap);
 
311
    fprintf(stderr, "erlc: %s\n", sbuf);
 
312
    exit(1);
 
313
}
 
314
 
 
315
static char*
 
316
emalloc(size_t size)
 
317
{
 
318
  char *p = malloc(size);
 
319
  if (p == NULL)
 
320
    error("Insufficient memory");
 
321
  return p;
 
322
}
 
323
 
 
324
static char*
 
325
strsave(char* string)
 
326
{
 
327
    char* p = emalloc(strlen(string)+1);
 
328
    strcpy(p, string);
 
329
    return p;
 
330
}
 
331
 
 
332
static char*
 
333
get_default_emulator(char* progname)
 
334
{
 
335
    char sbuf[MAXPATHLEN];
 
336
    char* s;
 
337
 
 
338
    strcpy(sbuf, progname);
 
339
    for (s = sbuf+strlen(sbuf); s >= sbuf; s--) {
 
340
        if (IS_DIRSEP(*s)) {
 
341
            strcpy(s+1, ERL_NAME);
 
342
            if (access(sbuf, 1) != -1) {
 
343
                return strsave(sbuf);
 
344
            }
 
345
            break;
 
346
        }
 
347
    }
 
348
    return ERL_NAME;
 
349
}
 
350
 
 
351
#ifdef __WIN32__
 
352
static char*
 
353
possibly_quote(char* arg)
 
354
{
 
355
    int mustQuote = NO;
 
356
    int n = 0;
 
357
    char* s;
 
358
    char* narg;
 
359
 
 
360
    if (arg == NULL) {
 
361
        return arg;
 
362
    }
 
363
 
 
364
    /*
 
365
     * Scan the string to find out if it needs quoting and return
 
366
     * the original argument if not.
 
367
     */
 
368
 
 
369
    for (s = arg; *s; s++, n++) {
 
370
        switch(*s) {
 
371
        case ' ':
 
372
            mustQuote = YES;
 
373
            continue;
 
374
        case '"':
 
375
            mustQuote = YES;
 
376
            n++;
 
377
            continue;
 
378
        case '\\':
 
379
            if(s[1] == '"')
 
380
                n++;
 
381
            continue;
 
382
        default:
 
383
            continue;
 
384
        }
 
385
    }
 
386
    if (!mustQuote) {
 
387
        return arg;
 
388
    }
 
389
 
 
390
    /*
 
391
     * Insert the quotes and put a backslash in front of every quote
 
392
     * inside the string.
 
393
     */
 
394
 
 
395
    s = narg = emalloc(n+2+1);
 
396
    for (*s++ = '"'; *arg; arg++, s++) {
 
397
        if (*arg == '"' || (*arg == '\\' && arg[1] == '"')) {
 
398
            *s++ = '\\';
 
399
        }
 
400
        *s = *arg;
 
401
    }
 
402
    if (s[-1] == '\\') {
 
403
        *s++ ='\\';
 
404
    }
 
405
    *s++ = '"';
 
406
    *s = '\0';
 
407
    return narg;
 
408
}
 
409
#endif /* __WIN32__ */