home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / metamail / richmail / richtext.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-26  |  28.4 KB  |  933 lines

  1. /*
  2. Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore)
  3.  
  4. Permission to use, copy, modify, and distribute this material 
  5. for any purpose and without fee is hereby granted, provided 
  6. that the above copyright notice and this permission notice 
  7. appear in all copies, and that the name of Bellcore not be 
  8. used in advertising or publicity pertaining to this 
  9. material without the specific, prior written permission 
  10. of an authorized representative of Bellcore.  BELLCORE 
  11. MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY 
  12. OF THIS MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", 
  13. WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES.
  14. */
  15.  
  16. #include <stdio.h>
  17. #include <ctype.h>
  18. #include <signal.h>
  19. #include "richlex.h"
  20. #include "richset.h"
  21. #include <config.h>
  22.  
  23. extern char *getenv();
  24. #ifdef AMIGA
  25. extern char *strchr();
  26. #endif
  27.  
  28. #ifdef __MSDOS__
  29. unsigned _stklen=16384;    /* Increase stack size under MS-DOS */
  30. #endif
  31.  
  32. int iso2022_fputc ();
  33.  
  34. /*
  35.  * ########################################################################
  36.  * The function "InitGlobals" must be updated whenever a new variable is
  37.  * added here or a default value is changed.  The same must be done for
  38.  * the next section of variables also.  This is needed because this module
  39.  * could be linked into another program as a library and called more than
  40.  * once in a single program execution.
  41.  * ########################################################################
  42.  */
  43. static int linepos = 0, inspace = 0, leftmargin = 0, rightmargin, biggertext=0;
  44. static int workingleft = 0, workingright, inexcerpt = 0, insignature = 0;
  45. static int standout=0, underline=0, bold=0;
  46. static int termcolumns=80, termrows=23;
  47. int controlputc();
  48.  
  49. /* A common problem, in justifying text, is figuring out how to format a 
  50.    line when part of it wants to be left-justified, part right-justified, 
  51.    and part centered, or some combination thereof.  There is no perfect 
  52.    solution to this problem, so this program takes an incredibly cheesy 
  53.    but simple way out:  voting.  For each character on the line, a point
  54.    is added to the "center" score if it is supposed to be centered, and 
  55.    so on.  If it is inside TWO "center" environments, two points are added.
  56.    This may be the world's first implementation of justification by voting...
  57. */
  58.  
  59. static int centerenv=0, leftjustenv=0, rightjustenv=0;
  60. static int centerct=0, leftjustct=0, rightjustct=0;
  61. static int UsePager = 0;
  62. static int linesused = 0;
  63. static int JustSawCmd=0;
  64. static int JustCorrect = 0;    /* Non-zero to just correct and not format */
  65. static int OverStrike = 0;
  66. static char MoveRight[10];
  67. static char standoutbuf[50], standendbuf[50], StartUnderline[50], StopUnderline[50];
  68. static char KS[50], KE[50], BoldOn[50], BoldOff[50];
  69. static char charsetname[50];
  70. static int FakeTerminal;
  71.  
  72. #ifndef AMIGA
  73. #ifndef __MSDOS__
  74. #define TPUTS_OK
  75. #endif
  76. #endif
  77. #ifndef TPUTS_OK
  78. extern tputs();
  79. #endif
  80.  
  81. static outputc(), realoutputc(), MakeWorkingMargins(), Pause(), fputsmovingright(), ResetTerminalCodes(), FinalizeTerminal(), outputstr(), FPUTS();
  82.  
  83. #define    OUTC(c)        (outputc((RCHAR)(c)))
  84.  
  85. static void
  86. InitGlobals()
  87. {
  88.     linepos = 0;
  89.     inspace = 0;
  90.     leftmargin = 0;
  91.     biggertext = 0;
  92.     workingleft = 0;
  93.     inexcerpt = 0;
  94.     insignature = 0;
  95.     termcolumns = 80;
  96.     termrows = 23;
  97.     centerenv = 0;
  98.     leftjustenv = 0;
  99.     rightjustenv = 0;
  100.     centerct = 0;
  101.     leftjustct = 0;
  102.     rightjustct = 0;
  103.     UsePager = 0;
  104.     linesused = 0;
  105.     JustSawCmd = 0;
  106.     JustCorrect = 0;
  107.     standout = 0;
  108.     underline = 0;
  109.     bold = 0;
  110. }
  111.  
  112. static void
  113. cleanup(signum)
  114. int signum;
  115. {
  116.     FinalizeTerminal();
  117. #if defined(AMIGA) || defined(__MSDOS__)
  118.     exit(signum);
  119. #else
  120.     signal(signum, SIG_DFL);
  121.     kill(getpid(), signum);
  122. #endif
  123. }
  124.  
  125. static InitSignals() {
  126.     signal(SIGINT, cleanup);
  127. #if !defined(AMIGA)
  128. #if !defined(__MSDOS__)
  129.     signal(SIGILL, cleanup);
  130.     signal(SIGTRAP, cleanup);
  131.     signal(SIGIOT, cleanup);
  132.     signal(SIGFPE, cleanup);
  133. #ifndef LINUX
  134.     signal(SIGEMT, cleanup);
  135.     signal(SIGBUS, cleanup);
  136. #endif
  137.     signal(SIGSEGV, cleanup);
  138.     signal(SIGTERM, cleanup);
  139. #ifdef SIGXCPU
  140.     signal(SIGXCPU, cleanup);
  141. #endif
  142. #endif
  143. #endif
  144. }
  145.  
  146. static nomemabort() {
  147.     fprintf(stderr, "richtext: Out of memory\n");
  148.     FinalizeTerminal();
  149. #ifdef AMIGA
  150.     exit(20);
  151. #else
  152.     exit(-1);
  153. #endif
  154. }
  155.  
  156. #ifndef    RICHTEXT_LIBRARY
  157.  
  158. /*
  159.  * Only include the main function if this module is not being used as a
  160.  * library call.
  161.  */
  162.  
  163. main(argc, argv)
  164. int argc;
  165. char **argv;
  166. {
  167.   exit(richtext_main(argc, argv));
  168. }
  169.  
  170. #endif
  171.  
  172. richtext_main(argc, argv)
  173. int argc;
  174. char **argv;
  175. {
  176.     RCHAR c;
  177.     int i, atstart, negated,
  178.     ForceTermcap=0, ForcePlain=0, NotTtyEnv = 0;
  179.     char token[MAX_TOKEN_SIZE], *tok, *nottty;
  180.     char tbuf[1024], *term, *dum;
  181.     FILE *InputFP = stdin, *tmpfp;
  182. #ifdef __MSDOS__
  183.     int ansi = 0;
  184. #endif
  185.  
  186.     InitSignals();
  187.     InitGlobals();
  188.     richtextreset();
  189.     strcpy(charsetname,"us-ascii");
  190.     dum = (char *) getenv("MM_USEPAGER");
  191.     if (dum && atoi(dum)) ++UsePager;
  192.     for (i=1; i< argc; ++i) {
  193.         if (!strcmp(argv[i], "-p")) {
  194.             ++UsePager;
  195.         } else if (!strcmp(argv[i],"-c")) {
  196.             /* Only perform correction: don't format */
  197.             JustCorrect = 1;
  198.         } else if (!strcmp(argv[i], "-f")) {
  199.             /* Force termcap usage */
  200.             ForceTermcap = 1;
  201.         } else if (!strcmp(argv[i], "-t")) {
  202.             /* Force plain text */
  203.             ForcePlain = 1;
  204.         } else if (!strcmp(argv[i],"-n")) {
  205.             /* Disable the richtext correction routines */
  206.             CorrectionEnabled = 0;
  207.         } else if (!strcmp(argv[i],"-m")) {
  208.             /* Enable the multi-byte '<' hack */
  209.             RichtextLessThanFlag = 1;
  210.     } else if (!strncmp(argv[i], "-s", 2)) {
  211.         /* Specify the character set to use (and convert to lower case) */
  212.         char *name;
  213.         if (argv[i][2])
  214.         strcpy(charsetname, argv[i] + 2);
  215.         else if (i < (argc - 1))
  216.         strcpy(charsetname, argv[++i]);
  217.         name = charsetname;
  218.         while (*name) {
  219.         if (isupper(*name))
  220.             *name = tolower(*name);
  221.         ++name;
  222.         }
  223.     } else if (!strcmp(argv[i], "-o")) {
  224.         /* Use Overstriking */
  225.         OverStrike = 1;
  226.         ForcePlain = 1;
  227. #ifdef __MSDOS__
  228.         } else if (!strcmp(argv[i], "-a")) {
  229.             ansi = !ansi;
  230. #endif
  231.         } else {
  232.             /* open for input */
  233.             tmpfp = fopen(argv[i], "r");
  234.             if (tmpfp)
  235.             InputFP = tmpfp;
  236.         else {
  237.             perror (argv[i]);
  238.         exit (1);
  239.         }
  240.         }
  241.     }
  242. #ifdef AMIGA
  243.     /* THIS IS THE AMIGA TERMINAL INITIALIZATION CODE */
  244.     nottty = (char *) getenv("MM_NOTTTY");
  245.     if (nottty) NotTtyEnv = atoi(nottty);
  246.     if (!isatty(0) || !isatty(1) || NotTtyEnv) {
  247.         UsePager = 0;   /* Disable pager if I/O has been redirected or we're under a window-oriented mail reader */
  248.     }
  249.     KS[0] = 0;
  250.     KE[0] = 0;
  251.     if ((!ForcePlain && isatty(1)) || ForceTermcap) {
  252.         FakeTerminal = 0;
  253.         strcpy(standoutbuf, "\x9b\x37m");   /* Enter standout (highlighted) mode */
  254.         strcpy(standendbuf, "\x9b\x30m");   /* Exit standout mode */
  255.         strcpy(BoldOn,      "\x9b\x31m");   /* Enter bold mode */
  256.         strcpy(BoldOff,     "\x9b\x30m");   /* Exit bold mode */
  257.         strcpy(StartUnderline,"\x9b\x34m"); /* Enter underline mode */
  258.         strcpy(StopUnderline,"\x9b\x30m");  /* Exit underline mode */
  259.         strcpy(MoveRight, " ");
  260.     } else if (OverStrike) {
  261.     FakeTerminal = 1;
  262.     BoldOn[0] = '\0';
  263.     BoldOff[0] = '\0';
  264.     standoutbuf[0] = '\0';
  265.     standendbuf[0] = '\0';
  266.     StartUnderline[0] = '\0';
  267.     StopUnderline[0] = '\0';
  268.     strcpy(MoveRight, " ");
  269.     } else {
  270.         FakeTerminal = 1;
  271.         strcpy(BoldOn, "*");
  272.         strcpy(BoldOff, "*");
  273.         strcpy(standoutbuf, "_");
  274.         strcpy(standendbuf, "_");
  275.         strcpy(StartUnderline, "_");
  276.         strcpy(StopUnderline, "_");
  277.         strcpy(MoveRight, " ");
  278.     }
  279. #else
  280. #ifdef __MSDOS__
  281.     /* THIS IS THE DOS TERMINAL INITIALIZATION CODE */
  282.     FakeTerminal = 1;
  283.     termcolumns = 80;
  284.     termrows = 23;
  285.     strcpy(MoveRight, " ");
  286.     if (!ansi && !OverStrike) {
  287.         KS[0] = NULL;
  288.         KE[0] = NULL;
  289.         strcpy(BoldOn, "*");
  290.         strcpy(BoldOff, "*");
  291.         strcpy(standoutbuf, "_");
  292.         strcpy(standendbuf, "_");
  293.         strcpy(StartUnderline, "_");
  294.         strcpy(StopUnderline, "_");
  295.     } else if (OverStrike) {
  296.         KS[0] = NULL;
  297.         KE[0] = NULL;
  298.     BoldOn[0] = '\0';
  299.     BoldOff[0] = '\0';
  300.     standoutbuf[0] = '\0';
  301.     standendbuf[0] = '\0';
  302.     StartUnderline[0] = '\0';
  303.     StopUnderline[0] = '\0';
  304.     } else {
  305.         strcpy(KS, "\x01B[37m");  /* White text (reset) */
  306.         strcpy(KE, "\x01B[37m");  /* White text (reset) */
  307.         strcpy(BoldOn, "\x01B[1m");   /* Bold text */
  308.         strcpy(BoldOff, "\x01B[0m");   /* End bold text (normal) */
  309.         strcpy(StartUnderline, "\x01B[31m");  /* Underline (red text) */
  310.         strcpy(StopUnderline, "\x01B[37m");   /* Underline end (white) */
  311.         /* The following should probably be something else, for italic */
  312.         strcpy(standoutbuf, "\x01B[31m"); 
  313.         strcpy(standendbuf, "\x01B[37m"); 
  314.     }
  315. #else
  316.     /* THIS IS THE UNIX TERMINAL INITIALIZATION CODE */
  317.     nottty = (char *) getenv("MM_NOTTTY");
  318.     if (nottty) NotTtyEnv = atoi(nottty);
  319.     if (UsePager && (!isatty(0) || !isatty(1) || NotTtyEnv)) {
  320.         UsePager = 0;   /* Disable pager if I/O has been redirected or we're under a window-oriented mail reader */
  321.     }
  322.     if ((!ForcePlain && (isatty(1) || isatty(0))) || ForceTermcap) {
  323.         term = (char *) getenv("TERM");
  324.     } else {
  325.         term = NULL;
  326.     }
  327.     if (term && tgetent(tbuf, term) != 1) {
  328.         term = NULL;
  329.     }
  330.     if (term) {
  331.         dum = KS;
  332.         if (tgetstr("ks", &dum)) *dum = '\0'; else KS[0] = '\0';
  333.         dum = KE;
  334.         if (tgetstr("ke", &dum)) *dum = '\0'; else KE[0] = '\0';
  335.         dum = standoutbuf;
  336.         if (tgetstr("so", &dum)) *dum = '\0'; else standoutbuf[0] = '\0';
  337.         dum = standendbuf;
  338.         if (tgetstr("se", &dum)) *dum = '\0'; else standendbuf[0] = '\0';
  339.         dum = BoldOn;
  340.         if (tgetstr("md", &dum)) *dum = '\0'; else strcpy(BoldOn, standoutbuf);
  341.         dum = BoldOff;
  342.         if (tgetstr("me", &dum)) *dum = '\0'; else strcpy(BoldOff, standendbuf);
  343.         dum = StartUnderline;
  344.         if (tgetstr("us", &dum)) *dum = '\0'; else StartUnderline[0] = '\0';
  345.         dum = StopUnderline;
  346.         if (tgetstr("ue", &dum)) *dum = '\0'; else StopUnderline[0] = '\0';
  347.         dum = MoveRight;
  348.         if (tgetstr("nd", &dum)) *dum = '\0'; else {
  349.             MoveRight[0] = ' ';
  350.             MoveRight[1] = '\0';
  351.         }
  352.         /* Some TERMCAP entries have REALLY screwed up "nd" fields, sigh... */
  353.         if (!strcmp(MoveRight, "\014")) strcpy(MoveRight, " ");
  354.         termcolumns = tgetnum("co");
  355.         if (termcolumns <= 0) termcolumns = 80;
  356.         termrows = tgetnum("li");
  357.         if (termrows <= 0) termrows = 23;
  358.     else termrows--;
  359.         FakeTerminal=0;
  360.     } else if (OverStrike) {
  361.         KS[0] = '\0';
  362.         KE[0] = '\0';
  363.     FakeTerminal = 1;
  364.     BoldOn[0] = '\0';
  365.     BoldOff[0] = '\0';
  366.     standoutbuf[0] = '\0';
  367.     standendbuf[0] = '\0';
  368.     StartUnderline[0] = '\0';
  369.     StopUnderline[0] = '\0';
  370.     strcpy(MoveRight, " ");
  371.         termcolumns = 80;
  372.         termrows = 23;
  373.     } else {
  374.         KS[0] = '\0';
  375.         KE[0] = '\0';
  376.         FakeTerminal = 1;
  377.         strcpy(BoldOn, "*");
  378.         strcpy(BoldOff, "*");
  379.         strcpy(standoutbuf, "_");
  380.         strcpy(standendbuf, "_");
  381.         strcpy(StartUnderline, "_");
  382.         strcpy(StopUnderline, "_");
  383.         strcpy(MoveRight, " ");
  384.         termcolumns = 80;
  385.         termrows = 23;
  386.     }
  387. #endif
  388. #endif
  389.     /* Check for the LINES & COLUMNS hack */
  390.     dum = getenv("LINES");
  391.     if (dum && ((i=atoi(dum)) > 0)) termrows = i - 1;
  392.     dum = getenv("COLUMNS");
  393.     if (dum && ((i=atoi(dum)) > 0)) termcolumns = i;
  394.     charsetnameinit(charsetname);
  395.     RichtextPutc = iso2022_fputc;
  396.     if (JustCorrect) {
  397.         richtextcorrect(InputFP,stdout);
  398.         return(0);
  399.     }
  400.     FPUTS(KS, stdout);
  401.     rightmargin = workingright = termcolumns - 1;
  402.     while((c = richtextlex(InputFP,token)) != (RCHAR)EOF) {
  403.         if (c == RICHTEXT_COMMAND || c == RICHTEXT_NEG_COMMAND) { 
  404.             negated = (c == RICHTEXT_NEG_COMMAND);
  405.             tok = token;
  406.  
  407.         /* Try to process the command with the character set processors */
  408.         if (charsetcommand (tok,negated))
  409.             continue;
  410.  
  411.         /* Do the default action for the command */
  412.             switch(tok[0]) {
  413.                 case 'b':
  414.                     if (!strcmp(tok, "bold")) {
  415.                         if (negated) {
  416.                             --bold;
  417.                             if (bold <= 0) {
  418.                 if (FakeTerminal) outputstr(BoldOff);
  419.                 else controloutput(BoldOff, 0);
  420.                 }
  421.                         } else {
  422.                             ++bold;
  423.                         }
  424.                         ResetTerminalCodes(FakeTerminal, standout, underline,
  425.                                             bold, standoutbuf, standendbuf, 0,
  426.                                             StartUnderline, StopUnderline, 0, BoldOn,
  427.                                             BoldOff, 1);
  428.                     } else if (!strcmp(tok, "bigger")) {
  429.                         if (negated) --biggertext; else ++biggertext;
  430.                     }
  431.                     break;
  432.                 case 'c':
  433.                     if (!strcmp(tok, "center")) {
  434.                         if (negated) --centerenv; else ++centerenv;
  435.                     } else if (!strcmp(tok, "comment")) {
  436.                         int commct=1;
  437.             int tempc;
  438.                         while (commct > 0) {
  439.                             while ((tempc = getc(InputFP)) != '<' 
  440.                                     && tempc != EOF) ;
  441.                             if (tempc == EOF) break;
  442.                             for (i=0; (tempc = getc(InputFP)) != '>' 
  443.                               && tempc != EOF; ++i) {
  444.                                 token[i] = isupper(tempc) ? 
  445.                                   tolower(tempc) : tempc;
  446.                             }
  447.                             if (tempc== EOF) break;
  448.                             token[i] = 0;
  449.                             if (!strcmp(token, "/comment")) --commct;
  450.                             if (!strcmp(token, "comment")) ++commct;
  451.                         }
  452.                     }
  453.                     break;
  454.                 case 'e':
  455.                     if (!strcmp(tok, "excerpt")) {
  456.                         atstart = !(linepos > workingleft);
  457.                         if (negated) {
  458.                             leftmargin -= 4;
  459.                             rightmargin += 4;
  460.                             --inexcerpt;
  461.                         } else {
  462.                             leftmargin += 4;
  463.                             rightmargin -= 4;
  464.                             ++inexcerpt;
  465.                         }
  466.                         MakeWorkingMargins();
  467.                         if (!atstart) OUTC('\n');
  468.                     }
  469.                     break;
  470.                 case 'f':
  471.                     if (!strcmp(tok, "flushleft")) {
  472.                         if (negated) --leftjustenv; else ++leftjustenv;
  473.                     } else if (!strcmp(tok, "flushright")) {
  474.                         if (negated) --rightjustenv; else ++rightjustenv;
  475.                     }
  476.                     break;
  477.                 case 'i':
  478.                     if (!strcmp(tok, "italic")) {
  479.                         if (negated) {
  480.                             --standout;
  481.                             if (standout <= 0) {
  482.                 if (FakeTerminal) outputstr(standendbuf);
  483.                 else controloutput(standendbuf, 0);
  484.                 }
  485.                         } else {
  486.                             ++standout;
  487.                         }
  488.                         ResetTerminalCodes(FakeTerminal, standout, underline, bold,
  489.                                             standoutbuf, standendbuf, 1, StartUnderline,
  490.                                             StopUnderline, 0, BoldOn, BoldOff, 0);
  491.                     } else if (!strcmp(tok, "indent")) {
  492.                         if (negated) {
  493.                             leftmargin -= 4;
  494.                         } else {
  495.                             leftmargin += 4;
  496.                         }
  497.                     } else if (!strcmp(tok, "indentright")) {
  498.                         if (negated) {
  499.                             rightmargin += 4;
  500.                         } else {
  501.                             rightmargin -= 4;
  502.                         }
  503.                     }
  504.                     MakeWorkingMargins();
  505.                     break;
  506.                 case 'l':
  507.                     if (!strcmp(tok, "lt")) {
  508.                         OUTC('<');
  509.                     }
  510.                     break;
  511.                 case 'n':
  512.                     if (!strcmp(tok, "nl")) {
  513.                         OUTC('\n');
  514.                     } else if (!strcmp(tok, "np")) {
  515.                         OUTC('\n');
  516.                         OUTC('\014');
  517.                     }
  518.                     break;
  519.                 case 'u':
  520.                     if (!strcmp(tok, "underline")) {
  521.                         if (negated) {
  522.                             --underline;
  523.                             if (underline <= 0) {
  524.                 if (FakeTerminal) outputstr(StopUnderline);
  525.                 else controloutput(StopUnderline,0);
  526.                 }
  527.                         } else {
  528.                             ++underline;
  529.                         }
  530.                         ResetTerminalCodes(FakeTerminal, standout, underline, bold,
  531.                                             standoutbuf, standendbuf, 0, StartUnderline,
  532.                                             StopUnderline, 1, BoldOn, BoldOff, 0);
  533.                     }
  534.                     break;
  535.                 case 'o':
  536.                     if (!strcmp(tok, "outdent")) {
  537.                         if (negated) {
  538.                             leftmargin += 4;
  539.                         } else {
  540.                             leftmargin -= 4;
  541.                         }
  542.                     } else if (!strcmp(tok, "outdentright")) {
  543.                         if (negated) {
  544.                             rightmargin -= 4;
  545.                         } else {
  546.                             rightmargin += 4;
  547.                         }
  548.                     }
  549.                     MakeWorkingMargins();
  550.                     break;                    
  551.                 case 'p':
  552.                     if (!strcmp(tok, "paragraph")) {
  553.                         if (negated) OUTC('\n');
  554.                         OUTC('\n');
  555.                     }
  556.                     break;
  557.                 case 's':
  558.                     if (!strcmp(tok, "signature")) {
  559.                         atstart = !(linepos > workingleft);
  560.                         if (negated) {
  561.                             leftmargin -= 4;
  562.                             rightmargin += 4;
  563.                             --insignature;
  564.                         } else {
  565.                             leftmargin += 4;
  566.                             rightmargin -= 4;
  567.                             ++insignature;
  568.                         }
  569.                         MakeWorkingMargins();
  570.                         if (!atstart) OUTC('\n');
  571.                     }
  572.                     break;
  573.                 default:
  574.                     /* Ignore all other tokens */
  575.                     break;
  576.             }
  577.             JustSawCmd = 1;
  578.         } else if (c == '\n') {
  579.             if (linepos > 0 && !inspace) {
  580.                 OUTC(' ');
  581.             }
  582.             JustSawCmd = 0;
  583.         } else {
  584.             OUTC(c);
  585.             JustSawCmd = 0;
  586.         }
  587.     }
  588.     if (term) { /* cleanup a bit for insurance */
  589.         controloutput(standendbuf, 0);
  590.         controloutput(StopUnderline, 0);
  591.     }
  592.     OUTC('\n'); /* for good measure */
  593.     FPUTS(KE, stdout);
  594.     fflush(stdout);
  595.     if (UsePager) {
  596.         Pause();
  597.     }
  598.     return(0);
  599. }
  600.  
  601. static struct charsetmember OutputBuf[1000] = {0,0};
  602. static int PendingOutput = 0, PendingControls = 0;
  603.  
  604. controlputc(c)
  605. int c;
  606. {
  607.     charmemberctrl (&OutputBuf[PendingOutput],(RCHAR)c);
  608.     ++PendingOutput;
  609.     ++PendingControls;
  610. }
  611.  
  612. static immediate_controlputc(c)
  613. int c;
  614. {
  615.     (*RichtextPutc) (c, stdout);
  616. }
  617.  
  618. controloutput(s, immediate)
  619. char *s;
  620. int immediate;
  621. {
  622.     tputs(s, 1, immediate ? immediate_controlputc : controlputc);
  623. }
  624.  
  625. static folding_point (buf, pos)
  626. struct    charsetmember *buf;
  627. int    pos;
  628. {
  629.     int i;
  630.     for (i = pos; i > 0; --i) {
  631.         if (!charisctrl (buf[i]) && charmemberfold (buf[i]))
  632.         return (i);
  633.     }
  634.     return (0);
  635. }
  636.  
  637. static calc_column (buf, pos)
  638. struct    charsetmember *buf;
  639. int    pos;
  640. {
  641.     struct charsetmember *s;
  642.     int col = 0;
  643.     for (s = buf; (s -> ch); ++s) {
  644.         if (!charisctrl (*s))
  645.             col += charmemberwidth (*s);
  646.     else
  647.         ++col;
  648.     }
  649.     return (col);
  650. }
  651.  
  652. static FlushOut() {
  653.     int i, j, x;
  654.     static struct charsetmember NewOutputBuf[1000];
  655.     struct charsetmember *s;
  656.     int NewPendingControls=0, NewPendingOutput = 0;
  657.  
  658.     OutputBuf[PendingOutput].ch = 0;
  659.     OutputBuf[PendingOutput].charset = NULL;
  660.     if (linepos >= workingright) {
  661.         for (i=0, j=0; j<workingright && i < PendingOutput; ++i) {
  662.             if (!charisctrl (OutputBuf[i])) ++j;
  663.         }
  664.     x = folding_point (OutputBuf,i);
  665.     if ((workingleft + 4) < x)
  666.         i = x;
  667.     else
  668.             while (i > workingleft + 4) {
  669.                 if (!charisctrl (OutputBuf[i])
  670.                      && isspace((unsigned char) OutputBuf[i].ch)) {
  671.                     break;
  672.                 }
  673.                 --i;
  674.             }
  675.         for (j=0; i<PendingOutput; ++j, ++i) {
  676.             NewOutputBuf[j] = OutputBuf[i];
  677.             ++NewPendingOutput;
  678.             if (charisctrl (NewOutputBuf[j])) ++NewPendingControls;
  679.         }
  680.         PendingOutput -= NewPendingOutput;
  681.         PendingControls -= NewPendingControls;
  682.         charmember (&OutputBuf[PendingOutput],(RCHAR)'\n');
  683.     PendingOutput++;
  684.         OutputBuf[PendingOutput].ch = 0;
  685.         OutputBuf[PendingOutput].charset = 0;
  686. #ifdef MISTAKE
  687.         ResetTerminalCodes(FakeTerminal, standout, underline, bold,
  688.                             standoutbuf, standendbuf, 0, StartUnderline,
  689.                             StopUnderline, 0, BoldOn, BoldOff, 0);
  690. #endif
  691.     }
  692.     if ((rightjustct > leftjustct)
  693.          && (rightjustct > centerct)
  694.          && (rightjustct > 0)) {
  695.         /* right justified */
  696.         i = termcolumns - calc_column (OutputBuf,PendingOutput) - 1
  697.         + PendingControls;
  698.         for (j=0; j<i; ++j)  {
  699.             controloutput(MoveRight, 1);
  700.         }
  701.         fputsmovingright(OutputBuf, stdout);
  702.         ++linesused;
  703.     } else if ((leftjustct > centerct)
  704.                 && (leftjustct > 0)) {
  705.         /* left justified */
  706.         for (s=OutputBuf; s -> ch && isspace((unsigned char) (s -> ch)); ++s)
  707.         {;}
  708.         fputsmovingright(s, stdout);
  709.         ++linesused;
  710.     } else if (centerct > 0) {
  711.         /* centered */
  712.         i = (termcolumns - calc_column (OutputBuf,PendingOutput) - 1
  713.         + PendingControls) / 2;
  714.         for (j=0; j<i; ++j) {
  715.             controloutput(MoveRight, 1);
  716.         }
  717.         fputsmovingright(OutputBuf, stdout);
  718.         ++linesused;
  719.     } else {
  720.         /* Leave indentation (margins) as-is */
  721.         fputsmovingright(OutputBuf, stdout);
  722.         ++linesused;
  723.     }
  724.     if (linesused >= termrows && UsePager) Pause();
  725.     rightjustct = leftjustct = centerct = 0; /* not quite right for wrapping, sigh... */
  726.     PendingOutput = PendingControls = linepos = 0;
  727.     inspace = 1;
  728.     j = (isspace((unsigned char) NewOutputBuf[0].ch)) ? 1 : 0;
  729.     for ( ; j<NewPendingOutput; ++j) {
  730.         if (charisctrl (NewOutputBuf[j])) {
  731.         OutputBuf[PendingOutput++] = NewOutputBuf[j];
  732.             ++PendingControls;
  733.         } else {
  734.             realoutputc(NewOutputBuf[j], 1);
  735.         }
  736.     }
  737.     ResetTerminalCodes(FakeTerminal, standout, underline, bold,
  738.                         standoutbuf, standendbuf, 0, StartUnderline,
  739.                         StopUnderline, 0, BoldOn, BoldOff, 0);
  740. }
  741.  
  742. static outputc(c)
  743. RCHAR c;
  744. {
  745.     struct charsetmember member;
  746.     charmember (&member,c);
  747.     realoutputc(member, 0);
  748. }
  749.  
  750. static realoutputc(c, alreadyformatted)
  751. struct charsetmember c;
  752. int alreadyformatted;
  753. {
  754.     int i, newinspace;
  755.  
  756.     if (c.ch == '\n') {
  757.         charmember (&OutputBuf[PendingOutput],(RCHAR)'\n');
  758.     PendingOutput++;
  759.         FlushOut();
  760.     } else if (c.ch == '\t') {
  761.         int tabpos = (linepos + 8) / 8;
  762.         if (tabpos >= workingright) {
  763.             charmember (&OutputBuf[PendingOutput],(RCHAR)'\n');
  764.         PendingOutput++;
  765.             FlushOut();
  766.         } else {
  767.             int spaces = (8*tabpos) - linepos;
  768.             while (spaces-->0) {
  769.                 charmember (&OutputBuf[PendingOutput],(RCHAR)' ');
  770.             PendingOutput++;
  771.                 ++linepos;
  772.             }
  773.         }
  774.     } else {
  775.         newinspace = isspace((unsigned char) c.ch);
  776.         if (!inspace || !newinspace || !JustSawCmd) {
  777.             if (linepos == 0) {
  778.                 int i = workingleft;
  779.                 if (inexcerpt) {
  780.                     charmember (&OutputBuf[PendingOutput],(RCHAR)'>');
  781.                 PendingOutput++;
  782.                     --i;
  783.                 }
  784.                 if (insignature) {
  785.                     charmember (&OutputBuf[PendingOutput],(RCHAR)'+');
  786.                 PendingOutput++;
  787.                     --i;
  788.                 }
  789.                 while (i-->0) {
  790.                     charmember (&OutputBuf[PendingOutput],(RCHAR)' ');
  791.                 PendingOutput++;
  792.                 }
  793.                 linepos = workingleft;
  794.             }
  795.             if (!alreadyformatted && biggertext && !(inspace && newinspace)) {
  796.                 charmember (&OutputBuf[PendingOutput],(RCHAR)'_');
  797.             PendingOutput++;
  798.                 ++linepos;
  799.             }
  800.             inspace = newinspace;
  801.             linepos += charmemberwidth (c);
  802.         OutputBuf[PendingOutput++] = c;
  803.         if (OverStrike && !inspace) {
  804.         if (bold) {
  805.             controlputc('\b');
  806.             controlputc((int) c.ch);
  807.         }
  808.         if (standout||underline) {
  809.             controlputc('\b');
  810.             controlputc('_');
  811.         }
  812.         }
  813.             leftjustct += leftjustenv;
  814.             rightjustct += rightjustenv;
  815.             centerct += centerenv;
  816.             if (c.ch == '\014') inspace = 1;
  817.             if (linepos >= workingright) FlushOut();
  818.         }
  819.     }
  820. }
  821.  
  822. static MakeWorkingMargins() {
  823.     int oldworkingleft=workingleft, i;
  824.  
  825.     workingleft = leftmargin;
  826.     workingright = rightmargin;
  827.     if (workingleft < 0) workingleft = 0;
  828.     if (workingright < 0) workingright = 0;
  829.     if (workingright > (termcolumns - 1)) workingright = (termcolumns - 1);
  830.     if (workingleft > (workingright - 8)) workingleft = workingright -8;
  831.     if (linepos == oldworkingleft && linepos != 0) {
  832.         for (i=workingleft-oldworkingleft; i > 0; --i) OUTC(' ');
  833.     }
  834. }
  835.  
  836. static Pause()
  837. {
  838.     int    c;
  839.  
  840.     (void) fputs("Press RETURN to continue (or 'q' to quit): \n", stdout);
  841.     fflush(stdout);
  842.     c = getc(stdin);
  843.     if (c == 'q' || c == 'Q') exit(0);
  844.     linesused = 0;
  845. }
  846.  
  847. /* Leading spaces should be output as MoveRight, to avoid 
  848.    having margins that are underlined or reverse video */
  849.  
  850. static fputsmovingright(s, fp)
  851. struct charsetmember *s;
  852. FILE *fp;
  853. {
  854.     int inmargin=1;
  855.     if (!s) return;
  856.     while (s -> ch) {
  857.         if (inmargin && (s -> ch) == ' ') {
  858.             controloutput(MoveRight, 1);
  859.         } else {
  860.             if (inmargin) inmargin = 0;
  861.         if (charisctrl (*s))
  862.             (*RichtextPutc) ((int)(s -> ch), fp);
  863.         else
  864.             charmemberrender (*s, fp);
  865.         }
  866.         ++s;
  867.     }
  868. }
  869.  
  870. static ResetTerminalCodes(FakeTerminal, standout, underline, bold, standoutbuf, standendbuf,
  871.                     modifiedstandout, StartUnderline, StopUnderline, modifiedunderline,
  872.                     BoldOn, BoldOff, modifiedbold)
  873. char *standoutbuf, *standendbuf, *StartUnderline, *StopUnderline,
  874.     *BoldOn, *BoldOff;
  875. {
  876.     if (OverStrike)
  877.     return;
  878.  
  879.     /* We always turn back on the appropriate terminal modes, because
  880.       on some terminals one thing turns off all of them */
  881.     if (standout >= 1) {
  882.         if (FakeTerminal) {
  883.             if (modifiedstandout && standout == 1) outputstr(standoutbuf);
  884.         } else controloutput(standoutbuf, 0);
  885.     }
  886.     if (bold >= 1) {
  887.         if (FakeTerminal) {
  888.             if (modifiedbold && bold == 1) outputstr(BoldOn);
  889.         } else controloutput(BoldOn, 0);
  890.     }
  891.     if (underline >= 1) {
  892.         if (FakeTerminal) {
  893.             if (modifiedunderline && underline == 1) outputstr(StartUnderline);
  894.         } else controloutput(StartUnderline, 0);
  895.     }
  896. }
  897.  
  898. static FinalizeTerminal() {
  899.     tputs(standendbuf, 1, immediate_controlputc);
  900.     tputs(BoldOff, 1, immediate_controlputc);
  901.     tputs(StopUnderline, 1, immediate_controlputc);
  902.     FPUTS(KE, stdout);
  903. }
  904.  
  905. static outputstr(s)
  906. char *s;
  907. {
  908.     while (*s) OUTC(*s++);
  909. }
  910.  
  911. #ifndef TPUTS_OK
  912. tputs(s, n, func)
  913. char *s;
  914. int n;
  915. int (*func)();
  916. {
  917.     if (s) {
  918.         while (*s) {
  919.             func((int)*s);
  920.             ++s;
  921.         }
  922.     }
  923.     return (0);
  924. }
  925. #endif
  926.  
  927. static FPUTS(s,fp)
  928. unsigned char *s;
  929. FILE *fp;
  930. {
  931.     while(*s) (*RichtextPutc)((int)(*s++),fp);
  932. }
  933.