Listing 4: Module ui_text.c, to be linked with application code requiring multi-language support

/* -------------------------------------------------------*\
| ui_text.c (version 1.4) Copyright (C) SichemSoft 1995/98 |
| Roghorst 160, 6708 KS Wageningen, Netherlands. Module    |
| for language independent applications                    |
| author: Anneke Sicherer-Roetman, date: 950804            |
\* -------------------------------------------------------*/

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "lingua.h"
#include "files.inc"

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

char **ui_text;                
/* pointers into memory text buffer */

unsigned _ui_memcount,_ui_filcount;  
/* undocumented global variables */

static char *ui_textbuffer;        
/* memory text buffer */

static unsigned long *ui_file;      
/* pointers into file */

static char *ui_filebuffer;        
/* file text buffer */

static char **ui_fileptr;         
/* pointers into array from file */

static unsigned itemchecksum=0;     
/* for checksumming file items */

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

/* converts string to all lower 
   case (common ANSI extension) */
static char *strlwr(char *s)
{
  char *p;
  for (p=s; *s; s++) 
    if (isupper(*s)) 
      *s=tolower(*s);
  return p;
} /* strlwr */

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

/* decrypts text and computes checksum */
static unsigned decrypt(char *buffer,
                        unsigned long size)
{
  register unsigned long offset;
  unsigned checksum;
  char *q;

  for (offset=0,checksum=0,q=buffer; 
      offset<size; offset++,q++) {
    *q^=UIT_ENCRYPT; 
    checksum+=(unsigned char)(*q);
  }
  return checksum;
} /* decrypt */

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

/* loads text from file into ui_filebuffer */
static char *loadtext(unsigned long pos,
                      unsigned size)
{
  static unsigned long oldpos=(unsigned long)(-1L);

  if (pos==oldpos) 
    return ui_filebuffer;
  if (!fileseek(pos)) 
    return NULL;
  if (ui_filebuffer) 
    free(ui_filebuffer);
  ui_filebuffer=(char *)malloc(size*sizeof(char));
  if (!ui_filebuffer) 
    return NULL;
  if (!fileread(ui_filebuffer,size*sizeof(char))) 
    return NULL;
  itemchecksum=decrypt(ui_filebuffer,size);
  oldpos=pos; /* next time only load if necessary */
  return ui_filebuffer;
} /* loadtext */

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

/* loads text (no array) 
   from file into ui_filebuffer */
/* note: the programmer should not 
   call this routine directly */
#pragma warn -sig
char *ui_filetext(unsigned pos)
{
  return loadtext(ui_file[pos],
                  ui_file[pos+1]-ui_file[pos]);
} /* ui_filetext */

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

/* loads text array from file 
   into ui_filebuffer */
/* note: the programmer should not 
   call this routine directly */
char **ui_filearray(unsigned pos)
{
  unsigned size; 
  register int i;

  if (!fileseek(ui_file[pos])) 
    return NULL;
  if (!fileread(&size,sizeof(size))) 
    return NULL;
  if (!loadtext(filetell(),
                ui_file[pos+size]-
                ui_file[pos]-sizeof(size)))
    return NULL;
  if (ui_fileptr) 
    free(ui_fileptr);
  ui_fileptr=(char **)malloc(size*sizeof(char*));
  if (!ui_fileptr) 
    return NULL;
  ui_fileptr[0]=ui_filebuffer;
  for (i=1; i<size; i++)
    ui_fileptr[i]=ui_filebuffer+ui_file[pos+i]-
                  ui_file[pos]-sizeof(size);
  return ui_fileptr;
} /* ui_filearray */

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

/* opens file, loads text and 
   offsets into memory */
/* call this routine at the very 
   beginning of the application */
int ui_loadtext(char *fname,
                char *vers)
/* fname is name of desired .etf 
   file without extension
   vers is optional version 
   number, may also be "" */
{
  char *q;
  unsigned len,i;
  unsigned checksum,checksum1=0,checksum2=0;
  char buf[256],file[81];
  unsigned long offset,size;

  if (ui_text || ui_file) 
    return FALSE;

  /* open encrypted text file */
  strcpy(file,fname);
  if (!strchr(file,'.')) 
    strcat(file,".etf");
  if (!fileopen(file)) 
    return FALSE;

  /* read file header */
  if (!vers) vers="";
  q=strrchr(file,dirsep); 
  if (q) 
    q++; 
  else 
    q=file;
  len=strlen(q)+strlen(vers);
  if (!fileread(buf,(len+1)*sizeof(char))) 
    return FALSE;
  strlwr(buf); 
  strlwr(q); 
  strlwr(vers);
  if (strncmp(buf,q,strlen(q))) 
    return FALSE;
  if (strncmp(buf+strlen(q),vers,strlen(vers))) 
    return FALSE;

  /* read number of items */
  if (!fileread(&checksum,sizeof(checksum))) 
    return FALSE;
  if (!fileread(&_ui_memcount,sizeof(_ui_memcount))) 
    return FALSE;
  if (!fileread(&_ui_filcount,sizeof(_ui_filcount))) 
    return FALSE;
  if (!fileread(&size,sizeof(size))) 
    return FALSE;
  if (_ui_memcount) {
    /* reserve space */
    ui_text=
      (char **)malloc(_ui_memcount*sizeof(char *));
    if (!ui_text) 
      return FALSE;
    ui_textbuffer=(char *)malloc(size*sizeof(char));
    if (!ui_textbuffer) 
      return FALSE;

    /* read offsets and compute pointers */
    for (i=0; i<_ui_memcount; i++) {
      if (!fileread(&offset,sizeof(offset))) 
        return FALSE;
      ui_text[i]=ui_textbuffer+offset;
    }
  }

  if (_ui_filcount) {
    /* reserve space */
    ui_file=(unsigned long *)malloc
            ((_ui_filcount+1)*sizeof(unsigned long));
    if (!ui_file) 
      return FALSE;

    /* read offsets of file items */
    for (i=0; i<_ui_filcount+1; i++) {
      if (!fileread(&offset,sizeof(offset))) 
        return FALSE;
      ui_file[i]=offset;
    }
  }

  if (_ui_memcount) {
    /* read text lines and decrypt */
    if (!fileread(ui_textbuffer,size*sizeof(char))) 
      return FALSE;
    checksum1=decrypt(ui_textbuffer,size);
  }

  if (_ui_filcount) {
    /* read file items and decrypt for checksumming */
    for (i=0; i<_ui_filcount; i++) {
      q=ui_filetext(i); 
      if (!q) 
        return FALSE;
      checksum2+=itemchecksum;
    }
  }

  /* close file if no file items present */
  if (!_ui_filcount) 
    fileclose();

  /* succesful load if checksum is ok */
  return (checksum==checksum1+checksum2);
} /* ui_loadtext */
#pragma warn .sig

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

/* frees all space and closes file if necessary */
/* call this routine at the 
   very end of the application */
void ui_unloadtext(void)
{
  if (ui_text) { 
    free(ui_text); 
    ui_text=NULL; 
  }
  if (ui_textbuffer) { 
    free(ui_textbuffer);  
    ui_textbuffer=NULL; 
  }
  if (ui_file) { 
    free(ui_file); 
    ui_file=NULL; 
  }
  if (ui_filebuffer) { 
    free(ui_filebuffer); 
    ui_filebuffer=NULL; 
  }
  if (ui_fileptr) { 
    free(ui_fileptr); 
    ui_fileptr=NULL; 
  }
  fileclose();
} /* ui_unloadtext */

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

- End of Listing -