mirror of
https://github.com/fastfetch-cli/fastfetch.git
synced 2026-09-12 10:22:12 +02:00
Compare commits
1029 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e5d6006006 | |||
| 18f3809681 | |||
| 1cd87dc994 | |||
| 1e58e04024 | |||
| 408d939664 | |||
| 9b1061719c | |||
| 179539ccba | |||
| 6d73ecb944 | |||
| b981e4fd8b | |||
| 8e660136e0 | |||
| 90ca39b464 | |||
| 63f7e15554 | |||
| ab37216f7d | |||
| 57440a7a45 | |||
| f50059dc7b | |||
| 92fb5cb0c1 | |||
| 5f84630276 | |||
| 22696fe3de | |||
| cd00820546 | |||
| 918153f974 | |||
| 58e67dcc7a | |||
| 940d15c2e6 | |||
| 9ffa46652d | |||
| d45dc53da0 | |||
| 00d1812e8d | |||
| 50dc260fd6 | |||
| bf99aeda92 | |||
| 397822d0db | |||
| 12746a9681 | |||
| 355e21c099 | |||
| 9036b891a8 | |||
| b7e4e91664 | |||
| aabab6dff5 | |||
| 62c2eb4d96 | |||
| c69a6b7640 | |||
| 0521513609 | |||
| a1c5fe2bf2 | |||
| 2d4a77b6f0 | |||
| 9027f72353 | |||
| fe0f292cec | |||
| 06ecd5a1ff | |||
| 8fdaa987e3 | |||
| 15804091b0 | |||
| d8b44a5eae | |||
| 6357dcc6b4 | |||
| 947cddd926 | |||
| 246ff0bc88 | |||
| 339de56407 | |||
| 795bbde459 | |||
| f32bf9e94f | |||
| 8facb7c6e9 | |||
| 92c65aad10 | |||
| 76d6e86fe5 | |||
| e3d7eab4df | |||
| ff8d4b46ef | |||
| 4fb7860a8e | |||
| f188e9518d | |||
| a39419b12a | |||
| 941502d718 | |||
| de146c6370 | |||
| 09efb0d897 | |||
| 8defffabff | |||
| 1b543b1eb8 | |||
| ab17fb08ef | |||
| a4bc3c812d | |||
| c8fcabf4cc | |||
| a961a964ff | |||
| 412de625b2 | |||
| b739736527 | |||
| 2b19f8078e | |||
| 56eabbe2cb | |||
| b0215aae37 | |||
| 86cfa4eded | |||
| bab1e4ff82 | |||
| 6ec59f8654 | |||
| d3459af71f | |||
| 00b5f17f0d | |||
| b8ad833b4b | |||
| fb412576e1 | |||
| d551651d63 | |||
| 4e234c52a3 | |||
| edc718d1d1 | |||
| 42e01e7b8f | |||
| 8edfda979e | |||
| cc3595c3a4 | |||
| 8c72792e31 | |||
| f7ebeb58e2 | |||
| ea4a4f0691 | |||
| 81984e6e97 | |||
| f46e97fc62 | |||
| 7821552761 | |||
| cd8a0fc5f1 | |||
| 30f32f1fb5 | |||
| 9af918b1ef | |||
| 37b8bb4fc0 | |||
| 66edea702e | |||
| 930fb06ca7 | |||
| ca9c67353f | |||
| ea6ad4ac86 | |||
| 6ed8aac6bb | |||
| cfabee4ba7 | |||
| 3a35f9735b | |||
| 05fa8b0994 | |||
| 07f6f93415 | |||
| d2de3a01bb | |||
| c9b7c65ba5 | |||
| 6ad8e68d26 | |||
| b128260eb2 | |||
| ecfaf4d54d | |||
| 72bdee7fbf | |||
| bdb9593c0d | |||
| 1e234754c2 | |||
| 4a4afdadb8 | |||
| 7cadece9a0 | |||
| 724ab6ba69 | |||
| 6370485dcb | |||
| 60d343ca14 | |||
| bdc844f857 | |||
| d49c018f86 | |||
| be2201b5fc | |||
| 9ba1cd1291 | |||
| 22fa9b51e8 | |||
| f781f8d9ea | |||
| 06ecc9c480 | |||
| 50288d91e4 | |||
| 499b4ff445 | |||
| dd0021cd5e | |||
| f5b70dd8b7 | |||
| 8f8ca11203 | |||
| 121d399641 | |||
| 26ae4eb21b | |||
| 52a81dbdc4 | |||
| f924a8bf06 | |||
| c7363f904a | |||
| 53ffe8459f | |||
| 1b702e123e | |||
| 14dccce393 | |||
| d040cc810f | |||
| 224bea2559 | |||
| 777d3e599d | |||
| 7c47bc2656 | |||
| e4d31381d8 | |||
| abf8d75454 | |||
| 2ce152beaf | |||
| 766ed07999 | |||
| ddc2131343 | |||
| b64d8a013d | |||
| e6db59fdde | |||
| 7ea0bbfb21 | |||
| ab041e0ad2 | |||
| 207f742624 | |||
| 68f0b11b6f | |||
| b86c0880b9 | |||
| 75f4a3d92d | |||
| 70fa1341a8 | |||
| 0a55314d37 | |||
| 2198e6123e | |||
| dd37ee0e50 | |||
| 7006ae0420 | |||
| 86458ab32a | |||
| 67ca907e38 | |||
| e15d06bbad | |||
| eb53797174 | |||
| c8c32a78b0 | |||
| 1c032624ac | |||
| 5087ea77b4 | |||
| b6b42e69c3 | |||
| 000a688bb6 | |||
| 3e25b213b1 | |||
| a69cf456ea | |||
| 072b76cb12 | |||
| ca8f54d331 | |||
| 6423feaa94 | |||
| 92ada88ea7 | |||
| 1789ef85d7 | |||
| 42509f115c | |||
| 340a58bda1 | |||
| 08dfd1321c | |||
| 45d324a8c6 | |||
| afa986efd4 | |||
| bc6e8c7813 | |||
| 627fee23d1 | |||
| 27b474f205 | |||
| 418c7eecc7 | |||
| 350250d640 | |||
| 3cc21905af | |||
| c698eb8eb5 | |||
| 463c24beb8 | |||
| a5d1b96ecc | |||
| 63106ebdc1 | |||
| fd36783adb | |||
| 3b5186da53 | |||
| 0140a46090 | |||
| 9c38e1255f | |||
| 663f9d69ff | |||
| d12e5ab801 | |||
| 1d770d85f6 | |||
| 5b00afe45d | |||
| 5b276567ac | |||
| 56566916e3 | |||
| 2c0b4ca3a2 | |||
| 54ffdd32dc | |||
| 64f24bdee9 | |||
| 4706f97bf0 | |||
| 0bdb198d52 | |||
| fc7710821e | |||
| e22a9990ec | |||
| fc7f3a1650 | |||
| 915af9546d | |||
| 54a68640ef | |||
| ec1af7c92b | |||
| a1e20270ad | |||
| 4996986ce6 | |||
| e6de2d4fd9 | |||
| 5347e74a1b | |||
| 0ea5639a22 | |||
| aa3a916d5a | |||
| 6e64b758bf | |||
| 49ef7fc51f | |||
| 0e9a5acdbd | |||
| 4f6e80e940 | |||
| df87cdfa6e | |||
| dee4b36a46 | |||
| d04a26337a | |||
| 2afe8d11d1 | |||
| f31d3b8b21 | |||
| 8a20af9917 | |||
| fc5c2f6213 | |||
| 6c314e148a | |||
| a86d0017a9 | |||
| 4038ed2656 | |||
| 0f4bb47c2f | |||
| 19f7c67ede | |||
| ff7e81ed81 | |||
| 681a102a2b | |||
| ba27f4f2ef | |||
| cbe33a4860 | |||
| 5847e3f269 | |||
| b248dfa01c | |||
| 357aa77e21 | |||
| a44bde6f94 | |||
| 5825bce57d | |||
| 996cdd3155 | |||
| 61cdfcabf8 | |||
| 359a77097c | |||
| 1323d007d3 | |||
| d2215f26ac | |||
| 958e7dbd8f | |||
| 5b10cde59f | |||
| e8f2b9a1c7 | |||
| 0686d1db4a | |||
| 7c284f9ee8 | |||
| dc04273bd7 | |||
| d698be6239 | |||
| e44df27c96 | |||
| b365d4cca1 | |||
| 19d3c948ad | |||
| 4a581039d5 | |||
| 79849fb2b5 | |||
| c116a5abdf | |||
| 8f082730a8 | |||
| b81c4a04db | |||
| e26a05e3ac | |||
| f08a1fb0b4 | |||
| 2a82009ffe | |||
| e851f3a7ed | |||
| 3a865df09e | |||
| bae80e2932 | |||
| 4445e1e78d | |||
| f0e3d3d8e1 | |||
| a313fd1572 | |||
| 927d44d919 | |||
| 3b9a91e8af | |||
| 70b4582bb6 | |||
| 461552b8d0 | |||
| 0f3db37199 | |||
| 67f16b269a | |||
| 25671fa4b4 | |||
| 4eaa04d4a4 | |||
| 7592885b9f | |||
| 508a3fde36 | |||
| f0273224e0 | |||
| 31e833c02e | |||
| a20d915412 | |||
| d3453de73c | |||
| 79a11c4728 | |||
| 24591417ce | |||
| de6d066fc9 | |||
| 6362c896f8 | |||
| 0418e9ca5e | |||
| ba0eeab18c | |||
| 5ef630cbc8 | |||
| 1699d14984 | |||
| 501746a270 | |||
| e6bd1c340f | |||
| 49fc95689d | |||
| 3d84ad19be | |||
| 57aa0cf499 | |||
| 6496dcd7d0 | |||
| 1c066bc69a | |||
| 2f1e37bb7c | |||
| fd3c87abe7 | |||
| af075b8ef8 | |||
| 71d461266e | |||
| 163781557f | |||
| 16e6decebf | |||
| e10c9cc164 | |||
| 7ef994d0cf | |||
| 019c9f0f77 | |||
| 5fec607ebe | |||
| b065b3da51 | |||
| 1337525eb5 | |||
| 30ea52938e | |||
| d43ed33661 | |||
| 03aab33507 | |||
| 420d1cf804 | |||
| 5d901da81b | |||
| 5c783e64c0 | |||
| 2efa5a1869 | |||
| 5bfabe7a52 | |||
| c9c9a58f59 | |||
| 546908fc29 | |||
| 0a17da2da0 | |||
| bc6fd025cb | |||
| 9e49451340 | |||
| 4d185e64ac | |||
| 1fa9a61b3f | |||
| 234552fbf2 | |||
| 8423efb686 | |||
| cd8c15d01e | |||
| 3163cfb1b6 | |||
| 7ae007a1d0 | |||
| 0b52d75415 | |||
| 3a7f4f5848 | |||
| 072f67988f | |||
| c640ddbff7 | |||
| 981ae6bdd1 | |||
| 977e3f317e | |||
| e2ee24598c | |||
| 1be90084ab | |||
| 6ded0f9bb0 | |||
| d60b25e424 | |||
| 874f3918b7 | |||
| 61690a1804 | |||
| 1e43e35857 | |||
| 8c86003220 | |||
| 18c3cd2e66 | |||
| b21f35e914 | |||
| 32e3ed1fda | |||
| 6f87026b0c | |||
| e23edae917 | |||
| bdc867031a | |||
| e96b0f7a73 | |||
| 37fe446a58 | |||
| f03a0bc202 | |||
| bcbc5a4bff | |||
| 0b1e2faba1 | |||
| 4708a5e59c | |||
| 7925469e2f | |||
| 53116d65f1 | |||
| 01917b781b | |||
| d01fc56ea2 | |||
| 9c870a57f0 | |||
| 7e557a06b3 | |||
| fa63038862 | |||
| 8439204cef | |||
| 710df0b87b | |||
| 302f0fc85f | |||
| 241aa3a02c | |||
| a17f3dc3f8 | |||
| 34c0bf58cb | |||
| b64b93fc4a | |||
| a9f43ff466 | |||
| 924d78d3c4 | |||
| fa92bb84ae | |||
| 288d25e17c | |||
| 610fc2ea36 | |||
| 716c0e2b5c | |||
| 945aed7160 | |||
| 1d4d68f6e0 | |||
| 3e1167260d | |||
| 0130f610e9 | |||
| 94941daf4f | |||
| 2bbd723321 | |||
| 608382109c | |||
| bdc5174f68 | |||
| bc869f1be9 | |||
| dc69e44829 | |||
| d236850119 | |||
| 60ec8c9097 | |||
| 42e7a7d2f7 | |||
| e766809e3a | |||
| cb1f0300b9 | |||
| f2a29309f3 | |||
| 6e7b4bab75 | |||
| b4f39e251c | |||
| af6196fe6e | |||
| bca56b2049 | |||
| f4401f172e | |||
| c11b88fee5 | |||
| 88b1b558d7 | |||
| ba6cdc77c9 | |||
| b952772902 | |||
| 7a322154fa | |||
| 0b6ca158ea | |||
| 100cd9a72b | |||
| 98fb810f1f | |||
| c613e558fd | |||
| c324f83826 | |||
| e50421a6ce | |||
| 417b944e1c | |||
| cb8b4b335d | |||
| c0160537b0 | |||
| 4cb7a6424a | |||
| 7d6c79d73e | |||
| 8652737f64 | |||
| d6ac89ea8d | |||
| 2b620cf487 | |||
| f644df481c | |||
| e99ecacb52 | |||
| 3e22dd4b0e | |||
| 19f30ec687 | |||
| 76bee78200 | |||
| ce7455d8f0 | |||
| 5e27ee0f57 | |||
| 84a5c6ebe8 | |||
| ad7e23f64c | |||
| 2738f20eea | |||
| 09362b236c | |||
| 3cfef81877 | |||
| 3a04ae2542 | |||
| dbaf8a319d | |||
| 2fe2a21bfe | |||
| 37639c3582 | |||
| 9a74e6d7bc | |||
| 5d13389827 | |||
| 1c2c6644d5 | |||
| ffcddf30e3 | |||
| 22c92c7b05 | |||
| b569048010 | |||
| f703d9ac89 | |||
| ed6abfd626 | |||
| 50388efc78 | |||
| 7e8fb0fa14 | |||
| 9d70469665 | |||
| a94f0efb5b | |||
| da3a9be7c6 | |||
| cd8ab8e55a | |||
| 1b5b32afad | |||
| 917f784438 | |||
| c2d5d5cca1 | |||
| b435738c34 | |||
| 934905e63a | |||
| d15bb8a232 | |||
| c22bca1f87 | |||
| e04cc9c9d5 | |||
| 7a2bf4e0ac | |||
| 662f5127fa | |||
| fb9117553b | |||
| 9f24e4363f | |||
| 084f9294f2 | |||
| a9f1f9a647 | |||
| 0aed89036b | |||
| df15bbc5f2 | |||
| e6b0bd3817 | |||
| 11cd7153a2 | |||
| f8bc1cb605 | |||
| 8b8eb6f290 | |||
| 056fe21ee2 | |||
| cb0a88df22 | |||
| 298c0431c3 | |||
| 448de9afa5 | |||
| 9401a4b9ad | |||
| ea92ad3785 | |||
| 7aaad5e03e | |||
| 645bf5c839 | |||
| 7638e0e4a1 | |||
| 302b8a7b1b | |||
| dbb9d8a660 | |||
| c51a164042 | |||
| 6b8a62da6e | |||
| 578ca23e75 | |||
| 2e73a90835 | |||
| cc6273fecc | |||
| e63b777916 | |||
| 907567f511 | |||
| e0fd7308be | |||
| b761034aae | |||
| 04d6b1453d | |||
| 11d1754686 | |||
| 25e84decff | |||
| 7d665b203f | |||
| ac62442798 | |||
| 758f96de60 | |||
| db623b9c86 | |||
| c353bf3c96 | |||
| 338b552499 | |||
| 5d73cc1232 | |||
| faddef7a3b | |||
| 2d9bbc8049 | |||
| 64afaa07e7 | |||
| 5cf3ab23b0 | |||
| 3fe926d3a0 | |||
| f71bb682de | |||
| 904f860f3c | |||
| 8f15c9604c | |||
| ff28f5807b | |||
| 6a317366d7 | |||
| dc3e4a2d18 | |||
| 46c4a71ba3 | |||
| f0759acd11 | |||
| 96c7c2966d | |||
| 554e7bce4a | |||
| 70377a8afd | |||
| 51bc6d421a | |||
| be0756f8ba | |||
| 71a2cb4e1b | |||
| 2eba761bed | |||
| 4b5e1a816b | |||
| a92e4b2d67 | |||
| a32404ba98 | |||
| 0a792e4935 | |||
| 05108977e8 | |||
| 25353261d0 | |||
| 4b517263d0 | |||
| 98a65966e7 | |||
| 32dcf9487f | |||
| e3a698f7b1 | |||
| 1631f74700 | |||
| 78c6d71049 | |||
| 0b9ecdeade | |||
| 185a9211f1 | |||
| 24459b2fbf | |||
| 88c8dcb3e8 | |||
| f3a8fedf0a | |||
| 6b8b7c1a62 | |||
| af26828f91 | |||
| f4c43abbf7 | |||
| e84739bff0 | |||
| 66aad0e4f1 | |||
| 77c43c0214 | |||
| 31ae7a642a | |||
| 1bbb21486c | |||
| 316d8ddf9b | |||
| 5d8c21a5ca | |||
| 240ba5c00c | |||
| 554184ec72 | |||
| 7a055a2254 | |||
| 0a807ac1a3 | |||
| 4d831c8c73 | |||
| e6e78a7aae | |||
| 09bef5f41d | |||
| e394efdd85 | |||
| c10b652a2e | |||
| 1594a69d6c | |||
| 9b1e318bd1 | |||
| e292bf1dee | |||
| 55a0c6e97d | |||
| 8b8e4a40a4 | |||
| 8be070998f | |||
| 093f56a03d | |||
| bd9744c27c | |||
| adc25f4420 | |||
| 229fe7c7bf | |||
| 5d571752ae | |||
| 512ddfae6b | |||
| 7b689f94df | |||
| 9eed149b09 | |||
| 0f5d321df8 | |||
| 4e84094fd8 | |||
| 7b9fce0189 | |||
| 9ab5c33008 | |||
| 613b1d63f1 | |||
| 8c86cafec7 | |||
| 4098cf51b3 | |||
| bfc23232f8 | |||
| 483fba44dc | |||
| 851751f99d | |||
| 3e86130ddd | |||
| 350ffced13 | |||
| cdcdb78b97 | |||
| 2ae9d01200 | |||
| e95393750b | |||
| de9229697a | |||
| 9d23d28594 | |||
| 57a4b9b6ed | |||
| ef3989d18d | |||
| 3079b44f63 | |||
| 403900639c | |||
| 0bb5b4cc9c | |||
| 1180eb55a4 | |||
| f0e9caaf04 | |||
| 2c22c3b0c0 | |||
| e9065e15e8 | |||
| 9e7816069b | |||
| 82cdc4cd91 | |||
| 822ddc6dc6 | |||
| 8bd171a9ff | |||
| 509d6bf30c | |||
| ab8a13b2d3 | |||
| 3bcdcc5dbf | |||
| 38f4215a94 | |||
| e3eec3f62a | |||
| e025f28cdc | |||
| 3ece4e3b4d | |||
| 6d72a32d1d | |||
| 45be29bad3 | |||
| 6f5e618341 | |||
| 1abfa70237 | |||
| baaeef5ab5 | |||
| 8eafec479e | |||
| 5f9e7c799a | |||
| aeb1722eb9 | |||
| de18a07938 | |||
| 88147f80ac | |||
| 505ff6ff65 | |||
| 390549394d | |||
| f7e7d54c16 | |||
| 5e068d22c8 | |||
| b77646f23e | |||
| aa40366a49 | |||
| a64a82f215 | |||
| 0a4d6220e9 | |||
| 6b037c595f | |||
| f628f5c382 | |||
| cf713e32e1 | |||
| 7d08f81075 | |||
| 8822653335 | |||
| 75ff054255 | |||
| c51cc8ce6b | |||
| 44e23412b5 | |||
| 59742bca00 | |||
| 303edb97ce | |||
| 37ab380a6f | |||
| a06e245c34 | |||
| 5de432b083 | |||
| 817285ac01 | |||
| 8687505505 | |||
| 34c34d25c4 | |||
| 21b15ee944 | |||
| 8e0a65126e | |||
| 54d8b0a95d | |||
| 48fc72e95c | |||
| e3d6a85888 | |||
| 7d92da8829 | |||
| 2f3a361b1f | |||
| ac71f21e6c | |||
| 8d5316f6aa | |||
| 1242fda66f | |||
| 5a2b618d27 | |||
| d836d7569f | |||
| 8a412e6823 | |||
| 16b6aac764 | |||
| 9f5046d69f | |||
| cace1a7156 | |||
| 9c0cf863ba | |||
| ffe55d9eee | |||
| 28bc9523d6 | |||
| ebf810ad4b | |||
| 5c9a0a1f88 | |||
| bc05a30724 | |||
| 98c7803a24 | |||
| 0893013e78 | |||
| e6985a8832 | |||
| 7a87638fec | |||
| 00f163be32 | |||
| 68bbb2980e | |||
| dd1a799abb | |||
| 7611d672b7 | |||
| bfb93cd8f5 | |||
| 0998b1e59e | |||
| 588c4c0026 | |||
| a80ea2b117 | |||
| 13110e3074 | |||
| 0b2c0445c0 | |||
| 062963d6cc | |||
| 4b7f231b5a | |||
| 74e0732390 | |||
| e9104c38c6 | |||
| 4a7b3a8493 | |||
| 20fafa5a21 | |||
| 1d32344cf7 | |||
| 82a1eaf276 | |||
| 75a023f4d7 | |||
| 53424300e3 | |||
| d553bc4893 | |||
| add2bfd108 | |||
| e508100a15 | |||
| 1a2f4b4c1f | |||
| e968bca89d | |||
| 71fbe04367 | |||
| f2f9b10b18 | |||
| fae4892643 | |||
| 8589bf2392 | |||
| 8b18e69980 | |||
| 9ae968fbd3 | |||
| 8f6608db74 | |||
| 45b6a333ec | |||
| 5012bc250b | |||
| 5775409cb9 | |||
| 64da80d520 | |||
| 8b1bfcb34b | |||
| 784a7a92c8 | |||
| 8331242f42 | |||
| 79fea61c90 | |||
| a8e7d38afd | |||
| 24467e8c46 | |||
| 6867b87c3e | |||
| cb13d43a7a | |||
| bd7190ca6d | |||
| 49982588cf | |||
| de2dff5da0 | |||
| b05c54486f | |||
| 1f1d7cf936 | |||
| 26253f8863 | |||
| 08e6db090b | |||
| ec0fa89cc8 | |||
| 7f48500cfd | |||
| a7eecf6fc7 | |||
| 8e282a3865 | |||
| dcbf76b233 | |||
| 70b11d953c | |||
| fa3b634c07 | |||
| ea86273a0e | |||
| 4f88e1f26d | |||
| 805e277429 | |||
| 3ce3de2963 | |||
| 3b5e9c74d6 | |||
| a9aaa36b2c | |||
| bef4ee1fbc | |||
| b3ddd084ba | |||
| fef3b7c647 | |||
| 4dfba31cae | |||
| 3004f29c08 | |||
| b994ce5b55 | |||
| 6356f9d0e5 | |||
| 597c6f3dbc | |||
| 41cffac80c | |||
| c4cb6c65a9 | |||
| 46081a3e52 | |||
| a5fd671b92 | |||
| 8319512c83 | |||
| c1db692982 | |||
| aec2bfd2a4 | |||
| 7bacf20f72 | |||
| 1479de19ef | |||
| bb9ca73db1 | |||
| 81bac8bca4 | |||
| 56d22292b0 | |||
| 9a11ff8ddb | |||
| a99b6d602d | |||
| 40921156b8 | |||
| bc3703140b | |||
| bd5b385909 | |||
| 0fe3db419e | |||
| e80bb480c4 | |||
| d4773212b7 | |||
| 9ebff9fd22 | |||
| 5d8edc0c8b | |||
| 78530b4e34 | |||
| 61f2823903 | |||
| 7446828866 | |||
| 0b37acec5b | |||
| 53ecf57f19 | |||
| e1c4365c10 | |||
| ebc60ac66c | |||
| 4004501d0f | |||
| a0265c3204 | |||
| 3ef84834fc | |||
| 3276949663 | |||
| 1ec69d6838 | |||
| 7f1063d09b | |||
| 883923de4a | |||
| 146981009b | |||
| 060b69293c | |||
| 3345c1e9dd | |||
| 1c8e2e34ba | |||
| 5ab51c07d1 | |||
| eee98e54d0 | |||
| b0340d5581 | |||
| 1124342eda | |||
| 329cb229f8 | |||
| bedb5eb6c5 | |||
| f184f8dab5 | |||
| 7ee0e8726e | |||
| a7347130de | |||
| f3c82ad837 | |||
| 1bde2b31f9 | |||
| 1edc617b55 | |||
| 2bb451d9e4 | |||
| 4588644d39 | |||
| ed94b4c46c | |||
| f96ddb4c10 | |||
| 1b0a65ecf2 | |||
| 33983c5402 | |||
| 8cfee9d693 | |||
| 64568b31d1 | |||
| 02c999725c | |||
| be11013ae2 | |||
| a84c4dc1f4 | |||
| d9455adc7f | |||
| b20aea7ab8 | |||
| 5e770dc8b0 | |||
| 137d5dfe90 | |||
| 655d11c1cc | |||
| e32987c408 | |||
| fa4e11c73b | |||
| e753d4d3a4 | |||
| 75d2c668d0 | |||
| 559082806b | |||
| 6f8d276545 | |||
| 582268f44f | |||
| 9b68674c4f | |||
| badae2ba9d | |||
| dd4f006b5f | |||
| c491c9e8fc | |||
| 094d736d38 | |||
| 22bfaf3c69 | |||
| 980e552eba | |||
| 4a141c3f57 | |||
| 59289bef6c | |||
| 0b02543ef2 | |||
| 3cef51ec4a | |||
| 6d86813647 | |||
| fb267acac3 | |||
| ba3e26f2b4 | |||
| 4f8d8de749 | |||
| 54c5bc5110 | |||
| c6675f82f0 | |||
| afe2c85047 | |||
| 671b11157e | |||
| 78fb55c35c | |||
| 559905da60 | |||
| e093c8aa72 | |||
| ba8a21142f | |||
| eca3625165 | |||
| 677e920dc8 | |||
| 38c0b24daa | |||
| 4e05502d7a | |||
| d0928a63bf | |||
| aa0bbd5aee | |||
| ce554dbdd0 | |||
| a0174e8666 | |||
| 8be419cfd6 | |||
| ca79bae36e | |||
| b1f0248fb3 | |||
| 77dd18466b | |||
| 5bb6e22679 | |||
| 9ea9291ab8 | |||
| 6ec73863ab | |||
| 8c2f93151d | |||
| 71ddc4ffc6 | |||
| 4909d693e3 | |||
| fe76bbe68a | |||
| d1f20822f1 | |||
| 1ed804db52 | |||
| 0e8b9bec2d | |||
| a3182c31cb | |||
| d2f2c76dfc | |||
| 2d1ae1b4c5 | |||
| 316409ecc3 | |||
| f0fc38bcb5 | |||
| e7a6b84107 | |||
| 02c3254961 | |||
| a90e1d7ccf | |||
| 6cdd64ac55 | |||
| aa1201ffb8 | |||
| 9b491c2f49 | |||
| be3e2ba521 | |||
| ccbb9e90ea | |||
| d07fe997a9 | |||
| b60996bcd1 | |||
| 272c0aad9c | |||
| 7566f10bb6 | |||
| 847b76b863 | |||
| 5c0ad030cc | |||
| 02aafbd7f4 | |||
| 72da8150bd | |||
| aca2b5336d | |||
| c79b67efc1 | |||
| 30af91ce8e | |||
| 6c56348e54 | |||
| 531b25dc2f | |||
| 8c6dc34654 | |||
| cf2034b93e | |||
| f7db03b8c4 | |||
| 8647e366f9 | |||
| 1bf41d68f9 | |||
| 1ac1f1f889 | |||
| 14f1278485 | |||
| c2c6856159 | |||
| c89f3d2896 | |||
| 8e773470df | |||
| ea4fc7bdda | |||
| 468d1e0903 | |||
| 6851e7b082 | |||
| a734f18fd5 | |||
| 30b1e29785 | |||
| dde0c22195 | |||
| 1311a809db | |||
| 60a54f4880 | |||
| b4e65e7e48 | |||
| 6f3ed4a7b4 | |||
| cc8f8ff0f7 | |||
| 8a00f2d901 | |||
| c5c0e543e4 | |||
| 97255f37da | |||
| fb8a04f97a | |||
| c3ce5ac947 | |||
| eae69049b2 | |||
| 102e8fcc72 | |||
| 8372708f98 | |||
| 5011edc9d9 | |||
| 94a5228ffc | |||
| 382c0cd7c3 | |||
| ab496b23b7 | |||
| 939f428da7 | |||
| 2d496c91e1 | |||
| 442d58b646 | |||
| 4d377b94b7 | |||
| 7248868e33 | |||
| 2eda6464ad | |||
| 2622fc12a6 | |||
| b178e43428 | |||
| d00fca26c5 | |||
| 23e4d1c4aa | |||
| 6871c8bb73 | |||
| 61adc7cf64 | |||
| 9ba30adcba | |||
| 010b2c6262 | |||
| c65fb1a868 | |||
| 2029679ea5 | |||
| 817f70c2cd | |||
| 3a1f0485f4 | |||
| 64910d0781 | |||
| 821462e152 | |||
| b015fd579c | |||
| 8b40a81e22 | |||
| 8be64714ba | |||
| fe5d739cba | |||
| dba0672a11 | |||
| 3ed6acf3ca | |||
| 8c74c54bb0 | |||
| 818473102c | |||
| f1cc4a7805 | |||
| c574af97a4 | |||
| 74ae84e719 | |||
| 98738b6920 | |||
| 2e5769def2 | |||
| 18a6929662 | |||
| 0e61d1134d | |||
| 4abb183735 | |||
| d5b56be4ff | |||
| 1854953d8c | |||
| 2406015c81 | |||
| ec7f14ab96 | |||
| d94cdf4424 | |||
| 40e57b7698 | |||
| 974c658fff | |||
| ad0ddfd7f1 | |||
| 1da8367f55 | |||
| bdbc885811 | |||
| 86e5a5997b | |||
| 9832a0e45b | |||
| addf674621 | |||
| 863c5583ef | |||
| 45cbc6de83 | |||
| e68f766b4d | |||
| 29d7a1acac | |||
| 8d59d14b80 | |||
| ed1883909a | |||
| 049701a8a9 | |||
| 13b7bc89eb | |||
| 92fe44183d | |||
| 8ebc980c17 | |||
| dbeb338bda | |||
| 65ff11a8d0 | |||
| 7a73211484 | |||
| ca049997b1 | |||
| a9f021ccb9 | |||
| 55249c2294 | |||
| c13da56959 | |||
| 665c7cd5d3 | |||
| 469e21cce9 | |||
| 925e09c88a | |||
| 488454c1aa | |||
| c67c52d606 | |||
| e4e11ee509 | |||
| a3e2592555 | |||
| e0e966dadf | |||
| b079a8643b | |||
| 3291a9945f | |||
| 68fd21d0e4 | |||
| 0e1ef96992 | |||
| c377872438 | |||
| 4f42d38e4d | |||
| 7b2243496b | |||
| 960a817d03 | |||
| 6917f9479e | |||
| 8559cc45eb | |||
| 40e33c676d | |||
| d20371040e | |||
| 71faf1c7e3 | |||
| d182f3f743 | |||
| 39e009b945 | |||
| a1873f3e9e | |||
| 636bcaaaf9 | |||
| 3fcbd80ef0 | |||
| 38887e7fbd | |||
| da958e11f9 | |||
| c2ed71c4eb | |||
| 2e1ddcf9f8 | |||
| f1cc2d124c | |||
| 1e32a95f83 | |||
| 9e959bc57f | |||
| e68406ee22 | |||
| ba69e316b2 | |||
| f3e8e8af52 | |||
| c9adab3892 | |||
| c8d1d29017 | |||
| 541acca7c0 | |||
| ddf5099461 | |||
| 781a692b06 | |||
| 9c37f1b370 | |||
| a66c26f4df | |||
| 3bd750bedf | |||
| 4a1ada604c | |||
| e5f57a34a2 | |||
| 20a3737dce |
@@ -0,0 +1,3 @@
|
||||
github: LinusDierheimer
|
||||
ko_fi: carterli
|
||||
custom: https://paypal.me/zhangsongcui
|
||||
@@ -16,6 +16,15 @@ body:
|
||||
options:
|
||||
- label: I have checked the FAQ but the issue is not covered
|
||||
required: true
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Not a known issue
|
||||
description: Please check if the issue is already known and being worked on.
|
||||
options:
|
||||
- label: I have checked the existing issues but the issue is not covered
|
||||
required: true
|
||||
- label: My issue is not about crashing on Fedora and KDE 6.6
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: "### General description of the bug"
|
||||
|
||||
@@ -6,33 +6,42 @@ body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Tip: A logo can be displayed by fastfetch without getting into fastfetch's official repo.
|
||||
For highly customized logo for personal use, it's recommended to keep it locally.
|
||||
Tip: You can display a logo in fastfetch without adding it to fastfetch's official repo.
|
||||
For highly customized, personal logos, we recommend keeping them locally.
|
||||
Please refer to https://github.com/fastfetch-cli/fastfetch/wiki/Migrate-Neofetch-Logo-To-Fastfetch
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: OS
|
||||
description: Paste content of `/etc/os-release` and `/etc/lsb-release` here. If none of these files exist, describe a way to identify the distro
|
||||
description: Paste the contents of `/etc/os-release` and `/etc/lsb-release` here. If neither file exists, describe how to identify the distro.
|
||||
placeholder: cat /etc/os-release
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Distro Website
|
||||
description: To help prevent spam and verify the request, a distro website is required, and a downloadable ISO must be available on that site.
|
||||
placeholder: https://example.com
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: ASCII Art
|
||||
description: An ASCII logo should not take up too much space (smaller than 50x20 characters). Please also include the color codes if not available in `os-release`
|
||||
description: The ASCII logo should not take up too much space (smaller than 50x20 characters, W x H). Please also include the color codes if they are not available in `os-release`.
|
||||
placeholder: Paste ASCII art here
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
attributes:
|
||||
label: Original Image
|
||||
description: If the ASCII art is based on an image, please provide a link to the original image
|
||||
placeholder: Image URL or distro website URL
|
||||
label: Original Image URL
|
||||
description: If the ASCII art is based on an image, please provide a link to the original image file.
|
||||
placeholder: Image URL from the distro website mentioned above
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Checklist
|
||||
options:
|
||||
- label: The ASCII art is smaller than 50x20 characters (width x height)
|
||||
- label: The ASCII art is smaller than 50x20 characters (W x H).
|
||||
required: true
|
||||
- label: The ASCII art contains color codes, or the color codes are available in `os-release`
|
||||
- label: The ASCII art includes color codes, or the color codes are available in `os-release`.
|
||||
required: true
|
||||
- label: The ASCII art has no internal padding (spaces at the start and/or end of lines).
|
||||
required: true
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
## Summary
|
||||
|
||||
<!-- Briefly describe what this PR does. -->
|
||||
|
||||
## Related issue (required for new logos for new distros)
|
||||
|
||||
<!--
|
||||
If this PR adds a new logo, it MUST be linked to an existing "Logo Request" issue and has the requests fulfilled.
|
||||
|
||||
Use one of the following formats so GitHub links it properly:
|
||||
- Closes #1234
|
||||
- Fixes #1234
|
||||
- Resolves #1234
|
||||
|
||||
PRs that add logos without an associated Logo Request issue will not be accepted.
|
||||
-->
|
||||
|
||||
Closes #
|
||||
|
||||
## Changes
|
||||
|
||||
-
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] I have tested my changes locally.
|
||||
+247
-254
@@ -4,13 +4,16 @@ on:
|
||||
- push
|
||||
- pull_request
|
||||
|
||||
env:
|
||||
CMAKE_BUILD_TYPE: ${{ vars.CMAKE_BUILD_TYPE || 'RelWithDebInfo' }}
|
||||
|
||||
jobs:
|
||||
spellcheck:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Install codespell
|
||||
shell: bash
|
||||
@@ -29,13 +32,13 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_XFCONF=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_DIRECTX_HEADERS=OFF -DENABLE_THREADS=OFF
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr . -DENABLE_VULKAN=OFF -DENABLE_WAYLAND=OFF -DENABLE_XCB_RANDR=OFF -DENABLE_XCB=OFF -DENABLE_XRANDR=OFF -DENABLE_X11=OFF -DENABLE_DRM=OFF -DENABLE_DRM_AMDGPU=OFF -DENABLE_GIO=OFF -DENABLE_DCONF=OFF -DENABLE_DBUS=OFF -DENABLE_SQLITE3=OFF -DENABLE_RPM=OFF -DENABLE_IMAGEMAGICK7=OFF -DENABLE_IMAGEMAGICK6=OFF -DENABLE_CHAFA=OFF -DENABLE_ZLIB=OFF -DENABLE_EGL=OFF -DENABLE_GLX=OFF -DENABLE_OPENCL=OFF -DENABLE_FREETYPE=OFF -DENABLE_PULSE=OFF -DENABLE_DDCUTIL=OFF -DENABLE_ELF=OFF -DENABLE_THREADS=OFF
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
@@ -58,17 +61,24 @@ jobs:
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
|
||||
linux-amd64:
|
||||
name: Linux-amd64
|
||||
runs-on: ubuntu-22.04
|
||||
linux-hosts:
|
||||
name: Linux-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
runs-on: ubuntu-22.04
|
||||
- arch: aarch64
|
||||
runs-on: ubuntu-22.04-arm
|
||||
outputs:
|
||||
ffversion: ${{ steps.ffversion.outputs.ffversion }}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -79,8 +89,11 @@ jobs:
|
||||
- name: cat /proc/cpuinfo
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: add gcc-13 repo
|
||||
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev directx-headers-dev
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
@@ -88,18 +101,20 @@ jobs:
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
if: matrix.arch == 'amd64'
|
||||
uses: github/codeql-action/init@v4
|
||||
with:
|
||||
languages: c
|
||||
|
||||
- name: configure project
|
||||
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
- name: perform CodeQL analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
if: matrix.arch == 'amd64'
|
||||
uses: github/codeql-action/analyze@v4
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
@@ -123,21 +138,33 @@ jobs:
|
||||
id: ffversion
|
||||
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: polyfill glibc
|
||||
run: |
|
||||
wget https://github.com/CarterLi/polyfill-glibc/releases/download/v0.0.1/polyfill-glibc-${{ matrix.arch }} -O polyfill-glibc
|
||||
chmod +x polyfill-glibc
|
||||
strip fastfetch && ./polyfill-glibc fastfetch --target-glibc=2.17
|
||||
strip flashfetch && ./polyfill-glibc flashfetch --target-glibc=2.17
|
||||
echo 'set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_FILE_NAME}-polyfilled")' >> CPackConfig.cmake
|
||||
echo 'set(CPACK_PACKAGE_RELOCATABLE OFF)' >> CPackConfig.cmake
|
||||
echo 'set(CPACK_DEBIAN_PACKAGE_DEPENDS "libc6 (>= 2.17)")' >> CPackConfig.cmake
|
||||
echo 'set(CPACK_RPM_SPEC_MORE_DEFINE "%global __os_install_post %{nil}")' >> CPackConfig.cmake
|
||||
cpack -V
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-linux-amd64
|
||||
name: fastfetch-linux-${{ matrix.arch }}
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
linux-aarch64:
|
||||
name: Linux-aarch64
|
||||
runs-on: ubuntu-22.04-arm
|
||||
linux-i686:
|
||||
name: Linux-i686
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -148,20 +175,29 @@ jobs:
|
||||
- name: cat /proc/cpuinfo
|
||||
run: cat /proc/cpuinfo
|
||||
|
||||
- name: add gcc-13 repo
|
||||
run: sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
|
||||
- name: install required packages
|
||||
run: sudo apt-get update && sudo apt-get install -y libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev libchafa-dev libddcutil-dev rpm
|
||||
run: sudo apt-get update && sudo apt-get install -y gcc-13 gcc-13-multilib libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev libddcutil-dev rpm ninja-build
|
||||
|
||||
- name: install linuxbrew packages
|
||||
run: |
|
||||
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||
/home/linuxbrew/.linuxbrew/bin/brew install imagemagick chafa --ignore-dependencies
|
||||
|
||||
- name: cmake version
|
||||
run: cmake --version
|
||||
|
||||
- name: configure project
|
||||
run: PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
run: CC=gcc-13 PKG_CONFIG_PATH=/home/linuxbrew/.linuxbrew/lib/pkgconfig:$PKG_CONFIG_PATH cmake -DCMAKE_C_FLAGS="-m32 -march=i686 -mtune=i686" -DCMAKE_SYSTEM_PROCESSOR_OVERRIDE=i686 -DCPACK_DEBIAN_PACKAGE_ARCHITECTURE=i386 -GNinja -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
|
||||
- name: check deb package
|
||||
run: dpkg -I fastfetch-*.deb
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
|
||||
@@ -180,14 +216,10 @@ jobs:
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: get fastfetch version
|
||||
id: ffversion
|
||||
run: echo "ffversion=$(./fastfetch --version-raw)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-linux-aarch64
|
||||
name: fastfetch-linux-i686
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
linux-armv7l:
|
||||
@@ -198,23 +230,24 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: armv7
|
||||
distro: ubuntu20.04
|
||||
distro: ubuntu22.04
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y wget
|
||||
# CMake installed by apt has bug `list sub-command REMOVE_ITEM requires two or more arguments`
|
||||
wget --no-check-certificate https://apt.kitware.com/ubuntu/pool/main/c/cmake/{cmake_3.29.2-0kitware1ubuntu20.04.1_armhf.deb,cmake-data_3.29.2-0kitware1ubuntu20.04.1_all.deb}
|
||||
dpkg -i *.deb
|
||||
apt-get install -y make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
apt-get update && apt-get install -y software-properties-common ca-certificates gpg curl
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
curl -L https://apt.kitware.com/keys/kitware-archive-latest.asc | gpg --dearmor - | tee /usr/share/keyrings/kitware-archive-keyring.gpg >/dev/null
|
||||
echo 'deb [signed-by=/usr/share/keyrings/kitware-archive-keyring.gpg] https://apt.kitware.com/ubuntu/ jammy main' | tee /etc/apt/sources.list.d/kitware.list >/dev/null
|
||||
echo -e 'Acquire::https::Verify-Peer "false";\nAcquire::https::Verify-Host "false";' >> /etc/apt/apt.conf.d/99ignore-certificates
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -224,7 +257,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-linux-armv7l
|
||||
path: ./fastfetch-*.*
|
||||
@@ -237,7 +270,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
@@ -249,7 +282,7 @@ jobs:
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y wget
|
||||
apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev directx-headers-dev rpm
|
||||
apt-get install -y cmake make gcc libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libelf-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -260,32 +293,40 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-linux-armv6l
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
linux-riscv64:
|
||||
name: Linux-riscv64
|
||||
runs-on: ubuntu-24.04
|
||||
linux-vms:
|
||||
name: Linux-${{ matrix.arch }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: riscv64
|
||||
- arch: ppc64le
|
||||
- arch: s390x
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: riscv64
|
||||
arch: ${{ matrix.arch }}
|
||||
distro: ubuntu22.04
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libddcutil-dev libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
apt-get update && apt-get install -y software-properties-common
|
||||
add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
apt-get update && apt-get install -y cmake make gcc-13 libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev rpm
|
||||
CC=gcc-13 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -295,86 +336,16 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-linux-riscv64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
linux-ppc64le:
|
||||
name: Linux-ppc64le
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: ppc64le
|
||||
distro: ubuntu20.04
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-linux-ppc64le
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
linux-s390x:
|
||||
name: Linux-s390x
|
||||
runs-on: ubuntu-24.04
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: run VM
|
||||
uses: uraimo/run-on-arch-action@v3
|
||||
id: runcmd
|
||||
with:
|
||||
arch: s390x
|
||||
distro: ubuntu20.04
|
||||
githubToken: ${{ github.token }}
|
||||
run: |
|
||||
uname -a
|
||||
apt-get update && apt-get install -y cmake make g++ libvulkan-dev libwayland-dev libxrandr-dev libxcb-randr0-dev libdconf-dev libdbus-1-dev libmagickcore-dev libxfconf-0-dev libsqlite3-dev librpm-dev libegl-dev libglx-dev ocl-icd-opencl-dev libpulse-dev libdrm-dev libchafa-dev libelf-dev directx-headers-dev rpm
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_INSTALL_PREFIX=/usr .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: fastfetch-linux-s390x
|
||||
name: fastfetch-linux-${{ matrix.arch }}
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
musl-amd64:
|
||||
name: Musl-amd64
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: setup alpine linux
|
||||
uses: jirutka/setup-alpine@master
|
||||
@@ -383,7 +354,7 @@ jobs:
|
||||
run: |
|
||||
cat /etc/alpine-release
|
||||
uname -a
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev xfconf-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
apk add cmake samurai vulkan-loader-dev libxcb-dev libxrandr-dev rpm-dev wayland-dev libdrm-dev dconf-dev imagemagick-dev chafa-dev zlib-dev dbus-dev mesa-dev opencl-dev sqlite-dev networkmanager-dev pulseaudio-dev ddcutil-dev elfutils-dev gcc g++
|
||||
shell: alpine.sh --root {0}
|
||||
|
||||
- name: build
|
||||
@@ -403,20 +374,27 @@ jobs:
|
||||
shell: alpine.sh {0}
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-musl-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
macos-universal:
|
||||
name: macOS-universal
|
||||
runs-on: macos-latest
|
||||
macos-hosts:
|
||||
name: macOS-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
runs-on: macos-15-intel
|
||||
- arch: aarch64
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: uname -a
|
||||
run: uname -a
|
||||
@@ -426,7 +404,7 @@ jobs:
|
||||
HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install --overwrite vulkan-loader vulkan-headers molten-vk imagemagick chafa
|
||||
|
||||
- name: configure project
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DCMAKE_OSX_ARCHITECTURES='arm64;x86_64' .
|
||||
run: cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --target package --verbose -j4
|
||||
@@ -435,10 +413,10 @@ jobs:
|
||||
run: ./fastfetch --list-features
|
||||
|
||||
- name: run fastfetch
|
||||
run: time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
run: time ./fastfetch -c presets/ci.jsonc --structure-disabled vulkan --stat false
|
||||
|
||||
- name: run fastfetch --format json
|
||||
run: time ./fastfetch -c presets/ci.jsonc --format json
|
||||
run: time ./fastfetch -c presets/ci.jsonc --structure-disabled vulkan --format json
|
||||
|
||||
- name: run flashfetch
|
||||
run: time ./flashfetch
|
||||
@@ -450,42 +428,80 @@ jobs:
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-macos-universal
|
||||
name: fastfetch-macos-${{ matrix.arch }}
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
sunos-amd64:
|
||||
omnios-amd64:
|
||||
runs-on: ubuntu-latest
|
||||
name: SunOS-amd64
|
||||
name: OmniOS-amd64
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/omnios-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
envs: 'CMAKE_BUILD_TYPE'
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg update --accept
|
||||
pkg install gcc13 cmake git pkg-config glib2 dbus sqlite-3 imagemagick
|
||||
pkg install gcc14 cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja
|
||||
|
||||
run: |
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -GNinja .
|
||||
cmake --build . --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
cpack
|
||||
echo 'set(CPACK_PACKAGE_FILE_NAME "fastfetch-omnios-amd64")' >> CPackConfig.cmake
|
||||
cpack -V
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-sunos-amd64
|
||||
name: fastfetch-omnios-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
solaris-amd64:
|
||||
runs-on: ubuntu-latest
|
||||
name: Solaris-amd64
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/solaris-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
envs: 'CMAKE_BUILD_TYPE'
|
||||
release: "11.4-gcc-14"
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg install cmake git pkg-config glib2 dbus sqlite-3 imagemagick ninja dconf mesa
|
||||
|
||||
run: |
|
||||
export PKG_CONFIG_PATH=/usr/lib/64/pkgconfig
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -GNinja .
|
||||
cmake --build . --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
echo 'set(CPACK_PACKAGE_FILE_NAME "fastfetch-solaris-amd64")' >> CPackConfig.cmake
|
||||
cpack -V
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-solaris-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
freebsd-amd64:
|
||||
@@ -496,7 +512,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -505,11 +521,12 @@ jobs:
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: '14.2'
|
||||
version: '15.0'
|
||||
environment_variables: 'CMAKE_BUILD_TYPE'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg update
|
||||
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa
|
||||
sudo pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
@@ -520,7 +537,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-freebsd-amd64
|
||||
path: ./fastfetch-*.*
|
||||
@@ -533,7 +550,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -542,11 +559,13 @@ jobs:
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: '7.6'
|
||||
version: '7.8'
|
||||
environment_variables: 'CMAKE_BUILD_TYPE'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkg_add -r cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 xfconf imagemagick chafa
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
sudo pkg_add -u
|
||||
sudo pkg_add -r llvm-21.1.2p0 cmake git pkgconf wayland vulkan-headers vulkan-loader glib2 dconf dbus sqlite3 imagemagick chafa
|
||||
CC=clang-21 cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -556,7 +575,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-openbsd-amd64
|
||||
path: ./fastfetch-*.*
|
||||
@@ -569,7 +588,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
@@ -579,10 +598,11 @@ jobs:
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: '10.1'
|
||||
environment_variables: 'CMAKE_BUILD_TYPE'
|
||||
run: |
|
||||
uname -a
|
||||
sudo pkgin -y install cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick opencl-headers ocl-icd
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
sudo pkgin -y install clang cmake git pkgconf wayland vulkan-headers dconf dbus sqlite3 ImageMagick
|
||||
CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -592,7 +612,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-netbsd-amd64
|
||||
path: ./fastfetch-*.*
|
||||
@@ -600,25 +620,25 @@ jobs:
|
||||
dragonfly-amd64:
|
||||
name: DragonFly-amd64
|
||||
runs-on: ubuntu-latest
|
||||
if: false
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: vmactions/dragonflybsd-vm@v1
|
||||
with:
|
||||
usesh: yes
|
||||
envs: 'CMAKE_BUILD_TYPE'
|
||||
prepare: |
|
||||
uname -a
|
||||
pkg update
|
||||
pkg install -y cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl xfce4-conf egl opencl ocl-icd v4l_compat chafa libelf
|
||||
pkg install -y llvm cmake git pkgconf binutils wayland vulkan-headers vulkan-loader libxcb libXrandr libX11 libdrm glib dconf dbus sqlite3-tcl egl opencl ocl-icd v4l_compat chafa libelf
|
||||
|
||||
run: |
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
env CC=clang cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
@@ -628,7 +648,7 @@ jobs:
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-dragonfly-amd64
|
||||
path: ./fastfetch-*.*
|
||||
@@ -636,72 +656,83 @@ jobs:
|
||||
haiku-amd64:
|
||||
name: Haiku-amd64
|
||||
runs-on: ubuntu-latest
|
||||
if: false
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: run VM
|
||||
uses: cross-platform-actions/action@master
|
||||
with:
|
||||
operating_system: haiku
|
||||
version: 'r1beta5'
|
||||
architecture: x86-64
|
||||
cpu_count: 4
|
||||
shell: bash
|
||||
version: 'r1beta5'
|
||||
environment_variables: 'CMAKE_BUILD_TYPE'
|
||||
run: |
|
||||
uname -a
|
||||
ls -l
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
|
||||
pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10 || pkgman install -y git dbus_devel mesa_devel libelf_devel imagemagick_devel opencl_headers ocl_icd_devel vulkan_devel zlib_devel chafa_devel cmake gcc make pkgconfig python3.10
|
||||
cmake -DSET_TWEAK=Off -DBUILD_TESTS=On -DENABLE_EMBEDDED_PCIIDS=On -DENABLE_EMBEDDED_AMDGPUIDS=On .
|
||||
cmake --build . --target package --verbose -j4
|
||||
./fastfetch --list-features
|
||||
time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
time ./fastfetch -c presets/ci.jsonc --format json
|
||||
time ./flashfetch
|
||||
ldd fastfetch
|
||||
ctest --output-on-failure
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-haiku-amd64
|
||||
path: ./fastfetch-*.*
|
||||
|
||||
windows-amd64:
|
||||
name: Windows-amd64
|
||||
runs-on: windows-latest
|
||||
windows-hosts:
|
||||
name: Windows-${{ matrix.arch }}
|
||||
runs-on: ${{ matrix.runs-on }}
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- arch: amd64
|
||||
runs-on: windows-latest
|
||||
msystem: CLANG64
|
||||
msystem-lower: clang64
|
||||
msys-arch: x86_64
|
||||
- arch: aarch64
|
||||
runs-on: windows-11-arm
|
||||
msystem: CLANGARM64
|
||||
msystem-lower: clangarm64
|
||||
msys-arch: aarch64
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: CLANG64
|
||||
msystem: ${{ matrix.msystem }}
|
||||
update: true
|
||||
install: git mingw-w64-clang-x86_64-7zip mingw-w64-clang-x86_64-cmake mingw-w64-clang-x86_64-clang mingw-w64-clang-x86_64-vulkan-loader mingw-w64-clang-x86_64-vulkan-headers mingw-w64-clang-x86_64-opencl-icd mingw-w64-clang-x86_64-opencl-headers mingw-w64-clang-x86_64-cppwinrt mingw-w64-clang-x86_64-imagemagick
|
||||
install: git mingw-w64-clang-${{ matrix.msys-arch }}-7zip mingw-w64-clang-${{ matrix.msys-arch }}-cmake mingw-w64-clang-${{ matrix.msys-arch }}-clang mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-loader mingw-w64-clang-${{ matrix.msys-arch }}-vulkan-headers mingw-w64-clang-${{ matrix.msys-arch }}-opencl-icd mingw-w64-clang-${{ matrix.msys-arch }}-opencl-headers mingw-w64-clang-${{ matrix.msys-arch }}-cppwinrt mingw-w64-clang-${{ matrix.msys-arch }}-imagemagick mingw-w64-clang-${{ matrix.msys-arch }}-chafa mingw-w64-clang-${{ matrix.msys-arch }}-directx-headers
|
||||
|
||||
- name: print msys version
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: env PKG_CONFIG_PATH=/clang64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
run: env PKG_CONFIG_PATH=/${{ matrix.msystem-lower }}/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --verbose -j4
|
||||
|
||||
- name: copy necessary dlls
|
||||
run: cp /clang64/bin/{OpenCL,vulkan-1}.dll .
|
||||
run: cp /${{ matrix.msystem-lower }}/bin/{OpenCL,vulkan-1}.dll .
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
@@ -721,100 +752,62 @@ jobs:
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
|
||||
- name: create zip archive
|
||||
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-amd64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: create 7z archive
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-amd64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
|
||||
id: upload-unsigned-artifact
|
||||
name: upload artifacts for signing
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-windows-amd64
|
||||
path: ./fastfetch-windows-amd64.*
|
||||
name: fastfetch-windows-${{ matrix.arch }}
|
||||
path: |
|
||||
*.dll
|
||||
fastfetch.exe
|
||||
flashfetch.exe
|
||||
|
||||
windows-aarch64:
|
||||
name: Windows-aarch64
|
||||
runs-on: windows-11-arm
|
||||
permissions:
|
||||
security-events: write
|
||||
contents: read
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
steps:
|
||||
- name: checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: setup-msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
- if: github.event_name == 'push' && github.repository == 'fastfetch-cli/fastfetch'
|
||||
name: submit signing request
|
||||
uses: signpath/github-action-submit-signing-request@v1
|
||||
with:
|
||||
msystem: CLANGARM64
|
||||
update: true
|
||||
install: git mingw-w64-clang-aarch64-7zip mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-vulkan-loader mingw-w64-clang-aarch64-vulkan-headers mingw-w64-clang-aarch64-opencl-icd mingw-w64-clang-aarch64-opencl-headers mingw-w64-clang-aarch64-cppwinrt mingw-w64-clang-aarch64-imagemagick
|
||||
|
||||
- name: print msys version
|
||||
run: uname -a
|
||||
|
||||
- name: configure project
|
||||
run: env PKG_CONFIG_PATH=/clangarm64/lib/pkgconfig/:$PKG_CONFIG_PATH cmake -DSET_TWEAK=Off -DBUILD_TESTS=On .
|
||||
|
||||
- name: build project
|
||||
run: cmake --build . --verbose -j4
|
||||
|
||||
- name: copy necessary dlls
|
||||
run: cp /clangarm64/bin/{OpenCL,vulkan-1}.dll .
|
||||
|
||||
- name: list features
|
||||
run: ./fastfetch --list-features
|
||||
|
||||
- name: run fastfetch
|
||||
run: time ./fastfetch -c presets/ci.jsonc --stat false
|
||||
|
||||
- name: run fastfetch --format json
|
||||
run: time ./fastfetch -c presets/ci.jsonc --format json
|
||||
|
||||
- name: run flashfetch
|
||||
run: time ./flashfetch
|
||||
|
||||
- name: print dependencies
|
||||
run: ldd fastfetch
|
||||
|
||||
- name: run tests
|
||||
run: ctest --output-on-failure
|
||||
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
|
||||
organization-id: '${{ vars.SIGNPATH_ORG_ID }}'
|
||||
project-slug: 'fastfetch'
|
||||
signing-policy-slug: ${{ github.ref == 'refs/heads/master' && 'release-signing' || 'test-signing' }}
|
||||
github-artifact-id: '${{ steps.upload-unsigned-artifact.outputs.artifact-id }}'
|
||||
wait-for-completion: true
|
||||
output-artifact-directory: '.'
|
||||
|
||||
- name: create zip archive
|
||||
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-aarch64.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
run: 7z a -tzip -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.zip LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: create 7z archive
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-aarch64.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
run: 7z a -t7z -mx9 -bd -y fastfetch-windows-${{ matrix.arch }}.7z LICENSE *.dll fastfetch.exe flashfetch.exe presets
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
- name: upload true artifacts
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: fastfetch-windows-aarch64
|
||||
path: ./fastfetch-windows-aarch64.*
|
||||
name: fastfetch-windows-${{ matrix.arch }}
|
||||
path: ./fastfetch-windows-${{ matrix.arch }}.*
|
||||
overwrite: true
|
||||
|
||||
release:
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/master' && github.repository == 'fastfetch-cli/fastfetch'
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- linux-amd64
|
||||
- linux-aarch64
|
||||
- linux-hosts
|
||||
- linux-i686
|
||||
- linux-armv7l
|
||||
- linux-armv6l
|
||||
- linux-riscv64
|
||||
- linux-ppc64le
|
||||
- linux-s390x
|
||||
- linux-vms
|
||||
- musl-amd64
|
||||
- macos-universal
|
||||
- macos-hosts
|
||||
- freebsd-amd64
|
||||
- openbsd-amd64
|
||||
- netbsd-amd64
|
||||
- sunos-amd64
|
||||
- windows-amd64
|
||||
- windows-aarch64
|
||||
- dragonfly-amd64
|
||||
- solaris-amd64
|
||||
- omnios-amd64
|
||||
- haiku-amd64
|
||||
- windows-hosts
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
@@ -825,29 +818,29 @@ jobs:
|
||||
repository: ${{ github.repository }}
|
||||
|
||||
- name: download artifacts
|
||||
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: actions/download-artifact@v4
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: actions/download-artifact@v8
|
||||
|
||||
- name: create release
|
||||
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
tag: ${{ needs.linux-amd64.outputs.ffversion }}
|
||||
tag: ${{ needs.linux-hosts.outputs.ffversion }}
|
||||
commit: ${{ github.sha }}
|
||||
artifactErrorsFailBuild: true
|
||||
artifacts: fastfetch-*/fastfetch-*
|
||||
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-amd64.outputs.ffversion }}/CHANGELOG.md) for details."
|
||||
body: "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-hosts.outputs.ffversion }}/CHANGELOG.md) for details."
|
||||
|
||||
- name: download source tarballs
|
||||
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
run: |
|
||||
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux-amd64.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
|
||||
for i in 1 2 3 4 5; do curl -L --remote-name-all --output-dir fastfetch-source --create-dirs https://github.com/${{ github.repository }}/archive/refs/tags/${{ needs.linux-hosts.outputs.ffversion }}.{tar.gz,zip} && break || sleep 5; done
|
||||
ls fastfetch-*/*
|
||||
|
||||
- name: generate release notes
|
||||
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
run: |
|
||||
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-amd64.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
|
||||
echo "Please refer to [CHANGELOG.md](https://github.com/${{ github.repository }}/blob/${{ needs.linux-hosts.outputs.ffversion }}/CHANGELOG.md) for details." > fastfetch-release-notes.md
|
||||
echo -e "\n---\n\n<details><summary>SHA256SUMs</summary><br>\n\n\`\`\`" >> fastfetch-release-notes.md
|
||||
sha256sum fastfetch-*/* >> fastfetch-release-notes.md
|
||||
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
|
||||
@@ -856,10 +849,10 @@ jobs:
|
||||
echo -e "\`\`\`\n</details>" >> fastfetch-release-notes.md
|
||||
|
||||
- name: update release body
|
||||
if: needs.linux-amd64.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
if: needs.linux-hosts.outputs.ffversion != steps.get_version_release.outputs.release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
tag: ${{ needs.linux-amd64.outputs.ffversion }}
|
||||
tag: ${{ needs.linux-hosts.outputs.ffversion }}
|
||||
commit: ${{ github.sha }}
|
||||
bodyFile: fastfetch-release-notes.md
|
||||
allowUpdates: true
|
||||
|
||||
+670
@@ -1,3 +1,673 @@
|
||||
# 2.61.0
|
||||
|
||||
Changes:
|
||||
* Support for Windows 7 and 8 has been removed.
|
||||
* Windows 8.1 is now the oldest version supported by fastfetch.
|
||||
* The GPU module on WSL no longer relies on `DXCore`.
|
||||
* The `directx-headers` dependency is no longer required.
|
||||
* Fastfetch on Linux is now pure C; a C++ compiler is no longer required.
|
||||
* GPU type detection is now slightly less accurate, but detection speed should be slightly faster.
|
||||
* The GPU module on Windows now uses `DXCore` for more accurate GPU type detection (requires Windows 10 or later).
|
||||
* This feature is built only when `DXCore` headers are available, which requires installing `mingw-w64-<msystem>-x86_64-directx-headers` on MSYS2.
|
||||
|
||||
Features:
|
||||
* Adds a `brightness` option for color display configuration (#2238, Colors)
|
||||
* Adds support for detecting Bluetooth keyboards on Linux (#2220, Keyboard)
|
||||
* Adds support for detecting GlazeWM (WM, macOS)
|
||||
* Adds a `showEmptySlots` option to display empty memory slots on Linux (#2222, PhysicalMemory)
|
||||
* Adds marketing product name detection on Asahi Linux (Host, Linux)
|
||||
* Adds support for new M5 Mac models (Host, macOS)
|
||||
* Improves SMBIOS robustness by validating malformed data and improving error handling
|
||||
* Improves reliability when terminating child processes (Processing, Windows)
|
||||
* Improves Intel Mac support by querying SMBIOS data directly (Global, macOS)
|
||||
* Includes numerous internal cleanups and optimizations
|
||||
|
||||
Bugfixes:
|
||||
* Fixes missing memory devices on some machines (PhysicalMemory)
|
||||
* Fixes CPUCache deduplication for shared caches (#2228, CPUCache, Linux)
|
||||
* Fixes WM version reporting for niri (#2218, WM, Linux)
|
||||
* Fixes SSID decoding issues from `iw` output (Wifi, Linux)
|
||||
* Fixes the CMD code page being changed after running fastfetch on Windows (#2245, Windows)
|
||||
|
||||
# 2.60.0
|
||||
|
||||
Changes:
|
||||
* The CMake option `ENABLE_WIN7_COMPAT:BOOLEAN` now defaults to `OFF` and will be removed in v2.61.0, effectively dropping support for Windows 7 in the next release.
|
||||
* This follows the Windows 7 deprecation notice introduced in v2.57.0.
|
||||
* `wm.detectPlugin` now defaults to `true` (WM)
|
||||
|
||||
Features:
|
||||
* Adds `{cwd}` for custom title formatting, which displays the current working directory (Title)
|
||||
* Adds support for detecting the Zed version (#2200, Editor)
|
||||
* Adds support for detecting `moss` packages (Packages, Linux)
|
||||
* Adds support for detecting komorebi, FancyWM, and GlazeWM (WM, Windows)
|
||||
* Adds support for WM plugin version detection on macOS (WM, macOS)
|
||||
* Adds support for retrieving the executable path on OpenBSD (#2195, OpenBSD)
|
||||
|
||||
Bugfixes:
|
||||
* Fixes a potential segmentation fault caused by dereferencing a negative index (#2198)
|
||||
* Fixes `tempSensor` parsing so that it accepts only string values (#2202, CPU)
|
||||
* Fixes an issue that unexpectedly caused fewer devices to be reported (Keyboard, Linux)
|
||||
* Improves WM detection on LXQt by querying WM settings only when no WM has already been detected (#2199, WM, Linux)
|
||||
* Fixes memory leaks in DBus connection handling and in the OpenGL EGL context lifecycle
|
||||
* Fixes niri version detection on Fedora (WM, Linux)
|
||||
* Includes various internal cleanups and optimizations
|
||||
|
||||
Logos:
|
||||
* Adds `RengeOS` (#2170)
|
||||
* Adds `Emmabuntüs` (#2207)
|
||||
* Updates Artix Linux (#2157)
|
||||
* Updates Linux Mint (#2186)
|
||||
* Renames `Refracted Devuan` to `Refracta`
|
||||
* Renames `ExodiaPredator` to `ExodiaOS`
|
||||
|
||||
# 2.59.0
|
||||
|
||||
Changes:
|
||||
* Fastfetch no longer relies on the unreliable environment variables `$USER` or `%USERPROFILE%` to determine the current username (Title)
|
||||
* People who set `$USER` to customize the Fastfetch title should use `{ "type": "title", "format": "your-custom-user-name" }` to achieve the same result.
|
||||
* Fastfetch no longer tries to probe inaccessible remote disk drives on Windows (Disk, Windows)
|
||||
* People who have remote drives may use `{ "type": "disk", "hideFolders": "X:\\" }` to ignore problematic ones.
|
||||
* This change removes some ugly hacks from the codebase and matches the behavior on `*nix`.
|
||||
|
||||
Features:
|
||||
* Adds Oracle Solaris support (#2176, SunOS)
|
||||
* Adds UID / SID detection (Title)
|
||||
* In custom format: `{user-id}`
|
||||
* Switches to native GPU detection on GNU/Hurd and removes the `libpciaccess` dependency (GPU, Hurd)
|
||||
* Improves memory size detection on macOS (Memory, macOS)
|
||||
* Avoids relying on `hw.memsize_usable` by default, which may not be available on older macOS versions
|
||||
* Improves Windows disk detection accuracy and performance (Disk, Windows)
|
||||
* Adds more ARM CPU parts and removes duplicated cases (CPU, ARM)
|
||||
|
||||
Logos:
|
||||
* Adds 6-color support to the NixOS logo (including the small variant) (#2180)
|
||||
|
||||
# 2.58.0
|
||||
|
||||
An early release to fix compatibility issues with KDE Plasma 6.6.
|
||||
|
||||
Breaking changes:
|
||||
* The `de.slowVersionDetection` option has been removed. Slow version detection is now always enabled, as required on non-FHS-compliant distros (e.g., NixOS). (#2149, DE, Linux)
|
||||
|
||||
Features:
|
||||
* Adds the `--structure-disabled <modules...>` command-line flag to temporarily disable module structure printing.
|
||||
* For example: `fastfetch --structure-disabled colors` removes the color blocks from the default output.
|
||||
* Supports chassis type detection on Linux ARM devices when reported via the device tree (Chassis, Linux)
|
||||
* Supports Bedrock Linux version detection (#2155, OS, Linux)
|
||||
* Honors the `DBPath` and `RootDir` settings in `pacman.conf` when detecting Pacman packages (#2154, Packages, Linux)
|
||||
|
||||
Bugfixes:
|
||||
* Fixes a crash issue on KDE Plasma 6.6 (Display, Linux)
|
||||
* Fixes the Command module not working with `--dynamic-interval` (#2152, Command)
|
||||
* Fixes Quartz Compositor version detection. It now correctly reports the version of `WindowServer` (`SkyLight`) instead of `WindowManager`. (WM, macOS)
|
||||
|
||||
Logos:
|
||||
* Adds Kiss2
|
||||
|
||||
# 2.57.1
|
||||
|
||||
Features:
|
||||
* Tiny performance improvements (Windows)
|
||||
* Improves the reliability of hostname retrieval (Title, Windows)
|
||||
|
||||
Bugfixes:
|
||||
* Fixes potential compilation issues on Linux (#2142, Linux)
|
||||
* Fixes compilation errors on macOS when building with older SDKs (#2140, macOS)
|
||||
* Fixes compilation issues when building with `-DENABLE_SYSTEM_YYJSON=ON` (#2143)
|
||||
|
||||
Logos:
|
||||
* Updates PrismLinux and adds a small variant
|
||||
|
||||
# 2.57.0
|
||||
|
||||
Deprecation notice:
|
||||
* Support for Windows 7 (and 8.x) is deprecated and will be removed in a future release. Extended support for Windows 7 (and 8.1) ended on January 10, 2023. These versions do not officially support ANSI escape codes (running fastfetch on them requires a third-party terminal such as ConEmu). In addition, Windows 7 lacks some APIs used by fastfetch. Fastfetch currently loads these APIs dynamically at runtime to maintain compatibility, but this adds complexity to the codebase and increases the maintenance burden.
|
||||
* A CMake flag `ENABLE_WIN7_COMPAT:BOOLEAN` has been introduced (defaults to `ON` for now). If set to `OFF`, Windows 7 compatibility code is excluded, and the resulting binaries will support only Windows 10 (version 1607 and later) and Windows 11.
|
||||
* The main prebuilt Windows binaries on the Release page (`fastfetch-windows-amd64.*`) are built with `ENABLE_WIN7_COMPAT=OFF`. These are the binaries used by `scoop` and `winget`. Users who need Windows 7 (or 8.x) support can download the `-win7` variant instead.
|
||||
* ~~The `ENABLE_WIN7_COMPAT` CMake option and the `-win7` variant binaries are planned to be removed in 2.60.0~~.
|
||||
|
||||
Features:
|
||||
* Supports COSMIC DE version detection (DE, Linux)
|
||||
* Supports niri version detection (#2121, WM, Linux)
|
||||
* Supports cosmic-term version and terminal font detection (Terminal / TerminalFont, Linux)
|
||||
* Supports urxvt font detection (TerminalFont, Linux) (#2105)
|
||||
* Improves xterm font detection by checking `xterm.vt100.faceName` (TerminalFont, Linux)
|
||||
* Supports Secure Boot detection (Bootmgr, macOS)
|
||||
* Supports DPI scale factor detection on Windows 7 (Display, Windows)
|
||||
* Supports xterm 256-color codes in color configuration
|
||||
* In `display.color`: "`@<color-index>`" (e.g., "`@34`" for color index `34`)
|
||||
* In `*.format` strings: "`#@<color-index>`" (e.g., "`#@34`" for color index `34`)
|
||||
* Improves uptime accuracy on Windows 10+ (Uptime, Windows)
|
||||
* Adds a new module `Logo` to query built-in logo raw data in JSON output (Logo)
|
||||
* Usage: `fastfetch -s logo -l <logo-name> -j # Supported in JSON format only`
|
||||
* Supports shell version detection even if the binary has been deleted (#2136, Shell, Linux)
|
||||
* Overall code refinements and optimizations
|
||||
|
||||
Bugfixes:
|
||||
* Skips local / loopback routes when detecting network interfaces (LocalIP, Linux) (#2127)
|
||||
* Fixes CPU speed detection on s390x (CPU, Linux) (#2129)
|
||||
* Fixes GPU detection error handling and supports case-insensitive PCI ID parsing (GPU, Windows)
|
||||
* Fixes some networking issues and memory leaks (Networking)
|
||||
* Fixes `exePath` reporting relative paths on macOS (Shell, macOS)
|
||||
|
||||
Logos:
|
||||
* Adds openSUSE Tumbleweed braille logo
|
||||
* Adds Xinux
|
||||
* Renames HydraPWK to NetHydra
|
||||
* Fixes colors of deepin and UOS
|
||||
* Fixes colors of macOS and variants
|
||||
|
||||
# 2.56.1
|
||||
|
||||
Features:
|
||||
* Improves compatibility with KDE Plasma 6.5 (#2093, Display)
|
||||
* Adds a `tempSensor` option to specify the sensor name used for CPU temperature detection (CPU)
|
||||
* Example: `{ "type": "cpu", "tempSensor": "hwmon0" /* Use /sys/class/hwmon/hwmon0 for temperature detection */ }`
|
||||
* Refines Memory usage detection on macOS to match Activity Monitor more closely (Memory, macOS)
|
||||
* Minor optimizations
|
||||
|
||||
Bugfixes:
|
||||
* Fixes cache line size detection (CPU, macOS)
|
||||
|
||||
Logos:
|
||||
* Removes Opak
|
||||
* Updates GXDE
|
||||
|
||||
# 2.56.0
|
||||
|
||||
Features:
|
||||
* Enhances config file loading. `--config` and `-c` with relative path now also searches paths defined in `fastfetch --list-config-paths` (typically `~/.config/fastfetch/`)
|
||||
* This allows users to use `fastfetch -c my-config` without needing to specify the full path.
|
||||
* Adds NUMA node count detection (CPU)
|
||||
* Exposed via `{numa-nodes}` in custom format
|
||||
* Supported on Linux, FreeBSD and Windows
|
||||
* Supports the newest Alacritty config format (#2070, TerminalFont)
|
||||
* Detects driver specific info for Zhaoxin GPUs (GPU, Linux)
|
||||
* Detects Android OEM UI for certain OSes (DE, Android)
|
||||
* Improves users detection on Linux (#2064, Users, Linux)
|
||||
* Adds systemd fallback when utmp is unavailable
|
||||
* Fixes resource leaks
|
||||
* Always reports the newest session info
|
||||
* Adds kiss package manager support (#2072, Packages, Linux)
|
||||
* Reports `sshd` if `$SSH_TTY` is not available (Terminal)
|
||||
* Zpool module rewrite (#2051, Zpool)
|
||||
* Adds new Zpool properties: allocated, guid, readOnly
|
||||
* Zpool module now uses runtime lookup for properties to ensure portability
|
||||
* Adds NetBSD (requires `sudo`) and macOS support
|
||||
* Adds `splitLines` option for Command module, which splits the output into sub modules, each containing one line of the output (Command)
|
||||
```
|
||||
* Command output:
|
||||
Line 1
|
||||
Line 2
|
||||
Line 3
|
||||
|
||||
* Old behavior:
|
||||
Command: Line 1
|
||||
Line 2
|
||||
Line 3
|
||||
|
||||
* With `"splitLines": true`:
|
||||
Command 1: Line 1
|
||||
Command 2: Line 2
|
||||
Command 3: Line 3
|
||||
```
|
||||
|
||||
Bugfixes:
|
||||
* Fixes {m,o}ksh version detection on Linux (Shell)
|
||||
* Fixes Alacritty config parsing for TOML format (#2070, TerminalFont)
|
||||
* Improves builtin logo printing for piping and buffering (#2065, Logo)
|
||||
* Uses absolute path when detecting shell and terminal version if available (#2067, TerminalShell)
|
||||
|
||||
Logos:
|
||||
* Updates Codex Linux logo (#2071)
|
||||
* Adds OS/2 Warp logo (#2062)
|
||||
* Adds Amiga logo (#2061)
|
||||
|
||||
# 2.55.1
|
||||
|
||||
Bugfixes:
|
||||
* Fix parallel command execution breaks randomly (#2056 / #2058, Command)
|
||||
* Regression from v2.55.0
|
||||
* Fix `dylib` searching path on macOS (macOS)
|
||||
* Regression from v2.55.0
|
||||
* Fix an uninitialized field (#2057, Display)
|
||||
|
||||
# 2.55.0
|
||||
|
||||
Changes:
|
||||
* Commands are now executed in parallel by default to improve performance (#2045, Command)
|
||||
* This behavior can be disabled in the config file with `"parallel": false` if it causes problems with certain scripts
|
||||
* Folder/filesystem hiding is moved to the detection stage; hidden entries are no longer probed, improving performance (#2043, Disk)
|
||||
|
||||
Features:
|
||||
* Adds `command.parallel` and `command.useStdErr` config options (Command)
|
||||
* `parallel`: set to `false` to disable parallel execution (see Changes above)
|
||||
* `useStdErr`: set to `true` to use stderr output instead of stdout
|
||||
* Adds the command-line flag `--dynamic-interval <interval-in-ms>` to enable dynamic output auto-refresh (#2041)
|
||||
* Due to internal limitations, some modules do not support dynamic updates (notably Display and Media)
|
||||
* Adds support for using the current playing media's cover art as a logo source (Media / Logo)
|
||||
* Usage: `"logo": { "type": "<image-protocol>", "source": "media-cover" }` in JSON config; or `--<image-protocol> media-cover` in command line
|
||||
* Supports local sources only
|
||||
* Adds native GPU detection support on OpenBSD and NetBSD (instead of depending on `libpciaccess`) (GPU)
|
||||
* No functional changes
|
||||
* Root privileges are required to access PCI config space on OpenBSD (as always)
|
||||
* Adds GPU detection support on GNU/Hurd (GPU)
|
||||
* Requires building with `libpciaccess`
|
||||
* Shows Debian point release on Raspberry Pi OS (#2032, OS, Linux)
|
||||
* Adds `Brush` shell version detection (Shell)
|
||||
* Improves Mac family detection via prefix matching (Host)
|
||||
|
||||
Bugfixes:
|
||||
* Ignores `run-parts` during terminal/shell detection (#2048, Terminal / Shell, Linux)
|
||||
* Fixes fish version detection when `LC_ALL` is set (#2014, Shell, Linux)
|
||||
* Hides the module when no desktop icons are found (#2023, Icons, Windows)
|
||||
* Skips auxiliary display controllers to prevent the module from reporting duplicate entries (#2034, GPU, Linux)
|
||||
* Refines Apple rpath handling; fixes building for the Homebrew version on macOS (#1998, CMake)
|
||||
|
||||
Logos:
|
||||
* Adds Vincent OS and MacaroniOS
|
||||
|
||||
# 2.54.0
|
||||
|
||||
Windows binaries in Release page are now signed by SignPath.
|
||||
|
||||
Changes:
|
||||
* Moves macOS and Windows design language detection from the DE module to the Theme module
|
||||
|
||||
Features:
|
||||
* Adds `--json` and `-j` command line flags as a shortcut for `--format json`
|
||||
* Various improvements to the OS module (OS)
|
||||
* Displays point releases for Debian
|
||||
* Displays code names for Ubuntu
|
||||
* Displays build ID for macOS
|
||||
* Displays code names for Windows (previously shown in the Kernel module)
|
||||
* Adds basic support for Wine (Windows)
|
||||
* Adds basic support for hppa and sh architectures (CPU, Linux)
|
||||
* Improves T-Head SoC name detection from the device tree (#1997, CPU, Linux)
|
||||
* Supports glob patterns in `Disk.hideFolders` (Disk)
|
||||
* For example, `/boot/*` will match both `/boot/efi` and `/boot/firmware`
|
||||
* Adds brightness-level detection for external monitor support on Intel macOS (Brightness, macOS)
|
||||
* Adds configurable spacing between icon and text in keys
|
||||
* `display.key.type: "both-N"` where N is `0-4`
|
||||
* Useful for non-monospaced Nerd Fonts
|
||||
* Adds detection support for modern Samsung Exynos SoCs (CPU, Android)
|
||||
* Adds a new CMake option `-DENABLE_WORDEXP=<ON|OFF>` to enable or disable using `wordexp(3)` for acquiring logo file paths (`logo.source`)
|
||||
* Enabled by default for compatibility
|
||||
* Disabling this option reverts to using `glob(3)`, which is less functional but more secure
|
||||
|
||||
Bugfixes:
|
||||
* Avoids integer overflow when calculating swap size (#1988, Swap, Windows)
|
||||
* Trims whitespace from full user name (Title, macOS)
|
||||
* Fixes default font size for Ghostty (#1986, TerminalFont, Linux)
|
||||
* Works around an issue that could report impossibly high memory usage in rare cases (#1988, Memory, Linux)
|
||||
* Fixes incorrect glibc dependency in polyfilled DEB packages (#1983, Linux)
|
||||
* Fixes corrupted binaries in polyfilled RPM packages (#1990, Linux)
|
||||
* Fixes crashes on ancient Android kernels (#1993, Disk, Android)
|
||||
* Fixes incorrect usage of `glob(3)` (OpenBSD)
|
||||
* Prefers resolutions reported by RandR mode info, fixing incorrect resolutions on XFCE when DPI scaling is enabled (Display, Linux)
|
||||
* Various code cleanups and minor fixes
|
||||
|
||||
Logos:
|
||||
* Adds secureblue, PrismLinux, EmperorOS and Zraxyl
|
||||
* Updates T2
|
||||
|
||||
# 2.53.0
|
||||
|
||||
Changes:
|
||||
* JSON property `length` in `Separator` module has been renamed to `times` for clarity (Separator)
|
||||
|
||||
Features:
|
||||
* Adds IPv6 type selection (#1459, LocalIP)
|
||||
* For example: `{ "type": "localip", "showIpv6": "ula" /* Show ULA only */ }`
|
||||
* Adds more ARM CPU part IDs (CPU, Linux)
|
||||
* Improves Ghostty font config parsing with fallback font detection (#1967, TerminalFont)
|
||||
* Replaces statx(2) call with syscall(2) for better compatibility (Disk, Linux)
|
||||
* Allows array input for disk folder and filesystem options (Disk)
|
||||
* For example: `{ "type": "disk", "folders": ["/", "/home"] }`
|
||||
* Adds support for ignoring input devices by name prefix (#1950, Keyboard / Mouse / Gamepad)
|
||||
* For example: `{ "type": "keyboard", "ignores": ["Apple ", "Corsair "] }`
|
||||
* Adds support for (B)SSID detection on macOS Tahoe (Wifi, macOS)
|
||||
* Please don't expect it to work on later macOS versions
|
||||
* Improves Ubuntu flavor detection (#1975, OS, Linux)
|
||||
* Refines ARMv8.4-A detection to require LSE2 (CPU, Windows)
|
||||
* Detects the latest Dimensity & Snapdragon SoC names (CPU, Android)
|
||||
|
||||
Bugfixes:
|
||||
* Handles zero temperature data (#1960, CPU, Windows)
|
||||
* Fixes `dlopen libzfs.so failed` error on Proxmox 9 (#1973, Zpool, Linux)
|
||||
|
||||
Logos:
|
||||
* Removes Starry Linux
|
||||
* Adds TempleOS
|
||||
* Updates ObsidianOS
|
||||
|
||||
# 2.52.0
|
||||
|
||||
Changes:
|
||||
* New optional build dependencies on Android
|
||||
* main: chafa dbus glib imagemagick libelf libxcb libxrandr pulseaudio zlib
|
||||
* x11: dconf (Optional)
|
||||
* Dependency on `libxfconf` is removed. XFCE related detection now uses `libdbus` instead (Linux)
|
||||
* The default format of `Display` module is updated to `{width}x{height} @ {scale-factor}x in {inch}", {refresh-rate} Hz`
|
||||
* Replaced scaled resolution with scale factor for shorter texts and avoiding potential confusion.
|
||||
|
||||
Bugfixes:
|
||||
* Fixes linking on 32-bit Android (#1939)
|
||||
* Skips network interfaces without IPs unless MAC address is requested (#1949, LocalIP)
|
||||
* Fixes unexpected padding when setting `logo.width` with chafa logos (#1947, Logo)
|
||||
* Regression from v2.51.0
|
||||
* Improves Wallpaper detection on XFCE4 (Wallpaper, Linux)
|
||||
* Ignores process `Relay(xxx)` when detecting terminal on WSL2 (Terminal, Linux)
|
||||
|
||||
Features:
|
||||
* Enables X11-related info (i.e., WM/DE) detection on Android (Global, Android)
|
||||
* This requires many dependencies. See above.
|
||||
* Adds scale factors detection for X11 (Display, Linux)
|
||||
* X11 doesn't natively report scale factor as Wayland does. Instead, Fastfetch tries to detect `Xft.dpi` (DPI used by X FreeType for scaling fonts), which is usually set by the WM when DPI scaling is enabled.
|
||||
* It's not always accurate. For example, XFCE4 has a separate config for text scaling, which is unaffected by the global DPI scaling setting.
|
||||
* Adds `display.fraction.trailingZeros: [always|never]` option for fraction formatting
|
||||
* The default value of `display.fraction.ndigits` is changed from `-1` (unlimited) to `2` for usability.
|
||||
* Used for displaying scale factor in Display module mentioned above, alongside other places for printing raw fraction numbers.
|
||||
* Informs users that module-specific CLI options are no longer supported and provide guidance for transitioning to JSON config
|
||||
* Adds CPU name detection support for IA64 (CPU, Linux)
|
||||
* Support Btrfs allocation profile detection (#1941, Btrfs, Linux)
|
||||
|
||||
# 2.51.1
|
||||
|
||||
Bugfixes:
|
||||
* Fix building on macOS 14 or older; no functional changes (CPU, macOS)
|
||||
|
||||
# 2.51.0
|
||||
|
||||
Changes:
|
||||
* Fastfetch now requires [yyjson 0.12](https://github.com/ibireme/yyjson/releases/tag/0.12.0) to build when using `-DENABLE_SYSTEM_YYJSON=ON`.
|
||||
* The Disk module no longer shows hyperlink mountpoints by default, which cause issues on some real consoles (Disk)
|
||||
* Instead, the custom key for the Disk module now supports `{mountpoint-link}` and `{name-link}` to show hyperlinks for mountpoints and names. For example, `{ "type": "disk", "key": "Disk ({mountpoint-link})" }` can be used to restore the old behavior.
|
||||
|
||||
Features:
|
||||
* Adds `succeeded` module condition to JSONC config. When set to `false`, the module will only run if the last module failed (#1908)
|
||||
* Useful for displaying fallback placeholders when a module fails. For example:
|
||||
```jsonc
|
||||
{
|
||||
"host",
|
||||
// If fastfetch fails to detect host info, display "DIY PC" instead
|
||||
{
|
||||
"type": "custom",
|
||||
"condition": {
|
||||
"succeeded": false
|
||||
},
|
||||
"key": "Host",
|
||||
"format": "DIY PC"
|
||||
}
|
||||
}
|
||||
```
|
||||
* By upgrading to yyjson 0.12, fastfetch now adds [JSON5](https://json5.org/) format support for configuration files (#1907)
|
||||
* [JSON5](https://json5.org/) is a superset of JSONC that allows unquoted keys, single quotes, multi-line strings, etc., and is fully compatible with JSONC and strict JSON.
|
||||
* To use JSON5, simply name your config file with a `.json5` extension. The `.jsonc` extension is still supported and used as the default extension for better IDE syntax highlighting support.
|
||||
* Fastfetch has been ported to [`GNU/Hurd`](https://www.gnu.org/software/hurd/) (#1895)
|
||||
* Thanks to the efforts of @yelninei!
|
||||
* Built-in logos now honor `logo.width` (#1905)
|
||||
* When its value is larger than the actual logo width, the logo will be padded with spaces to the right
|
||||
* Adds Trinity DE version detection (#1917, DE, Linux)
|
||||
* Adds formatted free and available disk size fields (#1929, Disk)
|
||||
* `{size-free}`: free size of the disk
|
||||
* `{size-available}`: available size of the disk
|
||||
* See [askubuntu.com](https://askubuntu.com/questions/249387/df-h-used-space-avail-free-space-is-less-than-the-total-size-of-home) for the difference between free and available size
|
||||
* Adds [x86_64 micro-architecture level](https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels) detection (#1928, CPU)
|
||||
* Useful when installing software that requires or is optimized for specific CPU features. E.g., [CachyOS](https://wiki.cachyos.org/features/optimized_repos/)
|
||||
* Exposed via `{march}` in custom format
|
||||
* Adds [Aarch64 micro-architecture level](https://en.wikipedia.org/wiki/AArch64#Profiles) detection (CPU)
|
||||
* Supported on Linux (including Android), macOS and Windows
|
||||
* This is not fully accurate because there are many optional features across different levels, and not all levels are detectable.
|
||||
* Exposed via `{march}` in custom format.
|
||||
* Adds shepherd detection support (InitSystem, Linux)
|
||||
|
||||
Bugfixes:
|
||||
* Refines GPU detection logic to correctly handle virtual devices (#1920, GPU, Windows)
|
||||
* Fixes possible default route detection failure when the route table is very large (#1919, LocalIP, Linux)
|
||||
* Fastfetch now correctly parses `hwdata/pci.ids` files alongside `pciids/pci.ids` on FreeBSD when detecting GPU names (#1924, GPU, FreeBSD)
|
||||
* Fixes twin WM detection (#1917, WM, Linux)
|
||||
* Various fixes for Android support
|
||||
* Corrects WM name for Android (WM, Android)
|
||||
* Fixes battery temperature detection when running in ADB (Battery, Android)
|
||||
* Adds CPU and GPU temperature detection support (CPU, Android)
|
||||
|
||||
Logos:
|
||||
* Adds AerynOS
|
||||
|
||||
# 2.50.2
|
||||
|
||||
Bugfixes:
|
||||
* Fixes linglong package detection V2 (#1903, Packages, Linux)
|
||||
* Fixes building with `-DENABLE_SYSTEM_YYJSON=ON` (#1904)
|
||||
* Fixes `showMac` does not honor `defaultRouteOnly` (#1902, LocalIP, Linux)
|
||||
* Fixes failing to acquire default route on Linux in certain cases (#1902, LocalIP, Linux)
|
||||
|
||||
# 2.50.1
|
||||
|
||||
Bugfixes:
|
||||
* Fixes percentage bar not displaying correctly in certain cases
|
||||
* Fixes linglong package detection on Debian 13 (#1899, Packages, Linux)
|
||||
|
||||
# 2.50.0
|
||||
|
||||
Changes:
|
||||
* Keys in JSON configuration files are now case-sensitive, as stated in v2.49.0.
|
||||
* This is a breaking change, but it should not affect most users as long as your config file passes JSON schema validation.
|
||||
* All module config flags have been removed, as stated in v2.49.0.
|
||||
* To configure modules via the command line, use: `echo '{"modules": [{"type":"custom","format":"Hello Fastfetch!"}]}' | fastfetch -c -`.
|
||||
* The percent bar config `display.bar.*` options have been replaced with a more organized, nested object structure.
|
||||
* `display.bar.charElapsed` has been renamed to `display.bar.char.elapsed`.
|
||||
* `display.bar.charTotal` has been renamed to `display.bar.char.total`.
|
||||
* `display.bar.borderLeft` has been renamed to `display.bar.border.left`.
|
||||
* `display.bar.borderRight` has been renamed to `display.bar.border.right`.
|
||||
* The undocumented flag `--load-config` has been removed.
|
||||
* Use `--config` or `-c` instead.
|
||||
* Flashfetch, a simplified fastfetch variant that used a hardcoded module list with direct function calls to reduce startup overhead, has been changed to a version that aims to match neofetch's behavior as closely as possible, for demonstration purposes.
|
||||
* Flashfetch is intended to be built from source (like [st](https://st.suckless.org/)). We do not provide prebuilt binaries in distributions.
|
||||
|
||||
Features:
|
||||
* Added support for reading JSON config from stdin using `--config -` or `-c -`.
|
||||
* Added `display.bar.border.{leftElapsed,rightElapsed}` for using the border as part of the bar content. (#1875)
|
||||
* `display.bar.border: null` has been added as a shorthand to disable bar borders.
|
||||
* Added `display.bar.color.{elapsed,total,border}` to customize the color of the elapsed, total, and border sections of the percent bar.
|
||||
* `display.bar.color: null` has been added as a shorthand to disable bar colors.
|
||||
* Improved Bedrock Linux detection (#1881, OS / Disk, Linux)
|
||||
* Added the command flag `--gen-config-full`, which generates a JSON config file containing all optional module options.
|
||||
* Improved the default IP address display when `localip.showAllIPs` is not set (LocalIP)
|
||||
* For IPv4, the preferred source address (if detected) is shown.
|
||||
* For IPv6, the first GUA or ULA that is not deprecated or temporary is shown.
|
||||
* Added support for interface speed detection on SunOS (LocalIP, SunOS)
|
||||
* Added detection support for Xlibre (#1888, WM, Linux)
|
||||
* Improved the accuracy of color detection (Cursor, macOS)
|
||||
* Improved the proformance of `Nix` package manager detection on macOS by porting optimizations form Linux port (#1893, Packages, macOS)
|
||||
|
||||
Bugfixes:
|
||||
* Fixed custom object inheriting a key from the previous custom object if the key is blank (#1477)
|
||||
* Fixed a possible segfault when parsing color strings in the JSON config (#1878)
|
||||
* Fixed GPU driver detection when DRM is used (GPU, FreeBSD)
|
||||
* Fixed default route detection on DragonFly BSD (LocalIP, DFBSD)
|
||||
* Fixed lliurex detection (#1882, OS, Linux)
|
||||
* Fixed compatibility with `-ffast-math` (#1894)
|
||||
* Fixed physical GPU sometimes being ignored (#1896, GPU, Windows)
|
||||
|
||||
Logos:
|
||||
* Added ObsidianOS (#1890)
|
||||
|
||||
# 2.49.0
|
||||
|
||||
Deprecation Notice:
|
||||
* In fastfetch v2, the JSONC configuration format has been introduced, while command line configuration flags are kept for compatibility. Although they have the same effects, they use two different code paths, and as the number of flags grows, the codebase is becoming increasingly difficult to maintain.
|
||||
* Removal of module config flags is planned for **v2.50.0**, which will also fix a long-standing issue #1477.
|
||||
* Removal of most other config flags is also planned for later versions.
|
||||
* Keys of JSON configuration files will be all case-sensitive. Currently they are inconsistent. Planned for **v2.50.0**.
|
||||
|
||||
Changes:
|
||||
* Due to more restrictive permissions in macOS Tahoe, SSID detection on macOS 26+ requires root privileges. `<redacted>` will be displayed otherwise.
|
||||
|
||||
Features:
|
||||
* Improve `nouveau` driver support for `--gpu-driver-specific` (GPU, Linux)
|
||||
* VRAM size detection
|
||||
* GPU temperature detection
|
||||
* Core count detection (when available)
|
||||
* Improve Scoop package manager detection (Packages, Windows)
|
||||
* Support [`scoop-global`](https://github.com/ScoopInstaller/Install?tab=readme-ov-file#advanced-installation)
|
||||
* Read Scoop's config file to find the installation path of Scoop
|
||||
* Improve ARM SoC detection (CPU, Android)
|
||||
* Make SoC detection more lenient. Higher chance to match at the cost of accuracy.
|
||||
* Add more Snapdragon SoC names
|
||||
* Support labwc WM version detection, used for XFCE4 on Wayland (WM, Linux)
|
||||
* Improve accuracy of GPU temperature detection for Intel dedicated GPUs on Windows (GPU, Windows)
|
||||
* Parse unicode escaped strings generated by qt5ct (#1864, Font, Linux)
|
||||
* Add `--{duration,percent,size,freq,temp}-space-before-unit [always|never]` options to add a space before the unit when printing duration, percent, size, frequency and temperature values
|
||||
* Add `--duration-abbreviation` to abbreviate duration values in custom format
|
||||
* For example: `1 day, 2 hours, 3 mins` will be displayed as `1d 2h 3m`
|
||||
* Add `--percent-width` to pad the percent value with spaces to a fixed width
|
||||
* For example: `--percent-width 3` will display ` 50%` instead of `50%`; useful for aligning percent values in custom format
|
||||
|
||||
Bugfixes:
|
||||
* Improve accuracy of Flatpak count detection (#1856, Packages, Linux)
|
||||
* Remove qi package manager support (#1858, Packages, Linux)
|
||||
* Fix LocalIP module on Windows (LocalIP, Windows)
|
||||
* Fix default route detection when multiple network interfaces are connected
|
||||
* Fix link speed calculation
|
||||
* Fix interface status when the interface is up but not connected (Wifi, Linux)
|
||||
* Fix variable names in custom format (#1861)
|
||||
* `full-path` to `path` (Editor)
|
||||
* `session` to `session-name` (Users)
|
||||
* `name` to `project-name` (Version)
|
||||
* Fix wrong /s assignment in custom format (#1871, DiskIO)
|
||||
|
||||
Logos:
|
||||
* Add `Aeon`
|
||||
* Remove `Evolinx`
|
||||
|
||||
# 2.48.1
|
||||
|
||||
Features:
|
||||
* Add support for detecting Openbox WM version (WM, Linux)
|
||||
* Improve reliability of child process spawning on Windows (Windows)
|
||||
* Add a new option `--packages-combined`, which combines related package managers into single counts (#1851, Packages)
|
||||
* For example: if you have both `flatpak-system` and `flatpak-user` packages installed, they will be combined into a single `flatpak` count with `--packages-combined` enabled.
|
||||
* Add `modules[n].condition` to conditionally enable modules on different platforms
|
||||
* Useful when sharing configuration files across platforms
|
||||
* For example:
|
||||
```jsonc
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "This string will be printed on Intel macOS only",
|
||||
"condition": {
|
||||
"system": "macOS", // Can be an array, optional
|
||||
"arch": "x86_64" // Can be an array, optional too
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Bugfixes:
|
||||
* Revert the change of `posix_spawn` in v2.48.0 for Android and OpenBSD (Android / OpenBSD)
|
||||
* Fix completion for Android 7 (Required by Termux)
|
||||
|
||||
# 2.48.0
|
||||
|
||||
Features:
|
||||
* Add support for detecting Fedora variants (#1830, OS, Linux)
|
||||
* Currently supported variants: CoreOS, Kinoite, Sericea, Silverblue
|
||||
* Optimize GPU detection on Windows when `--gpu-driver-specific` is not used (GPU, Windows)
|
||||
* Improve accuracy of GPU type detection. Previously it was guessed based on the dedicated vmem size, which causes issues on newer AMD integrated GPUs such as 9000 HX and AI 9 HX series. Supported on Windows 8.1 or later.
|
||||
* Add support for generic frequency detection of GPU 3D engine on Windows 11 22H2 or later.
|
||||
* Improve performance. GPU temperature detection is significantly improved when `--gpu-driver-specific` is not used.
|
||||
* Improve performance and security when spawning child processes by replacing `fork-exec` with `posix_spawn` (*nix)
|
||||
* Improve accuracy of sound device detection on macOS (Sound, macOS)
|
||||
* Trim leading and trailing whitespaces in disk serial numbers (PhysicalDisk)
|
||||
* Add `/etc/profiles/per-user` detection for Nix user packages (#1782, Packages, Linux)
|
||||
* Introduce `years` (whole years as integer), `days-of-year` (days since the last anniversary) and `years-fraction` (years as fraction, e.g. 1.5 means 1 year and 6 months) formatting placeholder to `Disk` (since disk creation), `Users` (since user login) and `Uptime` (since system boot) modules
|
||||
* For example: `fastfetch -s disk --disk-key 'OS Installation' --disk-format '{years} years {days-of-year} days'`
|
||||
* Add `--fraction-ndigits` option to specify the number of digits after the decimal point when displaying ordinary fractional values
|
||||
* Typically used with `{years-fraction}` above
|
||||
* This option does not affect percentage values, sizes, etc, which are controlled by individual options.
|
||||
|
||||
Bugfixes:
|
||||
* Fix compilation issues when not using `-DBINARY_LINK_TYPE=dlopen`
|
||||
* Regression from v2.47.0
|
||||
* Note: this option was added for debugging purposes only and is not recommended for production use
|
||||
* Replace `MTLDevice::hasUnifiedMemory` with `MTLDevice::location` for GPU type Detection (GPU, macOS)
|
||||
* This should resolve the issue where discrete GPUs were detected as integrated GPUs on Intel MacBooks with multi-GPU configurations.
|
||||
* Prevent text files from being loaded as image files (#1843, Logo)
|
||||
|
||||
Logos:
|
||||
* Add Minimal System
|
||||
* Add AxOS
|
||||
* Rename Ada to Xray OS
|
||||
|
||||
# 2.47.0
|
||||
|
||||
Features:
|
||||
* Various improvements for Solaris / OpenIndiana support
|
||||
* Support BIOS (UEFI or legacy) type detection (BIOS)
|
||||
* Support physical disk detection (PhysicalDisk)
|
||||
* Remove leading `-` from login shells (Shell)
|
||||
* Improve GPU detection performance (GPU)
|
||||
* Drop `libpciaccess` dependency
|
||||
* Use native API to detect sound devices (Sound)
|
||||
* Drop `PulseAudio` dependency
|
||||
* Improve DietPi OS and Raspberry Pi OS detection (#1816, OS, Linux)
|
||||
* Force reporting version 26 on macOS Tahoe (OS, macOS)
|
||||
* Append version string to Ubuntu variants (OS, Linux)
|
||||
* Improve performance of media detection for macOS 15.4+ (Media, macOS)
|
||||
* Increase `PROC_FILE_BUFFSIZ` to avoid possible short reads (Linux)
|
||||
* Fix potential bugs in `DiskIO`, `NetIO` and `CPUUsage` modules
|
||||
* Improve accuracy of CPU usage calculations by including interrupt and softirq times (CPUUsage, Linux / *BSD)
|
||||
* Ignore `init` and `systemd` processes when detecting terminals (Terminal, Linux)
|
||||
* Improve accuracy of CPU usage detection on Windows 10+ with perflib, which matches values reported by Task Manager (CPUUsage, Windows)
|
||||
|
||||
Bugfixes:
|
||||
* Fix `pci.ids` file location (#1819, GPU, OpenBSD)
|
||||
* Fix compiling on FreeBSD when `libdrm` support is disabled (#1820, GPU, FreeBSD)
|
||||
|
||||
Logos:
|
||||
* Improve visibility on white-background terminals for some logos by replacing white with the default foreground color
|
||||
* According to Wikipedia, the default foreground color is implementation-defined. It's usually black for white themes and white for dark themes. However, some terminals, notably Konsole with the default theme, use a different color, which may cause issues with some logos.
|
||||
* Add Xubuntu
|
||||
|
||||
# 2.46.0
|
||||
|
||||
Features:
|
||||
* Support Rio terminal font detection (#1789, TerminalFont, Linux)
|
||||
* Support GPU detection by DRM on FreeBSD (GPU, FreeBSD)
|
||||
* Enable by `--gpu-detection-method auto`
|
||||
* Require proper DRM drivers installed and loaded
|
||||
* Support PowerPC CPU detection on NetBSD (#1802, CPU, NetBSD)
|
||||
* Support Aerospace WM detection (#1796, WM, macOS)
|
||||
* Improve Raspberry Pi OS for RPI5 detection (#1773, OS, Linux)
|
||||
* Support Linux Binary Compatibility detection on FreeBSD (#1786, Host, Linux)
|
||||
* Use `board-id` as board name if available (Board, macOS)
|
||||
* Intel only
|
||||
* Support shared VRAM usage detection for AMD GPUs (GPU, Linux)
|
||||
* Use `perflib.h` instead of `pdh.h` for CPU temperature querying to get rid of `pdh.dll` dependency (#1787, CPU, Windows)
|
||||
* Support GPU info detection for old ATI radeon driver (#1810, GPU, Linux)
|
||||
* Add macOS 26 Tahoe support (macOS)
|
||||
* Report macOS 26 code name (OS)
|
||||
* Report Liquid Glass DE on macOS 26+ (DE)
|
||||
* Detect Metal 4 support (GPU)
|
||||
|
||||
Bugfixes:
|
||||
* Fix packages counting by ignoring hidden folders (Packages, OpenBSD)
|
||||
* Fix Hyprland version detection (WM, FreeBSD)
|
||||
* Don't show `Please insert a disk into drive D:` error dialogs (#1805, Disk, Windows)
|
||||
* Hide `/boot/firmware` by default (Disk, Linux)
|
||||
|
||||
Logos:
|
||||
* Rename Hydra Framework to HydraPwk (#1812)
|
||||
* Add AnushOS (#1806)
|
||||
* Add HarmonyOS (#1804)
|
||||
* Add GhostFreak (#1801)
|
||||
* Add TrueNAS Scale (#1795)
|
||||
* Add Fedora2_small (#1785)
|
||||
* Add xenia_old; update colors of xenia (#1797)
|
||||
* Improve colors of bedrock_small (#1790)
|
||||
* Add Kalpa Desktop (#1807)
|
||||
|
||||
# 2.45.0
|
||||
|
||||
Features:
|
||||
|
||||
+415
-261
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021-2023 Linus Dierheimer
|
||||
Copyright (c) 2022-2025 Carter Li
|
||||
Copyright (c) 2022-2026 Carter Li
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
# Fastfetch
|
||||
|
||||
Fastfetch 是一款类似 neofetch 的系统信息展示工具,主要用 C 编写,强调性能和可定制性。支持 Linux、macOS、Windows 7+、Android、FreeBSD、OpenBSD、NetBSD、DragonFly、Haiku、SunOS。
|
||||
|
||||
示例配置见 presets/examples,更多截图与平台说明见 Wiki。
|
||||
|
||||
## 安装
|
||||
|
||||
Linux(部分):
|
||||
- Debian 13+ / Ubuntu: apt install fastfetch
|
||||
- Arch: pacman -S fastfetch
|
||||
- Fedora: dnf install fastfetch
|
||||
- openSUSE: zypper install fastfetch
|
||||
- Linuxbrew:brew install fastfetch
|
||||
- 各发行版打包状态:https://repology.org/project/fastfetch/versions
|
||||
|
||||
macOS:
|
||||
- Homebrew:brew install fastfetch
|
||||
- MacPorts:sudo port install fastfetch
|
||||
|
||||
Windows:
|
||||
- scoop install fastfetch
|
||||
- choco install fastfetch
|
||||
- winget install fastfetch
|
||||
- MSYS2:pacman -S mingw-w64-<subsystem>-<arch>-fastfetch
|
||||
|
||||
BSD:
|
||||
- FreeBSD:pkg install fastfetch
|
||||
- NetBSD:pkgin in fastfetch
|
||||
- OpenBSD:pkg_add fastfetch
|
||||
|
||||
Android(Termux):
|
||||
- pkg install fastfetch
|
||||
|
||||
Nightly 构建:
|
||||
- https://nightly.link/fastfetch-cli/fastfetch/workflows/ci/dev?preview
|
||||
|
||||
## 源码构建
|
||||
|
||||
基本上是 `cmake . && make`。详见 Wiki:https://github.com/fastfetch-cli/fastfetch/wiki/Building
|
||||
|
||||
## 使用
|
||||
|
||||
- 默认运行:`fastfetch`
|
||||
- 查看所有可用模块示例:`fastfetch -c all.jsonc`
|
||||
- 以 JSON 输出指定模块:`fastfetch -s <module1>[:<module2>] --format json`
|
||||
- 完整命令行帮助:`fastfetch --help`
|
||||
- 生成最小配置:`fastfetch --gen-config [</path/to/config.jsonc>]`
|
||||
- 生成完整配置:`fastfetch --gen-config-full`
|
||||
- 请使用支持 JSON schema 的编辑器(如 VSCode)编辑配置文件!
|
||||
- 如果你连接 Github 有网络困难(智能提示不生效),可将配置文件中的 `$schema` 的值替换为 `https://gitee.com/carterl/fastfetch/raw/dev/doc/json_schema.json`
|
||||
|
||||
## 定制
|
||||
|
||||
- 配置使用 JSONC,语法与选项见 Wiki:https://github.com/fastfetch-cli/fastfetch/wiki/Configuration
|
||||
- 预设示例位于 presets,可用 `-c <filename>` 加载
|
||||
- Logo 选项与图像显示见文档:https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options
|
||||
- 模块格式化(示例,仅显示 GPU 名称):
|
||||
```jsonc
|
||||
{
|
||||
"modules": [
|
||||
{ "type": "gpu", "format": "{name}" }
|
||||
]
|
||||
}
|
||||
```
|
||||
详见:https://github.com/fastfetch-cli/fastfetch/wiki/Format-String-Guide
|
||||
|
||||
## 反馈与支持
|
||||
|
||||
- 使用问题:Discussions https://github.com/fastfetch-cli/fastfetch/discussions
|
||||
- 疑似缺陷:Issues https://github.com/fastfetch-cli/fastfetch/issues(请填写模版)
|
||||
|
||||
## 赞助
|
||||
|
||||
<img src="https://github.com/user-attachments/assets/a36a6501-e8b0-4a10-9061-b9206d12ffba" width="220">
|
||||
@@ -10,8 +10,12 @@
|
||||
[](https://github.com/fastfetch-cli/fastfetch/releases)
|
||||
[](https://repology.org/project/fastfetch/versions)
|
||||
[](https://repology.org/project/fastfetch/versions)
|
||||
[](https://deepwiki.com/fastfetch-cli/fastfetch)
|
||||
[](README-cn.md)
|
||||
|
||||
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 7+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku, and SunOS.
|
||||
Fastfetch is a [neofetch](https://github.com/dylanaraps/neofetch)-like tool for fetching system information and displaying it in a visually appealing way. It is written mainly in C, with a focus on performance and customizability. Currently, it supports Linux, macOS, Windows 8.1+, Android, FreeBSD, OpenBSD, NetBSD, DragonFly, Haiku and SunOS (illumos, Solaris).
|
||||
|
||||
> Note: Fastfetch is only actively tested on x86-64 and aarch64 platforms. It may work on other platforms but is not guaranteed to do so.
|
||||
|
||||
<img src="screenshots/example1.png" width="49%" align="left" />
|
||||
<img src="https://upload.wikimedia.org/wikipedia/commons/2/24/Transparent_Square_Tiles_Texture.png" width="49%" height="16px" align="left" />
|
||||
@@ -35,8 +39,8 @@ Some distributions package outdated versions of fastfetch. Older versions receiv
|
||||
<img src="https://repology.org/badge/vertical-allrepos/fastfetch.svg?columns=2" alt="Packaging status" align="right">
|
||||
</a>
|
||||
|
||||
* Ubuntu: [`ppa:zhangsongcui3371/fastfetch`](https://launchpad.net/~zhangsongcui3371/+archive/ubuntu/fastfetch) (for Ubuntu 22.04 or newer)
|
||||
* Debian: `apt install fastfetch` (for Debian 13 or newer)
|
||||
* Ubuntu: [`ppa:zhangsongcui3371/fastfetch`](https://launchpad.net/~zhangsongcui3371/+archive/ubuntu/fastfetch) (Ubuntu 22.04 or newer; latest version)
|
||||
* Debian / Ubuntu: `apt install fastfetch` (Debian 13 or newer; Ubuntu 25.04 or newer)
|
||||
* Debian / Ubuntu: Download `fastfetch-linux-<proper architecture>.deb` from [Github release page](https://github.com/fastfetch-cli/fastfetch/releases/latest) and double-click it (for Ubuntu 20.04 or newer and Debian 11 or newer).
|
||||
* Arch Linux: `pacman -S fastfetch`
|
||||
* Fedora: `dnf install fastfetch`
|
||||
@@ -57,7 +61,7 @@ If fastfetch is not packaged for your distribution or an outdated version is pac
|
||||
|
||||
### macOS
|
||||
|
||||
* [HomeBrew](https://formulae.brew.sh/formula/fastfetch#default): `brew install fastfetch`
|
||||
* [Homebrew](https://formulae.brew.sh/formula/fastfetch#default): `brew install fastfetch`
|
||||
* [MacPorts](https://ports.macports.org/port/fastfetch/): `sudo port install fastfetch`
|
||||
|
||||
### Windows
|
||||
@@ -69,13 +73,12 @@ If fastfetch is not packaged for your distribution or an outdated version is pac
|
||||
|
||||
You may also download the program directly from [the GitHub releases page](https://github.com/fastfetch-cli/fastfetch/releases/latest) in the form of an archive file.
|
||||
|
||||
### FreeBSD
|
||||
### BSD systems
|
||||
|
||||
* `pkg install fastfetch`
|
||||
|
||||
### NetBSD
|
||||
|
||||
* `pkgin in fastfetch`
|
||||
* FreeBSD: `pkg install fastfetch`
|
||||
* NetBSD: `pkgin in fastfetch`
|
||||
* OpenBSD: `pkg_add fastfetch` (Snapshots only)
|
||||
* DragonFly BSD: `pkg install fastfetch` (Snapshots only)
|
||||
|
||||
### Android (Termux)
|
||||
|
||||
@@ -93,9 +96,10 @@ See the Wiki: https://github.com/fastfetch-cli/fastfetch/wiki/Building
|
||||
|
||||
* Run with default configuration: `fastfetch`
|
||||
* Run with [all supported modules](https://github.com/fastfetch-cli/fastfetch/wiki/Support+Status#available-modules) to find what interests you: `fastfetch -c all.jsonc`
|
||||
* View all data that fastfetch detects: `fastfetch -s <module> --format json`
|
||||
* View all data that fastfetch detects: `fastfetch -s <module1>[:<module2>][:<module3>] --format json`
|
||||
* Display help messages: `fastfetch --help`
|
||||
* Generate a config file based on command line arguments: `fastfetch --arg1 --arg2 --gen-config`
|
||||
* Generate a minimal config file: `fastfetch [-s <module1>[:<module2>]] --gen-config [</path/to/config.jsonc>]`
|
||||
* Use: `--gen-config-full` to generate a full config file with all optional options
|
||||
|
||||
## Customization
|
||||
|
||||
@@ -103,6 +107,10 @@ Fastfetch uses JSONC (JSON with comments) for configuration. [See the Wiki for d
|
||||
|
||||
Logos can also be heavily customized; see the [logo documentation](https://github.com/fastfetch-cli/fastfetch/wiki/Logo-options) for more information.
|
||||
|
||||
### WARNING
|
||||
|
||||
Fastfetch supports a `Command` module that can run arbitrary shell commands. If you copy-paste a config file from an untrusted source, it may contain malicious commands that can harm your system or compromise your privacy. Please always review the config file before using it.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Q: Neofetch is good enough. Why do I need fastfetch?
|
||||
@@ -317,6 +325,11 @@ If you find Fastfetch useful, please consider donating.
|
||||
* Current maintainer: [@CarterLi](https://paypal.me/zhangsongcui)
|
||||
* Original author: [@LinusDierheimer](https://github.com/sponsors/LinusDierheimer)
|
||||
|
||||
## Code signing
|
||||
|
||||
* Free code signing provided by [SignPath.io](https://about.signpath.io/), certificate by [SignPath Foundation](https://signpath.org/)
|
||||
* This program will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it
|
||||
|
||||
## Star History
|
||||
|
||||
Give us a star to show your support!
|
||||
|
||||
+109
-1
@@ -1,3 +1,112 @@
|
||||
fastfetch (2.58.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.58.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 22 Jan 2026 15:30:58 +0800
|
||||
|
||||
fastfetch (2.57.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.57.1
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 14 Jan 2026 14:00:17 +0800
|
||||
|
||||
fastfetch (2.57.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.57.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 12 Jan 2026 10:11:21 +0800
|
||||
|
||||
fastfetch (2.56.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.56.1
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 18 Dec 2025 14:57:36 +0800
|
||||
|
||||
fastfetch (2.56.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.56.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 08 Dec 2025 09:21:58 +0800
|
||||
|
||||
fastfetch (2.55.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.55.1
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 17 Nov 2025 10:15:44 +0800
|
||||
|
||||
fastfetch (2.55.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.55.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Wed, 12 Nov 2025 09:15:24 +0800
|
||||
|
||||
fastfetch (2.54.1~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Fix building on plucky
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 20 Oct 2025 14:27:02 +0800
|
||||
|
||||
fastfetch (2.54.0~#UBUNTU_CODENAME#) #UBUNTU_CODENAME#; urgency=medium
|
||||
|
||||
* Update to 2.54.0
|
||||
* Test independent changelog entries for different Ubuntu releases
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Mon, 20 Oct 2025 10:47:02 +0800
|
||||
|
||||
fastfetch (2.53.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.53.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Tue, 23 Sep 2025 09:58:48 +0800
|
||||
|
||||
fastfetch (2.52.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.52.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 05 Sep 2025 14:59:44 +0800
|
||||
|
||||
fastfetch (2.51.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.51.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 29 Aug 2025 08:55:03 +0800
|
||||
|
||||
fastfetch (2.50.2) jammy; urgency=medium
|
||||
|
||||
* Update to 2.50.2
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 21 Aug 2025 10:33:07 +0800
|
||||
|
||||
fastfetch (2.49.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.49.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 31 Jul 2025 14:32:59 +0800
|
||||
|
||||
fastfetch (2.48.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.48.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 17 Jul 2025 16:16:52 +0800
|
||||
|
||||
fastfetch (2.47.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.47.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 03 Jul 2025 14:51:45 +0800
|
||||
|
||||
fastfetch (2.46.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.46.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Fri, 20 Jun 2025 15:01:21 +0800
|
||||
|
||||
fastfetch (2.45.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.45.0
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Thu, 05 Jun 2025 10:56:38 +0800
|
||||
|
||||
fastfetch (2.44.0) jammy; urgency=medium
|
||||
|
||||
* Update to 2.44.0
|
||||
@@ -381,4 +490,3 @@ fastfetch (2.7.1) jammy; urgency=medium
|
||||
* Initial release.
|
||||
|
||||
-- Carter Li <zhangsongcui@live.cn> Tue, 06 Feb 2024 15:01:11 +0800
|
||||
|
||||
Vendored
+1
-1
@@ -2,7 +2,7 @@ Source: fastfetch
|
||||
Section: universe/utils
|
||||
Priority: optional
|
||||
Maintainer: Carter Li <zhangsongcui@live.cn>
|
||||
Build-Depends: libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libxfconf-0-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build
|
||||
Build-Depends: libelf-dev, libvulkan-dev, libwayland-dev, libxrandr-dev, libxcb-randr0-dev, libdconf-dev, libdbus-1-dev, libmagickcore-dev, libsqlite3-dev, librpm-dev, libegl-dev, libglx-dev, ocl-icd-opencl-dev, libpulse-dev, libdrm-dev, libddcutil-dev, libchafa-dev, directx-headers-dev, pkgconf, cmake (>= 3.12), debhelper (>= 11.2), dh-cmake, dh-cmake-compat (= 1), dh-sequence-cmake, dh-sequence-ctest, ninja-build, python3-setuptools
|
||||
Standards-Version: 4.0.0
|
||||
Homepage: https://github.com/fastfetch-cli/fastfetch
|
||||
|
||||
|
||||
Vendored
-1
@@ -1 +0,0 @@
|
||||
fastfetch_2.44.0_source.buildinfo universe/utils optional
|
||||
Vendored
+74
-2
@@ -1,4 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# WARNING: DO NOT RUN THIS SCRIPT UNLESS YOU KNOW WHAT YOU ARE DOING.
|
||||
|
||||
debuild -S -i -I
|
||||
dput ppa:zhangsongcui3371/fastfetch ~/fastfetch_*.changes
|
||||
set -euo pipefail
|
||||
|
||||
command -v debuild >/dev/null 2>&1 || { echo "debuild not found. Install devscripts." >&2; exit 1; }
|
||||
command -v dput >/dev/null 2>&1 || { echo "dput not found." >&2; exit 1; }
|
||||
|
||||
SCRIPT_DIR="$(cd -- "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
|
||||
ROOT_DIR="$(cd -- "$SCRIPT_DIR/.." >/dev/null 2>&1 && pwd)"
|
||||
OUT_DIR="$(dirname "$ROOT_DIR")"
|
||||
PPA="ppa:zhangsongcui3371/fastfetch"
|
||||
CODENAMES=( jammy noble plucky questing resolute )
|
||||
DRY_RUN=0
|
||||
|
||||
if [[ -d "$OUT_DIR/build" ]]; then
|
||||
echo "Output directory exists: $OUT_DIR/build" >&2
|
||||
echo "Please move or delete it before proceeding." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TEMPLATE="$ROOT_DIR/debian/changelog.tpl"
|
||||
CHANGELOG_DEBIAN="$ROOT_DIR/debian/changelog"
|
||||
|
||||
if [[ ! -f "$TEMPLATE" ]]; then
|
||||
echo "Template not found: $TEMPLATE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! grep -q '#UBUNTU_CODENAME#' "$TEMPLATE"; then
|
||||
echo "Template missing placeholder: #UBUNTU_CODENAME#" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "IMPORTANT: Before proceeding, please ensure that 'debian/changelog.tpl' is up-to-date"
|
||||
echo " with the correct version number, release notes, and maintainer information."
|
||||
echo
|
||||
echo " The template must contain a placeholder like '#UBUNTU_CODENAME#' for the codename."
|
||||
echo
|
||||
read -p "Have you reviewed and updated 'debian/changelog.tpl'? (y/N): " -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
rm -f "$CHANGELOG_DEBIAN"
|
||||
rm -f "$ROOT_DIR/debian/files"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
for codename in "${CODENAMES[@]}"; do
|
||||
echo "==> Publishing distro: $codename"
|
||||
sed "s/#UBUNTU_CODENAME#/${codename}/g" "$TEMPLATE" > "$CHANGELOG_DEBIAN"
|
||||
|
||||
( cd "$ROOT_DIR" && debuild -S -i -I )
|
||||
|
||||
changes=( "$OUT_DIR"/fastfetch_*~${codename}_source.changes )
|
||||
if [[ ${#changes[@]} -ne 1 ]]; then
|
||||
echo "Unable to uniquely identify .changes for '$codename' in: $OUT_DIR" >&2
|
||||
printf 'Found:\n'; printf ' %s\n' "${changes[@]}" >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $DRY_RUN -eq 1 ]]; then
|
||||
echo "[DRY-RUN] dput \"$PPA\" \"${changes[0]}\""
|
||||
else
|
||||
dput "$PPA" "${changes[0]}"
|
||||
fi
|
||||
|
||||
rm -f "$OUT_DIR"/fastfetch_*~${codename}_source.{changes,dsc,tar.*}
|
||||
|
||||
echo "<== Done: $codename"
|
||||
done
|
||||
|
||||
+1233
-210
File diff suppressed because it is too large
Load Diff
+4
-1
@@ -52,7 +52,10 @@
|
||||
},
|
||||
"memory",
|
||||
"physicalmemory",
|
||||
"swap",
|
||||
{
|
||||
"type": "swap",
|
||||
"separate": true
|
||||
},
|
||||
"disk",
|
||||
"btrfs",
|
||||
"zpool",
|
||||
|
||||
+5
-1
@@ -54,7 +54,10 @@
|
||||
},
|
||||
"memory",
|
||||
"physicalmemory",
|
||||
"swap",
|
||||
{
|
||||
"type": "swap",
|
||||
"separate": true
|
||||
},
|
||||
"disk",
|
||||
"btrfs",
|
||||
"zpool",
|
||||
@@ -106,6 +109,7 @@
|
||||
},
|
||||
"tpm",
|
||||
"version",
|
||||
"logo",
|
||||
"break",
|
||||
"colors"
|
||||
]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Load with --load-config examples/2.jsonc
|
||||
// Load with --config examples/2.jsonc
|
||||
// Note that you must replace the image path to an existing image to display it.
|
||||
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Load with --load-config examples/2.jsonc
|
||||
// Load with --config examples/2.jsonc
|
||||
// Note that you must replace the image path to an existing image to display it.
|
||||
|
||||
{
|
||||
|
||||
@@ -12,10 +12,11 @@
|
||||
"type": ["bar", "hide-others"]
|
||||
},
|
||||
"bar": {
|
||||
"borderLeft": "",
|
||||
"borderRight": "",
|
||||
"charElapsed": "█",
|
||||
"charTotal": "░",
|
||||
"border": null,
|
||||
"char": {
|
||||
"elapsed": "█",
|
||||
"total": "░"
|
||||
},
|
||||
"width": 40
|
||||
},
|
||||
"constants": [
|
||||
|
||||
+137
-62
@@ -6,236 +6,311 @@
|
||||
"keys": "blue"
|
||||
},
|
||||
"separator": "",
|
||||
// Constants are reusable strings referenced by {$1}, {$2}, etc.
|
||||
// These contain ANSI escape codes for cursor positioning
|
||||
"constants": [
|
||||
"──────────────────────────────────────────────",
|
||||
"\u001b[47D",
|
||||
"\u001b[47C",
|
||||
"\u001b[46C"
|
||||
"──────────────────────────────────────────────", // {$1} - horizontal line for inner borders
|
||||
"\u001b[47D", // {$2} - move cursor left 47 columns
|
||||
"\u001b[47C", // {$3} - move cursor right 47 columns
|
||||
"\u001b[46C", // {$4} - move cursor right 46 columns
|
||||
"══════════════════════════════════════════════" // {$5} - horizontal line for outer borders
|
||||
],
|
||||
"brightColor": false
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"type": "version",
|
||||
"key": "┌───────────────┬─{$1}┐\u001b[41D",
|
||||
"key": "╔═══════════════╦═{$5}╗\u001b[41D",
|
||||
"format": "\u001b[1m{#keys} {1} - {2} "
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
"key": "│ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}│{$2}"
|
||||
// Key format breakdown for OS module:
|
||||
// "║ {icon} \u001b[s{sysname}\u001b[u\u001b[10C│{$3}║{$2}"
|
||||
//
|
||||
// ║ - Left border of key block
|
||||
// {icon} - OS icon (defined internally by fastfetch)
|
||||
// \u001b[s - ANSI escape: save cursor position (ESC[s)
|
||||
// {sysname} - Format variable: system name (e.g., "Linux", "Darwin")
|
||||
// \u001b[u - ANSI escape: restore cursor to saved position (ESC[u)
|
||||
// Necessary because the length of `{sysname}` differs between different platforms
|
||||
// \u001b[10C - ANSI escape: move cursor right 10 columns (ESC[10C)
|
||||
// │ - Right border of key block (always 10 columns from left border)
|
||||
// {$3} - Reference to constants[2]: move cursor right 47 columns
|
||||
// ║ - Right border of value block
|
||||
// {$2} - Reference to constants[1]: move cursor left 47 columns
|
||||
//
|
||||
// This creates a fixed-width layout where the key block is exactly 10 columns wide,
|
||||
// regardless of the actual content length. The cursor manipulation ensures proper
|
||||
// alignment for the table-like structure.
|
||||
"key": "║ {icon} \u001b[s{sysname}\u001b[u\u001b[10C║{$3}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "datetime",
|
||||
"key": "│ {icon} Fetched │{$3}│{$2}",
|
||||
"key": "║ {icon} Fetched ║{$3}║{$2}",
|
||||
"format": "{year}-{month-pretty}-{day-pretty} {hour-pretty}:{minute-pretty}:{second-pretty} {timezone-name}"
|
||||
},
|
||||
{
|
||||
"type": "locale",
|
||||
"key": "│ {icon} Locale │{$3}│{$2}"
|
||||
"key": "║ {icon} Locale ║{$3}║{$2}"
|
||||
},
|
||||
|
||||
// Hardware
|
||||
// Hardware section with cyan color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#cyan}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
"key": "║{#cyan}┌──────────────┬{$1}┐{#keys}║\u001b[37D",
|
||||
"format": "{#bright_cyan} Hardware "
|
||||
},
|
||||
{
|
||||
"type": "chassis",
|
||||
"key": "│{#cyan}│ {icon} Chassis │{$4}│{#keys}│{$2}"
|
||||
// Similar structure but with cyan color formatting:
|
||||
// │{#cyan}│ - Left border with cyan color
|
||||
// {icon} - Chassis icon
|
||||
// Chassis - Fixed label text
|
||||
// │{$4}│{#keys}║{$2} - Positioning and borders for value area
|
||||
"key": "║{#cyan}│ {icon} Chassis │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "│{#cyan}│ {icon} RAM │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#cyan}│ {icon} RAM │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "swap",
|
||||
"key": "│{#cyan}│ {icon} SWAP │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#cyan}│ {icon} SWAP │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "cpu",
|
||||
"key": "│{#cyan}│ {icon} CPU │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#cyan}│ {icon} CPU │{$4}│{#keys}║{$2}",
|
||||
"showPeCoreCount": true
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "│{#cyan}│ {icon} GPU │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#cyan}│ {icon} GPU │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"key": "│{#cyan}│ {icon} Disk │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#cyan}│ {icon} Disk │{$4}│{#keys}║{$2}",
|
||||
"format": "{size-used} \/ {size-total} ({size-percentage}) - {filesystem}",
|
||||
},
|
||||
{
|
||||
"type": "battery",
|
||||
"key": "│{#cyan}│ {icon} Battery │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#cyan}│ {icon} Battery │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#cyan}└──────────────┴{$1}┘{#keys}│",
|
||||
"key": "║{#cyan}└──────────────┴{$1}┘{#keys}║",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Desktop
|
||||
// Desktop section with green color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#green}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
"key": "║{#green}┌──────────────┬{$1}┐{#keys}║\u001b[37D",
|
||||
"format": "{#bright_green} Desktop "
|
||||
},
|
||||
{
|
||||
"type": "de",
|
||||
"key": "│{#green}│ {icon} Desktop │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#green}│ {icon} Desktop │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "wm",
|
||||
"key": "│{#green}│ {icon} Session │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#green}│ {icon} Session │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "display",
|
||||
"key": "│{#green}│ {icon} Display │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#green}│ {icon} Display │{$4}│{#keys}║{$2}",
|
||||
"compactType": "original-with-refresh-rate"
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "│{#green}│ {icon} G-Driver │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#green}│ {icon} G-Driver │{$4}│{#keys}║{$2}",
|
||||
"format": "{driver}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#green}└──────────────┴{$1}┘{#keys}│",
|
||||
"key": "║{#green}└──────────────┴{$1}┘{#keys}║",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Terminal
|
||||
// Terminal section with yellow color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#yellow}┌──────────────┬{$1}┐{#keys}│\u001b[37D",
|
||||
"key": "║{#yellow}┌──────────────┬{$1}┐{#keys}║\u001b[37D",
|
||||
"format": "{#bright_yellow} Terminal "
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"key": "│{#yellow}│ {icon} Shell │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#yellow}│ {icon} Shell │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "│{#yellow}│ {icon} Terminal │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#yellow}│ {icon} Terminal │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "terminalfont",
|
||||
"key": "│{#yellow}│ {icon} Term Font │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#yellow}│ {icon} Term Font │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "terminaltheme",
|
||||
"key": "│{#yellow}│ {icon} Colors │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#yellow}│ {icon} Colors │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "packages",
|
||||
"key": "│{#yellow}│ {icon} Packages │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#yellow}│ {icon} Packages │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#yellow}└──────────────┴{$1}┘{#keys}│",
|
||||
"key": "║{#yellow}└──────────────┴{$1}┘{#keys}║",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Development
|
||||
// Development section with red color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#red}┌──────────────┬{$1}┐{#keys}│\u001b[39D",
|
||||
"key": "║{#red}┌──────────────┬{$1}┐{#keys}║\u001b[39D",
|
||||
"format": "{#bright_red} Development "
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Rust │{$4}│{#keys}│{$2}",
|
||||
"text": "rustc --version | cut -d' ' -f2",
|
||||
"format": "rustc {}"
|
||||
"keyIcon": "", // Custom icon override
|
||||
"key": "║{#red}│ {icon} Rust │{$4}│{#keys}║{$2}",
|
||||
"text": "rustc --version",
|
||||
"format": "rustc {~6,13}" // Print 6th to 13th characters (version number)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"condition": {
|
||||
"!system": "Windows" // Posix version
|
||||
},
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Clang │{$4}│{#keys}│{$2}",
|
||||
"text": "clang --version | head -1 | awk '{print $NF}'",
|
||||
"key": "║{#red}│ {icon} Clang │{$4}│{#keys}║{$2}",
|
||||
"text": "clang --version | sed -n 's/.*version \\([0-9][0-9.]*\\).*/\\1/p'",
|
||||
"format": "clang {}"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"condition": {
|
||||
"system": "Windows" // Windows version
|
||||
},
|
||||
"keyIcon": "",
|
||||
"key": "║{#red}│ {icon} Clang │{$4}│{#keys}║{$2}",
|
||||
"text": "clang --version | findstr version", // Finds the line with "version"
|
||||
"format": "clang {~-6}" // Prints the last 6 characters (version number)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} NodeJS │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} NodeJS │{$4}│{#keys}║{$2}",
|
||||
"text": "node --version",
|
||||
"format": "node {~1}"
|
||||
"format": "node {~1}" // {~1} removes first character (v)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Go │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} Go │{$4}│{#keys}║{$2}",
|
||||
"text": "go version | cut -d' ' -f3",
|
||||
"format": "go {~2}"
|
||||
"format": "go {~2}" // {~2} removes first 2 characters (go)
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Zig │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} Zig │{$4}│{#keys}║{$2}",
|
||||
"text": "zig version",
|
||||
"format": "zig {}"
|
||||
},
|
||||
{
|
||||
"type": "editor",
|
||||
"key": "│{#red}│ {icon} Editor │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#red}│ {icon} Editor │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "command",
|
||||
"keyIcon": "",
|
||||
"key": "│{#red}│ {icon} Git │{$4}│{#keys}│{$2}",
|
||||
"key": "║{#red}│ {icon} Git │{$4}│{#keys}║{$2}",
|
||||
"text": "git version",
|
||||
"format": "git {~12}"
|
||||
},
|
||||
{
|
||||
"type": "font",
|
||||
"key": "│{#red}│ {icon} Interface │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#red}│ {icon} Interface │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#red}└──────────────┴{$1}┘{#keys}│",
|
||||
"key": "║{#red}└──────────────┴{$1}┘{#keys}║",
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// Uptime
|
||||
// Uptime section with magenta color theme
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#magenta}┌──────────────┬{$1}┐{#keys}│\u001b[36D",
|
||||
"key": "║{#magenta}┌──────────────┬{$1}┐{#keys}║\u001b[36D",
|
||||
"format": "{#bright_magenta} Uptime "
|
||||
},
|
||||
{
|
||||
"type": "uptime",
|
||||
"key": "│{#magenta}│ {icon} Uptime │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#magenta}│ {icon} Uptime │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"type": "users",
|
||||
"myselfOnly": true,
|
||||
"myselfOnly": true, // Only show current user
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} Login │{$4}│{#keys}│{$2}"
|
||||
"key": "║{#magenta}│ {icon} Login │{$4}│{#keys}║{$2}"
|
||||
},
|
||||
{
|
||||
"condition": { // Conditional module: only show on non-macOS
|
||||
"!system": "macOS"
|
||||
},
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "│{#magenta}│ {icon} OS Age │{$4}│{#keys}│{$2}",
|
||||
"folders": "/", // On macOS, "/System/Volumes/VM" works for me
|
||||
"key": "║{#magenta}│ {icon} OS Age │{$4}│{#keys}║{$2}",
|
||||
"folders": "/", // Check root filesystem
|
||||
"format": "{create-time:10} [{days} days]" // Show creation time and age in days
|
||||
},
|
||||
{
|
||||
"condition": { // Conditional module: only show on macOS
|
||||
"system": "macOS"
|
||||
},
|
||||
"type": "disk",
|
||||
"keyIcon": "",
|
||||
"key": "║{#magenta}│ {icon} OS Age │{$4}│{#keys}║{$2}",
|
||||
"folders": "/System/Volumes/VM", // Work around for APFS on macOS
|
||||
"format": "{create-time:10} [{days} days]"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│{#magenta}└──────────────┴{$1}┘{#keys}│",
|
||||
"key": "║{#magenta}└──────────────┴{$1}┘{#keys}║",
|
||||
"format": ""
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "└─────────────────{$1}┘",
|
||||
"key": "╚═════════════════{$5}╝", // Bottom border of the entire layout
|
||||
"format": ""
|
||||
},
|
||||
|
||||
// End
|
||||
"break",
|
||||
"colors"
|
||||
// End with color palette and line break
|
||||
"break", // Add a blank line
|
||||
"colors" // Display color palette
|
||||
]
|
||||
}
|
||||
|
||||
/*
|
||||
Key Format Structure Explanation:
|
||||
|
||||
The key format uses a combination of:
|
||||
1. Unicode box drawing characters (│ ┌ ┐ └ ┘ ┬ ┴) for borders
|
||||
2. ANSI escape codes for cursor positioning (\u001b[...)
|
||||
3. Format variables ({icon}, {sysname}, etc.)
|
||||
4. Constant references ({$1}, {$2}, etc.)
|
||||
5. Color formatting ({#color})
|
||||
|
||||
ANSI Escape Codes Used:
|
||||
- \u001b[s - Save cursor position (ESC[s)
|
||||
- \u001b[u - Restore cursor position (ESC[u)
|
||||
- \u001b[nC - Move cursor right n columns (ESC[nC)
|
||||
- \u001b[nD - Move cursor left n columns (ESC[nD)
|
||||
|
||||
This creates a table-like layout with fixed column widths and proper alignment,
|
||||
regardless of the actual content length in each field.
|
||||
|
||||
For more ANSI escape code reference, see:
|
||||
https://gist.github.com/fnky/458719343aabd01cfb17a3a4f7296797#cursor-controls
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
"type": "small",
|
||||
"padding": {
|
||||
"top": 1
|
||||
}
|
||||
},
|
||||
"display": {
|
||||
"separator": " "
|
||||
},
|
||||
"modules": [
|
||||
"break",
|
||||
"title",
|
||||
{
|
||||
"type": "os",
|
||||
"key": "os ",
|
||||
"keyColor": "red"
|
||||
},
|
||||
{
|
||||
"type": "kernel",
|
||||
"key": "kernel",
|
||||
"keyColor": "green"
|
||||
},
|
||||
{
|
||||
"type": "host",
|
||||
"format": "{vendor} {family}",
|
||||
"key": "host ",
|
||||
"keyColor": "yellow"
|
||||
},
|
||||
{
|
||||
"type": "packages",
|
||||
"key": "pkgs ",
|
||||
"keyColor": "blue"
|
||||
},
|
||||
{
|
||||
"type": "uptime",
|
||||
"format": "{?days}{days}d {?}{hours}h {minutes}m",
|
||||
"key": "uptime",
|
||||
"keyColor": "magenta"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "memory",
|
||||
"keyColor": "cyan"
|
||||
},
|
||||
"break"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
"type": "small"
|
||||
},
|
||||
"display": {
|
||||
"separator": " ",
|
||||
"key": {
|
||||
"type": "both"
|
||||
},
|
||||
"bar": {
|
||||
"border": {
|
||||
"left": "\uee00",
|
||||
"leftElapsed": "\uee03",
|
||||
"right": "\uee02",
|
||||
"rightElapsed": "\uee05"
|
||||
},
|
||||
"char": {
|
||||
"total": "\uee01",
|
||||
"elapsed": "\uee04"
|
||||
},
|
||||
"color": {
|
||||
"total": null
|
||||
}
|
||||
},
|
||||
"percent": {
|
||||
"type": [
|
||||
"bar",
|
||||
"bar-monochrome"
|
||||
]
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
"title",
|
||||
"separator",
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "MEM"
|
||||
},
|
||||
{
|
||||
"type": "swap",
|
||||
"key": "SWP"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"folders": "/",
|
||||
"key": "DSK"
|
||||
},
|
||||
{
|
||||
"type": "battery",
|
||||
"key": "BAT"
|
||||
},
|
||||
{
|
||||
"type": "brightness",
|
||||
"key": "BGT"
|
||||
},
|
||||
{
|
||||
"type": "colors",
|
||||
"paddingLeft": 6,
|
||||
"symbol": "circle"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
// #1887
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": null,
|
||||
"display": {
|
||||
"constants": [
|
||||
"\u001b[s\u001b[33C│\u001b[u",
|
||||
" » "
|
||||
],
|
||||
"separator": "",
|
||||
"percent": {
|
||||
"type": ["num", "bar"]
|
||||
},
|
||||
"brightColor": false,
|
||||
"bar": {
|
||||
"border": {
|
||||
"left": "[",
|
||||
"leftElapsed": "[",
|
||||
"right": "]",
|
||||
"rightElapsed": "]"
|
||||
},
|
||||
"char": {
|
||||
"elapsed": "─",
|
||||
"total": "─"
|
||||
},
|
||||
"color": {
|
||||
"elapsed": "default",
|
||||
"total": "light_black"
|
||||
},
|
||||
"width": 16
|
||||
},
|
||||
"color": {
|
||||
"separator": "default",
|
||||
"keys": "default",
|
||||
"output": "default"
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
"title",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "┌────「 {#1}OS{#} 」────────────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"folders": "/",
|
||||
"key": "│ {$1}",
|
||||
"format": "{size-percentage-bar} {size-percentage}"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"folders": "/",
|
||||
"key": "│ {$1}",
|
||||
"format": "{size-used} / {size-total}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "└────────────────────────────────────────┘"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "┌────「 {#1}UI{#} 」────────────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "wm",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "wmtheme",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│ {$1}"
|
||||
},
|
||||
{
|
||||
"type": "display",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{width}x{height} @ {refresh-rate} Hz"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│ {$1}"
|
||||
},
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "terminalfont",
|
||||
"key": "│ {icon}{$2}{$1}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "└────────────────────────────────────────┘"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "┌────「 {#1}HW{#} 」────────────────────────────┐"
|
||||
},
|
||||
{
|
||||
"type": "cpu",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{name}"
|
||||
},
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{name}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"key": "│ {$1}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "│ {icon}{$2}{$1}",
|
||||
"format": "{percentage-bar} {percentage}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "│ {$1}",
|
||||
"format": "{used} / {total}"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "└────────────────────────────────────────┘"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Load with --load-config examples/3.jsonc
|
||||
// Load with --config examples/3.jsonc
|
||||
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": null,
|
||||
"display": {
|
||||
"key": {
|
||||
"type": "both",
|
||||
"paddingLeft": 6,
|
||||
"width": 17
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "|---------------------: {#1}Hardware{#} : ---------------------|"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"keyColor": "green",
|
||||
"type": "host"
|
||||
},
|
||||
{
|
||||
"keyColor": "green",
|
||||
"type": "cpu"
|
||||
},
|
||||
{
|
||||
"keyColor": "yellow",
|
||||
"type": "memory"
|
||||
},
|
||||
{
|
||||
"keyColor": "yellow",
|
||||
"type": "swap"
|
||||
},
|
||||
{
|
||||
"type": "custom",
|
||||
"keyIcon": "",
|
||||
"key": "Disks"
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"key": " ",
|
||||
"format": " [{mountpoint}] - {size-used} / {size-total} ({size-percentage})"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "title",
|
||||
"format": "|-------------------------------------------------------|\u001b[40D: {#1}{user-name} @ {host-name}{#} :"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "os",
|
||||
"keyColor": "cyan"
|
||||
},
|
||||
{
|
||||
"type": "kernel",
|
||||
"keyColor": "cyan"
|
||||
},
|
||||
{
|
||||
"type": "packages",
|
||||
"keyColor": "red",
|
||||
"key": "Pkgs"
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"keyColor": "red"
|
||||
},
|
||||
{
|
||||
"type": "terminal",
|
||||
"key": "Term",
|
||||
"keyColor": "red"
|
||||
},
|
||||
{
|
||||
"type": "locale",
|
||||
"keyColor": "magenta"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "custom",
|
||||
"format": "|---------------------: {#1}Software{#} : ---------------------|"
|
||||
},
|
||||
"break",
|
||||
{
|
||||
"type": "colors",
|
||||
"symbol": "circle",
|
||||
"paddingLeft": 8
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,57 @@
|
||||
// Inspired by microfetch
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
"logo": {
|
||||
"type": "small"
|
||||
},
|
||||
"general": {
|
||||
"detectVersion": false
|
||||
},
|
||||
"display": {
|
||||
"separator": " ",
|
||||
"brightColor": false,
|
||||
"key": {
|
||||
"type": "both-2"
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
{
|
||||
"type": "title",
|
||||
"format": "{user-name-colored}{#light_red}@{host-name-colored} {#}{cwd}"
|
||||
},
|
||||
{
|
||||
"type": "os",
|
||||
"key": "System "
|
||||
},
|
||||
{
|
||||
"type": "kernel",
|
||||
"key": "Kernel "
|
||||
},
|
||||
{
|
||||
"type": "shell",
|
||||
"key": "Shell "
|
||||
},
|
||||
{
|
||||
"type": "uptime",
|
||||
"key": "Uptime "
|
||||
},
|
||||
{
|
||||
"type": "wm",
|
||||
"key": "Desktop "
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"key": "Memory "
|
||||
},
|
||||
{
|
||||
"type": "disk",
|
||||
"key": "Storage (/) ",
|
||||
"folders": "/"
|
||||
},
|
||||
{
|
||||
"type": "colors",
|
||||
"key": "Colors ",
|
||||
"symbol": "circle"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Load with --load-config examples/4.jsonc
|
||||
// Load with --config examples/4.jsonc
|
||||
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Load with --load-config examples/5.jsonc
|
||||
// Load with --config examples/5.jsonc
|
||||
|
||||
{
|
||||
"$schema": "https://github.com/fastfetch-cli/fastfetch/raw/dev/doc/json_schema.json",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Load with --load-config examples/2.jsonc
|
||||
// Load with --config examples/2.jsonc
|
||||
// Note that you must replace the image path to an existing image to display it.
|
||||
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Load with --load-config examples/2.jsonc
|
||||
// Load with --config examples/2.jsonc
|
||||
// Note that you must replace the image path to an existing image to display it.
|
||||
|
||||
{
|
||||
|
||||
@@ -8,8 +8,10 @@
|
||||
"width": 11
|
||||
},
|
||||
"bar": {
|
||||
"charElapsed": "=",
|
||||
"charTotal": "-",
|
||||
"char": {
|
||||
"elapsed": "=",
|
||||
"total": "-"
|
||||
},
|
||||
"width": 13
|
||||
},
|
||||
"percent": {
|
||||
|
||||
+13
-4
@@ -3,7 +3,12 @@
|
||||
"display": {
|
||||
"size": {
|
||||
"maxPrefix": "MB",
|
||||
"ndigits": 0
|
||||
"ndigits": 0,
|
||||
"spaceBeforeUnit": "never"
|
||||
},
|
||||
"freq": {
|
||||
"ndigits": 3,
|
||||
"spaceBeforeUnit": "never"
|
||||
}
|
||||
},
|
||||
"modules": [
|
||||
@@ -16,7 +21,10 @@
|
||||
"format": "{release}"
|
||||
},
|
||||
"uptime",
|
||||
"packages",
|
||||
{
|
||||
"type": "packages",
|
||||
"combined": true
|
||||
},
|
||||
"shell",
|
||||
{
|
||||
"type": "display",
|
||||
@@ -36,11 +44,12 @@
|
||||
"cpu",
|
||||
{
|
||||
"type": "gpu",
|
||||
"key": "GPU"
|
||||
"key": "GPU",
|
||||
"format": "{name}"
|
||||
},
|
||||
{
|
||||
"type": "memory",
|
||||
"format": "{} / {}"
|
||||
"format": "{used} / {total}"
|
||||
},
|
||||
"break",
|
||||
"colors"
|
||||
|
||||
@@ -6,6 +6,9 @@ def main(amdgpu_ids_path: str):
|
||||
with open(amdgpu_ids_path, 'r') as f:
|
||||
full_text = f.read()
|
||||
|
||||
if full_text == '':
|
||||
sys.exit(f'Error: {amdgpu_ids_path} file is empty')
|
||||
|
||||
products = []
|
||||
for line in full_text.split('\n'):
|
||||
if not line or line[0] == '#' or not ',\t' in line:
|
||||
|
||||
@@ -18,6 +18,9 @@ def main(keep_vendor_list: set, pci_ids_path: str):
|
||||
with open(pci_ids_path, 'r') as f:
|
||||
full_text = f.read()
|
||||
|
||||
if full_text == '':
|
||||
sys.exit(f'Error: {pci_ids_path} file is empty')
|
||||
|
||||
dev_list_text = full_text[:full_text.rfind('\n\n\n')] # remove known classes
|
||||
for line in dev_list_text.split('\n'):
|
||||
if not line or line[0] == '#':
|
||||
|
||||
Vendored
-7
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"home": "https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c",
|
||||
"license": "MIT compatible (embed in source)",
|
||||
"version": "2007-05-26 (Unicode 5.0)",
|
||||
"author": "Markus Kuhn",
|
||||
"modified": "CarterLi"
|
||||
}
|
||||
Vendored
-314
@@ -1,314 +0,0 @@
|
||||
/*
|
||||
* This is an implementation of wcwidth() and wcswidth() (defined in
|
||||
* IEEE Std 1002.1-2001) for Unicode.
|
||||
*
|
||||
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
|
||||
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
|
||||
*
|
||||
* In fixed-width output devices, Latin characters all occupy a single
|
||||
* "cell" position of equal width, whereas ideographic CJK characters
|
||||
* occupy two such cells. Interoperability between terminal-line
|
||||
* applications and (teletype-style) character terminals using the
|
||||
* UTF-8 encoding requires agreement on which character should advance
|
||||
* the cursor by how many cell positions. No established formal
|
||||
* standards exist at present on which Unicode character shall occupy
|
||||
* how many cell positions on character terminals. These routines are
|
||||
* a first attempt of defining such behavior based on simple rules
|
||||
* applied to data provided by the Unicode Consortium.
|
||||
*
|
||||
* For some graphical characters, the Unicode standard explicitly
|
||||
* defines a character-cell width via the definition of the East Asian
|
||||
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
|
||||
* In all these cases, there is no ambiguity about which width a
|
||||
* terminal shall use. For characters in the East Asian Ambiguous (A)
|
||||
* class, the width choice depends purely on a preference of backward
|
||||
* compatibility with either historic CJK or Western practice.
|
||||
* Choosing single-width for these characters is easy to justify as
|
||||
* the appropriate long-term solution, as the CJK practice of
|
||||
* displaying these characters as double-width comes from historic
|
||||
* implementation simplicity (8-bit encoded characters were displayed
|
||||
* single-width and 16-bit ones double-width, even for Greek,
|
||||
* Cyrillic, etc.) and not any typographic considerations.
|
||||
*
|
||||
* Much less clear is the choice of width for the Not East Asian
|
||||
* (Neutral) class. Existing practice does not dictate a width for any
|
||||
* of these characters. It would nevertheless make sense
|
||||
* typographically to allocate two character cells to characters such
|
||||
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
|
||||
* represented adequately with a single-width glyph. The following
|
||||
* routines at present merely assign a single-cell width to all
|
||||
* neutral characters, in the interest of simplicity. This is not
|
||||
* entirely satisfactory and should be reconsidered before
|
||||
* establishing a formal standard in this area. At the moment, the
|
||||
* decision which Not East Asian (Neutral) characters should be
|
||||
* represented by double-width glyphs cannot yet be answered by
|
||||
* applying a simple rule from the Unicode database content. Setting
|
||||
* up a proper standard for the behavior of UTF-8 character terminals
|
||||
* will require a careful analysis not only of each Unicode character,
|
||||
* but also of each presentation form, something the author of these
|
||||
* routines has avoided to do so far.
|
||||
*
|
||||
* http://www.unicode.org/unicode/reports/tr11/
|
||||
*
|
||||
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* for any purpose and without fee is hereby granted. The author
|
||||
* disclaims all warranties with regard to this software.
|
||||
*
|
||||
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
|
||||
*/
|
||||
|
||||
#include <wchar.h>
|
||||
|
||||
struct interval {
|
||||
int first;
|
||||
int last;
|
||||
};
|
||||
|
||||
/* auxiliary function for binary search in interval table */
|
||||
static int bisearch(wchar_t ucs, const struct interval *table, int max) {
|
||||
int min = 0;
|
||||
int mid;
|
||||
|
||||
if (ucs < table[0].first || ucs > table[max].last)
|
||||
return 0;
|
||||
while (max >= min) {
|
||||
mid = (min + max) / 2;
|
||||
if (ucs > table[mid].last)
|
||||
min = mid + 1;
|
||||
else if (ucs < table[mid].first)
|
||||
max = mid - 1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* The following two functions define the column width of an ISO 10646
|
||||
* character as follows:
|
||||
*
|
||||
* - The null character (U+0000) has a column width of 0.
|
||||
*
|
||||
* - Other C0/C1 control characters and DEL will lead to a return
|
||||
* value of -1.
|
||||
*
|
||||
* - Non-spacing and enclosing combining characters (general
|
||||
* category code Mn or Me in the Unicode database) have a
|
||||
* column width of 0.
|
||||
*
|
||||
* - SOFT HYPHEN (U+00AD) has a column width of 1.
|
||||
*
|
||||
* - Other format characters (general category code Cf in the Unicode
|
||||
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
|
||||
*
|
||||
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
|
||||
* have a column width of 0.
|
||||
*
|
||||
* - Spacing characters in the East Asian Wide (W) or East Asian
|
||||
* Full-width (F) category as defined in Unicode Technical
|
||||
* Report #11 have a column width of 2.
|
||||
*
|
||||
* - All remaining characters (including all printable
|
||||
* ISO 8859-1 and WGL4 characters, Unicode control characters,
|
||||
* etc.) have a column width of 1.
|
||||
*
|
||||
* This implementation assumes that wchar_t characters are encoded
|
||||
* in ISO 10646.
|
||||
*/
|
||||
|
||||
int mk_wcwidth(wchar_t ucs)
|
||||
{
|
||||
/* sorted list of non-overlapping intervals of non-spacing characters */
|
||||
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
|
||||
static const struct interval combining[] = {
|
||||
{ 0x0300, 0x036F }, { 0x0483, 0x0486 }, { 0x0488, 0x0489 },
|
||||
{ 0x0591, 0x05BD }, { 0x05BF, 0x05BF }, { 0x05C1, 0x05C2 },
|
||||
{ 0x05C4, 0x05C5 }, { 0x05C7, 0x05C7 }, { 0x0600, 0x0603 },
|
||||
{ 0x0610, 0x0615 }, { 0x064B, 0x065E }, { 0x0670, 0x0670 },
|
||||
{ 0x06D6, 0x06E4 }, { 0x06E7, 0x06E8 }, { 0x06EA, 0x06ED },
|
||||
{ 0x070F, 0x070F }, { 0x0711, 0x0711 }, { 0x0730, 0x074A },
|
||||
{ 0x07A6, 0x07B0 }, { 0x07EB, 0x07F3 }, { 0x0901, 0x0902 },
|
||||
{ 0x093C, 0x093C }, { 0x0941, 0x0948 }, { 0x094D, 0x094D },
|
||||
{ 0x0951, 0x0954 }, { 0x0962, 0x0963 }, { 0x0981, 0x0981 },
|
||||
{ 0x09BC, 0x09BC }, { 0x09C1, 0x09C4 }, { 0x09CD, 0x09CD },
|
||||
{ 0x09E2, 0x09E3 }, { 0x0A01, 0x0A02 }, { 0x0A3C, 0x0A3C },
|
||||
{ 0x0A41, 0x0A42 }, { 0x0A47, 0x0A48 }, { 0x0A4B, 0x0A4D },
|
||||
{ 0x0A70, 0x0A71 }, { 0x0A81, 0x0A82 }, { 0x0ABC, 0x0ABC },
|
||||
{ 0x0AC1, 0x0AC5 }, { 0x0AC7, 0x0AC8 }, { 0x0ACD, 0x0ACD },
|
||||
{ 0x0AE2, 0x0AE3 }, { 0x0B01, 0x0B01 }, { 0x0B3C, 0x0B3C },
|
||||
{ 0x0B3F, 0x0B3F }, { 0x0B41, 0x0B43 }, { 0x0B4D, 0x0B4D },
|
||||
{ 0x0B56, 0x0B56 }, { 0x0B82, 0x0B82 }, { 0x0BC0, 0x0BC0 },
|
||||
{ 0x0BCD, 0x0BCD }, { 0x0C3E, 0x0C40 }, { 0x0C46, 0x0C48 },
|
||||
{ 0x0C4A, 0x0C4D }, { 0x0C55, 0x0C56 }, { 0x0CBC, 0x0CBC },
|
||||
{ 0x0CBF, 0x0CBF }, { 0x0CC6, 0x0CC6 }, { 0x0CCC, 0x0CCD },
|
||||
{ 0x0CE2, 0x0CE3 }, { 0x0D41, 0x0D43 }, { 0x0D4D, 0x0D4D },
|
||||
{ 0x0DCA, 0x0DCA }, { 0x0DD2, 0x0DD4 }, { 0x0DD6, 0x0DD6 },
|
||||
{ 0x0E31, 0x0E31 }, { 0x0E34, 0x0E3A }, { 0x0E47, 0x0E4E },
|
||||
{ 0x0EB1, 0x0EB1 }, { 0x0EB4, 0x0EB9 }, { 0x0EBB, 0x0EBC },
|
||||
{ 0x0EC8, 0x0ECD }, { 0x0F18, 0x0F19 }, { 0x0F35, 0x0F35 },
|
||||
{ 0x0F37, 0x0F37 }, { 0x0F39, 0x0F39 }, { 0x0F71, 0x0F7E },
|
||||
{ 0x0F80, 0x0F84 }, { 0x0F86, 0x0F87 }, { 0x0F90, 0x0F97 },
|
||||
{ 0x0F99, 0x0FBC }, { 0x0FC6, 0x0FC6 }, { 0x102D, 0x1030 },
|
||||
{ 0x1032, 0x1032 }, { 0x1036, 0x1037 }, { 0x1039, 0x1039 },
|
||||
{ 0x1058, 0x1059 }, { 0x1160, 0x11FF }, { 0x135F, 0x135F },
|
||||
{ 0x1712, 0x1714 }, { 0x1732, 0x1734 }, { 0x1752, 0x1753 },
|
||||
{ 0x1772, 0x1773 }, { 0x17B4, 0x17B5 }, { 0x17B7, 0x17BD },
|
||||
{ 0x17C6, 0x17C6 }, { 0x17C9, 0x17D3 }, { 0x17DD, 0x17DD },
|
||||
{ 0x180B, 0x180D }, { 0x18A9, 0x18A9 }, { 0x1920, 0x1922 },
|
||||
{ 0x1927, 0x1928 }, { 0x1932, 0x1932 }, { 0x1939, 0x193B },
|
||||
{ 0x1A17, 0x1A18 }, { 0x1B00, 0x1B03 }, { 0x1B34, 0x1B34 },
|
||||
{ 0x1B36, 0x1B3A }, { 0x1B3C, 0x1B3C }, { 0x1B42, 0x1B42 },
|
||||
{ 0x1B6B, 0x1B73 }, { 0x1DC0, 0x1DCA }, { 0x1DFE, 0x1DFF },
|
||||
{ 0x200B, 0x200F }, { 0x202A, 0x202E }, { 0x2060, 0x2063 },
|
||||
{ 0x206A, 0x206F }, { 0x20D0, 0x20EF }, { 0x302A, 0x302F },
|
||||
{ 0x3099, 0x309A }, { 0xA806, 0xA806 }, { 0xA80B, 0xA80B },
|
||||
{ 0xA825, 0xA826 }, { 0xFB1E, 0xFB1E }, { 0xFE00, 0xFE0F },
|
||||
{ 0xFE20, 0xFE23 }, { 0xFEFF, 0xFEFF }, { 0xFFF9, 0xFFFB },
|
||||
{ 0x10A01, 0x10A03 }, { 0x10A05, 0x10A06 }, { 0x10A0C, 0x10A0F },
|
||||
{ 0x10A38, 0x10A3A }, { 0x10A3F, 0x10A3F }, { 0x1D167, 0x1D169 },
|
||||
{ 0x1D173, 0x1D182 }, { 0x1D185, 0x1D18B }, { 0x1D1AA, 0x1D1AD },
|
||||
{ 0x1D242, 0x1D244 }, { 0xE0001, 0xE0001 }, { 0xE0020, 0xE007F },
|
||||
{ 0xE0100, 0xE01EF }
|
||||
};
|
||||
|
||||
/* test for 8-bit control characters */
|
||||
if (ucs == 0)
|
||||
return 0;
|
||||
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
|
||||
return -1;
|
||||
|
||||
/* binary search in table of non-spacing characters */
|
||||
if (bisearch(ucs, combining,
|
||||
sizeof(combining) / sizeof(struct interval) - 1))
|
||||
return 0;
|
||||
|
||||
/* if we arrive here, ucs is not a combining or C0/C1 control character */
|
||||
|
||||
return 1 +
|
||||
(ucs >= 0x1100 &&
|
||||
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
|
||||
ucs == 0x2329 || ucs == 0x232a ||
|
||||
(ucs >= 0x2e80 && ucs <= 0xa4cf &&
|
||||
ucs != 0x303f) || /* CJK ... Yi */
|
||||
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
|
||||
(ucs >= 0xf900 && ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
|
||||
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
|
||||
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
|
||||
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
|
||||
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
|
||||
|
||||
#ifndef _WIN32 // sizeof(wchar_t) == 2
|
||||
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
|
||||
(ucs >= 0x30000 && ucs <= 0x3fffd) ||
|
||||
#endif
|
||||
0
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
int mk_wcswidth(const wchar_t *pwcs, size_t n)
|
||||
{
|
||||
int w, width = 0;
|
||||
|
||||
for (;*pwcs && n-- > 0; pwcs++)
|
||||
if ((w = mk_wcwidth(*pwcs)) < 0)
|
||||
return -1;
|
||||
else
|
||||
width += w;
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The following functions are the same as mk_wcwidth() and
|
||||
* mk_wcswidth(), except that spacing characters in the East Asian
|
||||
* Ambiguous (A) category as defined in Unicode Technical Report #11
|
||||
* have a column width of 2. This variant might be useful for users of
|
||||
* CJK legacy encodings who want to migrate to UCS without changing
|
||||
* the traditional terminal character-width behaviour. It is not
|
||||
* otherwise recommended for general use.
|
||||
*/
|
||||
int mk_wcwidth_cjk(wchar_t ucs)
|
||||
{
|
||||
/* sorted list of non-overlapping intervals of East Asian Ambiguous
|
||||
* characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
|
||||
static const struct interval ambiguous[] = {
|
||||
{ 0x00A1, 0x00A1 }, { 0x00A4, 0x00A4 }, { 0x00A7, 0x00A8 },
|
||||
{ 0x00AA, 0x00AA }, { 0x00AE, 0x00AE }, { 0x00B0, 0x00B4 },
|
||||
{ 0x00B6, 0x00BA }, { 0x00BC, 0x00BF }, { 0x00C6, 0x00C6 },
|
||||
{ 0x00D0, 0x00D0 }, { 0x00D7, 0x00D8 }, { 0x00DE, 0x00E1 },
|
||||
{ 0x00E6, 0x00E6 }, { 0x00E8, 0x00EA }, { 0x00EC, 0x00ED },
|
||||
{ 0x00F0, 0x00F0 }, { 0x00F2, 0x00F3 }, { 0x00F7, 0x00FA },
|
||||
{ 0x00FC, 0x00FC }, { 0x00FE, 0x00FE }, { 0x0101, 0x0101 },
|
||||
{ 0x0111, 0x0111 }, { 0x0113, 0x0113 }, { 0x011B, 0x011B },
|
||||
{ 0x0126, 0x0127 }, { 0x012B, 0x012B }, { 0x0131, 0x0133 },
|
||||
{ 0x0138, 0x0138 }, { 0x013F, 0x0142 }, { 0x0144, 0x0144 },
|
||||
{ 0x0148, 0x014B }, { 0x014D, 0x014D }, { 0x0152, 0x0153 },
|
||||
{ 0x0166, 0x0167 }, { 0x016B, 0x016B }, { 0x01CE, 0x01CE },
|
||||
{ 0x01D0, 0x01D0 }, { 0x01D2, 0x01D2 }, { 0x01D4, 0x01D4 },
|
||||
{ 0x01D6, 0x01D6 }, { 0x01D8, 0x01D8 }, { 0x01DA, 0x01DA },
|
||||
{ 0x01DC, 0x01DC }, { 0x0251, 0x0251 }, { 0x0261, 0x0261 },
|
||||
{ 0x02C4, 0x02C4 }, { 0x02C7, 0x02C7 }, { 0x02C9, 0x02CB },
|
||||
{ 0x02CD, 0x02CD }, { 0x02D0, 0x02D0 }, { 0x02D8, 0x02DB },
|
||||
{ 0x02DD, 0x02DD }, { 0x02DF, 0x02DF }, { 0x0391, 0x03A1 },
|
||||
{ 0x03A3, 0x03A9 }, { 0x03B1, 0x03C1 }, { 0x03C3, 0x03C9 },
|
||||
{ 0x0401, 0x0401 }, { 0x0410, 0x044F }, { 0x0451, 0x0451 },
|
||||
{ 0x2010, 0x2010 }, { 0x2013, 0x2016 }, { 0x2018, 0x2019 },
|
||||
{ 0x201C, 0x201D }, { 0x2020, 0x2022 }, { 0x2024, 0x2027 },
|
||||
{ 0x2030, 0x2030 }, { 0x2032, 0x2033 }, { 0x2035, 0x2035 },
|
||||
{ 0x203B, 0x203B }, { 0x203E, 0x203E }, { 0x2074, 0x2074 },
|
||||
{ 0x207F, 0x207F }, { 0x2081, 0x2084 }, { 0x20AC, 0x20AC },
|
||||
{ 0x2103, 0x2103 }, { 0x2105, 0x2105 }, { 0x2109, 0x2109 },
|
||||
{ 0x2113, 0x2113 }, { 0x2116, 0x2116 }, { 0x2121, 0x2122 },
|
||||
{ 0x2126, 0x2126 }, { 0x212B, 0x212B }, { 0x2153, 0x2154 },
|
||||
{ 0x215B, 0x215E }, { 0x2160, 0x216B }, { 0x2170, 0x2179 },
|
||||
{ 0x2190, 0x2199 }, { 0x21B8, 0x21B9 }, { 0x21D2, 0x21D2 },
|
||||
{ 0x21D4, 0x21D4 }, { 0x21E7, 0x21E7 }, { 0x2200, 0x2200 },
|
||||
{ 0x2202, 0x2203 }, { 0x2207, 0x2208 }, { 0x220B, 0x220B },
|
||||
{ 0x220F, 0x220F }, { 0x2211, 0x2211 }, { 0x2215, 0x2215 },
|
||||
{ 0x221A, 0x221A }, { 0x221D, 0x2220 }, { 0x2223, 0x2223 },
|
||||
{ 0x2225, 0x2225 }, { 0x2227, 0x222C }, { 0x222E, 0x222E },
|
||||
{ 0x2234, 0x2237 }, { 0x223C, 0x223D }, { 0x2248, 0x2248 },
|
||||
{ 0x224C, 0x224C }, { 0x2252, 0x2252 }, { 0x2260, 0x2261 },
|
||||
{ 0x2264, 0x2267 }, { 0x226A, 0x226B }, { 0x226E, 0x226F },
|
||||
{ 0x2282, 0x2283 }, { 0x2286, 0x2287 }, { 0x2295, 0x2295 },
|
||||
{ 0x2299, 0x2299 }, { 0x22A5, 0x22A5 }, { 0x22BF, 0x22BF },
|
||||
{ 0x2312, 0x2312 }, { 0x2460, 0x24E9 }, { 0x24EB, 0x254B },
|
||||
{ 0x2550, 0x2573 }, { 0x2580, 0x258F }, { 0x2592, 0x2595 },
|
||||
{ 0x25A0, 0x25A1 }, { 0x25A3, 0x25A9 }, { 0x25B2, 0x25B3 },
|
||||
{ 0x25B6, 0x25B7 }, { 0x25BC, 0x25BD }, { 0x25C0, 0x25C1 },
|
||||
{ 0x25C6, 0x25C8 }, { 0x25CB, 0x25CB }, { 0x25CE, 0x25D1 },
|
||||
{ 0x25E2, 0x25E5 }, { 0x25EF, 0x25EF }, { 0x2605, 0x2606 },
|
||||
{ 0x2609, 0x2609 }, { 0x260E, 0x260F }, { 0x2614, 0x2615 },
|
||||
{ 0x261C, 0x261C }, { 0x261E, 0x261E }, { 0x2640, 0x2640 },
|
||||
{ 0x2642, 0x2642 }, { 0x2660, 0x2661 }, { 0x2663, 0x2665 },
|
||||
{ 0x2667, 0x266A }, { 0x266C, 0x266D }, { 0x266F, 0x266F },
|
||||
{ 0x273D, 0x273D }, { 0x2776, 0x277F }, { 0xE000, 0xF8FF },
|
||||
{ 0xFFFD, 0xFFFD }, { 0xF0000, 0xFFFFD }, { 0x100000, 0x10FFFD }
|
||||
};
|
||||
|
||||
/* binary search in table of non-spacing characters */
|
||||
if (bisearch(ucs, ambiguous,
|
||||
sizeof(ambiguous) / sizeof(struct interval) - 1))
|
||||
return 2;
|
||||
|
||||
return mk_wcwidth(ucs);
|
||||
}
|
||||
|
||||
|
||||
int mk_wcswidth_cjk(const wchar_t *pwcs, size_t n)
|
||||
{
|
||||
int w, width = 0;
|
||||
|
||||
for (;*pwcs && n-- > 0; pwcs++)
|
||||
if ((w = mk_wcwidth_cjk(*pwcs)) < 0)
|
||||
return -1;
|
||||
else
|
||||
width += w;
|
||||
|
||||
return width;
|
||||
}
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"home": "https://github.com/ridiculousfish/widecharwidth",
|
||||
"license": "Public domain",
|
||||
"version": "Unicode 17",
|
||||
"author": "ridiculousfish"
|
||||
}
|
||||
+1590
File diff suppressed because it is too large
Load Diff
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"home": "https://github.com/ibireme/yyjson",
|
||||
"license": "MIT ( embed in source )",
|
||||
"version": "0.11.1",
|
||||
"version": "0.12.0",
|
||||
"author": "ibireme"
|
||||
}
|
||||
|
||||
Vendored
+4196
-3943
File diff suppressed because it is too large
Load Diff
Vendored
+174
-116
@@ -32,7 +32,7 @@
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Header Files
|
||||
* MARK: - Header Files
|
||||
*============================================================================*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Compile-time Options
|
||||
* MARK: - Compile-time Options
|
||||
*============================================================================*/
|
||||
|
||||
/*
|
||||
@@ -89,14 +89,8 @@
|
||||
#endif
|
||||
|
||||
/*
|
||||
Define as 1 to disable non-standard JSON features support at compile-time:
|
||||
- YYJSON_READ_ALLOW_INF_AND_NAN
|
||||
- YYJSON_READ_ALLOW_COMMENTS
|
||||
- YYJSON_READ_ALLOW_TRAILING_COMMAS
|
||||
- YYJSON_READ_ALLOW_INVALID_UNICODE
|
||||
- YYJSON_READ_ALLOW_BOM
|
||||
- YYJSON_WRITE_ALLOW_INF_AND_NAN
|
||||
- YYJSON_WRITE_ALLOW_INVALID_UNICODE
|
||||
Define as 1 to disable non-standard JSON features support at compile-time,
|
||||
such as YYJSON_READ_ALLOW_XXX and YYJSON_WRITE_ALLOW_XXX.
|
||||
|
||||
This reduces binary size by about 10%, and slightly improves performance.
|
||||
*/
|
||||
@@ -151,7 +145,7 @@
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Compiler Macros
|
||||
* MARK: - Compiler Macros
|
||||
*============================================================================*/
|
||||
|
||||
/** compiler version (MSVC) */
|
||||
@@ -179,8 +173,10 @@
|
||||
#endif
|
||||
|
||||
/** real gcc check */
|
||||
#if !defined(__clang__) && !defined(__INTEL_COMPILER) && !defined(__ICC) && \
|
||||
defined(__GNUC__)
|
||||
#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
|
||||
!defined(__clang__) && !defined(__llvm__) && \
|
||||
!defined(__INTEL_COMPILER) && !defined(__ICC) && \
|
||||
!defined(__NVCC__) && !defined(__PGI) && !defined(__TINYC__)
|
||||
# define YYJSON_IS_REAL_GCC 1
|
||||
#else
|
||||
# define YYJSON_IS_REAL_GCC 0
|
||||
@@ -465,7 +461,7 @@
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Compile Hint Begin
|
||||
* MARK: - Compile Hint Begin
|
||||
*============================================================================*/
|
||||
|
||||
/* extern "C" begin */
|
||||
@@ -492,23 +488,23 @@ extern "C" {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Version
|
||||
* MARK: - Version
|
||||
*============================================================================*/
|
||||
|
||||
/** The major version of yyjson. */
|
||||
#define YYJSON_VERSION_MAJOR 0
|
||||
|
||||
/** The minor version of yyjson. */
|
||||
#define YYJSON_VERSION_MINOR 11
|
||||
#define YYJSON_VERSION_MINOR 12
|
||||
|
||||
/** The patch version of yyjson. */
|
||||
#define YYJSON_VERSION_PATCH 1
|
||||
#define YYJSON_VERSION_PATCH 0
|
||||
|
||||
/** The version of yyjson in hex: `(major << 16) | (minor << 8) | (patch)`. */
|
||||
#define YYJSON_VERSION_HEX 0x000B01
|
||||
#define YYJSON_VERSION_HEX 0x000C00
|
||||
|
||||
/** The version string of yyjson. */
|
||||
#define YYJSON_VERSION_STRING "0.11.1"
|
||||
#define YYJSON_VERSION_STRING "0.12.0"
|
||||
|
||||
/** The version of yyjson in hex, same as `YYJSON_VERSION_HEX`. */
|
||||
yyjson_api uint32_t yyjson_version(void);
|
||||
@@ -516,7 +512,7 @@ yyjson_api uint32_t yyjson_version(void);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Types
|
||||
* MARK: - JSON Types
|
||||
*============================================================================*/
|
||||
|
||||
/** Type of a JSON value (3 bit). */
|
||||
@@ -578,7 +574,7 @@ typedef uint8_t yyjson_subtype;
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Allocator
|
||||
* MARK: - Allocator
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -662,7 +658,7 @@ yyjson_api void yyjson_alc_dyn_free(yyjson_alc *alc);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Text Locating
|
||||
* MARK: - Text Locating
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -686,7 +682,7 @@ yyjson_api bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Structure
|
||||
* MARK: - JSON Structure
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -720,7 +716,7 @@ typedef struct yyjson_mut_val yyjson_mut_val;
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Reader API
|
||||
* MARK: - JSON Reader API
|
||||
*============================================================================*/
|
||||
|
||||
/** Run-time options for JSON reader. */
|
||||
@@ -734,7 +730,7 @@ typedef uint32_t yyjson_read_flag;
|
||||
- Report error if double number is infinity.
|
||||
- Report error if string contains invalid UTF-8 character or BOM.
|
||||
- Report error on trailing commas, comments, inf and nan literals. */
|
||||
static const yyjson_read_flag YYJSON_READ_NOFLAG = 0;
|
||||
static const yyjson_read_flag YYJSON_READ_NOFLAG = 0;
|
||||
|
||||
/** Read the input data in-situ.
|
||||
This option allows the reader to modify and use input data to store string
|
||||
@@ -742,27 +738,27 @@ static const yyjson_read_flag YYJSON_READ_NOFLAG = 0;
|
||||
The caller should hold the input data before free the document.
|
||||
The input data must be padded by at least `YYJSON_PADDING_SIZE` bytes.
|
||||
For example: `[1,2]` should be `[1,2]\0\0\0\0`, input length should be 5. */
|
||||
static const yyjson_read_flag YYJSON_READ_INSITU = 1 << 0;
|
||||
static const yyjson_read_flag YYJSON_READ_INSITU = 1 << 0;
|
||||
|
||||
/** Stop when done instead of issuing an error if there's additional content
|
||||
after a JSON document. This option may be used to parse small pieces of JSON
|
||||
in larger data, such as `NDJSON`. */
|
||||
static const yyjson_read_flag YYJSON_READ_STOP_WHEN_DONE = 1 << 1;
|
||||
static const yyjson_read_flag YYJSON_READ_STOP_WHEN_DONE = 1 << 1;
|
||||
|
||||
/** Allow single trailing comma at the end of an object or array,
|
||||
such as `[1,2,3,]`, `{"a":1,"b":2,}` (non-standard). */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_TRAILING_COMMAS = 1 << 2;
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_TRAILING_COMMAS = 1 << 2;
|
||||
|
||||
/** Allow C-style single line and multiple line comments (non-standard). */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_COMMENTS = 1 << 3;
|
||||
/** Allow C-style single-line and mult-line comments (non-standard). */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_COMMENTS = 1 << 3;
|
||||
|
||||
/** Allow inf/nan number and literal, case-insensitive,
|
||||
such as 1e999, NaN, inf, -Infinity (non-standard). */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_INF_AND_NAN = 1 << 4;
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_INF_AND_NAN = 1 << 4;
|
||||
|
||||
/** Read all numbers as raw strings (value with `YYJSON_TYPE_RAW` type),
|
||||
inf/nan literal is also read as raw with `ALLOW_INF_AND_NAN` flag. */
|
||||
static const yyjson_read_flag YYJSON_READ_NUMBER_AS_RAW = 1 << 5;
|
||||
static const yyjson_read_flag YYJSON_READ_NUMBER_AS_RAW = 1 << 5;
|
||||
|
||||
/** Allow reading invalid unicode when parsing string values (non-standard).
|
||||
Invalid characters will be allowed to appear in the string values, but
|
||||
@@ -772,16 +768,62 @@ static const yyjson_read_flag YYJSON_READ_NUMBER_AS_RAW = 1 << 5;
|
||||
@warning Strings in JSON values may contain incorrect encoding when this
|
||||
option is used, you need to handle these strings carefully to avoid security
|
||||
risks. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_INVALID_UNICODE = 1 << 6;
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_INVALID_UNICODE = 1 << 6;
|
||||
|
||||
/** Read big numbers as raw strings. These big numbers include integers that
|
||||
cannot be represented by `int64_t` and `uint64_t`, and floating-point
|
||||
numbers that cannot be represented by finite `double`.
|
||||
The flag will be overridden by `YYJSON_READ_NUMBER_AS_RAW` flag. */
|
||||
static const yyjson_read_flag YYJSON_READ_BIGNUM_AS_RAW = 1 << 7;
|
||||
static const yyjson_read_flag YYJSON_READ_BIGNUM_AS_RAW = 1 << 7;
|
||||
|
||||
/** Allow UTF-8 BOM and skip it before parsing if any (non-standard). */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_BOM = 1 << 8;
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_BOM = 1 << 8;
|
||||
|
||||
/** Allow extended number formats (non-standard):
|
||||
- Hexadecimal numbers, such as `0x7B`.
|
||||
- Numbers with leading or trailing decimal point, such as `.123`, `123.`.
|
||||
- Numbers with a leading plus sign, such as `+123`. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_NUMBER = 1 << 9;
|
||||
|
||||
/** Allow extended escape sequences in strings (non-standard):
|
||||
- Additional escapes: `\a`, `\e`, `\v`, ``\'``, `\?`, `\0`.
|
||||
- Hex escapes: `\xNN`, such as `\x7B`.
|
||||
- Line continuation: backslash followed by line terminator sequences.
|
||||
- Unknown escape: if backslash is followed by an unsupported character,
|
||||
the backslash will be removed and the character will be kept as-is.
|
||||
However, `\1`-`\9` will still trigger an error. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_ESCAPE = 1 << 10;
|
||||
|
||||
/** Allow extended whitespace characters (non-standard):
|
||||
- Vertical tab `\v` and form feed `\f`.
|
||||
- Line separator `\u2028` and paragraph separator `\u2029`.
|
||||
- Non-breaking space `\xA0`.
|
||||
- Byte order mark: `\uFEFF`.
|
||||
- Other Unicode characters in the Zs (Separator, space) category. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_WHITESPACE = 1 << 11;
|
||||
|
||||
/** Allow strings enclosed in single quotes (non-standard), such as ``'ab'``. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_SINGLE_QUOTED_STR = 1 << 12;
|
||||
|
||||
/** Allow object keys without quotes (non-standard), such as `{a:1,b:2}`.
|
||||
This extends the ECMAScript IdentifierName rule by allowing any
|
||||
non-whitespace character with code point above `U+007F`. */
|
||||
static const yyjson_read_flag YYJSON_READ_ALLOW_UNQUOTED_KEY = 1 << 13;
|
||||
|
||||
/** Allow JSON5 format, see: [https://json5.org].
|
||||
This flag supports all JSON5 features with some additional extensions:
|
||||
- Accepts more escape sequences than JSON5 (e.g. `\a`, `\e`).
|
||||
- Unquoted keys are not limited to ECMAScript IdentifierName.
|
||||
- Allow case-insensitive `NaN`, `Inf` and `Infinity` literals. */
|
||||
static const yyjson_read_flag YYJSON_READ_JSON5 =
|
||||
(1 << 2) | /* YYJSON_READ_ALLOW_TRAILING_COMMAS */
|
||||
(1 << 3) | /* YYJSON_READ_ALLOW_COMMENTS */
|
||||
(1 << 4) | /* YYJSON_READ_ALLOW_INF_AND_NAN */
|
||||
(1 << 9) | /* YYJSON_READ_ALLOW_EXT_NUMBER */
|
||||
(1 << 10) | /* YYJSON_READ_ALLOW_EXT_ESCAPE */
|
||||
(1 << 11) | /* YYJSON_READ_ALLOW_EXT_WHITESPACE */
|
||||
(1 << 12) | /* YYJSON_READ_ALLOW_SINGLE_QUOTED_STR */
|
||||
(1 << 13); /* YYJSON_READ_ALLOW_UNQUOTED_KEY */
|
||||
|
||||
|
||||
|
||||
@@ -794,7 +836,7 @@ static const yyjson_read_code YYJSON_READ_SUCCESS = 0;
|
||||
/** Invalid parameter, such as NULL input string or 0 input length. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_PARAMETER = 1;
|
||||
|
||||
/** Memory allocation failure occurs. */
|
||||
/** Memory allocation failed. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_MEMORY_ALLOCATION = 2;
|
||||
|
||||
/** Input JSON string is empty. */
|
||||
@@ -803,7 +845,7 @@ static const yyjson_read_code YYJSON_READ_ERROR_EMPTY_CONTENT = 3;
|
||||
/** Unexpected content after document, such as `[123]abc`. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CONTENT = 4;
|
||||
|
||||
/** Unexpected ending, such as `[123`. */
|
||||
/** Unexpected end of input, the parsed part is valid, such as `[123`. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_END = 5;
|
||||
|
||||
/** Unexpected character inside the document, such as `[abc]`. */
|
||||
@@ -812,7 +854,7 @@ static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CHARACTER = 6;
|
||||
/** Invalid JSON structure, such as `[1,]`. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_JSON_STRUCTURE = 7;
|
||||
|
||||
/** Invalid comment, such as unclosed multi-line comment. */
|
||||
/** Invalid comment, deprecated, use `UNEXPECTED_END` for unclosed comment. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_COMMENT = 8;
|
||||
|
||||
/** Invalid number, such as `123.e12`, `000`. */
|
||||
@@ -830,7 +872,7 @@ static const yyjson_read_code YYJSON_READ_ERROR_FILE_OPEN = 12;
|
||||
/** Failed to read a file. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_FILE_READ = 13;
|
||||
|
||||
/** Unexpected ending during incremental parsing. Parsing state is saved. */
|
||||
/** Incomplete input during incremental parsing; parsing state is preserved. */
|
||||
static const yyjson_read_code YYJSON_READ_ERROR_MORE = 14;
|
||||
|
||||
/** Error information for JSON reader. */
|
||||
@@ -884,6 +926,7 @@ yyjson_api yyjson_doc *yyjson_read_opts(char *dat,
|
||||
2. The `alc` is thread-safe or NULL.
|
||||
|
||||
@param path The JSON file's path.
|
||||
This should be a null-terminated string using the system's native encoding.
|
||||
If this path is NULL or invalid, the function will fail and return NULL.
|
||||
@param flg The JSON read options.
|
||||
Multiple options can be combined with `|` operator. 0 means no options.
|
||||
@@ -960,6 +1003,9 @@ typedef struct yyjson_incr_state yyjson_incr_state;
|
||||
2. Call `yyjson_incr_read()` repeatedly.
|
||||
3. Call `yyjson_incr_free()` to free the state.
|
||||
|
||||
Note: The incremental JSON reader only supports standard JSON.
|
||||
Flags for non-standard features (e.g. comments, trailing commas) are ignored.
|
||||
|
||||
@param buf The JSON data, null-terminator is not required.
|
||||
If this parameter is NULL, the function will fail and return NULL.
|
||||
@param buf_len The length of the JSON data in `buf`.
|
||||
@@ -1088,27 +1134,7 @@ yyjson_api const char *yyjson_read_number(const char *dat,
|
||||
const yyjson_alc *alc,
|
||||
yyjson_read_err *err);
|
||||
|
||||
/**
|
||||
Read a JSON number.
|
||||
|
||||
This function is thread-safe when data is not modified by other threads.
|
||||
|
||||
@param dat The JSON data (UTF-8 without BOM), null-terminator is required.
|
||||
If this parameter is NULL, the function will fail and return NULL.
|
||||
@param val The output value where result is stored.
|
||||
If this parameter is NULL, the function will fail and return NULL.
|
||||
The value will hold either UINT or SINT or REAL number;
|
||||
@param flg The JSON read options.
|
||||
Multiple options can be combined with `|` operator. 0 means no options.
|
||||
Supports `YYJSON_READ_NUMBER_AS_RAW` and `YYJSON_READ_ALLOW_INF_AND_NAN`.
|
||||
@param alc The memory allocator used for long number.
|
||||
It is only used when the built-in floating point reader is disabled.
|
||||
Pass NULL to use the libc's default allocator.
|
||||
@param err A pointer to receive error information.
|
||||
Pass NULL if you don't need error information.
|
||||
@return If successful, a pointer to the character after the last character
|
||||
used in the conversion, NULL if an error occurs.
|
||||
*/
|
||||
/** Same as `yyjson_read_number()`. */
|
||||
yyjson_api_inline const char *yyjson_mut_read_number(const char *dat,
|
||||
yyjson_mut_val *val,
|
||||
yyjson_read_flag flg,
|
||||
@@ -1122,7 +1148,7 @@ yyjson_api_inline const char *yyjson_mut_read_number(const char *dat,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Writer API
|
||||
* MARK: - JSON Writer API
|
||||
*============================================================================*/
|
||||
|
||||
/** Run-time options for JSON writer. */
|
||||
@@ -1230,7 +1256,7 @@ typedef struct yyjson_write_err {
|
||||
#if !defined(YYJSON_DISABLE_WRITER) || !YYJSON_DISABLE_WRITER
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Document Writer API
|
||||
* MARK: - JSON Document Writer API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -1267,6 +1293,7 @@ yyjson_api char *yyjson_write_opts(const yyjson_doc *doc,
|
||||
2. The `alc` is thread-safe or NULL.
|
||||
|
||||
@param path The JSON file's path.
|
||||
This should be a null-terminated string using the system's native encoding.
|
||||
If this path is NULL or invalid, the function will fail and return false.
|
||||
If this file is not empty, the content will be discarded.
|
||||
@param doc The JSON document.
|
||||
@@ -1370,6 +1397,7 @@ yyjson_api char *yyjson_mut_write_opts(const yyjson_mut_doc *doc,
|
||||
3. The `alc` is thread-safe or NULL.
|
||||
|
||||
@param path The JSON file's path.
|
||||
This should be a null-terminated string using the system's native encoding.
|
||||
If this path is NULL or invalid, the function will fail and return false.
|
||||
If this file is not empty, the content will be discarded.
|
||||
@param doc The mutable JSON document.
|
||||
@@ -1439,7 +1467,7 @@ yyjson_api_inline char *yyjson_mut_write(const yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value Writer API
|
||||
* MARK: - JSON Value Writer API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -1476,6 +1504,7 @@ yyjson_api char *yyjson_val_write_opts(const yyjson_val *val,
|
||||
2. The `alc` is thread-safe or NULL.
|
||||
|
||||
@param path The JSON file's path.
|
||||
This should be a null-terminated string using the system's native encoding.
|
||||
If this path is NULL or invalid, the function will fail and return false.
|
||||
If this file is not empty, the content will be discarded.
|
||||
@param val The JSON root value.
|
||||
@@ -1577,6 +1606,7 @@ yyjson_api char *yyjson_mut_val_write_opts(const yyjson_mut_val *val,
|
||||
3. The `alc` is thread-safe or NULL.
|
||||
|
||||
@param path The JSON file's path.
|
||||
This should be a null-terminated string using the system's native encoding.
|
||||
If this path is NULL or invalid, the function will fail and return false.
|
||||
If this file is not empty, the content will be discarded.
|
||||
@param val The mutable JSON root value.
|
||||
@@ -1643,12 +1673,40 @@ yyjson_api_inline char *yyjson_mut_val_write(const yyjson_mut_val *val,
|
||||
return yyjson_mut_val_write_opts(val, flg, NULL, len, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
Write a JSON number.
|
||||
|
||||
@param val A JSON number value to be converted to a string.
|
||||
If this parameter is invalid, the function will fail and return NULL.
|
||||
@param buf A buffer to store the resulting null-terminated string.
|
||||
If this parameter is NULL, the function will fail and return NULL.
|
||||
For integer values, the buffer must be at least 21 bytes.
|
||||
For floating-point values, the buffer must be at least 40 bytes.
|
||||
@return On success, returns a pointer to the character after the last
|
||||
written character. On failure, returns NULL.
|
||||
@note
|
||||
- This function is thread-safe and does not allocate memory
|
||||
(when `YYJSON_DISABLE_FAST_FP_CONV` is not defined).
|
||||
- This function will fail and return NULL only in the following cases:
|
||||
1) `val` or `buf` is NULL;
|
||||
2) `val` is not a number type;
|
||||
3) `val` is `inf` or `nan`, and non-standard JSON is explicitly disabled
|
||||
via the `YYJSON_DISABLE_NON_STANDARD` flag.
|
||||
*/
|
||||
yyjson_api char *yyjson_write_number(const yyjson_val *val, char *buf);
|
||||
|
||||
/** Same as `yyjson_write_number()`. */
|
||||
yyjson_api_inline char *yyjson_mut_write_number(const yyjson_mut_val *val,
|
||||
char *buf) {
|
||||
return yyjson_write_number((const yyjson_val *)val, buf);
|
||||
}
|
||||
|
||||
#endif /* YYJSON_DISABLE_WRITER */
|
||||
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Document API
|
||||
* MARK: - JSON Document API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the root value of this JSON document.
|
||||
@@ -1673,7 +1731,7 @@ yyjson_api_inline void yyjson_doc_free(yyjson_doc *doc);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value Type API
|
||||
* MARK: - JSON Value Type API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns whether the JSON value is raw.
|
||||
@@ -1735,7 +1793,7 @@ yyjson_api_inline bool yyjson_is_ctn(yyjson_val *val);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value Content API
|
||||
* MARK: - JSON Value Content API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the JSON value's type.
|
||||
@@ -1760,7 +1818,7 @@ yyjson_api_inline const char *yyjson_get_type_desc(yyjson_val *val);
|
||||
yyjson_api_inline const char *yyjson_get_raw(yyjson_val *val);
|
||||
|
||||
/** Returns the content if the value is bool.
|
||||
Returns NULL if `val` is NULL or type is not bool. */
|
||||
Returns false if `val` is NULL or type is not bool. */
|
||||
yyjson_api_inline bool yyjson_get_bool(yyjson_val *val);
|
||||
|
||||
/** Returns the content and cast to uint64_t.
|
||||
@@ -1888,7 +1946,7 @@ yyjson_api_inline bool yyjson_set_str_noesc(yyjson_val *val, bool noesc);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Array API
|
||||
* MARK: - JSON Array API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the number of elements in this array.
|
||||
@@ -1914,7 +1972,7 @@ yyjson_api_inline yyjson_val *yyjson_arr_get_last(yyjson_val *arr);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Array Iterator API
|
||||
* MARK: - JSON Array Iterator API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -1996,7 +2054,7 @@ yyjson_api_inline yyjson_val *yyjson_arr_iter_next(yyjson_arr_iter *iter);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Object API
|
||||
* MARK: - JSON Object API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the number of key-value pairs in this object.
|
||||
@@ -2026,7 +2084,7 @@ yyjson_api_inline yyjson_val *yyjson_obj_getn(yyjson_val *obj, const char *key,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Object Iterator API
|
||||
* MARK: - JSON Object Iterator API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -2169,7 +2227,7 @@ yyjson_api_inline yyjson_val *yyjson_obj_iter_getn(yyjson_obj_iter *iter,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Document API
|
||||
* MARK: - Mutable JSON Document API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the root value of this JSON document.
|
||||
@@ -2273,7 +2331,7 @@ yyjson_api yyjson_doc *yyjson_mut_val_imut_copy(yyjson_mut_val *val,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Type API
|
||||
* MARK: - Mutable JSON Value Type API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns whether the JSON value is raw.
|
||||
@@ -2335,7 +2393,7 @@ yyjson_api_inline bool yyjson_mut_is_ctn(yyjson_mut_val *val);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Content API
|
||||
* MARK: - Mutable JSON Value Content API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the JSON value's type.
|
||||
@@ -2504,7 +2562,7 @@ yyjson_api_inline bool yyjson_mut_set_obj(yyjson_mut_val *val);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Creation API
|
||||
* MARK: - Mutable JSON Value Creation API
|
||||
*============================================================================*/
|
||||
|
||||
/** Creates and returns a raw value, returns NULL on error.
|
||||
@@ -2605,7 +2663,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_strncpy(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array API
|
||||
* MARK: - Mutable JSON Array API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the number of elements in this array.
|
||||
@@ -2629,7 +2687,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_last(yyjson_mut_val *arr);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Iterator API
|
||||
* MARK: - Mutable JSON Array Iterator API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -2731,7 +2789,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_remove(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Creation API
|
||||
* MARK: - Mutable JSON Array Creation API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -3092,7 +3150,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strncpy(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Modification API
|
||||
* MARK: - Mutable JSON Array Modification API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -3205,7 +3263,7 @@ yyjson_api_inline bool yyjson_mut_arr_rotate(yyjson_mut_val *arr,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Modification Convenience API
|
||||
* MARK: - Mutable JSON Array Modification Convenience API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -3411,7 +3469,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_obj(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object API
|
||||
* MARK: - Mutable JSON Object API
|
||||
*============================================================================*/
|
||||
|
||||
/** Returns the number of key-value pairs in this object.
|
||||
@@ -3443,7 +3501,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_getn(yyjson_mut_val *obj,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Iterator API
|
||||
* MARK: - Mutable JSON Object Iterator API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -3605,7 +3663,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_getn(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Creation API
|
||||
* MARK: - Mutable JSON Object Creation API
|
||||
*============================================================================*/
|
||||
|
||||
/** Creates and returns a mutable object, returns NULL on error. */
|
||||
@@ -3652,7 +3710,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_kv(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Modification API
|
||||
* MARK: - Mutable JSON Object Modification API
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -3762,7 +3820,7 @@ yyjson_api_inline bool yyjson_mut_obj_rotate(yyjson_mut_val *obj,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Modification Convenience API
|
||||
* MARK: - Mutable JSON Object Modification Convenience API
|
||||
*============================================================================*/
|
||||
|
||||
/** Adds a `null` value at the end of the object.
|
||||
@@ -4002,7 +4060,7 @@ yyjson_api_inline bool yyjson_mut_obj_rename_keyn(yyjson_mut_doc *doc,
|
||||
#if !defined(YYJSON_DISABLE_UTILS) || !YYJSON_DISABLE_UTILS
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Pointer API (RFC 6901)
|
||||
* MARK: - JSON Pointer API (RFC 6901)
|
||||
* https://tools.ietf.org/html/rfc6901
|
||||
*============================================================================*/
|
||||
|
||||
@@ -4587,7 +4645,7 @@ yyjson_api_inline bool yyjson_ptr_ctx_remove(yyjson_ptr_ctx *ctx);
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Patch API (RFC 6902)
|
||||
* MARK: - JSON Patch API (RFC 6902)
|
||||
* https://tools.ietf.org/html/rfc6902
|
||||
*============================================================================*/
|
||||
|
||||
@@ -4655,7 +4713,7 @@ yyjson_api yyjson_mut_val *yyjson_mut_patch(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Merge-Patch API (RFC 7386)
|
||||
* MARK: - JSON Merge-Patch API (RFC 7386)
|
||||
* https://tools.ietf.org/html/rfc7386
|
||||
*============================================================================*/
|
||||
|
||||
@@ -4688,7 +4746,7 @@ yyjson_api yyjson_mut_val *yyjson_mut_merge_patch(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Structure (Implementation)
|
||||
* MARK: - JSON Structure (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
/** Payload of a JSON value (8 bytes). */
|
||||
@@ -4725,7 +4783,7 @@ struct yyjson_doc {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Unsafe JSON Value API (Implementation)
|
||||
* MARK: - Unsafe JSON Value API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
/*
|
||||
@@ -5054,7 +5112,7 @@ yyjson_api_inline void unsafe_yyjson_set_obj(void *val, size_t size) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Document API (Implementation)
|
||||
* MARK: - JSON Document API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_val *yyjson_doc_get_root(yyjson_doc *doc) {
|
||||
@@ -5081,7 +5139,7 @@ yyjson_api_inline void yyjson_doc_free(yyjson_doc *doc) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value Type API (Implementation)
|
||||
* MARK: - JSON Value Type API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_is_raw(yyjson_val *val) {
|
||||
@@ -5143,7 +5201,7 @@ yyjson_api_inline bool yyjson_is_ctn(yyjson_val *val) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value Content API (Implementation)
|
||||
* MARK: - JSON Value Content API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_type yyjson_get_type(yyjson_val *val) {
|
||||
@@ -5326,7 +5384,7 @@ yyjson_api_inline bool yyjson_set_str_noesc(yyjson_val *val, bool noesc) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Array API (Implementation)
|
||||
* MARK: - JSON Array API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline size_t yyjson_arr_size(yyjson_val *arr) {
|
||||
@@ -5376,7 +5434,7 @@ yyjson_api_inline yyjson_val *yyjson_arr_get_last(yyjson_val *arr) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Array Iterator API (Implementation)
|
||||
* MARK: - JSON Array Iterator API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_arr_iter_init(yyjson_val *arr,
|
||||
@@ -5415,7 +5473,7 @@ yyjson_api_inline yyjson_val *yyjson_arr_iter_next(yyjson_arr_iter *iter) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Object API (Implementation)
|
||||
* MARK: - JSON Object API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline size_t yyjson_obj_size(yyjson_val *obj) {
|
||||
@@ -5444,7 +5502,7 @@ yyjson_api_inline yyjson_val *yyjson_obj_getn(yyjson_val *obj,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Object Iterator API (Implementation)
|
||||
* MARK: - JSON Object Iterator API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_obj_iter_init(yyjson_val *obj,
|
||||
@@ -5521,7 +5579,7 @@ yyjson_api_inline yyjson_val *yyjson_obj_iter_getn(yyjson_obj_iter *iter,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Structure (Implementation)
|
||||
* MARK: - Mutable JSON Structure (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -5637,7 +5695,7 @@ yyjson_api_inline yyjson_mut_val *unsafe_yyjson_mut_val(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Document API (Implementation)
|
||||
* MARK: - Mutable JSON Document API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_mut_val *yyjson_mut_doc_get_root(yyjson_mut_doc *doc) {
|
||||
@@ -5652,7 +5710,7 @@ yyjson_api_inline void yyjson_mut_doc_set_root(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Type API (Implementation)
|
||||
* MARK: - Mutable JSON Value Type API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_is_raw(yyjson_mut_val *val) {
|
||||
@@ -5714,7 +5772,7 @@ yyjson_api_inline bool yyjson_mut_is_ctn(yyjson_mut_val *val) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Content API (Implementation)
|
||||
* MARK: - Mutable JSON Value Content API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_type yyjson_mut_get_type(yyjson_mut_val *val) {
|
||||
@@ -5893,7 +5951,7 @@ yyjson_api_inline bool yyjson_mut_set_obj(yyjson_mut_val *val) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Value Creation API (Implementation)
|
||||
* MARK: - Mutable JSON Value Creation API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
#define yyjson_mut_val_one(func) \
|
||||
@@ -6034,7 +6092,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_strncpy(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array API (Implementation)
|
||||
* MARK: - Mutable JSON Array API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline size_t yyjson_mut_arr_size(yyjson_mut_val *arr) {
|
||||
@@ -6070,7 +6128,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_get_last(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Iterator API (Implementation)
|
||||
* MARK: - Mutable JSON Array Iterator API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_arr_iter_init(yyjson_mut_val *arr,
|
||||
@@ -6130,7 +6188,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_iter_remove(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Creation API (Implementation)
|
||||
* MARK: - Mutable JSON Array Creation API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_mut_val *yyjson_mut_arr(yyjson_mut_doc *doc) {
|
||||
@@ -6310,7 +6368,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_with_strncpy(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Modification API (Implementation)
|
||||
* MARK: - Mutable JSON Array Modification API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_arr_insert(yyjson_mut_val *arr,
|
||||
@@ -6520,7 +6578,7 @@ yyjson_api_inline bool yyjson_mut_arr_rotate(yyjson_mut_val *arr,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Array Modification Convenience API (Implementation)
|
||||
* MARK: - Mutable JSON Array Modification Convenience API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_arr_add_val(yyjson_mut_val *arr,
|
||||
@@ -6686,7 +6744,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_arr_add_obj(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object API (Implementation)
|
||||
* MARK: - Mutable JSON Object API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline size_t yyjson_mut_obj_size(yyjson_mut_val *obj) {
|
||||
@@ -6715,7 +6773,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_getn(yyjson_mut_val *obj,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Iterator API (Implementation)
|
||||
* MARK: - Mutable JSON Object Iterator API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline bool yyjson_mut_obj_iter_init(yyjson_mut_val *obj,
|
||||
@@ -6806,7 +6864,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_iter_getn(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Creation API (Implementation)
|
||||
* MARK: - Mutable JSON Object Creation API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline yyjson_mut_val *yyjson_mut_obj(yyjson_mut_doc *doc) {
|
||||
@@ -6886,7 +6944,7 @@ yyjson_api_inline yyjson_mut_val *yyjson_mut_obj_with_kv(yyjson_mut_doc *doc,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Modification API (Implementation)
|
||||
* MARK: - Mutable JSON Object Modification API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
yyjson_api_inline void unsafe_yyjson_mut_obj_add(yyjson_mut_val *obj,
|
||||
@@ -7079,7 +7137,7 @@ yyjson_api_inline bool yyjson_mut_obj_rotate(yyjson_mut_val *obj,
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Mutable JSON Object Modification Convenience API (Implementation)
|
||||
* MARK: - Mutable JSON Object Modification Convenience API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
#define yyjson_mut_obj_add_func(func) \
|
||||
@@ -7306,7 +7364,7 @@ yyjson_api_inline bool yyjson_mut_obj_rename_keyn(yyjson_mut_doc *doc,
|
||||
#if !defined(YYJSON_DISABLE_UTILS) || !YYJSON_DISABLE_UTILS
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Pointer API (Implementation)
|
||||
* MARK: - JSON Pointer API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
#define yyjson_ptr_set_err(_code, _msg) do { \
|
||||
@@ -7965,7 +8023,7 @@ yyjson_api_inline bool yyjson_ptr_ctx_remove(yyjson_ptr_ctx *ctx) {
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* JSON Value at Pointer API (Implementation)
|
||||
* MARK: - JSON Value at Pointer API (Implementation)
|
||||
*============================================================================*/
|
||||
|
||||
/**
|
||||
@@ -8068,7 +8126,7 @@ yyjson_api_inline bool yyjson_ptr_get_str(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Deprecated
|
||||
* MARK: - Deprecated
|
||||
*============================================================================*/
|
||||
|
||||
/** @deprecated renamed to `yyjson_doc_ptr_get` */
|
||||
@@ -8152,7 +8210,7 @@ yyjson_api_inline yyjson_mut_val *unsafe_yyjson_mut_get_pointer(
|
||||
|
||||
|
||||
/*==============================================================================
|
||||
* Compiler Hint End
|
||||
* MARK: - Compiler Hint End
|
||||
*============================================================================*/
|
||||
|
||||
#if defined(__clang__)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/FFstrbuf.h"
|
||||
#include "util/FFlist.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/FFlist.h"
|
||||
|
||||
typedef struct FFPlatformSysinfo
|
||||
{
|
||||
@@ -9,7 +9,6 @@ typedef struct FFPlatformSysinfo
|
||||
FFstrbuf release;
|
||||
FFstrbuf version;
|
||||
FFstrbuf architecture;
|
||||
FFstrbuf displayVersion;
|
||||
uint32_t pageSize;
|
||||
} FFPlatformSysinfo;
|
||||
|
||||
@@ -19,8 +18,15 @@ typedef struct FFPlatform
|
||||
FFstrbuf cacheDir; // Trailing slash included
|
||||
FFlist configDirs; // List of FFstrbuf, trailing slash included
|
||||
FFlist dataDirs; // List of FFstrbuf, trailing slash included
|
||||
FFstrbuf exePath; // The real path of current exe
|
||||
FFstrbuf exePath; // The real path of current exe (empty if unavailable)
|
||||
FFstrbuf cwd; // Trailing slash included
|
||||
|
||||
uint32_t pid;
|
||||
#ifndef _WIN32
|
||||
uint32_t uid;
|
||||
#else
|
||||
FFstrbuf sid;
|
||||
#endif
|
||||
FFstrbuf userName;
|
||||
FFstrbuf fullUserName;
|
||||
FFstrbuf hostName;
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <sal.h>
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(__warn_unused_result__)
|
||||
#define FF_C_NODISCARD __attribute__((__warn_unused_result__))
|
||||
#elif defined(_MSC_VER)
|
||||
#define FF_C_NODISCARD _Check_return_
|
||||
#else
|
||||
#define FF_C_NODISCARD
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(__format__)
|
||||
#define FF_C_PRINTF(formatStrIndex, argsStartIndex) __attribute__((__format__ (printf, formatStrIndex, argsStartIndex)))
|
||||
#else
|
||||
#define FF_C_PRINTF(formatStrIndex, argsStartIndex)
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(__format__)
|
||||
#define FF_C_SCANF(formatStrIndex, argsStartIndex) __attribute__((__format__ (scanf, formatStrIndex, argsStartIndex)))
|
||||
#else
|
||||
#define FF_C_SCANF(formatStrIndex, argsStartIndex)
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(__nonnull__)
|
||||
#define FF_C_NONNULL(argIndex, ...) __attribute__((__nonnull__(argIndex, ##__VA_ARGS__)))
|
||||
#else
|
||||
#define FF_C_NONNULL(argIndex, ...)
|
||||
#endif
|
||||
|
||||
#if defined(__has_attribute) && __has_attribute(__returns_nonnull__)
|
||||
#define FF_C_RETURNS_NONNULL __attribute__((__returns_nonnull__))
|
||||
#else
|
||||
#define FF_C_RETURNS_NONNULL
|
||||
#endif
|
||||
@@ -106,6 +106,15 @@ static inline void ffListClear(FFlist* list)
|
||||
list->length = 0;
|
||||
}
|
||||
|
||||
static inline void ffListReserve(FFlist* list, uint32_t newCapacity)
|
||||
{
|
||||
if (__builtin_expect(newCapacity <= list->capacity, false))
|
||||
return;
|
||||
|
||||
list->data = (uint8_t*) realloc(list->data, (size_t) newCapacity * list->elementSize);
|
||||
list->capacity = newCapacity;
|
||||
}
|
||||
|
||||
#define FF_LIST_FOR_EACH(itemType, itemVarName, listVar) \
|
||||
assert(sizeof(itemType) == (listVar).elementSize); \
|
||||
for(itemType* itemVarName = (itemType*)(listVar).data; \
|
||||
@@ -120,3 +129,16 @@ static inline void ffListClear(FFlist* list)
|
||||
assert((listVar).capacity > (index)); \
|
||||
(itemType*)(listVar).data + (index); \
|
||||
})
|
||||
|
||||
#define FF_LIST_ADD(itemType, listVar) \
|
||||
({ \
|
||||
assert(sizeof(itemType) == (listVar).elementSize); \
|
||||
(itemType*) ffListAdd(&(listVar)); \
|
||||
})
|
||||
|
||||
#define FF_LIST_FIRST(itemType, listVar) FF_LIST_GET(itemType, listVar, 0)
|
||||
#define FF_LIST_LAST(itemType, listVar) \
|
||||
({ \
|
||||
assert((listVar).length > 0); \
|
||||
FF_LIST_GET(itemType, listVar, ((listVar).length - 1)); \
|
||||
})
|
||||
@@ -10,6 +10,12 @@
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef FF_USE_SYSTEM_YYJSON
|
||||
#include <yyjson.h>
|
||||
#else
|
||||
#include "3rdparty/yyjson/yyjson.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// #include <shlwapi.h>
|
||||
__stdcall char* StrStrIA(const char* lpFirst, const char* lpSrch);
|
||||
@@ -18,6 +24,8 @@
|
||||
|
||||
#define FASTFETCH_STRBUF_DEFAULT_ALLOC 32
|
||||
|
||||
// static string (allocated == 0), chars points to a string literal
|
||||
// dynamic string (allocated > 0), chars points to a heap allocated buffer
|
||||
typedef struct FFstrbuf
|
||||
{
|
||||
uint32_t allocated;
|
||||
@@ -28,6 +36,7 @@ typedef struct FFstrbuf
|
||||
static inline void ffStrbufInit(FFstrbuf* strbuf);
|
||||
void ffStrbufInitA(FFstrbuf* strbuf, uint32_t allocate);
|
||||
void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments);
|
||||
void ffStrbufInitMoveNS(FFstrbuf* strbuf, uint32_t length, char* heapStr);
|
||||
|
||||
void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free);
|
||||
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free);
|
||||
@@ -48,11 +57,15 @@ void ffStrbufPrependC(FFstrbuf* strbuf, char c);
|
||||
|
||||
void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c);
|
||||
|
||||
// Clear the content of strbuf and set new value
|
||||
// NOTE: Unlike ffStrbufAppend*, ffStrbufSet* functions may NOT reserve extra space
|
||||
void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value);
|
||||
void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value);
|
||||
FF_C_PRINTF(2, 3) void ffStrbufSetF(FFstrbuf* strbuf, const char* format, ...);
|
||||
|
||||
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c);
|
||||
void ffStrbufTrimRight(FFstrbuf* strbuf, char c);
|
||||
void ffStrbufTrimLeftSpace(FFstrbuf* strbuf);
|
||||
void ffStrbufTrimRightSpace(FFstrbuf* strbuf);
|
||||
|
||||
bool ffStrbufRemoveSubstr(FFstrbuf* strbuf, uint32_t startIndex, uint32_t endIndex);
|
||||
@@ -72,6 +85,7 @@ bool ffStrbufSubstrAfter(FFstrbuf* strbuf, uint32_t index); // Not including the
|
||||
bool ffStrbufSubstrAfterFirstC(FFstrbuf* strbuf, char c);
|
||||
bool ffStrbufSubstrAfterFirstS(FFstrbuf* strbuf, const char* str);
|
||||
bool ffStrbufSubstrAfterLastC(FFstrbuf* strbuf, char c);
|
||||
bool ffStrbufSubstr(FFstrbuf* strbuf, uint32_t start, uint32_t end);
|
||||
|
||||
FF_C_NODISCARD uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c);
|
||||
|
||||
@@ -82,17 +96,61 @@ bool ffStrbufEnsureEndsWithC(FFstrbuf* strbuf, char c);
|
||||
void ffStrbufWriteTo(const FFstrbuf* strbuf, FILE* file);
|
||||
void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file);
|
||||
|
||||
FF_C_NODISCARD double ffStrbufToDouble(const FFstrbuf* strbuf);
|
||||
FF_C_NODISCARD double ffStrbufToDouble(const FFstrbuf* strbuf, double defaultValue);
|
||||
FF_C_NODISCARD int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue);
|
||||
FF_C_NODISCARD uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue);
|
||||
|
||||
void ffStrbufUpperCase(FFstrbuf* strbuf);
|
||||
void ffStrbufLowerCase(FFstrbuf* strbuf);
|
||||
|
||||
bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer);
|
||||
void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer);
|
||||
// Function alters the buffer to extract lines or delimited segments (replaces the delimiter with '\0')
|
||||
// so that buffer MUST be heap allocated (NOT a static string)
|
||||
// `lineptr` must be `NULL` and `n` MUST be `0` for the first call
|
||||
// Caller MUST NOT free `*lineptr`
|
||||
bool ffStrbufGetdelim(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer);
|
||||
void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer);
|
||||
|
||||
/**
|
||||
* @brief Read a line from a FFstrbuf.
|
||||
*
|
||||
* @details Behaves like getline(3) but reads from a FFstrbuf.
|
||||
*
|
||||
* @param[in,out] lineptr The pointer to a pointer that will be set to the start of the line
|
||||
(points to buffer's internal memory address to avoid memory allocation and copy).
|
||||
MUST NOT be freed by the caller, unlike `getline(3)`.
|
||||
* MUST be NULL for the first call.
|
||||
* @param[in,out] n The pointer to the size of the buffer of lineptr.
|
||||
MUST be 0 for the first call.
|
||||
* @param[in] buffer The buffer to read from.
|
||||
MUST be heap allocated (NOT a static string).
|
||||
*
|
||||
* @return true if a line has been read, false if the end of the buffer has been reached.
|
||||
*/
|
||||
static inline bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
|
||||
{
|
||||
return ffStrbufGetdelim(lineptr, n, '\n', buffer);
|
||||
}
|
||||
/**
|
||||
* @brief Restore the end of a line that was modified by ffStrbufGetline.
|
||||
* @warning This function should be called before breaking an ffStrbufGetline loop if `buffer` will be used later.
|
||||
*/
|
||||
static inline void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer)
|
||||
{
|
||||
ffStrbufGetdelimRestore(lineptr, n, '\n', buffer);
|
||||
}
|
||||
bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf);
|
||||
bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
|
||||
bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
|
||||
bool ffStrbufSeparatedContainNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
|
||||
bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator);
|
||||
|
||||
int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint);
|
||||
|
||||
void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value);
|
||||
void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value);
|
||||
// Appends a double value to the string buffer with the specified precision (0~15).
|
||||
// if `precision < 0`, let yyjson decide the precision
|
||||
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros);
|
||||
|
||||
FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate)
|
||||
{
|
||||
@@ -104,7 +162,7 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateA(uint32_t allocate)
|
||||
static inline void ffStrbufInitCopy(FFstrbuf* __restrict strbuf, const FFstrbuf* __restrict src)
|
||||
{
|
||||
if (src->allocated == 0) // static string
|
||||
memcpy(strbuf, src, sizeof(FFstrbuf));
|
||||
*strbuf = *src;
|
||||
else
|
||||
{
|
||||
ffStrbufInitA(strbuf, src->allocated);
|
||||
@@ -124,9 +182,7 @@ static inline void ffStrbufInitMove(FFstrbuf* strbuf, FFstrbuf* src)
|
||||
{
|
||||
if (src)
|
||||
{
|
||||
strbuf->allocated = src->allocated;
|
||||
strbuf->chars = src->chars;
|
||||
strbuf->length = src->length;
|
||||
*strbuf = *src;
|
||||
ffStrbufInit(src);
|
||||
}
|
||||
else
|
||||
@@ -169,21 +225,18 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateF(const char* format, ...)
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
static inline void ffStrbufInitMoveS(FFstrbuf* strbuf, char* heapStr)
|
||||
{
|
||||
ffStrbufInitMoveNS(strbuf, (uint32_t) strlen(heapStr), heapStr);
|
||||
}
|
||||
|
||||
// Despite the name, this function resets strbuf to the initial/unallocated state
|
||||
static inline void ffStrbufDestroy(FFstrbuf* strbuf)
|
||||
{
|
||||
extern char* CHAR_NULL_PTR;
|
||||
if(strbuf->allocated > 0)
|
||||
free(strbuf->chars);
|
||||
|
||||
if(strbuf->allocated == 0)
|
||||
{
|
||||
strbuf->length = 0;
|
||||
strbuf->chars = CHAR_NULL_PTR;
|
||||
return;
|
||||
}
|
||||
|
||||
//Avoid free-after-use. These 3 assignments are cheap so don't remove them
|
||||
strbuf->allocated = strbuf->length = 0;
|
||||
free(strbuf->chars);
|
||||
strbuf->chars = CHAR_NULL_PTR;
|
||||
ffStrbufInit(strbuf);
|
||||
}
|
||||
|
||||
FF_C_NODISCARD static inline uint32_t ffStrbufGetFree(const FFstrbuf* strbuf)
|
||||
@@ -200,6 +253,30 @@ static inline void ffStrbufRecalculateLength(FFstrbuf* strbuf)
|
||||
strbuf->length = (uint32_t) strlen(strbuf->chars);
|
||||
}
|
||||
|
||||
static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value)
|
||||
{
|
||||
assert(strbuf != NULL);
|
||||
|
||||
if (value == NULL)
|
||||
ffStrbufClear(strbuf);
|
||||
else
|
||||
ffStrbufSetNS(strbuf, (uint32_t) strlen(value), value);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSetJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
|
||||
{
|
||||
assert(strbuf != NULL);
|
||||
|
||||
if (yyjson_is_str(jsonVal))
|
||||
{
|
||||
ffStrbufSetNS(strbuf, (uint32_t) unsafe_yyjson_get_len(jsonVal), unsafe_yyjson_get_str(jsonVal));
|
||||
return true;
|
||||
}
|
||||
|
||||
ffStrbufClear(strbuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void ffStrbufAppendS(FFstrbuf* strbuf, const char* value)
|
||||
{
|
||||
if(value == NULL)
|
||||
@@ -207,30 +284,20 @@ static inline void ffStrbufAppendS(FFstrbuf* strbuf, const char* value)
|
||||
ffStrbufAppendNS(strbuf, (uint32_t) strlen(value), value);
|
||||
}
|
||||
|
||||
static inline void ffStrbufSetS(FFstrbuf* strbuf, const char* value)
|
||||
static inline bool ffStrbufAppendJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
|
||||
{
|
||||
ffStrbufClear(strbuf);
|
||||
|
||||
if(value != NULL)
|
||||
ffStrbufAppendNS(strbuf, (uint32_t) strlen(value), value);
|
||||
}
|
||||
|
||||
static inline void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value)
|
||||
{
|
||||
assert(value && value != strbuf);
|
||||
if (strbuf->allocated == 0 && value->allocated == 0)
|
||||
if (yyjson_is_str(jsonVal))
|
||||
{
|
||||
memcpy(strbuf, value, sizeof(FFstrbuf));
|
||||
return;
|
||||
ffStrbufAppendNS(strbuf, (uint32_t) unsafe_yyjson_get_len(jsonVal), unsafe_yyjson_get_str(jsonVal));
|
||||
return true;
|
||||
}
|
||||
ffStrbufSetNS(strbuf, value->length, value->chars);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline void ffStrbufInit(FFstrbuf* strbuf)
|
||||
{
|
||||
extern char* CHAR_NULL_PTR;
|
||||
strbuf->allocated = 0;
|
||||
strbuf->length = 0;
|
||||
strbuf->allocated = strbuf->length = 0;
|
||||
strbuf->chars = CHAR_NULL_PTR;
|
||||
}
|
||||
|
||||
@@ -261,10 +328,12 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateStatic(const char* str)
|
||||
static inline void ffStrbufSetStatic(FFstrbuf* strbuf, const char* value)
|
||||
{
|
||||
if(strbuf->allocated > 0)
|
||||
ffStrbufDestroy(strbuf);
|
||||
free(strbuf->chars);
|
||||
|
||||
if(value != NULL)
|
||||
ffStrbufInitStatic(strbuf, value);
|
||||
else
|
||||
ffStrbufInit(strbuf);
|
||||
}
|
||||
|
||||
static inline void ffStrbufInitNS(FFstrbuf* strbuf, uint32_t length, const char* str)
|
||||
@@ -280,6 +349,12 @@ FF_C_NODISCARD static inline FFstrbuf ffStrbufCreateNS(uint32_t length, const ch
|
||||
return strbuf;
|
||||
}
|
||||
|
||||
static inline bool ffStrbufInitJsonVal(FFstrbuf* strbuf, yyjson_val* jsonVal)
|
||||
{
|
||||
ffStrbufInit(strbuf);
|
||||
return ffStrbufAppendJsonVal(strbuf, jsonVal);
|
||||
}
|
||||
|
||||
static inline void ffStrbufInitS(FFstrbuf* strbuf, const char* str)
|
||||
{
|
||||
ffStrbufInit(strbuf);
|
||||
@@ -315,7 +390,7 @@ static inline void ffStrbufPrependS(FFstrbuf* strbuf, const char* value)
|
||||
ffStrbufPrependNS(strbuf, (uint32_t) strlen(value), value);
|
||||
}
|
||||
|
||||
static inline int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp)
|
||||
static inline FF_C_NODISCARD int ffStrbufComp(const FFstrbuf* strbuf, const FFstrbuf* comp)
|
||||
{
|
||||
uint32_t length = strbuf->length > comp->length ? comp->length : strbuf->length;
|
||||
return memcmp(strbuf->chars, comp->chars, length + 1);
|
||||
@@ -473,7 +548,7 @@ static inline FF_C_NODISCARD bool ffStrbufEndsWithS(const FFstrbuf* strbuf, cons
|
||||
return ffStrbufEndsWithNS(strbuf, (uint32_t) strlen(end), end);
|
||||
}
|
||||
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*fn)(int))
|
||||
static inline FF_C_NODISCARD bool ffStrbufEndsWithFn(const FFstrbuf* strbuf, int (*const fn)(int))
|
||||
{
|
||||
return strbuf->length == 0 ? false :
|
||||
fn(strbuf->chars[strbuf->length - 1]);
|
||||
@@ -507,6 +582,12 @@ static inline void ffStrbufTrim(FFstrbuf* strbuf, char c)
|
||||
ffStrbufTrimLeft(strbuf, c);
|
||||
}
|
||||
|
||||
static inline void ffStrbufTrimSpace(FFstrbuf* strbuf)
|
||||
{
|
||||
ffStrbufTrimRightSpace(strbuf);
|
||||
ffStrbufTrimLeftSpace(strbuf);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufMatchSeparatedS(const FFstrbuf* strbuf, const char* comp, char separator)
|
||||
{
|
||||
return ffStrbufMatchSeparatedNS(strbuf, (uint32_t) strlen(comp), comp, separator);
|
||||
@@ -517,4 +598,37 @@ static inline bool ffStrbufMatchSeparated(const FFstrbuf* strbuf, const FFstrbuf
|
||||
return ffStrbufMatchSeparatedNS(strbuf, comp->length, comp->chars, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufMatchSeparatedIgnCaseS(const FFstrbuf* strbuf, const char* comp, char separator)
|
||||
{
|
||||
return ffStrbufMatchSeparatedIgnCaseNS(strbuf, (uint32_t) strlen(comp), comp, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufMatchSeparatedIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
|
||||
{
|
||||
return ffStrbufMatchSeparatedIgnCaseNS(strbuf, comp->length, comp->chars, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSeparatedContainS(const FFstrbuf* strbuf, const char* comp, char separator)
|
||||
{
|
||||
return ffStrbufSeparatedContainNS(strbuf, (uint32_t) strlen(comp), comp, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSeparatedContain(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
|
||||
{
|
||||
return ffStrbufSeparatedContainNS(strbuf, comp->length, comp->chars, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSeparatedContainIgnCaseS(const FFstrbuf* strbuf, const char* comp, char separator)
|
||||
{
|
||||
return ffStrbufSeparatedContainIgnCaseNS(strbuf, (uint32_t) strlen(comp), comp, separator);
|
||||
}
|
||||
|
||||
static inline bool ffStrbufSeparatedContainIgnCase(const FFstrbuf* strbuf, const FFstrbuf* comp, char separator)
|
||||
{
|
||||
return ffStrbufSeparatedContainIgnCaseNS(strbuf, comp->length, comp->chars, separator);
|
||||
}
|
||||
|
||||
// Returns true if the strbuf is modified
|
||||
bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf);
|
||||
|
||||
#define FF_STRBUF_AUTO_DESTROY FFstrbuf __attribute__((__cleanup__(ffStrbufDestroy)))
|
||||
@@ -6,8 +6,8 @@
|
||||
<string>fastfetch</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>@PROJECT_NAME@</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@PROJECT_VERSION@</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>@PROJECT_VERSION@</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>English</string>
|
||||
<key>NSBluetoothAlwaysUsageDescription</key>
|
||||
@@ -40,11 +40,9 @@ const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result)
|
||||
|
||||
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result)
|
||||
{
|
||||
ffStrbufClear(result);
|
||||
if (!cf)
|
||||
{
|
||||
ffStrbufClear(result);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (CFGetTypeID(cf) == CFStringGetTypeID())
|
||||
{
|
||||
@@ -56,6 +54,8 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result)
|
||||
else
|
||||
{
|
||||
uint32_t length = (uint32_t) CFStringGetLength(cfStr);
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
ffStrbufEnsureFixedLengthFree(result, (uint32_t) CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8));
|
||||
if(!CFStringGetCString(cfStr, result->chars, result->allocated, kCFStringEncodingUTF8))
|
||||
return "CFStringGetCString() failed";
|
||||
@@ -68,7 +68,9 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result)
|
||||
{
|
||||
CFDataRef cfData = (CFDataRef)cf;
|
||||
uint32_t length = (uint32_t)CFDataGetLength(cfData);
|
||||
ffStrbufEnsureFree(result, length + 1);
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
ffStrbufEnsureFixedLengthFree(result, length + 1);
|
||||
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars);
|
||||
result->length = (uint32_t)strnlen(result->chars, length);
|
||||
result->chars[result->length] = '\0';
|
||||
@@ -79,6 +81,29 @@ const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result)
|
||||
{
|
||||
ffStrbufClear(result);
|
||||
if (!cf)
|
||||
return NULL;
|
||||
|
||||
if (CFGetTypeID(cf) == CFDataGetTypeID())
|
||||
{
|
||||
CFDataRef cfData = (CFDataRef)cf;
|
||||
uint32_t length = (uint32_t)CFDataGetLength(cfData);
|
||||
if (length == 0)
|
||||
return NULL;
|
||||
ffStrbufEnsureFixedLengthFree(result, length + 1);
|
||||
CFDataGetBytes(cfData, CFRangeMake(0, length), (uint8_t*)result->chars);
|
||||
result->length = length;
|
||||
result->chars[result->length] = '\0';
|
||||
}
|
||||
else
|
||||
return "TypeID is not 'CFData'";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result)
|
||||
{
|
||||
CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key);
|
||||
@@ -88,6 +113,15 @@ const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* r
|
||||
return ffCfStrGetString(cf, result);
|
||||
}
|
||||
|
||||
const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result)
|
||||
{
|
||||
CFTypeRef cf = (CFTypeRef)CFDictionaryGetValue(dict, key);
|
||||
if(cf == NULL)
|
||||
return "CFDictionaryGetValue() failed";
|
||||
|
||||
return ffCfDataGetDataAsString(cf, result);
|
||||
}
|
||||
|
||||
const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result)
|
||||
{
|
||||
CFBooleanRef cf = (CFBooleanRef)CFDictionaryGetValue(dict, key);
|
||||
@@ -8,11 +8,13 @@
|
||||
const char* ffCfStrGetString(CFTypeRef cf, FFstrbuf* result);
|
||||
const char* ffCfNumGetInt(CFTypeRef cf, int32_t* result);
|
||||
const char* ffCfNumGetInt64(CFTypeRef cf, int64_t* result);
|
||||
const char* ffCfDataGetDataAsString(CFTypeRef cf, FFstrbuf* result);
|
||||
const char* ffCfDictGetString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result);
|
||||
const char* ffCfDictGetBool(CFDictionaryRef dict, CFStringRef key, bool* result);
|
||||
const char* ffCfDictGetInt(CFDictionaryRef dict, CFStringRef key, int* result);
|
||||
const char* ffCfDictGetInt64(CFDictionaryRef dict, CFStringRef key, int64_t* result);
|
||||
const char* ffCfDictGetData(CFDictionaryRef dict, CFStringRef key, uint32_t offset, uint32_t size, uint8_t* result, uint32_t* length);
|
||||
const char* ffCfDictGetDataAsString(CFDictionaryRef dict, CFStringRef key, FFstrbuf* result);
|
||||
const char* ffCfDictGetDict(CFDictionaryRef dict, CFStringRef key, CFDictionaryRef* result);
|
||||
|
||||
static inline CFNumberRef ffCfCreateInt(int value)
|
||||
@@ -22,6 +24,7 @@ static inline CFNumberRef ffCfCreateInt(int value)
|
||||
|
||||
static inline void cfReleaseWrapper(void* type)
|
||||
{
|
||||
assert(type);
|
||||
if (*(CFTypeRef*) type)
|
||||
CFRelease(*(CFTypeRef*) type);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "fastfetch.h"
|
||||
#include "smc_temps.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "common/apple/cf_helpers.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
@@ -137,14 +137,11 @@ static const char *smcReadSmcVal(io_connect_t conn, const UInt32Char_t key, SmcV
|
||||
|
||||
static const char *smcOpen(io_connect_t *conn)
|
||||
{
|
||||
io_object_t device = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMC"));
|
||||
FF_IOOBJECT_AUTO_RELEASE io_object_t device = IOServiceGetMatchingService(MACH_PORT_NULL, IOServiceMatching("AppleSMC"));
|
||||
if (!device)
|
||||
return "No SMC device found";
|
||||
|
||||
kern_return_t result = IOServiceOpen(device, mach_task_self(), 0, conn);
|
||||
IOObjectRelease(device);
|
||||
|
||||
if (result != kIOReturnSuccess)
|
||||
if (IOServiceOpen(device, mach_task_self(), 0, conn) != kIOReturnSuccess)
|
||||
return "IOServiceOpen() failed";
|
||||
|
||||
return NULL;
|
||||
@@ -159,113 +156,108 @@ static const char *smcReadValue(io_connect_t conn, const UInt32Char_t key, doubl
|
||||
if (val.dataSize == 0)
|
||||
return "Empty SMC result";
|
||||
|
||||
if (ffStrEquals(val.dataType, "ui8 ") ||
|
||||
ffStrEquals(val.dataType, "ui16") ||
|
||||
ffStrEquals(val.dataType, "ui32") ||
|
||||
ffStrEquals(val.dataType, "ui64"))
|
||||
switch (val.dataType[0])
|
||||
{
|
||||
uint64_t tmp = 0;
|
||||
for (uint32_t i = 0; i < val.dataSize; i++)
|
||||
tmp += (uint64_t)((uint8_t)(val.bytes[i]) * pow(256, val.dataSize - 1 - i));
|
||||
*value = (double)tmp;
|
||||
case 'u': // unsigned integer types
|
||||
if (val.dataType[1] == 'i')
|
||||
{
|
||||
switch (val.dataSize)
|
||||
{
|
||||
case 1: *value = *(uint8_t *)(val.bytes); break;
|
||||
case 2: *value = ntohs(*(uint16_t *)(val.bytes)); break;
|
||||
case 4: *value = ntohl(*(uint32_t *)(val.bytes)); break;
|
||||
case 8: *value = (double) ntohll(*(uint64_t *)(val.bytes)); break;
|
||||
default:
|
||||
return "Unsupported SMC unsigned integer data size";
|
||||
}
|
||||
}
|
||||
else
|
||||
return "Unsupported SMC unsigned data type";
|
||||
break;
|
||||
|
||||
case 'f': // floating point types
|
||||
if (ffStrEquals(val.dataType, "flt ") && val.dataSize == 4)
|
||||
*value = *(float *)(val.bytes);
|
||||
else if (val.dataType[1] == 'p' && val.dataSize == 2) // fixed point types
|
||||
{
|
||||
if (ffStrEquals(val.dataType, "fp1f"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 32768.0;
|
||||
else if (ffStrEquals(val.dataType, "fp4c"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 4096.0;
|
||||
else if (ffStrEquals(val.dataType, "fp5b"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 2048.0;
|
||||
else if (ffStrEquals(val.dataType, "fp6a"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 1024.0;
|
||||
else if (ffStrEquals(val.dataType, "fp79"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 512.0;
|
||||
else if (ffStrEquals(val.dataType, "fp88"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 256.0;
|
||||
else if (ffStrEquals(val.dataType, "fpa6"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 64.0;
|
||||
else if (ffStrEquals(val.dataType, "fpc4"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 16.0;
|
||||
else if (ffStrEquals(val.dataType, "fpe2"))
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 4.0;
|
||||
else
|
||||
return "Unsupported SMC floating point data type";
|
||||
}
|
||||
else
|
||||
return "Unsupported SMC floating point data type";
|
||||
break;
|
||||
|
||||
case 's': // signed integer types
|
||||
if (val.dataType[1] == 'i')
|
||||
{
|
||||
switch (val.dataSize)
|
||||
{
|
||||
case 1: *value = *(int8_t *)(val.bytes); break;
|
||||
case 2: *value = ntohs(*(int16_t *)(val.bytes)); break;
|
||||
case 4: *value = ntohl(*(int32_t *)(val.bytes)); break;
|
||||
case 8: *value = (double)ntohll(*(int64_t *)(val.bytes)); break;
|
||||
default: return "Unsupported SMC signed integer data size";
|
||||
}
|
||||
}
|
||||
else if (val.dataType[1] == 'p' && val.dataSize == 2) // signed fixed point types
|
||||
{
|
||||
if (ffStrEquals(val.dataType, "sp1e"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 16384.0;
|
||||
else if (ffStrEquals(val.dataType, "sp3c"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 4096.0;
|
||||
else if (ffStrEquals(val.dataType, "sp4b"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 2048.0;
|
||||
else if (ffStrEquals(val.dataType, "sp5a"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 1024.0;
|
||||
else if (ffStrEquals(val.dataType, "sp69"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 512.0;
|
||||
else if (ffStrEquals(val.dataType, "sp78"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 256.0;
|
||||
else if (ffStrEquals(val.dataType, "sp87"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 128.0;
|
||||
else if (ffStrEquals(val.dataType, "sp96"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 64.0;
|
||||
else if (ffStrEquals(val.dataType, "spb4"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 16.0;
|
||||
else if (ffStrEquals(val.dataType, "spf0"))
|
||||
*value = (int16_t)ntohs(*(int16_t *)(val.bytes)) / 1.0;
|
||||
else
|
||||
return "Unsupported SMC signed integer data type";
|
||||
}
|
||||
else
|
||||
return "Unsupported SMC signed data type";
|
||||
break;
|
||||
|
||||
case '{': // special types like pwm
|
||||
if (ffStrEquals(val.dataType, "{pwm") && val.dataSize == 2)
|
||||
{
|
||||
*value = (double)ntohs(*(uint16_t *)(val.bytes)) * 100 / 65536.0;
|
||||
}
|
||||
else
|
||||
return "Unsupported SMC special data type";
|
||||
break;
|
||||
|
||||
default:
|
||||
return "Unsupported SMC data type";
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "flt "))
|
||||
{
|
||||
*value = *(float *)(val.bytes);
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "fp1f") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 32768.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "fp4c") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 4096.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "fp5b") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 2048.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "fp6a") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 1024.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "fp79") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 512.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "fp88") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 256.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "fpa6") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 64.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "fpc4") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 16.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "fpe2") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 4.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "sp1e") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 16384.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "sp3c") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 4096.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "sp4b") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 2048.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "sp5a") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 1024.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "sp69") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 512.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "sp78") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 256.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "sp87") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 128.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "sp96") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 64.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "spb4") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 16.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "spf0") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(uint16_t *)(val.bytes)) / 1.0;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "si8 ") && val.dataSize == 1)
|
||||
{
|
||||
signed char *bytes = (signed char *)val.bytes;
|
||||
int16_t temp = 0;
|
||||
temp += (int8_t)(bytes[0]);
|
||||
*value = temp;
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "si16") && val.dataSize == 2)
|
||||
{
|
||||
*value = ntohs(*(int16_t *)(val.bytes));
|
||||
}
|
||||
else if (ffStrEquals(val.dataType, "{pwm") && val.dataSize == 2)
|
||||
{
|
||||
*value = (double)ntohs(*(uint16_t *)(val.bytes)) * 100 / 65536.0;
|
||||
}
|
||||
else
|
||||
return "Unknown SMC data type";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -280,15 +272,32 @@ static bool detectTemp(io_connect_t conn, const char* sensor, double* sum)
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* ffDetectSmcTemps(enum FFTempType type, double* result)
|
||||
static io_connect_t conn;
|
||||
|
||||
const char* ffDetectSmcSpecificTemp(const char* sensor, double* result)
|
||||
{
|
||||
static io_connect_t conn;
|
||||
if (!conn)
|
||||
{
|
||||
if (smcOpen(&conn) != NULL)
|
||||
conn = (io_connect_t) -1;
|
||||
}
|
||||
else if (conn == (io_connect_t) -1)
|
||||
if (conn == (io_connect_t) -1)
|
||||
return "Could not open SMC connection";
|
||||
|
||||
if (!detectTemp(conn, sensor, result))
|
||||
return "Could not read SMC temperature";
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* ffDetectSmcTemps(enum FFTempType type, double* result)
|
||||
{
|
||||
if (!conn)
|
||||
{
|
||||
if (smcOpen(&conn) != NULL)
|
||||
conn = (io_connect_t) -1;
|
||||
}
|
||||
if (conn == (io_connect_t) -1)
|
||||
return "Could not open SMC connection";
|
||||
|
||||
uint32_t count = 0;
|
||||
@@ -30,4 +30,5 @@ enum FFTempType
|
||||
FF_TEMP_MEMORY,
|
||||
};
|
||||
|
||||
const char* ffDetectSmcSpecificTemp(const char* sensor, double* result);
|
||||
const char* ffDetectSmcTemps(enum FFTempType type, double* result);
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
// For ffRegReadValue(s)
|
||||
// If length is 0, data will be allocated with malloc() and must be freed by the caller
|
||||
// Otherwise, data must point to a buffer of at least length bytes, and the actual length of the data will be written to length.
|
||||
typedef struct FFArgBuffer
|
||||
{
|
||||
void* data;
|
||||
uint32_t length;
|
||||
} FFArgBuffer;
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFArgType
|
||||
{
|
||||
FF_ARG_TYPE_NULL = 0,
|
||||
FF_ARG_TYPE_UINT,
|
||||
FF_ARG_TYPE_UINT64,
|
||||
FF_ARG_TYPE_UINT16,
|
||||
FF_ARG_TYPE_UINT8,
|
||||
FF_ARG_TYPE_INT,
|
||||
FF_ARG_TYPE_STRING,
|
||||
FF_ARG_TYPE_STRBUF,
|
||||
FF_ARG_TYPE_FLOAT,
|
||||
FF_ARG_TYPE_DOUBLE,
|
||||
FF_ARG_TYPE_LIST,
|
||||
FF_ARG_TYPE_BOOL,
|
||||
FF_ARG_TYPE_BUFFER,
|
||||
} FFArgType;
|
||||
|
||||
#define FF_ARG(variable, var_name) { _Generic((variable), \
|
||||
uint32_t: FF_ARG_TYPE_UINT, \
|
||||
uint64_t: FF_ARG_TYPE_UINT64, \
|
||||
uint16_t: FF_ARG_TYPE_UINT16, \
|
||||
uint8_t: FF_ARG_TYPE_UINT8, \
|
||||
int32_t: FF_ARG_TYPE_INT, \
|
||||
char*: FF_ARG_TYPE_STRING, \
|
||||
const char*: FF_ARG_TYPE_STRING, \
|
||||
FFstrbuf: FF_ARG_TYPE_STRBUF, \
|
||||
float: FF_ARG_TYPE_FLOAT, \
|
||||
double: FF_ARG_TYPE_DOUBLE, \
|
||||
FFlist: FF_ARG_TYPE_LIST, \
|
||||
bool: FF_ARG_TYPE_BOOL, \
|
||||
FFArgBuffer: FF_ARG_TYPE_BUFFER \
|
||||
), _Generic((variable), char*: (variable), const char*: (variable), default: &(variable) ), (var_name) }
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __has_builtin
|
||||
#if !__cplusplus && FF_SUPPORTS_COUNT_OF
|
||||
#define ARRAY_SIZE(x) _Countof(x)
|
||||
#elif __has_builtin(__is_array)
|
||||
#define ARRAY_SIZE(x) ({ static_assert(__is_array(__typeof__(x)), "Must be an array"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
|
||||
#elif __has_builtin(__builtin_types_compatible_p)
|
||||
#define ARRAY_SIZE(x) ({ static_assert(!__builtin_types_compatible_p(__typeof__(x), __typeof__(&*(x))), "Must not be a pointer"); (uint32_t) (sizeof(x) / sizeof(*(x))); })
|
||||
#endif
|
||||
#endif
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) ((uint32_t) (sizeof(x) / sizeof(*(x))))
|
||||
#endif
|
||||
@@ -1,166 +0,0 @@
|
||||
#include "commandoption.h"
|
||||
#include "common/color.h"
|
||||
#include "common/printing.h"
|
||||
#include "common/time.h"
|
||||
#include "common/jsonconfig.h"
|
||||
#include "fastfetch_datatext.h"
|
||||
#include "modules/modules.h"
|
||||
#include "util/stringUtils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
bool ffParseModuleOptions(const char* key, const char* value)
|
||||
{
|
||||
if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) return false;
|
||||
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (baseInfo->parseCommandOptions(baseInfo, key, value)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffPrepareCommandOption(FFdata* data)
|
||||
{
|
||||
FFOptionsModules* const options = &instance.config.modules;
|
||||
//If we don't have a custom structure, use the default one
|
||||
if(data->structure.length == 0)
|
||||
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_CPUUSAGE_MODULE_NAME))
|
||||
ffPrepareCPUUsage();
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_DISKIO_MODULE_NAME))
|
||||
ffPrepareDiskIO(&options->diskIo);
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_NETIO_MODULE_NAME))
|
||||
ffPrepareNetIO(&options->netIo);
|
||||
|
||||
if(instance.config.general.multithreading)
|
||||
{
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_PUBLICIP_MODULE_NAME))
|
||||
ffPreparePublicIp(&options->publicIP);
|
||||
|
||||
if(ffStrbufContainIgnCaseS(&data->structure, FF_WEATHER_MODULE_NAME))
|
||||
ffPrepareWeather(&options->weather);
|
||||
}
|
||||
}
|
||||
|
||||
static void genJsonConfig(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
|
||||
{
|
||||
yyjson_mut_val* modules = yyjson_mut_obj_get(doc->root, "modules");
|
||||
if (!modules)
|
||||
modules = yyjson_mut_obj_add_arr(doc, doc->root, "modules");
|
||||
|
||||
yyjson_mut_val* module = yyjson_mut_obj(doc);
|
||||
FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateS(baseInfo->name);
|
||||
ffStrbufLowerCase(&type);
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
|
||||
|
||||
if (baseInfo->generateJsonConfig)
|
||||
baseInfo->generateJsonConfig(baseInfo, doc, module);
|
||||
|
||||
if (yyjson_mut_obj_size(module) > 1)
|
||||
yyjson_mut_arr_add_val(modules, module);
|
||||
else
|
||||
yyjson_mut_arr_add_strbuf(doc, modules, &type);
|
||||
}
|
||||
|
||||
static void genJsonResult(FFModuleBaseInfo* baseInfo, yyjson_mut_doc* doc)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJsonResult)
|
||||
baseInfo->generateJsonResult(baseInfo, doc, module);
|
||||
else
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
|
||||
}
|
||||
|
||||
static void parseStructureCommand(
|
||||
const char* line,
|
||||
void (*fn)(FFModuleBaseInfo *baseInfo, yyjson_mut_doc* jsonDoc),
|
||||
yyjson_mut_doc* jsonDoc
|
||||
)
|
||||
{
|
||||
if(ffCharIsEnglishAlphabet(line[0]))
|
||||
{
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(line[0]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(line, baseInfo->name))
|
||||
{
|
||||
if (__builtin_expect(jsonDoc != NULL, false))
|
||||
fn(baseInfo, jsonDoc);
|
||||
else
|
||||
baseInfo->printModule(baseInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ffPrintError(line, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
|
||||
}
|
||||
|
||||
void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc)
|
||||
{
|
||||
//Parse the structure and call the modules
|
||||
int32_t thres = instance.config.display.stat;
|
||||
uint32_t startIndex = 0;
|
||||
while (startIndex < data->structure.length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(&data->structure, startIndex, ':');
|
||||
data->structure.chars[colonIndex] = '\0';
|
||||
|
||||
double ms = 0;
|
||||
if(thres >= 0)
|
||||
ms = ffTimeGetTick();
|
||||
|
||||
parseStructureCommand(data->structure.chars + startIndex, genJsonResult, jsonDoc);
|
||||
|
||||
if(thres >= 0)
|
||||
{
|
||||
ms = ffTimeGetTick() - ms;
|
||||
|
||||
if (jsonDoc)
|
||||
{
|
||||
yyjson_mut_val* moduleJson = yyjson_mut_arr_get_last(jsonDoc->root);
|
||||
yyjson_mut_obj_add_real(jsonDoc, moduleJson, "stat", ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
char str[64];
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (!jsonDoc && !instance.config.display.noBuffer) fflush(stdout);
|
||||
#endif
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc)
|
||||
{
|
||||
//If we don't have a custom structure, use the default one
|
||||
if(data->structure.length == 0)
|
||||
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
|
||||
|
||||
//Parse the structure and call the modules
|
||||
uint32_t startIndex = 0;
|
||||
while (startIndex < data->structure.length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(&data->structure, startIndex, ':');
|
||||
data->structure.chars[colonIndex] = '\0';
|
||||
|
||||
parseStructureCommand(data->structure.chars + startIndex, genJsonConfig, jsonDoc);
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
#include "common/ffdata.h"
|
||||
|
||||
// Things only needed by fastfetch
|
||||
typedef struct FFdata
|
||||
{
|
||||
FFstrbuf structure;
|
||||
bool configLoaded;
|
||||
} FFdata;
|
||||
|
||||
bool ffParseModuleOptions(const char* key, const char* value);
|
||||
void ffPrepareCommandOption(FFdata* data);
|
||||
void ffPrintCommandOption(FFdata* data, yyjson_mut_doc* jsonDoc);
|
||||
void ffMigrateCommandOptionToJsonc(FFdata* data, yyjson_mut_doc* jsonDoc);
|
||||
void ffPrintCommandOption(FFdata* data);
|
||||
void ffMigrateCommandOptionToJsonc(FFdata* data);
|
||||
bool ffParseModuleOptions(const char* key, const char* value);
|
||||
|
||||
+8
-3
@@ -3,7 +3,7 @@
|
||||
#ifdef FF_HAVE_DBUS
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
#include "util/FFstrbuf.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/library.h"
|
||||
|
||||
typedef struct FFDBusLibrary
|
||||
@@ -19,6 +19,7 @@ typedef struct FFDBusLibrary
|
||||
FF_LIBRARY_SYMBOL(dbus_message_iter_next)
|
||||
FF_LIBRARY_SYMBOL(dbus_message_unref)
|
||||
FF_LIBRARY_SYMBOL(dbus_connection_send_with_reply_and_block)
|
||||
FF_LIBRARY_SYMBOL(dbus_connection_unref)
|
||||
} FFDBusLibrary;
|
||||
|
||||
typedef struct FFDBusData
|
||||
@@ -31,14 +32,18 @@ const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data); //Returns an
|
||||
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result);
|
||||
bool ffDBusGetBool(FFDBusData* dbus, DBusMessageIter* iter, bool* result);
|
||||
bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result);
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg);
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2);
|
||||
DBusMessage* ffDBusGetProperty(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property);
|
||||
bool ffDBusGetPropertyString(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, FFstrbuf* result);
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result);
|
||||
bool ffDBusGetPropertyUint(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* property, uint32_t* result);
|
||||
void ffDBusDestroyData(FFDBusData* data);
|
||||
|
||||
static inline DBusMessage* ffDBusGetAllProperties(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface)
|
||||
{
|
||||
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface);
|
||||
return ffDBusGetMethodReply(dbus, busName, objectPath, "org.freedesktop.DBus.Properties", "GetAll", interface, NULL);
|
||||
}
|
||||
|
||||
#define FF_DBUS_AUTO_DESTROY_DATA __attribute__((__cleanup__(ffDBusDestroyData)))
|
||||
|
||||
#endif // FF_HAVE_DBUS
|
||||
|
||||
@@ -28,4 +28,8 @@ static inline const char* ffFindFileName(const char* file)
|
||||
|
||||
#define FF_DEBUG(format, ...) FF_DEBUG_PRINT(__FILE__, __LINE__, format, ##__VA_ARGS__)
|
||||
|
||||
const char* ffDebugWin32Error(unsigned long errorCode);
|
||||
#if _WIN32
|
||||
const char* ffDebugWin32Error(DWORD errorCode);
|
||||
const char* ffDebugNtStatus(NTSTATUS status);
|
||||
const char* ffDebugHResult(HRESULT hr);
|
||||
#endif
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result);
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "util/FFstrbuf.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
void ffEdidGetVendorAndModel(const uint8_t edid[128], FFstrbuf* result);
|
||||
bool ffEdidGetName(const uint8_t edid[128], FFstrbuf* name);
|
||||
@@ -10,3 +10,4 @@ void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint3
|
||||
void ffEdidGetPhysicalSize(const uint8_t edid[128], uint32_t* width, uint32_t* height); // in mm
|
||||
void ffEdidGetSerialAndManufactureDate(const uint8_t edid[128], uint32_t* serial, uint16_t* year, uint16_t* week);
|
||||
bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length);
|
||||
bool ffEdidIsValid(const uint8_t edid[128], uint32_t length);
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFDataResultDocType
|
||||
{
|
||||
FF_RESULT_DOC_TYPE_DEFAULT = 0,
|
||||
FF_RESULT_DOC_TYPE_JSON,
|
||||
FF_RESULT_DOC_TYPE_CONFIG,
|
||||
FF_RESULT_DOC_TYPE_CONFIG_FULL,
|
||||
} FFDataResultDocType;
|
||||
|
||||
// FFdata aggregates configuration, generation parameters, and output state used by fastfetch.
|
||||
// It holds the parsed configuration document, a mutable JSON document for results, and related metadata.
|
||||
typedef struct FFdata
|
||||
{
|
||||
yyjson_doc* configDoc; // Parsed JSON configuration document
|
||||
yyjson_mut_doc* resultDoc; // Mutable JSON document for storing results
|
||||
FFstrbuf structure; // Custom output structure from command line
|
||||
FFstrbuf structureDisabled; // Disabled modules in the output structure from command line
|
||||
FFstrbuf genConfigPath; // Path to generate configuration file
|
||||
FFDataResultDocType docType; // Type of result document
|
||||
bool configLoaded;
|
||||
} FFdata;
|
||||
@@ -1,221 +0,0 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/font.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
void ffFontInit(FFfont* font)
|
||||
{
|
||||
// Ensure no memory allocates
|
||||
ffStrbufInit(&font->pretty);
|
||||
ffStrbufInit(&font->name);
|
||||
ffStrbufInit(&font->size);
|
||||
ffListInit(&font->styles, sizeof(FFstrbuf));
|
||||
}
|
||||
|
||||
static void strbufAppendNSExcludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude)
|
||||
{
|
||||
if(value == NULL || length == 0)
|
||||
return;
|
||||
|
||||
ffStrbufEnsureFree(strbuf, length);
|
||||
|
||||
for(uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
if(value[i] != exclude)
|
||||
strbuf->chars[strbuf->length++] = value[i];
|
||||
}
|
||||
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
static void fontInitPretty(FFfont* font)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, &font->name);
|
||||
|
||||
if(font->size.length == 0 && font->styles.length == 0)
|
||||
return;
|
||||
else if(font->pretty.length == 0)
|
||||
ffStrbufAppendS(&font->pretty, "default");
|
||||
|
||||
ffStrbufAppendS(&font->pretty, " (");
|
||||
|
||||
if(font->size.length > 0)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, &font->size);
|
||||
ffStrbufAppendS(&font->pretty, "pt");
|
||||
|
||||
if(font->styles.length > 0)
|
||||
ffStrbufAppendS(&font->pretty, ", ");
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < font->styles.length; i++)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, FF_LIST_GET(FFstrbuf, font->styles, i));
|
||||
|
||||
if(i < font->styles.length - 1)
|
||||
ffStrbufAppendS(&font->pretty, ", ");
|
||||
}
|
||||
|
||||
ffStrbufAppendC(&font->pretty, ')');
|
||||
}
|
||||
|
||||
void ffFontInitQt(FFfont* font, const char* data)
|
||||
{
|
||||
ffFontInit(font);
|
||||
|
||||
//See https://doc.qt.io/qt-5/qfont.html#toString
|
||||
|
||||
//Family
|
||||
data = ffStrbufAppendSUntilC(&font->name, data, ',');
|
||||
ffStrbufTrim(&font->name, ' ');
|
||||
if (!data) goto exit;
|
||||
data++;
|
||||
|
||||
//Size
|
||||
data = ffStrbufAppendSUntilC(&font->size, data, ',');
|
||||
ffStrbufTrim(&font->size, ' ');
|
||||
if (!data) goto exit;
|
||||
data++;
|
||||
|
||||
//Style
|
||||
data = strrchr(data, ',');
|
||||
if (!data) goto exit;
|
||||
data++;
|
||||
if (isalpha(*data))
|
||||
{
|
||||
do
|
||||
{
|
||||
FFstrbuf* style = (FFstrbuf*) ffListAdd(&font->styles);
|
||||
ffStrbufInit(style);
|
||||
data = ffStrbufAppendSUntilC(style, data, ' ');
|
||||
if (data) data++;
|
||||
} while (data);
|
||||
}
|
||||
|
||||
exit:
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* alternativeBuffer)
|
||||
{
|
||||
while(**data == ' ' || **data == '\t' || **data == ',')
|
||||
++(*data);
|
||||
|
||||
const char* wordStart = *data;
|
||||
|
||||
while(**data != ' ' && **data != '\t' && **data != ',' && **data != '\0' && **data != '`' && **data != '\\')
|
||||
++(*data);
|
||||
|
||||
uint32_t wordLength = (uint32_t) (*data - wordStart);
|
||||
if(wordLength == 0)
|
||||
return;
|
||||
|
||||
if(**data == '\0' || **data == '`' || **data == '\\')
|
||||
{
|
||||
ffStrbufAppendNS(&font->size, wordLength, wordStart);
|
||||
if(ffStrbufEndsWithS(&font->size, "px"))
|
||||
ffStrbufSubstrBefore(&font->size, font->size.length - 2);
|
||||
|
||||
double dummy;
|
||||
if(sscanf(font->size.chars, "%lf", &dummy) == 1)
|
||||
return;
|
||||
|
||||
ffStrbufClear(&font->size);
|
||||
}
|
||||
|
||||
if(
|
||||
strncasecmp(wordStart, "Ultra", 5) == 0 ||
|
||||
strncasecmp(wordStart, "Extra", 5) == 0 ||
|
||||
strncasecmp(wordStart, "Semi", 4) == 0 ||
|
||||
strncasecmp(wordStart, "Demi", 4) == 0 ||
|
||||
strncasecmp(wordStart, "Normal", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Roman", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Oblique", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Italic", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Thin", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Light", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Bold", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Black", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Condensed", wordLength) == 0 ||
|
||||
strncasecmp(wordStart, "Expanded", wordLength) == 0
|
||||
) {
|
||||
if(alternativeBuffer == NULL)
|
||||
{
|
||||
alternativeBuffer = (FFstrbuf*) ffListAdd(&font->styles);
|
||||
ffStrbufInit(alternativeBuffer);
|
||||
}
|
||||
|
||||
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
|
||||
if(
|
||||
strncasecmp(wordStart, "Ultra ", 6) == 0 ||
|
||||
strncasecmp(wordStart, "Extra ", 6) == 0 ||
|
||||
strncasecmp(wordStart, "Semi ", 5) == 0 ||
|
||||
strncasecmp(wordStart, "Demi ", 5) == 0
|
||||
) {
|
||||
fontPangoParseWord(data, font, alternativeBuffer);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(alternativeBuffer != NULL)
|
||||
{
|
||||
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
return;
|
||||
}
|
||||
|
||||
if(font->name.length > 0)
|
||||
ffStrbufAppendC(&font->name, ' ');
|
||||
ffStrbufAppendNS(&font->name, wordLength, wordStart);
|
||||
}
|
||||
|
||||
void ffFontInitPango(FFfont* font, const char* data)
|
||||
{
|
||||
ffFontInit(font);
|
||||
|
||||
while(*data != '\0' && *data != '`' && *data != '\\')
|
||||
fontPangoParseWord(&data, font, NULL);
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitValues(FFfont* font, const char* name, const char* size)
|
||||
{
|
||||
ffFontInit(font);
|
||||
|
||||
ffStrbufAppendS(&font->name, name);
|
||||
ffStrbufTrim(&font->name, '"');
|
||||
ffStrbufAppendS(&font->size, size);
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitWithSpace(FFfont* font, const char* rawName)
|
||||
{
|
||||
const char* pspace = strrchr(rawName, ' ');
|
||||
if(pspace == NULL)
|
||||
{
|
||||
ffFontInitCopy(font, rawName);
|
||||
return;
|
||||
}
|
||||
|
||||
ffFontInit(font);
|
||||
|
||||
ffStrbufAppendNS(&font->name, (uint32_t)(pspace - rawName), rawName);
|
||||
ffStrbufAppendS(&font->size, pspace + 1);
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontDestroy(FFfont* font)
|
||||
{
|
||||
ffStrbufDestroy(&font->pretty);
|
||||
ffStrbufDestroy(&font->name);
|
||||
ffStrbufDestroy(&font->size);
|
||||
|
||||
FF_LIST_FOR_EACH(FFstrbuf, str, font->styles)
|
||||
ffStrbufDestroy(str);
|
||||
ffListDestroy(&font->styles);
|
||||
}
|
||||
+5
-2
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/FFstrbuf.h"
|
||||
#include "util/FFlist.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/FFlist.h"
|
||||
|
||||
typedef struct FFfont
|
||||
{
|
||||
@@ -15,6 +15,9 @@ void ffFontInit(FFfont* font);
|
||||
void ffFontInitQt(FFfont* font, const char* data);
|
||||
void ffFontInitPango(FFfont* font, const char* data);
|
||||
void ffFontInitValues(FFfont* font, const char* name, const char* size);
|
||||
void ffFontInitXlfd(FFfont* font, const char* xlfd);
|
||||
void ffFontInitXft(FFfont* font, const char* xft);
|
||||
void ffFontInitMoveValues(FFfont* font, FFstrbuf* name, FFstrbuf* size, FFstrbuf* style);
|
||||
void ffFontInitWithSpace(FFfont* font, const char* rawName);
|
||||
void ffFontDestroy(FFfont* font);
|
||||
|
||||
|
||||
+2
-33
@@ -1,41 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "util/FFstrbuf.h"
|
||||
|
||||
typedef enum __attribute__((__packed__)) FFformatArgType
|
||||
{
|
||||
FF_FORMAT_ARG_TYPE_NULL = 0,
|
||||
FF_FORMAT_ARG_TYPE_UINT,
|
||||
FF_FORMAT_ARG_TYPE_UINT64,
|
||||
FF_FORMAT_ARG_TYPE_UINT16,
|
||||
FF_FORMAT_ARG_TYPE_UINT8,
|
||||
FF_FORMAT_ARG_TYPE_INT,
|
||||
FF_FORMAT_ARG_TYPE_STRING,
|
||||
FF_FORMAT_ARG_TYPE_STRBUF,
|
||||
FF_FORMAT_ARG_TYPE_FLOAT,
|
||||
FF_FORMAT_ARG_TYPE_DOUBLE,
|
||||
FF_FORMAT_ARG_TYPE_LIST,
|
||||
FF_FORMAT_ARG_TYPE_BOOL
|
||||
} FFformatArgType;
|
||||
|
||||
#define FF_FORMAT_ARG(variable, var_name) { _Generic((variable), \
|
||||
uint32_t: FF_FORMAT_ARG_TYPE_UINT, \
|
||||
uint64_t: FF_FORMAT_ARG_TYPE_UINT64, \
|
||||
uint16_t: FF_FORMAT_ARG_TYPE_UINT16, \
|
||||
uint8_t: FF_FORMAT_ARG_TYPE_UINT8, \
|
||||
int32_t: FF_FORMAT_ARG_TYPE_INT, \
|
||||
char*: FF_FORMAT_ARG_TYPE_STRING, \
|
||||
const char*: FF_FORMAT_ARG_TYPE_STRING, \
|
||||
FFstrbuf: FF_FORMAT_ARG_TYPE_STRBUF, \
|
||||
float: FF_FORMAT_ARG_TYPE_FLOAT, \
|
||||
double: FF_FORMAT_ARG_TYPE_DOUBLE, \
|
||||
FFlist: FF_FORMAT_ARG_TYPE_LIST, \
|
||||
bool: FF_FORMAT_ARG_TYPE_BOOL \
|
||||
), _Generic((variable), char*: (variable), const char*: (variable), default: &(variable) ), (var_name) }
|
||||
#include "common/argType.h"
|
||||
|
||||
typedef struct FFformatarg
|
||||
{
|
||||
FFformatArgType type;
|
||||
FFArgType type;
|
||||
const void* value;
|
||||
const char* name; // argument name, must start with an alphabet
|
||||
} FFformatarg;
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include "fastfetch.h"
|
||||
|
||||
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result);
|
||||
@@ -1,3 +1,3 @@
|
||||
#include "util/FFstrbuf.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
|
||||
bool ffGetFileVersion(const char* filePath, FFstrbuf* version);
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "FFPlatform_private.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/io.h"
|
||||
#include "detection/version/version.h"
|
||||
|
||||
void ffPlatformInit(FFPlatform* platform)
|
||||
@@ -10,12 +10,17 @@ void ffPlatformInit(FFPlatform* platform)
|
||||
ffListInit(&platform->configDirs, sizeof(FFstrbuf));
|
||||
ffListInit(&platform->dataDirs, sizeof(FFstrbuf));
|
||||
ffStrbufInit(&platform->exePath);
|
||||
ffStrbufInit(&platform->cwd);
|
||||
|
||||
ffStrbufInit(&platform->userName);
|
||||
ffStrbufInit(&platform->fullUserName);
|
||||
ffStrbufInit(&platform->hostName);
|
||||
ffStrbufInit(&platform->userShell);
|
||||
|
||||
#ifdef _WIN32
|
||||
ffStrbufInit(&platform->sid);
|
||||
#endif
|
||||
|
||||
FFPlatformSysinfo* info = &platform->sysinfo;
|
||||
|
||||
ffStrbufInit(&info->name);
|
||||
@@ -45,18 +50,22 @@ void ffPlatformDestroy(FFPlatform* platform)
|
||||
ffStrbufDestroy(dir);
|
||||
ffListDestroy(&platform->dataDirs);
|
||||
ffStrbufDestroy(&platform->exePath);
|
||||
ffStrbufDestroy(&platform->cwd);
|
||||
|
||||
ffStrbufDestroy(&platform->userName);
|
||||
ffStrbufDestroy(&platform->hostName);
|
||||
ffStrbufDestroy(&platform->userShell);
|
||||
ffStrbufDestroy(&platform->fullUserName);
|
||||
|
||||
#ifdef _WIN32
|
||||
ffStrbufDestroy(&platform->sid);
|
||||
#endif
|
||||
|
||||
FFPlatformSysinfo* info = &platform->sysinfo;
|
||||
ffStrbufDestroy(&info->architecture);
|
||||
ffStrbufDestroy(&info->name);
|
||||
ffStrbufDestroy(&info->release);
|
||||
ffStrbufDestroy(&info->version);
|
||||
ffStrbufDestroy(&info->displayVersion);
|
||||
}
|
||||
|
||||
void ffPlatformPathAddAbsolute(FFlist* dirs, const char* path)
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "FFPlatform.h"
|
||||
#include "common/FFPlatform.h"
|
||||
|
||||
void ffPlatformInitImpl(FFPlatform* platform);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
#include "FFPlatform_private.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/arrayUtils.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/io.h"
|
||||
#include "fastfetch_config.h"
|
||||
#include "common/io/io.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
@@ -10,10 +12,14 @@
|
||||
#include <paths.h>
|
||||
|
||||
#ifdef __APPLE__
|
||||
#include <libproc.h>
|
||||
#include <mach-o/dyld.h>
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined(__OpenBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#include <kvm.h>
|
||||
#include "common/path.h"
|
||||
#elif defined(__HAIKU__)
|
||||
#include <image.h>
|
||||
#include <OS.h>
|
||||
@@ -21,21 +27,25 @@
|
||||
|
||||
static void getExePath(FFPlatform* platform)
|
||||
{
|
||||
char exePath[PATH_MAX + 1];
|
||||
#ifdef __linux__
|
||||
char exePath[PATH_MAX];
|
||||
#if defined(__linux__) || defined (__GNU__)
|
||||
ssize_t exePathLen = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1);
|
||||
if (exePathLen >= 0)
|
||||
exePath[exePathLen] = '\0';
|
||||
#elif defined(__APPLE__)
|
||||
int exePathLen = proc_pidpath((int) getpid(), exePath, sizeof(exePath));
|
||||
uint32_t exePathLen = sizeof(exePath);
|
||||
if (_NSGetExecutablePath(exePath, &exePathLen) == 0)
|
||||
exePathLen = (uint32_t) strlen(exePath);
|
||||
else
|
||||
exePathLen = 0;
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
size_t exePathLen = sizeof(exePath);
|
||||
if(sysctl(
|
||||
(int[]){CTL_KERN,
|
||||
#ifdef __FreeBSD__
|
||||
KERN_PROC, KERN_PROC_PATHNAME, (int) getpid()
|
||||
KERN_PROC, KERN_PROC_PATHNAME, (pid_t) platform->pid
|
||||
#else
|
||||
KERN_PROC_ARGS, (int) getpid(), KERN_PROC_PATHNAME
|
||||
KERN_PROC_ARGS, platform->pid, KERN_PROC_PATHNAME
|
||||
#endif
|
||||
}, 4,
|
||||
exePath, &exePathLen,
|
||||
@@ -45,7 +55,81 @@ static void getExePath(FFPlatform* platform)
|
||||
else
|
||||
exePathLen--; // remove terminating NUL
|
||||
#elif defined(__OpenBSD__)
|
||||
// OpenBSD doesn't have a reliable way to get the executable path.
|
||||
// Current implementation uses argv[0], which can be easily spoofed.
|
||||
// See #2195
|
||||
size_t exePathLen = 0;
|
||||
kvm_t* kd = kvm_openfiles(NULL, NULL, NULL, KVM_NO_FILES, NULL);
|
||||
if (kd)
|
||||
{
|
||||
int kpCount;
|
||||
struct kinfo_proc* kp = kvm_getprocs(kd, KERN_PROC_PID, (pid_t) platform->pid, sizeof(*kp), &kpCount);
|
||||
if (kp && kpCount == 1)
|
||||
{
|
||||
char** argv = kvm_getargv(kd, kp, 0);
|
||||
if (argv && argv[0])
|
||||
{
|
||||
char* arg0 = argv[0];
|
||||
if (arg0[0])
|
||||
{
|
||||
if (strchr(arg0, '/') != NULL) // likely a path (absolute or relative)
|
||||
{
|
||||
exePathLen = strlen(arg0);
|
||||
if (exePathLen < ARRAY_SIZE(exePath))
|
||||
{
|
||||
memcpy(exePath, arg0, exePathLen);
|
||||
exePath[exePathLen] = '\0';
|
||||
}
|
||||
else
|
||||
exePathLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY tmpPath = ffStrbufCreate();
|
||||
if (ffFindExecutableInPath(arg0, &tmpPath) == NULL && tmpPath.length < ARRAY_SIZE(exePath))
|
||||
{
|
||||
memcpy(exePath, tmpPath.chars, tmpPath.length + 1);
|
||||
exePathLen = tmpPath.length;
|
||||
}
|
||||
}
|
||||
|
||||
if (exePathLen > 0)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(exePath, &st) == 0 && S_ISREG(st.st_mode))
|
||||
{
|
||||
int cntp;
|
||||
struct kinfo_file* kf = kvm_getfiles(kd, KERN_FILE_BYPID, platform->pid, sizeof(*kf), &cntp);
|
||||
if (kf)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < cntp; i++)
|
||||
{
|
||||
if (kf[i].fd_fd == KERN_FILE_TEXT)
|
||||
{
|
||||
// KERN_FILE_TEXT is the executable file, not a shared library, and should be unique in the list.
|
||||
if (st.st_dev != (dev_t)kf[i].va_fsid || st.st_ino != (ino_t)kf[i].va_fileid)
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i < 0)
|
||||
exePathLen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If we can't get the list of open files, we can't verify that the file is actually the executable
|
||||
// Assume it is
|
||||
}
|
||||
}
|
||||
else
|
||||
exePathLen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
kvm_close(kd);
|
||||
}
|
||||
#elif defined(__sun)
|
||||
ssize_t exePathLen = readlink("/proc/self/path/a.out", exePath, sizeof(exePath) - 1);
|
||||
if (exePathLen >= 0)
|
||||
@@ -57,7 +141,7 @@ static void getExePath(FFPlatform* platform)
|
||||
|
||||
while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
|
||||
if (info.type == B_APP_IMAGE) {
|
||||
exePathLen = strlcpy(exePath, info.name, PATH_MAX);
|
||||
exePathLen = strlcpy(exePath, info.name, sizeof(exePath));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -176,13 +260,16 @@ static void getDataDirs(FFPlatform* platform)
|
||||
|
||||
static void getUserName(FFPlatform* platform, const struct passwd* pwd)
|
||||
{
|
||||
const char* user = getenv("USER");
|
||||
if(!ffStrSet(user) && pwd)
|
||||
user = pwd->pw_name;
|
||||
|
||||
ffStrbufAppendS(&platform->userName, user);
|
||||
|
||||
if (pwd) ffStrbufAppendS(&platform->fullUserName, pwd->pw_gecos);
|
||||
if (pwd)
|
||||
{
|
||||
ffStrbufSetS(&platform->userName, pwd->pw_name);
|
||||
ffStrbufSetS(&platform->fullUserName, pwd->pw_gecos);
|
||||
ffStrbufTrimSpace(&platform->fullUserName);
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufSetS(&platform->userName, getenv("USER"));
|
||||
}
|
||||
}
|
||||
|
||||
static void getHostName(FFPlatform* platform, const struct utsname* uts)
|
||||
@@ -211,7 +298,6 @@ static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts)
|
||||
else
|
||||
#endif
|
||||
ffStrbufAppendS(&info->architecture, uts->machine);
|
||||
ffStrbufInit(&info->displayVersion);
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
size_t length = sizeof(info->pageSize);
|
||||
@@ -221,15 +307,28 @@ static void getSysinfo(FFPlatformSysinfo* info, const struct utsname* uts)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void getCwd(FFPlatform* platform)
|
||||
{
|
||||
char cwd[PATH_MAX];
|
||||
if (getcwd(cwd, sizeof(cwd)) != NULL)
|
||||
{
|
||||
ffStrbufSetS(&platform->cwd, cwd);
|
||||
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
|
||||
}
|
||||
}
|
||||
|
||||
void ffPlatformInitImpl(FFPlatform* platform)
|
||||
{
|
||||
struct passwd* pwd = getpwuid(getuid());
|
||||
platform->pid = (uint32_t) getpid();
|
||||
platform->uid = getuid();
|
||||
struct passwd* pwd = getpwuid(platform->uid);
|
||||
|
||||
struct utsname uts;
|
||||
if(uname(&uts) < 0)
|
||||
memset(&uts, 0, sizeof(uts));
|
||||
|
||||
getExePath(platform);
|
||||
getCwd(platform);
|
||||
getHomeDir(platform, pwd);
|
||||
getCacheDir(platform);
|
||||
getConfigDirs(platform);
|
||||
@@ -1,13 +1,15 @@
|
||||
#include "FFPlatform_private.h"
|
||||
#include "common/io/io.h"
|
||||
#include "common/io.h"
|
||||
#include "common/library.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/windows/unicode.h"
|
||||
#include "util/windows/registry.h"
|
||||
#include "util/windows/nt.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/windows/unicode.h"
|
||||
#include "common/windows/registry.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
#include <Windows.h>
|
||||
#include <stdalign.h>
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <sddl.h>
|
||||
|
||||
#define SECURITY_WIN32 1 // For secext.h
|
||||
#include <secext.h>
|
||||
@@ -15,20 +17,32 @@
|
||||
static void getExePath(FFPlatform* platform)
|
||||
{
|
||||
wchar_t exePathW[MAX_PATH];
|
||||
DWORD exePathWLen = GetModuleFileNameW(NULL, exePathW, MAX_PATH);
|
||||
if (exePathWLen == 0 && exePathWLen >= MAX_PATH) return;
|
||||
|
||||
FF_AUTO_CLOSE_FD HANDLE hPath = CreateFileW(exePathW, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
FF_AUTO_CLOSE_FD HANDLE hPath = CreateFileW(
|
||||
ffGetPeb()->ProcessParameters->ImagePathName.Buffer,
|
||||
GENERIC_READ,
|
||||
FILE_SHARE_READ,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL);
|
||||
if (hPath != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_OPENED);
|
||||
DWORD len = GetFinalPathNameByHandleW(hPath, exePathW, MAX_PATH, FILE_NAME_NORMALIZED);
|
||||
if (len > 0 && len < MAX_PATH)
|
||||
exePathWLen = len;
|
||||
{
|
||||
ffStrbufSetNWS(&platform->exePath, len, exePathW);
|
||||
if (ffStrbufStartsWithS(&platform->exePath, "\\\\?\\"))
|
||||
ffStrbufSubstrAfter(&platform->exePath, 3);
|
||||
}
|
||||
}
|
||||
|
||||
if (platform->exePath.length == 0)
|
||||
{
|
||||
PCUNICODE_STRING imagePathName = &ffGetPeb()->ProcessParameters->ImagePathName;
|
||||
ffStrbufSetNWS(&platform->exePath, imagePathName->Length / sizeof(wchar_t), imagePathName->Buffer);
|
||||
}
|
||||
|
||||
ffStrbufSetNWS(&platform->exePath, exePathWLen, exePathW);
|
||||
if (ffStrbufStartsWithS(&platform->exePath, "\\\\?\\"))
|
||||
ffStrbufSubstrAfter(&platform->exePath, 3);
|
||||
ffStrbufReplaceAllC(&platform->exePath, '\\', '/');
|
||||
}
|
||||
|
||||
@@ -70,15 +84,15 @@ static void getCacheDir(FFPlatform* platform)
|
||||
static void platformPathAddKnownFolder(FFlist* dirs, REFKNOWNFOLDERID folderId)
|
||||
{
|
||||
PWSTR pPath = NULL;
|
||||
if(SUCCEEDED(SHGetKnownFolderPath(folderId, 0, NULL, &pPath)))
|
||||
if (SUCCEEDED(SHGetKnownFolderPath(folderId, KF_FLAG_DEFAULT, NULL, &pPath)))
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreateWS(pPath);
|
||||
CoTaskMemFree(pPath);
|
||||
ffStrbufReplaceAllC(&buffer, '\\', '/');
|
||||
ffStrbufEnsureEndsWithC(&buffer, '/');
|
||||
if (!ffListContains(dirs, &buffer, (void*) ffStrbufEqual))
|
||||
ffStrbufInitMove((FFstrbuf*) ffListAdd(dirs), &buffer);
|
||||
}
|
||||
CoTaskMemFree(pPath);
|
||||
}
|
||||
|
||||
static void platformPathAddEnvSuffix(FFlist* dirs, const char* env, const char* suffix)
|
||||
@@ -136,102 +150,106 @@ static void getDataDirs(FFPlatform* platform)
|
||||
|
||||
static void getUserName(FFPlatform* platform)
|
||||
{
|
||||
const char* userName = getenv("USERNAME");
|
||||
if (ffStrSet(userName))
|
||||
ffStrbufSetS(&platform->userName, userName);
|
||||
else
|
||||
{
|
||||
wchar_t buffer[256];
|
||||
DWORD len = ARRAY_SIZE(buffer);
|
||||
if(GetUserNameW(buffer, &len))
|
||||
ffStrbufSetWS(&platform->userName, buffer);
|
||||
}
|
||||
|
||||
wchar_t buffer[256];
|
||||
DWORD len = ARRAY_SIZE(buffer);
|
||||
if (GetUserNameExW(NameDisplay, buffer, &len))
|
||||
DWORD size = ARRAY_SIZE(buffer);
|
||||
if (GetUserNameExW(NameDisplay, buffer, &size))
|
||||
ffStrbufSetWS(&platform->fullUserName, buffer);
|
||||
|
||||
size = ARRAY_SIZE(buffer);
|
||||
if (GetUserNameW(buffer, &size)) // GetUserNameExW(10002)?
|
||||
ffStrbufSetWS(&platform->userName, buffer);
|
||||
else
|
||||
ffStrbufSetS(&platform->userName, getenv("USERNAME"));
|
||||
|
||||
alignas(TOKEN_USER) char buf[SECURITY_MAX_SID_SIZE + sizeof(TOKEN_USER)];
|
||||
if (NT_SUCCESS(NtQueryInformationToken(NtCurrentProcessToken(), TokenUser, buf, sizeof(buf), &size)))
|
||||
{
|
||||
TOKEN_USER* tokenUser = (TOKEN_USER*) buf;
|
||||
UNICODE_STRING sidString = { .Buffer = buffer, .Length = 0, .MaximumLength = sizeof(buffer) };
|
||||
if (NT_SUCCESS(RtlConvertSidToUnicodeString(&sidString, tokenUser->User.Sid, FALSE)))
|
||||
ffStrbufSetNWS(&platform->sid, sidString.Length / sizeof(wchar_t), sidString.Buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void getHostName(FFPlatform* platform)
|
||||
{
|
||||
wchar_t buffer[128];
|
||||
wchar_t buffer[256];
|
||||
DWORD len = ARRAY_SIZE(buffer);
|
||||
if(GetComputerNameExW(ComputerNameDnsHostname, buffer, &len))
|
||||
ffStrbufSetWS(&platform->hostName, buffer);
|
||||
if (GetComputerNameExW(ComputerNameDnsHostname, buffer, &len) && len > 0)
|
||||
ffStrbufSetNWS(&platform->hostName, len, buffer);
|
||||
else
|
||||
{
|
||||
len = ARRAY_SIZE(buffer);
|
||||
if (GetComputerNameExW(ComputerNameNetBIOS, buffer, &len) && len > 0)
|
||||
ffStrbufSetNWS(&platform->hostName, len, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void getUserShell(FFPlatform* platform)
|
||||
{
|
||||
// Works in MSYS2
|
||||
ffStrbufAppendS(&platform->userShell, getenv("SHELL"));
|
||||
ffStrbufReplaceAllC(&platform->userShell, '\\', '/');
|
||||
const char* userShell = getenv("SHELL");
|
||||
if (userShell)
|
||||
{
|
||||
ffStrbufAppendS(&platform->userShell, userShell);
|
||||
ffStrbufReplaceAllC(&platform->userShell, '\\', '/');
|
||||
}
|
||||
}
|
||||
|
||||
static void detectWine(FFstrbuf* buf)
|
||||
static const char* detectWine(void)
|
||||
{
|
||||
static const char *(__cdecl *pwine_get_version)(void);
|
||||
HMODULE hntdll = GetModuleHandleW(L"ntdll.dll");
|
||||
if (!hntdll) return;
|
||||
pwine_get_version = (void *)GetProcAddress(hntdll, "wine_get_version");
|
||||
if (!pwine_get_version) return;
|
||||
ffStrbufAppendS(buf, buf->length ? " - wine " : "wine ");
|
||||
ffStrbufAppendS(buf, pwine_get_version());
|
||||
const char * __cdecl wine_get_version(void);
|
||||
void* hntdll = ffLibraryGetModule(L"ntdll.dll");
|
||||
if (!hntdll) return NULL;
|
||||
FF_LIBRARY_LOAD_SYMBOL_LAZY(hntdll, wine_get_version);
|
||||
if (!ffwine_get_version) return NULL;
|
||||
return ffwine_get_version();
|
||||
}
|
||||
|
||||
static void getSystemReleaseAndVersion(FFPlatformSysinfo* info)
|
||||
{
|
||||
RTL_OSVERSIONINFOW osVersion = { .dwOSVersionInfoSize = sizeof(osVersion) };
|
||||
if (!NT_SUCCESS(RtlGetVersion(&osVersion)))
|
||||
return;
|
||||
|
||||
FF_HKEY_AUTO_DESTROY hKey = NULL;
|
||||
FF_AUTO_CLOSE_FD HANDLE hKey = NULL;
|
||||
if(!ffRegOpenKeyForRead(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", &hKey, NULL))
|
||||
return;
|
||||
|
||||
uint32_t ubr = 0;
|
||||
ffRegReadUint(hKey, L"UBR", &ubr, NULL);
|
||||
ffRegReadValues(hKey, 2, (FFRegValueArg[]) {
|
||||
FF_ARG(ubr, L"UBR"),
|
||||
FF_ARG(info->version, L"BuildLabEx"),
|
||||
}, NULL);
|
||||
|
||||
ffStrbufAppendF(&info->release,
|
||||
PPEB_FULL peb = ffGetPeb();
|
||||
|
||||
ffStrbufSetF(&info->release,
|
||||
"%u.%u.%u.%u",
|
||||
(unsigned) osVersion.dwMajorVersion,
|
||||
(unsigned) osVersion.dwMinorVersion,
|
||||
(unsigned) osVersion.dwBuildNumber,
|
||||
(unsigned) peb->OSMajorVersion,
|
||||
(unsigned) peb->OSMinorVersion,
|
||||
(unsigned) peb->OSBuildNumber,
|
||||
(unsigned) ubr);
|
||||
|
||||
ffStrbufInit(&info->displayVersion);
|
||||
if(!ffRegReadStrbuf(hKey, L"DisplayVersion", &info->displayVersion, NULL))
|
||||
{
|
||||
if (osVersion.szCSDVersion[0])
|
||||
ffStrbufSetWS(&info->displayVersion, osVersion.szCSDVersion);
|
||||
else
|
||||
ffRegReadStrbuf(hKey, L"ReleaseId", &info->displayVersion, NULL); // For old Windows 10
|
||||
}
|
||||
detectWine(&info->displayVersion);
|
||||
|
||||
ffRegReadStrbuf(hKey, L"BuildLabEx", &info->version, NULL);
|
||||
|
||||
switch (osVersion.dwPlatformId)
|
||||
{
|
||||
case VER_PLATFORM_WIN32s:
|
||||
ffStrbufSetStatic(&info->name, "WIN32s");
|
||||
break;
|
||||
case VER_PLATFORM_WIN32_WINDOWS:
|
||||
ffStrbufSetStatic(&info->name, "WIN32_WINDOWS");
|
||||
break;
|
||||
case VER_PLATFORM_WIN32_NT:
|
||||
const char* wineVersion = detectWine();
|
||||
if (wineVersion)
|
||||
ffStrbufSetF(&info->name, "Wine_%s", wineVersion);
|
||||
else
|
||||
ffStrbufSetStatic(&info->name, "WIN32_NT");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
|
||||
static void getSystemPageSize(FFPlatformSysinfo* info)
|
||||
{
|
||||
SYSTEM_INFO sysInfo;
|
||||
GetNativeSystemInfo(&sysInfo);
|
||||
SYSTEM_BASIC_INFORMATION sbi;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemBasicInformation, &sbi, sizeof(sbi), NULL)))
|
||||
info->pageSize = sbi.PhysicalPageSize;
|
||||
else
|
||||
info->pageSize = 4096;
|
||||
}
|
||||
|
||||
switch(sysInfo.wProcessorArchitecture)
|
||||
static void getSystemArchitecture(FFPlatformSysinfo* info)
|
||||
{
|
||||
SYSTEM_PROCESSOR_INFORMATION spi;
|
||||
if (NT_SUCCESS(NtQuerySystemInformation(SystemProcessorInformation, &spi, sizeof(spi), NULL)))
|
||||
{
|
||||
switch (spi.ProcessorArchitecture)
|
||||
{
|
||||
case PROCESSOR_ARCHITECTURE_AMD64:
|
||||
ffStrbufSetStatic(&info->architecture, "x86_64");
|
||||
break;
|
||||
@@ -239,7 +257,7 @@ static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
|
||||
ffStrbufSetStatic(&info->architecture, "ia64");
|
||||
break;
|
||||
case PROCESSOR_ARCHITECTURE_INTEL:
|
||||
switch (sysInfo.wProcessorLevel)
|
||||
switch (spi.ProcessorLevel)
|
||||
{
|
||||
case 4:
|
||||
ffStrbufSetStatic(&info->architecture, "i486");
|
||||
@@ -277,14 +295,23 @@ static void getSystemArchitectureAndPageSize(FFPlatformSysinfo* info)
|
||||
default:
|
||||
ffStrbufSetStatic(&info->architecture, "unknown");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info->pageSize = sysInfo.dwPageSize;
|
||||
static void getCwd(FFPlatform* platform)
|
||||
{
|
||||
PCURDIR cwd = &ffGetPeb()->ProcessParameters->CurrentDirectory;
|
||||
ffStrbufSetNWS(&platform->cwd, cwd->DosPath.Length / sizeof(WCHAR), cwd->DosPath.Buffer);
|
||||
ffStrbufReplaceAllC(&platform->cwd, '\\', '/');
|
||||
ffStrbufEnsureEndsWithC(&platform->cwd, '/');
|
||||
}
|
||||
|
||||
void ffPlatformInitImpl(FFPlatform* platform)
|
||||
{
|
||||
platform->pid = (uint32_t) (uintptr_t) ffGetTeb()->ClientId.UniqueProcess;
|
||||
getExePath(platform);
|
||||
getCwd(platform);
|
||||
getHomeDir(platform);
|
||||
getCacheDir(platform);
|
||||
getConfigDirs(platform);
|
||||
@@ -295,5 +322,6 @@ void ffPlatformInitImpl(FFPlatform* platform)
|
||||
getUserShell(platform);
|
||||
|
||||
getSystemReleaseAndVersion(&platform->sysinfo);
|
||||
getSystemArchitectureAndPageSize(&platform->sysinfo);
|
||||
getSystemArchitecture(&platform->sysinfo);
|
||||
getSystemPageSize(&platform->sysinfo);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "FFlist.h"
|
||||
#include "common/FFlist.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -6,11 +6,7 @@
|
||||
void* ffListAdd(FFlist* list)
|
||||
{
|
||||
if(list->length == list->capacity)
|
||||
{
|
||||
list->capacity = list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2;
|
||||
// realloc(NULL, newSize) is same as malloc(newSize)
|
||||
list->data = realloc(list->data, (size_t)list->capacity * list->elementSize);
|
||||
}
|
||||
ffListReserve(list, list->capacity == 0 ? FF_LIST_DEFAULT_ALLOC : list->capacity * 2);
|
||||
|
||||
++list->length;
|
||||
return ffListGet(list, list->length - 1);
|
||||
@@ -1,7 +1,10 @@
|
||||
#include "FFstrbuf.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <math.h>
|
||||
|
||||
char* CHAR_NULL_PTR = "";
|
||||
|
||||
@@ -20,11 +23,27 @@ void ffStrbufInitVF(FFstrbuf* strbuf, const char* format, va_list arguments)
|
||||
{
|
||||
assert(format != NULL);
|
||||
|
||||
int len = vasprintf(&strbuf->chars, format, arguments);
|
||||
char* buffer = NULL;
|
||||
int len = vasprintf(&buffer, format, arguments);
|
||||
assert(len >= 0);
|
||||
|
||||
strbuf->allocated = (uint32_t)(len + 1);
|
||||
strbuf->length = (uint32_t)len;
|
||||
ffStrbufInitMoveNS(strbuf, (uint32_t)len, buffer);
|
||||
}
|
||||
|
||||
// Takes ownership of `heapStr`. The caller must not free `heapStr` after calling this
|
||||
// function; the memory will be managed and freed via the associated FFstrbuf.
|
||||
void ffStrbufInitMoveNS(FFstrbuf* strbuf, uint32_t length, char* heapStr)
|
||||
{
|
||||
assert(heapStr != NULL);
|
||||
|
||||
strbuf->length = length;
|
||||
size_t allocSize = ffMallocUsableSize(heapStr);
|
||||
if (allocSize == 0)
|
||||
allocSize = length + 1;
|
||||
else if (allocSize > UINT32_MAX)
|
||||
allocSize = UINT32_MAX;
|
||||
strbuf->allocated = (uint32_t) allocSize;
|
||||
strbuf->chars = heapStr;
|
||||
}
|
||||
|
||||
void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free)
|
||||
@@ -54,6 +73,7 @@ void ffStrbufEnsureFree(FFstrbuf* strbuf, uint32_t free)
|
||||
strbuf->allocated = allocate;
|
||||
}
|
||||
|
||||
// Ensure that at least `free` bytes are available in the buffer besides the current length
|
||||
// for an empty buffer, free + 1 length memory will be allocated(+1 for the NUL)
|
||||
void ffStrbufEnsureFixedLengthFree(FFstrbuf* strbuf, uint32_t free)
|
||||
{
|
||||
@@ -147,7 +167,7 @@ void ffStrbufAppendVF(FFstrbuf* strbuf, const char* format, va_list arguments)
|
||||
uint32_t free = ffStrbufGetFree(strbuf);
|
||||
int written = vsnprintf(strbuf->chars + strbuf->length, strbuf->allocated > 0 ? free + 1 : 0, format, arguments);
|
||||
|
||||
if(written > 0 && strbuf->length + (uint32_t) written > free)
|
||||
if(written > 0 && (uint32_t) written > free)
|
||||
{
|
||||
ffStrbufEnsureFree(strbuf, (uint32_t) written);
|
||||
written = vsnprintf(strbuf->chars + strbuf->length, (uint32_t) written + 1, format, copy);
|
||||
@@ -164,7 +184,7 @@ const char* ffStrbufAppendSUntilC(FFstrbuf* strbuf, const char* value, char unti
|
||||
if(value == NULL)
|
||||
return NULL;
|
||||
|
||||
char* end = strchr(value, until);
|
||||
const char* end = strchr(value, until);
|
||||
if(end == NULL)
|
||||
ffStrbufAppendS(strbuf, value);
|
||||
else
|
||||
@@ -221,8 +241,51 @@ void ffStrbufPrependC(FFstrbuf* strbuf, char c)
|
||||
|
||||
void ffStrbufSetNS(FFstrbuf* strbuf, uint32_t length, const char* value)
|
||||
{
|
||||
ffStrbufClear(strbuf);
|
||||
ffStrbufAppendNS(strbuf, length, value);
|
||||
assert(strbuf != NULL);
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
ffStrbufClear(strbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(value != NULL);
|
||||
|
||||
if (strbuf->allocated < length + 1)
|
||||
{
|
||||
if (strbuf->allocated > 0)
|
||||
free(strbuf->chars);
|
||||
strbuf->allocated = length + 1;
|
||||
strbuf->chars = malloc(sizeof(char) * strbuf->allocated);
|
||||
}
|
||||
|
||||
memcpy(strbuf->chars, value, length);
|
||||
strbuf->length = length;
|
||||
strbuf->chars[length] = '\0';
|
||||
}
|
||||
|
||||
void ffStrbufSet(FFstrbuf* strbuf, const FFstrbuf* value)
|
||||
{
|
||||
assert(value && value != strbuf);
|
||||
|
||||
if (value->length == 0)
|
||||
{
|
||||
ffStrbufClear(strbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
if (value->allocated == 0) // static string
|
||||
{
|
||||
if (strbuf->allocated != 0)
|
||||
{
|
||||
free(strbuf->chars);
|
||||
strbuf->allocated = 0;
|
||||
}
|
||||
strbuf->chars = value->chars;
|
||||
strbuf->length = value->length;
|
||||
return;
|
||||
}
|
||||
ffStrbufSetNS(strbuf, value->length, value->chars);
|
||||
}
|
||||
|
||||
void ffStrbufTrimLeft(FFstrbuf* strbuf, char c)
|
||||
@@ -272,6 +335,31 @@ void ffStrbufTrimRight(FFstrbuf* strbuf, char c)
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
void ffStrbufTrimLeftSpace(FFstrbuf* strbuf)
|
||||
{
|
||||
if(strbuf->length == 0)
|
||||
return;
|
||||
|
||||
uint32_t index = 0;
|
||||
while(index < strbuf->length && isspace(strbuf->chars[index]))
|
||||
++index;
|
||||
|
||||
if(index == 0)
|
||||
return;
|
||||
|
||||
if(strbuf->allocated == 0)
|
||||
{
|
||||
//static string
|
||||
strbuf->length -= index;
|
||||
strbuf->chars += index;
|
||||
return;
|
||||
}
|
||||
|
||||
memmove(strbuf->chars, strbuf->chars + index, strbuf->length - index);
|
||||
strbuf->length -= index;
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
void ffStrbufTrimRightSpace(FFstrbuf* strbuf)
|
||||
{
|
||||
if (strbuf->length == 0)
|
||||
@@ -361,7 +449,15 @@ void ffStrbufReplaceAllC(FFstrbuf* strbuf, char find, char replace)
|
||||
return;
|
||||
|
||||
ffStrbufEnsureFree(strbuf, 0);
|
||||
for (char *current_pos = strchr(strbuf->chars, find); current_pos; current_pos = strchr(current_pos + 1, find))
|
||||
for (
|
||||
char *current_pos = memchr(strbuf->chars, find, strbuf->length);
|
||||
current_pos;
|
||||
current_pos = memchr(
|
||||
current_pos + 1,
|
||||
find,
|
||||
strbuf->length - (uint32_t)(current_pos + 1 - strbuf->chars)
|
||||
)
|
||||
)
|
||||
*current_pos = replace;
|
||||
}
|
||||
|
||||
@@ -373,7 +469,8 @@ bool ffStrbufSubstrBefore(FFstrbuf* strbuf, uint32_t index)
|
||||
if(strbuf->allocated == 0)
|
||||
{
|
||||
//static string
|
||||
ffStrbufInitNS(strbuf, strbuf->length, strbuf->chars);
|
||||
if (index < strbuf->length)
|
||||
ffStrbufInitNS(strbuf, index, strbuf->chars);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -436,6 +533,26 @@ bool ffStrbufSubstrAfterLastC(FFstrbuf* strbuf, char c)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffStrbufSubstr(FFstrbuf* strbuf, uint32_t start, uint32_t end)
|
||||
{
|
||||
if (__builtin_expect(start >= end, false))
|
||||
{
|
||||
ffStrbufClear(strbuf);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (__builtin_expect(start == 0, false)) return ffStrbufSubstrBefore(strbuf, end);
|
||||
if (__builtin_expect(end >= strbuf->length, false)) return ffStrbufSubstrAfter(strbuf, start - 1);
|
||||
|
||||
uint32_t len = end - start;
|
||||
ffStrbufEnsureFixedLengthFree(strbuf, len); // In case of static string
|
||||
memmove(strbuf->chars, strbuf->chars + start, len);
|
||||
|
||||
strbuf->length = len;
|
||||
strbuf->chars[len] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t ffStrbufCountC(const FFstrbuf* strbuf, char c)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
@@ -481,11 +598,11 @@ void ffStrbufPutTo(const FFstrbuf* strbuf, FILE* file)
|
||||
fputc('\n', file);
|
||||
}
|
||||
|
||||
double ffStrbufToDouble(const FFstrbuf* strbuf)
|
||||
double ffStrbufToDouble(const FFstrbuf* strbuf, double defaultValue)
|
||||
{
|
||||
char* str_end;
|
||||
double result = strtod(strbuf->chars, &str_end);
|
||||
return str_end == strbuf->chars ? 0.0/0.0 : result;
|
||||
return str_end == strbuf->chars ? defaultValue : result;
|
||||
}
|
||||
|
||||
uint64_t ffStrbufToUInt(const FFstrbuf* strbuf, uint64_t defaultValue)
|
||||
@@ -502,6 +619,87 @@ int64_t ffStrbufToSInt(const FFstrbuf* strbuf, int64_t defaultValue)
|
||||
return str_end == strbuf->chars ? defaultValue : (int64_t)result;
|
||||
}
|
||||
|
||||
void ffStrbufAppendSInt(FFstrbuf* strbuf, int64_t value)
|
||||
{
|
||||
ffStrbufEnsureFree(strbuf, 21); // Required by yyjson_write_number
|
||||
char* start = strbuf->chars + strbuf->length;
|
||||
|
||||
yyjson_val val = {};
|
||||
unsafe_yyjson_set_sint(&val, value);
|
||||
char* end = yyjson_write_number(&val, start);
|
||||
|
||||
assert(end != NULL);
|
||||
|
||||
strbuf->length += (uint32_t)(end - start);
|
||||
}
|
||||
|
||||
void ffStrbufAppendUInt(FFstrbuf* strbuf, uint64_t value)
|
||||
{
|
||||
ffStrbufEnsureFree(strbuf, 21); // Required by yyjson_write_number
|
||||
char* start = strbuf->chars + strbuf->length;
|
||||
|
||||
yyjson_val val = {};
|
||||
unsafe_yyjson_set_uint(&val, value);
|
||||
char* end = yyjson_write_number(&val, start);
|
||||
|
||||
assert(end != NULL);
|
||||
|
||||
strbuf->length += (uint32_t)(end - start);
|
||||
}
|
||||
|
||||
void ffStrbufAppendDouble(FFstrbuf* strbuf, double value, int8_t precision, bool trailingZeros)
|
||||
{
|
||||
assert(precision <= 15); // yyjson_write_number supports up to 15 digits after the decimal point
|
||||
|
||||
ffStrbufEnsureFree(strbuf, 40); // Required by yyjson_write_number
|
||||
char* start = strbuf->chars + strbuf->length;
|
||||
|
||||
if (precision == 0)
|
||||
value = round(value);
|
||||
yyjson_val val = {};
|
||||
unsafe_yyjson_set_double(&val, value);
|
||||
if (precision > 0)
|
||||
unsafe_yyjson_set_fp_to_fixed(&val, precision);
|
||||
|
||||
// Write at most <precision> digits after the decimal point; doesn't append trailing zeros
|
||||
char* end = yyjson_write_number(&val, start);
|
||||
|
||||
assert(end > start);
|
||||
|
||||
strbuf->length += (uint32_t)(end - start);
|
||||
|
||||
if (__builtin_expect(value > 1e21 || value < -1e21, false))
|
||||
{
|
||||
// If the value is too large, yyjson_write_number will write it in scientific notation
|
||||
return;
|
||||
}
|
||||
|
||||
if (trailingZeros)
|
||||
{
|
||||
if (precision > 1)
|
||||
{
|
||||
for (char* p = end - 1; *p != '.' && p > start; --p)
|
||||
--precision;
|
||||
if (precision > 0)
|
||||
ffStrbufAppendNC(strbuf, (uint32_t) precision, '0');
|
||||
}
|
||||
else if (precision == 0 || (precision < 0 && end[-1] == '0'))
|
||||
{
|
||||
goto removeDecimalPoint;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (end[-1] == '0')
|
||||
{
|
||||
removeDecimalPoint:
|
||||
// yyjson always appends ".0" to make it a float point number. We need to remove it
|
||||
strbuf->length -= 2;
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ffStrbufUpperCase(FFstrbuf* strbuf)
|
||||
{
|
||||
for (uint32_t i = 0; i < strbuf->length; ++i)
|
||||
@@ -526,19 +724,7 @@ void ffStrbufInsertNC(FFstrbuf* strbuf, uint32_t index, uint32_t num, char c)
|
||||
strbuf->length += num;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Read a line from a FFstrbuf.
|
||||
*
|
||||
* @details Behaves like getline(3) but reads from a FFstrbuf.
|
||||
*
|
||||
* @param[in,out] lineptr The pointer to a pointer that will be set to the start of the line.
|
||||
* Can be NULL for the first call.
|
||||
* @param[in,out] n The pointer to the size of the buffer of lineptr.
|
||||
* @param[in] buffer The buffer to read from. The buffer must not be a string literal.
|
||||
*
|
||||
* @return true if a line has been read, false if the end of the buffer has been reached.
|
||||
*/
|
||||
bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
|
||||
bool ffStrbufGetdelim(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer)
|
||||
{
|
||||
assert(lineptr && n && buffer);
|
||||
assert(buffer->allocated > 0 || (buffer->allocated == 0 && buffer->length == 0));
|
||||
@@ -552,14 +738,14 @@ bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
|
||||
*lineptr += *n;
|
||||
if (*lineptr >= pBufferEnd) // non-empty last line
|
||||
return false;
|
||||
**lineptr = '\n';
|
||||
**lineptr = delimiter;
|
||||
++*lineptr;
|
||||
}
|
||||
if (*lineptr >= pBufferEnd) // empty last line
|
||||
return false;
|
||||
|
||||
size_t remaining = (size_t) (pBufferEnd - *lineptr);
|
||||
char* ending = memchr(*lineptr, '\n', remaining);
|
||||
char* ending = memchr(*lineptr, delimiter, remaining);
|
||||
if (ending)
|
||||
{
|
||||
*n = (size_t) (ending - *lineptr);
|
||||
@@ -570,9 +756,7 @@ bool ffStrbufGetline(char** lineptr, size_t* n, FFstrbuf* buffer)
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @brief Restore the end of a line that was modified by ffStrbufGetline.
|
||||
/// @warning This function should be called before breaking an ffStrbufGetline loop.
|
||||
void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer)
|
||||
void ffStrbufGetdelimRestore(char** lineptr, size_t* n, char delimiter, FFstrbuf* buffer)
|
||||
{
|
||||
assert(buffer && lineptr && n);
|
||||
assert(buffer->allocated > 0 || (buffer->allocated == 0 && buffer->length == 0));
|
||||
@@ -583,7 +767,7 @@ void ffStrbufGetlineRestore(char** lineptr, size_t* n, FFstrbuf* buffer)
|
||||
|
||||
*lineptr += *n;
|
||||
if (*lineptr < buffer->chars + buffer->length)
|
||||
**lineptr = '\n';
|
||||
**lineptr = delimiter;
|
||||
}
|
||||
|
||||
bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf)
|
||||
@@ -608,7 +792,7 @@ bool ffStrbufRemoveDupWhitespaces(FFstrbuf* strbuf)
|
||||
return changed;
|
||||
}
|
||||
|
||||
/// @brief Check if a separated string contains a substring.
|
||||
/// @brief Check if a separated string (comp) contains a substring (strbuf).
|
||||
/// @param strbuf The substring to check.
|
||||
/// @param compLength The length of the separated string to check.
|
||||
/// @param comp The separated string to check.
|
||||
@@ -636,3 +820,140 @@ bool ffStrbufMatchSeparatedNS(const FFstrbuf* strbuf, uint32_t compLength, const
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @brief Case insensitive version of ffStrbufMatchSeparatedNS.
|
||||
bool ffStrbufMatchSeparatedIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator)
|
||||
{
|
||||
if (strbuf->length == 0)
|
||||
return true;
|
||||
|
||||
if (compLength == 0)
|
||||
return false;
|
||||
|
||||
for (const char* p = comp; p < comp + compLength;)
|
||||
{
|
||||
const char* colon = memchr(p, separator, compLength);
|
||||
if (colon == NULL)
|
||||
return strcasecmp(strbuf->chars, p) == 0;
|
||||
|
||||
uint32_t substrLength = (uint32_t) (colon - p);
|
||||
if (strbuf->length == substrLength && strncasecmp(strbuf->chars, p, substrLength) == 0)
|
||||
return true;
|
||||
|
||||
p = colon + 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ffStrbufAppendUtf32CodePoint(FFstrbuf* strbuf, uint32_t codepoint)
|
||||
{
|
||||
if (codepoint <= 0x7F) {
|
||||
ffStrbufAppendC(strbuf, (char)codepoint);
|
||||
return 1;
|
||||
} else if (codepoint <= 0x7FF) {
|
||||
ffStrbufAppendNS(strbuf, 2, (char[]){
|
||||
(char) (0xC0 | (codepoint >> 6)),
|
||||
(char) (0x80 | (codepoint & 0x3F))
|
||||
});
|
||||
return 2;
|
||||
} else if (codepoint <= 0xFFFF) {
|
||||
ffStrbufAppendNS(strbuf, 3, (char[]){
|
||||
(char) (0xE0 | (codepoint >> 12)),
|
||||
(char) (0x80 | ((codepoint >> 6) & 0x3F)),
|
||||
(char) (0x80 | (codepoint & 0x3F))
|
||||
});
|
||||
return 3;
|
||||
} else if (codepoint <= 0x10FFFF) {
|
||||
ffStrbufAppendNS(strbuf, 4, (char[]){
|
||||
(char) (0xF0 | (codepoint >> 18)),
|
||||
(char) (0x80 | ((codepoint >> 12) & 0x3F)),
|
||||
(char) (0x80 | ((codepoint >> 6) & 0x3F)),
|
||||
(char) (0x80 | (codepoint & 0x3F))
|
||||
});
|
||||
return 4;
|
||||
}
|
||||
|
||||
ffStrbufAppendS(strbuf, "�"); // U+FFFD REPLACEMENT CHARACTER
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// @brief Check if a separated string (strbuf) contains a substring (comp).
|
||||
/// @param strbuf The separated to check.
|
||||
/// @param compLength The length of the separated string to check.
|
||||
/// @param comp The substring to check.
|
||||
/// @param separator The separator character.
|
||||
bool ffStrbufSeparatedContainNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator)
|
||||
{
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < strbuf->length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(strbuf, startIndex, separator);
|
||||
|
||||
uint32_t folderLength = colonIndex - startIndex;
|
||||
if (folderLength == compLength && memcmp(strbuf->chars + startIndex, comp, compLength) == 0)
|
||||
return true;
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffStrbufSeparatedContainIgnCaseNS(const FFstrbuf* strbuf, uint32_t compLength, const char* comp, char separator)
|
||||
{
|
||||
uint32_t startIndex = 0;
|
||||
while(startIndex < strbuf->length)
|
||||
{
|
||||
uint32_t colonIndex = ffStrbufNextIndexC(strbuf, startIndex, separator);
|
||||
|
||||
uint32_t folderLength = colonIndex - startIndex;
|
||||
if (folderLength == compLength && strncasecmp(strbuf->chars + startIndex, comp, compLength) == 0)
|
||||
return true;
|
||||
|
||||
startIndex = colonIndex + 1;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffStrbufDecodeHexEscapeSequences(FFstrbuf* strbuf)
|
||||
{
|
||||
assert(strbuf);
|
||||
|
||||
if (strbuf->length < 4)
|
||||
return false;
|
||||
|
||||
// Static string must be converted first.
|
||||
assert(strbuf->allocated > 0);
|
||||
|
||||
bool changed = false;
|
||||
uint32_t read = 0;
|
||||
uint32_t write = 0;
|
||||
|
||||
while (read < strbuf->length)
|
||||
{
|
||||
if (
|
||||
read + 3 < strbuf->length &&
|
||||
strbuf->chars[read] == '\\' &&
|
||||
strbuf->chars[read + 1] == 'x'
|
||||
)
|
||||
{
|
||||
int8_t hi = ffHexCharToInt(strbuf->chars[read + 2]);
|
||||
int8_t lo = ffHexCharToInt(strbuf->chars[read + 3]);
|
||||
if (hi >= 0 && lo >= 0)
|
||||
{
|
||||
strbuf->chars[write++] = (char) ((hi << 4) | lo);
|
||||
read += 4;
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
strbuf->chars[write++] = strbuf->chars[read++];
|
||||
}
|
||||
|
||||
strbuf->length = write;
|
||||
strbuf->chars[write] = '\0';
|
||||
return changed;
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "base64.h"
|
||||
#include "common/base64.h"
|
||||
|
||||
// https://github.com/kostya/benchmarks/blob/master/base64/test-nolib.c#L145
|
||||
void ffBase64EncodeRaw(uint32_t size, const char *str, uint32_t *out_size, char *output)
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "binary.h"
|
||||
#include "common/io/io.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "common/binary.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/mallocHelper.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -1,10 +1,10 @@
|
||||
#include "binary.h"
|
||||
#include "common/binary.h"
|
||||
|
||||
#if defined(FF_HAVE_ELF) || defined(__sun) || (defined(__FreeBSD__) && !defined(__DragonFly__)) || defined(__OpenBSD__) || defined(__NetBSD__)
|
||||
|
||||
#include "common/io/io.h"
|
||||
#include "common/io.h"
|
||||
#include "common/library.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <libelf.h> // #1254
|
||||
#include <fcntl.h>
|
||||
@@ -42,7 +42,7 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
|
||||
if (!elfData.inited)
|
||||
{
|
||||
elfData.inited = true;
|
||||
FF_LIBRARY_LOAD(libelf, "dlopen libelf" FF_LIBRARY_EXTENSION " failed", "libelf" FF_LIBRARY_EXTENSION, 1);
|
||||
FF_LIBRARY_LOAD_MESSAGE(libelf, "libelf" FF_LIBRARY_EXTENSION, 1);
|
||||
FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libelf, elfData, elf_version)
|
||||
if (elfData.ffelf_version(EV_CURRENT) == EV_NONE) return "elf_version() failed";
|
||||
|
||||
@@ -63,7 +63,7 @@ const char* ffBinaryExtractStrings(const char* elfFile, bool (*cb)(const char* s
|
||||
return "load libelf failed";
|
||||
|
||||
// Open the ELF file
|
||||
FF_AUTO_CLOSE_FD int fd = open(elfFile, O_RDONLY, 0);
|
||||
FF_AUTO_CLOSE_FD int fd = open(elfFile, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0) return "open() failed";
|
||||
|
||||
Elf* elf = elfData.ffelf_begin(fd, ELF_C_READ, NULL);
|
||||
@@ -1,10 +1,9 @@
|
||||
#include "binary.h"
|
||||
#include "common/io/io.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "util/mallocHelper.h"
|
||||
#include "common/binary.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/windows/nt.h"
|
||||
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
@@ -17,19 +16,34 @@
|
||||
*/
|
||||
const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *str, uint32_t len, void *userdata), void *userdata, uint32_t minLength)
|
||||
{
|
||||
// Use MapAndLoad with cleanup attribute to ensure proper unloading
|
||||
__attribute__((__cleanup__(UnMapAndLoad))) LOADED_IMAGE loadedImage = {};
|
||||
if (!MapAndLoad(peFile, NULL, &loadedImage, FALSE, TRUE))
|
||||
return "File could not be loaded";
|
||||
FF_AUTO_CLOSE_FD HANDLE hFile = CreateFileA(peFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
return "CreateFileA() failed";
|
||||
|
||||
// Iterate through all sections in the PE file
|
||||
for (ULONG i = 0; i < loadedImage.NumberOfSections; ++i)
|
||||
FF_AUTO_CLOSE_FD HANDLE hSection = NULL;
|
||||
if (!NT_SUCCESS(NtCreateSection(&hSection, SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_COMMIT, hFile)))
|
||||
return "NtCreateSection() failed";
|
||||
|
||||
PVOID base = NULL;
|
||||
SIZE_T viewSize = 0;
|
||||
if (!NT_SUCCESS(NtMapViewOfSection(hSection, NtCurrentProcess(), &base, 0, 0, NULL, &viewSize, ViewUnmap, 0, PAGE_READONLY)))
|
||||
return "NtMapViewOfSection() failed";
|
||||
|
||||
PIMAGE_NT_HEADERS ntHeaders = RtlImageNtHeader(base);
|
||||
if (!ntHeaders)
|
||||
{
|
||||
NtUnmapViewOfSection(NtCurrentProcess(), base);
|
||||
return "RtlImageNtHeader() failed";
|
||||
}
|
||||
|
||||
PIMAGE_SECTION_HEADER section = IMAGE_FIRST_SECTION(ntHeaders);
|
||||
for (WORD i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i, ++section)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER section = &loadedImage.Sections[i];
|
||||
// Look for initialized data sections with the name ".rdata" which typically contains string literals
|
||||
if ((section->Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) && ffStrEquals((const char*) section->Name, ".rdata"))
|
||||
{
|
||||
uint8_t *data = (uint8_t *) loadedImage.MappedAddress + section->PointerToRawData;
|
||||
uint8_t *data = (uint8_t *) base + section->PointerToRawData;
|
||||
|
||||
// Scan the section for string literals
|
||||
for (size_t off = 0; off < section->SizeOfRawData; ++off)
|
||||
@@ -48,5 +62,6 @@ const char* ffBinaryExtractStrings(const char *peFile, bool (*cb)(const char *st
|
||||
}
|
||||
}
|
||||
|
||||
NtUnmapViewOfSection(NtCurrentProcess(), base);
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,257 @@
|
||||
#include "common/commandoption.h"
|
||||
#include "common/color.h"
|
||||
#include "common/printing.h"
|
||||
#include "common/time.h"
|
||||
#include "common/jsonconfig.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "fastfetch_datatext.h"
|
||||
#include "modules/modules.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
bool ffParseModuleOptions(const char* key, const char* value)
|
||||
{
|
||||
if (!ffStrStartsWith(key, "--") || !ffCharIsEnglishAlphabet(key[2])) return false;
|
||||
if (value && !*value) value = NULL;
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(key[2]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
const char* subKey = ffOptionTestPrefix(key, baseInfo->name);
|
||||
if (subKey != NULL)
|
||||
{
|
||||
if (subKey[0] == '\0' || subKey[0] == '-') // Key is exactly the module name or has a leading '-'
|
||||
{
|
||||
fprintf(stderr, "Error: unknown module key %s\n", key);
|
||||
exit(477);
|
||||
}
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY moduleName = ffStrbufCreateS(baseInfo->name);
|
||||
ffStrbufLowerCase(&moduleName);
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY jsonKey = ffStrbufCreate();
|
||||
bool flag = false;
|
||||
for (const char* p = subKey; *p; ++p)
|
||||
{
|
||||
if (*p == '-')
|
||||
{
|
||||
if (flag)
|
||||
{
|
||||
fprintf(stderr, "Error: invalid double `-` in module key %s\n", key);
|
||||
exit(477);
|
||||
}
|
||||
flag = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!isalpha((unsigned char)*p) && !isdigit((unsigned char)*p))
|
||||
{
|
||||
fprintf(stderr, "Error: invalid character `%c` in module key %s\n", *p, key);
|
||||
exit(477);
|
||||
}
|
||||
|
||||
if (flag)
|
||||
{
|
||||
flag = false;
|
||||
ffStrbufAppendC(&jsonKey, (char) toupper((unsigned char) *p));
|
||||
}
|
||||
else
|
||||
ffStrbufAppendC(&jsonKey, *p);
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "Error: Unsupported module option: %s\n", key);
|
||||
fputs(" Support of module options has been removed. Please add the flag to the JSON config instead.\n", stderr);
|
||||
fprintf(stderr, " Example (demonstration only): `{ \"modules\": [ { \"type\": \"%s\", \"%s\": %s%s%s } ] }`\n", moduleName.chars, jsonKey.chars, value ? "\"" : "", value ?: "true", value ? "\"" : "");
|
||||
fputs(" See <https://github.com/fastfetch-cli/fastfetch/wiki/Configuration> for more information.\n", stderr);
|
||||
exit(477);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffPrepareCommandOption(FFdata* data)
|
||||
{
|
||||
char* moduleType = NULL;
|
||||
size_t moduleLen = 0;
|
||||
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure))
|
||||
{
|
||||
#define FF_IF_MODULE_MATCH(moduleNameConstant) if (moduleLen == strlen(moduleNameConstant) \
|
||||
&& ffStrEqualsIgnCase(moduleType, moduleNameConstant) \
|
||||
&& !ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleNameConstant, ':'))
|
||||
|
||||
switch (moduleType[0])
|
||||
{
|
||||
case 'C': case 'c':
|
||||
FF_IF_MODULE_MATCH(FF_CPUUSAGE_MODULE_NAME)
|
||||
ffPrepareCPUUsage();
|
||||
break;
|
||||
|
||||
case 'D': case 'd':
|
||||
FF_IF_MODULE_MATCH(FF_DISKIO_MODULE_NAME)
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
|
||||
ffInitDiskIOOptions(&options);
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'N': case 'n':
|
||||
FF_IF_MODULE_MATCH(FF_NETIO_MODULE_NAME)
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
|
||||
ffInitNetIOOptions(&options);
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'P': case 'p':
|
||||
FF_IF_MODULE_MATCH(FF_PUBLICIP_MODULE_NAME)
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
|
||||
ffInitPublicIpOptions(&options);
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'W': case 'w':
|
||||
FF_IF_MODULE_MATCH(FF_WEATHER_MODULE_NAME)
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
|
||||
ffInitWeatherOptions(&options);
|
||||
ffPrepareWeather(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#undef FF_IF_MODULE_MATCH
|
||||
}
|
||||
}
|
||||
|
||||
static void genJsonConfig(FFdata* data, FFModuleBaseInfo* baseInfo, void* options)
|
||||
{
|
||||
yyjson_mut_doc* doc = data->resultDoc;
|
||||
|
||||
yyjson_mut_val* modules = yyjson_mut_obj_get(doc->root, "modules");
|
||||
if (!modules)
|
||||
modules = yyjson_mut_obj_add_arr(doc, doc->root, "modules");
|
||||
|
||||
FF_STRBUF_AUTO_DESTROY type = ffStrbufCreateS(baseInfo->name);
|
||||
ffStrbufLowerCase(&type);
|
||||
|
||||
if (data->docType == FF_RESULT_DOC_TYPE_CONFIG_FULL)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_obj(doc);
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "type", &type);
|
||||
|
||||
if (baseInfo->generateJsonConfig)
|
||||
baseInfo->generateJsonConfig(options, doc, module);
|
||||
|
||||
if (yyjson_mut_obj_size(module) > 1)
|
||||
yyjson_mut_arr_add_val(modules, module);
|
||||
else
|
||||
yyjson_mut_arr_add_strbuf(doc, modules, &type);
|
||||
}
|
||||
else
|
||||
{
|
||||
yyjson_mut_arr_add_strbuf(doc, modules, &type);
|
||||
}
|
||||
}
|
||||
|
||||
static void genJsonResult(FFdata* data, FFModuleBaseInfo* baseInfo, void* options)
|
||||
{
|
||||
yyjson_mut_doc* doc = data->resultDoc;
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(doc, doc->root);
|
||||
yyjson_mut_obj_add_str(doc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJsonResult)
|
||||
baseInfo->generateJsonResult(options, doc, module);
|
||||
else
|
||||
yyjson_mut_obj_add_str(doc, module, "error", "Unsupported for JSON format");
|
||||
}
|
||||
|
||||
static void parseStructureCommand(
|
||||
FFdata* data,
|
||||
const char* line,
|
||||
void (*fn)(FFdata*, FFModuleBaseInfo* baseInfo, void* options)
|
||||
)
|
||||
{
|
||||
if(ffCharIsEnglishAlphabet(line[0]))
|
||||
{
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(line[0]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(line, baseInfo->name))
|
||||
{
|
||||
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
|
||||
baseInfo->initOptions(optionBuf);
|
||||
if (__builtin_expect(data->resultDoc != NULL, false))
|
||||
fn(data, baseInfo, optionBuf);
|
||||
else
|
||||
baseInfo->printModule(optionBuf);
|
||||
baseInfo->destroyOptions(optionBuf);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ffPrintError(line, 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "<no implementation provided>");
|
||||
}
|
||||
|
||||
void ffPrintCommandOption(FFdata* data)
|
||||
{
|
||||
//Parse the structure and call the modules
|
||||
int32_t thres = instance.config.display.stat;
|
||||
|
||||
char* moduleType = NULL;
|
||||
size_t moduleLen = 0;
|
||||
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure))
|
||||
{
|
||||
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':'))
|
||||
continue;
|
||||
|
||||
double ms = 0;
|
||||
if(thres >= 0)
|
||||
ms = ffTimeGetTick();
|
||||
|
||||
parseStructureCommand(data, moduleType, genJsonResult);
|
||||
|
||||
if(thres >= 0)
|
||||
{
|
||||
ms = ffTimeGetTick() - ms;
|
||||
|
||||
if (data->resultDoc)
|
||||
{
|
||||
yyjson_mut_val* moduleJson = yyjson_mut_arr_get_last(data->resultDoc->root);
|
||||
yyjson_mut_obj_add_real(data->resultDoc, moduleJson, "stat", ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
char str[64];
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (!data->resultDoc && !instance.config.display.noBuffer) fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void ffMigrateCommandOptionToJsonc(FFdata* data)
|
||||
{
|
||||
//If we don't have a custom structure, use the default one
|
||||
if(data->structure.length == 0)
|
||||
ffStrbufAppendS(&data->structure, FASTFETCH_DATATEXT_STRUCTURE); // Cannot use `ffStrbufSetStatic` here because we will modify the string
|
||||
|
||||
char* moduleType = NULL;
|
||||
size_t moduleLen = 0;
|
||||
while (ffStrbufGetdelim(&moduleType, &moduleLen, ':', &data->structure))
|
||||
{
|
||||
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, moduleType, ':'))
|
||||
continue;
|
||||
|
||||
parseStructureCommand(data, moduleType, genJsonConfig);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "dbus.h"
|
||||
#include "common/dbus.h"
|
||||
|
||||
#ifdef FF_HAVE_DBUS
|
||||
|
||||
#include "common/thread.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
static bool loadLibSymbols(FFDBusLibrary* lib)
|
||||
{
|
||||
@@ -19,6 +19,7 @@ static bool loadLibSymbols(FFDBusLibrary* lib)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_iter_next, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_message_unref, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_send_with_reply_and_block, false)
|
||||
FF_LIBRARY_LOAD_SYMBOL_PTR(dbus, lib, dbus_connection_unref, false)
|
||||
dbus = NULL; // don't auto dlclose
|
||||
return true;
|
||||
}
|
||||
@@ -51,6 +52,15 @@ const char* ffDBusLoadData(DBusBusType busType, FFDBusData* data)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffDBusDestroyData(FFDBusData* data)
|
||||
{
|
||||
if (data->connection != NULL)
|
||||
{
|
||||
data->lib->ffdbus_connection_unref(data->connection);
|
||||
data->connection = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool ffDBusGetString(FFDBusData* dbus, DBusMessageIter* iter, FFstrbuf* result)
|
||||
{
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
@@ -162,14 +172,67 @@ bool ffDBusGetUint(FFDBusData* dbus, DBusMessageIter* iter, uint32_t* result)
|
||||
return ffDBusGetUint(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg)
|
||||
bool ffDBusGetInt(FFDBusData* dbus, DBusMessageIter* iter, int32_t* result)
|
||||
{
|
||||
int argType = dbus->lib->ffdbus_message_iter_get_arg_type(iter);
|
||||
|
||||
if(argType == DBUS_TYPE_INT16)
|
||||
{
|
||||
int16_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_INT32)
|
||||
{
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_BYTE)
|
||||
{
|
||||
uint8_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_UINT16)
|
||||
{
|
||||
uint16_t value = 0;
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, &value);
|
||||
*result = (int16_t) value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType == DBUS_TYPE_UINT32)
|
||||
{
|
||||
dbus->lib->ffdbus_message_iter_get_basic(iter, result);
|
||||
return true;
|
||||
}
|
||||
|
||||
if(argType != DBUS_TYPE_VARIANT)
|
||||
return false;
|
||||
|
||||
DBusMessageIter subIter;
|
||||
dbus->lib->ffdbus_message_iter_recurse(iter, &subIter);
|
||||
return ffDBusGetInt(dbus, &subIter, result);
|
||||
}
|
||||
|
||||
DBusMessage* ffDBusGetMethodReply(FFDBusData* dbus, const char* busName, const char* objectPath, const char* interface, const char* method, const char* arg1, const char* arg2)
|
||||
{
|
||||
DBusMessage* message = dbus->lib->ffdbus_message_new_method_call(busName, objectPath, interface, method);
|
||||
if(message == NULL)
|
||||
return NULL;
|
||||
|
||||
if (arg)
|
||||
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
|
||||
if (arg1)
|
||||
{
|
||||
if (arg2)
|
||||
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_STRING, &arg2, DBUS_TYPE_INVALID);
|
||||
else
|
||||
dbus->lib->ffdbus_message_append_args(message, DBUS_TYPE_STRING, &arg1, DBUS_TYPE_INVALID);
|
||||
}
|
||||
|
||||
DBusMessage* reply = dbus->lib->ffdbus_connection_send_with_reply_and_block(dbus->connection, message, instance.config.general.processingTimeout, NULL);
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "common/debug.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
const char* ffDebugWin32Error(DWORD errorCode)
|
||||
{
|
||||
static char buffer[256];
|
||||
|
||||
DWORD len = FormatMessageA(
|
||||
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
(DWORD) errorCode,
|
||||
0,
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
NULL);
|
||||
|
||||
if (len == 0) {
|
||||
snprintf(buffer, sizeof(buffer), "Unknown error code (%lu)", errorCode);
|
||||
} else {
|
||||
// Remove trailing newline
|
||||
while (len > 0 && (buffer[len - 1] == '\r' || buffer[len - 1] == '\n')) {
|
||||
buffer[--len] = '\0';
|
||||
}
|
||||
snprintf(buffer + len, sizeof(buffer) - len + 2, " (%lu)", errorCode);
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
const char* ffDebugNtStatus(NTSTATUS status)
|
||||
{
|
||||
return ffDebugWin32Error(RtlNtStatusToDosError(status));
|
||||
}
|
||||
|
||||
static inline DWORD HRESULTToWin32Error(HRESULT hr)
|
||||
{
|
||||
if (SUCCEEDED(hr))
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
if (HRESULT_FACILITY(hr) == FACILITY_WIN32)
|
||||
return HRESULT_CODE(hr);
|
||||
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
const char* ffDebugHResult(HRESULT hr)
|
||||
{
|
||||
return ffDebugWin32Error(HRESULTToWin32Error(hr));
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
#include "common/duration.h"
|
||||
|
||||
void ffDurationAppendNum(uint64_t totalSeconds, FFstrbuf* result)
|
||||
{
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
|
||||
bool spaceBeforeUnit = options->durationSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER;
|
||||
|
||||
if (totalSeconds < 60)
|
||||
{
|
||||
ffStrbufAppendUInt(result, totalSeconds);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
ffStrbufAppendS(result, options->durationAbbreviation ? "sec" : "second");
|
||||
if (totalSeconds != 1)
|
||||
ffStrbufAppendC(result, 's');
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t seconds = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
if (seconds >= 30)
|
||||
totalSeconds++;
|
||||
|
||||
uint32_t minutes = (uint32_t) (totalSeconds % 60);
|
||||
totalSeconds /= 60;
|
||||
uint32_t hours = (uint32_t) (totalSeconds % 24);
|
||||
totalSeconds /= 24;
|
||||
uint32_t days = (uint32_t) totalSeconds;
|
||||
|
||||
if (days > 0)
|
||||
{
|
||||
ffStrbufAppendUInt(result, days);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (options->durationAbbreviation)
|
||||
{
|
||||
ffStrbufAppendC(result, 'd');
|
||||
|
||||
if (hours > 0 || minutes > 0)
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendS(result, days == 1 ? "day" : "days");
|
||||
|
||||
if (days >= 100)
|
||||
ffStrbufAppendS(result, "(!)");
|
||||
|
||||
if (hours > 0 || minutes > 0)
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
if (hours > 0)
|
||||
{
|
||||
ffStrbufAppendUInt(result, hours);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (options->durationAbbreviation)
|
||||
{
|
||||
ffStrbufAppendC(result, 'h');
|
||||
|
||||
if (minutes > 0)
|
||||
ffStrbufAppendC(result, ' ');
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendS(result, hours == 1 ? "hour" : "hours");
|
||||
|
||||
if (minutes > 0)
|
||||
ffStrbufAppendS(result, ", ");
|
||||
}
|
||||
}
|
||||
|
||||
if (minutes > 0)
|
||||
{
|
||||
ffStrbufAppendUInt(result, minutes);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
if (options->durationAbbreviation)
|
||||
ffStrbufAppendC(result, 'm');
|
||||
else
|
||||
ffStrbufAppendS(result, minutes == 1 ? "min" : "mins");
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "edidHelper.h"
|
||||
#include "common/edidHelper.h"
|
||||
|
||||
void ffEdidGetPhysicalResolution(const uint8_t edid[128], uint32_t* width, uint32_t* height)
|
||||
{
|
||||
@@ -128,3 +128,16 @@ bool ffEdidGetHdrCompatible(const uint8_t* edid, uint32_t length)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ffEdidIsValid(const uint8_t edid[128], uint32_t length)
|
||||
{
|
||||
if (length < 128 || length % 128 != 0) return false;
|
||||
|
||||
static const uint8_t edidHeader[] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
|
||||
if (memcmp(edid, edidHeader, sizeof(edidHeader)) != 0) return false;
|
||||
|
||||
uint8_t sum = 0;
|
||||
for (uint32_t i = 0; i < 128; i++) sum += edid[i];
|
||||
|
||||
return sum == 0;
|
||||
}
|
||||
@@ -0,0 +1,520 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/FFlist.h"
|
||||
#include "common/FFstrbuf.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/font.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
void ffFontInit(FFfont* font)
|
||||
{
|
||||
// Ensure no memory allocates
|
||||
ffStrbufInit(&font->pretty);
|
||||
ffStrbufInit(&font->name);
|
||||
ffStrbufInit(&font->size);
|
||||
ffListInit(&font->styles, sizeof(FFstrbuf));
|
||||
}
|
||||
|
||||
static void strbufAppendNSExcludingC(FFstrbuf* strbuf, uint32_t length, const char* value, char exclude)
|
||||
{
|
||||
if(value == NULL || length == 0)
|
||||
return;
|
||||
|
||||
ffStrbufEnsureFree(strbuf, length);
|
||||
|
||||
for(uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
if(value[i] != exclude)
|
||||
strbuf->chars[strbuf->length++] = value[i];
|
||||
}
|
||||
|
||||
strbuf->chars[strbuf->length] = '\0';
|
||||
}
|
||||
|
||||
static void fontInitPretty(FFfont* font)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, &font->name);
|
||||
|
||||
if(font->size.length == 0 && font->styles.length == 0)
|
||||
return;
|
||||
else if(font->pretty.length == 0)
|
||||
ffStrbufAppendS(&font->pretty, "default");
|
||||
|
||||
ffStrbufAppendS(&font->pretty, " (");
|
||||
|
||||
if(font->size.length > 0)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, &font->size);
|
||||
if (!ffStrbufEndsWithS(&font->size, "pt") && !ffStrbufEndsWithS(&font->size, "px"))
|
||||
ffStrbufAppendS(&font->pretty, "pt");
|
||||
|
||||
if(font->styles.length > 0)
|
||||
ffStrbufAppendS(&font->pretty, ", ");
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < font->styles.length; i++)
|
||||
{
|
||||
ffStrbufAppend(&font->pretty, FF_LIST_GET(FFstrbuf, font->styles, i));
|
||||
|
||||
if(i < font->styles.length - 1)
|
||||
ffStrbufAppendS(&font->pretty, ", ");
|
||||
}
|
||||
|
||||
ffStrbufAppendC(&font->pretty, ')');
|
||||
}
|
||||
|
||||
void ffFontInitQt(FFfont* font, const char* data)
|
||||
{
|
||||
ffFontInit(font);
|
||||
|
||||
//See https://doc.qt.io/qt-5/qfont.html#toString
|
||||
|
||||
//Family
|
||||
data = ffStrbufAppendSUntilC(&font->name, data, ',');
|
||||
ffStrbufTrim(&font->name, ' ');
|
||||
if (!data) goto exit;
|
||||
data++;
|
||||
|
||||
//Size
|
||||
data = ffStrbufAppendSUntilC(&font->size, data, ',');
|
||||
ffStrbufTrim(&font->size, ' ');
|
||||
if (!data) goto exit;
|
||||
data++;
|
||||
|
||||
//Style
|
||||
data = strrchr(data, ',');
|
||||
if (!data) goto exit;
|
||||
data++;
|
||||
if (isalpha(*data))
|
||||
{
|
||||
do
|
||||
{
|
||||
FFstrbuf* style = (FFstrbuf*) ffListAdd(&font->styles);
|
||||
ffStrbufInit(style);
|
||||
data = ffStrbufAppendSUntilC(style, data, ' ');
|
||||
if (data) data++;
|
||||
} while (data);
|
||||
}
|
||||
|
||||
exit:
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
static void fontPangoParseWord(const char** data, FFfont* font, FFstrbuf* alternativeBuffer)
|
||||
{
|
||||
while(**data == ' ' || **data == '\t' || **data == ',')
|
||||
++(*data);
|
||||
|
||||
const char* wordStart = *data;
|
||||
|
||||
while(**data != ' ' && **data != '\t' && **data != ',' && **data != '\0' && **data != '`' && **data != '\\')
|
||||
++(*data);
|
||||
|
||||
uint32_t wordLength = (uint32_t) (*data - wordStart);
|
||||
if(wordLength == 0)
|
||||
return;
|
||||
|
||||
if(**data == '\0' || **data == '`' || **data == '\\')
|
||||
{
|
||||
ffStrbufAppendNS(&font->size, wordLength, wordStart);
|
||||
if(ffStrbufEndsWithS(&font->size, "px"))
|
||||
ffStrbufSubstrBefore(&font->size, font->size.length - 2);
|
||||
|
||||
double dummy;
|
||||
if(sscanf(font->size.chars, "%lf", &dummy) == 1)
|
||||
return;
|
||||
|
||||
ffStrbufClear(&font->size);
|
||||
}
|
||||
|
||||
if(
|
||||
ffStrStartsWithIgnCase(wordStart, "Ultra") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Extra") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Semi") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Demi") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Normal") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Roman") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Oblique") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Italic") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Thin") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Light") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Bold") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Black") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Condensed") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Expanded")
|
||||
) {
|
||||
if(alternativeBuffer == NULL)
|
||||
{
|
||||
alternativeBuffer = (FFstrbuf*) ffListAdd(&font->styles);
|
||||
ffStrbufInit(alternativeBuffer);
|
||||
}
|
||||
|
||||
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
|
||||
if(
|
||||
ffStrStartsWithIgnCase(wordStart, "Ultra ") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Extra ") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Semi ") ||
|
||||
ffStrStartsWithIgnCase(wordStart, "Demi ")
|
||||
) {
|
||||
fontPangoParseWord(data, font, alternativeBuffer);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(alternativeBuffer != NULL)
|
||||
{
|
||||
strbufAppendNSExcludingC(alternativeBuffer, wordLength, wordStart, '-');
|
||||
return;
|
||||
}
|
||||
|
||||
if(font->name.length > 0)
|
||||
ffStrbufAppendC(&font->name, ' ');
|
||||
ffStrbufAppendNS(&font->name, wordLength, wordStart);
|
||||
}
|
||||
|
||||
void ffFontInitPango(FFfont* font, const char* data)
|
||||
{
|
||||
ffFontInit(font);
|
||||
|
||||
while(*data != '\0' && *data != '`' && *data != '\\')
|
||||
fontPangoParseWord(&data, font, NULL);
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitValues(FFfont* font, const char* name, const char* size)
|
||||
{
|
||||
ffFontInit(font);
|
||||
|
||||
ffStrbufAppendS(&font->name, name);
|
||||
ffStrbufTrim(&font->name, '"');
|
||||
ffStrbufAppendS(&font->size, size);
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitXlfd(FFfont* font, const char* xlfd)
|
||||
{
|
||||
assert(xlfd && *xlfd);
|
||||
|
||||
// https://en.wikipedia.org/wiki/X_logical_font_description
|
||||
ffFontInit(font);
|
||||
|
||||
// XLFD: -foundry-family-weight-slant-setwidth-addstyle-pixelsize-pointsize-xres-yres-spacing-averagewidth-charsetregistry-charsetencoding
|
||||
// It often starts with '-', which would create an empty first field. Skip it to align indexes.
|
||||
if(*xlfd == '-')
|
||||
xlfd++;
|
||||
|
||||
const char* pstart = xlfd;
|
||||
|
||||
for(int field = 0; field < 14; field++)
|
||||
{
|
||||
const char* pend = strchr(pstart, '-');
|
||||
uint32_t length = pend ? (uint32_t)(pend - pstart) : (uint32_t) strlen(pstart);
|
||||
|
||||
if(length > 0)
|
||||
{
|
||||
if(field == 1) // family
|
||||
{
|
||||
ffStrbufAppendNS(&font->name, length, pstart);
|
||||
}
|
||||
else if(field == 7) // pointsize (decipoints, preferred)
|
||||
{
|
||||
// parse positive integer from substring
|
||||
long deciPt = 0;
|
||||
bool ok = true;
|
||||
for(uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
char c = pstart[i];
|
||||
if(c < '0' || c > '9') { ok = false; break; }
|
||||
deciPt = deciPt * 10 + (c - '0');
|
||||
}
|
||||
|
||||
if(ok && deciPt > 0)
|
||||
{
|
||||
ffStrbufClear(&font->size);
|
||||
|
||||
char tmp[32];
|
||||
if(deciPt % 10 == 0)
|
||||
snprintf(tmp, sizeof(tmp), "%ldpt", deciPt / 10);
|
||||
else
|
||||
snprintf(tmp, sizeof(tmp), "%ld.%ldpt", deciPt / 10, deciPt % 10);
|
||||
|
||||
ffStrbufAppendS(&font->size, tmp);
|
||||
}
|
||||
}
|
||||
else if(field == 6) // pixelsize (fallback if pointsize missing/invalid)
|
||||
{
|
||||
if(font->size.length == 0)
|
||||
{
|
||||
long px = 0;
|
||||
bool ok = true;
|
||||
for(uint32_t i = 0; i < length; i++)
|
||||
{
|
||||
char c = pstart[i];
|
||||
if(c < '0' || c > '9') { ok = false; break; }
|
||||
px = px * 10 + (c - '0');
|
||||
}
|
||||
|
||||
if(ok && px > 0)
|
||||
{
|
||||
ffStrbufAppendNS(&font->size, length, pstart);
|
||||
ffStrbufAppendS(&font->size, "px");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(field >= 2 && field <= 5) // weight/slant/setwidth/addstyle
|
||||
{
|
||||
// ignore "normal" (case-insensitive)
|
||||
if(!(length == 6 && ffStrStartsWithIgnCase(pstart, "normal")))
|
||||
{
|
||||
FFstrbuf* style = (FFstrbuf*) ffListAdd(&font->styles);
|
||||
ffStrbufInitNS(style, length, pstart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!pend)
|
||||
break;
|
||||
|
||||
pstart = pend + 1;
|
||||
}
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitXft(FFfont* font, const char* xft)
|
||||
{
|
||||
assert(xft);
|
||||
|
||||
// https://en.wikipedia.org/wiki/Xft
|
||||
// Xft/Fontconfig pattern examples:
|
||||
// "DejaVu Sans Mono-10"
|
||||
// "monospace:size=10:weight=bold:slant=italic"
|
||||
// "Fira Code-12:style=Regular"
|
||||
// Goal: extract family(name), size, and some common styles.
|
||||
|
||||
ffFontInit(font);
|
||||
|
||||
// 1) Parse "head" part before first ':' => usually "family[-size]" (may include commas)
|
||||
const char* p = xft;
|
||||
|
||||
while(*p == ' ' || *p == '\t')
|
||||
++p;
|
||||
|
||||
const char* headStart = p;
|
||||
while(*p != '\0' && *p != ':')
|
||||
++p;
|
||||
const char* headEnd = p;
|
||||
|
||||
// trim tail spaces
|
||||
while(headEnd > headStart && (headEnd[-1] == ' ' || headEnd[-1] == '\t'))
|
||||
--headEnd;
|
||||
|
||||
// If multiple families are listed, take the first one (up to comma)
|
||||
for(const char* q = headStart; q < headEnd; ++q)
|
||||
{
|
||||
if(*q == ',')
|
||||
{
|
||||
headEnd = q;
|
||||
while(headEnd > headStart && (headEnd[-1] == ' ' || headEnd[-1] == '\t'))
|
||||
--headEnd;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Try parse trailing "-<number>" as size, otherwise entire head is name
|
||||
const char* dashPos = NULL;
|
||||
const char* sizeStart = NULL;
|
||||
|
||||
for(const char* q = headEnd; q > headStart; )
|
||||
{
|
||||
--q;
|
||||
if(*q == '-' && (q + 1) < headEnd && ffCharIsDigit(q[1]))
|
||||
{
|
||||
dashPos = q;
|
||||
sizeStart = q + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(dashPos)
|
||||
{
|
||||
bool ok = true;
|
||||
bool seenDigit = false;
|
||||
for(const char* q = sizeStart; q < headEnd; ++q)
|
||||
{
|
||||
if(ffCharIsDigit(*q))
|
||||
seenDigit = true;
|
||||
else if(*q == '.')
|
||||
continue;
|
||||
else
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ok && seenDigit)
|
||||
{
|
||||
const char* nameEnd = dashPos;
|
||||
while(nameEnd > headStart && (nameEnd[-1] == ' ' || nameEnd[-1] == '\t'))
|
||||
--nameEnd;
|
||||
|
||||
if(nameEnd > headStart)
|
||||
ffStrbufAppendNS(&font->name, (uint32_t) (nameEnd - headStart), headStart);
|
||||
|
||||
if(headEnd > sizeStart)
|
||||
ffStrbufAppendNS(&font->size, (uint32_t) (headEnd - sizeStart), sizeStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(headEnd > headStart)
|
||||
ffStrbufAppendNS(&font->name, (uint32_t) (headEnd - headStart), headStart);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(headEnd > headStart)
|
||||
ffStrbufAppendNS(&font->name, (uint32_t) (headEnd - headStart), headStart);
|
||||
}
|
||||
|
||||
ffStrbufTrim(&font->name, ' ');
|
||||
ffStrbufTrim(&font->name, '"');
|
||||
|
||||
// 2) Parse key=value fields after ':' (Fontconfig-like). Fields separated by ':'.
|
||||
// Common keys: size, pixelsize, pointsize, style, weight, slant, width
|
||||
while(*p == ':')
|
||||
{
|
||||
++p;
|
||||
|
||||
// key
|
||||
const char* keyStart = p;
|
||||
while(*p != '\0' && *p != '=' && *p != ':')
|
||||
++p;
|
||||
const char* keyEnd = p;
|
||||
|
||||
if(*p != '=')
|
||||
continue; // skip tokens without '='
|
||||
|
||||
++p; // skip '='
|
||||
|
||||
// value (until next ':', allow backslash-escaping)
|
||||
FF_STRBUF_AUTO_DESTROY value = ffStrbufCreate();
|
||||
|
||||
while(*p != '\0' && *p != ':')
|
||||
{
|
||||
if(*p == '\\' && p[1] != '\0')
|
||||
{
|
||||
++p;
|
||||
ffStrbufAppendC(&value, *p);
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
|
||||
ffStrbufAppendC(&value, *p);
|
||||
++p;
|
||||
}
|
||||
|
||||
ffStrbufTrim(&value, ' ');
|
||||
ffStrbufTrim(&value, '"');
|
||||
|
||||
uint32_t keyLen = (uint32_t) (keyEnd - keyStart);
|
||||
|
||||
// helper: set numeric size if not set yet
|
||||
const bool sizeEmpty = (font->size.length == 0);
|
||||
if(value.length > 0)
|
||||
{
|
||||
if(
|
||||
(keyLen == 4 && ffStrStartsWithIgnCase(keyStart, "size")) ||
|
||||
(keyLen == 9 && ffStrStartsWithIgnCase(keyStart, "pixelsize"))
|
||||
)
|
||||
{
|
||||
if(sizeEmpty && ffCharIsDigit(value.chars[0]))
|
||||
{
|
||||
ffStrbufAppend(&font->size, &value);
|
||||
ffStrbufAppendS(&font->size, keyLen == 4 ? "pt" : "px");
|
||||
}
|
||||
}
|
||||
else if(keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "style"))
|
||||
{
|
||||
// style may contain multiple words: "Bold Italic"
|
||||
const char* s = value.chars;
|
||||
while(*s != '\0')
|
||||
{
|
||||
while(*s == ' ' || *s == '\t' || *s == ',')
|
||||
++s;
|
||||
|
||||
const char* w = s;
|
||||
while(*s != '\0' && *s != ' ' && *s != '\t' && *s != ',')
|
||||
++s;
|
||||
|
||||
if(s > w)
|
||||
{
|
||||
FFstrbuf* style = FF_LIST_ADD(FFstrbuf, font->styles);
|
||||
ffStrbufInitNS(style, (uint32_t) (s - w), w);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(
|
||||
(keyLen == 6 && ffStrStartsWithIgnCase(keyStart, "weight")) ||
|
||||
(keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "slant")) ||
|
||||
(keyLen == 5 && ffStrStartsWithIgnCase(keyStart, "width"))
|
||||
) {
|
||||
// normalize: remove '-' to align with other parsers ("Semi-Bold" -> "SemiBold")
|
||||
FFstrbuf* style = FF_LIST_ADD(FFstrbuf, font->styles);
|
||||
ffStrbufInit(style);
|
||||
strbufAppendNSExcludingC(style, value.length, value.chars, '-');
|
||||
ffStrbufTrim(style, ' ');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitMoveValues(FFfont* font, FFstrbuf* name, FFstrbuf* size, FFstrbuf* style)
|
||||
{
|
||||
ffFontInit(font);
|
||||
|
||||
if (name) ffStrbufInitMove(&font->name, name);
|
||||
if (size) ffStrbufInitMove(&font->size, size);
|
||||
if (style)
|
||||
{
|
||||
FFstrbuf* styleBuf = FF_LIST_ADD(FFstrbuf, font->styles);
|
||||
ffStrbufInitMove(styleBuf, style);
|
||||
}
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontInitWithSpace(FFfont* font, const char* rawName)
|
||||
{
|
||||
const char* pspace = strrchr(rawName, ' ');
|
||||
if(pspace == NULL)
|
||||
{
|
||||
ffFontInitCopy(font, rawName);
|
||||
return;
|
||||
}
|
||||
|
||||
ffFontInit(font);
|
||||
|
||||
ffStrbufAppendNS(&font->name, (uint32_t)(pspace - rawName), rawName);
|
||||
ffStrbufAppendS(&font->size, pspace + 1);
|
||||
|
||||
fontInitPretty(font);
|
||||
}
|
||||
|
||||
void ffFontDestroy(FFfont* font)
|
||||
{
|
||||
ffStrbufDestroy(&font->pretty);
|
||||
ffStrbufDestroy(&font->name);
|
||||
ffStrbufDestroy(&font->size);
|
||||
|
||||
FF_LIST_FOR_EACH(FFstrbuf, str, font->styles)
|
||||
ffStrbufDestroy(str);
|
||||
ffListDestroy(&font->styles);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/format.h"
|
||||
#include "common/parsing.h"
|
||||
#include "util/textModifier.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "common/textModifier.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -10,37 +10,37 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
|
||||
{
|
||||
switch(formatarg->type)
|
||||
{
|
||||
case FF_FORMAT_ARG_TYPE_INT:
|
||||
ffStrbufAppendF(buffer, "%" PRIi32, *(int32_t*)formatarg->value);
|
||||
case FF_ARG_TYPE_INT:
|
||||
ffStrbufAppendSInt(buffer, *(int32_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT:
|
||||
ffStrbufAppendF(buffer, "%" PRIu32, *(uint32_t*)formatarg->value);
|
||||
case FF_ARG_TYPE_UINT:
|
||||
ffStrbufAppendUInt(buffer, *(uint32_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT64:
|
||||
ffStrbufAppendF(buffer, "%" PRIu64, *(uint64_t*)formatarg->value);
|
||||
case FF_ARG_TYPE_UINT64:
|
||||
ffStrbufAppendUInt(buffer, *(uint64_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT16:
|
||||
ffStrbufAppendF(buffer, "%" PRIu16, *(uint16_t*)formatarg->value);
|
||||
case FF_ARG_TYPE_UINT16:
|
||||
ffStrbufAppendUInt(buffer, *(uint16_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_UINT8:
|
||||
ffStrbufAppendF(buffer, "%" PRIu8, *(uint8_t*)formatarg->value);
|
||||
case FF_ARG_TYPE_UINT8:
|
||||
ffStrbufAppendUInt(buffer, *(uint8_t*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_STRING:
|
||||
case FF_ARG_TYPE_STRING:
|
||||
ffStrbufAppendS(buffer, (const char*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_STRBUF:
|
||||
ffStrbufAppend(buffer, (FFstrbuf*)formatarg->value);
|
||||
case FF_ARG_TYPE_STRBUF:
|
||||
ffStrbufAppend(buffer, (const FFstrbuf*)formatarg->value);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_FLOAT:
|
||||
ffStrbufAppendF(buffer, "%f", *(float*)formatarg->value);
|
||||
case FF_ARG_TYPE_FLOAT:
|
||||
ffStrbufAppendDouble(buffer, *(float*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_DOUBLE:
|
||||
ffStrbufAppendF(buffer, "%g", *(double*)formatarg->value);
|
||||
case FF_ARG_TYPE_DOUBLE:
|
||||
ffStrbufAppendDouble(buffer, *(double*)formatarg->value, instance.config.display.fractionNdigits, instance.config.display.fractionTrailingZeros != FF_FRACTION_TRAILING_ZEROS_TYPE_NEVER);
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_BOOL:
|
||||
case FF_ARG_TYPE_BOOL:
|
||||
ffStrbufAppendS(buffer, *(bool*)formatarg->value ? "true" : "false");
|
||||
break;
|
||||
case FF_FORMAT_ARG_TYPE_LIST:
|
||||
case FF_ARG_TYPE_LIST:
|
||||
{
|
||||
const FFlist* list = (const FFlist*) formatarg->value;
|
||||
for(uint32_t i = 0; i < list->length; i++)
|
||||
@@ -51,8 +51,15 @@ void ffFormatAppendFormatArg(FFstrbuf* buffer, const FFformatarg* formatarg)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FF_ARG_TYPE_BUFFER:
|
||||
{
|
||||
// Placeholder for binary data, just print the size for now
|
||||
const FFArgBuffer* argBuffer = (const FFArgBuffer*) formatarg->value;
|
||||
ffStrbufAppendF(buffer, "buffer(%u bytes)", argBuffer->length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
if(formatarg->type != FF_FORMAT_ARG_TYPE_NULL)
|
||||
if(formatarg->type != FF_ARG_TYPE_NULL)
|
||||
fprintf(stderr, "Error: format string \"%s\": argument is not implemented: %i\n", buffer->chars, formatarg->type);
|
||||
break;
|
||||
}
|
||||
@@ -87,7 +94,7 @@ static uint32_t getArgumentIndex(const char* placeholderValue, uint32_t numArgs,
|
||||
for (uint32_t i = 0; i < numArgs; ++i)
|
||||
{
|
||||
const FFformatarg* arg = &arguments[i];
|
||||
if (arg->name && strcasecmp(placeholderValue, arg->name) == 0)
|
||||
if (arg->name && ffStrEqualsIgnCase(placeholderValue, arg->name))
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
@@ -107,15 +114,16 @@ static inline void appendInvalidPlaceholder(FFstrbuf* buffer, const char* start,
|
||||
static inline bool formatArgSet(const FFformatarg* arg)
|
||||
{
|
||||
return arg->value != NULL && (
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) || //Also is false for NaN
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_INT && *(int*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_UINT8 && *(uint8_t*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_UINT16 && *(uint16_t*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_BOOL && *(bool*)arg->value) ||
|
||||
(arg->type == FF_FORMAT_ARG_TYPE_LIST && ((FFlist*)arg->value)->length > 0)
|
||||
(arg->type == FF_ARG_TYPE_DOUBLE && *(double*)arg->value > 0.0) ||
|
||||
(arg->type == FF_ARG_TYPE_FLOAT && *(float*)arg->value > 0.0) ||
|
||||
(arg->type == FF_ARG_TYPE_INT && *(int*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_STRBUF && ((FFstrbuf*)arg->value)->length > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_STRING && ffStrSet((char*)arg->value)) ||
|
||||
(arg->type == FF_ARG_TYPE_UINT8 && *(uint8_t*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_UINT16 && *(uint16_t*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_UINT && *(uint32_t*)arg->value > 0) ||
|
||||
(arg->type == FF_ARG_TYPE_BOOL && *(bool*)arg->value) ||
|
||||
(arg->type == FF_ARG_TYPE_LIST && ((FFlist*)arg->value)->length > 0)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -203,7 +211,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
|
||||
|
||||
// testing for an invalid index
|
||||
if (index > numArgs)
|
||||
if (index > numArgs || index < 1)
|
||||
{
|
||||
appendInvalidPlaceholder(buffer, "{?", &placeholderValue, i, formatstr->length);
|
||||
continue;
|
||||
@@ -229,7 +237,7 @@ void ffParseFormatString(FFstrbuf* buffer, const FFstrbuf* formatstr, uint32_t n
|
||||
uint32_t index = getArgumentIndex(placeholderValue.chars, numArgs, arguments);
|
||||
|
||||
// testing for an invalid index
|
||||
if (index > numArgs)
|
||||
if (index > numArgs || index < 1)
|
||||
{
|
||||
appendInvalidPlaceholder(buffer, "{/", &placeholderValue, i, formatstr->length);
|
||||
continue;
|
||||
@@ -0,0 +1,25 @@
|
||||
#include "common/frequency.h"
|
||||
|
||||
bool ffFreqAppendNum(uint32_t mhz, FFstrbuf* result)
|
||||
{
|
||||
if (mhz == 0)
|
||||
return false;
|
||||
|
||||
const FFOptionsDisplay* options = &instance.config.display;
|
||||
bool spaceBeforeUnit = options->freqSpaceBeforeUnit != FF_SPACE_BEFORE_UNIT_NEVER;
|
||||
int8_t ndigits = options->freqNdigits;
|
||||
|
||||
if (ndigits >= 0)
|
||||
{
|
||||
ffStrbufAppendDouble(result, mhz / 1000., ndigits, true);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
ffStrbufAppendS(result, "GHz");
|
||||
}
|
||||
else
|
||||
{
|
||||
ffStrbufAppendUInt(result, mhz);
|
||||
if (spaceBeforeUnit) ffStrbufAppendC(result, ' ');
|
||||
ffStrbufAppendS(result, "MHz");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2,9 +2,9 @@
|
||||
#include "common/init.h"
|
||||
#include "common/parsing.h"
|
||||
#include "common/thread.h"
|
||||
#include "common/textModifier.h"
|
||||
#include "detection/displayserver/displayserver.h"
|
||||
#include "detection/terminaltheme/terminaltheme.h"
|
||||
#include "util/textModifier.h"
|
||||
#include "logo/logo.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <locale.h>
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include "util/windows/unicode.h"
|
||||
#include "common/windows/unicode.h"
|
||||
#else
|
||||
#include <signal.h>
|
||||
#endif
|
||||
@@ -25,10 +25,10 @@ static void initState(FFstate* state)
|
||||
state->logoHeight = 0;
|
||||
state->keysHeight = 0;
|
||||
state->terminalLightTheme = false;
|
||||
state->titleFqdn = false;
|
||||
|
||||
ffPlatformInit(&state->platform);
|
||||
state->configDoc = NULL;
|
||||
state->resultDoc = NULL;
|
||||
state->dynamicInterval = 0;
|
||||
|
||||
{
|
||||
// don't enable bright color if the terminal is in light mode
|
||||
@@ -42,26 +42,28 @@ static void defaultConfig(void)
|
||||
{
|
||||
ffOptionsInitLogo(&instance.config.logo);
|
||||
ffOptionsInitGeneral(&instance.config.general);
|
||||
ffOptionsInitModules(&instance.config.modules);
|
||||
ffOptionsInitDisplay(&instance.config.display);
|
||||
}
|
||||
|
||||
void ffInitInstance(void)
|
||||
{
|
||||
#ifdef WIN32
|
||||
//https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendations&view=msvc-170#utf-8-support
|
||||
#ifdef _WIN32
|
||||
// https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/setlocale-wsetlocale?source=recommendat>
|
||||
setlocale(LC_ALL, ".UTF8");
|
||||
#else
|
||||
// Never use `setlocale(LC_ALL, "")`
|
||||
setlocale(LC_TIME, "");
|
||||
#endif
|
||||
|
||||
initState(&instance.state);
|
||||
defaultConfig();
|
||||
initState(&instance.state);
|
||||
}
|
||||
|
||||
static volatile bool ffDisableLinewrap = true;
|
||||
static volatile bool ffHideCursor = true;
|
||||
#if _WIN32
|
||||
static volatile UINT oldCp = CP_UTF8;
|
||||
#endif
|
||||
|
||||
static void resetConsole(void)
|
||||
{
|
||||
@@ -71,8 +73,14 @@ static void resetConsole(void)
|
||||
if(ffHideCursor)
|
||||
fputs("\033[?25h", stdout);
|
||||
|
||||
if(instance.state.dynamicInterval > 0)
|
||||
fputs("\033[?1049l", stdout); // Disable alternate buffer
|
||||
|
||||
#if defined(_WIN32)
|
||||
fflush(stdout);
|
||||
|
||||
if(oldCp != CP_UTF8)
|
||||
SetConsoleOutputCP(oldCp);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -88,23 +96,15 @@ static void exitSignalHandler(FF_MAYBE_UNUSED int signal)
|
||||
resetConsole();
|
||||
exit(0);
|
||||
}
|
||||
static void chldSignalHandler(FF_MAYBE_UNUSED int signal)
|
||||
{
|
||||
// empty; used to interrupt the poll and read syscalls
|
||||
}
|
||||
#endif
|
||||
|
||||
void ffStart(void)
|
||||
{
|
||||
#ifdef FF_START_DETECTION_THREADS
|
||||
if(instance.config.general.multithreading)
|
||||
startDetectionThreads();
|
||||
#endif
|
||||
|
||||
ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe && !instance.state.resultDoc;
|
||||
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe && !instance.state.resultDoc;
|
||||
ffDisableLinewrap = instance.config.display.disableLinewrap && !instance.config.display.pipe;
|
||||
ffHideCursor = instance.config.display.hideCursor && !instance.config.display.pipe;
|
||||
|
||||
#ifdef _WIN32
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
if (instance.config.display.noBuffer)
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
else
|
||||
@@ -112,20 +112,26 @@ void ffStart(void)
|
||||
SetConsoleCtrlHandler(consoleHandler, TRUE);
|
||||
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
DWORD mode = 0;
|
||||
GetConsoleMode(hStdout, &mode);
|
||||
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
if (GetConsoleMode(hStdout, &mode))
|
||||
{
|
||||
SetConsoleMode(hStdout, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
|
||||
oldCp = GetConsoleOutputCP();
|
||||
if (oldCp != CP_UTF8) SetConsoleOutputCP(CP_UTF8);
|
||||
}
|
||||
#else
|
||||
if (instance.config.display.noBuffer) setvbuf(stdout, NULL, _IONBF, 0);
|
||||
struct sigaction action = { .sa_handler = exitSignalHandler };
|
||||
sigaction(SIGINT, &action, NULL);
|
||||
sigaction(SIGTERM, &action, NULL);
|
||||
sigaction(SIGQUIT, &action, NULL);
|
||||
sigaction(SIGCHLD, &(struct sigaction) { .sa_handler = chldSignalHandler }, NULL);
|
||||
sigset_t newmask;
|
||||
sigemptyset(&newmask);
|
||||
sigaddset(&newmask, SIGCHLD);
|
||||
sigprocmask(SIG_BLOCK, &newmask, NULL);
|
||||
#endif
|
||||
|
||||
//reset everything to default before we start printing
|
||||
if(!instance.config.display.pipe && !instance.state.resultDoc)
|
||||
if(!instance.config.display.pipe)
|
||||
fputs(FASTFETCH_TEXT_MODIFIER_RESET, stdout);
|
||||
|
||||
if(ffHideCursor)
|
||||
@@ -134,14 +140,15 @@ void ffStart(void)
|
||||
if(ffDisableLinewrap)
|
||||
fputs("\033[?7l", stdout);
|
||||
|
||||
ffLogoPrint();
|
||||
if(instance.state.dynamicInterval > 0)
|
||||
{
|
||||
fputs("\033[?1049h\033[H", stdout); // Enable alternate buffer
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
void ffFinish(void)
|
||||
{
|
||||
if(instance.config.logo.printRemaining)
|
||||
ffLogoPrintRemaining();
|
||||
|
||||
resetConsole();
|
||||
}
|
||||
|
||||
@@ -149,16 +156,12 @@ static void destroyConfig(void)
|
||||
{
|
||||
ffOptionsDestroyLogo(&instance.config.logo);
|
||||
ffOptionsDestroyGeneral(&instance.config.general);
|
||||
ffOptionsDestroyModules(&instance.config.modules);
|
||||
ffOptionsDestroyDisplay(&instance.config.display);
|
||||
}
|
||||
|
||||
static void destroyState(void)
|
||||
{
|
||||
ffPlatformDestroy(&instance.state.platform);
|
||||
yyjson_doc_free(instance.state.configDoc);
|
||||
yyjson_mut_doc_free(instance.state.resultDoc);
|
||||
ffStrbufDestroy(&instance.state.genConfigPath);
|
||||
}
|
||||
|
||||
void ffDestroyInstance(void)
|
||||
@@ -213,9 +216,6 @@ void ffListFeatures(void)
|
||||
#if FF_HAVE_ZLIB
|
||||
"zlib\n"
|
||||
#endif
|
||||
#if FF_HAVE_XFCONF
|
||||
"xfconf\n"
|
||||
#endif
|
||||
#if FF_HAVE_SQLITE3
|
||||
"sqlite3\n"
|
||||
#endif
|
||||
@@ -234,9 +234,6 @@ void ffListFeatures(void)
|
||||
#if FF_HAVE_FREETYPE
|
||||
"freetype\n"
|
||||
#endif
|
||||
#if FF_HAVE_PCIACCESS
|
||||
"libpciaccess\n"
|
||||
#endif
|
||||
#if FF_HAVE_PULSE
|
||||
"libpulse\n"
|
||||
#endif
|
||||
@@ -249,9 +246,6 @@ void ffListFeatures(void)
|
||||
#if FF_HAVE_LIBZFS
|
||||
"libzfs\n"
|
||||
#endif
|
||||
#if FF_HAVE_DIRECTX_HEADERS
|
||||
"Directx Headers\n"
|
||||
#endif
|
||||
#if FF_USE_SYSTEM_YYJSON
|
||||
"System yyjson\n"
|
||||
#endif
|
||||
@@ -264,6 +258,12 @@ void ffListFeatures(void)
|
||||
#if FF_HAVE_EMBEDDED_PCIIDS
|
||||
"Embedded pciids\n"
|
||||
#endif
|
||||
#if FF_WIN81_COMPAT
|
||||
"Windows 8.1 Compatibility\n"
|
||||
#endif
|
||||
#if FF_APPLE_MEMSIZE_USABLE
|
||||
"Apple memsize_usable\n"
|
||||
#endif
|
||||
""
|
||||
, stdout);
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
#include "io.h"
|
||||
#include "common/io.h"
|
||||
#include "fastfetch.h"
|
||||
#include "util/stringUtils.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/time.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
@@ -15,18 +15,15 @@
|
||||
|
||||
#if FF_HAVE_WORDEXP
|
||||
#include <wordexp.h>
|
||||
#elif FF_HAVE_GLOB
|
||||
#warning "<wordexp.h> is not available, use <glob.h> instead"
|
||||
#include <glob.h>
|
||||
#else
|
||||
#warning "Neither <wordexp.h> nor <glob.h> is available"
|
||||
#include <glob.h>
|
||||
#endif
|
||||
|
||||
static void createSubfolders(const char* fileName)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY path = ffStrbufCreate();
|
||||
|
||||
char *token = NULL;
|
||||
const char *token = NULL;
|
||||
while((token = strchr(fileName, '/')) != NULL)
|
||||
{
|
||||
ffStrbufAppendNS(&path, (uint32_t)(token - fileName + 1), fileName);
|
||||
@@ -100,50 +97,14 @@ bool ffAppendFDBuffer(int fd, FFstrbuf* buffer)
|
||||
return buffer->length > 0;
|
||||
}
|
||||
|
||||
ssize_t ffReadFileData(const char* fileName, size_t dataSize, void* data)
|
||||
{
|
||||
int FF_AUTO_CLOSE_FD fd = open(fileName, O_RDONLY | O_CLOEXEC);
|
||||
if(fd == -1)
|
||||
return -1;
|
||||
|
||||
return ffReadFDData(fd, dataSize, data);
|
||||
}
|
||||
|
||||
ssize_t ffReadFileDataRelative(int dfd, const char* fileName, size_t dataSize, void* data)
|
||||
{
|
||||
int FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
|
||||
if(fd == -1)
|
||||
return -1;
|
||||
|
||||
return ffReadFDData(fd, dataSize, data);
|
||||
}
|
||||
|
||||
bool ffAppendFileBuffer(const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
int FF_AUTO_CLOSE_FD fd = open(fileName, O_RDONLY | O_CLOEXEC);
|
||||
if(fd == -1)
|
||||
return false;
|
||||
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
bool ffAppendFileBufferRelative(int dfd, const char* fileName, FFstrbuf* buffer)
|
||||
{
|
||||
int FF_AUTO_CLOSE_FD fd = openat(dfd, fileName, O_RDONLY | O_CLOEXEC);
|
||||
if(fd == -1)
|
||||
return false;
|
||||
|
||||
return ffAppendFDBuffer(fd, buffer);
|
||||
}
|
||||
|
||||
bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* out)
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
#if FF_HAVE_WORDEXP // https://github.com/termux/termux-packages/pull/7056
|
||||
#if FF_HAVE_WORDEXP
|
||||
|
||||
wordexp_t exp;
|
||||
if (wordexp(in, &exp, 0) != 0)
|
||||
if (wordexp(in, &exp, 0) != 0) // WARN: 0 = no safety flags; command substitution allowed
|
||||
return false;
|
||||
|
||||
if (exp.we_wordc >= 1)
|
||||
@@ -154,16 +115,23 @@ bool ffPathExpandEnv(FF_MAYBE_UNUSED const char* in, FF_MAYBE_UNUSED FFstrbuf* o
|
||||
|
||||
wordfree(&exp);
|
||||
|
||||
#elif FF_HAVE_GLOB
|
||||
#else
|
||||
|
||||
glob_t gb;
|
||||
if (glob(in, GLOB_NOSORT | GLOB_TILDE, NULL, &gb) != 0)
|
||||
if (glob(in, GLOB_NOSORT
|
||||
#ifdef GLOB_TILDE
|
||||
| GLOB_TILDE
|
||||
#endif
|
||||
#ifdef GLOB_BRACE
|
||||
| GLOB_BRACE
|
||||
#endif
|
||||
, NULL, &gb) != 0)
|
||||
return false;
|
||||
|
||||
if (gb.gl_matchc >= 1)
|
||||
if (gb.gl_pathc >= 1)
|
||||
{
|
||||
result = true;
|
||||
ffStrbufSetS(out, gb.gl_pathv[gb.gl_matchc > 1 ? ffTimeGetNow() % gb.gl_matchc : 0]);
|
||||
ffStrbufSetS(out, gb.gl_pathv[gb.gl_pathc > 1 ? ffTimeGetNow() % (unsigned) gb.gl_pathc : 0]);
|
||||
}
|
||||
|
||||
globfree(&gb);
|
||||
@@ -290,7 +258,7 @@ bool ffSuppressIO(bool suppress)
|
||||
|
||||
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty)
|
||||
{
|
||||
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY);
|
||||
FF_AUTO_CLOSE_FD int dfd = open(folder->chars, O_RDONLY | O_CLOEXEC);
|
||||
if (dfd < 0)
|
||||
return;
|
||||
|
||||
@@ -358,3 +326,17 @@ void ffListFilesRecursively(const char* path, bool pretty)
|
||||
ffStrbufEnsureEndsWithC(&folder, '/');
|
||||
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
|
||||
}
|
||||
|
||||
FFNativeFD ffGetNullFD(void)
|
||||
{
|
||||
static FFNativeFD hNullFile = -1;
|
||||
if (hNullFile != -1)
|
||||
return hNullFile;
|
||||
hNullFile = open("/dev/null", O_WRONLY | O_CLOEXEC);
|
||||
return hNullFile;
|
||||
}
|
||||
|
||||
bool ffRemoveFile(const char* fileName)
|
||||
{
|
||||
return unlink(fileName) == 0;
|
||||
}
|
||||
@@ -0,0 +1,506 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/io.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include "common/windows/unicode.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
static bool createSubfolders(wchar_t* fileName)
|
||||
{
|
||||
HANDLE hRoot = ffGetPeb()->ProcessParameters->CurrentDirectory.Handle;
|
||||
bool closeRoot = false;
|
||||
wchar_t* ptr = fileName;
|
||||
|
||||
// Absolute drive path: C:\...
|
||||
if (ffCharIsEnglishAlphabet((char)ptr[0]) && ptr[1] == L':' && ptr[2] == L'\\')
|
||||
{
|
||||
wchar_t saved = ptr[3];
|
||||
ptr[3] = L'\0';
|
||||
|
||||
hRoot = CreateFileW(
|
||||
fileName,
|
||||
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL
|
||||
);
|
||||
|
||||
ptr[3] = saved;
|
||||
if (hRoot == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
closeRoot = true;
|
||||
ptr += 3; // skip "C:\"
|
||||
}
|
||||
// UNC path: \\server\share\...
|
||||
else if (ptr[0] == L'\\' && ptr[1] == L'\\')
|
||||
{
|
||||
wchar_t* serverEnd = wcschr(ptr + 2, L'\\');
|
||||
if (serverEnd == NULL)
|
||||
return false;
|
||||
|
||||
wchar_t* shareEnd = wcschr(serverEnd + 1, L'\\');
|
||||
if (shareEnd == NULL)
|
||||
return true; // no parent subfolder exists before file name
|
||||
|
||||
wchar_t saved = *shareEnd;
|
||||
*shareEnd = L'\0';
|
||||
|
||||
hRoot = CreateFileW(
|
||||
fileName,
|
||||
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL
|
||||
);
|
||||
|
||||
*shareEnd = saved;
|
||||
if (hRoot == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
|
||||
closeRoot = true;
|
||||
ptr = shareEnd + 1; // first component under share
|
||||
}
|
||||
// Rooted path on current drive: \foo\bar
|
||||
else if (ptr[0] == L'\\')
|
||||
{
|
||||
UNICODE_STRING* dosPath = &ffGetPeb()->ProcessParameters->CurrentDirectory.DosPath;
|
||||
wchar_t driveRoot[] = { dosPath->Buffer[0], L':', L'\\', L'\0' };
|
||||
hRoot = CreateFileW(
|
||||
driveRoot,
|
||||
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_FLAG_BACKUP_SEMANTICS,
|
||||
NULL
|
||||
);
|
||||
if (hRoot == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
closeRoot = true;
|
||||
ptr++; // skip leading '\'
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
wchar_t* token = wcschr(ptr, L'\\');
|
||||
if (token == NULL)
|
||||
break;
|
||||
|
||||
// Skip empty path segments caused by duplicated '\'
|
||||
if (token == ptr)
|
||||
{
|
||||
ptr = token + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
HANDLE hNew = INVALID_HANDLE_VALUE;
|
||||
IO_STATUS_BLOCK iosb = {};
|
||||
|
||||
NTSTATUS status = NtCreateFile(
|
||||
&hNew,
|
||||
FILE_LIST_DIRECTORY | FILE_TRAVERSE | SYNCHRONIZE,
|
||||
&(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = hRoot,
|
||||
.ObjectName = &(UNICODE_STRING) {
|
||||
.Buffer = ptr,
|
||||
.Length = (USHORT)((USHORT)(token - ptr) * sizeof(wchar_t)),
|
||||
.MaximumLength = (USHORT)((USHORT)(token - ptr) * sizeof(wchar_t)),
|
||||
},
|
||||
.Attributes = OBJ_CASE_INSENSITIVE,
|
||||
},
|
||||
&iosb,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
FILE_OPEN_IF,
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
|
||||
if (!NT_SUCCESS(status))
|
||||
{
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
|
||||
NtClose(hRoot);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
|
||||
NtClose(hRoot);
|
||||
hRoot = hNew;
|
||||
closeRoot = true;
|
||||
|
||||
ptr = token + 1;
|
||||
}
|
||||
|
||||
if (closeRoot && hRoot != INVALID_HANDLE_VALUE)
|
||||
NtClose(hRoot);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffWriteFileData(const char* fileName, size_t dataSize, const void* data)
|
||||
{
|
||||
wchar_t fileNameW[MAX_PATH];
|
||||
ULONG len = 0;
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG)strlen(fileName) + 1)))
|
||||
return false;
|
||||
|
||||
for (ULONG i = 0; i < len / sizeof(wchar_t); ++i)
|
||||
{
|
||||
if (fileNameW[i] == L'/')
|
||||
fileNameW[i] = L'\\';
|
||||
}
|
||||
|
||||
HANDLE FF_AUTO_CLOSE_FD handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
if (GetLastError() == ERROR_PATH_NOT_FOUND)
|
||||
{
|
||||
if (!createSubfolders(fileNameW))
|
||||
return false;
|
||||
handle = CreateFileW(fileNameW, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (handle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
DWORD written;
|
||||
return !!WriteFile(handle, data, (DWORD)dataSize, &written, NULL);
|
||||
}
|
||||
|
||||
static inline void readWithLength(HANDLE handle, FFstrbuf* buffer, uint32_t length)
|
||||
{
|
||||
ffStrbufEnsureFree(buffer, length);
|
||||
DWORD bytesRead = 0;
|
||||
while(
|
||||
length > 0 &&
|
||||
ReadFile(handle, buffer->chars + buffer->length, length, &bytesRead, NULL) != FALSE &&
|
||||
bytesRead > 0
|
||||
) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
length -= (uint32_t) bytesRead;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void readUntilEOF(HANDLE handle, FFstrbuf* buffer)
|
||||
{
|
||||
ffStrbufEnsureFree(buffer, 31);
|
||||
uint32_t available = ffStrbufGetFree(buffer);
|
||||
DWORD bytesRead = 0;
|
||||
while(
|
||||
ReadFile(handle, buffer->chars + buffer->length, available, &bytesRead, NULL) != FALSE &&
|
||||
bytesRead > 0
|
||||
) {
|
||||
buffer->length += (uint32_t) bytesRead;
|
||||
if((uint32_t) bytesRead == available)
|
||||
ffStrbufEnsureFree(buffer, buffer->allocated - 1); // Doubles capacity every round. -1 for the null byte.
|
||||
available = ffStrbufGetFree(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool ffAppendFDBuffer(HANDLE handle, FFstrbuf* buffer)
|
||||
{
|
||||
FILE_STANDARD_INFORMATION fileInfo;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
if(!NT_SUCCESS(NtQueryInformationFile(handle, &iosb, &fileInfo, sizeof(fileInfo), FileStandardInformation)))
|
||||
fileInfo.EndOfFile.QuadPart = 0;
|
||||
|
||||
if (fileInfo.EndOfFile.QuadPart > 0)
|
||||
readWithLength(handle, buffer, (uint32_t)fileInfo.EndOfFile.QuadPart);
|
||||
else
|
||||
readUntilEOF(handle, buffer);
|
||||
|
||||
buffer->chars[buffer->length] = '\0';
|
||||
|
||||
return buffer->length > 0;
|
||||
}
|
||||
|
||||
HANDLE openatW(HANDLE dfd, const wchar_t* fileName, uint16_t fileNameLen, bool directory)
|
||||
{
|
||||
assert(fileNameLen <= 0x7FFF);
|
||||
|
||||
HANDLE hFile;
|
||||
IO_STATUS_BLOCK iosb = {};
|
||||
if(!NT_SUCCESS(NtOpenFile(&hFile,
|
||||
(directory ? FILE_LIST_DIRECTORY | FILE_TRAVERSE : FILE_READ_DATA | FILE_READ_EA) | FILE_READ_ATTRIBUTES | SYNCHRONIZE, &(OBJECT_ATTRIBUTES) {
|
||||
.Length = sizeof(OBJECT_ATTRIBUTES),
|
||||
.RootDirectory = dfd,
|
||||
.ObjectName = &(UNICODE_STRING) {
|
||||
.Buffer = (PWSTR) fileName,
|
||||
.Length = fileNameLen * (USHORT) sizeof(wchar_t),
|
||||
.MaximumLength = (fileNameLen + 1) * (USHORT) sizeof(wchar_t),
|
||||
},
|
||||
.Attributes = OBJ_CASE_INSENSITIVE,
|
||||
},
|
||||
&iosb,
|
||||
FILE_SHARE_READ | (directory ? FILE_SHARE_WRITE | FILE_SHARE_DELETE : 0),
|
||||
FILE_SYNCHRONOUS_IO_NONALERT | (directory ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE)
|
||||
)))
|
||||
return INVALID_HANDLE_VALUE;
|
||||
|
||||
return hFile;
|
||||
}
|
||||
|
||||
HANDLE openat(HANDLE dfd, const char* fileName, int oflag)
|
||||
{
|
||||
wchar_t fileNameW[MAX_PATH];
|
||||
ULONG len;
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(fileNameW, (ULONG) sizeof(fileNameW), &len, fileName, (ULONG)strlen(fileName) + 1)))
|
||||
return INVALID_HANDLE_VALUE;
|
||||
// Implies `fileNameW[len] = L'\0';` and `len` includes the null terminator
|
||||
len /= sizeof(wchar_t); // convert from bytes to characters
|
||||
|
||||
for (uint32_t i = 0; i < len - 1; ++i)
|
||||
{
|
||||
if (fileNameW[i] == L'/')
|
||||
fileNameW[i] = L'\\';
|
||||
}
|
||||
|
||||
return openatW(dfd, fileNameW, (uint16_t)(len - 1), !!(oflag & O_DIRECTORY));
|
||||
}
|
||||
|
||||
bool ffPathExpandEnv(const char* in, FFstrbuf* out)
|
||||
{
|
||||
if (in[0] == '~') {
|
||||
if ((in[1] == '/' || in[1] == '\\' || in[1] == '\0') && !ffStrContainsC(in, '%')) {
|
||||
ffStrbufSet(out, &instance.state.platform.homeDir);
|
||||
ffStrbufAppendS(out, in + 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t pathInW[MAX_PATH], pathOutW[MAX_PATH];
|
||||
ULONG len = (ULONG) strlen(in);
|
||||
if (!NT_SUCCESS(RtlUTF8ToUnicodeN(pathInW, (ULONG) sizeof(pathInW), &len, in, len)))
|
||||
return false;
|
||||
len /= sizeof(wchar_t); // convert from bytes to characters
|
||||
|
||||
size_t outLen; // in characters, including null terminator
|
||||
if (!NT_SUCCESS(RtlExpandEnvironmentStrings(NULL, pathInW, len, pathOutW, ARRAY_SIZE(pathOutW), &outLen)))
|
||||
return false;
|
||||
|
||||
ffStrbufSetNWS(out, (uint32_t) outLen - 1, pathOutW);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ffSuppressIO(bool suppress)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (instance.config.display.debugMode)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
static bool init = false;
|
||||
static HANDLE hOrigOut = INVALID_HANDLE_VALUE;
|
||||
static HANDLE hOrigErr = INVALID_HANDLE_VALUE;
|
||||
HANDLE hNullFile = ffGetNullFD();
|
||||
static int fOrigOut = -1;
|
||||
static int fOrigErr = -1;
|
||||
static int fNullFile = -1;
|
||||
|
||||
if (!init)
|
||||
{
|
||||
if(!suppress)
|
||||
return true;
|
||||
|
||||
hOrigOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
hOrigErr = GetStdHandle(STD_ERROR_HANDLE);
|
||||
fOrigOut = _dup(STDOUT_FILENO);
|
||||
fOrigErr = _dup(STDERR_FILENO);
|
||||
fNullFile = _open_osfhandle((intptr_t) hNullFile, 0);
|
||||
|
||||
init = true;
|
||||
}
|
||||
if (hNullFile == INVALID_HANDLE_VALUE || fNullFile == -1)
|
||||
return false;
|
||||
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
|
||||
SetStdHandle(STD_OUTPUT_HANDLE, suppress ? hNullFile : hOrigOut);
|
||||
SetStdHandle(STD_ERROR_HANDLE, suppress ? hNullFile : hOrigErr);
|
||||
_dup2(suppress ? fNullFile : fOrigOut, STDOUT_FILENO);
|
||||
_dup2(suppress ? fNullFile : fOrigErr, STDERR_FILENO);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void listFilesRecursively(uint32_t baseLength, FFstrbuf* folder, uint8_t indentation, const char* folderName, bool pretty)
|
||||
{
|
||||
uint32_t folderLength = folder->length;
|
||||
|
||||
if(pretty && folderName != NULL)
|
||||
{
|
||||
for(uint8_t i = 0; i < indentation - 1; i++)
|
||||
fputs(" | ", stdout);
|
||||
printf("%s/\n", folderName);
|
||||
}
|
||||
|
||||
ffStrbufAppendC(folder, '*');
|
||||
WIN32_FIND_DATAA entry;
|
||||
HANDLE hFind = FindFirstFileA(folder->chars, &entry);
|
||||
ffStrbufTrimRight(folder, '*');
|
||||
if(hFind == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
|
||||
do
|
||||
{
|
||||
if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
if(ffStrEquals(entry.cFileName, ".") || ffStrEquals(entry.cFileName, ".."))
|
||||
continue;
|
||||
|
||||
ffStrbufSubstrBefore(folder, folderLength);
|
||||
ffStrbufAppendS(folder, entry.cFileName);
|
||||
ffStrbufAppendC(folder, '/');
|
||||
listFilesRecursively(baseLength, folder, (uint8_t) (indentation + 1), entry.cFileName, pretty);
|
||||
ffStrbufSubstrBefore(folder, folderLength);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pretty)
|
||||
{
|
||||
for(uint8_t i = 0; i < indentation; i++)
|
||||
fputs(" | ", stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
fputs(folder->chars + baseLength, stdout);
|
||||
}
|
||||
|
||||
puts(entry.cFileName);
|
||||
} while (FindNextFileA(hFind, &entry));
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
void ffListFilesRecursively(const char* path, bool pretty)
|
||||
{
|
||||
FF_STRBUF_AUTO_DESTROY folder = ffStrbufCreateS(path);
|
||||
ffStrbufEnsureEndsWithC(&folder, '/');
|
||||
listFilesRecursively(folder.length, &folder, 0, NULL, pretty);
|
||||
}
|
||||
|
||||
const char* ffGetTerminalResponse(const char* request, int nParams, const char* format, ...)
|
||||
{
|
||||
HANDLE hInput = GetStdHandle(STD_INPUT_HANDLE);
|
||||
FF_AUTO_CLOSE_FD HANDLE hConin = INVALID_HANDLE_VALUE;
|
||||
DWORD inputMode;
|
||||
if (!GetConsoleMode(hInput, &inputMode))
|
||||
{
|
||||
hConin = CreateFileW(L"CONIN$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, NULL);
|
||||
hInput = hConin;
|
||||
}
|
||||
SetConsoleMode(hInput, 0);
|
||||
|
||||
FlushConsoleInputBuffer(hInput);
|
||||
|
||||
{
|
||||
DWORD bytes = 0;
|
||||
HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
FF_AUTO_CLOSE_FD HANDLE hConout = INVALID_HANDLE_VALUE;
|
||||
DWORD outputMode;
|
||||
if (!GetConsoleMode(hOutput, &outputMode))
|
||||
{
|
||||
hConout = CreateFileW(L"CONOUT$", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, NULL);
|
||||
hOutput = hConout;
|
||||
}
|
||||
WriteFile(hOutput, request, (DWORD) strlen(request), &bytes, NULL);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (NtWaitForSingleObject(hInput, FALSE, &(LARGE_INTEGER) { .QuadPart = (int64_t) FF_IO_TERM_RESP_WAIT_MS * -10000 }) != STATUS_WAIT_0)
|
||||
{
|
||||
SetConsoleMode(hInput, inputMode);
|
||||
return "NtWaitForSingleObject() failed or timeout";
|
||||
}
|
||||
|
||||
// Ignore all unexpected input events
|
||||
INPUT_RECORD record;
|
||||
DWORD len = 0;
|
||||
if (!PeekConsoleInputW(hInput, &record, 1, &len))
|
||||
break;
|
||||
|
||||
if (
|
||||
record.EventType == KEY_EVENT &&
|
||||
record.Event.KeyEvent.uChar.UnicodeChar != L'\r' &&
|
||||
record.Event.KeyEvent.uChar.UnicodeChar != L'\n'
|
||||
)
|
||||
break;
|
||||
else
|
||||
ReadConsoleInputW(hInput, &record, 1, &len);
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
char buffer[1024];
|
||||
uint32_t bytesRead = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
DWORD bytes = 0;
|
||||
if (!ReadFile(hInput, buffer, sizeof(buffer) - 1, &bytes, NULL) || bytes == 0)
|
||||
{
|
||||
va_end(args);
|
||||
return "ReadFile() failed";
|
||||
}
|
||||
|
||||
bytesRead += bytes;
|
||||
buffer[bytesRead] = '\0';
|
||||
|
||||
va_list cargs;
|
||||
va_copy(cargs, args);
|
||||
int ret = vsscanf(buffer, format, cargs);
|
||||
va_end(cargs);
|
||||
|
||||
if (ret <= 0)
|
||||
{
|
||||
va_end(args);
|
||||
return "vsscanf(buffer, format, args) failed";
|
||||
}
|
||||
if (ret >= nParams)
|
||||
break;
|
||||
}
|
||||
|
||||
SetConsoleMode(hInput, inputMode);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FFNativeFD ffGetNullFD(void)
|
||||
{
|
||||
static FFNativeFD hNullFile = INVALID_HANDLE_VALUE;
|
||||
if (hNullFile != INVALID_HANDLE_VALUE)
|
||||
return hNullFile;
|
||||
hNullFile = CreateFileW(
|
||||
L"NUL",
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_WRITE,
|
||||
0,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
&(SECURITY_ATTRIBUTES){
|
||||
.nLength = sizeof(SECURITY_ATTRIBUTES),
|
||||
.lpSecurityDescriptor = NULL,
|
||||
.bInheritHandle = TRUE,
|
||||
});
|
||||
return hNullFile;
|
||||
}
|
||||
|
||||
bool ffRemoveFile(const char* fileName)
|
||||
{
|
||||
return DeleteFileA(fileName) != FALSE;
|
||||
}
|
||||
@@ -0,0 +1,351 @@
|
||||
#include "fastfetch.h"
|
||||
#include "common/color.h"
|
||||
#include "common/jsonconfig.h"
|
||||
#include "common/printing.h"
|
||||
#include "common/io.h"
|
||||
#include "common/time.h"
|
||||
#include "common/stringUtils.h"
|
||||
#include "detection/version/version.h"
|
||||
#include "modules/modules.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
bool ffJsonConfigParseModuleArgs(yyjson_val* key, yyjson_val* val, FFModuleArgs* moduleArgs)
|
||||
{
|
||||
if (unsafe_yyjson_equals_str(key, "type") || unsafe_yyjson_equals_str(key, "condition"))
|
||||
return true;
|
||||
|
||||
if (unsafe_yyjson_equals_str(key, "key"))
|
||||
{
|
||||
ffStrbufSetJsonVal(&moduleArgs->key, val);
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_yyjson_equals_str(key, "format"))
|
||||
{
|
||||
ffStrbufSetJsonVal(&moduleArgs->outputFormat, val);
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_yyjson_equals_str(key, "outputColor"))
|
||||
{
|
||||
ffOptionParseColor(yyjson_get_str(val), &moduleArgs->outputColor);
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_yyjson_equals_str(key, "keyColor"))
|
||||
{
|
||||
ffOptionParseColor(yyjson_get_str(val), &moduleArgs->keyColor);
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_yyjson_equals_str(key, "keyWidth"))
|
||||
{
|
||||
moduleArgs->keyWidth = (uint32_t) yyjson_get_uint(val);
|
||||
return true;
|
||||
}
|
||||
else if (unsafe_yyjson_equals_str(key, "keyIcon"))
|
||||
{
|
||||
ffStrbufSetJsonVal(&moduleArgs->keyIcon, val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ffJsonConfigGenerateModuleArgsConfig(yyjson_mut_doc* doc, yyjson_mut_val* module, FFModuleArgs* moduleArgs)
|
||||
{
|
||||
if (moduleArgs->key.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "key", &moduleArgs->key);
|
||||
if (moduleArgs->outputFormat.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "format", &moduleArgs->outputFormat);
|
||||
if (moduleArgs->outputColor.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "outputColor", &moduleArgs->outputColor);
|
||||
if (moduleArgs->keyColor.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "keyColor", &moduleArgs->keyColor);
|
||||
if (moduleArgs->keyWidth > 0)
|
||||
yyjson_mut_obj_add_uint(doc, module, "keyWidth", moduleArgs->keyWidth);
|
||||
if (moduleArgs->keyIcon.length > 0)
|
||||
yyjson_mut_obj_add_strbuf(doc, module, "keyIcon", &moduleArgs->keyIcon);
|
||||
}
|
||||
|
||||
const char* ffJsonConfigParseEnum(yyjson_val* val, int* result, FFKeyValuePair pairs[])
|
||||
{
|
||||
if (yyjson_is_int(val))
|
||||
{
|
||||
int intVal = yyjson_get_int(val);
|
||||
|
||||
for (const FFKeyValuePair* pPair = pairs; pPair->key; ++pPair)
|
||||
{
|
||||
if (intVal == pPair->value)
|
||||
{
|
||||
*result = pPair->value;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return "Invalid enum integer";
|
||||
}
|
||||
else if (yyjson_is_str(val))
|
||||
{
|
||||
const char* strVal = yyjson_get_str(val);
|
||||
for (const FFKeyValuePair* pPair = pairs; pPair->key; ++pPair)
|
||||
{
|
||||
if (ffStrEqualsIgnCase(strVal, pPair->key))
|
||||
{
|
||||
*result = pPair->value;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return "Invalid enum string";
|
||||
}
|
||||
else
|
||||
return "Invalid enum value type; must be a string or integer";
|
||||
}
|
||||
|
||||
static bool parseModuleJsonObject(const char* type, yyjson_val* jsonVal, yyjson_mut_doc* jsonDoc)
|
||||
{
|
||||
if(!ffCharIsEnglishAlphabet(type[0])) return false;
|
||||
|
||||
for (FFModuleBaseInfo** modules = ffModuleInfos[toupper(type[0]) - 'A']; *modules; ++modules)
|
||||
{
|
||||
FFModuleBaseInfo* baseInfo = *modules;
|
||||
if (ffStrEqualsIgnCase(type, baseInfo->name))
|
||||
{
|
||||
uint8_t optionBuf[FF_OPTION_MAX_SIZE];
|
||||
baseInfo->initOptions(optionBuf);
|
||||
if (jsonVal) baseInfo->parseJsonObject(optionBuf, jsonVal);
|
||||
bool succeeded;
|
||||
if (jsonDoc)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(jsonDoc, jsonDoc->root);
|
||||
yyjson_mut_obj_add_str(jsonDoc, module, "type", baseInfo->name);
|
||||
if (baseInfo->generateJsonResult)
|
||||
succeeded = baseInfo->generateJsonResult(optionBuf, jsonDoc, module);
|
||||
else
|
||||
{
|
||||
yyjson_mut_obj_add_str(jsonDoc, module, "error", "Unsupported for JSON format");
|
||||
succeeded = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
succeeded = baseInfo->printModule(optionBuf);
|
||||
baseInfo->destroyOptions(optionBuf);
|
||||
return succeeded;
|
||||
}
|
||||
}
|
||||
|
||||
if (jsonDoc)
|
||||
{
|
||||
yyjson_mut_val* module = yyjson_mut_arr_add_obj(jsonDoc, jsonDoc->root);
|
||||
yyjson_mut_obj_add_strcpy(jsonDoc, module, "type", type);
|
||||
yyjson_mut_obj_add_str(jsonDoc, module, "error", "Unknown module type");
|
||||
}
|
||||
else
|
||||
{
|
||||
FFModuleArgs moduleArgs;
|
||||
ffOptionInitModuleArg(&moduleArgs, "");
|
||||
ffPrintError(type, 0, &moduleArgs, FF_PRINT_TYPE_DEFAULT, "Unknown module type");
|
||||
ffOptionDestroyModuleArg(&moduleArgs);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void prepareModuleJsonObject(const char* type, yyjson_val* module)
|
||||
{
|
||||
switch (type[0])
|
||||
{
|
||||
case 'b': case 'B': {
|
||||
if (ffStrEqualsIgnCase(type, FF_CPUUSAGE_MODULE_NAME))
|
||||
ffPrepareCPUUsage();
|
||||
break;
|
||||
}
|
||||
case 'c': case 'C': {
|
||||
if (ffStrEqualsIgnCase(type, FF_COMMAND_MODULE_NAME))
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyCommandOptions))) FFCommandOptions options;
|
||||
ffInitCommandOptions(&options);
|
||||
if (module) ffCommandModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareCommand(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'd': case 'D': {
|
||||
if (ffStrEqualsIgnCase(type, FF_DISKIO_MODULE_NAME))
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyDiskIOOptions))) FFDiskIOOptions options;
|
||||
ffInitDiskIOOptions(&options);
|
||||
if (module) ffDiskIOModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareDiskIO(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'n': case 'N': {
|
||||
if (ffStrEqualsIgnCase(type, FF_NETIO_MODULE_NAME))
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyNetIOOptions))) FFNetIOOptions options;
|
||||
ffInitNetIOOptions(&options);
|
||||
if (module) ffNetIOModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareNetIO(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'p': case 'P': {
|
||||
if (ffStrEqualsIgnCase(type, FF_PUBLICIP_MODULE_NAME))
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyPublicIpOptions))) FFPublicIPOptions options;
|
||||
ffInitPublicIpOptions(&options);
|
||||
if (module) ffPublicIPModuleInfo.parseJsonObject(&options, module);
|
||||
ffPreparePublicIp(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'w': case 'W': {
|
||||
if (ffStrEqualsIgnCase(type, FF_WEATHER_MODULE_NAME))
|
||||
{
|
||||
__attribute__((__cleanup__(ffDestroyWeatherOptions))) FFWeatherOptions options;
|
||||
ffInitWeatherOptions(&options);
|
||||
if (module) ffWeatherModuleInfo.parseJsonObject(&options, module);
|
||||
ffPrepareWeather(&options);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool matchesJsonArray(const char* str, yyjson_val* val)
|
||||
{
|
||||
assert(val);
|
||||
|
||||
if (unsafe_yyjson_is_str(val))
|
||||
return ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(val));
|
||||
|
||||
if (!unsafe_yyjson_is_arr(val)) return false;
|
||||
|
||||
size_t idx, max;
|
||||
yyjson_val* item;
|
||||
yyjson_arr_foreach(val, idx, max, item)
|
||||
{
|
||||
if (yyjson_is_str(item) && ffStrEqualsIgnCase(str, unsafe_yyjson_get_str(item)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static const char* printJsonConfig(FFdata* data, bool prepare)
|
||||
{
|
||||
yyjson_mut_doc* jsonDoc = data->resultDoc;
|
||||
yyjson_val* const root = yyjson_doc_get_root(data->configDoc);
|
||||
assert(root);
|
||||
|
||||
if (!yyjson_is_obj(root))
|
||||
return "Invalid JSON config format. Root value must be an object";
|
||||
|
||||
yyjson_val* modules = yyjson_obj_get(root, "modules");
|
||||
if (!modules) return NULL;
|
||||
if (!yyjson_is_arr(modules)) return "Property 'modules' must be an array of strings or objects";
|
||||
|
||||
bool succeeded = true;
|
||||
int32_t thres = instance.config.display.stat;
|
||||
yyjson_val* item;
|
||||
size_t idx, max;
|
||||
yyjson_arr_foreach(modules, idx, max, item)
|
||||
{
|
||||
double ms = 0;
|
||||
if(!prepare && thres >= 0)
|
||||
ms = ffTimeGetTick();
|
||||
|
||||
yyjson_val* module = item;
|
||||
const char* type = yyjson_get_str(module);
|
||||
if (type)
|
||||
module = NULL;
|
||||
else if (yyjson_is_obj(module))
|
||||
{
|
||||
yyjson_val* conditions = yyjson_obj_get(module, "condition");
|
||||
if (conditions)
|
||||
{
|
||||
if (!yyjson_is_obj(conditions))
|
||||
return "Property 'conditions' must be an object";
|
||||
|
||||
yyjson_val* system = yyjson_obj_get(conditions, "system");
|
||||
if (system && !matchesJsonArray(ffVersionResult.sysName, system))
|
||||
continue;
|
||||
|
||||
system = yyjson_obj_get(conditions, "!system");
|
||||
if (system && matchesJsonArray(ffVersionResult.sysName, system))
|
||||
continue;
|
||||
|
||||
yyjson_val* arch = yyjson_obj_get(conditions, "arch");
|
||||
if (arch && !matchesJsonArray(ffVersionResult.architecture, arch))
|
||||
continue;
|
||||
|
||||
arch = yyjson_obj_get(conditions, "!arch");
|
||||
if (arch && matchesJsonArray(ffVersionResult.architecture, arch))
|
||||
continue;
|
||||
|
||||
yyjson_val* previousSucceeded = yyjson_obj_get(conditions, "succeeded");
|
||||
if (previousSucceeded && !unsafe_yyjson_is_null(previousSucceeded))
|
||||
{
|
||||
if (!unsafe_yyjson_is_bool(previousSucceeded))
|
||||
return "Property 'succeeded' in 'condition' must be a boolean";
|
||||
if (succeeded != unsafe_yyjson_get_bool(previousSucceeded))
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
type = yyjson_get_str(yyjson_obj_get(module, "type"));
|
||||
if (!type) return "module object must contain a \"type\" key ( case sensitive )";
|
||||
if (yyjson_obj_size(module) == 1) // contains only Property type
|
||||
module = NULL;
|
||||
}
|
||||
else
|
||||
return "modules must be an array of strings or objects";
|
||||
|
||||
if (ffStrbufSeparatedContainIgnCaseS(&data->structureDisabled, type, ':'))
|
||||
continue;
|
||||
|
||||
if(prepare)
|
||||
prepareModuleJsonObject(type, module);
|
||||
else
|
||||
succeeded = parseModuleJsonObject(type, module, jsonDoc);
|
||||
|
||||
if(!prepare && thres >= 0)
|
||||
{
|
||||
ms = ffTimeGetTick() - ms;
|
||||
if (jsonDoc)
|
||||
{
|
||||
yyjson_mut_val* moduleJson = yyjson_mut_arr_get_last(jsonDoc->root);
|
||||
yyjson_mut_obj_add_real(jsonDoc, moduleJson, "stat", ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
char str[64];
|
||||
int len = snprintf(str, sizeof str, "%.3fms", ms);
|
||||
if (thres > 0)
|
||||
snprintf(str, sizeof str, "\e[%sm%.3fms\e[m", (ms <= thres ? FF_COLOR_FG_GREEN : ms <= 2 * thres ? FF_COLOR_FG_YELLOW : FF_COLOR_FG_RED), ms);
|
||||
printf("\e7\e[1A\e[9999999C\e[%dD%s\e8", len, str); // Save; Up 1; Right 9999999; Left <len>; Print <str>; Load
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (!instance.config.display.noBuffer && !jsonDoc) fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ffPrintJsonConfig(FFdata* data, bool prepare)
|
||||
{
|
||||
yyjson_mut_doc* jsonDoc = data->resultDoc;
|
||||
const char* error = printJsonConfig(data, prepare);
|
||||
if (error)
|
||||
{
|
||||
if (jsonDoc)
|
||||
{
|
||||
yyjson_mut_val* obj = yyjson_mut_obj(jsonDoc);
|
||||
yyjson_mut_obj_add_str(jsonDoc, obj, "error", error);
|
||||
yyjson_mut_doc_set_root(jsonDoc, obj);
|
||||
}
|
||||
else
|
||||
ffPrintError("JsonConfig", 0, NULL, FF_PRINT_TYPE_NO_CUSTOM_KEY, "%s", error);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/apple/cf_helpers.h"
|
||||
#include <IOKit/kext/KextManager.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
FF_CFTYPE_AUTO_RELEASE CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, modName, kCFStringEncodingUTF8);
|
||||
FF_CFTYPE_AUTO_RELEASE CFArrayRef identifiers = CFArrayCreate(kCFAllocatorDefault, (const void**) &name, 1, &kCFTypeArrayCallBacks);
|
||||
FF_CFTYPE_AUTO_RELEASE CFArrayRef keys = CFArrayCreate(kCFAllocatorDefault, NULL, 0, NULL);
|
||||
FF_CFTYPE_AUTO_RELEASE CFDictionaryRef kextInfo = KextManagerCopyLoadedKextInfo(identifiers, keys);
|
||||
return CFDictionaryContainsKey(kextInfo, name);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include "common/kmod.h"
|
||||
#include <sys/param.h>
|
||||
#include <sys/module.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
return modfind(modName) >= 0;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/io.h"
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
static FFstrbuf modules;
|
||||
if (modules.chars == NULL)
|
||||
{
|
||||
ffStrbufInitS(&modules, "\n");
|
||||
ffAppendFileBuffer("/proc/modules", &modules);
|
||||
}
|
||||
|
||||
if (modules.length == 0) return false;
|
||||
|
||||
uint32_t len = (uint32_t) strlen(modName);
|
||||
if (len > 250) return false;
|
||||
|
||||
char temp[256];
|
||||
temp[0] = '\n';
|
||||
memcpy(temp + 1, modName, len);
|
||||
temp[1 + len] = ' ';
|
||||
return memmem(modules.chars, modules.length, temp, len + 2) != NULL;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <sys/module.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
typedef struct __attribute__((__packed__)) FFNbsdModList
|
||||
{
|
||||
int len;
|
||||
modstat_t mods[];
|
||||
} FFNbsdModList;
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
static FFNbsdModList* list = NULL;
|
||||
|
||||
if (list == NULL)
|
||||
{
|
||||
struct iovec iov = {};
|
||||
|
||||
for (size_t len = 8192;; len = iov.iov_len)
|
||||
{
|
||||
iov.iov_len = len;
|
||||
iov.iov_base = realloc(iov.iov_base, len);
|
||||
if (modctl(MODCTL_STAT, &iov) < 0)
|
||||
{
|
||||
free(iov.iov_base);
|
||||
return true; // ignore errors
|
||||
}
|
||||
|
||||
if (len >= iov.iov_len) break;
|
||||
}
|
||||
list = (FFNbsdModList*) iov.iov_base;
|
||||
}
|
||||
|
||||
for (int i = 0; i < list->len; i++)
|
||||
{
|
||||
if (ffStrEquals(list->mods[i].ms_name, modName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include "common/kmod.h"
|
||||
|
||||
bool ffKmodLoaded(FF_MAYBE_UNUSED const char* modName)
|
||||
{
|
||||
return true; // Don't generate kernel module related errors
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
#include <sys/modctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
struct modinfo modinfo = {
|
||||
.mi_id = -1,
|
||||
.mi_nextid = -1,
|
||||
.mi_info = MI_INFO_ALL,
|
||||
};
|
||||
|
||||
for (int id = -1; modctl(MODINFO, id, &modinfo) == 0; id = modinfo.mi_id)
|
||||
{
|
||||
modinfo.mi_name[MODMAXNAMELEN - 1] = '\0';
|
||||
|
||||
if (ffStrEquals(modinfo.mi_name, modName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return !(errno == EINVAL || errno == ENOENT);
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include "common/kmod.h"
|
||||
#include "common/windows/nt.h"
|
||||
#include "common/mallocHelper.h"
|
||||
#include "common/stringUtils.h"
|
||||
|
||||
bool ffKmodLoaded(const char* modName)
|
||||
{
|
||||
ULONG bufferSize = 0;
|
||||
NtQuerySystemInformation(SystemModuleInformation, NULL, 0, &bufferSize);
|
||||
if (bufferSize == 0)
|
||||
return true; // ignore errors
|
||||
|
||||
FF_AUTO_FREE RTL_PROCESS_MODULES* buffer = malloc(bufferSize);
|
||||
|
||||
if (!NT_SUCCESS(NtQuerySystemInformation(SystemModuleInformation, buffer, bufferSize, &bufferSize)))
|
||||
return true; // ignore errors
|
||||
|
||||
for (ULONG i = 0; i < buffer->NumberOfModules; i++)
|
||||
{
|
||||
const char* name = (const char*) buffer->Modules[i].FullPathName + buffer->Modules[i].OffsetToFileName;
|
||||
|
||||
if (ffStrEqualsIgnCase(name, modName))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user