add base build system
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/dst/
|
62
Makefile
Normal file
62
Makefile
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
EMIT_ASSETS := index.html 404.html info.html \
|
||||||
|
styles.css icons.css \
|
||||||
|
countdown.js theme.js theme.js \
|
||||||
|
stallman.webp stallman_2024.webp
|
||||||
|
SEARCH_REPLACE := lib/search_and_replace/target/release/search_and_replace
|
||||||
|
COMPONENTS := head.html header.html nav.html footer.html
|
||||||
|
|
||||||
|
.PHONY: build
|
||||||
|
build: $(EMIT_ASSETS:%=dst/cz/%) $(EMIT_ASSETS:%=dst/en/%) dst/favicon.ico
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm -rf dst
|
||||||
|
|
||||||
|
$(SEARCH_REPLACE): $(shell find lib/search_and_replace/src)
|
||||||
|
cd lib/search_and_replace && cargo build --release
|
||||||
|
|
||||||
|
define make_page
|
||||||
|
cat $(1) | \
|
||||||
|
$(SEARCH_REPLACE) \
|
||||||
|
'<!--#include virtual="components/head.html" -->' "$$(cat components/$(3)/head.html)" \
|
||||||
|
'<!--#include virtual="components/header.html" -->' "$$(cat components/$(3)/header.html)" \
|
||||||
|
'<!--#include virtual="components/nav.html" -->' "$$(cat components/$(3)/nav.html)" \
|
||||||
|
'<!--#include virtual="components/footer.html" -->' "$$(cat components/$(3)/footer.html)" \
|
||||||
|
> $(2)
|
||||||
|
endef
|
||||||
|
|
||||||
|
dst/cz/%.html: cz_%.html $(SEARCH_REPLACE) $(COMPONENTS:%=components/cz/%)
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(call make_page,$<,$@,cz)
|
||||||
|
|
||||||
|
dst/cz/%.css: %.css
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ln -f $< $@
|
||||||
|
|
||||||
|
dst/cz/%.js: js/%.js
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ln -f $< $@
|
||||||
|
|
||||||
|
dst/cz/%.webp: images/%.jpg
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
magick $< $@
|
||||||
|
|
||||||
|
dst/en/%.html: en_%.html $(SEARCH_REPLACE) $(COMPONENTS:%=components/en/%)
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
$(call make_page,$<,$@,en)
|
||||||
|
|
||||||
|
dst/en/%.css: %.css
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ln -f $< $@
|
||||||
|
|
||||||
|
dst/en/%.js: js/%.js
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ln -f $< $@
|
||||||
|
|
||||||
|
dst/en/%.webp: images/%.jpg
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
magick $< $@
|
||||||
|
|
||||||
|
dst/favicon.ico: images/favicon.ico
|
||||||
|
@mkdir -p $(@D)
|
||||||
|
ln -f $< $@
|
@@ -1,5 +1,3 @@
|
|||||||
<footer>
|
<footer>
|
||||||
<!--#set var="URL" value="https://${HTTP_HOST}${DOCUMENT_URI}"-->
|
|
||||||
<p>Tato webová stránka podléhá licenci GNU Free Documentation License v1.3.</p>
|
<p>Tato webová stránka podléhá licenci GNU Free Documentation License v1.3.</p>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
@@ -4,5 +4,4 @@
|
|||||||
<link rel="icon" type="image/png" href="favicon.png">
|
<link rel="icon" type="image/png" href="favicon.png">
|
||||||
<link href="icons.css" rel="stylesheet">
|
<link href="icons.css" rel="stylesheet">
|
||||||
<link href="styles.css" rel="stylesheet">
|
<link href="styles.css" rel="stylesheet">
|
||||||
<script src="js/theme.js"></script>
|
<script src="theme.js"></script>
|
||||||
|
|
@@ -4,4 +4,3 @@
|
|||||||
<img src="data:," alt="Přepínač světlého a tmavého režimu" class="light-dark-switch" onclick="switch_theme();">
|
<img src="data:," alt="Přepínač světlého a tmavého režimu" class="light-dark-switch" onclick="switch_theme();">
|
||||||
<img src="data:," alt="Přepínač širokého a úzkého rozvržení" class="layout-switch" onclick="switch_layout();">
|
<img src="data:," alt="Přepínač širokého a úzkého rozvržení" class="layout-switch" onclick="switch_layout();">
|
||||||
</header>
|
</header>
|
||||||
|
|
@@ -6,4 +6,3 @@
|
|||||||
<li><a href="javascript">JavaScript</a></li>
|
<li><a href="javascript">JavaScript</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
3
components/en/footer.html
Normal file
3
components/en/footer.html
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<footer>
|
||||||
|
<p>This website falls under the GNU Free Documentation License v1.3.</p>
|
||||||
|
</footer>
|
7
components/en/head.html
Normal file
7
components/en/head.html
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="theme-color" content="darkred">
|
||||||
|
<link rel="icon" type="image/png" href="favicon.png">
|
||||||
|
<link href="icons.css" rel="stylesheet">
|
||||||
|
<link href="styles.css" rel="stylesheet">
|
||||||
|
<script src="theme.js"></script>
|
6
components/en/header.html
Normal file
6
components/en/header.html
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<header>
|
||||||
|
<div class="header-title">Software Libre Liberec</div>
|
||||||
|
<div class="header-subtitle">Richard Stallman at Technical University of Liberec</div>
|
||||||
|
<img src="data:," alt="Přepínač světlého a tmavého režimu" class="light-dark-switch" onclick="switch_theme();">
|
||||||
|
<img src="data:," alt="Přepínač širokého a úzkého rozvržení" class="layout-switch" onclick="switch_layout();">
|
||||||
|
</header>
|
8
components/en/nav.html
Normal file
8
components/en/nav.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<nav>
|
||||||
|
<ul>
|
||||||
|
<li><a href=".">Homepage</a></li>
|
||||||
|
<li><a href="stallman">Richard Stallman</a></li>
|
||||||
|
<li><a href="free">Software Libre</a></li>
|
||||||
|
<li><a href="javascript">JavaScript</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
@@ -15,4 +15,3 @@
|
|||||||
<!--#include virtual="components/footer.html" -->
|
<!--#include virtual="components/footer.html" -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@@ -17,7 +17,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<a href="https://commons.wikimedia.org/wiki/File:Richard_Stallman_Bologna_2024_abc23.jpg">
|
<a href="https://commons.wikimedia.org/wiki/File:Richard_Stallman_Bologna_2024_abc23.jpg">
|
||||||
<figure>
|
<figure>
|
||||||
<img class="countdown-bg" src="images/stallman_2024.jpg" alt="Pan Stallman v Itálii">
|
<img class="countdown-bg" src="stallman_2024.webp" alt="Pan Stallman v Itálii">
|
||||||
<figcaption>Snímek z přednášky pana Stallmana z roku 2024</figcaption>
|
<figcaption>Snímek z přednášky pana Stallmana z roku 2024</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
</a>
|
</a>
|
||||||
@@ -42,8 +42,7 @@
|
|||||||
a Free Software Foundation.
|
a Free Software Foundation.
|
||||||
</p>
|
</p>
|
||||||
</main>
|
</main>
|
||||||
<script src="js/countdown.js"></script>
|
<script src="countdown.js"></script>
|
||||||
<!--#include virtual="components/footer.html" -->
|
<!--#include virtual="components/footer.html" -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@@ -4,27 +4,17 @@
|
|||||||
<!--#include virtual="components/head.html" -->
|
<!--#include virtual="components/head.html" -->
|
||||||
<title>Richard Stallman - Svobodný software Liberec</title>
|
<title>Richard Stallman - Svobodný software Liberec</title>
|
||||||
<meta name="description" content="Krátký životopis pana Stallmana.">
|
<meta name="description" content="Krátký životopis pana Stallmana.">
|
||||||
<script src="js/lang.js"></script>
|
<script src="lang.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<!--#include virtual="components/header.html" -->
|
<!--#include virtual="components/header.html" -->
|
||||||
<!--#include virtual="components/nav.html" -->
|
<!--#include virtual="components/nav.html" -->
|
||||||
<main>
|
<main>
|
||||||
<p>
|
|
||||||
Tato stránka obsahuje překlad textu v angličtině,
|
|
||||||
který nám poskytl sám pan Stallman.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
<a href="javascript:change_lang('#stallman_bio');">Kliknutím zde</a>
|
|
||||||
si zobrazíte původní znění textu (či znovu překlad po opakovaném kliknutí).
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<h1>Kdo je Richard Stallman?</h1>
|
<h1>Kdo je Richard Stallman?</h1>
|
||||||
|
|
||||||
<a href="https://commons.wikimedia.org/wiki/File:Richard_Stallman_Bologna_2024_abc1.jpg">
|
<a href="https://commons.wikimedia.org/wiki/File:Richard_Stallman_Bologna_2024_abc1.jpg">
|
||||||
<figure class="aside">
|
<figure class="aside">
|
||||||
<img src="images/stallman.jpg" alt="Richard Stallman">
|
<img src="stallman.webp" alt="Richard Stallman">
|
||||||
<figcaption>Richard Stallman, 2024</figcaption>
|
<figcaption>Richard Stallman, 2024</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
</a>
|
</a>
|
||||||
@@ -55,35 +45,7 @@
|
|||||||
Zakladatel a vedoucí vývoje <a href="https://www.gnu.org/">operačního systému GNU</a>
|
Zakladatel a vedoucí vývoje <a href="https://www.gnu.org/">operačního systému GNU</a>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="stallman_bio_en" style="display: none">
|
|
||||||
<p>
|
|
||||||
Dr. Richard Stallman launched the free software movement in 1983 and
|
|
||||||
started the development of the GNU operating system
|
|
||||||
(see <a href="https://www.gnu.org">www.gnu.org</a>) in 1984.
|
|
||||||
GNU is free software: everyone has the freedom to copy it
|
|
||||||
and redistribute it, with or without changes. The GNU/Linux system,
|
|
||||||
basically the GNU operating system with <a href="https://kernel.org/">Linux</a>
|
|
||||||
as the kernel, is used on tens of millions of computers today.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Stallman has received the ACM Grace
|
|
||||||
Hopper Award and the ACM Software and Systems Award, a MacArthur
|
|
||||||
Foundation fellowship, the Electronic Frontier Foundation's Pioneer
|
|
||||||
Award, and the the Takeda Award for Social/Economic Betterment, as
|
|
||||||
well as many doctorates honoris causa, and has been inducted into the
|
|
||||||
<a href="https://www.internethalloffame.org/">Internet Hall of Fame</a>.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
Dr Richard Stallman<br>
|
|
||||||
Founder of the <a href="https://www.fsf.org/">Free Software Foundation</a><br>
|
|
||||||
Founder and development leader of the <a href="https://www.gnu.org/">GNU operating system</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</main>
|
</main>
|
||||||
<!--#include virtual="components/footer.html" -->
|
<!--#include virtual="components/footer.html" -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
17
en_404.html
Normal file
17
en_404.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="cs">
|
||||||
|
<head>
|
||||||
|
<!--#include virtual="components/head.html" -->
|
||||||
|
<title>Page not found - Software Libre Liberec</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!--#include virtual="components/header.html" -->
|
||||||
|
<!--#include virtual="components/nav.html" -->
|
||||||
|
<main style="text-align: center">
|
||||||
|
<h1>Page not found.</h1>
|
||||||
|
<p>You have attempted to load a page that does not exist on this server.</p>
|
||||||
|
<p>Please click on one of the links above.</p>
|
||||||
|
</main>
|
||||||
|
<!--#include virtual="components/footer.html" -->
|
||||||
|
</body>
|
||||||
|
</html>
|
48
en_index.html
Normal file
48
en_index.html
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="cs">
|
||||||
|
<head>
|
||||||
|
<!--#include virtual="components/head.html" -->
|
||||||
|
<title>Svobodný software Liberec</title>
|
||||||
|
<meta name="description" content="Richard Stallman at Technical University of Liberec.">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!--#include virtual="components/header.html" -->
|
||||||
|
<!--#include virtual="components/nav.html" -->
|
||||||
|
<main>
|
||||||
|
<h1>Richard Stallman on free software</h1>
|
||||||
|
|
||||||
|
<div class="img-text-container">
|
||||||
|
<div class="img-text">
|
||||||
|
<div class="countdown">--:--:--:--</div>
|
||||||
|
</div>
|
||||||
|
<a href="https://commons.wikimedia.org/wiki/File:Richard_Stallman_Bologna_2024_abc23.jpg">
|
||||||
|
<figure>
|
||||||
|
<img class="countdown-bg" src="stallman_2024.webp" alt="Pan Stallman v Itálii">
|
||||||
|
<figcaption>Photograph from Mr Stallman's lecture in 2024</figcaption>
|
||||||
|
</figure>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The event will happen on the <b>7th of may from 16:30 to 19:30</b> in the auditorium of building G at Technical University of Liberec.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The main part of the event will be a lecture by Mr. Richard Stallman on free software –
|
||||||
|
a movement that Mr. Stallman himself founded in 1983.
|
||||||
|
It will focus on the dangers of the constant proliferation of non-free software in our digital society,
|
||||||
|
how such software limits us as users, and how we can fight against it with free software.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
This event is organized by the Faculty of Mechatronics, Informatics and Interdisciplinary Studies
|
||||||
|
of the Technical University of Liberec. Like most of Mr. Stallman's lectures, this event
|
||||||
|
is intended for the general public. There will be a voluntary admission fee only,
|
||||||
|
after the lecture it will also be possible to purchase items with the theme of the GNU operating system
|
||||||
|
and the Free Software Foundation.
|
||||||
|
</p>
|
||||||
|
</main>
|
||||||
|
<script src="countdown.js"></script>
|
||||||
|
<!--#include virtual="components/footer.html" -->
|
||||||
|
</body>
|
||||||
|
</html>
|
51
en_info.html
Normal file
51
en_info.html
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="cs">
|
||||||
|
<head>
|
||||||
|
<!--#include virtual="components/head.html" -->
|
||||||
|
<title>Richard Stallman - Software Libre Liberec</title>
|
||||||
|
<meta name="description" content="Short bio of mister Stallman.">
|
||||||
|
<script src="lang.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!--#include virtual="components/header.html" -->
|
||||||
|
<!--#include virtual="components/nav.html" -->
|
||||||
|
<main>
|
||||||
|
<h1>Who is Richard Stallman?</h1>
|
||||||
|
|
||||||
|
<a href="https://commons.wikimedia.org/wiki/File:Richard_Stallman_Bologna_2024_abc1.jpg">
|
||||||
|
<figure class="aside">
|
||||||
|
<img src="stallman.webp" alt="Richard Stallman">
|
||||||
|
<figcaption>Richard Stallman, 2024</figcaption>
|
||||||
|
</figure>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div id="stallman_bio_en">
|
||||||
|
<p>
|
||||||
|
Dr. Richard Stallman launched the free software movement in 1983 and
|
||||||
|
started the development of the GNU operating system
|
||||||
|
(see <a href="https://www.gnu.org">www.gnu.org</a>) in 1984.
|
||||||
|
GNU is free software: everyone has the freedom to copy it
|
||||||
|
and redistribute it, with or without changes. The GNU/Linux system,
|
||||||
|
basically the GNU operating system with <a href="https://kernel.org/">Linux</a>
|
||||||
|
as the kernel, is used on tens of millions of computers today.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Stallman has received the ACM Grace
|
||||||
|
Hopper Award and the ACM Software and Systems Award, a MacArthur
|
||||||
|
Foundation fellowship, the Electronic Frontier Foundation's Pioneer
|
||||||
|
Award, and the the Takeda Award for Social/Economic Betterment, as
|
||||||
|
well as many doctorates honoris causa, and has been inducted into the
|
||||||
|
<a href="https://www.internethalloffame.org/">Internet Hall of Fame</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Dr Richard Stallman<br>
|
||||||
|
Founder of the <a href="https://www.fsf.org/">Free Software Foundation</a><br>
|
||||||
|
Founder and development leader of the <a href="https://www.gnu.org/">GNU operating system</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<!--#include virtual="components/footer.html" -->
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
favicon.png
BIN
favicon.png
Binary file not shown.
Before Width: | Height: | Size: 185 B |
@@ -129,4 +129,3 @@
|
|||||||
<!--#include virtual="components/footer.html" -->
|
<!--#include virtual="components/footer.html" -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
BIN
images/favicon.ico
Normal file
BIN
images/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 198 B |
@@ -54,4 +54,3 @@
|
|||||||
<!--#include virtual="components/footer.html" -->
|
<!--#include virtual="components/footer.html" -->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
1
lib/search_and_replace/.gitignore
vendored
Normal file
1
lib/search_and_replace/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
target/
|
7
lib/search_and_replace/Cargo.lock
generated
Normal file
7
lib/search_and_replace/Cargo.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "search_and_replace"
|
||||||
|
version = "0.1.0"
|
9
lib/search_and_replace/Cargo.toml
Normal file
9
lib/search_and_replace/Cargo.toml
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
[package]
|
||||||
|
name = "search_and_replace"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
strip = true
|
||||||
|
|
||||||
|
[dependencies]
|
371
lib/search_and_replace/src/main.rs
Normal file
371
lib/search_and_replace/src/main.rs
Normal file
@@ -0,0 +1,371 @@
|
|||||||
|
use std::{env::args, io::Read};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct JumpTable {
|
||||||
|
jumps: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JumpTable {
|
||||||
|
fn resolve_char(
|
||||||
|
pat: &Vec<char>,
|
||||||
|
ptr: &usize,
|
||||||
|
cur_char: &char,
|
||||||
|
) -> usize {
|
||||||
|
if pat.get(*ptr).unwrap() == cur_char {
|
||||||
|
return *ptr + 1;
|
||||||
|
}
|
||||||
|
if pat.get(0).unwrap() == cur_char {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(pat: &Vec<char>) -> Self {
|
||||||
|
if pat.len() == 0 {
|
||||||
|
return Self { jumps: vec![] };
|
||||||
|
}
|
||||||
|
let mut ptr = 0_usize;
|
||||||
|
let mut jumps = vec![0];
|
||||||
|
for cur_char in pat.iter().skip(1) {
|
||||||
|
ptr = JumpTable::resolve_char(pat, &ptr, cur_char);
|
||||||
|
jumps.push(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Self { jumps }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn search(&self, pat: &Vec<char>, needle: &char, ptr: &usize) -> usize {
|
||||||
|
let mut ptr = *ptr;
|
||||||
|
while ptr != 0 {
|
||||||
|
if pat.get(ptr).unwrap() == needle {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr = *self.jumps.get(ptr.saturating_sub(1)).unwrap();
|
||||||
|
}
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
struct Pattern {
|
||||||
|
pat: Vec<char>,
|
||||||
|
jt: JumpTable,
|
||||||
|
ptr: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Pattern {
|
||||||
|
pub fn new(pat: String) -> Result<Self, ()> {
|
||||||
|
if pat.len() == 0 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
let pat = pat.chars().collect::<Vec<_>>();
|
||||||
|
let jt = JumpTable::new(&pat);
|
||||||
|
Ok(Self {
|
||||||
|
pat,
|
||||||
|
jt,
|
||||||
|
ptr: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn search_and_update(&mut self, cur_char: &char) -> bool {
|
||||||
|
if self.pat.get(self.ptr).unwrap() == cur_char {
|
||||||
|
self.ptr += 1;
|
||||||
|
return if self.ptr == self.pat.len() { true } else { false };
|
||||||
|
}
|
||||||
|
let found = self.jt.search(&self.pat, &cur_char, &self.ptr);
|
||||||
|
self.ptr = found;
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reset_ptr(&mut self) {
|
||||||
|
self.ptr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.pat.len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
struct Match {
|
||||||
|
pub pat_id: usize,
|
||||||
|
pub start_pos: usize,
|
||||||
|
pub len: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Match {
|
||||||
|
pub fn new(pat_id: usize, start_pos: usize, len: usize) -> Self {
|
||||||
|
Self { pat_id, start_pos, len }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct MPSearch {
|
||||||
|
pats: Vec<Pattern>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MPSearch {
|
||||||
|
pub fn new(pats: Vec<Pattern>) -> Self {
|
||||||
|
Self { pats }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reset_all_ptrs(&mut self) {
|
||||||
|
for pat in self.pats.iter_mut() {
|
||||||
|
pat.reset_ptr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search_at_pos(&mut self, cur_char: &char, pos: &usize) -> Option<Match> {
|
||||||
|
let mut cur_match = None;
|
||||||
|
for (idx, pat) in self.pats.iter_mut().enumerate() {
|
||||||
|
if pat.search_and_update(cur_char) {
|
||||||
|
cur_match = Some(Match::new(idx, pos.saturating_sub(pat.len() - 1), pat.len()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(_) = cur_match {
|
||||||
|
self.reset_all_ptrs();
|
||||||
|
}
|
||||||
|
cur_match
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn search(&mut self, haystack: &String) -> Vec<Match> {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
for (cur_idx, cur_char) in haystack.chars().enumerate() {
|
||||||
|
if let Some(cur_match) = self.search_at_pos(&cur_char, &cur_idx) {
|
||||||
|
res.push(cur_match);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! skip_n {
|
||||||
|
($iter: ident, $n: expr) => {
|
||||||
|
for _ in 0..$n {
|
||||||
|
$iter.next().ok_or(())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! append_n {
|
||||||
|
($iter: ident, $target: ident, $n: expr) => {
|
||||||
|
for _ in 0..$n {
|
||||||
|
$target.push($iter.next().ok_or(())?);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct MPReplace {
|
||||||
|
replacements: Vec<String>,
|
||||||
|
matches: Vec<Match>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MPReplace {
|
||||||
|
pub fn new(matches: Vec<Match>, replacements: Vec<String>) -> Self {
|
||||||
|
Self { replacements, matches }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn replace(&self, target: &String) -> Result<String, ()> {
|
||||||
|
let mut ptr = 0;
|
||||||
|
let mut iter = target.chars();
|
||||||
|
let mut res = String::new();
|
||||||
|
for cur_match in self.matches.iter() {
|
||||||
|
append_n!(iter, res, cur_match.start_pos - ptr);
|
||||||
|
skip_n!(iter, cur_match.len);
|
||||||
|
res.push_str(self.replacements.get(cur_match.pat_id).ok_or(())?);
|
||||||
|
ptr = cur_match.start_pos + cur_match.len;
|
||||||
|
}
|
||||||
|
append_n!(iter, res, target.chars().count() - ptr);
|
||||||
|
Ok(res)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PatMatchArgs<I: Iterator<Item = String>> {
|
||||||
|
inner: I,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = String>> PatMatchArgs<I> {
|
||||||
|
pub fn new(inner: I, count: usize) -> Result<Self, ()> {
|
||||||
|
if count % 2 != 0 {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
Ok(Self { inner })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<I: Iterator<Item = String>> Iterator for PatMatchArgs<I> {
|
||||||
|
type Item = (String, String);
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
Some((self.inner.next()?, self.inner.next()?))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let mut contents = Vec::new();
|
||||||
|
std::io::stdin().lock().read_to_end(&mut contents).unwrap();
|
||||||
|
let contents = std::str::from_utf8(&contents).unwrap().to_string();
|
||||||
|
|
||||||
|
let args = match PatMatchArgs::new(args().skip(1), args().len() - 1) {
|
||||||
|
Ok(val) => val,
|
||||||
|
Err(()) => {
|
||||||
|
eprintln!("the number of arguments after filepath must be divisible by two");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut pats = Vec::new();
|
||||||
|
let mut replacements = Vec::new();
|
||||||
|
for (cur_pat, cur_replacement) in args {
|
||||||
|
let Ok(cur_pat) = Pattern::new(cur_pat) else {
|
||||||
|
eprintln!("the patterns can't be empty");
|
||||||
|
std::process::exit(1);
|
||||||
|
};
|
||||||
|
pats.push(cur_pat);
|
||||||
|
replacements.push(cur_replacement);
|
||||||
|
}
|
||||||
|
|
||||||
|
let matches = MPSearch::new(pats).search(&contents);
|
||||||
|
let replaced = MPReplace::new(matches, replacements)
|
||||||
|
.replace(&contents).unwrap();
|
||||||
|
println!("{}", replaced);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::{JumpTable, MPReplace, MPSearch, Match, Pattern};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn jumps_01() {
|
||||||
|
let src = String::from("thisthen").chars().collect::<Vec<_>>();
|
||||||
|
let target = vec![0_usize, 0, 0, 0, 1, 2, 0, 0];
|
||||||
|
let jt = JumpTable::new(&src);
|
||||||
|
assert_eq!(jt.jumps, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn jumps_02() {
|
||||||
|
let src = String::from("tthis").chars().collect::<Vec<_>>();
|
||||||
|
let target = vec![0, 1, 0, 0, 0];
|
||||||
|
let jt = JumpTable::new(&src);
|
||||||
|
assert_eq!(jt.jumps, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn jumps_03() {
|
||||||
|
let src = String::from("t").chars().collect::<Vec<_>>();
|
||||||
|
let target = vec![0];
|
||||||
|
let jt = JumpTable::new(&src);
|
||||||
|
assert_eq!(jt.jumps, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn jumps_04() {
|
||||||
|
let src = String::from("tt").chars().collect::<Vec<_>>();
|
||||||
|
let target = vec![0, 1];
|
||||||
|
let jt = JumpTable::new(&src);
|
||||||
|
assert_eq!(jt.jumps, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn jumps_05() {
|
||||||
|
let src = String::from("").chars().collect::<Vec<_>>();
|
||||||
|
let target = vec![];
|
||||||
|
let jt = JumpTable::new(&src);
|
||||||
|
assert_eq!(jt.jumps, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn search_01() {
|
||||||
|
let pat = String::from("tthis").chars().collect::<Vec<_>>();
|
||||||
|
let jt = JumpTable::new(&pat);
|
||||||
|
assert_eq!(jt.search(&pat, &'t', &1), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn search_02() {
|
||||||
|
let pat = String::from("testtesa").chars().collect::<Vec<_>>();
|
||||||
|
let jt = JumpTable::new(&pat);
|
||||||
|
assert_eq!(jt.search(&pat, &'t', &7), 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn search_03() {
|
||||||
|
let pat = String::from("ahojahoj").chars().collect::<Vec<_>>();
|
||||||
|
let jt = JumpTable::new(&pat);
|
||||||
|
assert_eq!(jt.search(&pat, &'j', &7), 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn search_04() {
|
||||||
|
let pat = String::from("ahojahoj").chars().collect::<Vec<_>>();
|
||||||
|
let jt = JumpTable::new(&pat);
|
||||||
|
assert_eq!(jt.search(&pat, &'j', &7), 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn search_05() {
|
||||||
|
let pat = String::from("jojojojojojoja").chars().collect::<Vec<_>>();
|
||||||
|
let jt = JumpTable::new(&pat);
|
||||||
|
assert_eq!(jt.search(&pat, &'o', &13), 11);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn search_and_update_01() {
|
||||||
|
let pat = String::from("test");
|
||||||
|
let mut pat = Pattern::new(pat).unwrap();
|
||||||
|
let haystack = String::from("thisisatest");
|
||||||
|
for cur_haystack in haystack.chars().take(haystack.len() - 1) {
|
||||||
|
assert_eq!(pat.search_and_update(&cur_haystack), false);
|
||||||
|
println!("{:?}", pat);
|
||||||
|
}
|
||||||
|
println!("{:?}", pat);
|
||||||
|
assert_eq!(pat.search_and_update(&'t'), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn empty_pattern() {
|
||||||
|
assert_eq!(Pattern::new("".chars().collect()), Err(()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mpsearch_01() {
|
||||||
|
let mut mpsearch = MPSearch::new(
|
||||||
|
vec!["this", "is", "a", "test"]
|
||||||
|
.iter()
|
||||||
|
.map(|p| Pattern::new(p.to_string()).unwrap())
|
||||||
|
.collect()
|
||||||
|
);
|
||||||
|
println!("{:?}", mpsearch);
|
||||||
|
let haystack = String::from("this is a test");
|
||||||
|
let target = vec![
|
||||||
|
Match::new(0, 0, 4),
|
||||||
|
Match::new(1, 5, 2),
|
||||||
|
Match::new(2, 8, 1),
|
||||||
|
Match::new(3, 10, 4)
|
||||||
|
];
|
||||||
|
assert_eq!(mpsearch.search(&haystack), target);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mpreplace_01() {
|
||||||
|
let mut mpsearch = MPSearch::new(
|
||||||
|
vec!["this", "is", "a", "test"]
|
||||||
|
.iter()
|
||||||
|
.map(|p| Pattern::new(p.to_string()).unwrap())
|
||||||
|
.collect()
|
||||||
|
);
|
||||||
|
let haystack = String::from("this-is.a*test///");
|
||||||
|
let matches = mpsearch.search(&haystack);
|
||||||
|
let mpreplace = MPReplace::new(matches, vec![
|
||||||
|
"that".to_string(),
|
||||||
|
"isn't".to_string(),
|
||||||
|
"the".to_string(),
|
||||||
|
"final".to_string(),
|
||||||
|
]);
|
||||||
|
let replaced = mpreplace.replace(&haystack).unwrap();
|
||||||
|
assert_eq!(replaced, "that-isn't.the*final///");
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user