1/* 2 * Copyright (C) 1984-2000 Mark Nudelman 3 * 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. 6 * 7 * For more information about less, or for information on how to 8 * contact the author, see the README file. 9 */ 10 11 12/* 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. 19 */ 20 21#include "less.h" 22#include "position.h" 23 24extern int pr_type; 25extern int hit_eof; 26extern int new_file; 27extern int sc_width; 28extern int so_s_width, so_e_width; 29extern int linenums; 30extern int hshift; 31extern int sc_height; 32extern int jump_sline; 33extern IFILE curr_ifile; 34#if EDITOR 35extern char *editor; 36extern char *editproto; 37#endif 38 39/* 40 * Prototypes for the three flavors of prompts. 41 * These strings are expanded by pr_expand(). 42 */ 43static constant char s_proto[] = 44 "?n?f%f .?m(file %i of %m) ..?e(END) ?x- Next\\: %x..%t"; 45static constant char m_proto[] = 46 "?n?f%f .?m(file %i of %m) ..?e(END) ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t"; 47static constant char M_proto[] = 48 "?f%f .?n?m(file %i of %m) ..?ltlines %lt-%lb?L/%L. :byte %bB?s/%s. .?e(END) ?x- Next\\: %x.:?pB%pB\\%..%t"; 49static constant char e_proto[] = 50 "?f%f .?m(file %i of %m) .?ltlines %lt-%lb?L/%L. .byte %bB?s/%s. ?e(END) :?pB%pB\\%..%t"; 51static constant char h_proto[] = 52 "HELP -- ?eEND -- Press g to see it again:Press RETURN for more., or q when done"; 53 54public char *prproto[3]; 55public char constant *eqproto = e_proto; 56public char constant *hproto = h_proto; 57 58static char message[PROMPT_SIZE]; 59static char *mp; 60 61/* 62 * Initialize the prompt prototype strings. 63 */ 64 public void 65init_prompt() 66{ 67 prproto[0] = save(s_proto); 68 prproto[1] = save(m_proto); 69 prproto[2] = save(M_proto); 70 eqproto = save(e_proto); 71 hproto = save(h_proto); 72} 73 74/* 75 * Append a string to the end of the message. 76 */ 77 static void 78ap_str(s) 79 char *s; 80{ 81 int len; 82 83 len = strlen(s); 84 if (mp + len >= message + PROMPT_SIZE) 85 len = message + PROMPT_SIZE - mp - 1; 86 strncpy(mp, s, len); 87 mp += len; 88 *mp = '\0'; 89} 90 91/* 92 * Append a character to the end of the message. 93 */ 94 static void 95ap_char(c) 96 char c; 97{ 98 char buf[2]; 99 100 buf[0] = c; 101 buf[1] = '\0'; 102 ap_str(buf); 103} 104 105/* 106 * Append a POSITION (as a decimal integer) to the end of the message. 107 */ 108 static void 109ap_pos(pos) 110 POSITION pos; 111{ 112 char buf[MAX_PRINT_POSITION]; 113
| 2/* 3 * Copyright (C) 1984-2000 Mark Nudelman 4 * 5 * You may distribute under the terms of either the GNU General Public 6 * License or the Less License, as specified in the README file. 7 * 8 * For more information about less, or for information on how to 9 * contact the author, see the README file. 10 */ 11 12 13/* 14 * Prompting and other messages. 15 * There are three flavors of prompts, SHORT, MEDIUM and LONG, 16 * selected by the -m/-M options. 17 * There is also the "equals message", printed by the = command. 18 * A prompt is a message composed of various pieces, such as the 19 * name of the file being viewed, the percentage into the file, etc. 20 */ 21 22#include "less.h" 23#include "position.h" 24 25extern int pr_type; 26extern int hit_eof; 27extern int new_file; 28extern int sc_width; 29extern int so_s_width, so_e_width; 30extern int linenums; 31extern int hshift; 32extern int sc_height; 33extern int jump_sline; 34extern IFILE curr_ifile; 35#if EDITOR 36extern char *editor; 37extern char *editproto; 38#endif 39 40/* 41 * Prototypes for the three flavors of prompts. 42 * These strings are expanded by pr_expand(). 43 */ 44static constant char s_proto[] = 45 "?n?f%f .?m(file %i of %m) ..?e(END) ?x- Next\\: %x..%t"; 46static constant char m_proto[] = 47 "?n?f%f .?m(file %i of %m) ..?e(END) ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t"; 48static constant char M_proto[] = 49 "?f%f .?n?m(file %i of %m) ..?ltlines %lt-%lb?L/%L. :byte %bB?s/%s. .?e(END) ?x- Next\\: %x.:?pB%pB\\%..%t"; 50static constant char e_proto[] = 51 "?f%f .?m(file %i of %m) .?ltlines %lt-%lb?L/%L. .byte %bB?s/%s. ?e(END) :?pB%pB\\%..%t"; 52static constant char h_proto[] = 53 "HELP -- ?eEND -- Press g to see it again:Press RETURN for more., or q when done"; 54 55public char *prproto[3]; 56public char constant *eqproto = e_proto; 57public char constant *hproto = h_proto; 58 59static char message[PROMPT_SIZE]; 60static char *mp; 61 62/* 63 * Initialize the prompt prototype strings. 64 */ 65 public void 66init_prompt() 67{ 68 prproto[0] = save(s_proto); 69 prproto[1] = save(m_proto); 70 prproto[2] = save(M_proto); 71 eqproto = save(e_proto); 72 hproto = save(h_proto); 73} 74 75/* 76 * Append a string to the end of the message. 77 */ 78 static void 79ap_str(s) 80 char *s; 81{ 82 int len; 83 84 len = strlen(s); 85 if (mp + len >= message + PROMPT_SIZE) 86 len = message + PROMPT_SIZE - mp - 1; 87 strncpy(mp, s, len); 88 mp += len; 89 *mp = '\0'; 90} 91 92/* 93 * Append a character to the end of the message. 94 */ 95 static void 96ap_char(c) 97 char c; 98{ 99 char buf[2]; 100 101 buf[0] = c; 102 buf[1] = '\0'; 103 ap_str(buf); 104} 105 106/* 107 * Append a POSITION (as a decimal integer) to the end of the message. 108 */ 109 static void 110ap_pos(pos) 111 POSITION pos; 112{ 113 char buf[MAX_PRINT_POSITION]; 114
|
115 ap_str(buf); 116} 117 118/* 119 * Append an integer to the end of the message. 120 */ 121 static void 122ap_int(n) 123 int n; 124{ 125 char buf[MAX_PRINT_INT]; 126 127 sprintf(buf, "%d", n); 128 ap_str(buf); 129} 130 131/* 132 * Append a question mark to the end of the message. 133 */ 134 static void 135ap_quest() 136{ 137 ap_str("?"); 138} 139 140/* 141 * Return the "current" byte offset in the file. 142 */ 143 static POSITION 144curr_byte(where) 145 int where; 146{ 147 POSITION pos; 148 149 pos = position(where); 150 while (pos == NULL_POSITION && where >= 0 && where < sc_height) 151 pos = position(++where); 152 if (pos == NULL_POSITION) 153 pos = ch_length(); 154 return (pos); 155} 156 157/* 158 * Return the value of a prototype conditional. 159 * A prototype string may include conditionals which consist of a 160 * question mark followed by a single letter. 161 * Here we decode that letter and return the appropriate boolean value. 162 */ 163 static int 164cond(c, where) 165 char c; 166 int where; 167{ 168 POSITION len; 169 170 switch (c) 171 { 172 case 'a': /* Anything in the message yet? */ 173 return (mp > message); 174 case 'b': /* Current byte offset known? */ 175 return (curr_byte(where) != NULL_POSITION); 176 case 'c': 177 return (hshift != 0); 178 case 'e': /* At end of file? */ 179 return (hit_eof); 180 case 'f': /* Filename known? */ 181 return (strcmp(get_filename(curr_ifile), "-") != 0); 182 case 'l': /* Line number known? */ 183 case 'd': /* Same as l */ 184 return (linenums); 185 case 'L': /* Final line number known? */ 186 case 'D': /* Same as L */ 187 return (linenums && ch_length() != NULL_POSITION); 188 case 'm': /* More than one file? */ 189 return (nifile() > 1); 190 case 'n': /* First prompt in a new file? */ 191 return (new_file); 192 case 'p': /* Percent into file (bytes) known? */ 193 return (curr_byte(where) != NULL_POSITION && 194 ch_length() > 0); 195 case 'P': /* Percent into file (lines) known? */ 196 return (currline(where) != 0 && 197 (len = ch_length()) > 0 && 198 find_linenum(len) != 0); 199 case 's': /* Size of file known? */ 200 case 'B': 201 return (ch_length() != NULL_POSITION); 202 case 'x': /* Is there a "next" file? */ 203 return (next_ifile(curr_ifile) != NULL_IFILE); 204 } 205 return (0); 206} 207 208/* 209 * Decode a "percent" prototype character. 210 * A prototype string may include various "percent" escapes; 211 * that is, a percent sign followed by a single letter. 212 * Here we decode that letter and take the appropriate action, 213 * usually by appending something to the message being built. 214 */ 215 static void 216protochar(c, where, iseditproto) 217 int c; 218 int where; 219 int iseditproto; 220{ 221 POSITION pos; 222 POSITION len; 223 int n; 224 IFILE h; 225 char *s; 226 char *escs; 227 228 switch (c) 229 { 230 case 'b': /* Current byte offset */ 231 pos = curr_byte(where); 232 if (pos != NULL_POSITION) 233 ap_pos(pos); 234 else 235 ap_quest(); 236 break; 237 case 'c': 238 ap_int(hshift); 239 break; 240 case 'd': /* Current page number */ 241 n = currline(where); 242 if (n > 0 && sc_height > 1) 243 ap_int(((n - 1) / (sc_height - 1)) + 1); 244 else 245 ap_quest(); 246 break; 247 case 'D': /* Last page number */ 248 len = ch_length(); 249 if (len == NULL_POSITION || len == ch_zero() || 250 (n = find_linenum(len)) <= 0) 251 ap_quest(); 252 else 253 ap_int(((n - 1) / (sc_height - 1)) + 1); 254 break; 255#if EDITOR 256 case 'E': /* Editor name */ 257 ap_str(editor); 258 break; 259#endif 260 case 'f': /* File name */ 261 s = unquote_file(get_filename(curr_ifile)); 262 /* 263 * If we are expanding editproto then we escape metachars. 264 * This allows us to run the editor on files with funny names. 265 */ 266 if (iseditproto && (escs = esc_metachars(s)) != NULL) 267 { 268 free(s); 269 s = escs; 270 } 271 ap_str(s); 272 free(s); 273 break; 274 case 'i': /* Index into list of files */ 275 ap_int(get_index(curr_ifile)); 276 break; 277 case 'l': /* Current line number */ 278 n = currline(where); 279 if (n != 0) 280 ap_int(n); 281 else 282 ap_quest(); 283 break; 284 case 'L': /* Final line number */ 285 len = ch_length(); 286 if (len == NULL_POSITION || len == ch_zero() || 287 (n = find_linenum(len)) <= 0) 288 ap_quest(); 289 else 290 ap_int(n-1); 291 break; 292 case 'm': /* Number of files */ 293 ap_int(nifile()); 294 break; 295 case 'p': /* Percent into file (bytes) */ 296 pos = curr_byte(where); 297 len = ch_length(); 298 if (pos != NULL_POSITION && len > 0) 299 ap_int(percentage(pos,len)); 300 else 301 ap_quest(); 302 break; 303 case 'P': /* Percent into file (lines) */ 304 pos = (POSITION) currline(where); 305 if (pos == 0 || 306 (len = ch_length()) == NULL_POSITION || len == ch_zero() || 307 (n = find_linenum(len)) <= 0) 308 ap_quest(); 309 else 310 ap_int(percentage(pos, (POSITION)n)); 311 break; 312 case 's': /* Size of file */ 313 case 'B': 314 len = ch_length(); 315 if (len != NULL_POSITION) 316 ap_pos(len); 317 else 318 ap_quest(); 319 break; 320 case 't': /* Truncate trailing spaces in the message */ 321 while (mp > message && mp[-1] == ' ') 322 mp--; 323 break; 324 case 'x': /* Name of next file */ 325 h = next_ifile(curr_ifile); 326 if (h != NULL_IFILE) 327 { 328 s = unquote_file(get_filename(h)); 329 ap_str(s); 330 free(s); 331 } else 332 ap_quest(); 333 break; 334 } 335} 336 337/* 338 * Skip a false conditional. 339 * When a false condition is found (either a false IF or the ELSE part 340 * of a true IF), this routine scans the prototype string to decide 341 * where to resume parsing the string. 342 * We must keep track of nested IFs and skip them properly. 343 */ 344 static char * 345skipcond(p) 346 register char *p; 347{ 348 register int iflevel; 349 350 /* 351 * We came in here after processing a ? or :, 352 * so we start nested one level deep. 353 */ 354 iflevel = 1; 355 356 for (;;) switch (*++p) 357 { 358 case '?': 359 /* 360 * Start of a nested IF. 361 */ 362 iflevel++; 363 break; 364 case ':': 365 /* 366 * Else. 367 * If this matches the IF we came in here with, 368 * then we're done. 369 */ 370 if (iflevel == 1) 371 return (p); 372 break; 373 case '.': 374 /* 375 * Endif. 376 * If this matches the IF we came in here with, 377 * then we're done. 378 */ 379 if (--iflevel == 0) 380 return (p); 381 break; 382 case '\\': 383 /* 384 * Backslash escapes the next character. 385 */ 386 ++p; 387 break; 388 case '\0': 389 /* 390 * Whoops. Hit end of string. 391 * This is a malformed conditional, but just treat it 392 * as if all active conditionals ends here. 393 */ 394 return (p-1); 395 } 396 /*NOTREACHED*/ 397} 398 399/* 400 * Decode a char that represents a position on the screen. 401 */ 402 static char * 403wherechar(p, wp) 404 char *p; 405 int *wp; 406{ 407 switch (*p) 408 { 409 case 'b': case 'd': case 'l': case 'p': case 'P': 410 switch (*++p) 411 { 412 case 't': *wp = TOP; break; 413 case 'm': *wp = MIDDLE; break; 414 case 'b': *wp = BOTTOM; break; 415 case 'B': *wp = BOTTOM_PLUS_ONE; break; 416 case 'j': *wp = adjsline(jump_sline); break; 417 default: *wp = TOP; p--; break; 418 } 419 } 420 return (p); 421} 422 423/* 424 * Construct a message based on a prototype string. 425 */ 426 public char * 427pr_expand(proto, maxwidth) 428 char *proto; 429 int maxwidth; 430{ 431 register char *p; 432 register int c; 433 int where; 434 435 mp = message; 436 437 if (*proto == '\0') 438 return (""); 439 440 for (p = proto; *p != '\0'; p++) 441 { 442 switch (*p) 443 { 444 default: /* Just put the character in the message */ 445 ap_char(*p); 446 break; 447 case '\\': /* Backslash escapes the next character */ 448 p++; 449 ap_char(*p); 450 break; 451 case '?': /* Conditional (IF) */ 452 if ((c = *++p) == '\0') 453 --p; 454 else 455 { 456 where = 0; 457 p = wherechar(p, &where); 458 if (!cond(c, where)) 459 p = skipcond(p); 460 } 461 break; 462 case ':': /* ELSE */ 463 p = skipcond(p); 464 break; 465 case '.': /* ENDIF */ 466 break; 467 case '%': /* Percent escape */ 468 if ((c = *++p) == '\0') 469 --p; 470 else 471 { 472 where = 0; 473 p = wherechar(p, &where); 474 protochar(c, where, 475#if EDITOR 476 (proto == editproto)); 477#else 478 0); 479#endif 480 481 } 482 break; 483 } 484 } 485 486 new_file = 0; 487 if (mp == message) 488 return (NULL); 489 if (maxwidth > 0 && mp >= message + maxwidth) 490 { 491 /* 492 * Message is too long. 493 * Return just the final portion of it. 494 */ 495 return (mp - maxwidth); 496 } 497 return (message); 498} 499 500/* 501 * Return a message suitable for printing by the "=" command. 502 */ 503 public char * 504eq_message() 505{ 506 return (pr_expand(eqproto, 0)); 507} 508 509/* 510 * Return a prompt. 511 * This depends on the prompt type (SHORT, MEDIUM, LONG), etc. 512 * If we can't come up with an appropriate prompt, return NULL 513 * and the caller will prompt with a colon. 514 */ 515 public char * 516pr_string() 517{ 518 if (ch_getflags() & CH_HELPFILE) 519 return (pr_expand(hproto, sc_width-so_s_width-so_e_width-2)); 520 return (pr_expand(prproto[pr_type], sc_width-so_s_width-so_e_width-2)); 521}
| 116 ap_str(buf); 117} 118 119/* 120 * Append an integer to the end of the message. 121 */ 122 static void 123ap_int(n) 124 int n; 125{ 126 char buf[MAX_PRINT_INT]; 127 128 sprintf(buf, "%d", n); 129 ap_str(buf); 130} 131 132/* 133 * Append a question mark to the end of the message. 134 */ 135 static void 136ap_quest() 137{ 138 ap_str("?"); 139} 140 141/* 142 * Return the "current" byte offset in the file. 143 */ 144 static POSITION 145curr_byte(where) 146 int where; 147{ 148 POSITION pos; 149 150 pos = position(where); 151 while (pos == NULL_POSITION && where >= 0 && where < sc_height) 152 pos = position(++where); 153 if (pos == NULL_POSITION) 154 pos = ch_length(); 155 return (pos); 156} 157 158/* 159 * Return the value of a prototype conditional. 160 * A prototype string may include conditionals which consist of a 161 * question mark followed by a single letter. 162 * Here we decode that letter and return the appropriate boolean value. 163 */ 164 static int 165cond(c, where) 166 char c; 167 int where; 168{ 169 POSITION len; 170 171 switch (c) 172 { 173 case 'a': /* Anything in the message yet? */ 174 return (mp > message); 175 case 'b': /* Current byte offset known? */ 176 return (curr_byte(where) != NULL_POSITION); 177 case 'c': 178 return (hshift != 0); 179 case 'e': /* At end of file? */ 180 return (hit_eof); 181 case 'f': /* Filename known? */ 182 return (strcmp(get_filename(curr_ifile), "-") != 0); 183 case 'l': /* Line number known? */ 184 case 'd': /* Same as l */ 185 return (linenums); 186 case 'L': /* Final line number known? */ 187 case 'D': /* Same as L */ 188 return (linenums && ch_length() != NULL_POSITION); 189 case 'm': /* More than one file? */ 190 return (nifile() > 1); 191 case 'n': /* First prompt in a new file? */ 192 return (new_file); 193 case 'p': /* Percent into file (bytes) known? */ 194 return (curr_byte(where) != NULL_POSITION && 195 ch_length() > 0); 196 case 'P': /* Percent into file (lines) known? */ 197 return (currline(where) != 0 && 198 (len = ch_length()) > 0 && 199 find_linenum(len) != 0); 200 case 's': /* Size of file known? */ 201 case 'B': 202 return (ch_length() != NULL_POSITION); 203 case 'x': /* Is there a "next" file? */ 204 return (next_ifile(curr_ifile) != NULL_IFILE); 205 } 206 return (0); 207} 208 209/* 210 * Decode a "percent" prototype character. 211 * A prototype string may include various "percent" escapes; 212 * that is, a percent sign followed by a single letter. 213 * Here we decode that letter and take the appropriate action, 214 * usually by appending something to the message being built. 215 */ 216 static void 217protochar(c, where, iseditproto) 218 int c; 219 int where; 220 int iseditproto; 221{ 222 POSITION pos; 223 POSITION len; 224 int n; 225 IFILE h; 226 char *s; 227 char *escs; 228 229 switch (c) 230 { 231 case 'b': /* Current byte offset */ 232 pos = curr_byte(where); 233 if (pos != NULL_POSITION) 234 ap_pos(pos); 235 else 236 ap_quest(); 237 break; 238 case 'c': 239 ap_int(hshift); 240 break; 241 case 'd': /* Current page number */ 242 n = currline(where); 243 if (n > 0 && sc_height > 1) 244 ap_int(((n - 1) / (sc_height - 1)) + 1); 245 else 246 ap_quest(); 247 break; 248 case 'D': /* Last page number */ 249 len = ch_length(); 250 if (len == NULL_POSITION || len == ch_zero() || 251 (n = find_linenum(len)) <= 0) 252 ap_quest(); 253 else 254 ap_int(((n - 1) / (sc_height - 1)) + 1); 255 break; 256#if EDITOR 257 case 'E': /* Editor name */ 258 ap_str(editor); 259 break; 260#endif 261 case 'f': /* File name */ 262 s = unquote_file(get_filename(curr_ifile)); 263 /* 264 * If we are expanding editproto then we escape metachars. 265 * This allows us to run the editor on files with funny names. 266 */ 267 if (iseditproto && (escs = esc_metachars(s)) != NULL) 268 { 269 free(s); 270 s = escs; 271 } 272 ap_str(s); 273 free(s); 274 break; 275 case 'i': /* Index into list of files */ 276 ap_int(get_index(curr_ifile)); 277 break; 278 case 'l': /* Current line number */ 279 n = currline(where); 280 if (n != 0) 281 ap_int(n); 282 else 283 ap_quest(); 284 break; 285 case 'L': /* Final line number */ 286 len = ch_length(); 287 if (len == NULL_POSITION || len == ch_zero() || 288 (n = find_linenum(len)) <= 0) 289 ap_quest(); 290 else 291 ap_int(n-1); 292 break; 293 case 'm': /* Number of files */ 294 ap_int(nifile()); 295 break; 296 case 'p': /* Percent into file (bytes) */ 297 pos = curr_byte(where); 298 len = ch_length(); 299 if (pos != NULL_POSITION && len > 0) 300 ap_int(percentage(pos,len)); 301 else 302 ap_quest(); 303 break; 304 case 'P': /* Percent into file (lines) */ 305 pos = (POSITION) currline(where); 306 if (pos == 0 || 307 (len = ch_length()) == NULL_POSITION || len == ch_zero() || 308 (n = find_linenum(len)) <= 0) 309 ap_quest(); 310 else 311 ap_int(percentage(pos, (POSITION)n)); 312 break; 313 case 's': /* Size of file */ 314 case 'B': 315 len = ch_length(); 316 if (len != NULL_POSITION) 317 ap_pos(len); 318 else 319 ap_quest(); 320 break; 321 case 't': /* Truncate trailing spaces in the message */ 322 while (mp > message && mp[-1] == ' ') 323 mp--; 324 break; 325 case 'x': /* Name of next file */ 326 h = next_ifile(curr_ifile); 327 if (h != NULL_IFILE) 328 { 329 s = unquote_file(get_filename(h)); 330 ap_str(s); 331 free(s); 332 } else 333 ap_quest(); 334 break; 335 } 336} 337 338/* 339 * Skip a false conditional. 340 * When a false condition is found (either a false IF or the ELSE part 341 * of a true IF), this routine scans the prototype string to decide 342 * where to resume parsing the string. 343 * We must keep track of nested IFs and skip them properly. 344 */ 345 static char * 346skipcond(p) 347 register char *p; 348{ 349 register int iflevel; 350 351 /* 352 * We came in here after processing a ? or :, 353 * so we start nested one level deep. 354 */ 355 iflevel = 1; 356 357 for (;;) switch (*++p) 358 { 359 case '?': 360 /* 361 * Start of a nested IF. 362 */ 363 iflevel++; 364 break; 365 case ':': 366 /* 367 * Else. 368 * If this matches the IF we came in here with, 369 * then we're done. 370 */ 371 if (iflevel == 1) 372 return (p); 373 break; 374 case '.': 375 /* 376 * Endif. 377 * If this matches the IF we came in here with, 378 * then we're done. 379 */ 380 if (--iflevel == 0) 381 return (p); 382 break; 383 case '\\': 384 /* 385 * Backslash escapes the next character. 386 */ 387 ++p; 388 break; 389 case '\0': 390 /* 391 * Whoops. Hit end of string. 392 * This is a malformed conditional, but just treat it 393 * as if all active conditionals ends here. 394 */ 395 return (p-1); 396 } 397 /*NOTREACHED*/ 398} 399 400/* 401 * Decode a char that represents a position on the screen. 402 */ 403 static char * 404wherechar(p, wp) 405 char *p; 406 int *wp; 407{ 408 switch (*p) 409 { 410 case 'b': case 'd': case 'l': case 'p': case 'P': 411 switch (*++p) 412 { 413 case 't': *wp = TOP; break; 414 case 'm': *wp = MIDDLE; break; 415 case 'b': *wp = BOTTOM; break; 416 case 'B': *wp = BOTTOM_PLUS_ONE; break; 417 case 'j': *wp = adjsline(jump_sline); break; 418 default: *wp = TOP; p--; break; 419 } 420 } 421 return (p); 422} 423 424/* 425 * Construct a message based on a prototype string. 426 */ 427 public char * 428pr_expand(proto, maxwidth) 429 char *proto; 430 int maxwidth; 431{ 432 register char *p; 433 register int c; 434 int where; 435 436 mp = message; 437 438 if (*proto == '\0') 439 return (""); 440 441 for (p = proto; *p != '\0'; p++) 442 { 443 switch (*p) 444 { 445 default: /* Just put the character in the message */ 446 ap_char(*p); 447 break; 448 case '\\': /* Backslash escapes the next character */ 449 p++; 450 ap_char(*p); 451 break; 452 case '?': /* Conditional (IF) */ 453 if ((c = *++p) == '\0') 454 --p; 455 else 456 { 457 where = 0; 458 p = wherechar(p, &where); 459 if (!cond(c, where)) 460 p = skipcond(p); 461 } 462 break; 463 case ':': /* ELSE */ 464 p = skipcond(p); 465 break; 466 case '.': /* ENDIF */ 467 break; 468 case '%': /* Percent escape */ 469 if ((c = *++p) == '\0') 470 --p; 471 else 472 { 473 where = 0; 474 p = wherechar(p, &where); 475 protochar(c, where, 476#if EDITOR 477 (proto == editproto)); 478#else 479 0); 480#endif 481 482 } 483 break; 484 } 485 } 486 487 new_file = 0; 488 if (mp == message) 489 return (NULL); 490 if (maxwidth > 0 && mp >= message + maxwidth) 491 { 492 /* 493 * Message is too long. 494 * Return just the final portion of it. 495 */ 496 return (mp - maxwidth); 497 } 498 return (message); 499} 500 501/* 502 * Return a message suitable for printing by the "=" command. 503 */ 504 public char * 505eq_message() 506{ 507 return (pr_expand(eqproto, 0)); 508} 509 510/* 511 * Return a prompt. 512 * This depends on the prompt type (SHORT, MEDIUM, LONG), etc. 513 * If we can't come up with an appropriate prompt, return NULL 514 * and the caller will prompt with a colon. 515 */ 516 public char * 517pr_string() 518{ 519 if (ch_getflags() & CH_HELPFILE) 520 return (pr_expand(hproto, sc_width-so_s_width-so_e_width-2)); 521 return (pr_expand(prproto[pr_type], sc_width-so_s_width-so_e_width-2)); 522}
|