LCOV - code coverage report
Current view: top level - omega-rpg-0.90-pa9 - genclr.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 92 107 86.0 %
Date: 2017-08-31 19:31:11 Functions: 7 7 100.0 %
Branches: 57 78 73.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Generate C code to initialize and support Omega colors on UNIX.
       3                 :            :  *
       4                 :            :  * Usage:
       5                 :            :  *   cpp -DOMEGA_CLRGEN *.[ch] | genclr <c-file> <h-file>
       6                 :            :  * where <c-file> should be compiled and linked with the Omega binary and
       7                 :            :  * <h-file> should be #included in all Omega sources that reference colors.
       8                 :            :  *
       9                 :            :  * Curses color micro-tutorial:
      10                 :            :  *   The curses library requires color attributes to be specified as
      11                 :            :  *   COLOR_PAIR(<n>) macro calls, where init_pair(<n>, <fore-color>,
      12                 :            :  *   <back-color>) has previously been called.  <n> must fall in the range
      13                 :            :  *   1..COLOR_PAIRS, where COLOR_PAIRS is a run-time read-only curses variable
      14                 :            :  *   typically set to something like 64.
      15                 :            :  *
      16                 :            :  * <c-file> defines function clrgen_init(), which contains the minimal number
      17                 :            :  * of curses init_pair() calls to support the color usages detected by this
      18                 :            :  * program on standard input.
      19                 :            :  *
      20                 :            :  * <h-file> defines preprocessor variables that cause each detected color
      21                 :            :  * usage to expand to an appropriate curses COLOR_PAIR() call.
      22                 :            :  *
      23                 :            :  * This approach to UNIX color support is perhaps overkill, but does have
      24                 :            :  * advantages over these alternative approaches:
      25                 :            :  *
      26                 :            :  *   - hard-coded init_pair() calls and color definitions, which would
      27                 :            :  *     require manual checking and possibly editing for color reference added
      28                 :            :  *     or removed anywhere in the sources;
      29                 :            :  *
      30                 :            :  *   - replacement of color references with function calls that lazily call
      31                 :            :  *     init_pair() as necessary, which would consume more run-time resources
      32                 :            :  *     and behave unpredictably if the number of pairs exceeded COLOR_PAIRS;
      33                 :            :  *
      34                 :            :  *   - run-time analysis of color pairs required by e.g. monster list, which
      35                 :            :  *     would be a bit more complex to code, consume more run-time resources,
      36                 :            :  *     and require significant code changes to move all color references into
      37                 :            :  *     static storage.
      38                 :            :  */
      39                 :            : 
      40                 :            : #ifndef OMEGA_CLRGEN            /* this file confuses its own scanner */
      41                 :            : 
      42                 :            : #include <stdio.h>
      43                 :            : #include <stdlib.h>
      44                 :            : #include <string.h>
      45                 :            : 
      46                 :            : /*
      47                 :            :  * Special tag cpp prepends to color symbols
      48                 :            :  */
      49                 :            : #define PREFIX "OMEGA_CLRGEN"
      50                 :            : 
      51                 :            : /*
      52                 :            :  * Return whether a character could be part of a C identifier
      53                 :            :  */
      54                 :            : #define ISCID(c) \
      55                 :            : (((c) >= 'A' && (c) <= 'Z') || \
      56                 :            :  ((c) >= 'a' && (c) <= 'z') || \
      57                 :            :  ((c) >= '0' && (c) <= '9') || \
      58                 :            :  (c) == '_')
      59                 :            : 
      60                 :            : /*
      61                 :            :  * Colors specified in cpp output on standard input
      62                 :            :  */
      63                 :            : typedef struct {
      64                 :            :     char *ofg, *obg;                    /* Omega fore/background color */
      65                 :            :     char *cfg, *cbg;                    /* curses fore/background color */
      66                 :            :     unsigned int boldfg, boldbg;        /* fore/background bold flag */
      67                 :            :     unsigned int idx;                   /* COLOR_PAIR() argument */
      68                 :            : } ClrPair;
      69                 :            : 
      70                 :            : /*
      71                 :            :  * Omega versus curses color names
      72                 :            :  */
      73                 :            : typedef struct {
      74                 :            :     char *omega;
      75                 :            :     char *curses;
      76                 :            :     unsigned int bold;
      77                 :            : } ClrEquiv;
      78                 :            : 
      79                 :            : #ifdef USE_OPCURSES
      80                 :            : static ClrEquiv clr_equiv[17] = {
      81                 :            :     { "BLACK",                "BLACK",      0 },
      82                 :            :     { "BLUE",         "BLUE",               0 },
      83                 :            :     { "GREEN",                "GREEN",      0 },
      84                 :            :     { "CYAN",         "CYAN",               0 },
      85                 :            :     { "RED",          "RED",                0 },
      86                 :            :     { "PURPLE",               "MAGENTA",    0 },
      87                 :            :     { "BROWN",                "YELLOW",     0 },
      88                 :            :     { "WHITE",                "WHITE",      0 },
      89                 :            :     { "GREY",         "WHITE",      1 },
      90                 :            :     { "LIGHT_BLUE",   "BLUE",               1 },
      91                 :            :     { "LIGHT_GREEN",  "GREEN",      1 },
      92                 :            :     { "LIGHT_CYAN",   "CYAN",               1 },
      93                 :            :     { "LIGHT_RED",    "RED",                1 },
      94                 :            :     { "LIGHT_PURPLE", "MAGENTA",    1 },
      95                 :            :     { "YELLOW",               "YELLOW",     1 },
      96                 :            :     { "BRIGHT_WHITE", "WHITE",      1 },
      97                 :            :     { NULL, NULL, 0 } };
      98                 :            : #else
      99                 :            : static ClrEquiv clr_equiv[17] = {
     100                 :            :     { "BLACK",                "BLACK",      0 },
     101                 :            :     { "BLUE",         "BLUE",               0 },
     102                 :            :     { "GREEN",                "GREEN",      0 },
     103                 :            :     { "CYAN",         "CYAN",               0 },
     104                 :            :     { "RED",          "RED",                0 },
     105                 :            :     { "PURPLE",               "MAGENTA",    0 },
     106                 :            :     { "BROWN",                "YELLOW",     0 },
     107                 :            :     { "WHITE",                "WHITE",      0 },
     108                 :            :     { "GREY",         "BLACK",      1 },
     109                 :            :     { "LIGHT_BLUE",   "BLUE",               1 },
     110                 :            :     { "LIGHT_GREEN",  "GREEN",      1 },
     111                 :            :     { "LIGHT_CYAN",   "CYAN",               1 },
     112                 :            :     { "LIGHT_RED",    "RED",                1 },
     113                 :            :     { "LIGHT_PURPLE", "MAGENTA",    1 },
     114                 :            :     { "YELLOW",               "YELLOW",     1 },
     115                 :            :     { "BRIGHT_WHITE", "WHITE",      1 },
     116                 :            :     { NULL, NULL, 0 } };
     117                 :            : #endif
     118                 :            : 
     119                 :       2450 : static char *clr_lookup (char *omega, char **curses, unsigned int *bold)
     120                 :            : {
     121                 :            :     /*
     122                 :            :      * Point CURSES to the curses color corresponding to Omega color OMEGA,
     123                 :            :      * set *BOLD to whether the bold attribute should accompany that curses
     124                 :            :      * color, and return a copy of OMEGA.  If OMEGA is unrecognized, return
     125                 :            :      * null.
     126                 :            :      */
     127                 :       2450 :     ClrEquiv *e = clr_equiv;
     128         [ +  - ]:      11299 :     for (; e->omega; e++)
     129         [ +  + ]:      11299 :         if (!strcmp (e->omega, omega)) {
     130                 :       2450 :             *curses = e->curses;
     131                 :       2450 :             *bold = e->bold;
     132                 :       2450 :             return e->omega;
     133                 :            :         }
     134                 :          0 :     return NULL;
     135                 :            : }
     136                 :            : 
     137                 :       1303 : static char *clr_scan (char *p, char **curses, unsigned int *bold, char **end)
     138                 :            : {
     139                 :            :     /*
     140                 :            :      * Return a copy of the Omega color nearest the start of writable buffer
     141                 :            :      * P, point CURSES to the corresponding curses color, and point END just
     142                 :            :      * past the color's location in P.
     143                 :            :      *
     144                 :            :      * If the Omega color is unrecognized, issue an error and exit.
     145                 :            :      */
     146                 :            :     char c, *start, *omega;
     147         [ +  - ]:       2606 :     for (; (c = *p); p++) {
     148 [ +  + ][ -  + ]:       2606 :         if (!ISCID (c))
         [ -  + ][ #  # ]
         [ -  + ][ #  # ]
                 [ +  - ]
     149                 :       1303 :             continue;
     150         [ +  - ]:       6855 :         for (start = p++; (c = *p); p++) {
     151 [ +  + ][ +  + ]:       6855 :             if (ISCID (c))
         [ -  + ][ #  # ]
         [ +  + ][ +  - ]
                 [ +  + ]
     152                 :       5552 :                 continue;
     153                 :       1303 :             *p = '\0';
     154         [ -  + ]:       1303 :             if (!(omega = clr_lookup (start, curses, bold))) {
     155                 :          0 :                 fprintf (stderr, "unrecognized Omega color \"%s\"\n", start);
     156                 :          0 :                 exit (1);
     157                 :            :             }
     158                 :       1303 :             *p = c;
     159                 :       1303 :             *end = p;
     160                 :       1303 :             return omega;
     161                 :            :         }
     162                 :            :     }
     163                 :          0 :     return NULL;
     164                 :            : }
     165                 :            : 
     166                 :      11429 : static int opaircmp (const void *pair1, const void *pair2)
     167                 :            : {
     168                 :            :     /*
     169                 :            :      * qsort comparison function: return less than, equal to, or greater than
     170                 :            :      * 0 according to whether PAIR1 precedes, coincides with, or follows PAIR2
     171                 :            :      * in a sorted list of Omega color pairs.
     172                 :            :      */
     173                 :      11429 :     ClrPair *p1 = (ClrPair *)pair1, *p2 = (ClrPair *)pair2;
     174                 :      11429 :     int diff = strcmp (p1->ofg, p2->ofg);
     175         [ +  + ]:      11429 :     if (diff)
     176                 :       5406 :         return diff;
     177                 :       6023 :     return strcmp (p1->obg, p2->obg);
     178                 :            : }
     179                 :            : 
     180                 :        172 : static int cpaircmp (const void *pair1, const void *pair2)
     181                 :            : {
     182                 :            :     /*
     183                 :            :      * qsort comparison function: return less than, equal to, or greater than
     184                 :            :      * 0 according to whether PAIR1 precedes, coincides with, or follows PAIR2
     185                 :            :      * in a sorted list of curses color pairs.
     186                 :            :      */
     187                 :        172 :     ClrPair *p1 = *(ClrPair **)pair1, *p2 = *(ClrPair **)pair2;
     188                 :        172 :     int diff = strcmp (p1->cfg, p2->cfg);
     189         [ +  + ]:        172 :     if (diff)
     190                 :         81 :         return diff;
     191                 :         91 :     return strcmp (p1->cbg, p2->cbg);
     192                 :            : }
     193                 :            : 
     194                 :          2 : static FILE *emitopen (char *file, char **argv)
     195                 :            : {
     196                 :            :     /*
     197                 :            :      * Write to the top of FILE a suitable header based on ARGV, and return a
     198                 :            :      * writable file pointer on FILE.  Exit on error.
     199                 :            :      */
     200                 :          2 :     FILE *fp = fopen (file, "w");
     201         [ -  + ]:          2 :     if (!fp) {
     202                 :          0 :         fprintf (stderr, "error opening %s", file);
     203                 :          0 :         perror ("");
     204                 :          0 :         exit (1);
     205                 :            :     }
     206                 :          2 :     fprintf (fp, "\
     207                 :            : /*\n\
     208                 :            :  * Do not edit this file.  It was automatically generated by running:\n\
     209                 :            :  *   %s %s %s\n\
     210                 :            :  */\n\
     211                 :            : \n\
     212                 :            : ",
     213                 :          4 :              argv[0], argv[1], argv[2]);
     214                 :          2 :     return fp;
     215                 :            : }
     216                 :            : 
     217                 :          2 : static void emitclose (FILE *fp, char *file)
     218                 :            : {
     219                 :            :     /*
     220                 :            :      * Close FP attached to FILE, exiting on error.
     221                 :            :      */
     222         [ +  - ]:          2 :     if (fclose (fp) == 0)
     223                 :          2 :         return;
     224                 :          0 :     fprintf (stderr, "error closing %s", file);
     225                 :          0 :     perror ("");
     226                 :          0 :     exit (1);    
     227                 :            : }
     228                 :            : 
     229                 :          1 : int main (int argc, char **argv)
     230                 :            : {
     231                 :            :     char line[1024], *p;
     232                 :          1 :     unsigned int i, j, nopairs = 0, ncpairs, opairslen = 80, one;
     233                 :            :     ClrPair *pair;
     234                 :            :     ClrPair *opairs;                    /* Omega color pairs */
     235                 :            :     ClrPair **cpairs;                   /* curses color pairs */
     236                 :            :     char *cfile, *hfile;
     237                 :            :     FILE *fp;
     238                 :            : 
     239         [ -  + ]:          1 :     if (argc != 3) {
     240                 :          0 :         fprintf (stderr, "usage: %s <c-file> <h-file>\n", argv[0]);
     241                 :          0 :         exit (1);
     242                 :            :     }
     243                 :          1 :     cfile = argv[1];
     244                 :          1 :     hfile = argv[2];
     245                 :            : 
     246                 :            :     /*
     247                 :            :      * Accumulate Omega color pairs from standard input into pairs.
     248                 :            :      */
     249                 :          1 :     opairs = (ClrPair *)malloc (opairslen * sizeof (ClrPair));
     250         [ +  + ]:     289990 :     while (fgets (line, 1024, stdin)) {
     251         [ +  + ]:     291214 :         for (p = line; (p = strstr (p, PREFIX));) {
     252                 :       1225 :             p += sizeof (PREFIX) - 1;
     253         [ +  + ]:       1225 :             if (nopairs == opairslen) {
     254                 :          4 :                 opairslen *= 2;
     255                 :          4 :                 opairs = (ClrPair *)realloc (opairs, opairslen *
     256                 :            :                                              sizeof (ClrPair));
     257                 :            :             }
     258                 :       1225 :             pair = opairs + nopairs++;
     259                 :       1225 :             one = *p++ == '1';
     260                 :       1225 :             pair->ofg = clr_scan (p, &pair->cfg, &pair->boldfg, &p);
     261                 :       1225 :             pair->obg = one ?
     262         [ +  + ]:       1225 :                 clr_lookup ("BLACK", &pair->cbg, &pair->boldbg) :
     263                 :         78 :                     clr_scan (p, &pair->cbg, &pair->boldbg, &p);
     264         [ -  + ]:       1225 :             if (pair->boldbg)
     265                 :          0 :                 fprintf (stderr, "warning: \"%s\": bg bold unimplemented\n",
     266                 :            :                          pair->obg);
     267                 :            :         }
     268                 :            :     }
     269         [ -  + ]:          1 :     if (!nopairs) {
     270                 :          0 :         fputs ("no colors detected in standard input\n", stderr);
     271                 :          0 :         exit (1);
     272                 :            :     }
     273                 :            : 
     274                 :            :     /*
     275                 :            :      * Remove duplicate Omega color pairs.
     276                 :            :      */
     277                 :          1 :     qsort (opairs, nopairs, sizeof (ClrPair), opaircmp);
     278         [ +  + ]:       1225 :     for (i = 0, j = 1; j < nopairs; j++) {
     279         [ +  + ]:       1224 :         if (opaircmp (opairs + i, opairs + j))
     280                 :         38 :             opairs[++i] = opairs[j];
     281                 :            :     }
     282                 :          1 :     nopairs = i + 1;
     283                 :            : 
     284                 :            :     /*
     285                 :            :      * Construct a list of unique curses color pairs, and instantiate all
     286                 :            :      * ClrPair.idx fields.
     287                 :            :      */
     288                 :          1 :     cpairs = (ClrPair **)malloc (nopairs * sizeof (ClrPair *));
     289         [ +  + ]:         40 :     for (i = 0; i < nopairs; i++)
     290                 :         39 :         cpairs[i] = opairs + i;
     291                 :          1 :     qsort (cpairs, nopairs, sizeof (ClrPair *), cpaircmp);
     292                 :          1 :     cpairs[0]->idx = 1;
     293                 :            : 
     294         [ +  + ]:         39 :     for (i = 0, j = 1; j < nopairs; j++) {
     295         [ +  + ]:         38 :         if (cpaircmp (cpairs + i, cpairs + j))
     296                 :         24 :             cpairs[++i] = cpairs[j];
     297                 :         38 :         cpairs[j]->idx = i + 1;
     298                 :            :     }
     299                 :          1 :     ncpairs = i + 1;
     300                 :            : 
     301                 :            :     /*
     302                 :            :      * Emit .c file.
     303                 :            :      */
     304                 :          1 :     fp = emitopen (cfile, argv);
     305                 :            : 
     306                 :            : #ifdef USE_OPCURSES
     307                 :            :     fprintf (fp, "\
     308                 :            : #include \"../opcurses/curses.h\"\n");
     309                 :            : #else
     310                 :          1 :     fprintf (fp, "\
     311                 :            : #include <curses.h>\n");
     312                 :            : #endif
     313                 :            : 
     314                 :          1 :     fprintf (fp, "\
     315                 :            : #include <stdio.h>\n\
     316                 :            : #include <stdlib.h>\n\
     317                 :            : \
     318                 :            : #include \"%s\"\n\
     319                 :            : \
     320                 :            : void clrgen_init (void)\n\
     321                 :            : ""{\n\
     322                 :            :     if (!has_colors()) {\n\
     323                 :            :       fprintf(stderr,\"Omega currently requires ncurses or op-curses color support.\\n\");\n\
     324                 :            :       return;\n\
     325                 :            :     } else\n\
     326                 :            :     if (%d > COLOR_PAIRS - 1) {\n\
     327                 :            :         endwin();\n\
     328                 :            :         fprintf (stderr,\"Too few available color pairs (found %%d, need %d)!\\n\", COLOR_PAIRS);\n\
     329                 :            :         exit (1);\n\
     330                 :            :     }\n\
     331                 :            : ",
     332                 :            :              hfile, ncpairs, ncpairs);
     333         [ +  + ]:         26 :     for (i = 0; i < ncpairs; i++)
     334                 :         25 :         fprintf (fp, "\
     335                 :            :     init_pair (%d, COLOR_%s, COLOR_%s);\n\
     336                 :            : ",
     337                 :         75 :                  cpairs[i]->idx, cpairs[i]->cfg, cpairs[i]->cbg);
     338                 :          1 :     fputs ("\
     339                 :            : ""}\n\
     340                 :            : ",
     341                 :            :            fp);
     342                 :          1 :     emitclose (fp, cfile);
     343                 :            : 
     344                 :            :     /*
     345                 :            :      * Emit .h file.
     346                 :            :      */
     347                 :          1 :     fp = emitopen (hfile, argv);
     348         [ +  + ]:         40 :     for (i = 0; i < nopairs; i++) {
     349                 :         39 :         pair = opairs + i;
     350 [ +  + ][ +  + ]:         39 :         fprintf (fp, "#define CLR_%s_%s\t%sCOLOR_PAIR(%d)%s\n",
     351                 :            :                  pair->ofg, pair->obg,
     352                 :         39 :                  strlen (pair->ofg) + strlen (pair->obg) > 10 ? "" : "\t",
     353                 :         39 :                  pair->idx, pair->boldfg ? "|A_BOLD" : "");
     354                 :            :     }
     355                 :          1 :     fputs ("\
     356                 :            : \n\
     357                 :            : extern void clrgen_init (void);\n\
     358                 :            : ",
     359                 :            :             fp);
     360                 :          1 :     emitclose (fp, hfile);
     361                 :            : 
     362                 :          1 :     return 0;
     363                 :            : }
     364                 :            : 
     365                 :            : #endif   /* !OMEGA_CLRGEN */

Generated by: LCOV version 1.11