Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 34 additions & 45 deletions room/src/doom/d_iwad.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,17 +38,6 @@ const DIR_SEPARATOR: c_char = b'/' as c_char;
/// C string-joining functions.
const DIR_SEPARATOR_S: &[u8] = b"/\0";

/// Convenience macro that appends a null terminator to a string literal and
/// returns a `*mut c_char` pointer to it.
///
/// The resulting pointer points into the program's read-only data segment;
/// callers must never write through it.
macro_rules! cstr {
($s:literal) => {
concat!($s, "\0").as_ptr() as *mut c_char
};
}

extern "C" {
/// C standard `printf`; used to emit diagnostic messages during IWAD
/// search.
Expand Down Expand Up @@ -114,88 +103,88 @@ unsafe impl Sync for iwad_t {}
/// shareware releases. Mirrors `iwads[]` in `d_iwad.c`.
static IWADS: [iwad_t; 14] = [
iwad_t {
name: cstr!("doom2.wad"),
name: c"doom2.wad".as_ptr().cast_mut(),
mission: d_mode::doom2,
mode: d_mode::commercial,
description: cstr!("Doom II"),
description: c"Doom II".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("plutonia.wad"),
name: c"plutonia.wad".as_ptr().cast_mut(),
mission: d_mode::pack_plut,
mode: d_mode::commercial,
description: cstr!("Final Doom: Plutonia Experiment"),
description: c"Final Doom: Plutonia Experiment".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("tnt.wad"),
name: c"tnt.wad".as_ptr().cast_mut(),
mission: d_mode::pack_tnt,
mode: d_mode::commercial,
description: cstr!("Final Doom: TNT: Evilution"),
description: c"Final Doom: TNT: Evilution".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("doom.wad"),
name: c"doom.wad".as_ptr().cast_mut(),
mission: d_mode::doom,
mode: d_mode::retail,
description: cstr!("Doom"),
description: c"Doom".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("doom1.wad"),
name: c"doom1.wad".as_ptr().cast_mut(),
mission: d_mode::doom,
mode: d_mode::shareware,
description: cstr!("Doom Shareware"),
description: c"Doom Shareware".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("chex.wad"),
name: c"chex.wad".as_ptr().cast_mut(),
mission: d_mode::pack_chex,
mode: d_mode::shareware,
description: cstr!("Chex Quest"),
description: c"Chex Quest".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("hacx.wad"),
name: c"hacx.wad".as_ptr().cast_mut(),
mission: d_mode::pack_hacx,
mode: d_mode::commercial,
description: cstr!("Hacx"),
description: c"Hacx".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("freedm.wad"),
name: c"freedm.wad".as_ptr().cast_mut(),
mission: d_mode::doom2,
mode: d_mode::commercial,
description: cstr!("FreeDM"),
description: c"FreeDM".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("freedoom2.wad"),
name: c"freedoom2.wad".as_ptr().cast_mut(),
mission: d_mode::doom2,
mode: d_mode::commercial,
description: cstr!("Freedoom: Phase 2"),
description: c"Freedoom: Phase 2".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("freedoom1.wad"),
name: c"freedoom1.wad".as_ptr().cast_mut(),
mission: d_mode::doom,
mode: d_mode::retail,
description: cstr!("Freedoom: Phase 1"),
description: c"Freedoom: Phase 1".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("heretic.wad"),
name: c"heretic.wad".as_ptr().cast_mut(),
mission: d_mode::heretic,
mode: d_mode::retail,
description: cstr!("Heretic"),
description: c"Heretic".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("heretic1.wad"),
name: c"heretic1.wad".as_ptr().cast_mut(),
mission: d_mode::heretic,
mode: d_mode::shareware,
description: cstr!("Heretic Shareware"),
description: c"Heretic Shareware".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("hexen.wad"),
name: c"hexen.wad".as_ptr().cast_mut(),
mission: d_mode::hexen,
mode: d_mode::commercial,
description: cstr!("Hexen"),
description: c"Hexen".as_ptr().cast_mut(),
},
iwad_t {
name: cstr!("strife1.wad"),
name: c"strife1.wad".as_ptr().cast_mut(),
mission: d_mode::strife,
mode: d_mode::commercial,
description: cstr!("Strife"),
description: c"Strife".as_ptr().cast_mut(),
},
];

Expand Down Expand Up @@ -281,7 +270,7 @@ unsafe fn CheckDirectoryHasIWAD(dir: *mut c_char, iwadname: *mut c_char) -> *mut
return strdup(dir);
}

let filename = if strcmp(dir, cstr!(".")) == 0 {
let filename = if strcmp(dir, c".".as_ptr()) == 0 {
strdup(iwadname)
} else {
let strs: [*const c_char; 4] = [
Expand Down Expand Up @@ -386,7 +375,7 @@ unsafe fn IdentifyIWADByName(mut name: *mut c_char, mask: c_int) -> c_int {
/// `iwad_dirs_built` without synchronisation, and calls `AddIWADDir` which
/// imposes the same requirement.
unsafe fn BuildIWADDirList() {
AddIWADDir(cstr!("."));
AddIWADDir(c".".as_ptr().cast_mut());
iwad_dirs_built = true;
}

Expand Down Expand Up @@ -471,7 +460,7 @@ pub unsafe extern "C" fn D_TryFindWADByName(filename: *mut c_char) -> *mut c_cha
/// `mission` must be a valid, non-null pointer.
#[no_mangle]
pub unsafe extern "C" fn D_FindIWAD(mask: c_int, mission: *mut c_int) -> *mut c_char {
let iwadparm = M_CheckParmWithArgs(cstr!("-iwad"), 1);
let iwadparm = M_CheckParmWithArgs(c"-iwad".as_ptr(), 1);

if iwadparm != 0 {
let iwadfile = *myargv.offset((iwadparm + 1) as isize);
Expand Down Expand Up @@ -554,7 +543,7 @@ pub unsafe extern "C" fn D_SaveGameIWADName(gamemission: c_int) -> *mut c_char {
return IWADS[i].name;
}
}
cstr!("unknown.wad")
c"unknown.wad".as_ptr().cast_mut()
}

/// Returns the canonical IWAD filename that best matches `mission` and `mode`.
Expand All @@ -570,7 +559,7 @@ pub unsafe extern "C" fn D_SuggestIWADName(mission: c_int, mode: c_int) -> *mut
return IWADS[i].name;
}
}
cstr!("unknown.wad")
c"unknown.wad".as_ptr().cast_mut()
}

/// Returns a human-readable game name for the given `mission` and `mode`.
Expand All @@ -587,7 +576,7 @@ pub unsafe extern "C" fn D_SuggestGameName(mission: c_int, mode: c_int) -> *mut
return IWADS[i].description;
}
}
cstr!("Unknown game?")
c"Unknown game?".as_ptr().cast_mut()
}

/// Validates that the loaded IWAD matches the expected `_mission`.
Expand Down
30 changes: 10 additions & 20 deletions room/src/doom/d_mode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -486,16 +486,6 @@ pub extern "C" fn D_IsEpisodeMap(mission: c_int) -> Boolean {
}
}

/// Convenience macro to produce a `*mut c_char` from a string literal.
///
/// Appends a NUL terminator and casts the resulting static byte slice to a raw
/// `c_char` pointer. Used only within [`D_GameMissionString`].
macro_rules! cstr {
($s:literal) => {
concat!($s, "\0").as_ptr() as *mut c_char
};
}

/// Return a NUL-terminated C string naming the given mission.
///
/// Returns one of `"doom"`, `"doom2"`, `"tnt"`, `"plutonia"`, `"hacx"`,
Expand All @@ -512,16 +502,16 @@ macro_rules! cstr {
#[no_mangle]
pub extern "C" fn D_GameMissionString(mission: c_int) -> *mut c_char {
match mission {
doom => cstr!("doom"),
doom2 => cstr!("doom2"),
pack_tnt => cstr!("tnt"),
pack_plut => cstr!("plutonia"),
pack_hacx => cstr!("hacx"),
pack_chex => cstr!("chex"),
heretic => cstr!("heretic"),
hexen => cstr!("hexen"),
strife => cstr!("strife"),
_ => cstr!("none"),
doom => c"doom".as_ptr().cast_mut(),
doom2 => c"doom2".as_ptr().cast_mut(),
pack_tnt => c"tnt".as_ptr().cast_mut(),
pack_plut => c"plutonia".as_ptr().cast_mut(),
pack_hacx => c"hacx".as_ptr().cast_mut(),
pack_chex => c"chex".as_ptr().cast_mut(),
heretic => c"heretic".as_ptr().cast_mut(),
hexen => c"hexen".as_ptr().cast_mut(),
strife => c"strife".as_ptr().cast_mut(),
_ => c"none".as_ptr().cast_mut(),
}
}

Expand Down
48 changes: 18 additions & 30 deletions room/src/doom/dstrings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
//! `Sync` by default, even though the pointers here only ever point at
//! immutable `'static` data.
//!
//! The `cstr!` macro appends `"\0"` at compile time and casts the resulting
//! `&str` to `*const c_char`, producing a valid NUL-terminated C string from
//! a Rust string literal without any heap allocation.
//! C string literals (`c"..."`) provide static NUL-terminated pointers without
//! heap allocation.
//!
//! The engine selects a message from these tables at random when the player
//! attempts to quit, using `gamemission` to pick the correct table
Expand Down Expand Up @@ -42,17 +41,6 @@ impl Ptr {
}
}

/// Construct a [`Ptr`] pointing to a NUL-terminated C string from a string literal.
///
/// The macro concatenates `"\0"` onto the literal at compile time, then casts
/// the `&'static str` data pointer to `*const c_char`. No heap allocation
/// occurs; the string resides in the binary's read-only data segment.
macro_rules! cstr {
($s:literal) => {
Ptr(concat!($s, "\0").as_ptr() as *const c_char)
};
}

/// Eight randomised quit messages shown when a Doom 1 player tries to exit.
///
/// Corresponds to `char *doom1_endmsg[]` in `dstrings.c`. The game picks
Expand All @@ -61,14 +49,14 @@ macro_rules! cstr {
/// equivalent) to access the table by its original symbol name.
#[no_mangle]
pub static doom1_endmsg: [Ptr; 8] = [
cstr!("are you sure you want to\nquit this great game?"),
cstr!("please don't leave, there's more\ndemons to toast!"),
cstr!("let's beat it -- this is turning\ninto a bloodbath!"),
cstr!("i wouldn't leave if i were you.\ndos is much worse."),
cstr!("you're trying to say you like dos\nbetter than me, right?"),
cstr!("don't leave yet -- there's a\ndemon around that corner!"),
cstr!("ya know, next time you come in here\ni'm gonna toast ya."),
cstr!("go ahead and leave. see if i care."),
Ptr(c"are you sure you want to\nquit this great game?".as_ptr()),
Ptr(c"please don't leave, there's more\ndemons to toast!".as_ptr()),
Ptr(c"let's beat it -- this is turning\ninto a bloodbath!".as_ptr()),
Ptr(c"i wouldn't leave if i were you.\ndos is much worse.".as_ptr()),
Ptr(c"you're trying to say you like dos\nbetter than me, right?".as_ptr()),
Ptr(c"don't leave yet -- there's a\ndemon around that corner!".as_ptr()),
Ptr(c"ya know, next time you come in here\ni'm gonna toast ya.".as_ptr()),
Ptr(c"go ahead and leave. see if i care.".as_ptr()),
];

/// Eight randomised quit messages shown when a Doom 2 player tries to exit.
Expand All @@ -78,14 +66,14 @@ pub static doom1_endmsg: [Ptr; 8] = [
/// `gamemission` is `doom2`, `pack_tnt`, or `pack_plut`.
#[no_mangle]
pub static doom2_endmsg: [Ptr; 8] = [
cstr!("are you sure you want to\nquit this great game?"),
cstr!("you want to quit?\nthen, thou hast lost an eighth!"),
cstr!("don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!"),
cstr!("get outta here and go back\nto your boring programs."),
cstr!("if i were your boss, i'd \n deathmatch ya in a minute!"),
cstr!("look, bud. you leave now\nand you forfeit your body count!"),
cstr!("just leave. when you come\nback, i'll be waiting with a bat."),
cstr!("you're lucky i don't smack\nyou for thinking about leaving."),
Ptr(c"are you sure you want to\nquit this great game?".as_ptr()),
Ptr(c"you want to quit?\nthen, thou hast lost an eighth!".as_ptr()),
Ptr(c"don't go now, there's a \ndimensional shambler waiting\nat the dos prompt!".as_ptr()),
Ptr(c"get outta here and go back\nto your boring programs.".as_ptr()),
Ptr(c"if i were your boss, i'd \n deathmatch ya in a minute!".as_ptr()),
Ptr(c"look, bud. you leave now\nand you forfeit your body count!".as_ptr()),
Ptr(c"just leave. when you come\nback, i'll be waiting with a bat.".as_ptr()),
Ptr(c"you're lucky i don't smack\nyou for thinking about leaving.".as_ptr()),
];

#[cfg(test)]
Expand Down
Loading