#include "locale/japanese.h"
#include "system/player-type-definition.h"
#include "term/gameterm.h"
+#include "term/z-form.h"
#include "util/angband-files.h"
#include "view/display-messages.h"
#include <algorithm>
#define FRESH_QUEUE_SIZE 4096
#define DEFAULT_DELAY 50
#define RECVBUF_SIZE 1024
+/* 「n」、「t」、および「w」コマンドでは、長さが「signed char」に配置されるときに負の値を回避するために、これよりも長い長さを使用しないでください。 */
+static constexpr auto split_max = 127;
static long epoch_time; /* バッファ開始時刻 */
static int browse_delay; /* 表示するまでの時間(100ms単位)(この間にラグを吸収する) */
#endif
}
-/* リングバッファ構造体に buf の内容を加える */
-static errr insert_ringbuf(char *buf)
+/*!
+ * @brief リングバッファにヘッダとペイロードを追加する
+ * @param header ヘッダ
+ * @param payload ペイロード (オプション)
+ * @return エラーコード
+ */
+static errr insert_ringbuf(std::string_view header, std::string_view payload = "")
{
- int len;
- len = strlen(buf) + 1; /* +1は終端文字分 */
-
if (movie_mode) {
- fd_write(movie_fd, buf, len);
+ fd_write(movie_fd, header.data(), header.length());
+ if (!payload.empty()) {
+ fd_write(movie_fd, payload.data(), payload.length());
+ }
+ fd_write(movie_fd, "", 1);
return 0;
}
/* バッファをオーバー */
- if (ring.inlen + len >= RINGBUF_SIZE) {
+ auto all_length = header.length() + payload.length();
+ if (ring.inlen + all_length + 1 >= RINGBUF_SIZE) {
return -1;
}
/* バッファの終端までに収まる */
- if (ring.wptr + len < RINGBUF_SIZE) {
- memcpy(ring.buf + ring.wptr, buf, len);
- ring.wptr += len;
+ if (ring.wptr + all_length + 1 < RINGBUF_SIZE) {
+ memcpy(ring.buf + ring.wptr, header.data(), header.length());
+ if (!payload.empty()) {
+ memcpy(ring.buf + ring.wptr + header.length(), payload.data(), payload.length());
+ }
+ *(ring.buf + ring.wptr + all_length) = '\0';
+ ring.wptr += all_length + 1;
}
/* バッファの終端までに収まらない(ピッタリ収まる場合も含む) */
else {
int head = RINGBUF_SIZE - ring.wptr; /* 前半 */
- int tail = len - head; /* 後半 */
+ int tail = all_length - head; /* 後半 */
- memcpy(ring.buf + ring.wptr, buf, head);
- memcpy(ring.buf, buf + head, tail);
- ring.wptr = tail;
+ if ((int)header.length() <= head) {
+ memcpy(ring.buf + ring.wptr, header.data(), header.length());
+ head -= header.length();
+ if (head > 0) {
+ memcpy(ring.buf + ring.wptr + header.length(), payload.data(), head);
+ }
+ memcpy(ring.buf, payload.data() + head, tail);
+ } else {
+ memcpy(ring.buf + ring.wptr, header.data(), head);
+ int part = header.length() - head;
+ memcpy(ring.buf, header.data() + head, part);
+ if (tail > part) {
+ memcpy(ring.buf + part, payload.data(), tail - part);
+ }
+ }
+ *(ring.buf + tail) = '\0';
+ ring.wptr = tail + 1;
}
- ring.inlen += len;
+ ring.inlen += all_length + 1;
/* Success */
return 0;
}
/* strが同じ文字の繰り返しかどうか調べる */
-static bool string_is_repeat(char *str, int len)
+static bool string_is_repeat(concptr str, int len)
{
char c = str[0];
int i;
return true;
}
-static errr send_text_to_chuukei_server(TERM_LEN x, TERM_LEN y, int len, TERM_COLOR col, concptr str)
+#ifdef JP
+/* マルチバイト文字を分割せずに str を分割する長さを len 以下で返す */
+static int find_split(concptr str, int len)
{
- char buf[1024 + 32];
- char buf2[1024];
-
- strncpy(buf2, str, len);
- buf2[len] = '\0';
+ /*
+ * SJIS が定義されている場合でも、str は常に EUC-JP としてエンコードされます。
+ * 他の場所で行われているような 3 バイトのエンコーディングは想定していません。
+ */
+ int last_split = 0, i = 0;
+ while (i < len) {
+ if (iseuckanji(str[i])) {
+ if (i < len - 1) {
+ last_split = i + 2;
+ }
+ i += 2;
+ } else {
+ last_split = i + 1;
+ ++i;
+ }
+ }
+ return last_split;
+}
+#endif
+static errr send_text_to_chuukei_server(TERM_LEN x, TERM_LEN y, int len, TERM_COLOR col, concptr str)
+{
if (len == 1) {
- sprintf(buf, "s%c%c%c%c", x + 1, y + 1, col, buf2[0]);
- } else if (string_is_repeat(buf2, len)) {
- int i;
- for (i = len; i > 0; i -= 127) {
- sprintf(buf, "n%c%c%c%c%c", x + 1, y + 1, std::min<int>(i, 127), col, buf2[0]);
+ insert_ringbuf(format("s%c%c%c%c", x + 1, y + 1, col, *str));
+ } else if (string_is_repeat(str, len)) {
+ while (len > split_max) {
+ insert_ringbuf(format("n%c%c%c%c%c", x + 1, y + 1, split_max, col, *str));
+ x += split_max;
+ len -= split_max;
+ }
+ if (len > 1) {
+ insert_ringbuf(format("n%c%c%c%c%c", x + 1, y + 1, len, col, *str));
+ } else {
+ insert_ringbuf(format("s%c%c%c%c", x + 1, y + 1, col, *str));
}
} else {
+ concptr payload;
#if defined(SJIS) && defined(JP)
- sjis2euc(buf2);
+ std::string buffer = str;
+ payload = buf.data();
+ sjis2euc(payload);
+#else
+ payload = str;
#endif
- sprintf(buf, "t%c%c%c%c%s", x + 1, y + 1, len, col, buf2);
- }
+ while (len > split_max) {
+ int split_len = _(find_split(payload, split_max), split_max);
- insert_ringbuf(buf);
+ insert_ringbuf(format("t%c%c%c%c", x + 1, y + 1, split_len, col), std::string_view(payload, split_len));
+ x += split_len;
+ len -= split_len;
+ payload += split_len;
+ }
+ insert_ringbuf(format("t%c%c%c%c", x + 1, y + 1, len, col), std::string_view(payload, len));
+ }
return (*old_text_hook)(x, y, len, col, str);
}
static errr send_wipe_to_chuukei_server(int x, int y, int len)
{
- char buf[1024];
-
- sprintf(buf, "w%c%c%c", x + 1, y + 1, len);
-
- insert_ringbuf(buf);
+ while (len > split_max) {
+ insert_ringbuf(format("w%c%c%c", x + 1, y + 1, split_max));
+ x += split_max;
+ len -= split_max;
+ }
+ insert_ringbuf(format("w%c%c%c", x + 1, y + 1, len));
return (*old_wipe_hook)(x, y, len);
}
static errr send_xtra_to_chuukei_server(int n, int v)
{
- char buf[1024];
-
if (n == TERM_XTRA_CLEAR || n == TERM_XTRA_FRESH || n == TERM_XTRA_SHAPE) {
- sprintf(buf, "x%c", n + 1);
-
- insert_ringbuf(buf);
+ insert_ringbuf(format("x%c", n + 1));
if (n == TERM_XTRA_FRESH) {
- sprintf(buf, "d%ld", get_current_time() - epoch_time);
- insert_ringbuf(buf);
+ insert_ringbuf("d", std::to_string(get_current_time() - epoch_time));
}
}
static errr send_curs_to_chuukei_server(int x, int y)
{
- char buf[1024];
-
- sprintf(buf, "c%c%c", x + 1, y + 1);
-
- insert_ringbuf(buf);
+ insert_ringbuf(format("c%c%c", x + 1, y + 1));
return (*old_curs_hook)(x, y);
}
static errr send_bigcurs_to_chuukei_server(int x, int y)
{
- char buf[1024];
-
- sprintf(buf, "C%c%c", x + 1, y + 1);
-
- insert_ringbuf(buf);
+ insert_ringbuf(format("C%c%c", x + 1, y + 1));
return (*old_bigcurs_hook)(x, y);
}
*/
void prepare_movie_hooks(PlayerType *player_ptr)
{
- char buf[1024];
- char tmp[80];
-
if (movie_mode) {
movie_mode = 0;
disable_chuukei_server();
fd_close(movie_fd);
msg_print(_("録画を終了しました。", "Stopped recording."));
} else {
- sprintf(tmp, "%s.amv", player_ptr->base_name);
- if (get_string(_("ムービー記録ファイル: ", "Movie file name: "), tmp, 80)) {
+ char filename[80];
+ strnfmt(filename, sizeof(filename), "%s.amv", player_ptr->base_name);
+ if (get_string(_("ムービー記録ファイル: ", "Movie file name: "), filename, 80)) {
+ char buf[1024];
int fd;
- path_build(buf, sizeof(buf), ANGBAND_DIR_USER, tmp);
+ path_build(buf, sizeof(buf), ANGBAND_DIR_USER, filename);
fd = fd_open(buf, O_RDONLY);
/* Existing file */
if (fd >= 0) {
- char out_val[sizeof(buf) + 128];
(void)fd_close(fd);
/* Build query */
- (void)sprintf(out_val, _("現存するファイルに上書きしますか? (%s)", "Replace existing file %s? "), buf);
+ std::string query = _("現存するファイルに上>書きしますか? (", "Replace existing file ");
+ query.append(buf);
+ query.append(_(")", "? "));
/* Ask */
- if (!get_check(out_val)) {
+ if (!get_check(query)) {
return;
}
static char recv_buf[RECVBUF_SIZE];
static int remain_bytes = 0;
int recv_bytes;
- int i;
+ int i, start;
recv_bytes = read(movie_fd, recv_buf + remain_bytes, RECVBUF_SIZE - remain_bytes);
/* 前回残ったデータ量に今回読んだデータ量を追加 */
remain_bytes += recv_bytes;
- for (i = 0; i < remain_bytes; i++) {
+ for (i = 0, start = 0; i < remain_bytes; i++) {
/* データのくぎり('\0')を探す */
if (recv_buf[i] == '\0') {
/* 'd'で始まるデータ(タイムスタンプ)の場合は
描画キューに保存する処理を呼ぶ */
- if ((recv_buf[0] == 'd') && (handle_movie_timestamp_data(atoi(recv_buf + 1)) < 0)) {
+ if ((recv_buf[start] == 'd') && (handle_movie_timestamp_data(atoi(recv_buf + start + 1)) < 0)) {
return -1;
}
/* 受信データを保存 */
- if (insert_ringbuf(recv_buf) < 0) {
+ if (insert_ringbuf(std::string_view(recv_buf + start, i - start)) < 0) {
return -1;
}
- /* 次のデータ移行をrecv_bufの先頭に移動 */
- memmove(recv_buf, recv_buf + i + 1, remain_bytes - i - 1);
-
- remain_bytes -= (i + 1);
- i = 0;
+ start = i + 1;
+ }
+ }
+ if (start > 0) {
+ if (remain_bytes >= start) {
+ memmove(recv_buf, recv_buf + start, remain_bytes - start);
+ remain_bytes -= start;
+ } else {
+ remain_bytes = 0;
}
}