Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/Debug.h>
8#include <AK/DeprecatedString.h>
9#include <AK/HashMap.h>
10#include <AK/Vector.h>
11#include <assert.h>
12#include <string.h>
13#include <termcap.h>
14
15extern "C" {
16
17char PC;
18char* UP;
19char* BC;
20
21int __attribute__((weak)) tgetent([[maybe_unused]] char* bp, [[maybe_unused]] char const* name)
22{
23 warnln_if(TERMCAP_DEBUG, "tgetent: bp={:p}, name='{}'", bp, name);
24 PC = '\0';
25 BC = const_cast<char*>("\033[D");
26 UP = const_cast<char*>("\033[A");
27 return 1;
28}
29
30static HashMap<DeprecatedString, char const*>* caps = nullptr;
31
32static void ensure_caps()
33{
34 if (caps)
35 return;
36 caps = new HashMap<DeprecatedString, char const*>;
37 caps->set("DC", "\033[%p1%dP");
38 caps->set("IC", "\033[%p1%d@");
39 caps->set("ce", "\033[K");
40 caps->set("cl", "\033[H\033[J");
41 caps->set("cr", "\015");
42 caps->set("dc", "\033[P");
43 caps->set("ei", "");
44 caps->set("ic", "");
45 caps->set("im", "");
46 caps->set("kd", "\033[B");
47 caps->set("kl", "\033[D");
48 caps->set("kr", "\033[C");
49 caps->set("ku", "\033[A");
50 caps->set("ks", "");
51 caps->set("ke", "");
52 caps->set("le", "\033[D");
53 caps->set("mm", "");
54 caps->set("mo", "");
55 caps->set("pc", "");
56 caps->set("up", "\033[A");
57 caps->set("vb", "");
58 caps->set("am", "");
59 caps->set("@7", "");
60 caps->set("kH", "");
61 caps->set("kI", "\033[L");
62 caps->set("kh", "\033[H");
63 caps->set("vs", "");
64 caps->set("ve", "");
65 caps->set("E3", "");
66 caps->set("kD", "");
67 caps->set("nd", "\033[C");
68
69 caps->set("co", "80");
70 caps->set("li", "25");
71}
72
73// Unfortunately, tgetstr() doesn't accept a size argument for the buffer
74// pointed to by area, so we have to use bare strcpy().
75#pragma GCC diagnostic push
76#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
77
78char* __attribute__((weak)) tgetstr(char const* id, char** area)
79{
80 ensure_caps();
81 warnln_if(TERMCAP_DEBUG, "tgetstr: id='{}'", id);
82 auto it = caps->find(id);
83 if (it != caps->end()) {
84 char* ret = *area;
85 char const* val = (*it).value;
86 strcpy(*area, val);
87 *area += strlen(val) + 1;
88 return ret;
89 }
90 warnln_if(TERMCAP_DEBUG, "tgetstr: missing cap id='{}'", id);
91 return nullptr;
92}
93
94#pragma GCC diagnostic pop
95
96int __attribute__((weak)) tgetflag([[maybe_unused]] char const* id)
97{
98 warnln_if(TERMCAP_DEBUG, "tgetflag: '{}'", id);
99 auto it = caps->find(id);
100 if (it != caps->end())
101 return 1;
102 return 0;
103}
104
105int __attribute__((weak)) tgetnum(char const* id)
106{
107 warnln_if(TERMCAP_DEBUG, "tgetnum: '{}'", id);
108 auto it = caps->find(id);
109 if (it != caps->end())
110 return atoi((*it).value);
111 return -1;
112}
113
114static Vector<char> s_tgoto_buffer;
115char* __attribute__((weak)) tgoto([[maybe_unused]] char const* cap, [[maybe_unused]] int col, [[maybe_unused]] int row)
116{
117 auto cap_str = StringView { cap, strlen(cap) }.replace("%p1%d"sv, DeprecatedString::number(col), ReplaceMode::FirstOnly).replace("%p2%d"sv, DeprecatedString::number(row), ReplaceMode::FirstOnly);
118
119 s_tgoto_buffer.clear_with_capacity();
120 s_tgoto_buffer.ensure_capacity(cap_str.length());
121 (void)cap_str.copy_characters_to_buffer(s_tgoto_buffer.data(), cap_str.length());
122 return s_tgoto_buffer.data();
123}
124
125int __attribute__((weak)) tputs(char const* str, [[maybe_unused]] int affcnt, int (*putc)(int))
126{
127 size_t len = strlen(str);
128 for (size_t i = 0; i < len; ++i)
129 putc(str[i]);
130 return 0;
131}
132}