compiler-init/sci18n.c
branchfaluco
changeset 2282 05c25f435814
parent 16 1feb2e0ff0ce
child 2285 9dd80a672eb9
     1.1 --- a/compiler-init/sci18n.c	Sat Jul 15 01:36:48 2006 +0000
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,428 +0,0 @@
     1.4 -/*  Codepage translation to Unicode, and UTF-8 support
     1.5 - *
     1.6 - *  The translation is based on codepage mapping files that are distributed
     1.7 - *  by the Unicode consortium, see ftp://ftp.unicode.org/Public/MAPPINGS/.
     1.8 - *
     1.9 - *  Character sets with a maximum of 256 codes are translated via a lookup
    1.10 - *  table (these are Single-Byte Character Sets). Character sets like Shift-JIS
    1.11 - *  with single-byte characters and multi-byte characters (introduced by a
    1.12 - *  leader byte) are split into two tables: the 256-entry lookup table for
    1.13 - *  the single-byte characters and an extended table for the multi-byte
    1.14 - *  characters. The extended table is allocated dynamically; the lookup table
    1.15 - *  is allocated statically, so loading SBCS tables cannot fail (if the tables
    1.16 - *  themselves are valid, of course).
    1.17 - *
    1.18 - *  Copyright (c) ITB CompuPhase, 2004-2006
    1.19 - *
    1.20 - *  This software is provided "as-is", without any express or implied warranty.
    1.21 - *  In no event will the authors be held liable for any damages arising from
    1.22 - *  the use of this software.
    1.23 - *
    1.24 - *  Permission is granted to anyone to use this software for any purpose,
    1.25 - *  including commercial applications, and to alter it and redistribute it
    1.26 - *  freely, subject to the following restrictions:
    1.27 - *
    1.28 - *  1.  The origin of this software must not be misrepresented; you must not
    1.29 - *      claim that you wrote the original software. If you use this software in
    1.30 - *      a product, an acknowledgment in the product documentation would be
    1.31 - *      appreciated but is not required.
    1.32 - *  2.  Altered source versions must be plainly marked as such, and must not be
    1.33 - *      misrepresented as being the original software.
    1.34 - *  3.  This notice may not be removed or altered from any source distribution.
    1.35 - *
    1.36 - *  Version: $Id: CODEPAGE.C,v 1.0 2004-02-18 12:13:04+01 thiadmer Exp thiadmer $
    1.37 - */
    1.38 -#include <assert.h>
    1.39 -#include <stdio.h>
    1.40 -#include <stddef.h>
    1.41 -#include <stdlib.h>
    1.42 -#include <string.h>
    1.43 -#include "sc.h"
    1.44 -
    1.45 -#if !defined TRUE
    1.46 -  #define FALSE         0
    1.47 -  #define TRUE          1
    1.48 -#endif
    1.49 -#if !defined _MAX_PATH
    1.50 -  #define _MAX_PATH     250
    1.51 -#endif
    1.52 -#if !defined DIRSEP_CHAR
    1.53 -  #if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
    1.54 -    #define DIRSEP_CHAR '/'
    1.55 -  #elif defined macintosh
    1.56 -    #define DIRSEP_CHAR ':'
    1.57 -  #else
    1.58 -    #define DIRSEP_CHAR '\\'
    1.59 -  #endif
    1.60 -#endif
    1.61 -
    1.62 -#if !defined ELEMENTS
    1.63 -  #define ELEMENTS(array)       (sizeof(array) / sizeof(array[0]))
    1.64 -#endif
    1.65 -
    1.66 -#if !defined NO_CODEPAGE
    1.67 -
    1.68 -#if !defined MAXCODEPAGE
    1.69 -  #define MAXCODEPAGE   12      /* typically "cp" + 4 digits + ".txt" */
    1.70 -#endif
    1.71 -#define INVALID         0xffffu /* 0xffff and 0xfffe are invalid Unicode characters */
    1.72 -#define LEADBYTE        0xfffeu
    1.73 -
    1.74 -struct wordpair {
    1.75 -  unsigned short index;
    1.76 -  wchar_t code;
    1.77 -};
    1.78 -static char cprootpath[_MAX_PATH] = { DIRSEP_CHAR, '\0' };
    1.79 -static wchar_t bytetable[256];
    1.80 -static struct wordpair *wordtable = NULL;
    1.81 -static unsigned wordtablesize = 0;
    1.82 -static unsigned wordtabletop = 0;
    1.83 -
    1.84 -
    1.85 -/* read in a line delimited by '\r' or '\n'; do NOT store the '\r' or '\n' into
    1.86 - * the string and ignore empty lines
    1.87 - * returns 1 for success and 0 for failure
    1.88 - */
    1.89 -static int cp_readline(FILE *fp,char *string,size_t size)
    1.90 -{
    1.91 -  size_t count=0;
    1.92 -  int c;
    1.93 -  assert(size>1);
    1.94 -  while ((c=fgetc(fp))!=EOF && count<size-1) {
    1.95 -    if (c=='\r' || c=='\n') {
    1.96 -      if (count>0)  /* '\r' or '\n' ends a string */
    1.97 -        break;
    1.98 -      /* if count==0, the line started with a '\r' or '\n', or perhaps line
    1.99 -       * ends in the file are '\r\n' and we read and stopped on the '\r' of
   1.100 -       * the preceding line
   1.101 -       */
   1.102 -    } else {
   1.103 -      string[count++]=(char)c;
   1.104 -    } /* if */
   1.105 -  } /* while */
   1.106 -  string[count]='\0';
   1.107 -  return count>0;
   1.108 -}
   1.109 -
   1.110 -/* cp_path() sets the directory where all codepage files must be found (if
   1.111 - * the parameter to cp_set() specifies a full path, that is used instead).
   1.112 - * The path is specified into two parts: root and directory; the full path
   1.113 - * for the codepage direcory is just the concatenation of the two, with a
   1.114 - * directory separator in between. The directory is given in two parts,
   1.115 - * because often a program already retrieves its "home" directory and the
   1.116 - * codepages are most conveniently stored in a subdirectory of this home
   1.117 - * directory.
   1.118 - */
   1.119 -SC_FUNC int cp_path(const char *root, const char *directory)
   1.120 -{
   1.121 -  size_t len1,len2;
   1.122 -  int add_slash1,add_slash2;
   1.123 -
   1.124 -  len1= (root!=NULL) ? strlen(root) : 0;
   1.125 -  add_slash1= (len1==0 || root[len1-1]!=DIRSEP_CHAR);
   1.126 -  len2= (directory!=NULL) ? strlen(directory) : 0;
   1.127 -  add_slash2= (len2>0 && root[len2-1]!=DIRSEP_CHAR);
   1.128 -  if (len1+add_slash1+len2+add_slash2>=(_MAX_PATH-MAXCODEPAGE))
   1.129 -    return FALSE;       /* full filename may not fit */
   1.130 -  if (root!=NULL)
   1.131 -    strcpy(cprootpath,root);
   1.132 -  if (add_slash1) {
   1.133 -    assert(len1==0 || cprootpath[len1]=='\0');
   1.134 -    cprootpath[len1]=DIRSEP_CHAR;
   1.135 -    cprootpath[len1+1]='\0';
   1.136 -  } /* if */
   1.137 -  if (directory!=NULL)
   1.138 -    strcat(cprootpath,directory);
   1.139 -  if (add_slash2) {
   1.140 -    assert(cprootpath[len1+add_slash1+len2]=='\0');
   1.141 -    cprootpath[len1+add_slash1+len2]=DIRSEP_CHAR;
   1.142 -    cprootpath[len1+add_slash1+len2+1]='\0';
   1.143 -  } /* if */
   1.144 -  cp_set(NULL);         /* start with a "linear" table (no translation) */
   1.145 -  return TRUE;
   1.146 -}
   1.147 -
   1.148 -/* cp_set() loads a codepage from a file. The name parameter may be a
   1.149 - * filename (including a full path) or it may be a partial codepage name.
   1.150 - * If the name parameter is NULL, the codepage is cleared to be a "linear"
   1.151 - * table (no translation).
   1.152 - * The following files are attempted to open (where <name> specifies the
   1.153 - * value of the parameter):
   1.154 - *    <name>
   1.155 - *    <cprootpath>/<name>
   1.156 - *    <cprootpath>/<name>.txt
   1.157 - *    <cprootpath>/cp<name>
   1.158 - *    <cprootpath>/cp<name>.txt
   1.159 - */
   1.160 -SC_FUNC int cp_set(const char *name)
   1.161 -{
   1.162 -  char filename[_MAX_PATH];
   1.163 -  FILE *fp=NULL;
   1.164 -  unsigned index;
   1.165 -
   1.166 -  /* for name==NULL, set up an identity table */
   1.167 -  if (name==NULL || *name=='\0') {
   1.168 -    if (wordtable!=NULL) {
   1.169 -      free(wordtable);
   1.170 -      wordtable=NULL;
   1.171 -      wordtablesize=0;
   1.172 -      wordtabletop=0;
   1.173 -    } /* if */
   1.174 -    for (index=0; index<ELEMENTS(bytetable); index++)
   1.175 -      bytetable[index]=(wchar_t)index;
   1.176 -    return TRUE;
   1.177 -  } /* if */
   1.178 -
   1.179 -  /* try to open the file as-is */
   1.180 -  if (strchr(name,DIRSEP_CHAR)!=NULL)
   1.181 -    fp=fopen(name,"rt");
   1.182 -  if (fp==NULL) {
   1.183 -    /* try opening the file in the "root path" for codepages */
   1.184 -    if (strlen(name)>MAXCODEPAGE)
   1.185 -      return 0;
   1.186 -    assert(strlen(name)+strlen(cprootpath)<_MAX_PATH);
   1.187 -    strcpy(filename,cprootpath);
   1.188 -    strcat(filename,name);
   1.189 -    fp=fopen(filename,"rt");
   1.190 -  } /* if */
   1.191 -  if (fp==NULL) {
   1.192 -    /* try opening the file in the "root path" for codepages, with a ".txt" extension */
   1.193 -    if (strlen(name)+4>=MAXCODEPAGE)
   1.194 -      return 0;
   1.195 -    assert(strlen(filename)+4<_MAX_PATH);
   1.196 -    strcat(filename,".txt");
   1.197 -    fp=fopen(filename,"rt");
   1.198 -  } /* if */
   1.199 -  if (fp==NULL) {
   1.200 -    /* try opening the file in the "root path" for codepages, with "cp" prefixed before the name */
   1.201 -    if (strlen(name)+2>MAXCODEPAGE)
   1.202 -      return 0;
   1.203 -    assert(2+strlen(name)+strlen(cprootpath)<_MAX_PATH);
   1.204 -    strcpy(filename,cprootpath);
   1.205 -    strcat(filename,"cp");
   1.206 -    strcat(filename,name);
   1.207 -    fp=fopen(filename,"rt");
   1.208 -  } /* if */
   1.209 -  if (fp==NULL) {
   1.210 -    /* try opening the file in the "root path" for codepages, with "cp" prefixed an ".txt" appended */
   1.211 -    if (strlen(name)+2+4>MAXCODEPAGE)
   1.212 -      return 0;
   1.213 -    assert(strlen(filename)+4<_MAX_PATH);
   1.214 -    strcat(filename,".txt");
   1.215 -    fp=fopen(filename,"rt");
   1.216 -  } /* if */
   1.217 -  if (fp==NULL)
   1.218 -    return FALSE;       /* all failed */
   1.219 -
   1.220 -  /* clear the tables */
   1.221 -  for (index=0; index<ELEMENTS(bytetable); index++)
   1.222 -    bytetable[index]=INVALID;   /* special code meaning "not found" */
   1.223 -  assert(wordtablesize==0 && wordtabletop==0 && wordtable==NULL
   1.224 -         || wordtablesize>0 && wordtable!=NULL);
   1.225 -  if (wordtable!=NULL) {
   1.226 -    free(wordtable);
   1.227 -    wordtable=NULL;
   1.228 -    wordtablesize=0;
   1.229 -    wordtabletop=0;
   1.230 -  } /* if */
   1.231 -
   1.232 -  /* read in the table */
   1.233 -  while (cp_readline(fp,filename,sizeof filename)) {
   1.234 -    char *ptr;
   1.235 -    if ((ptr=strchr(filename,'#'))!=NULL)
   1.236 -      *ptr='\0';                /* strip of comment */
   1.237 -    for (ptr=filename; *ptr>0 && *ptr<' '; ptr++)
   1.238 -      /* nothing */;            /* skip leading whitespace */
   1.239 -    if (*ptr!='\0') {
   1.240 -      /* content on line */
   1.241 -      unsigned code=LEADBYTE;
   1.242 -      int num=sscanf(ptr,"%i %i",&index,&code);
   1.243 -      /* if sscanf() returns 1 and the index is in range 0..255, then the
   1.244 -       * code is a DBCS lead byte; if sscanf() returns 2 and index>=256, this
   1.245 -       * is a double byte pair (lead byte + follower)
   1.246 -       */
   1.247 -      if (num>=1 && index<256) {
   1.248 -        bytetable[index]=(wchar_t)code;
   1.249 -      } else if (num==2 && index>=256 && index<LEADBYTE) {
   1.250 -        /* store the DBCS character in wordtable */
   1.251 -        if (wordtabletop>=wordtablesize) {
   1.252 -          /* grow the list */
   1.253 -          int newsize;
   1.254 -          struct wordpair *newblock;
   1.255 -          newsize= (wordtablesize==0) ? 128 : 2*wordtablesize;
   1.256 -          newblock=(struct wordpair *)malloc(newsize*sizeof(*wordtable));
   1.257 -          if (newblock!=NULL) {
   1.258 -            memcpy(newblock,wordtable,wordtabletop*sizeof(*wordtable));
   1.259 -            free(wordtable);
   1.260 -            wordtable=newblock;
   1.261 -            wordtablesize=newsize;
   1.262 -          } /* if */
   1.263 -        } /* if */
   1.264 -        if (wordtabletop<wordtablesize) {
   1.265 -          /* insert at sorted position */
   1.266 -          int pos=wordtabletop;
   1.267 -          assert(wordtable!=NULL);
   1.268 -          while (pos>0 && (unsigned)wordtable[pos-1].index>index) {
   1.269 -            wordtable[pos]=wordtable[pos-1];
   1.270 -            pos--;
   1.271 -          } /* while */
   1.272 -          wordtable[pos].index=(unsigned short)index;
   1.273 -          wordtable[pos].code=(wchar_t)code;
   1.274 -        } /* if */
   1.275 -      } /* if */
   1.276 -    } /* if */
   1.277 -  } /* while */
   1.278 -
   1.279 -  fclose(fp);
   1.280 -  return TRUE;
   1.281 -}
   1.282 -
   1.283 -SC_FUNC cell cp_translate(const unsigned char *string,const unsigned char **endptr)
   1.284 -{
   1.285 -  wchar_t result;
   1.286 -
   1.287 -  result=bytetable[*string++];
   1.288 -  /* check whether this is a leader code */
   1.289 -  if ((unsigned)result==LEADBYTE && wordtable!=NULL) {
   1.290 -    /* look up the code via binary search */
   1.291 -    int low,high,mid;
   1.292 -    unsigned short index=(unsigned short)(((*(string-1)) << 8) | *string);
   1.293 -    string++;
   1.294 -    assert(wordtabletop>0);
   1.295 -    low=0;
   1.296 -    high=wordtabletop-1;
   1.297 -    while (low<high) {
   1.298 -      mid=(low+high)/2;
   1.299 -      assert(low<=mid && mid<high);
   1.300 -      if (index>wordtable[mid].index)
   1.301 -        low=mid+1;
   1.302 -      else
   1.303 -        high=mid;
   1.304 -    } /* while */
   1.305 -    assert(low==high);
   1.306 -    if (wordtable[low].index==index)
   1.307 -      result=wordtable[low].code;
   1.308 -  } /* if */
   1.309 -
   1.310 -  if (endptr!=NULL)
   1.311 -    *endptr=string;
   1.312 -  return (cell)result;
   1.313 -}
   1.314 -
   1.315 -#endif  /* NO_CODEPAGE */
   1.316 -
   1.317 -#if !defined NO_UTF8
   1.318 -SC_FUNC cell get_utf8_char(const unsigned char *string,const unsigned char **endptr)
   1.319 -{
   1.320 -  int follow=0;
   1.321 -  long lowmark=0;
   1.322 -  unsigned char ch;
   1.323 -  cell result=0;
   1.324 -
   1.325 -  if (endptr!=NULL)
   1.326 -    *endptr=string;
   1.327 -
   1.328 -  for ( ;; ) {
   1.329 -    ch=*string++;
   1.330 -
   1.331 -    if (follow>0 && (ch & 0xc0)==0x80) {
   1.332 -      /* leader code is active, combine with earlier code */
   1.333 -      result=(result << 6) | (ch & 0x3f);
   1.334 -      if (--follow==0) {
   1.335 -        /* encoding a character in more bytes than is strictly needed,
   1.336 -         * is not really valid UTF-8; we are strict here to increase
   1.337 -         * the chance of heuristic dectection of non-UTF-8 text
   1.338 -         * (JAVA writes zero bytes as a 2-byte code UTF-8, which is invalid)
   1.339 -         */
   1.340 -        if (result<lowmark)
   1.341 -          return -1;
   1.342 -        /* the code positions 0xd800--0xdfff and 0xfffe & 0xffff do not
   1.343 -         * exist in UCS-4 (and hence, they do not exist in Unicode)
   1.344 -         */
   1.345 -        if (result>=0xd800 && result<=0xdfff || result==0xfffe || result==0xffff)
   1.346 -          return -1;
   1.347 -      } /* if */
   1.348 -      break;
   1.349 -    } else if (follow==0 && (ch & 0x80)==0x80) {
   1.350 -      /* UTF-8 leader code */
   1.351 -      if ((ch & 0xe0)==0xc0) {
   1.352 -        /* 110xxxxx 10xxxxxx */
   1.353 -        follow=1;
   1.354 -        lowmark=0x80L;
   1.355 -        result=ch & 0x1f;
   1.356 -      } else if ((ch & 0xf0)==0xe0) {
   1.357 -        /* 1110xxxx 10xxxxxx 10xxxxxx (16 bits, BMP plane) */
   1.358 -        follow=2;
   1.359 -        lowmark=0x800L;
   1.360 -        result=ch & 0x0f;
   1.361 -      } else if ((ch & 0xf8)==0xf0) {
   1.362 -        /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
   1.363 -        follow=3;
   1.364 -        lowmark=0x10000L;
   1.365 -        result=ch & 0x07;
   1.366 -      } else if ((ch & 0xfc)==0xf8) {
   1.367 -        /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */
   1.368 -        follow=4;
   1.369 -        lowmark=0x200000L;
   1.370 -        result=ch & 0x03;
   1.371 -      } else if ((ch & 0xfe)==0xfc) {
   1.372 -        /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx (32 bits) */
   1.373 -        follow=5;
   1.374 -        lowmark=0x4000000L;
   1.375 -        result=ch & 0x01;
   1.376 -      } else {
   1.377 -        /* this is invalid UTF-8 */
   1.378 -        return -1;
   1.379 -      } /* if */
   1.380 -    } else if (follow==0 && (ch & 0x80)==0x00) {
   1.381 -      /* 0xxxxxxx (US-ASCII) */
   1.382 -      result=ch;
   1.383 -      break;
   1.384 -    } else {
   1.385 -      /* this is invalid UTF-8 */
   1.386 -      return -1;
   1.387 -    } /* if */
   1.388 -
   1.389 -  } /* for */
   1.390 -
   1.391 -  if (endptr!=NULL)
   1.392 -    *endptr=string;
   1.393 -  return result;
   1.394 -}
   1.395 -#endif
   1.396 -
   1.397 -SC_FUNC int scan_utf8(FILE *fp,const char *filename)
   1.398 -{
   1.399 -  #if defined NO_UTF8
   1.400 -    return 0;
   1.401 -  #else
   1.402 -    void *resetpos=pc_getpossrc(fp);
   1.403 -    int utf8=TRUE;
   1.404 -    int firstchar=TRUE,bom_found=FALSE;
   1.405 -    const unsigned char *ptr;
   1.406 -
   1.407 -    while (utf8 && pc_readsrc(fp,pline,sLINEMAX)!=NULL) {
   1.408 -      ptr=pline;
   1.409 -      if (firstchar) {
   1.410 -        /* check whether the very first character on the very first line
   1.411 -         * starts with a BYTE order mark
   1.412 -         */
   1.413 -        cell c=get_utf8_char(ptr,&ptr);
   1.414 -        bom_found= (c==0xfeff);
   1.415 -        utf8= (c>=0);
   1.416 -        firstchar=FALSE;
   1.417 -      } /* if */
   1.418 -      while (utf8 && *ptr!='\0')
   1.419 -        utf8= (get_utf8_char(ptr,&ptr)>=0);
   1.420 -    } /* while */
   1.421 -    pc_resetsrc(fp,resetpos);
   1.422 -    if (bom_found) {
   1.423 -      unsigned char bom[3];
   1.424 -      if (!utf8)
   1.425 -        error(77,filename);     /* malformed UTF-8 encoding */
   1.426 -      pc_readsrc(fp,bom,3);
   1.427 -      assert(bom[0]==0xef && bom[1]==0xbb && bom[2]==0xbf);
   1.428 -    } /* if */
   1.429 -    return utf8;
   1.430 -  #endif  /* NO_UTF8 */
   1.431 -}