home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / libi18n / csstrlen.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  13.7 KB  |  512 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*    csstrlen.c    */
  19. /*
  20.     Routines that tell you information about one csid
  21. */
  22. #include "intlpriv.h"
  23.  
  24. /*    csinfoindex and csinfo_tbl work together for performance inprovement. 
  25.     Whenever you add an entry inside csinfo_tbl, you also need to change
  26.     csinfoindex
  27. */
  28. #define MAX_FIRSTBYTE_RANGE  3
  29. typedef struct {
  30.     struct {
  31.         unsigned char bytes;       /* number of bytes for range */
  32.         unsigned char columns;     /* number of columns for range */
  33.         unsigned char range[2];    /* Multibyte first byte range */
  34.     } enc[MAX_FIRSTBYTE_RANGE];
  35. } csinfo_t;
  36.  
  37. PRIVATE csinfo_t csinfo_tbl[] =
  38. {
  39. /* b = bytes; c = columns                                               */
  40. /*                b c  range 1       b c  range 2       b c  range 3     */
  41.     /*  0 */ {{{2,2,{0x81,0x9f}}, {2,2,{0xe0,0xfc}}, {0,0,{0x00,0x00}}}},    /* For SJIS */
  42.     /*  1 */ {{{2,2,{0xa1,0xfe}}, {2,1,{0x8e,0x8e}}, {3,2,{0x8f,0x8f}}}},    /* For EUC_JP */
  43.     /*  2 */ {{{2,2,{0xa1,0xfe}}, {0,0,{0x00,0x00}}, {0,0,{0x00,0x00}}}},    /* For BIG5 GB KSC */
  44.     /*  3 */ {{{2,2,{0xa1,0xfe}}, {4,2,{0x8e,0x8e}}, {0,0,{0x00,0x00}}}},    /* For CNS_8BIT */
  45.     /*  4 */ {{{2,2,{0x21,0x7e}}, {0,0,{0x00,0x00}}, {0,0,{0x00,0x00}}}},    /* For 2 Byte GL */
  46.     /*  5 */ {{{2,2,{0xC0,0xDF}}, {3,2,{0xE0,0xEF}}, {0,0,{0x00,0x00}}}},    /* For UTF8 */
  47.     /*  0 */ {{{0,0,{0x00,0x00}}, {0,0,{0x00,0x00}}, {0,0,{0x00,0x00}}}}
  48. };
  49. /*    Array to index from the lower 8 bits of csid into the index of csinfo_tbl */
  50. PRIVATE int csinfoindex[256] =
  51. {/*    0    1    2    3    4    5    6    7    8    9    a    b    c    d    e    f    */    
  52.     -1,    -1,    -1,    -1,    0,    1,    -1,    2,    2,    3,    -1,    -1,    2,    -1,    -1,    -1,    /*    0x00 */
  53.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    4,    4,    4,    4,    -1,    4,    4,    -1,    /*    0x10 */
  54.     -1,    -1,    5,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0x20 */
  55.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0x30 */
  56.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0x40 */
  57.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0x50 */
  58.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0x60 */
  59.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0x70 */
  60.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0x80 */
  61.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0x90 */
  62.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0xa0 */
  63.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0xb0 */
  64.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0xc0 */
  65.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0xd0 */
  66.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0xe0 */
  67.     -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    -1,    /*    0xf0 */
  68. };
  69. #define INTL_GETTBLINDEX(csid)    (csinfoindex[ (csid) & 0x00FF ])
  70.  
  71. PRIVATE csinfo_t* intl_GetInfoTbl(int16 csid)
  72. {
  73.     int idx = INTL_GETTBLINDEX(csid);
  74.     if(idx < 0)    
  75.         return NULL;
  76.     else
  77.         return &csinfo_tbl[idx];
  78. }
  79.  
  80. /***********************************************************
  81.  INTL_MidTruncateString  truncate a string removing the
  82.                          middle
  83.  Input:  int16 csid  Char Set ID
  84.          char *input un-truncated string
  85.  
  86.  Output: char *output pointer to truncated string buffer
  87.  
  88. ***********************************************************/
  89.  
  90. PUBLIC void
  91. INTL_MidTruncateString (int16 csid, const char *input, char *output, int max_length)
  92. {
  93.   char *begin_part, *p;
  94.   int L = strlen (input);
  95.   char *tmp = 0;
  96.   int begin_len, mid, rem;
  97.  
  98.   /*
  99.    * If it fits then no need to truncate
  100.    */
  101.   if (L <= max_length)
  102.     {
  103.       strcpy (output, input);
  104.       return;
  105.     }
  106.  
  107.   if (input == output) /* if copying in place use tmp buf */
  108.     {
  109.       tmp = output;
  110.       output = (char *) calloc (1, max_length + 1);
  111.     }
  112.  
  113.   /* 
  114.    * find the 1st half
  115.    */
  116.   mid = (max_length - 3) / 2; /* approx 1st half */
  117.   /* find 1st half to whole char */
  118.   for (begin_part=p=(char*)input; 
  119.         *p && p<=((char*)input+mid); p=INTL_NextChar(csid, p))
  120.     begin_part = p; /* remember last good point before mid */
  121.   /* exact mid point */
  122.   begin_len = begin_part - input;
  123.  
  124.   /*
  125.    * Copy 1st half
  126.    */
  127.   strncpy (output, input, begin_len);
  128.   strncpy (output + begin_len, "...", 3);
  129.  
  130.   /* 
  131.    * find the remainder
  132.    */
  133.   rem = L - mid; /* approx remainder */
  134.   /* find remainder to whole char */
  135.   for (p=begin_part; *p && p<((char*)input+rem); p=INTL_NextChar(csid, p))
  136.     continue;
  137.   /* exact remainder */
  138.   rem = p - input;
  139.   strncpy (output + begin_len + 3, p, L - rem + 1);
  140.  
  141.   if (tmp)
  142.     {
  143.       strncpy (tmp, output, max_length + 1);
  144.       free (output);
  145.     }
  146. }
  147. /***********************************************************
  148.  Input:  int (int16) charsetid        Char Set ID
  149.          char *pstr                   Buffer which always point to Multibyte char first byte
  150.                                      or normal single byte char
  151.  Output: return next char position
  152. ***********************************************************/
  153. PUBLIC char * INTL_NextChar(int charsetid, char *pstr)
  154. {
  155.     csinfo_t    *pInfo ;
  156.     unsigned char ch ;
  157.     int i;
  158.  
  159.     if ((INTL_CharSetType(charsetid) == SINGLEBYTE) || (*pstr == 0)) /* If no csid, assume it's not multibyte */
  160.         return pstr + 1;
  161.  
  162.     ch = *pstr ;
  163.     if((pInfo = intl_GetInfoTbl((int16)charsetid)) != NULL)
  164.     {
  165.         for (i=0; i<MAX_FIRSTBYTE_RANGE && pInfo->enc[i].bytes > 0; i++)
  166.         {
  167.             if ((ch >= pInfo->enc[i].range[0]) && (ch <= pInfo->enc[i].range[1]))
  168.             {    
  169.                 int j = 0;
  170.                 for (j=0; pstr[j] && j < pInfo->enc[i].bytes; j++)
  171.                     ;
  172.                 if (j < pInfo->enc[i].bytes)
  173.                     return pstr+1;
  174.                 else
  175.                     return pstr+j;
  176.             }
  177.         }
  178.         return pstr + 1;
  179.     }
  180.     return pstr + 1;
  181. }
  182.  
  183. /********************************************************
  184.  Input:  DocumentContext context Window Context
  185.          unsigned char ch         Buffer which always point to Multibyte char
  186.                                  first byte or normal single byte char
  187.  Output: 1, if ch is under ShiftJIS type MultiByte first byte range
  188.          2, if ch is under EUC type MultiByte first byte range
  189.          0, if it's not MultiByte firstbyte
  190. *********************************************************/
  191.  
  192. PUBLIC
  193. int PR_CALLBACK
  194. INTL_IsLeadByte(int charsetid, unsigned char ch)
  195. {
  196.     csinfo_t    *pInfo ;
  197.     int i;
  198.  
  199.     if ((INTL_CharSetType(charsetid) == SINGLEBYTE) || (ch == 0)) /* If no csid, assume it's not multibyte */
  200.         return 0;
  201.  
  202.     if((pInfo = intl_GetInfoTbl((int16)charsetid)) != NULL)
  203.     {
  204.         for (i=0; i<MAX_FIRSTBYTE_RANGE && pInfo->enc[i].bytes > 0; i++)
  205.             if ((ch >= pInfo->enc[i].range[0]) &&
  206.                 (ch <= pInfo->enc[i].range[1]))
  207.                 return pInfo->enc[i].bytes-1;
  208.         return 0 ;
  209.     }
  210.     return 0;
  211. }
  212.  
  213. PUBLIC int 
  214. INTL_CharLen(int charsetid, unsigned char *pstr)
  215. {
  216.     int i,l;
  217.     if ((!pstr) || (!*pstr)) return 0;
  218.     l = 1 + INTL_IsLeadByte(charsetid, *pstr);
  219.     for(i=1, pstr++ ; (i<l) && (*pstr); i++, pstr++)
  220.         ;
  221.     return i;
  222. }
  223.  
  224. PUBLIC int
  225. INTL_ColumnWidth(int charsetid, unsigned char *str)
  226. {
  227.     unsigned char    b;
  228.     csinfo_t    *pInfo;
  229.     int        i;
  230.  
  231.     if ((!str) || (!*str))
  232.         return 0;
  233.  
  234.     if (INTL_CharSetType(charsetid) == SINGLEBYTE)
  235.         return 1;
  236.     if((pInfo = intl_GetInfoTbl((int16)charsetid)) != NULL)
  237.     {
  238.         b = *str;
  239.         for (i = 0; (i < MAX_FIRSTBYTE_RANGE) &&
  240.             pInfo->enc[i].bytes; i++)
  241.         {
  242.             if ((b >= pInfo->enc[i].range[0]) &&
  243.                 (b <= pInfo->enc[i].range[1]))
  244.             {
  245.                 return pInfo->enc[i].columns;
  246.             }
  247.         }
  248.     }
  249.  
  250.     return 1;
  251. }
  252.  
  253. /********************************************************
  254.  Input:  int (int16) charsetid    Char Set ID
  255.          char *pstr                Buffer which always point to Multibyte char
  256.                                 first byte or normal single byte char
  257.          int  pos                byte position
  258.  Output: 0,   if pos is not on kanji char
  259.           1,   if pos is on kanji 1st byte
  260.          2,   if pos is on kanji 2nd byte
  261.          3,   if pos is on kanji 3rd byte
  262.  Note:   Current this one only works for ShiftJis type multibyte not for JIS or EUC
  263. *********************************************************/
  264. PUBLIC int
  265. INTL_NthByteOfChar(int charsetid, char *pstr, int pos)
  266. {
  267.     int    i;
  268.     int    prev;
  269.  
  270.     pos--;
  271.  
  272.     if
  273.     (
  274.         (INTL_CharSetType(charsetid) == SINGLEBYTE) ||
  275.         (!pstr)  ||
  276.         (!*pstr) ||
  277.         (pos < 0)
  278.     )
  279.     {
  280.         return 0;
  281.     }
  282.  
  283.     i = 0;
  284.     prev = 0;
  285.     while (pstr[i] && (i <= pos))
  286.     {
  287.         prev = i;
  288.         i += INTL_CharLen(charsetid, (unsigned char *) &pstr[i]);
  289.     }
  290.     if (i <= pos)
  291.     {
  292.         return 0;
  293.     }
  294.     if (INTL_CharLen(charsetid, (unsigned char *) &pstr[prev]) < 2)
  295.     {
  296.         return 0;
  297.     }
  298.  
  299.     return pos - prev + 1;
  300. }
  301.  
  302. PUBLIC int
  303. INTL_IsHalfWidth(uint16 win_csid, unsigned char *pstr)
  304. {
  305.     int    c;
  306.  
  307.     c = *pstr;
  308.  
  309.     switch (win_csid)
  310.     {
  311.     case CS_SJIS:
  312.         if ((0xa1 <= c) && (c <= 0xdf))
  313.         {
  314.             return 1;
  315.         }
  316.         break;
  317.     case CS_EUCJP:
  318.         if (c == 0x8e)
  319.         {
  320.             return 1;
  321.         }
  322.         break;
  323.     default:
  324.         break;
  325.     }
  326.  
  327.     return 0;
  328. }
  329.  
  330.  
  331. /*    
  332.     INTL_NextCharIdxInText 
  333.         Input:     csid - window csid    
  334.                 text - point to a text buffer
  335.                 pos  - origional index position
  336.         output: index of the position of next character
  337.         Called by lo_next_character in layfind.c
  338. */
  339. PUBLIC int INTL_NextCharIdxInText(int16 csid, unsigned char *text, int pos)
  340. {
  341.     return pos + INTL_CharLen(csid ,text+pos);
  342. }
  343. /*    
  344.     INTL_PrevCharIdxInText 
  345.         Input:     csid - window csid    
  346.                 text - point to a text buffer
  347.                 pos  - origional index position
  348.         output: index of the position of previous character
  349.         Called by lo_next_character in layfind.c
  350. */
  351. PUBLIC int INTL_PrevCharIdxInText(int16 csid, unsigned char *text, int pos)
  352. {
  353.     int rev, ff , thislen;
  354.     if((INTL_CharSetType(csid) == SINGLEBYTE) ) {
  355.         return pos - 1;
  356.     }
  357.     else 
  358.     {
  359.         /*    First, backward to character in ASCII range */
  360.         for(rev=pos - 1; rev > 0 ; rev--)
  361.         {
  362.             if(((text[rev] & 0x80 ) == 0) &&
  363.                ((rev + INTL_CharLen(csid ,text+rev)) < pos))
  364.                 break;
  365.         }
  366.             
  367.         /*    Then forward till we cross the position. */
  368.         for(ff = rev ; ff < pos ; ff += thislen)
  369.         {
  370.             thislen = INTL_CharLen(csid ,text+ff);
  371.             if((ff + thislen) >= pos)
  372.                 break;
  373.         }
  374.         return ff;
  375.     }
  376. }
  377.  
  378. /*    
  379.     INTL_NextCharIdx
  380.         Input:     csid - window csid    
  381.                 text - point to a text buffer
  382.                 pos  - 0 based position
  383.         output: 0 based next char position
  384.         Note: this one works for any position no matter it's legal or not
  385. */
  386.  
  387. PUBLIC int INTL_NextCharIdx(int16 csid, unsigned char *str, int pos)
  388. {
  389.     int n;
  390.     unsigned char *p;
  391.  
  392.     if((INTL_CharSetType(csid) == SINGLEBYTE) || (pos < 0))
  393.         return pos + 1;
  394.  
  395.     n = INTL_NthByteOfChar(csid, (char *) str, pos+1);
  396.     if (n == 0)
  397.         return pos + 1;
  398.  
  399.     p = str + pos - n + 1;
  400.     return pos + INTL_CharLen(csid, p) - n + 1;
  401. }
  402. /*    
  403.     INTL_PrevCharIdx
  404.         Input:     csid - window csid    
  405.                 text - point to a text buffer
  406.                 pos  - 0 based position
  407.         output: 0 based prev char position
  408.         Note: this one works for any position no matter it's legal or not
  409. */
  410. PUBLIC int INTL_PrevCharIdx(int16 csid, unsigned char *str, int pos)
  411. {
  412.     int n;
  413.     if((INTL_CharSetType(csid) == SINGLEBYTE) || (pos <= 0))
  414.         return pos - 1;
  415. #ifdef DEBUG
  416.     n = INTL_NthByteOfChar(csid, (char *) str, pos+1);
  417.     if (n > 1)
  418.     {
  419.         XP_TRACE(("Wrong position passed to INTL_PrevCharIdx"));
  420.         pos -= (n - 1); 
  421.     }
  422. #endif
  423.  
  424.     pos --;
  425.     if ((n = INTL_NthByteOfChar(csid, (char *) str, pos+1)) > 1)
  426.         return pos - n + 1;
  427.     else
  428.         return pos;
  429. }
  430.  
  431.  
  432.  
  433. PUBLIC
  434. int32  INTL_TextByteCountToCharLen(int16 csid, unsigned char* text, uint32 byteCount)
  435. {
  436.     /* quickly return if it is zero */
  437.     if(byteCount == 0 )
  438.         return 0;
  439.     if(INTL_CharSetType(csid) == SINGLEBYTE)
  440.     {
  441.         /* for single byte csid, byteCount equal to charLen */
  442.         return byteCount;
  443.     }
  444.     else
  445.     {
  446.         csinfo_t    *pInfo ;
  447.         if((pInfo = intl_GetInfoTbl(csid)) != NULL)
  448.         {
  449.             uint32 curByte, curChar;
  450.             int thislen;
  451.             for(curByte=curChar=0; curByte < byteCount ;curChar++,curByte += thislen)
  452.             {
  453.                 int i;
  454.                 unsigned char ch = text[curByte];
  455.                 /* preset thislen to 1 and looking for the entry for this char */
  456.                 for (i=0, thislen = 1; i<MAX_FIRSTBYTE_RANGE && pInfo->enc[i].bytes > 0; i++)
  457.                 {
  458.                     if ((ch >= pInfo->enc[i].range[0]) && (ch <= pInfo->enc[i].range[1]))
  459.                         thislen = pInfo->enc[i].bytes;
  460.                 }
  461.             }
  462.             return curChar;        
  463.         }
  464.     }
  465.     /* it should not come to here */
  466.     XP_ASSERT(byteCount);
  467.     return byteCount;        
  468. }
  469.  
  470.  
  471.  
  472. PUBLIC
  473. int32  INTL_TextCharLenToByteCount(int16 csid, unsigned char* text, uint32 charLen)
  474. {
  475.     /* quickly return if it is zero */
  476.     if(charLen == 0 )
  477.         return 0;
  478.     if(INTL_CharSetType(csid) == SINGLEBYTE)
  479.     {
  480.         /* for single byte csid, byteCount equal to charLen */
  481.         return charLen;
  482.     }
  483.     else
  484.     {
  485.         csinfo_t    *pInfo ;
  486.         if((pInfo = intl_GetInfoTbl(csid)) != NULL)
  487.         {
  488.             uint32 curByte, curChar;
  489.             int thislen;
  490.             for(curByte=curChar=0; curChar < charLen ;curChar++,curByte += thislen)
  491.             {
  492.                 int i;
  493.                 unsigned char ch = text[curByte];
  494.                 /* preset thislen to 1 and looking for the entry for this char */
  495.                 for (i=0, thislen = 1; i<MAX_FIRSTBYTE_RANGE && pInfo->enc[i].bytes > 0; i++)
  496.                 {
  497.                     if ((ch >= pInfo->enc[i].range[0]) && (ch <= pInfo->enc[i].range[1]))
  498.                         thislen = pInfo->enc[i].bytes;
  499.                 }
  500.             }
  501.             return curByte;    
  502.         }
  503.     }
  504.     /* it should not come to here */
  505.     XP_ASSERT(charLen);
  506.     return charLen;
  507. }
  508.  
  509.  
  510.  
  511.  
  512.