1 | | |
2 | | |
3 | | |
4 | | |
5 | | |
6 | | |
7 | | |
8 | | |
9 | | |
10 | | |
11 | | |
12 | | |
13 | | |
14 | | |
15 | | |
16 | | |
17 | | |
18 | | |
19 | | |
20 | | |
21 | | |
22 | | |
23 | | |
24 | | |
25 | | |
26 | | |
27 | | |
28 | | |
29 | | |
30 | | |
31 | | |
32 | | |
33 | | |
34 | | |
35 | | |
36 | | |
37 | | |
38 | | |
39 | | |
40 | | |
41 | | |
42 | | |
43 | | |
44 | | |
45 | | |
46 | | |
47 | | |
48 | | |
49 | | |
50 | | |
51 | | |
52 | | |
53 | | |
54 | | |
55 | | |
56 | | |
57 | | |
58 | | |
59 | | |
60 | | |
61 | | |
62 | | |
63 | | |
64 | | |
65 | | |
66 | | |
67 | | |
68 | | |
69 | | |
70 | | |
71 | | |
72 | | |
73 | | |
74 | | |
75 | | |
76 | | |
77 | | |
78 | | |
79 | | |
80 | | |
81 | | |
82 | | |
83 | | |
84 | | |
85 | | |
86 | | |
87 | | |
88 | | |
89 | | |
90 | | |
91 | | |
92 | | |
93 | | |
94 | | |
95 | | |
96 | | |
97 | | |
98 | | |
99 | | |
100 | | |
101 | | |
102 | | |
103 | | |
104 | | |
105 | | |
106 | | |
107 | | |
108 | | |
109 | | |
110 | | |
111 | | |
112 | | |
113 | | |
114 | | |
115 | | |
116 | | |
117 | | |
118 | | |
119 | | |
120 | | |
121 | | |
122 | | |
123 | | |
124 | | |
125 | | |
126 | | |
127 | | |
128 | | |
129 | | |
130 | | |
131 | | |
132 | | |
133 | | |
134 | | |
135 | | |
136 | | |
137 | | |
138 | | |
139 | | |
140 | | |
141 | | |
142 | | |
143 | | |
144 | | |
145 | | |
146 | | |
147 | | |
148 | | |
149 | | |
150 | | |
151 | | |
152 | | |
153 | | |
154 | | |
155 | | |
156 | | |
157 | | |
158 | | |
159 | | |
160 | | |
161 | | |
162 | | |
163 | | |
164 | | |
165 | | |
166 | | |
167 | | |
168 | | |
169 | | |
170 | | |
171 | | |
172 | | |
173 | | |
174 | | |
175 | | |
176 | | |
177 | | |
178 | | |
179 | | |
180 | | |
181 | | |
182 | | |
183 | | |
184 | | |
185 | | |
186 | | |
187 | | |
188 | | |
189 | | |
190 | | |
191 | | |
192 | | |
193 | | |
194 | | |
195 | | |
196 | | |
197 | | |
198 | | |
199 | | |
200 | | |
201 | | |
202 | | |
203 | | |
204 | | |
205 | | |
206 | | |
207 | | |
208 | | |
209 | | |
210 | | |
211 | | |
212 | | |
213 | | |
214 | | |
215 | | |
216 | | |
217 | | |
218 | | |
219 | | |
220 | | |
221 | | |
222 | | |
223 | | |
224 | | |
225 | | |
226 | | |
227 | | |
228 | | |
229 | | |
230 | | |
231 | | |
232 | | |
233 | | |
234 | | |
235 | | |
236 | | |
237 | | |
238 | | |
239 | | |
240 | | |
241 | | |
242 | | |
243 | | |
244 | | |
245 | | |
246 | | |
247 | | |
248 | | |
249 | | |
250 | | |
251 | | |
252 | | |
253 | | |
254 | | |
255 | | |
256 | | |
257 | | |
258 | | |
259 | | |
260 | | |
261 | | |
262 | | |
263 | | |
264 | | |
265 | | |
266 | | |
267 | | |
268 | | |
269 | | |
270 | | |
271 | | |
272 | | |
273 | | |
274 | | |
275 | | |
276 | | |
277 | | |
278 | | |
279 | | |
280 | | |
281 | | |
282 | | |
283 | | |
284 | | |
285 | | |
286 | | |
287 | | |
288 | | |
289 | | |
290 | | |
291 | | |
292 | | |
293 | | |
294 | | |
295 | | |
296 | | |
297 | | |
298 | | |
299 | | |
300 | | |
301 | | |
302 | | |
303 | | |
304 | | |
305 | | |
306 | | |
307 | | |
308 | | |
309 | | |
310 | | |
311 | | |
312 | | |
313 | | |
314 | | |
315 | | |
316 | | |
317 | | |
318 | | |
319 | | |
320 | | |
321 | | |
322 | | |
323 | | |
324 | | |
325 | | |
326 | | |
327 | | |
328 | | |
329 | | |
330 | | |
331 | | |
332 | | |
333 | | |
334 | | |
335 | | |
336 | | |
337 | | |
338 | | |
339 | | |
340 | | |
341 | | |
342 | | |
343 | | |
344 | | |
345 | | |
346 | | |
347 | | |
348 | | |
349 | | |
350 | | |
351 | | |
352 | | |
353 | | |
354 | | |
355 | | |
356 | | |
357 | | |
358 | | |
359 | | |
360 | | |
361 | | |
362 | | |
363 | | |
364 | | |
365 | | |
366 | | |
367 | | |
368 | | |
369 | | |
370 | | |
371 | | |
372 | | |
373 | | |
374 | | |
375 | | |
376 | | |
377 | | |
378 | | |
379 | | |
380 | | |
381 | | |
382 | | |
383 | | |
384 | | |
385 | | |
386 | | |
387 | | |
388 | | |
389 | | |
390 | | |
391 | | |
392 | | |
393 | | |
394 | | |
395 | | |
396 | | |
397 | | |
398 | | |
399 | | |
400 | | |
401 | | |
402 | | |
403 | | |
404 | | |
405 | | |
406 | | |
407 | | |
408 | | |
409 | | |
410 | | |
411 | | |
412 | | |
413 | | |
414 | | |
415 | | |
416 | | |
417 | | |
418 | | |
419 | | |
420 | | |
421 | | |
422 | | |
423 | | |
424 | | |
425 | | |
426 | | |
427 | | |
428 | | |
429 | | |
430 | | |
431 | | |
432 | | |
433 | | |
434 | | |
435 | | |
436 | | |
437 | | |
438 | | |
439 | | |
440 | | |
441 | | |
442 | | |
443 | | |
444 | | |
445 | | |
446 | | |
447 | | |
448 | | |
449 | | |
450 | | |
451 | | |
452 | | |
453 | | |
454 | | |
455 | | |
456 | | |
457 | | |
458 | | |
459 | | |
460 | | |
461 | | |
462 | | |
463 | | |
464 | | |
465 | | |
466 | | |
467 | | |
468 | | |
469 | | |
470 | | |
471 | | |
472 | | |
473 | | |
474 | | |
475 | | |
476 | | |
477 | | |
478 | | |
479 | | |
480 | | |
481 | | |
482 | | |
483 | | |
484 | | |
485 | | |
486 | | |
487 | | |
488 | | |
489 | | |
490 | | |
491 | | |
492 | | |
493 | | |
494 | | |
495 | | |
496 | | |
497 | | |
498 | | |
499 | | |
500 | | |
501 | | |
502 | | |
503 | | |
504 | | |
505 | | |
506 | | |
507 | | |
508 | | |
509 | | |
510 | | |
511 | | |
512 | | |
513 | | |
514 | | |
515 | | |
516 | | |
517 | | |
518 | | |
519 | | |
520 | | |
521 | | |
522 | | |
523 | | |
524 | | |
525 | | |
526 | | |
527 | | |
528 | | |
529 | | |
530 | | |
531 | | |
532 | | |
533 | | |
534 | | |
535 | | |
536 | | |
537 | | |
538 | | |
539 | | |
540 | | |
541 | | |
542 | | |
543 | | |
544 | | |
545 | | |
546 | | |
547 | | |
548 | | |
549 | | |
550 | | |
551 | | |
552 | | |
553 | | |
554 | | |
555 | | |
556 | | |
557 | | |
558 | | |
559 | | |
560 | | |
561 | | |
562 | | |
563 | | |
564 | | |
565 | | |
566 | | |
567 | | |
568 | | |
569 | | |
570 | | |
571 | | |
572 | | |
573 | | |
574 | | |
575 | | |
576 | | |
577 | | |
578 | | |
579 | | |
580 | | |
581 | | |
582 | | |
583 | | |
584 | | |
585 | | |
586 | | |
587 | | |
588 | | |
589 | | |
590 | | |
591 | | |
592 | | |
593 | | |
594 | | |
595 | | |
596 | | |
597 | | |
598 | | |
599 | | |
600 | | |
601 | | |
602 | | |
603 | | |
604 | | |
605 | | |
606 | | |
607 | | |
608 | | |
609 | | |
610 | | |
611 | | |
612 | | |
613 | | |
614 | | |
615 | | |
616 | | |
617 | | |
618 | | |
619 | | |
620 | | |
621 | | |
622 | | |
623 | | |
624 | | |
625 | | |
626 | | |
627 | | |
628 | | |
629 | | |
630 | | |
631 | | |
632 | | |
633 | | |
634 | | |
635 | | |
636 | | |
637 | | |
638 | | |
639 | | |
640 | | |
641 | | |
642 | | |
643 | | |
644 | | |
645 | | |
646 | | |
647 | | |
648 | | |
649 | | |
650 | | |
651 | | |
652 | | |
653 | | |
654 | | |
655 | | |
656 | | |
657 | | |
658 | | |
659 | | |
660 | | |
661 | | |
662 | | |
663 | | |
664 | | |
665 | | |
666 | | |
667 | | |
668 | | |
669 | | |
670 | | |
671 | | |
672 | | |
673 | | |
674 | | |
675 | | |
676 | | |
677 | | |
678 | | |
679 | | |
680 | | |
681 | | |
682 | | |
683 | | |
684 | | |
685 | | |
686 | | |
687 | | |
688 | | |
689 | | |
690 | | |
691 | | |
692 | | |
693 | | |
694 | | |
695 | | |
696 | | |
697 | | |
698 | | |
699 | | |
700 | | |
701 | | |
702 | | |
703 | | |
704 | | |
705 | | |
706 | | |
707 | | |
708 | | |
709 | | |
710 | | |
711 | | |
712 | | |
713 | | |
714 | | |
715 | | |
716 | | |
717 | | |
718 | | |
719 | | |
720 | | |
721 | | |
722 | | |
723 | | |
724 | | |
725 | | |
726 | | |
727 | | |
728 | | |
729 | | |
730 | | |
731 | | |
732 | | |
733 | | |
734 | | |
735 | | |
736 | | |
737 | | |
738 | | |
739 | | |
740 | | |
741 | | |
742 | | |
743 | | |
744 | | |
745 | | |
746 | | |
747 | | |
748 | | |
749 | | |
750 | | |
751 | | |
752 | | |
753 | | |
754 | | |
755 | | |
756 | | |
757 | | |
758 | | |
759 | | |
760 | | |
761 | | |
762 | | |
763 | | |
764 | | |
765 | | |
766 | | |
767 | | |
768 | | |
769 | | |
770 | | |
771 | | |
772 | | |
773 | | |
774 | | |
775 | | |
776 | | |
777 | | |
778 | | |
779 | | |
780 | | |
781 | | |
782 | | |
783 | | |
784 | | |
785 | | |
786 | | |
787 | | |
788 | | |
789 | | |
790 | | |
791 | | |
792 | | |
793 | | |
794 | | |
795 | | |
796 | | |
797 | | |
798 | | |
799 | | |
800 | | |
801 | | |
802 | | |
803 | | |
804 | | |
805 | | |
806 | | |
807 | | |
808 | | |
809 | | |
810 | | |
811 | | |
812 | | |
813 | | |
814 | | |
815 | | |
816 | | |
817 | | |
818 | | |
819 | | |
820 | | |
821 | | |
822 | | |
823 | | |
824 | | |
825 | | |
826 | | |
827 | | |
828 | | |
829 | | |
830 | | |
831 | | |
832 | | |
833 | | |
834 | | |
835 | | |
836 | | |
837 | | |
838 | | |
839 | | |
840 | | |
841 | | |
842 | | |
843 | | |
844 | | |
845 | | |
846 | | |
847 | | |
848 | | |
849 | | |
850 | | |
851 | | |
852 | | |
853 | | |
854 | | |
855 | | |
856 | | |
857 | | |
858 | | |
859 | | |
860 | | |
861 | | |
862 | | |
863 | | |
864 | | |
865 | | |
866 | | |
867 | | |
868 | | |
869 | | |
870 | | |
871 | | |
872 | | |
873 | | |
874 | | |
875 | | |
876 | | |
877 | | |
878 | | |
879 | | |
880 | | |
881 | | |
882 | | |
883 | | |
884 | | |
885 | | |
886 | | |
887 | | |
888 | | |
889 | | |
890 | | |
891 | | |
892 | | |
893 | | |
894 | | |
895 | | |
896 | | |
897 | | |
898 | | |
899 | | |
900 | | |
901 | | |
902 | | |
903 | | |
904 | | |
905 | | |
906 | | |
907 | | |
908 | | |
909 | | |
910 | | |
911 | | |
912 | | |
913 | | |
914 | | |
915 | | |
916 | | |
917 | | |
918 | | |
919 | | |
920 | | |
921 | | |
922 | | |
923 | | |
924 | | |
925 | | |
926 | | |
927 | | |
928 | | |
929 | | |
930 | | |
931 | | |
932 | | |
933 | | |
934 | | |
935 | | |
936 | | |
937 | | |
938 | | |
939 | | |
940 | | |
941 | | |
942 | | |
943 | | |
944 | | |
945 | | |
946 | | |
947 | | |
948 | | |
949 | | |
| #pike __REAL_VERSION__ | | | #if constant(thread_create) | #define LOCK object m_key = mutex->lock() | #define UNLOCK destruct(m_key) | #define MUTEX protected private object(Thread.Mutex) mutex = Thread.Mutex(); | #else | #define LOCK | #define UNLOCK | #define MUTEX | #endif | | MUTEX | | protected private array ctrlcharsfrom = | map(indices(allocate(32)), | lambda(int z) { return sprintf("^%c",z+64); })+ | map(indices(allocate(32)), | lambda(int z) { return sprintf("^%c",z+96); }); | protected private array ctrlcharsto = | map(indices(allocate(32)), | lambda(int z) { return sprintf("%c",z); })+ | map(indices(allocate(32)), | lambda(int z) { return sprintf("%c",z); }); | | | protected private class TermMachine { | | mapping(string:string|int) map = ([]); | | int tgetflag(string id) | { | return map[id]==1; | } | | int tgetnum(string id) | { | return intp(map[id]) && [int]map[id]; | } | | string tgetstr(string id) | { | return stringp(map[id]) && [string]map[id]; | } | | string tparam(string f, mixed ... args) | { | array(string) fmt=f/"%"; | string res=fmt[0]; | string tmp; | int z; | mapping var=([]); | array args0=args; | | #define POP (z=[int]args[0],args=args[1..],z) | #define PUSH(x) (args=({x})+args) | | while ( (fmt=fmt[1..])!=({}) ) | if (fmt[0]=="") res+="%"; | else | { | switch (fmt[0][0]) | { | case 'd': res+=sprintf("%d%s",POP,fmt[0][1..]); break; | case 'x': res+=sprintf("%x%s",POP,fmt[0][1..]); break; | case '0': case '2': case '3': | sscanf(fmt[0],"%[0-9]%s",tmp,fmt[0]); | res+=sprintf("%"+tmp+fmt[0][..0]+"%s",POP,fmt[0][1..]); | break; | case 'c': res+=sprintf("%c%s",POP,fmt[0][1..]); break; | case 's': res+=sprintf("%s%s",[string](mixed)POP,fmt[0][1..]); break; | | case '\'': | sscanf(fmt[0],"'%s'%s",tmp,fmt[0]); | if (tmp=="") tmp="\0"; | if (tmp[0]=='\\') tmp=sprintf("%c",(int)("0"+tmp[1..])); | PUSH(tmp[0]); | res+=fmt[0]; | break; | case '{': | sscanf(fmt[0],"{%d}%s",z,fmt[0]); | res+=fmt[0]; | PUSH(z); | break; | case 'p': | PUSH(args0[fmt[0][1]-'1']); | res+=fmt[0][2..]; | break; | case 'P': | var[fmt[0][1]]=POP; | res+=fmt[0][2..]; | break; | case 'g': | PUSH(var[fmt[0][1]]); | res+=fmt[0][2..]; | break; | case 'i': | args[0]+=1; | args[1]+=1; | break; | case '+': PUSH(POP+POP); res+=fmt[0][1..]; break; | case '-': PUSH(POP-POP); res+=fmt[0][1..]; break; | case '*': PUSH(POP*POP); res+=fmt[0][1..]; break; | case '/': PUSH(POP/POP); res+=fmt[0][1..]; break; | case 'm': PUSH(POP%POP); res+=fmt[0][1..]; break; | case '&': PUSH(POP&POP); res+=fmt[0][1..]; break; | case '|': PUSH(POP|POP); res+=fmt[0][1..]; break; | case '^': PUSH(POP^POP); res+=fmt[0][1..]; break; | case '=': PUSH(POP==POP); res+=fmt[0][1..]; break; | case '>': PUSH(POP>POP); res+=fmt[0][1..]; break; | case '<': PUSH(POP<POP); res+=fmt[0][1..]; break; | case 'A': PUSH(POP && POP); res+=fmt[0][1..]; break; | case 'O': PUSH(POP || POP); res+=fmt[0][1..]; break; | case '!': PUSH(!POP); res+=fmt[0][1..]; break; | case '~': PUSH(~POP); res+=fmt[0][1..]; break; | case '?': | error("Sorry, Terminal can't handle if-else's\n"); | default: | error("Unknown opcode: %%%s\n",fmt[0][..0]); | } | } | return res; | } | | string tgoto(string cap, int col, int row) | { | return tparam(cap, col, row); | } | | string tputs(string s) | { | return s; | } | | string put(string cap, mixed ... args) | { | string str = tgetstr(cap); | string tstr = str && tparam(str, @args); | return tstr && tputs(tstr); | } | | } | | | class Termcap { | | inherit TermMachine; | | | array(string) aliases; | | protected Termcap parent; | | | string tputs(string s) | { | | sscanf(s, "%*d%s", s); | return s; | } | | private protected multiset(string) load_cap(string en) | { | string br=":"; | int i=search(en,":"); | int j=search(en,","); | multiset(string) clears = (<>); | | if (i==-1) { i=j; br=","; } | else if (j!=-1) { i=min(i,j); if (i==j) br=","; } | if (i<1) | error("Termcap: Unparsable entry\n"); | aliases=en[..i-1]/"|"; | en=en[i..]; | | while (en!="") | { | string name; | string data; | if(sscanf(en,"%*[ \t]%[a-zA-Z_0-9&]%s"+br+"%s",name,data,en) < 4) | { | sscanf(en,"%*[ \t]%[a-zA-Z_0-9&]%s",name,data); | en=""; | } | | if (data=="") | { | if (name!="") map[name]=1; | } | else if (data[0]=='@') | { | clears[name]=1; | } | else if (data[0]=='#') | { | int z; | sscanf(data,"#%d",z); | map[name]=z; | } | else if (data[0]=='=') | { | data=data[1..]; | while (sizeof(data) && data[-1]=='\\') | { | string add; | if (sscanf(en,"%s"+br+"%s",add,en)<2) break; | data+="\\"+add; | } | | data=replace(data,"\\^","\\*"); | | if (has_value(data, "^")) | data=replace(data,ctrlcharsfrom,ctrlcharsto); | | data = replace(data, | ({"\\E","\\e","\\n","\\r","\\t","\\b","\\f", | "\\*","\\\\","\\,","\\:","#", | "\\0","\\1","\\2","\\3","\\4","\\5","\\6","\\7"}), | ({"\033","\033","\n","\r","\t","\b","\f", | "^","\\",",",":","#!", | "#0","#1","#2","#3","#4","#5","#6","#7"})); | | array(string) parts = data/"#"; | data = parts[0]; | foreach (parts[1..], string p) | if (sizeof(p) && p[0]=='!') | data += "#"+p[1..]; | else | { | int n; | string x; | if(2==sscanf(p[..2], "%o%s", n, x)) | data += sprintf("%c%s%s", n, x, p[3..]); | else | data += p; | } | | map[name]=data; | | } | else | { | | } | } | | return clears; | } | | | protected void create(string cap, TermcapDB|void tcdb, int|void maxrecurse) | { | int i=0; | while((i=search(cap, "\\\n", i))>=0) { | string capr; | if(2!=sscanf(cap[i..], "\\\n%*[ \t\r]%s", capr)) | break; | cap = cap[..i-1]+capr; | } | multiset(string) clears = load_cap(cap); | if(map->tc) { | if(maxrecurse==1) | error("Termcap: maximum inheritance depth exceeded (loop?)\n"); | parent = (tcdb||defaultTermcapDB())-> | load(map->tc, maxrecurse? (maxrecurse-1):25); | if(!parent) | error("Termcap: can't find parent terminal \"%s\"\n", map->tc); | map = parent->map | map; | } | map |= mkmapping(indices(clears), allocate(sizeof(clears))); | } | } | | | | class Terminfo { | | inherit TermMachine; | | protected local constant MAGIC = 0432; | protected local constant MAGIC2 = 01036; | | | array(string) aliases; | | protected private constant boolnames = | ({ "bw","am","xb","xs","xn","eo","gn","hc","km","hs","in","da","db","mi", | "ms","os","es","xt","hz","ul","xo","nx","5i","HC","NR","NP","ND","cc", | "ut","hl","YA","YB","YC","YD","YE","YF","YG" }); | protected private constant numnames = | ({ "co","it","li","lm","sg","pb","vt","ws","Nl","lh","lw","ma","MW","Co", | "pa","NC","Ya","Yb","Yc","Yd","Ye","Yf","Yg","Yh","Yi","Yj","Yk","Yl", | "Ym","Yn","BT","Yo","Yp" }); | protected private constant strnames = | ({ "bt","bl","cr","cs","ct","cl","ce","cd","ch","CC","cm","do","ho","vi", | "le","CM","ve","nd","ll","up","vs","dc","dl","ds","hd","as","mb","md", | "ti","dm","mh","im","mk","mp","mr","so","us","ec","ae","me","te","ed", | "ei","se","ue","vb","ff","fs","i1","is","i3","if","ic","al","ip","kb", | "ka","kC","kt","kD","kL","kd","kM","kE","kS","k0","k1","k;","k2","k3", | "k4","k5","k6","k7","k8","k9","kh","kI","kA","kl","kH","kN","kP","kr", | "kF","kR","kT","ku","ke","ks","l0","l1","la","l2","l3","l4","l5","l6", | "l7","l8","l9","mo","mm","nw","pc","DC","DL","DO","IC","SF","AL","LE", | "RI","SR","UP","pk","pl","px","ps","pf","po","rp","r1","r2","r3","rf", | "rc","cv","sc","sf","sr","sa","st","wi","ta","ts","uc","hu","iP","K1", | "K3","K2","K4","K5","pO","rP","ac","pn","kB","SX","RX","SA","RA","XN", | "XF","eA","LO","LF","@1","@2","@3","@4","@5","@6","@7","@8","@9","@0", | "%1","%2","%3","%4","%5","%6","%7","%8","%9","%0","&1","&2","&3","&4", | "&5","&6","&7","&8","&9","&0","*1","*2","*3","*4","*5","*6","*7","*8", | "*9","*0","#1","#2","#3","#4","%a","%b","%c","%d","%e","%f","%g","%h", | "%i","%j","!1","!2","!3","RF","F1","F2","F3","F4","F5","F6","F7","F8", | "F9","FA","FB","FC","FD","FE","FF","FG","FH","FI","FJ","FK","FL","FM", | "FN","FO","FP","FQ","FR","FS","FT","FU","FV","FW","FX","FY","FZ","Fa", | "Fb","Fc","Fd","Fe","Ff","Fg","Fh","Fi","Fj","Fk","Fl","Fm","Fn","Fo", | "Fp","Fq","Fr","cb","MC","ML","MR","Lf","SC","DK","RC","CW","WG","HU", | "DI","QD","TO","PU","fh","PA","WA","u0","u1","u2","u3","u4","u5","u6", | "u7","u8","u9","op","oc","Ic","Ip","sp","Sf","Sb","ZA","ZB","ZC","ZD", | "ZE","ZF","ZG","ZH","ZI","ZJ","ZK","ZL","ZM","ZN","ZO","ZP","ZQ","ZR", | "ZS","ZT","ZU","ZV","ZW","ZX","ZY","ZZ","Za","Zb","Zc","Zd","Ze","Zf", | "Zg","Zh","Zi","Zj","Zk","Zl","Zm","Zn","Zo","Zp","Zq","Zr","Zs","Zt", | "Zu","Zv","Zw","Zx","Zy","Km","Mi","RQ","Gm","AF","AB","xl","dv","ci", | "s0","s1","s2","s3","ML","MT","Xy","Zz","Yv","Yw","Yx","Yy","Yz","YZ", | "S1","S2","S3","S4","S5","S6","S7","S8","Xh","Xl","Xo","Xr","Xt","Xv", | "sA","sL" }); | | | | string tputs(string s) | { | | string pre, post; | while (3==sscanf(s, "%s$<%*[0-9.]>%s", pre, post)) | s = pre+post; | return s; | } | | protected private string swab(string s) | { | return predef::map(s/2, reverse)*""; | } | | protected private int load_cap(.File f, int|void bug_compat) | { | int magic, sname, nbool, nnum, nstr, sstr; | | if (6!=sscanf(swab(f->read(12)), "%2c%2c%2c%2c%2c%2c", | magic, sname, nbool, nnum, nstr, sstr) || | (magic != MAGIC && magic != MAGIC2)) | return 0; | aliases = (f->read(sname)-"\0")/"|"; | { | int blen = nbool; | if(((nbool+sname)&1) && !bug_compat) | blen++; | array(int) bools = values(f->read(blen)[..nbool-1]); | if (sizeof(bools)>sizeof(boolnames)) | bools = bools[..sizeof(boolnames)-1]; | map = mkmapping(boolnames[..sizeof(bools)-1], bools); | } | { | array(int) nums; | if (magic == MAGIC2) { | | nums = array_sscanf(f->read(nnum*4), "%-4c"*nnum); | } else { | nums = [array(int)] | array_sscanf(swab(f->read(nnum*2)), "%2c"*nnum); | } | if (sizeof(nums)>sizeof(numnames)) | nums = nums[..sizeof(numnames)-1]; | mapping(string:int) tmp = mkmapping(numnames[..sizeof(nums)-1], nums); | foreach (numnames[..sizeof(nums)-1], string name) { | if (tmp[name]>=0xfffe) { | if ((magic == MAGIC) || (tmp[name] >= 0xfffffffe)) | m_delete(tmp, name); | } | } | map += tmp; | } | { | string stroffs = swab(f->read(nstr*2)); | string strbuf = f->read(sstr); | if(sizeof(strbuf)==sstr-1 && !bug_compat && (nbool&1)) { | | f->seek(0); | return load_cap(f, 1); | } | if(sizeof(strbuf)!=sstr) | return 0; | array(string) strarr = predef::map(array_sscanf(stroffs, "%2c"*nstr), | lambda(int offs, string buf) { | return offs<0xfffe && | offs<sizeof(buf) && | buf[offs.. | search(buf, "\0", offs)-1]; | }, strbuf+"\0"); | if (sizeof(strarr)>sizeof(strnames)) | strarr = strarr[..sizeof(strnames)-1]; | mapping(string:string) tmp = mkmapping(strnames[..sizeof(strarr)-1], | strarr); | foreach (strnames[..sizeof(strarr)-1], string name) | if (!tmp[name]) | m_delete(tmp, name); | map += tmp; | } | return 1; | } | | | protected void create(string filename) | { | .File f = .File(); | if (!f->open(filename, "r")) | error("Terminfo: unable to open terminfo file \"%s\"\n", filename); | int r = load_cap(f); | f->close(); | if (!r) | error("Terminfo: unparsable terminfo file \"%s\"\n", filename); | } | } | | | class TermcapDB { | | MUTEX | | protected private inherit .File; | | protected private string buf=""; | protected private mapping(string:int|Termcap) cache=([]); | protected private int complete_index=0; | | protected void create(string|void filename) | { | if (!filename) { | string tce = [string]getenv("TERMCAP"); | if (tce && sizeof(tce) && tce[0]=='/') | filename = tce; | else if ((getenv("OSTYPE") == "msys") && | (filename = getenv("SHELL"))) { | | | | filename = combine_path(filename, "../../etc/termcap"); | } | else { | filename = "/etc/termcap"; | foreach(({ "/etc/termcap", "/usr/share/termcap", | "/usr/share/misc/termcap", }), string fname) { | .Stat s = file_stat(fname); | if (s && s->type == "reg") { | filename = fname; | break; | } | } | } | } | if (!::open(filename, "r")) { | error("failed to open termcap file %O\n", filename); | } | } | | protected private void rewind(int|void pos) | { | ::seek(pos); | buf=""; | } | | protected private int more_data() | { | string q; | q=::read(8192); | if (q=="" || !q) return 0; | buf+=q; | return 1; | } | | protected private array(string) get_names(string cap) | { | sscanf(cap, "%s:", cap); | sscanf(cap, "%s,", cap); | return cap/"|"; | } | | protected private string read() | { | int i, st; | string res=""; | for (;;) | { | if (buf=="" && !more_data()) return 0; | | sscanf(buf,"%*[ \t\r\n]%s",buf); | if (buf=="") continue; | | if (buf[0]=='#') | { | while ((i=search(buf,"\n"))<0) | { | | buf=""; | if(!more_data()) return 0; | } | buf=buf[i+1..]; | continue; | } | | break; | } | | st = ::tell()-sizeof(buf); | | while ((i=search(buf, "\n"))<0) | { | if (!more_data()) return 0; | } | | while (buf[i-1]=='\\') | { | res+=buf[..i-2]; | buf=buf[i+1..]; | while (sscanf(buf,"%*[ \t\r]%s",buf)<2 || !sizeof(buf)) | if (!more_data()) { | buf = ""; | return res; | } | while ((i=search(buf, "\n"))<0) | { | if (!more_data()) return 0; | } | } | | res+=buf[..i-1]; | buf=buf[i+1..]; | | foreach(get_names(res), string name) | if(!objectp(cache[name])) | cache[name]=st; | | return res; | } | | protected private string readat(int pos) | { | rewind(pos); | return read(); | } | | protected array(string) _indices() | { | LOCK; | if(!complete_index) { | rewind(); | while(read()); | complete_index = 1; | } | UNLOCK; | return sort(indices(cache)); | } | | protected array(Termcap) _values() | { | array(object|int) res = ({}); | mapping(int:string) extra = ([]); | LOCK; | if (complete_index) | res = predef::map(sort(indices(cache)), | [function(string,mapping(int:string):Termcap)] | lambda(string name, mapping(int:string) extra) { | if (!objectp(cache[name]) && !extra[cache[name]]) | extra[cache[name]] = readat(cache[name]); | return cache[name]; | }, extra); | else { | array(string) resi = ({}); | string cap; | int i = 1; | rewind(); | while ((cap = read())) { | array(string) names = get_names(cap); | object|int o = objectp(cache[names[0]]) && cache[names[0]]; | if (!o) | { | o = i++; | extra[o] = cap; | } | res += ({ o }) * sizeof(names); | resi += names; | } | sort(resi, res); | complete_index = 1; | } | UNLOCK; | return [array(Termcap)] | predef::map(res, | lambda(int|Termcap x, mapping(int:Termcap) y) { | return objectp(x)? [object(Termcap)]x : y[x]; | }, | mkmapping(indices(extra), | predef::map(values(extra), | Termcap, this))); | } | | protected private string read_next(string find) | { | for (;;) | { | int i, j; | | if (buf=="" && !more_data()) return 0; | | i=search(buf,find); | if (i!=-1) | { | int j=i; | while (j>=0 && buf[j]!='\n') j--; | | if (buf!="" && buf[j+1]!='#') | { | buf=buf[j+1..]; | return read(); | } | | while ((i=search(buf,"\n",j+1))<0) | if (!more_data()) return 0; | | buf = buf[i+1..]; | | continue; | } | for(j=-1; (i=search(buf,"\n",j+1))>=0; j=i); | buf = buf[j+1..]; | if (!more_data()) return 0; | } | } | | protected Termcap load(string term, int|void maxrecurse) | { | int|string|Termcap cap; | | LOCK; | if (!has_index(cache, term)) | { | if (!complete_index) | { | rewind(); | do | cap = read_next(term); | while(cap && search(get_names(cap), term)<0); | } | } | else if (intp(cap=cache[term])) { | rewind(cap); | cap = read(); | } | UNLOCK; | if (stringp(cap)) | { | array(string) names = get_names(cap); | if ((cap = Termcap(cap, this, maxrecurse))) | { | LOCK; | foreach(names, string name) | cache[name] = [object(Termcap)]cap; | UNLOCK; | } | } | return objectp(cap) && [object(Termcap)]cap; | } | | protected Termcap `[](string name) | { | return load(name); | } | } | | | class TerminfoDB { | | MUTEX | | protected private string dir; | protected private mapping(string:Terminfo) cache = ([]); | protected private int complete_index=0; | | protected string _sprintf(int c) | { | return sprintf("Stdio.Terminfo.TerminfoDB(%O)", dir); | } | | protected void create(string|void dirname) | { | if (!dirname) | { | | | foreach (({"/usr/share/lib/terminfo", "/usr/share/terminfo", | "/usr/share/termcap", | "/usr/lib/terminfo", "/usr/share/misc/terminfo", | "/lib/terminfo", "/etc/terminfo" }), string dn) | { | .Stat s = file_stat(dn); | if (s && s->type=="dir") | { | dirname = dn; | break; | } | } | if (!dirname) { | destruct(this); | return; | } | } | | if(sizeof(dirname)<1 || dirname[-1]!='/') | dirname += "/"; | | if (!get_dir(dir = dirname)) | error("failed to read terminfo dir %O\n", dirname); | } | | protected array(string) _indices() | { | LOCK; | if (!complete_index) { | foreach (get_dir(dir), string a) | if (sizeof(a) == 1) | foreach (get_dir(dir+a), string b) | if(!has_index(cache, b)) | cache[b] = 0; | complete_index = 1; | } | UNLOCK; | return sort(indices(cache)); | } | | protected array(object) _values() | { | return predef::map(_indices(), | [function(string:object(Terminfo))] | lambda(string name) { | return cache[name] || | Terminfo(dir+name[..0]+"/"+name); | }); | } | | protected Terminfo load(string term) | { | Terminfo ti; | | if (!sizeof(term)) | return 0; | LOCK; | if (!(ti = cache[term])) | { | if (file_stat(dir+term[..0]+"/"+term)) { | | ti = Terminfo(dir+term[..0]+"/"+term); | } else if (file_stat(sprintf("%s%02x/%s", dir, term[0], term))) { | | ti = Terminfo(sprintf("%s%02x/%s", dir, term[0], term)); | } | if (ti) | cache[term] = ti; | } | UNLOCK; | return ti; | } | | protected Terminfo `[](string name) | { | return load(name); | } | } | | | class MetaTerminfoDB { | protected array(TerminfoDB) dbs = ({}); | | | | | | | | | | | | | | | | protected void create(array(TerminfoDB|string)|void dbs) | { | if (!dbs) { | | dbs = ({ | | "/etc/terminfo", | | "/lib/terminfo", "/usr/lib/terminfo", | | "/usr/share/lib/terminfo", "/usr/share/terminfo", | "/usr/share/termcap", "/usr/share/misc/terminfo", | }); | } | foreach(dbs, string|TerminfoDB db) { | if (stringp(db)) { | .Stat st = file_stat(db); | if (!st || !st->isdir) continue; | db = TerminfoDB(db); | } | if (!db) continue; | this::dbs += ({ db }); | } | | if (!sizeof(this::dbs)) { | destruct(this); | } | } | | protected Terminfo `[](string name) | { | foreach(dbs, TerminfoDB db) { | Terminfo ti = db[name]; | if (ti) return ti; | } | return 0; | } | } | | protected private Termcap defterm; | protected private TermcapDB deftermcap; | protected private MetaTerminfoDB defterminfo; | | TermcapDB defaultTermcapDB() | { | TermcapDB tcdb; | LOCK; | catch { tcdb = deftermcap || (deftermcap = TermcapDB()); }; | UNLOCK; | return tcdb; | } | | MetaTerminfoDB defaultTerminfoDB() | { | MetaTerminfoDB tidb; | LOCK; | catch { tidb = defterminfo || (defterminfo = MetaTerminfoDB()); }; | UNLOCK; | return tidb; | } | | | | | | | Termcap getTermcap(string term) | { | TermcapDB tcdb = defaultTermcapDB(); | return tcdb && tcdb[term]; | } | | | | | | | Terminfo getTerminfo(string term) | { | TerminfoDB tidb = defaultTerminfoDB(); | return tidb && tidb[term]; | } | | | | | | | | | | | Termcap getTerm(string|void term) | { | if (!term) { | Termcap t = defterm; | if (!t) | { | string tc = [string]getenv("TERMCAP"); | if (mixed err = catch { | t = tc && sizeof(tc) && tc[0] != '/' && Termcap(tc); | }) | werror("%s", describe_backtrace(err)); | if (!t) | t = getTerm(getenv("TERM") || "dumb"); | LOCK; | if (!defterm) | defterm = t; | UNLOCK; | } | return t; | } | return getTerminfo(term) || getTermcap(term) || getFallbackTerm(term); | } | | | | | | | protected Termcap getFallbackTerm(string term) | { | return (term=="dumb"? Termcap("dumb:\\\n\t:am:co#80:do=^J:") : | getTerm("dumb")); | } | | protected int is_tty_cache; | | int is_tty() | | | | { | if(!is_tty_cache) | { | #ifdef __NT__ | is_tty_cache=1; | #else | is_tty_cache=!!.stdin->tcgetattr(); | #endif | if(!is_tty_cache) | { | is_tty_cache=-1; | }else{ | switch(getenv("TERM")) | { | case "dumb": | case "emacs": | is_tty_cache=-1; | } | } | } | return is_tty_cache>0; | } | | |
|