mirror of
https://codeberg.org/icewind/tf-log-parser.git
synced 2026-06-03 18:24:09 +02:00
quote in name handling somewhat
This commit is contained in:
parent
484fd735d1
commit
de2e940974
5 changed files with 81 additions and 9 deletions
|
|
@ -21,6 +21,8 @@ memchr = "2.5.0"
|
|||
ahash = "0.8.3"
|
||||
tf-log-parser-derive = { version = "0.1", path = "./derive" }
|
||||
miette = "5.5.0"
|
||||
walkdir = "2.3.2"
|
||||
once_cell = "1.17.1"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.4"
|
||||
|
|
|
|||
28
examples/dir.rs
Normal file
28
examples/dir.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
use main_error::MainError;
|
||||
use std::env::args;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
use tf_log_parser::parse;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
fn main() -> Result<(), MainError> {
|
||||
let path = args().nth(1).expect("No path provided");
|
||||
for entry in WalkDir::new(path) {
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.extension() == Some(OsStr::new("log")) {
|
||||
print!("{} - ", path.display());
|
||||
let input = match fs::read_to_string(path) {
|
||||
Ok(input) => input,
|
||||
Err(e) => {
|
||||
println!("failed to read file: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let (output, _) = parse(&input)?;
|
||||
println!("{} messages", output.chat.len());
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ mod medic;
|
|||
mod player;
|
||||
|
||||
use crate::event::game::{RoundLengthEvent, RoundWinEvent};
|
||||
use crate::parsing::{skip, skip_matches, split_once};
|
||||
use crate::parsing::{skip, skip_matches, split_once, split_subject_end};
|
||||
use crate::raw_event::{against_subject_parser, RawSubject};
|
||||
use crate::{Error, Events, IResult, RawEvent, RawEventType, Result, SubjectId};
|
||||
pub use game::*;
|
||||
|
|
@ -15,7 +15,7 @@ use std::str::FromStr;
|
|||
|
||||
#[derive(thiserror::Error, Debug)]
|
||||
pub enum GameEventError {
|
||||
#[error("malformed game event({ty:?}): {err}")]
|
||||
#[error("malformed game event({ty:?}): {err} in \"{params}\"")]
|
||||
Error {
|
||||
err: Box<Error>,
|
||||
ty: RawEventType,
|
||||
|
|
@ -167,7 +167,12 @@ pub fn param_parse_with<'a, T, P: Fn(&'a str) -> Result<T>>(
|
|||
|
||||
let input = skip(input, key.len() + 2)?; // skip space + key + quote
|
||||
|
||||
let (value, input) = split_once(input, b'"', 1)?;
|
||||
// hack to handle quotes in names
|
||||
let (value, input) = if key == "against" || key == "objectowner" {
|
||||
split_subject_end(input, 1)?
|
||||
} else {
|
||||
split_once(input, b'"', 1)?
|
||||
};
|
||||
|
||||
let value = parser(value)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
use crate::{Error, Result};
|
||||
use memchr::memmem::Finder;
|
||||
use memchr::{memchr, memrchr};
|
||||
use once_cell::unsync::Lazy;
|
||||
|
||||
pub fn split_once(input: &str, delim: u8, offset: usize) -> Result<(&str, &str)> {
|
||||
debug_assert!(delim < 128); // only basic ascii
|
||||
|
|
@ -13,6 +15,25 @@ pub fn split_once(input: &str, delim: u8, offset: usize) -> Result<(&str, &str)>
|
|||
})
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static SUBJECT_END_FINDER: Lazy<Finder<'static>> = Lazy::new(|| Finder::new(br#">""#));
|
||||
}
|
||||
|
||||
pub fn split_subject_end<'a>(input: &'a str, offset: usize) -> Result<(&'a str, &'a str)> {
|
||||
let start_offset = 1;
|
||||
let end_offset = start_offset + offset;
|
||||
let end = SUBJECT_END_FINDER
|
||||
.with(|finder| finder.find(input.as_bytes()))
|
||||
.ok_or(Error::Incomplete)?;
|
||||
// safety, memchr returns indices that are inside the input length and we only split on ascii
|
||||
Ok(unsafe {
|
||||
(
|
||||
input.get_unchecked(..end + start_offset),
|
||||
input.get_unchecked(end + end_offset..),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn take_until(input: &str, delim: u8) -> (&str, &str) {
|
||||
debug_assert!(delim < 128); // only basic ascii
|
||||
if let Some(end) = memchr(delim, input.as_bytes()) {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
use crate::common::Team;
|
||||
use crate::parsing::split_once;
|
||||
use crate::parsing::{split_once, split_subject_end};
|
||||
use crate::{Error, Result};
|
||||
use crate::{SubjectError, SubjectId};
|
||||
use chrono::{NaiveDate, NaiveDateTime};
|
||||
|
|
@ -120,7 +120,7 @@ fn test_split_player_subject() {
|
|||
|
||||
pub fn against_subject_parser(input: &str) -> Result<RawSubject> {
|
||||
// "against" fields are always players, and unquoted
|
||||
if input.ends_with("e>") {
|
||||
if input.ends_with("le>") {
|
||||
Ok(RawSubject::Console)
|
||||
} else {
|
||||
Ok(RawSubject::Player(input))
|
||||
|
|
@ -128,9 +128,12 @@ pub fn against_subject_parser(input: &str) -> Result<RawSubject> {
|
|||
}
|
||||
|
||||
pub fn subject_parser(input: &str) -> Result<(&str, RawSubject)> {
|
||||
let full = input;
|
||||
if let Some(input) = input.strip_prefix('"') {
|
||||
let (player, input) = split_once(input, b'"', 1)?;
|
||||
if player.ends_with("e>") {
|
||||
let Ok((player, input)) = split_subject_end(input, 1) else {
|
||||
return Ok((full, RawSubject::Console))
|
||||
};
|
||||
if player.ends_with("le>") {
|
||||
Ok((input, RawSubject::Console))
|
||||
} else {
|
||||
Ok((input, RawSubject::Player(player)))
|
||||
|
|
@ -151,6 +154,17 @@ pub fn subject_parser(input: &str) -> Result<(&str, RawSubject)> {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_subject_parser() {
|
||||
assert_eq!(
|
||||
(
|
||||
"connected",
|
||||
RawSubject::Player(r#"Buddie :")<25><[U:1:123]><>"#)
|
||||
),
|
||||
subject_parser(r#""Buddie :")<25><[U:1:123]><>" connected"#).unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Logos)]
|
||||
pub enum RawEventType {
|
||||
#[token(r#"joined"#)]
|
||||
|
|
@ -194,9 +208,9 @@ pub enum RawEventType {
|
|||
#[token(r#"triggered "killedobject""#)]
|
||||
KilledObject,
|
||||
#[token(r#"triggered "object_detonated""#)]
|
||||
Extinguished,
|
||||
#[token(r#"triggered "player_extinguished""#)]
|
||||
ObjectDetonated,
|
||||
#[token(r#"triggered "player_extinguished""#)]
|
||||
Extinguished,
|
||||
#[token(r#"picked up"#)]
|
||||
PickedUp,
|
||||
#[token(r#"triggered "medic_death""#)]
|
||||
|
|
@ -269,6 +283,8 @@ pub enum RawEventType {
|
|||
TournamentModeStarted,
|
||||
#[token(r#"triggered "flagevent""#)]
|
||||
FlagEvent,
|
||||
#[token(r#"cvars"#)]
|
||||
CVars,
|
||||
#[error]
|
||||
Unknown,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue