#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 #include #include #include #include #include #include #include #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; }