1b8ba871bSPeter Wemm /*- 2b8ba871bSPeter Wemm * Copyright (c) 1991, 1993, 1994 3b8ba871bSPeter Wemm * The Regents of the University of California. All rights reserved. 4b8ba871bSPeter Wemm * Copyright (c) 1991, 1993, 1994, 1995, 1996 5b8ba871bSPeter Wemm * Keith Bostic. All rights reserved. 6b8ba871bSPeter Wemm * 7b8ba871bSPeter Wemm * See the LICENSE file for redistribution information. 8b8ba871bSPeter Wemm */ 9b8ba871bSPeter Wemm 10b8ba871bSPeter Wemm #include "config.h" 11b8ba871bSPeter Wemm 12b8ba871bSPeter Wemm #ifndef lint 13*c271fa92SBaptiste Daroussin static const char sccsid[] = "$Id: msg.c,v 11.1 2015/02/09 11:12:44 marc Exp $"; 14b8ba871bSPeter Wemm #endif /* not lint */ 15b8ba871bSPeter Wemm 16f0957ccaSPeter Wemm #include <sys/types.h> 17b8ba871bSPeter Wemm #include <sys/queue.h> 18b8ba871bSPeter Wemm #include <sys/stat.h> 19b8ba871bSPeter Wemm 20b8ba871bSPeter Wemm #include <bitstring.h> 21b8ba871bSPeter Wemm #include <ctype.h> 22b8ba871bSPeter Wemm #include <errno.h> 23b8ba871bSPeter Wemm #include <fcntl.h> 24b8ba871bSPeter Wemm #include <limits.h> 25f0957ccaSPeter Wemm #include <locale.h> 26f0957ccaSPeter Wemm #include <stdarg.h> 27b8ba871bSPeter Wemm #include <stdio.h> 28b8ba871bSPeter Wemm #include <stdlib.h> 29b8ba871bSPeter Wemm #include <string.h> 30b8ba871bSPeter Wemm #include <unistd.h> 31b8ba871bSPeter Wemm 32b8ba871bSPeter Wemm #include "common.h" 33b8ba871bSPeter Wemm #include "../vi/vi.h" 34b8ba871bSPeter Wemm 35b8ba871bSPeter Wemm /* 36b8ba871bSPeter Wemm * msgq -- 37b8ba871bSPeter Wemm * Display a message. 38b8ba871bSPeter Wemm * 39*c271fa92SBaptiste Daroussin * PUBLIC: void msgq(SCR *, mtype_t, const char *, ...); 40b8ba871bSPeter Wemm */ 41b8ba871bSPeter Wemm void 42f0957ccaSPeter Wemm msgq( 43f0957ccaSPeter Wemm SCR *sp, 44f0957ccaSPeter Wemm mtype_t mt, 45f0957ccaSPeter Wemm const char *fmt, 46f0957ccaSPeter Wemm ...) 47b8ba871bSPeter Wemm { 48b8ba871bSPeter Wemm #ifndef NL_ARGMAX 49b8ba871bSPeter Wemm #define __NL_ARGMAX 20 /* Set to 9 by System V. */ 50b8ba871bSPeter Wemm struct { 51b8ba871bSPeter Wemm const char *str; /* String pointer. */ 52b8ba871bSPeter Wemm size_t arg; /* Argument number. */ 53b8ba871bSPeter Wemm size_t prefix; /* Prefix string length. */ 54b8ba871bSPeter Wemm size_t skip; /* Skipped string length. */ 55b8ba871bSPeter Wemm size_t suffix; /* Suffix string length. */ 56b8ba871bSPeter Wemm } str[__NL_ARGMAX]; 57b8ba871bSPeter Wemm #endif 58b8ba871bSPeter Wemm static int reenter; /* STATIC: Re-entrancy check. */ 59b8ba871bSPeter Wemm GS *gp; 60f0957ccaSPeter Wemm size_t blen, len, mlen, nlen; 61f0957ccaSPeter Wemm const char *p; 62f0957ccaSPeter Wemm char *bp, *mp; 63b8ba871bSPeter Wemm va_list ap; 64f0957ccaSPeter Wemm #ifndef NL_ARGMAX 65f0957ccaSPeter Wemm int ch; 66f0957ccaSPeter Wemm char *rbp, *s_rbp; 67f0957ccaSPeter Wemm const char *t, *u; 68f0957ccaSPeter Wemm size_t cnt1, cnt2, soff; 69f0957ccaSPeter Wemm #endif 70b8ba871bSPeter Wemm 71b8ba871bSPeter Wemm /* 72b8ba871bSPeter Wemm * !!! 73b8ba871bSPeter Wemm * It's possible to enter msg when there's no screen to hold the 74b8ba871bSPeter Wemm * message. If sp is NULL, ignore the special cases and put the 75b8ba871bSPeter Wemm * message out to stderr. 76b8ba871bSPeter Wemm */ 77b8ba871bSPeter Wemm if (sp == NULL) { 78b8ba871bSPeter Wemm gp = NULL; 79b8ba871bSPeter Wemm if (mt == M_BERR) 80b8ba871bSPeter Wemm mt = M_ERR; 81b8ba871bSPeter Wemm else if (mt == M_VINFO) 82b8ba871bSPeter Wemm mt = M_INFO; 83b8ba871bSPeter Wemm } else { 84b8ba871bSPeter Wemm gp = sp->gp; 85b8ba871bSPeter Wemm switch (mt) { 86b8ba871bSPeter Wemm case M_BERR: 87b8ba871bSPeter Wemm if (F_ISSET(sp, SC_VI) && !O_ISSET(sp, O_VERBOSE)) { 88b8ba871bSPeter Wemm F_SET(gp, G_BELLSCHED); 89b8ba871bSPeter Wemm return; 90b8ba871bSPeter Wemm } 91b8ba871bSPeter Wemm mt = M_ERR; 92b8ba871bSPeter Wemm break; 93b8ba871bSPeter Wemm case M_VINFO: 94b8ba871bSPeter Wemm if (!O_ISSET(sp, O_VERBOSE)) 95b8ba871bSPeter Wemm return; 96b8ba871bSPeter Wemm mt = M_INFO; 97b8ba871bSPeter Wemm /* FALLTHROUGH */ 98b8ba871bSPeter Wemm case M_INFO: 99b8ba871bSPeter Wemm if (F_ISSET(sp, SC_EX_SILENT)) 100b8ba871bSPeter Wemm return; 101b8ba871bSPeter Wemm break; 102b8ba871bSPeter Wemm case M_ERR: 103b8ba871bSPeter Wemm case M_SYSERR: 104b8ba871bSPeter Wemm break; 105b8ba871bSPeter Wemm default: 106b8ba871bSPeter Wemm abort(); 107b8ba871bSPeter Wemm } 108b8ba871bSPeter Wemm } 109b8ba871bSPeter Wemm 110b8ba871bSPeter Wemm /* 111b8ba871bSPeter Wemm * It's possible to reenter msg when it allocates space. We're 112b8ba871bSPeter Wemm * probably dead anyway, but there's no reason to drop core. 113b8ba871bSPeter Wemm * 114b8ba871bSPeter Wemm * XXX 115b8ba871bSPeter Wemm * Yes, there's a race, but it should only be two instructions. 116b8ba871bSPeter Wemm */ 117b8ba871bSPeter Wemm if (reenter++) 118b8ba871bSPeter Wemm return; 119b8ba871bSPeter Wemm 120b8ba871bSPeter Wemm /* Get space for the message. */ 121b8ba871bSPeter Wemm nlen = 1024; 122b8ba871bSPeter Wemm if (0) { 123b8ba871bSPeter Wemm retry: FREE_SPACE(sp, bp, blen); 124b8ba871bSPeter Wemm nlen *= 2; 125b8ba871bSPeter Wemm } 126b8ba871bSPeter Wemm bp = NULL; 127b8ba871bSPeter Wemm blen = 0; 128f0957ccaSPeter Wemm GET_SPACE_GOTOC(sp, bp, blen, nlen); 129b8ba871bSPeter Wemm 130b8ba871bSPeter Wemm /* 131b8ba871bSPeter Wemm * Error prefix. 132b8ba871bSPeter Wemm * 133b8ba871bSPeter Wemm * mp: pointer to the current next character to be written 134b8ba871bSPeter Wemm * mlen: length of the already written characters 135b8ba871bSPeter Wemm * blen: total length of the buffer 136b8ba871bSPeter Wemm */ 137b8ba871bSPeter Wemm #define REM (blen - mlen) 138b8ba871bSPeter Wemm mp = bp; 139b8ba871bSPeter Wemm mlen = 0; 140b8ba871bSPeter Wemm if (mt == M_SYSERR) { 141b8ba871bSPeter Wemm p = msg_cat(sp, "020|Error: ", &len); 142b8ba871bSPeter Wemm if (REM < len) 143b8ba871bSPeter Wemm goto retry; 144b8ba871bSPeter Wemm memcpy(mp, p, len); 145b8ba871bSPeter Wemm mp += len; 146b8ba871bSPeter Wemm mlen += len; 147b8ba871bSPeter Wemm } 148b8ba871bSPeter Wemm 149b8ba871bSPeter Wemm /* 150b8ba871bSPeter Wemm * If we're running an ex command that the user didn't enter, display 151b8ba871bSPeter Wemm * the file name and line number prefix. 152b8ba871bSPeter Wemm */ 153b8ba871bSPeter Wemm if ((mt == M_ERR || mt == M_SYSERR) && 154b8ba871bSPeter Wemm sp != NULL && gp != NULL && gp->if_name != NULL) { 155f0957ccaSPeter Wemm CHAR_T *wp; 156f0957ccaSPeter Wemm size_t wlen; 157f0957ccaSPeter Wemm 158f0957ccaSPeter Wemm CHAR2INT(sp, gp->if_name, strlen(gp->if_name) + 1, wp, wlen); 159f0957ccaSPeter Wemm for (; *wp != '\0'; ++wp) { 160f0957ccaSPeter Wemm len = snprintf(mp, REM, "%s", KEY_NAME(sp, *wp)); 161b8ba871bSPeter Wemm mp += len; 162b8ba871bSPeter Wemm if ((mlen += len) > blen) 163b8ba871bSPeter Wemm goto retry; 164b8ba871bSPeter Wemm } 165b8ba871bSPeter Wemm len = snprintf(mp, REM, ", %d: ", gp->if_lno); 166b8ba871bSPeter Wemm mp += len; 167b8ba871bSPeter Wemm if ((mlen += len) > blen) 168b8ba871bSPeter Wemm goto retry; 169b8ba871bSPeter Wemm } 170b8ba871bSPeter Wemm 171b8ba871bSPeter Wemm /* If nothing to format, we're done. */ 172b8ba871bSPeter Wemm if (fmt == NULL) 173b8ba871bSPeter Wemm goto nofmt; 174b8ba871bSPeter Wemm fmt = msg_cat(sp, fmt, NULL); 175b8ba871bSPeter Wemm 176b8ba871bSPeter Wemm #ifndef NL_ARGMAX 177b8ba871bSPeter Wemm /* 178b8ba871bSPeter Wemm * Nvi should run on machines that don't support the numbered argument 179b8ba871bSPeter Wemm * specifications (%[digit]*$). We do this by reformatting the string 180b8ba871bSPeter Wemm * so that we can hand it to vsprintf(3) and it will use the arguments 181b8ba871bSPeter Wemm * in the right order. When vsprintf returns, we put the string back 182b8ba871bSPeter Wemm * into the right order. It's undefined, according to SVID III, to mix 183b8ba871bSPeter Wemm * numbered argument specifications with the standard style arguments, 184b8ba871bSPeter Wemm * so this should be safe. 185b8ba871bSPeter Wemm * 186b8ba871bSPeter Wemm * In addition, we also need a character that is known to not occur in 187b8ba871bSPeter Wemm * any vi message, for separating the parts of the string. As callers 188b8ba871bSPeter Wemm * of msgq are responsible for making sure that all the non-printable 189b8ba871bSPeter Wemm * characters are formatted for printing before calling msgq, we use a 190b8ba871bSPeter Wemm * random non-printable character selected at terminal initialization 191b8ba871bSPeter Wemm * time. This code isn't fast by any means, but as messages should be 192b8ba871bSPeter Wemm * relatively short and normally have only a few arguments, it won't be 193b8ba871bSPeter Wemm * too bad. Regardless, nobody has come up with any other solution. 194b8ba871bSPeter Wemm * 195b8ba871bSPeter Wemm * The result of this loop is an array of pointers into the message 196b8ba871bSPeter Wemm * string, with associated lengths and argument numbers. The array 197b8ba871bSPeter Wemm * is in the "correct" order, and the arg field contains the argument 198b8ba871bSPeter Wemm * order. 199b8ba871bSPeter Wemm */ 200b8ba871bSPeter Wemm for (p = fmt, soff = 0; soff < __NL_ARGMAX;) { 201b8ba871bSPeter Wemm for (t = p; *p != '\0' && *p != '%'; ++p); 202b8ba871bSPeter Wemm if (*p == '\0') 203b8ba871bSPeter Wemm break; 204b8ba871bSPeter Wemm ++p; 205b8ba871bSPeter Wemm if (!isdigit(*p)) { 206b8ba871bSPeter Wemm if (*p == '%') 207b8ba871bSPeter Wemm ++p; 208b8ba871bSPeter Wemm continue; 209b8ba871bSPeter Wemm } 210b8ba871bSPeter Wemm for (u = p; *++p != '\0' && isdigit(*p);); 211b8ba871bSPeter Wemm if (*p != '$') 212b8ba871bSPeter Wemm continue; 213b8ba871bSPeter Wemm 214b8ba871bSPeter Wemm /* Up to, and including the % character. */ 215b8ba871bSPeter Wemm str[soff].str = t; 216b8ba871bSPeter Wemm str[soff].prefix = u - t; 217b8ba871bSPeter Wemm 218b8ba871bSPeter Wemm /* Up to, and including the $ character. */ 219b8ba871bSPeter Wemm str[soff].arg = atoi(u); 220b8ba871bSPeter Wemm str[soff].skip = (p - u) + 1; 221b8ba871bSPeter Wemm if (str[soff].arg >= __NL_ARGMAX) 222b8ba871bSPeter Wemm goto ret; 223b8ba871bSPeter Wemm 224b8ba871bSPeter Wemm /* Up to, and including the conversion character. */ 225b8ba871bSPeter Wemm for (u = p; (ch = *++p) != '\0';) 226b8ba871bSPeter Wemm if (isalpha(ch) && 227b8ba871bSPeter Wemm strchr("diouxXfeEgGcspn", ch) != NULL) 228b8ba871bSPeter Wemm break; 229b8ba871bSPeter Wemm str[soff].suffix = p - u; 230b8ba871bSPeter Wemm if (ch != '\0') 231b8ba871bSPeter Wemm ++p; 232b8ba871bSPeter Wemm ++soff; 233b8ba871bSPeter Wemm } 234b8ba871bSPeter Wemm 235b8ba871bSPeter Wemm /* If no magic strings, we're done. */ 236b8ba871bSPeter Wemm if (soff == 0) 237b8ba871bSPeter Wemm goto format; 238b8ba871bSPeter Wemm 239b8ba871bSPeter Wemm /* Get space for the reordered strings. */ 240b8ba871bSPeter Wemm if ((rbp = malloc(nlen)) == NULL) 241b8ba871bSPeter Wemm goto ret; 242b8ba871bSPeter Wemm s_rbp = rbp; 243b8ba871bSPeter Wemm 244b8ba871bSPeter Wemm /* 245b8ba871bSPeter Wemm * Reorder the strings into the message string based on argument 246b8ba871bSPeter Wemm * order. 247b8ba871bSPeter Wemm * 248b8ba871bSPeter Wemm * !!! 249b8ba871bSPeter Wemm * We ignore arguments that are out of order, i.e. if we don't find 250b8ba871bSPeter Wemm * an argument, we continue. Assume (almost certainly incorrectly) 251b8ba871bSPeter Wemm * that whoever created the string knew what they were doing. 252b8ba871bSPeter Wemm * 253b8ba871bSPeter Wemm * !!! 254b8ba871bSPeter Wemm * Brute force "sort", but since we don't expect more than one or two 255b8ba871bSPeter Wemm * arguments in a string, the setup cost of a fast sort will be more 256b8ba871bSPeter Wemm * expensive than the loop. 257b8ba871bSPeter Wemm */ 258b8ba871bSPeter Wemm for (cnt1 = 1; cnt1 <= soff; ++cnt1) 259b8ba871bSPeter Wemm for (cnt2 = 0; cnt2 < soff; ++cnt2) 260b8ba871bSPeter Wemm if (cnt1 == str[cnt2].arg) { 261b8ba871bSPeter Wemm memmove(s_rbp, str[cnt2].str, str[cnt2].prefix); 262b8ba871bSPeter Wemm memmove(s_rbp + str[cnt2].prefix, 263b8ba871bSPeter Wemm str[cnt2].str + str[cnt2].prefix + 264b8ba871bSPeter Wemm str[cnt2].skip, str[cnt2].suffix); 265b8ba871bSPeter Wemm s_rbp += str[cnt2].prefix + str[cnt2].suffix; 266b8ba871bSPeter Wemm *s_rbp++ = 267b8ba871bSPeter Wemm gp == NULL ? DEFAULT_NOPRINT : gp->noprint; 268b8ba871bSPeter Wemm break; 269b8ba871bSPeter Wemm } 270b8ba871bSPeter Wemm *s_rbp = '\0'; 271b8ba871bSPeter Wemm fmt = rbp; 272b8ba871bSPeter Wemm #endif 273b8ba871bSPeter Wemm 274f0957ccaSPeter Wemm #ifndef NL_ARGMAX 275b8ba871bSPeter Wemm format: /* Format the arguments into the string. */ 276b8ba871bSPeter Wemm #endif 277f0957ccaSPeter Wemm va_start(ap, fmt); 278b8ba871bSPeter Wemm len = vsnprintf(mp, REM, fmt, ap); 279b8ba871bSPeter Wemm va_end(ap); 280b8ba871bSPeter Wemm if (len >= nlen) 281b8ba871bSPeter Wemm goto retry; 282b8ba871bSPeter Wemm 283b8ba871bSPeter Wemm #ifndef NL_ARGMAX 284b8ba871bSPeter Wemm if (soff == 0) 285b8ba871bSPeter Wemm goto nofmt; 286b8ba871bSPeter Wemm 287b8ba871bSPeter Wemm /* 288b8ba871bSPeter Wemm * Go through the resulting string, and, for each separator character 289b8ba871bSPeter Wemm * separated string, enter its new starting position and length in the 290b8ba871bSPeter Wemm * array. 291b8ba871bSPeter Wemm */ 292b8ba871bSPeter Wemm for (p = t = mp, cnt1 = 1, 293b8ba871bSPeter Wemm ch = gp == NULL ? DEFAULT_NOPRINT : gp->noprint; *p != '\0'; ++p) 294b8ba871bSPeter Wemm if (*p == ch) { 295b8ba871bSPeter Wemm for (cnt2 = 0; cnt2 < soff; ++cnt2) 296b8ba871bSPeter Wemm if (str[cnt2].arg == cnt1) 297b8ba871bSPeter Wemm break; 298b8ba871bSPeter Wemm str[cnt2].str = t; 299b8ba871bSPeter Wemm str[cnt2].prefix = p - t; 300b8ba871bSPeter Wemm t = p + 1; 301b8ba871bSPeter Wemm ++cnt1; 302b8ba871bSPeter Wemm } 303b8ba871bSPeter Wemm 304b8ba871bSPeter Wemm /* 305b8ba871bSPeter Wemm * Reorder the strings once again, putting them back into the 306b8ba871bSPeter Wemm * message buffer. 307b8ba871bSPeter Wemm * 308b8ba871bSPeter Wemm * !!! 309b8ba871bSPeter Wemm * Note, the length of the message gets decremented once for 310b8ba871bSPeter Wemm * each substring, when we discard the separator character. 311b8ba871bSPeter Wemm */ 312b8ba871bSPeter Wemm for (s_rbp = rbp, cnt1 = 0; cnt1 < soff; ++cnt1) { 313b8ba871bSPeter Wemm memmove(rbp, str[cnt1].str, str[cnt1].prefix); 314b8ba871bSPeter Wemm rbp += str[cnt1].prefix; 315b8ba871bSPeter Wemm --len; 316b8ba871bSPeter Wemm } 317b8ba871bSPeter Wemm memmove(mp, s_rbp, rbp - s_rbp); 318b8ba871bSPeter Wemm 319b8ba871bSPeter Wemm /* Free the reordered string memory. */ 320b8ba871bSPeter Wemm free(s_rbp); 321b8ba871bSPeter Wemm #endif 322b8ba871bSPeter Wemm 323b8ba871bSPeter Wemm nofmt: mp += len; 324b8ba871bSPeter Wemm if ((mlen += len) > blen) 325b8ba871bSPeter Wemm goto retry; 326b8ba871bSPeter Wemm if (mt == M_SYSERR) { 327b8ba871bSPeter Wemm len = snprintf(mp, REM, ": %s", strerror(errno)); 328b8ba871bSPeter Wemm mp += len; 329b8ba871bSPeter Wemm if ((mlen += len) > blen) 330b8ba871bSPeter Wemm goto retry; 331b8ba871bSPeter Wemm mt = M_ERR; 332b8ba871bSPeter Wemm } 333b8ba871bSPeter Wemm 334b8ba871bSPeter Wemm /* Add trailing newline. */ 335b8ba871bSPeter Wemm if ((mlen += 1) > blen) 336b8ba871bSPeter Wemm goto retry; 337b8ba871bSPeter Wemm *mp = '\n'; 338b8ba871bSPeter Wemm 339b8ba871bSPeter Wemm if (sp != NULL) 340b8ba871bSPeter Wemm (void)ex_fflush(sp); 341b8ba871bSPeter Wemm if (gp != NULL) 342b8ba871bSPeter Wemm gp->scr_msg(sp, mt, bp, mlen); 343b8ba871bSPeter Wemm else 344b8ba871bSPeter Wemm (void)fprintf(stderr, "%.*s", (int)mlen, bp); 345b8ba871bSPeter Wemm 346b8ba871bSPeter Wemm /* Cleanup. */ 347f0957ccaSPeter Wemm #ifndef NL_ARGMAX 348f0957ccaSPeter Wemm ret: 349f0957ccaSPeter Wemm #endif 350f0957ccaSPeter Wemm FREE_SPACE(sp, bp, blen); 351b8ba871bSPeter Wemm alloc_err: 352b8ba871bSPeter Wemm reenter = 0; 353b8ba871bSPeter Wemm } 354b8ba871bSPeter Wemm 355b8ba871bSPeter Wemm /* 356f0957ccaSPeter Wemm * msgq_wstr -- 357f0957ccaSPeter Wemm * Display a message with an embedded string. 358f0957ccaSPeter Wemm * 359*c271fa92SBaptiste Daroussin * PUBLIC: void msgq_wstr(SCR *, mtype_t, const CHAR_T *, const char *); 360f0957ccaSPeter Wemm */ 361f0957ccaSPeter Wemm void 362f0957ccaSPeter Wemm msgq_wstr( 363f0957ccaSPeter Wemm SCR *sp, 364f0957ccaSPeter Wemm mtype_t mtype, 365f0957ccaSPeter Wemm const CHAR_T *str, 366f0957ccaSPeter Wemm const char *fmt) 367f0957ccaSPeter Wemm { 368f0957ccaSPeter Wemm size_t nlen; 369f0957ccaSPeter Wemm CONST char *nstr; 370f0957ccaSPeter Wemm 371f0957ccaSPeter Wemm if (str == NULL) { 372f0957ccaSPeter Wemm msgq(sp, mtype, "%s", fmt); 373f0957ccaSPeter Wemm return; 374f0957ccaSPeter Wemm } 375f0957ccaSPeter Wemm INT2CHAR(sp, str, STRLEN(str) + 1, nstr, nlen); 376f0957ccaSPeter Wemm msgq_str(sp, mtype, nstr, fmt); 377f0957ccaSPeter Wemm } 378f0957ccaSPeter Wemm 379f0957ccaSPeter Wemm /* 380b8ba871bSPeter Wemm * msgq_str -- 381b8ba871bSPeter Wemm * Display a message with an embedded string. 382b8ba871bSPeter Wemm * 383*c271fa92SBaptiste Daroussin * PUBLIC: void msgq_str(SCR *, mtype_t, const char *, const char *); 384b8ba871bSPeter Wemm */ 385b8ba871bSPeter Wemm void 386f0957ccaSPeter Wemm msgq_str( 387f0957ccaSPeter Wemm SCR *sp, 388f0957ccaSPeter Wemm mtype_t mtype, 389f0957ccaSPeter Wemm const char *str, 390f0957ccaSPeter Wemm const char *fmt) 391b8ba871bSPeter Wemm { 392b8ba871bSPeter Wemm int nf, sv_errno; 393b8ba871bSPeter Wemm char *p; 394b8ba871bSPeter Wemm 395b8ba871bSPeter Wemm if (str == NULL) { 396f0957ccaSPeter Wemm msgq(sp, mtype, "%s", fmt); 397b8ba871bSPeter Wemm return; 398b8ba871bSPeter Wemm } 399b8ba871bSPeter Wemm 400b8ba871bSPeter Wemm sv_errno = errno; 401b8ba871bSPeter Wemm p = msg_print(sp, str, &nf); 402b8ba871bSPeter Wemm errno = sv_errno; 403b8ba871bSPeter Wemm msgq(sp, mtype, fmt, p); 404b8ba871bSPeter Wemm if (nf) 405b8ba871bSPeter Wemm FREE_SPACE(sp, p, 0); 406b8ba871bSPeter Wemm } 407b8ba871bSPeter Wemm 408b8ba871bSPeter Wemm /* 409b8ba871bSPeter Wemm * mod_rpt -- 410b8ba871bSPeter Wemm * Report on the lines that changed. 411b8ba871bSPeter Wemm * 412b8ba871bSPeter Wemm * !!! 413b8ba871bSPeter Wemm * Historic vi documentation (USD:15-8) claimed that "The editor will also 414b8ba871bSPeter Wemm * always tell you when a change you make affects text which you cannot see." 415b8ba871bSPeter Wemm * This wasn't true -- edit a large file and do "100d|1". We don't implement 416b8ba871bSPeter Wemm * this semantic since it requires tracking each line that changes during a 417b8ba871bSPeter Wemm * command instead of just keeping count. 418b8ba871bSPeter Wemm * 419b8ba871bSPeter Wemm * Line counts weren't right in historic vi, either. For example, given the 420b8ba871bSPeter Wemm * file: 421b8ba871bSPeter Wemm * abc 422b8ba871bSPeter Wemm * def 423b8ba871bSPeter Wemm * the command 2d}, from the 'b' would report that two lines were deleted, 424b8ba871bSPeter Wemm * not one. 425b8ba871bSPeter Wemm * 426*c271fa92SBaptiste Daroussin * PUBLIC: void mod_rpt(SCR *); 427b8ba871bSPeter Wemm */ 428b8ba871bSPeter Wemm void 429f0957ccaSPeter Wemm mod_rpt(SCR *sp) 430b8ba871bSPeter Wemm { 431b8ba871bSPeter Wemm static char * const action[] = { 432b8ba871bSPeter Wemm "293|added", 433b8ba871bSPeter Wemm "294|changed", 434b8ba871bSPeter Wemm "295|deleted", 435b8ba871bSPeter Wemm "296|joined", 436b8ba871bSPeter Wemm "297|moved", 437b8ba871bSPeter Wemm "298|shifted", 438b8ba871bSPeter Wemm "299|yanked", 439b8ba871bSPeter Wemm }; 440b8ba871bSPeter Wemm static char * const lines[] = { 441b8ba871bSPeter Wemm "300|line", 442b8ba871bSPeter Wemm "301|lines", 443b8ba871bSPeter Wemm }; 444b8ba871bSPeter Wemm recno_t total; 445b8ba871bSPeter Wemm u_long rptval; 446b8ba871bSPeter Wemm int first, cnt; 447b8ba871bSPeter Wemm size_t blen, len, tlen; 448b8ba871bSPeter Wemm const char *t; 449b8ba871bSPeter Wemm char * const *ap; 450b8ba871bSPeter Wemm char *bp, *p; 451b8ba871bSPeter Wemm 452b8ba871bSPeter Wemm /* Change reports are turned off in batch mode. */ 453b8ba871bSPeter Wemm if (F_ISSET(sp, SC_EX_SILENT)) 454b8ba871bSPeter Wemm return; 455b8ba871bSPeter Wemm 456b8ba871bSPeter Wemm /* Reset changing line number. */ 457b8ba871bSPeter Wemm sp->rptlchange = OOBLNO; 458b8ba871bSPeter Wemm 459b8ba871bSPeter Wemm /* 460b8ba871bSPeter Wemm * Don't build a message if not enough changed. 461b8ba871bSPeter Wemm * 462b8ba871bSPeter Wemm * !!! 463b8ba871bSPeter Wemm * And now, a vi clone test. Historically, vi reported if the number 464b8ba871bSPeter Wemm * of changed lines was > than the value, not >=, unless it was a yank 465b8ba871bSPeter Wemm * command, which used >=. No lie. Furthermore, an action was never 466b8ba871bSPeter Wemm * reported for a single line action. This is consistent for actions 467b8ba871bSPeter Wemm * other than yank, but yank didn't report single line actions even if 468b8ba871bSPeter Wemm * the report edit option was set to 1. In addition, setting report to 469b8ba871bSPeter Wemm * 0 in the 4BSD historic vi was equivalent to setting it to 1, for an 470b8ba871bSPeter Wemm * unknown reason (this bug was fixed in System III/V at some point). 471b8ba871bSPeter Wemm * I got complaints, so nvi conforms to System III/V historic practice 472b8ba871bSPeter Wemm * except that we report a yank of 1 line if report is set to 1. 473b8ba871bSPeter Wemm */ 474b8ba871bSPeter Wemm #define ARSIZE(a) sizeof(a) / sizeof (*a) 475b8ba871bSPeter Wemm #define MAXNUM 25 476b8ba871bSPeter Wemm rptval = O_VAL(sp, O_REPORT); 477b8ba871bSPeter Wemm for (cnt = 0, total = 0; cnt < ARSIZE(action); ++cnt) 478b8ba871bSPeter Wemm total += sp->rptlines[cnt]; 479b8ba871bSPeter Wemm if (total == 0) 480b8ba871bSPeter Wemm return; 481b8ba871bSPeter Wemm if (total <= rptval && sp->rptlines[L_YANKED] < rptval) { 482b8ba871bSPeter Wemm for (cnt = 0; cnt < ARSIZE(action); ++cnt) 483b8ba871bSPeter Wemm sp->rptlines[cnt] = 0; 484b8ba871bSPeter Wemm return; 485b8ba871bSPeter Wemm } 486b8ba871bSPeter Wemm 487b8ba871bSPeter Wemm /* Build and display the message. */ 488f0957ccaSPeter Wemm GET_SPACE_GOTOC(sp, bp, blen, sizeof(action) * MAXNUM + 1); 489b8ba871bSPeter Wemm for (p = bp, first = 1, tlen = 0, 490b8ba871bSPeter Wemm ap = action, cnt = 0; cnt < ARSIZE(action); ++ap, ++cnt) 491b8ba871bSPeter Wemm if (sp->rptlines[cnt] != 0) { 492b8ba871bSPeter Wemm if (first) 493b8ba871bSPeter Wemm first = 0; 494b8ba871bSPeter Wemm else { 495b8ba871bSPeter Wemm *p++ = ';'; 496b8ba871bSPeter Wemm *p++ = ' '; 497b8ba871bSPeter Wemm tlen += 2; 498b8ba871bSPeter Wemm } 499c513aafeSBruce Evans len = snprintf(p, MAXNUM, "%lu ", 500c513aafeSBruce Evans (u_long)sp->rptlines[cnt]); 501b8ba871bSPeter Wemm p += len; 502b8ba871bSPeter Wemm tlen += len; 503b8ba871bSPeter Wemm t = msg_cat(sp, 504b8ba871bSPeter Wemm lines[sp->rptlines[cnt] == 1 ? 0 : 1], &len); 505b8ba871bSPeter Wemm memcpy(p, t, len); 506b8ba871bSPeter Wemm p += len; 507b8ba871bSPeter Wemm tlen += len; 508b8ba871bSPeter Wemm *p++ = ' '; 509b8ba871bSPeter Wemm ++tlen; 510b8ba871bSPeter Wemm t = msg_cat(sp, *ap, &len); 511b8ba871bSPeter Wemm memcpy(p, t, len); 512b8ba871bSPeter Wemm p += len; 513b8ba871bSPeter Wemm tlen += len; 514b8ba871bSPeter Wemm sp->rptlines[cnt] = 0; 515b8ba871bSPeter Wemm } 516b8ba871bSPeter Wemm 517b8ba871bSPeter Wemm /* Add trailing newline. */ 518b8ba871bSPeter Wemm *p = '\n'; 519b8ba871bSPeter Wemm ++tlen; 520b8ba871bSPeter Wemm 521b8ba871bSPeter Wemm (void)ex_fflush(sp); 522b8ba871bSPeter Wemm sp->gp->scr_msg(sp, M_INFO, bp, tlen); 523b8ba871bSPeter Wemm 524b8ba871bSPeter Wemm FREE_SPACE(sp, bp, blen); 525b8ba871bSPeter Wemm alloc_err: 526b8ba871bSPeter Wemm return; 527b8ba871bSPeter Wemm 528b8ba871bSPeter Wemm #undef ARSIZE 529b8ba871bSPeter Wemm #undef MAXNUM 530b8ba871bSPeter Wemm } 531b8ba871bSPeter Wemm 532b8ba871bSPeter Wemm /* 533b8ba871bSPeter Wemm * msgq_status -- 534b8ba871bSPeter Wemm * Report on the file's status. 535b8ba871bSPeter Wemm * 536*c271fa92SBaptiste Daroussin * PUBLIC: void msgq_status(SCR *, recno_t, u_int); 537b8ba871bSPeter Wemm */ 538b8ba871bSPeter Wemm void 539f0957ccaSPeter Wemm msgq_status( 540f0957ccaSPeter Wemm SCR *sp, 541f0957ccaSPeter Wemm recno_t lno, 542f0957ccaSPeter Wemm u_int flags) 543b8ba871bSPeter Wemm { 544b8ba871bSPeter Wemm recno_t last; 545b8ba871bSPeter Wemm size_t blen, len; 546b8ba871bSPeter Wemm int cnt, needsep; 547b8ba871bSPeter Wemm const char *t; 548f0957ccaSPeter Wemm char **ap, *bp, *np, *p, *s, *ep; 549f0957ccaSPeter Wemm CHAR_T *wp; 550f0957ccaSPeter Wemm size_t wlen; 551b8ba871bSPeter Wemm 552b8ba871bSPeter Wemm /* Get sufficient memory. */ 553b8ba871bSPeter Wemm len = strlen(sp->frp->name); 554f0957ccaSPeter Wemm GET_SPACE_GOTOC(sp, bp, blen, len * MAX_CHARACTER_COLUMNS + 128); 555b8ba871bSPeter Wemm p = bp; 556f0957ccaSPeter Wemm ep = bp + blen; 557f0957ccaSPeter Wemm 558f0957ccaSPeter Wemm /* Convert the filename. */ 559f0957ccaSPeter Wemm CHAR2INT(sp, sp->frp->name, len + 1, wp, wlen); 560b8ba871bSPeter Wemm 561b8ba871bSPeter Wemm /* Copy in the filename. */ 562f0957ccaSPeter Wemm for (; *wp != '\0'; ++wp) { 563f0957ccaSPeter Wemm len = KEY_LEN(sp, *wp); 564f0957ccaSPeter Wemm memcpy(p, KEY_NAME(sp, *wp), len); 565b8ba871bSPeter Wemm p += len; 566b8ba871bSPeter Wemm } 567b8ba871bSPeter Wemm np = p; 568b8ba871bSPeter Wemm *p++ = ':'; 569b8ba871bSPeter Wemm *p++ = ' '; 570b8ba871bSPeter Wemm 571b8ba871bSPeter Wemm /* Copy in the argument count. */ 572b8ba871bSPeter Wemm if (F_ISSET(sp, SC_STATUS_CNT) && sp->argv != NULL) { 573b8ba871bSPeter Wemm for (cnt = 0, ap = sp->argv; *ap != NULL; ++ap, ++cnt); 574b8ba871bSPeter Wemm if (cnt > 1) { 575f0957ccaSPeter Wemm (void)snprintf(p, ep - p, 576b8ba871bSPeter Wemm msg_cat(sp, "317|%d files to edit", NULL), cnt); 577b8ba871bSPeter Wemm p += strlen(p); 578b8ba871bSPeter Wemm *p++ = ':'; 579b8ba871bSPeter Wemm *p++ = ' '; 580b8ba871bSPeter Wemm } 581b8ba871bSPeter Wemm F_CLR(sp, SC_STATUS_CNT); 582b8ba871bSPeter Wemm } 583b8ba871bSPeter Wemm 584b8ba871bSPeter Wemm /* 585b8ba871bSPeter Wemm * See nvi/exf.c:file_init() for a description of how and when the 586b8ba871bSPeter Wemm * read-only bit is set. 587b8ba871bSPeter Wemm * 588b8ba871bSPeter Wemm * !!! 589b8ba871bSPeter Wemm * The historic display for "name changed" was "[Not edited]". 590b8ba871bSPeter Wemm */ 591b8ba871bSPeter Wemm needsep = 0; 592b8ba871bSPeter Wemm if (F_ISSET(sp->frp, FR_NEWFILE)) { 593b8ba871bSPeter Wemm F_CLR(sp->frp, FR_NEWFILE); 594b8ba871bSPeter Wemm t = msg_cat(sp, "021|new file", &len); 595b8ba871bSPeter Wemm memcpy(p, t, len); 596b8ba871bSPeter Wemm p += len; 597b8ba871bSPeter Wemm needsep = 1; 598b8ba871bSPeter Wemm } else { 599b8ba871bSPeter Wemm if (F_ISSET(sp->frp, FR_NAMECHANGE)) { 600b8ba871bSPeter Wemm t = msg_cat(sp, "022|name changed", &len); 601b8ba871bSPeter Wemm memcpy(p, t, len); 602b8ba871bSPeter Wemm p += len; 603b8ba871bSPeter Wemm needsep = 1; 604b8ba871bSPeter Wemm } 605b8ba871bSPeter Wemm if (needsep) { 606b8ba871bSPeter Wemm *p++ = ','; 607b8ba871bSPeter Wemm *p++ = ' '; 608b8ba871bSPeter Wemm } 609b8ba871bSPeter Wemm if (F_ISSET(sp->ep, F_MODIFIED)) 610b8ba871bSPeter Wemm t = msg_cat(sp, "023|modified", &len); 611b8ba871bSPeter Wemm else 612b8ba871bSPeter Wemm t = msg_cat(sp, "024|unmodified", &len); 613b8ba871bSPeter Wemm memcpy(p, t, len); 614b8ba871bSPeter Wemm p += len; 615b8ba871bSPeter Wemm needsep = 1; 616b8ba871bSPeter Wemm } 617b8ba871bSPeter Wemm if (F_ISSET(sp->frp, FR_UNLOCKED)) { 618b8ba871bSPeter Wemm if (needsep) { 619b8ba871bSPeter Wemm *p++ = ','; 620b8ba871bSPeter Wemm *p++ = ' '; 621b8ba871bSPeter Wemm } 622b8ba871bSPeter Wemm t = msg_cat(sp, "025|UNLOCKED", &len); 623b8ba871bSPeter Wemm memcpy(p, t, len); 624b8ba871bSPeter Wemm p += len; 625b8ba871bSPeter Wemm needsep = 1; 626b8ba871bSPeter Wemm } 627b8ba871bSPeter Wemm if (O_ISSET(sp, O_READONLY)) { 628b8ba871bSPeter Wemm if (needsep) { 629b8ba871bSPeter Wemm *p++ = ','; 630b8ba871bSPeter Wemm *p++ = ' '; 631b8ba871bSPeter Wemm } 632b8ba871bSPeter Wemm t = msg_cat(sp, "026|readonly", &len); 633b8ba871bSPeter Wemm memcpy(p, t, len); 634b8ba871bSPeter Wemm p += len; 635b8ba871bSPeter Wemm needsep = 1; 636b8ba871bSPeter Wemm } 637b8ba871bSPeter Wemm if (needsep) { 638b8ba871bSPeter Wemm *p++ = ':'; 639b8ba871bSPeter Wemm *p++ = ' '; 640b8ba871bSPeter Wemm } 641b8ba871bSPeter Wemm if (LF_ISSET(MSTAT_SHOWLAST)) { 642b8ba871bSPeter Wemm if (db_last(sp, &last)) 643b8ba871bSPeter Wemm return; 644b8ba871bSPeter Wemm if (last == 0) { 645b8ba871bSPeter Wemm t = msg_cat(sp, "028|empty file", &len); 646b8ba871bSPeter Wemm memcpy(p, t, len); 647b8ba871bSPeter Wemm p += len; 648b8ba871bSPeter Wemm } else { 649f0957ccaSPeter Wemm t = msg_cat(sp, "027|line %lu of %lu [%ld%%]", &len); 650*c271fa92SBaptiste Daroussin (void)snprintf(p, ep - p, t, (u_long)lno, (u_long)last, 651f0957ccaSPeter Wemm ((u_long)lno * 100) / last); 652b8ba871bSPeter Wemm p += strlen(p); 653b8ba871bSPeter Wemm } 654b8ba871bSPeter Wemm } else { 655b8ba871bSPeter Wemm t = msg_cat(sp, "029|line %lu", &len); 656f0957ccaSPeter Wemm (void)snprintf(p, ep - p, t, (u_long)lno); 657b8ba871bSPeter Wemm p += strlen(p); 658b8ba871bSPeter Wemm } 659b8ba871bSPeter Wemm #ifdef DEBUG 660f0957ccaSPeter Wemm (void)snprintf(p, ep - p, " (pid %lu)", (u_long)getpid()); 661b8ba871bSPeter Wemm p += strlen(p); 662b8ba871bSPeter Wemm #endif 663b8ba871bSPeter Wemm *p++ = '\n'; 664b8ba871bSPeter Wemm len = p - bp; 665b8ba871bSPeter Wemm 666b8ba871bSPeter Wemm /* 667b8ba871bSPeter Wemm * There's a nasty problem with long path names. Cscope and tags files 668b8ba871bSPeter Wemm * can result in long paths and vi will request a continuation key from 669b8ba871bSPeter Wemm * the user as soon as it starts the screen. Unfortunately, the user 670b8ba871bSPeter Wemm * has already typed ahead, and chaos results. If we assume that the 671b8ba871bSPeter Wemm * characters in the filenames and informational messages only take a 672b8ba871bSPeter Wemm * single screen column each, we can trim the filename. 673b8ba871bSPeter Wemm * 674b8ba871bSPeter Wemm * XXX 675b8ba871bSPeter Wemm * Status lines get put up at fairly awkward times. For example, when 676b8ba871bSPeter Wemm * you do a filter read (e.g., :read ! echo foo) in the top screen of a 677b8ba871bSPeter Wemm * split screen, we have to repaint the status lines for all the screens 678b8ba871bSPeter Wemm * below the top screen. We don't want users having to enter continue 679b8ba871bSPeter Wemm * characters for those screens. Make it really hard to screw this up. 680b8ba871bSPeter Wemm */ 681b8ba871bSPeter Wemm s = bp; 682b8ba871bSPeter Wemm if (LF_ISSET(MSTAT_TRUNCATE) && len > sp->cols) { 683b8ba871bSPeter Wemm for (; s < np && (*s != '/' || (p - s) > sp->cols - 3); ++s); 684b8ba871bSPeter Wemm if (s == np) { 685b8ba871bSPeter Wemm s = p - (sp->cols - 5); 686b8ba871bSPeter Wemm *--s = ' '; 687b8ba871bSPeter Wemm } 688b8ba871bSPeter Wemm *--s = '.'; 689b8ba871bSPeter Wemm *--s = '.'; 690b8ba871bSPeter Wemm *--s = '.'; 691b8ba871bSPeter Wemm len = p - s; 692b8ba871bSPeter Wemm } 693b8ba871bSPeter Wemm 694b8ba871bSPeter Wemm /* Flush any waiting ex messages. */ 695b8ba871bSPeter Wemm (void)ex_fflush(sp); 696b8ba871bSPeter Wemm 697b8ba871bSPeter Wemm sp->gp->scr_msg(sp, M_INFO, s, len); 698b8ba871bSPeter Wemm 699b8ba871bSPeter Wemm FREE_SPACE(sp, bp, blen); 700b8ba871bSPeter Wemm alloc_err: 701b8ba871bSPeter Wemm return; 702b8ba871bSPeter Wemm } 703b8ba871bSPeter Wemm 704b8ba871bSPeter Wemm /* 705b8ba871bSPeter Wemm * msg_open -- 706b8ba871bSPeter Wemm * Open the message catalogs. 707b8ba871bSPeter Wemm * 708*c271fa92SBaptiste Daroussin * PUBLIC: int msg_open(SCR *, char *); 709b8ba871bSPeter Wemm */ 710b8ba871bSPeter Wemm int 711f0957ccaSPeter Wemm msg_open( 712f0957ccaSPeter Wemm SCR *sp, 713f0957ccaSPeter Wemm char *file) 714b8ba871bSPeter Wemm { 715b8ba871bSPeter Wemm /* 716b8ba871bSPeter Wemm * !!! 717b8ba871bSPeter Wemm * Assume that the first file opened is the system default, and that 718b8ba871bSPeter Wemm * all subsequent ones user defined. Only display error messages 719b8ba871bSPeter Wemm * if we can't open the user defined ones -- it's useful to know if 720b8ba871bSPeter Wemm * the system one wasn't there, but if nvi is being shipped with an 721b8ba871bSPeter Wemm * installed system, the file will be there, if it's not, then the 722b8ba871bSPeter Wemm * message will be repeated every time nvi is started up. 723b8ba871bSPeter Wemm */ 724b8ba871bSPeter Wemm static int first = 1; 725f0957ccaSPeter Wemm nl_catd catd; 726f0957ccaSPeter Wemm char *p; 727f0957ccaSPeter Wemm int rval = 0; 728b8ba871bSPeter Wemm 729f0957ccaSPeter Wemm if ((p = strrchr(file, '/')) != NULL && p[1] == '\0') { 730f0957ccaSPeter Wemm /* Confirms to XPG4. */ 731f0957ccaSPeter Wemm if ((p = join(file, setlocale(LC_MESSAGES, NULL))) == NULL) { 732f0957ccaSPeter Wemm msgq(sp, M_SYSERR, NULL); 733b8ba871bSPeter Wemm return (1); 734b8ba871bSPeter Wemm } 735f0957ccaSPeter Wemm } else { 736f0957ccaSPeter Wemm /* Make sure it's recognized as a path by catopen(3). */ 737f0957ccaSPeter Wemm if ((p = join(".", file)) == NULL) { 738f0957ccaSPeter Wemm msgq(sp, M_SYSERR, NULL); 739b8ba871bSPeter Wemm return (1); 740b8ba871bSPeter Wemm } 741f0957ccaSPeter Wemm } 742f0957ccaSPeter Wemm errno = 0; 743f0957ccaSPeter Wemm if ((catd = catopen(p, NL_CAT_LOCALE)) == (nl_catd)-1) { 744f0957ccaSPeter Wemm if (first) { 745f0957ccaSPeter Wemm first = 0; 746f0957ccaSPeter Wemm rval = 1; 747f0957ccaSPeter Wemm goto ret; 748f0957ccaSPeter Wemm } 749b8ba871bSPeter Wemm 750b8ba871bSPeter Wemm /* 751f0957ccaSPeter Wemm * POSIX.1-2008 gives no instruction on how to report a 752f0957ccaSPeter Wemm * corrupt catalog file. Errno == 0 is not rare; add 753f0957ccaSPeter Wemm * EFTYPE, which is seen on FreeBSD, for a good measure. 754b8ba871bSPeter Wemm */ 755f0957ccaSPeter Wemm if (errno == 0 || errno == EFTYPE) 756b8ba871bSPeter Wemm msgq_str(sp, M_ERR, p, 757b8ba871bSPeter Wemm "030|The file %s is not a message catalog"); 758f0957ccaSPeter Wemm else 759f0957ccaSPeter Wemm msgq_str(sp, M_SYSERR, p, "%s"); 760f0957ccaSPeter Wemm rval = 1; 761f0957ccaSPeter Wemm goto ret; 762b8ba871bSPeter Wemm } 763b8ba871bSPeter Wemm first = 0; 764b8ba871bSPeter Wemm 765f0957ccaSPeter Wemm msg_close(sp->gp); 766f0957ccaSPeter Wemm sp->gp->catd = catd; 767f0957ccaSPeter Wemm ret: free(p); 768f0957ccaSPeter Wemm return (rval); 769b8ba871bSPeter Wemm } 770b8ba871bSPeter Wemm 771b8ba871bSPeter Wemm /* 772b8ba871bSPeter Wemm * msg_close -- 773b8ba871bSPeter Wemm * Close the message catalogs. 774b8ba871bSPeter Wemm * 775*c271fa92SBaptiste Daroussin * PUBLIC: void msg_close(GS *); 776b8ba871bSPeter Wemm */ 777b8ba871bSPeter Wemm void 778f0957ccaSPeter Wemm msg_close(GS *gp) 779b8ba871bSPeter Wemm { 780f0957ccaSPeter Wemm if (gp->catd != (nl_catd)-1) 781f0957ccaSPeter Wemm (void)catclose(gp->catd); 782b8ba871bSPeter Wemm } 783b8ba871bSPeter Wemm 784b8ba871bSPeter Wemm /* 785b8ba871bSPeter Wemm * msg_cont -- 786b8ba871bSPeter Wemm * Return common continuation messages. 787b8ba871bSPeter Wemm * 788*c271fa92SBaptiste Daroussin * PUBLIC: const char *msg_cmsg(SCR *, cmsg_t, size_t *); 789b8ba871bSPeter Wemm */ 790b8ba871bSPeter Wemm const char * 791f0957ccaSPeter Wemm msg_cmsg( 792f0957ccaSPeter Wemm SCR *sp, 793f0957ccaSPeter Wemm cmsg_t which, 794f0957ccaSPeter Wemm size_t *lenp) 795b8ba871bSPeter Wemm { 796b8ba871bSPeter Wemm switch (which) { 797b8ba871bSPeter Wemm case CMSG_CONF: 798b8ba871bSPeter Wemm return (msg_cat(sp, "268|confirm? [ynq]", lenp)); 799b8ba871bSPeter Wemm case CMSG_CONT: 800b8ba871bSPeter Wemm return (msg_cat(sp, "269|Press any key to continue: ", lenp)); 801b8ba871bSPeter Wemm case CMSG_CONT_EX: 802b8ba871bSPeter Wemm return (msg_cat(sp, 803b8ba871bSPeter Wemm "270|Press any key to continue [: to enter more ex commands]: ", 804b8ba871bSPeter Wemm lenp)); 805b8ba871bSPeter Wemm case CMSG_CONT_R: 806b8ba871bSPeter Wemm return (msg_cat(sp, "161|Press Enter to continue: ", lenp)); 807b8ba871bSPeter Wemm case CMSG_CONT_S: 808b8ba871bSPeter Wemm return (msg_cat(sp, "275| cont?", lenp)); 809b8ba871bSPeter Wemm case CMSG_CONT_Q: 810b8ba871bSPeter Wemm return (msg_cat(sp, 811b8ba871bSPeter Wemm "271|Press any key to continue [q to quit]: ", lenp)); 812b8ba871bSPeter Wemm default: 813b8ba871bSPeter Wemm abort(); 814b8ba871bSPeter Wemm } 815b8ba871bSPeter Wemm /* NOTREACHED */ 816b8ba871bSPeter Wemm } 817b8ba871bSPeter Wemm 818b8ba871bSPeter Wemm /* 819b8ba871bSPeter Wemm * msg_cat -- 820b8ba871bSPeter Wemm * Return a single message from the catalog, plus its length. 821b8ba871bSPeter Wemm * 822b8ba871bSPeter Wemm * !!! 823b8ba871bSPeter Wemm * Only a single catalog message can be accessed at a time, if multiple 824b8ba871bSPeter Wemm * ones are needed, they must be copied into local memory. 825b8ba871bSPeter Wemm * 826*c271fa92SBaptiste Daroussin * PUBLIC: const char *msg_cat(SCR *, const char *, size_t *); 827b8ba871bSPeter Wemm */ 828b8ba871bSPeter Wemm const char * 829f0957ccaSPeter Wemm msg_cat( 830f0957ccaSPeter Wemm SCR *sp, 831f0957ccaSPeter Wemm const char *str, 832f0957ccaSPeter Wemm size_t *lenp) 833b8ba871bSPeter Wemm { 834b8ba871bSPeter Wemm GS *gp; 835f0957ccaSPeter Wemm char *p; 836f0957ccaSPeter Wemm int msgno; 837b8ba871bSPeter Wemm 838b8ba871bSPeter Wemm /* 839b8ba871bSPeter Wemm * If it's not a catalog message, i.e. has doesn't have a leading 840b8ba871bSPeter Wemm * number and '|' symbol, we're done. 841b8ba871bSPeter Wemm */ 842b8ba871bSPeter Wemm if (isdigit(str[0]) && 843b8ba871bSPeter Wemm isdigit(str[1]) && isdigit(str[2]) && str[3] == '|') { 844b8ba871bSPeter Wemm msgno = atoi(str); 845b8ba871bSPeter Wemm str = &str[4]; 846f0957ccaSPeter Wemm 847f0957ccaSPeter Wemm gp = sp == NULL ? NULL : sp->gp; 848f0957ccaSPeter Wemm if (gp != NULL && gp->catd != (nl_catd)-1 && 849f0957ccaSPeter Wemm (p = catgets(gp->catd, 1, msgno, str)) != NULL) { 850f0957ccaSPeter Wemm if (lenp != NULL) 851f0957ccaSPeter Wemm *lenp = strlen(p); 852f0957ccaSPeter Wemm return (p); 853f0957ccaSPeter Wemm } 854b8ba871bSPeter Wemm } 855b8ba871bSPeter Wemm if (lenp != NULL) 856b8ba871bSPeter Wemm *lenp = strlen(str); 857b8ba871bSPeter Wemm return (str); 858b8ba871bSPeter Wemm } 859b8ba871bSPeter Wemm 860b8ba871bSPeter Wemm /* 861b8ba871bSPeter Wemm * msg_print -- 862b8ba871bSPeter Wemm * Return a printable version of a string, in allocated memory. 863b8ba871bSPeter Wemm * 864*c271fa92SBaptiste Daroussin * PUBLIC: char *msg_print(SCR *, const char *, int *); 865b8ba871bSPeter Wemm */ 866b8ba871bSPeter Wemm char * 867f0957ccaSPeter Wemm msg_print( 868f0957ccaSPeter Wemm SCR *sp, 869f0957ccaSPeter Wemm const char *s, 870f0957ccaSPeter Wemm int *needfree) 871b8ba871bSPeter Wemm { 872b8ba871bSPeter Wemm size_t blen, nlen; 873b8ba871bSPeter Wemm char *bp, *ep, *p, *t; 874f0957ccaSPeter Wemm CHAR_T *wp, *cp; 875f0957ccaSPeter Wemm size_t wlen; 876b8ba871bSPeter Wemm 877b8ba871bSPeter Wemm *needfree = 0; 878b8ba871bSPeter Wemm 879f0957ccaSPeter Wemm /* XXX Not good for debugging ex_read & ex_filter.*/ 880f0957ccaSPeter Wemm CHAR2INT5(sp, EXP(sp)->ibcw, (char *)s, strlen(s) + 1, wp, wlen); 881f0957ccaSPeter Wemm for (cp = wp; *cp != '\0'; ++cp) 882f0957ccaSPeter Wemm if (!ISPRINT(*cp)) 883b8ba871bSPeter Wemm break; 884b8ba871bSPeter Wemm if (*cp == '\0') 885b8ba871bSPeter Wemm return ((char *)s); /* SAFE: needfree set to 0. */ 886b8ba871bSPeter Wemm 887b8ba871bSPeter Wemm nlen = 0; 888b8ba871bSPeter Wemm if (0) { 889b8ba871bSPeter Wemm retry: if (sp == NULL) 890b8ba871bSPeter Wemm free(bp); 891b8ba871bSPeter Wemm else 892b8ba871bSPeter Wemm FREE_SPACE(sp, bp, blen); 893f0957ccaSPeter Wemm *needfree = 0; 894b8ba871bSPeter Wemm } 895b8ba871bSPeter Wemm nlen += 256; 896b8ba871bSPeter Wemm if (sp == NULL) { 897b8ba871bSPeter Wemm if ((bp = malloc(nlen)) == NULL) 898b8ba871bSPeter Wemm goto alloc_err; 899b8ba871bSPeter Wemm } else 900f0957ccaSPeter Wemm GET_SPACE_GOTOC(sp, bp, blen, nlen); 901b8ba871bSPeter Wemm if (0) { 902b8ba871bSPeter Wemm alloc_err: return (""); 903b8ba871bSPeter Wemm } 904b8ba871bSPeter Wemm *needfree = 1; 905b8ba871bSPeter Wemm 906f0957ccaSPeter Wemm for (p = bp, ep = (bp + blen) - 1; *wp != '\0' && p < ep; ++wp) 907f0957ccaSPeter Wemm for (t = KEY_NAME(sp, *wp); *t != '\0' && p < ep; *p++ = *t++); 908b8ba871bSPeter Wemm if (p == ep) 909b8ba871bSPeter Wemm goto retry; 910b8ba871bSPeter Wemm *p = '\0'; 911b8ba871bSPeter Wemm return (bp); 912b8ba871bSPeter Wemm } 913