Conversation
* add japanese/ * remove non-ascii char
# Conflicts: # sys/windows/Makefile.nmake
Walkthrough本PRはNetHackに日本語ローカライズ(JNetHack)を導入する変更です。新規に日本語処理ライブラリ(jlib.c/jconj.c)とパッチレベルヘッダを追加し、ヘッダファイルのデータ構造・マクロ・拡張宣言をJP条件分岐で拡張、多数のヘッダ/ソースファイルの表示文字列・データテーブルを英語から日本語へ置換しました。CIワークフローの成果物パスも更新されています。 ChangesJNetHack 日本語化
Estimated code review effort: 5 (Critical) | ~150 minutes Sequence Diagram(s)sequenceDiagram
participant SrcC as "src/*.c"
participant jconj as jconj()/jcan()/jpast()
participant jlib as jlib.c(str2ic/jbuffer)
participant Output as 画面出力
SrcC->>jconj: 動詞語幹とサフィックスを渡す
jconj->>jconj: jconj_tabで活用種別を検索
jconj-->>SrcC: 活用済み日本語文字列を返す
SrcC->>jlib: str2ic/jputsで文字コード変換
jlib-->>Output: 変換済み文字列を出力
関連Issue: 特になし 関連PR: 特になし Suggested labels: localization, i18n, japanese Suggested reviewers: jnethack開発チームのコアメンテナ Poem:
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 11
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/do_wear.c (1)
3875-3901: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
src/potion.c:2878のinaccessible_equipment()呼び出しも日本語の動詞句に揃えてください
apply.c側は置き換わっていますが、dip_into()だけverbに"dip"を渡したままです。ここも"を浸す"にしないと、拒否メッセージに英語の動詞が混ざります。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/do_wear.c` around lines 3875 - 3901, The `dip_into()` path still passes the English verb string to `inaccessible_equipment()`, so the refusal message can mix English and Japanese. Update the call site in `dip_into()` to use the localized Japanese verb phrase matching the rest of the `apply.c` changes, and verify the message flow through `inaccessible_equipment()` uses the Japanese action text consistently.src/cmd.c (1)
841-842: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
extcmd_via_menu()の幅計算を表示幅ベースに置き換えてください。
strlen()はバイト数なので、日本語のef_descではbiggestと実際の表示幅がずれ、#メニューの整列が崩れます。表示幅を返す共通処理に切り替えるか、この用途のヘルパーを追加してください。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/cmd.c` around lines 841 - 842, `extcmd_via_menu()` の幅計算が strlen() ベースになっており、`ef_desc` に日本語などのマルチバイト文字が含まれると `biggest` が実表示幅とずれてメニュー整列が崩れます。`extcmd_via_menu()` 内の `ef_desc` 長さ取得を、表示幅を返す共通ヘルパー(既存のものがあればそれ)に置き換えるか、この用途専用の幅計算ヘルパーを追加して `biggest` の更新に使ってください。
🧹 Nitpick comments (2)
src/dogmove.c (1)
1104-1113: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value既に
#if 0で無効化された到達不能コードの翻訳このブロックは外側の
#if 0 /* [this is now handled in dochug()] */ ...#endif`` により既にコンパイル対象外です。実行されないコードにまで翻訳を適用する必要性は低く、レビュー・保守コストが増えるだけです。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/dogmove.c` around lines 1104 - 1113, This block is already disabled by the surrounding `#if` 0 in dogmove.c and is unreachable, so the translation should not be applied here. Remove the translated You() text from this dead code block and keep the disabled comment block unchanged, using dochug() and unstuck()/You() as the relevant symbols to locate the section.src/do_name.c (1)
131-139: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
offset_in_kanji()の引数キャストを 136 行目と 159 行目でも統一136/159 行目の
char *渡しも、454 行目と同じく(const unsigned char *)を付けておくと型が揃い、-Wpointer-sign系の警告を避けやすいです。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/do_name.c` around lines 131 - 139, The offset_in_kanji() calls in do_name.c should use the same pointer-sign cast consistently to avoid warning mismatches. Update the call sites in the do_name logic (including the block around the PL_PSIZ trimming code and the other matching call near the later line) so the argument is passed as (const unsigned char *) instead of a plain char *; keep the existing function name and surrounding outbuf handling unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@include/AGENTS.md`:
- Around line 6-8: `defsysm.h` is likely a typo for the actual file `defsym.h`,
and the guideline text should be aligned with the real filename. Update the
`include/AGENTS.md` exception list and any matching path-pattern references so
they consistently use `defsym.h`, keeping the other unique symbols
(`artilist.h`, `monsters.h`, `objects.h`, `optlist.h`) unchanged. Verify the
document no longer propagates the misspelling anywhere else in the coding
guidelines.
In `@include/extern.h`:
- Around line 712-715: Restore the extern declaration for monverbself in
extern.h by removing the `#if` 0 guard so the prototype is visible again to all
translation units. Keep the existing symbol signature and NONNULLARG123
annotation, since src/apply.c, src/muse.c, and src/steed.c still reference
monverbself and need the shared declaration.
In `@japanese/jlib.c`:
- Around line 190-227: str2ic() の IC == input_kcode で入る高速パスだけ境界チェックなしの strcpy
を使っており、静的バッファ buf をオーバーフローさせる可能性があります。str2ic() 内の他分岐と同様に、input_kcode でもコピー長を
sizeof(buf) - 1 に制限し、末尾の終端を保証するように修正してください。対象は str2ic() とその buf への代入処理です。
- Around line 296-311: The charlen function’s UTF-8 byte-length detection is
misclassifying 2-byte leading bytes as 3-byte characters because the thresholds
are ordered too broadly. Update the ICUTF8 branch in charlen to distinguish
0xC0-0xDF as 2 bytes, 0xE0-0xEF as 3 bytes, and 0xF0-0xF7 as 4 bytes, keeping
the fallback for 0x80+ and 1-byte values intact. Use the existing charlen logic
in japanese/jlib.c as the single place to correct the byte-length checks.
- Around line 481-524: split_japanese() currently relies on is_kanji1/is_kanji2,
which advance in 2-byte steps and will break UTF-8 by splitting multibyte
characters. Add a UTF-8-specific branch in split_japanese(), following the same
style as jrubout(), so that when IC == UTF8 it computes the split position using
UTF-8 character boundaries instead of the kanji helpers. Keep the existing
non-UTF-8 path unchanged and ensure the new branch uses the relevant split logic
in split_japanese() rather than modifying is_kanji1/is_kanji2.
In `@src/attrib.c`:
- Around line 1175-1192: The FAST branch in attrib.c still uses
ysimple_name(uarmf), which can introduce the unwanted “your/your...” wording
instead of matching the simplified naming used elsewhere. Update the FAST
handling inside the Very_fast block to use simpleonames(uarmf) so the message
text stays consistent with the other status-name formatting paths.
In `@src/botl.c`:
- Around line 570-576: The level label change in botl.c breaks the existing
Dlvl: replacement flow because dungeon.c still expects that exact token in
strsubst() for level-name formatting. Keep the Dlvl: prefix in the text produced
by the status display, or update both the botl.c output and the dungeon.c
strsubst(lbuf, "Dlvl:", "level "); logic together so the downstream substitution
still works from the relevant display path.
In `@src/cmd.c`:
- Around line 3205-3209: The branch handling extcmdlist lookup in cmd.c is
mismatched: it checks key2cmdbuf with STRNCMP2 against "接頭辞:" but still calls
strsubst with "prefix:", so the replacement never fires for this path. Update
the strsubst call in the same conditional block to use the same Japanese prefix
string as the matcher, and keep the reqmenu handling consistent with the
surrounding extcmdlist logic so the two-line display conversion runs correctly.
In `@src/dog.c`:
- Around line 872-878: The current JP translation wraps only part of a
multi-line original `pline` call with `/*JP */`, leaving `Monnam(mtmp));`
outside the preserved original text. Update the `dog.c` translation block around
`mon_has_amulet` / `canseemon` to use the full `#if 0 /*JP:T*/ ... `#else` ...
`#endif`` form, matching the nearby translated sections, so the entire original
multi-line statement is kept intact and only one complete translated version is
emitted.
- Around line 255-277: The petname assignments in the Role_if(PM_SAMURAI),
Role_if(PM_BARBARIAN), and Role_if(PM_RANGER) branches are single-line
independent changes, so replace the current `#if` 0 /*JP:T*/ ... `#else` ... `#endif`
blocks in dog.c with the single-line JP replacement form using the surrounding
petname assignment lines as the anchor.
In `@src/dogmove.c`:
- Around line 304-311: This change uses a multi-line `#if` 0 block for a one-line
independent substitution in the seeobj branch of dogmove.c, which violates the
single-line replacement guideline. Replace the existing pline statement and its
translated variant in the same spot with the single-line comment form using the
JP marker, so the original English line is kept as a comment and the translated
pline line is placed directly beneath it. Keep the change localized around the
seeobj handling and do not leave the `#if` 0 / `#else` / `#endif` wrapper in place.
---
Outside diff comments:
In `@src/cmd.c`:
- Around line 841-842: `extcmd_via_menu()` の幅計算が strlen() ベースになっており、`ef_desc`
に日本語などのマルチバイト文字が含まれると `biggest` が実表示幅とずれてメニュー整列が崩れます。`extcmd_via_menu()` 内の
`ef_desc` 長さ取得を、表示幅を返す共通ヘルパー(既存のものがあればそれ)に置き換えるか、この用途専用の幅計算ヘルパーを追加して `biggest`
の更新に使ってください。
In `@src/do_wear.c`:
- Around line 3875-3901: The `dip_into()` path still passes the English verb
string to `inaccessible_equipment()`, so the refusal message can mix English and
Japanese. Update the call site in `dip_into()` to use the localized Japanese
verb phrase matching the rest of the `apply.c` changes, and verify the message
flow through `inaccessible_equipment()` uses the Japanese action text
consistently.
---
Nitpick comments:
In `@src/do_name.c`:
- Around line 131-139: The offset_in_kanji() calls in do_name.c should use the
same pointer-sign cast consistently to avoid warning mismatches. Update the call
sites in the do_name logic (including the block around the PL_PSIZ trimming code
and the other matching call near the later line) so the argument is passed as
(const unsigned char *) instead of a plain char *; keep the existing function
name and surrounding outbuf handling unchanged.
In `@src/dogmove.c`:
- Around line 1104-1113: This block is already disabled by the surrounding `#if` 0
in dogmove.c and is unreachable, so the translation should not be applied here.
Remove the translated You() text from this dead code block and keep the disabled
comment block unchanged, using dochug() and unstuck()/You() as the relevant
symbols to locate the section.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: eee1f64f-c1de-47df-b99c-66da7780e50d
⛔ Files ignored due to path filters (116)
dat/Arc-fila.luais excluded by!dat/**dat/Arc-filb.luais excluded by!dat/**dat/Arc-goal.luais excluded by!dat/**dat/Arc-loca.luais excluded by!dat/**dat/Arc-strt.luais excluded by!dat/**dat/Bar-fila.luais excluded by!dat/**dat/Bar-filb.luais excluded by!dat/**dat/Bar-goal.luais excluded by!dat/**dat/Bar-loca.luais excluded by!dat/**dat/Bar-strt.luais excluded by!dat/**dat/Cav-fila.luais excluded by!dat/**dat/Cav-filb.luais excluded by!dat/**dat/Cav-goal.luais excluded by!dat/**dat/Cav-loca.luais excluded by!dat/**dat/Cav-strt.luais excluded by!dat/**dat/Hea-fila.luais excluded by!dat/**dat/Hea-filb.luais excluded by!dat/**dat/Hea-goal.luais excluded by!dat/**dat/Hea-loca.luais excluded by!dat/**dat/Hea-strt.luais excluded by!dat/**dat/Kni-fila.luais excluded by!dat/**dat/Kni-filb.luais excluded by!dat/**dat/Kni-goal.luais excluded by!dat/**dat/Kni-loca.luais excluded by!dat/**dat/Kni-strt.luais excluded by!dat/**dat/Mon-fila.luais excluded by!dat/**dat/Mon-filb.luais excluded by!dat/**dat/Mon-goal.luais excluded by!dat/**dat/Mon-loca.luais excluded by!dat/**dat/Mon-strt.luais excluded by!dat/**dat/Pri-fila.luais excluded by!dat/**dat/Pri-filb.luais excluded by!dat/**dat/Pri-goal.luais excluded by!dat/**dat/Pri-loca.luais excluded by!dat/**dat/Pri-strt.luais excluded by!dat/**dat/Ran-fila.luais excluded by!dat/**dat/Ran-filb.luais excluded by!dat/**dat/Ran-goal.luais excluded by!dat/**dat/Ran-loca.luais excluded by!dat/**dat/Ran-strt.luais excluded by!dat/**dat/Rog-fila.luais excluded by!dat/**dat/Rog-filb.luais excluded by!dat/**dat/Rog-goal.luais excluded by!dat/**dat/Rog-loca.luais excluded by!dat/**dat/Rog-strt.luais excluded by!dat/**dat/Sam-fila.luais excluded by!dat/**dat/Sam-filb.luais excluded by!dat/**dat/Sam-goal.luais excluded by!dat/**dat/Sam-loca.luais excluded by!dat/**dat/Sam-strt.luais excluded by!dat/**dat/Tou-fila.luais excluded by!dat/**dat/Tou-filb.luais excluded by!dat/**dat/Tou-goal.luais excluded by!dat/**dat/Tou-loca.luais excluded by!dat/**dat/Tou-strt.luais excluded by!dat/**dat/Val-fila.luais excluded by!dat/**dat/Val-filb.luais excluded by!dat/**dat/Val-goal.luais excluded by!dat/**dat/Val-loca.luais excluded by!dat/**dat/Val-strt.luais excluded by!dat/**dat/Wiz-fila.luais excluded by!dat/**dat/Wiz-filb.luais excluded by!dat/**dat/Wiz-goal.luais excluded by!dat/**dat/Wiz-loca.luais excluded by!dat/**dat/Wiz-strt.luais excluded by!dat/**dat/air.luais excluded by!dat/**dat/asmodeus.luais excluded by!dat/**dat/astral.luais excluded by!dat/**dat/baalz.luais excluded by!dat/**dat/bigrm-11.luais excluded by!dat/**dat/castle.luais excluded by!dat/**dat/earth.luais excluded by!dat/**dat/fakewiz1.luais excluded by!dat/**dat/fakewiz2.luais excluded by!dat/**dat/fire.luais excluded by!dat/**dat/hellfill.luais excluded by!dat/**dat/juiblex.luais excluded by!dat/**dat/knox.luais excluded by!dat/**dat/medusa-1.luais excluded by!dat/**dat/medusa-2.luais excluded by!dat/**dat/medusa-3.luais excluded by!dat/**dat/medusa-4.luais excluded by!dat/**dat/minefill.luais excluded by!dat/**dat/minend-1.luais excluded by!dat/**dat/minend-2.luais excluded by!dat/**dat/minend-3.luais excluded by!dat/**dat/minetn-1.luais excluded by!dat/**dat/minetn-2.luais excluded by!dat/**dat/minetn-3.luais excluded by!dat/**dat/minetn-4.luais excluded by!dat/**dat/minetn-5.luais excluded by!dat/**dat/minetn-6.luais excluded by!dat/**dat/minetn-7.luais excluded by!dat/**dat/nhlib.luais excluded by!dat/**dat/oracle.luais excluded by!dat/**dat/orcus.luais excluded by!dat/**dat/quest.luais excluded by!dat/**dat/sanctum.luais excluded by!dat/**dat/soko1-1.luais excluded by!dat/**dat/soko1-2.luais excluded by!dat/**dat/soko2-1.luais excluded by!dat/**dat/soko2-2.luais excluded by!dat/**dat/soko3-1.luais excluded by!dat/**dat/soko3-2.luais excluded by!dat/**dat/soko4-1.luais excluded by!dat/**dat/soko4-2.luais excluded by!dat/**dat/themerms.luais excluded by!dat/**dat/tower1.luais excluded by!dat/**dat/tower2.luais excluded by!dat/**dat/tower3.luais excluded by!dat/**dat/tut-1.luais excluded by!dat/**dat/valley.luais excluded by!dat/**dat/water.luais excluded by!dat/**dat/wizard1.luais excluded by!dat/**dat/wizard3.luais excluded by!dat/**rej.txtis excluded by!*.txt
📒 Files selected for processing (127)
.github/workflows/windows.ymlAGENTS.mdinclude/AGENTS.mdinclude/artilist.hinclude/config.hinclude/decl.hinclude/defsym.hinclude/extern.hinclude/hack.hinclude/monsters.hinclude/objects.hinclude/optlist.hinclude/you.hjapanese/jconj.cjapanese/jlib.cjapanese/jpatchlevel.hsrc/allmain.csrc/apply.csrc/artifact.csrc/attrib.csrc/ball.csrc/bones.csrc/botl.csrc/cfgfiles.csrc/cmd.csrc/dbridge.csrc/decl.csrc/detect.csrc/dig.csrc/do.csrc/do_name.csrc/do_wear.csrc/dog.csrc/dogmove.csrc/dokick.csrc/dothrow.csrc/drawing.csrc/dungeon.csrc/eat.csrc/end.csrc/engrave.csrc/exper.csrc/explode.csrc/files.csrc/fountain.csrc/getpos.csrc/hack.csrc/hacklib.csrc/insight.csrc/invent.csrc/light.csrc/lock.csrc/mail.csrc/makemon.csrc/mcastu.csrc/mdlib.csrc/mhitm.csrc/mhitu.csrc/minion.csrc/mklev.csrc/mkmaze.csrc/mkobj.csrc/mon.csrc/mondata.csrc/monmove.csrc/mplayer.csrc/mthrowu.csrc/muse.csrc/music.csrc/nhlua.csrc/o_init.csrc/objnam.csrc/options.csrc/pager.csrc/pickup.csrc/pline.csrc/polyself.csrc/potion.csrc/pray.csrc/priest.csrc/quest.csrc/questpgr.csrc/read.csrc/region.csrc/restore.csrc/rip.csrc/role.csrc/rumors.csrc/save.csrc/shk.csrc/shknam.csrc/sit.csrc/sounds.csrc/sp_lev.csrc/spell.csrc/steal.csrc/steed.csrc/symbols.csrc/teleport.csrc/timeout.csrc/topten.csrc/trap.csrc/uhitm.csrc/vault.csrc/version.csrc/weapon.csrc/were.csrc/wield.csrc/windows.csrc/wizard.csrc/wizcmds.csrc/worm.csrc/worn.csrc/write.csrc/zap.csys/windows/Makefile.nmakesys/windows/consoletty.csys/windows/vs/NetHack/NetHack.vcxprojsys/windows/windmain.csys/windows/windsys.cutil/makedefs.cutil/recover.cwin/share/tilemap.cwin/share/tiletext.cwin/tty/getline.cwin/tty/topl.cwin/tty/wintty.c
| 原則として*.cと同様に原文をコメントアウトして残しますが、例外として | ||
| artilist.h, defsysm.h, monsters.h, objects.h, optlist.h は | ||
| 変更点が多いため原文を残さずに直接日本語に書き換えます。 |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
defsysm.h は defsym.h の誤記の可能性があります。
他レイヤーの変更サマリでは実際のファイルとして include/defsym.h が挙げられています。本ドキュメント(およびコーディングガイドラインのパスパターン)の綴りが実ファイル名と異なると、将来的にパスベースの設定・ツールがこのファイルにマッチしなくなる恐れがあります。
As per coding guidelines, include/**/{artilist.h,defsysm.h,monsters.h,objects.h,optlist.h} と同じ綴りが使われており、実ファイル名との不一致がドキュメント全体に伝播しています。
✏️ 修正案
-artilist.h, defsysm.h, monsters.h, objects.h, optlist.h は
+artilist.h, defsym.h, monsters.h, objects.h, optlist.h は📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 原則として*.cと同様に原文をコメントアウトして残しますが、例外として | |
| artilist.h, defsysm.h, monsters.h, objects.h, optlist.h は | |
| 変更点が多いため原文を残さずに直接日本語に書き換えます。 | |
| 原則として*.cと同様に原文をコメントアウトして残しますが、例外として | |
| artilist.h, defsym.h, monsters.h, objects.h, optlist.h は | |
| 変更点が多いため原文を残さずに直接日本語に書き換えます。 |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@include/AGENTS.md` around lines 6 - 8, `defsysm.h` is likely a typo for the
actual file `defsym.h`, and the guideline text should be aligned with the real
filename. Update the `include/AGENTS.md` exception list and any matching
path-pattern references so they consistently use `defsym.h`, keeping the other
unique symbols (`artilist.h`, `monsters.h`, `objects.h`, `optlist.h`) unchanged.
Verify the document no longer propagates the misspelling anywhere else in the
coding guidelines.
Source: Coding guidelines
| const char * | ||
| str2ic(const char *s) | ||
| { | ||
| static unsigned char buf[1024]; | ||
| const unsigned char *up; | ||
| unsigned char *p; | ||
|
|
||
| if(!s) | ||
| return s; | ||
|
|
||
| buf[0] = '\0'; | ||
|
|
||
| if( IC==input_kcode ){ | ||
| strcpy((char *)buf, s); | ||
| return (char *)buf; | ||
| } | ||
|
|
||
| p = buf; | ||
| #ifdef POSIX_ICONV | ||
| if (input_dsc) { | ||
| size_t src_len, dst_len; | ||
| up = (unsigned char *)s; | ||
| src_len = strlen(s); | ||
| dst_len = sizeof(buf) - 1; | ||
| if (iconv(input_dsc, (char**)&up, &src_len, | ||
| (char**)&p, &dst_len) == (size_t)-1){ | ||
| strncpy((char *) buf, s, sizeof(buf) - 1); | ||
| buf[sizeof(buf) - 1] = '\0'; | ||
| return (char *)buf; | ||
| } | ||
| *p = '\0'; | ||
| return (char *)buf; | ||
| } else { | ||
| strncpy((char *) buf, s, sizeof(buf) - 1); | ||
| buf[sizeof(buf) - 1] = '\0'; | ||
| return (char *)buf; | ||
| } | ||
| #else /*WIN32*/ |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
str2ic()の高速パスで境界チェックなしのstrcpyが使われています。
IC == input_kcodeの場合(202-205行目)はstrcpy((char *)buf, s)を無制限に実行しますが、同じ関数の他の分岐(216-217行目、223-224行目)はstrncpyでsizeof(buf) - 1に制限しています。この分岐だけ境界チェックが抜けており、sが1024バイトを超えると静的バッファbufがオーバーフローします。
🛡️ 修正案
if( IC==input_kcode ){
- strcpy((char *)buf, s);
+ strncpy((char *)buf, s, sizeof(buf) - 1);
+ buf[sizeof(buf) - 1] = '\0';
return (char *)buf;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const char * | |
| str2ic(const char *s) | |
| { | |
| static unsigned char buf[1024]; | |
| const unsigned char *up; | |
| unsigned char *p; | |
| if(!s) | |
| return s; | |
| buf[0] = '\0'; | |
| if( IC==input_kcode ){ | |
| strcpy((char *)buf, s); | |
| return (char *)buf; | |
| } | |
| p = buf; | |
| #ifdef POSIX_ICONV | |
| if (input_dsc) { | |
| size_t src_len, dst_len; | |
| up = (unsigned char *)s; | |
| src_len = strlen(s); | |
| dst_len = sizeof(buf) - 1; | |
| if (iconv(input_dsc, (char**)&up, &src_len, | |
| (char**)&p, &dst_len) == (size_t)-1){ | |
| strncpy((char *) buf, s, sizeof(buf) - 1); | |
| buf[sizeof(buf) - 1] = '\0'; | |
| return (char *)buf; | |
| } | |
| *p = '\0'; | |
| return (char *)buf; | |
| } else { | |
| strncpy((char *) buf, s, sizeof(buf) - 1); | |
| buf[sizeof(buf) - 1] = '\0'; | |
| return (char *)buf; | |
| } | |
| #else /*WIN32*/ | |
| const char * | |
| str2ic(const char *s) | |
| { | |
| static unsigned char buf[1024]; | |
| const unsigned char *up; | |
| unsigned char *p; | |
| if(!s) | |
| return s; | |
| buf[0] = '\0'; | |
| if( IC==input_kcode ){ | |
| `#if` 0 /*JP*/ | |
| strcpy((char *)buf, s); | |
| `#else` | |
| strncpy((char *)buf, s, sizeof(buf) - 1); | |
| buf[sizeof(buf) - 1] = '\0'; | |
| `#endif` | |
| return (char *)buf; | |
| } | |
| p = buf; | |
| `#ifdef` POSIX_ICONV | |
| if (input_dsc) { | |
| size_t src_len, dst_len; | |
| up = (unsigned char *)s; | |
| src_len = strlen(s); | |
| dst_len = sizeof(buf) - 1; | |
| if (iconv(input_dsc, (char**)&up, &src_len, | |
| (char**)&p, &dst_len) == (size_t)-1){ | |
| strncpy((char *) buf, s, sizeof(buf) - 1); | |
| buf[sizeof(buf) - 1] = '\0'; | |
| return (char *)buf; | |
| } | |
| *p = '\0'; | |
| return (char *)buf; | |
| } else { | |
| strncpy((char *) buf, s, sizeof(buf) - 1); | |
| buf[sizeof(buf) - 1] = '\0'; | |
| return (char *)buf; | |
| } | |
| `#else` /*WIN32*/ |
🧰 Tools
🪛 ast-grep (0.44.0)
[error] 202-202: Use of an unbounded buffer function that can overflow the destination; use a size-bounded equivalent (fgets, strncpy/strlcpy, strncat/strlcat, snprintf).
Context: strcpy((char *)buf, s)
Note: [CWE-120] Buffer Copy without Checking Size of Input ('Classic Buffer Overflow').
(dangerous-buffer-functions-c)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@japanese/jlib.c` around lines 190 - 227, str2ic() の IC == input_kcode
で入る高速パスだけ境界チェックなしの strcpy を使っており、静的バッファ buf をオーバーフローさせる可能性があります。str2ic()
内の他分岐と同様に、input_kcode でもコピー長を sizeof(buf) - 1 に制限し、末尾の終端を保証するように修正してください。対象は
str2ic() とその buf への代入処理です。
Source: Linters/SAST tools
| static int | ||
| charlen(unsigned int c) | ||
| { | ||
| #ifdef ICUTF8 | ||
| if(c >= 0xf0){ | ||
| return 4; | ||
| } | ||
| if(c >= 0xc0){ | ||
| return 3; | ||
| } | ||
| #endif | ||
| if(c >= 0x80){ | ||
| return 2; | ||
| } | ||
| return 1; | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
UTF-8先頭バイト判定に誤りがあります。
0xC0~0xDF(本来2バイト文字の先頭バイト)がc >= 0xc0の条件に該当して3バイトと誤判定されます。UTF-8の正しい判定は 0xC0-0xDF→2バイト、0xE0-0xEF→3バイト、0xF0-0xF7→4バイト です。ひらがな・漢字(3バイト)自体は影響を受けませんが、ラテン拡張文字等の2バイト文字が混在すると後続バイト列がずれ、文字化けを引き起こします。
🐛 修正案
static int
charlen(unsigned int c)
{
`#ifdef` ICUTF8
if(c >= 0xf0){
return 4;
}
- if(c >= 0xc0){
+ if(c >= 0xe0){
return 3;
}
+ if(c >= 0xc0){
+ return 2;
+ }
`#endif`
if(c >= 0x80){
return 2;
}
return 1;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| static int | |
| charlen(unsigned int c) | |
| { | |
| #ifdef ICUTF8 | |
| if(c >= 0xf0){ | |
| return 4; | |
| } | |
| if(c >= 0xc0){ | |
| return 3; | |
| } | |
| #endif | |
| if(c >= 0x80){ | |
| return 2; | |
| } | |
| return 1; | |
| } | |
| static int | |
| charlen(unsigned int c) | |
| { | |
| `#ifdef` ICUTF8 | |
| `#if` 0 /*JP*/ | |
| if(c >= 0xf0){ | |
| return 4; | |
| } | |
| if(c >= 0xc0){ | |
| return 3; | |
| } | |
| `#else` | |
| if(c >= 0xf0){ | |
| return 4; | |
| } | |
| if(c >= 0xe0){ | |
| return 3; | |
| } | |
| if(c >= 0xc0){ | |
| return 2; | |
| } | |
| `#endif` | |
| `#endif` | |
| if(c >= 0x80){ | |
| return 2; | |
| } | |
| return 1; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@japanese/jlib.c` around lines 296 - 311, The charlen function’s UTF-8
byte-length detection is misclassifying 2-byte leading bytes as 3-byte
characters because the thresholds are ordered too broadly. Update the ICUTF8
branch in charlen to distinguish 0xC0-0xDF as 2 bytes, 0xE0-0xEF as 3 bytes, and
0xF0-0xF7 as 4 bytes, keeping the fallback for 0x80+ and 1-byte values intact.
Use the existing charlen logic in japanese/jlib.c as the single place to correct
the byte-length checks.
| int | ||
| is_kanji2(const char *s,int pos) | ||
| { | ||
| unsigned char *str; | ||
|
|
||
| str = (unsigned char *)s; | ||
| while(*str && pos>0){ | ||
| if(is_kanji(*str)){ | ||
| str+=2; | ||
| pos-=2; | ||
| } | ||
| else{ | ||
| ++str; | ||
| --pos; | ||
| } | ||
| } | ||
| if(pos<0) | ||
| return 1; | ||
| else | ||
| return 0; | ||
| } | ||
|
|
||
| int | ||
| is_kanji1(const char *s,int pos) | ||
| { | ||
| unsigned char *str; | ||
|
|
||
| str = (unsigned char *)s; | ||
| while(*str && pos>0){ | ||
| if(is_kanji(*str)){ | ||
| str+=2; | ||
| pos-=2; | ||
| } | ||
| else{ | ||
| ++str; | ||
| --pos; | ||
| } | ||
| } | ||
| if(!pos && is_kanji(*str)) | ||
| return 1; | ||
| else | ||
| return 0; | ||
| } | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
set -e
git ls-files japanese/jlib.c
printf '\n--- split_japanese / jrubout refs ---\n'
rg -n "split_japanese|jrubout|IC == UTF8|UTF8" japanese/jlib.c
printf '\n--- relevant sections ---\n'
sed -n '430,740p' japanese/jlib.c
printf '\n--- jrubout section ---\n'
sed -n '1340,1415p' japanese/jlib.cRepository: jnethack/temp-370
Length of output: 8205
🏁 Script executed:
set -e
sed -n '430,740p' japanese/jlib.c | cat -n
printf '\n---\n'
sed -n '1340,1415p' japanese/jlib.c | cat -n
printf '\n--- search ---\n'
rg -n "split_japanese|jrubout|IC == UTF8|UTF8" japanese/jlib.cRepository: jnethack/temp-370
Length of output: 10828
🏁 Script executed:
set -e
printf '%s\n' '--- split_japanese call sites ---'
rg -n "split_japanese\s*\(" -S .
printf '%s\n' '--- is_kanji definition ---'
rg -n "`#define`[[:space:]]+is_kanji|int[[:space:]]+is_kanji|is_kanji\(" japanese/jlib.cRepository: jnethack/temp-370
Length of output: 763
🏁 Script executed:
set -e
sed -n '80,120p' japanese/jlib.c | cat -n
printf '\n--- topten context ---\n'
sed -n '1220,1265p' src/topten.c | cat -n
printf '\n--- topl context ---\n'
sed -n '235,275p' win/tty/topl.c | cat -nRepository: jnethack/temp-370
Length of output: 4078
split_japanese() に UTF-8 専用の分岐を追加してください。
is_kanji1/2 は 2 バイト前提で進むため、IC == UTF8 では 3 バイト文字を途中で切ってしまいます。jrubout() と同様に UTF-8 では別経路で分割位置を決める必要があります。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@japanese/jlib.c` around lines 481 - 524, split_japanese() currently relies on
is_kanji1/is_kanji2, which advance in 2-byte steps and will break UTF-8 by
splitting multibyte characters. Add a UTF-8-specific branch in split_japanese(),
following the same style as jrubout(), so that when IC == UTF8 it computes the
split position using UTF-8 character boundaries instead of the kanji helpers.
Keep the existing non-UTF-8 path unchanged and ensure the new branch uses the
relevant split logic in split_japanese() rather than modifying
is_kanji1/is_kanji2.
| #if 0 /*JP:T*/ | ||
| Sprintf(buf, "%s:%-2d", /* "Dlvl:n" (grep fodder) */ | ||
| In_tutorial(&u.uz) ? "Tutorial" : "Dlvl", depth(&u.uz)); | ||
| #else | ||
| Sprintf(buf, "%s:%-2d", /* "Dlvl:n" (grep fodder) */ | ||
| In_tutorial(&u.uz) ? "説明" : "地下", depth(&u.uz)); | ||
| #endif |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# "Dlvl:" 文字列への依存(grep等)がないか確認
rg -n 'Dlvl:' --type=c --type=cpp -g '!src/botl.c'
rg -n 'Dlvl' win/ sys/ 2>/dev/nullRepository: jnethack/temp-370
Length of output: 155
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '== exact string matches ==\n'
rg -n --hidden --glob '!.git' 'Dlvl:' . || true
printf '\n== broader Dlvl matches ==\n'
rg -n --hidden --glob '!.git' 'Dlvl' . || true
printf '\n== nearby botl.c context ==\n'
sed -n '560,585p' src/botl.cRepository: jnethack/temp-370
Length of output: 3242
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '== src/dungeon.c around the substitution ==\n'
sed -n '2688,2706p' src/dungeon.c
printf '\n== win/tty/wintty.c around Dlvl shrinking ==\n'
sed -n '4400,4420p' win/tty/wintty.c
sed -n '5064,5084p' win/tty/wintty.c
printf '\n== win/curses/cursstat.c around Dlvl-N wording ==\n'
sed -n '1234,1250p' win/curses/cursstat.cRepository: jnethack/temp-370
Length of output: 3406
Dlvl: の表記は維持するか、置換処理も合わせて修正してください
src/botl.c:570-576 で Dlvl: を 説明 / 地下 に変えると、src/dungeon.c の strsubst(lbuf, "Dlvl:", "level "); が効かなくなり、レベル名の整形が崩れます。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/botl.c` around lines 570 - 576, The level label change in botl.c breaks
the existing Dlvl: replacement flow because dungeon.c still expects that exact
token in strsubst() for level-name formatting. Keep the Dlvl: prefix in the text
produced by the status display, or update both the botl.c output and the
dungeon.c strsubst(lbuf, "Dlvl:", "level "); logic together so the downstream
substitution still works from the relevant display path.
| #if 0 /*JP:T*/ | ||
| if (!strncmpi(key2cmdbuf, "prefix:", 7) && !strcmpi(txt, "reqmenu")) | ||
| #else /* extcmdlistの文字列を見ている */ | ||
| if (!STRNCMP2(key2cmdbuf, "接頭辞:") && !strcmpi(txt, "reqmenu")) | ||
| #endif |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# STRNCMP2 マクロの定義を検索
rg -n -C3 '\bSTRNCMP2\b' --type=c --type=h -g '*.h' -g '*.c'Repository: jnethack/temp-370
Length of output: 155
🏁 Script executed:
#!/bin/bash
set -e
echo '--- STRNCMP2 search (entire repo) ---'
rg -n -C3 '\bSTRNCMP2\b' .
echo
echo '--- nearby context in src/cmd.c ---'
sed -n '3188,3220p' src/cmd.cRepository: jnethack/temp-370
Length of output: 11154
🏁 Script executed:
#!/bin/bash
set -e
echo '--- search for related string-compare macros/functions ---'
rg -n -C2 '\b(STRNCMP2|STRN?CMP|strncmpi|strcmpi)\b' src include .Repository: jnethack/temp-370
Length of output: 50374
strsubst の検索文字列を日本語に揃えてください (src/cmd.c:3208-3211)
STRNCMP2(key2cmdbuf, "接頭辞:") には入りますが、直後の strsubst(key2cmdbuf, "prefix:", ...) は一致せず、この分岐での2行表示変換が実行されません。"接頭辞:" に合わせてください。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/cmd.c` around lines 3205 - 3209, The branch handling extcmdlist lookup in
cmd.c is mismatched: it checks key2cmdbuf with STRNCMP2 against "接頭辞:" but still
calls strsubst with "prefix:", so the replacement never fires for this path.
Update the strsubst call in the same conditional block to use the same Japanese
prefix string as the matcher, and keep the reqmenu handling consistent with the
surrounding extcmdlist logic so the two-line display conversion runs correctly.
| #if 0 /*JP:T*/ | ||
| petname = "Slasher"; /* The Warrior */ | ||
| #else | ||
| petname = "スラッシャー"; | ||
| #endif | ||
| if (Role_if(PM_SAMURAI)) | ||
| #if 0 /*JP:T*/ | ||
| petname = "Hachi"; /* Shibuya Station */ | ||
| #else | ||
| petname = "ハチ公"; | ||
| #endif | ||
| if (Role_if(PM_BARBARIAN)) | ||
| #if 0 /*JP:T*/ | ||
| petname = "Idefix"; /* Obelix */ | ||
| #else | ||
| petname = "イデフィクス"; | ||
| #endif | ||
| if (Role_if(PM_RANGER)) | ||
| #if 0 /*JP:T*/ | ||
| petname = "Sirius"; /* Orion's dog */ | ||
| #else | ||
| petname = "シリウス"; | ||
| #endif |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win
単一行の独立変更には #if 0ブロックではなく単一行形式を使うべき
petname = "..." は各行とも1行で完結し、周囲から独立した変更です。コーディングガイドラインでは「原文・変更後コードがともに1行に収まり、変更が独立している場合は単一行置換形式 /*JP ... */ を使う」とされています。ここでは複数行を要する #if 0 /*JP:T*/ ... #else...#endif`` ブロックが使われており、規約と一致しません。
♻️ 修正例(1件目のみ抜粋)
if (Role_if(PM_CAVE_DWELLER))
-#if 0 /*JP:T*/
- petname = "Slasher"; /* The Warrior */
-#else
- petname = "スラッシャー";
-#endif
+/*JP
+ petname = "Slasher"; /* The Warrior */
+*/
+ petname = "スラッシャー";As per coding guidelines: "If the original and changed code each fit on a single line and the change is independent, use the single-line replacement form /*JP ... */ followed by the replacement line."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/dog.c` around lines 255 - 277, The petname assignments in the
Role_if(PM_SAMURAI), Role_if(PM_BARBARIAN), and Role_if(PM_RANGER) branches are
single-line independent changes, so replace the current `#if` 0 /*JP:T*/ ... `#else`
... `#endif` blocks in dog.c with the single-line JP replacement form using the
surrounding petname assignment lines as the anchor.
Source: Coding guidelines
5.0.0化する
Summary by CodeRabbit
New Features
Documentation
Bug Fixes