home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / ltroff / part02 / catsup.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-15  |  15.4 KB  |  605 lines

  1. /*LINTLIBRARY*/
  2.  
  3. #include "ansic.h"
  4. #include "cat.h"
  5.  
  6. #ifndef lint
  7. #ifndef NOID
  8. static char    elsieid[] = "@(#)catsup.c    4.1";
  9. #endif /* !defined NOID */
  10. #endif /* !defined lint */
  11.  
  12. extern int    qsort();
  13.  
  14. #if !defined TRUE
  15. #define TRUE    1
  16. #define FALSE    0
  17. #endif /* !defined TRUE */
  18.  
  19. typedef struct {
  20.     int    c_special;
  21.     int    c_tophalf;
  22.     int    c_catcode;
  23.     int    c_vfindex;
  24.     int    c_ftindex;
  25.     char    c_ntname[3];
  26. } catinfo;
  27.  
  28. static catinfo    cattbl[] = {
  29.     /*    SPECIAL    TOPHALF    CATCODE    VFINDEX    FTINDEX    NTNAME    */
  30.     {    -1,    -1,    -1,    -1,    32,    " " },
  31.     {    -1,    -1,    -1,    -1,    32,    "\\ " },
  32.     {    FALSE,    TRUE,    37,    33,    33,    "!" },
  33.     {    TRUE,    FALSE,    24,    34,    34,    "\"" },
  34.     {    TRUE,    TRUE,    31,    35,    35,    "#" },
  35.     {    FALSE,    TRUE,    45,    36,    36,    "$" },
  36.     {    FALSE,    FALSE,    43,    37,    37,    "%" },
  37.     {    FALSE,    FALSE,    40,    38,    38,    "&" },
  38.     {    FALSE,    FALSE,    26,    39,    39,    "'" },
  39.     {    TRUE,    TRUE,    28,    39,    146,    "\\'" },
  40.     {    FALSE,    TRUE,    26,    40,    40,    "(" },
  41.     {    FALSE,    TRUE,    27,    41,    41,    ")" },
  42.     {    FALSE,    TRUE,    18,    42,    42,    "*" },
  43.     {    TRUE,    TRUE,    39,    57,    228,    "**" },
  44.     {    FALSE,    TRUE,    35,    43,    43,    "+" },
  45.     {    FALSE,    FALSE,    39,    44,    44,    "," },
  46.     {    FALSE,    FALSE,    32,    45,    45,    "-" },
  47.     {    FALSE,    TRUE,    19,    4,    136,    "\\-" },
  48.     {    TRUE,    TRUE,    21,    8,    205,    "+-" },
  49.     {    TRUE,    FALSE,    28,    52,    199,    "<-" },
  50.     {    FALSE,    FALSE,    36,    46,    46,    "." },
  51.     {    FALSE,    FALSE,    35,    47,    47,    "/" },
  52.     {    FALSE,    TRUE,    8,    48,    48,    "0" },
  53.     {    FALSE,    TRUE,    9,    49,    49,    "1" },
  54.     {    FALSE,    TRUE,    10,    50,    50,    "2" },
  55.     {    FALSE,    FALSE,    30,    18,    134,    "12" },
  56.     {    FALSE,    TRUE,    11,    51,    51,    "3" },
  57.     {    FALSE,    TRUE,    12,    52,    52,    "4" },
  58.     {    FALSE,    FALSE,    28,    17,    133,    "14" },
  59.     {    FALSE,    FALSE,    38,    19,    135,    "34" },
  60.     {    FALSE,    TRUE,    13,    53,    53,    "5" },
  61.     {    FALSE,    TRUE,    14,    54,    54,    "6" },
  62.     {    FALSE,    TRUE,    15,    55,    55,    "7" },
  63.     {    FALSE,    TRUE,    16,    56,    56,    "8" },
  64.     {    FALSE,    TRUE,    17,    57,    57,    "9" },
  65.     {    FALSE,    TRUE,    34,    58,    58,    ":" },
  66.     {    FALSE,    FALSE,    19,    59,    59,    ";" },
  67.     {    TRUE,    TRUE,    3,    60,    60,    "<" },
  68.     {    FALSE,    TRUE,    32,    61,    61,    "=" },
  69.     {    TRUE,    FALSE,    63,    49,    195,    "~=" },
  70.     {    TRUE,    TRUE,    22,    9,    192,    "<=" },
  71.     {    TRUE,    TRUE,    25,    51,    197,    "!=" },
  72.     {    TRUE,    TRUE,    24,    48,    193,    "==" },
  73.     {    TRUE,    TRUE,    23,    10,    191,    ">=" },
  74.     {    TRUE,    TRUE,    1,    62,    62,    ">" },
  75.     {    TRUE,    TRUE,    44,    53,    198,    "->" },
  76.     {    FALSE,    TRUE,    39,    63,    63,    "?" },
  77.     {    TRUE,    FALSE,    18,    64,    64,    "@" },
  78.     {    FALSE,    TRUE,    3,    65,    65,    "A" },
  79.     {    FALSE,    TRUE,    3,    65,    65,    "*A" },
  80.     {    FALSE,    FALSE,    61,    66,    66,    "B" },
  81.     {    FALSE,    FALSE,    61,    66,    66,    "*B" },
  82.     {    FALSE,    FALSE,    56,    67,    67,    "C" },
  83.     {    TRUE,    TRUE,    2,    78,    180,    "*C" },
  84.     {    FALSE,    FALSE,    60,    68,    68,    "D" },
  85.     {    TRUE,    FALSE,    60,    68,    177,    "*D" },
  86.     {    FALSE,    FALSE,    58,    69,    69,    "E" },
  87.     {    FALSE,    FALSE,    58,    69,    69,    "*E" },
  88.     {    FALSE,    TRUE,    1,    70,    70,    "F" },
  89.     {    TRUE,    FALSE,    45,    85,    185,    "*F" },
  90.     {    FALSE,    FALSE,    53,    71,    71,    "G" },
  91.     {    TRUE,    FALSE,    53,    67,    176,    "*G" },
  92.     {    FALSE,    FALSE,    48,    72,    72,    "H" },
  93.     {    TRUE,    FALSE,    46,    72,    178,    "*H" },
  94.     {    FALSE,    FALSE,    54,    73,    73,    "I" },
  95.     {    FALSE,    FALSE,    54,    73,    73,    "*I" },
  96.     {    FALSE,    TRUE,    5,    74,    74,    "J" },
  97.     {    FALSE,    TRUE,    7,    75,    75,    "K" },
  98.     {    FALSE,    TRUE,    7,    75,    75,    "*K" },
  99.     {    FALSE,    FALSE,    51,    76,    76,    "L" },
  100.     {    TRUE,    FALSE,    51,    75,    179,    "*L" },
  101.     {    FALSE,    FALSE,    50,    77,    77,    "M" },
  102.     {    FALSE,    FALSE,    50,    77,    77,    "*M" },
  103.     {    FALSE,    FALSE,    49,    78,    78,    "N" },
  104.     {    FALSE,    FALSE,    49,    78,    78,    "*N" },
  105.     {    FALSE,    FALSE,    47,    79,    79,    "O" },
  106.     {    FALSE,    FALSE,    47,    79,    79,    "*O" },
  107.     {    FALSE,    FALSE,    55,    80,    80,    "P" },
  108.     {    TRUE,    FALSE,    55,    80,    181,    "*P" },
  109.     {    FALSE,    FALSE,    45,    81,    81,    "Q" },
  110.     {    TRUE,    FALSE,    34,    87,    186,    "*Q" },
  111.     {    FALSE,    FALSE,    52,    82,    82,    "R" },
  112.     {    FALSE,    FALSE,    55,    80,    80,    "*R" },
  113.     {    FALSE,    FALSE,    62,    83,    83,    "S" },
  114.     {    TRUE,    FALSE,    62,    82,    182,    "*S" },
  115.     {    FALSE,    FALSE,    46,    84,    84,    "T" },
  116.     {    FALSE,    FALSE,    46,    84,    84,    "*T" },
  117.     {    FALSE,    TRUE,    6,    85,    85,    "U" },
  118.     {    TRUE,    TRUE,    6,    84,    184,    "*U" },
  119.     {    FALSE,    FALSE,    57,    86,    86,    "V" },
  120.     {    FALSE,    TRUE,    4,    87,    87,    "W" },
  121.     {    TRUE,    FALSE,    47,    88,    187,    "*W" },
  122.     {    FALSE,    TRUE,    2,    88,    88,    "X" },
  123.     {    FALSE,    TRUE,    2,    88,    88,    "*X" },
  124.     {    FALSE,    FALSE,    63,    89,    89,    "Y" },
  125.     {    FALSE,    FALSE,    48,    72,    72,    "*Y" },
  126.     {    FALSE,    FALSE,    59,    90,    90,    "Z" },
  127.     {    FALSE,    FALSE,    59,    90,    90,    "*Z" },
  128.     {    FALSE,    TRUE,    28,    91,    91,    "[" },
  129.     {    TRUE,    FALSE,    33,    92,    92,    "\\" },
  130.     {    FALSE,    TRUE,    29,    93,    93,    "]" },
  131.     {    TRUE,    TRUE,    30,    94,    94,    "^" },
  132.     {    -1,    -1,    -1,    -1,    150,    "\\^" },
  133.     {    TRUE,    FALSE,    32,    95,    95,    "_" },
  134.     {    FALSE,    FALSE,    24,    96,    96,    "`" },
  135.     {    TRUE,    TRUE,    29,    96,    147,    "\\`" },
  136.     {    FALSE,    FALSE,    21,    97,    97,    "a" },
  137.     {    TRUE,    FALSE,    19,    55,    201,    "da" },
  138.     {    TRUE,    TRUE,    5,    28,    207,    "ca" },
  139.     {    TRUE,    FALSE,    21,    97,    152,    "*a" },
  140.     {    TRUE,    TRUE,    28,    39,    146,    "aa" },
  141.     {    TRUE,    FALSE,    30,    54,    200,    "ua" },
  142.     {    TRUE,    TRUE,    29,    96,    147,    "ga" },
  143.     {    FALSE,    FALSE,    10,    98,    98,    "b" },
  144.     {    TRUE,    TRUE,    15,    23,    235,    "rb" },
  145.     {    TRUE,    TRUE,    40,    91,    210,    "ib" },
  146.     {    TRUE,    TRUE,    12,    21,    233,    "lb" },
  147.     {    TRUE,    FALSE,    10,    98,    153,    "*b" },
  148.     {    TRUE,    FALSE,    56,    26,    208,    "sb" },
  149.     {    FALSE,    FALSE,    23,    99,    99,    "c" },
  150.     {    TRUE,    TRUE,    8,    19,    242,    "rc" },
  151.     {    TRUE,    TRUE,    45,    56,    144,    "sc" },
  152.     {    TRUE,    TRUE,    18,    18,    241,    "lc" },
  153.     {    TRUE,    FALSE,    11,    110,    165,    "*c" },
  154.     {    FALSE,    FALSE,    9,    100,    100,    "d" },
  155.     {    TRUE,    FALSE,    59,    121,    213,    "pd" },
  156.     {    TRUE,    FALSE,    9,    100,    155,    "*d" },
  157.     {    TRUE,    TRUE,    37,    89,    225,    "dd" },
  158.     {    FALSE,    FALSE,    25,    101,    101,    "e" },
  159.     {    TRUE,    FALSE,    25,    101,    156,    "*e" },
  160.     {    FALSE,    TRUE,    30,    11,    142,    "de" },
  161.     {    FALSE,    FALSE,    12,    102,    102,    "f" },
  162.     {    TRUE,    TRUE,    17,    16,    239,    "lf" },
  163.     {    TRUE,    TRUE,    16,    17,    240,    "rf" },
  164.     {    TRUE,    FALSE,    13,    117,    172,    "*f" },
  165.     {    FALSE,    TRUE,    22,    3,    139,    "ff" },
  166.     {    TRUE,    FALSE,    36,    1,    212,    "if" },
  167.     {    FALSE,    FALSE,    37,    103,    103,    "g" },
  168.     {    TRUE,    FALSE,    37,    99,    154,    "*g" },
  169.     {    FALSE,    TRUE,    31,    12,    143,    "dg" },
  170.     {    FALSE,    TRUE,    33,    15,    221,    "rg" },
  171.     {    FALSE,    FALSE,    1,    104,    104,    "h" },
  172.     {    TRUE,    FALSE,    2,    104,    159,    "*h" },
  173.     {    TRUE,    FALSE,    40,    4,    226,    "rh" },
  174.     {    TRUE,    TRUE,    32,    30,    227,    "lh" },
  175.     {    FALSE,    FALSE,    6,    105,    105,    "i" },
  176.     {    TRUE,    FALSE,    6,    105,    160,    "*i" },
  177.     {    TRUE,    FALSE,    52,    45,    194,    "mi" },
  178.     {    FALSE,    TRUE,    25,    9,    140,    "Fi" },
  179.     {    FALSE,    TRUE,    20,    1,    137,    "fi" },
  180.     {    TRUE,    TRUE,    20,    47,    204,    "di" },
  181.     {    TRUE,    TRUE,    41,    93,    231,    "ci" },
  182.     {    FALSE,    FALSE,    13,    106,    106,    "j" },
  183.     {    FALSE,    FALSE,    15,    107,    107,    "k" },
  184.     {    TRUE,    FALSE,    15,    106,    161,    "*k" },
  185.     {    TRUE,    TRUE,    14,    25,    237,    "rk" },
  186.     {    TRUE,    TRUE,    11,    24,    236,    "lk" },
  187.     {    FALSE,    FALSE,    5,    108,    108,    "l" },
  188.     {    FALSE,    TRUE,    24,    10,    141,    "Fl" },
  189.     {    FALSE,    TRUE,    21,    2,    138,    "fl" },
  190.     {    TRUE,    TRUE,    4,    14,    149,    "sl" },
  191.     {    TRUE,    FALSE,    5,    107,    162,    "*l" },
  192.     {    TRUE,    TRUE,    43,    43,    220,    "pl" },
  193.     {    TRUE,    FALSE,    32,    95,    148,    "ul" },
  194.     {    FALSE,    FALSE,    4,    109,    109,    "m" },
  195.     {    FALSE,    TRUE,    40,    13,    145,    "fm" },
  196.     {    TRUE,    FALSE,    4,    108,    163,    "*m" },
  197.     {    FALSE,    FALSE,    18,    6,    131,    "em" },
  198.     {    FALSE,    FALSE,    3,    110,    110,    "n" },
  199.     {    TRUE,    FALSE,    49,    6,    190,    "rn" },
  200.     {    TRUE,    FALSE,    3,    109,    164,    "*n" },
  201.     {    FALSE,    FALSE,    27,    111,    111,    "o" },
  202.     {    FALSE,    TRUE,    43,    14,    222,    "co" },
  203.     {    TRUE,    TRUE,    7,    29,    215,    "no" },
  204.     {    TRUE,    TRUE,    33,    31,    219,    "mo" },
  205.     {    TRUE,    FALSE,    27,    111,    166,    "*o" },
  206.     {    FALSE,    FALSE,    17,    112,    112,    "p" },
  207.     {    TRUE,    FALSE,    17,    112,    167,    "*p" },
  208.     {    TRUE,    FALSE,    38,    2,    211,    "ip" },
  209.     {    TRUE,    FALSE,    57,    27,    209,    "sp" },
  210.     {    TRUE,    FALSE,    58,    50,    196,    "ap" },
  211.     {    FALSE,    FALSE,    34,    113,    113,    "q" },
  212.     {    TRUE,    FALSE,    1,    119,    174,    "*q" },
  213.     {    TRUE,    FALSE,    26,    61,    202,    "eq" },
  214.     {    FALSE,    TRUE,    44,    8,    130,    "sq" },
  215.     {    FALSE,    FALSE,    29,    114,    114,    "r" },
  216.     {    TRUE,    FALSE,    43,    40,    214,    "gr" },
  217.     {    TRUE,    FALSE,    61,    11,    188,    "sr" },
  218.     {    TRUE,    FALSE,    22,    124,    230,    "or" },
  219.     {    TRUE,    FALSE,    29,    113,    168,    "*r" },
  220.     {    TRUE,    TRUE,    38,    90,    223,    "br" },
  221.     {    FALSE,    FALSE,    8,    115,    115,    "s" },
  222.     {    TRUE,    FALSE,    8,    114,    169,    "*s" },
  223.     {    TRUE,    FALSE,    54,    13,    216,    "is" },
  224.     {    TRUE,    FALSE,    50,    12,    189,    "ts" },
  225.     {    TRUE,    FALSE,    35,    7,    229,    "bs" },
  226.     {    TRUE,    TRUE,    35,    122,    218,    "es" },
  227.     {    FALSE,    FALSE,    2,    116,    116,    "t" },
  228.     {    TRUE,    TRUE,    13,    22,    234,    "rt" },
  229.     {    FALSE,    TRUE,    23,    16,    224,    "ct" },
  230.     {    TRUE,    TRUE,    9,    20,    232,    "lt" },
  231.     {    TRUE,    FALSE,    31,    115,    170,    "*t" },
  232.     {    TRUE,    FALSE,    39,    3,    217,    "pt" },
  233.     {    FALSE,    FALSE,    14,    117,    117,    "u" },
  234.     {    TRUE,    FALSE,    48,    5,    206,    "cu" },
  235.     {    FALSE,    TRUE,    38,    7,    129,    "bu" },
  236.     {    TRUE,    TRUE,    19,    42,    203,    "mu" },
  237.     {    FALSE,    FALSE,    22,    5,    132,    "ru" },
  238.     {    TRUE,    FALSE,    14,    116,    171,    "*u" },
  239.     {    FALSE,    FALSE,    31,    118,    118,    "v" },
  240.     {    TRUE,    TRUE,    10,    15,    238,    "bv" },
  241.     {    FALSE,    FALSE,    33,    119,    119,    "w" },
  242.     {    TRUE,    FALSE,    41,    120,    175,    "*w" },
  243.     {    FALSE,    FALSE,    11,    120,    120,    "x" },
  244.     {    TRUE,    FALSE,    23,    118,    173,    "*x" },
  245.     {    FALSE,    FALSE,    41,    121,    121,    "y" },
  246.     {    FALSE,    FALSE,    32,    45,    128,    "hy" },
  247.     {    TRUE,    FALSE,    12,    103,    158,    "*y" },
  248.     {    FALSE,    FALSE,    7,    122,    122,    "z" },
  249.     {    TRUE,    FALSE,    7,    102,    157,    "*z" },
  250.     {    TRUE,    TRUE,    26,    123,    123,    "{" },
  251.     {    FALSE,    TRUE,    41,    124,    124,    "|" },
  252.     {    -1,    -1,    -1,    -1,    127,    "\\|" },
  253.     {    TRUE,    TRUE,    27,    125,    125,    "}" },
  254.     {    TRUE,    TRUE,    34,    126,    126,    "~" },
  255.     {    -1,    -1,    -1,    -1,    0,    "" }
  256. };
  257.  
  258. #if !defined NVPC
  259. #define NVPC    256        /* Number of Values Per Character */
  260. #endif /* !defined NVPC */
  261.  
  262. static const catinfo *    code2cip[2][2][CAT_MAX_FLASH + 1];
  263. static const catinfo *    char2cip[NVPC];
  264. static int        didinit;
  265.  
  266. static void
  267. tblinit()
  268. {
  269.     const catinfo *        acip;
  270.     const catinfo *        bcip;
  271.     int            i;
  272.     int            c;
  273.  
  274.     if (didinit)
  275.         return;
  276.     for (acip = cattbl; acip->c_ntname[0] != '\0'; ++acip) {
  277.         if ((c = acip->c_ntname[1]) == '\0')
  278.             c = acip->c_ntname[0];
  279.         if (char2cip[(unsigned char) c] == NULL)
  280.             char2cip[(unsigned char) c] = acip;
  281.         if (acip->c_catcode <= 0)
  282.             continue;
  283.         bcip = code2cip[acip->c_special]
  284.             [acip->c_tophalf]
  285.             [acip->c_catcode];
  286.         if (bcip != NULL && (bcip->c_ntname[1] == '\0' ||
  287.             (acip->c_ntname[1] != '\0' &&
  288.             acip->c_ntname[1] == '\\')))
  289.                 continue;
  290.         code2cip[acip->c_special]
  291.             [acip->c_tophalf]
  292.             [acip->c_catcode] = acip;
  293.     }
  294.     for (i = 0; i < NVPC; ++i)
  295.         if (char2cip[i] == NULL)
  296.             char2cip[i] = acip;
  297.     didinit = TRUE;
  298. }
  299.  
  300. static const catinfo *
  301. ntn2cip(name)
  302. char *    name;
  303. {
  304.     const catinfo *    cip;
  305.     int        c;
  306.  
  307.     if (!didinit)
  308.         tblinit();
  309.     if (name == NULL)
  310.         return NULL;
  311.     if (name[1] == '\0')
  312.         return char2cip[(unsigned char) name[0]];
  313.     if (name[0] == '\\' && name[1] == '(')
  314.         name += 2;
  315.     if (name[0] == '\0')
  316.         return NULL;
  317.     if ((c = name[1]) == '\0')
  318.         c = name[0];
  319.     else if (name[2] != '\0')
  320.         return NULL;
  321.     cip = char2cip[(unsigned char) c];
  322.     while (cip->c_ntname[0] != '\0')
  323.         if (cip->c_ntname[0] == name[0] &&
  324.             cip->c_ntname[1] == name[1])
  325.                 return cip;
  326.         else    ++cip;
  327.     return NULL;
  328. }
  329.  
  330. int
  331. ntn2vfi(name)
  332. char * const    name;
  333. {
  334.     const catinfo *    cip;
  335.  
  336.     return ((cip = ntn2cip(name)) == NULL) ? -1 : cip->c_vfindex;
  337. }
  338.  
  339. int
  340. ntn2fti(name)
  341. char * const    name;
  342. {
  343.     const catinfo *    cip;
  344.  
  345.     return ((cip = ntn2cip(name)) == NULL) ? -1 : cip->c_ftindex;
  346. }
  347.  
  348. const char *
  349. fti2ntn(fti)
  350. int const    fti;
  351. {
  352.     catinfo *    cip;
  353.  
  354.     for (cip = cattbl; ; ++cip)
  355.         if (cip->c_ntname[0] == '\0')
  356.             return NULL;
  357.         else if (cip->c_ftindex == fti)
  358.             return cip->c_ntname;
  359. }
  360.  
  361. int
  362. ntnons(name)
  363. char * const    name;
  364. {
  365.     const catinfo *    cip;
  366.  
  367.     return ((cip = ntn2cip(name)) == NULL) ? -1 : cip->c_special;
  368. }
  369.  
  370. int
  371. ntnonr(name)
  372. char * const    name;
  373. {
  374.     const catinfo *    cip;
  375.  
  376.     return ((cip = ntn2cip(name)) == NULL) ? -1 : !cip->c_special;
  377. }
  378.  
  379. /*
  380. ** Now here's something we hope you'll really like. . .
  381. */
  382.  
  383. extern char *    malloc();
  384. extern char *    realloc();
  385.  
  386. static int    curfont = 0;        /* current font */
  387. static long    horizontal = -16;    /* horizontal position */
  388. static long    vertical = 0    ;    /* vertical position */
  389. static int    escape_forward = TRUE;    /* should escape forward */
  390. static int    lead_forward = TRUE;    /* should lead forward */
  391. static int    tophalf = FALSE;    /* TRUE if top half of font is wanted */
  392. static int    true_point_size = 10;
  393.  
  394. static void
  395. catinit()
  396. {
  397.     escape_forward = TRUE;
  398.     lead_forward = TRUE;
  399.     tophalf = FALSE;
  400.     curfont = 0;
  401.     true_point_size = 10;    /* troff default */
  402.     horizontal = -16;
  403. }
  404.  
  405. typedef struct {
  406.     long    horizontal;
  407.     long    vertical;
  408.     char    size;
  409.     char    fontname[3];
  410.     char    charname[3];
  411. } memory;
  412.  
  413. static int
  414. mcomp(avp, bvp)
  415. void * const    avp;
  416. void * const    bvp;
  417. {
  418.     const memory * const    amp = (const memory *) avp;
  419.     const memory * const    bmp = (const memory *) bvp;
  420.     long            diff = amp->horizontal - bmp->horizontal;
  421.  
  422.     if (diff == 0) {
  423.         diff = amp->size - bmp->size;
  424.         if (diff == 0)
  425.             return 0;
  426.     }
  427.     return (diff > 0) ? 1 : -1;
  428. }
  429.  
  430. static char     fontnicks[8][3] = {
  431.     "R",
  432.     "",
  433.     "I",
  434.     "",
  435.     "B",
  436.     "",
  437.     "S",
  438.     "",
  439. };
  440.  
  441. static int
  442. doflash(catcode, outp, dosort)
  443. int const    catcode;
  444. int (* const    outp)();
  445. int const    dosort;
  446. {
  447.     const catinfo *    cip;
  448.     memory *    mp;
  449.     static memory *    memories;
  450.     static int    memused;
  451.     static int    memavail;
  452.     static memory    zm;
  453.  
  454.     if (fontnicks[curfont][0] == 'S' && fontnicks[curfont][1] == '\0')
  455.         cip = code2cip[TRUE][tophalf][catcode];
  456.     else    cip = code2cip[FALSE][tophalf][catcode];
  457.     if (!dosort)
  458.         if (catcode <= 0)
  459.             return 0;
  460.         else    return ((*outp)(cip->c_ntname, horizontal, vertical,
  461.                 true_point_size, fontnicks[curfont]) == 0) ?
  462.                     0 : -1;
  463.     /*
  464.     ** Flush if appropriate.
  465.     */
  466.     if (memused > 0 && (catcode <= 0 || vertical != memories[0].vertical)) {
  467.         int    i;
  468.  
  469.         (void) qsort((char *) memories, memused,
  470.             sizeof *memories, mcomp);
  471.         for (i = 0; i < memused; ++i) {
  472.             mp = &memories[i];
  473.             if ((*outp)(mp->charname,
  474.                 mp->horizontal, mp->vertical,
  475.                 mp->size, mp->fontname) != 0)
  476.                     return -1;
  477.         }
  478.         memused = 0;
  479.     }
  480.     /*
  481.     ** Remember if appropriate.
  482.     */
  483.     if (catcode <= 0)
  484.         return 0;
  485.     if (memused >= memavail) {
  486.         if (memavail++ == 0)
  487.             memories = (memory *) malloc(sizeof *memories);
  488.         else    memories = (memory *) realloc((char *) memories,
  489.                 (unsigned) (memavail * sizeof *memories));
  490.         if (memories == NULL) {
  491.             memavail = 0;
  492.             return -1;
  493.         }
  494.         memories[memused] = zm;
  495.     }
  496.     mp = &memories[memused];
  497.     mp->horizontal = horizontal;
  498.     mp->vertical = vertical;
  499.     mp->size = true_point_size;
  500.     mp->fontname[0] = fontnicks[curfont][0];
  501.     mp->fontname[1] = fontnicks[curfont][1];
  502.     mp->charname[0] = cip->c_ntname[0];
  503.     mp->charname[1] = cip->c_ntname[1];
  504.     ++memused;
  505.     return 0;
  506. }
  507.  
  508. int
  509. catsup(inp, outp, dosort, skipinit)
  510. int (* const    inp)();
  511. int (* const    outp)();
  512. int const    dosort;
  513. int const    skipinit;
  514. {
  515.     int    c;
  516.     int    i;
  517.  
  518.     if (inp == NULL || outp == NULL ||
  519.         (dosort != TRUE && dosort != FALSE) ||
  520.         (skipinit != TRUE && skipinit != FALSE))
  521.             return -1;
  522.     if (!skipinit) {
  523.         catinit();
  524.         vertical = 0;
  525.     }
  526.     tblinit();
  527.     while ((c = (*inp)()) >= 0) {
  528.         if (CAT_IS_FLASH(c)) {
  529.             if (doflash(c, outp, dosort) != 0)
  530.                 return -1;
  531.         } else if (CAT_IS_ESCAPE(c)) {
  532.             i = CAT_ESCAPE(c);
  533.             if (escape_forward)
  534.                 horizontal += i;
  535.             else {
  536.                 horizontal -= i;
  537.                 if (horizontal < 0)
  538.                     horizontal = 0;
  539.             }
  540.         } else if (CAT_IS_LEADING(c)) {
  541.             i = CAT_LEAD(c);
  542.             if (lead_forward)
  543.                 vertical += i;
  544.             else    vertical -= i;
  545.         } else if (CAT_IS_SIZE_CHANGE(c)) {
  546.             i = CAT_SIZE_CHANGE(c);
  547.             if (CAT_IS_DOUBLE_TO_SINGLE(true_point_size, i))
  548.                 horizontal += CAT_LENSE_COMPENSATION;
  549.             else if (CAT_IS_SINGLE_TO_DOUBLE(true_point_size, i)) {
  550.                 horizontal -= CAT_LENSE_COMPENSATION;
  551.                 if (horizontal < 0)
  552.                     horizontal = 0;
  553.             }
  554.             true_point_size = i;
  555.         } else switch (c) {
  556.             case CAT_INITIALIZE:
  557.                 catinit();
  558.                 break;
  559.             case CAT_UPPER_RAIL:
  560.                 curfont |= CAT_RAIL;
  561.                 break;
  562.             case CAT_LOWER_RAIL:
  563.                 curfont &= ~CAT_RAIL;
  564.                 break;
  565.             case CAT_UPPER_MAGAZINE:
  566.                 curfont |= CAT_MAGAZINE;
  567.                 break;
  568.             case CAT_LOWER_MAGAZINE:
  569.                 curfont &= ~CAT_MAGAZINE;
  570.                 break;
  571.             case CAT_TILT_UP:
  572.                 curfont |= CAT_TILT;
  573.                 break;
  574.             case CAT_TILT_DOWN:
  575.                 curfont &= ~CAT_TILT;
  576.                 break;
  577.             case CAT_UPPER_FONT:
  578.                 tophalf = TRUE;
  579.                 break;
  580.             case CAT_LOWER_FONT:
  581.                 tophalf = FALSE;
  582.                 break;
  583.             case CAT_ESCAPE_FORWARD:
  584.                 escape_forward = TRUE;
  585.                 break;
  586.             case CAT_ESCAPE_BACKWARD:
  587.                 escape_forward = FALSE;
  588.                 break;
  589.             case CAT_LEAD_FORWARD:
  590.                 lead_forward = TRUE;
  591.                 break;
  592.             case CAT_LEAD_BACKWARD:
  593.                 lead_forward = FALSE;
  594.                 break;
  595.             case CAT_STOP:
  596.                 break;    /* ? */
  597.             default:
  598.                 return -1;
  599.         }
  600.     }
  601.     if (doflash(0, outp, dosort) != 0)
  602.         return -1;
  603.     return 0;
  604. }
  605.