Subversion Repositories SvarDOS

Rev

Rev 244 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 244 Rev 269
1
/* Functions that emulate UNIX catgets */
1
/* Functions that emulate UNIX catgets */
2
 
2
 
3
/* Copyright (C) 1999,2000,2001 Jim Hall <jhall@freedos.org> */
3
/* Copyright (C) 1999,2000,2001 Jim Hall <jhall@freedos.org> */
4
/* Kitten version 2003 by Tom Ehlert, heavily modified by Eric Auer 2003 */
4
/* Kitten version 2003 by Tom Ehlert, heavily modified by Eric Auer 2003 */
5
 
5
 
6
/*
6
/*
7
  This library is free software; you can redistribute it and/or
7
  This library is free software; you can redistribute it and/or
8
  modify it under the terms of the GNU Lesser General Public
8
  modify it under the terms of the GNU Lesser General Public
9
  License as published by the Free Software Foundation; either
9
  License as published by the Free Software Foundation; either
10
  version 2.1 of the License, or (at your option) any later version.
10
  version 2.1 of the License, or (at your option) any later version.
11

11

12
  This library is distributed in the hope that it will be useful,
12
  This library is distributed in the hope that it will be useful,
13
  but WITHOUT ANY WARRANTY; without even the implied warranty of
13
  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
  Lesser General Public License for more details.
15
  Lesser General Public License for more details.
16

16

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