Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / miscellany / less-177 / charset.c
1 /*
2  * Functions to define the character set
3  * and do things specific to the character set.
4  */
5
6 #include "less.h"
7
8 /*
9  * Predefined character sets,
10  * selected by the LESSCHARSET environment variable.
11  */
12 struct charset {
13         char *name;
14         char *desc;
15 } charsets[] = {
16         { "ascii",      "8bcccbcc18b95.b"       },
17         { "latin1",     "8bcccbcc18b95.33b."    },
18         { NULL }
19 };
20
21 #define IS_BINARY_CHAR  01
22 #define IS_CONTROL_CHAR 02
23
24 static char chardef[256];
25 static char *binfmt = "\\%o";
26 public int binattr = BLINK;
27
28 extern char *getenv();
29
30 /*
31  * Define a charset, given a description string.
32  * The string consists of 256 letters,
33  * one for each character in the charset.
34  * If the string is shorter than 256 letters, missing letters
35  * are taken to be identical to the last one.
36  * A decimal number followed by a letter is taken to be a 
37  * repetition of the letter.
38  *
39  * Each letter is one of:
40  *      . normal character
41  *      b binary character
42  *      c control character
43  */
44         static void
45 ichardef(s)
46         char *s;
47 {
48         register char *cp;
49         register int n;
50         register char v;
51
52         n = 0;
53         cp = chardef;
54         while (*s != '\0')
55         {
56                 switch (*s++)
57                 {
58                 case '.':
59                         v = 0;
60                         break;
61                 case 'c':
62                         v = IS_CONTROL_CHAR;
63                         break;
64                 case 'b':
65                         v = IS_BINARY_CHAR|IS_CONTROL_CHAR;
66                         break;
67
68                 case '0': case '1': case '2': case '3': case '4':
69                 case '5': case '6': case '7': case '8': case '9':
70                         n = (10 * n) + (s[-1] - '0');
71                         continue;
72
73                 default:
74                         error("invalid chardef", NULL_PARG);
75                         quit(1);
76                         /*NOTREACHED*/
77                 }
78
79                 do
80                 {
81                         if (cp >= chardef + sizeof(chardef))
82                         {
83                                 error("chardef longer than 256", NULL_PARG);
84                                 quit(1);
85                                 /*NOTREACHED*/
86                         }
87                         *cp++ = v;
88                 } while (--n > 0);
89                 n = 0;
90         }
91
92         while (cp < chardef + sizeof(chardef))
93                 *cp++ = v;
94 }
95
96 /*
97  * Define a charset, given a charset name.
98  * The valid charset names are listed in the "charsets" array.
99  */
100         static int
101 icharset(name)
102         register char *name;
103 {
104         register struct charset *p;
105
106         if (name == NULL || *name == '\0')
107                 return (0);
108
109         for (p = charsets;  p->name != NULL;  p++)
110         {
111                 if (strcmp(name, p->name) == 0)
112                 {
113                         ichardef(p->desc);
114                         return (1);
115                 }
116         }
117
118         error("invalid charset name", NULL_PARG);
119         quit(1);
120         /*NOTREACHED*/
121 }
122
123 /*
124  * Initialize charset data structures.
125  */
126         public void
127 init_charset()
128 {
129         register char *s;
130
131         /*
132          * Try environment variable LESSCHARSET.
133          * If LESSCHARSET is not set, try LESSCHARDEF.
134          * If LESSCHARDEF is not set, default to "ascii" charset.
135          */
136         s = getenv("LESSCHARSET");
137         if (icharset(s))
138                 return;
139
140         s = getenv("LESSCHARDEF");
141         if (s != NULL && *s != '\0')
142         {
143                 ichardef(s);
144                 return;
145         }
146
147         (void) icharset("ascii");
148
149         s = getenv("LESSBINFMT");
150         if (s != NULL && *s != '\0')
151         {
152                 if (*s == '*')
153                 {
154                         switch (s[1])
155                         {
156                         case 'd':  binattr = BOLD;      break;
157                         case 'k':  binattr = BLINK;     break;
158                         case 'u':  binattr = UNDERLINE; break;
159                         default:   binattr = NORMAL;    break;
160                         }
161                         s += 2;
162                 }
163                 if (*s != '\0')
164                         binfmt = s;
165         }
166 }
167
168 /*
169  * Is a given character a "binary" character?
170  */
171         public int
172 binary_char(c)
173         int c;
174 {
175         return (chardef[c] & IS_BINARY_CHAR);
176 }
177
178 /*
179  * Is a given character a "control" character?
180  */
181         public int
182 control_char(c)
183         int c;
184 {
185         return (chardef[c] & IS_CONTROL_CHAR);
186 }
187
188 /*
189  * Return the printable form of a character.
190  * For example, in the "ascii" charset '\3' is printed as "^C".
191  */
192         public char *
193 prchar(c)
194         int c;
195 {
196         static char buf[8];
197
198         if (!control_char(c))
199                 sprintf(buf, "%c", c);
200         else if (!control_char(c ^ 0100))
201                 sprintf(buf, "^%c", c ^ 0100);
202         else
203                 sprintf(buf, binfmt, c);
204         return (buf);
205 }