fork of PCE focusing on macplus, supporting DaynaPort SCSI network emulation
1/*****************************************************************************
2 * pce *
3 *****************************************************************************/
4
5/*****************************************************************************
6 * File name: src/arch/dos/main.c *
7 * Created: 2012-12-30 by Hampa Hug <hampa@hampa.ch> *
8 * Copyright: (C) 2012-2022 Hampa Hug <hampa@hampa.ch> *
9 *****************************************************************************/
10
11/*****************************************************************************
12 * This program is free software. You can redistribute it and / or modify it *
13 * under the terms of the GNU General Public License version 2 as published *
14 * by the Free Software Foundation. *
15 * *
16 * This program is distributed in the hope that it will be useful, but *
17 * WITHOUT ANY WARRANTY, without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General *
19 * Public License for more details. *
20 *****************************************************************************/
21
22
23#include "main.h"
24#include "dos.h"
25#include "exec.h"
26#include "path.h"
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include <signal.h>
33
34#include <lib/getopt.h>
35#include <lib/sysdep.h>
36
37
38static pce_option_t opts[] = {
39 { '?', 0, "help", NULL, "Print usage information" },
40 { 'c', 0, "command", NULL, "Set the DOS command" },
41 { 'd', 2, "drive", "char string", "Attach a host path to a DOS drive" },
42 { 'e', 1, "setenv", "string", "Add a string to the environment" },
43 { 'l', 0, "log-int", NULL, "Log interrupts [no]" },
44 { 'm', 1, "memory", "int", "Set the memory size in KiB [640]" },
45 { 'V', 0, "version", NULL, "Print version information" },
46 { -1, 0, NULL, NULL, NULL }
47};
48
49
50const char *arg0 = NULL;
51
52static const char *par_drives[26];
53
54static unsigned par_env_cnt = 0;
55static unsigned char *par_env = NULL;
56
57
58static
59void print_help (void)
60{
61 pce_getopt_help (
62 "pce-dos: Run DOS applications",
63 "usage: pce-dos [options] [program [options]]",
64 opts
65 );
66
67 fflush (stdout);
68}
69
70static
71void print_version (void)
72{
73 fputs (
74 "pce-dos version " PCE_VERSION_STR
75 "\n\n"
76 "Copyright (C) 2012-" PCE_YEAR " Hampa Hug <hampa@hampa.ch>\n",
77 stdout
78 );
79
80 fflush (stdout);
81}
82
83static
84void sig_int (int s)
85{
86 fprintf (stderr, "pce-dos: sigint\n");
87 fflush (stderr);
88 exit (1);
89}
90
91static
92void sig_term (int s)
93{
94 fprintf (stderr, "pce-dos: sigterm\n");
95 fflush (stderr);
96 exit (1);
97}
98
99static
100void sig_segv (int s)
101{
102 fprintf (stderr, "pce-dos: segmentation fault\n");
103 fflush (stderr);
104 exit (1);
105}
106
107static
108int set_drive (const char *drv, const char *name)
109{
110 unsigned d;
111
112 if ((drv[0] != 0) && (drv[1] == 0)) {
113 if ((drv[0] >= 'a') && (drv[0] <= 'z')) {
114 d = drv[0] - 'a';
115 }
116 else if ((drv[0] >= 'A') && (drv[0] <= 'Z')) {
117 d = drv[0] - 'Z';
118 }
119 else {
120 return (1);
121 }
122 }
123 else {
124 d = strtoul (drv, NULL, 0);
125 }
126
127 if (d > sizeof (par_drives)) {
128 return (1);
129 }
130
131 par_drives[d] = name;
132
133 return (0);
134}
135
136static
137int env_add (const char *str)
138{
139 unsigned cnt, max;
140 unsigned char *tmp;
141
142 cnt = strlen (str);
143 max = par_env_cnt + cnt + (par_env_cnt > 0);
144
145 if ((tmp = realloc (par_env, max)) == NULL) {
146 return (1);
147 }
148
149 if (par_env_cnt > 0) {
150 tmp[par_env_cnt++] = 0;
151 }
152
153 memcpy (tmp + par_env_cnt, str, cnt);
154
155 par_env = tmp;
156 par_env_cnt = max;
157
158 return (0);
159}
160
161int main (int argc, char **argv)
162{
163 int r;
164 unsigned i;
165 char **optarg;
166 char *prog_dos, *prog_host;
167 char log_int;
168 unsigned mem;
169 dos_t sim;
170
171 arg0 = argv[0];
172
173 mem = 640;
174 log_int = 0;
175
176 while (1) {
177 r = pce_getopt (argc, argv, &optarg, opts);
178
179 if (r == GETOPT_DONE) {
180 return (1);
181 }
182
183 if (r < 0) {
184 return (1);
185 }
186
187 if ((r == 0) || (r == 'c')) {
188 break;
189 }
190
191 switch (r) {
192 case '?':
193 print_help();
194 return (0);
195
196 case 'V':
197 print_version();
198 return (0);
199
200 case 'd':
201 if (set_drive (optarg[0], optarg[1])) {
202 return (1);
203 }
204 break;
205
206 case 'e':
207 if (env_add (optarg[0])) {
208 return (1);
209 }
210 break;
211
212 case 'l':
213 log_int = 1;
214 break;
215
216 case 'm':
217 mem = strtoul (optarg[0], NULL, 0);
218 break;
219
220 default:
221 return (1);
222 }
223 }
224
225 signal (SIGINT, sig_int);
226 signal (SIGTERM, sig_term);
227 signal (SIGSEGV, sig_segv);
228
229 if (sim_init (&sim, mem)) {
230 return (1);
231 }
232
233 sim.log_int = log_int || 0;
234
235 for (i = 0; i < 26; i++) {
236 if (par_drives[i] != NULL) {
237 if (sim_set_drive (&sim, i, par_drives[i])) {
238 return (1);
239 }
240 }
241 }
242
243 if ((prog_dos = sim_get_dos_full_name (&sim, optarg[0])) == NULL) {
244 return (1);
245 }
246
247 if ((prog_host = sim_get_host_name (&sim, prog_dos)) == NULL) {
248 return (1);
249 }
250
251 if (par_env_cnt == 0) {
252 if (env_add ("PATH=C:\\")) {
253 return (1);
254 }
255 }
256
257 if (sim_init_env (&sim, prog_dos, par_env, par_env_cnt)) {
258 return (1);
259 }
260
261 if (sim_exec (&sim, prog_host)) {
262 fprintf (stderr, "%s: loading exe file failed (%s)\n", arg0, optarg[0]);
263 return (1);
264 }
265
266 if (sim_init_args (&sim, (const char **) optarg + 1)) {
267 fprintf (stderr, "%s: argument list too long\n", arg0);
268 return (1);
269 }
270
271 sim_run (&sim);
272
273 sim_free (&sim);
274
275 return (0);
276}