/*** *disked.c - DISKED The DISK EDitor for MS(tm)-DOS. * *Copyright (c) 1991-1995, Gregg Jennings. All wrongs reserved. * P O Box 200, Falmouth, MA 02541-0200 * *Purpose: * Command module. * *Notice: * This progam may be freely used and distributed. Any distrubution * with modifications must retain the above copyright statement and * modifications noted. * No pulp-publication, in whole or in part, permitted without * permission (magazines or books). *******************************************************************************/ /* Versions: 2.7 25-Dec-1994 'y': view .SAV file (some command letter changes) 2.6 04-Sep-1994 ^T, find() changes, extern reference consolodation 2.5 18-Apr-1994 cleaning up of extern defs input/output function pointers 2.4 23-Jan-1994 moved all startup code to SETUP.C 2.3 19-Jan-1994 'removable' test 2.2 16-Jan-1994 '^Q', replaced 'moved' with 'disk_moved' 2.1 04-Jan-1994 Translate if !Files for startup, Borland 2.0 28-Nov-1993 Release Notes: Programming Notes: */ #include #include #include /* _MAX_DIR */ #include /* kbhit() */ #include /* isalpha() */ #include /* _dos_set_drive() */ #include /* for exist() */ #include /* getcwd(),chdir() */ #include /* spawnl() */ #include "disked.h" #include "mylib.h" #include "diskio.h" #include "keys.h" #include "alloc.h" #include "files.h" #include "error.h" #include "dirent.h" #include "direct.h" #include "console.h" #include "arrays.h" /* for find() */ enum FIND_ARGUMENTS { F_BUFFER, F_DISK, F_CASE = 0, F_NOCASE }; struct Msg ps[]={ /* for inputing a two argument commnd */ {" from ",6}, {" number ",3}, }; struct Msg ap[]={ /* for inputing a two argument commnd */ {" from ",3}, {" number ",3} }; struct Msg st[]={ /* three argument command 's' */ {" track ",3}, {" sector ",2}, {" head ",1} }; /* shared with SETUP.C only */ char comspec[FILENAME_MAX]; /* location of COMMAND.COM */ char promptvar[40]; /* DOS prompt variable */ char inifile[FILENAME_MAX]; /* INI file path/name */ char savfile[FILENAME_MAX]; /* Save file path/name */ char curdir[_MAX_DIR]; /* current working directory */ long set_sector; /* startup sector number */ int Save,Restore; int files_indexed; /* shared with SETUP.C and INIT.C */ int write_to; /* double protection on write */ unsigned long tagged[10]; /* shared with SETUP.C and DISKLIB.C */ int BigScreen; /* 50 line display */ unsigned int dir_cluster; /* start up directory cluster nu. */ /* shared with many */ unsigned int byte_cnt; /* buffer byte count */ unsigned int max_bytes; /* maximum buffer size */ unsigned char *save_sec; /* duplicate sector buffer */ unsigned char *spare_sec; /* spare sector buffer */ unsigned char *data_buf; /* pointer to area for data buffer */ #ifdef __BORLANDC__ #pragma argsused #endif #ifdef _MSC_VER #pragma warning(disable:4035; disable:4100) #endif int main(int argc,char **argv) { unsigned int c; char tmpstr[MAXSTR+1]; char ccurdir[_MAX_DIR]; unsigned int cdisk; register unsigned int u; /* vars for loops */ register int i; unsigned int temps,tempt,temph,tempu; long templ; int tempd; unsigned int bufptr; /* pointer to file buffer */ int drives[MAX_DRIVE+1]; /* valid drive number array 1-MAX_DRIVE */ int noput; char *bufferfull=" buffer full "; tmpstr[0] = '\0'; bufptr = 0; noput = TRUE; #ifdef __WATCOMC__ setvbuf(stdout,NULL,_IONBF,0); /* flush stdout every printf */ #endif #ifndef NDEBUG printf(""); /* for alloc/free debugging; MSC will call malloc */ /* during first printf() */ #endif error.num = -1; cdisk = setup(argv,drives,&disk); startup(ccurdir,cdisk); /* The rest of the code is one huge switch/case in a loop. (It is so big that MSC gives: "main() too big for global optimizations", but I can't see trimming it any more.) The interface I chose to use, a TTY or Teletype-like interface (which may seem out dated to some be I find it extremely easy to use), presents some programming constructs that are hard to keep consistant and can be confusing :-) DISKED WILL NEVER HAVE A "WINDOWED" OR GUI INTERFACE! (colors and sound board support might cool though) */ for (;;) { if (error.num != -1) { /*if (!Verify)*/ /* there's lots of these ' 's */ output(' '); /* it gets confusing and there may */ printerror(Debug); /* be others that aren't quite right */ } if (disk_moved) { disk_moved = 0; dumpsector(); } c = prompt(byte_cnt,Radix); /* translate movement keys if file tracking is on */ if (trackfile(&c) == -1) continue; switch (c) { case '!': output(' '); /* if "File not found" */ if (spawnl(P_WAIT,comspec,NULL)!=-1) disk_moved=1; /* display sector on return */ break; case F1: if (Files && n_files==1) print(" no files"); else { print(" Current Directory: %s\n",curdir); directory(); } break; case F2: if (!Files) break; if (n_files==1) { print(" no files"); break; } for (u = 1; u < n_files; u++) /* more than 32767 files ? */ { print("\n%s",gfile(u)); if (kbhit()) { if ((c=input())==0) input(); else if (c==0x1b) break; else if (c==' ') pause(); } } break; case SHFTF1: dump(sec_buf,0,sec_size,128,Radix); break; case SHFTF2: dumpf(sec_buf,sec_size,Radix); break; case SHFTF3: case 'V'-'@': view(sec_buf,0,sec_size,NOPAUSE,Radix); break; case SHFTF4: dumpdir(sec_buf,sec_size); break; case SHFTF5: dumpboot(sec_buf); break; case SHFTF6: help(); break; case SHFTF7: break; case F3: if (!Files) break; print(" %u Files, %u Directories",n_files-1,n_dirs); break; case F4: /* change dir */ if (Display) print("directory "); else print("cd "); if (getstr(tmpstr,MAXSTR,_ALPHA) < 1) break; if (_chdir(tmpstr) == -1) print(" not found"); _getcwd(curdir,_MAX_DIR); break; case F5: /* re-read */ readsector(); disk_moved = 1; break; case F6: case F7: case F8: case F9: if (byte_cnt > (max_bytes-sec_size)) break; if (Display) print("append w/"); tempt = temph = temps = 0; switch (c) { case F6: if (Display) print(StripTxt); temph = 1; break; case F7: if (Display) print(ConvertTxt); temps = 1; break; case F8: if (Display) print(MaskTxt); tempt = 1; break; case F9: if (Display) print("options"); tempt = Strip; temph = Mask; temps = Convert; break; default: break; } append(tempt,temph,temps,sec_buf,sec_size); break; case F0: if (!Files) break; if (n_files == 1) { print(" no files"); break; } if (Display) print("goto "); print("file: "); if (getstr(tmpstr,MAXSTR,_ALPHA) < 1) break; if ((tempu = findfile(tmpstr)) != 0) { setcluster(tempu); } else print(" not found"); break; case ALTA:case ALTC:case ALTD: case ALTF:case ALTG:case ALTH:case ALTL: case ALTM:case ALTP:case ALTS:case ALTB: case ALTV:case ALTW:case ALTT: setkeyword(c,kw); if (ft_track) Get = FALSE; break; case '*': Filter = !Filter; print("filter:%s",(Filter) ? "ON" : "OFF"); break; case 'T'-'@': if (!Files) break; if (ft_track != 0) { filetrack(NULL,0); print(" file unlocked"); break; } tempu = sectortocluster(log_sector); i = clusters[tempu]; if (i > 0 && (unsigned)i <= n_files) { char *b; if (Display || Verify) print(" track file "); if (Verify && !getver("",0)) break; print(" %s locked",b=gfile(i)); if ((i = filetrack(b,i)) != 1) print(" lock error %d",i); } break; /* **** Display **** */ case '\n': header(); break; case '\r': if (!Ascii && !BigScreen && Partial) dump(sec_buf,(sec_size==128)?(0):(128),sec_size, \ (sec_size==512)?(384):(sec_size),Radix); else disk_moved = 1; break; case ' ': disk_moved = 1; break; case '\b': dparams(curdir); output('\n'); break; case '/': disptext(command_text1); if (BigScreen) output('\n'); else break; case '?': disptext(command_text2); break; /* **** movement **** */ case 'Q'-'@': /* go back */ if (back_log_sector != log_sector) { if (Display) print(" go back"); setsector(back_log_sector); disk_moved = 1; } break; case 'H': /* go root */ if (Display) print(" root"); rootsector(); break; case HOME: /* go root or */ if (Display) /* go start */ print(" home"); if (set_sector != -1L) setsector(set_sector); else rootsector(); break; case 'E': /* go drive end */ case END: if (Display) print(" end"); lastsector(); break; case 'b': /* back sector */ case UP: if (Display) print(" back sector"); backsector(); break; case 'n': /* next sector */ case DOWN: if (Display) print(" next sector"); nextsector(); break; case 'B': /* back cluster */ case LEFT: if (Display) print(" back cluster"); backcluster(); break; case 'N': /* next cluster */ case RIGHT: if (Display) print(" next cluster"); nextcluster(); break; case 'B'-'@': /* back track */ case PGUP: if (Display) print(" back track"); backtrack(); break; case 'N'-'@': /* next track */ case PGDN: if (Display) print(" next track"); nexttrack(); break; case 'h': /* next head */ if (max_head==1) break; if (Display) print(" next head"); nexthead(); break; case 'r': /* range (continuous) */ case 'R': case CTRLR: if (c=='R') tempd=secs_cluster; else tempd=1; if (Display) { print(" range "); if (c==CTRLR) output('-'); putbyte(tempd); } tempd *= (c==CTRLR) ? -1 : 1; range(tempd); break; case '-': /* plus/minus sectors */ case '+': case '=': if (Display) print( (c=='-') ? " move back " : " move ahead "); if (getlnumb(num_sectors,&templ) <= 0) break; if (templ == 0) break; if (c=='-') templ *= -1; movesector(templ); break; case 'S'-'@': /* set to sector */ if (Display) print(" sector "); if (getlnumb(num_sectors,&templ) <= 0) break; setsector(templ); break; case 'S': /* set to cluster */ if (Display) print(" cluster "); if (getnumb(num_clusters,&tempu) <= 0) break; if (tempu < 2) break; setcluster(tempu); break; case 's': /* set physical */ tempt=track; temps=sector; temph=head; c=set(st,(int *)&tempt,(int *)&temps,(int *)&temph); if (c=='f') fatsector(); else if (c=='b') bootsector(); else if (c==0) break; else { if (tempt > max_track) tempt = track; if (temps > max_sector || temps==0) temps = sector; if (temph >= max_head) temph = head; if (tempt==track && temps==sector && temph==head) break; setphysical(tempt,temps,temph); } break; case SRIGHT: /* back/next free cluster */ case SLEFT: if (!Files) break; tempu=sectortocluster(log_sector); if (tempu==0) tempu=2; temps = (c==SLEFT) ? (-1) : (1); if (Display) { print( (temps==1) ? " next" : " back"); print(" free cluster"); } for (u=tempu+temps;;u+=temps) { if (u>=num_clusters) u=2; if (u<2) u=num_clusters; if (u==tempu) break; if (clusters[u] < 1) { setcluster(u); break; } } break; case CEND: /* end of file */ if (!Files) break; tempu = sectortocluster(log_sector); if (clusters[tempu] > 0 && (unsigned)clusters[tempu] <= n_files) { if (Display) print(" end file"); if ((tempu=arraylast(clusters,num_clusters,clusters[tempu])) == 0) break; setcluster(tempu); } break; case CHOME: /* start of file */ if (!Files) break; tempu=sectortocluster(log_sector); if (clusters[tempu] > 0 && (unsigned)clusters[tempu] <= n_files) { if (Display) print(" home file"); tempu=arrayfirst(clusters,num_clusters,clusters[tempu]); if (tempu == num_clusters) break; setcluster(tempu); } break; case 'j': /* back/next file cluster */ case 'J': case CLEFT: case CRIGHT: if (!Files) break; tempu = sectortocluster(log_sector); /* get current cluster */ temps = (c=='j' || c==CRIGHT) ? 1 : -1; /* set direction */ if (clusters[tempu] == 0) break; if ((u = arraytrav(clusters,num_clusters,tempu,temps)) == tempu) break; /* just one cluster? */ if (Display) { print((temps==1)?" next":" back"); print(" file's cluster"); } setcluster(u); /* got it */ break; /* **** Buffer stuff **** */ case 'a': if (byte_cnt==max_bytes) break; if (Display) print(" append sector"); if ((byte_cnt+sec_size)>max_bytes) { print(bufferfull); tempu=max_bytes-byte_cnt; } else tempu=sec_size; memcpy(data_buf+byte_cnt,sec_buf,tempu); byte_cnt+=tempu; break; case 'A': if (log_sector<=data_sector) break; if (byte_cnt==max_bytes) break; if (Display) print(" append cluster"); savesector(); i=clustersector(log_sector); /* goto 1st sector */ if (movesector(-i) != DISK_OK) { restoresector(); break; } for (u=0;;u++) /* get it loop */ { if ((byte_cnt+sec_size)>max_bytes) tempu=max_bytes-byte_cnt; else tempu=sec_size; memcpy(data_buf+byte_cnt,sec_buf,tempu); if ((byte_cnt+=tempu)==max_bytes) { print(bufferfull); break; } if (u == secs_cluster-1) break; if (nextsector() != DISK_OK) break; } restoresector(); if (readsector() != DISK_OK) disk_moved = 1; break; case 'A'-'@': if (byte_cnt==max_bytes) break; if (Display) print(" append bytes"); tempd=temps=0; /* tempd=from, temps=number */ if (!get(ap,&tempd,(int *)&temps)) break; if ((temps+tempd > sec_size) || temps==0) break; if (byte_cnt+temps > max_bytes) break; memcpy(data_buf+byte_cnt,sec_buf+tempd,temps); if ((byte_cnt+=temps)==max_bytes) print(bufferfull); break; case 'u': case 'U': if (byte_cnt==0) break; if (Display) { print(" unappend "); print((c=='u')?"sector":"cluster"); } tempu = (c=='u') ? sec_size : cluster_size; if (byte_cnt < tempu) byte_cnt = 0; else byte_cnt-=tempu; break; case 'U'-'@': if (byte_cnt==0) break; if (Display) print(" unappend bytes "); if (getnumb(byte_cnt,&tempu)<=0) break; if (byte_cnt < tempu) byte_cnt=0; else byte_cnt-=tempu; break; case 'e': case 'E'-'@': if (byte_cnt==0) break; if (Display || Verify) print(" empty buffer"); if (c=='e' && Verify && !getver("",0)) break; bufptr=byte_cnt=0; break; case 'k': if (save_sec==NULL) break; if (Display) print(" kill changes"); if (Verify && !getver("",0)) break; memcpy(sec_buf,save_sec,sec_size); disk_moved=1; break; case '>': if (spare_sec==NULL) break; if (Display || Verify) print(" store sector"); if (Verify && !getver("",0)) break; memcpy(spare_sec,sec_buf,sec_size); noput=FALSE; break; case '<': if (spare_sec == NULL) break; if (noput) { print(" no sector stored"); break; } if (Display || Verify) print(" retrieve sector"); if (Verify && !getver("",0)) break; memcpy(sec_buf,spare_sec,sec_size); disk_moved = 1; break; case 'd': case 'v': if (byte_cnt == 0) break; if (Display) { print((c == 'd') ? " dump" : " view"); print(" file buffer from "); } if ((tempd = getlnumb(byte_cnt,&tempu)) == ABORT) break; if (tempd > 0) bufptr = tempu; if (c == 'd') { output('\n'); bufptr = dump(data_buf,bufptr,byte_cnt,256,Radix); output('\n'); } else bufptr = view(data_buf,bufptr,byte_cnt,PAUSE,Radix); break; case 'c': if (Display) print(" change sector buffer from "); if (change(sec_buf,sec_size,Radix)) disk_moved = 1; break; case 'C': if (!byte_cnt) break; if (Display) print(" change file buffer from "); change(data_buf,byte_cnt,Radix); break; case 'D'-'@': case 'C'-'@': if (changedir(sec_buf,sec_size)) disk_moved = 1; break; case 'g': /*** get sectors ***/ case 'G'-'@': /* uses tempd, tempt, i */ if (byte_cnt == max_bytes) /* full? */ break; if (Display) /* display */ { print(" get sectors "); if (c == 'G'-'@' || Get) print("w/move "); } /* get number */ if (getbyte(&tempu) <= 0) break; /* tempd = number to get */ savesector(); if (tempu==0) /* 0 = get whole track from beginning */ { tempu=max_sector; /* count to get */ log_sector=logicalsector(track,1,head); } else if (tempu == 1) /* get rest of track */ tempu = (max_sector - sector) + 1; if (log_sector == 0) log_sector = num_sectors-1; else --log_sector; if (Display) output(' '); for (i = 1 ; i <= (int)tempu ; i++) { if (kbhit()) break; if (Display) { pn(i,Radix); put(len(i),8); } if ((tempd=nextsector()) != DISK_OK) { savecursor(); if (!Display) output(' '); printerror(Debug); if (!getver("continue",0)) { put(3,8); break; } restcursor(); clreol(); } if ((byte_cnt+sec_size)>max_bytes) break; memcpy(data_buf+byte_cnt,sec_buf,sec_size); if ((byte_cnt+=sec_size)==max_bytes) { print(bufferfull); break; } } if (Display && tempd == DISK_OK) clreol(); if (Get || c=='G'-'@') nextsector(); else { restoresector(); readsector(); disk_moved = 0; } break; /* **** Log Drive **** */ case 'l': case 'L'-'@': if (c == 'l') { if (Display) print(" disk "); c = input(); if (!isalpha(c)) break; tempd = toupper(c)-'@'; if (drives[tempd]!=TRUE) break; output(toupper(c)); output(':'); if (Verify) { if (!getver("log disk",MOV_YN)) break; } } else tempd = disk; if (newdisk(tempd)) { disk = tempd; if (avail_clusters == 0) avail_clusters = get_avail_clusters(); dparams(curdir); } if (error.num != -1) /* if theres gonna be an error */ { if (disk_moved == 1) { output('\n'); /* put it on a new line */ output('\n'); } /* if its bad BOOT, reset diskio flag */ if (strcmp(error.func,"diskio") == 0) diskio_error = 0; } break; /* **** Misc. **** */ case 'T': for (i=1;i<10;i++) if (tagged[i]!=0L) break; if (i<10) { if (Display) print(" tagged sector list"); for (i=1;i<10;i++) { if (!tagged[i]) continue; output(' '); output(i+'0'); output(':'); pln(tagged[i],Radix); } } else if (Display) print(" no tagged sectors"); break; case 't': if (Display) print(" number of this tag? "); if ((c=input()) < '0' || c > '9') break; output(c); if (c == '0') { if (getver(" clear all",0)) memset(tagged,0,sizeof(tagged)); break; } tagged[c-'0']=log_sector; break; case 'f': case '\\': if (Display) print(" find "); tempd = find(F_DISK,1,(c=='f') ? F_CASE : F_NOCASE); if (tempd>=0) { print("\nfound at "); pn(tempd,Radix); } if (tempd!=ABORT) /* user pressed ESC */ readsector(); break; case 'F': case 'F'-'@': if (byte_cnt==0) break; if (Display) print(" find "); if (find(F_BUFFER,1,(c=='F') ? F_CASE : F_NOCASE) == -1) print(" not found"); break; case 'P': if (Display) print(" put"); templ=log_sector; temps=0; /* templ=from, temps=number */ if (!getl(ps,&templ,(int *)&temps)) break; if (templ+(long)temps > (long)num_sectors) break; if (Display) print(" file: "); else output(':'); if (getstr(tmpstr,64,_ALPHA) > 0) { if (Verify) { if (!getver(" put file",MOV_YN)) break; } if (exist(tmpstr)) { savecursor(); if (!Verify) output(' '); if (!getver("exists, overwrite",MOV_YN)) break; restcursor(); clreol(); } if (error.num == -1) { if (Display && !Verify) output(' '); else if (Display && Verify) { put(3,' '); put(3,8); } putsectors(tmpstr,templ,temps); readsector(); } } break; case 'P'-'@': case 'p': if (byte_cnt==0) break; if (Display) print(" file: "); getstr(tmpstr,64,_ALPHA); if (!tmpstr[0]) break; if (Verify) { print(" put file "); if (Display && c=='p') print("w/options"); else if (Display) print("w/o options"); if (!getver("",MOV_YN)) break; } if (access(tmpstr,0) == 0) { savecursor(); if (!Verify) output(' '); if (!getver("exists, overwrite",MOV_YN)) break; restcursor(); clreol(); if (unlink(tmpstr) == -1) break; } if (error.num != -1) break; if (Display) { savecursor(); if (!Verify) output(' '); print("putting"); restcursor(); } putfile(tmpstr,(c=='p') ? XLATE : NOXLATE,Mask,Strip,Convert); break; case 'I'-'@': case 'i': if (byte_cnt==max_bytes) break; if (Display) print(" file: "); getstr(tmpstr,64,_ALPHA); if (!tmpstr[0]) break; if (Verify) { print(" insert file "); if (Display && c=='i') print("w/options"); else if (Display) print("w/o options"); if (!getver("",MOV_YN)) break; } if (Display) { savecursor(); if (!Verify) output(' '); print("inserting"); restcursor(); } tempd=getfile(tmpstr, (c=='i') ? XLATE : NOXLATE,Mask,Strip,Convert); if (tempd == -2) { if (!Verify) output(' '); print("buffer full "); } break; case 'w': if (!write_to || !Write) { print(" write not enabled"); break; } if (Display || Verify) print(" write sector"); if (log_sector0) ckey(tmpstr,kw); break; case '0':case '1':case '2':case '3': case '4':case '5':case '6':case '7': case '8':case '9': c-=0x30; if (!tagged[c]) break; if (Display || Verify) { print(" goto sector "); pln(tagged[c],Radix); } if (Verify && !getver("",0)) break; if (log_sector != tagged[c]) { log_sector = tagged[c]; readsector(); disk_moved = 1; } break; case ',': /* toggle radix */ if (Radix==10) Radix=16; else Radix=10; if (Display) { print(" radix is now "); print((Radix==16)?"hex":"dec"); } break; case 'D': if (Debug) debug(); break; case 'm': if (!Files) break; tempu = sectortocluster(log_sector); if (clusters[tempu] > 0 && (unsigned)clusters[tempu] <= n_files) { if (Display) print(" map file "); print(gfile(clusters[tempu])); output('\n'); arraymap(clusters,num_clusters,clusters[tempu],Radix); } break; case 'M': if (Files) { if (Display) print(" map free space"); output('\n'); if (arraymap(clusters,num_clusters,0,Radix) == 0) print(" no free space"); } break; case 'I': if (!Files) break; tempd = sectortocluster(log_sector); if (clusters[tempd] < 0 || clusters[tempd] > (int)n_files) break; if (files[clusters[tempd]].dir) { print(" can not insert directories"); break; } sprintf(tmpstr,gfile(clusters[tempd])); if (Display) { print(" insert file "); print(tmpstr); } if (Verify) { if (!getver("",0)) break; } if (Display) { savecursor(); if (!Verify) output(' '); print("inserting"); restcursor(); } if (getfile(tmpstr,XLATE,Mask,Strip,Convert) == -2) { if (!Verify) output(' '); print("buffer full "); } break; case 'Y'-'@': if (Display && !Verify) print(" saving"); else if (Verify && !getver(" save",0)) break; saveinit(savfile); break; case 'Y': if (Display && !Verify) print(" restoring"); else if (Verify && !getver(" restore",0)) break; tempd = Home; Home = FALSE; tempt = disk; templ = log_sector; if (getinit(savfile,INIT_RESTORE)) { if (tempt != disk) { if (!newdisk(disk)) { disk = tempt; log_sector = templ; } } else if ((unsigned long)templ != log_sector) readsector(); else if (Display) output('\n'); disk_moved = 1; } else { disk = tempt; log_sector = tempu; } Home = tempd; break; case 'x': viewfile(inifile,Display); break; case 'y': getinit(savfile,INIT_VIEW); break; case 'q': case '.': case ESC: case ALTX: if (Display || Verify) print(" exit DISKED"); if (c != ALTX && Verify && !getver("",0)) break; _dos_setdrive(cdisk,&tempu); if (ccurdir[0]) _chdir(ccurdir); if (Save && c != ALTX) { if (Verify) if (!getver(" save",1)) break; if (Display) print(" saving..."); saveinit(savfile); } if (files_indexed) /* free calls are for an IDE */ { /* such as QuickC that I use */ hugefreep(files); /* which can get confused if */ hugefreep(clusters); /* if you don't do this */ } if (spare_sec) freep(spare_sec); if (save_sec) freep(save_sec); freep(sec_buf); freep(data_buf); exit(0); break; default: break; } } }