/* * ZOOSHELL.C * A GEM-based shell for painlessly invoking the ZOO archiver * Author: Steve Yelvington * Internet * GEnie S.YELVINGTO2 * This program is hereby released to the public domain. * You are solely responsible for any use you make of it. */ #define VERSION "ZOOSHELL Version 0.6 beta" #ifdef APSTART /* If using APSTART.O instead of DSTART.O, */ /* some kludgery to get around peculiarities of dLibs */ #define NULL (void *)(0) #define exit Pterm #define FALSE (0) #define TRUE (!FALSE) #define ERROR (-1) int errno; #else #include #endif #include /* Atari operating system bindings */ #include /* you may prefer gemdefs.h and obdefs.h */ #include /* abs, loword/hiword, etc. */ #include /* standard limits such as PATHSIZ */ #include /* values returned by string functions */ #include "zooshell.h" /* file generated by resource editor */ #define RESOURCE_FILE "zooshell.rsc" #define STDOUT 1 /* GEMDOS handle */ #define STDPRN 3 /* GEMDOS handle */ #define CON 2 /* BIOS device number */ OBJECT *menubar; /* pointer for resource menu */ char cwd[PATHSIZE]; /* current working directory */ char zoottp[PATHSIZE]; /* name of ZOO program */ int m_hidden; /* mouse hidden flag */ char mycmd[256]; /* command buffer for launching ZOO */ char myargs[256]; /* argument buffer for launching ZOO */ int confh,outfh; /* file handles for redirection */ extern char *h_ex[], /* help screens from zoohelp.c */ *h_rest[], *h_view[], *h_spec[], *h_buttons[]; /* * Function: g_clrscr() * Returns: void * Description: Instructs GEM to redraw the workspace */ void g_clrscr() { int x,y,w,h; wind_get(0,WF_FULLXYWH,&x,&y,&w,&h); /* get desktop dimensions */ form_dial(FMD_START,1,1,1,1,x,y,w,h); /* this may be unnecessary */ form_dial(FMD_FINISH,1,1,1,1,x,y,w,h); /* generate redraw msg */ } /* * Function: hide_mouse * Returns: void * Description: hide the mouse and set the m_hidden flag */ void hide_mouse() { if (m_hidden) return; graf_mouse(M_OFF,NULL); m_hidden = TRUE; } /* * Function: show_mouse * Returns: void * Description: if the mouse is hidden, show the mouse and set the flag */ void show_mouse() { if (m_hidden) { graf_mouse(M_ON,NULL); m_hidden = FALSE; } } /* * Function: show_about() * Returns: void * Description: Shows the ABOUTBOX until 4-second timeout or mouse click * Note: This function uses the GEMFAST evnx_multi function, which is * available in C source code if you don't have GEMFAST. */ void show_about() { OBJECT *aboutbox; XMULTI xm; int x,y,w,h; static long delay; delay = 4*1000L; rsrc_gaddr(0,ABOUTBOX, &aboutbox); hide_mouse(); form_center(aboutbox, &x, &y, &w, &h); form_dial(FMD_START,1,1,1,1,x,y,w,h); form_dial(FMD_GROW,1,1,1,1,x,y,w,h); objc_draw(aboutbox, 0, 10, x, y, w, h); show_mouse(); /* now wait for timer, keyboard or button activity */ xm.mflags = MU_TIMER|MU_KEYBD|MU_BUTTON; xm.mtlocount = loword(delay); xm.mthicount = hiword(delay); xm.mbclicks = 1; /* wait for single */ xm.mbmask = 1; /* click of left */ xm.mbstate = 1; /* button */ evnx_multi(&xm); form_dial(FMD_SHRINK,1,1,1,1,x,y,w,h); form_dial(FMD_FINISH,1,1,1,1,x,y,w,h); } /* * Function: do_dialog * Returns: index of exit object * Description: This smart wrapper for form_dial handles centering, etc. */ int do_dialog(ind) int ind; { OBJECT *form; int exit_obj; int x,y,w,h; rsrc_gaddr(0,ind,&form); hide_mouse(); form_center(form, &x, &y, &w, &h); form_dial(FMD_START,1,1,1,1,x,y,w,h); form_dial(FMD_GROW,1,1,1,1,x,y,w,h); objc_draw(form, 0, 10, x, y, w, h); show_mouse(); exit_obj = form_do(form, 0); hide_mouse(); form_dial(FMD_SHRINK,1,1,1,1,x,y,w,h); form_dial(FMD_FINISH,1,1,1,1,x,y,w,h); form[exit_obj].ob_state = NORMAL; show_mouse(); return(exit_obj); } /* * Function: forcedir * Returns: void * Description: combines set-drive and set-path functions into one call */ void forcedir(d) char *d; { Dsetdrv(((int)d[0]) - 'A'); Dsetpath(&d[2]); } /* * Function: change_dir * Returns: void * Description: Prompt user with a file selector and change directories * as appropriate */ void change_dir() { char file[14]; int status; char *p; file[0] = '\0'; getcwd(cwd,PATHSIZE); strupr(cwd); status = fsel_exinput(cwd,file, &status, "Select directory for output"); if (p=strrchr(cwd,'\\')) *p = '\0'; if (status) forcedir(cwd); } /* * Function: fsel * Returns: 0 if [CANCEL], 1 if [OK] * Description: Display the GEM file selector, including a prompt if * one is supplied. The path and default filename will * be shown, if supplied. Convert the user's input into * a complete filename and copy the result into the * supplied buffer. * * Side effects: fsel remembers the previous values of inpath and default * filename and uses them if those args are NULL */ int fsel(prompt, path, insel, filename) char *prompt, /* message to user, or NULL */ *path, /* initial path, or NULL */ *insel, /* initial filename, or NULL */ *filename; /* 128-byte buffer for full selected name */ { static char xpath[128], xinsel[14]; char *p; int button; if (!prompt) prompt = "Please choose a file"; if (!path) { xpath[0] = Dgetdrv() + 'A'; xpath[1] = ':'; Dgetpath(&xpath[2],(int)(xpath[0]-'A'+1)); strcat(xpath,"\\*.*"); path = xpath; } if (!strchr(path,':')) /* nonabsolute path */ { xpath[0] = Dgetdrv() + 'A'; xpath[1] = ':'; Dgetpath(&xpath[2],(int)(xpath[0]-'A'+1)); strcat(xpath,"\\"); strcat(xpath,path); } else if (path != xpath) strcpy(xpath,path); if (insel) strcpy(xinsel,insel); fsel_exinput(xpath,xinsel,&button,prompt); if (!button) return button; strcpy(filename,xpath); if (p = strrchr(filename,'\\')) *++p = '\0'; else if (p = strrchr(filename,':')) *++p = '\0'; else if (p = strchr(filename,'*')) *p = '\0'; else { strcat(filename,"\\"); p = filename + strlen(filename); } strcpy(p,xinsel); return button; } /* * Function: Bconws * Returns: void * Description: Like Cconws, but to redirection-proof BIOS device */ void Bconws(dev,s) int dev; char *s; { while (*s) Bconout(dev,*s++); } /* * Function: xparse_args * Returns: void * Description: Parse a command line into an argv array * (modified from dlibs) */ void xparse_args(cmdln, argv) char *cmdln; register char *argv[]; { register char *p; static char delim[] = " \t\r\n"; if(p = strtok(cmdln, delim)) { do { *argv++ = p; } while(p = strtok(NULL, delim)); } } /* * Function: xsystem * Returns: the value returned by a child process * Description: this is a simple, system()-like interface to * invoke fork/wait in a palatable fashion. It's * modified from dlibs; basically this is system() * without the _shell_p support. I don't want to * pass commands to a shell because I don't want * to give it the opportunity to mangle the args * ... this lets me control exactly what ZOO sees. */ int xsystem(command) register char *command; { register char *p; char rv[2]; char cmdln[1024]; char *args[64]; if(!command) return(ERROR); strcpy(cmdln, command); xparse_args(cmdln, args); p = args[0]; forkvpe(p, args, NULL); wait(rv); return((rv[1] == 0) ? rv[0] : rv[1]); } /* * Function: exzoo * Returns: void * Description: Prompt the user for a ZOO file name. Then, if flag is * true, prompt the user for a file to process. Build * a command line including the cmd argument, and then * clear the screen and invoke xsystem. Restore the * GEM screen afterward. */ void exzoo(cmd,flag,prompt) char *cmd; int flag; char *prompt; { char insel[14]; int rv; insel[0] = '\0'; strcpy(mycmd,zoottp); strcat(mycmd,cmd); if (!fsel("Choose ZOO file to process","*.ZOO",insel,myargs)) return; strcat(mycmd," "); strcat(mycmd,myargs); if (strcmp(cmd,"-backup") ==0) strcat(mycmd," *"); if (flag) /* get more args */ { myargs[0] = '\0'; if (!fsel(prompt,"*.*",insel,myargs)) return; strcat(mycmd," "); strcat(mycmd,myargs); } /* now clear the screen, run ZOO, and restore the screen */ menu_bar(menubar,FALSE); hide_mouse(); Bconws(CON,"\033E\033e"); /* cls, home, cursor on */ Bconws(CON,"Setting current directory: "); Bconws(CON,cwd); Bconws(CON,"\r\n"); forcedir(cwd); Bconws(CON,"Current directory set to: "); Bconout(CON,Dgetdrv() + 'A'); Bconout(CON,':'); { char buf[PATHSIZE]; Dgetpath(buf, Dgetdrv()+1); Bconws(CON,buf); } Bconws(CON,"\r\n"); Bconws(CON,"Executing command xsystem( "); Bconws(CON,mycmd); Bconws(CON," )\r\n"); if ((rv = xsystem(mycmd)) < 0) { show_mouse(); form_error(abs(rv)); } else { Bconws(CON,"\a**** Strike any key to continue ****"); Bconin(CON); } Bconws(CON,"\033E\033f"); /* cls, home, cursor off */ g_clrscr(); menu_bar(menubar,TRUE); show_mouse(); } /* * Function: notimpl * Returns: void * Description: Displays informative message for unimplemented features */ void notimpl() { form_alert(1,"[0][That option is|not yet|implemented][Sorry]"); } /* * Function: load_resource * Returns: TRUE if the resource was loaded, else FALSE. * Description: This is just a standard wrapper. */ int load_resource(rfile) char *rfile; { if (!rsrc_load(rfile)) { form_alert(1,"[0][Can't find|resource file][EXIT]"); return(FALSE); } return(TRUE); } /* * Function: prt_output * Returns: TRUE or FALSE depending on whether redirection succeeded. * Description: Redirects GEMDOS console output to the printer device. * If the printer is not ready, redirection is considered * to have failed. */ int prt_output() { if (!Cprnos()) { form_alert(1,"[0][Printer not ready!][Oops]"); return FALSE; } confh = Fdup(STDOUT); if (confh < 0) { form_alert(1,"[0][Fdup() failed!][Oops]"); form_error(abs(confh)); return FALSE; } outfh = Fopen("PRN:",1); if (outfh < -3) { form_alert(1,"[0][Fopen() failed!][Oops]"); form_error(abs(outfh)); return FALSE; } if (Fforce(STDOUT,outfh)) { form_alert(1,"[0][Fforce() failed!][Oops]"); return FALSE; } return TRUE; } /* * Function: restore_output * Returns: void * Description: Close redirected file handles and restore the originals. */ void restore_output() { if (outfh) { Fclose(outfh); outfh = 0; } Fforce(STDOUT,confh); } /* * Function: do_menuitem * Returns: void * Description: Respond to a user's menu action; dispatch appropriately. */ void do_menuitem(title,item) int title, item; { menu_tnormal(menubar,title,TRUE); menu_tnormal(menubar,item,TRUE); switch (item) { case MNABOUT : do_dialog(ABOUTBOX); return; case QUIT : g_clrscr(); rsrc_free(); appl_exit(); exit(0); case CHDIR : change_dir(); return; /* the help functions */ case WHATIS : do_dialog(FWHATIS); return; case HELPEX : frm_dsdial(h_ex, h_buttons, TRUE); return; case HELPREST : frm_dsdial(h_rest, h_buttons, TRUE); return; case HELPVIEW : frm_dsdial(h_view, h_buttons, TRUE); return; case HELPSPEC : frm_dsdial(h_spec, h_buttons, TRUE); return; /* the rest of the cases will spawn ZOO */ /* here are the adds */ case ADD : exzoo("-add",TRUE,"Choose file to add"); break; case MOVE : exzoo("-move",TRUE,"Choose file to move"); break; case BACKUP : exzoo("-backup",FALSE,NULL); break; case COMMENT : exzoo("-comment",FALSE,NULL); break; /* here are the extracts */ case EXTRACT : exzoo("x",FALSE,NULL); break; case PRINT : notimpl(); break; case PRINTPRN : notimpl(); break; case RESTORE : exzoo("x//",FALSE,NULL); break; case RELATIVE : exzoo("x.//",FALSE,NULL); break; case LIST : exzoo("-list",FALSE,NULL); break; case LISTPRN : if (prt_output()) { exzoo("-list",FALSE,NULL); restore_output(); } break; case TEST : exzoo("-test",FALSE,NULL); break; default: notimpl(); break; } } /* * Function: maintevent * Returns: void * Description: Call the GEMFAST evnx_multi function and wait for * a menu message. Pass the results to do_menuitem. * Note: This function uses the GEMFAST evnx_multi function, which is * available in C source code if you don't have GEMFAST. */ void mainevent() { XMULTI xm; int events; xm.mflags = MU_MESAG; while (1) { events = evnx_multi(&xm); if (events & MU_MESAG) if (xm.msgbuf[0] == MN_SELECTED) do_menuitem(xm.msgbuf[3], xm.msgbuf[4]); } } /* * Function: main * Returns: Only returns on failure, in which case an error value is set. * Description: Initialize GEM, load the resource, find ZOO, and otherwise * prepare for mainevent. */ main() { void g_clrscr(); char *pfindfile(); char *fullpath(); char *p; appl_init(); g_clrscr(); if (!load_resource(RESOURCE_FILE)) { appl_exit(); exit(-1); } rsrc_gaddr(0,MENUBAR, &menubar); menu_bar(menubar,TRUE); graf_mouse(ARROW,NULL); show_about(); cwd[0] = Dgetdrv() + 'A'; cwd[1] = ':'; Dgetpath(&cwd[2],(int)(cwd[0]-'A'+1)); if (access("ZOO.TTP",0)) p = fullpath(NULL,"ZOO.TTP"); else if (!(p = pfindfile(NULL,"ZOO.TTP",NULL))) { if (!fsel("Where is the ZOO program?","ZOO*.TTP",NULL,zoottp)) { form_alert(1,"[0][ZOO.TTP must be available][Exit]"); appl_exit(); exit(-1); } } strcpy(zoottp,p); strcat(zoottp," "); mainevent(); /* There should be no path to this, but just to be safe ... */ g_clrscr(); rsrc_free(); appl_exit(); } /* EOF */