Repository navigation
Expand file tree
/
Copy pathlmsg.c
More file actions
218 lines (203 loc) · 4.95 KB
/
Copy pathlmsg.c
File metadata and controls
218 lines (203 loc) · 4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
/*
* Copyright (C) 1984-2026 Mark Nudelman
*
* You may distribute under the terms of either the GNU General Public
* License or the Less License, as specified in the README file.
*
* For more information, see the README file.
*/
#include "less.h"
struct lmsg_sym { lessmsg_id id; constant char *sym; };
/*
* lmsgs is the array of all messages, indexed by lmsg id.
* Initialize it to the default messages.
* Individual message can be overridden by a custom lessmsg file.
*/
#undef M
#define M(sym,msg) msg,
static char *lmsgs[] = {
NULL, /* id 0 (LM_NULL) is not in lessmsg.inc */
#include "lessmsg.inc"
};
/*
* lmsg_syms is the map of symbol names to lmsg ids.
*/
#undef M
#define M(sym,msg) { LM_##sym, #sym },
static constant struct lmsg_sym lmsg_syms[] = {
#include "lessmsg.inc"
M(HELP,"")
};
/*
* For historical reasons the help file is stored separately rather than
* in the lmsgs array but it can still be overridden by a lessmsg file.
*/
public char *help_data;
public int size_help_data;
extern char helpdata[];
extern int size_helpdata;
/*
* Report an error in a lessmsg file.
*/
static void lmsg_error(constant char *err, constant char *lmsg_file, int linenum)
{
PARG parg[3];
parg[0].p_string = lmsg_file;
parg[1].p_int = linenum;
parg[2].p_string = err;
error("Error in lessmsg file %s line %d: %s", parg);
}
/*
* Return a numeric lmsg id given a symbolic name.
*/
static lessmsg_id lmsg_id(constant char *sym)
{
size_t i;
for (i = 0; i < countof(lmsg_syms); i++)
if (strcmp(sym, lmsg_syms[i].sym) == 0)
return lmsg_syms[i].id;
return LM_NULL;
}
/*
* Return a numeric char value from a string.
*/
static char numeric_char(char **pp, int radix, constant char *lmsg_file, int linenum)
{
constant int max_chars = (radix == 16) ? 2 : 3;
char nbuf[4]; /* max_chars+1 */
char *p = *pp;
int val;
strncpy(nbuf, p, max_chars);
nbuf[max_chars] = '\0';
val = lstrtoi(nbuf, &p, radix);
if (p == nbuf || val < 0 || val > 255)
{
lmsg_error("invalid numeric char value", lmsg_file, linenum);
return '?';
}
*pp += ptr_diff(p,nbuf);
return (char) val;
}
/*
* Process one character in a lessmsg file.
*/
static char * lmsg_char(char *mp, char *line, size_t line_size, FILE* fd, struct xbuffer *xbuf, constant char *lmsg_file, int *linenum)
{
if (*mp != '\\')
xbuf_add_char(xbuf, *mp++);
else
{
/* Handle backslash escape. */
switch (*++mp)
{
case '\0': break;
case 'n': xbuf_add_char(xbuf, '\n'); ++mp; break;
case 'r': xbuf_add_char(xbuf, '\r'); ++mp; break;
case 't': xbuf_add_char(xbuf, '\t'); ++mp; break;
case '\n': case '\r': /* continued on next line */
if (fgets(line, line_size, fd) != NULL)
{
++*linenum;
mp = line;
}
break;
case 'x': /* hex value */
++mp;
xbuf_add_char(xbuf, numeric_char(&mp, 16, lmsg_file, *linenum));
break;
default:
if (*mp >= '0' && *mp <= '7') /* octal value */
xbuf_add_char(xbuf, numeric_char(&mp, 8, lmsg_file, *linenum));
else /* literal char */
xbuf_add_char(xbuf, *mp++);
break;
}
}
return mp;
}
/*
* Process one line in a lessmsg file.
*/
static lbool lmsg_line(char *line, size_t line_size, FILE* fd, struct xbuffer *xbuf, constant char *lmsg_file, int *linenum)
{
lessmsg_id id;
char *msg;
char *mp;
char *sym = skipsp(line);
if (sym[0] == '\n' || sym[0] == '\r' || sym[0] == '#')
return TRUE; /* skip comments and blank lines */
msg = strchr(sym, ' ');
if (msg == NULL)
{
lmsg_error("missing space", lmsg_file, *linenum);
return FALSE;
}
*msg++ = '\0'; /* terminate symbol */
msg = skipsp(msg);
id = lmsg_id(sym);
if (id == 0)
{
lmsg_error("unknown lessmsg symbol", lmsg_file, *linenum);
return FALSE;
}
/* Copy the message string into xbuf. */
xbuf_reset(xbuf);
for (mp = msg; *mp != '\0' && *mp != '\n' && *mp != '\r'; )
mp = lmsg_char(mp, line, line_size, fd, xbuf, lmsg_file, linenum);
/* Store the message string in the table. */
msg = saven(xbuf_char_data(xbuf), xbuf->end);
if (id == LM_HELP)
{
help_data = msg;
size_help_data = xbuf->end;
} else
lmsgs[id] = msg;
return TRUE;
}
/*
* Initialize the lmsgs array from an lmsg file.
*/
public void lmsg_init(constant char *lmsg_file)
{
FILE *fd;
char line[512];
struct xbuffer xbuf;
int linenum;
PARG parg;
help_data = helpdata;
size_help_data = size_helpdata;
if (isnullenv(lmsg_file))
return;
fd = fopen(lmsg_file, "r");
if (fd == NULL)
{
parg.p_string = lmsg_file;
error("Cannot open lessmsg file %s", &parg);
return;
}
xbuf_init(&xbuf); /* for efficiency, init once here and reuse for each line */
linenum = 0;
while (fgets(line, sizeof(line), fd) != NULL)
{
++linenum;
lmsg_line(line, sizeof(line), fd, &xbuf, lmsg_file, &linenum);
}
xbuf_deinit(&xbuf);
fclose(fd);
}
/*
* Return the string associated with a numeric lmsg id.
*/
public constant char * lmsg(lessmsg_id id)
{
#if 1
if (id <= 0 || id >= countof(lmsgs))
{
PARG parg;
parg.p_int = (int) id;
error("invalid lessmsg id %d", &parg);
return NULL;
}
#endif
return lmsgs[id];
}