Subversion Repositories SvarDOS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
37 mv_fox 1
/* Functions that emulate UNIX catgets */
2
 
3
/* Copyright (C) 1999,2000,2001 Jim Hall <jhall@freedos.org> */
4
/* Kitten version 2003 by Tom Ehlert, heavily modified by Eric Auer 2003 */
5
 
6
/*
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public
9
  License as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
11
 
12
  This library is distributed in the hope that it will be useful,
13
  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
  Lesser General Public License for more details.
16
 
17
  You should have received a copy of the GNU Lesser General Public
18
  License along with this library; if not, write to the Free Software
19
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20
*/
21
 
22
#ifndef NO_KITTEN
23
 
24
#include <stdio.h>		/* sprintf */
25
#ifndef _MICROC_
26
#include <stdlib.h>		/* getenv  */
27
#include <string.h>		/* strchr */
28
#include <dos.h>
29
#ifndef __PACIFIC__
30
#include <fcntl.h>
31
#else
32
#define O_RDONLY 0
33
#define O_TEXT 0
34
#endif
35
#else
36
#include <intr.h>
37
#include <file.h>
38
#define O_RDONLY READONLY
39
#define O_TEXT 0
40
#endif
41
/* assert we are running in small model */
42
/* else pointer below has to be done correctly */
43
/* char verify_small_pointers[sizeof(void*) == 2 ? 1 : -1]; */
44
 
45
#include "kitten.h"
46
 
47
char catcontents[8192];
48
 
49
struct catstring
50
{
51
  char key1;
52
  char key2;
53
  char *text;
54
};
55
 
56
/* Micro-C does not support typedef */
57
#define catstring_t struct catstring
58
 
59
catstring_t catpoints[128];
60
 
61
 
62
/* Local prototypes */
63
 
64
int catread (char *catfile);	/* Reads a catfile into the hash */
65
char *processEscChars (char *line);	/* Converts c escape sequences to chars */
66
 
67
int get_char (int file);	/* not meant for external use    */
68
/* external use would cause consistency problems if */
69
/* value or related file of the file handle changes */
70
 
71
int mystrtoul (char *src, int base, int size);
72
 
73
 
74
/* Globals */
75
 
76
nl_catd _kitten_catalog = 0;	/* _kitten_catalog descriptor or 0 */
77
char catfile[128];		/* full path to _kitten_catalog */
78
 
79
char getlbuf[8192];		/* read buffer for better speed  */
80
char *getlp;			/* current point in buffer       */
81
int getlrem = -1;		/* remaining bytes in buffer     */
82
char lastcr = 0;		/* for 2byte CR LF sequences     */
83
 
84
 
85
#ifndef _MICROC_
86
#ifndef __DJGPP__
87
 
88
/* DOS handle based file usage */
89
 
90
int
91
dos_open (char *filename, int mode)
92
{
93
  union REGS r;
94
  struct SREGS s;
95
#ifndef __WATCOMC__
96
  if (mode);			/* mode ignored - readonly supported */
97
#endif
98
  r.h.ah = 0x3d;
99
  r.h.al = 0;			/* read mode only supoported now !! */
100
  r.x.dx = FP_OFF (filename);
101
  s.ds = FP_SEG (filename);
102
  intdosx (&r, &r, &s);
103
  return ((r.x.cflag) ? -1 : (int) r.x.ax);
104
}
105
 
106
 
107
int
108
dos_read (int file, void *ptr, unsigned count)
109
{
110
  union REGS r;
111
  struct SREGS s;
112
  r.h.ah = 0x3f;
113
  r.x.bx = file;
114
  r.x.cx = count;
115
  r.x.dx = FP_OFF (ptr);
116
  s.ds = FP_SEG (ptr);
117
  intdosx (&r, &r, &s);
118
  return ((r.x.cflag) ? 0 : r.x.ax);
119
}
120
 
121
 
122
int
123
dos_write (int file, void *ptr, unsigned count)
124
{
125
  union REGS r;
126
  struct SREGS s;
127
  r.h.ah = 0x40;
128
  r.x.bx = file;
129
  r.x.cx = count;
130
  r.x.dx = FP_OFF (ptr);
131
  s.ds = FP_SEG (ptr);
132
  intdosx (&r, &r, &s);
133
  return ((r.x.cflag) ? 0 : r.x.ax);
134
}
135
 
136
 
137
void
138
dos_close (int file)
139
{
140
  union REGS r;
141
  r.h.ah = 0x3e;
142
  r.x.bx = file;
143
  intdos (&r, &r);
144
}
145
 
146
#endif /*DJGPP*/
147
#endif /*Micro-C */
148
/* Functions */
149
/**
150
 * On success, catgets() returns a pointer to an internal
151
 * buffer area containing the null-terminated message string.
152
 * On failure, catgets() returns the value 'message'.
153
 */
154
char *
155
kittengets (int setnum, int msgnum, char *message)
156
{
157
/* In Micro-C, variables must be defined at the start of the
158
 * function and may not be immediately assigned a value
159
 */
160
#ifdef _MICROC_
161
  int i;
162
  i = 0;
163
#else
164
  int i = 0;
165
#endif
166
 
167
  while ((catpoints[i].key1 != setnum) || (catpoints[i].key2 != msgnum))
168
    {
169
      if ((catpoints[i].text == NULL) || (i > 127))	/* at EOF */
170
	return message;
171
      i++;
172
    }
173
 
174
  if (catpoints[i].text == NULL)
175
    return message;
176
  else
177
    return (catpoints[i].text);
178
}
179
 
180
 
181
/**
182
 * Initialize kitten for program (name).
183
 */
184
 
185
nl_catd
186
kittenopen (char *name)
187
{
188
  /* catopen() returns a message _kitten_catalog descriptor  *
189
   * of type nl_catd on success.  On failure, it returns -1. */
190
 
191
  char catlang[3];		/* from LANG environment var. */
192
  char *nlsptr;			/* ptr to NLSPATH */
193
  char *lang;			/* ptr to LANG */
194
  int i;
195
#ifdef _MICROC_
196
  char *tok;
197
  int toklen;
198
#endif
199
 
200
  /* Open the _kitten_catalog file */
201
  /* The value of `_kitten_catalog' will be set based on catread */
202
 
203
  if (_kitten_catalog)
204
    {				/* Already one open */
205
      write (1, "cat already open\r\n", strlen ("cat already open\r\n"));
206
      return (-1);
207
    }
208
 
209
  for (i = 0; i < 128; i++)
210
    catpoints[i].text = NULL;
211
 
212
  if (strchr (name, '\\'))
213
    {
214
      /* unusual case: 'name' is a filename */
215
      write (1, "found \\\r\n", 9);
216
      _kitten_catalog = catread (name);
217
      if (_kitten_catalog)
218
	return (_kitten_catalog);
219
    }
220
 
221
  /* If the message _kitten_catalog file name does not contain a directory *
222
   * separator, then we need to try to locate the message _kitten_catalog. */
223
 
224
  /* We will need the value of LANG, and may need a 2-letter abbrev of
225
     LANG later on, so get it now. */
226
 
227
  lang = getenv ("LANG");
228
 
229
  if (lang == NULL)
230
    {
231
      /* printf("no lang= found\n"); *//* not fatal, though */
232
      /* Return failure - we won't be able to locate the cat file */
233
      return (-1);
234
    }
235
 
236
  if ((strlen (lang) < 2) || ((strlen (lang) > 2) && (lang[2] != '-')))
237
    {
238
      /* Return failure - we won't be able to locate the cat file */
239
      return (-1);
240
    }
241
 
242
  memcpy (catlang, lang, 2);
243
  /* we copy the full LANG value or the part before "-" if "-" found */
244
  catlang[2] = '\0';
245
 
246
  /* step through NLSPATH */
247
 
248
  nlsptr = getenv ("NLSPATH");
249
 
250
  if (nlsptr == NULL)
251
    {
252
      /* printf("no NLSPATH= found\n"); *//* not fatal either */
253
      /* Return failure - we won't be able to locate the cat file */
254
      return (-1);
255
    }
256
 
257
  catfile[0] = '\0';
258
 
259
  while (nlsptr && nlsptr[0])
260
    {
261
#ifdef _MICROC_
262
      tok = strchr (nlsptr, ';');
263
#else
264
      char *tok = strchr (nlsptr, ';');
265
      int toklen;
266
#endif
267
 
268
      if (tok == NULL)
269
	toklen = strlen (nlsptr);	/* last segment */
270
      else
271
	toklen = tok - nlsptr;	/* segment terminated by ';' */
272
 
273
      /* catfile = malloc(toklen+1+strlen(name)+1+strlen(lang)+1); */
274
      /* Try to find the _kitten_catalog file in each path from NLSPATH */
275
 
276
      if ((toklen + 6 + strlen (name)) > sizeof (catfile))
277
	{
278
	  write (1, "NLSPATH overflow\r\n", strlen ("NLSPATH overflow\r\n"));
279
	  return 0;		/* overflow in NLSPATH, should never happen */
280
	}
281
 
282
      /* Rule #1: %NLSPATH%\%LANG%\cat */
283
 
284
      memcpy (catfile, nlsptr, toklen);
285
      strcpy (catfile + toklen, "\\");
286
      strcat (catfile, catlang);
287
      strcat (catfile, "\\");
288
      strcat (catfile, name);
289
      _kitten_catalog = catread (catfile);
290
      if (_kitten_catalog)
291
	return (_kitten_catalog);
292
 
293
      /* Rule #2: %NLSPATH%\cat.%LANG% */
294
 
295
      /* memcpy(catfile, nlsptr, toklen); */
296
      strcpy (catfile + toklen, "\\");
297
      strcat (catfile, name);
298
      strcat (catfile, ".");
299
      strcat (catfile, catlang);
300
      _kitten_catalog = catread (catfile);
301
      if (_kitten_catalog)
302
	return (_kitten_catalog);
303
 
304
      /* Grab next tok for the next while iteration */
305
 
306
      nlsptr = tok;
307
      if (nlsptr)
308
	nlsptr++;
309
 
310
    }				/* while tok */
311
 
312
  /* We could not find it.  Return failure. */
313
 
314
  return (-1);
315
}
316
 
317
 
318
/**
319
 * Load a message catalog into memory.
320
 */
321
 
322
int
323
catread (char *catfile)
324
{
325
  int file;			/* pointer to the catfile */
326
  int i;
327
  char *where;
328
  char *tok;
329
#ifdef _MICROC_
330
  char *msg;
331
  char *key;
332
  int key1;
333
  int key2;
334
#endif
335
 
336
  /* Get the whole catfile into a buffer and parse it */
337
 
338
  file = open (catfile, O_RDONLY | O_TEXT);
339
  if (file < 0)
340
    /* Cannot open the file.  Return failure */
341
    return 0;
342
 
343
  for (i = 0; i < 128; i++)
344
    catpoints[i].text = NULL;
345
 
346
  for (i = 0; (unsigned int) i < sizeof (catcontents); i++)
347
    catcontents[i] = '\0';
348
 
349
  /* Read the file into memory */
350
  i = read (file, catcontents, sizeof (catcontents) - 1);
351
 
352
  if ((i == sizeof (catcontents) - 1) || (i < 1))
353
    return 0;			/* file was too big or too small */
354
 
355
  where = catcontents;
356
  i = 0;			/* catpoints entry */
357
 
358
  do
359
    {
360
#ifndef _MICROC_
361
      char *msg;
362
      char *key;
363
      int key1 = 0;
364
      int key2 = 0;
365
#else
366
      key1 = 0;
367
      key2 = 0;
368
#endif
369
 
370
      tok = strchr (where, '\n');
371
 
372
      if (tok == NULL)
373
	{			/* done? */
374
	  close (file);
375
	  return 1;		/* success */
376
	}
377
 
378
      tok[0] = '\0';		/* terminate here */
379
      tok--;			/* guess: \r before \n */
380
      if (tok[0] != '\r')
381
	tok++;			/* if not, go back */
382
      else
383
	{
384
	  tok[0] = '\0';	/* terminate here already */
385
	  tok++;
386
	}
387
      tok++;			/* this is where the next line starts */
388
 
389
      if ((where[0] >= '0') && (where[0] <= '9') &&
390
	  ((msg = strchr (where, ':')) != NULL))
391
	{
392
	  /* Skip everything which starts with # or with no digit */
393
	  /* Entries look like "1.2:This is a message" */
394
 
395
	  msg[0] = '\0';	/* remove : */
396
	  msg++;		/* go past the : */
397
 
398
	  if ((key = strchr (where, '.')) != NULL)
399
	    {
400
	      key[0] = '\0';	/* turn . into terminator */
401
	      key++;		/* go past the . */
402
	      key1 = mystrtoul (where, 10, strlen (where));
403
	      key2 = mystrtoul (key, 10, strlen (key));
404
 
405
	      if ((key1 >= 0) && (key2 >= 0))
406
		{
407
		  catpoints[i].key1 = key1;
408
		  catpoints[i].key2 = key2;
409
		  catpoints[i].text = processEscChars (msg);
410
		  if (catpoints[i].text == NULL)	/* ESC parse error */
411
		    catpoints[i].text = msg;
412
		  i++;		/* next entry! */
413
		}		/* valid keys */
414
 
415
	    }			/* . found */
416
 
417
	}			/* : and digit found */
418
 
419
      where = tok;		/* go to next line */
420
 
421
    }
422
  while (1);
423
#ifdef __PACIFIC__
424
  return 0;
425
#endif
426
}
427
 
428
 
429
void
430
kittenclose (void)
431
{
432
  /* close a message _kitten_catalog */
433
  _kitten_catalog = 0;
434
}
435
 
436
 
437
/**
438
 * Parse a string that represents an unsigned integer.
439
 * Returns -1 if an error is found. The first size
440
 * chars of the string are parsed.
441
 */
442
 
443
int
444
mystrtoul (char *src, int base, int size)
445
{
446
#ifdef _MICROC_
447
  int ret;
448
  int digit;
449
  int ch;
450
  ret = 0;
451
#else
452
  int ret = 0;
453
#endif
454
 
455
  for (; size > 0; size--)
456
    {
457
#ifdef _MICROC_
458
      ch = *src;
459
#else
460
      int digit;
461
      int ch = *src;
462
#endif
463
      src++;
464
 
465
      if (ch >= '0' && ch <= '9')
466
	digit = ch - '0';
467
      else if (ch >= 'A' && ch <= 'Z')
468
	digit = ch - 'A' + 10;
469
      else if (ch >= 'a' && ch <= 'z')
470
	digit = ch - 'a' + 10;
471
      else
472
	return -1;
473
 
474
      if (digit >= base)
475
	return -1;
476
 
477
      ret = ret * base + digit;
478
    }				/* for */
479
 
480
  return ret;
481
}
482
 
483
 
484
/**
485
 * Process strings, converting \n, \t, \v, \b, \r, \f, \\,
486
 * \ddd, \xdd and \x0dd to actual chars.
487
 * (Note: \x is an extension to support hexadecimal)
488
 * This is used to allow the messages to use c escape sequences.
489
 * Modifies the line in-place (always same size or shorter).
490
 * Returns a pointer to input string.
491
 */
492
 
493
char *
494
processEscChars (char *line)
495
{
496
  /* used when converting \xdd and \ddd (hex or octal) characters */
497
  char ch;
498
#ifdef _MICROC_
499
  char *src;
500
  char *dst;
501
  int chx;
502
  src = line;
503
  dst = line;
504
#else
505
  char *src = line;
506
  char *dst = line;		/* possible as dst is shorter than src */
507
#endif
508
 
509
  if (line == NULL)
510
    return line;
511
 
512
  /* cycle through copying characters, except when a \ is encountered. */
513
  while (*src != '\0')
514
    {
515
      ch = *src;
516
      src++;
517
 
518
      if (ch == '\\')
519
	{
520
	  ch = *src;		/* what follows slash? */
521
	  src++;
522
 
523
	  switch (ch)
524
	    {
525
	    case '\\':		/* a single slash */
526
	      *dst = '\\';
527
	      dst++;
528
	      break;
529
	    case 'n':		/* a newline (linefeed) */
530
	      *dst = '\n';
531
	      dst++;
532
	      break;
533
	    case 'r':		/* a carriage return */
534
	      *dst = '\r';
535
	      dst++;
536
	      break;
537
	    case 't':		/* a horizontal tab */
538
	      *dst = '\t';
539
	      dst++;
540
	      break;
541
	    case 'v':		/* a vertical tab */
542
	      *dst = '\v';
543
	      dst++;
544
	      break;
545
	    case 'b':		/* a backspace */
546
	      *dst = '\b';
547
	      dst++;
548
	      break;
549
	    case 'a':		/* alert */
550
	      *dst = '\a';
551
	      dst++;
552
	      break;
553
	    case 'f':		/* formfeed */
554
	      *dst = '\f';
555
	      dst++;
556
	      break;
557
	    case 'x':		/* extension supporting hex numbers \xdd or \x0dd */
558
	      {
559
#ifdef _MICROC_
560
		chx = mystrtoul (src, 16, 2);	/* get value */
561
#else
562
		int chx = mystrtoul (src, 16, 2);	/* get value */
563
#endif
564
		if (chx >= 0)
565
		  {		/* store character */
566
		    *dst = chx;
567
		    dst++;
568
		    src += 2;
569
		  }
570
		else		/* error so just store x (loose slash) */
571
		  {
572
		    *dst = *src;
573
		    dst++;
574
		  }
575
	      }
576
	      break;
577
	    default:		/* just store letter (loose slash) or handle octal */
578
	      {
579
#ifdef _MICROC_
580
		chx = mystrtoul (src, 8, 3);	/* get value */
581
#else
582
		int chx = mystrtoul (src, 8, 3);	/* get value */
583
#endif
584
		if (chx >= 0)
585
		  {		/* store character */
586
		    *dst = chx;
587
		    dst++;
588
		    src += 3;
589
		  }
590
		else
591
		  {
592
		    *dst = *src;
593
		    dst++;
594
		  }
595
	      }
596
	      break;
597
	    }			/* switch */
598
	}			/* if backslash */
599
      else
600
	{
601
	  *dst = ch;
602
	  dst++;
603
	}
604
    }				/* while */
605
 
606
  /* ensure '\0' terminated */
607
  *dst = '\0';
608
 
609
  return line;
610
}
611
 
612
 
613
int
614
get_char (int file)
615
{
616
#ifdef _MICROC_
617
  int rval;
618
  rval = -1;
619
#else
620
  int rval = -1;
621
#endif
622
 
623
  if (getlrem <= 0)
624
    {				/* (re)init buffer */
625
      getlrem = read (file, getlbuf, sizeof (getlbuf));
626
      if (getlrem <= 0)
627
	return -1;		/* fail: read error / EOF */
628
      getlp = getlbuf;		/* init pointer */
629
    }
630
 
631
  if (getlrem > 0)
632
    {				/* consume byte from buffer */
633
      rval = getlp[0];
634
      getlp++;
635
      getlrem--;
636
    }
637
 
638
  return rval;
639
}
640
 
641
 
642
/**
643
 * Read a line of text from file. You must call this with
644
 * a null buffer or null size to flush buffers when you are
645
 * done with a file before using it on the next file. Cannot
646
 * be used for 2 files at the same time.
647
 */
648
 
649
int
650
get_line (int file, char *str, int size)
651
{
652
  int ch;
653
#ifdef _MICROC_
654
  int success;
655
  success = 0;
656
#else
657
  int success = 0;
658
#endif
659
 
660
  if ((size == 0) || (str == NULL))
661
    {				/* re-init get_line buffers */
662
      getlp = getlbuf;
663
      getlrem = -1;
664
      lastcr = 0;
665
      return 0;
666
    }
667
 
668
  str[0] = '\0';
669
 
670
  while ((size > 0) && (success == 0))
671
    {
672
      ch = get_char (file);
673
      if (ch < 0)
674
	break;			/* (can cause fail if no \n found yet) */
675
 
676
      if (ch == '\r')
677
	ch = get_char (file);	/* ignore \r */
678
 
679
      str[0] = ch;
680
 
681
      if ((ch == '\n') || (ch == '\r'))
682
	{			/* done? */
683
	  str[0] = '\0';
684
	  return 1;		/* success */
685
	}
686
 
687
      str++;
688
      size--;
689
 
690
    }				/* while */
691
 
692
  str[0] = '\0';		/* terminate buffer */
693
 
694
  return success;
695
 
696
}
697
 
698
#endif /*NO_KITTEN */