1 /* $Id: mreadline.c 2515 2008-03-02 23:20:52Z kuhlmann $ */
2
3 /*****************************************************
4 * Copyright (C) 1998 Sergey Shkonda (serg@bcs.zp.ua)
5 * This file may be distributed under version 2 of the GPL licence.
6 * Originally placed in the public domain by Sergey Shkonda Nov 27, 1998
7 *****************************************************/
8
9 #include "climm.h"
10
11 #ifdef USE_MREADLINE
12
13 #include "mreadline.h"
14 #include "util_ui.h"
15 #include "util_rl.h"
16 #include "util.h"
17 #include "cmd_user.h"
18 #include "util_tabs.h"
19 #include "conv.h"
20 #include "contact.h"
21 #include "preferences.h"
22
23 #include <stdarg.h>
24 #include <ctype.h>
25 #include <signal.h>
26 #include <assert.h>
27
28 static int CharCount = 0; /* number of characters printed on line. */
29 static int IndentCount = 0;
30
31 #define LOGOS 10
32 static const char *logos[LOGOS] = { NULL };
33 static UBYTE logoc = 0;
34 static UBYTE first = 0;
35
rl_logo(const char * logo)36 void rl_logo (const char *logo)
37 {
38 if (logoc != LOGOS)
39 logos[logoc++] = logo;
40 first = 2;
41 }
42
M_getlogo(void)43 static const char *M_getlogo (void)
44 {
45 UBYTE i;
46 const char *logo;
47
48 if (!logoc)
49 return first ? " " : "";
50 logo = logos[0];
51 logoc--;
52 for (i = 0; i < logoc; i++)
53 logos[i] = logos[i + 1];
54 return ConvTo (logo, prG->enc_loc)->txt;
55 }
56
rl_logo_clear()57 void rl_logo_clear ()
58 {
59 first = 1;
60 puts ("");
61 while (logoc)
62 puts (M_getlogo ());
63 rl_print ("\r");
64 first = 0;
65 }
66
67 #define chardiff(aa,bb) (ENC(enc_loc) == ENC_UTF8 ? s_strnlen ((bb), (aa) - (bb)) : (aa) - (bb))
68
69 #define USECOLORINVCHAR if (!colinvchar) colinvchar = ((prG->flags & FLAG_COLOR) ? ContactPrefStr (NULL, CO_COLORINVCHAR) : "")
70
71 /*
72 * Print a string to the output, interpreting color and indenting codes.
73 */
rl_print(const char * org)74 void rl_print (const char *org)
75 {
76 const char *test, *save, *temp, *str, *para;
77 char *fstr;
78 const char *colnone = NULL, *colinvchar = NULL, *col;
79 UBYTE isline = 0, ismsg = 0;
80 int i;
81 static str_s colbuf = { NULL, 0, 0 };
82 int sw = rl_columns - IndentCount;
83
84 fstr = strdup (ConvTo (org, prG->enc_loc)->txt);
85 str = fstr;
86 switch (ENC(enc_loc))
87 {
88 case ENC_UTF8: para = "\xc2\xb6"; break;
89 case ENC_LATIN1:
90 case ENC_LATIN9: para = "\xb6"; break;
91 default: para = "P"; break;
92 }
93 col = colnone = (prG->flags & FLAG_COLOR) ? ContactPrefStr (NULL, CO_COLORNONE) : "";
94
95 if (first)
96 {
97 sw -= 9;
98 if (first == 2)
99 {
100 if (!CharCount)
101 printf ("%s", M_getlogo ());
102 first = 1;
103 }
104 }
105
106 ReadLinePromptHide ();
107
108 #ifdef ENABLE_TCL
109 if (prG->tclout)
110 {
111 prG->tclout (fstr);
112 free (fstr);
113 return;
114 }
115 #endif
116
117 for (; *str; str++)
118 {
119 for (test = save = str; *test; test++)
120 {
121 if (!(*test & 0xe0) || (*test == 127)) /* special character reached - emit text till last saved position */
122 {
123 if (save != str)
124 test = save;
125 break;
126 }
127 else if (strchr ("-.,_:;!?/ ", *test)) /* punctuation found - save position after it */
128 {
129 temp = test + 1;
130 if (chardiff (temp, str) <= sw - CharCount)
131 save = temp;
132 else
133 {
134 if (save != str)
135 test = save;
136 else
137 test = temp;
138 break;
139 }
140 }
141 }
142 if (test != str) /* Print out (block of) word(s) from str to test*/
143 {
144 while (chardiff (test, str) > sw) /* word is longer than line, print till end of line */
145 {
146 printf ("%.*s%*s", (int) c_offset (str, sw - CharCount), str, IndentCount, "");
147 str += c_offset (str, sw - CharCount);
148 if (isline)
149 {
150 USECOLORINVCHAR;
151 printf ("%s...%s", colinvchar, col);
152 CharCount = 0;
153 free (fstr);
154 return;
155 }
156 CharCount = 0;
157 }
158 if (chardiff (test, str) > sw - CharCount) /* remainder doesn't fit anymore => linebreak */
159 {
160 if (isline)
161 {
162 USECOLORINVCHAR;
163 printf ("%s...%s", colinvchar, col);
164 CharCount = 0;
165 free (fstr);
166 return;
167 }
168 printf ("\n%s%*s%s", M_getlogo (), IndentCount, "", col);
169 CharCount = 0;
170 }
171 printf ("%.*s", (int)(test - str), str);
172 CharCount += chardiff (test, str);
173 str = test;
174 }
175 if (*str != 0x7f && (*str <= 0 || *str >= ' '))
176 {
177 str--;
178 continue;
179 }
180 if (isline && (*str == '\n' || *str == '\r'))
181 {
182 if (str[1])
183 {
184 USECOLORINVCHAR;
185 printf ("%s%s..", colinvchar, para);
186 }
187 printf ("%s", col);
188 CharCount = 0;
189 free (fstr);
190 return;
191 }
192 if (*str == '\n' || *str == '\r' || (*str == '\t' && !isline))
193 {
194 if (!str[1] && ismsg)
195 {
196 printf ("%s\n", colnone);
197 CharCount = 0;
198 IndentCount = 0;
199 free (fstr);
200 return;
201 }
202 }
203 else if (ismsg || isline)
204 {
205 USECOLORINVCHAR;
206 printf ("%s%c%s", colinvchar, *str - 1 + 'A', col);
207 CharCount++;
208 continue;
209 }
210 switch (*str) /* Take care of specials */
211 {
212 case '\b':
213 CharCount--;
214 printf ("\b");
215 break;
216 case '\r':
217 if (!ismsg)
218 {
219 putchar ('\r');
220 if (str[1] != '\n' && IndentCount)
221 {
222 printf ("\x1b[%dD", IndentCount);
223 }
224 CharCount = 0;
225 break;
226 }
227 case '\n':
228 if (ismsg && (str[1] == (*str ^ '\r' ^ '\n')))
229 str++;
230 printf ("\n%s%*s%s", M_getlogo (), IndentCount, "", col);
231 CharCount = 0;
232 break;
233 case '\t':
234 i = TAB_STOP - (CharCount % TAB_STOP);
235 if (CharCount + i > sw)
236 {
237 printf ("\n%s%*s", M_getlogo (), IndentCount, "");
238 CharCount = 0;
239 }
240 else
241 {
242 printf ("%*s", i, "");
243 CharCount += i;
244 }
245 break;
246 case '\a':
247 if (prG->sound == SFLAG_EVENT && prG->event_cmd && *prG->event_cmd)
248 EventExec (NULL, prG->event_cmd, ev_beep, 0, ims_online, NULL);
249 else if (prG->sound == SFLAG_BEEP)
250 printf ("\a");
251 break;
252 case '\x1b':
253 if (isline)
254 break;
255 switch (*++test)
256 {
257 case '<':
258 ismsg = 1;
259 switch (prG->flags & (FLAG_LIBR_BR | FLAG_LIBR_INT))
260 {
261 case FLAG_LIBR_BR:
262 printf ("\n%s", M_getlogo ());
263 CharCount = 0;
264 break;
265 case FLAG_LIBR_INT:
266 IndentCount = CharCount;
267 sw -= IndentCount;
268 CharCount = 0;
269 break;
270 case FLAG_LIBR_BR | FLAG_LIBR_INT:
271 save = strstr (str, "\x1bv");
272 if (save && chardiff (save, str) - 2 > sw - CharCount)
273 {
274 printf ("\n%s", M_getlogo ());
275 CharCount = 0;
276 break;
277 }
278 break;
279 }
280 str++;
281 break;
282 case 'v':
283 IndentCount += CharCount;
284 sw -= IndentCount;
285 CharCount = 0;
286 str++;
287 break;
288 case '^':
289 CharCount += IndentCount;
290 sw += IndentCount;
291 IndentCount = 0;
292 str++;
293 break;
294 case '.':
295 isline = 1;
296 sw -= 3;
297 if (sw <= CharCount)
298 {
299 printf ("%s", col);
300 CharCount = IndentCount = 0;
301 free (fstr);
302 return;
303 }
304 str++;
305 break;
306 default:
307 save = strchr (test, 'm');
308 if (save)
309 {
310 while (!strncmp (save, "m" ESC "[", 3) && strchr (save + 1, 'm'))
311 save = strchr (save + 1, 'm');
312 if (prG->flags & FLAG_COLOR)
313 {
314 s_init (&colbuf, "", (int)(save - str) + 1);
315 s_catf (&colbuf, "%.*s", (int)(save - str) + 1, str);
316 printf ("%s", col = colbuf.txt);
317 }
318 else
319 col = "";
320 str = save;
321 }
322 break;
323 }
324 break;
325 default:
326 USECOLORINVCHAR;
327 printf ("%s%c%s", colinvchar, *str - 1 + 'A', col);
328
329 }
330 }
331 free (fstr);
332 }
333
334 /*
335 * Print a formatted string to the output, interpreting color and indenting
336 * codes.
337 * Note: does not use the same static buffer as s_sprintf().
338 */
rl_printf(const char * str,...)339 void rl_printf (const char *str, ...)
340 {
341 va_list args;
342 char buf[8 * 1024];
343
344 va_start (args, str);
345 vsnprintf (buf, sizeof (buf), str, args);
346 rl_print (buf);
347 va_end (args);
348 }
349
350 /*
351 * Returns current horizontal position
352 */
rl_pos()353 int rl_pos ()
354 {
355 return CharCount;
356 }
357
rl_log_for(const char * nick,const char * col)358 void rl_log_for (const char *nick, const char *col)
359 {
360 rl_printf ("%s %s", s_now, ReadLinePrintCont (nick, col));
361 }
362
363
364 #endif /* USE_MREADLINE */
365