home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / uconv123.zip / uconvexp.c < prev    next >
Text File  |  2000-03-03  |  31KB  |  1,172 lines

  1. /*
  2.  * uconvexp:  Expand a uconv table
  3.  *
  4.  * Function:
  5.  *     Expand a uconv table from the binary to a source file.
  6.  *     This has the secondary effect of being a good test case.
  7.  *
  8.  * Author:
  9.  *     Ken Borgendale    kwb@us.ibm.com
  10.  *
  11.  * Copyright:
  12.  *     Copyright (C) IBM Copr. 1995, 2000
  13.  *
  14.  * Notes:
  15.  *     In order to always get the primary mapping last, the file
  16.  *     is processed in two passes.  The first pass puts out all
  17.  *     alternate mappings, and the second pass puts out the
  18.  *     primary mappings.
  19.  */
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <wcstr.h>
  23. #include <ctype.h>
  24. #include <stdio.h>
  25. #include <direct.h>
  26. #include <io.h>
  27. #define  INCL_DOS
  28. #include <os2.h>
  29.  
  30. /*
  31.  * Basic defines
  32.  */
  33. typedef unsigned long  int uint32;
  34. typedef unsigned short int uint16;
  35.  
  36. /*
  37.  * Do ULS specific defines
  38.  */
  39. #include <uconv.h>
  40. #define SHIFT_TO   1
  41. #define SHIFT_FROM 2
  42.  
  43. /*
  44.  * File structure of ucmap files.  This is just a subset but allows
  45.  * us to get at a couple of fields for which there are no queries.
  46.  */
  47. typedef struct {
  48.     uint32    size;                /* size of header                  */
  49.     uint16    bom;                 /* = 0xfeff      (our endian)      */
  50.     char      version;             /* = UC_VERSION                    */
  51.     char      release;             /* = UC_RELEASE                    */
  52.     char      eyecatcher[4];       /* "ucv"                           */
  53.     uint16    codepage;            /* IBM registered codepage         */
  54.     uint16    flags;
  55.     char      name[12];            /* Name of codepage                */
  56.     uint32    resv2;
  57.     uint16    hdrlen;              /* Length of base header           */
  58.     uint16    copyright;           /* Offset to copyright             */
  59.     uint16    desc;                /* Offset to description           */
  60.     uint16    uconv_more;          /* Additional codepoints           */
  61. } ucm_hdr_t;
  62.  
  63. /*
  64.  * Name table for names read from file
  65.  */
  66. typedef struct {
  67.     char  * name;
  68.     uint16  uni;
  69.     uint16  len;
  70. } NAMETAB;
  71. #define NOTHEXVAL 999999
  72.  
  73. /*
  74.  * Function prototypes
  75.  */
  76. void   help (void);
  77. int    doargs (int argc, char * * argv);
  78. void   putmap (int uchr, int match);
  79. void   outheader(FILE * f);
  80. char * encname(uint16 encoding, int flag);
  81. int    getglyph(UniChar uni);
  82. char * getline(char * buf, FILE * f);
  83. int    getnames(NAMETAB * * tab, char * name, char * * text, NAMETAB * * utab);
  84. long   gethexval(char * cp);
  85. long   parse (char * line, char * * value);
  86. char * nexttoken(char * value);
  87. void   nullword(char * cptr);
  88. FILE * findopen (char * fname, char * mode, char * path, int msg);
  89. void   searchenv (const char *fname, const char *env_var, char *path);
  90. char * getpath (char *src, char *dst);
  91. void   replaceext(char * in, char * ext, char * out);
  92. void   touni(UniChar * ustr, char * str);
  93.  
  94. /*
  95.  * Encoding names
  96.  */
  97. struct {
  98.     char * name;             /* Encoding name  */
  99.     uint16 encoding;         /* Encoding value */
  100.     uint16 class;            /* UCONV class    */
  101.     char   min;              /* Default min    */
  102.     char   max;              /* Default max    */
  103. } EncNames[] = {
  104.     { "sbcs-ebcdic",     0x1100, 1, 1, 1 },
  105.     { "sbcs-ebcdic-v",   0x1100, 2, 1, 2 },
  106.     { "dbcs-ebcdic",     0x1200, 2, 1, 2 },
  107.     { "mbcs-ebcdic",     0x1301, 4, 1, 2 },
  108.     { "sbcs-data",       0x2100, 1, 1, 1 },
  109.     { "sbcs",            0x2100, 1, 1, 1 },
  110.     { "dbcs-data",       0x2200, 2, 1, 2 },
  111.     { "dbcs",            0x2200, 2, 1, 2 },
  112.     { "mbcs-data",       0x2300, 3, 1, 2 },
  113.     { "mbcs",            0x2300, 3, 1, 2 },
  114.     { "sbcs-pc",         0x3100, 1, 1, 1 },
  115.     { "dbcs-pc",         0x3200, 2, 1, 2 },
  116.     { "mbcs-pc",         0x3300, 3, 1, 2 },
  117.     { "sbcs-iso",        0x4100, 1, 1, 1 },
  118.     { "sbcs-iso-v",      0x4100, 2, 1, 2 },
  119.     { "sbcs-windows",    0x4105, 1, 1, 1 },
  120.     { "sbcs-windows-v",  0x4105, 2, 1, 2 },
  121.     { "sbcs-alt",        0xF100, 1, 1, 1 },
  122.     { "ucs-2",           0x7200, 5, 2, 2 },
  123.     { "utf-8",           0x7807, 6, 1, 3 },
  124.     { "upf-8",           0x78FF, 0, 1, 3 },
  125.     { NULL,              0,      0, 0, 0 }
  126. };
  127.  
  128. char  EncHex[32];
  129.  
  130. /*
  131.  * Class names.  These are used for the standard output
  132.  */
  133. char * ClassName[] = {
  134.     "INVALID",
  135.     "SBCS",
  136.     "DBCS",
  137.     "MBCS",
  138.     "EBCDIC_STATEFUL",
  139.     "UCS-2",
  140.     "UTF-8",
  141.     "UPF-8",
  142. };
  143.  
  144. /*
  145.  * Global variables
  146.  */
  147. char      Debugflag;         /* -d option */
  148. char      Quietflag;         /* -q option */
  149. char      Stdflag;           /* -s option */
  150. char      Upflag;            /* -u option */
  151. char      Displayflag;        /* -z option */
  152. char      Javaflag;          /* -j option */
  153. char      CDRAflag;          /* -c option */
  154. char      GlyphAdobe[64];
  155. char      GlyphIBM[12];
  156. char      Fn[260];           /* Expanded file name */
  157. char      InLine[256];       /* Input line from names file */
  158. char      InName[260];       /* Input file name    */
  159. char      OutName[260];      /* Output file name   */
  160. int       MaxLen;
  161. int       MinLen;
  162. int       CClass;
  163. UconvObject Hand;            /* Uconv object handle */
  164. FILE    * Outf;
  165. NAMETAB * Unicode;           /* Unicode name table  */
  166. char    * Unitext;           /* Unicode name data   */
  167. NAMETAB * Utab[256];
  168. char    * Value;
  169. int       CharCnt;
  170. char      DbcsStarter[256];
  171. udcrange_t UdcRange[32];
  172. char      TableHdr[2048];
  173. uconv_attribute_t  Attr;
  174. uint16  * JToChar;
  175. uint16  * JToByte;
  176.  
  177.  
  178. /*
  179.  * main:  Expand uconv object
  180.  */
  181. main(int argc, char * * argv) {
  182.     int        rc;
  183.     UniChar    ucbuf[256];
  184.     int        i, j;
  185.     FILE *     ufile;
  186.     uint32     bootdrive;
  187.     char       xfile[268];
  188.  
  189.     /*
  190.      * Process the input arguments
  191.      */
  192.     doargs(argc, argv);
  193.     if (!*InName)                 /* Input name not specified */
  194.         help();                   /* Does not return */
  195.     if (!Quietflag) {
  196.         printf("uconvexp - (C) Copyright IBM Corp. 1995, 2000\n");
  197.     }
  198.  
  199.     /*
  200.      * Open the input file (using uconv services)
  201.      */
  202.     touni(ucbuf, InName);
  203.     rc = UniCreateUconvObject(ucbuf, &Hand);
  204.     if (rc) {
  205.         printf("Unable to open input uconv object: %s (%d)\n", InName, rc);
  206.         exit (4);
  207.     }
  208.     rc = UniQueryUconvObject(Hand, &Attr, sizeof(Attr), DbcsStarter, NULL, UdcRange);
  209.     if (rc) {
  210.         printf("Unable to query uconv object: %s (%d)\n", InName, rc);
  211.         exit (5);
  212.     }
  213.     Attr.options = 0;
  214.     if (Displayflag) {
  215.         Attr.displaymask = DSPMASK_DISPLAY;
  216.     }
  217.     if (CDRAflag) {
  218.         Attr.converttype = CVTTYPE_CDRA;
  219.     }
  220.     rc = UniSetUconvObject(Hand, &Attr);
  221.     if (rc) {
  222.         printf("Unable to set uconv object: %s (%d)\n", InName, rc);
  223.         exit (6);
  224.     }
  225.  
  226.     /*
  227.      * Open the output file
  228.      */
  229.     if (!OutName[0])
  230.         replaceext(InName, ".ucx", OutName);
  231.     Outf = fopen(OutName, "w");
  232.     if (!Outf) {
  233.         printf("Unable to open output file - %s\n", OutName);
  234.         exit(5);
  235.     }
  236.  
  237.     /*
  238.      * Get the names of the unicode characters
  239.      */
  240.     getnames(&Unicode,  "unicode.nam",  &Unitext, Utab);
  241.  
  242.     /*
  243.      * Open the file to get extra header information.  This is
  244.      * not needed for standard output.
  245.      */
  246.     strcpy(xfile, "CODEPAGE\\");
  247.     strcat(xfile, InName);
  248.     ufile = findopen(xfile, "rb", "ULSPATH", 0);
  249.     if (!ufile) {
  250.         ufile = findopen(InName, "rb", "ULSPATH", 0);
  251.     }
  252.     if (!ufile) {
  253.         strcpy(xfile, "C:\\LANGUAGE\\CODEPAGE\\");
  254.         strcat(xfile, InName);
  255.         bootdrive = 3;
  256.         DosQuerySysInfo ( QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &bootdrive, 4);
  257.         xfile[0] = 'A' + bootdrive - 1;
  258.         ufile = findopen(xfile, "rb", "ULSPATH", 0);
  259.     }
  260.     if (ufile) {
  261.         fread(TableHdr, 2048, 1, ufile);
  262.         fclose(ufile);
  263.     } else {
  264.         printf("Extended header information not available\n");
  265.     }
  266.  
  267.     /*
  268.      * Output the header of the uconvobj
  269.      */
  270.     outheader(Outf);
  271.  
  272.     /*
  273.      * Create the charmap section
  274.      */
  275.     CharCnt = 0;
  276.     fprintf(Outf, Upflag?"#\nCHARMAP\n":"#\ncharmap\n");
  277.  
  278.     /*
  279.      * First put out all entries which do not reverse map
  280.      */
  281.     fprintf(Outf, "# Alternate mappings\n");
  282.     for (i=0; i<0xfffe; i++) {
  283.         putmap(i, 1);
  284.     }
  285.     /*
  286.      * Then put out all entries with do reverse map
  287.      */
  288.     fprintf(Outf, "#\n# Primary mappings\n#\n");
  289.     for (i=0; i<0xfffe; i++) {
  290.         putmap(i, 0);
  291.     }
  292.  
  293.     fprintf(Outf, Upflag?"END CHARMAP\n":"end charmap\n");
  294.  
  295.     if (Javaflag) {
  296.         uint16 * index = calloc(2, 256);
  297.         uint16 maxpos = 0;
  298.         for (i=0; i<256; i++) {
  299.             uint16 ch;
  300.             if (i%8 == 0) {
  301.                 printf("        \"");
  302.             }
  303.             ch = JToChar[i];
  304.             printf("\\u%04x", ch);
  305.             if (i%8 == 7) {
  306.                 printf("\" + /* %02x - %02x */\n", i-7, i);
  307.             }
  308.         }
  309.         for (i=0; i<256; i++) {
  310.             for (j=0; j<maxpos; j++) {
  311.                 if (!memcmp(JToByte+j, JToByte+(i*256), 512)) {
  312.                     break;
  313.                 }
  314.             }
  315.             index[i] = j;
  316.             if (j==maxpos) {
  317.                 memmove(JToByte+j, JToByte+(i*256), 512);
  318.                 maxpos += 256;
  319.             } else {
  320.                 if (j+256 > maxpos)
  321.                     maxpos = j+256;
  322.             }
  323.         }
  324.         printf("\n");
  325.         for (i=0; i<maxpos; i++) {
  326.             uint16 ch;
  327.             if (i%10 == 0) {
  328.                 printf("        \"");
  329.             }
  330.             ch = JToByte[i];
  331.             printf("\\u%04x", ch);
  332.             if (i%10 == 9) {
  333.                 printf("\" + /* %3d - %3d */\n", i-9, i);
  334.             }
  335.         }
  336.         printf("\n");
  337.         for (i=0; i<256; i++) {
  338.             printf("%4d,", index[i]);
  339.             if (i%16 == 15) {
  340.                 printf("\n");
  341.             }
  342.         }
  343.         free(index);
  344.     }
  345.  
  346.     /*
  347.      * Completion
  348.      */
  349.     rc = UniFreeUconvObject(Hand);
  350.     if (!Quietflag)
  351.         printf("Codepage source '%s' created - %ld characters\n", OutName, CharCnt);
  352.     return 0;
  353. }
  354.  
  355.  
  356. /*
  357.  * help:  Simple help
  358.  */
  359. void  help(void) {
  360.     printf("uconvexp - Expand Unicode Conversion Object - V1.2 3 March 2000\n");
  361.     printf("           (C) Copyright IBM Corp. 1995, 2000\n\n");
  362.     printf("uconvexp uconvname outname -options\n");
  363.     printf("uconvname = Name of a uconv to expand (must be simple name)\n");
  364.     printf("outname   = Name of output (defaults from uconv name)\n\n");
  365.     printf("-s  =  Standard - Produce output suitable for Unix\n");
  366.     printf("-u  =  Upper    - Show hex constants and names in upper case\n");
  367.     printf("-q  =  Quiet    - Do not put out informational messages\n\n");
  368.     printf("-f  =  Full     - Use mapping to allow recreation of table\n");
  369.     printf("-c  =  CDRA     - Use CDRA mappings (default is no CDRA)\n");
  370.     printf("-z  =  Display  - Use display mappings (default is data mapping)\n");
  371.     printf("\nThe name of the uconv object must be the name known to the system.\n");
  372.     printf("It does not contain the path name. \n");
  373.     printf("\nexamples:\n");
  374.     printf("    uconvexp -f IBM850\n");
  375.     printf("    uconvexp -s -z IBM932 ibm-932.ucm\n");
  376.     exit (1);
  377. }
  378.  
  379.  
  380.  
  381. /*
  382.  * putmap:  Put out a map entry
  383.  *    match = 0 : Put out only matching entries
  384.  *    match = 1 : Put out only non-matching entries
  385.  *    match = 2 : Put out all entries
  386.  */
  387. void  putmap (int uchr, int match) {
  388.     UniChar    ucbuf[256], * up;
  389.     char       chbuf[256], * cp;
  390.  
  391.     size_t     insize, outsize, outlen;
  392.     size_t     subs;
  393.     int        skip;
  394.     int        rc;
  395.     int        j;
  396.  
  397.  
  398.     /*
  399.      * Convert the character from unicode to multibyte
  400.      */
  401.     ucbuf[0] = uchr;
  402.     up       = ucbuf;
  403.     cp       = chbuf;
  404.     insize   = 1;
  405.     outsize  = 4;
  406.     subs     = 0;
  407.     skip     = 0;
  408.  
  409.     rc = UniUconvFromUcs ( Hand, &up, &insize, (void * *)&cp, &outsize, &subs);
  410.     if (!rc) {
  411.         outsize = 4-outsize;
  412.         /*
  413.          * Check if this is a reverse translate
  414.          */
  415.         if (match<2) {
  416.             up = ucbuf;
  417.             cp = chbuf;
  418.             insize = outsize;
  419.             outlen = 2;
  420.             rc = UniUconvToUcs ( Hand, (void * *)&cp, &insize, &up, &outlen, &subs);
  421.             outlen = 2-outlen;
  422.             if (rc || outlen != 1) {    /* Reverse map failed */
  423.                 printf("Bad glyph: %04x  (%d, %d)\n", uchr, rc, outlen);
  424.                 if (!match)             /* Mismatch */
  425.                     return;
  426.             } else {
  427.                 if (*ucbuf == uchr) {
  428.                     if (JToChar) {
  429.                         JToChar[chbuf[0]] = uchr;
  430.                     }
  431.                     if (match)          /* Fail on match */
  432.                         return;
  433.                 } else {
  434.                     if (!match)         /* Fail on mismatch */
  435.                         return;
  436.                 }
  437.             }
  438.         }
  439.         if (Attr.esid==ESID_mbcs_ebcdic) {
  440.             if (outsize>1 && (*chbuf==0x0e || *chbuf==0x0f)) {
  441.                 skip = 1;
  442.                 outsize--;
  443.             }
  444.         }
  445.         CharCnt++;
  446.         fprintf(Outf, Upflag?"<U%04X>     ":"<u%04x>     ", uchr);
  447.         for (j=0; j<4; j++) {
  448.             if (j<outsize)
  449.                 fprintf(Outf, Upflag?"\\x%02X":"\\x%02x", chbuf[j+skip]);
  450.             else
  451.                 fprintf(Outf, "    ");
  452.         }
  453.         if (getglyph(uchr)) {
  454.             fprintf(Outf, "    #  %8s  %s", GlyphIBM, GlyphAdobe);
  455.         }
  456.         fprintf(Outf, "\n");
  457.         if (JToByte) {
  458.              JToByte[uchr] = chbuf[0];
  459.         }
  460.     }
  461. }
  462.  
  463.  
  464. /*
  465.  *  doargs:  Process arguments
  466.  */
  467. int doargs(int argc, char * * argv) {
  468.     int       argcnt, filecnt;
  469.     char  *   argp;
  470.     char      swchar;
  471.  
  472.     argcnt = 1;
  473.     filecnt = 0;
  474.     /*
  475.      * Read the arguments and decide what we are doing
  476.      */
  477.     while (argcnt<argc) {
  478.         argp = argv[argcnt];
  479.         /*
  480.          * Check for switches.
  481.          */
  482.         if (*argp == '-' && argp[1]) {
  483.             /* Process switches */
  484.             swchar = (char)tolower(argp[1]);
  485.             argp += 2;
  486.             switch (swchar) {
  487.             case '?':
  488.                 help();      /* Does not return */
  489.                 break;
  490.  
  491.             /*
  492.              * -c -- CDRA mappings
  493.              */
  494.             case 'c':
  495.                 CDRAflag = 1;
  496.                 break;
  497.  
  498.             /*
  499.              * -f -- Full roundtrip mappings
  500.              */
  501.             case 'f':
  502.                 CDRAflag = 1;
  503.                 Displayflag = 1;
  504.                 break;
  505.  
  506.             /*
  507.              * -d -- Debug option.
  508.              */
  509.             case 'd':
  510.                 Debugflag = 1;
  511.                 if (argp[-1]=='D') Debugflag=2;
  512.                 break;
  513.  
  514.  
  515.             /*
  516.              * -q -- Quiet option.  This is normally used in cmd files
  517.              */
  518.             case 'q':
  519.                 Quietflag = 1;
  520.                 break;
  521.  
  522.             /*
  523.              * -s -- Standard flag
  524.              */
  525.             case 's':
  526.                 Stdflag = 1;
  527.                 Upflag  = 1;
  528.                 break;
  529.  
  530.             /*
  531.              * -u -- Uppercas flag
  532.              */
  533.             case 'u':
  534.                 Upflag = 1;
  535.                 break;
  536.  
  537.             /*
  538.              * -j -- Java flag (put to stdout)
  539.              */
  540.             case 'j':
  541.                 Javaflag = 1;
  542.                 JToChar = calloc(2, 256);
  543.                 JToByte = calloc(2, 64*1024);
  544.                 break;
  545.  
  546.             /*
  547.              * -z -- Data mappings
  548.              */
  549.             case 'z':
  550.                 Displayflag = 1;
  551.                 break;
  552.  
  553.             /*
  554.              *  Any other switch is an error
  555.              */
  556.             default:
  557.                 printf("Unknown switch ignored - %s\n", (argp-2));
  558.             }
  559.         } else {
  560.             /*
  561.              *  Check for help specified as just a ?. This does now work
  562.              *  in unix, since the shell will try to interpret these.
  563.              */
  564.             if (*argp=='?') {
  565.                 if (argp[1]==0) help();      /* Does not return */
  566.             }
  567.             filecnt++;
  568.             switch(filecnt) {
  569.                 /*
  570.                  *  The first file name is the source file name.
  571.                  */
  572.                 case 1:
  573.                 strncpy(InName, argp, 259);
  574.                 break;
  575.  
  576.             /*
  577.              *  The second name is the output file name
  578.              */
  579.             case 2:
  580.                 strncpy(OutName, argp, 259);
  581.                 break;
  582.  
  583.             /*
  584.              *  The third name is an error
  585.              */
  586.             default:
  587.                 printf("Extra parameter ignored - %s\n", argp);
  588.             }
  589.         }
  590.         argcnt++;
  591.     }
  592.     return filecnt;
  593. }
  594.  
  595.  
  596. /*
  597.  * encname: Get encoding name
  598.  */
  599. char * encname(uint16 encoding, int flag) {
  600.     int   i;
  601.  
  602.     i=0;
  603.     while (EncNames[i].encoding) {
  604.         if (encoding == EncNames[i].encoding) {
  605.             if ((flag&1) && EncNames[i+1].encoding==encoding)
  606.                 i++;
  607.             MinLen = EncNames[i].min;
  608.             MaxLen = EncNames[i].max;
  609.             CClass = EncNames[i].class;
  610.             return EncNames[i].name;
  611.         }
  612.         i++;
  613.     }
  614.     sprintf(EncHex, "%04X", encoding);
  615.     return EncHex;
  616. }
  617.  
  618.  
  619. /*
  620.  * outheader:  Output the ucmap header
  621.  */
  622. void   outheader(FILE * f) {
  623.     char      * ucx;
  624.     ucm_hdr_t * ucmap;
  625.     char      * encn;
  626.     char      * starter;
  627.     char      * udc;
  628.     int         first, last, i;
  629.  
  630.     ucx   = (char *) TableHdr;
  631.     ucmap = (ucm_hdr_t *) TableHdr;
  632.  
  633.     /*
  634.      * Comment
  635.      */
  636.     if (Upflag)
  637.         strupr(InName);
  638.     fprintf(f, "#\n# uconvexp - %s", InName);
  639.     if (ucmap->codepage)
  640.         fprintf(f, " (%d)    %s", ucmap->codepage, ucx+84);
  641.     fprintf(f, "\n#\n");
  642.  
  643.     /*
  644.      * Codepage name
  645.      */
  646.     if (!*ucmap->name)
  647.         strncpy(ucmap->name, InName, 10);
  648.     if (Stdflag) {
  649.         fprintf(f, "<code_set_name>  \"%s\"\n", ucmap->name);
  650.     } else {
  651.         fprintf(f, "<codepage>       \"%s\"\n", ucmap->name);
  652.     }
  653.  
  654.     /*
  655.      * Description
  656.      */
  657.     if (ucmap->desc) {
  658.         if (Stdflag)
  659.             fprintf(f, "# ");
  660.         fprintf(f, "<description>    \"%s\"\n", ucx+ucmap->desc);
  661.     }
  662.  
  663.     /*
  664.      * Encoding
  665.      */
  666.     encn = encname(Attr.esid, ucmap->flags);
  667.     if (Upflag) {
  668.         encn = strdup(encn);
  669.         strupr(encn);
  670.     }
  671.     if (Stdflag)
  672.         fprintf(f, "# ");
  673.     fprintf(f, "<encoding>       \"%s\"\n", encn);
  674.     if (Stdflag) {
  675.         fprintf(f, "<uls_class>    \"%s\"\n", ClassName[CClass]);
  676.         fprintf(f, "<mb_min_len>     %d\n", Attr.mb_min_len);
  677.         fprintf(f, "<mb_max_len>     %d\n", Attr.mb_max_len);
  678.         fprintf(f, "<char_name_mask> \"AXXXX\"\n");
  679.     }
  680.  
  681.     /*
  682.      * Min and max lengths
  683.      */
  684.     if (!Stdflag) {
  685.         if (MinLen != Attr.mb_min_len ||
  686.             MaxLen != Attr.mb_max_len) {
  687.             fprintf(f, "<mb_min_len>     %d\n", Attr.mb_min_len);
  688.             fprintf(f, "<mb_max_len>     %d\n", Attr.mb_max_len);
  689.         }
  690.     }
  691.  
  692.     /*
  693.      * Copyright
  694.      */
  695.     if (ucmap->copyright) {
  696.         if (Stdflag)
  697.             fprintf(f, "# ");
  698.         fprintf(f, "<copyright>      \"%s\"\n", ucx+ucmap->copyright);
  699.     }
  700.  
  701.     /*
  702.      * Substitution character
  703.      */
  704.     if (Attr.subchar_len) {
  705.         fprintf(f, "<subchar>        ");
  706.         for (i=0; i<Attr.subchar_len; i++) {
  707.             fprintf(f, Upflag?"\\x%02X":"\\x%02x", Attr.subchar[i]);
  708.         }
  709.         fprintf(f, "\n");
  710.     }
  711.  
  712.     /*
  713.      * Substitution character
  714.      */
  715.     if (!Stdflag) {
  716.         fprintf(f, "<subcharuni>     ");
  717.         fprintf(f, Upflag?"\\x%02X\\x%02X\n":"\\x%02x\\x%02x\n",
  718.                    (Attr.subuni[0]>>8), (Attr.subuni[0]&0xff));
  719.     }
  720.  
  721.     /*
  722.      * Uconv more
  723.      */
  724.     if (ucmap->uconv_more) {
  725.         if (Stdflag)
  726.             fprintf(f, "# ");
  727.         fprintf(f, "<uconv_more>     \"%s\"\n", ucx+ucmap->uconv_more);
  728.  
  729.     }
  730.  
  731.     /*
  732.      * User defined range
  733.      */
  734.     udc = (char *) UdcRange;
  735.     while (*udc) {
  736.         if (Stdflag)
  737.             fprintf(f, "# ");
  738.         fprintf(f, "<user_defined>   ");
  739.         if (Upflag) {
  740.             fprintf(f, "\\x%02X\\x%02X...\\x%02X\\x%02X\n",
  741.                        udc[1], udc[0], udc[3], udc[2]);
  742.         } else {
  743.             fprintf(f, "\\x%02x\\x%02x...\\x%02x\\x%02x\n",
  744.                        udc[1], udc[0], udc[3], udc[2]);
  745.         }
  746.         udc += 4;
  747.     }
  748.  
  749.     /*
  750.      * DBCS starter
  751.      */
  752.     if (Attr.esid==0x3200 || Attr.esid==0x2200) {
  753.         starter = DbcsStarter;
  754.         first = 0;
  755.         for (i=0; i<=256; i++) {
  756.             if (starter[i]==2) {
  757.                 if (!first)
  758.                     first=i;
  759.             } else {
  760.                 if (first) {
  761.                     last = i-1;
  762.                     if (Stdflag)
  763.                         fprintf(f, "# ");
  764.                     fprintf(f, "<dbcs_starter>   ");
  765.                     fprintf(f, Upflag?"\\x%02X":"\\x%02x", first);
  766.                     if (first != last)
  767.                         fprintf(f, Upflag?"...\\x%02X":"...\\x%02x", last);
  768.                     fprintf(f, "\n");
  769.                     first = 0;
  770.                 }
  771.             }
  772.         }
  773.     }
  774. }
  775.  
  776.  
  777. /*
  778.  * getglyph:  Get the glyph name in IBM and Adobe styles
  779.  */
  780. int  getglyph(UniChar uni) {
  781.     NAMETAB * np;
  782.  
  783.     GlyphIBM[0] = 0;
  784.     GlyphAdobe[0] = 0;
  785.     np = Utab[uni>>8];
  786.     if (!np)
  787.         return 0;
  788.  
  789.     while (np->name) {
  790.         if (np->uni==uni) {
  791.             if (np->len==8 && np->name[2]>='0' && np->name[2]<='9') {
  792.                 strcpy(GlyphIBM, np->name);
  793.                 if (Upflag)
  794.                     strupr(GlyphIBM);
  795.                 np++;
  796.                 if (np->uni != uni)
  797.                     return 1;
  798.             }
  799.             strcpy(GlyphAdobe, np->name);
  800.             return 1;
  801.         }
  802.         np++;
  803.     }
  804.     return 0;
  805. }
  806.  
  807.  
  808. /*
  809.  * getline: Get the line a remember it for an error message
  810.  */
  811. char * getline(char * buf, FILE * f) {
  812.     char * ret;
  813.     char * cp;
  814.  
  815.     *buf = 0;
  816.     ret = fgets(buf, 255, f);
  817.  
  818.     /* Strip CR and LF from the end of the line */
  819.     cp = buf+strlen(buf)-1;
  820.     while (*cp=='\n' || *cp=='\r') {
  821.         cp--;
  822.     }
  823.     cp[1]=0;
  824.     cp[2]=0;
  825.  
  826.     strncpy(InLine, buf, 255);
  827.     return ret;
  828. }
  829.  
  830.  
  831. /*
  832.  *  getnames: Read in a name table.
  833.  *            The file is read twice, once to get the sizes, and
  834.  *            a second time to make the actual tables.
  835.  *
  836.  *  Notes:
  837.  *      The code in this section is taken from the original code within
  838.  *      makekb.  Several of the support routines came with it even though
  839.  *      they are minimally used.
  840.  */
  841. int   getnames(NAMETAB * * tab, char * name, char * * text, NAMETAB * * utab) {
  842.     FILE  * f;
  843.     int     len;
  844.     NAMETAB * np;
  845.     char  * tp;
  846.     char    line[256];
  847.     long    val;
  848.     long    entrycount;
  849.     long    stringlen;
  850.  
  851.     f = findopen(name, "r", "PATH", 1);
  852.     if (!f) return 1;
  853.  
  854.     entrycount = 0;
  855.     stringlen  = 0;
  856.  
  857.  
  858.     /*
  859.      * Process one pass to find the sizes of stuff
  860.      */
  861.     line[255]=0;
  862.     getline(line, f);
  863.     while (!feof(f) && !ferror(f)) {
  864.         if (*line!='*' && *line!=';' && *line!='#') {
  865.             val = parse(line, &Value);
  866.             nullword(Value);
  867.             if (val && val<=0xffff) {
  868.                 while (*Value && *Value!=';') {
  869.                     entrycount++;
  870.                     stringlen += (strlen(Value)+1);
  871.                     Value = nexttoken(Value);
  872.                 }
  873.             } else {
  874.                 if (val)
  875.                     printf("Bad name entry - %s\n", InLine);
  876.             }
  877.         }
  878.         getline(line, f);
  879.     }
  880.  
  881.     if (ferror(f)) {
  882.         printf("Error reading file - %s\n", name);
  883.         return 2;
  884.     }
  885.  
  886.     /*
  887.      * Allocate the tables
  888.      */
  889.     entrycount++;
  890.     stringlen += 8;
  891.     *tab  = malloc(entrycount*sizeof(NAMETAB));
  892.     *text = malloc(stringlen);
  893.     np = *tab;
  894.     tp = *text;
  895.  
  896.  
  897.     /*
  898.      * Process second pass to create the tables
  899.      */
  900.     rewind(f);
  901.     getline(line, f);
  902.     while (!feof(f) && !ferror(f)) {
  903.         val = parse(line, &Value);
  904.         nullword(Value);
  905.         if (val && val<=0xffff) {
  906.             while (*Value && *Value!=';') {
  907.                 np->name = tp;
  908.                 strcpy(tp, Value);
  909.                 len = strlen(Value);
  910.                 tp += (len+1);
  911.                 np->len = len;
  912.                 np->uni = val;
  913.                 Value = nexttoken(Value);
  914.                 if (!utab[val>>8]) {
  915.                     utab[val>>8] = np;
  916.                 }
  917.                 np++;
  918.             }
  919.         }
  920.         getline(line, f);
  921.     }
  922.     np->name = 0;
  923.     np->uni = 0;
  924.     np->len = 0;
  925.  
  926.     fclose(f);
  927.     return 0;
  928. }
  929.  
  930.  
  931. /*
  932.  *  parse:  Parse the input line
  933.  */
  934. long  parse (char * line, char * * value) {
  935.     char * cp, * kp;
  936.  
  937.     /* Strip CR and LF from the end of the line */
  938.     cp = line+strlen(line)-1;
  939.     while (*cp=='\n' || *cp=='\r') {
  940.         cp--;
  941.     }
  942.     cp[1]=0;
  943.     cp[2]=0;
  944.  
  945.     *value = line;
  946.     cp = line;
  947.  
  948.     /*
  949.      * Skip leading spaces and detect comments
  950.      */
  951.     while (*cp==' ' || *cp=='\t')
  952.         cp++;
  953.     if (*cp=='*' || *cp==';' || *cp=='#' || *cp=='/' || *cp==0 || *cp==0x1a) {
  954.         return 0;
  955.     }
  956.  
  957.     /* Find the keyword */
  958.     kp = cp;
  959.     while (*cp && *cp!=' ' && *cp!='\t' && *cp!='=') {
  960.         *cp = (char) tolower(*cp);
  961.         cp++;
  962.     }
  963.     *cp++=0;                 /* Make keyword into string */
  964.  
  965.     /* Skip blanks and = after keyword */
  966.     while (*cp==' ' || *cp=='\t') cp++;  /* Skip blanks after keyword */
  967.     if (*cp=='=') {          /* If = found, skip it and trailing blank */
  968.         cp++;
  969.         if(*cp==' ' || *cp=='\t') cp++;
  970.     }
  971.     *value = cp;
  972.  
  973.     return gethexval(kp);
  974. }
  975.  
  976.  
  977. /*
  978.  *  gethexval:  Get a hex number.  Convert a hex value with an optional
  979.  *              leading 0x.
  980.  */
  981. long gethexval(char * cp) {
  982.     long    val;
  983.     char   gotone;
  984.     char   ch;
  985.  
  986.     val = 0;
  987.     gotone = 0;
  988.     if (*cp=='0') {
  989.         cp++;
  990.         if (!*cp) return 0;
  991.         if (*cp=='x') cp++;
  992.     }
  993.     while (*cp) {
  994.         if (*cp>='0' && *cp<='9') {
  995.             ch = *cp-'0';
  996.         } else {
  997.             if (*cp>='a' && *cp<='f') {
  998.                 ch = *cp-'a'+10;
  999.             } else {
  1000.                 return NOTHEXVAL;
  1001.             }
  1002.         }
  1003.         val *= 16;
  1004.         val += ch;
  1005.         gotone = 1;
  1006.         cp++;
  1007.     }
  1008.     if (!gotone)
  1009.         return NOTHEXVAL;
  1010.     return val;
  1011. }
  1012.  
  1013.  
  1014. /*
  1015.  *  nexttoken:  Set value to the next token
  1016.  */
  1017. char * nexttoken(char * value) {
  1018.     if (!*value) return value;
  1019.     value += strlen(value);
  1020.     value++;
  1021.     while (*value==' ' || *value=='\t') value++;
  1022.     nullword(value);
  1023.     return value;
  1024. }
  1025.  
  1026.  
  1027. /*
  1028.  *  nullword:  Put a null at the end of the word
  1029.  */
  1030. void nullword(char * cptr) {
  1031.     char * cp;
  1032.  
  1033.     cp = cptr;
  1034.     while (*cp>' ') cp++;
  1035.     *cp = 0;
  1036. }
  1037.  
  1038.  
  1039. /*
  1040.  *  replaceext:  Replace extension
  1041.  */
  1042. void  replaceext(char * in, char * ext, char * out) {
  1043.     char  * cp;
  1044.  
  1045.     if (in != out)
  1046.         strcpy(out, in);
  1047.     cp = out + strlen(out) - 1;
  1048.     while (*cp!='.' && *cp!='\\' && *cp!='/' && *cp!=':') {
  1049.         if (cp==out) break;
  1050.         cp--;
  1051.     }
  1052.     if (*cp=='.') *cp=0;
  1053.     strcat(out, ext);       /* Replace extension */
  1054. }
  1055.  
  1056.  
  1057. /*
  1058.  *  findopen:  Common file open routine
  1059.  */
  1060. FILE * findopen(char * fname, char * mode, char * path, int msg) {
  1061.     FILE   * f;
  1062.  
  1063.     searchenv(fname, path, Fn);
  1064.     if (*Fn==0 && msg) {
  1065.         printf("File not found - %s\n", fname);
  1066.         return NULL;
  1067.     }
  1068.  
  1069.     f = fopen(Fn, mode);
  1070.     if (!f && msg) {
  1071.         printf("Unable to open file - %s\n", fname);
  1072.         return NULL;
  1073.     }
  1074.     return f;
  1075. }
  1076.  
  1077. #define PATHSEP '/'
  1078. /*
  1079.  * searchenv:  Search for file along paths from environment variable
  1080.  */
  1081. void  searchenv(const char *fname, const char *env_var, register char *path) {
  1082.     register char *p;
  1083.     register int c;
  1084.     char *env_p;
  1085.  
  1086.     /* Check for fully specified file name */
  1087.     if (*fname=='/' || *fname=='\\' || fname[1]==':') {
  1088.         if (access(fname, 0)==0) {
  1089.             strcpy(path, fname);
  1090.         } else {
  1091.             *path = 0;
  1092.         }
  1093.         return;
  1094.     }
  1095.  
  1096.     /* Check exists in current directory */
  1097.     if (access(fname, 0) == 0) {
  1098.         getcwd(path, 256);
  1099.         p = path + strlen(path);
  1100.         if (((c = *(p - 1)) != '/') && (c != '\\') && (c != ':')) {
  1101.             *p++ = PATHSEP;
  1102.             *p = 0;
  1103.         }
  1104.         strcat(path, fname);
  1105.         return;
  1106.     }
  1107.  
  1108.     /* Get environment variable.  Return if it does not exist */
  1109.     env_p = getenv(env_var);
  1110.     if (!env_p || !*env_p) {
  1111.         *path = 0;
  1112.         return;
  1113.     }
  1114.  
  1115.     /* Loop thru all paths in the environment variable */
  1116.     env_p = getpath(env_p, path);
  1117.     while (env_p && *path) {
  1118.         p = path + strlen(path);
  1119.         if (((c = *(p - 1)) != '/') && (c != '\\') && (c != ':')) {
  1120.             *p++ = PATHSEP;
  1121.         }
  1122.         strcpy(p, fname);
  1123.         if (access(path, 0) == 0)
  1124.             return;
  1125.         strcpy(p, "codepage/");
  1126.         strcpy(p+9, fname);
  1127.         if (access(path, 0) == 0)
  1128.             return;
  1129.         env_p = getpath(env_p, path);
  1130.     }
  1131.  
  1132.     /* File not found, return an empty string */
  1133.     *path = 0;
  1134. }
  1135.  
  1136.  
  1137. /*
  1138.  *  getpath:  Extract a pathname from a semicolon-delimited list of pathnames
  1139.  */
  1140. char * getpath(register char *src, register char *dst) {
  1141.     const char *keepsrc;
  1142.  
  1143.     keepsrc = src;
  1144.     while (*src && *src != ';') {
  1145.         if (*src != '"') {        /* Process quoted path */
  1146.             *dst++ = *src++;
  1147.         } else {
  1148.             src++;                /* skip over opening quote */
  1149.             while (*src && (*src != '"')) {
  1150.                 *dst++ = *src++;
  1151.             }
  1152.             if (*src) src++;      /* skip over closing quote */
  1153.         }
  1154.     }
  1155.  
  1156.     while ( *src == ';' )  src++;
  1157.     *dst = 0;
  1158.     return((keepsrc != src) ? src : NULL);
  1159. }
  1160.  
  1161.  
  1162. /*
  1163.  * touni: Make unicode string the simple way.
  1164.  *        We know the name string is limited to ASCII-7 characters.
  1165.  */
  1166. void touni(UniChar * ustr, char * str) {
  1167.     while (*str) {
  1168.         *ustr++ = *str++;
  1169.     }
  1170.     *ustr = 0;
  1171. }
  1172.