[Back to TEXTFILE SWAG index]  [Back to Main SWAG index]  [Original]

{
From: "Scott F. Earnest" <tiobe+@CMU.EDU>

About a month ago, I posted a program called "SmartConvert" which does auto-
matic conversions between DOS and UNIX format text files.

Unfortunately, there were a couple problems with the code I posted I wasn't
aware of:

1.)  While debugging, I accidentally removed the code which called the
     procedures to check that the files existed.  Hopefully nobody's
     gotten in trouble by overwriting files they didn't mean to. . . .
2.)  S . . . L . . . O . . . W . . . !  I clocked a large file (~650K)
     both ways, and got a time over 7 minutes.  In this version, I
     reassigned the text file buffers to 8K, and got much better times.

I've also added an overwrite switch to ignore the output file.

And could the kind soul(s) who donated the previous version to SWAG please
make sure this replaces the old version in the next upgrade?  Thanks!

 þ Done! - Kerry þ
}
program SConvert;

{Smart-converts UN*X/DOS format files

 Usage:  sconvert infile [outfile] [/u | /d] [/o]

         /u -- force output to UNIX  (LF only)
         /d -- force output to DOS   (CR/LF)
         /o -- Overwrite output file if it exists (for batch support)

         -- or --

         sconvert /?  (-?, /h, -h, /H, and -H analogous)
           for help message

         This program is capabable of having its output piped, provided
          it is the first in the pipeline.  Doesn't do well as an inter-
          mediary pipe section.

 Written by Scott F. Earnest, Aug 1993
 Original version:  30 Aug 1993
 Updated versions:   9 May 1994  (Added force flags.)
                     9 Jun 1994  (Bug fix, added /o flag.)

 This version uses 8K input/output buffers instead of the default 128-byte
 text buffers.  The result is a performance of over 250% (only noticeable
 with large files).  Untyped files turned out to be worthless here--they
 performed worse than text files, believe it or not.

 Unless I come up with a phenomenal improvement, this is the last version
 I plan to post.
}

uses Crt;

const
  CR = chr(13);               {Carriage Return}
  LF = chr(10);               {Line Feed}

type
  sys = (dos,unix,bad);       {system identifier}
                              {Note to people who make upgrades--if you
                               need the DOS unit, you'll have to modify
                               this variable so that "DOS" isn't a label.}
  fbuf = array [0 .. 8191] of char;

var
  sysID : sys;                {system identifier for case branch}
  infile, outfile : string;   {input/output files}
  force : sys;                {what mode to work in}
  overwrite : boolean;        {(don't) check if outfile exists}
  ibuf, obuf : fbuf;          {increase text buffers}

function exist (filename : string) : boolean;

{Check if a file exists or not
 returns:  true  -->  file exists
           false -->  file non-existent}

var
  openfile : text;
  errcode : integer;

begin
  {$I-}                       {Turn off error-checking}
  assign (openfile, filename);
  reset (openfile);
  {$I+}                       {Turn it back on}
  errcode := IOResult;        {Get error code}
  if  errcode <> 0  then      {There's an error if non-zero}
    exist := false            {So flag that it doesn't exist.}
  else
    begin
      close (openfile);       {Otherwise, close file}
      exist := true;          {Flag that it does exist}
    end;
end;

function selectyn : boolean;

{Get a yes/no single-keypress response
 returns:  true  -->  yes response, y or Y
           false -->  no response, n or N}

var
  getchar : char;             {Need something to read into}

begin
  while KeyPressed do         {Clean keyboard buffer}
    getchar := ReadKey;
  repeat                      {Get a key until it's a (Y)es or (N)o.}
    getchar := ReadKey;
    getchar := upcase (getchar);
  until (getchar in ['Y', 'N']);
  writeln (getchar);          {Print the response}
  case getchar of             {Tell it what it should return}
    'Y' : selectyn := true;
    'N' : selectyn := false;
  end;
end;

procedure help (badflag : boolean);

{brief message if command format was abused}

begin
  writeln ('SmartConvert, Written by Scott F. Earnest -- v1.4 -- 9 Jun 1994');
  writeln;
  if badflag then
    begin
      writeln ('Invalid flag.');
      writeln;
    end;
  writeln ('Usage');
  writeln ('  sconvert infile [outfile] [/d | /u] [/o]');
  writeln;
  writeln ('  /d -- convert input to DOS format');
  writeln ('  /u -- convert input to UNIX format');
  writeln ('  /o -- unconditionally overwrite output');
  writeln ('        (for batch files or writing to devices)');
  halt (1);
end;

procedure incheck (filename : string);

{Make sure source exists, if specified}

begin
  if not (exist (filename)) then
    begin
      writeln ('Source file does not exist!');
      halt (3);
    end;
end;

procedure outcheck (filename : string);

{Make sure target does NOT exist, if specified, allow overwrite}

var
  select : boolean;

begin
  if exist (filename) and (filename <> '') then
    begin
      write ('Target file exists!  Overwrite?  [y/n] ');
      select := selectyn;
      case select of
        true : ;
        false : halt (4);
      end;
    end;
end;

function checktype (readfile : string) : sys;

var
  FileCheck : text;
  checkvar : sys;
  CROk, LFOk : boolean;
  ReadBuf : char;

begin
  CROk := False;
  LFOk := False;                        {Init flags.}
  checkvar := bad;                      {Assume that type isn't known.}
  assign (FileCheck, readfile);
  reset (FileCheck);
  while (not eof(FileCheck)) and (not CROk) and (not LFOk) do
    begin                               {Look for CR or LF}
      read (FileCheck, ReadBuf);
      if ReadBuf = CR then              {CR found?}
        begin
          CROk := True;                 {If yes, set the CR flag.}
          Read (FileCheck, ReadBuf);    {and get next char}
          if ReadBuf = LF then          {next one a LF?}
            LFOk := True;               {Flag it as found.}
          if CROk and LFOk then         {So is it CR/LF?}
             begin
               checktype := dos;        {If yes, specify DOS, and exit.}
               close (FileCheck);
               exit;
             end;
        end;
      if ReadBuf = LF then              {Found a LF?}
         begin
           checktype := unix;           {If yes, assume unix.}
           close (FileCheck);           {Close and exit.}
           exit;
         end;
    end;
  if checkvar = bad then                {If there was a problem:}
    begin
      writeln ('Ambiguous file type.  Can''t determine type.');
      close (FileCheck);
      halt(2);
    end;
end;

procedure dos2unix (infile, outfile : string);

var
  intext, outtext : text;
  ReadBuf1, ReadBuf2 : char;

begin
  writeln ('Converting DOS -> UNIX. . . .');
  assign (intext, infile);
  settextbuf (intext, ibuf, sizeof(ibuf));
  reset (intext);
  assign (outtext, outfile);
  settextbuf (outtext, obuf, sizeof(obuf));
  rewrite (outtext);
  while not eof(intext) do
    begin
      read (intext, ReadBuf1);          {Get character}
      if ReadBuf1 = CR then             {If it's CR then. . . }
        begin
          read (intext, ReadBuf2);      {. . . get next . . .}
          if ReadBuf2 = LF then         {. . . and see if it's LF.}
            write (outtext, LF)         {If yes, just put LF into new file.}
          else
            write (outtext, ReadBuf1, ReadBuf2); {Not CR/LF, dump to file.}
        end
      else
        write (outtext, ReadBuf1);      {Dump the character to file.}
    end;
  close (intext);
  close (outtext);
end;

procedure unix2dos (infile, outfile : string);

var
  intext, outtext : text;
  ReadBuf : char;

begin
  writeln ('Converting UNIX -> DOS. . . .');
  assign (intext, infile);
  settextbuf (intext, ibuf, sizeof(ibuf));
  reset (intext);
  assign (outtext, outfile);
  settextbuf (outtext, obuf, sizeof(obuf));
  rewrite (outtext);
  while not eof(intext) do
    begin
      read (intext, ReadBuf);           {Get a character.}
      if ReadBuf = LF then              {Is it LF?}
        write (outtext, CR+LF)          {If yes, put a CR/LF in its place.}
      else
        write (outtext, ReadBuf);       {Otherwise, replace the character.}
    end;
  close (intext);
  close (outtext);
end;

procedure getcommandline;

{get commandline info. . . .}

var
  pnum : byte;                          {paramater counter}
  pstr : string[2];                     {string snippet}
  fname : string;                       {temporary string}

begin
  if (paramcount < 1) or (paramcount > 4) then
    help (false);                       {too few, too many--show help}
  infile := '';                         {Init names.}
  outfile := '';
  force := bad;
  for pnum := 1 to paramcount do        {Do this in two passes.}
    begin                               {#1.)  Flags}
      pstr := paramstr(pnum);           {Get parameter.}
      pstr[2] := upcase(pstr[2]);
      if pstr[1] in ['-', '/'] then     {Flag?}
        case pstr[2] of  
          'H', '?' : help (false);      {Is help.}
          'D'      : force := dos;      {Is force DOS.}
          'U'      : force := unix;     {Is force UNIX.}
          'O'      : overwrite := true; {is overwrite.}
        else
          help (true);                  {Bad switch.}
        end;
    end;
  for pnum := 1 to paramcount do        {#2.)  Filenames}
    begin  
      fname := paramstr(pnum);          {Get parameter.}
      if not (fname[1] in ['-', '/']) then
        begin                           {If not flag then}
          if infile = '' then           {Get infile}
            infile := fname
          else if (infile <> '') and (outfile = '') then
            outfile := fname            {Get outfile}
          else
            help (false);               {Oops, too many.}
        end;
    end;
end;

begin
  overwrite := false;                   {Initialize flag}
  getcommandline;                       {Parse parameters}
  sysID := checktype (infile);          {Check the input file type}
  incheck (infile);                     {verify that infile exists}
  if not overwrite then                 {/o specified?}
    outcheck (outfile);                 {verify that outfile doesn't exist}
  if sysID = force then                 {If it's getting forced, then}
    begin                               {compare types and skip if same.}
      write ('Input file is already type ');
      case sysID of
        dos  : write ('DOS');
        unix : write ('UNIX');
      end;
      writeln (', skipped.');
      halt(5);
    end;
  case sysID of
    dos : dos2unix (infile, outfile);    {DOS -> UNIX}
    unix : unix2dos (infile, outfile);   {UNIX -> DOS}
    bad : begin                          {Not likely to happen but. . . .}
            writeln ('Internal error!  Check source code and recompile.');
            halt (6);
          end;
  end;
end.

[Back to TEXTFILE SWAG index]  [Back to Main SWAG index]  [Original]