more porting

This commit is contained in:
chayleaf 2024-08-14 20:01:37 +07:00
parent 30e7205ebf
commit aac6c64779
Signed by: chayleaf
GPG key ID: 78171AD46227E68E
4 changed files with 703 additions and 203 deletions

329
Cargo.lock generated
View file

@ -47,7 +47,7 @@ version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
dependencies = [ dependencies = [
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -57,9 +57,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]]
name = "arrayvec"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.3.0" version = "1.3.0"
@ -72,6 +78,19 @@ version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "brush-parser"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98bbbd29d06a11b0819fd28f076633bdb6e9943777fe0ed61201b283e7523f20"
dependencies = [
"indenter",
"peg",
"thiserror",
"tracing",
"utf8-chars",
]
[[package]] [[package]]
name = "build-env" name = "build-env"
version = "0.3.1" version = "0.3.1"
@ -90,12 +109,39 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cfg_aliases"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
version = "1.0.2" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
[[package]]
name = "dirs"
version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
dependencies = [
"dirs-sys",
]
[[package]]
name = "dirs-sys"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c"
dependencies = [
"libc",
"option-ext",
"redox_users",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "dlib" name = "dlib"
version = "0.5.2" version = "0.5.2"
@ -111,6 +157,12 @@ version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "env_filter" name = "env_filter"
version = "0.1.2" version = "0.1.2"
@ -141,7 +193,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys", "windows-sys 0.52.0",
]
[[package]]
name = "getrandom"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
dependencies = [
"cfg-if",
"libc",
"wasi",
] ]
[[package]] [[package]]
@ -150,12 +213,27 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "indenter"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
[[package]] [[package]]
name = "is_terminal_polyfill" name = "is_terminal_polyfill"
version = "1.70.1" version = "1.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
[[package]]
name = "itertools"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
dependencies = [
"either",
]
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.155" version = "0.2.155"
@ -169,7 +247,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"windows-targets", "windows-targets 0.52.6",
]
[[package]]
name = "libredox"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags",
"libc",
] ]
[[package]] [[package]]
@ -210,6 +298,63 @@ dependencies = [
"autocfg", "autocfg",
] ]
[[package]]
name = "nix"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags",
"cfg-if",
"cfg_aliases",
"libc",
]
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "option-ext"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
[[package]]
name = "peg"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "295283b02df346d1ef66052a757869b2876ac29a6bb0ac3f5f7cd44aebe40e8f"
dependencies = [
"peg-macros",
"peg-runtime",
]
[[package]]
name = "peg-macros"
version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdad6a1d9cf116a059582ce415d5f5566aabcd4008646779dab7fdc2a9a9d426"
dependencies = [
"peg-runtime",
"proc-macro2",
"quote",
]
[[package]]
name = "peg-runtime"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3aeb8f54c078314c2065ee649a7241f46b9d8e418e1a9581ba0546657d7aa3a"
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.30" version = "0.3.30"
@ -243,6 +388,17 @@ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]]
name = "redox_users"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
dependencies = [
"getrandom",
"libredox",
"thiserror",
]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.10.6" version = "1.10.6"
@ -282,7 +438,7 @@ dependencies = [
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
"windows-sys", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -301,26 +457,107 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
name = "swayidle-rs" name = "swayidle-rs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"brush-parser",
"dirs",
"env_logger", "env_logger",
"itertools",
"libc", "libc",
"libsystemd-sys", "libsystemd-sys",
"log", "log",
"nix",
"wayland-client", "wayland-client",
"wayland-sys", "wayland-sys",
] ]
[[package]]
name = "syn"
version = "2.0.74"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing"
version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
"once_cell",
]
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.12" version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "utf8-chars"
version = "3.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb8b618e8c34f77c00710bbe6adaff80f3c856296be49241071e1aa08df45cec"
dependencies = [
"arrayvec",
]
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]] [[package]]
name = "wayland-backend" name = "wayland-backend"
version = "0.3.6" version = "0.3.6"
@ -372,13 +609,37 @@ dependencies = [
"pkg-config", "pkg-config",
] ]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.5",
]
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"
version = "0.52.0" version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [ dependencies = [
"windows-targets", "windows-targets 0.52.6",
]
[[package]]
name = "windows-targets"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
dependencies = [
"windows_aarch64_gnullvm 0.48.5",
"windows_aarch64_msvc 0.48.5",
"windows_i686_gnu 0.48.5",
"windows_i686_msvc 0.48.5",
"windows_x86_64_gnu 0.48.5",
"windows_x86_64_gnullvm 0.48.5",
"windows_x86_64_msvc 0.48.5",
] ]
[[package]] [[package]]
@ -387,28 +648,46 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm 0.52.6",
"windows_aarch64_msvc", "windows_aarch64_msvc 0.52.6",
"windows_i686_gnu", "windows_i686_gnu 0.52.6",
"windows_i686_gnullvm", "windows_i686_gnullvm",
"windows_i686_msvc", "windows_i686_msvc 0.52.6",
"windows_x86_64_gnu", "windows_x86_64_gnu 0.52.6",
"windows_x86_64_gnullvm", "windows_x86_64_gnullvm 0.52.6",
"windows_x86_64_msvc", "windows_x86_64_msvc 0.52.6",
] ]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
[[package]]
name = "windows_i686_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.52.6" version = "0.52.6"
@ -421,24 +700,48 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
[[package]]
name = "windows_i686_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.52.6" version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.52.6" version = "0.52.6"

View file

@ -6,9 +6,13 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
brush-parser = "0.2.5"
dirs = "5.0.1"
env_logger = "0.11.5" env_logger = "0.11.5"
itertools = "0.13.0"
libc = "0.2.155" libc = "0.2.155"
libsystemd-sys = "0.9.3" libsystemd-sys = "0.9.3"
log = "0.4.22" log = "0.4.22"
nix = { version = "0.29.0", features = ["fs"] }
wayland-client = { version = "0.31.5", features = ["log"] } wayland-client = { version = "0.31.5", features = ["log"] }
wayland-sys = { version = "0.31.4", features = ["client", "server"] } wayland-sys = { version = "0.31.4", features = ["client", "server"] }

228
src/expand.rs Normal file
View file

@ -0,0 +1,228 @@
use brush_parser::word::WordPiece;
use itertools::Itertools;
fn expand_backslash_escapes(s: &str) -> Result<(Vec<u8>, bool), ()> {
let mut result: Vec<u8> = vec![];
let mut it = s.chars();
while let Some(c) = it.next() {
if c != '\\' {
// Not a backslash, add and move on.
result.append(c.to_string().into_bytes().as_mut());
continue;
}
match it.next() {
Some('a') => result.push(b'\x07'),
Some('b') => result.push(b'\x08'),
Some('c') => {
if let Some(_next_next) = it.next() {
// "control character in ANSI C quotes"
return Err(());
} else {
result.push(b'\\');
result.push(b'c');
}
}
Some('e' | 'E') => result.push(b'\x1b'),
Some('f') => result.push(b'\x0c'),
Some('n') => result.push(b'\n'),
Some('r') => result.push(b'\r'),
Some('t') => result.push(b'\t'),
Some('v') => result.push(b'\x0b'),
Some('\\') => result.push(b'\\'),
Some('\'') => result.push(b'\''),
Some('\"') => result.push(b'\"'),
Some('?') => result.push(b'?'),
Some('0') => {
// Consume 0-3 valid octal chars
let mut taken_so_far = 0;
let mut octal_chars: String = it
.take_while_ref(|c| {
if taken_so_far < 3 && matches!(*c, '0'..='7') {
taken_so_far += 1;
true
} else {
false
}
})
.collect();
if octal_chars.is_empty() {
octal_chars.push('0');
}
let value = u8::from_str_radix(octal_chars.as_str(), 8).map_err(|_| ())?;
result.push(value);
}
Some('x') => {
// Consume 1-2 valid hex chars
let mut taken_so_far = 0;
let hex_chars: String = it
.take_while_ref(|c| {
if taken_so_far < 2 && c.is_ascii_hexdigit() {
taken_so_far += 1;
true
} else {
false
}
})
.collect();
if hex_chars.is_empty() {
result.push(b'\\');
result.append(c.to_string().into_bytes().as_mut());
} else {
let value = u8::from_str_radix(hex_chars.as_str(), 16).map_err(|_| ())?;
result.push(value);
}
}
Some('u') => {
// Consume 1-4 hex digits
let mut taken_so_far = 0;
let hex_chars: String = it
.take_while_ref(|c| {
if taken_so_far < 4 && c.is_ascii_hexdigit() {
taken_so_far += 1;
true
} else {
false
}
})
.collect();
if hex_chars.is_empty() {
result.push(b'\\');
result.append(c.to_string().into_bytes().as_mut());
} else {
let value = u16::from_str_radix(hex_chars.as_str(), 16).map_err(|_| ())?;
if let Some(decoded) = char::from_u32(u32::from(value)) {
result.append(decoded.to_string().into_bytes().as_mut());
} else {
result.push(b'\\');
result.append(c.to_string().into_bytes().as_mut());
}
}
}
Some('U') => {
// Consume 1-8 hex digits
let mut taken_so_far = 0;
let hex_chars: String = it
.take_while_ref(|c| {
if taken_so_far < 8 && c.is_ascii_hexdigit() {
taken_so_far += 1;
true
} else {
false
}
})
.collect();
if hex_chars.is_empty() {
result.push(b'\\');
result.append(c.to_string().into_bytes().as_mut());
} else {
let value = u32::from_str_radix(hex_chars.as_str(), 16).map_err(|_| ())?;
if let Some(decoded) = char::from_u32(value) {
result.append(decoded.to_string().into_bytes().as_mut());
} else {
result.push(b'\\');
result.append(c.to_string().into_bytes().as_mut());
}
}
}
Some(c) => {
// Not a valid escape sequence.
result.push(b'\\');
result.append(c.to_string().into_bytes().as_mut());
}
None => {
// Trailing backslash.
result.push(b'\\');
}
}
}
Ok((result, true))
}
fn expand_tilde_expression(prefix: &str) -> Result<String, ()> {
if !prefix.is_empty() {
// "expansion: complex tilde expression"
return Err(());
}
if let Some(home_dir) = dirs::home_dir() {
Ok(home_dir.to_string_lossy().to_string())
} else {
Err(())
}
}
fn expand_word_piece(word_piece: WordPiece) -> Result<(Vec<String>, bool), ()> {
let mut cat = true;
let expansion: Vec<String> = match word_piece {
brush_parser::word::WordPiece::Text(s) => vec![s],
brush_parser::word::WordPiece::SingleQuotedText(s) => vec![s],
brush_parser::word::WordPiece::AnsiCQuotedText(s) => {
let (expanded, _) = expand_backslash_escapes(s.as_str())?;
vec![String::from_utf8_lossy(expanded.as_slice()).into_owned()]
}
brush_parser::word::WordPiece::DoubleQuotedSequence(pieces) => {
let mut fields: Vec<String> = vec![];
let pieces_is_empty = pieces.is_empty();
for piece in pieces {
let (this_fields, concatenate) = expand_word_piece(piece)?;
if concatenate {
fields.push(this_fields.join(" "));
} else {
fields.extend(this_fields);
};
}
// If there were no pieces, then make sure we yield a single field containing an
// empty, unsplittable string.
if pieces_is_empty {
fields.push(String::new());
}
cat = false;
fields
}
brush_parser::word::WordPiece::TildePrefix(prefix) => {
vec![expand_tilde_expression(prefix.as_str())?]
}
brush_parser::word::WordPiece::ParameterExpansion(_) => return Err(()),
brush_parser::word::WordPiece::CommandSubstitution(_) => return Err(()),
brush_parser::word::WordPiece::EscapeSequence(s) => {
let expanded = s.strip_prefix('\\').unwrap();
vec![expanded.to_owned()]
}
brush_parser::word::WordPiece::ArithmeticExpression(_) => return Err(()),
};
Ok((expansion, cat))
}
pub fn wordexp(cmd: &str) -> Result<Vec<String>, ()> {
let frags = brush_parser::word::parse(
cmd,
&brush_parser::ParserOptions {
enable_extended_globbing: false,
posix_mode: false,
sh_mode: false,
tilde_expansion: true,
},
)
.map_err(|_| ())?;
Ok(frags
.into_iter()
.map(|x| Ok(expand_word_piece(x)?.0))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.flatten()
.collect())
}

View file

@ -8,9 +8,11 @@ use std::{
borrow::Cow, borrow::Cow,
env, env,
ffi::{CStr, CString}, ffi::{CStr, CString},
mem, fs::File,
mem::MaybeUninit, io::{BufRead, BufReader},
mem::{self, MaybeUninit},
os::raw::c_void, os::raw::c_void,
path::Path,
process, ptr, process, ptr,
}; };
@ -18,9 +20,8 @@ use ext_idle_notify_v1_protocol::{
ext_idle_notification_v1_interface, ext_idle_notifier_v1_interface, ext_idle_notification_v1_interface, ext_idle_notifier_v1_interface,
}; };
use libc::{ use libc::{
__errno_location, abort, access, calloc, close, execvp, exit, fclose, fopen, fork, free, __errno_location, abort, calloc, close, execvp, exit, fork, getenv, getopt, getpid,
getenv, getline, getopt, getpid, printf, sigemptyset, signal, sigprocmask, sigset_t, size_t, sigemptyset, signal, sigprocmask, sigset_t, size_t, sprintf, strcmp, strdup, strstr, waitpid,
sprintf, strcmp, strdup, strlen, strncmp, strstr, strtoul, waitpid,
}; };
use libsystemd_sys::bus::{ use libsystemd_sys::bus::{
sd_bus, sd_bus_call_method, sd_bus_default_system, sd_bus_error, sd_bus_error_free, sd_bus, sd_bus_call_method, sd_bus_default_system, sd_bus_error, sd_bus_error_free,
@ -29,6 +30,7 @@ use libsystemd_sys::bus::{
sd_bus_message_read, sd_bus_message_read_basic, sd_bus_message_skip, sd_bus_message_unref, sd_bus_message_read, sd_bus_message_read_basic, sd_bus_message_skip, sd_bus_message_unref,
sd_bus_process, sd_bus_slot, sd_bus_process, sd_bus_slot,
}; };
use nix::unistd::AccessFlags;
use wayland_client::protocol::__interfaces::{wl_registry_interface, wl_seat_interface}; use wayland_client::protocol::__interfaces::{wl_registry_interface, wl_seat_interface};
use wayland_sys::{ use wayland_sys::{
client::{ client::{
@ -44,6 +46,7 @@ use wayland_sys::{
}, },
}; };
mod expand;
mod ext_idle_notify_v1_protocol; mod ext_idle_notify_v1_protocol;
#[repr(C)] #[repr(C)]
@ -76,12 +79,6 @@ extern "C" {
flags: u32, flags: u32,
_: ... _: ...
) -> *mut wl_proxy; ) -> *mut wl_proxy;
fn wordexp(
__words: *const libc::c_char,
__pwordexp: *mut wordexp_t,
__flags: libc::c_int,
) -> libc::c_int;
fn wordfree(__wordexp: *mut wordexp_t);
fn sd_bus_match_signal( fn sd_bus_match_signal(
bus_0: *mut sd_bus, bus_0: *mut sd_bus,
ret: *mut *mut sd_bus_slot, ret: *mut *mut sd_bus_slot,
@ -119,13 +116,6 @@ const WL_EVENT_WRITABLE: u32 = 2;
const WL_EVENT_READABLE: u32 = 1; const WL_EVENT_READABLE: u32 = 1;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
#[repr(C)] #[repr(C)]
struct wordexp_t {
we_wordc: size_t,
we_wordv: *mut *mut libc::c_char,
we_offs: size_t,
}
#[derive(Copy, Clone)]
#[repr(C)]
struct ext_idle_notification_v1_listener { struct ext_idle_notification_v1_listener {
idled: Option<unsafe extern "C" fn(*mut libc::c_void, *mut ext_idle_notification_v1) -> ()>, idled: Option<unsafe extern "C" fn(*mut libc::c_void, *mut ext_idle_notification_v1) -> ()>,
resumed: Option<unsafe extern "C" fn(*mut libc::c_void, *mut ext_idle_notification_v1) -> ()>, resumed: Option<unsafe extern "C" fn(*mut libc::c_void, *mut ext_idle_notification_v1) -> ()>,
@ -170,7 +160,7 @@ struct seat {
capabilities: u32, capabilities: u32,
} }
#[inline] #[inline]
unsafe extern "C" fn wl_display_get_registry(wl_display: *mut wl_display) -> *mut wl_registry { unsafe fn wl_display_get_registry(wl_display: *mut wl_display) -> *mut wl_registry {
wl_proxy_marshal_flags( wl_proxy_marshal_flags(
wl_display.cast(), wl_display.cast(),
1, 1,
@ -182,7 +172,7 @@ unsafe extern "C" fn wl_display_get_registry(wl_display: *mut wl_display) -> *mu
.cast() .cast()
} }
#[inline] #[inline]
unsafe extern "C" fn wl_registry_add_listener( unsafe fn wl_registry_add_listener(
wl_registry: *mut wl_registry, wl_registry: *mut wl_registry,
listener: *mut wl_registry_listener, listener: *mut wl_registry_listener,
data: *mut libc::c_void, data: *mut libc::c_void,
@ -190,7 +180,7 @@ unsafe extern "C" fn wl_registry_add_listener(
wl_proxy_add_listener(wl_registry.cast(), listener.cast(), data) wl_proxy_add_listener(wl_registry.cast(), listener.cast(), data)
} }
#[inline] #[inline]
unsafe extern "C" fn wl_registry_bind( unsafe fn wl_registry_bind(
wl_registry: *mut wl_registry, wl_registry: *mut wl_registry,
name: u32, name: u32,
interface: *const wl_interface, interface: *const wl_interface,
@ -210,7 +200,7 @@ unsafe extern "C" fn wl_registry_bind(
.cast() .cast()
} }
#[inline] #[inline]
unsafe extern "C" fn wl_seat_add_listener( unsafe fn wl_seat_add_listener(
wl_seat: *mut wl_seat, wl_seat: *mut wl_seat,
listener: *const wl_seat_listener, listener: *const wl_seat_listener,
data: *mut libc::c_void, data: *mut libc::c_void,
@ -218,7 +208,7 @@ unsafe extern "C" fn wl_seat_add_listener(
wl_proxy_add_listener(wl_seat.cast(), listener.cast_mut().cast(), data) wl_proxy_add_listener(wl_seat.cast(), listener.cast_mut().cast(), data)
} }
#[inline] #[inline]
unsafe extern "C" fn ext_idle_notifier_v1_get_idle_notification( unsafe fn ext_idle_notifier_v1_get_idle_notification(
ext_idle_notifier_v1: *mut ext_idle_notifier_v1, ext_idle_notifier_v1: *mut ext_idle_notifier_v1,
timeout: u32, timeout: u32,
seat_0: *mut wl_seat, seat_0: *mut wl_seat,
@ -236,7 +226,7 @@ unsafe extern "C" fn ext_idle_notifier_v1_get_idle_notification(
.cast() .cast()
} }
#[inline] #[inline]
unsafe extern "C" fn ext_idle_notification_v1_add_listener( unsafe fn ext_idle_notification_v1_add_listener(
ext_idle_notification_v1: *mut ext_idle_notification_v1, ext_idle_notification_v1: *mut ext_idle_notification_v1,
listener: *const ext_idle_notification_v1_listener, listener: *const ext_idle_notification_v1_listener,
data: *mut libc::c_void, data: *mut libc::c_void,
@ -248,7 +238,7 @@ unsafe extern "C" fn ext_idle_notification_v1_add_listener(
) )
} }
#[inline] #[inline]
unsafe extern "C" fn ext_idle_notification_v1_destroy( unsafe fn ext_idle_notification_v1_destroy(
ext_idle_notification_v1: *mut ext_idle_notification_v1, ext_idle_notification_v1: *mut ext_idle_notification_v1,
) { ) {
wl_proxy_marshal_flags( wl_proxy_marshal_flags(
@ -261,7 +251,6 @@ unsafe extern "C" fn ext_idle_notification_v1_destroy(
} }
static mut idle_notifier: *mut ext_idle_notifier_v1 = ptr::null_mut(); static mut idle_notifier: *mut ext_idle_notifier_v1 = ptr::null_mut();
static mut seat: *mut wl_seat = ptr::null_mut(); static mut seat: *mut wl_seat = ptr::null_mut();
#[no_mangle]
static mut state: swayidle_state = swayidle_state { static mut state: swayidle_state = swayidle_state {
display: ptr::null_mut(), display: ptr::null_mut(),
event_loop: ptr::null_mut(), event_loop: ptr::null_mut(),
@ -282,8 +271,7 @@ static mut state: swayidle_state = swayidle_state {
timeouts_enabled: false, timeouts_enabled: false,
wait: false, wait: false,
}; };
#[no_mangle] unsafe fn swayidle_log_init(verbosity: log_importance) {
unsafe extern "C" fn swayidle_log_init(verbosity: log_importance) {
env_logger::builder() env_logger::builder()
.filter( .filter(
None, None,
@ -368,7 +356,7 @@ impl swayidle_state {
} }
}; };
} }
unsafe extern "C" fn connect_to_bus(&self) { unsafe fn connect_to_bus(&self) {
let ret = sd_bus_default_system(ptr::addr_of_mut!(bus)); let ret = sd_bus_default_system(ptr::addr_of_mut!(bus));
if ret < 0 { if ret < 0 {
*__errno_location() = -ret; *__errno_location() = -ret;
@ -444,7 +432,7 @@ impl swayidle_state {
&mut self, &mut self,
argc: usize, argc: usize,
argv: *mut *mut libc::c_char, argv: *mut *mut libc::c_char,
config_path: *mut *mut libc::c_char, config_path: &mut Option<String>,
) -> libc::c_int { ) -> libc::c_int {
let mut c: libc::c_int; let mut c: libc::c_int;
loop { loop {
@ -452,55 +440,65 @@ impl swayidle_state {
if c == -1 { if c == -1 {
break; break;
} }
match c { match c as u8 {
67 => { b'C' => {
free((*config_path).cast()); *config_path = Some(read_str(optarg).into());
*config_path = strdup(optarg);
} }
100 => { b'd' => {
swayidle_log_init(LOG_DEBUG); swayidle_log_init(LOG_DEBUG);
} }
119 => { b'w' => {
self.wait = 1 != 0; self.wait = 1 != 0;
} }
83 => { b'S' => {
self.seat_name = read_str2(optarg); self.seat_name = read_str2(optarg);
} }
104 | 63 => { b'h' | b'?' => {
printf(b"Usage: %s [OPTIONS]\n\0".as_ptr().cast(), *argv); println!("Usage: {} [OPTIONS]", read_str(*argv));
printf(b" -h\tthis help menu\n\0".as_ptr().cast()); println!(" -h\tthis help menu");
printf(b" -C\tpath to config file\n\0".as_ptr().cast()); println!(" -C\tpath to config file");
printf(b" -d\tdebug\n\0".as_ptr().cast()); println!(" -d\tdebug");
printf(b" -w\twait for command to finish\n\0".as_ptr().cast()); println!(" -w\twait for command to finish");
printf(b" -S\tpick the seat to work with\n\0".as_ptr().cast()); println!(" -S\tpick the seat to work with");
return 1; return 1;
} }
_ => return 1, _ => return 1,
} }
} }
let mut i = optind as usize; let args = (optind as usize..argc)
while i < argc { .map(|i| read_str(*argv.add(i)).into_owned())
if strcmp(b"timeout\0".as_ptr().cast(), *argv.add(i)) == 0 { .collect::<Vec<_>>();
log::debug!("Got timeout"); let mut i = 0;
i += self.parse_timeout(argc - i, &mut *argv.add(i)); while i < args.len() {
} else if strcmp(b"before-sleep\0".as_ptr().cast(), *argv.add(i)) == 0 { match args[i].as_str() {
log::debug!("Got before-sleep"); "timeout" => {
i += self.parse_sleep(argc - i, &mut *argv.add(i)); log::debug!("Got timeout");
} else if strcmp(b"after-resume\0".as_ptr().cast(), *argv.add(i)) == 0 { i += self.parse_timeout(&args[i..]);
log::debug!("Got after-resume"); }
i += self.parse_resume(argc - i, &mut *argv.add(i)); "before-sleep" => {
} else if strcmp(b"lock\0".as_ptr().cast(), *argv.add(i)) == 0 { log::debug!("Got before-sleep");
log::debug!("Got lock"); i += self.parse_sleep(&args[i..]);
i += self.parse_lock(argc - i, &mut *argv.add(i)); }
} else if strcmp(b"unlock\0".as_ptr().cast(), *argv.add(i)) == 0 { "after-resume" => {
log::debug!("Got unlock"); log::debug!("Got after-resume");
i += self.parse_unlock(argc - i, &mut *argv.add(i)); i += self.parse_resume(&args[i..]);
} else if strcmp(b"idlehint\0".as_ptr().cast(), *argv.add(i)) == 0 { }
log::debug!("Got idlehint"); "lock" => {
i += self.parse_idlehint(argc - i, &mut *argv.add(i)); log::debug!("Got lock");
} else { i += self.parse_lock(&args[i..]);
log::error!("Unsupported command '{}'", read_str(*argv.add(i))); }
return 1; "unlock" => {
log::debug!("Got unlock");
i += self.parse_unlock(&args[i..]);
}
"idlehint" => {
log::debug!("Got idlehint");
i += self.parse_idlehint(&args[i..]);
}
_ => {
log::error!("Unsupported command '{}'", read_str(*argv.add(i)));
return 1;
}
} }
} }
0 0
@ -594,7 +592,7 @@ impl swayidle_state {
cmd = (*cmd).link.next.cast(); cmd = (*cmd).link.next.cast();
} }
} }
unsafe extern "C" fn disable_timeouts(&mut self) { unsafe fn disable_timeouts(&mut self) {
if !self.timeouts_enabled { if !self.timeouts_enabled {
return; return;
} }
@ -610,20 +608,20 @@ impl swayidle_state {
set_idle_hint(false); set_idle_hint(false);
} }
} }
unsafe fn parse_timeout(&mut self, argc: usize, argv: *mut *mut libc::c_char) -> usize { unsafe fn parse_timeout(&mut self, args: &[String]) -> usize {
if argc < 3 { if args.len() < 3 {
log::error!( log::error!(
"Too few parameters to timeout command. Usage: timeout <seconds> <command>" "Too few parameters to timeout command. Usage: timeout <seconds> <command>"
); );
exit(-1); exit(-1);
} }
let cmd = build_timeout_cmd(argv); let cmd = build_timeout_cmd(args);
log::debug!("Register idle timeout at {} ms", (*cmd).timeout,); log::debug!("Register idle timeout at {} ms", (*cmd).timeout,);
log::debug!("Setup idle"); log::debug!("Setup idle");
(*cmd).idle_cmd = parse_command(argc - 2, &mut *argv.offset(2)); (*cmd).idle_cmd = parse_command(&args[2..]);
let result = if argc >= 5 && strcmp(b"resume\0".as_ptr().cast(), *argv.offset(3)) == 0 { let result = if args.len() >= 5 && args[3] == "resume" {
log::debug!("Setup resume"); log::debug!("Setup resume");
(*cmd).resume_cmd = parse_command(argc - 4, &mut *argv.offset(4)); (*cmd).resume_cmd = parse_command(&args[4..]);
5 5
} else { } else {
3 3
@ -631,123 +629,111 @@ impl swayidle_state {
wl_list_insert(&mut self.timeout_cmds, &mut (*cmd).link); wl_list_insert(&mut self.timeout_cmds, &mut (*cmd).link);
result result
} }
unsafe fn parse_sleep(&mut self, argc: usize, argv: *mut *mut libc::c_char) -> usize { unsafe fn parse_sleep(&mut self, args: &[String]) -> usize {
if argc < 2 { if args.len() < 2 {
log::error!( log::error!(
"Too few parameters to before-sleep command. Usage: before-sleep <command>" "Too few parameters to before-sleep command. Usage: before-sleep <command>"
); );
exit(-1); exit(-1);
} }
self.before_sleep_cmd = parse_command(argc - 1, &mut *argv.offset(1)); self.before_sleep_cmd = parse_command(&args[1..]);
if let Some(before_sleep_cmd) = &self.before_sleep_cmd { if let Some(before_sleep_cmd) = &self.before_sleep_cmd {
log::debug!("Setup sleep lock: {before_sleep_cmd}"); log::debug!("Setup sleep lock: {before_sleep_cmd}");
} }
2 2
} }
unsafe fn parse_resume(&mut self, argc: usize, argv: *mut *mut libc::c_char) -> usize { unsafe fn parse_resume(&mut self, args: &[String]) -> usize {
if argc < 2 { if args.len() < 2 {
log::error!( log::error!(
"Too few parameters to after-resume command. Usage: after-resume <command>" "Too few parameters to after-resume command. Usage: after-resume <command>"
); );
exit(-1); exit(-1);
} }
self.after_resume_cmd = parse_command(argc - 1, &mut *argv.offset(1)); self.after_resume_cmd = parse_command(&args[1..]);
if let Some(after_resume_cmd) = &self.after_resume_cmd { if let Some(after_resume_cmd) = &self.after_resume_cmd {
log::debug!("Setup resume hook: {after_resume_cmd}"); log::debug!("Setup resume hook: {after_resume_cmd}");
} }
2 2
} }
unsafe fn parse_lock(&mut self, argc: usize, argv: *mut *mut libc::c_char) -> usize { unsafe fn parse_lock(&mut self, args: &[String]) -> usize {
if argc < 2 { if args.len() < 2 {
log::error!("Too few parameters to lock command. Usage: lock <command>"); log::error!("Too few parameters to lock command. Usage: lock <command>");
exit(-1); exit(-1);
} }
self.logind_lock_cmd = parse_command(argc - 1, &mut *argv.offset(1)); self.logind_lock_cmd = parse_command(&args[1..]);
if let Some(logind_lock_cmd) = &self.logind_lock_cmd { if let Some(logind_lock_cmd) = &self.logind_lock_cmd {
log::debug!("Setup lock hook: {logind_lock_cmd}"); log::debug!("Setup lock hook: {logind_lock_cmd}");
} }
2 2
} }
unsafe fn parse_unlock(&mut self, argc: usize, argv: *mut *mut libc::c_char) -> usize { unsafe fn parse_unlock(&mut self, args: &[String]) -> usize {
if argc < 2 { if args.len() < 2 {
log::error!("Too few parameters to unlock command. Usage: unlock <command>"); log::error!("Too few parameters to unlock command. Usage: unlock <command>");
exit(-1); exit(-1);
} }
self.logind_unlock_cmd = parse_command(argc - 1, &mut *argv.offset(1)); self.logind_unlock_cmd = parse_command(&args[1..]);
if let Some(logind_unlock_cmd) = &self.logind_unlock_cmd { if let Some(logind_unlock_cmd) = &self.logind_unlock_cmd {
log::debug!("Setup unlock hook: {logind_unlock_cmd}"); log::debug!("Setup unlock hook: {logind_unlock_cmd}");
} }
2 2
} }
unsafe fn parse_idlehint(&mut self, argc: usize, argv: *mut *mut libc::c_char) -> usize { unsafe fn parse_idlehint(&mut self, args: &[String]) -> usize {
if self.logind_idlehint { if self.logind_idlehint {
log::error!("Cannot add multiple idlehint events"); log::error!("Cannot add multiple idlehint events");
exit(-1); exit(-1);
} }
if argc < 2 { if args.len() < 2 {
log::error!("Too few parameters to idlehint command. Usage: idlehint <seconds>"); log::error!("Too few parameters to idlehint command. Usage: idlehint <seconds>");
exit(-1); exit(-1);
} }
let cmd: *mut swayidle_timeout_cmd = build_timeout_cmd(argv); let cmd: *mut swayidle_timeout_cmd = build_timeout_cmd(args);
(*cmd).idlehint = true; (*cmd).idlehint = true;
log::debug!("Register idlehint timeout at {} ms", (*cmd).timeout,); log::debug!("Register idlehint timeout at {} ms", (*cmd).timeout,);
wl_list_insert(&mut self.timeout_cmds, &mut (*cmd).link); wl_list_insert(&mut self.timeout_cmds, &mut (*cmd).link);
self.logind_idlehint = true; self.logind_idlehint = true;
2 2
} }
unsafe extern "C" fn load_config(&mut self, config_path: *const libc::c_char) -> i32 { unsafe fn load_config(&mut self, config_path: &Path) -> i32 {
let f = fopen(config_path, b"r\0".as_ptr().cast()); let Ok(file) = File::open(config_path) else {
if f.is_null() {
return -2; return -2;
} };
let mut file = BufReader::new(file);
let mut lineno: size_t = 0; let mut lineno: size_t = 0;
let mut line = ptr::null_mut(); let mut line = String::new();
let mut n = 0;
let mut nread;
loop { loop {
nread = getline(&mut line, &mut n, f); line.clear();
if nread == -1 { let Ok(nread) = file.read_line(&mut line) else {
break;
};
if nread == 0 {
break; break;
} }
lineno = lineno.wrapping_add(1); lineno = lineno.wrapping_add(1);
if *line.offset(nread - 1) as u8 == b'\n' { let line = line.strip_suffix('\n').unwrap_or(&line);
*line.offset(nread - 1) = 0; if line.is_empty() || line.starts_with('#') {
}
if strlen(line) == 0 || *line as u8 == b'#' {
continue; continue;
} }
let mut i = 0; let (cmd, args) = if let Some((a, b)) = line.split_once(' ') {
while *line.add(i) as u8 != b'\0' && *line.add(i) as u8 != b' ' { (a, Some(b))
i = i.wrapping_add(1);
}
let mut p = wordexp_t {
we_wordc: 0,
we_wordv: ptr::null_mut(),
we_offs: 0,
};
wordexp(line, &mut p, 0);
if strncmp(b"timeout\0".as_ptr().cast(), line, i) == 0 {
self.parse_timeout(p.we_wordc, p.we_wordv);
} else if strncmp(b"before-sleep\0".as_ptr().cast(), line, i) == 0 {
self.parse_sleep(p.we_wordc, p.we_wordv);
} else if strncmp(b"after-resume\0".as_ptr().cast(), line, i) == 0 {
self.parse_resume(p.we_wordc, p.we_wordv);
} else if strncmp(b"lock\0".as_ptr().cast(), line, i) == 0 {
self.parse_lock(p.we_wordc, p.we_wordv);
} else if strncmp(b"unlock\0".as_ptr().cast(), line, i) == 0 {
self.parse_unlock(p.we_wordc, p.we_wordv);
} else if strncmp(b"idlehint\0".as_ptr().cast(), line, i) == 0 {
self.parse_idlehint(p.we_wordc, p.we_wordv);
} else { } else {
*line.add(i) = 0; (line, None)
log::error!("Unexpected keyword {} in line {lineno}", read_str(line)); };
free(line.cast::<libc::c_void>()); let args = args
return -22; .map(|args| expand::wordexp(args).unwrap())
} .unwrap_or_default();
wordfree(&mut p); match cmd {
"timeout" => self.parse_timeout(&args),
"before-sleep" => self.parse_sleep(&args),
"after-resume" => self.parse_resume(&args),
"lock" => self.parse_lock(&args),
"unlock" => self.parse_unlock(&args),
"idlehint" => self.parse_idlehint(&args),
_ => {
log::error!("Unexpected keyword {cmd} in line {lineno}");
return -22;
}
};
} }
free(line.cast());
fclose(f);
0 0
} }
} }
@ -773,7 +759,7 @@ unsafe fn read_str(ptr: *const libc::c_char) -> Cow<'static, str> {
static mut sleep_lock_fd: libc::c_int = -1; static mut sleep_lock_fd: libc::c_int = -1;
static mut bus: *mut sd_bus = ptr::null_mut(); static mut bus: *mut sd_bus = ptr::null_mut();
static mut session_name: *mut libc::c_char = ptr::null_mut(); static mut session_name: *mut libc::c_char = ptr::null_mut();
unsafe extern "C" fn acquire_inhibitor_lock( unsafe fn acquire_inhibitor_lock(
type_0: *const libc::c_char, type_0: *const libc::c_char,
mode: *const libc::c_char, mode: *const libc::c_char,
fd: *mut libc::c_int, fd: *mut libc::c_int,
@ -835,13 +821,13 @@ unsafe extern "C" fn acquire_inhibitor_lock(
sd_bus_error_free(&mut error); sd_bus_error_free(&mut error);
sd_bus_message_unref(msg); sd_bus_message_unref(msg);
} }
unsafe extern "C" fn release_inhibitor_lock(fd: libc::c_int) { unsafe fn release_inhibitor_lock(fd: libc::c_int) {
if fd >= 0 { if fd >= 0 {
log::debug!("Releasing inhibitor lock {}", fd); log::debug!("Releasing inhibitor lock {}", fd);
close(fd); close(fd);
} }
} }
unsafe extern "C" fn set_idle_hint(hint: bool) { unsafe fn set_idle_hint(hint: bool) {
log::debug!("SetIdleHint {}", i32::from(hint)); log::debug!("SetIdleHint {}", i32::from(hint));
let mut msg = ptr::null_mut(); let mut msg = ptr::null_mut();
let mut error = sd_bus_error { let mut error = sd_bus_error {
@ -869,7 +855,7 @@ unsafe extern "C" fn set_idle_hint(hint: bool) {
sd_bus_error_free(&mut error); sd_bus_error_free(&mut error);
sd_bus_message_unref(msg); sd_bus_message_unref(msg);
} }
unsafe extern "C" fn get_logind_idle_inhibit() -> bool { unsafe fn get_logind_idle_inhibit() -> bool {
let mut locks: *const libc::c_char = ptr::null(); let mut locks: *const libc::c_char = ptr::null();
let res: bool; let res: bool;
let mut reply = ptr::null_mut(); let mut reply = ptr::null_mut();
@ -1032,7 +1018,7 @@ unsafe extern "C" fn dbus_event(
} }
count count
} }
unsafe extern "C" fn set_session() { unsafe fn set_session() {
let mut is_error = false; let mut is_error = false;
let mut msg = ptr::null_mut(); let mut msg = ptr::null_mut();
let mut error = sd_bus_error { let mut error = sd_bus_error {
@ -1089,7 +1075,7 @@ unsafe extern "C" fn set_session() {
sd_bus_error_free(&mut error); sd_bus_error_free(&mut error);
sd_bus_message_unref(msg); sd_bus_message_unref(msg);
} }
unsafe extern "C" fn setup_sleep_listener() { unsafe fn setup_sleep_listener() {
let ret = sd_bus_match_signal( let ret = sd_bus_match_signal(
bus, bus,
ptr::null_mut(), ptr::null_mut(),
@ -1114,7 +1100,7 @@ unsafe extern "C" fn setup_sleep_listener() {
ptr::addr_of_mut!(sleep_lock_fd), ptr::addr_of_mut!(sleep_lock_fd),
); );
} }
unsafe extern "C" fn setup_lock_listener() { unsafe fn setup_lock_listener() {
let ret = sd_bus_match_signal( let ret = sd_bus_match_signal(
bus, bus,
ptr::null_mut(), ptr::null_mut(),
@ -1133,7 +1119,7 @@ unsafe extern "C" fn setup_lock_listener() {
); );
} }
} }
unsafe extern "C" fn setup_unlock_listener() { unsafe fn setup_unlock_listener() {
let ret = sd_bus_match_signal( let ret = sd_bus_match_signal(
bus, bus,
ptr::null_mut(), ptr::null_mut(),
@ -1152,7 +1138,7 @@ unsafe extern "C" fn setup_unlock_listener() {
); );
} }
} }
unsafe extern "C" fn setup_property_changed_listener() { unsafe fn setup_property_changed_listener() {
let ret = sd_bus_match_signal( let ret = sd_bus_match_signal(
bus, bus,
ptr::null_mut(), ptr::null_mut(),
@ -1210,13 +1196,13 @@ static mut registry_listener: wl_registry_listener = wl_registry_listener {
global: Some(handle_global), global: Some(handle_global),
global_remove: Some(handle_global_remove), global_remove: Some(handle_global_remove),
}; };
unsafe extern "C" fn destroy_cmd_timer(cmd: *mut swayidle_timeout_cmd) { unsafe fn destroy_cmd_timer(cmd: *mut swayidle_timeout_cmd) {
if !(*cmd).idle_notification.is_null() { if !(*cmd).idle_notification.is_null() {
ext_idle_notification_v1_destroy((*cmd).idle_notification); ext_idle_notification_v1_destroy((*cmd).idle_notification);
(*cmd).idle_notification = ptr::null_mut(); (*cmd).idle_notification = ptr::null_mut();
} }
} }
unsafe extern "C" fn register_timeout(cmd: *mut swayidle_timeout_cmd, timeout: libc::c_int) { unsafe fn register_timeout(cmd: *mut swayidle_timeout_cmd, timeout: libc::c_int) {
destroy_cmd_timer(cmd); destroy_cmd_timer(cmd);
if timeout < 0 { if timeout < 0 {
log::debug!("Not registering idle timeout"); log::debug!("Not registering idle timeout");
@ -1263,30 +1249,24 @@ static mut idle_notification_listener: ext_idle_notification_v1_listener =
idled: Some(handle_idled), idled: Some(handle_idled),
resumed: Some(handle_resumed), resumed: Some(handle_resumed),
}; };
unsafe fn parse_command(argc: usize, argv: *mut *mut libc::c_char) -> Option<String> { unsafe fn parse_command(args: &[String]) -> Option<String> {
if argc < 1 { let Some(ret) = args.first() else {
log::error!("Missing command");
return None;
}
let Some(ret) = read_str2(*argv) else {
log::error!("Missing command"); log::error!("Missing command");
return None; return None;
}; };
log::debug!("Command: {ret}"); log::debug!("Command: {ret}");
Some(ret) Some(ret.clone())
} }
unsafe extern "C" fn build_timeout_cmd(argv: *mut *mut libc::c_char) -> *mut swayidle_timeout_cmd { unsafe fn build_timeout_cmd(args: &[String]) -> *mut swayidle_timeout_cmd {
*__errno_location() = 0; *__errno_location() = 0;
let mut endptr = ptr::null_mut(); let Ok(seconds) = args[1].parse::<i32>() else {
let seconds = strtoul(*argv.offset(1), &mut endptr, 10) as libc::c_int;
if *__errno_location() != 0 || *endptr as u8 != b'\0' {
log::error!( log::error!(
"Invalid {} parameter '{}', it should be a numeric value representing seconds", "Invalid {} parameter '{}', it should be a numeric value representing seconds",
read_str(*argv), args[0],
read_str(*argv.offset(1)), args[1],
); );
exit(-1); exit(-1);
} };
Box::into_raw(Box::new(swayidle_timeout_cmd { Box::into_raw(Box::new(swayidle_timeout_cmd {
idlehint: false, idlehint: false,
resume_pending: false, resume_pending: false,
@ -1311,69 +1291,54 @@ unsafe extern "C" fn display_event(
) -> libc::c_int { ) -> libc::c_int {
state.display_event(mask) state.display_event(mask)
} }
unsafe extern "C" fn get_config_path() -> *mut libc::c_char { unsafe fn get_config_path() -> Option<String> {
static mut config_paths: [*const libc::c_char; 3] = [ static mut config_paths: [&str; 3] = [
b"$XDG_CONFIG_HOME/swayidle/config\0" "$XDG_CONFIG_HOME/swayidle/config",
.as_ptr() "$HOME/.swayidle/config",
.cast::<libc::c_char>(), "/usr/local/etc/swayidle/config",
b"$HOME/.swayidle/config\0".as_ptr().cast::<libc::c_char>(),
b"/usr/local/etc/swayidle/config\0"
.as_ptr()
.cast::<libc::c_char>(),
]; ];
let config_home = getenv(b"XDG_CONFIG_HOME\0".as_ptr().cast::<libc::c_char>()); let config_home = getenv(b"XDG_CONFIG_HOME\0".as_ptr().cast::<libc::c_char>());
if config_home.is_null() || *config_home as u8 == b'\n' { if config_home.is_null() || *config_home as u8 == b'\n' {
config_paths[0] = b"$HOME/.config/swayidle/config\0" config_paths[0] = "$HOME/.config/swayidle/config";
.as_ptr()
.cast::<libc::c_char>();
} }
let mut p = wordexp_t {
we_wordc: 0,
we_wordv: ptr::null_mut(),
we_offs: 0,
};
let mut path; let mut path;
let mut i = 0; let mut i = 0;
while i while i
< (mem::size_of::<[*mut libc::c_char; 3]>()) < (mem::size_of::<[*mut libc::c_char; 3]>())
.wrapping_div(mem::size_of::<*mut libc::c_char>()) .wrapping_div(mem::size_of::<*mut libc::c_char>())
{ {
if wordexp(config_paths[i], &mut p, 0) == 0 { if let Ok(res) = expand::wordexp(config_paths[i]) {
path = strdup(*p.we_wordv); path = &res[0];
wordfree(&mut p); if !path.is_empty() && nix::unistd::access(path.as_str(), AccessFlags::R_OK).is_ok() {
if !path.is_null() && access(path, 4) == 0 { return Some(path.clone());
return path;
} }
free(path.cast());
} }
i = i.wrapping_add(1); i = i.wrapping_add(1);
} }
ptr::null_mut() None
} }
unsafe fn main_0(argc: usize, argv: *mut *mut libc::c_char) -> libc::c_int { unsafe fn main_0(argc: usize, argv: *mut *mut libc::c_char) -> libc::c_int {
state.init(); state.init();
let mut config_path = ptr::null_mut(); let mut config_path = None;
if state.parse_args(argc, argv, &mut config_path) != 0 { if state.parse_args(argc, argv, &mut config_path) != 0 {
free(config_path.cast());
return -1; return -1;
} }
if config_path.is_null() { if config_path.is_none() {
config_path = get_config_path(); config_path = get_config_path();
} }
let config_load = if config_path.is_null() { let config_load = if let Some(ref config_path) = config_path {
-2 state.load_config(Path::new(&config_path))
} else { } else {
state.load_config(config_path) -2
}; };
if config_load == -2 { if config_load == -2 {
log::debug!("No config file found."); log::debug!("No config file found.");
} else if config_load == -22 { } else if config_load == -22 {
log::error!("Config file {} has errors, exiting.", read_str(config_path)); log::error!("Config file {} has errors, exiting.", config_path.unwrap());
exit(-1); exit(-1);
} else { } else {
log::debug!("Loaded config at {}", read_str(config_path)); log::debug!("Loaded config at {}", config_path.unwrap());
} }
free(config_path.cast());
state.event_loop = wl_event_loop_create(); state.event_loop = wl_event_loop_create();
wl_event_loop_add_signal(state.event_loop, 2, handle_signal, ptr::null_mut()); wl_event_loop_add_signal(state.event_loop, 2, handle_signal, ptr::null_mut());
wl_event_loop_add_signal(state.event_loop, 15, handle_signal, ptr::null_mut()); wl_event_loop_add_signal(state.event_loop, 15, handle_signal, ptr::null_mut());