| File: | src/usr.bin/vi/build/../vi/vs_msg.c |
| Warning: | line 692, column 20 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: vs_msg.c,v 1.20 2017/04/18 01:45:35 deraadt Exp $ */ | |||
| 2 | ||||
| 3 | /*- | |||
| 4 | * Copyright (c) 1993, 1994 | |||
| 5 | * The Regents of the University of California. All rights reserved. | |||
| 6 | * Copyright (c) 1992, 1993, 1994, 1995, 1996 | |||
| 7 | * Keith Bostic. All rights reserved. | |||
| 8 | * | |||
| 9 | * See the LICENSE file for redistribution information. | |||
| 10 | */ | |||
| 11 | ||||
| 12 | #include "config.h" | |||
| 13 | ||||
| 14 | #include <sys/types.h> | |||
| 15 | #include <sys/queue.h> | |||
| 16 | #include <sys/time.h> | |||
| 17 | ||||
| 18 | #include <bitstring.h> | |||
| 19 | #include <ctype.h> | |||
| 20 | #include <stdio.h> | |||
| 21 | #include <stdlib.h> | |||
| 22 | #include <string.h> | |||
| 23 | #include <time.h> | |||
| 24 | #include <unistd.h> | |||
| 25 | ||||
| 26 | #include "../common/common.h" | |||
| 27 | #include "vi.h" | |||
| 28 | ||||
| 29 | typedef enum { | |||
| 30 | SCROLL_W, /* User wait. */ | |||
| 31 | SCROLL_W_EX, /* User wait, or enter : to continue. */ | |||
| 32 | SCROLL_W_QUIT /* User wait, or enter q to quit. */ | |||
| 33 | /* | |||
| 34 | * SCROLL_W_QUIT has another semantic | |||
| 35 | * -- only wait if the screen is full | |||
| 36 | */ | |||
| 37 | } sw_t; | |||
| 38 | ||||
| 39 | static void vs_divider(SCR *); | |||
| 40 | static void vs_msgsave(SCR *, mtype_t, char *, size_t); | |||
| 41 | static void vs_output(SCR *, mtype_t, const char *, int); | |||
| 42 | static void vs_scroll(SCR *, int *, sw_t); | |||
| 43 | static void vs_wait(SCR *, int *, sw_t); | |||
| 44 | ||||
| 45 | /* | |||
| 46 | * vs_busy -- | |||
| 47 | * Display, update or clear a busy message. | |||
| 48 | * | |||
| 49 | * This routine is the default editor interface for vi busy messages. It | |||
| 50 | * implements a standard strategy of stealing lines from the bottom of the | |||
| 51 | * vi text screen. Screens using an alternate method of displaying busy | |||
| 52 | * messages, e.g. X11 clock icons, should set their scr_busy function to the | |||
| 53 | * correct function before calling the main editor routine. | |||
| 54 | * | |||
| 55 | * PUBLIC: void vs_busy(SCR *, const char *, busy_t); | |||
| 56 | */ | |||
| 57 | void | |||
| 58 | vs_busy(SCR *sp, const char *msg, busy_t btype) | |||
| 59 | { | |||
| 60 | GS *gp; | |||
| 61 | VI_PRIVATE *vip; | |||
| 62 | static const char flagc[] = "|/-\\"; | |||
| 63 | struct timespec ts, ts_diff; | |||
| 64 | size_t notused; | |||
| 65 | ||||
| 66 | /* Ex doesn't display busy messages. */ | |||
| 67 | if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)(((sp)->flags) & ((0x00000001 | 0x00000010)))) | |||
| 68 | return; | |||
| 69 | ||||
| 70 | gp = sp->gp; | |||
| 71 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); | |||
| 72 | ||||
| 73 | /* | |||
| 74 | * Most of this routine is to deal with the screen sharing real estate | |||
| 75 | * between the normal edit messages and the busy messages. Logically, | |||
| 76 | * all that's needed is something that puts up a message, periodically | |||
| 77 | * updates it, and then goes away. | |||
| 78 | */ | |||
| 79 | switch (btype) { | |||
| 80 | case BUSY_ON: | |||
| 81 | ++vip->busy_ref; | |||
| 82 | if (vip->totalcount != 0 || vip->busy_ref != 1) | |||
| 83 | break; | |||
| 84 | ||||
| 85 | /* Initialize state for updates. */ | |||
| 86 | vip->busy_ch = 0; | |||
| 87 | (void)clock_gettime(CLOCK_MONOTONIC3, &vip->busy_ts); | |||
| 88 | ||||
| 89 | /* Save the current cursor. */ | |||
| 90 | (void)gp->scr_cursor(sp, &vip->busy_oldy, &vip->busy_oldx); | |||
| 91 | ||||
| 92 | /* Display the busy message. */ | |||
| 93 | (void)gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), 0); | |||
| 94 | (void)gp->scr_addstr(sp, msg, strlen(msg)); | |||
| 95 | (void)gp->scr_cursor(sp, ¬used, &vip->busy_fx); | |||
| 96 | (void)gp->scr_clrtoeol(sp); | |||
| 97 | (void)gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), vip->busy_fx); | |||
| 98 | break; | |||
| 99 | case BUSY_OFF: | |||
| 100 | if (vip->busy_ref == 0) | |||
| 101 | break; | |||
| 102 | --vip->busy_ref; | |||
| 103 | ||||
| 104 | /* | |||
| 105 | * If the line isn't in use for another purpose, clear it. | |||
| 106 | * Always return to the original position. | |||
| 107 | */ | |||
| 108 | if (vip->totalcount == 0 && vip->busy_ref == 0) { | |||
| 109 | (void)gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), 0); | |||
| 110 | (void)gp->scr_clrtoeol(sp); | |||
| 111 | } | |||
| 112 | (void)gp->scr_move(sp, vip->busy_oldy, vip->busy_oldx); | |||
| 113 | break; | |||
| 114 | case BUSY_UPDATE: | |||
| 115 | if (vip->totalcount != 0 || vip->busy_ref == 0) | |||
| 116 | break; | |||
| 117 | ||||
| 118 | /* Update no more than every 1/8 of a second. */ | |||
| 119 | (void)clock_gettime(CLOCK_MONOTONIC3, &ts); | |||
| 120 | ts_diff = ts; | |||
| 121 | ts_diff.tv_sec -= vip->busy_ts.tv_sec; | |||
| 122 | ts_diff.tv_nsec -= vip->busy_ts.tv_nsec; | |||
| 123 | if (ts_diff.tv_nsec < 0) { | |||
| 124 | ts_diff.tv_sec--; | |||
| 125 | ts_diff.tv_nsec += 1000000000; | |||
| 126 | } | |||
| 127 | if ((ts_diff.tv_sec == 0 && ts_diff.tv_nsec < 125000000) || | |||
| 128 | ts_diff.tv_sec < 0) | |||
| 129 | return; | |||
| 130 | vip->busy_ts = ts; | |||
| 131 | ||||
| 132 | /* Display the update. */ | |||
| 133 | if (vip->busy_ch == sizeof(flagc) - 1) | |||
| 134 | vip->busy_ch = 0; | |||
| 135 | (void)gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), vip->busy_fx); | |||
| 136 | (void)gp->scr_addstr(sp, flagc + vip->busy_ch++, 1); | |||
| 137 | (void)gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), vip->busy_fx); | |||
| 138 | break; | |||
| 139 | } | |||
| 140 | (void)gp->scr_refresh(sp, 0); | |||
| 141 | } | |||
| 142 | ||||
| 143 | /* | |||
| 144 | * vs_home -- | |||
| 145 | * Home the cursor to the bottom row, left-most column. | |||
| 146 | * | |||
| 147 | * PUBLIC: void vs_home(SCR *); | |||
| 148 | */ | |||
| 149 | void | |||
| 150 | vs_home(SCR *sp) | |||
| 151 | { | |||
| 152 | (void)sp->gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), 0); | |||
| 153 | (void)sp->gp->scr_refresh(sp, 0); | |||
| 154 | } | |||
| 155 | ||||
| 156 | /* | |||
| 157 | * vs_update -- | |||
| 158 | * Update a command. | |||
| 159 | * | |||
| 160 | * PUBLIC: void vs_update(SCR *, const char *, const char *); | |||
| 161 | */ | |||
| 162 | void | |||
| 163 | vs_update(SCR *sp, const char *m1, const char *m2) | |||
| 164 | { | |||
| 165 | GS *gp; | |||
| 166 | size_t len, mlen, oldx, oldy; | |||
| 167 | ||||
| 168 | gp = sp->gp; | |||
| 169 | ||||
| 170 | /* | |||
| 171 | * This routine displays a message on the bottom line of the screen, | |||
| 172 | * without updating any of the command structures that would keep it | |||
| 173 | * there for any period of time, i.e. it is overwritten immediately. | |||
| 174 | * | |||
| 175 | * It's used by the ex read and ! commands when the user's command is | |||
| 176 | * expanded, and by the ex substitution confirmation prompt. | |||
| 177 | */ | |||
| 178 | if (F_ISSET(sp, SC_SCR_EXWROTE)(((sp)->flags) & ((0x00000010)))) { | |||
| 179 | (void)ex_printf(sp, | |||
| 180 | "%s\n", m1 == NULL((void *)0)? "" : m1, m2 == NULL((void *)0) ? "" : m2); | |||
| 181 | (void)ex_fflush(sp); | |||
| 182 | } | |||
| 183 | ||||
| 184 | /* | |||
| 185 | * Save the cursor position, the substitute-with-confirmation code | |||
| 186 | * will have already set it correctly. | |||
| 187 | */ | |||
| 188 | (void)gp->scr_cursor(sp, &oldy, &oldx); | |||
| 189 | ||||
| 190 | /* Clear the bottom line. */ | |||
| 191 | (void)gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), 0); | |||
| 192 | (void)gp->scr_clrtoeol(sp); | |||
| 193 | ||||
| 194 | /* | |||
| 195 | * XXX | |||
| 196 | * Don't let long file names screw up the screen. | |||
| 197 | */ | |||
| 198 | if (m1 != NULL((void *)0)) { | |||
| 199 | mlen = len = strlen(m1); | |||
| 200 | if (len > sp->cols - 2) | |||
| 201 | mlen = len = sp->cols - 2; | |||
| 202 | (void)gp->scr_addstr(sp, m1, mlen); | |||
| 203 | } else | |||
| 204 | len = 0; | |||
| 205 | if (m2 != NULL((void *)0)) { | |||
| 206 | mlen = strlen(m2); | |||
| 207 | if (len + mlen > sp->cols - 2) | |||
| 208 | mlen = (sp->cols - 2) - len; | |||
| 209 | (void)gp->scr_addstr(sp, m2, mlen); | |||
| 210 | } | |||
| 211 | ||||
| 212 | (void)gp->scr_move(sp, oldy, oldx); | |||
| 213 | (void)gp->scr_refresh(sp, 0); | |||
| 214 | } | |||
| 215 | ||||
| 216 | /* | |||
| 217 | * vs_msg -- | |||
| 218 | * Display ex output or error messages for the screen. | |||
| 219 | * | |||
| 220 | * This routine is the default editor interface for all ex output, and all ex | |||
| 221 | * and vi error/informational messages. It implements the standard strategy | |||
| 222 | * of stealing lines from the bottom of the vi text screen. Screens using an | |||
| 223 | * alternate method of displaying messages, e.g. dialog boxes, should set their | |||
| 224 | * scr_msg function to the correct function before calling the editor. | |||
| 225 | * | |||
| 226 | * PUBLIC: void vs_msg(SCR *, mtype_t, char *, size_t); | |||
| 227 | */ | |||
| 228 | void | |||
| 229 | vs_msg(SCR *sp, mtype_t mtype, char *line, size_t len) | |||
| 230 | { | |||
| 231 | GS *gp; | |||
| 232 | VI_PRIVATE *vip; | |||
| 233 | size_t maxcols, oldx, oldy, padding; | |||
| 234 | const char *e, *s, *t; | |||
| 235 | ||||
| 236 | gp = sp->gp; | |||
| 237 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); | |||
| 238 | ||||
| 239 | /* | |||
| 240 | * Ring the bell if it's scheduled. | |||
| 241 | * | |||
| 242 | * XXX | |||
| 243 | * Shouldn't we save this, too? | |||
| 244 | */ | |||
| 245 | if (F_ISSET(sp, SC_TINPUT_INFO)(((sp)->flags) & ((0x10000000))) || F_ISSET(gp, G_BELLSCHED)(((gp)->flags) & ((0x0002)))) { | |||
| 246 | if (F_ISSET(sp, SC_SCR_VI)(((sp)->flags) & ((0x00000008)))) { | |||
| 247 | F_CLR(gp, G_BELLSCHED)(((gp)->flags) &= ~((0x0002))); | |||
| 248 | (void)gp->scr_bell(sp); | |||
| 249 | } else | |||
| 250 | F_SET(gp, G_BELLSCHED)(((gp)->flags) |= ((0x0002))); | |||
| 251 | } | |||
| 252 | ||||
| 253 | /* | |||
| 254 | * If vi is using the error line for text input, there's no screen | |||
| 255 | * real-estate for the error message. Nothing to do without some | |||
| 256 | * information as to how important the error message is. | |||
| 257 | */ | |||
| 258 | if (F_ISSET(sp, SC_TINPUT_INFO)(((sp)->flags) & ((0x10000000)))) | |||
| 259 | return; | |||
| 260 | ||||
| 261 | /* | |||
| 262 | * Ex or ex controlled screen output. | |||
| 263 | * | |||
| 264 | * If output happens during startup, e.g., a .exrc file, we may be | |||
| 265 | * in ex mode but haven't initialized the screen. Initialize here, | |||
| 266 | * and in this case, stay in ex mode. | |||
| 267 | * | |||
| 268 | * If the SC_SCR_EXWROTE bit is set, then we're switching back and | |||
| 269 | * forth between ex and vi, but the screen is trashed and we have | |||
| 270 | * to respect that. Switch to ex mode long enough to put out the | |||
| 271 | * message. | |||
| 272 | * | |||
| 273 | * If the SC_EX_WAIT_NO bit is set, turn it off -- we're writing to | |||
| 274 | * the screen, so previous opinions are ignored. | |||
| 275 | */ | |||
| 276 | if (F_ISSET(sp, SC_EX | SC_SCR_EXWROTE)(((sp)->flags) & ((0x00000001 | 0x00000010)))) { | |||
| 277 | if (!F_ISSET(sp, SC_SCR_EX)(((sp)->flags) & ((0x00000004)))) { | |||
| 278 | if (F_ISSET(sp, SC_SCR_EXWROTE)(((sp)->flags) & ((0x00000010)))) { | |||
| 279 | if (sp->gp->scr_screen(sp, SC_EX0x00000001)) | |||
| 280 | return; | |||
| 281 | } else | |||
| 282 | if (ex_init(sp)) | |||
| 283 | return; | |||
| 284 | } | |||
| 285 | ||||
| 286 | if (mtype == M_ERR) | |||
| 287 | (void)gp->scr_attr(sp, SA_INVERSE, 1); | |||
| 288 | (void)printf("%.*s", (int)len, line); | |||
| 289 | if (mtype == M_ERR) | |||
| 290 | (void)gp->scr_attr(sp, SA_INVERSE, 0); | |||
| 291 | (void)fflush(stdout(&__sF[1])); | |||
| 292 | ||||
| 293 | F_CLR(sp, SC_EX_WAIT_NO)(((sp)->flags) &= ~((0x00080000))); | |||
| 294 | ||||
| 295 | if (!F_ISSET(sp, SC_SCR_EX)(((sp)->flags) & ((0x00000004)))) | |||
| 296 | (void)sp->gp->scr_screen(sp, SC_VI0x00000002); | |||
| 297 | return; | |||
| 298 | } | |||
| 299 | ||||
| 300 | /* If the vi screen isn't ready, save the message. */ | |||
| 301 | if (!F_ISSET(sp, SC_SCR_VI)(((sp)->flags) & ((0x00000008)))) { | |||
| 302 | (void)vs_msgsave(sp, mtype, line, len); | |||
| 303 | return; | |||
| 304 | } | |||
| 305 | ||||
| 306 | /* Save the cursor position. */ | |||
| 307 | (void)gp->scr_cursor(sp, &oldy, &oldx); | |||
| 308 | ||||
| 309 | /* If it's an ex output message, just write it out. */ | |||
| 310 | if (mtype == M_NONE) { | |||
| 311 | vs_output(sp, mtype, line, len); | |||
| 312 | goto ret; | |||
| 313 | } | |||
| 314 | ||||
| 315 | /* | |||
| 316 | * If it's a vi message, strip the trailing <newline> so we can | |||
| 317 | * try and paste messages together. | |||
| 318 | */ | |||
| 319 | if (line[len - 1] == '\n') | |||
| 320 | --len; | |||
| 321 | ||||
| 322 | /* | |||
| 323 | * If a message won't fit on a single line, try to split on a <blank>. | |||
| 324 | * If a subsequent message fits on the same line, write a separator | |||
| 325 | * and output it. Otherwise, put out a newline. | |||
| 326 | * | |||
| 327 | * Need up to two padding characters normally; a semi-colon and a | |||
| 328 | * separating space. If only a single line on the screen, add some | |||
| 329 | * more for the trailing continuation message. | |||
| 330 | * | |||
| 331 | * XXX | |||
| 332 | * Assume that periods and semi-colons take up a single column on the | |||
| 333 | * screen. | |||
| 334 | * | |||
| 335 | * XXX | |||
| 336 | * There are almost certainly pathological cases that will break this | |||
| 337 | * code. | |||
| 338 | */ | |||
| 339 | if (IS_ONELINE(sp)((sp)->rows == 1)) | |||
| 340 | (void)msg_cmsg(sp, CMSG_CONT_S, &padding); | |||
| 341 | else | |||
| 342 | padding = 0; | |||
| 343 | padding += 2; | |||
| 344 | ||||
| 345 | maxcols = sp->cols - 1; | |||
| 346 | if (vip->lcontinue != 0) { | |||
| 347 | if (len + vip->lcontinue + padding > maxcols) | |||
| 348 | vs_output(sp, vip->mtype, ".\n", 2); | |||
| 349 | else { | |||
| 350 | vs_output(sp, vip->mtype, ";", 1); | |||
| 351 | vs_output(sp, M_NONE, " ", 1); | |||
| 352 | } | |||
| 353 | } | |||
| 354 | vip->mtype = mtype; | |||
| 355 | for (s = line;; s = t) { | |||
| 356 | for (; len > 0 && isblank(*s); --len, ++s); | |||
| 357 | if (len == 0) | |||
| 358 | break; | |||
| 359 | if (len + vip->lcontinue > maxcols) { | |||
| 360 | for (e = s + (maxcols - vip->lcontinue); | |||
| 361 | e > s && !isblank(*e); --e); | |||
| 362 | if (e == s) | |||
| 363 | e = t = s + (maxcols - vip->lcontinue); | |||
| 364 | else | |||
| 365 | for (t = e; isblank(e[-1]); --e); | |||
| 366 | } else | |||
| 367 | e = t = s + len; | |||
| 368 | ||||
| 369 | /* | |||
| 370 | * If the message ends in a period, discard it, we want to | |||
| 371 | * gang messages where possible. | |||
| 372 | */ | |||
| 373 | len -= t - s; | |||
| 374 | if (len == 0 && (e - s) > 1 && s[(e - s) - 1] == '.') | |||
| 375 | --e; | |||
| 376 | vs_output(sp, mtype, s, e - s); | |||
| 377 | ||||
| 378 | if (len != 0) | |||
| 379 | vs_output(sp, M_NONE, "\n", 1); | |||
| 380 | ||||
| 381 | if (INTERRUPTED(sp)(((((sp)->gp)->flags) & ((0x0004))) || (!v_event_get ((sp), ((void *)0), 0, 0x001) && ((((sp)->gp)-> flags) & ((0x0004)))))) | |||
| 382 | break; | |||
| 383 | } | |||
| 384 | ||||
| 385 | ret: (void)gp->scr_move(sp, oldy, oldx); | |||
| 386 | (void)gp->scr_refresh(sp, 0); | |||
| 387 | } | |||
| 388 | ||||
| 389 | /* | |||
| 390 | * vs_output -- | |||
| 391 | * Output the text to the screen. | |||
| 392 | */ | |||
| 393 | static void | |||
| 394 | vs_output(SCR *sp, mtype_t mtype, const char *line, int llen) | |||
| 395 | { | |||
| 396 | CHAR_T *kp; | |||
| 397 | GS *gp; | |||
| 398 | VI_PRIVATE *vip; | |||
| 399 | size_t chlen, notused; | |||
| 400 | int ch, len, tlen; | |||
| 401 | const char *p, *t; | |||
| 402 | char *cbp, *ecbp, cbuf[128]; | |||
| 403 | ||||
| 404 | gp = sp->gp; | |||
| 405 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); | |||
| 406 | for (p = line; llen > 0;) { | |||
| 407 | /* Get the next physical line. */ | |||
| 408 | if ((p = memchr(line, '\n', llen)) == NULL((void *)0)) | |||
| 409 | len = llen; | |||
| 410 | else | |||
| 411 | len = p - line; | |||
| 412 | ||||
| 413 | /* | |||
| 414 | * The max is sp->cols characters, and we may have already | |||
| 415 | * written part of the line. | |||
| 416 | */ | |||
| 417 | if (len + vip->lcontinue > sp->cols) | |||
| 418 | len = sp->cols - vip->lcontinue; | |||
| 419 | ||||
| 420 | /* | |||
| 421 | * If the first line output, do nothing. If the second line | |||
| 422 | * output, draw the divider line. If drew a full screen, we | |||
| 423 | * remove the divider line. If it's a continuation line, move | |||
| 424 | * to the continuation point, else, move the screen up. | |||
| 425 | */ | |||
| 426 | if (vip->lcontinue == 0) { | |||
| 427 | if (!IS_ONELINE(sp)((sp)->rows == 1)) { | |||
| 428 | if (vip->totalcount == 1) { | |||
| 429 | (void)gp->scr_move(sp, | |||
| 430 | LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1) - 1, 0); | |||
| 431 | (void)gp->scr_clrtoeol(sp); | |||
| 432 | (void)vs_divider(sp); | |||
| 433 | F_SET(vip, VIP_DIVIDER)(((vip)->flags) |= ((0x0002))); | |||
| 434 | ++vip->totalcount; | |||
| 435 | ++vip->linecount; | |||
| 436 | } | |||
| 437 | if (vip->totalcount == sp->t_maxrows && | |||
| 438 | F_ISSET(vip, VIP_DIVIDER)(((vip)->flags) & ((0x0002)))) { | |||
| 439 | --vip->totalcount; | |||
| 440 | --vip->linecount; | |||
| 441 | F_CLR(vip, VIP_DIVIDER)(((vip)->flags) &= ~((0x0002))); | |||
| 442 | } | |||
| 443 | } | |||
| 444 | if (vip->totalcount != 0) | |||
| 445 | vs_scroll(sp, NULL((void *)0), SCROLL_W_QUIT); | |||
| 446 | ||||
| 447 | (void)gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), 0); | |||
| 448 | ++vip->totalcount; | |||
| 449 | ++vip->linecount; | |||
| 450 | ||||
| 451 | if (INTERRUPTED(sp)(((((sp)->gp)->flags) & ((0x0004))) || (!v_event_get ((sp), ((void *)0), 0, 0x001) && ((((sp)->gp)-> flags) & ((0x0004)))))) | |||
| 452 | break; | |||
| 453 | } else | |||
| 454 | (void)gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), vip->lcontinue); | |||
| 455 | ||||
| 456 | /* Error messages are in inverse video. */ | |||
| 457 | if (mtype == M_ERR) | |||
| 458 | (void)gp->scr_attr(sp, SA_INVERSE, 1); | |||
| 459 | ||||
| 460 | /* Display the line, doing character translation. */ | |||
| 461 | #define FLUSH{ *cbp = '\0'; (void)gp->scr_addstr(sp, cbuf, cbp - cbuf); cbp = cbuf; } { \ | |||
| 462 | *cbp = '\0'; \ | |||
| 463 | (void)gp->scr_addstr(sp, cbuf, cbp - cbuf); \ | |||
| 464 | cbp = cbuf; \ | |||
| 465 | } | |||
| 466 | ecbp = (cbp = cbuf) + sizeof(cbuf) - 1; | |||
| 467 | for (t = line, tlen = len; tlen--; ++t) { | |||
| 468 | ch = *t; | |||
| 469 | /* | |||
| 470 | * Replace tabs with spaces, there are places in | |||
| 471 | * ex that do column calculations without looking | |||
| 472 | * at <tabs> -- and all routines that care about | |||
| 473 | * <tabs> do their own expansions. This catches | |||
| 474 | * <tabs> in things like tag search strings. | |||
| 475 | */ | |||
| 476 | if (ch == '\t') | |||
| 477 | ch = ' '; | |||
| 478 | chlen = KEY_LEN(sp, ch)((unsigned char)(ch) <= 254 ? (sp)->gp->cname[(unsigned char)(ch)].len : v_key_len((sp), (ch))); | |||
| 479 | if (cbp + chlen >= ecbp) | |||
| 480 | FLUSH{ *cbp = '\0'; (void)gp->scr_addstr(sp, cbuf, cbp - cbuf); cbp = cbuf; }; | |||
| 481 | for (kp = KEY_NAME(sp, ch)((unsigned char)(ch) <= 254 ? (sp)->gp->cname[(unsigned char)(ch)].name : v_key_name((sp), (ch))); chlen--;) | |||
| 482 | *cbp++ = *kp++; | |||
| 483 | } | |||
| 484 | if (cbp > cbuf) | |||
| 485 | FLUSH{ *cbp = '\0'; (void)gp->scr_addstr(sp, cbuf, cbp - cbuf); cbp = cbuf; }; | |||
| 486 | if (mtype == M_ERR) | |||
| 487 | (void)gp->scr_attr(sp, SA_INVERSE, 0); | |||
| 488 | ||||
| 489 | /* Clear the rest of the line. */ | |||
| 490 | (void)gp->scr_clrtoeol(sp); | |||
| 491 | ||||
| 492 | /* If we loop, it's a new line. */ | |||
| 493 | vip->lcontinue = 0; | |||
| 494 | ||||
| 495 | /* Reset for the next line. */ | |||
| 496 | line += len; | |||
| 497 | llen -= len; | |||
| 498 | if (p != NULL((void *)0)) { | |||
| 499 | ++line; | |||
| 500 | --llen; | |||
| 501 | } | |||
| 502 | } | |||
| 503 | ||||
| 504 | /* Set up next continuation line. */ | |||
| 505 | if (p == NULL((void *)0)) | |||
| 506 | gp->scr_cursor(sp, ¬used, &vip->lcontinue); | |||
| 507 | } | |||
| 508 | ||||
| 509 | /* | |||
| 510 | * vs_ex_resolve -- | |||
| 511 | * Deal with ex message output. | |||
| 512 | * | |||
| 513 | * This routine is called when exiting a colon command to resolve any ex | |||
| 514 | * output that may have occurred. | |||
| 515 | * | |||
| 516 | * PUBLIC: int vs_ex_resolve(SCR *, int *); | |||
| 517 | */ | |||
| 518 | int | |||
| 519 | vs_ex_resolve(SCR *sp, int *continuep) | |||
| 520 | { | |||
| 521 | EVENT ev; | |||
| 522 | GS *gp; | |||
| 523 | VI_PRIVATE *vip; | |||
| 524 | sw_t wtype; | |||
| 525 | ||||
| 526 | gp = sp->gp; | |||
| 527 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); | |||
| 528 | *continuep = 0; | |||
| 529 | ||||
| 530 | /* If we ran any ex command, we can't trust the cursor position. */ | |||
| 531 | F_SET(vip, VIP_CUR_INVALID)(((vip)->flags) |= ((0x0001))); | |||
| 532 | ||||
| 533 | /* Terminate any partially written message. */ | |||
| 534 | if (vip->lcontinue != 0) { | |||
| 535 | vs_output(sp, vip->mtype, ".", 1); | |||
| 536 | vip->lcontinue = 0; | |||
| 537 | ||||
| 538 | vip->mtype = M_NONE; | |||
| 539 | } | |||
| 540 | ||||
| 541 | /* | |||
| 542 | * If we switched out of the vi screen into ex, switch back while we | |||
| 543 | * figure out what to do with the screen and potentially get another | |||
| 544 | * command to execute. | |||
| 545 | * | |||
| 546 | * If we didn't switch into ex, we're not required to wait, and less | |||
| 547 | * than 2 lines of output, we can continue without waiting for the | |||
| 548 | * wait. | |||
| 549 | * | |||
| 550 | * Note, all other code paths require waiting, so we leave the report | |||
| 551 | * of modified lines until later, so that we won't wait for no other | |||
| 552 | * reason than a threshold number of lines were modified. This means | |||
| 553 | * we display cumulative line modification reports for groups of ex | |||
| 554 | * commands. That seems right to me (well, at least not wrong). | |||
| 555 | */ | |||
| 556 | if (F_ISSET(sp, SC_SCR_EXWROTE)(((sp)->flags) & ((0x00000010)))) { | |||
| 557 | if (sp->gp->scr_screen(sp, SC_VI0x00000002)) | |||
| 558 | return (1); | |||
| 559 | } else | |||
| 560 | if (!F_ISSET(sp, SC_EX_WAIT_YES)(((sp)->flags) & ((0x00100000))) && vip->totalcount < 2) { | |||
| 561 | F_CLR(sp, SC_EX_WAIT_NO)(((sp)->flags) &= ~((0x00080000))); | |||
| 562 | return (0); | |||
| 563 | } | |||
| 564 | ||||
| 565 | /* Clear the required wait flag, it's no longer needed. */ | |||
| 566 | F_CLR(sp, SC_EX_WAIT_YES)(((sp)->flags) &= ~((0x00100000))); | |||
| 567 | ||||
| 568 | /* | |||
| 569 | * Wait, unless explicitly told not to wait or the user interrupted | |||
| 570 | * the command. If the user is leaving the screen, for any reason, | |||
| 571 | * they can't continue with further ex commands. | |||
| 572 | */ | |||
| 573 | if (!F_ISSET(sp, SC_EX_WAIT_NO)(((sp)->flags) & ((0x00080000))) && !INTERRUPTED(sp)(((((sp)->gp)->flags) & ((0x0004))) || (!v_event_get ((sp), ((void *)0), 0, 0x001) && ((((sp)->gp)-> flags) & ((0x0004)))))) { | |||
| 574 | wtype = F_ISSET(sp, SC_EXIT | SC_EXIT_FORCE |(((sp)->flags) & ((0x00000200 | 0x00000400 | 0x00000800 | 0x00001000))) | |||
| 575 | SC_FSWITCH | SC_SSWITCH)(((sp)->flags) & ((0x00000200 | 0x00000400 | 0x00000800 | 0x00001000))) ? SCROLL_W : SCROLL_W_EX; | |||
| 576 | if (F_ISSET(sp, SC_SCR_EXWROTE)(((sp)->flags) & ((0x00000010)))) | |||
| 577 | vs_wait(sp, continuep, wtype); | |||
| 578 | else | |||
| 579 | vs_scroll(sp, continuep, wtype); | |||
| 580 | if (*continuep) | |||
| 581 | return (0); | |||
| 582 | } | |||
| 583 | ||||
| 584 | /* If ex wrote on the screen, refresh the screen image. */ | |||
| 585 | if (F_ISSET(sp, SC_SCR_EXWROTE)(((sp)->flags) & ((0x00000010)))) | |||
| 586 | F_SET(vip, VIP_N_EX_PAINT)(((vip)->flags) |= ((0x0004))); | |||
| 587 | ||||
| 588 | /* | |||
| 589 | * If we're not the bottom of the split screen stack, the screen | |||
| 590 | * image itself is wrong, so redraw everything. | |||
| 591 | */ | |||
| 592 | if (TAILQ_NEXT(sp, q)((sp)->q.tqe_next)) | |||
| 593 | F_SET(sp, SC_SCR_REDRAW)(((sp)->flags) |= ((0x00000040))); | |||
| 594 | ||||
| 595 | /* If ex changed the underlying file, the map itself is wrong. */ | |||
| 596 | if (F_ISSET(vip, VIP_N_EX_REDRAW)(((vip)->flags) & ((0x0008)))) | |||
| 597 | F_SET(sp, SC_SCR_REFORMAT)(((sp)->flags) |= ((0x00000020))); | |||
| 598 | ||||
| 599 | /* Ex may have switched out of the alternate screen, return. */ | |||
| 600 | (void)gp->scr_attr(sp, SA_ALTERNATE, 1); | |||
| 601 | ||||
| 602 | /* | |||
| 603 | * Whew. We're finally back home, after what feels like years. | |||
| 604 | * Kiss the ground. | |||
| 605 | */ | |||
| 606 | F_CLR(sp, SC_SCR_EXWROTE | SC_EX_WAIT_NO)(((sp)->flags) &= ~((0x00000010 | 0x00080000))); | |||
| 607 | ||||
| 608 | /* | |||
| 609 | * We may need to repaint some of the screen, e.g.: | |||
| 610 | * | |||
| 611 | * :set | |||
| 612 | * :!ls | |||
| 613 | * | |||
| 614 | * gives us a combination of some lines that are "wrong", and a need | |||
| 615 | * for a full refresh. | |||
| 616 | */ | |||
| 617 | if (vip->totalcount > 1) { | |||
| 618 | /* Set up the redraw of the overwritten lines. */ | |||
| 619 | ev.e_event = E_REPAINT; | |||
| 620 | ev.e_flno_u_event._e_mark.lno1 = vip->totalcount >= | |||
| 621 | sp->rows ? 1 : sp->rows - vip->totalcount; | |||
| 622 | ev.e_tlno_u_event._e_mark.lno2 = sp->rows; | |||
| 623 | ||||
| 624 | /* Reset the count of overwriting lines. */ | |||
| 625 | vip->linecount = vip->lcontinue = vip->totalcount = 0; | |||
| 626 | ||||
| 627 | /* Redraw. */ | |||
| 628 | (void)vs_repaint(sp, &ev); | |||
| 629 | } else | |||
| 630 | /* Reset the count of overwriting lines. */ | |||
| 631 | vip->linecount = vip->lcontinue = vip->totalcount = 0; | |||
| 632 | ||||
| 633 | return (0); | |||
| 634 | } | |||
| 635 | ||||
| 636 | /* | |||
| 637 | * vs_resolve -- | |||
| 638 | * Deal with message output. | |||
| 639 | * | |||
| 640 | * PUBLIC: int vs_resolve(SCR *, SCR *, int); | |||
| 641 | */ | |||
| 642 | int | |||
| 643 | vs_resolve(SCR *sp, SCR *csp, int forcewait) | |||
| 644 | { | |||
| 645 | EVENT ev; | |||
| 646 | GS *gp; | |||
| 647 | MSGS *mp; | |||
| 648 | VI_PRIVATE *vip; | |||
| 649 | size_t oldy, oldx; | |||
| 650 | int redraw; | |||
| 651 | ||||
| 652 | /* | |||
| 653 | * Vs_resolve is called from the main vi loop and the refresh function | |||
| 654 | * to periodically ensure that the user has seen any messages that have | |||
| 655 | * been displayed and that any status lines are correct. The sp screen | |||
| 656 | * is the screen we're checking, usually the current screen. When it's | |||
| 657 | * not, csp is the current screen, used for final cursor positioning. | |||
| 658 | */ | |||
| 659 | gp = sp->gp; | |||
| 660 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); | |||
| 661 | if (csp == NULL((void *)0)) | |||
| ||||
| 662 | csp = sp; | |||
| 663 | ||||
| 664 | /* Save the cursor position. */ | |||
| 665 | (void)gp->scr_cursor(csp, &oldy, &oldx); | |||
| 666 | ||||
| 667 | /* Ring the bell if it's scheduled. */ | |||
| 668 | if (F_ISSET(gp, G_BELLSCHED)(((gp)->flags) & ((0x0002)))) { | |||
| 669 | F_CLR(gp, G_BELLSCHED)(((gp)->flags) &= ~((0x0002))); | |||
| 670 | (void)gp->scr_bell(sp); | |||
| 671 | } | |||
| 672 | ||||
| 673 | /* Display new file status line. */ | |||
| 674 | if (F_ISSET(sp, SC_STATUS)(((sp)->flags) & ((0x02000000)))) { | |||
| 675 | F_CLR(sp, SC_STATUS)(((sp)->flags) &= ~((0x02000000))); | |||
| 676 | msgq_status(sp, sp->lno, MSTAT_TRUNCATE0x02); | |||
| 677 | } | |||
| 678 | ||||
| 679 | /* Report on line modifications. */ | |||
| 680 | mod_rpt(sp); | |||
| 681 | ||||
| 682 | /* | |||
| 683 | * Flush any saved messages. If the screen isn't ready, refresh | |||
| 684 | * it. (A side-effect of screen refresh is that we can display | |||
| 685 | * messages.) Once this is done, don't trust the cursor. That | |||
| 686 | * extra refresh screwed the pooch. | |||
| 687 | */ | |||
| 688 | if (LIST_FIRST(&gp->msgq)((&gp->msgq)->lh_first) != NULL((void *)0)) { | |||
| 689 | if (!F_ISSET(sp, SC_SCR_VI)(((sp)->flags) & ((0x00000008))) && vs_refresh(sp, 1)) | |||
| 690 | return (1); | |||
| 691 | while ((mp = LIST_FIRST(&gp->msgq)((&gp->msgq)->lh_first)) != NULL((void *)0)) { | |||
| 692 | gp->scr_msg(sp, mp->mtype, mp->buf, mp->len); | |||
| ||||
| 693 | LIST_REMOVE(mp, q)do { if ((mp)->q.le_next != ((void *)0)) (mp)->q.le_next ->q.le_prev = (mp)->q.le_prev; *(mp)->q.le_prev = (mp )->q.le_next; ; ; } while (0); | |||
| 694 | free(mp->buf); | |||
| 695 | free(mp); | |||
| 696 | } | |||
| 697 | F_SET(vip, VIP_CUR_INVALID)(((vip)->flags) |= ((0x0001))); | |||
| 698 | } | |||
| 699 | ||||
| 700 | switch (vip->totalcount) { | |||
| 701 | case 0: | |||
| 702 | redraw = 0; | |||
| 703 | break; | |||
| 704 | case 1: | |||
| 705 | /* | |||
| 706 | * If we're switching screens, we have to wait for messages, | |||
| 707 | * regardless. If we don't wait, skip updating the modeline. | |||
| 708 | */ | |||
| 709 | if (forcewait) | |||
| 710 | vs_scroll(sp, NULL((void *)0), SCROLL_W); | |||
| 711 | else | |||
| 712 | F_SET(vip, VIP_S_MODELINE)(((vip)->flags) |= ((0x0080))); | |||
| 713 | ||||
| 714 | redraw = 0; | |||
| 715 | break; | |||
| 716 | default: | |||
| 717 | /* | |||
| 718 | * If >1 message line in use, prompt the user to continue and | |||
| 719 | * repaint overwritten lines. | |||
| 720 | */ | |||
| 721 | vs_scroll(sp, NULL((void *)0), SCROLL_W); | |||
| 722 | ||||
| 723 | ev.e_event = E_REPAINT; | |||
| 724 | ev.e_flno_u_event._e_mark.lno1 = vip->totalcount >= | |||
| 725 | sp->rows ? 1 : sp->rows - vip->totalcount; | |||
| 726 | ev.e_tlno_u_event._e_mark.lno2 = sp->rows; | |||
| 727 | ||||
| 728 | redraw = 1; | |||
| 729 | break; | |||
| 730 | } | |||
| 731 | ||||
| 732 | /* Reset the count of overwriting lines. */ | |||
| 733 | vip->linecount = vip->lcontinue = vip->totalcount = 0; | |||
| 734 | ||||
| 735 | /* Redraw. */ | |||
| 736 | if (redraw) | |||
| 737 | (void)vs_repaint(sp, &ev); | |||
| 738 | ||||
| 739 | /* Restore the cursor position. */ | |||
| 740 | (void)gp->scr_move(csp, oldy, oldx); | |||
| 741 | ||||
| 742 | return (0); | |||
| 743 | } | |||
| 744 | ||||
| 745 | /* | |||
| 746 | * vs_scroll -- | |||
| 747 | * Scroll the screen for output. | |||
| 748 | */ | |||
| 749 | static void | |||
| 750 | vs_scroll(SCR *sp, int *continuep, sw_t wtype) | |||
| 751 | { | |||
| 752 | GS *gp; | |||
| 753 | VI_PRIVATE *vip; | |||
| 754 | ||||
| 755 | gp = sp->gp; | |||
| 756 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); | |||
| 757 | if (!IS_ONELINE(sp)((sp)->rows == 1)) { | |||
| 758 | /* | |||
| 759 | * Scroll the screen. Instead of scrolling the entire screen, | |||
| 760 | * delete the line above the first line output so preserve the | |||
| 761 | * maximum amount of the screen. | |||
| 762 | */ | |||
| 763 | (void)gp->scr_move(sp, vip->totalcount < | |||
| 764 | sp->rows ? LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1) - vip->totalcount : 0, 0); | |||
| 765 | (void)gp->scr_deleteln(sp); | |||
| 766 | ||||
| 767 | /* If there are screens below us, push them back into place. */ | |||
| 768 | if (TAILQ_NEXT(sp, q)((sp)->q.tqe_next)) { | |||
| 769 | (void)gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), 0); | |||
| 770 | (void)gp->scr_insertln(sp); | |||
| 771 | } | |||
| 772 | } | |||
| 773 | if (wtype == SCROLL_W_QUIT && vip->linecount < sp->t_maxrows) | |||
| 774 | return; | |||
| 775 | vs_wait(sp, continuep, wtype); | |||
| 776 | } | |||
| 777 | ||||
| 778 | /* | |||
| 779 | * vs_wait -- | |||
| 780 | * Prompt the user to continue. | |||
| 781 | */ | |||
| 782 | static void | |||
| 783 | vs_wait(SCR *sp, int *continuep, sw_t wtype) | |||
| 784 | { | |||
| 785 | EVENT ev; | |||
| 786 | VI_PRIVATE *vip; | |||
| 787 | const char *p; | |||
| 788 | GS *gp; | |||
| 789 | size_t len; | |||
| 790 | ||||
| 791 | gp = sp->gp; | |||
| 792 | vip = VIP(sp)((VI_PRIVATE *)((sp)->vi_private)); | |||
| 793 | ||||
| 794 | (void)gp->scr_move(sp, LASTLINE(sp)((sp)->t_maxrows < (sp)->rows ? (sp)->t_maxrows : (sp)->rows - 1), 0); | |||
| 795 | if (IS_ONELINE(sp)((sp)->rows == 1)) | |||
| 796 | p = msg_cmsg(sp, CMSG_CONT_S, &len); | |||
| 797 | else | |||
| 798 | switch (wtype) { | |||
| 799 | case SCROLL_W_QUIT: | |||
| 800 | p = msg_cmsg(sp, CMSG_CONT_Q, &len); | |||
| 801 | break; | |||
| 802 | case SCROLL_W_EX: | |||
| 803 | p = msg_cmsg(sp, CMSG_CONT_EX, &len); | |||
| 804 | break; | |||
| 805 | case SCROLL_W: | |||
| 806 | p = msg_cmsg(sp, CMSG_CONT, &len); | |||
| 807 | break; | |||
| 808 | default: | |||
| 809 | abort(); | |||
| 810 | /* NOTREACHED */ | |||
| 811 | } | |||
| 812 | (void)gp->scr_addstr(sp, p, len); | |||
| 813 | ||||
| 814 | ++vip->totalcount; | |||
| 815 | vip->linecount = 0; | |||
| 816 | ||||
| 817 | (void)gp->scr_clrtoeol(sp); | |||
| 818 | (void)gp->scr_refresh(sp, 0); | |||
| 819 | ||||
| 820 | /* Get a single character from the terminal. */ | |||
| 821 | if (continuep != NULL((void *)0)) | |||
| 822 | *continuep = 0; | |||
| 823 | for (;;) { | |||
| 824 | if (v_event_get(sp, &ev, 0, 0)) | |||
| 825 | return; | |||
| 826 | if (ev.e_event == E_CHARACTER) | |||
| 827 | break; | |||
| 828 | if (ev.e_event == E_INTERRUPT) { | |||
| 829 | ev.e_c_u_event._e_ch.c = CH_QUIT'q'; | |||
| 830 | F_SET(gp, G_INTERRUPTED)(((gp)->flags) |= ((0x0004))); | |||
| 831 | break; | |||
| 832 | } | |||
| 833 | (void)gp->scr_bell(sp); | |||
| 834 | } | |||
| 835 | switch (wtype) { | |||
| 836 | case SCROLL_W_QUIT: | |||
| 837 | if (ev.e_c_u_event._e_ch.c == CH_QUIT'q') | |||
| 838 | F_SET(gp, G_INTERRUPTED)(((gp)->flags) |= ((0x0004))); | |||
| 839 | break; | |||
| 840 | case SCROLL_W_EX: | |||
| 841 | if (ev.e_c_u_event._e_ch.c == ':' && continuep != NULL((void *)0)) | |||
| 842 | *continuep = 1; | |||
| 843 | break; | |||
| 844 | case SCROLL_W: | |||
| 845 | break; | |||
| 846 | } | |||
| 847 | } | |||
| 848 | ||||
| 849 | /* | |||
| 850 | * vs_divider -- | |||
| 851 | * Draw a dividing line between the screen and the output. | |||
| 852 | */ | |||
| 853 | static void | |||
| 854 | vs_divider(SCR *sp) | |||
| 855 | { | |||
| 856 | GS *gp; | |||
| 857 | size_t len; | |||
| 858 | ||||
| 859 | #define DIVIDESTR"+=+=+=+=+=+=+=+" "+=+=+=+=+=+=+=+" | |||
| 860 | len = | |||
| 861 | sizeof(DIVIDESTR"+=+=+=+=+=+=+=+") - 1 > sp->cols ? sp->cols : sizeof(DIVIDESTR"+=+=+=+=+=+=+=+") - 1; | |||
| 862 | gp = sp->gp; | |||
| 863 | (void)gp->scr_attr(sp, SA_INVERSE, 1); | |||
| 864 | (void)gp->scr_addstr(sp, DIVIDESTR"+=+=+=+=+=+=+=+", len); | |||
| 865 | (void)gp->scr_attr(sp, SA_INVERSE, 0); | |||
| 866 | } | |||
| 867 | ||||
| 868 | /* | |||
| 869 | * vs_msgsave -- | |||
| 870 | * Save a message for later display. | |||
| 871 | */ | |||
| 872 | static void | |||
| 873 | vs_msgsave(SCR *sp, mtype_t mt, char *p, size_t len) | |||
| 874 | { | |||
| 875 | GS *gp; | |||
| 876 | MSGS *mp_c, *mp_n; | |||
| 877 | ||||
| 878 | /* | |||
| 879 | * We have to handle messages before we have any place to put them. | |||
| 880 | * If there's no screen support yet, allocate a msg structure, copy | |||
| 881 | * in the message, and queue it on the global structure. If we can't | |||
| 882 | * allocate memory here, we're genuinely screwed, dump the message | |||
| 883 | * to stderr in the (probably) vain hope that someone will see it. | |||
| 884 | */ | |||
| 885 | CALLOC_GOTO(sp, mp_n, 1, sizeof(MSGS)){ if (((mp_n) = calloc((1), (sizeof(MSGS)))) == ((void *)0)) goto alloc_err; }; | |||
| 886 | MALLOC_GOTO(sp, mp_n->buf, len){ if (((mp_n->buf) = malloc(len)) == ((void *)0)) goto alloc_err ; }; | |||
| 887 | ||||
| 888 | memmove(mp_n->buf, p, len); | |||
| 889 | mp_n->len = len; | |||
| 890 | mp_n->mtype = mt; | |||
| 891 | ||||
| 892 | gp = sp->gp; | |||
| 893 | if ((mp_c = LIST_FIRST(&gp->msgq)((&gp->msgq)->lh_first)) == NULL((void *)0)) { | |||
| 894 | LIST_INSERT_HEAD(&gp->msgq, mp_n, q)do { if (((mp_n)->q.le_next = (&gp->msgq)->lh_first ) != ((void *)0)) (&gp->msgq)->lh_first->q.le_prev = &(mp_n)->q.le_next; (&gp->msgq)->lh_first = (mp_n); (mp_n)->q.le_prev = &(&gp->msgq)-> lh_first; } while (0); | |||
| 895 | } else { | |||
| 896 | for (; LIST_NEXT(mp_c, q)((mp_c)->q.le_next) != NULL((void *)0); mp_c = LIST_NEXT(mp_c, q)((mp_c)->q.le_next)); | |||
| 897 | LIST_INSERT_AFTER(mp_c, mp_n, q)do { if (((mp_n)->q.le_next = (mp_c)->q.le_next) != ((void *)0)) (mp_c)->q.le_next->q.le_prev = &(mp_n)->q .le_next; (mp_c)->q.le_next = (mp_n); (mp_n)->q.le_prev = &(mp_c)->q.le_next; } while (0); | |||
| 898 | } | |||
| 899 | return; | |||
| 900 | ||||
| 901 | alloc_err: | |||
| 902 | free(mp_n); | |||
| 903 | (void)fprintf(stderr(&__sF[2]), "%.*s\n", (int)len, p); | |||
| 904 | } |