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.23 1993/11/20 10:05:25 bostic Exp $ (Berkeley) $Date: 1993/11/20 10:05:25 $";
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 len
= snprintf(msgbuf
, sizeof(msgbuf
), "Error: %s%s%s.",
83 fmt
== NULL
? "" : fmt
, fmt
== NULL
? "" : ": ",
86 len
= vsnprintf(msgbuf
, sizeof(msgbuf
), fmt
, ap
);
87 if (len
> sizeof(msgbuf
))
90 msg_app(__global_list
, sp
, mt
== M_ERR
? 1 : 0, msgbuf
, len
);
95 * Append a message into the queue. This can fail, but there's
96 * nothing we can do if it does.
99 msg_app(gp
, sp
, inv_video
, p
, len
)
106 static int reenter
; /* STATIC: Re-entrancy check. */
110 * It's possible to reenter msg when it allocates space.
111 * We're probably dead anyway, but no reason to drop core.
118 * Find an empty structure, or allocate a new one. Use the
119 * screen structure if possible, otherwise the global one.
122 if ((mp
= sp
->msgq
.lh_first
) == NULL
) {
123 if ((mp
= malloc(sizeof(MSG
))) == NULL
)
125 memset(mp
, 0, sizeof(MSG
));
126 LIST_INSERT_HEAD(&sp
->msgq
, mp
, q
);
129 } else if ((mp
= gp
->msgq
.lh_first
) == NULL
) {
130 if ((mp
= malloc(sizeof(MSG
))) == NULL
)
132 memset(mp
, 0, sizeof(MSG
));
133 LIST_INSERT_HEAD(&gp
->msgq
, mp
, q
);
136 while (!F_ISSET(mp
, M_EMPTY
) && mp
->q
.le_next
!= NULL
)
138 if (!F_ISSET(mp
, M_EMPTY
)) {
139 if ((nmp
= malloc(sizeof(MSG
))) == NULL
)
141 memset(nmp
, 0, sizeof(MSG
));
142 LIST_INSERT_AFTER(mp
, nmp
, q
);
146 /* Get enough memory for the message. */
147 store
: if (len
> mp
->blen
&& binc(sp
, &mp
->mbuf
, &mp
->blen
, len
))
150 /* Store the message. */
151 memmove(mp
->mbuf
, p
, len
);
153 mp
->flags
= inv_video
? M_INV_VIDEO
: 0;
160 * Report on the lines that changed.
163 * Historic vi documentation (USD:15-8) claimed that "The editor will also
164 * always tell you when a change you make affects text which you cannot see."
165 * This isn't true -- edit a large file and do "100d|1". We don't implement
166 * this semantic as it would require that we track each line that changes
167 * during a command instead of just keeping count.
170 msg_rpt(sp
, is_message
)
174 static const char *const action
[] = {
175 "added", "changed", "copied", "deleted", "joined", "moved",
176 "put", "left shifted", "right shifted", "yanked", NULL
,
182 const char *const *ap
;
183 char *bp
, *p
, number
[40];
185 if ((rval
= O_VAL(sp
, O_REPORT
)) == 0)
188 GET_SPACE(sp
, bp
, blen
, 512);
192 for (ap
= action
, cnt
= 0, first
= 1; *ap
!= NULL
; ++ap
, ++cnt
)
193 if (sp
->rptlines
[cnt
] != 0) {
194 total
+= sp
->rptlines
[cnt
];
195 len
= snprintf(number
, sizeof(number
),
196 "%s%lu line%s %s", first
? "" : "; ",
198 sp
->rptlines
[cnt
] > 1 ? "s" : "", *ap
);
199 memmove(p
, number
, len
);
205 * If nothing to report, return. Note that the number of lines
206 * must be > than the user's value, not >=. This is historic
207 * practice and means that users cannot report on single line
214 msgq(sp
, M_INFO
, "%s", bp
);
216 ex_printf(EXCOOKIE
, "%s\n", bp
);
219 FREE_SPACE(sp
, bp
, blen
);
221 /* Clear after each report. */
222 norpt
: memset(sp
->rptlines
, 0, sizeof(sp
->rptlines
));
228 * Increase the size of a buffer.
231 binc(sp
, argp
, bsizep
, min
)
232 SCR
*sp
; /* MAY BE NULL */
239 /* If already larger than the minimum, just return. */
241 if (min
&& csize
>= min
)
244 csize
+= MAX(min
, 256);
245 bpp
= *(char **)argp
;
247 /* For non-ANSI C realloc implementations. */
251 bpp
= realloc(bpp
, csize
);
253 msgq(sp
, M_SYSERR
, NULL
);
257 *(char **)argp
= bpp
;
264 * Set the column number of the first non-blank character
265 * including or after the starting column. On error, set
266 * the column to 0, it's safest.
269 nonblank(sp
, ep
, lno
, cnop
)
276 size_t cnt
, len
, off
;
283 if ((p
= file_gline(sp
, ep
, lno
, &len
)) == NULL
) {
284 if (file_lline(sp
, ep
, &lno
))
288 GETLINE_ERR(sp
, lno
);
292 /* Set the offset. */
293 if (len
== 0 || off
>= len
)
296 for (cnt
= off
, p
= &p
[off
],
297 len
-= off
; len
&& isblank(*p
); ++cnt
, ++p
, --len
);
299 /* Set the return. */
300 *cnop
= len
? cnt
: cnt
- 1;
306 * Return tail of a path.
314 if ((p
= strrchr(path
, '/')) == NULL
)
321 * Set the window size, the row may be provided as an argument.
324 set_window_size(sp
, set_row
, ign_env
)
332 char *argv
[2], *s
, buf
[2048];
338 * Get the screen rows and columns. If the values are wrong, it's
339 * not a big deal -- as soon as the user sets them explicitly the
340 * environment will be set and the screen package will use the new
343 * Try TIOCGWINSZ, followed by the termcap entry.
345 if (ioctl(STDERR_FILENO
, TIOCGWINSZ
, &win
) != -1 &&
346 win
.ws_row
!= 0 && win
.ws_col
!= 0) {
351 if (F_ISSET(&sp
->opts
[O_TERM
], OPT_SET
))
352 s
= O_STR(sp
, O_TERM
);
355 if (s
!= NULL
&& tgetent(buf
, s
) == 1) {
362 * POSIX 1003.2 requires the environment to override, however,
363 * if we're here because of a signal, we don't want to use the
367 if ((s
= getenv("ROWS")) != NULL
)
368 row
= strtol(s
, NULL
, 10);
369 if ((s
= getenv("COLUMNS")) != NULL
)
370 col
= strtol(s
, NULL
, 10);
373 /* But, if we got an argument for the rows, use it. */
381 * Tell the options code that the screen size has changed.
382 * Since the user didn't do the set, clear the set bits.
384 user_set
= F_ISSET(&sp
->opts
[O_LINES
], OPT_SET
);
385 (void)snprintf(buf
, sizeof(buf
), "ls=%u", row
);
386 if (opts_set(sp
, argv
))
389 F_CLR(&sp
->opts
[O_LINES
], OPT_SET
);
390 user_set
= F_ISSET(&sp
->opts
[O_COLUMNS
], OPT_SET
);
391 (void)snprintf(buf
, sizeof(buf
), "co=%u", col
);
392 if (opts_set(sp
, argv
))
395 F_CLR(&sp
->opts
[O_COLUMNS
], OPT_SET
);
401 * Set the alternate file name.
403 * Swap the alternate file name. It's a routine because I wanted some place
404 * to hang this comment. The alternate file name (normally referenced using
405 * the special character '#' during file expansion) is set by many
406 * operations. In the historic vi, the commands "ex", and "edit" obviously
407 * set the alternate file name because they switched the underlying file.
408 * Less obviously, the "read", "file", "write" and "wq" commands set it as
409 * well. In this implementation, some new commands have been added to the
410 * list. Where it gets interesting is that the alternate file name is set
411 * multiple times by some commands. If an edit attempt fails (for whatever
412 * reason, like the current file is modified but as yet unwritten), it is
413 * set to the file name that the user was unable to edit. If the edit
414 * succeeds, it is set to the last file name that was edited. Good fun.
417 set_alt_name(sp
, name
)
421 if (sp
->alt_name
!= NULL
)
422 FREE(sp
->alt_name
, strlen(sp
->alt_name
) + 1);
423 if ((sp
->alt_name
= strdup(name
)) == NULL
)
424 msgq(sp
, M_SYSERR
, NULL
);
429 * Return the baud rate using the standard defines.
437 switch (v
= cfgetospeed(&sp
->gp
->original_termios
)) {
462 case B0
: /* Hangup -- ignore. */
471 * EXTA and EXTB aren't required by POSIX 1003.1, and
472 * are almost certainly the same as some of the above
473 * values, so they can't be part of the case statement.
483 msgq(sp
, M_ERR
, "Unknown terminal baud rate %u.\n", v
);