Headers and library sources from all versions of Lightspeed C and THINK C
1
2/*
3 * ccommand.c
4 *
5 * Copyright (c) 1991 Symantec Corporation. All rights reserved.
6 *
7 * This routine should be called from "main" as follows:
8 *
9 * main(int argc, char **argv)
10 * {
11 * argc = ccommand(&argv);
12 * ...
13 *
14 * A dialog is presented allowing entry of command line arguments
15 * and redirection of stdin/stdout.
16 *
17 */
18
19#include <MacHeaders>
20
21#include "stdlib.h"
22#include "errno.h"
23#include "console.h"
24#include "ansi_private.h"
25
26#define NARGS 25
27
28static char *argv[NARGS+1];
29static char argbuf[256];
30
31static void create_dialog(void);
32static Handle ditem(int);
33static void radio(int, int, int);
34static pascal void drawRing(DialogPtr, short);
35
36static Point getWhere = { 90, 82 };
37static Point putWhere = { 106, 104 };
38
39static void setfile(char *, SFReply *);
40
41static void init_command_line(char *, char *);
42static int parse(char *, char *);
43
44enum {
45 cmdLine = 3,
46 inCon, inFile,
47 outCon, outFile, outEcho, outPrint,
48 okRing,
49 labelIn, labelOut, labelLine
50};
51
52static struct {
53 short count;
54 struct {
55 Handle h;
56 Rect box;
57 char kind;
58 } item[13];
59} itemList = { 12,
60
61 /* OK */
62 0, { 176, 115, 196, 175 }, ctrlItem+btnCtrl,
63
64 /* Cancel */
65 0, { 176, 225, 196, 285 }, ctrlItem+btnCtrl,
66
67 /* command line */
68 0, { 141, 34, 157, 376 }, editText+itemDisable,
69
70 /* (stdin) console */
71 0, { 34, 30, 50, 180 }, ctrlItem+radCtrl,
72
73 /* (stdin) file */
74 0, { 54, 30, 70, 180 }, ctrlItem+radCtrl,
75
76 /* (stdout) console */
77 0, { 34, 230, 50, 380 }, ctrlItem+radCtrl,
78
79 /* (stdout) file */
80 0, { 54, 230, 70, 380 }, ctrlItem+radCtrl,
81
82 /* (stdout) console+file */
83 0, { 74, 230, 90, 380 }, ctrlItem+radCtrl,
84
85 /* (stdout) console+printer */
86 0, { 94, 230, 110, 380 }, ctrlItem+radCtrl,
87
88 /* ring around OK button */
89 (Handle) drawRing, { 172, 111, 200, 179 }, userItem+itemDisable,
90
91 /* "Standard Input:" */
92 0, { 10, 20, 26, 170 }, statText+itemDisable,
93
94 /* "Standard Output:" */
95 0, { 10, 220, 26, 370 }, statText+itemDisable,
96
97 /* "Command Line:" */
98 0, { 114, 20, 130, 170 }, statText+itemDisable,
99};
100
101static DialogPtr dp;
102static Rect bounds = { 60, 51, 270, 461 };
103static int inChoice = inCon, outChoice = outCon;
104
105
106/*
107 * ccommand - process "command line"
108 *
109 */
110
111int
112ccommand(av)
113char ***av;
114{
115 short i, argc;
116 SFReply input, output, scratch;
117 char buf[256];
118
119 /* present dialog */
120
121 cshow(stdin);
122 create_dialog();
123 init_command_line(buf, argbuf);
124 SetCtlValue((ControlHandle)ditem(inCon), 1);
125 SetCtlValue((ControlHandle)ditem(outCon), 1);
126 ShowWindow(dp);
127
128 /* engage in dialog */
129
130 do {
131 ModalDialog(0, &i);
132 switch (i) {
133 case cancel:
134 abort();
135 case inFile:
136 {
137 SFTypeList types = { 'TEXT' };
138
139 SFGetFile(getWhere, "\p", NULL, 1, types, NULL, &scratch);
140 if (!scratch.good)
141 break;
142 input = scratch;
143 }
144 /* ... */
145 case inCon:
146 radio(inChoice = i, inCon, 2);
147 break;
148 case outFile:
149 case outEcho:
150 SFPutFile(putWhere, "\p", "\p", NULL, &scratch);
151 if (!scratch.good)
152 break;
153 output = scratch;
154 /* ... */
155 case outCon:
156 case outPrint:
157 radio(outChoice = i, outCon, 4);
158 break;
159 }
160 } while (i != ok);
161
162 /* parse command line */
163
164 GetIText(ditem(cmdLine), (StringPtr)argbuf);
165 sprintf(buf, "%#s", argbuf);
166 argc = parse(buf, argbuf);
167 *av = argv;
168 DisposDialog(dp);
169
170 /* redirect stdout */
171
172 if (outChoice == outPrint)
173 cecho2printer(stdout);
174 else if (outChoice != outCon) {
175 setfile((char *) scratch.fName, &output);
176 if (outChoice == outFile)
177 freopen((char *) scratch.fName, "w", stdout);
178 else
179 cecho2file((char *) scratch.fName, 0, stdout);
180 }
181
182 /* redirect stdin */
183
184 if (inChoice == inFile) {
185 setfile((char *) scratch.fName, &input);
186 freopen((char *) scratch.fName, "r", stdin);
187 }
188
189 /* done */
190
191 errno = 0;
192 return(argc);
193}
194
195
196/* ---------- dialog utilities ---------- */
197
198
199/*
200 * create_dialog - build dialog in memory
201 *
202 */
203
204static void
205create_dialog(void)
206{
207 Handle items;
208
209 asm {
210 lea itemList,a0
211 move.l #sizeof itemList,d0
212 _PtrToHand
213 move.l a0,items
214 }
215 dp = NewDialog(0, &bounds, "\p", 0, 1, (WindowPtr) -1, 0, 0, items);
216 SetCTitle((ControlHandle)ditem(ok), "\pOK");
217 SetCTitle((ControlHandle)ditem(cancel), "\pCancel");
218 SetCTitle((ControlHandle)ditem(inCon), "\pconsole");
219 SetCTitle((ControlHandle)ditem(inFile), "\pfile");
220 SetCTitle((ControlHandle)ditem(outCon), "\pconsole");
221 SetCTitle((ControlHandle)ditem(outFile), "\pfile");
222 SetCTitle((ControlHandle)ditem(outEcho), "\pconsole+file");
223 SetCTitle((ControlHandle)ditem(outPrint), "\pconsole+printer");
224 SetIText(ditem(labelIn), "\pStandard Input:");
225 SetIText(ditem(labelOut), "\pStandard Output:");
226 SetIText(ditem(labelLine), "\pCommand Line:");
227}
228
229
230/*
231 * ditem - return item handle
232 *
233 */
234
235static Handle
236ditem(int i)
237{
238 short kind;
239 Handle item;
240 Rect box;
241
242 GetDItem(dp, i, &kind, &item, &box);
243 return(item);
244}
245
246
247/*
248 * radio - adjust a cluster of radio buttons
249 *
250 */
251
252static void
253radio(int i, int j, int n)
254{
255 for (; n--; j++)
256 SetCtlValue((ControlHandle)ditem(j), i == j);
257}
258
259
260/*
261 * drawRing - (user-item proc) draw ring around OK button
262 *
263 */
264
265static pascal void
266drawRing(DialogPtr dp, short i)
267{
268 PenNormal();
269 PenSize(3, 3);
270 FrameRoundRect(&itemList.item[okRing-1].box, 16, 16);
271 PenNormal();
272}
273
274
275/* ---------- file utilities ---------- */
276
277
278/*
279 * setfile - prepare to open file
280 *
281 */
282
283static void
284setfile(char *buf, SFReply *reply)
285{
286 IOParam pb;
287
288 pb.ioNamePtr = 0;
289 pb.ioVRefNum = reply->vRefNum;
290 PBSetVolSync((ParmBlkPtr)&pb);
291 sprintf(buf, "%#s", reply->fName);
292}
293
294
295/* ---------- string utilities ---------- */
296
297
298/*
299 * init_command_line - prepare initial command line
300 *
301 * The command line is preset to show the name of the program.
302 * The program name is quoted as necessary.
303 *
304 */
305
306static void
307init_command_line(char *buf1, char *buf2)
308{
309 register char *s, *t = buf2;
310 int c, space = 0, dquote = 0, squote = 0, quote = 0;
311
312 sprintf(s = buf1, "%#s", CurApName);
313 while (c = *s++) {
314 if (c == ' ')
315 space = 1;
316 else if (c == '"')
317 dquote = 1;
318 else if (c == '\'')
319 squote = 1;
320 }
321 if (space || dquote || squote)
322 *t++ = quote = dquote && !squote ? '\'' : '"';
323 for (s = buf1; c = *s++; *t++ = c) {
324 if (c == quote || c == '\\')
325 *t++ = '\\';
326 }
327 if (quote)
328 *t++ = quote;
329 *t++ = ' ';
330 *t++ = 0;
331 SetIText(ditem(cmdLine), __c2p(buf2, buf1));
332 SelIText(dp, cmdLine, 9999, 9999);
333}
334
335
336/*
337 * parse - divide command line into "words"
338 *
339 * Words are delimited by one or more spaces. Any characters within
340 * matching single (') or double (") quotes are taken literally. Any
341 * character preceded by a backslash (\) is taken literally.
342 *
343 */
344
345static int
346parse(char *s, char *t)
347{
348 int c, quote = 0, argc = 0;
349
350 while (c = *s++) {
351 if (c == ' ')
352 continue;
353 if (argc < NARGS)
354 argv[argc++] = t;
355 do {
356 if (c == '\\' && *s)
357 c = *s++;
358 else if (c == '"' || c == '\'') {
359 if (!quote) {
360 quote = c;
361 continue;
362 }
363 if (c == quote) {
364 quote = 0;
365 continue;
366 }
367 }
368 *t++ = c;
369 } while (*s && ((c = *s++) != ' ' || quote));
370 *t++ = 0;
371 }
372 return(argc);
373}