/***************************************************************************
 *                                                                         *
 *  Filename : TeXFormat.c                                                 *
 *                                                                         *
 *  Description : A front-end for the PasTeX TeX implementation.           *
 *                The program looks for the format files found in the path *
 *                TeX:Formats and enables the user to switch between the   *
 *                available format files via a gadtools interface.         *
 *                                                                         *
 *  Return Codes :   0 - Ordinary program halt.                            *
 *                  10 - No format files available.                        *
 *                  20 - Couldn't open MUI application.                    *
 *                  30 - No mui.library.                                   *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *                         Modification History                            *
 *                                                                         *
 *  Date      Author       Comments                                        *
 * ----------------------------------------------------------------------  *
 *  9.3.92    R.Bödi       Created.                                        *
 *  8.6.92    R.Bödi       Fixed bug (first format entry couldn't be       *
 *                         selected.)                                      *
 *  5.9.93    R.Bödi       Now TeXFormat is a MUI application.             *
 * 14.9.93    R.Bödi       Added 'Save' button.                            *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 * Copyright © 1992-1993 Richard Bödi,  All rights reserved.               *
 *                                                                         *
 ***************************************************************************/

/*----------------------------- INCLUDES ----------------------------------*/

#include "string.h"
#include "stdio.h"
#include "stdlib.h"
#include "dos.h"

#include "workbench/workbench.h"
#include "workbench/startup.h"
#include "libraries/mui.h"

#include "clib/alib_protos.h"
#include "clib/intuition_protos.h"
#include "clib/exec_protos.h"
#include "clib/dos_protos.h"
#include "clib/graphics_protos.h"
#include "clib/gadtools_protos.h"
#include "clib/icon_protos.h"
#include "clib/wb_protos.h"
#include "clib/muimaster_protos.h"

#include "pragmas/intuition_pragmas.h"
#include "pragmas/exec_pragmas.h"
#include "pragmas/dos_pragmas.h"
#include "pragmas/graphics_pragmas.h"
#include "pragmas/gadtools_pragmas.h"
#include "pragmas/icon_pragmas.h"
#include "pragmas/wb_pragmas.h"
#include "pragmas/muimaster_pragmas.h"


/*--------------------------- DEFINES -------------------------------------*/

#define  VERSION        " V2.00 "

#define  COMMENTLENGTH         82
#define  CMDSTRLENGTH         512

#define  ID_FORMAT_SEL          1
#define  ID_SAVE                2
#define  ID_ABOUT            1000
#define  ID_HIDE            10000
#define  ID_SHOW            10001

#define  NEWLINE             "\n"

/*-------------------- STRUCTURE DEFINITIONS ------------------------------*/

enum ScanError  { SCAN_OK, NO_LOCK, NO_FORMAT, NO_ENV, NO_MATCH, NO_MEMORY };
enum ErrorIDs   { ERR_NOERROR, ERR_FORMATFILES = 10, ERR_MUI = 20, ERR_NOMUILIB = 30 };
enum Keywords   { KW_CURRENTFORMAT, KW_FORMATPATH, KW_PATTERN, LAST_KW };


struct FormatNode
   {
   struct FormatNode   *NextNode;
   char                 Name[FNSIZE];
   char                 Comment[COMMENTLENGTH];
   int                  ID;
   };

struct TeXFormat
   {
   struct FormatNode   *FirstNode;
   char               **FormatArray;
   struct FormatNode   *CurrentFormat;
   int                  MaxCommentLength;
   int                  MaxCommentLines;
   char                 DummyComment[COMMENTLENGTH];
   int                  NoOfFormats;
   };

struct Settings
   {
   long     ArgPtr[LAST_KW];
   char     ArgStr[LAST_KW][FMSIZE];              // FMSIZE see file dos.h
   char     CurrentFormat[FNSIZE];
   };


/*--------------------- FUNCTION PROTOTYPES -------------------------------*/

BOOL              OpenLibs (void);
void              ParseShell (int, char **, struct Settings *);
void              ParseWB (struct WBStartup *, struct Settings *);
enum ScanError    ScanFormatPath (struct TeXFormat *, struct Settings *);
void              HandleIDCMP (struct TeXFormat *, struct Settings *);
int               LineLength (char *);
int               NoOfLines (char *);
char             *ConvertNL (char *);
void              Cleanup (char *, enum ErrorIDs);


/*------------------------ EXTERNAL VARIABLES ----------------------------*/

extern struct Library         *SysBase;
extern struct DOSBase         *DOSBase;
extern struct GfxBase         *GfxBase;
extern struct IntuitionBase   *IntuitionBase;
extern struct GadToolsBase    *GadToolsBase;
extern struct IconBase        *IconBase;
extern struct WorkbenchBase   *WorkbenchBase;

/*-------------------------- GLOBAL DATA ----------------------------------*/

struct Library                *MUIMasterBase;

char  Version[]   = "$VER: TeXFormat  Release " VERSION " (" __DATE__ ")         © R.Bödi";
char  Title[]     = "TeXFormat " VERSION "   © R.Bödi";
char  Author[]    = "Richard Bödi\nKäsenbachstr. 10/2\n72076 Tübingen\nGermany\n\ne-mail: mmisa01@mailserv.zdv.uni-tuebingen.de";

char  *Keywords[] = { "CURRENTFORMAT", "FORMATPATH", "PATTERN" };
char  *Switchs[]  = { "/K", "/K", "/K" };

STRPTR  ErrorMsg[] = { "",
                       "Couldn't find directory",
                       "Couldn't find a TeX format file in ",
                       "Environment variable unset",
                       "Couldn't find TeX format file defined by the environment variable ",
                       "Not enough memory available" };

struct NewMenu Menu[] = { NM_TITLE, "File", NULL, 0, 0, NULL,
                          NM_ITEM, "About",   NULL, 0, 0, (APTR)ID_ABOUT,
                          NM_ITEM, NM_BARLABEL,  NULL, 0, 0, NULL,
                          NM_ITEM, "Quit",    "Q",  0, 0, (APTR)MUIV_Application_ReturnID_Quit,
                          NM_END };

/*--------------------------- MUI Objects ---------------------------------*/

Object   *App;
Object   *Win;
Object   *Select_Gad;
Object   *Save_Gad;
Object   *Done_Gad;
Object   *Description_TextField;

/*------------------------------- CODE ------------------------------------*/

main (int argc, char *argv[])

{
struct TeXFormat  TeXFormat;
struct Settings   Settings;
enum ScanError    FormatAvail;
char              ErrorStrg[FMSIZE];


if (argc == 0) ParseWB ((struct WBStartup *)argv, &Settings);
if (argc > 1)  ParseShell (argc, argv, &Settings);

if (OpenLibs ())
   {
   FormatAvail = ScanFormatPath (&TeXFormat, &Settings);

   if (FormatAvail == SCAN_OK)
      {
      App = ApplicationObject,
         		MUIA_Application_Title      , "TeXFormat",
         		MUIA_Application_Version    , Version,
         		MUIA_Application_Copyright  , "© 1992-93, Richard Bödi",
         		MUIA_Application_Author     , Author,
         		MUIA_Application_Description, "Select TeX format files easily.",
         		MUIA_Application_Base       , "TEXFORMAT",
         		MUIA_Application_Menu       , Menu,
         		SubWindow, Win = WindowObject,
         			MUIA_Window_ID, 0,
         			MUIA_Window_Title, Title,
         			WindowContents, VGroup,
      	   			Child, HGroup,
        		   			Child, Select_Gad = Radio ("TeX format", TeXFormat.FormatArray),
        		   			End,
                     Child, HGroup, GroupFrameT ("Description"),
        		   			Child, Description_TextField = TextObject, TextFrame,
                           MUIA_Background, MUII_TextBack,
                           MUIA_Text_Contents, TeXFormat.DummyComment,
                           End,
                        End,
   						Child, VSpace(0),
                     Child, HGroup,
                        Child, Save_Gad = KeyButton ("Save", 's'),
                        Child, HSpace(0),
                        Child, HSpace(0),
                        Child, Done_Gad = KeyButton ("Done", 'd'),
                        End,
                     End,
                  End,
               End;

      if (App)
         {
         DoMethod (Win, MUIM_Notify,
                   MUIA_Window_CloseRequest, TRUE, App, 2,
                   MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

         DoMethod (App, MUIM_Notify,
                   MUIA_Application_Iconified, FALSE, App, 2,
                   MUIM_Application_ReturnID, ID_SHOW);

         DoMethod (App, MUIM_Notify,
                   MUIA_Application_Iconified, TRUE, App, 2,
                   MUIM_Application_ReturnID, ID_HIDE);

         DoMethod (Select_Gad, MUIM_Notify,
                   MUIA_Radio_Active, MUIV_EveryTime, App, 2,
                   MUIM_Application_ReturnID, ID_FORMAT_SEL);

         DoMethod (Save_Gad, MUIM_Notify,
                   MUIA_Pressed, FALSE, App, 2,
                   MUIM_Application_ReturnID, ID_SAVE);

         DoMethod (Done_Gad, MUIM_Notify,
                   MUIA_Pressed, FALSE, App, 2,
                   MUIM_Application_ReturnID, MUIV_Application_ReturnID_Quit);

         DoMethod (Win, MUIM_Window_SetCycleChain, Select_Gad, Save_Gad, Done_Gad, NULL);

         set (Win, MUIA_Window_Open, TRUE);
         set (Select_Gad, MUIA_Radio_Active, TeXFormat.CurrentFormat->ID);

         HandleIDCMP (&TeXFormat, &Settings);

         Cleanup (NULL, ERR_NOERROR);
         }
      else
         Cleanup ("Couldn't create MUI application.", ERR_MUI);
      }
   else
      {
      sprintf (ErrorStrg, "%s%s\n", ErrorMsg[FormatAvail], Settings.ArgStr[KW_FORMATPATH]);
      Cleanup (ErrorStrg, ERR_FORMATFILES);
      }
   }
else
   {
   sprintf (ErrorStrg, "No muimaster.library of version >= %d\n", MUIMASTER_VMIN);
   Cleanup (ErrorStrg, ERR_NOMUILIB);
   }
}


/***************************************************************************
 *                                                                         *
 *  Function name : ParseWB                                                *
 *                                                                         *
 *  Description : Fetches and parses the ToolTypes from the TeXFormat icon.*
 *                Allowed tooltypes are :                                  *
 *                   CURRENTFORMAT (Specifies the name of the environment  *
 *                                  variable in which the name of the      *
 *                                  current TeX format file is stored.)    *
 *                   FORMATPATH (Specifies the path for the TeX            *
 *                               format files is stored.)                  *
 *                   PATTERN (Specifies the file pattern for fromat files. *
 *                            Typically it's #?.fmt.)                      *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *  Synopsis : ParseWB (WBArgStr, Settings)                                *
 *                                                                         *
 *  Parameters :                                                           *
 *    (struct WBStartup **) WBArgStr:                                      *
 *          The WB argument string.                                        *
 *    (struct Settings *) Settings:                                        *
 *          The tags of theses structure are filled by this procedure.     *
 *                                                                         *
 *  Return value : None                                                    *
 *                                                                         *
 ***************************************************************************/

void  ParseWB (struct WBStartup *WBArgStr, struct Settings *Settings)

{
struct DiskObject   *DiskObj;
struct WBArg        *WBArg;
char               **ToolArray;


WBArg = WBArgStr->sm_ArgList;

if (WBArg->wa_Name)     // get tooltypes
   if (DiskObj = GetDiskObject (WBArg->wa_Name))
      {
      ToolArray = (char **)DiskObj->do_ToolTypes;
      stpcpy (Settings->ArgStr[KW_CURRENTFORMAT], FindToolType (ToolArray, Keywords[KW_CURRENTFORMAT]));
      stpcpy (Settings->ArgStr[KW_FORMATPATH], FindToolType (ToolArray, Keywords[KW_FORMATPATH]));
      stpcpy (Settings->ArgStr[KW_PATTERN], FindToolType (ToolArray, Keywords[KW_PATTERN]));
      FreeDiskObject (DiskObj);
      }

GetVar (Settings->ArgStr[KW_CURRENTFORMAT], Settings->CurrentFormat, sizeof (Settings->CurrentFormat), GVF_GLOBAL_ONLY);
}



/***************************************************************************
 *                                                                         *
 *  Function name : ParseShell                                             *
 *                                                                         *
 *  Description : Parses the commandline for parameters.                   *
 *                Allowed parameters are :                                 *
 *                   CURRENTFORMAT/K (Specifies the name of the environment*
 *                                    variable in which the name of the    *
 *                                    current TeX format file is stored.   *
 *                   FORMATPATH/K (Specifies the the path for the TeX      *
 *                                 format files is stored.                 *
 *                   PATTERN(K (Specifies the file pattern for fromat files*
 *                              Typically it's #?.fmt.)                    *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *  Synopsis : ParseShell (NoOfArgs, Arg, Settings)                        *
 *                                                                         *
 *  Parameters :                                                           *
 *    (int) NoOfArgs:                                                      *
 *          The number of arguments.                                       *
 *    (char **) Arg:                                                       *
 *          The shell argument string.                                     *
 *    (struct Settings *) Settings:                                        *
 *          The tags of theses structure are filled by this procedure.     *
 *                                                                         *
 *  Return value : None                                                    *
 *                                                                         *
 ***************************************************************************/

void  ParseShell (int NoOfArgs, char **Arg, struct Settings *Settings)

{
int            kword;
struct RDArgs *RDArgs;
char           Template[CMDSTRLENGTH];


for (kword = 0, Template[0] = 0; kword < LAST_KW; kword++)
   {
   if (Template[0]) strcat (Template, ",");
   strcat (Template, Keywords[kword]);
   strcat (Template, Switchs[kword]);
   }

if (RDArgs = ReadArgs (Template, Settings->ArgPtr, NULL))
   {
   for (kword = 0; kword < LAST_KW; kword++)
      if (Settings->ArgPtr[kword])
         stpcpy (Settings->ArgStr[kword], (char *)Settings->ArgPtr[kword]);
   }
else
   PrintFault (IoErr (), "Error reading arguments");

GetVar (Settings->ArgStr[KW_CURRENTFORMAT], Settings->CurrentFormat, sizeof (Settings->CurrentFormat), GVF_GLOBAL_ONLY);

FreeArgs (RDArgs);
}


/***************************************************************************
 *                                                                         *
 *  Function name : ScanFormatPath                                         *
 *                                                                         *
 *  Description : Scans the format path for TeX format files, creates      *
 *                and fills for each file a struct FormatNode, updates     *
 *                the TeXFormat structure and reads the Settings->Texformat*
 *                environment variable.                                    *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *  Synopsis : ScanFormatPath (TeXFormat, Settings)                        *
 *                                                                         *
 *  Parameters :                                                           *
 *    (struct TeXFormat *) TeXFormat:                                      *
 *          This structure will be filled with the names of the format     *
 *          files found.                                                   *
 *    (struct Settings *) Settings:                                        *
 *          Contains the path and extension of the format files and the    *
 *          name of the TEXFORMAT enviroenment variable.                   *
 *                                                                         *
 *  Return value : (enum ScanError)                                        *
 *    SCAN_OK, if at least one TeX format file was found and the content   *
 *             this variable matches a scanned TeX format file.            *
 *    NO_LOCK, if path couldn't be locked for examination.                 *
 *  NO_FORMAT, if no TeX format file was found.                            *
 *     NO_ENV, if one of the environment variables is unset.               *
 *   NO_MATCH, if content of the CURRENTFORMAT environment variable        *
 *             matches no scanned format file.                             *
 *  NO_MEMORY, if no memory for the FormatNodes was available.             *
 *                                                                         *
 ***************************************************************************/

enum ScanError    ScanFormatPath (struct TeXFormat *TeXFormat, struct Settings *Settings)

{
int                  Index;
BPTR                 OldLock, NewLock;
BOOL                 ActFormatFound = FALSE, Match, Error = FALSE;
struct AnchorPath    APath;
struct FormatNode   *NewNode, *LastNode = NULL;
char                 FormatName[FNSIZE];


APath.ap_BreakBits          = 0;
APath.ap_Strlen             = 0;
TeXFormat->FirstNode        = NULL;
TeXFormat->MaxCommentLength = 1;
TeXFormat->MaxCommentLines  = 1;

if ((strlen (Settings->CurrentFormat) != 0) && (strlen (Settings->ArgStr[KW_FORMATPATH]) != 0))
   {
   if (NewLock = Lock (Settings->ArgStr[KW_FORMATPATH], ACCESS_READ))
      {
      OldLock = CurrentDir (NewLock);

      for (Index = 0, Match = MatchFirst (Settings->ArgStr[KW_PATTERN], &APath); !Match; Match = MatchNext (&APath), Index++)
         {
         SplitName (APath.ap_Info.fib_FileName, '.', FormatName, 0, sizeof (FormatName));
         if (strlen (FormatName) == 0) Index--;
         else
            {
            if (NewNode = (struct FormatNode *) calloc (sizeof (struct FormatNode), 1))
               {
               if (TeXFormat->FirstNode == NULL) TeXFormat->FirstNode = NewNode;
               else                              LastNode->NextNode   = NewNode;

               sprintf (NewNode->Name, "%-s", FormatName);
               stpcpy (NewNode->Comment, APath.ap_Info.fib_Comment);
               LastNode = NewNode;

               if (!strcmpi (Settings->CurrentFormat, FormatName))
                  {
                  TeXFormat->CurrentFormat  = NewNode;
                  ActFormatFound            = TRUE;
                  }
               if (LineLength (NewNode->Comment) > TeXFormat->MaxCommentLength)
                  TeXFormat->MaxCommentLength = LineLength (NewNode->Comment);
               if (NoOfLines (NewNode->Comment) > TeXFormat->MaxCommentLines)
                  TeXFormat->MaxCommentLines = NoOfLines (NewNode->Comment);
               if (NoOfLines (NewNode->Comment) > 1)
                  ConvertNL (NewNode->Comment);
               }
            else
               {
               Error = TRUE;
               break;
               }
            }
         }

      MatchEnd (&APath);
      CurrentDir (OldLock);
      UnLock (NewLock);

      TeXFormat->NoOfFormats  = Index;

      if (Error)                    return (NO_MEMORY);
      if (!TeXFormat->NoOfFormats)  return (NO_FORMAT);
      if (!ActFormatFound)          return (NO_MATCH);

      TeXFormat->FormatArray  = (char **)calloc (TeXFormat->NoOfFormats + 1, sizeof (TeXFormat->FormatArray[0]));

      for (Index = 0, TeXFormat->DummyComment[0] = 0; Index < TeXFormat->MaxCommentLength; Index++)
         strcat (TeXFormat->DummyComment, " ");
      for (Index = 1; Index < TeXFormat->MaxCommentLines; Index++)
         strcat (TeXFormat->DummyComment, NEWLINE);

      if (TeXFormat->FormatArray)
         {
         for (Index = 0, NewNode = TeXFormat->FirstNode; Index < TeXFormat->NoOfFormats; Index++, NewNode = NewNode->NextNode)
            TeXFormat->FormatArray[Index]  = NewNode->Name;

         strsrt (TeXFormat->FormatArray, TeXFormat->NoOfFormats);
         TeXFormat->FormatArray[TeXFormat->NoOfFormats]  = NULL;

         for (NewNode = TeXFormat->FirstNode; NewNode != NULL; NewNode = NewNode->NextNode)
            for (Index = 0; Index < TeXFormat->NoOfFormats; Index++)
               if (TeXFormat->FormatArray[Index] == NewNode->Name)
                  NewNode->ID = Index;
         }
      else
         return (NO_MEMORY);
      }
   else
      return (NO_LOCK);
   }
else
   return (NO_ENV);

return (SCAN_OK);
}


/***************************************************************************
 *                                                                         *
 *  Function name : HandleIDCMP                                            *
 *                                                                         *
 *  Description : Tests IDCMP port for incoming messages.                  *
 *                This function returns if the window close gaget or the   *
 *                DONE gadget was activated.                               *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *  Synopsis : HandleIDCMP (TeXFormat, Settings)                           *
 *                                                                         *
 *  Parameters :                                                           *
 *    (struct TeXFormat *) TeXFormat:                                      *
 *          This structure contains the names of the TeX formats available.*
 *    (struct Settings *) Settings:                                        *
 *          Contains the path and extension of the format files and the    *
 *          name of the TEXFORMAT enviroenment variable.                   *
 *                                                                         *
 *  Return value : None                                                    *
 *                                                                         *
 ***************************************************************************/

void HandleIDCMP (struct TeXFormat *TeXFormat, struct Settings *Settings)

{
BOOL                 Running = TRUE;
ULONG                Signal;
struct FormatNode   *FNode;
int                  FormatID;
char                 CMDStrg[128];


while (Running)
   {
   switch (DoMethod (App, MUIM_Application_Input, &Signal))
      {
      case MUIV_Application_ReturnID_Quit:
         Running = FALSE;
         break;

      case ID_HIDE:
         set (Description_TextField, MUIA_Text_Contents, TeXFormat->DummyComment);
         break;

      case ID_SHOW:
         set (Description_TextField, MUIA_Text_Contents, TeXFormat->CurrentFormat->Comment);
         break;

      case ID_FORMAT_SEL:
         get (Select_Gad, MUIA_Radio_Active, &FormatID);
         for (FNode = TeXFormat->FirstNode; FNode != NULL; FNode = FNode->NextNode)
            if (FNode->ID == FormatID) break;
         TeXFormat->CurrentFormat = FNode;
         set (Description_TextField, MUIA_Text_Contents, FNode->Comment);
         SetVar (Settings->ArgStr[KW_CURRENTFORMAT], FNode->Name, strlen (FNode->Name), GVF_GLOBAL_ONLY);
         break;

      case ID_SAVE:
         sprintf (CMDStrg, "copy env:%s envarc:%s", Settings->ArgStr[KW_CURRENTFORMAT], Settings->ArgStr[KW_CURRENTFORMAT]);
         system (CMDStrg);
         break;

      case ID_ABOUT:
   		MUI_Request (App, Win, 0, NULL, "OK", "\n               TeXFormat %s         \n\n     A Format File Selector for TeX \n\n        (c) 1993 by Richard Bödi\n\n Mathematisches Institut\n Universität Tübingen\n Auf der Morgenstelle 10\n 72076 Tübingen\n Germany\n\ne-mail :\n mmisa01@mailserv.zdv.uni-tuebingen.de\n");
         break;
      }

	if (Running && Signal) Wait (Signal);
   }
}


/***************************************************************************
 *                                                                         *
 *  Function name : LineLength                                             *
 *                                                                         *
 *  Description : Determines the length of the longest lines of a string   *
 *                which contains '\n' as a newline token.                  *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *  Synopsis : LineLength (Strg)                                           *
 *                                                                         *
 *  Parameters :                                                           *
 *    (char *) Strg:                                                       *
 *          The input string.                                              *
 *                                                                         *
 *  Return value :                                                         *
 *    (int) The length of the longest line.                                *
 *                                                                         *
 ***************************************************************************/

int   LineLength (char *Strg)

{
char  Buffer[COMMENTLENGTH];
char *String = Strg;
int   MaxLength = 0;

while (1)
   {
   String = stptok (String, Buffer, sizeof (Buffer), "\\");
   if (strlen (Buffer) > MaxLength) MaxLength = strlen (Buffer);
   if (String[0] == '\0') break;
   if (String[1] == 'n')  String++;
   String++;
   }

return (MaxLength);
}


/***************************************************************************
 *                                                                         *
 *  Function name : NoOfLines                                              *
 *                                                                         *
 *  Description : Determines the number of lines of a string               *
 *                which contains '\n' as a newline token.                  *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *  Synopsis : NoOfLines (Strg)                                            *
 *                                                                         *
 *  Parameters :                                                           *
 *    (char *) Strg:                                                       *
 *          The input string.                                              *
 *                                                                         *
 *  Return value :                                                         *
 *    (int) The number of lines in the string.                             *
 *                                                                         *
 ***************************************************************************/

int   NoOfLines (char *Strg)

{
char  Buffer[COMMENTLENGTH];
char *String = Strg;
int   Lines = 1;

while (1)
   {
   String = stptok (String, Buffer, sizeof (Buffer), "\\");
   if (String[0] == '\0') break;
   if (String[1] == 'n')
      {
      String++;
      Lines++;
      }
   String++;
   }

return (Lines);
}


/***************************************************************************
 *                                                                         *
 *  Function name : ConvertNL                                              *
 *                                                                         *
 *  Description : Converts \n to newline characters.                       *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *  Synopsis : ConvertNL (Strg)                                            *
 *                                                                         *
 *  Parameters :                                                           *
 *    (char *) Strg:                                                       *
 *          The input string.                                              *
 *                                                                         *
 *  Return value :                                                         *
 *    (char *) Same as the input string.                                   *
 *                                                                         *
 ***************************************************************************/

char  *ConvertNL (char *Strg)

{
char  Buffer[COMMENTLENGTH];
char *String = Strg;

while (1)
   {
   String = stptok (String, Buffer, sizeof (Buffer), "\\");
   if (String[0] == '\0') break;
   if (String[1] == 'n')
      {
      String[0] = ' '; String[1] = '\n';
      String++;
      }
   String++;
   }

return (Strg);
}



/***************************************************************************
 *                                                                         *
 *  Function name : OpenLibs                                               *
 *                                                                         *
 *  Description : Opens the following libraries:                           *
 *                 mui.library                                             *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *  Synopsis : OpenLibs ()                                                 *
 *                                                                         *
 *  Parameters : None                                                      *
 *                                                                         *
 *  Return value : BOOL                                                    *
 *    TRUE, if successful                                                  *
 *   FALSE, if not.                                                        *
 *                                                                         *
 ***************************************************************************/

BOOL OpenLibs ()

{
if (MUIMasterBase = (struct Library *)OpenLibrary (MUIMASTER_NAME, MUIMASTER_VMIN))
   return (TRUE);
else
   return (FALSE);
}


/***************************************************************************
 *                                                                         *
 *  Function name : Cleanup                                                *
 *                                                                         *
 *  Description : Frees all allocated memory, closes down the MUI          *
 *                application, possibly prints some error message and      *
 *                exits.                                                   *
 *                                                                         *
 ***************************************************************************
 *                                                                         *
 *  Synopsis : Cleanup (Strg, ErrorID)                                     *
 *                                                                         *
 *  Parameters :                                                           *
 *    (char *) Strg:                                                       *
 *       Pointer to a message string.                                      *
 *    (enum ErrorIDs) ErrorID:                                             *
 *       Error code identifier.                                            *
 *                                                                         *
 *  Return value : None                                                    *
 *                                                                         *
 ***************************************************************************/

void Cleanup (char *Strg, enum ErrorIDs ErrorID)

{
if (Strg)            puts (Strg);
if (App)             MUI_DisposeObject (App);
if (MUIMasterBase)   CloseLibrary (MUIMasterBase);

exit (ErrorID);
}

