home *** CD-ROM | disk | FTP | other *** search
/ ProfitPress Mega CDROM2 …eeware (MSDOS)(1992)(Eng) / ProfitPress-MegaCDROM2.B6I / UTILITY / DISK / RESTAUR1.ZIP / RESTAUR.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1991-03-24  |  27.8 KB  |  748 lines

  1. Program restaur;
  2. { More versatile replacement for DOS RESTORE.                                }
  3. { Handles backups made by DOS versions 2.0..4.01                             }
  4. { Free Software by TapirSoft Gisbert W.Selke, 24/03/91                       }
  5. {$A+,B-,D+,E+,F-,I-,L+,N-,O-,R-,S-,V- }
  6. {$M 16384,0,75000 }
  7.  
  8.   Uses DOS;
  9.  
  10.   Const progname  = 'RESTAUR';
  11.         version   = '0.9';
  12.         copyright = 'Free Software by TapirSoft Gisbert W.Selke, Mar 1991';
  13.         bufsize   = 65000;
  14.         CtrlC     = #3;
  15.         CR        = #13;
  16.         Esc       = #27;
  17.  
  18.   Type  namestring = string[80];
  19.  
  20.        fileheader32 = Record
  21.                         lastone  : byte;
  22.                         partno   : word;
  23.                         dummy1   : word;
  24.                         origname : Array [1..77] Of char;
  25.                         orignamelength : byte;
  26.                         dummy2   : Array [1..45] Of byte;
  27.                       End;
  28.  
  29.        controlheader33 = Record
  30.                            headerlen  : byte;
  31.                            backupname : Array [1..8] Of char;
  32.                            diskno     : word;
  33.                            dummy      : Array [1..128] Of byte;
  34.                          End;
  35.  
  36.        direntry = Record
  37.                     dirname  : Array [1..63] Of char;
  38.                     nentries : word;
  39.                     dummy    : Array [1..4] Of byte;
  40.                   End;
  41.  
  42.        fileentry = Record
  43.                      filename : Array [1..12] Of char;
  44.                      dummy1 : byte;
  45.                      origlen : longint;
  46.                      partno : word;
  47.                      fileoffset : longint;
  48.                      entrylen : longint;
  49.                      attr : byte;
  50.                      dummy2 : byte;
  51.                      datetime : longint;
  52.                    End;
  53.  
  54.        fileinfo = Record
  55.                     oridir, dir, name : namestring;
  56.                     orilen, offset, oridate : longint;
  57.                     partnumber : word;
  58.                     attrib : byte;
  59.                    End;
  60.  
  61.        countryinfo = Record { really, only MSDOS 2.x+, PCDOS 3.0+ }
  62.                        datefmt     : word;
  63.                        currencystr : Array [1..5] Of char;
  64.                        thousandsep : char;
  65.                        fill1       : byte;
  66.                        decimal     : char;
  67.                        fill2       : byte;
  68.                        datesep     : char;
  69.                        fill3       : byte;
  70.                        timesep     : char;
  71.                        fill4       : byte;
  72.                        currencyfmt : byte;
  73.                        currencydig : byte;
  74.                        timefmt     : byte;
  75.                        casemapptr  : Pointer;
  76.                        datalistsep : char;
  77.                        fill5       : byte;
  78.                        fill6       : Array [1..10] Of byte;
  79.                      End;
  80.  
  81.        iobuffer = Array [1..bufsize] Of byte;
  82.  
  83.   Var backupfile, controlfile, destfile : File;
  84.       backupname, controlname, myname, backupid, curorigdir : namestring;
  85.       source, destination : namestring;
  86.       bufptr : ^iobuffer;
  87.       ctrlhead33 : controlheader33;
  88.       dir33 : direntry;
  89.       fil33 : fileentry;
  90.       fil32 : fileheader32;
  91.       countryinf : countryinfo;
  92.       searchr32 : SearchRec;
  93.       exitsave : Pointer;
  94.       disknumber, nfiles, foundct : word;
  95.       backupversion : byte;
  96.       all, overwrite, origdir, firstone, quit, isopenbackup,
  97.       isopencontrol, isopendest : boolean;
  98.  
  99.   {$F+ } Procedure myexit; {$F- }
  100.   { catch all programme exits                                                }
  101.   Begin                                                             { myexit }
  102.     ExitProc := exitsave;
  103.     If isopencontrol Then Close(controlfile);
  104.     If isopenbackup Then Close(backupfile);
  105.     If isopendest Then Close(destfile);
  106.   End;                                                              { myexit }
  107.  
  108.   Function UpCase(ch:char):char;
  109.   { adapted from Arne Schäpers, TurboPascal 4.0 - Tips und Tricks            }
  110.     Inline($58/$3C/$61/$72/$39/$3C/$7A/$76/$33/$3C/$84/$75/$02/$B0/$8E
  111.     /$3C/$94/$75/$02/$B0/$99/$3C/$81/$75/$02/$B0/$9A
  112.     /$3C/$87/$75/$02/$B0/$80/$3C/$86/$75/$02/$B0/$8F
  113.     /$3C/$82/$75/$02/$B0/$90/$3C/$91/$75/$02/$B0/$92
  114.     /$3C/$A4/$75/$02/$B0/$A5/$EB/03/90/$2C/$20);
  115.  
  116.   Function readkey : char;
  117.   { emulate CRT ReadKey                                                      }
  118.     Var regs : registers;
  119.   Begin                                                            { ReadKey }
  120.     With regs Do
  121.     Begin
  122.       ah := $07;
  123.       Intr($21,regs);
  124.       ReadKey := char(al);
  125.     End;
  126.   End;                                                             { ReadKey }
  127.  
  128.   Procedure clearline;
  129.   { wipe clear current line                                                  }
  130.   Begin                                                          { clearline }
  131.     write(CR,' ':79,CR);
  132.   End;                                                           { clearline }
  133.  
  134.   Procedure usage(err : byte);
  135.   { show help and die                                                        }
  136.   Begin                                                              { usage }
  137.     If IOResult <> 0 Then;
  138.     writeln;
  139.     writeln('Restores DOS backups selectively, both DOS pre-3.3 and after');
  140.     writeln;
  141.     writeln('Usage:  ',myname,'  <sourcedrive> <destinationpath> [<options>]');
  142.     writeln('  If <destinationpath> is just a drive,');
  143.     writeln('  the original directory structure is preserved.');
  144.     writeln('  Options are: /a : all files, no questions; /o : overwrite ',
  145.             'existing files.');
  146.     Halt(err);
  147.   End;                                                               { usage }
  148.  
  149.   Procedure error(s : string; err : byte; showusage : boolean);
  150.   { show error message, maybe usage hints, then die                          }
  151.   Begin                                                              { error }
  152.     If IOResult <> 0 Then;
  153.     writeln;
  154.     writeln(progname,' ',version,': ',s);
  155.     If showusage Then usage(err);
  156.     Halt(err);
  157.   End;                                                               { error }
  158.  
  159.   Procedure getcountryinfo;
  160.   { glean date/time format info from DOS                                     }
  161.     Var regs : Registers;
  162.   Begin                                                     { getcountryinfo }
  163.     With regs Do
  164.     Begin
  165.       With countryinf Do
  166.       Begin
  167.         datesep := #0;
  168.         timesep := #0;
  169.         timefmt := 0;
  170.         ax := $3800;
  171.         ds := Seg(countryinf);
  172.         dx := Ofs(countryinf);
  173.         Intr($21,regs);
  174.         If (flags And FCarry) <> 0 Then datefmt := 1;
  175.         If datefmt > 2 Then datefmt := 1;
  176.         If datesep < ' ' Then datesep := '/';
  177.         If timesep < ' ' Then timesep := ':';
  178.         If timefmt > 1 Then timefmt := 1;
  179.       End;
  180.     End;
  181.   End;                                                      { getcountryinfo }
  182.  
  183.   Function intstr(w : word; digs : byte) : string;
  184.   { turns number into a astring, given exact number of digits                }
  185.     Var temp : string;
  186.   Begin                                                             { intstr }
  187.     Str(w,temp);
  188.     While Length(temp) < digs Do temp := '0' + temp;
  189.     Delete(temp,Succ(digs),255);
  190.     intstr := temp;
  191.   End;                                                              { intstr }
  192.  
  193.   Procedure opencontrolfile(Var success : boolean);
  194.   { open files containing general info                                       }
  195.  
  196.     Var sr : SearchRec;
  197.         bytesread : word;
  198.         savefm, i : byte;
  199.  
  200.   Begin                                                    { opencontrolfile }
  201.     savefm := FileMode;
  202.     FileMode := 0;
  203.     success := False;
  204.     curorigdir := '';
  205.     If backupversion = $33 Then
  206.     Begin
  207.       If isopenbackup Then Close(backupfile);
  208.       If isopencontrol Then Close(controlfile);
  209.       isopenbackup  := False;
  210.       isopencontrol := False;
  211.       FindFirst(source+'\CONTROL.*',AnyFile-Directory-VolumeID,sr);
  212.       If DOSError = 0 Then
  213.       Begin
  214.         Assign(controlfile,source+'\'+sr.name);
  215.         Reset(controlfile,1);
  216.         If IOResult <> 0 Then error('Error opening backup file',4,False);
  217.         isopencontrol := True;
  218.         BlockRead(controlfile,ctrlhead33,SizeOf(ctrlhead33),bytesread);
  219.         If SizeOf(ctrlhead33) <> bytesread Then error(
  220.                                      'Invalid control file format',4,False);
  221.         With ctrlhead33 Do
  222.         Begin
  223.           i := 1;
  224.           backupid := '';
  225.           While (i<=SizeOf(backupname)) And (backupname[i] >= ' ') Do
  226.           Begin
  227.             backupid := backupid + backupname[i];
  228.             Inc(i);
  229.           End;
  230.           disknumber := diskno;
  231.         End;
  232.         success := True;
  233.       End;
  234.     End
  235.     Else
  236.     Begin
  237.       firstone := True;
  238.       success := True;
  239.     End;
  240.     FileMode := savefm;
  241.   End;                                                     { opencontrolfile }
  242.  
  243.   Procedure getnextname(Var filinf1 : fileinfo; Var foundone : boolean);
  244.   { get name of file to be restored next                                     }
  245.     Var len, i : byte;
  246.         bytesread : word;
  247.   Begin                                                        { getnextname }
  248.     If backupversion = $33 Then
  249.     Begin
  250.       foundone := False;
  251.       Repeat
  252.         BlockRead(controlfile,len,1,bytesread);
  253.         If bytesread = 0 Then Exit;
  254.         If bytesread <> 1 Then error('Invalid control file format',4,False);
  255.         Case len Of
  256.           34 : Begin { file entry proper }
  257.                  BlockRead(controlfile,fil33,SizeOf(fil33),bytesread);
  258.                  If bytesread <> SizeOf(fil33) Then
  259.                                error('Invalid control file format',4,False);
  260.                  foundone := True;
  261.                  With fil33 Do
  262.                  Begin
  263.                    With filinf1 Do
  264.                    Begin
  265.                      dir := curorigdir;
  266.                      oridir := curorigdir;
  267.                      name := '';
  268.                      i := 1;
  269.                      While (i <= Length(filename)) And (filename[i] >= ' ') Do
  270.                      Begin
  271.                        name := name + filename[i];
  272.                        Inc(i);
  273.                      End;
  274.                      orilen := origlen;
  275.                      partnumber := partno;
  276.                      offset := fileoffset;
  277.                      attrib := attr;
  278.                      oridate := datetime;
  279.                    End;
  280.                  End;
  281.                End;
  282.           70 : Begin { directory entry }
  283.                  BlockRead(controlfile,dir33,SizeOf(dir33),bytesread);
  284.                  If bytesread <> SizeOf(dir33) Then
  285.                                  error('Invalid control file format',4,False);
  286.                  i := 1;
  287.                  curorigdir := '';
  288.                  With dir33 Do
  289.                  Begin
  290.                    While (i <= Length(dirname)) And (dirname[i] >= ' ') Do
  291.                    Begin
  292.                      curorigdir := curorigdir + dirname[i];
  293.                      Inc(i);
  294.                    End;
  295.                    nfiles := nentries;
  296.                  End;
  297.                End;
  298.         End;
  299.       Until foundone;
  300.     End
  301.     Else
  302.     Begin
  303.       Repeat
  304.         If firstone Then FindFirst(source+'\*.*',
  305.                                    AnyFile-Directory-VolumeId,searchr32)
  306.                     Else FindNext(searchr32);
  307.         firstone := False;
  308.       Until searchr32.name <> 'BACKUPID.@@@';
  309.       If DOSError = 0 Then
  310.       Begin
  311.         foundone := True;
  312.         i := FileMode;
  313.         FileMode := 0;
  314.         Assign(backupfile,source+'\'+searchr32.name);
  315.         Reset(backupfile,1);
  316.         FileMode := i;
  317.         BlockRead(backupfile,fil32,SizeOf(fil32),bytesread);
  318.         If bytesread <> SizeOf(fil32) Then error('Invalid DOS 3.2 backup file',
  319.                                                  3,False);
  320.         With fil32 Do
  321.         Begin
  322.           With filinf1 Do
  323.           Begin
  324.             oridate := searchr32.time;
  325.             partnumber := partno;
  326.             If lastone = 0 Then orilen := -1
  327.                            Else orilen := -2;
  328.             attrib := 0;
  329.             dir := '';
  330.             name := '';
  331.             i := 1;
  332.             While (i <= SizeOf(origname)) And (origname[i] >= ' ') Do
  333.             Begin
  334.               If origname[i] In ['\','/'] Then
  335.               Begin
  336.                 If dir <> '' Then dir := dir + '\';
  337.                 dir := dir + name;
  338.                 name := '';
  339.               End
  340.                 Else name := name + origname[i];
  341.               Inc(i);
  342.             End;
  343.             oridir := dir;
  344.           End;
  345.         End;
  346.       End
  347.         Else foundone := False;
  348.     End;
  349.     If foundone Then
  350.     Begin
  351.       With filinf1 Do
  352.       Begin
  353.         If (dir <> '') And (dir[Length(dir)] <> '\') Then dir := dir + '\';
  354.         If (oridir <> '') And (oridir[Length(oridir)] <> '\') Then
  355.                                                     oridir := oridir + '\';
  356.         If origdir Then dir := destination+dir
  357.                    Else dir := destination;
  358.       End;
  359.     End;
  360.   End;                                                         { getnextname }
  361.  
  362.   Procedure restoreone(filinf1 : fileinfo);
  363.   { restore a single file                                                    }
  364.  
  365.     Var ch : char;
  366.  
  367.     Procedure offerfile(filinf2 : fileinfo);
  368.     { offer file for restoration                                             }
  369.  
  370.       Var dt : DateTime;
  371.  
  372.       Procedure showtime(dt : DateTime);
  373.       { show date and time on OUTPUT                                         }
  374.       Begin                                                       { showtime }
  375.         With dt Do
  376.         Begin
  377.           With countryinf Do
  378.           Begin
  379.             Case datefmt Of
  380.               0  : write(intstr(month,2),datesep,intstr(day,2),datesep,
  381.                          intstr(year Mod 100,2));
  382.               2  : write(intstr(year Mod 100,2),datesep,intstr(month,2),datesep,
  383.                          intstr(day,2));
  384.               Else write(intstr(day,2),datesep,intstr(month,2),datesep,
  385.                          intstr(year Mod 100,2));
  386.             End;
  387.             write(' ');
  388.             If timefmt = 0 Then
  389.             Begin
  390.               If hour <= 12 Then write(intstr(hour,2),timesep,
  391.                                        intstr(min,2),'a.m.')
  392.                             Else write(intstr(hour-12,2),timesep,
  393.                                        intstr(min,2),'p.m.');
  394.             End
  395.               Else write(intstr(hour,2),timesep,intstr(min,2));
  396.           End;
  397.         End;
  398.       End;                                                        { showtime }
  399.  
  400.     Begin                                                        { offerfile }
  401.       With filinf2 Do
  402.       Begin
  403.         write('Restore ',oridir+name,', ');
  404.         If orilen >= 0 Then write('size ',orilen,', ');
  405.         UnpackTime(oridate,dt);
  406.       End;
  407.       showtime(dt);
  408.       writeln(', to ',filinf2.dir);
  409.       write('Copy/Rename/Destination/Skip/Quit/All? ');
  410.       Repeat
  411.         If all Then ch := 'A'
  412.                Else ch := UpCase(ReadKey);
  413.       Until ch In ['C','Y','1','D','R','S','Q',Esc,CtrlC,'A'];
  414.       If ch In [Esc,CtrlC] Then ch := 'Q';
  415.       writeln(ch);
  416.       Case ch Of
  417.         'K', 'Y', '1' : ch := 'C';
  418.         'N', '0' : ch := 'S';
  419.         Else ;
  420.       End;
  421.     End;                                                         { offerfile }
  422.  
  423.     Procedure rename(Var filinf2 : fileinfo);
  424.     { offer file for renaming                                                }
  425.       Var newname : namestring;
  426.     Begin                                                           { rename }
  427.       clearline;
  428.       write('Old name: ',filinf2.name,'; new name (ENTER to keep): ');
  429.       readln(newname);
  430.       If newname <> '' Then filinf2.name := newname;
  431.     End;                                                            { rename }
  432.  
  433.     Procedure changedest(Var filinf2 : fileinfo);
  434.     { change file destination                                                }
  435.       Var newdest : namestring;
  436.     Begin                                                       { changedest }
  437.       clearline;
  438.       write('Destination: ',filinf2.dir,'; new destination (ENTER to keep): ');
  439.       readln(newdest);
  440.       If newdest <> '' Then
  441.       Begin
  442.         If newdest[Length(newdest)] <> '\' Then newdest := newdest + '\';
  443.         filinf2.dir := newdest;
  444.       End;
  445.     End;                                                        { changedest }
  446.  
  447.     Procedure makedirs(dirs : namestring);
  448.     { make directories as specified by dirs, if necessary and possible       }
  449.       Var dir1, savedir, absdir, temp : namestring;
  450.           l : byte;
  451.     Begin                                                         { makedirs }
  452.       absdir := '';
  453.       GetDir(0,savedir);
  454.       If dirs[Length(dirs)] <> '\' Then dirs := dirs + '\';
  455.       While dirs <> '' Do
  456.       Begin
  457.         l := Pos('\',dirs);
  458.         dir1 := Copy(dirs,1,Pred(l));
  459.         Delete(dirs,1,l);
  460.         absdir := absdir + dir1 + '\';
  461.         If (Length(dir1) = 2) And (dir1[2] = ':') Then dir1 := dir1 + '\';
  462.         ChDir(dir1);
  463.         If IOResult <> 0 Then
  464.         Begin
  465.           MkDir(dir1);
  466.           If IOResult <> 0 Then
  467.           Begin
  468.             ChDir(savedir);
  469.             error('Cannot create '+absdir,6,False);
  470.           End;
  471.           ChDir(dir1);
  472.         End;
  473.       End;
  474.       ChDir(savedir);
  475.     End;                                                          { makedirs }
  476.  
  477.     Procedure checkexistfile(Var filinf2 : fileinfo);
  478.     { check existence of file; if necessary, offer skip/rename/destination   }
  479.       Var sr : SearchRec;
  480.     Begin                                                   { checkexistfile }
  481.       With filinf2 Do
  482.       Begin
  483.         FindFirst(dir+name,AnyFile,sr);
  484.         If DOSError = 0 Then
  485.         Begin
  486.           clearline;
  487.           writeln('File ',dir+name,' already exists.');
  488.           write('Overwrite/Rename/Destination/Skip? ');
  489.           If overwrite Then ch := 'O'
  490.           Else
  491.           Begin
  492.             Repeat
  493.               ch := UpCase(ReadKey);
  494.               If ch In [Esc,CtrlC] Then ch := 'S';
  495.             Until ch In ['O','R','D','S'];
  496.           End;
  497.           write(ch);
  498.           If ch = 'O' Then ch := 'C';
  499.         End
  500.           Else ch := 'C';
  501.       End;
  502.     End;                                                    { checkexistfile }
  503.  
  504.     Procedure restorefile(filinf2 : fileinfo);
  505.     { do the restoration                                                     }
  506.  
  507.       Var sr : SearchRec;
  508.           done : longint;
  509.           toread, bytesread : word;
  510.           i : byte;
  511.  
  512.       Procedure opensourcefile;
  513.       { open and position the file containing the backup data                }
  514.       Begin                                                 { opensourcefile }
  515.         If backupversion = $33 Then
  516.         Begin
  517.           If Not isopenbackup Then
  518.           Begin
  519.             FindFirst(source+'\BACKUP*.*',AnyFile-Directory-VolumeId,sr);
  520.             If DOSError <> 0 Then error('Backup file missing from diskette',
  521.                                         7,False);
  522.             i := FileMode;
  523.             FileMode := 0;
  524.             Assign(backupfile,source+sr.name);
  525.             Reset(backupfile,1);
  526.             If IOResult <> 0 Then error('Cannot open backup file',7,False);
  527.             FileMode := i;
  528.             isopenbackup := True;
  529.           End;
  530.           Seek(backupfile,filinf2.offset);
  531.         End
  532.         Else
  533.         Begin
  534.           Seek(backupfile,SizeOf(fileheader32));
  535.         End;
  536.       End;                                                  { opensourcefile }
  537.  
  538.       Procedure getnewsourcedisk;
  539.       { backup fil stretches disks; get next disk                            }
  540.         Var filinf3 : fileinfo;
  541.             ch : char;
  542.             success, foundname : boolean;
  543.       Begin                                               { getnewsourcedisk }
  544.         If backupversion = $33 Then Close(controlfile);
  545.         Close(backupfile);
  546.         isopenbackup := False;
  547.         isopencontrol := False;
  548.         Repeat
  549.           Repeat
  550.             write(CR,'Please insert next disk for part ',
  551.                   Succ(filinf2.partnumber),', then hit space bar: ');
  552.             ch := UpCase(ReadKey);
  553.             If ch In [CtrlC, Esc, 'Q'] Then error(
  554.                                    'Restoration terminated by user',9,False);
  555.             clearline;
  556.             opencontrolfile(success);
  557.           Until success;
  558.           Repeat
  559.             getnextname(filinf3,foundname);
  560.             success := False;
  561.             If foundname Then
  562.             Begin
  563.               If (filinf2.name   = filinf3.name) And
  564.                  (filinf2.oridir = filinf3.oridir) Then
  565.               Begin
  566.                 If Succ(filinf2.partnumber) = filinf3.partnumber Then
  567.                                                                success := True
  568.                 Else
  569.                 Begin
  570.                   writeln(CR,'Looking for part #',Succ(filinf2.partnumber),
  571.                           ' but found part #',filinf3.partnumber);
  572.                 End;
  573.               End;
  574.             End;
  575.           Until success Or Not foundname;
  576.         Until success And foundname;
  577.         filinf2 := filinf3;
  578.         opensourcefile;
  579.       End;                                                { getnewsourcedisk }
  580.  
  581.       Procedure opendestfile;
  582.       { opens the file to be restored                                        }
  583.       Begin                                                   { opendestfile }
  584.         With filinf2 Do
  585.         Begin
  586.           Assign(destfile,dir+name);
  587.           Rewrite(destfile,1);
  588.           If IOResult <> 0 Then error('Cannot open output file '+
  589.                                dir+name+' for output',8,False);
  590.         End;
  591.         isopendest := True;
  592.       End;                                                    { opendestfile }
  593.  
  594.     Begin                                                      { restorefile }
  595.       clearline;
  596.       opensourcefile;
  597.       opendestfile;
  598.       done := 0;
  599.       With filinf2 Do
  600.       Begin
  601.         While (done < orilen) Or (orilen < 0) Do
  602.         Begin
  603.           toread := bufsize;
  604.           If (orilen >= 0) And (toread > orilen-done) Then
  605.                                                        toread := orilen - done;
  606.           Repeat
  607.             BlockRead(backupfile,bufptr^,toread,bytesread);
  608.             If bytesread = 0 Then
  609.             Begin
  610.               If orilen = -2 Then orilen := done
  611.                              Else getnewsourcedisk;
  612.             End;
  613.           Until (bytesread <> 0) Or (orilen <= done);
  614.           BlockWrite(destfile,bufptr^,bytesread,toread);
  615.           If IOResult <> 0 Then error('Error writing output file',9,False);
  616.           done := done + bytesread;
  617.           If orilen > 0 Then write(CR,done/orilen*100:3:0,'%')
  618.                         Else write(CR,(done+1023) ShR 10,'KB');
  619.         End;
  620.       End;
  621.       clearline;
  622.       SetFTime(destfile,filinf2.oridate);
  623.       Close(destfile);
  624.       isopendest := False;
  625.       Close(backupfile);
  626.       isopenbackup := False;
  627.     End;                                                       { restorefile }
  628.  
  629.   Begin                                                         { restoreone }
  630.     Inc(foundct);
  631.     offerfile(filinf1);
  632.     If ch = 'Q' Then
  633.     Begin
  634.       quit := True;
  635.       Exit;
  636.     End;
  637.     If ch = 'A' Then all := True;
  638.     Repeat
  639.       If ch = 'S' Then Exit;
  640.       If ch = 'R' Then rename(filinf1);
  641.       If ch = 'D' Then changedest(filinf1);
  642.       If (filinf1.dir <> '') And ((Length(filinf1.dir) <> 2) Or
  643.          (filinf1.dir[2] <> ':')) Then makedirs(filinf1.dir);
  644.       checkexistfile(filinf1);
  645.     Until ch In ['C', 'S'];
  646.     If ch = 'C' Then restorefile(filinf1);
  647.   End;                                                          { restoreone }
  648.  
  649.   Procedure dorestore;
  650.   { offer files for restoration; maybe even do it                            }
  651.     Var foundone : boolean;
  652.         filinf : fileinfo;
  653.   Begin                                                          { dorestore }
  654.     isopencontrol := False;
  655.     isopenbackup := False;
  656.     opencontrolfile(foundone);
  657.     If foundone Then getnextname(filinf,foundone);
  658.     While foundone And (filinf.name <> '') And (Not quit) Do
  659.     Begin
  660.       If filinf.partnumber = 1 Then restoreone(filinf);
  661.       getnextname(filinf,foundone);
  662.     End;
  663.     If isopencontrol Then Close(controlfile);
  664.     isopencontrol := False;
  665.     If foundct = 0 Then error('No backup files starting on this disk',10,False);
  666.   End;                                                           { dorestore }
  667.  
  668.   Procedure checkversion;
  669.   { finds out which DOS version the backup was made by                       }
  670.     Var sr : SearchRec;
  671.   Begin                                                       { checkversion }
  672.     FindFirst(source+'BACKUPID.@*',AnyFile,sr);
  673.     If DOSError = 0 Then backupversion := $32
  674.     Else
  675.     Begin
  676.       FindFirst(source+'CONTROL.*',AnyFile,sr);
  677.       If DOSError = 0 Then backupversion := $33
  678.                       Else error('Disk in drive '+source+
  679.                                  ' is not a valid DOS backup disk',3,False);
  680.     End;
  681.     write('Backup made by DOS ');
  682.     If backupversion = $33 Then writeln('3.3 or later')
  683.                            Else writeln('3.2 or earlier');
  684.   End;                                                        { checkversion }
  685.  
  686.   Procedure getargs;
  687.   { get arguments from command line                                          }
  688.     Var i, k : byte;
  689.         temp: string;
  690.   Begin                                                            { getargs }
  691.     isopencontrol := False;
  692.     isopenbackup  := False;
  693.     isopendest    := False;
  694.     exitsave := ExitProc;
  695.     ExitProc := @myexit;
  696.     myname := ParamStr(0);
  697.     If myname = '' Then myname := progname;
  698.     source := '';
  699.     destination := '';
  700.     all := False;
  701.     overwrite := False;
  702.     For i := 1 To ParamCount Do
  703.     Begin
  704.       temp := ParamStr(i);
  705.       For k := 1 To Length(temp) Do temp[k] := UpCase(temp[k]);
  706.       If (Length(temp) = 2) And (temp[1] In ['/','-']) Then
  707.       Begin
  708.         Case temp[2] Of
  709.           'A' : all := True;
  710.           'O' : overwrite := True;
  711.           'H', '?' : usage(1);
  712.           Else error('Unknown command line switch',2,True);
  713.         End
  714.       End
  715.       Else
  716.       Begin
  717.         If temp = '?' Then usage(1);
  718.         If source = '' Then source := temp
  719.         Else
  720.         Begin
  721.           If destination = '' Then destination := temp
  722.                               Else error('Too many acommand line arguments',
  723.                                          2,True);
  724.         End;
  725.       End;
  726.     End;
  727.     If destination = '' Then error('Command line arguments missing',2,True);
  728.     If Length(source) = 1 Then source := source + ':';
  729.     If Length(source) <> 2 Then error('Argument #1 must be plain source drive',
  730.                                       2,True);
  731.     If (Length(destination) = 1) And (destination <> '.') Then
  732.                                           destination := destination + ':';
  733.     origdir := Length(destination) = 2;
  734.     If destination[Length(destination)] <> '\' Then
  735.                                           destination := destination + '\';
  736.     If MaxAvail >= SizeOf(iobuffer) Then New(bufptr);
  737.     quit := False;
  738.     foundct := 0;
  739.     getcountryinfo;
  740.   End;                                                             { getargs }
  741.  
  742. Begin                                                                 { main }
  743.   writeln(progname,' ',version,' -- ',copyright);
  744.   getargs;
  745.   checkversion;
  746.   dorestore;
  747. End.
  748.