]> 4ch.mooo.com Git - 16.git/blob - src/lib/nyan/kitten.c
d72ab2832d9ce1c20d0410b16e6c24ff9676cade
[16.git] / src / lib / nyan / kitten.c
1 \r
2 /* Functions that emulate UNIX catgets */\r
3 \r
4 /* Copyright (C) 1999,2000,2001 Jim Hall <jhall@freedos.org> */\r
5 \r
6 /*\r
7   This library is free software; you can redistribute it and/or\r
8   modify it under the terms of the GNU Lesser General Public\r
9   License as published by the Free Software Foundation; either\r
10   version 2.1 of the License, or (at your option) any later version.\r
11 \r
12   This library is distributed in the hope that it will be useful,\r
13   but WITHOUT ANY WARRANTY; without even the implied warranty of\r
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
15   Lesser General Public License for more details.\r
16 \r
17   You should have received a copy of the GNU Lesser General Public\r
18   License along with this library; if not, write to the Free Software\r
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
20 */\r
21 \r
22 #include <stdio.h>                      /* sprintf */\r
23 #include <stdlib.h>                     /* getenv  */\r
24 #include <string.h>                     /* strchr */\r
25 #include <sys/stat.h>\r
26 #include <io.h>\r
27 #include <fcntl.h>\r
28 \r
29 #include "src/lib/nyan/kitten.h"\r
30 \r
31 \r
32 /* DB stuff */\r
33 \r
34 struct db_list{\r
35   struct db_list *next;\r
36   char *key;\r
37   char *value;\r
38 };\r
39 \r
40 typedef struct db_list db_t;\r
41 \r
42 db_t *db_insert (char *key, char *value);\r
43 db_t *db_fetch (char *key);\r
44 \r
45 \r
46 /* External functions */\r
47 \r
48 int get_line (int file, char *buffer, int size);\r
49 \r
50 \r
51 /* Local prototypes */\r
52 \r
53 int catread (char *catfile);            /* Reads a catfile into the hash */\r
54 char *processEscChars(char *line);  /* Converts c escape sequences to chars */\r
55 \r
56 /* Globals */\r
57 \r
58 nl_catd _kitten_catalog = 0;                    /* _kitten_catalog descriptor, either 0 or 1 */\r
59 \r
60 \r
61 \r
62 #if defined(__SMALL__)                                                  /* it's not very portable ;) */\r
63 \r
64 #include <dos.h>\r
65 /* assert we are running in small model */\r
66 /* else pointer below has to be done correctly */\r
67 char verify_small_pointers[sizeof(void*) == 2 ? 1 : -1];\r
68 \r
69 \r
70 int dos_open(char *filename, int mode);\r
71 #define open(filename,mode) dos_open(filename,mode)\r
72 \r
73 int dos_read(int file, void *ptr, unsigned count);\r
74 #define read(file, ptr, count) dos_read(file,ptr,count)\r
75 \r
76 void dos_close(int file);\r
77 #define close(file) dos_close(file)\r
78 \r
79 #ifdef __WATCOMC__\r
80 \r
81 #pragma aux dos_open = \\r
82 "mov ax, 0x3d00" \\r
83 "int 0x21" \\r
84 "jnc noerror" \\r
85 "mov ax, 0xffff" \\r
86 "noerror:" \\r
87 parm [dx] [ax] value [ax];\r
88 \r
89 #pragma aux dos_read = \\r
90 "mov ah, 0x3f" \\r
91 "int 0x21" \\r
92 "jnc noerror" \\r
93 "xor ax, ax" \\r
94 "noerror:" \\r
95 parm [bx] [dx] [cx] value [ax];\r
96 \r
97 #pragma aux dos_close = \\r
98 "mov ah, 0x3e" \\r
99 "int 0x21" \\r
100 parm [bx];\r
101 \r
102 #else\r
103 \r
104 int dos_open(char *filename, int mode)\r
105 {\r
106   union REGS r;\r
107 \r
108   if (mode);                                    /* mode ignored - readonly supported */\r
109 \r
110   r.h.ah = 0x3d;\r
111   r.h.al = 0;                                   /* read mode only supoported now !! */\r
112   r.x.dx = (unsigned)filename;\r
113   intdos(&r,&r);\r
114 \r
115   if (r.x.cflag)\r
116     return -1;\r
117   return r.x.ax;\r
118 }\r
119 \r
120 int dos_read(int file, void *ptr, unsigned count)\r
121 {\r
122   union REGS r;\r
123 \r
124   r.h.ah = 0x3f;\r
125   r.x.bx = file;\r
126   r.x.cx = count;\r
127   r.x.dx = (unsigned)ptr;\r
128   intdos(&r,&r);\r
129 \r
130   if (r.x.cflag)\r
131     return 0;\r
132   return r.x.ax;\r
133 }\r
134 \r
135 void dos_close(int file)\r
136 {\r
137   union REGS r;\r
138 \r
139   r.h.ah = 0x3e;\r
140   r.x.bx = file;\r
141   intdos(&r,&r);\r
142 }\r
143 \r
144 #endif\r
145 #endif\r
146 \r
147 #ifndef NOCATS\r
148 \r
149 /* Functions */\r
150 \r
151 char *\r
152 __pascal kittengets(int set_number, int message_number, char *message)\r
153 {\r
154   /* get message from a message _kitten_catalog */\r
155 \r
156   /* 'message' should really be const, but not when it is returned */\r
157 \r
158   /* On success, catgets() returns a pointer to an internal buffer\r
159      area containing the null-terminated message string.  On failure,\r
160      catgets() returns the value 'message'.  */\r
161 \r
162   char key[10];\r
163   db_t *ptr;\r
164 \r
165 \r
166   /* fetch the message that goes with the set/message number */\r
167 \r
168   sprintf (key, "%d.%d", set_number, message_number);\r
169   ptr = db_fetch (key);\r
170 \r
171   /* printf("\ncatgets %s\n",message); */\r
172 \r
173   if (ptr)\r
174     {\r
175       /*     printf("------> %s\n",ptr->value); */\r
176 \r
177       return (ptr->value);\r
178     }\r
179 \r
180   /* else */\r
181 \r
182   return (message);\r
183 }\r
184 \r
185 nl_catd\r
186 kittenopen(char *name)\r
187 {\r
188   /* catopen() returns a message _kitten_catalog descriptor of type nl_catd on\r
189      success.  On failure, it returns -1. */\r
190 \r
191   /* 'flag' is completely ignored here. */\r
192 \r
193   char catfile[256];                    /* full path to the msg _kitten_catalog */\r
194   char *nlsptr;                         /* ptr to NLSPATH */\r
195   char *lang;                   /* ptr to LANG */\r
196 \r
197 \r
198 \r
199   /* Open the _kitten_catalog file */\r
200 \r
201   /* The value of `_kitten_catalog' will be set based on catread */\r
202 \r
203   if (_kitten_catalog)\r
204     {\r
205       /* Already one open */\r
206 \r
207       printf("cat already open\n");\r
208       return (-1);\r
209     }\r
210 \r
211   /* If the message _kitten_catalog file name contains a directory separator,\r
212      assume that this is a real path to the _kitten_catalog file.  Note that\r
213      catread will return a true or false value based on its ability\r
214      to read the catfile. */\r
215 \r
216   if (strchr (name, '\\'))\r
217     {\r
218       /* first approximation: 'name' is a filename */\r
219 \r
220       printf("found \\\n");\r
221 \r
222       _kitten_catalog = catread (name);\r
223       return (_kitten_catalog);\r
224     }\r
225 \r
226   /* If the message _kitten_catalog file name does not contain a directory\r
227      separator, then we need to try to locate the message _kitten_catalog on\r
228      our own.  We will use several methods to find it. */\r
229 \r
230   /* We will need the value of LANG, and may need a 2-letter abbrev of\r
231      LANG later on, so get it now. */\r
232 \r
233   lang = getenv ("LANG");\r
234 \r
235   if (lang == NULL)\r
236     {\r
237       /* printf("no lang= found\n"); */\r
238 \r
239       /* Return failure - we won't be able to locate the cat file */\r
240       return (-1);\r
241     }\r
242 \r
243 \r
244   /* step through NLSPATH */\r
245 \r
246   nlsptr = getenv ("NLSPATH");\r
247 \r
248 \r
249   if (nlsptr == NULL)\r
250     {\r
251       /* printf("no NLSPATH= found\n"); */\r
252 \r
253       /* Return failure - we won't be able to locate the cat file */\r
254       return (-1);\r
255     }\r
256 \r
257       /* printf("nlsptr:%s\n",nlsptr); */\r
258 \r
259   while (*nlsptr)\r
260     {\r
261       char *tok = strchr(nlsptr, ';');\r
262       int toklen;\r
263 \r
264 \r
265       if (tok == NULL) tok = nlsptr + strlen(nlsptr);\r
266       toklen=tok-nlsptr;\r
267       /* Try to find the _kitten_catalog file in each path from NLSPATH */\r
268 \r
269       /* Rule #1: %NLSPATH%\%LANG%\cat */\r
270 \r
271       memcpy(catfile,nlsptr,toklen);\r
272       sprintf(catfile+toklen,"\\%s\\%s",lang,name);\r
273 \r
274       _kitten_catalog = catread (catfile);\r
275       if (_kitten_catalog)\r
276         {\r
277           return (_kitten_catalog);\r
278         }\r
279 \r
280       /* Rule #2: %NLSPATH%\cat.%LANG% */\r
281 \r
282       sprintf(catfile+toklen,"\\%s.%s",name, lang);\r
283 \r
284       _kitten_catalog = catread (catfile);\r
285 \r
286       if (_kitten_catalog)\r
287         {\r
288           return (_kitten_catalog);\r
289         }\r
290 \r
291       /* Rule #3: if LANG looks to be in format "en-UK" then\r
292          %NLSPATH%\cat.EN */\r
293 \r
294       if (lang[2] == '-')\r
295         {\r
296           lang[2] = 0;\r
297           sprintf(catfile+toklen,"\\%s.%s",name,lang);\r
298           lang[2] = '-';\r
299 \r
300           _kitten_catalog = catread (catfile);\r
301           if (_kitten_catalog)\r
302             {\r
303               return (_kitten_catalog);\r
304             }\r
305         }\r
306 \r
307       /* Grab next tok for the next while iteration */\r
308       nlsptr = tok;\r
309       if (*nlsptr) nlsptr++;\r
310 \r
311     } /* while tok */\r
312 \r
313   /* We could not find it.  Return failure. */\r
314 \r
315   return (0);\r
316 }\r
317 \r
318 int\r
319 catread (char *catfile)\r
320 {\r
321   int   file;                           /* pointer to the catfile */\r
322   char *key;                            /* part of key-value for hash */\r
323   char *value;                          /* part of key-value for hash */\r
324   char inBuffer[256];                   /* the string read from the file */\r
325 \r
326   /* Open the catfile for reading */\r
327 \r
328   /*printf("catread %s\n",catfile); */\r
329 \r
330   file = open (catfile, O_RDONLY | O_TEXT);\r
331   if (file < 0)\r
332     {\r
333       /* Cannot open the file.  Return failure */\r
334           /* printf("catread: cant read %s\n",catfile); */\r
335       return (0);\r
336     }\r
337 \r
338   /*printf("catread %s success\n",catfile);*/\r
339 \r
340   /* Read the file into memory */\r
341 \r
342   while (get_line (file, inBuffer, sizeof(inBuffer)))\r
343     {\r
344       /* Break into parts.  Entries should be of the form:\r
345          "1.2:This is a message" */\r
346 \r
347       /* A line that starts with '#' is considered a comment, and will\r
348          be thrown away without reading it. */\r
349 \r
350       if (inBuffer[0] == '#')           /* comment */\r
351         continue;\r
352 \r
353       if ((key = strchr (inBuffer, ':')) != NULL)\r
354         {\r
355           *key = 0;\r
356 \r
357           value = processEscChars(key+1);\r
358 \r
359           db_insert (inBuffer, value);\r
360         }\r
361 \r
362     } /* while */\r
363 \r
364   close (file);\r
365 \r
366   /* Return success */\r
367 \r
368   return (1);\r
369 }\r
370 \r
371 void\r
372 kittenclose (void)\r
373 {\r
374   /* close a message _kitten_catalog */\r
375 \r
376   _kitten_catalog = 0;\r
377 }\r
378 \r
379 \r
380 \r
381 /**\r
382  * Process strings, converting \n, \t, \v, \b, \r, \f, \\, \ddd, \xdd and \x0dd\r
383  * to actual chars. (Note: \x is an extension to support hexadecimal)\r
384  * This method is used to allow the message _kitten_catalog to use c escape sequences.\r
385  * Modifies the line in-place (always same size or shorter).\r
386  * Returns a pointer to input string.\r
387  */\r
388 \r
389 int mystrtoul(char __far*src, int base, int size, int __far*error)\r
390 {\r
391   int ret = 0;\r
392 \r
393   *error = 1;\r
394 \r
395   for (; size > 0; size--)\r
396     {\r
397       int digit;\r
398       int ch = *src++;\r
399 \r
400       if (ch >= '0' && ch <= '9') digit = ch - '0';\r
401       else if (ch >= 'A' && ch <= 'Z') digit = ch - 'A' + 10;\r
402       else if (ch >= 'a' && ch <= 'z') digit = ch - 'a' + 10;\r
403       else\r
404         {\r
405           return 0;\r
406         }\r
407 \r
408       if (digit >= base)\r
409         {\r
410           return 0;\r
411         }\r
412 \r
413       ret = ret * base + digit;\r
414     }\r
415 \r
416   *error = 0;\r
417 \r
418   return ret;\r
419 }\r
420 \r
421 \r
422 char *processEscChars(char *line)\r
423 {\r
424   register char *src = line, *dst = line;\r
425 \r
426   /* used when converting \xdd and \ddd (hex or octal) characters */\r
427   char ch;\r
428 \r
429   if (line == NULL) return NULL;\r
430 \r
431   /* cycle through copying characters, except when a \ is encountered. */\r
432   for ( ; *src != '\0'; src++, dst++)\r
433     {\r
434       ch = *src;\r
435 \r
436       if (ch == '\\')\r
437         {\r
438           src++; /* point to char following slash */\r
439           switch (ch = *src)\r
440             {\r
441             case '\\': /* a single slash */\r
442               ch = '\\';\r
443               break;\r
444             case 'n': /* a newline (linefeed) */\r
445               ch = '\n';\r
446               break;\r
447             case 'r': /* a carriage return */\r
448               ch = '\r';\r
449               break;\r
450             case 't': /* a horizontal tab */\r
451               ch = '\t';\r
452               break;\r
453             case 'v': /* a vertical tab */\r
454               ch = '\v';\r
455               break;\r
456             case 'b': /* a backspace */\r
457               ch = '\b';\r
458               break;\r
459             case 'a': /* alert */\r
460               ch = '\a';\r
461               break;\r
462             case 'f': /* formfeed */\r
463               ch = '\f';\r
464               break;\r
465             case 'x': /* extension supporting hex numbers \xdd or \x0dd */\r
466               {\r
467                 int error;\r
468                 ch  = mystrtoul(src+1,16,2, &error); /* get value */\r
469                 if (!error) /* store character */\r
470                   {\r
471                     src += 2;\r
472                   }\r
473                 else /* error so just store x (loose slash) */\r
474                   {\r
475                     ch = *src;\r
476                   }\r
477               }\r
478 \r
479               break;\r
480             default: /* just store letter (loose slash) or handle octal */\r
481 \r
482               {\r
483                 int error;\r
484                 ch  = mystrtoul(src,8,3, &error); /* get value */\r
485                 if (!error) /* store character */\r
486                   {\r
487                     src += 3;\r
488                   }\r
489                 else\r
490                   ch = *src;\r
491               }\r
492 \r
493               break;\r
494             }\r
495         }\r
496 \r
497       *dst = ch;\r
498     }\r
499 \r
500   /* ensure '\0' terminated */\r
501   *dst = '\0';\r
502 \r
503   return line;\r
504 }\r
505 \r
506 \r
507 \r
508 int\r
509 get_line (int file, char *str, int size)\r
510 {\r
511   int success = 0;\r
512 \r
513   /* now, read the string */\r
514 \r
515   for ( ; size > 0; )\r
516     {\r
517       if (read(file,str,1) <= 0)\r
518         break;\r
519 \r
520       success = 1;\r
521 \r
522       if (*str == '\r')\r
523         continue;\r
524 \r
525       if (*str == '\n')\r
526         break;\r
527 \r
528       str++;\r
529       size--;\r
530 \r
531     } /* while */\r
532 \r
533   *str = 0;\r
534 \r
535   return success;\r
536 }\r
537 \r
538 /* Function prototypes */\r
539 \r
540 \r
541 /* Global variables */\r
542 \r
543 static db_t *hashtab[1];\r
544 \r
545 \r
546 /* Functions */\r
547 \r
548 \r
549 /* db_fetch() - Query the hash and return a struct that contains the\r
550    key and the pointer.  The calling function should not look beyond\r
551    that. */\r
552 \r
553 db_t *\r
554 db_fetch (char *s)\r
555 {\r
556   db_t *db_ptr;\r
557 \r
558   for (db_ptr = hashtab[0]; db_ptr != NULL; db_ptr = db_ptr->next)\r
559     {\r
560       if (strcmp (s, db_ptr->key) == 0)\r
561         {\r
562           break;\r
563 \r
564         }\r
565     }\r
566 \r
567 \r
568   return (db_ptr);\r
569 }\r
570 \r
571 /* db_insert() - Inserts a key,value pair into the hash.  If the key\r
572    already exists in the hash, the new value is NOT inserted. */\r
573 \r
574 db_t *\r
575 db_insert (char *key, char *value)\r
576 {\r
577   db_t *db_ptr;\r
578 \r
579   if ((db_ptr = db_fetch (key)) == NULL)\r
580     {\r
581       /* not found */\r
582 \r
583       db_ptr = (db_t *) malloc (sizeof (*db_ptr));\r
584 \r
585       if (db_ptr == NULL || (db_ptr->key = strdup (key)) == NULL)\r
586         {\r
587           return (NULL);\r
588         }\r
589 \r
590       /* insert the key,value into the hash. */\r
591 \r
592       db_ptr->next = hashtab[0];\r
593       hashtab[0] = db_ptr;\r
594     }\r
595 \r
596   else\r
597     {\r
598       /* already there */\r
599 \r
600       free ((void *) db_ptr->value);\r
601     }\r
602 \r
603   if ((db_ptr ->value = strdup (value)) == NULL)\r
604     {\r
605       return (NULL);\r
606     }\r
607 \r
608   /* else */\r
609 \r
610   return (db_ptr);\r
611 }\r
612 \r
613 \r
614 \r
615 #endif /* NOCATS */\r