| 1 | /* |
| 2 | * ========== Copyright Header Begin ========================================== |
| 3 | * |
| 4 | * Hypervisor Software File: interact.c |
| 5 | * |
| 6 | * Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. |
| 7 | * |
| 8 | * - Do no alter or remove copyright notices |
| 9 | * |
| 10 | * - Redistribution and use of this software in source and binary forms, with |
| 11 | * or without modification, are permitted provided that the following |
| 12 | * conditions are met: |
| 13 | * |
| 14 | * - Redistribution of source code must retain the above copyright notice, |
| 15 | * this list of conditions and the following disclaimer. |
| 16 | * |
| 17 | * - Redistribution in binary form must reproduce the above copyright notice, |
| 18 | * this list of conditions and the following disclaimer in the |
| 19 | * documentation and/or other materials provided with the distribution. |
| 20 | * |
| 21 | * Neither the name of Sun Microsystems, Inc. or the names of contributors |
| 22 | * may be used to endorse or promote products derived from this software |
| 23 | * without specific prior written permission. |
| 24 | * |
| 25 | * This software is provided "AS IS," without a warranty of any kind. |
| 26 | * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, |
| 27 | * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A |
| 28 | * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN |
| 29 | * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR |
| 30 | * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR |
| 31 | * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN |
| 32 | * OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR |
| 33 | * FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE |
| 34 | * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, |
| 35 | * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF |
| 36 | * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. |
| 37 | * |
| 38 | * You acknowledge that this software is not designed, licensed or |
| 39 | * intended for use in the design, construction, operation or maintenance of |
| 40 | * any nuclear facility. |
| 41 | * |
| 42 | * ========== Copyright Header End ============================================ |
| 43 | */ |
| 44 | /* |
| 45 | * @(#)interact.c 1.1 02/05/02 |
| 46 | * Copyright 2001-2002 Sun Microsystems, Inc. All Rights Reserved |
| 47 | * Copyright Use is subject to license terms. |
| 48 | */ |
| 49 | #include <stdio.h> |
| 50 | #include <stdlib.h> |
| 51 | #include <unistd.h> |
| 52 | #include <string.h> |
| 53 | #include <curses.h> |
| 54 | |
| 55 | #include "fscope.h" |
| 56 | |
| 57 | typedef struct ISTRUCT_T { |
| 58 | WINDOW *win; /* main screen */ |
| 59 | int info_line; /* line# for information text */ |
| 60 | int cmdnum; /* command selected */ |
| 61 | int lmargin; /* left margin of selected command */ |
| 62 | int col; /* cursor position on cmd line */ |
| 63 | int line; /* which line we are on */ |
| 64 | int error; /* error status, status string contains msg */ |
| 65 | char *status; /* status message */ |
| 66 | char *input_line; /* input buffer, at least as wide as screen */ |
| 67 | int ipoint; /* insertion point */ |
| 68 | int ilen; /* current command length */ |
| 69 | int matches; /* number of matches found */ |
| 70 | int start; /* offset within matches */ |
| 71 | int tag_mode; /* tag_mode status */ |
| 72 | int tagged; /* number of things tagged */ |
| 73 | search_t *tags; /* list of tagged matches */ |
| 74 | search_t *items[9]; /* the 1-9 items on the screen */ |
| 75 | search_t *list; /* current match list */ |
| 76 | search_t *displaying; /* where we are displaying in the above list */ |
| 77 | } istruct_t; |
| 78 | |
| 79 | #define NUM_COMMANDS (sizeof (commands) / sizeof (command_t)) |
| 80 | |
| 81 | typedef struct COMMAND_T { |
| 82 | char *id; |
| 83 | int cursor; |
| 84 | int line; |
| 85 | void (*finder)(extract_t *info, istruct_t *w); |
| 86 | } command_t; |
| 87 | |
| 88 | #define DEBUG |
| 89 | #define CONTROL -('A'-1) + |
| 90 | |
| 91 | #ifdef DEBUG |
| 92 | #define DEBUGL(y, x) move(y, 0); clrtoeol(); printw x; refresh(); |
| 93 | #else |
| 94 | #define DEBUGL(y, x) |
| 95 | #endif |
| 96 | |
| 97 | static void |
| 98 | free_tag(istruct_t *w, search_t *item) |
| 99 | { |
| 100 | search_t *tag = item->private; |
| 101 | search_t *next, *prev; |
| 102 | |
| 103 | if (tag == NULL) |
| 104 | return; |
| 105 | next = tag->next; |
| 106 | prev = tag->prev; |
| 107 | if (tag->next != NULL) { |
| 108 | tag->next->prev = prev; |
| 109 | } |
| 110 | if (prev != NULL) { |
| 111 | prev->next = next; |
| 112 | } else { |
| 113 | w->tags = tag->next; |
| 114 | } |
| 115 | free(tag); |
| 116 | w->tagged--; |
| 117 | item->private = NULL; |
| 118 | } |
| 119 | |
| 120 | static void |
| 121 | tag_item(istruct_t *w, search_t *item) |
| 122 | { |
| 123 | search_t *new; |
| 124 | |
| 125 | if (item->private == NULL) { |
| 126 | new = new_search_t(); |
| 127 | new->xref = item->xref; |
| 128 | new->next = w->tags; |
| 129 | new->prev = NULL; |
| 130 | new->private = item; |
| 131 | if (w->tags != NULL) { |
| 132 | w->tags->prev = new; |
| 133 | } |
| 134 | w->tags = new; |
| 135 | w->tagged++; |
| 136 | item->private = new; |
| 137 | } else { |
| 138 | free_tag(w, item); |
| 139 | item->private = NULL; |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | static void |
| 144 | cancel_tags(istruct_t *w) |
| 145 | { |
| 146 | search_t *ptr, *next; |
| 147 | |
| 148 | w->tag_mode = 0; |
| 149 | w->tagged = 0; |
| 150 | ptr = w->tags; |
| 151 | while (ptr) { |
| 152 | next = ptr->next; |
| 153 | free_tag(w, ptr->private); |
| 154 | ptr = next; |
| 155 | } |
| 156 | w->tags = NULL; |
| 157 | } |
| 158 | |
| 159 | static void |
| 160 | find_exact_definition(extract_t *info, istruct_t *w) |
| 161 | { |
| 162 | search_t *list; |
| 163 | |
| 164 | info->symbol = w->input_line; |
| 165 | info->flags &= ~FLAG_REGEXP; |
| 166 | w->list = build_searchlist(info, NULL, |
| 167 | (XREF_DEFINITION | XREF_FORWARD)); |
| 168 | } |
| 169 | |
| 170 | static void |
| 171 | find_regexp_definition(extract_t *info, istruct_t *w) |
| 172 | { |
| 173 | info->symbol = w->input_line; |
| 174 | info->flags |= FLAG_REGEXP; |
| 175 | w->list = build_searchlist(info, NULL, |
| 176 | (XREF_DEFINITION | XREF_FORWARD)); |
| 177 | } |
| 178 | |
| 179 | static void |
| 180 | find_file(extract_t *info, istruct_t *w) |
| 181 | { |
| 182 | xref_file_t *fptr = info->state->sources; |
| 183 | search_t *new, *list = NULL; |
| 184 | xref_t *xref; |
| 185 | |
| 186 | info->symbol = w->input_line; |
| 187 | |
| 188 | while (fptr != NULL) { |
| 189 | if (strstr(fptr->name, info->symbol) != NULL) { |
| 190 | int i, j; |
| 191 | |
| 192 | xref = NULL; |
| 193 | for (i = 0; ((i < 128) && (xref == NULL)); i++) { |
| 194 | xref = fptr->defs[i]; |
| 195 | } |
| 196 | new = new_search_t(); |
| 197 | new->xref = xref; |
| 198 | new->next = list; |
| 199 | list = new; |
| 200 | } |
| 201 | fptr = fptr->next; |
| 202 | } |
| 203 | w->list = list; |
| 204 | } |
| 205 | |
| 206 | static void |
| 207 | find_callers_of(extract_t *info, istruct_t *w) |
| 208 | { |
| 209 | search_t *list, *item; |
| 210 | search_t *callers; |
| 211 | int j; |
| 212 | xref_t *xref; |
| 213 | ref_t *rref; |
| 214 | |
| 215 | info->symbol = w->input_line; |
| 216 | info->flags &= ~FLAG_REGEXP; |
| 217 | if (w->tag_mode) { |
| 218 | item = w->tags; |
| 219 | } else { |
| 220 | item = build_searchlist(info, NULL, XREF_DEFINITION); |
| 221 | if (item == NULL) { |
| 222 | return; |
| 223 | } |
| 224 | if (item->next != NULL) { |
| 225 | w->status = "more than one defintion, " |
| 226 | "refine your search using a tag"; |
| 227 | w->error = 1; |
| 228 | free_searchlist(item); |
| 229 | w->list = NULL; |
| 230 | return; |
| 231 | } |
| 232 | } |
| 233 | ASSERT((item != NULL), "tagged with item NULL??"); |
| 234 | list = NULL; |
| 235 | while (item != NULL) { |
| 236 | xref = item->xref; |
| 237 | rref = &xref->called_by; |
| 238 | for (j = 0; j < rref->insert; j++) { |
| 239 | callers = new_search_t(); |
| 240 | callers->xref = rref->ptr[j]; |
| 241 | callers->next = list; |
| 242 | list = callers; |
| 243 | } |
| 244 | item = item->next; |
| 245 | } |
| 246 | if (w->tag_mode) { |
| 247 | cancel_tags(w); |
| 248 | } else { |
| 249 | free_searchlist(item); |
| 250 | } |
| 251 | w->list = list; |
| 252 | } |
| 253 | |
| 254 | static void |
| 255 | find_text_string(extract_t *info, istruct_t *w) |
| 256 | { |
| 257 | search_t *list; |
| 258 | |
| 259 | info->symbol = w->input_line; |
| 260 | info->flags |= FLAG_REGEXP; |
| 261 | w->list = build_searchlist(info, NULL, |
| 262 | (XREF_STRING | XREF_DEFINITION)); |
| 263 | } |
| 264 | |
| 265 | command_t commands[] = { |
| 266 | { "Find definition:", 0, 0, find_exact_definition }, |
| 267 | { "Find fuzzy definition:", 0, 1, find_regexp_definition }, |
| 268 | { "Find callers of routine:", 0, 2, find_callers_of }, |
| 269 | { "Find text string:", 0, 3, find_text_string }, |
| 270 | { "Change text string:", 0, 4, NULL }, |
| 271 | { "Change definition name:", 0, 5, NULL }, |
| 272 | { "Find file:", 0, 6, find_file }, |
| 273 | }; |
| 274 | |
| 275 | static void |
| 276 | draw_command(extract_t *info, istruct_t *w) |
| 277 | { |
| 278 | static int computed_pos = 0; |
| 279 | int i; |
| 280 | command_t *cptr; |
| 281 | |
| 282 | if (!computed_pos) { |
| 283 | for (i = 0; i < NUM_COMMANDS; i++) { |
| 284 | cptr = &commands[i]; |
| 285 | if (cptr->cursor == 0) { |
| 286 | cptr->cursor = strlen(cptr->id)+1; |
| 287 | cptr->line += (LINES - NUM_COMMANDS); |
| 288 | } |
| 289 | } |
| 290 | w->info_line = commands[0].line -1; |
| 291 | computed_pos = 1; |
| 292 | } |
| 293 | move(commands[0].line, 0); |
| 294 | clrtobot(); |
| 295 | |
| 296 | for (i = 0; i < NUM_COMMANDS; i++) { |
| 297 | cptr = &commands[i]; |
| 298 | mvprintw(cptr->line, 0, cptr->id); |
| 299 | } |
| 300 | w->col = commands[w->cmdnum].cursor; |
| 301 | w->line = commands[w->cmdnum].line; |
| 302 | w->lmargin = w->col; |
| 303 | move(w->line, w->col); |
| 304 | refresh(); |
| 305 | } |
| 306 | |
| 307 | static void |
| 308 | hit_counter(extract_t *info, search_t *item) |
| 309 | { |
| 310 | int *iptr = info->private; |
| 311 | (*iptr)++; |
| 312 | } |
| 313 | |
| 314 | static char * |
| 315 | run_search(extract_t *info, istruct_t *w) |
| 316 | { |
| 317 | if ((w->ilen == 0) && !w->tag_mode) { |
| 318 | return ("Nothing to Do"); |
| 319 | } |
| 320 | if (commands[w->cmdnum].finder != NULL) { |
| 321 | w->matches = 0; |
| 322 | w->start = 0; |
| 323 | w->error = 0; |
| 324 | commands[w->cmdnum].finder(info, w); |
| 325 | if (w->error == 0) { |
| 326 | info->private = &w->matches; |
| 327 | w->displaying = w->list; |
| 328 | iterate_list(info, w->list, hit_counter); |
| 329 | if (w->matches == 0) { |
| 330 | return ("Nothing Found"); |
| 331 | } |
| 332 | return (""); |
| 333 | } |
| 334 | return (w->status); |
| 335 | } |
| 336 | return ("<unimplemented command>"); |
| 337 | } |
| 338 | |
| 339 | static void |
| 340 | match_mode(extract_t *info, istruct_t *w, int c) |
| 341 | { |
| 342 | int i; |
| 343 | search_t *this; |
| 344 | search_t *selected; |
| 345 | |
| 346 | redraw: |
| 347 | selected = NULL; |
| 348 | for (i = 0; i < 9; i++) { |
| 349 | move(i, 0); |
| 350 | clrtoeol(); |
| 351 | w->items[i] = NULL; |
| 352 | } |
| 353 | i = 0; |
| 354 | this = w->displaying; |
| 355 | while ((i < 9) && (this != NULL)) { |
| 356 | w->items[i] = this; |
| 357 | mvprintw(i, 0, " %d%c[%c%c%c] %s:%d .. %s ..\n", |
| 358 | ((i+1)%10), |
| 359 | ((this->private == NULL) ? ' ' : '>'), |
| 360 | ((this->xref->flags & XREF_FORWARD) ? 'F' : '.'), |
| 361 | ((this->xref->flags & XREF_DEFINITION) ? 'D' : '.'), |
| 362 | ((this->xref->flags & XREF_STRING) ? 'S' : '.'), |
| 363 | expand_filename(info, this->xref), |
| 364 | this->xref->linenum, |
| 365 | this->xref->name); |
| 366 | this = this->next; |
| 367 | i++; |
| 368 | } |
| 369 | refresh(); |
| 370 | if (c == 't') { |
| 371 | if (w->tag_mode) { |
| 372 | w->tag_mode = 0; |
| 373 | } else { |
| 374 | w->tag_mode = 1; |
| 375 | } |
| 376 | return; |
| 377 | } |
| 378 | if (c == ' ') { |
| 379 | if (w->matches > 9) { |
| 380 | if ((w->start + i) == w->matches) { |
| 381 | w->start = 0; |
| 382 | w->displaying = w->list; |
| 383 | } else { |
| 384 | w->displaying = this; |
| 385 | w->start += i; |
| 386 | } |
| 387 | } |
| 388 | c = 0; |
| 389 | goto redraw; |
| 390 | } |
| 391 | if ((c > '0') && (c <= '9')) { |
| 392 | selected = w->items[c-'1']; |
| 393 | if (w->tag_mode) { |
| 394 | tag_item(w, selected); |
| 395 | c = 0; |
| 396 | goto redraw; |
| 397 | } else |
| 398 | goto selected; |
| 399 | } |
| 400 | if (((c == '*') || (c == '&')) && (w->tag_mode)) { |
| 401 | int i; |
| 402 | search_t *this; |
| 403 | for (i = 0; i < 9; i++) { |
| 404 | this = w->items[i]; |
| 405 | if (this != NULL) { |
| 406 | if (c == '&') { |
| 407 | free_tag(w, this); |
| 408 | } else { |
| 409 | tag_item(w, this); |
| 410 | } |
| 411 | } |
| 412 | } |
| 413 | c = 0; |
| 414 | goto redraw; |
| 415 | } |
| 416 | if ((c == 0x4)) { |
| 417 | /* Control D */ |
| 418 | free_searchlist(w->list); |
| 419 | w->list = NULL; |
| 420 | w->displaying = NULL; |
| 421 | w->start = 0; |
| 422 | w->matches = 0; |
| 423 | if (w->tagged == 0) { |
| 424 | w->tag_mode = 0; |
| 425 | } |
| 426 | return; |
| 427 | } |
| 428 | if (c == 0x1b) { |
| 429 | /* Escape. */ |
| 430 | cancel_tags(w); |
| 431 | free_searchlist(w->list); |
| 432 | w->list = NULL; |
| 433 | w->displaying = NULL; |
| 434 | w->start = 0; |
| 435 | w->matches = 0; |
| 436 | return; |
| 437 | } |
| 438 | selected: |
| 439 | if (selected && !w->tag_mode) { |
| 440 | char *syscommand; |
| 441 | int bytes; |
| 442 | char *file; |
| 443 | char *editor; |
| 444 | |
| 445 | editor = getenv("EDITOR"); |
| 446 | if (editor == NULL) { |
| 447 | editor = "/bin/vi"; |
| 448 | } |
| 449 | bytes = strlen(editor); |
| 450 | file = expand_filename(info, selected->xref); |
| 451 | bytes += strlen(file); |
| 452 | bytes += 20; |
| 453 | syscommand = malloc(bytes); |
| 454 | snprintf(syscommand, bytes, "%s +%d %s", |
| 455 | editor, selected->xref->linenum, |
| 456 | file); |
| 457 | endwin(); |
| 458 | system(syscommand); |
| 459 | refresh(); |
| 460 | free(syscommand); |
| 461 | } |
| 462 | } |
| 463 | |
| 464 | static char * |
| 465 | select_mode(extract_t *info, istruct_t *w, int c) |
| 466 | { |
| 467 | char *tstatus; |
| 468 | |
| 469 | tstatus = ""; |
| 470 | |
| 471 | switch (c) { |
| 472 | case CONTROL 'B': |
| 473 | case KEY_LEFT: |
| 474 | if (w->ipoint) { |
| 475 | w->ipoint--; |
| 476 | w->col--; |
| 477 | } |
| 478 | if (0) move(w->line, w->col); |
| 479 | break; |
| 480 | |
| 481 | case CONTROL 'F': |
| 482 | case KEY_RIGHT: |
| 483 | if (w->ipoint < w->ilen) { |
| 484 | w->ipoint++; |
| 485 | w->col++; |
| 486 | } |
| 487 | if (0) move(w->line, w->col); |
| 488 | break; |
| 489 | |
| 490 | case CONTROL 'P': |
| 491 | case KEY_UP: |
| 492 | if (w->cmdnum) |
| 493 | w->cmdnum--; |
| 494 | else |
| 495 | w->cmdnum = NUM_COMMANDS-1; |
| 496 | w->ipoint = 0; |
| 497 | w->ilen = 0; |
| 498 | draw_command(info, w); |
| 499 | break; |
| 500 | |
| 501 | case CONTROL 'N': |
| 502 | case CONTROL 'I': |
| 503 | case KEY_DOWN: |
| 504 | if (w->cmdnum < (NUM_COMMANDS-1)) |
| 505 | w->cmdnum++; |
| 506 | else |
| 507 | w->cmdnum = 0; |
| 508 | w->ipoint = 0; |
| 509 | w->ilen = 0; |
| 510 | draw_command(info, w); |
| 511 | break; |
| 512 | |
| 513 | case CONTROL 'M': |
| 514 | case CONTROL 'J': |
| 515 | w->status = run_search(info, w); |
| 516 | if (w->matches) { |
| 517 | match_mode(info, w, 0); |
| 518 | } |
| 519 | break; |
| 520 | |
| 521 | case CONTROL 'A': |
| 522 | w->ipoint = 0; |
| 523 | w->col = w->lmargin; |
| 524 | if (0) move(w->line, w->col); |
| 525 | break; |
| 526 | |
| 527 | case 127: |
| 528 | case CONTROL 'H': |
| 529 | if (w->ipoint > 0) { |
| 530 | char *here = w->input_line + w->ipoint; |
| 531 | memcpy(here-1, here, (w->ilen - w->ipoint)+1); |
| 532 | w->ilen--; |
| 533 | w->col--; |
| 534 | w->ipoint--; |
| 535 | } |
| 536 | move(w->line, w->col); |
| 537 | clrtoeol(); |
| 538 | mvprintw(w->line, w->lmargin, w->input_line); |
| 539 | if (0) move(w->line, w->col); |
| 540 | break; |
| 541 | |
| 542 | case CONTROL 'D': |
| 543 | if (w->ipoint < w->ilen) { |
| 544 | char *here = w->input_line + w->ipoint; |
| 545 | memcpy(here, here+1, (w->ilen - w->ipoint)); |
| 546 | w->ilen--; |
| 547 | } |
| 548 | move(w->line, w->col); |
| 549 | clrtoeol(); |
| 550 | mvprintw(w->line, w->lmargin, w->input_line); |
| 551 | if (0) move(w->line, w->col); |
| 552 | break; |
| 553 | |
| 554 | case CONTROL 'E': |
| 555 | w->ipoint = w->ilen; |
| 556 | w->col = w->lmargin + w->ilen; |
| 557 | if (0) move(w->line, w->col); |
| 558 | break; |
| 559 | |
| 560 | case CONTROL 'K': |
| 561 | w->input_line[w->ipoint] = 0; |
| 562 | clrtoeol(); |
| 563 | mvprintw(w->line, w->lmargin, w->input_line); |
| 564 | if (0) move(w->line, w->col); |
| 565 | break; |
| 566 | |
| 567 | case 0x1b: |
| 568 | /* Escape, cancel all tags etc */ |
| 569 | cancel_tags(w); |
| 570 | break; |
| 571 | |
| 572 | default: |
| 573 | if ((c >= ' ') && (c <= 'z')) { |
| 574 | mvprintw(w->line, w->col, "%c", c); |
| 575 | if (w->col < (COLS-2)) { |
| 576 | w->input_line[w->ipoint++] = c; |
| 577 | w->col++; |
| 578 | } |
| 579 | if (w->ipoint > w->ilen) { |
| 580 | w->input_line[w->ipoint] = 0; |
| 581 | w->ilen = w->ipoint; |
| 582 | } |
| 583 | } |
| 584 | break; |
| 585 | } |
| 586 | return (tstatus); |
| 587 | } |
| 588 | |
| 589 | void |
| 590 | xref_interactive_mode(extract_t *info) |
| 591 | { |
| 592 | istruct_t *w; |
| 593 | int c; |
| 594 | char *tstatus; |
| 595 | char add_status[20]; |
| 596 | |
| 597 | w = malloc(sizeof (istruct_t)); |
| 598 | memset(w, 0, sizeof (istruct_t)); |
| 599 | w->win = initscr(); |
| 600 | w->cmdnum = 0; |
| 601 | clear(); |
| 602 | cbreak(); |
| 603 | noecho(); |
| 604 | keypad(w->win, 1); |
| 605 | mvprintw(0, 0, "match window"); |
| 606 | refresh(); |
| 607 | |
| 608 | draw_command(info, w); |
| 609 | c = 0; |
| 610 | w->ipoint = 0; |
| 611 | w->ilen = 0; |
| 612 | w->matches = 0; |
| 613 | w->input_line = malloc(COLS); |
| 614 | w->input_line[w->ipoint] = 0; |
| 615 | w->status = ""; |
| 616 | w->tags = NULL; |
| 617 | w->displaying = NULL; |
| 618 | w->list = NULL; |
| 619 | while (c != EOF) { |
| 620 | move(w->info_line, 0); |
| 621 | clrtoeol(); |
| 622 | add_status[0] = 0; |
| 623 | if (w->tag_mode) { |
| 624 | snprintf(add_status, sizeof (add_status), |
| 625 | "[Tagged:%d]", w->tagged); |
| 626 | } |
| 627 | if (w->matches) { |
| 628 | int upper, rem; |
| 629 | |
| 630 | rem = w->matches - w->start; |
| 631 | if (rem > 9) { |
| 632 | upper = w->start + 9; |
| 633 | rem -= 9; |
| 634 | } else { |
| 635 | upper = w->start + rem; |
| 636 | rem = 0; |
| 637 | } |
| 638 | if (!rem) { |
| 639 | mvprintw(w->info_line, 0, |
| 640 | "Status %s: displaying %d-%d" |
| 641 | " [press ESC to exit]", |
| 642 | add_status, (w->start+1), upper); |
| 643 | } else { |
| 644 | mvprintw(w->info_line, 0, |
| 645 | "Status %s: displaying %d-%d, %d more" |
| 646 | " [press SPACE for more, ESC to exit]", |
| 647 | add_status, (w->start+1), upper, rem); |
| 648 | } |
| 649 | } else { |
| 650 | mvprintw(w->info_line, 0, |
| 651 | "Select %s mode: %s", add_status, w->status); |
| 652 | } |
| 653 | c = mvgetch(w->line, w->col); |
| 654 | w->status = ""; |
| 655 | |
| 656 | if (w->matches) |
| 657 | match_mode(info, w, c); |
| 658 | else |
| 659 | tstatus = select_mode(info, w, c); |
| 660 | refresh(); |
| 661 | } |
| 662 | |
| 663 | nocbreak(); |
| 664 | echo(); |
| 665 | keypad(w->win, 0); |
| 666 | } |