/* * ccommand.c * * Copyright (c) 1991 Symantec Corporation. All rights reserved. * * This routine should be called from "main" as follows: * * main(int argc, char **argv) * { * argc = ccommand(&argv); * ... * * A dialog is presented allowing entry of command line arguments * and redirection of stdin/stdout. * */ #include #include "stdlib.h" #include "errno.h" #include "console.h" #include "ansi_private.h" #define NARGS 25 static char *argv[NARGS+1]; static char argbuf[256]; static void create_dialog(void); static Handle ditem(int); static void radio(int, int, int); static pascal void drawRing(DialogPtr, short); static Point getWhere = { 90, 82 }; static Point putWhere = { 106, 104 }; static void setfile(char *, SFReply *); static void init_command_line(char *, char *); static int parse(char *, char *); enum { cmdLine = 3, inCon, inFile, outCon, outFile, outEcho, outPrint, okRing, labelIn, labelOut, labelLine }; static struct { short count; struct { Handle h; Rect box; char kind; } item[13]; } itemList = { 12, /* OK */ 0, { 176, 115, 196, 175 }, ctrlItem+btnCtrl, /* Cancel */ 0, { 176, 225, 196, 285 }, ctrlItem+btnCtrl, /* command line */ 0, { 141, 34, 157, 376 }, editText+itemDisable, /* (stdin) console */ 0, { 34, 30, 50, 180 }, ctrlItem+radCtrl, /* (stdin) file */ 0, { 54, 30, 70, 180 }, ctrlItem+radCtrl, /* (stdout) console */ 0, { 34, 230, 50, 380 }, ctrlItem+radCtrl, /* (stdout) file */ 0, { 54, 230, 70, 380 }, ctrlItem+radCtrl, /* (stdout) console+file */ 0, { 74, 230, 90, 380 }, ctrlItem+radCtrl, /* (stdout) console+printer */ 0, { 94, 230, 110, 380 }, ctrlItem+radCtrl, /* ring around OK button */ (Handle) drawRing, { 172, 111, 200, 179 }, userItem+itemDisable, /* "Standard Input:" */ 0, { 10, 20, 26, 170 }, statText+itemDisable, /* "Standard Output:" */ 0, { 10, 220, 26, 370 }, statText+itemDisable, /* "Command Line:" */ 0, { 114, 20, 130, 170 }, statText+itemDisable, }; static DialogPtr dp; static Rect bounds = { 60, 51, 270, 461 }; static int inChoice = inCon, outChoice = outCon; /* * ccommand - process "command line" * */ int ccommand(av) char ***av; { short i, argc; SFReply input, output, scratch; char buf[256]; /* present dialog */ cshow(stdin); create_dialog(); init_command_line(buf, argbuf); SetCtlValue((ControlHandle)ditem(inCon), 1); SetCtlValue((ControlHandle)ditem(outCon), 1); ShowWindow(dp); /* engage in dialog */ do { ModalDialog(0, &i); switch (i) { case cancel: abort(); case inFile: { SFTypeList types = { 'TEXT' }; SFGetFile(getWhere, "\p", NULL, 1, types, NULL, &scratch); if (!scratch.good) break; input = scratch; } /* ... */ case inCon: radio(inChoice = i, inCon, 2); break; case outFile: case outEcho: SFPutFile(putWhere, "\p", "\p", NULL, &scratch); if (!scratch.good) break; output = scratch; /* ... */ case outCon: case outPrint: radio(outChoice = i, outCon, 4); break; } } while (i != ok); /* parse command line */ GetIText(ditem(cmdLine), (StringPtr)argbuf); sprintf(buf, "%#s", argbuf); argc = parse(buf, argbuf); *av = argv; DisposDialog(dp); /* redirect stdout */ if (outChoice == outPrint) cecho2printer(stdout); else if (outChoice != outCon) { setfile((char *) scratch.fName, &output); if (outChoice == outFile) freopen((char *) scratch.fName, "w", stdout); else cecho2file((char *) scratch.fName, 0, stdout); } /* redirect stdin */ if (inChoice == inFile) { setfile((char *) scratch.fName, &input); freopen((char *) scratch.fName, "r", stdin); } /* done */ errno = 0; return(argc); } /* ---------- dialog utilities ---------- */ /* * create_dialog - build dialog in memory * */ static void create_dialog(void) { Handle items; asm { lea itemList,a0 move.l #sizeof itemList,d0 _PtrToHand move.l a0,items } dp = NewDialog(0, &bounds, "\p", 0, 1, (WindowPtr) -1, 0, 0, items); SetCTitle((ControlHandle)ditem(ok), "\pOK"); SetCTitle((ControlHandle)ditem(cancel), "\pCancel"); SetCTitle((ControlHandle)ditem(inCon), "\pconsole"); SetCTitle((ControlHandle)ditem(inFile), "\pfile"); SetCTitle((ControlHandle)ditem(outCon), "\pconsole"); SetCTitle((ControlHandle)ditem(outFile), "\pfile"); SetCTitle((ControlHandle)ditem(outEcho), "\pconsole+file"); SetCTitle((ControlHandle)ditem(outPrint), "\pconsole+printer"); SetIText(ditem(labelIn), "\pStandard Input:"); SetIText(ditem(labelOut), "\pStandard Output:"); SetIText(ditem(labelLine), "\pCommand Line:"); } /* * ditem - return item handle * */ static Handle ditem(int i) { short kind; Handle item; Rect box; GetDItem(dp, i, &kind, &item, &box); return(item); } /* * radio - adjust a cluster of radio buttons * */ static void radio(int i, int j, int n) { for (; n--; j++) SetCtlValue((ControlHandle)ditem(j), i == j); } /* * drawRing - (user-item proc) draw ring around OK button * */ static pascal void drawRing(DialogPtr dp, short i) { PenNormal(); PenSize(3, 3); FrameRoundRect(&itemList.item[okRing-1].box, 16, 16); PenNormal(); } /* ---------- file utilities ---------- */ /* * setfile - prepare to open file * */ static void setfile(char *buf, SFReply *reply) { IOParam pb; pb.ioNamePtr = 0; pb.ioVRefNum = reply->vRefNum; PBSetVolSync((ParmBlkPtr)&pb); sprintf(buf, "%#s", reply->fName); } /* ---------- string utilities ---------- */ /* * init_command_line - prepare initial command line * * The command line is preset to show the name of the program. * The program name is quoted as necessary. * */ static void init_command_line(char *buf1, char *buf2) { register char *s, *t = buf2; int c, space = 0, dquote = 0, squote = 0, quote = 0; sprintf(s = buf1, "%#s", CurApName); while (c = *s++) { if (c == ' ') space = 1; else if (c == '"') dquote = 1; else if (c == '\'') squote = 1; } if (space || dquote || squote) *t++ = quote = dquote && !squote ? '\'' : '"'; for (s = buf1; c = *s++; *t++ = c) { if (c == quote || c == '\\') *t++ = '\\'; } if (quote) *t++ = quote; *t++ = ' '; *t++ = 0; SetIText(ditem(cmdLine), __c2p(buf2, buf1)); SelIText(dp, cmdLine, 9999, 9999); } /* * parse - divide command line into "words" * * Words are delimited by one or more spaces. Any characters within * matching single (') or double (") quotes are taken literally. Any * character preceded by a backslash (\) is taken literally. * */ static int parse(char *s, char *t) { int c, quote = 0, argc = 0; while (c = *s++) { if (c == ' ') continue; if (argc < NARGS) argv[argc++] = t; do { if (c == '\\' && *s) c = *s++; else if (c == '"' || c == '\'') { if (!quote) { quote = c; continue; } if (c == quote) { quote = 0; continue; } } *t++ = c; } while (*s && ((c = *s++) != ' ' || quote)); *t++ = 0; } return(argc); }