1 /* Digital Mars DMDScript source code.
2  * Copyright (c) 2000-2002 by Chromium Communications
3  * D version Copyright (c) 2004-2010 by Digital Mars
4  * Distributed under the Boost Software License, Version 1.0.
5  * (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  * written by Walter Bright
7  * http://www.digitalmars.com
8  *
9  * D2 port by Dmitry Olshansky
10  *
11  * DMDScript is implemented in the D Programming Language,
12  * http://www.digitalmars.com/d/
13  *
14  * For a C++ implementation of DMDScript, including COM support, see
15  * http://www.digitalmars.com/dscript/cppscript.html
16  */
17 
18 module testscript;
19 
20 import std.path;
21 import std.file;
22 import std.stdio;
23 import std.exception;
24 import core.stdc.stdlib;
25 import core.memory;
26 
27 import dmdscript.script;
28 import dmdscript.program;
29 import dmdscript.errmsgs;
30 
31 enum
32 {
33 	EXITCODE_INIT_ERROR = 1,
34 	EXITCODE_INVALID_ARGS = 2,
35 	EXITCODE_RUNTIME_ERROR = 3,
36 }
37 //Ehm, well, this fools VisualD, and of little convinience anyway
38 /*version (Windows)
39 {
40     pragma(lib, "dmdscript");
41 }*/
42 
43 
44 
45 /**************************************************
46 	Usage:
47 
48 	    ds
49 		will run test.ds
50 
51 	    ds foo
52 		will run foo.ds
53 
54 	    ds foo.js
55 		will run foo.js
56 
57 	    ds foo1 foo2 foo.bar
58 		will run foo1.ds, foo2.ds, foo.bar
59 
60 	The -iinc flag will prefix the source files with the contents of file inc.
61 	There can be multiple -i's. The include list is reset to empty any time
62 	a new -i is encountered that is not preceded by a -i.
63 
64 	    ds -iinc foo
65 		will prefix foo.ds with inc
66 
67 	    ds -iinc1 -iinc2 foo bar
68 		will prefix foo.ds with inc1+inc2, and will prefix bar.ds
69 		with inc1+inc2
70 
71 	    ds -iinc1 -iinc2 foo -iinc3 bar
72 		will prefix foo.ds with inc1+inc2, and will prefix bar.ds
73 		with inc3
74 
75 	    ds -iinc1 -iinc2 foo -i bar
76 		will prefix foo.ds with inc1+inc2, and will prefix bar.ds
77 		with nothing
78 
79  */
80 
81 int main(string[] args)
82 {
83     uint errors = 0;
84     string[] includes;
85     SrcFile[] srcfiles;
86     int result;
87     bool verbose;
88     ErrInfo errinfo;
89     //GC.disable();
90     if(args.length == 1)
91 		stderr.writefln(dmdscript.script.banner());
92     for (size_t i = 1; i < args.length; i++)
93     {	string p = args[i];
94 
95 	if (p[0] == '-')
96 	{
97 	    switch (p[1])
98 	    {
99 		case 'i':
100 		    if (p[2])
101 			includes ~= p[2 .. $];
102 		    break;
103 
104 		case 'v':
105 		    verbose = 1;
106 		    break;
107 
108 		default:
109 		    writefln(errmsgtbl[ERR_BAD_SWITCH],p);
110 		    errors++;
111 		    break;
112 	    }
113 	}
114 	else
115 	{
116 	    srcfiles ~= new SrcFile(p, includes);
117 	    includes = null;
118 	}
119     }
120     if (errors)
121 	return EXITCODE_INVALID_ARGS;
122 
123     if (srcfiles.length == 0)
124     {
125 	srcfiles ~= new SrcFile("test", null);
126     }
127 
128     stderr.writefln("%d source files", srcfiles.length);
129 
130     // Read files, parse them, execute them
131     foreach (SrcFile m; srcfiles)
132     {
133 	if (verbose)
134 	    writefln("read    %s:", m.srcfile);
135 	m.read();
136 	if (verbose)
137 	    writefln("compile %s:", m.srcfile);
138 	m.compile();
139 	if (verbose)
140 	    writefln("execute %s:", m.srcfile);
141 	m.execute();
142     }
143     return EXIT_SUCCESS;
144 }
145 
146 
147 class SrcFile
148 {
149     string srcfile;
150     string[] includes;
151 
152     Program program;
153     tchar[] buffer;
154 
155     this(string srcfilename, string[] includes)
156     {
157 	/* DMDScript source files default to a '.ds' extension
158 	 */
159 
160 	srcfile = defaultExtension(srcfilename, "ds");
161 	this.includes = includes;
162     }
163 
164     void read()
165     {
166 	/* Read the source file, prepend the include files,
167 	 * and put it all in buffer[]. Allocate an extra byte
168 	 * to buffer[] and terminate it with a 0x1A.
169 	 * (If the 0x1A isn't at the end, the lexer will put
170 	 * one there, forcing an extra copy to be made of the
171 	 * source text.)
172 	 */
173 
174 	//writef("read file '%s'\n",srcfile);
175 
176 	// Read the includes[] files
177 	size_t i;
178 	void[] buf;
179 	ulong len;
180 
181 	len = std.file.getSize(srcfile);
182 	foreach (string filename; includes)
183 	{
184 	    len += std.file.getSize(filename);
185 	}
186 	len++;				// leave room for sentinal
187 
188 	assert(len < uint.max);
189 
190 	// Prefix the includes[] files
191 
192 	int sz = cast(int)len;
193 	buffer = new tchar[sz];
194 
195 	foreach (string filename; includes)
196 	{
197 	    buf = std.file.read(filename);
198 	    buffer[i .. i + buf.length] = cast(string)buf[];
199 	    i += buf.length;
200 	}
201 
202 	buf = std.file.read(srcfile);
203 	buffer[i .. i + buf.length] = cast(string)buf[];
204 	i += buf.length;
205 
206 	buffer[i] = 0x1A;		// ending sentinal
207 	i++;
208 	assert(i == len);
209     }
210 
211     void compile()
212     {
213 	/* Create a DMDScript program, and compile our text buffer.
214 	 */
215 
216 	program = new Program();
217 	program.compile(srcfile, assumeUnique(buffer), null);
218     }
219 
220     void execute()
221     {
222 	/* Execute the resulting program.
223 	 */
224 
225 	program.execute(null);
226     }
227 }