/*-----------------------------------------*\
>  texas.c (c) 1992 by Jean-Pierre RIVIERE  <
\*-----------------------------------------*/

/* necessite que parse.c ait ete compile
*  avec ERR_MESS_WITHOUT_LETTER pas defini
*/
#include <stdio.h>
#include "parse.h"

#ifdef AMIGA
#  define ERROR_CODE 5
#else
#  define ERROR_CODE 5
#endif

#define OPTIONS "h t c;i;b s "
#define OPTION_AIDE  0
#define DEJATEX   1
#define COLONNES  2
#define INPUT     3
#define BYE_END   4
#define ESPACE    5
#define COLDEF    72
#define COLMIN    20
#ifndef   ENGLISH
#  define USAGE      "USAGE : texas [-h] [-t] [-c <colonnes>] [<entree> [<sortie>]]\n"
#  define AVIS       "tExas (c) 1992 par Jean-Pierre RIVIERE\n"
#  define REMARQUE   "%% --- traduction automatique ---\n"
#  define FORMAT     "a4"
#define AIDE   "tExas permet de traduire un texte à la norme Ansi en un" \
   " source TeX, qui devra\ncependant être édité. Si vous avez un source" \
   " TeX en 8 bits, l'option -t vous\npermettra de le transformer en 7" \
   " bits.\nL'option -c permet de préciser la colonne de césure pour les" \
   " textes d'entrée\nnon-TeX.\n" \
   "L'option -i permet de préciser le texte à inclure au début et si un" \
   "tiret est indiqué (\"-i -\"), de ne rien inclure du tout.\n" \
   "L'option -b indique de ne pas ajouter \\bye en fin de texte.\n" \
   "L'option -s enlève les espaces inutiles (très utile avec l'option -c).\n" \
   "L'option -h sert a afficher ce texte d'aide."
const char ERR_OUVERTURE [] = "impossible d'ouvrir %s\n";
#else
#  define USAGE      "USAGE : texas [-h] [-t] [-c <columns>] [<input> [<output>]]\n"
#  define AVIS       "tExas (c) 1992 by Jean-Pierre RIVIERE\n"
#  define REMARQUE   "%% --- automatic translation ---\n"
#  define FORMAT     "a4"
#define AIDE   "tExas allows that a text written according to the Ansi norm" \
   " to be converted\ninto a TeX source which you should then edit. If you" \
   " have an 8 bits TeX\nsource, the -t option will make the equivalent TeX" \
   " 7 bits source out of it.\nThe caesura columnn can be precised with the" \
   " -c option if the input text is\nnot already a TeX source.\n" \
   "The -i option specifies with text to include at the beginning, and" \
   " none if\nyou put a dash as the text name (\"-i -\").\n" \
   "The -b option indicates to not add a \\bye at the end of the text.\n" \
   "The -s option trashes extra-blanks (very useful with the -c option).\n" \
   "The -h option brings you this help text."
const char ERR_OUVERTURE [] = "cannot open %s\n";
#endif

typedef struct {
   char * commande;  /* commande ou macro TeX   */
   char code [4]; /* code de la séquence escape */
} sequence;

#ifdef DEBUG

void prseq (sequence * seq)
   /* affiche l'adresse et le contenu d'une séquence   */
{
   printf("sequence : ");
   if (!seq) {
      printf("NULL\n");
      return;
   }
   if (seq->code[0] == '\0')
      printf("~Null\n");
   printf("%x : %s --> %s .\n", seq, seq->code, seq->commande);
}

#endif

extern char * ListeSpeciaux [];
extern sequence ListeSequences [];

#define usage() { \
   fprintf(stderr, USAGE); \
   exit(ERROR_CODE);   \
   }

#define traduire_special(c,sortie)  \
   if (c >= 0xA0) \
      fprintf((sortie), ListeSpeciaux[(c) - 0xA0]);   \
   else  \
      fputc(' ', sortie)

void traduire_sequence (FILE * entree, FILE * sortie)

{
   sequence * seq;
   short sep;
   short suite;   /* utile en cas de séquences enchaînées */
   char c [3];

#  ifndef ENGLISH
   static const char * messErreur = " escape séquence a l'indice";
#  define MAUVAISE   "mauvaise"
#  define FAUSSE  "fausse"
#  define INCONNUE   "inconnue"
#  define NOCOLINTEX "pas de specification de colonnes autorisée en mode TeX\n"
#  define COLERR  "Nombre de colonnes incorrect, valeur par défaut (%d) prise\n"
#  else /* ENGLISH */
   static const char * messErreur = " escape sequence at offset";
#  define MAUVAISE   "bad"
#  define FAUSSE  "false"
#  define INCONNUE   "unknown"
#  define NOCOLINTEX "no columns specification authorized in TeX mode\n"
#  define COLERR  "incorrect columns number, default value(%d) taken\n"
   static const char * messErreur = " escape sequence at offset";
#  endif /* ENGLISH */
   static unsigned short imbrication;  /* de sequences escapes */

   if (fgetc(entree) != '[') {
      fprintf(stderr, MAUVAISE "%s%d\n",  messErreur, ftell(entree) - 1);
      return;
   }
   suite = 0;
   do {
      if (!isdigit(c[0] = fgetc(entree))) {
         fprintf(sortie, ":%c=" MAUVAISE "%s%d\n",  c[0], messErreur, ftell(entree) - 1);
         fprintf(stderr, "pseudo%s%d\n",  messErreur, ftell(entree) - 1);
         return;
      }
      if (isdigit(c[1] = fgetc(entree))) {
         sep = fgetc(entree);
         c[2] = '\0';
      } else {
         sep = c[1];
         c[1] = '\0';
      }
      if (sep != ';' && sep != 'm') {
         fprintf(stderr, FAUSSE "%s%d\n", messErreur, ftell(entree) - 1);
         return;
      }
      /* gestion de la sequence de RAZ    */
      seq = ListeSequences;
      if (*c == '0') {
         while (imbrication--)
             fprintf(sortie, "}");
         imbrication = suite = 0;
      } else {
         imbrication += 1 - suite;
         while (*seq->code != '\0' && strcmp(c, seq->code))
            seq++;
         if (!seq)
            fprintf(stderr, INCONNUE "%s%d\n", messErreur, ftell(entree) - 1);
         else
            fprintf(sortie, "%s", seq->commande + suite);
         suite = 1;  /* pour sauter { au debut   */
      }
   }while (sep == ';');
}

void traduire (FILE * entree, FILE * sortie, short maxcol, char dejatex,
               char economie)
   /*
      dejatex : indique qu'on traite un fichier deja oriente TeX,
                et par consequent on ne traduira que les que
                les caracteres etendus
      maxcol : colonne de début de césure possible. nul si pas de
               césure automatique.
      economie : vrai si les espaces inutiles au sens TeX sont à supprimer
   */
{
   short col = 0; /* colonnes en cours */
   unsigned char c;  /* caractère lu */

   c = '\n';
   while (!feof(entree)) {
      if (c >= 128)
         traduire_special(c, sortie);
      else
         switch (c) {
         default :
            fputc(c, sortie);
            col++;
            break;
         case '{' :
         case '}' :
            if (dejatex) {
               fputc(c, sortie);
               break;
            }
            /* la plupart du temps, \char`\{ est plus beau que \{ */
            fprintf(sortie, "\\char`\\%c", c);
            col += 8;
            break;
         case '<' :
         case '>' :
            if (dejatex)
               putchar(c);
            else {
               printf("$%c$", c);
               col += 3;
            }
            break;
         case ' ' :
         case '\t' :
            if (dejatex) {
               fputc(c, sortie);
               break;
            }
            if (!maxcol || ++col <= maxcol)
               fputc(' ', sortie);
            else {
               fputc('\n', sortie);
               col = 0;
            }
            if (economie) {
               while ((c = fgetc(entree)) == ' ' || c == '\t');
               continue;
            }
            break;
         case '\f' :
            fprintf(sortie, "\n\\vfill\\eject\n\n");
            col = 0;
            break;
         case 27 :
            traduire_sequence(entree, sortie);
            break;
         case '#' :
         case '$' :
         case '%' :
         case '&' :
         case '\\' :
         case '^' :
         case '_' :
            if (dejatex)
               fputc(c, sortie);
            else {
               /* \char`\ est parfois obligatoire et toujours plus beau */
               fprintf(sortie, "\\char`\\%c ", c);
               col += 9;
            }
            break;
         case '-' :
            if (dejatex) {
               fputc(c, sortie);
               break;
            }
            if ((c = fgetc(entree)) != '\n') {
               fputc('-', sortie);
               col++;
            } else {
               col = 0;
               while ((c = fgetc(entree)) == ' ' || c == '\t');
               if (!isalpha(c) && c < 0xC0)
                  fprintf(sortie, "-\n");
               else
                  fprintf(sortie, "\\-%%\n"); /* pour conserver le découpage   */
            }
            continue;
         case '\n' :
            if (dejatex) {
               fputc(c, sortie);
               break;
            }
            {
               short sauts = 0;   /* nombre de sauts de lignes */

               while ((c = fgetc(entree)) == '\n')
                  sauts++;
               /* risque d'espaces inutiles en début de ligne */
               if (economie && (c == ' ' || c == '\t'))
                  while ((c = fgetc(entree)) == ' ' || c == '\t');
               /* s'il y a beaucoup de lignes sautées, on génère un
                  espace vertical supplémentaire */
               switch(sauts) {
               case 0 :
                  if (!maxcol || ++col >= maxcol) {
                     fputc('\n', sortie);
                     col = 0;
                     break;
                  }
                  fputc(' ', sortie);
                  break;
               case 1 :
                  fputc('\n', sortie);
                  fputc('\n', sortie);
                  col = 0;
                  break;
               case 2 :
               case 3 :
                  fprintf(sortie, "\n\n\\smallskip\n\n");
                  col = 0;
                  break;
               case 4 :
               case 5 :
                  fprintf(sortie, "\n\n\\midskip\n\n");
                  col = 0;
                  break;
               default :
                  fprintf(sortie, "\n\n\\bigskip\n\n");
                  col = 0;
                  break;
               }
            }
            continue;
         }
      c = fgetc(entree);
   }
}

void main (int narg, char * parg [])

{
   FILE * entree;
   FILE * sortie;
   struct rapport rapport;
   short colonnes;
   char nopt;
   char dejatex;
   char economie;

   fprintf(stderr, AVIS);
   if ((nopt = parse(OPTIONS, narg, parg, &rapport)) < 0) {
      if (rapport.erreur == OPT_UNKNOWN_OPTION) {
         fprintf(stderr, USAGE);
         exit (0);
      }
      fprintf(stderr, ParseErrMess, rapport.lettre);
      fputc('\n', stderr);
      exit(1);
   }
   if (rapport.options[OPTION_AIDE]) {
      puts(AIDE);
      exit(0);
   }
   entree =stdin;
   sortie = stdout;
   if (rapport.narg) {
      /* attention, si le premier argument est "-", on ne fait rien */
      if (rapport.parg[0][0] != '-' || rapport.parg[0][1] != '\0')
         if (!(entree = (FILE *) fopen(rapport.parg[0], "r"))) {
            fprintf(stderr, ERR_OUVERTURE, rapport.parg[0]);
            parse_cleanup();
            exit(1);
         }
      if (rapport.narg == 2)
         if (!(sortie = (FILE *) fopen(rapport.parg[1], "w"))) {
            fprintf(stderr, ERR_OUVERTURE, rapport.parg[1]);
            parse_cleanup();
            /* exit fermera tout seul le premier fichier ouvert */
            exit(1);
         }
   }
   dejatex = rapport.options[DEJATEX];
   economie = rapport.options[ESPACE];
   colonnes = 0;
   if (rapport.options[COLONNES])
      if (dejatex)
         fprintf(stderr, NOCOLINTEX);
      else
         if ((colonnes = atoi(rapport.arguments[COLONNES])) <= COLMIN)
            fprintf(stderr, COLERR, colonnes = COLDEF);
   if (!rapport.options[INPUT])
      fprintf(sortie, REMARQUE "\\input " FORMAT "\n\n");
   else if (rapport.arguments[INPUT][0] == '-' && rapport.arguments[INPUT][1] == '\0')
      fprintf(sortie, REMARQUE "\n");
   else
      fprintf(sortie, REMARQUE "\\input %s\n\n", rapport.arguments[INPUT]);
   traduire(entree, sortie, colonnes, dejatex, economie);
   if (!rapport.options[BYE_END])
      fprintf(sortie, "\n\n\\bye\n");
   /* pour la fermeture des fichiers, on fait confiance a exit() */
   exit(0);
}

/* liste des macros traductions */

char * ListeSpeciaux [] = {
   /* 0xa0 */ " ",
   /* ¡ */ "!`",
   /* ¢ */ "\\cents",
   /* £ */ "\\pounds ",
   /* ¤ */ "\\star ",
   /* ¥ */ "\\yens ",
   /* ¦ */ "$\\mid$",
   /* § */ "\\S ",
   /* ¨ */ "\\\"\\ ",
   /* © */ "\\copyright ",
   /* ª */ "$^{\\underbar{^{a}}}$",
   /* « */ "$\\ll$",
   /* ¬ */ "\\neg ",
   /* ­ */ "{\\bf -}",
   /* ® */ "\\reserved",
   /* ¯ */ "$^{-}$",
   /* ° */ "$^{\\circ}$",
   /* ± */ "$\\pm $",
   /* ² */ "$^{2}$",
   /* ³ */ "$^{3}$",
   /* ´ */ "\\prime ",
   /* µ */ "$\\mu $",
   /* ¶ */ "$\\P $",
   /* · */ "\\cdot ",
   /* ¸ */ "\\c \\ ",
   /* ¹ */ "$^{1}$",
   /* º */ "$^{\\underbar{\\circ}}$",
   /* » */ "$\\gg$",
   /* ¼ */ "$^{1}/_{4}$",
   /* ½ */ "$^{1}/_{2}$",
   /* ¾ */ "$^{3}/_{4}$",
   /* ¿ */ "?`",
   /* À */ "\\`A",
   /* Á */ "\\\'A",
   /* Â */ "\\^A",
   /* Ä */ "\\\"A",
   /* Ã */ "\\~A",
   /* Å */ "\\AA ",
   /* Æ */ "\\AE ",
   /* Ç */ "\\c C",
   /* È */ "\\`E",
   /* É */ "\\\'E",
   /* Ê */ "\\^E",
   /* Ë */ "\\\"E",
   /* Ì */ "\\`\\I ",
   /* Í */ "\\\'\\I ",
   /* Î */ "\\^\\I ",
   /* Ï */ "\\\"\\I ",
   /* Ð */ "\\crossedD",
   /* Ñ */ "\\~N",
   /* Ò */ "\\`O",
   /* Ó */ "\\\'O",
   /* Ô */ "\\^O",
   /* Õ */ "\\~O",
   /* Ö */ "\\\"O",
   /* × */ "$\\times $",
   /* Ø */ "\\O ",
   /* Ù */ "\\`U",
   /* Ú */ "\\\'U",
   /* Û */ "\\^U",
   /* Ü */ "\\\"U",
   /* Ý */ "\\\'Y",
   /* Þ */ "$\\OEthp$",
   /* ß */ "\\ss ",
   /* à */ "\\`a",
   /* á */ "\\\'a",
   /* â */ "\\^a",
   /* ä */ "\\\"a",
   /* ã */ "\\~a",
   /* å */ "\\aa ",
   /* æ */ "\\ae ",
   /* ç */ "\\c c",
   /* è */ "\\`e",
   /* é */ "\\\'e",
   /* ê */ "\\^e",
   /* ë */ "\\\"e",
   /* ì */ "\\`\\i  ",
   /* í */ "\\\'\\i ",
   /* î */ "\\^\\i ",
   /* ï */ "\\\"\\i ",
   /* ð */ "\\OEthd",
   /* ñ */ "\\~n",
   /* ò */ "\\`o",
   /* ó */ "\\\'o",
   /* ô */ "\\^o",
   /* õ */ "\\~o",
   /* ö */ "\\\"o",
   /* ÷ */ "$\\div $",
   /* ø */ "\\o ",
   /* ù */ "\\`u",
   /* ú */ "\\\'u",
   /* û */ "\\^u",
   /* ü */ "\\\"u",
   /* ý */ "\\\'y",
   /* þ */ "\\OEthpp",
   /* ÿ */ "\\\"y"
};

/* traduction en deux parties des séquences escape */

sequence ListeSequences [] = {
   { "{\\bf ", '1' },
   { "{", "2\0\0\0" },
   { "{", "20\0\0" },
   { "{", "21\0\0" },
   { "{", "22\0\0" },
   { "{", "23\0\0" },
   { "{\\it ", "3\0\0\0" },
   { "{", "30\0\0" },
   { "{", "31\0\0" },
   { "{", "32\0\0" },
   { "{", "33\0\0" },
   { "\\underbar{", "4\0\0\0" },
   { "{", "7\0\0\0" },
   { NULL, 0,0,0,0 }
};
