1 /* @(#)message.c 1.29 09/07/28 Copyright 1984-2009 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)message.c 1.29 09/07/28 Copyright 1984-2009 J. Schilling";
6 #endif
7 /*
8 * Management routines for the system (status) line of the editor
9 * displayed at the top of the screen.
10 *
11 * Copyright (c) 1984-2009 J. Schilling
12 */
13 /*
14 * The contents of this file are subject to the terms of the
15 * Common Development and Distribution License, Version 1.0 only
16 * (the "License"). You may not use this file except in compliance
17 * with the License.
18 *
19 * See the file CDDL.Schily.txt in this distribution for details.
20 * A copy of the CDDL is also available via the Internet at
21 * http://www.opensource.org/licenses/cddl1.txt
22 *
23 * When distributing Covered Code, include this CDDL HEADER in each
24 * file and include the License file CDDL.Schily.txt from this distribution.
25 */
26
27 /*
28 * Layout of the systemline:
29 *
30 * |.123456789.123456789.123456789.123456789.123456789.123456789.123456789...
31 * |info |num |takebuf |filename |errortext
32 * |1/4 llen |1/8 llen |1/8 llen |1/4 llen |1/4 llen
33 *
34 * - info informational messages (search pattern, modflag ...)
35 * - num actual multiplying factor for the next command
36 * - take the name of the current take buffer
37 * - name the name of the file currently beeing edited
38 * - error error messages
39 */
40
41 #include "ved.h"
42 #include "terminal.h"
43 #include <schily/varargs.h>
44
45 /*
46 * INFOSIZE is 1/4th of the linelength of the terminal/window.
47 * If the screen has 1280 pixel and the width of a character is 8 pixel,
48 * a maximum of 160 charcters/line is sufficient.
49 * If the screen has 1280 pixel and the width of a character is 6 pixel,
50 * a maximum of 213 charcters/line is sufficient.
51 * A maximum linelength of 256 should be sufficient in any case.
52 *
53 * INFOSIZE should be at least 20+2 (see cmdline.c)
54 * We use ( 256 / 4 ) + 1. This should be enough for some time.
55 *
56 * The size of the info (left most) string should be big enough to print
57 * out a string of NAMESIZE length. The maximum length is 4 * INFOSIZE.
58 */
59 #define INFOSIZE 65 /* Allow screen width of 259 */
60 #define SYSLMIN NAMESIZE
61 #define SYSLSIZE (SYSLMIN > (4*INFOSIZE) ? (4*INFOSIZE) : SYSLMIN)
62 #define NUMSIZE (INFOSIZE/2)
63 #define TAKESIZE (INFOSIZE/2)
64
65 LOCAL Uchar infostr[SYSLSIZE]; /* left most part of message */
66 LOCAL Uchar namestr[2*INFOSIZE]; /* center part, name of file */
67 LOCAL Uchar errorstr[INFOSIZE]; /* right part, error messages*/
68 LOCAL Uchar numstr[NUMSIZE]; /* display of multiple */
69 LOCAL Uchar takestr[TAKESIZE]; /* display of take buffer */
70 LOCAL Uchar DefInfostr[INFOSIZE]; /* default info string */
71 LOCAL Uchar DefErrorstr[INFOSIZE-1]; /* default error string */
72 /* may be prepended by a ' ' */
73 /* to create error message */
74
75 EXPORT BOOL updatemsg = 0; /* infostr is temporary */
76 EXPORT BOOL updateerr = 0; /* errorstr is temporary */
77 EXPORT BOOL updatesysline = 0; /* whole systemline should be redrawn */
78 LOCAL int lastmsglen; /* the len of the last message */
79
80 LOCAL int numplace = 0; /* where the numstr starts */
81 LOCAL int takeplace = 0; /* where the takestr starts */
82 LOCAL int nameplace = 0; /* where the namestr starts */
83 LOCAL int errorplace = 0; /* where the errorstr starts */
84 LOCAL ecnt_t maxmsgnum = (ecnt_t)1; /* how big a displayed # can be */
85
86 #define infosize (numplace - 0) /* actual length of the infostring */
87 #define numsize (takeplace-numplace) /* actual length of the numstring */
88 #define takesize (nameplace-takeplace) /* actual length of the takestring */
89 #define namesize (errorplace-nameplace) /* actual length of the namestring */
90 #define errorsize (wp->llen-errorplace) /* actual length of the errorstring */
91 #define nameerrsize (wp->llen-nameplace) /* actual length of the name+errorstring */
92
93 EXPORT void initmessage __PR((ewin_t *wp));
94 EXPORT void initmsgsize __PR((ewin_t *wp));
95 EXPORT void writemsg __PR((ewin_t *wp, char *str, ...));
96 EXPORT void writenum __PR((ewin_t *wp, ecnt_t num));
97 EXPORT void writetake __PR((ewin_t *wp, Uchar *str));
98 EXPORT void namemsg __PR((Uchar* name));
99 EXPORT void writeerr __PR((ewin_t *wp, char *str, ...));
100 EXPORT void writeserr __PR((ewin_t *wp, char *str, ...));
101 LOCAL void _writeerr __PR((ewin_t *wp, BOOL dobeep, char *str, va_list args));
102 EXPORT void write_errno __PR((ewin_t *wp, char *msg, ...));
103 EXPORT void defaultinfo __PR((ewin_t *wp, Uchar *str));
104 EXPORT void defaulterr __PR((ewin_t *wp, Uchar *str));
105 LOCAL void errdefault __PR((void));
106 EXPORT void refreshmsg __PR((ewin_t *wp));
107 EXPORT void refreshsysline __PR((ewin_t *wp));
108 EXPORT void write_systemline __PR((ewin_t *wp));
109 EXPORT void abortmsg __PR((ewin_t *wp));
110 EXPORT void nomarkmsg __PR((ewin_t *wp));
111
112
113 /*---------------------------------------------------------------------------
114 |
115 | Init the system (status) message line.
116 |
117 | Do not print it yet, this will be done later.
118 |
119 +---------------------------------------------------------------------------*/
120
121 EXPORT void
initmessage(wp)122 initmessage(wp)
123 ewin_t *wp;
124 {
125 infostr[0] = '\0';
126 namestr[0] = '\0';
127 errorstr[0] = '\0';
128 numstr[0] = '\0';
129 takestr[0] = '\0';
130 DefInfostr[0] = '\0';
131 DefErrorstr[0] = '\0';
132
133 initmsgsize(wp);
134 }
135
136
137 /*---------------------------------------------------------------------------
138 |
139 | Set up the actual sizes for the various strings (will be called on resize)
140 |
141 +---------------------------------------------------------------------------*/
142
143 EXPORT void
initmsgsize(wp)144 initmsgsize(wp)
145 ewin_t *wp;
146 {
147 register int maxnumplaces;
148 register int i;
149 register ecnt_t n; /* same type as curnum */
150 register ecnt_t on; /* same type as curnum */
151
152 numplace = (2*wp->llen)/8;
153 takeplace = (3*wp->llen)/8;
154 nameplace = (4*wp->llen)/8;
155 errorplace = (6*wp->llen)/8;
156
157 /*
158 * Overflow bei Berechnung von maxmsgnum verhindern
159 */
160 for (on = (ecnt_t)0, n = (ecnt_t)1, maxnumplaces = 0;
161 n > 0 && n > on && maxnumplaces < NUMSIZE-1;
162 maxnumplaces++) {
163 on = n;
164 n = 10*n;
165 }
166 maxnumplaces--;
167
168 i = takeplace - numplace - 3;
169 if (i < 1)
170 i = 1;
171 if (i < maxnumplaces)
172 maxnumplaces = i;
173
174
175 maxmsgnum = (ecnt_t)1;
176 while (--maxnumplaces >= 0)
177 maxmsgnum = 10*maxmsgnum;
178 }
179
180
181 /*---------------------------------------------------------------------------
182 |
183 | Write a message to the (left) info part of the system (status) line.
184 |
185 | If called: writemsg(wp, NULL), display content of default info string
186 | If called: writemsg(wp, "text"), display "text" up to the next command
187 |
188 +---------------------------------------------------------------------------*/
189
190 /* PRINTFLIKE2 */
191 #ifdef PROTOTYPES
192 EXPORT void
writemsg(ewin_t * wp,char * str,...)193 writemsg(ewin_t *wp, char *str, ...)
194 #else
195 EXPORT void
196 writemsg(wp, str, va_alist)
197 ewin_t *wp;
198 char *str;
199 va_dcl
200 #endif
201 {
202 va_list args;
203 int len = 0;
204
205 if (str == 0) {
206 strncpy(C infostr, C DefInfostr, sizeof (infostr));
207 infostr[sizeof (infostr)-1] = '\0';
208 updatemsg = 0;
209 } else if (*str == '\0') {
210 infostr[0] = '\0';
211 updatemsg = 1;
212 } else {
213 #ifdef PROTOTYPES
214 va_start(args, str);
215 #else
216 va_start(args);
217 #endif
218 len = snprintf(C infostr, sizeof (infostr), "%r", str, args);
219 va_end(args);
220 updatemsg = 1;
221 }
222 CURSOR_HOME(wp);
223 if (len <= infosize) {
224 len = infosize;
225 if (updatesysline && len < lastmsglen)
226 len = lastmsglen;
227 } else {
228 updatesysline = 1;
229 }
230
231 /*
232 * We don't like the extended message to end in the middle of some text
233 * from another field. If we touch the next field, clear it temporary.
234 */
235 if (len > infosize && len <= (infosize+numsize))
236 len = (infosize+numsize);
237 if (len > (infosize+numsize) && len <= (infosize+numsize+takesize))
238 len = (infosize+numsize+takesize);
239 if (len > (infosize+numsize+takesize) &&
240 len <= (infosize+numsize+takesize+namesize))
241 len = (infosize+numsize+takesize+namesize);
242 lastmsglen = len;
243
244 printfield(infostr, len);
245 setcursor(wp);
246 if (str != 0)
247 flush();
248 }
249
250
251 /*---------------------------------------------------------------------------
252 |
253 | Write a number to the (left center) info part of the system (status) line.
254 |
255 | If called: writenum(wp, -1), erase content of the number string
256 | If called: writenum(wp, >=0), display number
257 |
258 +---------------------------------------------------------------------------*/
259
260 EXPORT void
writenum(wp,num)261 writenum(wp, num)
262 ewin_t *wp;
263 ecnt_t num;
264 {
265 if (num < (ecnt_t)0)
266 numstr[0] = '\0';
267 else if (num < maxmsgnum)
268 snprintf(C numstr, sizeof (numstr), " #:%lld", (Llong)num);
269 else
270 strcpy(C numstr, " #:BIG");
271 MOVE_CURSOR_ABS(wp, 0, numplace);
272 printfield(numstr, numsize);
273 setcursor(wp);
274 }
275
276
277 /*---------------------------------------------------------------------------
278 |
279 | Write the take buffer name to the center part of the system (status) line.
280 |
281 +---------------------------------------------------------------------------*/
282
283 EXPORT void
writetake(wp,str)284 writetake(wp, str)
285 ewin_t *wp;
286 Uchar *str;
287 {
288 snprintf(C takestr, sizeof (takestr), " \\:%s", str);
289 MOVE_CURSOR_ABS(wp, 0, takeplace);
290 printfield(takestr, takesize);
291 setcursor(wp);
292 }
293
294
295 /*---------------------------------------------------------------------------
296 |
297 | Set up the file name in the (right center) part of the system (status) line.
298 |
299 +---------------------------------------------------------------------------*/
300
301 EXPORT void
namemsg(name)302 namemsg(name)
303 Uchar *name;
304 {
305 snprintf(C namestr, sizeof (namestr), " %s", C name);
306 }
307
308 /*---------------------------------------------------------------------------
309 |
310 | Write a message to the (right) error part of the system (status) line.
311 |
312 | If called: writeerr(wp, NULL), display content of default error string
313 | If called: writeerr(wp, "text"), display error "text" up to the next
314 | command
315 |
316 | Ring the bell
317 |
318 +---------------------------------------------------------------------------*/
319
320 /* PRINTFLIKE2 */
321 #ifdef PROTOTYPES
322 EXPORT void
writeerr(ewin_t * wp,char * str,...)323 writeerr(ewin_t *wp, char *str, ...)
324 #else
325 EXPORT void
326 writeerr(wp, str, va_alist)
327 ewin_t *wp;
328 char *str;
329 va_dcl
330 #endif
331 {
332 va_list args;
333
334 #ifdef PROTOTYPES
335 va_start(args, str);
336 #else
337 va_start(args);
338 #endif
339 _writeerr(wp, TRUE, str, args);
340 va_end(args);
341 }
342
343 /*---------------------------------------------------------------------------
344 |
345 | Write a message to the (right) error part of the system (status) line.
346 |
347 | If called: writeserr(wp, NULL), display content of default error string
348 | If called: writeserr(wp, "text"), display error "text" up to the next
349 | command
350 |
351 | Don't ring the bell (be silent)
352 |
353 +---------------------------------------------------------------------------*/
354
355 /* PRINTFLIKE2 */
356 #ifdef PROTOTYPES
357 EXPORT void
writeserr(ewin_t * wp,char * str,...)358 writeserr(ewin_t *wp, char *str, ...)
359 #else
360 EXPORT void
361 writeserr(wp, str, va_alist)
362 ewin_t *wp;
363 char *str;
364 va_dcl
365 #endif
366 {
367 va_list args;
368
369 #ifdef PROTOTYPES
370 va_start(args, str);
371 #else
372 va_start(args);
373 #endif
374 _writeerr(wp, FALSE, str, args);
375 va_end(args);
376 }
377
378 /*---------------------------------------------------------------------------
379 |
380 | Write a message to the (right) error part of the system (status) line.
381 |
382 | If called: _writeerr(wp, NULL), display content of default error string
383 | If called: _writeerr(wp, "text"), display error "text" up to the next
384 | command
385 |
386 | Whether to ring the bell depends on 'dobeep'.
387 |
388 +---------------------------------------------------------------------------*/
389
390 LOCAL void
_writeerr(wp,dobeep,str,args)391 _writeerr(wp, dobeep, str, args)
392 ewin_t *wp;
393 BOOL dobeep;
394 char *str;
395 va_list args;
396 {
397 int len = 0;
398
399 if (str == 0) {
400 errdefault();
401 updateerr = 0;
402 } else {
403 if (*str == '\0') {
404 errorstr[0] = '\0';
405 updateerr = 1;
406 } else {
407 len = snprintf(C errorstr, sizeof (errorstr), " %r",
408 str, args);
409 if (dobeep)
410 ringbell();
411 updateerr = 1;
412 }
413 }
414 if (*errorstr) {
415 if (len < 0 || len > errorsize) {
416 MOVE_CURSOR_ABS(wp, 0, nameplace);
417 printfield(errorstr, nameerrsize);
418 } else {
419 MOVE_CURSOR_ABS(wp, 0, errorplace);
420 printfield(errorstr, errorsize);
421 }
422 } else { /* Let name field use rest of screen if no error */
423 MOVE_CURSOR_ABS(wp, 0, nameplace);
424 printfield(namestr, nameerrsize);
425 }
426 setcursor(wp);
427 if (str != 0)
428 flush();
429 }
430
431
432 /*---------------------------------------------------------------------------
433 |
434 | Write a message to the (right) error part of the system (status) line.
435 | The message contains the error text or the error number for the last
436 | failed syscall depending on the space.
437 | If the message including the error text will fit the error number
438 | is ommitted. If the text will overflow the space, the error number will be
439 | placed in front of the text because it will possibly be readeable.
440 |
441 +---------------------------------------------------------------------------*/
442
443 /* PRINTFLIKE2 */
444 #ifdef PROTOTYPES
445 EXPORT void
write_errno(ewin_t * wp,char * msg,...)446 write_errno(ewin_t *wp, char *msg, ...)
447 #else
448 EXPORT void
449 write_errno(wp, msg, va_alist)
450 ewin_t *wp;
451 char *msg;
452 va_dcl
453 #endif
454 {
455 va_list args;
456 char buf[100];
457 int len;
458 int err = geterrno();
459 char *errstr;
460
461 errstr = errmsgstr(err);
462 if (errstr == NULL)
463 errstr = "";
464
465 #ifdef PROTOTYPES
466 va_start(args, msg);
467 #else
468 va_start(args);
469 #endif
470 len = snprintf(buf, sizeof (buf), "%r: %s", msg, args, errstr);
471 va_end(args);
472
473 if (len <= nameerrsize) {
474 writeerr(wp, "%s", buf);
475 return;
476 }
477
478 #ifdef PROTOTYPES
479 va_start(args, msg);
480 #else
481 va_start(args);
482 #endif
483 snprintf(buf, sizeof (buf), "(%d) %r: %s", err, msg, args, errstr);
484 va_end(args);
485 writeerr(wp, "%s", buf);
486 }
487
488
489 /*---------------------------------------------------------------------------
490 |
491 | Set up the default info string (currently only used for modflag "*")
492 | It is displayed after the command that follows a command that sets
493 | the info string until a new info string is set.
494 |
495 +---------------------------------------------------------------------------*/
496
497 EXPORT void
defaultinfo(wp,str)498 defaultinfo(wp, str)
499 ewin_t *wp;
500 Uchar *str;
501 {
502 if (str == NULL)
503 DefInfostr[0] = '\0';
504 else
505 snprintf(C DefInfostr, sizeof (DefInfostr), "%s", str);
506 writemsg(wp, "%s", C DefInfostr);
507
508 }
509
510
511 /*---------------------------------------------------------------------------
512 |
513 | Set up the default error string (currently only used for "NEW FILE")
514 | It is displayed after the command that follows a command that sets
515 | the error string until a new error string is set.
516 |
517 +---------------------------------------------------------------------------*/
518
519 EXPORT void
defaulterr(wp,str)520 defaulterr(wp, str)
521 ewin_t *wp;
522 Uchar *str;
523 {
524 if (str == 0) {
525 DefErrorstr[0] = '\0';
526 writeerr(wp, "");
527 } else {
528 snprintf(C DefErrorstr, sizeof (DefErrorstr), "%s", str);
529 writeerr(wp, "%s", C DefErrorstr);
530 }
531 }
532
533
534 /*---------------------------------------------------------------------------
535 |
536 | Set the error string to the default error string.
537 | If the default error string contains a message, prepend a blank as a
538 | separator to the file name.
539 |
540 +---------------------------------------------------------------------------*/
541
542 LOCAL void
errdefault()543 errdefault()
544 {
545 if (*DefErrorstr == '\0') {
546 errorstr[0] = '\0';
547 } else {
548 /*
549 * Permanent error messages should be separated from
550 * the filename.
551 */
552 errorstr[0] = ' ';
553 strcpy(C &errorstr[1], C DefErrorstr); /* no overflow (same size)*/
554
555 }
556 }
557
558
559 /*---------------------------------------------------------------------------
560 |
561 | Refresh the whole system (status) line e.g when parts get overwritten.
562 |
563 +---------------------------------------------------------------------------*/
564
565 EXPORT void
refreshmsg(wp)566 refreshmsg(wp)
567 ewin_t *wp;
568 {
569 updatesysline = 0;
570 CURSOR_HOME(wp);
571 write_systemline(wp);
572 setcursor(wp);
573 }
574
575 /*---------------------------------------------------------------------------
576 |
577 | Refresh the whole system (status) line or parts of it depending on status.
578 |
579 +---------------------------------------------------------------------------*/
580
581 EXPORT void
refreshsysline(wp)582 refreshsysline(wp)
583 ewin_t *wp;
584 {
585 if (updatesysline) {
586 refreshmsg(wp);
587 } else {
588 if (updateerr)
589 writeerr(wp, C NULL);
590 if (updatemsg)
591 writemsg(wp, C NULL);
592 }
593 }
594
595 /*---------------------------------------------------------------------------
596 |
597 | Rewrite the whole system (status) line e.g when parts get overwritten.
598 | Reset info string & error string to the default if necessary.
599 | Allow the file name to use up the space of the error string
600 | if the error string is blank.
601 |
602 +---------------------------------------------------------------------------*/
603
604 EXPORT void
write_systemline(wp)605 write_systemline(wp)
606 ewin_t *wp;
607 {
608 if (updatemsg) {
609 strncpy(C infostr, C DefInfostr, sizeof (infostr));
610 infostr[sizeof (infostr)-1] = '\0';
611 updatemsg = 0;
612 }
613 if (updateerr) {
614 errdefault();
615 updateerr = 0;
616 }
617 printfield(infostr, infosize);
618 printfield(numstr, numsize);
619 printfield(takestr, takesize);
620
621 if (*errorstr) {
622 printfield(namestr, namesize);
623 printfield(errorstr, errorsize);
624 } else {
625 printfield(namestr, nameerrsize);
626 }
627 }
628
629 EXPORT void
abortmsg(wp)630 abortmsg(wp)
631 ewin_t *wp;
632 {
633 writeerr(wp, "ABORTED");
634 }
635
636 EXPORT void
nomarkmsg(wp)637 nomarkmsg(wp)
638 ewin_t *wp;
639 {
640 writeerr(wp, "No Mark !");
641 }
642