2
* Copyright (C) 1984-2000 Mark Nudelman
4
* You may distribute under the terms of either the GNU General Public
5
* License or the Less License, as specified in the README file.
7
* For more information about less, or for information on how to
8
* contact the author, see the README file.
13
* Prompting and other messages.
14
* There are three flavors of prompts, SHORT, MEDIUM and LONG,
15
* selected by the -m/-M options.
16
* There is also the "equals message", printed by the = command.
17
* A prompt is a message composed of various pieces, such as the
18
* name of the file being viewed, the percentage into the file, etc.
28
extern int so_s_width, so_e_width;
32
extern int jump_sline;
33
extern IFILE curr_ifile;
36
extern char *editproto;
40
* Prototypes for the three flavors of prompts.
41
* These strings are expanded by pr_expand().
43
static constant char s_proto[] =
44
"?n?f%f .?m(%T %i of %m) ..?e(END) ?x- Next\\: %x..%t";
45
static constant char m_proto[] =
46
"?n?f%f .?m(%T %i of %m) ..?e(END) ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t";
47
static constant char M_proto[] =
48
"?f%f .?n?m(%T %i of %m) ..?ltlines %lt-%lb?L/%L. :byte %bB?s/%s. .?e(END) ?x- Next\\: %x.:?pB%pB\\%..%t";
49
static constant char e_proto[] =
50
"?f%f .?m(%T %i of %m) .?ltlines %lt-%lb?L/%L. .byte %bB?s/%s. ?e(END) :?pB%pB\\%..%t";
51
static constant char h_proto[] =
52
"HELP -- ?eEND -- Press g to see it again:Press RETURN for more., or q when done";
53
static constant char w_proto[] =
56
public char *prproto[3];
57
public char constant *eqproto = e_proto;
58
public char constant *hproto = h_proto;
59
public char constant *wproto = w_proto;
61
static char message[PROMPT_SIZE];
65
* Initialize the prompt prototype strings.
70
prproto[0] = save(s_proto);
71
prproto[1] = save(m_proto);
72
prproto[2] = save(M_proto);
73
eqproto = save(e_proto);
74
hproto = save(h_proto);
75
wproto = save(w_proto);
79
* Append a string to the end of the message.
88
if (mp + len >= message + PROMPT_SIZE)
89
len = message + PROMPT_SIZE - mp - 1;
96
* Append a character to the end of the message.
110
* Append a POSITION (as a decimal integer) to the end of the message.
116
char buf[INT_STRLEN_BOUND(pos) + 1];
117
char *p = buf + sizeof(buf) - 1;
124
*--p = '0' + (pos % 10);
125
while ((pos /= 10) != 0);
132
* Append an integer to the end of the message.
138
char buf[INT_STRLEN_BOUND(n) + 1];
140
sprintf(buf, "%d", n);
145
* Append a question mark to the end of the message.
154
* Return the "current" byte offset in the file.
162
pos = position(where);
163
while (pos == NULL_POSITION && where >= 0 && where < sc_height)
164
pos = position(++where);
165
if (pos == NULL_POSITION)
171
* Return the value of a prototype conditional.
172
* A prototype string may include conditionals which consist of a
173
* question mark followed by a single letter.
174
* Here we decode that letter and return the appropriate boolean value.
185
case 'a': /* Anything in the message yet? */
186
return (mp > message);
187
case 'b': /* Current byte offset known? */
188
return (curr_byte(where) != NULL_POSITION);
190
return (hshift != 0);
191
case 'e': /* At end of file? */
193
case 'f': /* Filename known? */
194
return (strcmp(get_filename(curr_ifile), "-") != 0);
195
case 'l': /* Line number known? */
196
case 'd': /* Same as l */
198
case 'L': /* Final line number known? */
199
case 'D': /* Same as L */
200
return (linenums && ch_length() != NULL_POSITION);
201
case 'm': /* More than one file? */
202
return (ntags() ? (ntags() > 1) : (nifile() > 1));
203
case 'n': /* First prompt in a new file? */
204
return (ntags() ? 1 : new_file);
205
case 'p': /* Percent into file (bytes) known? */
206
return (curr_byte(where) != NULL_POSITION &&
208
case 'P': /* Percent into file (lines) known? */
209
return (currline(where) != 0 &&
210
(len = ch_length()) > 0 &&
211
find_linenum(len) != 0);
212
case 's': /* Size of file known? */
214
return (ch_length() != NULL_POSITION);
215
case 'x': /* Is there a "next" file? */
218
return (next_ifile(curr_ifile) != NULL_IFILE);
224
* Decode a "percent" prototype character.
225
* A prototype string may include various "percent" escapes;
226
* that is, a percent sign followed by a single letter.
227
* Here we decode that letter and take the appropriate action,
228
* usually by appending something to the message being built.
231
protochar(c, where, iseditproto)
243
case 'b': /* Current byte offset */
244
pos = curr_byte(where);
245
if (pos != NULL_POSITION)
253
case 'd': /* Current page number */
255
if (n > 0 && sc_height > 1)
256
ap_int(((n - 1) / (sc_height - 1)) + 1);
260
case 'D': /* Last page number */
262
if (len == NULL_POSITION || len == ch_zero() ||
263
(n = find_linenum(len)) <= 0)
266
ap_int(((n - 1) / (sc_height - 1)) + 1);
269
case 'E': /* Editor name */
273
case 'f': /* File name */
274
ap_str(get_filename(curr_ifile));
276
case 'i': /* Index into list of files */
280
ap_int(get_index(curr_ifile));
282
case 'l': /* Current line number */
289
case 'L': /* Final line number */
291
if (len == NULL_POSITION || len == ch_zero() ||
292
(n = find_linenum(len)) <= 0)
297
case 'm': /* Number of files */
304
case 'p': /* Percent into file (bytes) */
305
pos = curr_byte(where);
307
if (pos != NULL_POSITION && len > 0)
308
ap_int(percentage(pos,len));
312
case 'P': /* Percent into file (lines) */
313
pos = (POSITION) currline(where);
315
(len = ch_length()) == NULL_POSITION || len == ch_zero() ||
316
(n = find_linenum(len)) <= 0)
319
ap_int(percentage(pos, (POSITION)n));
321
case 's': /* Size of file */
324
if (len != NULL_POSITION)
329
case 't': /* Truncate trailing spaces in the message */
330
while (mp > message && mp[-1] == ' ')
333
case 'T': /* Type of list */
339
case 'x': /* Name of next file */
340
h = next_ifile(curr_ifile);
342
ap_str(get_filename(h));
350
* Skip a false conditional.
351
* When a false condition is found (either a false IF or the ELSE part
352
* of a true IF), this routine scans the prototype string to decide
353
* where to resume parsing the string.
354
* We must keep track of nested IFs and skip them properly.
360
register int iflevel;
363
* We came in here after processing a ? or :,
364
* so we start nested one level deep.
368
for (;;) switch (*++p)
372
* Start of a nested IF.
379
* If this matches the IF we came in here with,
388
* If this matches the IF we came in here with,
396
* Backslash escapes the next character.
402
* Whoops. Hit end of string.
403
* This is a malformed conditional, but just treat it
404
* as if all active conditionals ends here.
412
* Decode a char that represents a position on the screen.
421
case 'b': case 'd': case 'l': case 'p': case 'P':
424
case 't': *wp = TOP; break;
425
case 'm': *wp = MIDDLE; break;
426
case 'b': *wp = BOTTOM; break;
427
case 'B': *wp = BOTTOM_PLUS_ONE; break;
428
case 'j': *wp = adjsline(jump_sline); break;
429
default: *wp = TOP; p--; break;
436
* Construct a message based on a prototype string.
439
pr_expand(proto, maxwidth)
452
for (p = proto; *p != '\0'; p++)
456
default: /* Just put the character in the message */
459
case '\\': /* Backslash escapes the next character */
463
case '?': /* Conditional (IF) */
464
if ((c = *++p) == '\0')
469
p = wherechar(p, &where);
477
case '.': /* ENDIF */
479
case '%': /* Percent escape */
480
if ((c = *++p) == '\0')
485
p = wherechar(p, &where);
488
(proto == editproto));
500
if (maxwidth > 0 && mp >= message + maxwidth)
503
* Message is too long.
504
* Return just the final portion of it.
506
return (mp - maxwidth);
512
* Return a message suitable for printing by the "=" command.
517
return (pr_expand(eqproto, 0));
522
* This depends on the prompt type (SHORT, MEDIUM, LONG), etc.
523
* If we can't come up with an appropriate prompt, return NULL
524
* and the caller will prompt with a colon.
531
prompt = pr_expand((ch_getflags() & CH_HELPFILE) ?
532
hproto : prproto[pr_type],
533
sc_width-so_s_width-so_e_width-2);
539
* Return a message suitable for printing while waiting in the F command.
544
return (pr_expand(wproto, sc_width-so_s_width-so_e_width-2));