Headers and library sources from all versions of Lightspeed C and THINK C
at main 373 lines 7.1 kB view raw
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}