2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
5 * %sccs.include.redist.c%
9 static char sccsid
[] = "$Id: util.c,v 8.28 1993/11/27 15:53:19 bostic Exp $ (Berkeley) $Date: 1993/11/27 15:53:19 $";
12 #include <sys/types.h>
13 #include <sys/ioctl.h>
36 msgq(SCR
*sp
, enum msgtype mt
, const char *fmt
, ...)
38 msgq(sp
, mt
, fmt
, va_alist
)
55 * It's possible to enter msg when there's no screen to hold
56 * the message. Always check sp before using it, and, if it's
57 * NULL, use __global_list.
61 if (sp
!= NULL
&& !O_ISSET(sp
, O_VERBOSE
)) {
62 F_SET(sp
, S_BELLSCHED
);
68 if (sp
!= NULL
&& !O_ISSET(sp
, O_VERBOSE
))
80 /* Length is the min length of the message or the buffer. */
82 if (sp
->if_name
!= NULL
)
83 len
= snprintf(msgbuf
, sizeof(msgbuf
),
84 "Error: %s, %d: %s%s%s.", sp
->if_name
, sp
->if_lno
,
85 fmt
== NULL
? "" : fmt
, fmt
== NULL
? "" : ": ",
88 len
= snprintf(msgbuf
, sizeof(msgbuf
),
90 fmt
== NULL
? "" : fmt
, fmt
== NULL
? "" : ": ",
93 len
= sp
->if_name
== NULL
? 0 : snprintf(msgbuf
, sizeof(msgbuf
),
94 "%s, %d: ", sp
->if_name
, sp
->if_lno
);
95 len
+= vsnprintf(msgbuf
+ len
, sizeof(msgbuf
) - len
, fmt
, ap
);
99 * If len >= the size, some characters were discarded.
100 * Ignore trailing nul.
102 if (len
>= sizeof(msgbuf
))
103 len
= sizeof(msgbuf
) - 1;
105 msg_app(__global_list
, sp
, mt
== M_ERR
? 1 : 0, msgbuf
, len
);
110 * Append a message into the queue. This can fail, but there's
111 * nothing we can do if it does.
114 msg_app(gp
, sp
, inv_video
, p
, len
)
121 static int reenter
; /* STATIC: Re-entrancy check. */
125 * It's possible to reenter msg when it allocates space.
126 * We're probably dead anyway, but no reason to drop core.
133 * Find an empty structure, or allocate a new one. Use the
134 * screen structure if possible, otherwise the global one.
137 if ((mp
= sp
->msgq
.lh_first
) == NULL
) {
138 if ((mp
= malloc(sizeof(MSG
))) == NULL
)
140 memset(mp
, 0, sizeof(MSG
));
141 LIST_INSERT_HEAD(&sp
->msgq
, mp
, q
);
144 } else if ((mp
= gp
->msgq
.lh_first
) == NULL
) {
145 if ((mp
= malloc(sizeof(MSG
))) == NULL
)
147 memset(mp
, 0, sizeof(MSG
));
148 LIST_INSERT_HEAD(&gp
->msgq
, mp
, q
);
151 while (!F_ISSET(mp
, M_EMPTY
) && mp
->q
.le_next
!= NULL
)
153 if (!F_ISSET(mp
, M_EMPTY
)) {
154 if ((nmp
= malloc(sizeof(MSG
))) == NULL
)
156 memset(nmp
, 0, sizeof(MSG
));
157 LIST_INSERT_AFTER(mp
, nmp
, q
);
161 /* Get enough memory for the message. */
162 store
: if (len
> mp
->blen
&& binc(sp
, &mp
->mbuf
, &mp
->blen
, len
))
165 /* Store the message. */
166 memmove(mp
->mbuf
, p
, len
);
168 mp
->flags
= inv_video
? M_INV_VIDEO
: 0;
175 * Report on the lines that changed.
178 * Historic vi documentation (USD:15-8) claimed that "The editor will also
179 * always tell you when a change you make affects text which you cannot see."
180 * This isn't true -- edit a large file and do "100d|1". We don't implement
181 * this semantic as it would require that we track each line that changes
182 * during a command instead of just keeping count.
185 msg_rpt(sp
, is_message
)
189 static const char *const action
[] = {
190 "added", "changed", "copied", "deleted", "joined", "moved",
191 "put", "left shifted", "right shifted", "yanked", NULL
,
197 const char *const *ap
;
198 char *bp
, *p
, number
[40];
200 if ((rval
= O_VAL(sp
, O_REPORT
)) == 0)
203 GET_SPACE(sp
, bp
, blen
, 512);
207 for (ap
= action
, cnt
= 0, first
= 1; *ap
!= NULL
; ++ap
, ++cnt
)
208 if (sp
->rptlines
[cnt
] != 0) {
209 total
+= sp
->rptlines
[cnt
];
210 len
= snprintf(number
, sizeof(number
),
211 "%s%lu line%s %s", first
? "" : "; ",
213 sp
->rptlines
[cnt
] > 1 ? "s" : "", *ap
);
214 memmove(p
, number
, len
);
220 * If nothing to report, return. Note that the number of lines
221 * must be > than the user's value, not >=. This is historic
222 * practice and means that users cannot report on single line
229 msgq(sp
, M_INFO
, "%s", bp
);
231 ex_printf(EXCOOKIE
, "%s\n", bp
);
234 FREE_SPACE(sp
, bp
, blen
);
236 /* Clear after each report. */
237 norpt
: memset(sp
->rptlines
, 0, sizeof(sp
->rptlines
));
243 * Increase the size of a buffer.
246 binc(sp
, argp
, bsizep
, min
)
247 SCR
*sp
; /* MAY BE NULL */
254 /* If already larger than the minimum, just return. */
256 if (min
&& csize
>= min
)
259 csize
+= MAX(min
, 256);
260 bpp
= *(char **)argp
;
262 /* For non-ANSI C realloc implementations. */
266 bpp
= realloc(bpp
, csize
);
268 msgq(sp
, M_SYSERR
, NULL
);
272 *(char **)argp
= bpp
;
279 * Set the column number of the first non-blank character
280 * including or after the starting column. On error, set
281 * the column to 0, it's safest.
284 nonblank(sp
, ep
, lno
, cnop
)
291 size_t cnt
, len
, off
;
298 if ((p
= file_gline(sp
, ep
, lno
, &len
)) == NULL
) {
299 if (file_lline(sp
, ep
, &lno
))
303 GETLINE_ERR(sp
, lno
);
307 /* Set the offset. */
308 if (len
== 0 || off
>= len
)
311 for (cnt
= off
, p
= &p
[off
],
312 len
-= off
; len
&& isblank(*p
); ++cnt
, ++p
, --len
);
314 /* Set the return. */
315 *cnop
= len
? cnt
: cnt
- 1;
321 * Return tail of a path.
329 if ((p
= strrchr(path
, '/')) == NULL
)
336 * Set the window size, the row may be provided as an argument.
339 set_window_size(sp
, set_row
, ign_env
)
347 char *argv
[2], *s
, buf
[2048];
350 * Get the screen rows and columns. If the values are wrong, it's
351 * not a big deal -- as soon as the user sets them explicitly the
352 * environment will be set and the screen package will use the new
358 if (ioctl(STDERR_FILENO
, TIOCGWINSZ
, &win
) != -1) {
363 /* If TIOCGWINSZ failed, or had entries of 0, try termcap. */
364 if (row
== 0 || col
== 0) {
366 if (F_ISSET(&sp
->opts
[O_TERM
], OPT_SET
))
367 s
= O_STR(sp
, O_TERM
);
370 if (s
!= NULL
&& tgetent(buf
, s
) == 1) {
377 /* If nothing else, well, it's probably a VT100. */
384 * POSIX 1003.2 requires the environment to override, however,
385 * if we're here because of a signal, we don't want to use the
389 if ((s
= getenv("ROWS")) != NULL
)
390 row
= strtol(s
, NULL
, 10);
391 if ((s
= getenv("COLUMNS")) != NULL
)
392 col
= strtol(s
, NULL
, 10);
395 /* But, if we got an argument for the rows, use it. */
403 * Tell the options code that the screen size has changed.
404 * Since the user didn't do the set, clear the set bits.
406 user_set
= F_ISSET(&sp
->opts
[O_LINES
], OPT_SET
);
407 (void)snprintf(buf
, sizeof(buf
), "ls=%u", row
);
408 if (opts_set(sp
, argv
))
411 F_CLR(&sp
->opts
[O_LINES
], OPT_SET
);
412 user_set
= F_ISSET(&sp
->opts
[O_COLUMNS
], OPT_SET
);
413 (void)snprintf(buf
, sizeof(buf
), "co=%u", col
);
414 if (opts_set(sp
, argv
))
417 F_CLR(&sp
->opts
[O_COLUMNS
], OPT_SET
);
423 * Set the alternate file name.
425 * Swap the alternate file name. It's a routine because I wanted some place
426 * to hang this comment. The alternate file name (normally referenced using
427 * the special character '#' during file expansion) is set by many
428 * operations. In the historic vi, the commands "ex", and "edit" obviously
429 * set the alternate file name because they switched the underlying file.
430 * Less obviously, the "read", "file", "write" and "wq" commands set it as
431 * well. In this implementation, some new commands have been added to the
432 * list. Where it gets interesting is that the alternate file name is set
433 * multiple times by some commands. If an edit attempt fails (for whatever
434 * reason, like the current file is modified but as yet unwritten), it is
435 * set to the file name that the user was unable to edit. If the edit
436 * succeeds, it is set to the last file name that was edited. Good fun.
438 * If the user edits a temporary file, there are time when there isn't an
439 * alternative file name. A name argument of NULL turns it off.
442 set_alt_name(sp
, name
)
446 if (sp
->alt_name
!= NULL
)
447 FREE(sp
->alt_name
, strlen(sp
->alt_name
) + 1);
450 else if ((sp
->alt_name
= strdup(name
)) == NULL
)
451 msgq(sp
, M_SYSERR
, NULL
);
456 * Return the baud rate using the standard defines.
464 switch (v
= cfgetospeed(&sp
->gp
->original_termios
)) {
489 case B0
: /* Hangup -- ignore. */
498 * EXTA and EXTB aren't required by POSIX 1003.1, and
499 * are almost certainly the same as some of the above
500 * values, so they can't be part of the case statement.
510 msgq(sp
, M_ERR
, "Unknown terminal baud rate %u.\n", v
);