/* Compare two or three files. The assumption is that they are files known
   to be different from one another, already. We want to know *how*
   different they are from one another. Essentially, this program reads
   two or three files, notes the number of bytes read, and notes how many
   bytes do not match. (This is a strict byte-for-byte comparison.)

   Written by James Jacobs and Ward Shrake
   Last update: 13 October 2013 */

#ifdef AMIGA
    #include <exec/types.h>
    #include <exec/execbase.h>
    #include <dos/dos.h>
    #define MAX_PATH           512
#endif
#ifdef WIN32
    #include <windows.h>

    typedef unsigned char      UBYTE;
    typedef unsigned char      TEXT;
    typedef unsigned short     UWORD;
    typedef unsigned long      ULONG;
    typedef unsigned char*     STRPTR;
    #define IMPORT             extern
    #define __inline
#endif

#include <stdio.h>
#include <stdlib.h>          /* EXIT_SUCCESS, EXIT_FAILURE */
#define EXIT_WARN     5

typedef signed char  FLAG;   /* 8-bit signed quantity (replaces BOOL) */
typedef signed char  SBYTE;  /* 8-bit signed quantity (replaces Amiga BYTE) */
typedef signed short SWORD;  /* 16-bit signed quantity (replaces Amiga WORD) */
typedef signed long  SLONG;  /* 32-bit signed quantity (same as LONG) */
#define acase        break; case
#define elif         else if
#define DISCARD      (void)
#define MODULE       static  /* external static (file-scope) */
#define PERSIST      static  /* internal static (function-scope) */
#define TRANSIENT    auto    /* automatic (function-scope) */
#define EOS          '\0'

#define BPL           16 // bytes per line

#define HOWDIF_GREY    0 // black on Amiga
#define HOWDIF_GREEN   1 // black on Amiga
#define HOWDIF_RED     2 // white on Amiga
#define HOWDIF_YELLOW  3 // cyan on Amiga

// Module and global variables are initialized to zero by default.

MODULE STRPTR                memory[3] = {NULL, NULL}; // 3rd element doesn't need to be initialized
MODULE struct RDArgs*        ArgsPtr;
MODULE TEXT                  ansi_green[20],
                             ansi_red[20],
                             ansi_grey[20],
                             ansi_yellow[20],
                             errorstring[MAX_PATH + 80 + 1];
MODULE FLAG                  arcadia     = FALSE,
                             ascii       = TRUE,
                             elektor     = FALSE,
                             instructor  = FALSE,
                             vanilla     = FALSE;
MODULE ULONG                 shortestsize,
                             size[3];
MODULE int                   colour      = -1,
                             files       =  1;

#ifdef WIN32
    MODULE FLAG              lame        = FALSE,
                             rets        = FALSE;
#endif

MODULE void cleanexit(SLONG rc);
MODULE void hexalize(UBYTE data);
MODULE void go_red(void);
MODULE void go_green(void);
MODULE void go_grey(void);
MODULE void go_yellow(void);
MODULE void printusage(STRPTR name);
MODULE int getsize(STRPTR passedfilename);
MODULE void rq(STRPTR message);
MODULE void changecolour(int offset);
MODULE void newline(void);

int main(int argc, char** argv)
{   TRANSIENT ULONG  percent1,
                     percent2,
                     bw              = 0;
    PERSIST   TEXT   arcadia_chars[] = " /\\#bc_efghijklm0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ.,+$nopqrstu";
#ifdef AMIGA
    PERSIST   TEXT   elektor_chars[] = "0123456789AbCdEFGLInPr= +-:x···································································?································" \
                                       "··········_·······················!·······N················lT··································i······:················.········",
                  instructor_chars[] = "0123456789AbCdEFPLUrHo= J-?YN···································································································" \
                                       "································································································································";
#endif
#ifdef WIN32
    PERSIST   TEXT   elektor_chars[] = "0123456789AbCdEFGLInPr= +-:xúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúú?úúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúú" \
                                       "úúúúúúúúúú_úúúúúúúúúúúúúúúúúúúúúúú!úúúúúúúNúúúúúúúúúúúúúúúúlTúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúiúúúúúú:úúúúúúúúúúúúúúúú.úúúúúúúú",
                  instructor_chars[] = "0123456789AbCdEFPLUrHo= J-?YNúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúú" \
                                       "úúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúúú";
#endif
    TRANSIENT STRPTR thefilename[3]  = {NULL, NULL, NULL};
    TRANSIENT FILE*  FileHandle   /* = NULL */ ;
    TRANSIENT int    i, j;
#ifdef AMIGA
    TRANSIENT SLONG  args[7 + 2]     = {0, 0, 0, 0, 0, 0, 0, 0, 0};
#endif
#ifdef WIN32
    TRANSIENT OSVERSIONINFO Vers;
#endif

    if (0)
    {   printf("$VER: HowDif 3.0 (13.10.2013)");
    }

#ifdef AMIGA
    ansi_green[0] = 0x9b;
    ansi_green[1] = EOS;
    strcat(ansi_green, "0;39;39;>0m"); // means 'vanilla'

    ansi_red[0] = 0x9b;
    ansi_red[1] = EOS;
    strcat(ansi_red, "0;32;40;>0m"); // means 'white on grey'

    ansi_yellow[0] = 0x9b;
    ansi_yellow[1] = EOS;
    strcat(ansi_yellow, "0;36;40;>0m"); // means 'yellow on grey'

    strcpy(ansi_grey, ansi_green);

    if (argc) /* started from CLI */
    {   if
        (   (!(ArgsPtr = ReadArgs
            (   "FILE1/A,FILE2,FILE3,-V=VANILLA/S,-N=NOASCII/S,ARCADIA/S,ELEKTOR/S,INSTRUCTOR/S",
                (LONG *) args,
                NULL
            )))
        )
        {   printusage(argv[0]);
        }
        if (args[1])
        {   files = 2;
            if (args[2])
            {   files = 3;
        }   }
        if (args[3])
        {   vanilla = TRUE;
        }
        if (args[4])
        {   ascii   = FALSE;
        }
        if (args[5])
        {   arcadia = TRUE;
        }
        if (args[6])
        {   elektor = TRUE;
        }
        if (args[7])
        {   instructor = TRUE;
    }   }
    else
    {   // started from Workbench
        printusage("HowDif");
    }

    thefilename[0] = args[0];
    thefilename[1] = args[1];
    thefilename[2] = args[2];
#endif

#ifdef WIN32
    Vers.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
    DISCARD GetVersionEx((LPOSVERSIONINFO) &Vers);
    if (Vers.dwPlatformId == VER_PLATFORM_WIN32_NT)
    {   lame = TRUE;
        /* if (Vers.dwMajorVersion >= 6)
        {   // T1; zprintf("Vista/Windows 7/8 detected!\n"); T2;
            win7 = TRUE;
        } */
    } elif (Vers.dwPlatformId == VER_PLATFORM_WIN32s)
    {   ; // T1; zprintf("Please upgrade to Windows 9x!\n"); T2;
    } elif (Vers.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
    {   ; // T1; zprintf("Windows 9x detected.\n"); T2;
    } else
    {   // T1; zprintf("Unknown OS!\n"); T2;
        lame = TRUE;
    }

    if (!lame)
    {   ansi_green[0] = 27;
        ansi_green[1] = EOS;
        strcat(ansi_green, "[31m");

        ansi_red[0] = 27;
        ansi_red[1] = EOS;
        strcat(ansi_red, "[32m");

        ansi_grey[0] = 27;
        ansi_grey[1] = EOS;
        strcat(ansi_grey, "[37m");

        ansi_grey[0] = 27;
        ansi_grey[1] = EOS;
        strcat(ansi_yellow, "[33m");
    }

    if (argc >= 2)
    {   for (i = 1; i < argc; i++)
        {   if (!strcmp(argv[i], "?"))
            {   printusage(argv[0]);
            } elif (!stricmp(argv[i], "-v") || !stricmp(argv[i], "VANILLA"))
            {   vanilla = TRUE;
            } elif (!stricmp(argv[i], "-n") || !stricmp(argv[i], "NOASCII"))
            {   ascii = FALSE;
            } elif (!stricmp(argv[i], "ARCADIA"))
            {   arcadia = TRUE;
            } elif (!stricmp(argv[i], "ELEKTOR"))
            {   elektor = TRUE;
            } elif (!stricmp(argv[i], "INSTRUCTOR"))
            {   instructor = TRUE;
            } elif (!stricmp(argv[i], "-r") || !stricmp(argv[i], "RETURNS"))
            {   rets = TRUE;
            } else
            {   if (!thefilename[0])
                {   thefilename[0] = argv[i];
                } elif (!thefilename[1])
                {   thefilename[1] = argv[i];
                } elif (!thefilename[2])
                {   thefilename[2] = argv[i];
                } else
                {   printusage(argv[0]);
    }   }   }   }
    else
    {   printusage(argv[0]);
    }

    if (thefilename[1])
    {   if (thefilename[2])
        {   files = 3;
        } else
        {   files = 2;
    }   }
#endif

    if
    (   (arcadia && elektor   )
     || (arcadia && instructor)
     || (elektor && instructor)
    )
    {   printusage(argv[0]);
    }

    go_grey();
#ifdef AMIGA
    printf("HowDif 3.0 for Amiga\n\n");
#endif
#ifdef WIN32
    printf("HowDif 3.0 for Windows\n\n");
#endif

    size[0] = size[1] = size[2] = 0;

    for (i = 0; i < files; i++)
    {   size[i] = getsize(thefilename[i]);
        if (!(memory[i] = (UBYTE *) malloc(size[i])))
        {   printf("Out of memory!\n");
            cleanexit(EXIT_FAILURE);
        }
        if (!(FileHandle = fopen((char *) thefilename[i], "rb"))) // just cast for lint
        {   sprintf
            (   errorstring,
                "fopen(\"%s\") failed!",
                thefilename[i]
            );
            rq(errorstring);
        }
        if (fread(memory[i], (size_t) size[i], 1, FileHandle) != 1)
        {   fclose(FileHandle);
            // FileHandle = NULL;
            sprintf
            (   errorstring,
                "fread(\"%s\") failed!",
                thefilename[i]
            );
            rq(errorstring);
        }
        fclose(FileHandle);
        // FileHandle = NULL;
    }

    if (files == 1)
    {   printf(              "File is %s (%ld bytes).\n", thefilename[0], size[0]);
        shortestsize = size[0];
    } else
    {   printf(    "  Primary file is %s (%ld bytes).\n", thefilename[0], size[0]);
        printf(    "Secondary file is %s (%ld bytes).\n", thefilename[1], size[1]);
        if (size[0] < size[1])
        {   shortestsize = size[0];
        } else
        {   shortestsize = size[1];
        }
        if (files == 3)
        {   printf(" Tertiary file is %s (%ld bytes).\n", thefilename[2], size[2]);
            if (size[2] < shortestsize)
            {   shortestsize = size[2];
    }   }   }
    printf("\n");

    if (shortestsize > 65535)
    {   printf("  ");
    }
    printf("       0011 2233 4455 6677 8899 AABB CCDD EEFF");
    if (ascii)
    {   printf(" 0123456789ABCDEF");
    }
    if (arcadia || elektor || instructor)
    {   printf(" 0123456789ABCDEF");
    }
    newline();

    if (shortestsize > 65535)
    {   printf("  ");
    }
    printf("       ---------------------------------------");
    if (ascii)
    {   printf(" ----------------");
    }
    if (arcadia || elektor || instructor)
    {   printf(" ----------------");
    }
    newline();

    for (i = 0; i < (int) shortestsize; i += BPL)
    {   go_grey();
        printf("$");

        if (shortestsize > 65535)
        {   hexalize((UBYTE) (i / 16777216)); // do 1st byte
            j =  i % 16777216;                // remove 1st byte
            hexalize((UBYTE) (j /    65536)); // do 2nd byte
            j %= 65536;                       // remove 2nd byte
        } else
        {   j = i;
        }
        hexalize((UBYTE) (j / 256));          // do 3rd byte
        hexalize((UBYTE) (j % 256));          // do 4th byte

        printf(": ");

        for (j = 0; j < BPL; j++)
        {   if (i + j < (int) shortestsize)
            {   changecolour(i + j);
                hexalize(memory[0][i + j]);
            } else
            {   go_grey();
                printf("##");
            }
            if (j % 2 && j < BPL - 1)
            {   printf(" ");
        }   }

        if (ascii)
        {   printf(" ");
            for (j = 0; j < BPL; j++)
            {   if (i + j < (int) shortestsize)
                {   changecolour(i + j);
                    if
                    (    memory[0][i + j] < ' '
                      || (memory[0][i + j] >= 0x80 && memory[0][i + j] <= 0x9F)
                    ) // if an unprintable character
                    {
#ifdef AMIGA
                        printf("·");
#endif
#ifdef WIN32
                        printf("ú");
#endif
                    } else
                    {   printf("%c", memory[0][i + j]);
                }   }
                else
                {   go_grey();
                    printf("#");
        }   }   }

        if (arcadia)
        {   printf(" ");
            for (j = 0; j < BPL; j++)
            {   if (i + j < (int) shortestsize)
                {   changecolour(i + j);
                    printf("%c", arcadia_chars[memory[0][i + j] % 64]);
                } else
                {   go_grey();
                    printf("#");
        }   }   }

        if (elektor)
        {   printf(" ");
            for (j = 0; j < BPL; j++)
            {   if (i + j < (int) shortestsize)
                {   changecolour(i + j);
                    printf("%c", elektor_chars[memory[0][i + j]]);
                } else
                {   go_grey();
                    printf("#");
        }   }   }

        if (instructor)
        {   printf(" ");
            for (j = 0; j < BPL; j++)
            {   if (i + j < (int) shortestsize)
                {   changecolour(i + j);
                    printf("%c", instructor_chars[memory[0][i + j]]);
                } else
                {   go_grey();
                    printf("#");
        }   }   }

        newline();

#ifdef AMIGA
        /* From RKM Libraries, p. 432:

        get current state of signals */
        if (SetSignal(0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C)
        {   // then clear the Ctrl-C signal
            SetSignal(0L, SIGBREAKF_CTRL_C);
            go_grey();
            printf("User break!\n");
            cleanexit(EXIT_SUCCESS);
        }
#endif
    }

    // when the program is all done comparing, print a summary report onscreen
    go_grey();

    if (files >= 2)
    {   printf("\n");
        for (i = 0; i < (int) shortestsize; i++)
        {   if (files == 2)
            {   if (memory[0][i] != memory[1][i])
                {   bw++;
                    if (shortestsize > 65535)
                    {   printf
                        (   "Mismatch at byte $%08X ($%02X vs. $%02X)\n",
                            i,
                            memory[0][i],
                            memory[1][i]
                        );
                    } else
                    {   printf
                        (   "Mismatch at byte $%04X ($%02X vs. $%02X)\n",
                            i,
                            memory[0][i],
                            memory[1][i]
                        );
                    }
            }   }
            else
            {   // assert(files == 3);
                if
                (   memory[0][i] != memory[1][i]
                 && memory[0][i] != memory[2][i]
                 && memory[1][i] != memory[2][i]
                )
                {   bw++;
                    if (shortestsize > 65535)
                    {   printf
                        (   "Total   mismatch at byte $%08X ($%02X vs. $%02X vs. $%02X)\n",
                            i,
                            memory[0][i],
                            memory[1][i],
                            memory[2][i]
                        );
                    } else
                    {   printf
                        (   "Total   mismatch at byte $%04X ($%02X vs. $%02X vs. $%02X)\n",
                            i,
                            memory[0][i],
                            memory[1][i],
                            memory[2][i]
                        );
                }   }
                elif
                (   memory[0][i] != memory[1][i]
                 || memory[0][i] != memory[2][i]
                 || memory[1][i] != memory[2][i]
                )
                {   bw++;
                    if (shortestsize > 65535)
                    {   printf
                        (   "Partial mismatch at byte $%08X ($%02X vs. $%02X vs. $%02X)\n",
                            i,
                            memory[0][i],
                            memory[1][i],
                            memory[2][i]
                        );
                    } else
                    {   printf
                        (   "Partial mismatch at byte $%04X ($%02X vs. $%02X vs. $%02X)\n",
                            i,
                            memory[0][i],
                            memory[1][i],
                            memory[2][i]
                        );
        }   }   }   }

        if (!bw)
        {   percent1 =
            percent2 = 0;
        } else
        {   printf("\n");
            if (bw == shortestsize)
            {   percent1 = 100000000;
                percent2 =       100;
            } else
            {   percent1 = (100000000 / shortestsize) * bw;
                percent2 = percent1 / 1000000;
        }   }

        printf("Mismatches: %d of %d (", bw, shortestsize);

        if (percent1 > 0 && percent2 == 0)
        {   printf("<1%%)\n");
        } else
        {   printf("%d%%)\n", percent2);
    }   }

    if (bw)
    {   cleanexit(EXIT_WARN);
    } else
    {   cleanexit(EXIT_SUCCESS);
    }

    // control never reaches here
    return EXIT_SUCCESS; // to avoid spurious compiler warnings
}

MODULE void go_red(void)
{   if (!vanilla && colour != HOWDIF_RED)
    {
#ifdef WIN32
        if (lame)
        {   DISCARD SetConsoleTextAttribute
            (   GetStdHandle(STD_OUTPUT_HANDLE),
                FOREGROUND_INTENSITY | FOREGROUND_RED
            );
        } else
        {   printf("%s", ansi_red);
        }
#else
        printf("%s", ansi_red);
#endif
        colour = HOWDIF_RED;
}   }

MODULE void go_green(void)
{   if (!vanilla && colour != HOWDIF_GREEN)
    {
#ifdef WIN32
        if (lame)
        {   DISCARD SetConsoleTextAttribute
            (   GetStdHandle(STD_OUTPUT_HANDLE),
                FOREGROUND_INTENSITY | FOREGROUND_GREEN
            );
        } else
        {   printf("%s", ansi_green);
        }
#else
        printf("%s", ansi_green);
#endif
	    colour = HOWDIF_GREEN;
}   }

MODULE void go_yellow(void)
{   if (!vanilla && colour != HOWDIF_YELLOW)
    {
#ifdef WIN32
        if (lame)
        {   DISCARD SetConsoleTextAttribute
            (   GetStdHandle(STD_OUTPUT_HANDLE),
                FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN
            );
        } else
        {   printf("%s", ansi_yellow);
        }
#else
        printf("%s", ansi_yellow);
#endif
	    colour = HOWDIF_YELLOW;
}   }

MODULE void go_grey(void)
{   if (!vanilla && colour != HOWDIF_GREY)
    {
#ifdef WIN32
        if (lame)
        {   DISCARD SetConsoleTextAttribute
            (   GetStdHandle(STD_OUTPUT_HANDLE),
                FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
            );
        } else
        {   printf("%s", ansi_grey);
        }
#else
        printf("%s", ansi_grey);
#endif
        colour = HOWDIF_GREY;
}   }

MODULE void cleanexit(SLONG rc)
{   if (memory[0])
    {   free(memory[0]);
        // memory[0] = NULL;
    }
    if (memory[1])
    {   free(memory[1]);
        // memory[1] = NULL;
    }
    if (memory[2])
    {   free(memory[2]);
        // memory[2] = NULL;
    }

#ifdef AMIGA
    if (ArgsPtr)
    {   FreeArgs(ArgsPtr);
    }
#endif

    exit(rc);
}

MODULE void hexalize(UBYTE data)
{   TEXT tempstring[2 + 1];

    // Converts an unsigned byte into a hexadecimal string

    // do the high byte
    if (data / 16 >= 10)
    {   tempstring[0] = (data / 16) - 10 + 'A'; // must be done in this order to prevent overflow during calculation of the value
    } else
    {   tempstring[0] = (data / 16) + '0';
    }

    // now the low byte
    if (data % 16 >= 10)
    {   tempstring[1] = (data % 16) - 10 + 'A';
    } else
    {   tempstring[1] = (data % 16) + '0';
    }
    tempstring[2] = EOS;
    printf("%s", tempstring);
}

#ifdef AMIGA
    #define USAGE "Usage: %s <file1> [<file2> [<file3>]] [-v|VANILLA] [-n|NOASCII] " \
    "[ARCADIA|ELEKTOR|INSTRUCTOR]\n"
#endif
#ifdef WIN32
    #define USAGE "Usage: %s <file1> [<file2> [<file3>]] [-v|VANILLA] [-n|NOASCII] " \
    "[ARCADIA|ELEKTOR|INSTRUCTOR] [-r|RETURNS]\n"
#endif

MODULE void printusage(STRPTR name)
{   go_grey();
#ifdef AMIGA
    printf("HowDif 3.0 for Amiga\n\n");
#endif
#ifdef WIN32
    printf("HowDif 3.0 for Windows\n\n");
#endif
    printf(USAGE, name);
    cleanexit(EXIT_FAILURE);
}

MODULE int getsize(STRPTR passedfilename)
{   int localsize;

#ifdef AMIGA
    BPTR                  BHandle /* = NULL */ ;
    struct FileInfoBlock* FIBPtr  /* = NULL */ ;

    if (!(BHandle = (BPTR) Lock(passedfilename, ACCESS_READ)))
    {   sprintf
        (   errorstring,
            "Lock(\"%s\") failed!",
            passedfilename
        );
        rq(errorstring);
    }
    if (!(FIBPtr = AllocDosObject(DOS_FIB, NULL)))
    {   UnLock(BHandle);
        BHandle = NULL;
        sprintf
        (   errorstring,
            "AllocDosObject(\"%s\") failed!",
            passedfilename
        );
        rq(errorstring);
    }
    if (!(Examine(BHandle, FIBPtr)))
    {   FreeDosObject(DOS_FIB, FIBPtr);
        FIBPtr = NULL;
        UnLock(BHandle);
        BHandle = NULL;
        sprintf
        (   errorstring,
            "Examine(\"%s\") failed!",
            passedfilename
        );
        rq(errorstring);
    }
    UnLock(BHandle);
    // BHandle = NULL;
    localsize = FIBPtr->fib_Size;
    if (FIBPtr->fib_DirEntryType != -3)
    {   FreeDosObject(DOS_FIB, FIBPtr);
        FIBPtr = NULL;
        rq("Not a file!");
    }
    FreeDosObject(DOS_FIB, FIBPtr);
    // FIBPtr = NULL;
#endif
#ifdef WIN32
    HANDLE hFile /* = NULL */ ;

    hFile = CreateFile(passedfilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
    if (hFile == INVALID_HANDLE_VALUE)
    {   localsize = 0;
    } else
    {   localsize = GetFileSize(hFile, NULL);
        CloseHandle(hFile);
        // hFile = NULL;
        if (localsize == (ULONG) -1)
        {   localsize = 0;
    }   }
#endif

    return localsize;
}

MODULE void rq(STRPTR message)
{   printf("%s\n", message);
    cleanexit(EXIT_FAILURE);
}

MODULE void changecolour(int offset)
{   switch (files)
    {
    case 1:
        go_green();
    acase 2:
        if (memory[0][offset] == memory[1][offset])
        {   go_green();
        } else
        {   go_red();
        }
    acase 3:
        if
        (   memory[0][offset] == memory[1][offset]
         && memory[0][offset] == memory[2][offset]
        )
        {   // no need to compare memory[1] against memory[2]
            go_green();
        } elif
        (   memory[0][offset] == memory[1][offset]
         || memory[0][offset] == memory[2][offset]
         || memory[1][offset] == memory[2][offset]
        )
        {   go_yellow();
        } else
        {   go_red();
}   }   }

MODULE void newline(void)
{
#ifdef AMIGA
    printf("\n");
#endif
#ifdef WIN32
    if
    (   shortestsize <= 65535
     && ascii
     && (arcadia || elektor || instructor)
     && !rets
    )
    {   ;
    } else
    {   printf("\n");
    }
#endif
}
