www.sas.com > Service and Support > Technical Support
 
Technical Support SAS - The power to know(tm)
  TS Home | Intro to Services | News and Info | Contact TS | Site Map | FAQ | Feedback


#pragma title l$cldbex -- SAS/C double byte locale example
/*--------------------------------------------------------------------+
|                                                                     |
|              Copyright 1996 (c), SAS Institute Inc.                 |
|                Unpublished - All Rights Reserved                    |
|                                                                     |
|                     S A S / C  S A M P L E                          |
|                                                                     |
|       Name: L$CLDEBX                                                |
|                                                                     |
|   Language: C                                                       |
|                                                                     |
| EntryPoint: @DYNAMN                                                 |
|                                                                     |
| EntryType : C Linkage, reentrant                                    |
|                                                                     |
| Files Note: 'prefix' is the installation defined high level         |
|             qualifier for the SAS/C product.                        |
|                                                                     |
|    Purpose: Provide sample SAS/C DBCS user-added locale module.     |
|                                                                     |
| MVS -                                                               |
|                                                                     |
|     Source: prefix.SAMPLE.C(L$CLDBEX)                               |
|                                                                     |
|  Comp/Link: Use proc LC370CL, with parameter RENT and ENTRY=DYN.    |
|             Output module should placed in a library that can be    |
|             located by loadm() at execution time.                   |
|                                                                     |
|    Execute: via setlocale() function                                |
|                                                                     |
| CMS -                                                               |
|                                                                     |
|     Source: SAMPLC   MACLIB (L$CLSAMP)                              |
|                                                                     |
|       Note: The following compile/link are used for executing the   |
|             module as a nucelus extension.                          |
|                                                                     |
|    Compile:                                                         |
|             global maclig lc370                                     |
|             lc370 l$cldbex ( rent sname l$cldbe                     |
|                                                                     |
|       Link:                                                         |
|             clink l$cldbex                                          |
|             load clink370 ( rldsave                                 |
|             genmode l$cldbex                                        |
|                                                                     |
|    Execute: via setlocale() function                                |
|      Notes:                                                         |
|                                                                     |
|   This is an example DBCS locale value module table to support      |
|   DBCS environment.  It can be used via setlocale(LC_CTYPE,"DBEX"), |
|   (or setlocale(LC_ALL,"DBEX") to allow recognition and processing  |
|   of double byte strings by other library routines and provides     |
|   sample DBCS strxfrm() and strcoll() functions for DBCS support    |
|   which are loaded via setlocale(LC_COLLATE,"DBEX") or              |
|   setlocale(LC_ALL,"DBEX") and are invoked when the strcoll/strxfrm |
|   functions are called thereafter.                                  |
|                                                                     |
|   This sample is provided for locales that need to either modify    |
|   the DBCS collation sequence, or supply their own strxfrm and      |
|   strcoll functions.  See dbexxfrm and dbexcoll documentation below.|
|                                                                     |
|   The library functions strcoll and strxfrm provide limited builtin |
|   DBCS support: shift_out, shift_in sequence, and end-of-string     |
|   recognition, and limited DBCS character range and string          |
|   validation.  The library versions can be invoked through          |
|   setlocale(LC_COLLATE,"DBCS");                                     |
|                                                                     |
|                                                                     |
+--------------------------------------------------------------------*/

#include <stddef.h<
#include <locale.h<
#include <localeu.h<
#include <dynam.h<
#include <stdlib.h<
#include <errno.h<
#include <stdio.h<
#include <string.h<

#define SHIFT_OUT '\x0E'                /* SHIFT_OUT to DBCS mode  */
#define SHIFT_IN  '\x0F'                /* SHIFT_IN from DBCS mode */
#define DBCS_BLANK "  "                 /* Double byte blank       */
#define DBCS_COLLATE_LOW  "\x42\x41"    /* Lowest dbc in table     */
#define DBCS_COLLATE_HIGH "\x42\xfe"    /* Highest dbc in table    */

#eject

static const struct dbex_collate_table_entry {
    unsigned short int dbex_hex_value;   /* hex value of the dbcs char*/
    unsigned short int dbex_collate_pos; /* Relative position of the
                                            char in collating sequence.
                                            Can be, but not necessarily
                                            the same as the hex value
                                                                      */
    }   dbex_collate_table  []  = {
    /*                                                                */
    /*  dbex_hex entries 0x0000-0x00ff represent the equivalent       */
    /*  single byte ebcidic characters with values 00-ff              */
    /*                                                                */
        {0x0000, 0x0000}, {0x0001, 0x4001},   /* 0000-000f <=> 00-0f  */
        {0x0002, 0x4002}, {0x0003, 0x4003},
        {0x0004, 0x4004}, {0x0005, 0x4005},
        {0x0006, 0x4006}, {0x0007, 0x4007},
        {0x0008, 0x4008}, {0x0009, 0x4009},
        {0x000a, 0x400a}, {0x000b, 0x400b},
        {0x000c, 0x400c}, {0x000d, 0x400d},
        {0x000e, 0x400e}, {0x000f, 0x400f},

        {0x0010, 0x4010}, {0x0011, 0x4011},   /* 0010-001f <=> 10-1f  */
        {0x0012, 0x4012}, {0x0013, 0x4013},
        {0x0014, 0x4014}, {0x0015, 0x4015},
        {0x0016, 0x4016}, {0x0017, 0x4017},
        {0x0018, 0x4018}, {0x0019, 0x4019},
        {0x001a, 0x401a}, {0x001b, 0x401b},
        {0x001c, 0x401c}, {0x001d, 0x401d},
        {0x001e, 0x401e}, {0x001f, 0x401f},

        {0x0020, 0x4020}, {0x0021, 0x4021},   /* 0020-002f <=> 20-2f  */
        {0x0022, 0x4022}, {0x0023, 0x4023},
        {0x0024, 0x4024}, {0x0025, 0x4025},
        {0x0026, 0x4026}, {0x0027, 0x4027},
        {0x0028, 0x4028}, {0x0029, 0x4029},
        {0x002a, 0x402a}, {0x002b, 0x402b},
        {0x002c, 0x402c}, {0x002d, 0x402d},
        {0x002e, 0x402e}, {0x002f, 0x402f},

        {0x0030, 0x4030}, {0x0031, 0x4031},   /* 0030-003f <=> 30-3f  */
        {0x0032, 0x4032}, {0x0033, 0x4033},
        {0x0034, 0x4034}, {0x0035, 0x4035},
        {0x0036, 0x4036}, {0x0037, 0x4037},
        {0x0038, 0x4038}, {0x0039, 0x4039},
        {0x003a, 0x403a}, {0x003b, 0x403b},
        {0x003c, 0x403c}, {0x003d, 0x403d},
        {0x003e, 0x403e}, {0x003f, 0x403f},

        {0x0040, 0x4040}, {0x0041, 0x4041},   /* 0040-004f <=> 40-4f  */
        {0x0042, 0x4042}, {0x0043, 0x4043},
        {0x0044, 0x4044}, {0x0045, 0x4045},
        {0x0046, 0x4046}, {0x0047, 0x4047},
        {0x0048, 0x4048}, {0x0049, 0x4049},
        {0x004a, 0x404a}, {0x004b, 0x404b},
        {0x004c, 0x404c}, {0x004d, 0x404d},
        {0x004e, 0x404e}, {0x004f, 0x404f},

        {0x0050, 0x4050}, {0x0051, 0x4051},   /* 0050-005f <=>> 50-5f  */
        {0x0052, 0x4052}, {0x0053, 0x4053},
        {0x0054, 0x4054}, {0x0055, 0x4055},
        {0x0056, 0x4056}, {0x0057, 0x4057},
        {0x0058, 0x4058}, {0x0059, 0x4059},
        {0x005a, 0x405a}, {0x005b, 0x405b},
        {0x005c, 0x405c}, {0x005d, 0x405d},
        {0x005e, 0x405e}, {0x005f, 0x405f},

        {0x0060, 0x4060}, {0x0061, 0x4061},   /* 0060-006f <=> 60-6f  */
        {0x0062, 0x4062}, {0x0063, 0x4063},
        {0x0064, 0x4064}, {0x0065, 0x4065},
        {0x0066, 0x4066}, {0x0067, 0x4067},
        {0x0068, 0x4068}, {0x0069, 0x4069},
        {0x006a, 0x406a}, {0x006b, 0x406b},
        {0x006c, 0x406c}, {0x006d, 0x406d},
        {0x006e, 0x406e}, {0x006f, 0x406f},

        {0x0070, 0x4070}, {0x0071, 0x4071},   /* 0070-007f <=> 70-7f  */
        {0x0072, 0x4072}, {0x0073, 0x4073},
        {0x0074, 0x4074}, {0x0075, 0x4075},
        {0x0076, 0x4076}, {0x0077, 0x4077},
        {0x0078, 0x4078}, {0x0079, 0x4079},
        {0x007a, 0x407a}, {0x007b, 0x407b},
        {0x007c, 0x407c}, {0x007d, 0x407d},
        {0x007e, 0x407e}, {0x007f, 0x407f},

        {0x0080, 0x4080}, {0x0081, 0x4081},   /* 0080-008f <=> 80-8f  */
        {0x0082, 0x4082}, {0x0083, 0x4083},
        {0x0084, 0x4084}, {0x0085, 0x4085},
        {0x0086, 0x4086}, {0x0087, 0x4087},
        {0x0088, 0x4088}, {0x0089, 0x4089},
        {0x008a, 0x408a}, {0x008b, 0x408b},
        {0x008c, 0x408c}, {0x008d, 0x408d},
        {0x008e, 0x408e}, {0x008f, 0x408f},

        {0x0090, 0x4090}, {0x0091, 0x4091},   /* 0090-009f <=> 90-9f  */
        {0x0092, 0x4092}, {0x0093, 0x4093},
        {0x0094, 0x4094}, {0x0095, 0x4095},
        {0x0096, 0x4096}, {0x0097, 0x4097},
        {0x0098, 0x4098}, {0x0099, 0x4099},
        {0x009a, 0x409a}, {0x009b, 0x409b},
        {0x009c, 0x409c}, {0x009d, 0x409d},
        {0x009e, 0x409e}, {0x009f, 0x409f},

        {0x00a0, 0x40a0}, {0x00a1, 0x40a1},   /* 00a0-00af <=> a0-af  */
        {0x00a2, 0x40a2}, {0x00a3, 0x40a3},
        {0x00a4, 0x40a4}, {0x00a5, 0x40a5},
        {0x00a6, 0x40a6}, {0x00a7, 0x40a7},
        {0x00a8, 0x40a8}, {0x00a9, 0x40a9},
        {0x00aa, 0x40aa}, {0x00ab, 0x40ab},
        {0x00ac, 0x40ac}, {0x00ad, 0x40ad},
        {0x00ae, 0x40ae}, {0x00af, 0x40af},

        {0x00b0, 0x40b0}, {0x00b1, 0x40b1},   /* 00b0-00bf <=> b0-bf  */
        {0x00b2, 0x40b2}, {0x00b3, 0x40b3},
        {0x00b4, 0x40b4}, {0x00b5, 0x40b5},
        {0x00b6, 0x40b6}, {0x00b7, 0x40b7},
        {0x00b8, 0x40b8}, {0x00b9, 0x40b9},
        {0x00ba, 0x40ba}, {0x00bb, 0x40bb},
        {0x00bc, 0x40bc}, {0x00bd, 0x40bd},
        {0x00be, 0x40be}, {0x00bf, 0x40bf},

        {0x00c0, 0x40c0}, {0x00c1, 0x40c1},   /* 00c0-00cf <=> c0-cf  */
        {0x00c2, 0x40c2}, {0x00c3, 0x40c3},
        {0x00c4, 0x40c4}, {0x00c5, 0x40c5},
        {0x00c6, 0x40c6}, {0x00c7, 0x40c7},
        {0x00c8, 0x40c8}, {0x00c9, 0x40c9},
        {0x00ca, 0x40ca}, {0x00cb, 0x40cb},
        {0x00cc, 0x40cc}, {0x00cd, 0x40cd},
        {0x00ce, 0x40ce}, {0x00cf, 0x40cf},

        {0x00d0, 0x40d0}, {0x00d1, 0x40d1},   /* 00d0-00df <=> d0-df  */
        {0x00d2, 0x40d2}, {0x00d3, 0x40d3},
        {0x00d4, 0x40d4}, {0x00d5, 0x40d5},
        {0x00d6, 0x40d6}, {0x00d7, 0x40d7},
        {0x00d8, 0x40d8}, {0x00d9, 0x40d9},
        {0x00da, 0x40da}, {0x00db, 0x40db},
        {0x00dc, 0x40dc}, {0x00dd, 0x40dd},
        {0x00de, 0x40de}, {0x00df, 0x40df},

        {0x00e0, 0x40e0}, {0x00e1, 0x40e1},   /* 00e0-00ef <=> e0-ef  */
        {0x00e2, 0x40e2}, {0x00e3, 0x40e3},
        {0x00e4, 0x40e4}, {0x00e5, 0x40e5},
        {0x00e6, 0x40e6}, {0x00e7, 0x40e7},
        {0x00e8, 0x40e8}, {0x00e9, 0x40e9},
        {0x00ea, 0x40ea}, {0x00eb, 0x40eb},
        {0x00ec, 0x40ec}, {0x00ed, 0x40ed},
        {0x00ee, 0x40ee}, {0x00ef, 0x40ef},

        {0x00f0, 0x40f0}, {0x00f1, 0x40f1},   /* 00f0-00ff <=> f0-ff  */
        {0x00f2, 0x40f2}, {0x00f3, 0x40f3},
        {0x00f4, 0x40f4}, {0x00f5, 0x40f5},
        {0x00f6, 0x40f6}, {0x00f7, 0x40f7},
        {0x00f8, 0x40f8}, {0x00f9, 0x40f9},
        {0x00fa, 0x40fa}, {0x00fb, 0x40fb},
        {0x00fc, 0x40fc}, {0x00fd, 0x40fd},
        {0x00fe, 0x40fe}, {0x00ff, 0x40ff},


    /*  dbex_hex entries 0x4241-0x42fe are the double byte            */
    /*  representation of the alpahnumeric and special symbols        */
    /*  corresponding to their single byte representations            */
    /*                                                                */
        {0x4040, 0x4040},   /* element (256)     double byte blank    */

                          {0x4241, 0x4241},   /* 4241-424f <=> 41-4f  */
        {0x4242, 0x4242}, {0x4243, 0x4243},
        {0x4244, 0x4244}, {0x4245, 0x4245},
        {0x4246, 0x4246}, {0x4247, 0x4247},
        {0x4248, 0x4248}, {0x4249, 0x4249},
        {0x424a, 0x424a}, {0x424b, 0x424b},
        {0x424c, 0x424c}, {0x424d, 0x424d},
        {0x424e, 0x424e}, {0x424f, 0x424f},

        {0x4250, 0x4250}, {0x4251, 0x4251},   /* 4250-425f <=> 50-5f  */
        {0x4252, 0x4252}, {0x4253, 0x4253},
        {0x4254, 0x4254}, {0x4255, 0x4255},
        {0x4256, 0x4256}, {0x4257, 0x4257},
        {0x4258, 0x4258}, {0x4259, 0x4259},
        {0x425a, 0x425a}, {0x425b, 0x425b},
        {0x425c, 0x425c}, {0x425d, 0x425d},
        {0x425e, 0x425e}, {0x425f, 0x425f},

        {0x4260, 0x4260}, {0x4261, 0x4261},   /* 4260-426f <=> 60-6f  */
        {0x4262, 0x4262}, {0x4263, 0x4263},
        {0x4264, 0x4264}, {0x4265, 0x4265},
        {0x4266, 0x4266}, {0x4267, 0x4267},
        {0x4268, 0x4268}, {0x4269, 0x4269},
        {0x426a, 0x426a}, {0x426b, 0x426b},
        {0x426c, 0x426c}, {0x426d, 0x426d},
        {0x426e, 0x426e}, {0x426f, 0x426f},

        {0x4270, 0x4270}, {0x4271, 0x4271},   /* 4260-427f <=> 70-7f  */
        {0x4272, 0x4272}, {0x4273, 0x4273},
        {0x4274, 0x4274}, {0x4275, 0x4275},
        {0x4276, 0x4276}, {0x4277, 0x4277},
        {0x4278, 0x4278}, {0x4279, 0x4279},
        {0x427a, 0x427a}, {0x427b, 0x427b},
        {0x427c, 0x427c}, {0x427d, 0x427d},
        {0x427e, 0x427e}, {0x427f, 0x427f},

        {0x4280, 0x4280}, {0x4281, 0x4281},   /* 4280-428f <=> 80-8f  */
        {0x4282, 0x4282}, {0x4283, 0x4283},
        {0x4284, 0x4284}, {0x4285, 0x4285},
        {0x4286, 0x4286}, {0x4287, 0x4287},
        {0x4288, 0x4288}, {0x4289, 0x4289},
        {0x428a, 0x428a}, {0x428b, 0x428b},
        {0x428c, 0x428c}, {0x428d, 0x428d},
        {0x428e, 0x428e}, {0x428f, 0x428f},

        {0x4290, 0x4290}, {0x4291, 0x4291},   /* 4290-429f <=> 90-9f  */
        {0x4292, 0x4292}, {0x4293, 0x4293},
        {0x4294, 0x4294}, {0x4295, 0x4295},
        {0x4296, 0x4296}, {0x4297, 0x4297},
        {0x4298, 0x4298}, {0x4299, 0x4299},
        {0x429a, 0x429a}, {0x429b, 0x429b},
        {0x429c, 0x429c}, {0x429d, 0x429d},
        {0x429e, 0x429e}, {0x429f, 0x429f},

        {0x42a0, 0x42a0}, {0x42a1, 0x42a1},   /* 42a0-42af <=> a0-af  */
        {0x42a2, 0x42a2}, {0x42a3, 0x42a3},
        {0x42a4, 0x42a4}, {0x42a5, 0x42a5},
        {0x42a6, 0x42a6}, {0x42a7, 0x42a7},
        {0x42a8, 0x42a8}, {0x42a9, 0x42a9},
        {0x42aa, 0x42aa}, {0x42ab, 0x42ab},
        {0x42ac, 0x42ac}, {0x42ad, 0x42ad},
        {0x42ae, 0x42ae}, {0x42af, 0x42af},

        {0x42b0, 0x42b0}, {0x42b1, 0x42b1},   /* 42b0-42bf <=> b0-bf  */
        {0x42b2, 0x42b2}, {0x42b3, 0x42b3},
        {0x42b4, 0x42b4}, {0x42b5, 0x42b5},
        {0x42b6, 0x42b6}, {0x42b7, 0x42b7},
        {0x42b8, 0x42b8}, {0x42b9, 0x42b9},
        {0x42ba, 0x42ba}, {0x42bb, 0x42bb},
        {0x42bc, 0x42bc}, {0x42bd, 0x42bd},
        {0x42be, 0x42be}, {0x42bf, 0x42bf},

        {0x42c0, 0x42c0}, {0x42c1, 0x42c1},   /* 42c0-42cf <=> c0-cf  */
        {0x42c2, 0x42c2}, {0x42c3, 0x42c3},
        {0x42c4, 0x42c4}, {0x42c5, 0x42c5},
        {0x42c6, 0x42c6}, {0x42c7, 0x42c7},
        {0x42c8, 0x42c8}, {0x42c9, 0x42c9},
        {0x42ca, 0x42ca}, {0x42cb, 0x42cb},
        {0x42cc, 0x42cc}, {0x42cd, 0x42cd},
        {0x42ce, 0x42ce}, {0x42cf, 0x42cf},

        {0x42d0, 0x42d0}, {0x42d1, 0x42d1},   /* 42d0-42df <=> d0-df  */
        {0x42d2, 0x42d2}, {0x42d3, 0x42d3},
        {0x42d4, 0x42d4}, {0x42d5, 0x42d5},
        {0x42d6, 0x42d6}, {0x42d7, 0x42d7},
        {0x42d8, 0x42d8}, {0x42d9, 0x42d9},
        {0x42da, 0x42da}, {0x42db, 0x42db},
        {0x42dc, 0x42dc}, {0x42dd, 0x42dd},
        {0x42de, 0x42de}, {0x42df, 0x42df},

        {0x42e0, 0x42e0}, {0x42e1, 0x42e1},   /* 42e0-42ef <=> e0-ef  */
        {0x42e2, 0x42e2}, {0x42e3, 0x42e3},
        {0x42e4, 0x42e4}, {0x42e5, 0x42e5},
        {0x42e6, 0x42e6}, {0x42e7, 0x42e7},
        {0x42e8, 0x42e8}, {0x42e9, 0x42e9},
        {0x42ea, 0x42ea}, {0x42eb, 0x42eb},
        {0x42ec, 0x42ec}, {0x42ed, 0x42ed},
        {0x42ee, 0x42ee}, {0x42ef, 0x42ef},

        {0x42f0, 0x42f0}, {0x42f1, 0x42f1},   /* 42f0-42ff <=> f0-ff  */
        {0x42f2, 0x42f2}, {0x42f3, 0x42f3},
        {0x42f4, 0x42f4}, {0x42f5, 0x42f5},
        {0x42f6, 0x42f6}, {0x42f7, 0x42f7},
        {0x42f8, 0x42f8}, {0x42f9, 0x42f9},
        {0x42fa, 0x42fa}, {0x42fb, 0x42fb},
        {0x42fc, 0x42fc}, {0x42fd, 0x42fd},
        {0x42fe, 0x42fe}
        };

#eject
#title l$cldbex -- dbexfrm  - sample DBCS locale transform function

size_t dbexfrm(char *s1, const char *s2, size_t n, size_t *used)
{
/*-------------------------------------------------------------------
 * ENTRY:      <=== dbcexfrm
 *
 * USAGE:      <=== Prototype call:
 *
 * size_t dbexfrm(char *s1, const char *s2, size_t n, size_t *used);
 *
 *  nchar_xfrm = dbcexfrm(s1,s2,n,&used)
 *
 *
 * ARGUMENTS:  <===
 *
 *    -ARG-    -DCL--------- -DESCRIPTION-
 *
 *    s1       char  *       pointer to the transformed string
 *                           output array.
 *
 *    s2       const char *  pointer to input string array
 *
 *    n        size_t        max number of bytes (chars) to written
 *                           to s1 including terminating null. If n or
 *                           more chars are required for the
 *                           transformed string, only the first n
 *                           are written and the string is not null
 *                           terminated.
 *
 *    used     size_t *      pointer to size_t (unsigned int) value
 *                           where the number of input characters
 *                           consumed from the input string s2 is
 *                           returned.
 *
 *
 * RETURNS:    <=== The number of characters placed in the output
 *                  transformation arrary is returned.
 *
 *                  Also the number of characters consumed(scanned)
 *                  from the input string s2 is returned in size_t
 *                  int pointed to by *used.
 *
 *                  ******This return is different from the*********
 *                  ******ANSI strxfrm function.           *********
 *
 *                  The total number of characters required for the
 *                  dbcs transformation is obtained by a special call:
 *
 *                  total_dbcsxfrm_len = dbexfrm(0,s2,0,&used)
 *
 *
 *
 * NOTES:      <=== The arguments to dbexfrm and return values have
 *                  similiarities with the ANSI function strxfrm,
 *                  but note the difference that the number of chars
 *                  returned is the number xfrmed and placed in the
 *                  buffer not the total length of the xfrmed string.
 *                  Also the additional 4th paramter is required to
 *                  pass back the number of chars consumed from the
 *                  input string.  This different functionality
 *                  required for a locale that requires its own
 *                  strxfrm function to be loaded via setlocale and
 *                  invoked by the strxfrm function.
 *
 *                  The purpose of this function is to transform a
 *                  valid mixed DBCS character string.  into a string
 *                  such that strcmp can be used correctly to compare
 *                  two such transformed strings byte for byte so that
 *                  the strings can  be collated correctly according
 *                  to the rules for mixed mode DBCS strings.  Minimal
 *                  validation is done to to check that the DBCS chars
 *                  are in the proper range (x'4040', x'4241-x'42fe')
 *                  and that shift-in shift-out sequences are proper.
 *                  However,  dbexfrm merely copies the invalid
 *                  chars to the output string or null terminates it
 *                  for shift_in errors.  Also, this example uses
 *                  a DBCS collation table so that if the values
 *                  for the output side of the collation table were
 *                  edited, the collation order would change.
 *
 *
 * END
 *-------------------------------------------------------------------*/

size_t s2len,                              /* input string length   */
       cmode,                              /* DBCS or SBCS mode     */
       nchar,                              /* # char in output buff */
       tix;                                /* collation table index */

char *s2ptr,                               /* input string pointer  */
      errbuf [16] ;                        /* error message buffer  */

*used = nchar = cmode = 0;

s2ptr = (char *) s2;                       /* set input string ptr  */
s2len = strlen(s2ptr);                     /* and length            */

while ((*used = s2ptr - s2) < s2len) {     /* do until end of string*/

  if (cmode) {
     if (*(s2ptr) == SHIFT_IN) {           /* check for SHIFT_IN    */
        cmode = 0;                         /* reset dbcs mode if so */
        s2ptr++;
        continue;                          /* and continue          */
        }

     if (!(memcmp(s2ptr,DBCS_BLANK,2))){   /* check for a db blank   */
        if (nchar+2 <= n)                  /* if enough room         */
           memcpy(s1+nchar,                /* copy table entry       */
         &(dbex_collate_table [256] .dbex_collate_pos),
           2);
        else if (n) return nchar;          /* return #xfrmed so far  */
        nchar += 2;
        s2ptr += 2;
        continue;
        }
                                              /* validate char       */
     if ((memcmp(s2ptr,DBCS_COLLATE_LOW,2) >= 0)
        && (memcmp(s2ptr,DBCS_COLLATE_HIGH,2) <= 0))         {


 /*-------------------------------------------------------------------+
  *                                                                   *
  * If the table values were not semi-contigous it is possible to do  *
  * a search with the input dbcs char as the key against the          *
  * hex values in the collate table, however this is less efficient   *
  * than indexing directly into the collate table with some value     *
  * range checking and index maninipulation if possible.              *
  *                                                                   *
  +-------------------------------------------------------------------*/

 /* copy correct collating position for db char to *s1 string from    */
 /* the collate table entry                                           */

        if (nchar+2 <= n) {                /* make sure enough room   */
           tix = 256 + ((size_t) *(s2ptr+1) - 64); /* collate tbl indx*/
           memcpy(s1+nchar,
                 &(dbex_collate_table [ tix ] .dbex_collate_pos),
                 2);
           }
        else if (n) return nchar;          /* return # xfrmed so far  */

        nchar += 2;
        s2ptr += 2;
        continue;
        }

     else {   /* char not in collate table, issue msg but copy it    */

        sprintf(errbuf,"...0x%02X%02X",*s2ptr,*(s2ptr+1));
        fprintf(stderr,"Invalid DBCS string, =<%s>=",errbuf);

        if (nchar+2 <= n)                  /* make sure enough room  */
           memcpy(s1+nchar,s2ptr,2);
        else if (n) return nchar;          /* return # xfrmed so far */

        nchar += 2;
        s2ptr += 2;
        continue;
        }

     } /* end if (cmode) ... = dbcs mode */


  else { /* single byte character mode                             */

     if (*(s2ptr) == SHIFT_OUT) {          /* check for SHIFT_OUT   */
        cmode = DBCS;                      /* set DBCS mode on if so*/
        s2ptr++;                           /* dont include char     */
        continue;                          /* and continue          */
        }

        /*----------------------------------------------------------+
         * expand a single byte char to pseudo db char for collation*
         * purposes so that the sb char collates ahead of the       *
         * equivalent db char e.g. 'A' < double byte A              *
         * transform 0XC1 -> 0x40C1 < 0x42C1                        *
         +----------------------------------------------------------*/

     if (nchar+2 <= n) {               /* make sure enough room     */
        *(s1+nchar) = ' ';             /* insert blank              */
        *(s1+nchar+1) = *(s2ptr);      /* copy char                 */
        }
     else if (n) return nchar;         /* return number xfrm so far */
     s2ptr++;
     nchar += 2;

     }   /* end if (cmode) ... else    */

  }  /* end while (*used = (2ptr < s2+strlen(s2)))   */

if (cmode)                             /* should not be in dbcs mode  */
    fprintf(stderr,"Missing SHIFT_IN (0x0f) from DBCS mode");

if (nchar+1 <= n)                      /* null terminate if room      */
   *(s1+nchar) = '\0';

return nchar;                          /* return #chars in xfrm string*/
}


#eject
#title l$cldbex -- dbexcoll - sample DBCS locale collation function

int dbexcoll(const char *s1, const char *s2)
{

/*-------------------------------------------------------------------
 * ENTRY:      <=== dbexcoll  name (externally visible)
 *
 * USAGE:      <=== Prototype call:
 *
 *  int dbexcoll(const char *s1, const char *s2);
 *
 *  compare_result  =  dbexcoll(s1,s2);
 *
 *
 * ARGUMENTS:  <===
 *
 *    -ARG-    -DCL--------- -DESCRIPTION-
 *
 *    s1       const *s1     pointer to the first string to be
 *                           compared.
 *    s2       const *s2     pointer to the 2nd   string to be
 *                           compared.
 *
 *
 * RETURNS:    <=== 0 if the locale dependent transformation
 *                    of strings s1 and s2 are equal.
 *                  + a positive value (+)
 *                    if transformed(s1) > transformed(s2)
 *                  - a negative value (-)
 *                    if transformed(s1) > transformed(s2)
 *
 *
 * NOTES:      <=== The 2 strings are first tranformed by invoking:
 *
 *                   After the two strings are transformed or
 *                   partially transformed, the equivalent of a
 *                   strcmp is done to compare transformed s1 and
 *                   s2.
 *
 *
 * END
 *-------------------------------------------------------------------*/



int compare_result;                     /* compare result return     */
int rem1, rem2;                         /* uncompared xfrmed chars   */
                                        /* remaining in xfrm buffers */
size_t s1len, s2len, s1xlen, s2xlen;    /* input and xfrmed lengths  */
size_t used1, used2;                    /* number of chars used      */
                                        /* from input strings        */

#define BF_LIM 256                      /* length of xfrm buffers    */
char   tx1wk [BF_LIM] ,                 /* xfrm output buffers       */
       tx2wk [BF_LIM] ;
char   *txfm1, *txfm2;                  /* xfrm buffer pointers      */

/*-------------------------------------------------------------------*/



s1len = strlen((char *) s1);            /* obtain lengths            */
s2len = strlen((char *) s2);
txfm1 = tx1wk;                          /* point to transform        */
txfm2 = tx2wk;                          /* work areas                */

rem1 = rem2 = 0;                        /* zero xfrm uncompared rem. */

while (s1len  && s2len ) {              /* loop while chars remain   */
                                        /* un xfrmed in both strings */

   used1 = used2 = 0;

   if (!rem1)
      s1xlen = dbexfrm(txfm1+rem1,s1,BF_LIM-rem1,&used1);
   if (!rem2)
      s2xlen = dbexfrm(txfm2+rem2,s2,BF_LIM-rem2,&used2);

   if ((rem1 = s1xlen - s2xlen) > 0 ) {
      compare_result = memcmp(txfm1,txfm2,s2xlen);
      memmove(txfm1,txfm1+(BF_LIM-rem1),rem1);
      }
   else {
      compare_result=memcmp(txfm1,txfm2,s1xlen);
      rem2 = -rem1;
      rem1 = 0;
      if (rem2) memmove(txfm2,txfm2+(BF_LIM-rem2),rem2);
      }

   if (compare_result>0) return +1;
   if (compare_result<0) return -1;

   s1 += used1;
   s2 += used2;
   s1len -= used1;
   s2len -= used2;
   }   /* end while */

if (!s1len && !s2len) return 0;
if (s1len) return +1;
else return -1;
}

#eject
#title l$cldbex -- "C" double byte locale example

static const struct _lc_collate dbex_collate = {
      DBCS,                            /* double byte collation      */
      &dbex_collate_table,             /* pointer to collate table   */
      &dbexcoll,                       /* ptr to strcoll fnc  equiv  */
      &dbexfrm};                       /* ptr to strxfrm fnc  equiv  */

static const struct _lc_ctype dbex_ctype = {
      DBCS,                            /* double byte strings honored*/
      0};                              /* ptr to CTYPE table (NULL)  */

static const void *dbex_all [5]         = {
    &dbex_collate,                     /* collate pointer            */
    &dbex_ctype,                       /* ctype pointer              */
    0,                                 /* monetary pointer (NULL)    */
    0,                                 /* numeric pointer  (NULL)    */
    0                                  /* time format pointer (NULL) */
    };

void *_dynamn() /* l$cldbex */
{
return (void *) &dbex_all;
}


Copyright (c) 2000 SAS Institute Inc. All Rights Reserved.
Terms of Use & Legal Information | Privacy Statement