/*
Article: 3219 of alt.binaries.pictures.misc
From: jvoosten@isis.cs.du.edu (Jeroen van Oosten)
Newsgroups: alt.binaries.pictures.misc
Subject: MUFUD: C-source code
Summary: C source code for MUFUD 2.00
Message-ID: <jvoosten.2@isis.cs.du.edu>
Date: 9 Mar 92 12:05:55 GMT
Sender: news@donau.et.tudelft.nl (UseNet News System)
Organization: TU Delft
Lines: 778
Nntp-Posting-Host: dutiw209.tudelft.nl
*/
/* MUFUD */
#include <ctype.h>
#include <dir.h>
#include <dos.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __MSDOS__
#define SlashC   '\\'
#define SlashS   "\\"
#define AllFiles "*.*"
#else
#define SlashC   '/'
#define SlashS   "/"
#define AllFiles "*"
#endif
#define MaxBuf   8000
#define BufSpool MaxBuf - 100
#define LineLength 256
/* a linked structure of the file that are part of one output file */
struct LinkedFile {
   char Subject[30];  /* Subject line */
   char Name[30];     /* name of file on disk */
   int  Part;         /* part x... */
   int  Total;        /* ... of y */
   struct LinkedFile *Next;
};
/* chain to LinkedFiles.... */
struct FileChain {
   struct LinkedFile *Link;
   struct FileChain *Next;
};
typedef unsigned int uint;
/* Global Var */
char LineIn[LineLength];
static unsigned char Out[MaxBuf];
static unsigned char In[MaxBuf];
static unsigned char *UPos = &Out[0];
FILE *LogDevice;
struct FileChain *Chain = NULL;
struct FileChain *EndChain = NULL;
char *Options = "-h   "
                "-l   "
                "-c   "
                "-t   ";
/*                                                                        
 *  ########################################################################
 *  ########################################################################
 */
/* Split complete path in path and filemask, and provide defaults if 
 * necassary.
 */
int SplitPath(char *Complete, char *Pad, char *Name)
{    
   char SplitDrive[3];
   char SplitPad[80];
   char SplitName[30];
   char SplitExt[30];
   int SFlag, FFlag;
   struct ffblk File;
   SFlag = fnsplit(Complete, &SplitDrive[0], &SplitPad[0],
                   &SplitName[0], &SplitExt[0]);
   if (SFlag & WILDCARDS) { /* has wildcards. assume everyting's OK. */
     strcpy(Pad, SplitDrive);
     strcat(Pad, SplitPad);
     if (strcmp(Pad, ""))
       strcat(Pad, SlashS);
     strcpy(Name, SplitName);
     if (strcmp(SplitExt, "")) {
       strcat(Name, ".");
       strcat(Name, SplitExt);
     }
     return(0); /* succes */
   }
   else {
     /* Try to find out if it is just one file or a directory.
      * So look for files and directories, and if it's found, look at the 
      * fileattribute.
      */
     /* If it's just a drivespecification, take that. */
     if ((SFlag & DRIVE) && (strcmp(SplitPad, "") == 0) && (strcmp(SplitName, "") == 0)
         && (strcmp(SplitExt, "") == 0)) {
       strcpy(Pad, Complete);
       strcpy(Name, AllFiles);
       return(0);
     }
     if (findfirst(Complete, &File, FA_DIREC | FA_RDONLY | FA_ARCH) == 0)  /* found something! */
       if (File.ff_attrib & FA_DIREC) { /* it's just a directory */
         strcpy(Pad, Complete);
         strcat(Pad, SlashS);
         strcpy(Name, AllFiles);
         return(0);
       }
       else { /* just one file */
         strcpy(Pad, SplitDrive);
         strcat(Pad, SplitPad);
         strcat(Pad, SlashS);
         strcpy(Name, SplitName);
         strcat(Name, SplitExt);
         return(0);
       } 
     else 
       return(-1); /* couldn't find either subdir or file */
   }
} /* SplitPath */
int OptionNumber(char *OptionString)
{
   char *a;
   if ((a = strstr(Options, OptionString)) == NULL)
     return(0);
   else
     return(1 + (a - Options) / 5);
}
/* < 0 on error, >=0 otherwise */
int GetNumber(char **k)
{
   int t = 0;
   if (!isdigit(**k)) 
     return(-1);
   while(isdigit(**k) && **k != '\0') {
      t = t * 10 + **k - '0';
      (*k)++;
   }
   return(t);
} /* GetNumber */
/* Guess what this routine does...
 * Returns number of spaces skipped */
int SkipSpaces(char **k)
{
   int t = 0;
   while (isspace(**k) && *k != '\0') {
      (*k)++;
      t++;
   }
   return(t);
} /* SkipSpaces */
int ValidNameChar(char z)
{
   /* Note: !@#$%&()-_'{} are all valid filename characters for MS-DOS. I'm
    * still looking for the appropriate subset that will do on most systems.
    * I left out the () in the string below, because of some part-numbers 
    * were stuck to the filename in the Subject: line. For example:
    * Subject: mufud(1/3)
    * in stead of:
    * Subject: mufud (1/3)
    * Now they'll be sorted out correctly.
    */
   if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
              "!@#$%&-_'{}.", z) == NULL)
     return 0;
   else
     return 1;
} /* ValidNameChar */
/* Analyses NetNews header of given file. Returns a filled-in LinkedFile
 * structure when possible (must already have been created).
 * Returns 0 on succesfull analyzing.
 * -1  Error: is not a (recognized) netnews header
 * -2  Error: I/O error
 *  0  No warning or error
 * +1  Warning: is not part of a file (i.e. "Re:")
 * +2  Warning: couldn't determine number
 * Netnews headers consist of lines with keywords starting with a capital 
 * letter and is ended by an empty line.
 * Only the Subject line is important.
 */
int AnalyzeHeader(char *FileName, struct LinkedFile *c)
{
   FILE *af;
   char *l, *k;
   int tlen;
   char Tname[30];
   int Found = 0, TempError = -1;
   
   if ((af = fopen(FileName, "rt")) == NULL)
     return(-2);
   l = fgets(LineIn, LineLength, af);
   while ((l != NULL) && (strcmp(LineIn, "") != 0)) {
      if (strncmp(LineIn, "Subject:", 8) == 0) { /* now this is interesting... */
        l = &LineIn[8]; /* just after "Subject:" */
        LineIn[strlen(LineIn) - 1] = '\0'; /* get rid of \n */
        SkipSpaces(&l);
        if (*l == '\0') 
          TempError = 1; 
        else {
          k = l;
          tlen = 0;
          /* Now search until a character not valid for a filename */
          while (ValidNameChar(*k))
             k++, tlen++;
          /* if it is any word ending in ":", forget about it */
          if (*k == ':') 
            TempError = 1;
          else {
            /* so now we've scanned the subject. Copy this into the structure */
            strncpy(c->Subject, l, tlen);
            c->Subject[tlen] = '\0'; /* terminate properly */
            l = ++k;
            /* Now comes the most difficult part: finding out the right 
             * number. Things like "part x of y" or [x/y] or (x/y) must
             * all be recognized. */
            strlwr(l); /* to make things easier... */
            /* If not found /, look for "part" */
            if ((k = strstr(l, "/")) == NULL) {
              /* search for "part " */
              k = strstr(l, "part ");
              if (k != NULL)  { /* OK.... now we better find some digits*/
                k = k + 4;
                SkipSpaces(&k);
                if (*k == '\0')
                  TempError = 2; /* couldn't find number */
                else {
                  if ((c->Part = GetNumber(&k)) < 0)
                    TempError = 2;
                  /* now search past "of " */
                  if ((l = strstr(k, "of ")) == NULL)  /* not found */
                    TempError = 2;
                  else {
                    l = l + 2;
                    SkipSpaces(&l);
                    if ((c->Total = GetNumber(&l)) < 0)
                      TempError = 2;
                    else {
                      Found = 1;
                      TempError = 0;
                    }
                  }
                }
              }
              else /* didn't find "part " either */
                TempError = 2;
            }
            else {
              /* search left for (maybe) spaces and then digits */
              l = k--;
              while (isspace(*k)) k--;
              /* now go to begin of digits (if any) */
              if (!isdigit(*k))
                TempError = 2;
              else {
                while (isdigit(*k)) k--;
                k++;
                c->Part = GetNumber(&k);
                /* part number read. Now total */
                l++;
                SkipSpaces(&l); /* just in case */
                if ((c->Total = GetNumber(&l)) < 0)
                  TempError = 2;
                else
                  TempError = 0;
                Found = 1;
              }
            }
          }
        } /* .. if *l == '\0' */
        break;
      } /* .. if "Subject:" */
      l = fgets(LineIn, LineLength, af);
   } /* ..while */
   if (Found == 0) {
     if (strcmp(LineIn, "") == 0)
       TempError = -1; /* not recognized */
     if (l == NULL) 
       TempError = -2; /* I/O error */
   }
   if (TempError <= 0)  /* warnings won't have any effect here */
     switch (feof(af)) {
       case -1: /* error */
         TempError = -2;
         break;
       case 0:  /* no EOF or error: guess I found something */
         break;
       case 1: /* EOF */
         if (Found == 0) 
           TempError = -1; 
         break;
     }
   fclose(af);
   return(TempError);
} /* AnalyzeHeader */
/* Puts file in chain when needed.
 * Parts 0 are not chained (prob. description)
 * returns:
 * -11  Memory exhausted
 * -10  File already in link. Repost ?
 *   0  No error ro warning
 *  10  Part zero ignored
 */
int PutInChain(struct LinkedFile *l)
{
   struct LinkedFile *nl, *zl, *ol;
   struct FileChain *nc;
   int te = 0, SubComp;
   if (l->Part == 0) 
     return(10);
   if ((nl = (struct LinkedFile *) malloc(sizeof(struct LinkedFile))) == NULL)
     return(-11);
   *nl = *l;
   nl->Next = NULL;
   if (Chain == NULL) { /* empty: create one entry */
     if ((Chain = (struct FileChain *) malloc(sizeof(struct FileChain))) == NULL)
       return(-11);
     Chain->Link = nl;
     Chain->Next = NULL;
     EndChain = Chain;
     te = 0;
   }
   else { /* Search chain for matching subject */
     nc = Chain;
     SubComp = strcmp(l->Subject, nc->Link->Subject);
     while (nc->Next != NULL && SubComp != 0) {
        nc = nc->Next;
        SubComp = strcmp(l->Subject, nc->Link->Subject);
     }
     if (SubComp == 0) { /* same: put in LinkedFile */
       if (nc->Link->Part > nl->Part) { /* if smallest number, put it at begin of chain */
         nl->Next = nc->Link;
         nc->Link = nl;
       }
       else { /* search through chain to equal (= error) or greater */
         ol = zl = nc->Link;
         while (zl != NULL && zl->Part < nl->Part) {
            ol = zl;
            zl = zl->Next;
         }
         if (zl != NULL && zl->Part == nl->Part)
           te = -10; /* double entry */
         else {
           nl->Next = ol->Next;
           ol->Next = nl;
         }
       }
     }
     else { /* new entry needed. Put it at end */
       if ((nc = (struct FileChain *) malloc(sizeof(struct FileChain))) == NULL)
         return(-11);
       EndChain->Next = nc;
       nc->Next = NULL;
       nc->Link = nl;
       EndChain = nc;
     }
   }
   return(te);
} /* PutInChain */
void FindFiles(char *Pad, char *Masker)
{
   FILE *File;
   char Total[128];
   char TName[128];
   struct ffblk Zoek;
   int done, res = 0;
   struct LinkedFile lf;
   strcpy(Total, Pad);
   strcat(Total, Masker);
   done = findfirst(Total, &Zoek, FA_ARCH | FA_RDONLY);
   while (!done && res != -11) {
      strcpy(TName, Pad);
      strcat(TName, Zoek.ff_name);
      strcpy(lf.Name, Zoek.ff_name);
      res = AnalyzeHeader(TName, &lf);
      if (res == 0)  
        res = PutInChain(&lf);
      if (res != 0) {
        if (res < 0)
          fprintf(LogDevice, "*** Error");
        else 
          fprintf(LogDevice, "*** Warning");
        fprintf(LogDevice, " in %s, \"%.55s\"\n    ", Zoek.ff_name, LineIn);
        switch (res) {
          case -11:
            fprintf(LogDevice, "Memory exhausted.\n");
            break;
          case -10:
            fprintf(LogDevice, "Double entry; part %d.\n", lf.Part);
            break;
          case -2:
            fprintf(LogDevice, "I/O error.\n");
            break;
          case -1:
            fprintf(LogDevice, "Didn't recognize file as Netnews.\n");
            break;
          case 1:
            fprintf(LogDevice, "Reply. Not used.\n");  
            break;
          case 2:
            fprintf(LogDevice, "Couldn't determine which part.\n");
            break;
        } /* ..switch */
      } /* ..if res */
      done = findnext(&Zoek);
   }
} /* FindFiles */
void PrintFiles()
{
   struct FileChain  *zc;
   struct LinkedFile *lf;
   fprintf(LogDevice, "Found clusters:\n");
   zc = Chain;
   while (zc != NULL) {
      lf = zc->Link;
      fprintf(LogDevice, "%s\t Total = %d:\n", lf->Subject, lf->Total);
      do {
         fprintf(LogDevice, "\t\t\tpart %3d in %s\n", lf->Part,lf->Name);
         lf = lf->Next;
      } while (lf != NULL);
      zc = zc->Next;
   }
} /* PrintFiles */
/* Removes all nodes from memory */
void CleanUpChain()  
{
   struct FileChain  *c1, *c2;
   struct LinkedFile *l1, *l2;
   c1 = Chain;
   while (c1 != NULL) {
      l1 = c1->Link;
      while (l1 != NULL) {
         l2 = l1->Next;
         free(l1);
         l1 = l2;
      }
      c2 = c1->Next;
      free(c1);
      c1 = c2;
   }
}
/* Mode 0: Flush if necessary
 *      1: always
 */
void FlushWrite(FILE *Output, int Mode)
{
   static int Buffered;
   Buffered = UPos - &Out[0];
   if (Buffered > BufSpool || Mode) {
     if (fwrite(&Out[0], 1, Buffered, Output) < Buffered) {
       UPos = strerror(errno);
       printf("Error writing outputfile: %s\nAborting...\n", UPos);
       exit(2);
     }
     else {
       UPos = &Out[0];
       memcpy(&Out[0], &Out[Buffered], MaxBuf - Buffered);
     }
   }
} /* FlushWrite */
/* Returns:
 * 0: nothing special (header)
 * 1: BEGIN or END or CUT HERE or --
 * 2: begin nnn file, so it's the start of an uuencoded file. Returns in
 *    StartName the filename (provide a buffer for it).
 * 3: end
 * 4: empty line
 * 5: UUencoded line
 */
int AnalyzeLine(char *ThisLine, char *StartName)
{
   char *ScanPos;
   char *NameFill;
   char UpLine[LineLength];
   if (!strcmp(ThisLine, "\n") || !strcmp(ThisLine, ""))
     return(4);
   strcpy(UpLine, ThisLine);
   strupr(UpLine);
   /* OK: here's the trick: 
    * an uuencoded line consists only of capital letters, and in almost
    * any case starts with an 'M', en is approx. 60 chars long. So if this
    * is the case, there is a 99.999% chance it is an uuencoded line.
    */
   if (strncmp(ThisLine, UpLine, 61) == 0 && ThisLine[0] == 'M')
     return(5);
   if (strncmp(ThisLine, "begin", 5) == 0) { /* filename ! */
     ScanPos = ThisLine + 5; /* dirty, but it works */
     /* skip spaces, then check for numbers, skip spaces, copy
      * filename in StartName */
     while (*ScanPos != '\0' && isspace(*ScanPos))
        ScanPos++;
     if (isdigit(*ScanPos)) { /* if we've got a number now... */
       while(*ScanPos != '\0' && isdigit(*ScanPos))
          ScanPos++;
       while(*ScanPos != '\0' && isspace(*ScanPos))
          ScanPos++;
       /* So we have finally reached the filename (I hope). If it is the
        * end of the line, forget it: return 0, else copy filename with 
        * return 2.
        */
       if (*ScanPos != '\0') {
         NameFill = StartName;
         while (isgraph(*ScanPos)) 
            *NameFill++ = *ScanPos++;
         *NameFill = '\0';
         return(2);
       }
     }
   }
   else { 
     if (strncmp(ThisLine, "end", 3) == 0)
       return(3);
     else { /* maybe BEGIN, END, Cut Here, line with - or = */
       if (strncmp(ThisLine, "BEGIN-", 6) == 0 || strncmp(ThisLine, "END-", 4)
           == 0 || strstr(UpLine, "CUT HERE") != NULL || 
           strncmp(ThisLine, "CUTHERE", 7) == 0 ||
           (strncmp(ThisLine, "--", 2) == 0 && strlen(ThisLine) <= 4) || 
           (strstr(ThisLine, "include") != NULL) )
         return(1);
     }
   } 
   return(0);
} /* AnalyzeLine */
/* independant module to uudecode a netnews file. Takes care of the output
   file 
   Returns:
   -21  : something idiot
   -20  : I/O Error
     0  : no error
    20  : uuencoded without begin
 */
int UUDecodeFile(FILE *UIn, char *InName, FILE **UUit, char *OutPath)
{
    char Dummy1[30];
    char OutName[120];
    unsigned char c;
    char *CPos;
    int DecodLen, KindOfLine;
    static int BS;
    int TempError = 0;
    /* File is openend. Now read past NetNews header */
    do
      CPos = fgets(LineIn, LineLength, UIn);
    while (strcmp(LineIn, "\n") && CPos != NULL);
    if (CPos == NULL)
      return(-20);
    /* now keep looking out for number 1... :-) */
    /* I mean, a "begin" or uuencoded line */
    DecodLen = 0; /* flag to break out of loop */
    do {
      CPos = fgets(LineIn, LineLength, UIn);
      KindOfLine = AnalyzeLine(LineIn, Dummy1);
      if (CPos == NULL)
        TempError = -20;
      switch (KindOfLine) {
        case 1: /* BEGIN/END/CUT HERE */
          break;
        case 2: /* New output file */
          if (*UUit != NULL) {
            fprintf(LogDevice, "--- Warning ! File ended abnormally !\n");
            FlushWrite(*UUit, 1);
            fclose(*UUit);
            *UUit = NULL;
          }
          /* open new output file */
          strcpy(OutName, OutPath);
          strcat(OutName, Dummy1);
          if ((*UUit = fopen(OutName, "wb")) == NULL) {
            fprintf(LogDevice, "--- Error ! Couldn't open outputfile %s because\n", 
                    "     %s", Dummy1, sys_errlist[errno]);
            TempError = -20;
          }
          else {
            fprintf(LogDevice, "Started decoding of %s from %s\n", Dummy1, InName);
            BS = 0;
          }
          /* read next line */
          if (fgets(LineIn, LineLength, UIn) == NULL)
            TempError = -20;
          KindOfLine = AnalyzeLine(LineIn, Dummy1);
          DecodLen = 1;
          break;
        case 3: /* buh ? end without anything else ? */
          fprintf(LogDevice, "--- Buh ? End without anything preceding it ?\n"
                             "     File : %s\n", InName);
          if (*UUit != NULL) {
            FlushWrite(*UUit, 1);
            fclose(*UUit);
            *UUit = NULL;
          }
          TempError = -21;
          break;
        case 5: /* aha ! UUEncoded line ! */
          if (*UUit == NULL) {
            fprintf(LogDevice, "--- Warning ! %s is not the start of an uuencoded file.\n",
                    InName);
            TempError = 20;
          }
          else
            fprintf(LogDevice, "Continued in %s\n", InName);
          DecodLen = 2;
          break;
      } /* ..switch */
    } while (DecodLen == 0 && TempError == 0);
    /* if anything happened: quit now */
    if (TempError)
      return(TempError);
    do {
      CPos = LineIn;
      DecodLen = ((*CPos++ - 0x20) & 0x3F);
      while (DecodLen) {
         c = ((*CPos++ - 0x20) & 0x3F);
         switch(BS & 3) {
           case 0:
             *UPos = c << 2;
             break;
           case 1:
             *UPos++ |= c >> 4;
             DecodLen--;
             *UPos = c << 4;
             break;
           case 2:
             *UPos++ |= c >> 2;
             DecodLen--;
             *UPos = c << 6;
             break;
           case 3:
             *UPos++ |= c;
             DecodLen--;
             break;
         } /* ..switch */
         BS++;
      } /* ..while DecodLen */
      FlushWrite(*UUit, 0);
      fgets(LineIn, LineLength, UIn);
      KindOfLine = AnalyzeLine(LineIn, Dummy1);
      if (KindOfLine != 0 && KindOfLine != 5) {
        fseek(UIn, 0, SEEK_END);
        fgetc(UIn);
        if (KindOfLine == 3) { /* real "end" */
          FlushWrite(*UUit, 1);
          fclose(*UUit);
          *UUit = NULL;
          fprintf(LogDevice, "Ended normally.\n");
          break;
        }
      }
    } while (!feof(UIn));
    return(TempError);
} /* UUDecodeFile */
void DecodeFiles(char *PathIn, char *PathOut)
{
   struct FileChain  *zc;
   struct LinkedFile *lf, *of;
   int Expect, Decoded;
   char File[120];  /* complete filename */
   FILE *OutFile = NULL, *InFile;
   zc = Chain;
   while (zc != NULL) {
      of = lf = zc->Link;
      Expect = 1;  /* expect part 1 */
      Decoded = lf->Total; /* number of decoded parts */
      do {
         if (lf->Part != Expect) 
           fprintf(LogDevice, "### Warning ! File: %s, subject: %s\n"
                   "     Expected part %d, got %d.\n", lf->Name, lf->Subject,
                   Expect, lf->Part);
         strcpy(File, PathIn);
         strcat(File, lf->Name);
         if ((InFile = fopen(File, "rt")) == NULL) 
           fprintf(LogDevice, "### Error ! Couldn't open file %s, part %d of %s.\n",
                   lf->Name, lf->Part, lf->Subject);
         else {
           setvbuf(InFile, &In[0], _IOLBF, MaxBuf); /* buffer of 8K */
           UUDecodeFile(InFile, lf->Name, &OutFile, PathOut);
           Decoded--;
           fclose(InFile);
         }
         Expect = lf->Part;
         lf = lf->Next;
         Expect++;
      } while (lf != NULL);
      if (Decoded)
        fprintf(LogDevice, "### Warning ! Subject: %s\n     Decoded %d parts, expected %d.\n",
                of->Subject, of->Total - Decoded, of->Total);
      if (OutFile != NULL) {
        fprintf(LogDevice, "### Warning ! File ended abnormally !\n");
        FlushWrite(OutFile, 1);
        fclose(OutFile);
        OutFile = NULL;
      }
      zc = zc->Next;
   }
} /* DeocdeFiles */
void main(int argc, char *argv[])
{
   int i;
   int InPadLen;
   char InFile[80];   /* complete input name */
   char InPad[80];    /* source path for uuencoded files */
   char InMask[30];   /* the mask used for source files */
   char UitPad[80];   /* destination path */
   char LogFile[20];
   char c;
   struct {
     uint Help:      4;
     uint Cluster:   1;
     uint TestRound: 1;
   } F;
   strcpy(InFile, "");  /* choose current directory as input */
   strcpy(UitPad, "");  /* output path is current directory */
   strcpy(LogFile, ""); /* default log file is stderr */
   F.Help = 0;
   F.Cluster = 0;
   F.TestRound = 0;
   for (i = 1; i < argc && F.Help == 0; i++) {
      if (argv[i][0] == '-') /* command line option */
        switch (OptionNumber(argv[i])) {
          case 0: /* unknown option */
            F.Help = 1;
            break;
          case 1: /* help */
            F.Help = 2;
            break;
          case 2: /* logfile */
            if (i < argc) 
              strcpy(LogFile, argv[++i]);
            break;
          case 3: /* show clusters */
            F.Cluster = 1;
            break;
          case 4: /* Test round */
            F.TestRound = 1;
            break;
        } /* ..switch */
      else 
        if (!strcmp(InFile, ""))  /* copy first non-option in input */
          strcpy(InFile, argv[i]);
        else 
          if (!strcmp(UitPad, "")) { /* copy second non-option in output */
            strcpy(UitPad, argv[i]);
            c = UitPad[strlen(UitPad) - 1];
            if (c != SlashC && c != ':')
              strcat(UitPad, SlashS);
          }
          else  
            F.Help = 3;   /* too many non-options */
   } /* ..for */
   if (F.Help) { /* help */
     printf("MUFUD 2.00:             MUlti File UuDecoder.\n");
     printf("                        by: Jeroen van Oosten. Februari 1992\n");
     switch (F.Help) {
       case 1:
         printf("Unknown option !\n");
         break;
       case 3:
         printf("Too many files on commandline. One inputfilespec and outputpath allowed.\n");
         break;
     } /* ..switch */
     printf("Syntax: mufud [path[filespec]] [outputpath]\n");
     printf("Options may appear anywhere on the command line. They are:\n"
            "-h          This help\n"
            "-l <file>   Log activities to <file>. Default is standard output device\n"
            "-c          Show clustered files.\n"
            "-t          Test round (no decoding, just analyzing headers)\n"
            );
     exit(0);
   }
   if (strcmp(LogFile, "")) /* file name given */
     LogDevice = fopen(LogFile, "wt");
   else
     LogDevice = stdout; /* open standard device for error messages */
   if (LogDevice == NULL) { /* Somehow can't log */
     printf("Can't open log. Aborting...\n");
     exit(1);
   }
   if (InFile[0] == '\0')
     strcpy(InFile, ".");
   if (SplitPath(InFile, &InPad[0], &InMask[0])) {
     fprintf(LogDevice, "Error: couldn't find input file/path.\n");
     exit(2);
   }
   if (F.TestRound)
     fprintf(LogDevice, "&&&&& Just performing testround. Nothing's decoded.\n");
   FindFiles(&InPad[0], &InMask[0]);
   if (F.Cluster) 
     PrintFiles();
   if (!F.TestRound)
     DecodeFiles(InPad, UitPad);
   CleanUpChain();
   fclose(LogDevice);
   exit(0);
} /* main */ 


