Compare commits
2081 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
96a31f554a | ||
![]() |
d14ec6aea5 | ||
![]() |
917cedf893 | ||
![]() |
193dd71600 | ||
![]() |
6c293a3d7f | ||
![]() |
e847ddf011 | ||
![]() |
7e8b448985 | ||
![]() |
d1f3a87c08 | ||
![]() |
9f8145e590 | ||
![]() |
791efc171a | ||
![]() |
144312a525 | ||
![]() |
92684112ed | ||
![]() |
ef114ee6cb | ||
![]() |
667f209742 | ||
![]() |
4ad0747c78 | ||
![]() |
c5cf66402c | ||
![]() |
05417049eb | ||
![]() |
c7b0c46d9f | ||
![]() |
df578c91ad | ||
![]() |
70008c47c9 | ||
![]() |
938affef32 | ||
![]() |
a3c33000ee | ||
![]() |
1e54b7b294 | ||
![]() |
cc0dbcf3f4 | ||
![]() |
c5a2cadccc | ||
![]() |
9aa43416b6 | ||
![]() |
8364029db8 | ||
![]() |
d842d21be0 | ||
![]() |
3514fd2433 | ||
![]() |
6778ff27ea | ||
![]() |
f32315d699 | ||
![]() |
8b754b24b6 | ||
![]() |
b1bee9ff38 | ||
![]() |
569be2d402 | ||
![]() |
78a73eac53 | ||
![]() |
533cb99c33 | ||
![]() |
79726940dc | ||
![]() |
27c7891169 | ||
![]() |
7a3a793a12 | ||
![]() |
8088469eca | ||
![]() |
3dcb082015 | ||
![]() |
bece023028 | ||
![]() |
9c4df66925 | ||
![]() |
2b43ceb6c6 | ||
![]() |
c143adba91 | ||
![]() |
142fdc8d86 | ||
![]() |
67778dcd3d | ||
![]() |
ed80863eac | ||
![]() |
c3fc84de12 | ||
![]() |
904f83cd85 | ||
![]() |
28bf100a50 | ||
![]() |
accbd4e82a | ||
![]() |
d7f478c154 | ||
![]() |
8f7f13fea4 | ||
![]() |
c82b03a74c | ||
![]() |
58fb36bdb9 | ||
![]() |
4297a7b0a4 | ||
![]() |
1bab6d0dd7 | ||
![]() |
13b85edbe2 | ||
![]() |
dc53098e43 | ||
![]() |
3c66feff5a | ||
![]() |
218c3bc0d5 | ||
![]() |
9f5eddcd13 | ||
![]() |
3cba76552b | ||
![]() |
e98a8b624b | ||
![]() |
6c6947b01f | ||
![]() |
78c91e9e5b | ||
![]() |
44493ca0c4 | ||
![]() |
42acf78b09 | ||
![]() |
3aa9f8af18 | ||
![]() |
8a32ee30a5 | ||
![]() |
981dc0626b | ||
![]() |
8986d14e98 | ||
![]() |
5163b1a624 | ||
![]() |
860aa9d6d0 | ||
![]() |
64dc5212f9 | ||
![]() |
6cff3214f3 | ||
![]() |
fd910bd5e9 | ||
![]() |
c6086bed41 | ||
![]() |
1a9dfdfab8 | ||
![]() |
5284cd11a9 | ||
![]() |
d1a47cffad | ||
![]() |
f469595eee | ||
![]() |
9cfc52f114 | ||
![]() |
30bfb756c2 | ||
![]() |
711f85445e | ||
![]() |
8aae9766e5 | ||
![]() |
288b98ccbf | ||
![]() |
bde50b1be8 | ||
![]() |
a34dfd55be | ||
![]() |
609c1d4d4c | ||
![]() |
c12fe09969 | ||
![]() |
bd14afe347 | ||
![]() |
f445a13051 | ||
![]() |
8ddf607d9f | ||
![]() |
5900253b85 | ||
![]() |
ccec94925f | ||
![]() |
4504a9d0b5 | ||
![]() |
057f98ad45 | ||
![]() |
3b1c9aa026 | ||
![]() |
658397dc38 | ||
![]() |
0cd1c8e23e | ||
![]() |
0345c1e6f8 | ||
![]() |
f6c4cda0d4 | ||
![]() |
39fd713b91 | ||
![]() |
31d77ec580 | ||
![]() |
06116382ee | ||
![]() |
d2046de193 | ||
![]() |
4397fe3a13 | ||
![]() |
534e1fa6eb | ||
![]() |
3e8cc2c670 | ||
![]() |
3c565baf9d | ||
![]() |
2e182e84c3 | ||
![]() |
a42021655c | ||
![]() |
2498a2b0bd | ||
![]() |
4484411a77 | ||
![]() |
61a151c803 | ||
![]() |
5149c950aa | ||
![]() |
18f4d846c9 | ||
![]() |
db95aa250d | ||
![]() |
982d1bf662 | ||
![]() |
a0393e9ddf | ||
![]() |
a8d6328bd4 | ||
![]() |
13dab13319 | ||
![]() |
c623aa0f06 | ||
![]() |
79403afbe6 | ||
![]() |
4c650e87fa | ||
![]() |
3dde62befe | ||
![]() |
8bfabbe265 | ||
![]() |
e334b16aaa | ||
![]() |
5626ace245 | ||
![]() |
52652cb609 | ||
![]() |
256f40d4f5 | ||
![]() |
ef9acc54ec | ||
![]() |
a9f2d25957 | ||
![]() |
6fc47fbb69 | ||
![]() |
9c11184238 | ||
![]() |
a421c1dbfb | ||
![]() |
7ec707927d | ||
![]() |
837134daef | ||
![]() |
4011899846 | ||
![]() |
28e743ba70 | ||
![]() |
a161d404ad | ||
![]() |
cd607cb280 | ||
![]() |
4e60ab7f53 | ||
![]() |
71e7d32b08 | ||
![]() |
d5e422970c | ||
![]() |
871ba5a488 | ||
![]() |
249e8d59cb | ||
![]() |
8f4769d2ac | ||
![]() |
a3ca9963a5 | ||
![]() |
2d3c23876c | ||
![]() |
bd8d8eef3e | ||
![]() |
e786207cc2 | ||
![]() |
b042095ac2 | ||
![]() |
3413d1bf23 | ||
![]() |
018c5ef731 | ||
![]() |
fdb136f1fa | ||
![]() |
9e33074735 | ||
![]() |
d6d465cdf4 | ||
![]() |
e76573cc1a | ||
![]() |
3fa6dc71e2 | ||
![]() |
6fec269844 | ||
![]() |
b6004b6837 | ||
![]() |
86d3b25aec | ||
![]() |
8a407bfbb0 | ||
![]() |
d30a590d9e | ||
![]() |
f95e404be1 | ||
![]() |
ffb8b4fc68 | ||
![]() |
f86d6b0162 | ||
![]() |
71c72ed072 | ||
![]() |
a8d343e07b | ||
![]() |
d020172181 | ||
![]() |
e5c9f6c1fe | ||
![]() |
176dc11748 | ||
![]() |
c2abd02b9b | ||
![]() |
12ecfdd423 | ||
![]() |
67cfbfc2f3 | ||
![]() |
fc83d38e67 | ||
![]() |
7063c423eb | ||
![]() |
36b93993cf | ||
![]() |
ceffc5aa72 | ||
![]() |
ccb45b6f6e | ||
![]() |
d2e47e014a | ||
![]() |
a5b8d7917f | ||
![]() |
d0e735ee4b | ||
![]() |
ece5971027 | ||
![]() |
7c6b0d5c31 | ||
![]() |
03151310cf | ||
![]() |
baa2bc0c38 | ||
![]() |
7e1b53480e | ||
![]() |
6425b4f9f5 | ||
![]() |
fb907f5f76 | ||
![]() |
b107a1583f | ||
![]() |
ced3f320eb | ||
![]() |
a9d7293818 | ||
![]() |
add42e9edf | ||
![]() |
265ad4b96a | ||
![]() |
92eeb4969f | ||
![]() |
6fcddaf8fa | ||
![]() |
41fd583fbc | ||
![]() |
ceba6816de | ||
![]() |
093cb475bb | ||
![]() |
d44790b35f | ||
![]() |
f8164a3dd1 | ||
![]() |
c20126598f | ||
![]() |
6c818bb37a | ||
![]() |
8cb160b1f8 | ||
![]() |
df91f3738a | ||
![]() |
b5b268f606 | ||
![]() |
ce6b8c94a2 | ||
![]() |
6e643fe58b | ||
![]() |
2bf91a0487 | ||
![]() |
2775d747ac | ||
![]() |
99659e4cf9 | ||
![]() |
3bbcda917c | ||
![]() |
7e43fb79af | ||
![]() |
eb2b567da6 | ||
![]() |
ab332d7b2e | ||
![]() |
53e22b81ef | ||
![]() |
3fc9d50adb | ||
![]() |
c2da6dd45b | ||
![]() |
7146f825b2 | ||
![]() |
f61a5f5200 | ||
![]() |
dc05dd7ca1 | ||
![]() |
57dd344f3b | ||
![]() |
f7f59df8aa | ||
![]() |
0525a6f90f | ||
![]() |
7b4305d81b | ||
![]() |
94e9e93fa4 | ||
![]() |
d2a1294e9a | ||
![]() |
3d897f18cd | ||
![]() |
68c14d1e53 | ||
![]() |
48089394a5 | ||
![]() |
30bd190b41 | ||
![]() |
cf93cd9307 | ||
![]() |
f40816e063 | ||
![]() |
3759f29852 | ||
![]() |
bc5555933f | ||
![]() |
ead7ae8504 | ||
![]() |
ad5abba8c6 | ||
![]() |
61296cedd2 | ||
![]() |
d9c29a2c4f | ||
![]() |
f5172e6b84 | ||
![]() |
544bcbe903 | ||
![]() |
f35dab1b56 | ||
![]() |
caee420087 | ||
![]() |
e8c374113e | ||
![]() |
98a241a730 | ||
![]() |
be8297d6f6 | ||
![]() |
09da80e9f4 | ||
![]() |
df4ecf63a8 | ||
![]() |
b4d1937857 | ||
![]() |
0be5fbdc35 | ||
![]() |
ae7e25ea65 | ||
![]() |
fef45d469c | ||
![]() |
e7353ec7e7 | ||
![]() |
e3237f057d | ||
![]() |
54d5d9d1cc | ||
![]() |
31d9aebf0b | ||
![]() |
5013de6770 | ||
![]() |
301abac0c1 | ||
![]() |
9614c48e4c | ||
![]() |
c6e1ca1c22 | ||
![]() |
30dc473697 | ||
![]() |
65974ceabc | ||
![]() |
6caf53d1c2 | ||
![]() |
dee6e498d9 | ||
![]() |
b3723274f7 | ||
![]() |
9fb7cc796b | ||
![]() |
3472208c05 | ||
![]() |
fc30e1d559 | ||
![]() |
cd4bb444ff | ||
![]() |
e443513996 | ||
![]() |
3d16f22135 | ||
![]() |
6cc1ff5eeb | ||
![]() |
3000b9dcde | ||
![]() |
3b867462a3 | ||
![]() |
b8aa9348b9 | ||
![]() |
513e3a3d21 | ||
![]() |
bfb0897b54 | ||
![]() |
86e8b8c10d | ||
![]() |
ee57c3490a | ||
![]() |
77c1f54876 | ||
![]() |
dc5984d0e0 | ||
![]() |
7afbd4800f | ||
![]() |
0720702c91 | ||
![]() |
5f396e824f | ||
![]() |
4f229c254c | ||
![]() |
25e58df5e0 | ||
![]() |
1261327fa6 | ||
![]() |
09c3cc58e4 | ||
![]() |
7ef31f84a7 | ||
![]() |
85c2b396ce | ||
![]() |
0759d72108 | ||
![]() |
9b9144f25d | ||
![]() |
b677e891b4 | ||
![]() |
509f62f68d | ||
![]() |
868bf752f3 | ||
![]() |
051cdc9670 | ||
![]() |
4de5c216ff | ||
![]() |
ad2c7304ea | ||
![]() |
4dd1309c3f | ||
![]() |
541da2740d | ||
![]() |
95e2bec215 | ||
![]() |
72c96052b4 | ||
![]() |
2ab168735f | ||
![]() |
85cdf05890 | ||
![]() |
bf78b7f815 | ||
![]() |
ffb9874d84 | ||
![]() |
228cdbe6af | ||
![]() |
a303639c9e | ||
![]() |
c5133f6088 | ||
![]() |
27d368d48d | ||
![]() |
085b599f84 | ||
![]() |
3b84eb3b70 | ||
![]() |
aa877a29d7 | ||
![]() |
0abee77e62 | ||
![]() |
114fcee2ae | ||
![]() |
b488204093 | ||
![]() |
322bfbaf57 | ||
![]() |
2718f4c333 | ||
![]() |
8c342a764b | ||
![]() |
697c3f8cb9 | ||
![]() |
bb292f501d | ||
![]() |
723e54f74e | ||
![]() |
1a8c96a3f0 | ||
![]() |
a88040e4d5 | ||
![]() |
47a0f46ce8 | ||
![]() |
66fb352cca | ||
![]() |
fd77acc217 | ||
![]() |
595d1942cb | ||
![]() |
b905933999 | ||
![]() |
219a756abc | ||
![]() |
2f76f9da89 | ||
![]() |
b0b8f573bc | ||
![]() |
746aa6cc0f | ||
![]() |
fac610d47b | ||
![]() |
93209da176 | ||
![]() |
35a2a48c47 | ||
![]() |
7019f6bea4 | ||
![]() |
8bde47280a | ||
![]() |
521c6da830 | ||
![]() |
5c3e55b5b1 | ||
![]() |
22dcca9832 | ||
![]() |
db6c0d54cf | ||
![]() |
a17abc5557 | ||
![]() |
741c6f1179 | ||
![]() |
43b285ef7a | ||
![]() |
f4bb18b05e | ||
![]() |
14885f25b4 | ||
![]() |
4e16ea0f0a | ||
![]() |
42a696873b | ||
![]() |
cfd51db229 | ||
![]() |
12f11c97ae | ||
![]() |
6a78d11127 | ||
![]() |
256ee7a8c7 | ||
![]() |
07a51957ee | ||
![]() |
37c4470f10 | ||
![]() |
4dc7d1c0cd | ||
![]() |
f6a85f0b0b | ||
![]() |
5b8b660bd0 | ||
![]() |
d9cb85df83 | ||
![]() |
445e82be75 | ||
![]() |
98a12c49dd | ||
![]() |
b78cc7e48a | ||
![]() |
ac9ce0b3ad | ||
![]() |
cf2b814629 | ||
![]() |
bbe7a37359 | ||
![]() |
d0aa154ea6 | ||
![]() |
df4616ae4a | ||
![]() |
10f62db9fd | ||
![]() |
5c075210d6 | ||
![]() |
0cf85b0771 | ||
![]() |
fa90047e52 | ||
![]() |
b9f64fe19b | ||
![]() |
dd072912e8 | ||
![]() |
9dbdc75689 | ||
![]() |
dce211dbba | ||
![]() |
b4e5fa5c1b | ||
![]() |
f12fa7e20a | ||
![]() |
96f8f1da0c | ||
![]() |
db7eec042e | ||
![]() |
52aed3f8a1 | ||
![]() |
cadd186f1b | ||
![]() |
dd9ab16d67 | ||
![]() |
d8b6aff23a | ||
![]() |
b8aac3f8fc | ||
![]() |
4aab97ccb1 | ||
![]() |
4cd21f1e07 | ||
![]() |
403f0f8c64 | ||
![]() |
8c4246f2ad | ||
![]() |
1859ba5ec8 | ||
![]() |
54d5184255 | ||
![]() |
0c5b986fc4 | ||
![]() |
7b2cdd618e | ||
![]() |
30bb3f1fcb | ||
![]() |
b45ea66175 | ||
![]() |
543c5034af | ||
![]() |
c8aa7afdc6 | ||
![]() |
b35bb1b50c | ||
![]() |
6341be9cdf | ||
![]() |
93a14a93f9 | ||
![]() |
d6559e2ac9 | ||
![]() |
65e6755b8b | ||
![]() |
6ead9750f4 | ||
![]() |
6532c7e089 | ||
![]() |
8b3d934230 | ||
![]() |
e2b7c30811 | ||
![]() |
c8bb3c0b71 | ||
![]() |
9990e8473c | ||
![]() |
d765182bbb | ||
![]() |
5a63d1d5a4 | ||
![]() |
6d409d27ca | ||
![]() |
e9c2885f34 | ||
![]() |
ecb8f7362b | ||
![]() |
17ccfec358 | ||
![]() |
a55bb28069 | ||
![]() |
a2e3dc0592 | ||
![]() |
df142d4f61 | ||
![]() |
fac8edd47a | ||
![]() |
9a9da7b077 | ||
![]() |
131441846b | ||
![]() |
3ff728ab02 | ||
![]() |
78bf4ef5fa | ||
![]() |
318d0b3976 | ||
![]() |
90a14e14f4 | ||
![]() |
dea46e8d5a | ||
![]() |
7e5ce623fe | ||
![]() |
e17805f208 | ||
![]() |
d8bcdca55a | ||
![]() |
f6f2a3b366 | ||
![]() |
d52c7e7a1b | ||
![]() |
c4acccac14 | ||
![]() |
13001c018c | ||
![]() |
1b39efb694 | ||
![]() |
0c343cb1c3 | ||
![]() |
aead221184 | ||
![]() |
16d1c9f5d6 | ||
![]() |
0c464b24ad | ||
![]() |
a249a630c0 | ||
![]() |
f39823eac0 | ||
![]() |
69de99636f | ||
![]() |
afcff1fa77 | ||
![]() |
9b5bae049c | ||
![]() |
7a3415166e | ||
![]() |
5b2b4bf13c | ||
![]() |
4bd67bc298 | ||
![]() |
1560749579 | ||
![]() |
ed68fd4ab3 | ||
![]() |
e9a9dabb49 | ||
![]() |
31faafea9d | ||
![]() |
6961bd61ca | ||
![]() |
726fc53e62 | ||
![]() |
c598686bd9 | ||
![]() |
cab87e9398 | ||
![]() |
680037927d | ||
![]() |
ee026386e5 | ||
![]() |
60f72f0ff9 | ||
![]() |
debc855806 | ||
![]() |
49c04ccfc7 | ||
![]() |
11ba44870b | ||
![]() |
f9a64d24bf | ||
![]() |
e1a8dcfcc8 | ||
![]() |
1ee0e29974 | ||
![]() |
10e32454ef | ||
![]() |
8d41e9658f | ||
![]() |
086652dd50 | ||
![]() |
77a9940461 | ||
![]() |
9c1c180ae0 | ||
![]() |
06682bd2a9 | ||
![]() |
6135f0763b | ||
![]() |
307964d874 | ||
![]() |
f3dd50de87 | ||
![]() |
c776bcc5f6 | ||
![]() |
4bbc43d91a | ||
![]() |
db8b5dc698 | ||
![]() |
2f56c61b47 | ||
![]() |
1d340e7664 | ||
![]() |
ea62bc0bb2 | ||
![]() |
8380c3be02 | ||
![]() |
6470bcda19 | ||
![]() |
2d51349d1d | ||
![]() |
2f2b394d72 | ||
![]() |
ba181ae9df | ||
![]() |
f62546ec79 | ||
![]() |
7c251fe190 | ||
![]() |
1c155a0d03 | ||
![]() |
8f196db778 | ||
![]() |
a85455fb3f | ||
![]() |
d0302d1bbe | ||
![]() |
d73267df5e | ||
![]() |
8bbfb5cda1 | ||
![]() |
1e17d5b1cc | ||
![]() |
f881917d2f | ||
![]() |
99244f51b0 | ||
![]() |
606d029ed9 | ||
![]() |
e4b9d679fb | ||
![]() |
2bf2bd8932 | ||
![]() |
4a8a33ea85 | ||
![]() |
ac4b83046a | ||
![]() |
2a2ac35b98 | ||
![]() |
8c744efd56 | ||
![]() |
597e59f10d | ||
![]() |
3cd07d0b54 | ||
![]() |
13259225c2 | ||
![]() |
7acd91331c | ||
![]() |
0fdaca17a2 | ||
![]() |
539c0ed171 | ||
![]() |
553365b942 | ||
![]() |
100308db02 | ||
![]() |
ab967462e6 | ||
![]() |
1bc553ea62 | ||
![]() |
687ea53616 | ||
![]() |
220d9528a3 | ||
![]() |
fc7d3f64c0 | ||
![]() |
63ab7767a3 | ||
![]() |
20894d1c5e | ||
![]() |
2f03d2234a | ||
![]() |
dadf3d846b | ||
![]() |
941a9284b9 | ||
![]() |
4ee3820bd6 | ||
![]() |
c155df5d79 | ||
![]() |
33b70567c8 | ||
![]() |
720bf51ba6 | ||
![]() |
26bdb72428 | ||
![]() |
90c8a1b1cf | ||
![]() |
3143dbf3dc | ||
![]() |
38d587aaeb | ||
![]() |
fe9bafa741 | ||
![]() |
8092e18158 | ||
![]() |
6ed77f2a27 | ||
![]() |
a73688a2be | ||
![]() |
e7d327226a | ||
![]() |
ae1eb9ccde | ||
![]() |
860064c812 | ||
![]() |
845901ab01 | ||
![]() |
25f7360264 | ||
![]() |
78ec7d0fe1 | ||
![]() |
a1e9678b69 | ||
![]() |
be5d629c13 | ||
![]() |
957b399e90 | ||
![]() |
5e6c164b9f | ||
![]() |
5d9a889190 | ||
![]() |
a9acc9c971 | ||
![]() |
308010794a | ||
![]() |
0ce72cbf9d | ||
![]() |
6e52ab285a | ||
![]() |
3da4648112 | ||
![]() |
1897409476 | ||
![]() |
c60d65dd8f | ||
![]() |
f29949e14d | ||
![]() |
75aa98ddaa | ||
![]() |
06909f4f00 | ||
![]() |
aca081557a | ||
![]() |
a71efacd1e | ||
![]() |
871063dab7 | ||
![]() |
135662d6b0 | ||
![]() |
a69c3c1848 | ||
![]() |
50e5244e25 | ||
![]() |
1c07f197de | ||
![]() |
13c32111a0 | ||
![]() |
28c6975732 | ||
![]() |
12091fcfb1 | ||
![]() |
5598826eaf | ||
![]() |
3fea624cca | ||
![]() |
9007dd9ab7 | ||
![]() |
08166cf330 | ||
![]() |
e51b6a6233 | ||
![]() |
3887465d80 | ||
![]() |
d84f96a571 | ||
![]() |
f600e226da | ||
![]() |
d775f13a03 | ||
![]() |
b630afdeda | ||
![]() |
c39c259078 | ||
![]() |
a571c4ba33 | ||
![]() |
889be6e29d | ||
![]() |
d15f64ae5d | ||
![]() |
a07117ea55 | ||
![]() |
d0dae177cf | ||
![]() |
d4db873716 | ||
![]() |
de0752fd56 | ||
![]() |
4204d4928b | ||
![]() |
e2f6cc9c9f | ||
![]() |
05de0ecec3 | ||
![]() |
b05beb000f | ||
![]() |
093abaad29 | ||
![]() |
e84e4169f9 | ||
![]() |
cd6c5cfd4c | ||
![]() |
b855f2fcc2 | ||
![]() |
ba69ade024 | ||
![]() |
8748b2dc3f | ||
![]() |
5f66af3712 | ||
![]() |
31ae50b137 | ||
![]() |
87e0459fcc | ||
![]() |
07e58ae64f | ||
![]() |
a88d18148c | ||
![]() |
1cf43a9dc9 | ||
![]() |
196ce8426b | ||
![]() |
6a95c34a81 | ||
![]() |
ea0e6d9824 | ||
![]() |
14d3da0e18 | ||
![]() |
b6b8fb7d73 | ||
![]() |
2bca3cd247 | ||
![]() |
22a353b8e3 | ||
![]() |
743fa73a01 | ||
![]() |
a546bfe7d9 | ||
![]() |
25deae6cc7 | ||
![]() |
62000670e3 | ||
![]() |
ac49043fbb | ||
![]() |
37a7ca7f14 | ||
![]() |
4d6192adcd | ||
![]() |
9f1ada898e | ||
![]() |
5617521380 | ||
![]() |
9835a2545d | ||
![]() |
c28cefeeb0 | ||
![]() |
afd5b750dc | ||
![]() |
2b97b124bd | ||
![]() |
d042ab87da | ||
![]() |
588303b78d | ||
![]() |
36704c5e18 | ||
![]() |
21d747cd36 | ||
![]() |
ef3494f160 | ||
![]() |
2dc6c4a496 | ||
![]() |
5834843b8a | ||
![]() |
2777a23672 | ||
![]() |
32afd92d30 | ||
![]() |
762f3afb9d | ||
![]() |
7fb2f15a1a | ||
![]() |
7456dccd3a | ||
![]() |
245f41bb7e | ||
![]() |
9bfb844cfa | ||
![]() |
d790d3ba3c | ||
![]() |
c3dbc92766 | ||
![]() |
0bd25f1e17 | ||
![]() |
a4cd7411e8 | ||
![]() |
bf276f6235 | ||
![]() |
d916890a8f | ||
![]() |
071cacc9a4 | ||
![]() |
33f33323af | ||
![]() |
388fae2c47 | ||
![]() |
9f878b77e9 | ||
![]() |
a547d2aaba | ||
![]() |
c013026821 | ||
![]() |
96b48a2404 | ||
![]() |
9612975c2c | ||
![]() |
41bfd45a2e | ||
![]() |
bbdcbd1f08 | ||
![]() |
6b3c525a9d | ||
![]() |
83aed7051c | ||
![]() |
77c6e45e65 | ||
![]() |
8825393660 | ||
![]() |
2b9246c6ad | ||
![]() |
a9edb4de28 | ||
![]() |
a076ddf38c | ||
![]() |
0c809fbb40 | ||
![]() |
cafc266e0b | ||
![]() |
a3d020eff9 | ||
![]() |
8412d94d05 | ||
![]() |
d1c5bb956a | ||
![]() |
70986bc120 | ||
![]() |
f31fe8b865 | ||
![]() |
142a9fe530 | ||
![]() |
4dd2ad9b27 | ||
![]() |
62f7375804 | ||
![]() |
543296b5ba | ||
![]() |
5fee130d00 | ||
![]() |
073facea70 | ||
![]() |
dbe3b6eee4 | ||
![]() |
df97049647 | ||
![]() |
42c5f68362 | ||
![]() |
cc19e760cf | ||
![]() |
0ff22a16fa | ||
![]() |
47360ec906 | ||
![]() |
087a9938d2 | ||
![]() |
26d8e41a6b | ||
![]() |
750ae1d3f3 | ||
![]() |
f8a9a7a108 | ||
![]() |
eb192137d6 | ||
![]() |
c25b464f37 | ||
![]() |
710b48d410 | ||
![]() |
5e77a8199d | ||
![]() |
6637db086b | ||
![]() |
a271a55da7 | ||
![]() |
6eeec6cbfa | ||
![]() |
5e3f3b0400 | ||
![]() |
923c402f69 | ||
![]() |
4fed0b991c | ||
![]() |
ad80acb22a | ||
![]() |
bd8414f8ea | ||
![]() |
2eb467c788 | ||
![]() |
c436e29b89 | ||
![]() |
44219d5e91 | ||
![]() |
b9de3270f6 | ||
![]() |
590d6faeb0 | ||
![]() |
62e96e9a58 | ||
![]() |
1c818ef0a0 | ||
![]() |
d6ce2e3671 | ||
![]() |
85b6a52662 | ||
![]() |
0246082b9b | ||
![]() |
3b031c6ba5 | ||
![]() |
74740ca50b | ||
![]() |
631baa7120 | ||
![]() |
657d6edff7 | ||
![]() |
737c5a9549 | ||
![]() |
c5fb56f90f | ||
![]() |
4cd9abe632 | ||
![]() |
b67e7df38e | ||
![]() |
f28c746b6b | ||
![]() |
ab95027fc6 | ||
![]() |
ed3bc4ab63 | ||
![]() |
68064f1aa6 | ||
![]() |
475ac76a5f | ||
![]() |
79d4f8674c | ||
![]() |
e42eed4d4c | ||
![]() |
4a7042e847 | ||
![]() |
7f36923eb4 | ||
![]() |
2ca8d69126 | ||
![]() |
70367d70c8 | ||
![]() |
e068d62ac6 | ||
![]() |
e6389ff5a1 | ||
![]() |
b46cf57d98 | ||
![]() |
6f59d71e07 | ||
![]() |
f9130f42a2 | ||
![]() |
faf2eeaa99 | ||
![]() |
1c7de0b4ac | ||
![]() |
58487e484f | ||
![]() |
104075f3e0 | ||
![]() |
b8097eaf2e | ||
![]() |
5eb0cbc887 | ||
![]() |
1a4a6f3807 | ||
![]() |
a012b25335 | ||
![]() |
46e8b137e9 | ||
![]() |
4b25c5e8d6 | ||
![]() |
2fdbae3e1f | ||
![]() |
87e06793c2 | ||
![]() |
8cc451a2e2 | ||
![]() |
723c2c7fa9 | ||
![]() |
4dd2c5cdd5 | ||
![]() |
bdc257b40e | ||
![]() |
4728f7c697 | ||
![]() |
1c4c0fe8a1 | ||
![]() |
360274a6e9 | ||
![]() |
07228ff56a | ||
![]() |
a61f153df7 | ||
![]() |
34e91850d9 | ||
![]() |
ba8e579e9b | ||
![]() |
072e39c9cf | ||
![]() |
8dc3f3b21a | ||
![]() |
3a21241248 | ||
![]() |
5c75096bcd | ||
![]() |
a43b0f5253 | ||
![]() |
d93271e86d | ||
![]() |
4a6df9f961 | ||
![]() |
a43ae2369b | ||
![]() |
9a049de859 | ||
![]() |
58b8398aa0 | ||
![]() |
645751f680 | ||
![]() |
2d3b6879f5 | ||
![]() |
26c0924461 | ||
![]() |
d4f801a8e9 | ||
![]() |
cb1082c58c | ||
![]() |
8406864963 | ||
![]() |
85ef034fd0 | ||
![]() |
59141f62bb | ||
![]() |
d68cadba7b | ||
![]() |
1207fd1f16 | ||
![]() |
8aa61e230c | ||
![]() |
2c7bda8a3b | ||
![]() |
d58c5dd398 | ||
![]() |
171da7a347 | ||
![]() |
3fd70a769a | ||
![]() |
4280f84535 | ||
![]() |
c3d9c32615 | ||
![]() |
a938b609b9 | ||
![]() |
d3c7fac606 | ||
![]() |
fea3f6cc72 | ||
![]() |
aee5966e1c | ||
![]() |
95e53ac0a0 | ||
![]() |
5d11759f7d | ||
![]() |
829616534e | ||
![]() |
863f4d8366 | ||
![]() |
bdd0c3686d | ||
![]() |
91769d536d | ||
![]() |
9500343d85 | ||
![]() |
ef053035d0 | ||
![]() |
35faafb32c | ||
![]() |
f9fd868b99 | ||
![]() |
8b903626c2 | ||
![]() |
faf0c950fe | ||
![]() |
4ecd325371 | ||
![]() |
021519f295 | ||
![]() |
e83685d667 | ||
![]() |
81a198a76a | ||
![]() |
5771d67202 | ||
![]() |
b2b7974ba0 | ||
![]() |
f59ca94416 | ||
![]() |
22ff0d80ce | ||
![]() |
5a22a0c27d | ||
![]() |
287ef181ba | ||
![]() |
bc63810ebd | ||
![]() |
92cdea123e | ||
![]() |
e4c7e343c8 | ||
![]() |
6b75be183d | ||
![]() |
718f6d9cef | ||
![]() |
2ee43c403c | ||
![]() |
24fa3f5e7b | ||
![]() |
bbbda7f812 | ||
![]() |
e958900380 | ||
![]() |
74926c1dd3 | ||
![]() |
2654888782 | ||
![]() |
49597b0e9c | ||
![]() |
b5ecfb4c9a | ||
![]() |
07fa3764ef | ||
![]() |
5acc77a163 | ||
![]() |
0709878b4c | ||
![]() |
662e477028 | ||
![]() |
b7b7c381ee | ||
![]() |
995cd95474 | ||
![]() |
fe8a13f76f | ||
![]() |
9252432bc0 | ||
![]() |
f057f6768f | ||
![]() |
806bf0be8d | ||
![]() |
958506a108 | ||
![]() |
e8fd771b91 | ||
![]() |
fa4178fefa | ||
![]() |
1af59d31b9 | ||
![]() |
20758cef30 | ||
![]() |
272938529d | ||
![]() |
a67b7266ed | ||
![]() |
75c8aecffa | ||
![]() |
f26159a0e3 | ||
![]() |
675e8667c2 | ||
![]() |
a1a26b70bc | ||
![]() |
34a7f86a07 | ||
![]() |
e7311ac2f3 | ||
![]() |
8d9ecc0c62 | ||
![]() |
f01b991108 | ||
![]() |
f80736c3d7 | ||
![]() |
2c7f69cf85 | ||
![]() |
348ecc1118 | ||
![]() |
a9678f0ae0 | ||
![]() |
461f298d2c | ||
![]() |
068de7cf40 | ||
![]() |
d04eb87c4f | ||
![]() |
8af68db965 | ||
![]() |
1cf632e98b | ||
![]() |
58c11c3128 | ||
![]() |
efcda95dda | ||
![]() |
80d2028bac | ||
![]() |
215213fc2c | ||
![]() |
99d32dc0b4 | ||
![]() |
0998097253 | ||
![]() |
c17be5af6b | ||
![]() |
b376536a3b | ||
![]() |
e7edc02647 | ||
![]() |
69bf835059 | ||
![]() |
b97ffddfe8 | ||
![]() |
6407b7c591 | ||
![]() |
e14cd92d59 | ||
![]() |
73cadd1798 | ||
![]() |
fb9840f1f8 | ||
![]() |
492aaa3375 | ||
![]() |
33c5da700d | ||
![]() |
48d3af7d9a | ||
![]() |
9b3470eabd | ||
![]() |
86a505b4f3 | ||
![]() |
ed6c6296eb | ||
![]() |
b27a41812f | ||
![]() |
6c933d2b77 | ||
![]() |
fb5610f9bd | ||
![]() |
7adbd00811 | ||
![]() |
1c91d19163 | ||
![]() |
f491135318 | ||
![]() |
a7ced00520 | ||
![]() |
be3359fc67 | ||
![]() |
69ed35ed71 | ||
![]() |
280d35a053 | ||
![]() |
eca6b9f0af | ||
![]() |
aa5d05eaa4 | ||
![]() |
15735552f4 | ||
![]() |
d6d9dc9d95 | ||
![]() |
dc57966dc3 | ||
![]() |
cc9345e703 | ||
![]() |
3fb8f3ec95 | ||
![]() |
04ed50fb0f | ||
![]() |
c9553411bb | ||
![]() |
62221adf55 | ||
![]() |
a6bf4746c6 | ||
![]() |
72637d00e8 | ||
![]() |
27d4b15925 | ||
![]() |
7a77767e66 | ||
![]() |
1b26621860 | ||
![]() |
3db5f4d0aa | ||
![]() |
b2a6e327bf | ||
![]() |
9aec5fe907 | ||
![]() |
fc3e0dfcd1 | ||
![]() |
6513ff92a7 | ||
![]() |
a0eb6d0976 | ||
![]() |
7530770842 | ||
![]() |
11ea72e240 | ||
![]() |
c98330909a | ||
![]() |
bec6fa4ad7 | ||
![]() |
ac7ce73526 | ||
![]() |
4c6619e6c5 | ||
![]() |
e8121fdc11 | ||
![]() |
21f17270a1 | ||
![]() |
423cd5900e | ||
![]() |
b9f535cd49 | ||
![]() |
c731a82b71 | ||
![]() |
e6fad97edc | ||
![]() |
e228144159 | ||
![]() |
9431a7b022 | ||
![]() |
cd041f8574 | ||
![]() |
8ba3378096 | ||
![]() |
225984822d | ||
![]() |
01b68db30e | ||
![]() |
33fdaa5b6d | ||
![]() |
70495aada1 | ||
![]() |
f243f615ef | ||
![]() |
6a1f5667f9 | ||
![]() |
fab5f58ee0 | ||
![]() |
55be8e6f52 | ||
![]() |
c75b9b0d12 | ||
![]() |
9b85446808 | ||
![]() |
fd5d42836f | ||
![]() |
4eaa82fd22 | ||
![]() |
a497cc46f9 | ||
![]() |
178f737971 | ||
![]() |
74963bce9d | ||
![]() |
33a4dbe1e5 | ||
![]() |
60f32d0bce | ||
![]() |
dce36d3e55 | ||
![]() |
807c72b2f1 | ||
![]() |
4f393553f4 | ||
![]() |
91afc7b23c | ||
![]() |
36d158e13e | ||
![]() |
02a97b5985 | ||
![]() |
b980545012 | ||
![]() |
8aad152b23 | ||
![]() |
74dbaade6f | ||
![]() |
2deb5b7fec | ||
![]() |
53677172f2 | ||
![]() |
bef0ccf42a | ||
![]() |
2fd5182608 | ||
![]() |
7ad7caa2ae | ||
![]() |
6d1710c74f | ||
![]() |
233b8d0129 | ||
![]() |
f55bdf07d3 | ||
![]() |
6c2b532ae3 | ||
![]() |
2539f294e4 | ||
![]() |
b6a3ce9305 | ||
![]() |
b07495aae9 | ||
![]() |
686a53215d | ||
![]() |
6190da1300 | ||
![]() |
6fd7d8191e | ||
![]() |
2ccd1cc9f0 | ||
![]() |
8167bdd978 | ||
![]() |
dfb3e34f7b | ||
![]() |
45ee75055e | ||
![]() |
5da4e321c0 | ||
![]() |
e8519fecb4 | ||
![]() |
ff35aa07dc | ||
![]() |
06c172838c | ||
![]() |
1543dd85b5 | ||
![]() |
f37a1026f9 | ||
![]() |
91fb7fa3d8 | ||
![]() |
7b70153068 | ||
![]() |
7e096ee2c5 | ||
![]() |
86a90daf1b | ||
![]() |
42f7df9681 | ||
![]() |
2edad38c7c | ||
![]() |
296ee4961e | ||
![]() |
b1becddf11 | ||
![]() |
667edcd9d0 | ||
![]() |
b4e75bedf0 | ||
![]() |
5482ef5451 | ||
![]() |
a3afd5178c | ||
![]() |
f1285a6dfd | ||
![]() |
cf7c1afb93 | ||
![]() |
f254831aa6 | ||
![]() |
bd40c8649c | ||
![]() |
7c53df2ed1 | ||
![]() |
5ca6026787 | ||
![]() |
483daa5882 | ||
![]() |
e2bc92d128 | ||
![]() |
5ffe3773d4 | ||
![]() |
a7c68018a2 | ||
![]() |
5ffb82993e | ||
![]() |
07add0bd91 | ||
![]() |
9a9b6fa326 | ||
![]() |
ba43ec5759 | ||
![]() |
008a9560fe | ||
![]() |
6ff01cc72c | ||
![]() |
e140a28073 | ||
![]() |
de61c3b962 | ||
![]() |
c46fc4531b | ||
![]() |
065a9ed10f | ||
![]() |
e44c0254f7 | ||
![]() |
13f9f0315f | ||
![]() |
1532ffe215 | ||
![]() |
b24cbc68ba | ||
![]() |
976fdd76c1 | ||
![]() |
bbda335e02 | ||
![]() |
031410c72b | ||
![]() |
710def8e38 | ||
![]() |
c0bda1b103 | ||
![]() |
0e87ce4680 | ||
![]() |
b4d594eeff | ||
![]() |
ce09379bae | ||
![]() |
b27fb64317 | ||
![]() |
099455db25 | ||
![]() |
3146bf51e6 | ||
![]() |
b24a5e0662 | ||
![]() |
e52ac0b187 | ||
![]() |
eaa1590866 | ||
![]() |
071af004bd | ||
![]() |
23ab4e5e5f | ||
![]() |
8e563cbccd | ||
![]() |
1aee89f5ea | ||
![]() |
d2dd6f7c70 | ||
![]() |
e9a544fa98 | ||
![]() |
fb547260d1 | ||
![]() |
2065e32904 | ||
![]() |
ac15581c56 | ||
![]() |
9e2e882157 | ||
![]() |
99ded56047 | ||
![]() |
65386f52f0 | ||
![]() |
5b8dce7456 | ||
![]() |
de938eb621 | ||
![]() |
83cc6c0835 | ||
![]() |
304d78a4c8 | ||
![]() |
347590751c | ||
![]() |
fe4b1f96f1 | ||
![]() |
9de984f7f8 | ||
![]() |
b6cb9b853a | ||
![]() |
50b930f283 | ||
![]() |
cbeb809798 | ||
![]() |
ea626368a0 | ||
![]() |
c81747dd15 | ||
![]() |
f8810d7caf | ||
![]() |
92f54f0b59 | ||
![]() |
ddce544b53 | ||
![]() |
21fb7eea82 | ||
![]() |
fd7eb43366 | ||
![]() |
7d0ca894a4 | ||
![]() |
a1add27c4c | ||
![]() |
fc8194ee1e | ||
![]() |
8ffcdb73e8 | ||
![]() |
111528e51c | ||
![]() |
5628dcf47e | ||
![]() |
fb4f02cd38 | ||
![]() |
d1be643c0d | ||
![]() |
c9761bf6af | ||
![]() |
4a47265224 | ||
![]() |
f0f3017a76 | ||
![]() |
d3f0b62348 | ||
![]() |
6a53fb33da | ||
![]() |
dcaf299864 | ||
![]() |
ab2e00bc38 | ||
![]() |
48d02bef15 | ||
![]() |
1d67aa7bf2 | ||
![]() |
e56066f721 | ||
![]() |
5e3844ac13 | ||
![]() |
cb4f5d454b | ||
![]() |
e5c6fe1bb2 | ||
![]() |
bf65a9732c | ||
![]() |
1388b3219a | ||
![]() |
d9e8ce22cb | ||
![]() |
c85ba73371 | ||
![]() |
224944528f | ||
![]() |
cdcd3e77b3 | ||
![]() |
ed5058a363 | ||
![]() |
a670ff6d3e | ||
![]() |
32f6d34904 | ||
![]() |
d3ae05506d | ||
![]() |
96f4394dce | ||
![]() |
35567e6507 | ||
![]() |
ae37e25452 | ||
![]() |
c4537fe6f6 | ||
![]() |
677334f5a9 | ||
![]() |
3d9652ae35 | ||
![]() |
a9130cb99c | ||
![]() |
b1d60b5c85 | ||
![]() |
99a05c56ad | ||
![]() |
cfc65397b3 | ||
![]() |
cd8fd1ef42 | ||
![]() |
6350089e51 | ||
![]() |
79f2f8cddc | ||
![]() |
39fa949345 | ||
![]() |
e1d7a5cbf5 | ||
![]() |
f3cefaf043 | ||
![]() |
b3460f3f54 | ||
![]() |
8e5a67ed9f | ||
![]() |
cccbcf510a | ||
![]() |
a1e680fec7 | ||
![]() |
1b58bd64ff | ||
![]() |
196de8c758 | ||
![]() |
222b777552 | ||
![]() |
b5c206d3ae | ||
![]() |
17ace95268 | ||
![]() |
779d73f94b | ||
![]() |
73307bf2e7 | ||
![]() |
7623c1c5cb | ||
![]() |
de568c84c2 | ||
![]() |
1f5b9c6185 | ||
![]() |
a5f8fd774d | ||
![]() |
cc5443c38e | ||
![]() |
8a86460b8f | ||
![]() |
7ae9e49f51 | ||
![]() |
c682d087d9 | ||
![]() |
57da5c0841 | ||
![]() |
a224722ae2 | ||
![]() |
283ef5b163 | ||
![]() |
09a188bfd9 | ||
![]() |
10f086854b | ||
![]() |
d67c6c37e3 | ||
![]() |
136725dfb1 | ||
![]() |
438895842c | ||
![]() |
82b8f4f1ce | ||
![]() |
0705f42cf8 | ||
![]() |
cadc67ea40 | ||
![]() |
054e9ecaae | ||
![]() |
84fe3bfa87 | ||
![]() |
2ef8403bfa | ||
![]() |
1d3b2baee7 | ||
![]() |
86de876b24 | ||
![]() |
8a9f04f7fe | ||
![]() |
98bd4dfe04 | ||
![]() |
8e0e4d7c04 | ||
![]() |
a5e8269c72 | ||
![]() |
0acc88cde5 | ||
![]() |
1e0ad1f6bf | ||
![]() |
4abcb08cc9 | ||
![]() |
81e7833711 | ||
![]() |
3392cbbd91 | ||
![]() |
e7b211f2c0 | ||
![]() |
6c5bc9b4a3 | ||
![]() |
cd2f65aafc | ||
![]() |
3ee5093b03 | ||
![]() |
6e2ad6860f | ||
![]() |
8610eb84c6 | ||
![]() |
a2e008347c | ||
![]() |
a1ef0159e3 | ||
![]() |
1c5f76635a | ||
![]() |
e2a0fd7a28 | ||
![]() |
5869a4ba2d | ||
![]() |
ac9a93261b | ||
![]() |
4b79f0047d | ||
![]() |
6a789b660a | ||
![]() |
0d8e44a079 | ||
![]() |
f097952b42 | ||
![]() |
224d511616 | ||
![]() |
050c6cc4b0 | ||
![]() |
bc2d23ff0d | ||
![]() |
2939fadd6a | ||
![]() |
ef260377c3 | ||
![]() |
b9213df64b | ||
![]() |
aa7694047b | ||
![]() |
e2bc63217a | ||
![]() |
6c5b8bcf9d | ||
![]() |
e425fe3f97 | ||
![]() |
6507993972 | ||
![]() |
f081696f62 | ||
![]() |
09157c3130 | ||
![]() |
00626b1633 | ||
![]() |
7e0cdbe502 | ||
![]() |
ca08902d71 | ||
![]() |
fad0e834d5 | ||
![]() |
dc76eb6139 | ||
![]() |
55e113c7a7 | ||
![]() |
b62f5e079e | ||
![]() |
ac1eaff6ec | ||
![]() |
45f6129ae7 | ||
![]() |
f3503e0026 | ||
![]() |
826a654c95 | ||
![]() |
08754e6ce7 | ||
![]() |
3843972b05 | ||
![]() |
37862f0f20 | ||
![]() |
1f184f4aec | ||
![]() |
db5a691693 | ||
![]() |
48693250a4 | ||
![]() |
570dcb6309 | ||
![]() |
19e43087a8 | ||
![]() |
fe0b6a1117 | ||
![]() |
72851647ca | ||
![]() |
1c90400081 | ||
![]() |
672e18cac9 | ||
![]() |
e939d667d9 | ||
![]() |
8bb5a565cd | ||
![]() |
7562c5751c | ||
![]() |
e6e7d6dbd6 | ||
![]() |
fe60c52c70 | ||
![]() |
93f4590453 | ||
![]() |
1098d271b8 | ||
![]() |
51168169e7 | ||
![]() |
d256a0e98f | ||
![]() |
6717325c3f | ||
![]() |
c4a0571e7a | ||
![]() |
e4a06da14e | ||
![]() |
36d6ead65c | ||
![]() |
7eae3bc8c5 | ||
![]() |
24b2198668 | ||
![]() |
d29be0f460 | ||
![]() |
8f93c36466 | ||
![]() |
3092e5a8a5 | ||
![]() |
55f95b3ac9 | ||
![]() |
16218c8680 | ||
![]() |
c11345c4d9 | ||
![]() |
e31f0b8b0c | ||
![]() |
7dd3b72a8c | ||
![]() |
aeccccb33d | ||
![]() |
b46a27c554 | ||
![]() |
13bc15c05d | ||
![]() |
cb1e644230 | ||
![]() |
9bc0fada5c | ||
![]() |
82e261ad33 | ||
![]() |
cae2811762 | ||
![]() |
09112c6869 | ||
![]() |
77aaf1baee | ||
![]() |
6626c2d00d | ||
![]() |
019aea3d63 | ||
![]() |
21439108ed | ||
![]() |
754b30a7a6 | ||
![]() |
89d5d480d7 | ||
![]() |
fbcacb590b | ||
![]() |
f97ad2b2ee | ||
![]() |
e70f7141be | ||
![]() |
7a08ce7ece | ||
![]() |
86486336ec | ||
![]() |
ec2a2522aa | ||
![]() |
556f9ee39c | ||
![]() |
7dad662d69 | ||
![]() |
2daa3eb61f | ||
![]() |
3079aa1f9d | ||
![]() |
28f9a0a900 | ||
![]() |
a6bb3cf60a | ||
![]() |
004da5d385 | ||
![]() |
0368282486 | ||
![]() |
4404f20cf4 | ||
![]() |
faca8bc02a | ||
![]() |
5e93c05095 | ||
![]() |
0f4f04eaa4 | ||
![]() |
2e55d561d3 | ||
![]() |
76a9049739 | ||
![]() |
27bfcda20d | ||
![]() |
c6d1d360a3 | ||
![]() |
afc1236b06 | ||
![]() |
bedd5f00f8 | ||
![]() |
36239895bd | ||
![]() |
738583e3d4 | ||
![]() |
c513478c31 | ||
![]() |
a944927b56 | ||
![]() |
315f9d98f6 | ||
![]() |
f087518e7a | ||
![]() |
b9a8b0d146 | ||
![]() |
4d15db0134 | ||
![]() |
0d1a54262c | ||
![]() |
e7ef7f5159 | ||
![]() |
3dc989bccb | ||
![]() |
75d46efd23 | ||
![]() |
b83392cb04 | ||
![]() |
7640d333f4 | ||
![]() |
c880099deb | ||
![]() |
42f5ecd4a1 | ||
![]() |
733989a284 | ||
![]() |
493f74d94d | ||
![]() |
3b71e2abef | ||
![]() |
30cad0c5f1 | ||
![]() |
3a387643b3 | ||
![]() |
e6b37703da | ||
![]() |
990f473bb3 | ||
![]() |
cf1de78205 | ||
![]() |
ccea6dd74b | ||
![]() |
166b490eed | ||
![]() |
efd871ad2f | ||
![]() |
b78896d64e | ||
![]() |
e753c924ef | ||
![]() |
9dc7b5a6d9 | ||
![]() |
f5d21c9cdb | ||
![]() |
6ce13646da | ||
![]() |
151653dd98 | ||
![]() |
619cfe6a1c | ||
![]() |
8acf996d90 | ||
![]() |
15e432204e | ||
![]() |
4b1630e1ec | ||
![]() |
41e63031b0 | ||
![]() |
bb86f27fdf | ||
![]() |
5cf4f62610 | ||
![]() |
8e10a14866 | ||
![]() |
94f850a588 | ||
![]() |
db9997a106 | ||
![]() |
0cbfb610f2 | ||
![]() |
f901cd042b | ||
![]() |
5719207dfa | ||
![]() |
a84fbbe327 | ||
![]() |
3882c11450 | ||
![]() |
08f77c2b60 | ||
![]() |
6269abbcc8 | ||
![]() |
93c97972b9 | ||
![]() |
ac61d43720 | ||
![]() |
22ebe0e58f | ||
![]() |
1958f78cc1 | ||
![]() |
f072cbbba7 | ||
![]() |
1a5b66b78d | ||
![]() |
bea5973e0c | ||
![]() |
0366dcf604 | ||
![]() |
8211d4a1c2 | ||
![]() |
fc2154ee92 | ||
![]() |
76f85e6f7b | ||
![]() |
81ce684b35 | ||
![]() |
42bd888946 | ||
![]() |
6bea346c41 | ||
![]() |
8d23706354 | ||
![]() |
62bfb1a273 | ||
![]() |
38e86af75c | ||
![]() |
607c2c5ba2 | ||
![]() |
85f58eb082 | ||
![]() |
a7ee64a25b | ||
![]() |
2a58f22649 | ||
![]() |
f066bb7716 | ||
![]() |
4e3d182189 | ||
![]() |
205fba74cf | ||
![]() |
a9bcf8d50d | ||
![]() |
54383b017e | ||
![]() |
438b7b7bd0 | ||
![]() |
27a40a9843 | ||
![]() |
c7b0e9b05b | ||
![]() |
356c829b76 | ||
![]() |
ffbb5c48ed | ||
![]() |
6b6c7b0920 | ||
![]() |
de332a16d1 | ||
![]() |
84ab3ee3af | ||
![]() |
ce0d896492 | ||
![]() |
eae9cb4afe | ||
![]() |
459a812a54 | ||
![]() |
7743647460 | ||
![]() |
352ec364f0 | ||
![]() |
54f684b7b3 | ||
![]() |
1943b158fe | ||
![]() |
a36eeb5261 | ||
![]() |
a8b00faba1 | ||
![]() |
bf73d0f905 | ||
![]() |
193ffa06d9 | ||
![]() |
9d176e35d4 | ||
![]() |
cd2e8c6ef1 | ||
![]() |
8461d71b52 | ||
![]() |
e31cdf0df9 | ||
![]() |
6f41791ea6 | ||
![]() |
0bacbcd04e | ||
![]() |
ffe689363f | ||
![]() |
48d7fedbc0 | ||
![]() |
75dff64450 | ||
![]() |
f0b58c6f24 | ||
![]() |
f3661b19c0 | ||
![]() |
2f5106c97f | ||
![]() |
0c19418e84 | ||
![]() |
60c077c790 | ||
![]() |
7aaa4dda22 | ||
![]() |
109b3700b5 | ||
![]() |
71fecf4d1f | ||
![]() |
0f75c79665 | ||
![]() |
9bcb01a75e | ||
![]() |
4f29034f11 | ||
![]() |
567bf445bf | ||
![]() |
28a0c46ca7 | ||
![]() |
7cc33d0f27 | ||
![]() |
5fba8d773c | ||
![]() |
36cd73df51 | ||
![]() |
6f20889f00 | ||
![]() |
8e408725e9 | ||
![]() |
d053797340 | ||
![]() |
c8d0f947d2 | ||
![]() |
86e036c393 | ||
![]() |
7652a2986b | ||
![]() |
b1480167be | ||
![]() |
e118e958f7 | ||
![]() |
ee61dfe087 | ||
![]() |
9231f420c1 | ||
![]() |
0f92d021a1 | ||
![]() |
cbdc3194cc | ||
![]() |
993df0fd28 | ||
![]() |
4294fdb0b2 | ||
![]() |
082523bcea | ||
![]() |
5d13c13821 | ||
![]() |
21ef656e24 | ||
![]() |
3c4fe8cc04 | ||
![]() |
95ebd57b25 | ||
![]() |
84e09aa8dd | ||
![]() |
6cce3d2996 | ||
![]() |
77b34fa961 | ||
![]() |
024d978ae5 | ||
![]() |
e0f55b9295 | ||
![]() |
ccd83748f7 | ||
![]() |
291ee9f86a | ||
![]() |
59e4d7f0f5 | ||
![]() |
4647448399 | ||
![]() |
7dfe841876 | ||
![]() |
34db35c36d | ||
![]() |
3e9738dc66 | ||
![]() |
2ecf57cdd9 | ||
![]() |
c8b602038e | ||
![]() |
e384fa226e | ||
![]() |
cbb595ba83 | ||
![]() |
fdeec0307e | ||
![]() |
f084bbbf35 | ||
![]() |
20d69b957f | ||
![]() |
7de0a621e3 | ||
![]() |
3441ea9844 | ||
![]() |
83752e9349 | ||
![]() |
8fdfe85b5f | ||
![]() |
d4d9a85ad8 | ||
![]() |
6f22452b54 | ||
![]() |
a4a37d7a19 | ||
![]() |
d1b1a8e490 | ||
![]() |
104fe124df | ||
![]() |
5bdbd74d59 | ||
![]() |
e621c24270 | ||
![]() |
554888318a | ||
![]() |
49aaf98a7f | ||
![]() |
ccdb94b06c | ||
![]() |
6f7bfa71a9 | ||
![]() |
fb3564fbe7 | ||
![]() |
e1e365e16e | ||
![]() |
5b5a18db2a | ||
![]() |
3fa4dad418 | ||
![]() |
0756607e32 | ||
![]() |
a03be5a8a6 | ||
![]() |
39c5bb95d2 | ||
![]() |
4d33b089da | ||
![]() |
58996b841a | ||
![]() |
df03a7b3f8 | ||
![]() |
ac03871174 | ||
![]() |
2a086d20c6 | ||
![]() |
d5cfa6d4dc | ||
![]() |
f415167e59 | ||
![]() |
9477db2363 | ||
![]() |
8d11577ff2 | ||
![]() |
037d1d9ad1 | ||
![]() |
619ef2b341 | ||
![]() |
f06fe76d35 | ||
![]() |
eb86fdfbea | ||
![]() |
c7712e2ef0 | ||
![]() |
61fa770644 | ||
![]() |
334bd73792 | ||
![]() |
090ce262c4 | ||
![]() |
d551d40886 | ||
![]() |
aecfcaa8a2 | ||
![]() |
61a3028788 | ||
![]() |
11d048b8e3 | ||
![]() |
d814a01f2a | ||
![]() |
4c0916df79 | ||
![]() |
e4844b9936 | ||
![]() |
60aa8c527b | ||
![]() |
9f7c3b8ea6 | ||
![]() |
9f4f1bab39 | ||
![]() |
73bd6af0f9 | ||
![]() |
2aa54c5365 | ||
![]() |
bc8542503d | ||
![]() |
a6aea4ba58 | ||
![]() |
0b41faec89 | ||
![]() |
e12bd00b47 | ||
![]() |
50eac9b49e | ||
![]() |
e0405f1781 | ||
![]() |
680d03e4d6 | ||
![]() |
b4fc2e38ab | ||
![]() |
16639f9d71 | ||
![]() |
22f2605e25 | ||
![]() |
69476b4f21 | ||
![]() |
fdf92c5f3b | ||
![]() |
5e22c83baa | ||
![]() |
eed1a3c239 | ||
![]() |
94c037821b | ||
![]() |
e38e8eb636 | ||
![]() |
bef8c83388 | ||
![]() |
2e98324486 | ||
![]() |
6e2d7445c5 | ||
![]() |
90e7ace980 | ||
![]() |
b0ff3bc7a3 | ||
![]() |
06301e279c | ||
![]() |
6d6f274648 | ||
![]() |
9acefcb256 | ||
![]() |
e4d0293a31 | ||
![]() |
ae77542a11 | ||
![]() |
980187f856 | ||
![]() |
2b0a127fa5 | ||
![]() |
327a8e6c59 | ||
![]() |
d11e2724c4 | ||
![]() |
f768ca3a2d | ||
![]() |
947e902288 | ||
![]() |
07c5d3277f | ||
![]() |
d1d44a4fde | ||
![]() |
6837a67234 | ||
![]() |
3436a646b5 | ||
![]() |
aed0af1e00 | ||
![]() |
d6eb74262a | ||
![]() |
403aa8c5a1 | ||
![]() |
0d7ee2b014 | ||
![]() |
2f5fd91bd8 | ||
![]() |
cd1148c6aa | ||
![]() |
cfd26f53f0 | ||
![]() |
69ad5671ed | ||
![]() |
f9e0f0d257 | ||
![]() |
98f3135ad3 | ||
![]() |
8c9c3a91e6 | ||
![]() |
7f3518333d | ||
![]() |
f1f871f103 | ||
![]() |
6387b52896 | ||
![]() |
077e95da85 | ||
![]() |
7f6e1fbc8d | ||
![]() |
06827cfcf1 | ||
![]() |
6dc3097998 | ||
![]() |
cd35271698 | ||
![]() |
7b575f61d0 | ||
![]() |
400e3ea649 | ||
![]() |
622d871587 | ||
![]() |
63d04645c7 | ||
![]() |
3f4908c363 | ||
![]() |
dd0f1d9d2d | ||
![]() |
b31d171ae8 | ||
![]() |
085f06594c | ||
![]() |
ce3d41052c | ||
![]() |
44f3df697f | ||
![]() |
28c75b2283 | ||
![]() |
b6e56119c4 | ||
![]() |
a0e29b5435 | ||
![]() |
65ff72cdf8 | ||
![]() |
1da0956331 | ||
![]() |
983078992d | ||
![]() |
81059f80d8 | ||
![]() |
a261442279 | ||
![]() |
2f41eba100 | ||
![]() |
91a6fb81c1 | ||
![]() |
c95f0820bc | ||
![]() |
830a1bd130 | ||
![]() |
5c5ea8a254 | ||
![]() |
5222c684d3 | ||
![]() |
5798faa13b | ||
![]() |
a062693875 | ||
![]() |
6887d5d347 | ||
![]() |
39c9669445 | ||
![]() |
44565e22a0 | ||
![]() |
ddec10d494 | ||
![]() |
758e969cb6 | ||
![]() |
a9a6a5041b | ||
![]() |
59dd8ffbc6 | ||
![]() |
8f9fe1b11a | ||
![]() |
9ed0152cf2 | ||
![]() |
250332a8d5 | ||
![]() |
39825c6622 | ||
![]() |
cee3070ca4 | ||
![]() |
cd08e5c7da | ||
![]() |
dd4beea44c | ||
![]() |
5b48d59769 | ||
![]() |
4dec12fcfc | ||
![]() |
57ad3aca8e | ||
![]() |
f677f42be7 | ||
![]() |
a5760670ef | ||
![]() |
f04a3ec201 | ||
![]() |
f402c5fe3c | ||
![]() |
9352e25392 | ||
![]() |
1c90b0c19d | ||
![]() |
cd776ff1a8 | ||
![]() |
40a587bbaf | ||
![]() |
818d729d8b | ||
![]() |
dd5daa0767 | ||
![]() |
ef5090c397 | ||
![]() |
cf073de36c | ||
![]() |
f16054639b | ||
![]() |
b0983e8708 | ||
![]() |
0febb218ed | ||
![]() |
dfcfeeb550 | ||
![]() |
820debf45a | ||
![]() |
c19292c036 | ||
![]() |
4ee81e6a3d | ||
![]() |
87a8a3e22f | ||
![]() |
e9125ef8e4 | ||
![]() |
6ff394bcc9 | ||
![]() |
7ce96585f5 | ||
![]() |
41cc31c124 | ||
![]() |
605af61a0f | ||
![]() |
77e163e5b8 | ||
![]() |
0e00b9009d | ||
![]() |
a6dd998d31 | ||
![]() |
cdd0ccc67a | ||
![]() |
a918821868 | ||
![]() |
c637b96f10 | ||
![]() |
44b9197354 | ||
![]() |
7a8f96b1dd | ||
![]() |
f4f21f462d | ||
![]() |
d09b8b5bd7 | ||
![]() |
ee327db517 | ||
![]() |
90a61b6bab | ||
![]() |
00583bc4a8 | ||
![]() |
2d06a8e880 | ||
![]() |
e1a434edbc | ||
![]() |
6b3b1cbd99 | ||
![]() |
4dd861ee23 | ||
![]() |
4f0f81a047 | ||
![]() |
e3908c8de6 | ||
![]() |
81c49fba03 | ||
![]() |
eb174d5ba3 | ||
![]() |
4c899e9c5a | ||
![]() |
00b0f6ad51 | ||
![]() |
fe1e467a49 | ||
![]() |
73cb538d72 | ||
![]() |
64b9e7fd48 | ||
![]() |
12de22d3bb | ||
![]() |
821bc6d777 | ||
![]() |
6e66a5b77b | ||
![]() |
cf5c10bbe6 | ||
![]() |
4e30e74739 | ||
![]() |
42890b9acf | ||
![]() |
33a27379f9 | ||
![]() |
0cf57cc7ca | ||
![]() |
68fcbaf4c8 | ||
![]() |
9c83d3c78c | ||
![]() |
676dfabc91 | ||
![]() |
60e6d1d61b | ||
![]() |
975e275030 | ||
![]() |
afcd5670e3 | ||
![]() |
b17b53955c | ||
![]() |
ff2b427cc1 | ||
![]() |
5761800197 | ||
![]() |
0eebacc521 | ||
![]() |
4a5528697d | ||
![]() |
d38034bb5c | ||
![]() |
a62fe30546 | ||
![]() |
b3fe3e8b3d | ||
![]() |
25ebb427da | ||
![]() |
c5bde10b4f | ||
![]() |
e582e893cc | ||
![]() |
833ec3d3cd | ||
![]() |
3d446d3266 | ||
![]() |
e660229c40 | ||
![]() |
5489dec28d | ||
![]() |
ee6e0e16cb | ||
![]() |
eb1733609a | ||
![]() |
8a6b4db19f | ||
![]() |
df43b6a05c | ||
![]() |
e2e66404d5 | ||
![]() |
3ecb19d0f1 | ||
![]() |
fd02c87fa2 | ||
![]() |
63ac81c8f5 | ||
![]() |
557bee61d5 | ||
![]() |
3adca3c2fa | ||
![]() |
39abd3ecb4 | ||
![]() |
a4f4fc50b9 | ||
![]() |
7bf638b0de | ||
![]() |
56662a703c | ||
![]() |
8b5f47d3a3 | ||
![]() |
8bfb88840b | ||
![]() |
593bb5a8a7 | ||
![]() |
822ac7b100 | ||
![]() |
cc70c5c67d | ||
![]() |
ae7e1a22cb | ||
![]() |
a289dcb9ee | ||
![]() |
023b9c1e7e | ||
![]() |
4c61662644 | ||
![]() |
ad1b6ef0ac | ||
![]() |
16944b5397 | ||
![]() |
ed5c6be2f1 | ||
![]() |
30cb082932 | ||
![]() |
645554d12f | ||
![]() |
72e44d596f | ||
![]() |
8f2ca8f085 | ||
![]() |
6725c2afa1 | ||
![]() |
e9d4b73cc3 | ||
![]() |
212b0faf0c | ||
![]() |
929ec70512 | ||
![]() |
6cd5d73607 | ||
![]() |
80a7e1ea7d | ||
![]() |
0d3b26b3aa | ||
![]() |
52acea7b1f | ||
![]() |
e9b49a43e2 | ||
![]() |
4fa5538e2b | ||
![]() |
84e74173de | ||
![]() |
6cdb2a4896 | ||
![]() |
d8bef3270d | ||
![]() |
a33db8fe6f | ||
![]() |
1c3f5517fa | ||
![]() |
10972da060 | ||
![]() |
a38f02541d | ||
![]() |
fdba76ba47 | ||
![]() |
f900ab0121 | ||
![]() |
f80ab6a7a2 | ||
![]() |
6ed209bbf3 | ||
![]() |
fe85fa3bea | ||
![]() |
76b7882f33 | ||
![]() |
bf0ab2d44c | ||
![]() |
276a0d9500 | ||
![]() |
bcbfa560e9 | ||
![]() |
8b366f0795 | ||
![]() |
aa08f9692c | ||
![]() |
288ba84939 | ||
![]() |
4c74016b1a | ||
![]() |
384b6c8288 | ||
![]() |
a2af158fd3 | ||
![]() |
1d8544ef3b | ||
![]() |
91a12f76cd | ||
![]() |
f4627acc48 | ||
![]() |
2b1194d574 | ||
![]() |
f33d2fb2e7 | ||
![]() |
a9eec35aff | ||
![]() |
8534f2d1e2 | ||
![]() |
e8debd2e45 | ||
![]() |
1caa41a623 | ||
![]() |
bf59635280 | ||
![]() |
5d6f75aaef | ||
![]() |
eaf0662b75 | ||
![]() |
6e8ea2a2cb | ||
![]() |
b043b2a761 | ||
![]() |
ac7e0dfb77 | ||
![]() |
05d47bb09a | ||
![]() |
575a5bd0b8 | ||
![]() |
00740fb23b | ||
![]() |
ae4c189e19 | ||
![]() |
362a6e6d46 | ||
![]() |
c76c7c68ff | ||
![]() |
59ac9d39d5 | ||
![]() |
ec41caade4 | ||
![]() |
06ec06cdd7 | ||
![]() |
b7acf86408 | ||
![]() |
58c4db925b | ||
![]() |
fe0c4ff3c2 | ||
![]() |
7a2af0fbf4 | ||
![]() |
d83127722f | ||
![]() |
dc03ad05be | ||
![]() |
a62df3cb8f | ||
![]() |
18e32abda9 | ||
![]() |
15d29da43b | ||
![]() |
8b217d5313 | ||
![]() |
ac62586bad | ||
![]() |
c150fd9a1c | ||
![]() |
674d14879f | ||
![]() |
37e9010887 | ||
![]() |
4bd2c75056 | ||
![]() |
b9ed850b98 | ||
![]() |
11cea17496 | ||
![]() |
81df45a893 | ||
![]() |
c1f0708a5d | ||
![]() |
153f5854e2 | ||
![]() |
f532964fde | ||
![]() |
efea609dc3 | ||
![]() |
f3a160038d | ||
![]() |
f016eef48a | ||
![]() |
f649514183 | ||
![]() |
afd31677dd | ||
![]() |
b28710b08c | ||
![]() |
712ed555e6 | ||
![]() |
11fb5bc3d0 | ||
![]() |
2a5feb225b | ||
![]() |
970e338847 | ||
![]() |
0b9f650fe2 | ||
![]() |
977834179a | ||
![]() |
b42732743d | ||
![]() |
99e6409a67 | ||
![]() |
6a0a5f9693 | ||
![]() |
fe9db8b369 | ||
![]() |
ca035d0e8d | ||
![]() |
84c9260dc4 | ||
![]() |
987c02e946 | ||
![]() |
5c0bc612fe | ||
![]() |
0e28b53242 | ||
![]() |
5fc0ce80fc | ||
![]() |
af9092df39 | ||
![]() |
58a5da33c2 | ||
![]() |
7077eac589 | ||
![]() |
b3435ae432 | ||
![]() |
a31129333c | ||
![]() |
2983c2a24f | ||
![]() |
412bedb697 | ||
![]() |
163597ef69 | ||
![]() |
95f84afd33 | ||
![]() |
9f7fd1fbfb | ||
![]() |
940cab8620 | ||
![]() |
d37811f177 | ||
![]() |
5b84c99d79 | ||
![]() |
b295024574 | ||
![]() |
34180f1745 | ||
![]() |
665031467a | ||
![]() |
df33171107 | ||
![]() |
53f4044890 | ||
![]() |
a5049136ff | ||
![]() |
705b3c6b63 | ||
![]() |
6b4ac66962 | ||
![]() |
0964b06240 | ||
![]() |
92eeca3ba7 | ||
![]() |
2a86554ac4 | ||
![]() |
805caa30ce | ||
![]() |
d4ca853fd3 | ||
![]() |
5a8d2e8057 | ||
![]() |
687fc358fd | ||
![]() |
c4c2da06b7 | ||
![]() |
8928cd53bf | ||
![]() |
ca88fc4ed3 | ||
![]() |
b83a1d79b7 | ||
![]() |
cec2a837cf | ||
![]() |
cff47262da | ||
![]() |
da83eae754 | ||
![]() |
c5409d52f5 | ||
![]() |
54fc8f0e8c | ||
![]() |
2ea633a2f7 | ||
![]() |
9a52043fad | ||
![]() |
39a5be2df9 | ||
![]() |
96560e317a | ||
![]() |
adb27903eb | ||
![]() |
51150faa39 | ||
![]() |
a56949e9fa | ||
![]() |
ea96919b80 | ||
![]() |
43da4c0eca | ||
![]() |
5835afb849 | ||
![]() |
b9c7771830 | ||
![]() |
35db88affe | ||
![]() |
e38faca455 | ||
![]() |
0255e8710c | ||
![]() |
7f3fecbdf5 | ||
![]() |
a2c6d5e148 | ||
![]() |
373706c92b | ||
![]() |
7afe63aa06 | ||
![]() |
8fab855099 | ||
![]() |
062fef36f9 | ||
![]() |
fefe2df3ee | ||
![]() |
90b91ead72 | ||
![]() |
1e98e41381 | ||
![]() |
7030e8f050 | ||
![]() |
74bb514a8c | ||
![]() |
46914e486c | ||
![]() |
f9abc561fb | ||
![]() |
2e22ff2e36 | ||
![]() |
8c3be4a5f0 | ||
![]() |
3fe2f7337c | ||
![]() |
ec24eb1d8e | ||
![]() |
ffcaf85609 | ||
![]() |
d0c481e44e | ||
![]() |
67e2d9f9e1 | ||
![]() |
dd5aa2b483 | ||
![]() |
806494a254 | ||
![]() |
5c3afd020a | ||
![]() |
190cdfc326 | ||
![]() |
13b954c765 | ||
![]() |
49f6b50ed3 | ||
![]() |
0f2a304d34 | ||
![]() |
a142f93dca | ||
![]() |
2dfe2fb22c | ||
![]() |
e8564b4c90 | ||
![]() |
2fd81b4932 | ||
![]() |
0cf4c6ffea | ||
![]() |
25f89afbfb | ||
![]() |
43f3cdcd24 | ||
![]() |
3454fed324 | ||
![]() |
a64ffda688 | ||
![]() |
8400da9934 | ||
![]() |
6d89020f80 | ||
![]() |
9c56c49e73 | ||
![]() |
acb798e544 | ||
![]() |
c5720a15c7 | ||
![]() |
90709b332a | ||
![]() |
81f17d10c8 | ||
![]() |
773de38bd9 | ||
![]() |
ae8bdd473c | ||
![]() |
adfc5db3d2 | ||
![]() |
a48704925d | ||
![]() |
fa4beeee75 | ||
![]() |
d8351772d3 | ||
![]() |
68d1abdb85 | ||
![]() |
7e8474a85a | ||
![]() |
82da364b8b | ||
![]() |
7fa91ec175 | ||
![]() |
1d3a09d377 | ||
![]() |
02563a35f0 | ||
![]() |
d653f35bb7 | ||
![]() |
a543627abd | ||
![]() |
80f2ba7fca | ||
![]() |
32bca64920 | ||
![]() |
7fa1a84ec3 | ||
![]() |
ab4bb26a0a | ||
![]() |
4b8d258cff | ||
![]() |
3c29aa6271 | ||
![]() |
51464b4317 | ||
![]() |
3f32a6b607 | ||
![]() |
21aa1631a4 | ||
![]() |
49968541fd | ||
![]() |
cc143105b8 | ||
![]() |
fed44e95b3 | ||
![]() |
71ece56470 | ||
![]() |
204a1de3fd | ||
![]() |
80ddf4aecf | ||
![]() |
12b4a666bc | ||
![]() |
cfdbaf331e | ||
![]() |
052d350b19 | ||
![]() |
2ca18a7ee5 | ||
![]() |
7dbe5f4640 | ||
![]() |
432ecd1b6a | ||
![]() |
7d9aa5b716 | ||
![]() |
43267dc892 | ||
![]() |
3ec6c26e6c | ||
![]() |
7de684668b | ||
![]() |
2fec463542 | ||
![]() |
1affc641c4 | ||
![]() |
4741d7bfe2 | ||
![]() |
aea99a1222 | ||
![]() |
7c8038e2da | ||
![]() |
673336297d | ||
![]() |
ee4b7042ce | ||
![]() |
310ab7d41b | ||
![]() |
fc1796f3e8 | ||
![]() |
d8926ea5eb | ||
![]() |
0c1e428c7d | ||
![]() |
bcd97f5887 | ||
![]() |
0faf86c2b9 | ||
![]() |
b30957c89c | ||
![]() |
dbbcbc3616 | ||
![]() |
1889150013 | ||
![]() |
14f9cdde6b | ||
![]() |
3ab0691eec | ||
![]() |
1e073a196f | ||
![]() |
7b60e3916c | ||
![]() |
c486c5bf5b | ||
![]() |
fc0b6d143a | ||
![]() |
5f4252bcd2 | ||
![]() |
a588aef921 | ||
![]() |
b70df57f7b | ||
![]() |
e813c93e08 | ||
![]() |
900c4977cc | ||
![]() |
bb39fffab9 | ||
![]() |
f52aefb341 | ||
![]() |
aecb5630cb | ||
![]() |
0f0245625a | ||
![]() |
8583689fa4 | ||
![]() |
7a1e026bb5 | ||
![]() |
64f04ee6db | ||
![]() |
5c6f538b85 | ||
![]() |
00aa83a498 | ||
![]() |
e44848f8c4 | ||
![]() |
5ea8950a13 | ||
![]() |
184557bfed | ||
![]() |
b4253210d2 | ||
![]() |
8e1585aa8a | ||
![]() |
dee49d7488 | ||
![]() |
1ecde309e4 | ||
![]() |
d62a738460 | ||
![]() |
0cfd4fff62 | ||
![]() |
8904127c10 | ||
![]() |
0f1b1bb44d | ||
![]() |
16f870aa41 | ||
![]() |
16f729eb22 | ||
![]() |
36f0bd432c | ||
![]() |
457ab8b2ce | ||
![]() |
1ebf5f3bcb | ||
![]() |
a928a9640f | ||
![]() |
cb302476b4 | ||
![]() |
31726737df | ||
![]() |
082be33cbd | ||
![]() |
9aada2ef19 | ||
![]() |
4066b2767b | ||
![]() |
de43bddc1a | ||
![]() |
c46f48abec | ||
![]() |
4acbf7b90d | ||
![]() |
cbc1a58e93 | ||
![]() |
1b5f33a435 | ||
![]() |
41b4a63f2b | ||
![]() |
d8fc2db910 | ||
![]() |
dc11dea7cc | ||
![]() |
6edfc56c9d | ||
![]() |
5837a63942 | ||
![]() |
3a28f456b1 | ||
![]() |
4f6fc2675c | ||
![]() |
c7da1821c3 | ||
![]() |
1a8c3271da | ||
![]() |
bd49e8e76f | ||
![]() |
533699abe7 | ||
![]() |
267ccc98d3 | ||
![]() |
cd3c2fdb49 | ||
![]() |
5cbc319e96 | ||
![]() |
d435dcdca4 | ||
![]() |
e5ab456df3 | ||
![]() |
08bf4f74a9 | ||
![]() |
a838a03412 | ||
![]() |
ad4e597f74 | ||
![]() |
ee3610a2d2 | ||
![]() |
88b75b57d0 | ||
![]() |
aa4c7055f8 | ||
![]() |
4b70f9d213 | ||
![]() |
79d2d1c201 | ||
![]() |
406bda9b95 | ||
![]() |
405f1dd027 | ||
![]() |
51f349d504 | ||
![]() |
4f201d1e85 | ||
![]() |
03cfef100f | ||
![]() |
ff89b491dd | ||
![]() |
7552dff0e5 | ||
![]() |
110589c0f3 | ||
![]() |
3400398230 | ||
![]() |
5c244e9a8c | ||
![]() |
4e2f4e2091 | ||
![]() |
e69bef3ce3 | ||
![]() |
c1c0fc79bc | ||
![]() |
02a77f6797 | ||
![]() |
77b316cdfb | ||
![]() |
2abfc7b87b | ||
![]() |
050f0c3d8f | ||
![]() |
90e6c727da | ||
![]() |
d3d9a04e62 | ||
![]() |
a66051216f | ||
![]() |
0debba0f6e | ||
![]() |
f2bd2c318c | ||
![]() |
21c42819c7 | ||
![]() |
5899a272ef | ||
![]() |
27b4c62bc1 | ||
![]() |
b227fddec7 | ||
![]() |
2c1f1de33c | ||
![]() |
c26622cf8f | ||
![]() |
9e91873428 | ||
![]() |
7363d50a1e | ||
![]() |
15213a041d | ||
![]() |
fb70a34c80 | ||
![]() |
fbf76c6d21 | ||
![]() |
811af02f56 | ||
![]() |
bc00c38f9d | ||
![]() |
4658bd8208 | ||
![]() |
6eb1caa417 | ||
![]() |
41efc1376e | ||
![]() |
0f35016773 | ||
![]() |
c641ca90a9 | ||
![]() |
87c88fcb27 | ||
![]() |
4f80a129f1 | ||
![]() |
6987f2ba82 | ||
![]() |
563db580ae | ||
![]() |
125daea16a | ||
![]() |
fd2c6b8a4b | ||
![]() |
5b1db917bc | ||
![]() |
8780e23ed3 | ||
![]() |
be492ed108 | ||
![]() |
24da14f4f7 | ||
![]() |
03d2fb450f | ||
![]() |
849b0563ce | ||
![]() |
16a99ad515 | ||
![]() |
d93172bee8 | ||
![]() |
25429af122 | ||
![]() |
4bfd104a23 | ||
![]() |
7745067d99 | ||
![]() |
b19d3629b9 | ||
![]() |
84c519df09 | ||
![]() |
737a56a030 | ||
![]() |
12b6959ea2 | ||
![]() |
7519768cb1 | ||
![]() |
9af470c92d | ||
![]() |
ac8c1d0a01 | ||
![]() |
921d01b59d | ||
![]() |
8aa4a66ba0 | ||
![]() |
2e7153d8d6 | ||
![]() |
70b5a81a29 | ||
![]() |
83fd822e8b | ||
![]() |
dd3752956a | ||
![]() |
bf15cac980 | ||
![]() |
1a61b01315 | ||
![]() |
c643b6ff16 | ||
![]() |
b3f5b4932c | ||
![]() |
b3f5f2f75f | ||
![]() |
62288907dd | ||
![]() |
cdbdcec715 | ||
![]() |
ccf78448aa | ||
![]() |
ed001e0cfb | ||
![]() |
26382713c2 | ||
![]() |
f37481f843 | ||
![]() |
c3f6502be2 | ||
![]() |
0120f396ac | ||
![]() |
231fffe594 | ||
![]() |
e67afc35b8 | ||
![]() |
5e73007b1d | ||
![]() |
2d9876a261 | ||
![]() |
303d67aed2 | ||
![]() |
575fbad254 | ||
![]() |
fa0aa91bf9 | ||
![]() |
3e641e2147 | ||
![]() |
de7e4f0db7 | ||
![]() |
a1cb1d78bd | ||
![]() |
1178f2c1ab | ||
![]() |
76f277eeb4 | ||
![]() |
4000390dcd |
7
.gitignore
vendored
7
.gitignore
vendored
@@ -35,7 +35,8 @@ tags
|
||||
/mkinstalldirs
|
||||
/build
|
||||
/src/mpd
|
||||
/systemd/mpd.service
|
||||
/systemd/system/mpd.service
|
||||
/systemd/user/mpd.service
|
||||
/stamp-h1
|
||||
|
||||
/src/dsd2pcm/dsd2pcm
|
||||
@@ -77,7 +78,11 @@ tags
|
||||
/test/test_vorbis_encoder
|
||||
/test/DumpDatabase
|
||||
|
||||
/lib/
|
||||
|
||||
/*.tar.gz
|
||||
/*.tar.bz2
|
||||
/*.tar.xz
|
||||
/mpd-*/
|
||||
|
||||
__pycache__/
|
||||
|
3
AUTHORS
3
AUTHORS
@@ -1,5 +1,5 @@
|
||||
Music Player Daemon - http://www.musicpd.org
|
||||
Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
Copyright 2003-2017 The Music Player Daemon Project
|
||||
|
||||
The following people have contributed code to MPD:
|
||||
|
||||
@@ -29,3 +29,4 @@ The following people have contributed code to MPD:
|
||||
Denis Krjuchkov <denis@crazydev.net>
|
||||
Jurgen Kramer <gtmkramer@xs4all.nl>
|
||||
Jean-Francois Dockes <jf@dockes.org>
|
||||
Yue Wang <yuleopen@gmail.com>
|
||||
|
8
INSTALL
8
INSTALL
@@ -12,15 +12,12 @@ install MPD. If more information is desired, read the user manual:
|
||||
Dependencies
|
||||
------------
|
||||
|
||||
gcc 4.6 or later - http://gcc.gnu.org/
|
||||
gcc 4.7 or later - http://gcc.gnu.org/
|
||||
clang 3.2 or later - http://clang.llvm.org/
|
||||
Any other C++11 compliant compiler should also work.
|
||||
|
||||
Boost 1.46 - http://www.boost.org/
|
||||
|
||||
GLib 2.28 - http://www.gtk.org/
|
||||
General-purpose utility library.
|
||||
|
||||
|
||||
Optional Output Dependencies
|
||||
----------------------------
|
||||
@@ -116,9 +113,6 @@ For WavPack playback.
|
||||
libadplug - http://adplug.sourceforge.net/
|
||||
For AdLib playback.
|
||||
|
||||
despotify - https://github.com/SimonKagstrom/despotify
|
||||
For Spotify playback.
|
||||
|
||||
|
||||
Optional Miscellaneous Dependencies
|
||||
-----------------------------------
|
||||
|
756
Makefile.am
756
Makefile.am
File diff suppressed because it is too large
Load Diff
275
NEWS
275
NEWS
@@ -1,3 +1,259 @@
|
||||
ver 0.20.2 (2017/01/15)
|
||||
* input
|
||||
- alsa: fix crash bug
|
||||
- alsa: fix buffer overruns
|
||||
* decoder
|
||||
- flac: add options "probesize" and "analyzeduration"
|
||||
* resampler
|
||||
- libsamplerate: reset state after seeking
|
||||
* output
|
||||
- fix static noise after changing to a different audio format
|
||||
- alsa: fix the DSD_U32 sample rate
|
||||
- alsa: fix the DSD_U32 byte order
|
||||
- alsa: support DSD_U16
|
||||
- recorder: fix error "Failed to create : No such file or directory"
|
||||
* playlist
|
||||
- cue: fix skipping songs
|
||||
|
||||
ver 0.20.1 (2017/01/09)
|
||||
* input
|
||||
- curl: fix crash bug
|
||||
- curl: fix freeze bug
|
||||
* decoder
|
||||
- wavpack: fix crash bug
|
||||
* storage
|
||||
- curl: new storage plugin for WebDAV (work in progress)
|
||||
* mixer
|
||||
- alsa: normalize displayed volume according to human perception
|
||||
* fix crash with volume_normalization enabled
|
||||
|
||||
ver 0.20 (2017/01/04)
|
||||
* protocol
|
||||
- "commands" returns playlist commands only if playlist_directory configured
|
||||
- "search"/"find" have a "window" parameter
|
||||
- report song duration with milliseconds precision
|
||||
- "sticker find" can match sticker values
|
||||
- drop the "file:///" prefix for absolute file paths
|
||||
- add range parameter to command "plchanges" and "plchangesposid"
|
||||
- send verbose error message to client
|
||||
* input
|
||||
- curl: fix memory leak
|
||||
* tags
|
||||
- ape, ogg: drop support for non-standard tag "album artist"
|
||||
affected filetypes: vorbis, flac, opus & all files with ape2 tags
|
||||
(most importantly some mp3s)
|
||||
- id3: remove the "id3v1_encoding" setting; by definition, all ID3v1 tags
|
||||
are ISO-Latin-1
|
||||
- ape: support APE replay gain on remote files
|
||||
- read ID3 tags from NFS/SMB
|
||||
* decoder
|
||||
- improved error logging
|
||||
- report I/O errors to clients
|
||||
- ffmpeg: support ReplayGain and MixRamp
|
||||
- ffmpeg: support stream tags
|
||||
- gme: add option "accuracy"
|
||||
- gme: provide the TRACK tag
|
||||
- gme: faster scanning
|
||||
- mad: reduce memory usage while scanning tags
|
||||
- mpcdec: read the bit rate
|
||||
- pcm: support audio/L16 (RFC 2586) and audio/x-mpd-float
|
||||
- sidplay: faster scanning
|
||||
- wavpack: large file support
|
||||
- wavpack: support DSD (WavPack 5)
|
||||
- wavpack: archive support
|
||||
* playlist
|
||||
- cue: don't skip pregap
|
||||
- embcue: fix last track
|
||||
- flac: new plugin which reads the "CUESHEET" metadata block
|
||||
* output
|
||||
- alsa: fix multi-channel order
|
||||
- alsa: remove option "use_mmap"
|
||||
- alsa: support DSD_U32
|
||||
- alsa: disable DoP if it fails
|
||||
- jack: reduce CPU usage
|
||||
- pulse: set channel map to WAVE-EX
|
||||
- recorder: record tags
|
||||
- recorder: allow dynamic file names
|
||||
- sndio: new output plugin
|
||||
* mixer
|
||||
- null: new plugin
|
||||
* resampler
|
||||
- new block "resampler" in configuration file
|
||||
replacing the old "samplerate_converter" setting
|
||||
- soxr: allow multi-threaded resampling
|
||||
* player
|
||||
- reset song priority on playback
|
||||
- reduce xruns
|
||||
* write database and state file atomically
|
||||
* always write UTF-8 to the log file.
|
||||
* remove dependency on GLib
|
||||
* support libsystemd (instead of the older libsystemd-daemon)
|
||||
* database
|
||||
- proxy: add TCP keepalive option
|
||||
* update
|
||||
- apply .mpdignore matches to subdirectories
|
||||
* switch the code base to C++14
|
||||
- GCC 4.9 or clang 3.4 (or newer) recommended
|
||||
|
||||
ver 0.19.21 (2016/12/13)
|
||||
* decoder
|
||||
- ffmpeg: fix crash bug
|
||||
* fix unit test failure after recent "setprio" change
|
||||
* systemd: add user unit
|
||||
|
||||
ver 0.19.20 (2016/12/09)
|
||||
* protocol
|
||||
- "setprio" re-enqueues old song if priority has been raised
|
||||
* decoder
|
||||
- ffmpeg: ignore empty packets
|
||||
- pcm: fix corruption bug with partial frames (after short read)
|
||||
- sidplay: fix playback speed with libsidplayfp
|
||||
* output
|
||||
- winmm: fix 8 bit playback
|
||||
* fix gcc 7.0 -Wimplicit-fallthrough
|
||||
* systemd: paranoid security settings
|
||||
|
||||
ver 0.19.19 (2016/08/23)
|
||||
* decoder
|
||||
- ffmpeg: bug fix for FFmpeg 3.1 support
|
||||
- wildmidi: support libWildMidi 0.4
|
||||
* output
|
||||
- pulse: support 32 bit, 24 bit and floating point playback
|
||||
* support non-x86 NetBSD
|
||||
* fix clang 3.9 warnings
|
||||
|
||||
ver 0.19.18 (2016/08/05)
|
||||
* decoder
|
||||
- ffmpeg: fix crash with older FFmpeg versions (< 3.0)
|
||||
- ffmpeg: log detailed error message
|
||||
- ffmpeg: support FFmpeg 3.1
|
||||
- sidplay: detect libsidplay2 with pkg-config
|
||||
- sidplay: log detailed error message
|
||||
- sidplay: read the "date" tag
|
||||
- sidplay: allow building with libsidplayfp instead of libsidplay2
|
||||
* output
|
||||
- shout: recognize setting "encoder" instead of "encoding"
|
||||
* fix memory leak after stream failure
|
||||
* fix build failure with Boost 1.61
|
||||
* require gcc 4.7 or newer
|
||||
|
||||
ver 0.19.17 (2016/07/09)
|
||||
* decoder
|
||||
- flac: fix assertion failure while seeking
|
||||
- flac: fix stream duration indicator
|
||||
- fix seek problems in several plugins
|
||||
* fix spurious seek error "Failed to allocate silence buffer"
|
||||
* replay gain: fix "replay_gain_handler mixer" setting
|
||||
* DSD: use 0x69 as silence pattern
|
||||
* fix use-after-free bug on "close" and "kill"
|
||||
|
||||
ver 0.19.16 (2016/06/13)
|
||||
* faster seeking
|
||||
* fix system include path order
|
||||
* add missing DocBook file to tarball
|
||||
|
||||
ver 0.19.15 (2016/04/30)
|
||||
* decoder
|
||||
- ffmpeg: support FFmpeg 3.0
|
||||
- ffmpeg: use as fallback instead of "mad" if no plugin matches
|
||||
- opus: support bigger OpusTags packets
|
||||
* fix more build failures on non-glibc builds due to constexpr Mutex
|
||||
* fix build failure due to missing include
|
||||
* fix unit test on Alpha
|
||||
|
||||
ver 0.19.14 (2016/03/18)
|
||||
* decoder
|
||||
- dsdiff: fix off-by-one buffer overflow
|
||||
- opus: limit tag size to 64 kB
|
||||
* archive
|
||||
- iso9660: fix buffer overflow
|
||||
* fix quadratic runtime bug in the tag pool
|
||||
* fix build failures on non-glibc builds due to constexpr Mutex
|
||||
|
||||
ver 0.19.13 (2016/02/23)
|
||||
* tags
|
||||
- aiff, riff: fix ID3 chunk padding
|
||||
* decoder
|
||||
- ffmpeg: support the TAK codec
|
||||
* fix disappearing duration of remote songs during playback
|
||||
* initialize supplementary groups with glibc 2.19+
|
||||
|
||||
ver 0.19.12 (2015/12/15)
|
||||
* fix assertion failure on malformed UTF-8 tag
|
||||
* fix build failure on non-Linux systems
|
||||
* fix LimitRTTIME in systemd unit file
|
||||
|
||||
ver 0.19.11 (2015/10/27)
|
||||
* tags
|
||||
- ape: fix buffer overflow
|
||||
* decoder
|
||||
- ffmpeg: fix crash due to wrong avio_alloc_context() call
|
||||
- gme: don't loop forever, fall back to GME's default play length
|
||||
* encoder
|
||||
- flac: fix crash with 32 bit playback
|
||||
* mixer
|
||||
- fix mixer lag after enabling/disabling output
|
||||
|
||||
ver 0.19.10 (2015/06/21)
|
||||
* input
|
||||
- curl: fix deadlock on small responses
|
||||
- smbclient: fix DFF playback
|
||||
* decoder
|
||||
- ffmpeg: improve seeking accuracy
|
||||
- fix stuck stream tags
|
||||
* encoder
|
||||
- opus: fix bogus granulepos
|
||||
* output
|
||||
- fix failure to open device right after booting
|
||||
* neighbor
|
||||
- nfs: fix deadlock when connecting
|
||||
* fix "single" mode breakage due to queue edits
|
||||
|
||||
ver 0.19.9 (2015/02/06)
|
||||
* decoder
|
||||
- dsdiff, dsf: raise ID3 tag limit to 1 MB
|
||||
* playlist: fix loading duplicate tag types from state file
|
||||
* despotify: remove defunct plugin
|
||||
* fix clock integer overflow on OS X
|
||||
* fix gcc 5.0 warnings
|
||||
* fix build failure with uClibc
|
||||
* fix build failure on non-POSIX operating systems
|
||||
* fix dependency issue on parallel Android build
|
||||
* fix database/state file saving on Windows
|
||||
|
||||
ver 0.19.8 (2015/01/14)
|
||||
* input
|
||||
- curl: fix bug after rewinding from end-of-file
|
||||
- mms: reduce delay at the beginning of playback
|
||||
* decoder
|
||||
- dsdiff, dsf: allow ID3 tags larger than 4 kB
|
||||
- ffmpeg: support interleaved floating point
|
||||
* fix clang 3.6 warnings
|
||||
* fix build failure on NetBSD
|
||||
|
||||
ver 0.19.7 (2014/12/17)
|
||||
* input
|
||||
- nfs: fix crash while canceling a failing file open operation
|
||||
- nfs: fix memory leak on connection failure
|
||||
- nfs: fix reconnect after mount failure
|
||||
- nfs: implement mount timeout (60 seconds)
|
||||
* storage
|
||||
- nfs: implement I/O timeout (60 seconds)
|
||||
* playlist
|
||||
- embcue: fix filename suffix detection
|
||||
- don't skip non-existent songs in "listplaylist"
|
||||
* decoder
|
||||
- ffmpeg: fix time stamp underflow
|
||||
* fix memory allocator bug on Windows
|
||||
|
||||
ver 0.19.6 (2014/12/08)
|
||||
* decoder
|
||||
- ffmpeg: support FFmpeg 2.5
|
||||
* fix build failure with musl
|
||||
* android
|
||||
- update libFLAC to 1.3.1
|
||||
- update FFmpeg to 2.5
|
||||
|
||||
ver 0.19.5 (2014/11/26)
|
||||
* input
|
||||
- nfs: fix crash on connection failure
|
||||
@@ -138,6 +394,25 @@ ver 0.19 (2014/10/10)
|
||||
* install systemd unit for socket activation
|
||||
* Android port
|
||||
|
||||
ver 0.18.23 (2015/02/06)
|
||||
* despotify: remove defunct plugin
|
||||
* fix clock integer overflow on OS X
|
||||
* fix gcc 5.0 warnings
|
||||
|
||||
ver 0.18.22 (2015/01/14)
|
||||
* fix clang 3.6 warnings
|
||||
|
||||
ver 0.18.21 (2014/12/17)
|
||||
* playlist
|
||||
- embcue: fix filename suffix detection
|
||||
* decoder
|
||||
- ffmpeg: fix time stamp underflow
|
||||
|
||||
ver 0.18.20 (2014/12/08)
|
||||
* decoder
|
||||
- ffmpeg: support FFmpeg 2.5
|
||||
* fix build failure with musl
|
||||
|
||||
ver 0.18.19 (2014/11/26)
|
||||
* archive
|
||||
- zzip: fix crash after seeking
|
||||
|
17
README
17
README
@@ -1,17 +0,0 @@
|
||||
|
||||
Music Player Daemon (MPD)
|
||||
http://www.musicpd.org
|
||||
|
||||
A daemon for playing music of various formats. Music is played through the
|
||||
server's audio device. The daemon stores info about all available music,
|
||||
and this info can be easily searched and retrieved. Player control, info
|
||||
retrieval, and playlist management can all be managed remotely.
|
||||
|
||||
For basic installation information see the INSTALL file.
|
||||
|
||||
MPD is released under the GNU General Public License version 2, which is
|
||||
distributed in the COPYING file.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
28
README.md
Normal file
28
README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Music Player Daemon
|
||||
|
||||
http://www.musicpd.org
|
||||
|
||||
A daemon for playing music of various formats. Music is played through the
|
||||
server's audio device. The daemon stores info about all available music,
|
||||
and this info can be easily searched and retrieved. Player control, info
|
||||
retrieval, and playlist management can all be managed remotely.
|
||||
|
||||
For basic installation information see the INSTALL file.
|
||||
|
||||
# Users
|
||||
|
||||
- [Manual](http://www.musicpd.org/doc/user/)
|
||||
- [Forum](http://forum.musicpd.org/)
|
||||
- [IRC](irc://chat.freenode.net/#mpd)
|
||||
- [Bug tracker](http://bugs.musicpd.org/)
|
||||
|
||||
# Developers
|
||||
|
||||
- [Protocol specification](http://www.musicpd.org/doc/protocol/)
|
||||
- [Developer manual](http://www.musicpd.org/doc/developer/)
|
||||
|
||||
# Legal
|
||||
|
||||
MPD is released under the
|
||||
[GNU General Public License version 2](https://www.gnu.org/licenses/gpl-2.0.txt),
|
||||
which is distributed in the COPYING file.
|
@@ -2,8 +2,8 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.musicpd"
|
||||
android:installLocation="auto"
|
||||
android:versionCode="9"
|
||||
android:versionName="0.19.5">
|
||||
android:versionCode="13"
|
||||
android:versionName="0.19.9">
|
||||
|
||||
<uses-sdk android:minSdkVersion="9" android:targetSdkVersion="17"/>
|
||||
|
||||
|
458
android/build.py
458
android/build.py
@@ -1,10 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os, os.path
|
||||
import sys, shutil, subprocess
|
||||
import urllib.request
|
||||
import hashlib
|
||||
import re
|
||||
import sys, subprocess
|
||||
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: build.py SDK_PATH NDK_PATH [configure_args...]", file=sys.stderr)
|
||||
@@ -22,412 +19,135 @@ if not os.path.isdir(ndk_path):
|
||||
print("NDK not found in", ndk_path, file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# select the NDK target
|
||||
arch = 'arm-linux-androideabi'
|
||||
|
||||
# the path to the MPD sources
|
||||
mpd_path = os.path.dirname(os.path.dirname(sys.argv[0]))
|
||||
mpd_path = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]) or '.', '..'))
|
||||
sys.path[0] = os.path.join(mpd_path, 'python')
|
||||
|
||||
# output directories
|
||||
lib_path = os.path.abspath('lib')
|
||||
tarball_path = lib_path
|
||||
src_path = os.path.join(lib_path, 'src')
|
||||
build_path = os.path.join(lib_path, 'build')
|
||||
root_path = os.path.join(lib_path, 'root')
|
||||
from build.dirs import lib_path, tarball_path, src_path
|
||||
|
||||
arch_path = os.path.join(lib_path, arch)
|
||||
build_path = os.path.join(arch_path, 'build')
|
||||
|
||||
# build host configuration
|
||||
build_arch = 'linux-x86_64'
|
||||
|
||||
# redirect pkg-config to use our root directory instead of the default
|
||||
# one on the build host
|
||||
os.environ['PKG_CONFIG_LIBDIR'] = os.path.join(root_path, 'lib/pkgconfig')
|
||||
|
||||
# select the NDK compiler
|
||||
gcc_version = '4.9'
|
||||
llvm_version = '3.5'
|
||||
|
||||
# select the NDK target
|
||||
ndk_arch = 'arm'
|
||||
host_arch = 'arm-linux-androideabi'
|
||||
android_abi = 'armeabi-v7a'
|
||||
ndk_platform = 'android-14'
|
||||
|
||||
# set up the NDK toolchain
|
||||
|
||||
gcc_toolchain = os.path.join(ndk_path, 'toolchains', host_arch + '-' + gcc_version, 'prebuilt', build_arch)
|
||||
llvm_toolchain = os.path.join(ndk_path, 'toolchains', 'llvm-' + llvm_version, 'prebuilt', build_arch)
|
||||
ndk_platform_path = os.path.join(ndk_path, 'platforms', ndk_platform)
|
||||
target_root = os.path.join(ndk_platform_path, 'arch-' + ndk_arch)
|
||||
class AndroidNdkToolchain:
|
||||
def __init__(self, tarball_path, src_path, build_path,
|
||||
use_cxx):
|
||||
self.tarball_path = tarball_path
|
||||
self.src_path = src_path
|
||||
self.build_path = build_path
|
||||
|
||||
llvm_triple = 'armv7-none-linux-androideabi'
|
||||
self.ndk_arch = 'arm'
|
||||
android_abi = 'armeabi-v7a'
|
||||
ndk_platform = 'android-14'
|
||||
|
||||
def select_toolchain(use_cxx, use_clang):
|
||||
global cc, cxx, ar, strip, cflags, cxxflags, cppflags, ldflags, libs
|
||||
# select the NDK compiler
|
||||
gcc_version = '4.9'
|
||||
|
||||
target_arch = '-march=armv7-a -mfloat-abi=softfp'
|
||||
if use_clang:
|
||||
cc = os.path.join(llvm_toolchain, 'bin/clang')
|
||||
cxx = os.path.join(llvm_toolchain, 'bin/clang++')
|
||||
target_arch += ' -target ' + llvm_triple + ' -integrated-as -gcc-toolchain ' + gcc_toolchain
|
||||
else:
|
||||
cc = os.path.join(gcc_toolchain, 'bin', host_arch + '-gcc')
|
||||
cxx = os.path.join(gcc_toolchain, 'bin', host_arch + '-g++')
|
||||
ar = os.path.join(gcc_toolchain, 'bin', host_arch + '-ar')
|
||||
strip = os.path.join(gcc_toolchain, 'bin', host_arch + '-strip')
|
||||
ndk_platform_path = os.path.join(ndk_path, 'platforms', ndk_platform)
|
||||
sysroot = os.path.join(ndk_platform_path, 'arch-' + self.ndk_arch)
|
||||
|
||||
libstdcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/gnu-libstdc++', gcc_version)
|
||||
libstdcxx_cppflags = '-isystem ' + os.path.join(libstdcxx_path, 'include') + ' -isystem ' + os.path.join(libstdcxx_path, 'libs', android_abi, 'include')
|
||||
if use_clang:
|
||||
libstdcxx_cppflags += ' -D__STRICT_ANSI__'
|
||||
libstdcxx_ldadd = os.path.join(libstdcxx_path, 'libs', android_abi, 'libgnustl_static.a')
|
||||
install_prefix = os.path.join(arch_path, 'root')
|
||||
|
||||
cflags = '-Os -g ' + target_arch
|
||||
cxxflags = '-Os -g ' + target_arch
|
||||
cppflags = '--sysroot=' + target_root + ' -I' + root_path + '/include'
|
||||
ldflags = '--sysroot=' + target_root + ' -L' + root_path + '/lib'
|
||||
libs = ''
|
||||
self.arch = arch
|
||||
self.install_prefix = install_prefix
|
||||
self.sysroot = sysroot
|
||||
|
||||
if use_cxx:
|
||||
libs += ' ' + libstdcxx_ldadd
|
||||
cppflags += ' ' + libstdcxx_cppflags
|
||||
toolchain_path = os.path.join(ndk_path, 'toolchains', arch + '-' + gcc_version, 'prebuilt', build_arch)
|
||||
llvm_path = os.path.join(ndk_path, 'toolchains', 'llvm', 'prebuilt', build_arch)
|
||||
llvm_triple = 'armv7-none-linux-androideabi'
|
||||
|
||||
def file_md5(path):
|
||||
"""Calculate the MD5 checksum of a file and return it in hexadecimal notation."""
|
||||
common_flags = '-march=armv7-a -mfloat-abi=softfp'
|
||||
|
||||
with open(path, 'rb') as f:
|
||||
m = hashlib.md5()
|
||||
while True:
|
||||
data = f.read(65536)
|
||||
if len(data) == 0:
|
||||
# end of file
|
||||
return m.hexdigest()
|
||||
m.update(data)
|
||||
toolchain_bin = os.path.join(toolchain_path, 'bin')
|
||||
llvm_bin = os.path.join(llvm_path, 'bin')
|
||||
self.cc = os.path.join(llvm_bin, 'clang')
|
||||
self.cxx = os.path.join(llvm_bin, 'clang++')
|
||||
common_flags += ' -target ' + llvm_triple + ' -integrated-as -gcc-toolchain ' + toolchain_path
|
||||
|
||||
def download_tarball(url, md5):
|
||||
"""Download a tarball, verify its MD5 checksum and return the local path."""
|
||||
self.ar = os.path.join(toolchain_bin, arch + '-ar')
|
||||
self.ranlib = os.path.join(toolchain_bin, arch + '-ranlib')
|
||||
self.nm = os.path.join(toolchain_bin, arch + '-nm')
|
||||
self.strip = os.path.join(toolchain_bin, arch + '-strip')
|
||||
|
||||
global tarball_path
|
||||
os.makedirs(tarball_path, exist_ok=True)
|
||||
path = os.path.join(tarball_path, os.path.basename(url))
|
||||
self.cflags = '-Os -g ' + common_flags
|
||||
self.cxxflags = '-Os -g ' + common_flags
|
||||
self.cppflags = '--sysroot=' + self.sysroot + ' -isystem ' + os.path.join(install_prefix, 'include')
|
||||
self.ldflags = '--sysroot=' + self.sysroot + ' ' + common_flags + ' -L' + os.path.join(install_prefix, 'lib')
|
||||
self.libs = ''
|
||||
|
||||
try:
|
||||
calculated_md5 = file_md5(path)
|
||||
if md5 == calculated_md5: return path
|
||||
os.unlink(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
self.is_arm = self.ndk_arch == 'arm'
|
||||
self.is_armv7 = self.is_arm and 'armv7' in self.cflags
|
||||
self.is_windows = False
|
||||
|
||||
tmp_path = path + '.tmp'
|
||||
libstdcxx_path = os.path.join(ndk_path, 'sources/cxx-stl/gnu-libstdc++', gcc_version)
|
||||
libstdcxx_cppflags = '-isystem ' + os.path.join(libstdcxx_path, 'include') + ' -isystem ' + os.path.join(libstdcxx_path, 'libs', android_abi, 'include')
|
||||
libstdcxx_ldadd = os.path.join(libstdcxx_path, 'libs', android_abi, 'libgnustl_static.a')
|
||||
|
||||
print("download", url)
|
||||
urllib.request.urlretrieve(url, tmp_path)
|
||||
calculated_md5 = file_md5(tmp_path)
|
||||
if calculated_md5 != md5:
|
||||
os.unlink(tmp_path)
|
||||
raise "MD5 mismatch"
|
||||
if use_cxx:
|
||||
self.libs += ' ' + libstdcxx_ldadd
|
||||
self.cppflags += ' ' + libstdcxx_cppflags
|
||||
|
||||
os.rename(tmp_path, path)
|
||||
return path
|
||||
self.env = dict(os.environ)
|
||||
|
||||
class Project:
|
||||
def __init__(self, url, md5, installed, name=None, version=None,
|
||||
base=None,
|
||||
use_cxx=False, use_clang=False):
|
||||
if base is None:
|
||||
basename = os.path.basename(url)
|
||||
m = re.match(r'^(.+)\.(tar(\.(gz|bz2|xz|lzma))?|zip)$', basename)
|
||||
if not m: raise
|
||||
self.base = m.group(1)
|
||||
else:
|
||||
self.base = base
|
||||
|
||||
if name is None or version is None:
|
||||
m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?)$', self.base)
|
||||
if name is None: name = m.group(1)
|
||||
if version is None: version = m.group(2)
|
||||
|
||||
self.name = name
|
||||
self.version = version
|
||||
|
||||
self.url = url
|
||||
self.md5 = md5
|
||||
self.installed = installed
|
||||
|
||||
self.use_cxx = use_cxx
|
||||
self.use_clang = use_clang
|
||||
|
||||
def download(self):
|
||||
return download_tarball(self.url, self.md5)
|
||||
|
||||
def is_installed(self):
|
||||
global root_path
|
||||
tarball = self.download()
|
||||
installed = os.path.join(root_path, self.installed)
|
||||
tarball_mtime = os.path.getmtime(tarball)
|
||||
try:
|
||||
return os.path.getmtime(installed) >= tarball_mtime
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
|
||||
def unpack(self):
|
||||
global src_path
|
||||
tarball = self.download()
|
||||
path = os.path.join(src_path, self.base)
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
os.makedirs(src_path, exist_ok=True)
|
||||
subprocess.check_call(['/bin/tar', 'xfC', tarball, src_path])
|
||||
return path
|
||||
|
||||
def make_build_path(self):
|
||||
path = os.path.join(build_path, self.base)
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
os.makedirs(path, exist_ok=True)
|
||||
return path
|
||||
|
||||
class AutotoolsProject(Project):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
autogen=False,
|
||||
cppflags='',
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
self.configure_args = configure_args
|
||||
self.autogen = autogen
|
||||
self.cppflags = cppflags
|
||||
|
||||
def build(self):
|
||||
src = self.unpack()
|
||||
if self.autogen:
|
||||
subprocess.check_call(['/usr/bin/aclocal'], cwd=src)
|
||||
subprocess.check_call(['/usr/bin/automake', '--add-missing', '--force-missing', '--foreign'], cwd=src)
|
||||
subprocess.check_call(['/usr/bin/autoconf'], cwd=src)
|
||||
subprocess.check_call(['/usr/bin/libtoolize', '--force'], cwd=src)
|
||||
|
||||
build = self.make_build_path()
|
||||
|
||||
select_toolchain(use_cxx=self.use_cxx, use_clang=self.use_clang)
|
||||
configure = [
|
||||
os.path.join(src, 'configure'),
|
||||
'CC=' + cc,
|
||||
'CXX=' + cxx,
|
||||
'CFLAGS=' + cflags,
|
||||
'CXXFLAGS=' + cxxflags,
|
||||
'CPPFLAGS=' + cppflags + ' ' + self.cppflags,
|
||||
'LDFLAGS=' + ldflags,
|
||||
'LIBS=' + libs,
|
||||
'AR=' + ar,
|
||||
'STRIP=' + strip,
|
||||
'--host=' + host_arch,
|
||||
'--prefix=' + root_path,
|
||||
'--with-sysroot=' + target_root,
|
||||
'--enable-silent-rules',
|
||||
] + self.configure_args
|
||||
|
||||
subprocess.check_call(configure, cwd=build)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], cwd=build)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', 'install'], cwd=build)
|
||||
|
||||
class FfmpegProject(Project):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
cppflags='',
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
self.configure_args = configure_args
|
||||
self.cppflags = cppflags
|
||||
|
||||
def build(self):
|
||||
src = self.unpack()
|
||||
build = self.make_build_path()
|
||||
|
||||
select_toolchain(use_cxx=self.use_cxx, use_clang=self.use_clang)
|
||||
configure = [
|
||||
os.path.join(src, 'configure'),
|
||||
'--cc=' + cc,
|
||||
'--cxx=' + cxx,
|
||||
'--extra-cflags=' + cflags + ' ' + cppflags + ' ' + self.cppflags,
|
||||
'--extra-cxxflags=' + cxxflags + ' ' + cppflags + ' ' + self.cppflags,
|
||||
'--extra-ldflags=' + ldflags,
|
||||
'--extra-libs=' + libs,
|
||||
'--ar=' + ar,
|
||||
'--enable-cross-compile',
|
||||
'--target-os=linux',
|
||||
'--arch=' + ndk_arch,
|
||||
'--cpu=cortex-a8',
|
||||
'--prefix=' + root_path,
|
||||
] + self.configure_args
|
||||
|
||||
subprocess.check_call(configure, cwd=build)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], cwd=build)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', 'install'], cwd=build)
|
||||
|
||||
class BoostProject(Project):
|
||||
def __init__(self, url, md5, installed,
|
||||
**kwargs):
|
||||
m = re.match(r'.*/boost_(\d+)_(\d+)_(\d+)\.tar\.bz2$', url)
|
||||
version = "%s.%s.%s" % (m.group(1), m.group(2), m.group(3))
|
||||
Project.__init__(self, url, md5, installed,
|
||||
name='boost', version=version,
|
||||
**kwargs)
|
||||
|
||||
def build(self):
|
||||
src = self.unpack()
|
||||
|
||||
# install the headers manually; don't build any library
|
||||
# (because right now, we only use header-only libraries)
|
||||
includedir = os.path.join(root_path, 'include')
|
||||
for dirpath, dirnames, filenames in os.walk(os.path.join(src, 'boost')):
|
||||
relpath = dirpath[len(src)+1:]
|
||||
destdir = os.path.join(includedir, relpath)
|
||||
try:
|
||||
os.mkdir(destdir)
|
||||
except:
|
||||
pass
|
||||
for name in filenames:
|
||||
if name[-4:] == '.hpp':
|
||||
shutil.copyfile(os.path.join(dirpath, name),
|
||||
os.path.join(destdir, name))
|
||||
# redirect pkg-config to use our root directory instead of the
|
||||
# default one on the build host
|
||||
self.env['PKG_CONFIG_LIBDIR'] = os.path.join(install_prefix, 'lib/pkgconfig')
|
||||
|
||||
# a list of third-party libraries to be used by MPD on Android
|
||||
from build.libs import *
|
||||
thirdparty_libs = [
|
||||
AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/ogg/libogg-1.3.2.tar.xz',
|
||||
'5c3a34309d8b98640827e5d0991a4015',
|
||||
'lib/libogg.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.4.tar.xz',
|
||||
'55f2288055e44754275a17c9a2497391',
|
||||
'lib/libvorbis.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/opus/opus-1.1.tar.gz',
|
||||
'c5a8cf7c0b066759542bc4ca46817ac6',
|
||||
'lib/libopus.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
use_clang=True,
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'https://svn.xiph.org/releases/flac/flac-1.3.0.tar.xz',
|
||||
'13b5c214cee8373464d3d65dee362cdd',
|
||||
'lib/libFLAC.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-xmms-plugin', '--disable-cpplibs',
|
||||
],
|
||||
use_clang=True,
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'ftp://ftp.mars.org/pub/mpeg/libid3tag-0.15.1b.tar.gz',
|
||||
'e5808ad997ba32c498803822078748c3',
|
||||
'lib/libid3tag.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
autogen=True,
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'ftp://ftp.mars.org/pub/mpeg/libmad-0.15.1b.tar.gz',
|
||||
'1be543bc30c56fb6bea1d7bf6a64e66c',
|
||||
'lib/libmad.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
autogen=True,
|
||||
),
|
||||
|
||||
FfmpegProject(
|
||||
'http://www.ffmpeg.org/releases/ffmpeg-2.2.3.tar.bz2',
|
||||
'dbb5b6b69bd010916f17df0ae596e0b1',
|
||||
'lib/libavcodec.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--enable-gpl',
|
||||
'--enable-small',
|
||||
'--disable-pthreads',
|
||||
'--disable-runtime-cpudetect',
|
||||
'--disable-programs',
|
||||
'--disable-doc',
|
||||
'--disable-avdevice',
|
||||
'--disable-swresample',
|
||||
'--disable-swscale',
|
||||
'--disable-postproc',
|
||||
'--disable-avfilter',
|
||||
'--disable-network',
|
||||
'--disable-encoders',
|
||||
'--disable-protocols',
|
||||
'--disable-outdevs',
|
||||
'--disable-filters',
|
||||
],
|
||||
),
|
||||
|
||||
AutotoolsProject(
|
||||
'http://curl.haxx.se/download/curl-7.37.0.tar.lzma',
|
||||
'54bfd1eb5214f604186d6f5ac61c7781',
|
||||
'lib/libcurl.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-debug',
|
||||
'--enable-http',
|
||||
'--enable-ipv6',
|
||||
'--disable-ftp', '--disable-file',
|
||||
'--disable-ldap', '--disable-ldaps',
|
||||
'--disable-rtsp', '--disable-proxy', '--disable-dict', '--disable-telnet',
|
||||
'--disable-tftp', '--disable-pop3', '--disable-imap', '--disable-smtp',
|
||||
'--disable-gopher',
|
||||
'--disable-manual',
|
||||
'--disable-threaded-resolver', '--disable-verbose', '--disable-sspi',
|
||||
'--disable-crypto-auth', '--disable-ntlm-wb', '--disable-tls-srp', '--disable-cookies',
|
||||
'--without-ssl', '--without-gnutls', '--without-nss', '--without-libssh2',
|
||||
],
|
||||
use_clang=True,
|
||||
),
|
||||
|
||||
BoostProject(
|
||||
'http://netcologne.dl.sourceforge.net/project/boost/boost/1.55.0/boost_1_55_0.tar.bz2',
|
||||
'd6eef4b4cacb2183f2bf265a5a03a354',
|
||||
'include/boost/version.hpp',
|
||||
),
|
||||
libogg,
|
||||
libvorbis,
|
||||
opus,
|
||||
flac,
|
||||
libid3tag,
|
||||
libmad,
|
||||
ffmpeg,
|
||||
curl,
|
||||
boost,
|
||||
]
|
||||
|
||||
# build the third-party libraries
|
||||
for x in thirdparty_libs:
|
||||
if not x.is_installed():
|
||||
x.build()
|
||||
toolchain = AndroidNdkToolchain(tarball_path, src_path, build_path,
|
||||
use_cxx=x.use_cxx)
|
||||
if not x.is_installed(toolchain):
|
||||
x.build(toolchain)
|
||||
|
||||
# configure and build MPD
|
||||
select_toolchain(use_cxx=True, use_clang=True)
|
||||
toolchain = AndroidNdkToolchain(tarball_path, src_path, build_path,
|
||||
use_cxx=True)
|
||||
|
||||
configure = [
|
||||
os.path.join(mpd_path, 'configure'),
|
||||
'CC=' + cc,
|
||||
'CXX=' + cxx,
|
||||
'CFLAGS=' + cflags,
|
||||
'CXXFLAGS=' + cxxflags,
|
||||
'CPPFLAGS=' + cppflags,
|
||||
'LDFLAGS=' + ldflags,
|
||||
'LIBS=' + libs,
|
||||
'AR=' + ar,
|
||||
'STRIP=' + strip,
|
||||
'--host=' + host_arch,
|
||||
'--prefix=' + root_path,
|
||||
'--with-sysroot=' + target_root,
|
||||
'CC=' + toolchain.cc,
|
||||
'CXX=' + toolchain.cxx,
|
||||
'CFLAGS=' + toolchain.cflags,
|
||||
'CXXFLAGS=' + toolchain.cxxflags,
|
||||
'CPPFLAGS=' + toolchain.cppflags,
|
||||
'LDFLAGS=' + toolchain.ldflags,
|
||||
'LIBS=' + toolchain.libs,
|
||||
'AR=' + toolchain.ar,
|
||||
'RANLIB=' + toolchain.ranlib,
|
||||
'STRIP=' + toolchain.strip,
|
||||
'--host=' + toolchain.arch,
|
||||
'--prefix=' + toolchain.install_prefix,
|
||||
'--with-sysroot=' + toolchain.sysroot,
|
||||
'--with-android-sdk=' + sdk_path,
|
||||
|
||||
'--enable-silent-rules',
|
||||
|
||||
'--disable-glib',
|
||||
'--disable-icu',
|
||||
|
||||
# disabled for now because these features require GLib:
|
||||
'--disable-httpd-output',
|
||||
'--disable-vorbis-encoder',
|
||||
|
||||
] + configure_args
|
||||
|
||||
subprocess.check_call(configure)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'])
|
||||
subprocess.check_call(configure, env=toolchain.env)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], env=toolchain.env)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
983
configure.ac
983
configure.ac
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,11 @@
|
||||
<?xml version='1.0' encoding="utf-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"docbook/dtd/xml/4.2/docbookx.dtd">
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<book>
|
||||
<title>The Music Player Daemon - Developer's Manual</title>
|
||||
|
||||
<chapter>
|
||||
<chapter id="introduction">
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>
|
||||
@@ -20,7 +21,7 @@
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<chapter id="code_style">
|
||||
<title>Code Style</title>
|
||||
|
||||
<itemizedlist>
|
||||
@@ -39,9 +40,35 @@
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
the code should be C++11 compliant, and must compile with
|
||||
<application>GCC</application> 4.6 and
|
||||
<application>clang</application> 3.2
|
||||
comment your code, document your APIs
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
the code should be C++14 compliant, and must compile with
|
||||
<application>GCC</application> 4.9 and
|
||||
<application>clang</application> 3.4
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
report error conditions with C++ exceptions, preferable
|
||||
derived from <varname>std::runtime_error</varname>
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
all code must be exception-safe
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
classes and functions names use CamelCase; variables are
|
||||
lower-case with words separated by underscore
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
@@ -51,9 +78,9 @@
|
||||
</para>
|
||||
|
||||
<programlisting lang="C">static inline int
|
||||
foo(const char *abc, int xyz)
|
||||
Foo(const char *abc, int xyz)
|
||||
{
|
||||
if (abc == NULL) {
|
||||
if (abc == nullptr) {
|
||||
LogWarning("Foo happened!");
|
||||
return -1;
|
||||
}
|
||||
@@ -65,7 +92,7 @@ foo(const char *abc, int xyz)
|
||||
</itemizedlist>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<chapter id="hacking">
|
||||
<title>Hacking The Source</title>
|
||||
|
||||
<para>
|
||||
@@ -150,7 +177,7 @@ foo(const char *abc, int xyz)
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<chapter id="submitting_patches">
|
||||
<title>Submitting Patches</title>
|
||||
|
||||
<para>
|
||||
@@ -166,9 +193,16 @@ foo(const char *abc, int xyz)
|
||||
url="http://git.musicpd.org/account-policy.html">an account on
|
||||
git.musicpd.org</ulink>, but any public git repository will do.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There is <ulink url="https://github.com/MaxKellermann/MPD">a
|
||||
mirror of the <application>MPD</application> git repository on
|
||||
GitHub</ulink>, and you can use that as well to submit pull
|
||||
requests.
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<chapter id="tools">
|
||||
<title>Development Tools</title>
|
||||
|
||||
<section>
|
||||
|
2487
doc/doxygen.conf.in
2487
doc/doxygen.conf.in
File diff suppressed because it is too large
Load Diff
154
doc/include/tags.xml
Normal file
154
doc/include/tags.xml
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version='1.0' encoding="utf-8"?>
|
||||
<!DOCTYPE itemizedlist PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>artist</varname>: the artist name. Its meaning is not
|
||||
well-defined; see <varname>composer</varname> and
|
||||
<varname>performer</varname> for more specific tags.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>artistsort</varname>: same as
|
||||
<varname>artist</varname>, but for sorting. This usually omits
|
||||
prefixes such as "The".
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>album</varname>: the album name.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>albumsort</varname>: same as <varname>album</varname>,
|
||||
but for sorting.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>albumartist</varname>: on multi-artist albums, this is
|
||||
the artist name which shall be used for the whole album. The
|
||||
exact meaning of this tag is not well-defined.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>albumartistsort</varname>: same as
|
||||
<varname>albumartist</varname>, but for sorting.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>title</varname>: the song title.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>track</varname>: the track number within the album.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>name</varname>: a name for this song. This is not the
|
||||
song title. The exact meaning of this tag is not well-defined.
|
||||
It is often used by badly configured internet radio stations
|
||||
with broken tags to squeeze both the artist name and the song
|
||||
title in one tag.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>genre</varname>: the music genre.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>date</varname>: the song's release date. This is
|
||||
usually a 4-digit year.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>composer</varname>: the artist who composed the song.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>performer</varname>: the artist who performed the song.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>comment</varname>: a human-readable comment about this
|
||||
song. The exact meaning of this tag is not well-defined.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>disc</varname>: the disc number in a multi-disc album.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>musicbrainz_artistid</varname>: the artist id in the
|
||||
<ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>musicbrainz_albumid</varname>: the album id in the
|
||||
<ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>musicbrainz_albumartistid</varname>: the album artist
|
||||
id in the <ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>musicbrainz_trackid</varname>: the track id in the
|
||||
<ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>musicbrainz_releasetrackid</varname>: the release track
|
||||
id in the <ulink
|
||||
url="http://musicbrainz.org/doc/MusicBrainzTag">MusicBrainz</ulink>
|
||||
database.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
@@ -156,12 +156,6 @@ This specifies the character set used for the filesystem. A list of supported
|
||||
character sets can be obtained by running "iconv \-l". The default is
|
||||
determined from the locale when the db was originally created.
|
||||
.TP
|
||||
.B id3v1_encoding <charset>
|
||||
This specifies the character set which ID3v1 tags are encoded in. A list of
|
||||
supported character sets can be obtained by running "iconv \-l". The default is
|
||||
to let libid3tag convert them (from ISO-8859-1, as the standard specifies) and
|
||||
do no additional conversion.
|
||||
.TP
|
||||
.B gapless_mp3_playback <yes or no>
|
||||
This specifies whether to support gapless playback of MP3s which have the
|
||||
necessary headers. Useful if your MP3s have headers with incorrect
|
||||
@@ -174,18 +168,6 @@ MP3 playback.
|
||||
This specifies whether relative or absolute paths for song filenames are used
|
||||
when saving playlists. The default is "no".
|
||||
.TP
|
||||
.B metadata_to_use <tags>
|
||||
This specifies the tag types that will be scanned for and made available to
|
||||
clients. Note that you must recreate (not update) your database for changes to
|
||||
this parameter to take effect. Possible values are artist, album, title,
|
||||
track, name, genre, date, composer, performer, comment, disc,
|
||||
musicbrainz_artistid, musicbrainz_albumid, musicbrainz_albumartistid,
|
||||
musicbrainz_releasetrackid, musicbrainz_trackid. Multiple tags may be specified
|
||||
as a comma separated list.
|
||||
An example value is "artist,album,title,track". The special value "none" may
|
||||
be used alone to disable all metadata. The default is to use all known tag
|
||||
types except for comments and those starting with "musicbrainz".
|
||||
.TP
|
||||
.B auto_update <yes or no>
|
||||
This specifies the whether to support automatic update of music database when
|
||||
files are changed in music_directory. The default is to disable autoupdate
|
||||
@@ -195,16 +177,6 @@ of database.
|
||||
Limit the depth of the directories being watched, 0 means only watch
|
||||
the music directory itself. There is no limit by default.
|
||||
.TP
|
||||
.B despotify_user <name>
|
||||
This specifies the user to use when logging in to Spotify using the despotify plugins.
|
||||
.TP
|
||||
.B despotify_password <name>
|
||||
This specifies the password to use when logging in to Spotify using the despotify plugins.
|
||||
.TP
|
||||
.B despotify_high_bitrate <yes or no>
|
||||
This specifies if the requested bitrate for Spotify should be high or not. Higher sounds
|
||||
better but requires more processing and higher bandwidth. Default is yes.
|
||||
.TP
|
||||
.SH REQUIRED AUDIO OUTPUT PARAMETERS
|
||||
.TP
|
||||
.B type <type>
|
||||
@@ -254,11 +226,6 @@ probably only useful if your alsa device has more than one
|
||||
identically\-named mixer control. The default is "0". Use "amixer
|
||||
scontrols" to see the list of controls with their indexes.
|
||||
.TP
|
||||
.B use_mmap <yes or no>
|
||||
Setting this allows you to use memory-mapped I/O. Certain hardware setups may
|
||||
benefit from this, but most do not. Most users do not need to set this. The
|
||||
default is to not use memory-mapped I/O.
|
||||
.TP
|
||||
.B auto_resample <yes or no>
|
||||
Setting this to "no" disables ALSA's software resampling, if the
|
||||
hardware does not support a specific sample rate. This lets MPD do
|
||||
|
@@ -75,7 +75,8 @@
|
||||
#
|
||||
# This setting sets the address for the daemon to listen on. Careful attention
|
||||
# should be paid if this is assigned to anything other then the default, any.
|
||||
# This setting can deny access to control of the daemon.
|
||||
# This setting can deny access to control of the daemon. Not effective if
|
||||
# systemd socket activiation is in use.
|
||||
#
|
||||
# For network
|
||||
#bind_to_address "any"
|
||||
@@ -115,7 +116,7 @@
|
||||
#
|
||||
# This setting defines a list of tag types that will be extracted during the
|
||||
# audio file discovery process. The complete list of possible values can be
|
||||
# found in the mpd.conf man page.
|
||||
# found in the user manual.
|
||||
#metadata_to_use "artist,album,title,track,name,genre,date,composer,performer,disc"
|
||||
#
|
||||
# This setting enables automatic update of MPD's database when files in
|
||||
@@ -164,7 +165,7 @@
|
||||
# Permissions #################################################################
|
||||
#
|
||||
# If this setting is set, MPD will require password authorization. The password
|
||||
# can setting can be specified multiple times for different password profiles.
|
||||
# setting can be specified multiple times for different password profiles.
|
||||
#
|
||||
#password "password@read,add,control,admin"
|
||||
#
|
||||
@@ -231,7 +232,7 @@ input {
|
||||
#
|
||||
#audio_output {
|
||||
# type "shout"
|
||||
# encoding "ogg" # optional
|
||||
# encoder "vorbis" # optional
|
||||
# name "My Shout Stream"
|
||||
# host "localhost"
|
||||
# port "8000"
|
||||
@@ -304,6 +305,23 @@ input {
|
||||
## device "Digital Audio (S/PDIF) (High Definition Audio Device)" # optional
|
||||
#}
|
||||
#
|
||||
# An example of an sndio output.
|
||||
#
|
||||
#audio_output {
|
||||
# type "sndio"
|
||||
# name "sndio output"
|
||||
# mixer_type "software"
|
||||
#}
|
||||
#
|
||||
# An example of an OS X output:
|
||||
#
|
||||
#audio_output {
|
||||
# type "osx"
|
||||
# name "My OS X Device"
|
||||
## device "Built-in Output" # optional
|
||||
## channel_map "-1,-1,0,1" # optional
|
||||
#}
|
||||
#
|
||||
## Example "pipe" output:
|
||||
#
|
||||
#audio_output {
|
||||
@@ -325,13 +343,6 @@ input {
|
||||
# mixer_type "none" # optional
|
||||
#}
|
||||
#
|
||||
# If MPD has been compiled with libsamplerate support, this setting specifies
|
||||
# the sample rate converter to use. Possible values can be found in the
|
||||
# mpd.conf man page or the libsamplerate documentation. By default, this is
|
||||
# setting is disabled.
|
||||
#
|
||||
#samplerate_converter "Fastest Sinc Interpolator"
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
@@ -380,34 +391,4 @@ input {
|
||||
#
|
||||
#filesystem_charset "UTF-8"
|
||||
#
|
||||
# This setting controls the encoding that ID3v1 tags should be converted from.
|
||||
#
|
||||
#id3v1_encoding "ISO-8859-1"
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
||||
# SIDPlay decoder #############################################################
|
||||
#
|
||||
# songlength_database:
|
||||
# Location of your songlengths file, as distributed with the HVSC.
|
||||
# The sidplay plugin checks this for matching MD5 fingerprints.
|
||||
# See http://www.c64.org/HVSC/DOCUMENTS/Songlengths.faq
|
||||
#
|
||||
# default_songlength:
|
||||
# This is the default playing time in seconds for songs not in the
|
||||
# songlength database, or in case you're not using a database.
|
||||
# A value of 0 means play indefinitely.
|
||||
#
|
||||
# filter:
|
||||
# Turns the SID filter emulation on or off.
|
||||
#
|
||||
#decoder {
|
||||
# plugin "sidplay"
|
||||
# songlength_database "/media/C64Music/DOCUMENTS/Songlengths.txt"
|
||||
# default_songlength "120"
|
||||
# filter "true"
|
||||
#}
|
||||
#
|
||||
###############################################################################
|
||||
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<?xml version='1.0' encoding="utf-8"?>
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"docbook/dtd/xml/4.2/docbookx.dtd">
|
||||
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
|
||||
|
||||
<book>
|
||||
<title>The Music Player Daemon protocol</title>
|
||||
|
||||
@@ -65,8 +66,8 @@
|
||||
<function>strcpy</function> just fine with UTF-8 encoded
|
||||
strings. For example: <returnvalue>OK</returnvalue> encoded in
|
||||
UTF-8 is simply <returnvalue>OK</returnvalue>. For more
|
||||
information on UTF=8:
|
||||
http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)
|
||||
information on UTF-8:
|
||||
<ulink url="http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8"/>)
|
||||
</para>
|
||||
</section>
|
||||
|
||||
@@ -201,6 +202,25 @@
|
||||
omitted, then the maximum possible value is assumed.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="tags">
|
||||
<title>Tags</title>
|
||||
|
||||
<para>
|
||||
The following tags are supported by
|
||||
<application>MPD</application>:
|
||||
</para>
|
||||
|
||||
<xi:include href="include/tags.xml"
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude"/>
|
||||
|
||||
<para>
|
||||
There can be multiple values for some of these tags. For
|
||||
example, <application>MPD</application> may return multiple
|
||||
lines with a <varname>performer</varname> tag. A tag value is
|
||||
a UTF-8 string.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
<chapter id="recipes">
|
||||
@@ -238,9 +258,10 @@
|
||||
"before" the current song in that sequence) will only be
|
||||
scheduled for repeated playback if its priority has become
|
||||
bigger than the priority of the current song. Decreasing the
|
||||
priority of a song will moved it farther to the end of the
|
||||
priority of a song will move it farther to the end of the
|
||||
sequence. Changing the priority of the current song has no
|
||||
effect on the sequence.
|
||||
effect on the sequence. During playback, a song's priority is
|
||||
reset to zero.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
||||
@@ -515,6 +536,15 @@
|
||||
</returnvalue>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>duration</varname>:
|
||||
<footnote id="since_0_20"><simpara>Introduced with <application>MPD</application> 0.20</simpara></footnote>
|
||||
<returnvalue>
|
||||
Duration of the current song in seconds.
|
||||
</returnvalue>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<varname>bitrate</varname>:
|
||||
@@ -1141,7 +1171,7 @@ OK
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Searches case-sensitively for partial matches in the
|
||||
Searches case-insensitively for partial matches in the
|
||||
current playlist.
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -1151,12 +1181,15 @@ OK
|
||||
<cmdsynopsis>
|
||||
<command>plchanges</command>
|
||||
<arg choice="req"><replaceable>VERSION</replaceable></arg>
|
||||
<arg><replaceable>START:END</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Displays changed songs currently in the playlist since
|
||||
<varname>VERSION</varname>.
|
||||
<varname>VERSION</varname>. Start and end positions may
|
||||
be given to limit the output to changes in the given
|
||||
range.
|
||||
</para>
|
||||
<para>
|
||||
To detect songs that were deleted at the end of the
|
||||
@@ -1169,6 +1202,7 @@ OK
|
||||
<cmdsynopsis>
|
||||
<command>plchangesposid</command>
|
||||
<arg choice="req"><replaceable>VERSION</replaceable></arg>
|
||||
<arg><replaceable>START:END</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
@@ -1465,15 +1499,15 @@ OK
|
||||
<cmdsynopsis>
|
||||
<command>playlistmove</command>
|
||||
<arg choice="req"><replaceable>NAME</replaceable></arg>
|
||||
<arg choice="req"><replaceable>SONGID</replaceable></arg>
|
||||
<arg choice="req"><replaceable>SONGPOS</replaceable></arg>
|
||||
<arg choice="req"><replaceable>FROM</replaceable></arg>
|
||||
<arg choice="req"><replaceable>TO</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Moves <varname>SONGID</varname> in the playlist
|
||||
<filename>NAME.m3u</filename> to the position
|
||||
<varname>SONGPOS</varname>.
|
||||
Moves the song at position <varname>FROM</varname> in
|
||||
the playlist <filename>NAME.m3u</filename> to the
|
||||
position <varname>TO</varname>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -1559,6 +1593,7 @@ OK
|
||||
<arg choice="req"><replaceable>TYPE</replaceable></arg>
|
||||
<arg choice="req"><replaceable>WHAT</replaceable></arg>
|
||||
<arg choice="opt"><replaceable>...</replaceable></arg>
|
||||
<arg choice="opt">window <replaceable>START</replaceable>:<replaceable>END</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
@@ -1603,6 +1638,13 @@ OK
|
||||
<para>
|
||||
<varname>WHAT</varname> is what to find.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<varname>window</varname> can be used to query only a
|
||||
portion of the real response. The parameter is two
|
||||
zero-based record numbers; a start number and an end
|
||||
number.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry id="command_findadd">
|
||||
@@ -1754,7 +1796,7 @@ OK
|
||||
<para>
|
||||
Clients that are connected via UNIX domain socket may
|
||||
use this command to read the tags of an arbitrary local
|
||||
file (URI beginning with "file:///").
|
||||
file (URI is an absolute path).
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@@ -1769,8 +1811,7 @@ OK
|
||||
<para>
|
||||
Read "comments" (i.e. key-value pairs) from the file
|
||||
specified by "URI". This "URI" can be a path relative
|
||||
to the music directory or a URL in the form
|
||||
"file:///foo/bar.ogg".
|
||||
to the music directory or an absolute path.
|
||||
</para>
|
||||
<para>
|
||||
This command may be used to list metadata of remote
|
||||
@@ -1795,6 +1836,7 @@ OK
|
||||
<arg choice="req"><replaceable>TYPE</replaceable></arg>
|
||||
<arg choice="req"><replaceable>WHAT</replaceable></arg>
|
||||
<arg choice="opt"><replaceable>...</replaceable></arg>
|
||||
<arg choice="opt">window <replaceable>START</replaceable>:<replaceable>END</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
@@ -2119,6 +2161,30 @@ OK
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="command_sticker_find_equals">
|
||||
<term>
|
||||
<cmdsynopsis>
|
||||
<command>sticker</command>
|
||||
<arg choice="plain">find</arg>
|
||||
<arg choice="req"><replaceable>TYPE</replaceable></arg>
|
||||
<arg choice="req"><replaceable>URI</replaceable></arg>
|
||||
<arg choice="req"><replaceable>NAME</replaceable></arg>
|
||||
<arg choice="plain">=</arg>
|
||||
<arg choice="req"><replaceable>VALUE</replaceable></arg>
|
||||
</cmdsynopsis>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>
|
||||
Searches for stickers with the given value.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Other supported operators are:
|
||||
"<function><</function>", "<function>></function>"
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
|
1525
doc/user.xml
1525
doc/user.xml
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS])
|
||||
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
@@ -20,6 +20,8 @@
|
||||
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
|
||||
# force the compiler to issue an error when a bad flag is given.
|
||||
#
|
||||
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
|
||||
#
|
||||
# NOTE: This macro depends on the AX_APPEND_FLAG and
|
||||
# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
|
||||
# AX_APPEND_LINK_FLAGS.
|
||||
@@ -54,12 +56,12 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 4
|
||||
#serial 5
|
||||
|
||||
AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
|
||||
[AX_REQUIRE_DEFINED([AX_CHECK_COMPILE_FLAG])
|
||||
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
|
||||
for flag in $1; do
|
||||
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3])
|
||||
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3], [$4])
|
||||
done
|
||||
])dnl AX_APPEND_COMPILE_FLAGS
|
||||
|
@@ -49,21 +49,23 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 2
|
||||
#serial 6
|
||||
|
||||
AC_DEFUN([AX_APPEND_FLAG],
|
||||
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
|
||||
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl
|
||||
AS_VAR_SET_IF(FLAGS,
|
||||
[case " AS_VAR_GET(FLAGS) " in
|
||||
*" $1 "*)
|
||||
AC_RUN_LOG([: FLAGS already contains $1])
|
||||
;;
|
||||
*)
|
||||
AC_RUN_LOG([: FLAGS="$FLAGS $1"])
|
||||
AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"])
|
||||
;;
|
||||
esac],
|
||||
[AS_VAR_SET(FLAGS,["$1"])])
|
||||
[dnl
|
||||
AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_SET_IF
|
||||
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])
|
||||
AS_VAR_SET_IF(FLAGS,[
|
||||
AS_CASE([" AS_VAR_GET(FLAGS) "],
|
||||
[*" $1 "*], [AC_RUN_LOG([: FLAGS already contains $1])],
|
||||
[
|
||||
AS_VAR_APPEND(FLAGS,[" $1"])
|
||||
AC_RUN_LOG([: FLAGS="$FLAGS"])
|
||||
])
|
||||
],
|
||||
[
|
||||
AS_VAR_SET(FLAGS,[$1])
|
||||
AC_RUN_LOG([: FLAGS="$FLAGS"])
|
||||
])
|
||||
AS_VAR_POPDEF([FLAGS])dnl
|
||||
])dnl AX_APPEND_FLAG
|
||||
|
@@ -4,7 +4,7 @@
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS])
|
||||
# AX_APPEND_LINK_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS], [INPUT])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
@@ -19,6 +19,8 @@
|
||||
# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
|
||||
# issue an error when a bad flag is given.
|
||||
#
|
||||
# INPUT gives an alternative input source to AC_COMPILE_IFELSE.
|
||||
#
|
||||
# NOTE: This macro depends on the AX_APPEND_FLAG and AX_CHECK_LINK_FLAG.
|
||||
# Please keep this macro in sync with AX_APPEND_COMPILE_FLAGS.
|
||||
#
|
||||
@@ -52,12 +54,12 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 4
|
||||
#serial 5
|
||||
|
||||
AC_DEFUN([AX_APPEND_LINK_FLAGS],
|
||||
[AX_REQUIRE_DEFINED([AX_CHECK_LINK_FLAG])
|
||||
AX_REQUIRE_DEFINED([AX_APPEND_FLAG])
|
||||
for flag in $1; do
|
||||
AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3])
|
||||
AX_CHECK_LINK_FLAG([$flag], [AX_APPEND_FLAG([$flag], [m4_default([$2], [LDFLAGS])])], [], [$3], [$4])
|
||||
done
|
||||
])dnl AX_APPEND_LINK_FLAGS
|
||||
|
@@ -33,7 +33,7 @@
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 23
|
||||
#serial 27
|
||||
|
||||
AC_DEFUN([AX_BOOST_BASE],
|
||||
[
|
||||
@@ -92,7 +92,10 @@ if test "x$want_boost" = "xyes"; then
|
||||
libsubdirs="lib"
|
||||
ax_arch=`uname -m`
|
||||
case $ax_arch in
|
||||
x86_64|ppc64|s390x|sparc64|aarch64)
|
||||
x86_64)
|
||||
libsubdirs="lib64 libx32 lib lib64"
|
||||
;;
|
||||
ppc64|s390x|sparc64|aarch64|ppc64le)
|
||||
libsubdirs="lib64 lib lib64"
|
||||
;;
|
||||
esac
|
||||
@@ -170,6 +173,10 @@ if test "x$want_boost" = "xyes"; then
|
||||
dnl if we found no boost with system layout we search for boost libraries
|
||||
dnl built and installed without the --layout=system option or for a staged(not installed) version
|
||||
if test "x$succeeded" != "xyes"; then
|
||||
CPPFLAGS="$CPPFLAGS_SAVED"
|
||||
LDFLAGS="$LDFLAGS_SAVED"
|
||||
BOOST_CPPFLAGS=
|
||||
BOOST_LDFLAGS=
|
||||
_version=0
|
||||
if test "$ac_boost_path" != ""; then
|
||||
if test -d "$ac_boost_path" && test -r "$ac_boost_path"; then
|
||||
@@ -182,6 +189,12 @@ if test "x$want_boost" = "xyes"; then
|
||||
VERSION_UNDERSCORE=`echo $_version | sed 's/\./_/'`
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path/include/boost-$VERSION_UNDERSCORE"
|
||||
done
|
||||
dnl if nothing found search for layout used in Windows distributions
|
||||
if test -z "$BOOST_CPPFLAGS"; then
|
||||
if test -d "$ac_boost_path/boost" && test -r "$ac_boost_path/boost"; then
|
||||
BOOST_CPPFLAGS="-I$ac_boost_path"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if test "$cross_compiling" != yes; then
|
||||
|
@@ -55,10 +55,10 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 3
|
||||
#serial 4
|
||||
|
||||
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
|
||||
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
|
||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
|
||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
|
||||
@@ -67,7 +67,7 @@ AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
|
||||
AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
|
||||
AS_VAR_IF(CACHEVAR,yes,
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
|
@@ -55,10 +55,11 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 3
|
||||
#serial 4
|
||||
|
||||
AC_DEFUN([AX_CHECK_LINK_FLAG],
|
||||
[AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
|
||||
[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
|
||||
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
|
||||
AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
|
||||
ax_check_save_flags=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS $4 $1"
|
||||
@@ -66,7 +67,7 @@ AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
|
||||
[AS_VAR_SET(CACHEVAR,[yes])],
|
||||
[AS_VAR_SET(CACHEVAR,[no])])
|
||||
LDFLAGS=$ax_check_save_flags])
|
||||
AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
|
||||
AS_VAR_IF(CACHEVAR,yes,
|
||||
[m4_default([$2], :)],
|
||||
[m4_default([$3], :)])
|
||||
AS_VAR_POPDEF([CACHEVAR])dnl
|
||||
|
564
m4/ax_cxx_compile_stdcxx.m4
Normal file
564
m4/ax_cxx_compile_stdcxx.m4
Normal file
@@ -0,0 +1,564 @@
|
||||
# ===========================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
|
||||
# ===========================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the specified
|
||||
# version of the C++ standard. If necessary, add switches to CXX and
|
||||
# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
|
||||
# or '14' (for the C++14 standard).
|
||||
#
|
||||
# The second argument, if specified, indicates whether you insist on an
|
||||
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
|
||||
# -std=c++11). If neither is specified, you get whatever works, with
|
||||
# preference for an extended mode.
|
||||
#
|
||||
# The third argument, if specified 'mandatory' or if left unspecified,
|
||||
# indicates that baseline support for the specified C++ standard is
|
||||
# required and that the macro should error out if no mode with that
|
||||
# support is found. If specified 'optional', then configuration proceeds
|
||||
# regardless, after defining HAVE_CXX${VERSION} if and only if a
|
||||
# supporting mode is found.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
|
||||
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
|
||||
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
|
||||
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
|
||||
# Copyright (c) 2015 Paul Norman <penorman@mac.com>
|
||||
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 4
|
||||
|
||||
dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
|
||||
dnl (serial version number 13).
|
||||
|
||||
AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
|
||||
m4_if([$1], [11], [],
|
||||
[$1], [14], [],
|
||||
[$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
|
||||
[m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||
m4_if([$2], [], [],
|
||||
[$2], [ext], [],
|
||||
[$2], [noext], [],
|
||||
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
|
||||
m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
|
||||
[$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
|
||||
[$3], [optional], [ax_cxx_compile_cxx$1_required=false],
|
||||
[m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
|
||||
AC_LANG_PUSH([C++])dnl
|
||||
ac_success=no
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
|
||||
ax_cv_cxx_compile_cxx$1,
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[ax_cv_cxx_compile_cxx$1=yes],
|
||||
[ax_cv_cxx_compile_cxx$1=no])])
|
||||
if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
|
||||
ac_success=yes
|
||||
fi
|
||||
|
||||
m4_if([$2], [noext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
for switch in -std=gnu++$1 -std=gnu++0x; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXX="$CXX"
|
||||
CXX="$CXX $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXX="$ac_save_CXX"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXX="$CXX $switch"
|
||||
if test -n "$CXXCPP" ; then
|
||||
CXXCPP="$CXXCPP $switch"
|
||||
fi
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
|
||||
m4_if([$2], [ext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
dnl HP's aCC needs +std=c++11 according to:
|
||||
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
|
||||
dnl Cray's crayCC needs "-h std=c++11"
|
||||
for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXX="$CXX"
|
||||
CXX="$CXX $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXX="$ac_save_CXX"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXX="$CXX $switch"
|
||||
if test -n "$CXXCPP" ; then
|
||||
CXXCPP="$CXXCPP $switch"
|
||||
fi
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
AC_LANG_POP([C++])
|
||||
if test x$ax_cxx_compile_cxx$1_required = xtrue; then
|
||||
if test x$ac_success = xno; then
|
||||
AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
|
||||
fi
|
||||
fi
|
||||
if test x$ac_success = xno; then
|
||||
HAVE_CXX$1=0
|
||||
AC_MSG_NOTICE([No compiler with C++$1 support was found])
|
||||
else
|
||||
HAVE_CXX$1=1
|
||||
AC_DEFINE(HAVE_CXX$1,1,
|
||||
[define if the compiler supports basic C++$1 syntax])
|
||||
fi
|
||||
AC_SUBST(HAVE_CXX$1)
|
||||
])
|
||||
|
||||
|
||||
dnl Test body for checking C++11 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
)
|
||||
|
||||
|
||||
dnl Test body for checking C++14 support
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_11
|
||||
_AX_CXX_COMPILE_STDCXX_testbody_new_in_14
|
||||
)
|
||||
|
||||
|
||||
dnl Tests for new features in C++11
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
|
||||
|
||||
// If the compiler admits that it is not ready for C++11, why torture it?
|
||||
// Hopefully, this will speed up the test.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201103L
|
||||
|
||||
#error "This is not a C++11 compiler"
|
||||
|
||||
#else
|
||||
|
||||
namespace cxx11
|
||||
{
|
||||
|
||||
namespace test_static_assert
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace test_final_override
|
||||
{
|
||||
|
||||
struct Base
|
||||
{
|
||||
virtual void f() {}
|
||||
};
|
||||
|
||||
struct Derived : public Base
|
||||
{
|
||||
virtual void f() override {}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace test_double_right_angle_brackets
|
||||
{
|
||||
|
||||
template < typename T >
|
||||
struct check {};
|
||||
|
||||
typedef check<void> single_type;
|
||||
typedef check<check<void>> double_type;
|
||||
typedef check<check<check<void>>> triple_type;
|
||||
typedef check<check<check<check<void>>>> quadruple_type;
|
||||
|
||||
}
|
||||
|
||||
namespace test_decltype
|
||||
{
|
||||
|
||||
int
|
||||
f()
|
||||
{
|
||||
int a = 1;
|
||||
decltype(a) b = 2;
|
||||
return a + b;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_type_deduction
|
||||
{
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
struct is_same
|
||||
{
|
||||
static const bool value = false;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct is_same<T, T>
|
||||
{
|
||||
static const bool value = true;
|
||||
};
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
auto
|
||||
add(T1 a1, T2 a2) -> decltype(a1 + a2)
|
||||
{
|
||||
return a1 + a2;
|
||||
}
|
||||
|
||||
int
|
||||
test(const int c, volatile int v)
|
||||
{
|
||||
static_assert(is_same<int, decltype(0)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(c)>::value == false, "");
|
||||
static_assert(is_same<int, decltype(v)>::value == false, "");
|
||||
auto ac = c;
|
||||
auto av = v;
|
||||
auto sumi = ac + av + 'x';
|
||||
auto sumf = ac + av + 1.0;
|
||||
static_assert(is_same<int, decltype(ac)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(av)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(sumi)>::value == true, "");
|
||||
static_assert(is_same<int, decltype(sumf)>::value == false, "");
|
||||
static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
|
||||
return (sumf > 0.0) ? sumi : add(c, v);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_noexcept
|
||||
{
|
||||
|
||||
int f() { return 0; }
|
||||
int g() noexcept { return 0; }
|
||||
|
||||
static_assert(noexcept(f()) == false, "");
|
||||
static_assert(noexcept(g()) == true, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_constexpr
|
||||
{
|
||||
|
||||
template < typename CharT >
|
||||
unsigned long constexpr
|
||||
strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
|
||||
{
|
||||
return *s ? strlen_c_r(s + 1, acc + 1) : acc;
|
||||
}
|
||||
|
||||
template < typename CharT >
|
||||
unsigned long constexpr
|
||||
strlen_c(const CharT *const s) noexcept
|
||||
{
|
||||
return strlen_c_r(s, 0UL);
|
||||
}
|
||||
|
||||
static_assert(strlen_c("") == 0UL, "");
|
||||
static_assert(strlen_c("1") == 1UL, "");
|
||||
static_assert(strlen_c("example") == 7UL, "");
|
||||
static_assert(strlen_c("another\0example") == 7UL, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_rvalue_references
|
||||
{
|
||||
|
||||
template < int N >
|
||||
struct answer
|
||||
{
|
||||
static constexpr int value = N;
|
||||
};
|
||||
|
||||
answer<1> f(int&) { return answer<1>(); }
|
||||
answer<2> f(const int&) { return answer<2>(); }
|
||||
answer<3> f(int&&) { return answer<3>(); }
|
||||
|
||||
void
|
||||
test()
|
||||
{
|
||||
int i = 0;
|
||||
const int c = 0;
|
||||
static_assert(decltype(f(i))::value == 1, "");
|
||||
static_assert(decltype(f(c))::value == 2, "");
|
||||
static_assert(decltype(f(0))::value == 3, "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_uniform_initialization
|
||||
{
|
||||
|
||||
struct test
|
||||
{
|
||||
static const int zero {};
|
||||
static const int one {1};
|
||||
};
|
||||
|
||||
static_assert(test::zero == 0, "");
|
||||
static_assert(test::one == 1, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_lambdas
|
||||
{
|
||||
|
||||
void
|
||||
test1()
|
||||
{
|
||||
auto lambda1 = [](){};
|
||||
auto lambda2 = lambda1;
|
||||
lambda1();
|
||||
lambda2();
|
||||
}
|
||||
|
||||
int
|
||||
test2()
|
||||
{
|
||||
auto a = [](int i, int j){ return i + j; }(1, 2);
|
||||
auto b = []() -> int { return '0'; }();
|
||||
auto c = [=](){ return a + b; }();
|
||||
auto d = [&](){ return c; }();
|
||||
auto e = [a, &b](int x) mutable {
|
||||
const auto identity = [](int y){ return y; };
|
||||
for (auto i = 0; i < a; ++i)
|
||||
a += b--;
|
||||
return x + identity(a + b);
|
||||
}(0);
|
||||
return a + b + c + d + e;
|
||||
}
|
||||
|
||||
int
|
||||
test3()
|
||||
{
|
||||
const auto nullary = [](){ return 0; };
|
||||
const auto unary = [](int x){ return x; };
|
||||
using nullary_t = decltype(nullary);
|
||||
using unary_t = decltype(unary);
|
||||
const auto higher1st = [](nullary_t f){ return f(); };
|
||||
const auto higher2nd = [unary](nullary_t f1){
|
||||
return [unary, f1](unary_t f2){ return f2(unary(f1())); };
|
||||
};
|
||||
return higher1st(nullary) + higher2nd(nullary)(unary);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_variadic_templates
|
||||
{
|
||||
|
||||
template <int...>
|
||||
struct sum;
|
||||
|
||||
template <int N0, int... N1toN>
|
||||
struct sum<N0, N1toN...>
|
||||
{
|
||||
static constexpr auto value = N0 + sum<N1toN...>::value;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct sum<>
|
||||
{
|
||||
static constexpr auto value = 0;
|
||||
};
|
||||
|
||||
static_assert(sum<>::value == 0, "");
|
||||
static_assert(sum<1>::value == 1, "");
|
||||
static_assert(sum<23>::value == 23, "");
|
||||
static_assert(sum<1, 2>::value == 3, "");
|
||||
static_assert(sum<5, 5, 11>::value == 21, "");
|
||||
static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
|
||||
|
||||
}
|
||||
|
||||
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
|
||||
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
|
||||
// because of this.
|
||||
namespace test_template_alias_sfinae
|
||||
{
|
||||
|
||||
struct foo {};
|
||||
|
||||
template<typename T>
|
||||
using member = typename T::member_type;
|
||||
|
||||
template<typename T>
|
||||
void func(...) {}
|
||||
|
||||
template<typename T>
|
||||
void func(member<T>*) {}
|
||||
|
||||
void test();
|
||||
|
||||
void test() { func<foo>(0); }
|
||||
|
||||
}
|
||||
|
||||
} // namespace cxx11
|
||||
|
||||
#endif // __cplusplus >= 201103L
|
||||
|
||||
]])
|
||||
|
||||
|
||||
dnl Tests for new features in C++14
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
|
||||
|
||||
// If the compiler admits that it is not ready for C++14, why torture it?
|
||||
// Hopefully, this will speed up the test.
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
#error "This is not a C++ compiler"
|
||||
|
||||
#elif __cplusplus < 201300L
|
||||
|
||||
#error "This is not a C++14 compiler"
|
||||
|
||||
#else
|
||||
|
||||
namespace cxx14
|
||||
{
|
||||
|
||||
namespace test_polymorphic_lambdas
|
||||
{
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
const auto lambda = [](auto&&... args){
|
||||
const auto istiny = [](auto x){
|
||||
return (sizeof(x) == 1UL) ? 1 : 0;
|
||||
};
|
||||
const int aretiny[] = { istiny(args)... };
|
||||
return aretiny[0];
|
||||
};
|
||||
return lambda(1, 1L, 1.0f, '1');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_binary_literals
|
||||
{
|
||||
|
||||
constexpr auto ivii = 0b0000000000101010;
|
||||
static_assert(ivii == 42, "wrong value");
|
||||
|
||||
}
|
||||
|
||||
#ifdef DISALLOW_GCC48
|
||||
namespace test_generalized_constexpr
|
||||
{
|
||||
|
||||
template < typename CharT >
|
||||
constexpr unsigned long
|
||||
strlen_c(const CharT *const s) noexcept
|
||||
{
|
||||
auto length = 0UL;
|
||||
for (auto p = s; *p; ++p)
|
||||
++length;
|
||||
return length;
|
||||
}
|
||||
|
||||
static_assert(strlen_c("") == 0UL, "");
|
||||
static_assert(strlen_c("x") == 1UL, "");
|
||||
static_assert(strlen_c("test") == 4UL, "");
|
||||
static_assert(strlen_c("another\0test") == 7UL, "");
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace test_lambda_init_capture
|
||||
{
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
auto x = 0;
|
||||
const auto lambda1 = [a = x](int b){ return a + b; };
|
||||
const auto lambda2 = [a = lambda1(x)](){ return a; };
|
||||
return lambda2();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace test_digit_seperators
|
||||
{
|
||||
|
||||
constexpr auto ten_million = 100'000'000;
|
||||
static_assert(ten_million == 100000000, "");
|
||||
|
||||
}
|
||||
|
||||
namespace test_return_type_deduction
|
||||
{
|
||||
|
||||
auto f(int& x) { return x; }
|
||||
decltype(auto) g(int& x) { return x; }
|
||||
|
||||
template < typename T1, typename T2 >
|
||||
struct is_same
|
||||
{
|
||||
static constexpr auto value = false;
|
||||
};
|
||||
|
||||
template < typename T >
|
||||
struct is_same<T, T>
|
||||
{
|
||||
static constexpr auto value = true;
|
||||
};
|
||||
|
||||
int
|
||||
test()
|
||||
{
|
||||
auto x = 0;
|
||||
static_assert(is_same<int, decltype(f(x))>::value, "");
|
||||
static_assert(is_same<int&, decltype(g(x))>::value, "");
|
||||
return x;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace cxx14
|
||||
|
||||
#endif // __cplusplus >= 201402L
|
||||
|
||||
]])
|
@@ -1,107 +0,0 @@
|
||||
# ============================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_0x.html
|
||||
# ============================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX_0X
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the C++0x
|
||||
# standard.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 7
|
||||
|
||||
AU_ALIAS([AC_CXX_COMPILE_STDCXX_0X], [AX_CXX_COMPILE_STDCXX_0X])
|
||||
AC_DEFUN([AX_CXX_COMPILE_STDCXX_0X], [
|
||||
AC_CACHE_CHECK(if g++ supports C++0x features without additional flags,
|
||||
ax_cv_cxx_compile_cxx0x_native,
|
||||
[AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
AC_TRY_COMPILE([
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);],,
|
||||
ax_cv_cxx_compile_cxx0x_native=yes, ax_cv_cxx_compile_cxx0x_native=no)
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK(if g++ supports C++0x features with -std=c++0x,
|
||||
ax_cv_cxx_compile_cxx0x_cxx,
|
||||
[AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS -std=c++0x"
|
||||
AC_TRY_COMPILE([
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);],,
|
||||
ax_cv_cxx_compile_cxx0x_cxx=yes, ax_cv_cxx_compile_cxx0x_cxx=no)
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK(if g++ supports C++0x features with -std=gnu++0x,
|
||||
ax_cv_cxx_compile_cxx0x_gxx,
|
||||
[AC_LANG_SAVE
|
||||
AC_LANG_CPLUSPLUS
|
||||
ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS -std=gnu++0x"
|
||||
AC_TRY_COMPILE([
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);],,
|
||||
ax_cv_cxx_compile_cxx0x_gxx=yes, ax_cv_cxx_compile_cxx0x_gxx=no)
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"
|
||||
AC_LANG_RESTORE
|
||||
])
|
||||
|
||||
if test "$ax_cv_cxx_compile_cxx0x_native" = yes ||
|
||||
test "$ax_cv_cxx_compile_cxx0x_cxx" = yes ||
|
||||
test "$ax_cv_cxx_compile_cxx0x_gxx" = yes; then
|
||||
AC_DEFINE(HAVE_STDCXX_0X,,[Define if g++ supports C++0x features. ])
|
||||
fi
|
||||
])
|
34
m4/ax_cxx_compile_stdcxx_14.m4
Normal file
34
m4/ax_cxx_compile_stdcxx_14.m4
Normal file
@@ -0,0 +1,34 @@
|
||||
# ============================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_14.html
|
||||
# ============================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX_14([ext|noext], [mandatory|optional])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the C++14
|
||||
# standard; if necessary, add switches to CXX and CXXCPP to enable
|
||||
# support.
|
||||
#
|
||||
# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX
|
||||
# macro with the version set to C++14. The two optional arguments are
|
||||
# forwarded literally as the second and third argument respectively.
|
||||
# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for
|
||||
# more information. If you want to use this macro, you also need to
|
||||
# download the ax_cxx_compile_stdcxx.m4 file.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2015 Moritz Klammler <moritz@klammler.eu>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 4
|
||||
|
||||
AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX])
|
||||
AC_DEFUN([AX_CXX_COMPILE_STDCXX_14], [AX_CXX_COMPILE_STDCXX([14], [$1], [$2])])
|
387
m4/ax_pthread.m4
387
m4/ax_pthread.m4
@@ -19,10 +19,10 @@
|
||||
# is necessary on AIX to use the special cc_r compiler alias.)
|
||||
#
|
||||
# NOTE: You are assumed to not only compile your program with these flags,
|
||||
# but also link it with them as well. e.g. you should link with
|
||||
# but also to link with them as well. For example, you might link with
|
||||
# $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
|
||||
#
|
||||
# If you are only building threads programs, you may wish to use these
|
||||
# If you are only building threaded programs, you may wish to use these
|
||||
# variables in your default LIBS, CFLAGS, and CC:
|
||||
#
|
||||
# LIBS="$PTHREAD_LIBS $LIBS"
|
||||
@@ -30,8 +30,8 @@
|
||||
# CC="$PTHREAD_CC"
|
||||
#
|
||||
# In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
|
||||
# has a nonstandard name, defines PTHREAD_CREATE_JOINABLE to that name
|
||||
# (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
# has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
|
||||
# that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
|
||||
#
|
||||
# Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
|
||||
# PTHREAD_PRIO_INHERIT symbol is defined when compiling with
|
||||
@@ -82,35 +82,40 @@
|
||||
# modified version of the Autoconf Macro, you may extend this special
|
||||
# exception to the GPL to apply to your modified version as well.
|
||||
|
||||
#serial 21
|
||||
#serial 23
|
||||
|
||||
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
|
||||
AC_DEFUN([AX_PTHREAD], [
|
||||
AC_REQUIRE([AC_CANONICAL_HOST])
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([AC_PROG_SED])
|
||||
AC_LANG_PUSH([C])
|
||||
ax_pthread_ok=no
|
||||
|
||||
# We used to check for pthread.h first, but this fails if pthread.h
|
||||
# requires special compiler flags (e.g. on True64 or Sequent).
|
||||
# requires special compiler flags (e.g. on Tru64 or Sequent).
|
||||
# It gets checked for in the link test anyway.
|
||||
|
||||
# First of all, check if the user has set any of the PTHREAD_LIBS,
|
||||
# etcetera environment variables, and if threads linking works using
|
||||
# them:
|
||||
if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then
|
||||
save_CFLAGS="$CFLAGS"
|
||||
if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
|
||||
ax_pthread_save_CC="$CC"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS])
|
||||
AC_TRY_LINK_FUNC([pthread_join], [ax_pthread_ok=yes])
|
||||
AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
|
||||
AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
fi
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CC="$ax_pthread_save_CC"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
fi
|
||||
|
||||
# We must check for the threads library under a number of different
|
||||
@@ -123,7 +128,7 @@ fi
|
||||
# which indicates that we try without any flags at all, and "pthread-config"
|
||||
# which is a program returning the flags for the Pth emulation library.
|
||||
|
||||
ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
|
||||
|
||||
# The ordering *is* (sometimes) important. Some notes on the
|
||||
# individual items follow:
|
||||
@@ -132,82 +137,225 @@ ax_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mt
|
||||
# none: in case threads are in libc; should be tried before -Kthread and
|
||||
# other compiler flags to prevent continual compiler warnings
|
||||
# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads)
|
||||
# -pthreads: Solaris/gcc
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
|
||||
# (Note: HP C rejects this with "bad form for `-t' option")
|
||||
# -pthreads: Solaris/gcc (Note: HP C also rejects)
|
||||
# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
|
||||
# doesn't hurt to check since this sometimes defines pthreads too;
|
||||
# also defines -D_REENTRANT)
|
||||
# ... -mt is also the pthreads flag for HP/aCC
|
||||
# doesn't hurt to check since this sometimes defines pthreads and
|
||||
# -D_REENTRANT too), HP C (must be checked before -lpthread, which
|
||||
# is present but should not be used directly; and before -mthreads,
|
||||
# because the compiler interprets this as "-mt" + "-hreads")
|
||||
# -mthreads: Mingw32/gcc, Lynx/gcc
|
||||
# pthread: Linux, etcetera
|
||||
# --thread-safe: KAI C++
|
||||
# pthread-config: use pthread-config program (for GNU Pth library)
|
||||
|
||||
case ${host_os} in
|
||||
case $host_os in
|
||||
|
||||
freebsd*)
|
||||
|
||||
# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
|
||||
# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
|
||||
|
||||
ax_pthread_flags="-kthread lthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
hpux*)
|
||||
|
||||
# From the cc(1) man page: "[-mt] Sets various -D flags to enable
|
||||
# multi-threading and also sets -lpthread."
|
||||
|
||||
ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
openedition*)
|
||||
|
||||
# IBM z/OS requires a feature-test macro to be defined in order to
|
||||
# enable POSIX threads at all, so give the user a hint if this is
|
||||
# not set. (We don't define these ourselves, as they can affect
|
||||
# other portions of the system API in unpredictable ways.)
|
||||
|
||||
AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
|
||||
[
|
||||
# if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
|
||||
AX_PTHREAD_ZOS_MISSING
|
||||
# endif
|
||||
],
|
||||
[AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
|
||||
;;
|
||||
|
||||
solaris*)
|
||||
|
||||
# On Solaris (at least, for some versions), libc contains stubbed
|
||||
# (non-functional) versions of the pthreads routines, so link-based
|
||||
# tests will erroneously succeed. (We need to link with -pthreads/-mt/
|
||||
# -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
|
||||
# a function called by this macro, so we could check for that, but
|
||||
# who knows whether they'll stub that too in a future libc.) So,
|
||||
# we'll just look for -pthreads and -lpthread first:
|
||||
# tests will erroneously succeed. (N.B.: The stubs are missing
|
||||
# pthread_cleanup_push, or rather a function called by this macro,
|
||||
# so we could check for that, but who knows whether they'll stub
|
||||
# that too in a future libc.) So we'll check first for the
|
||||
# standard Solaris way of linking pthreads (-mt -lpthread).
|
||||
|
||||
ax_pthread_flags="-pthreads pthread -mt -pthread $ax_pthread_flags"
|
||||
;;
|
||||
|
||||
darwin*)
|
||||
ax_pthread_flags="-pthread $ax_pthread_flags"
|
||||
ax_pthread_flags="-mt,pthread pthread $ax_pthread_flags"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Clang doesn't consider unrecognized options an error unless we specify
|
||||
# -Werror. We throw in some extra Clang-specific options to ensure that
|
||||
# this doesn't happen for GCC, which also accepts -Werror.
|
||||
# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
|
||||
|
||||
AC_MSG_CHECKING([if compiler needs -Werror to reject unknown flags])
|
||||
save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_extra_flags="-Werror"
|
||||
CFLAGS="$CFLAGS $ax_pthread_extra_flags -Wunknown-warning-option -Wsizeof-array-argument"
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([int foo(void);],[foo()])],
|
||||
[AC_MSG_RESULT([yes])],
|
||||
[ax_pthread_extra_flags=
|
||||
AC_MSG_RESULT([no])])
|
||||
CFLAGS="$save_CFLAGS"
|
||||
AS_IF([test "x$GCC" = "xyes"],
|
||||
[ax_pthread_flags="-pthread -pthreads $ax_pthread_flags"])
|
||||
|
||||
if test x"$ax_pthread_ok" = xno; then
|
||||
for flag in $ax_pthread_flags; do
|
||||
# The presence of a feature test macro requesting re-entrant function
|
||||
# definitions is, on some systems, a strong hint that pthreads support is
|
||||
# correctly enabled
|
||||
|
||||
case $flag in
|
||||
case $host_os in
|
||||
darwin* | hpux* | linux* | osf* | solaris*)
|
||||
ax_pthread_check_macro="_REENTRANT"
|
||||
;;
|
||||
|
||||
aix*)
|
||||
ax_pthread_check_macro="_THREAD_SAFE"
|
||||
;;
|
||||
|
||||
*)
|
||||
ax_pthread_check_macro="--"
|
||||
;;
|
||||
esac
|
||||
AS_IF([test "x$ax_pthread_check_macro" = "x--"],
|
||||
[ax_pthread_check_cond=0],
|
||||
[ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
|
||||
|
||||
# Are we compiling with Clang?
|
||||
|
||||
AC_CACHE_CHECK([whether $CC is Clang],
|
||||
[ax_cv_PTHREAD_CLANG],
|
||||
[ax_cv_PTHREAD_CLANG=no
|
||||
# Note that Autoconf sets GCC=yes for Clang as well as GCC
|
||||
if test "x$GCC" = "xyes"; then
|
||||
AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
|
||||
[/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
|
||||
# if defined(__clang__) && defined(__llvm__)
|
||||
AX_PTHREAD_CC_IS_CLANG
|
||||
# endif
|
||||
],
|
||||
[ax_cv_PTHREAD_CLANG=yes])
|
||||
fi
|
||||
])
|
||||
ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
|
||||
|
||||
ax_pthread_clang_warning=no
|
||||
|
||||
# Clang needs special handling, because older versions handle the -pthread
|
||||
# option in a rather... idiosyncratic way
|
||||
|
||||
if test "x$ax_pthread_clang" = "xyes"; then
|
||||
|
||||
# Clang takes -pthread; it has never supported any other flag
|
||||
|
||||
# (Note 1: This will need to be revisited if a system that Clang
|
||||
# supports has POSIX threads in a separate library. This tends not
|
||||
# to be the way of modern systems, but it's conceivable.)
|
||||
|
||||
# (Note 2: On some systems, notably Darwin, -pthread is not needed
|
||||
# to get POSIX threads support; the API is always present and
|
||||
# active. We could reasonably leave PTHREAD_CFLAGS empty. But
|
||||
# -pthread does define _REENTRANT, and while the Darwin headers
|
||||
# ignore this macro, third-party headers might not.)
|
||||
|
||||
PTHREAD_CFLAGS="-pthread"
|
||||
PTHREAD_LIBS=
|
||||
|
||||
ax_pthread_ok=yes
|
||||
|
||||
# However, older versions of Clang make a point of warning the user
|
||||
# that, in an invocation where only linking and no compilation is
|
||||
# taking place, the -pthread option has no effect ("argument unused
|
||||
# during compilation"). They expect -pthread to be passed in only
|
||||
# when source code is being compiled.
|
||||
#
|
||||
# Problem is, this is at odds with the way Automake and most other
|
||||
# C build frameworks function, which is that the same flags used in
|
||||
# compilation (CFLAGS) are also used in linking. Many systems
|
||||
# supported by AX_PTHREAD require exactly this for POSIX threads
|
||||
# support, and in fact it is often not straightforward to specify a
|
||||
# flag that is used only in the compilation phase and not in
|
||||
# linking. Such a scenario is extremely rare in practice.
|
||||
#
|
||||
# Even though use of the -pthread flag in linking would only print
|
||||
# a warning, this can be a nuisance for well-run software projects
|
||||
# that build with -Werror. So if the active version of Clang has
|
||||
# this misfeature, we search for an option to squash it.
|
||||
|
||||
AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
|
||||
[ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
|
||||
# Create an alternate version of $ac_link that compiles and
|
||||
# links in two steps (.c -> .o, .o -> exe) instead of one
|
||||
# (.c -> exe), because the warning occurs only in the second
|
||||
# step
|
||||
ax_pthread_save_ac_link="$ac_link"
|
||||
ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
|
||||
ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
|
||||
ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
|
||||
AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
|
||||
CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[ac_link="$ax_pthread_2step_ac_link"
|
||||
AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
|
||||
[break])
|
||||
])
|
||||
done
|
||||
ac_link="$ax_pthread_save_ac_link"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
|
||||
ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
|
||||
])
|
||||
|
||||
case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
|
||||
no | unknown) ;;
|
||||
*) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
|
||||
esac
|
||||
|
||||
fi # $ax_pthread_clang = yes
|
||||
|
||||
if test "x$ax_pthread_ok" = "xno"; then
|
||||
for ax_pthread_try_flag in $ax_pthread_flags; do
|
||||
|
||||
case $ax_pthread_try_flag in
|
||||
none)
|
||||
AC_MSG_CHECKING([whether pthreads work without any flags])
|
||||
;;
|
||||
|
||||
-mt,pthread)
|
||||
AC_MSG_CHECKING([whether pthreads work with -mt -lpthread])
|
||||
PTHREAD_CFLAGS="-mt"
|
||||
PTHREAD_LIBS="-lpthread"
|
||||
;;
|
||||
|
||||
-*)
|
||||
AC_MSG_CHECKING([whether pthreads work with $flag])
|
||||
PTHREAD_CFLAGS="$flag"
|
||||
AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
|
||||
PTHREAD_CFLAGS="$ax_pthread_try_flag"
|
||||
;;
|
||||
|
||||
pthread-config)
|
||||
AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
|
||||
if test x"$ax_pthread_config" = xno; then continue; fi
|
||||
AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
|
||||
PTHREAD_CFLAGS="`pthread-config --cflags`"
|
||||
PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
|
||||
;;
|
||||
|
||||
*)
|
||||
AC_MSG_CHECKING([for the pthreads library -l$flag])
|
||||
PTHREAD_LIBS="-l$flag"
|
||||
AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
|
||||
PTHREAD_LIBS="-l$ax_pthread_try_flag"
|
||||
;;
|
||||
esac
|
||||
|
||||
save_LIBS="$LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $ax_pthread_extra_flags"
|
||||
|
||||
# Check for various functions. We must include pthread.h,
|
||||
# since some functions may be macros. (On the Sequent, we
|
||||
@@ -218,7 +366,11 @@ for flag in $ax_pthread_flags; do
|
||||
# pthread_cleanup_push because it is one of the few pthread
|
||||
# functions on Solaris that doesn't have a non-functional libc stub.
|
||||
# We try pthread_create on general principles.
|
||||
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
|
||||
# if $ax_pthread_check_cond
|
||||
# error "$ax_pthread_check_macro must be defined"
|
||||
# endif
|
||||
static void routine(void *a) { a = 0; }
|
||||
static void *start_routine(void *a) { return a; }],
|
||||
[pthread_t th; pthread_attr_t attr;
|
||||
@@ -227,16 +379,14 @@ for flag in $ax_pthread_flags; do
|
||||
pthread_attr_init(&attr);
|
||||
pthread_cleanup_push(routine, 0);
|
||||
pthread_cleanup_pop(0) /* ; */])],
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
[ax_pthread_ok=yes],
|
||||
[])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
AC_MSG_RESULT([$ax_pthread_ok])
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
break;
|
||||
fi
|
||||
AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
|
||||
|
||||
PTHREAD_LIBS=""
|
||||
PTHREAD_CFLAGS=""
|
||||
@@ -244,71 +394,74 @@ done
|
||||
fi
|
||||
|
||||
# Various other checks:
|
||||
if test "x$ax_pthread_ok" = xyes; then
|
||||
save_LIBS="$LIBS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
save_CFLAGS="$CFLAGS"
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ax_pthread_save_CFLAGS="$CFLAGS"
|
||||
ax_pthread_save_LIBS="$LIBS"
|
||||
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
|
||||
LIBS="$PTHREAD_LIBS $LIBS"
|
||||
|
||||
# Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
|
||||
AC_MSG_CHECKING([for joinable pthread attribute])
|
||||
attr_name=unknown
|
||||
for attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $attr; return attr /* ; */])],
|
||||
[attr_name=$attr; break],
|
||||
[])
|
||||
done
|
||||
AC_MSG_RESULT([$attr_name])
|
||||
if test "$attr_name" != PTHREAD_CREATE_JOINABLE; then
|
||||
AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE], [$attr_name],
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
fi
|
||||
AC_CACHE_CHECK([for joinable pthread attribute],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=unknown
|
||||
for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
|
||||
[int attr = $ax_pthread_attr; return attr /* ; */])],
|
||||
[ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
|
||||
[])
|
||||
done
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
|
||||
test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
|
||||
test "x$ax_pthread_joinable_attr_defined" != "xyes"],
|
||||
[AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
|
||||
[$ax_cv_PTHREAD_JOINABLE_ATTR],
|
||||
[Define to necessary symbol if this constant
|
||||
uses a non-standard name on your system.])
|
||||
ax_pthread_joinable_attr_defined=yes
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING([if more special flags are required for pthreads])
|
||||
flag=no
|
||||
case ${host_os} in
|
||||
aix* | freebsd* | darwin*) flag="-D_THREAD_SAFE";;
|
||||
osf* | hpux*) flag="-D_REENTRANT";;
|
||||
solaris*)
|
||||
if test "$GCC" = "yes"; then
|
||||
flag="-D_REENTRANT"
|
||||
else
|
||||
# TODO: What about Clang on Solaris?
|
||||
flag="-mt -D_REENTRANT"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
AC_MSG_RESULT([$flag])
|
||||
if test "x$flag" != xno; then
|
||||
PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS"
|
||||
fi
|
||||
AC_CACHE_CHECK([whether more special flags are required for pthreads],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS],
|
||||
[ax_cv_PTHREAD_SPECIAL_FLAGS=no
|
||||
case $host_os in
|
||||
solaris*)
|
||||
ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
|
||||
;;
|
||||
esac
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
|
||||
test "x$ax_pthread_special_flags_added" != "xyes"],
|
||||
[PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
|
||||
ax_pthread_special_flags_added=yes])
|
||||
|
||||
AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT],
|
||||
[AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
|
||||
[[int i = PTHREAD_PRIO_INHERIT;]])],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=yes],
|
||||
[ax_cv_PTHREAD_PRIO_INHERIT=no])
|
||||
])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])])
|
||||
AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
|
||||
test "x$ax_pthread_prio_inherit_defined" != "xyes"],
|
||||
[AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
|
||||
ax_pthread_prio_inherit_defined=yes
|
||||
])
|
||||
|
||||
LIBS="$save_LIBS"
|
||||
CFLAGS="$save_CFLAGS"
|
||||
CFLAGS="$ax_pthread_save_CFLAGS"
|
||||
LIBS="$ax_pthread_save_LIBS"
|
||||
|
||||
# More AIX lossage: compile with *_r variant
|
||||
if test "x$GCC" != xyes; then
|
||||
if test "x$GCC" != "xyes"; then
|
||||
case $host_os in
|
||||
aix*)
|
||||
AS_CASE(["x/$CC"],
|
||||
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
|
||||
[#handle absolute path differently from PATH based program lookup
|
||||
AS_CASE(["x$CC"],
|
||||
[x/*],
|
||||
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
|
||||
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
|
||||
[x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
|
||||
[#handle absolute path differently from PATH based program lookup
|
||||
AS_CASE(["x$CC"],
|
||||
[x/*],
|
||||
[AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])],
|
||||
[AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])])])
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
@@ -321,7 +474,7 @@ AC_SUBST([PTHREAD_CFLAGS])
|
||||
AC_SUBST([PTHREAD_CC])
|
||||
|
||||
# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
|
||||
if test x"$ax_pthread_ok" = xyes; then
|
||||
if test "x$ax_pthread_ok" = "xyes"; then
|
||||
ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
|
||||
:
|
||||
else
|
||||
|
73
m4/faad.m4
73
m4/faad.m4
@@ -1,73 +0,0 @@
|
||||
AC_DEFUN([AM_PATH_FAAD],
|
||||
[dnl ##
|
||||
dnl faad
|
||||
dnl ##
|
||||
|
||||
AC_ARG_ENABLE(aac,
|
||||
AS_HELP_STRING([--disable-aac],
|
||||
[disable AAC support (default: enable)]),,
|
||||
enable_aac=yes)
|
||||
|
||||
if test x$enable_aac = xyes; then
|
||||
FAAD_LIBS="-lfaad"
|
||||
FAAD_CFLAGS=""
|
||||
|
||||
oldcflags=$CFLAGS
|
||||
oldlibs=$LIBS
|
||||
oldcppflags=$CPPFLAGS
|
||||
CFLAGS="$CFLAGS $FAAD_CFLAGS"
|
||||
LIBS="$LIBS $FAAD_LIBS"
|
||||
CPPFLAGS=$CFLAGS
|
||||
AC_CHECK_HEADER(faad.h,,enable_aac=no)
|
||||
if test x$enable_aac = xyes; then
|
||||
AC_CHECK_DECL(FAAD2_VERSION,,enable_aac=no,[#include <faad.h>])
|
||||
fi
|
||||
if test x$enable_aac = xyes; then
|
||||
AC_CHECK_LIB(faad,NeAACDecInit2,,enable_aac=no)
|
||||
fi
|
||||
if test x$enable_aac = xyes; then
|
||||
AC_MSG_CHECKING(that FAAD2 can even be used)
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
|
||||
#include <faad.h>
|
||||
|
||||
int main() {
|
||||
char buffer;
|
||||
NeAACDecHandle decoder;
|
||||
NeAACDecFrameInfo frameInfo;
|
||||
NeAACDecConfigurationPtr config;
|
||||
unsigned char channels;
|
||||
long sampleRate;
|
||||
long bufferlen = 0;
|
||||
|
||||
decoder = NeAACDecOpen();
|
||||
config = NeAACDecGetCurrentConfiguration(decoder);
|
||||
config->outputFormat = FAAD_FMT_16BIT;
|
||||
NeAACDecSetConfiguration(decoder,config);
|
||||
NeAACDecInit(decoder,&buffer,bufferlen,&sampleRate,&channels);
|
||||
NeAACDecInit2(decoder,&buffer,bufferlen,&sampleRate,&channels);
|
||||
NeAACDecDecode(decoder,&frameInfo,&buffer,bufferlen);
|
||||
NeAACDecClose(decoder);
|
||||
|
||||
return 0;
|
||||
}
|
||||
])],AC_MSG_RESULT(yes),[AC_MSG_RESULT(no);enable_aac=no])
|
||||
fi
|
||||
if test x$enable_aac = xyes; then
|
||||
AC_DEFINE(HAVE_FAAD,1,[Define to use FAAD2 for AAC decoding])
|
||||
else
|
||||
AC_MSG_WARN([faad2 lib needed for MP4/AAC support -- disabling MP4/AAC support])
|
||||
fi
|
||||
CFLAGS=$oldcflags
|
||||
LIBS=$oldlibs
|
||||
CPPFLAGS=$oldcppflags
|
||||
fi
|
||||
|
||||
if test x$enable_aac = xno; then
|
||||
FAAD_LIBS=""
|
||||
FAAD_CFLAGS=""
|
||||
fi
|
||||
|
||||
AC_SUBST(FAAD_CFLAGS)
|
||||
AC_SUBST(FAAD_LIBS)
|
||||
|
||||
])
|
201
m4/mpd_auto.m4
201
m4/mpd_auto.m4
@@ -1,23 +1,18 @@
|
||||
dnl Parameters: varname1, description
|
||||
AC_DEFUN([MPD_AUTO_ENABLED], [
|
||||
var="enable_$1"
|
||||
feature="$2"
|
||||
|
||||
if eval "test x`echo '$'$var` = xauto"; then
|
||||
AC_MSG_NOTICE([auto-detected $feature])
|
||||
eval "$var=yes"
|
||||
if test x$[]enable_$1 = xauto; then
|
||||
AC_MSG_NOTICE([auto-detected $2])
|
||||
enable_$1=yes
|
||||
fi
|
||||
])
|
||||
|
||||
dnl Parameters: varname1, description, errmsg
|
||||
AC_DEFUN([MPD_AUTO_DISABLED], [
|
||||
var="enable_$1"
|
||||
feature="$2"
|
||||
msg="$3"
|
||||
|
||||
if eval "test x`echo '$'$var` = xauto"; then
|
||||
AC_MSG_WARN([$msg -- disabling $feature])
|
||||
eval "$var=no"
|
||||
elif eval "test x`echo '$'$var` = xyes"; then
|
||||
AC_MSG_ERROR([$feature: $msg])
|
||||
if test x$[]enable_$1 = xauto; then
|
||||
AC_MSG_WARN([$3 -- disabling $2])
|
||||
enable_$1=no
|
||||
elif test x$[]enable_$1 = xyes; then
|
||||
AC_MSG_ERROR([$2: $3])
|
||||
fi
|
||||
])
|
||||
|
||||
@@ -25,59 +20,59 @@ dnl Check whether a prerequisite for a feature was found. This is
|
||||
dnl very similar to MPD_AUTO_RESULT, but does not finalize the
|
||||
dnl detection; it assumes that more checks will follow.
|
||||
AC_DEFUN([MPD_AUTO_PRE], [
|
||||
name="$1"
|
||||
var="enable_$1"
|
||||
found="found_$name"
|
||||
feature="$2"
|
||||
msg="$3"
|
||||
|
||||
if eval "test x`echo '$'$var` != xno" && eval "test x`echo '$'$found` = xno"; then
|
||||
MPD_AUTO_DISABLED([$name], [$feature], [$msg])
|
||||
if test x$[]enable_$1 != xno && test x$[]found_$1 = xno; then
|
||||
MPD_AUTO_DISABLED([$1], [$2], [$3])
|
||||
fi
|
||||
])
|
||||
|
||||
dnl Evaluate a check's result. Abort if the feature was requested
|
||||
dnl explicitly but is unavailable.
|
||||
dnl
|
||||
dnl Parameters: varname1, description, errmsg
|
||||
AC_DEFUN([MPD_AUTO_RESULT], [
|
||||
name="$1"
|
||||
var="enable_$1"
|
||||
found="found_$name"
|
||||
feature="$2"
|
||||
msg="$3"
|
||||
|
||||
if eval "test x`echo '$'$var` = xno"; then
|
||||
eval "$found=no"
|
||||
if test x$[]enable_$1 = xno; then
|
||||
found_$1=no
|
||||
fi
|
||||
|
||||
if eval "test x`echo '$'$found` = xyes"; then
|
||||
MPD_AUTO_ENABLED([$name], [$feature])
|
||||
if test x$[]found_$1 = xyes; then
|
||||
MPD_AUTO_ENABLED([$1], [$2])
|
||||
else
|
||||
MPD_AUTO_DISABLED([$name], [$feature], [$msg])
|
||||
MPD_AUTO_DISABLED([$1], [$2], [$3])
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([MPD_AUTO_PKG], [
|
||||
if eval "test x`echo '$'enable_$1` != xno"; then
|
||||
PKG_CHECK_MODULES([$2], [$3],
|
||||
[eval "found_$1=yes"],
|
||||
[eval "found_$1=no"])
|
||||
dnl Invoke a check if its configuration is "yes" or "auto" and call
|
||||
dnl MPD_AUTO_RESULT.
|
||||
dnl
|
||||
dnl Parameters: varname1, description, errmsg, check
|
||||
AC_DEFUN([MPD_AUTO], [
|
||||
if test x$[]enable_$1 != xno; then
|
||||
$4
|
||||
fi
|
||||
MPD_AUTO_RESULT([$1], [$2], [$3])
|
||||
])
|
||||
|
||||
MPD_AUTO_RESULT([$1], [$4], [$5])
|
||||
dnl Wrapper for MPD_AUTO and PKG_CHECK_MODULES.
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, pkgname, description, errmsg
|
||||
AC_DEFUN([MPD_AUTO_PKG], [
|
||||
MPD_AUTO([$1], [$4], [$5],
|
||||
[PKG_CHECK_MODULES([$2], [$3],
|
||||
[found_$1=yes],
|
||||
[found_$1=no])])
|
||||
])
|
||||
|
||||
dnl Check with pkg-config first, fall back to AC_CHECK_LIB.
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, pkgname, libname, symname, libs, cflags, description, errmsg
|
||||
AC_DEFUN([MPD_AUTO_PKG_LIB], [
|
||||
if eval "test x`echo '$'enable_$1` != xno"; then
|
||||
PKG_CHECK_MODULES([$2], [$3],
|
||||
[eval "found_$1=yes"],
|
||||
MPD_AUTO([$1], [$8], [$9],
|
||||
[PKG_CHECK_MODULES([$2], [$3],
|
||||
[found_$1=yes],
|
||||
AC_CHECK_LIB($4, $5,
|
||||
[eval "found_$1=yes $2_LIBS='$6' $2_CFLAGS='$7'"],
|
||||
[eval "found_$1=no"],
|
||||
[$6]))
|
||||
fi
|
||||
|
||||
MPD_AUTO_RESULT([$1], [$8], [$9])
|
||||
[found_$1=yes $2_LIBS='$6' $2_CFLAGS='$7'],
|
||||
[found_$1=no],
|
||||
[$6]))])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_CHECK_LIB.
|
||||
@@ -87,12 +82,104 @@ AC_DEFUN([MPD_AUTO_LIB], [
|
||||
AC_SUBST([$2_LIBS], [])
|
||||
AC_SUBST([$2_CFLAGS], [])
|
||||
|
||||
if eval "test x`echo '$'enable_$1` != xno"; then
|
||||
AC_CHECK_LIB($3, $4,
|
||||
[eval "found_$1=yes $2_LIBS='$5' $2_CFLAGS='$6'"],
|
||||
[eval "found_$1=no"],
|
||||
[$5])
|
||||
fi
|
||||
|
||||
MPD_AUTO_RESULT([$1], [$7], [$8])
|
||||
MPD_AUTO([$1], [$7], [$8],
|
||||
[AC_CHECK_LIB($3, $4,
|
||||
[found_$1=yes $2_LIBS='$5' $2_CFLAGS='$6'],
|
||||
[found_$1=no],
|
||||
[$5])])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_CHECK_HEADER.
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, header, libs, cflags, description, errmsg
|
||||
AC_DEFUN([MPD_AUTO_HEADER], [
|
||||
AC_SUBST([$2_LIBS], [])
|
||||
AC_SUBST([$2_CFLAGS], [])
|
||||
|
||||
MPD_AUTO([$1], [$6], [$7],
|
||||
[AC_CHECK_HEADER([$3],
|
||||
[found_$1=yes $2_LIBS='$4' $2_CFLAGS='$5'],
|
||||
[found_$1=no])])
|
||||
])
|
||||
|
||||
dnl Convert the given string into a string for the "default value" in
|
||||
dnl the help text. If the string is a literal, then it is returned
|
||||
dnl as-is; if it contains a variable reference, just "auto" is
|
||||
dnl emitted.
|
||||
dnl
|
||||
dnl Parameters: varname1
|
||||
AC_DEFUN([MPD_FORMAT_DEFAULT],
|
||||
[ifelse([$1], [], [auto],
|
||||
index([$1], [$]), [-1], [$1],
|
||||
[auto])])
|
||||
|
||||
dnl Wrapper for AC_ARG_ENABLE, AC_DEFINE and AM_CONDITIONAL
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, description, default, check
|
||||
AC_DEFUN([MPD_ARG_ENABLE], [
|
||||
AC_ARG_ENABLE(translit([$1], [_], [-]),
|
||||
AS_HELP_STRING([--enable-]translit([$1], [_], [-]),
|
||||
[enable $3 (default: ]MPD_FORMAT_DEFAULT([$4])[)]),,
|
||||
[enable_$1=]ifelse([$4], [], [auto], [$4]))
|
||||
|
||||
$5
|
||||
|
||||
MPD_DEFINE_CONDITIONAL(enable_$1, ENABLE_$2, [$3])
|
||||
])
|
||||
|
||||
dnl Wrapper for MPD_ARG_ENABLE and MPD_AUTO
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, description, errmsg, default, check
|
||||
AC_DEFUN([MPD_ENABLE_AUTO], [
|
||||
MPD_ARG_ENABLE([$1], [$2], [$3], [$5], [
|
||||
MPD_AUTO([$1], [$3], [$4], [$6])
|
||||
])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_ARG_ENABLE and MPD_AUTO_PKG
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, pkg, description, errmsg, default, pre
|
||||
AC_DEFUN([MPD_ENABLE_AUTO_PKG], [
|
||||
MPD_ARG_ENABLE([$1], [$2], [$4], [$6], [
|
||||
$7
|
||||
MPD_AUTO_PKG($1, $2, $3, $4, $5)
|
||||
])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_ARG_ENABLE and MPD_AUTO_PKG_LIB
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, pkg, libname, symname, libs, cflags, description, errmsg, default, pre
|
||||
AC_DEFUN([MPD_ENABLE_AUTO_PKG_LIB], [
|
||||
MPD_ARG_ENABLE([$1], [$2], [$8], [$10], [
|
||||
$11
|
||||
MPD_AUTO_PKG_LIB($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_ARG_ENABLE and MPD_AUTO_LIB
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, libname, symname, libs, cflags, description, errmsg, default, pre
|
||||
AC_DEFUN([MPD_ENABLE_AUTO_LIB], [
|
||||
MPD_ARG_ENABLE([$1], [$2], [$7], [$9], [
|
||||
$10
|
||||
MPD_AUTO_LIB($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
])
|
||||
])
|
||||
|
||||
dnl Wrapper for AC_ARG_ENABLE and MPD_AUTO_HEADER
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, header, libs, cflags, description, errmsg, default, pre
|
||||
AC_DEFUN([MPD_ENABLE_AUTO_HEADER], [
|
||||
MPD_ARG_ENABLE([$1], [$2], [$6], [$8], [
|
||||
$9
|
||||
MPD_AUTO_HEADER($1, $2, $3, $4, $5, $6, $7)
|
||||
])
|
||||
])
|
||||
|
||||
dnl Wrapper for MPD_ENABLE_AUTO_PKG and MPD_DEPENDS
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, pkg, description, errmsg, default, dep_variable, dep_errmsg
|
||||
AC_DEFUN([MPD_ENABLE_AUTO_PKG_DEPENDS], [
|
||||
MPD_ENABLE_AUTO_PKG([$1], [$2], [$3], [$4], [$5], [$6],
|
||||
[MPD_DEPENDS([enable_$1], [$7], [$8])])
|
||||
])
|
||||
|
8
m4/mpd_define_conditional.m4
Normal file
8
m4/mpd_define_conditional.m4
Normal file
@@ -0,0 +1,8 @@
|
||||
dnl Wrapper for AC_DEFINE and AM_CONDITIONAL
|
||||
dnl
|
||||
dnl Parameters: varname1, varname2, description
|
||||
AC_DEFUN([MPD_DEFINE_CONDITIONAL], [dnl
|
||||
AM_CONDITIONAL($2, test x$[]$1 = xyes)
|
||||
if test x$[]$1 = xyes; then
|
||||
AC_DEFINE($2, 1, [Define to enable $3])
|
||||
fi])
|
@@ -6,7 +6,7 @@ AC_DEFUN([MPD_OPTIONAL_FUNC], [
|
||||
AC_ARG_ENABLE([$1],
|
||||
AS_HELP_STRING([--enable-$1],
|
||||
[use the function "$1" (default: auto)]),
|
||||
[test xenable_$1 = xyes && AC_DEFINE([$3], 1, [Define to use $1])],
|
||||
[test x$[]enable_$1 = xyes && AC_DEFINE([$3], 1, [Define to use $1])],
|
||||
[AC_CHECK_FUNC([$2],
|
||||
[AC_DEFINE([$3], 1, [Define to use $1])],)])
|
||||
])
|
||||
|
23
m4/mpd_with_flags.m4
Normal file
23
m4/mpd_with_flags.m4
Normal file
@@ -0,0 +1,23 @@
|
||||
dnl Run code with the specified CFLAGS/CXXFLAGS and LIBS appended.
|
||||
dnl Restores the old values afterwards.
|
||||
dnl
|
||||
dnl Parameters: cflags, libs, code
|
||||
AC_DEFUN([MPD_WITH_FLAGS], [
|
||||
ac_save_CFLAGS="$[]CFLAGS"
|
||||
ac_save_CXXFLAGS="$[]CXXFLAGS"
|
||||
ac_save_LIBS="$[]LIBS"
|
||||
CFLAGS="$[]CFLAGS $1"
|
||||
CXXFLAGS="$[]CXXFLAGS $1"
|
||||
LIBS="$[]LIBS $2"
|
||||
$3
|
||||
CFLAGS="$[]ac_save_CFLAGS"
|
||||
CXXFLAGS="$[]ac_save_CXXFLAGS"
|
||||
LIBS="$[]ac_save_LIBS"
|
||||
])
|
||||
|
||||
dnl Run code with the specified library's CFLAGS/CXXFLAGS and LIBS
|
||||
dnl appended. Restores the old values afterwards.
|
||||
dnl
|
||||
dnl Parameters: libname, code
|
||||
AC_DEFUN([MPD_WITH_LIBRARY],
|
||||
[MPD_WITH_FLAGS([$[]$1_CFLAGS], [$[]$1_LIBS], [$2])])
|
209
m4/pkg.m4
209
m4/pkg.m4
@@ -1,29 +1,60 @@
|
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
# serial 1 (pkg-config-0.24)
|
||||
#
|
||||
# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but
|
||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
#
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
dnl pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||||
dnl serial 11 (pkg-config-0.29)
|
||||
dnl
|
||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
|
||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com>
|
||||
dnl
|
||||
dnl This program is free software; you can redistribute it and/or modify
|
||||
dnl it under the terms of the GNU General Public License as published by
|
||||
dnl the Free Software Foundation; either version 2 of the License, or
|
||||
dnl (at your option) any later version.
|
||||
dnl
|
||||
dnl This program is distributed in the hope that it will be useful, but
|
||||
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
dnl General Public License for more details.
|
||||
dnl
|
||||
dnl You should have received a copy of the GNU General Public License
|
||||
dnl along with this program; if not, write to the Free Software
|
||||
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
dnl 02111-1307, USA.
|
||||
dnl
|
||||
dnl As a special exception to the GNU General Public License, if you
|
||||
dnl distribute this file as part of a program that contains a
|
||||
dnl configuration script generated by Autoconf, you may include it under
|
||||
dnl the same distribution terms that you use for the rest of that
|
||||
dnl program.
|
||||
|
||||
# PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
# ----------------------------------
|
||||
dnl PKG_PREREQ(MIN-VERSION)
|
||||
dnl -----------------------
|
||||
dnl Since: 0.29
|
||||
dnl
|
||||
dnl Verify that the version of the pkg-config macros are at least
|
||||
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's
|
||||
dnl installed version of pkg-config, this checks the developer's version
|
||||
dnl of pkg.m4 when generating configure.
|
||||
dnl
|
||||
dnl To ensure that this macro is defined, also add:
|
||||
dnl m4_ifndef([PKG_PREREQ],
|
||||
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])])
|
||||
dnl
|
||||
dnl See the "Since" comment for each macro you use to see what version
|
||||
dnl of the macros you require.
|
||||
m4_defun([PKG_PREREQ],
|
||||
[m4_define([PKG_MACROS_VERSION], [0.29])
|
||||
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1,
|
||||
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])])
|
||||
])dnl PKG_PREREQ
|
||||
|
||||
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||||
dnl ----------------------------------
|
||||
dnl Since: 0.16
|
||||
dnl
|
||||
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to
|
||||
dnl first found in the path. Checks that the version of pkg-config found
|
||||
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is
|
||||
dnl used since that's the first version where most current features of
|
||||
dnl pkg-config existed.
|
||||
AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||||
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
|
||||
@@ -45,18 +76,19 @@ if test -n "$PKG_CONFIG"; then
|
||||
PKG_CONFIG=""
|
||||
fi
|
||||
fi[]dnl
|
||||
])# PKG_PROG_PKG_CONFIG
|
||||
])dnl PKG_PROG_PKG_CONFIG
|
||||
|
||||
# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
# Check to see whether a particular set of modules exists. Similar
|
||||
# to PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
#
|
||||
# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
# only at the first occurence in configure.ac, so if the first place
|
||||
# it's called might be skipped (such as if it is within an "if", you
|
||||
# have to call PKG_CHECK_EXISTS manually
|
||||
# --------------------------------------------------------------
|
||||
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
dnl -------------------------------------------------------------------
|
||||
dnl Since: 0.18
|
||||
dnl
|
||||
dnl Check to see whether a particular set of modules exists. Similar to
|
||||
dnl PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||||
dnl
|
||||
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
dnl only at the first occurence in configure.ac, so if the first place
|
||||
dnl it's called might be skipped (such as if it is within an "if", you
|
||||
dnl have to call PKG_CHECK_EXISTS manually
|
||||
AC_DEFUN([PKG_CHECK_EXISTS],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
if test -n "$PKG_CONFIG" && \
|
||||
@@ -66,8 +98,10 @@ m4_ifvaln([$3], [else
|
||||
$3])dnl
|
||||
fi])
|
||||
|
||||
# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
# ---------------------------------------------
|
||||
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||||
dnl ---------------------------------------------
|
||||
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting
|
||||
dnl pkg_failed based on the result.
|
||||
m4_define([_PKG_CONFIG],
|
||||
[if test -n "$$1"; then
|
||||
pkg_cv_[]$1="$$1"
|
||||
@@ -79,10 +113,11 @@ m4_define([_PKG_CONFIG],
|
||||
else
|
||||
pkg_failed=untried
|
||||
fi[]dnl
|
||||
])# _PKG_CONFIG
|
||||
])dnl _PKG_CONFIG
|
||||
|
||||
# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
# -----------------------------
|
||||
dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||
dnl ---------------------------
|
||||
dnl Internal check to see if pkg-config supports short errors.
|
||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
@@ -90,19 +125,17 @@ if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||||
else
|
||||
_pkg_short_errors_supported=no
|
||||
fi[]dnl
|
||||
])# _PKG_SHORT_ERRORS_SUPPORTED
|
||||
])dnl _PKG_SHORT_ERRORS_SUPPORTED
|
||||
|
||||
|
||||
# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
# [ACTION-IF-NOT-FOUND])
|
||||
#
|
||||
#
|
||||
# Note that if there is a possibility the first call to
|
||||
# PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
#
|
||||
#
|
||||
# --------------------------------------------------------------
|
||||
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
dnl [ACTION-IF-NOT-FOUND])
|
||||
dnl --------------------------------------------------------------
|
||||
dnl Since: 0.4.0
|
||||
dnl
|
||||
dnl Note that if there is a possibility the first call to
|
||||
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||||
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||||
AC_DEFUN([PKG_CHECK_MODULES],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||||
@@ -156,16 +189,40 @@ else
|
||||
AC_MSG_RESULT([yes])
|
||||
$3
|
||||
fi[]dnl
|
||||
])# PKG_CHECK_MODULES
|
||||
])dnl PKG_CHECK_MODULES
|
||||
|
||||
|
||||
# PKG_INSTALLDIR(DIRECTORY)
|
||||
# -------------------------
|
||||
# Substitutes the variable pkgconfigdir as the location where a module
|
||||
# should install pkg-config .pc files. By default the directory is
|
||||
# $libdir/pkgconfig, but the default can be changed by passing
|
||||
# DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||
# parameter.
|
||||
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||||
dnl [ACTION-IF-NOT-FOUND])
|
||||
dnl ---------------------------------------------------------------------
|
||||
dnl Since: 0.29
|
||||
dnl
|
||||
dnl Checks for existence of MODULES and gathers its build flags with
|
||||
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags
|
||||
dnl and VARIABLE-PREFIX_LIBS from --libs.
|
||||
dnl
|
||||
dnl Note that if there is a possibility the first call to
|
||||
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to
|
||||
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your
|
||||
dnl configure.ac.
|
||||
AC_DEFUN([PKG_CHECK_MODULES_STATIC],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
_save_PKG_CONFIG=$PKG_CONFIG
|
||||
PKG_CONFIG="$PKG_CONFIG --static"
|
||||
PKG_CHECK_MODULES($@)
|
||||
PKG_CONFIG=$_save_PKG_CONFIG[]dnl
|
||||
])dnl PKG_CHECK_MODULES_STATIC
|
||||
|
||||
|
||||
dnl PKG_INSTALLDIR([DIRECTORY])
|
||||
dnl -------------------------
|
||||
dnl Since: 0.27
|
||||
dnl
|
||||
dnl Substitutes the variable pkgconfigdir as the location where a module
|
||||
dnl should install pkg-config .pc files. By default the directory is
|
||||
dnl $libdir/pkgconfig, but the default can be changed by passing
|
||||
dnl DIRECTORY. The user can override through the --with-pkgconfigdir
|
||||
dnl parameter.
|
||||
AC_DEFUN([PKG_INSTALLDIR],
|
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
|
||||
m4_pushdef([pkg_description],
|
||||
@@ -176,16 +233,18 @@ AC_ARG_WITH([pkgconfigdir],
|
||||
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
|
||||
m4_popdef([pkg_default])
|
||||
m4_popdef([pkg_description])
|
||||
]) dnl PKG_INSTALLDIR
|
||||
])dnl PKG_INSTALLDIR
|
||||
|
||||
|
||||
# PKG_NOARCH_INSTALLDIR(DIRECTORY)
|
||||
# -------------------------
|
||||
# Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||
# module should install arch-independent pkg-config .pc files. By
|
||||
# default the directory is $datadir/pkgconfig, but the default can be
|
||||
# changed by passing DIRECTORY. The user can override through the
|
||||
# --with-noarch-pkgconfigdir parameter.
|
||||
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY])
|
||||
dnl --------------------------------
|
||||
dnl Since: 0.27
|
||||
dnl
|
||||
dnl Substitutes the variable noarch_pkgconfigdir as the location where a
|
||||
dnl module should install arch-independent pkg-config .pc files. By
|
||||
dnl default the directory is $datadir/pkgconfig, but the default can be
|
||||
dnl changed by passing DIRECTORY. The user can override through the
|
||||
dnl --with-noarch-pkgconfigdir parameter.
|
||||
AC_DEFUN([PKG_NOARCH_INSTALLDIR],
|
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
|
||||
m4_pushdef([pkg_description],
|
||||
@@ -196,13 +255,15 @@ AC_ARG_WITH([noarch-pkgconfigdir],
|
||||
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
|
||||
m4_popdef([pkg_default])
|
||||
m4_popdef([pkg_description])
|
||||
]) dnl PKG_NOARCH_INSTALLDIR
|
||||
])dnl PKG_NOARCH_INSTALLDIR
|
||||
|
||||
|
||||
# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||
# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
# -------------------------------------------
|
||||
# Retrieves the value of the pkg-config variable for the given module.
|
||||
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
|
||||
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||||
dnl -------------------------------------------
|
||||
dnl Since: 0.28
|
||||
dnl
|
||||
dnl Retrieves the value of the pkg-config variable for the given module.
|
||||
AC_DEFUN([PKG_CHECK_VAR],
|
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
|
||||
@@ -211,4 +272,4 @@ _PKG_CONFIG([$1], [variable="][$3]["], [$2])
|
||||
AS_VAR_COPY([$1], [pkg_cv_][$1])
|
||||
|
||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl
|
||||
])# PKG_CHECK_VAR
|
||||
])dnl PKG_CHECK_VAR
|
||||
|
@@ -1,16 +1,6 @@
|
||||
AC_DEFUN([results], [
|
||||
dnl This is a hack to allow "with" names, otherwise "enable".
|
||||
num=`expr $1 : 'with'`
|
||||
if test "$num" != "0"; then
|
||||
var="`echo '$'$1`"
|
||||
else
|
||||
var="`echo '$'enable_$1`"
|
||||
fi
|
||||
|
||||
printf '('
|
||||
if eval "test x$var = xyes"; then
|
||||
printf '+'
|
||||
elif test -n "$3" && eval "test x$var = x$3"; then
|
||||
if test x$[]enable_$1 = xyes; then
|
||||
printf '+'
|
||||
else
|
||||
printf '-'
|
||||
|
46
python/build/autotools.py
Normal file
46
python/build/autotools.py
Normal file
@@ -0,0 +1,46 @@
|
||||
import os.path, subprocess
|
||||
|
||||
from build.project import Project
|
||||
|
||||
class AutotoolsProject(Project):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
autogen=False,
|
||||
cppflags='',
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
self.configure_args = configure_args
|
||||
self.autogen = autogen
|
||||
self.cppflags = cppflags
|
||||
|
||||
def build(self, toolchain):
|
||||
src = self.unpack(toolchain)
|
||||
if self.autogen:
|
||||
subprocess.check_call(['libtoolize', '--force'], cwd=src)
|
||||
subprocess.check_call(['aclocal'], cwd=src)
|
||||
subprocess.check_call(['automake', '--add-missing', '--force-missing', '--foreign'], cwd=src)
|
||||
subprocess.check_call(['autoconf'], cwd=src)
|
||||
|
||||
build = self.make_build_path(toolchain)
|
||||
|
||||
configure = [
|
||||
os.path.join(src, 'configure'),
|
||||
'CC=' + toolchain.cc,
|
||||
'CXX=' + toolchain.cxx,
|
||||
'CFLAGS=' + toolchain.cflags,
|
||||
'CXXFLAGS=' + toolchain.cxxflags,
|
||||
'CPPFLAGS=' + toolchain.cppflags + ' ' + self.cppflags,
|
||||
'LDFLAGS=' + toolchain.ldflags,
|
||||
'LIBS=' + toolchain.libs,
|
||||
'AR=' + toolchain.ar,
|
||||
'RANLIB=' + toolchain.ranlib,
|
||||
'STRIP=' + toolchain.strip,
|
||||
'--host=' + toolchain.arch,
|
||||
'--prefix=' + toolchain.install_prefix,
|
||||
'--enable-silent-rules',
|
||||
] + self.configure_args
|
||||
|
||||
subprocess.check_call(configure, cwd=build, env=toolchain.env)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'],
|
||||
cwd=build, env=toolchain.env)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', 'install'],
|
||||
cwd=build, env=toolchain.env)
|
23
python/build/boost.py
Normal file
23
python/build/boost.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import os, shutil
|
||||
import re
|
||||
|
||||
from build.project import Project
|
||||
|
||||
class BoostProject(Project):
|
||||
def __init__(self, url, md5, installed,
|
||||
**kwargs):
|
||||
m = re.match(r'.*/boost_(\d+)_(\d+)_(\d+)\.tar\.bz2$', url)
|
||||
version = "%s.%s.%s" % (m.group(1), m.group(2), m.group(3))
|
||||
Project.__init__(self, url, md5, installed,
|
||||
name='boost', version=version,
|
||||
**kwargs)
|
||||
|
||||
def build(self, toolchain):
|
||||
src = self.unpack(toolchain)
|
||||
|
||||
# install the headers manually; don't build any library
|
||||
# (because right now, we only use header-only libraries)
|
||||
includedir = os.path.join(toolchain.install_prefix, 'include')
|
||||
dest = os.path.join(includedir, 'boost')
|
||||
shutil.rmtree(dest, ignore_errors=True)
|
||||
shutil.copytree(os.path.join(src, 'boost'), dest)
|
9
python/build/dirs.py
Normal file
9
python/build/dirs.py
Normal file
@@ -0,0 +1,9 @@
|
||||
import os.path
|
||||
|
||||
lib_path = os.path.abspath('lib')
|
||||
|
||||
shared_path = lib_path
|
||||
if 'MPD_SHARED_LIB' in os.environ:
|
||||
shared_path = os.environ['MPD_SHARED_LIB']
|
||||
tarball_path = os.path.join(shared_path, 'download')
|
||||
src_path = os.path.join(shared_path, 'src')
|
26
python/build/download.py
Normal file
26
python/build/download.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from build.verify import verify_file_digest
|
||||
import os
|
||||
import urllib.request
|
||||
|
||||
def download_and_verify(url, md5, parent_path):
|
||||
"""Download a file, verify its MD5 checksum and return the local path."""
|
||||
|
||||
os.makedirs(parent_path, exist_ok=True)
|
||||
path = os.path.join(parent_path, os.path.basename(url))
|
||||
|
||||
try:
|
||||
if verify_file_digest(path, md5): return path
|
||||
os.unlink(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
tmp_path = path + '.tmp'
|
||||
|
||||
print("download", url)
|
||||
urllib.request.urlretrieve(url, tmp_path)
|
||||
if not verify_file_digest(tmp_path, md5):
|
||||
os.unlink(tmp_path)
|
||||
raise RuntimeError("Digest mismatch")
|
||||
|
||||
os.rename(tmp_path, path)
|
||||
return path
|
54
python/build/ffmpeg.py
Normal file
54
python/build/ffmpeg.py
Normal file
@@ -0,0 +1,54 @@
|
||||
import os.path, subprocess
|
||||
|
||||
from build.project import Project
|
||||
|
||||
class FfmpegProject(Project):
|
||||
def __init__(self, url, md5, installed, configure_args=[],
|
||||
cppflags='',
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
self.configure_args = configure_args
|
||||
self.cppflags = cppflags
|
||||
|
||||
def _filter_cflags(self, flags):
|
||||
# FFmpeg expects the GNU as syntax
|
||||
flags = flags.replace(' -integrated-as ', ' -no-integrated-as ')
|
||||
return flags
|
||||
|
||||
def build(self, toolchain):
|
||||
src = self.unpack(toolchain)
|
||||
build = self.make_build_path(toolchain)
|
||||
|
||||
if toolchain.is_arm:
|
||||
arch = 'arm'
|
||||
else:
|
||||
arch = 'x86'
|
||||
|
||||
if toolchain.is_windows:
|
||||
target_os = 'mingw32'
|
||||
else:
|
||||
target_os = 'linux'
|
||||
|
||||
configure = [
|
||||
os.path.join(src, 'configure'),
|
||||
'--cc=' + toolchain.cc,
|
||||
'--cxx=' + toolchain.cxx,
|
||||
'--nm=' + toolchain.nm,
|
||||
'--extra-cflags=' + self._filter_cflags(toolchain.cflags) + ' ' + toolchain.cppflags + ' ' + self.cppflags,
|
||||
'--extra-cxxflags=' + self._filter_cflags(toolchain.cxxflags) + ' ' + toolchain.cppflags + ' ' + self.cppflags,
|
||||
'--extra-ldflags=' + toolchain.ldflags,
|
||||
'--extra-libs=' + toolchain.libs,
|
||||
'--ar=' + toolchain.ar,
|
||||
'--ranlib=' + toolchain.ranlib,
|
||||
'--enable-cross-compile',
|
||||
'--arch=' + arch,
|
||||
'--target-os=' + target_os,
|
||||
'--prefix=' + toolchain.install_prefix,
|
||||
] + self.configure_args
|
||||
|
||||
if toolchain.is_armv7:
|
||||
configure.append('--cpu=cortex-a8')
|
||||
|
||||
subprocess.check_call(configure, cwd=build, env=toolchain.env)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', '-j12'], cwd=build, env=toolchain.env)
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet', 'install'], cwd=build, env=toolchain.env)
|
109
python/build/libs.py
Normal file
109
python/build/libs.py
Normal file
@@ -0,0 +1,109 @@
|
||||
from build.project import Project
|
||||
from build.zlib import ZlibProject
|
||||
from build.autotools import AutotoolsProject
|
||||
from build.ffmpeg import FfmpegProject
|
||||
from build.boost import BoostProject
|
||||
|
||||
libogg = AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/ogg/libogg-1.3.2.tar.xz',
|
||||
'5c3a34309d8b98640827e5d0991a4015',
|
||||
'lib/libogg.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
)
|
||||
|
||||
libvorbis = AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/vorbis/libvorbis-1.3.5.tar.xz',
|
||||
'28cb28097c07a735d6af56e598e1c90f',
|
||||
'lib/libvorbis.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
)
|
||||
|
||||
opus = AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/opus/opus-1.1.3.tar.gz',
|
||||
'32bbb6b557fe1b6066adc0ae1f08b629',
|
||||
'lib/libopus.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
)
|
||||
|
||||
flac = AutotoolsProject(
|
||||
'http://downloads.xiph.org/releases/flac/flac-1.3.2.tar.xz',
|
||||
'91cfc3ed61dc40f47f050a109b08610667d73477af6ef36dcad31c31a4a8d53f',
|
||||
'lib/libFLAC.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-xmms-plugin', '--disable-cpplibs',
|
||||
],
|
||||
)
|
||||
|
||||
zlib = ZlibProject(
|
||||
'http://zlib.net/zlib-1.2.8.tar.xz',
|
||||
'28f1205d8dd2001f26fec1e8c2cebe37',
|
||||
'lib/libz.a',
|
||||
)
|
||||
|
||||
libid3tag = AutotoolsProject(
|
||||
'ftp://ftp.mars.org/pub/mpeg/libid3tag-0.15.1b.tar.gz',
|
||||
'e5808ad997ba32c498803822078748c3',
|
||||
'lib/libid3tag.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
autogen=True,
|
||||
)
|
||||
|
||||
libmad = AutotoolsProject(
|
||||
'ftp://ftp.mars.org/pub/mpeg/libmad-0.15.1b.tar.gz',
|
||||
'1be543bc30c56fb6bea1d7bf6a64e66c',
|
||||
'lib/libmad.a',
|
||||
['--disable-shared', '--enable-static'],
|
||||
autogen=True,
|
||||
)
|
||||
|
||||
ffmpeg = FfmpegProject(
|
||||
'http://ffmpeg.org/releases/ffmpeg-3.2.2.tar.xz',
|
||||
'3f01bd1fe1a17a277f8c84869e5d9192b4b978cb660872aa2b54c3cc8a2fedfc',
|
||||
'lib/libavcodec.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--enable-gpl',
|
||||
'--enable-small',
|
||||
'--disable-pthreads',
|
||||
'--disable-programs',
|
||||
'--disable-doc',
|
||||
'--disable-avdevice',
|
||||
'--disable-swresample',
|
||||
'--disable-swscale',
|
||||
'--disable-postproc',
|
||||
'--disable-avfilter',
|
||||
'--disable-network',
|
||||
'--disable-encoders',
|
||||
'--disable-protocols',
|
||||
'--disable-outdevs',
|
||||
'--disable-filters',
|
||||
],
|
||||
)
|
||||
|
||||
curl = AutotoolsProject(
|
||||
'http://curl.haxx.se/download/curl-7.52.1.tar.lzma',
|
||||
'44286d4b825936e2430fc44ad730ce899afb736a5d328cbb8b5d42462f3f2365',
|
||||
'lib/libcurl.a',
|
||||
[
|
||||
'--disable-shared', '--enable-static',
|
||||
'--disable-debug',
|
||||
'--enable-http',
|
||||
'--enable-ipv6',
|
||||
'--disable-ftp', '--disable-file',
|
||||
'--disable-ldap', '--disable-ldaps',
|
||||
'--disable-rtsp', '--disable-proxy', '--disable-dict', '--disable-telnet',
|
||||
'--disable-tftp', '--disable-pop3', '--disable-imap', '--disable-smtp',
|
||||
'--disable-gopher',
|
||||
'--disable-manual',
|
||||
'--disable-threaded-resolver', '--disable-verbose', '--disable-sspi',
|
||||
'--disable-crypto-auth', '--disable-ntlm-wb', '--disable-tls-srp', '--disable-cookies',
|
||||
'--without-ssl', '--without-gnutls', '--without-nss', '--without-libssh2',
|
||||
],
|
||||
)
|
||||
|
||||
boost = BoostProject(
|
||||
'http://downloads.sourceforge.net/project/boost/boost/1.63.0/boost_1_63_0.tar.bz2',
|
||||
'beae2529f759f6b3bf3f4969a19c2e9d6f0c503edcb2de4a61d1428519fcb3b0',
|
||||
'include/boost/version.hpp',
|
||||
)
|
59
python/build/project.py
Normal file
59
python/build/project.py
Normal file
@@ -0,0 +1,59 @@
|
||||
import os, shutil
|
||||
import re
|
||||
|
||||
from build.download import download_and_verify
|
||||
from build.tar import untar
|
||||
|
||||
class Project:
|
||||
def __init__(self, url, md5, installed, name=None, version=None,
|
||||
base=None,
|
||||
use_cxx=False):
|
||||
if base is None:
|
||||
basename = os.path.basename(url)
|
||||
m = re.match(r'^(.+)\.(tar(\.(gz|bz2|xz|lzma))?|zip)$', basename)
|
||||
if not m: raise
|
||||
self.base = m.group(1)
|
||||
else:
|
||||
self.base = base
|
||||
|
||||
if name is None or version is None:
|
||||
m = re.match(r'^([-\w]+)-(\d[\d.]*[a-z]?)$', self.base)
|
||||
if name is None: name = m.group(1)
|
||||
if version is None: version = m.group(2)
|
||||
|
||||
self.name = name
|
||||
self.version = version
|
||||
|
||||
self.url = url
|
||||
self.md5 = md5
|
||||
self.installed = installed
|
||||
|
||||
self.use_cxx = use_cxx
|
||||
|
||||
def download(self, toolchain):
|
||||
return download_and_verify(self.url, self.md5, toolchain.tarball_path)
|
||||
|
||||
def is_installed(self, toolchain):
|
||||
tarball = self.download(toolchain)
|
||||
installed = os.path.join(toolchain.install_prefix, self.installed)
|
||||
tarball_mtime = os.path.getmtime(tarball)
|
||||
try:
|
||||
return os.path.getmtime(installed) >= tarball_mtime
|
||||
except FileNotFoundError:
|
||||
return False
|
||||
|
||||
def unpack(self, toolchain, out_of_tree=True):
|
||||
if out_of_tree:
|
||||
parent_path = toolchain.src_path
|
||||
else:
|
||||
parent_path = toolchain.build_path
|
||||
return untar(self.download(toolchain), parent_path, self.base)
|
||||
|
||||
def make_build_path(self, toolchain):
|
||||
path = os.path.join(toolchain.build_path, self.base)
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
os.makedirs(path, exist_ok=True)
|
||||
return path
|
11
python/build/tar.py
Normal file
11
python/build/tar.py
Normal file
@@ -0,0 +1,11 @@
|
||||
import os, shutil, subprocess
|
||||
|
||||
def untar(tarball_path, parent_path, base):
|
||||
path = os.path.join(parent_path, base)
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
os.makedirs(parent_path, exist_ok=True)
|
||||
subprocess.check_call(['/bin/tar', 'xfC', tarball_path, parent_path])
|
||||
return path
|
42
python/build/verify.py
Normal file
42
python/build/verify.py
Normal file
@@ -0,0 +1,42 @@
|
||||
import hashlib
|
||||
|
||||
def feed_file(h, f):
|
||||
"""Feed data read from an open file into the hashlib instance."""
|
||||
|
||||
while True:
|
||||
data = f.read(65536)
|
||||
if len(data) == 0:
|
||||
# end of file
|
||||
break
|
||||
h.update(data)
|
||||
|
||||
def feed_file_path(h, path):
|
||||
"""Feed data read from a file (to be opened by this function) into the hashlib instance."""
|
||||
|
||||
with open(path, 'rb') as f:
|
||||
feed_file(h, f)
|
||||
|
||||
def file_digest(algorithm, path):
|
||||
"""Calculate the digest of a file and return it in hexadecimal notation."""
|
||||
|
||||
h = algorithm()
|
||||
feed_file_path(h, path)
|
||||
return h.hexdigest()
|
||||
|
||||
def guess_digest_algorithm(digest):
|
||||
l = len(digest)
|
||||
if l == 32:
|
||||
return hashlib.md5
|
||||
elif l == 40:
|
||||
return hashlib.sha1
|
||||
elif l == 64:
|
||||
return hashlib.sha256
|
||||
else:
|
||||
return None
|
||||
|
||||
def verify_file_digest(path, expected_digest):
|
||||
"""Verify the digest of a file, and return True if the digest matches with the given expected digest."""
|
||||
|
||||
algorithm = guess_digest_algorithm(expected_digest)
|
||||
assert(algorithm is not None)
|
||||
return file_digest(algorithm, path) == expected_digest
|
22
python/build/zlib.py
Normal file
22
python/build/zlib.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import os.path, subprocess
|
||||
|
||||
from build.project import Project
|
||||
|
||||
class ZlibProject(Project):
|
||||
def __init__(self, url, md5, installed,
|
||||
**kwargs):
|
||||
Project.__init__(self, url, md5, installed, **kwargs)
|
||||
|
||||
def build(self, toolchain):
|
||||
src = self.unpack(toolchain, out_of_tree=False)
|
||||
|
||||
subprocess.check_call(['/usr/bin/make', '--quiet',
|
||||
'-f', 'win32/Makefile.gcc',
|
||||
'PREFIX=' + toolchain.arch + '-',
|
||||
'-j12',
|
||||
'install',
|
||||
'INCLUDE_PATH='+ os.path.join(toolchain.install_prefix, 'include'),
|
||||
'LIBRARY_PATH=' + os.path.join(toolchain.install_prefix, 'lib'),
|
||||
'BINARY_PATH=' + os.path.join(toolchain.install_prefix, 'bin'),
|
||||
'SHARED_MODE=1'],
|
||||
cwd=src, env=toolchain.env)
|
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "AudioConfig.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "AudioParser.hxx"
|
||||
#include "config/ConfigData.hxx"
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "config/ConfigOption.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
|
||||
static AudioFormat configured_audio_format;
|
||||
|
||||
AudioFormat
|
||||
getOutputAudioFormat(AudioFormat inAudioFormat)
|
||||
{
|
||||
AudioFormat out_audio_format = inAudioFormat;
|
||||
out_audio_format.ApplyMask(configured_audio_format);
|
||||
return out_audio_format;
|
||||
}
|
||||
|
||||
void initAudioConfig(void)
|
||||
{
|
||||
const struct config_param *param = config_get_param(CONF_AUDIO_OUTPUT_FORMAT);
|
||||
|
||||
if (param == nullptr)
|
||||
return;
|
||||
|
||||
Error error;
|
||||
if (!audio_format_parse(configured_audio_format, param->value.c_str(),
|
||||
true, error))
|
||||
FormatFatalError("error parsing line %i: %s",
|
||||
param->line, error.GetMessage());
|
||||
}
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -82,8 +82,19 @@ struct AudioFormat {
|
||||
SampleFormat format;
|
||||
|
||||
/**
|
||||
* The number of channels. Only mono (1) and stereo (2) are
|
||||
* fully supported currently.
|
||||
* The number of channels.
|
||||
*
|
||||
* Channel order follows the FLAC convention
|
||||
* (https://xiph.org/flac/format.html):
|
||||
*
|
||||
* - 1 channel: mono
|
||||
* - 2 channels: left, right
|
||||
* - 3 channels: left, right, center
|
||||
* - 4 channels: front left, front right, back left, back right
|
||||
* - 5 channels: front left, front right, front center, back/surround left, back/surround right
|
||||
* - 6 channels: front left, front right, front center, LFE, back/surround left, back/surround right
|
||||
* - 7 channels: front left, front right, front center, LFE, back center, side left, side right
|
||||
* - 8 channels: front left, front right, front center, LFE, back left, back right, side left, side right
|
||||
*/
|
||||
uint8_t channels;
|
||||
|
||||
@@ -99,8 +110,8 @@ struct AudioFormat {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the #audio_format object, i.e. sets all attributes to an
|
||||
* undefined (invalid) value.
|
||||
* Clears the object, i.e. sets all attributes to an undefined
|
||||
* (invalid) value.
|
||||
*/
|
||||
void Clear() {
|
||||
sample_rate = 0;
|
||||
@@ -148,6 +159,13 @@ struct AudioFormat {
|
||||
|
||||
void ApplyMask(AudioFormat mask);
|
||||
|
||||
gcc_pure
|
||||
AudioFormat WithMask(AudioFormat mask) const {
|
||||
AudioFormat result = *this;
|
||||
result.ApplyMask(mask);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of each (mono) sample in bytes.
|
||||
*/
|
||||
@@ -185,8 +203,6 @@ audio_valid_sample_rate(unsigned sample_rate)
|
||||
|
||||
/**
|
||||
* Checks whether the sample format is valid.
|
||||
*
|
||||
* @param bits the number of significant bits per sample
|
||||
*/
|
||||
static inline bool
|
||||
audio_valid_sample_format(SampleFormat format)
|
||||
@@ -289,10 +305,10 @@ AudioFormat::GetTimeToSize() const
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a #sample_format enum into a string, e.g. for printing it
|
||||
* Renders a #SampleFormat enum into a string, e.g. for printing it
|
||||
* in a log file.
|
||||
*
|
||||
* @param format a #sample_format enum value
|
||||
* @param format a #SampleFormat enum value
|
||||
* @return the string
|
||||
*/
|
||||
gcc_pure gcc_malloc
|
||||
@@ -300,12 +316,12 @@ const char *
|
||||
sample_format_to_string(SampleFormat format);
|
||||
|
||||
/**
|
||||
* Renders the #audio_format object into a string, e.g. for printing
|
||||
* Renders the #AudioFormat object into a string, e.g. for printing
|
||||
* it in a log file.
|
||||
*
|
||||
* @param af the #audio_format object
|
||||
* @param af the #AudioFormat object
|
||||
* @param s a buffer to print into
|
||||
* @return the string, or nullptr if the #audio_format object is invalid
|
||||
* @return the string, or nullptr if the #AudioFormat object is invalid
|
||||
*/
|
||||
gcc_pure gcc_malloc
|
||||
const char *
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,73 +25,59 @@
|
||||
#include "config.h"
|
||||
#include "AudioParser.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "CheckAudioFormat.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "Compiler.h"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static bool
|
||||
parse_sample_rate(const char *src, bool mask, uint32_t *sample_rate_r,
|
||||
const char **endptr_r, Error &error)
|
||||
static uint32_t
|
||||
ParseSampleRate(const char *src, bool mask, const char **endptr_r)
|
||||
{
|
||||
unsigned long value;
|
||||
char *endptr;
|
||||
|
||||
if (mask && *src == '*') {
|
||||
*sample_rate_r = 0;
|
||||
*endptr_r = src + 1;
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = strtoul(src, &endptr, 10);
|
||||
if (endptr == src) {
|
||||
error.Set(audio_format_domain,
|
||||
"Failed to parse the sample rate");
|
||||
return false;
|
||||
} else if (!audio_check_sample_rate(value, error))
|
||||
return false;
|
||||
throw std::runtime_error("Failed to parse the sample rate");
|
||||
} else if (!audio_valid_sample_rate(value))
|
||||
throw FormatRuntimeError("Invalid sample rate: %lu",
|
||||
value);
|
||||
|
||||
*sample_rate_r = value;
|
||||
*endptr_r = endptr;
|
||||
return true;
|
||||
return value;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_sample_format(const char *src, bool mask,
|
||||
SampleFormat *sample_format_r,
|
||||
const char **endptr_r, Error &error)
|
||||
static SampleFormat
|
||||
ParseSampleFormat(const char *src, bool mask, const char **endptr_r)
|
||||
{
|
||||
unsigned long value;
|
||||
char *endptr;
|
||||
SampleFormat sample_format;
|
||||
|
||||
if (mask && *src == '*') {
|
||||
*sample_format_r = SampleFormat::UNDEFINED;
|
||||
*endptr_r = src + 1;
|
||||
return true;
|
||||
return SampleFormat::UNDEFINED;
|
||||
}
|
||||
|
||||
if (*src == 'f') {
|
||||
*sample_format_r = SampleFormat::FLOAT;
|
||||
*endptr_r = src + 1;
|
||||
return true;
|
||||
return SampleFormat::FLOAT;
|
||||
}
|
||||
|
||||
if (memcmp(src, "dsd", 3) == 0) {
|
||||
*sample_format_r = SampleFormat::DSD;
|
||||
*endptr_r = src + 3;
|
||||
return true;
|
||||
return SampleFormat::DSD;
|
||||
}
|
||||
|
||||
value = strtoul(src, &endptr, 10);
|
||||
if (endptr == src) {
|
||||
error.Set(audio_format_domain,
|
||||
"Failed to parse the sample format");
|
||||
return false;
|
||||
}
|
||||
if (endptr == src)
|
||||
throw std::runtime_error("Failed to parse the sample format");
|
||||
|
||||
switch (value) {
|
||||
case 8:
|
||||
@@ -115,99 +101,65 @@ parse_sample_format(const char *src, bool mask,
|
||||
break;
|
||||
|
||||
default:
|
||||
error.Format(audio_format_domain,
|
||||
"Invalid sample format: %lu", value);
|
||||
return false;
|
||||
throw FormatRuntimeError("Invalid sample format: %lu", value);
|
||||
}
|
||||
|
||||
assert(audio_valid_sample_format(sample_format));
|
||||
|
||||
*sample_format_r = sample_format;
|
||||
*endptr_r = endptr;
|
||||
return true;
|
||||
return sample_format;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_channel_count(const char *src, bool mask, uint8_t *channels_r,
|
||||
const char **endptr_r, Error &error)
|
||||
static uint8_t
|
||||
ParseChannelCount(const char *src, bool mask, const char **endptr_r)
|
||||
{
|
||||
unsigned long value;
|
||||
char *endptr;
|
||||
|
||||
if (mask && *src == '*') {
|
||||
*channels_r = 0;
|
||||
*endptr_r = src + 1;
|
||||
return true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = strtoul(src, &endptr, 10);
|
||||
if (endptr == src) {
|
||||
error.Set(audio_format_domain,
|
||||
"Failed to parse the channel count");
|
||||
return false;
|
||||
} else if (!audio_check_channel_count(value, error))
|
||||
return false;
|
||||
if (endptr == src)
|
||||
throw std::runtime_error("Failed to parse the channel count");
|
||||
else if (!audio_valid_channel_count(value))
|
||||
throw FormatRuntimeError("Invalid channel count: %u", value);
|
||||
|
||||
*channels_r = value;
|
||||
*endptr_r = endptr;
|
||||
return true;
|
||||
return value;
|
||||
}
|
||||
|
||||
bool
|
||||
audio_format_parse(AudioFormat &dest, const char *src,
|
||||
bool mask, Error &error)
|
||||
AudioFormat
|
||||
ParseAudioFormat(const char *src, bool mask)
|
||||
{
|
||||
uint32_t rate;
|
||||
SampleFormat sample_format;
|
||||
uint8_t channels;
|
||||
|
||||
AudioFormat dest;
|
||||
dest.Clear();
|
||||
|
||||
/* parse sample rate */
|
||||
|
||||
#if GCC_CHECK_VERSION(4,7)
|
||||
/* workaround -Wmaybe-uninitialized false positive */
|
||||
rate = 0;
|
||||
#endif
|
||||
dest.sample_rate = ParseSampleRate(src, mask, &src);
|
||||
|
||||
if (!parse_sample_rate(src, mask, &rate, &src, error))
|
||||
return false;
|
||||
|
||||
if (*src++ != ':') {
|
||||
error.Set(audio_format_domain, "Sample format missing");
|
||||
return false;
|
||||
}
|
||||
if (*src++ != ':')
|
||||
throw std::runtime_error("Sample format missing");
|
||||
|
||||
/* parse sample format */
|
||||
|
||||
#if GCC_CHECK_VERSION(4,7)
|
||||
/* workaround -Wmaybe-uninitialized false positive */
|
||||
sample_format = SampleFormat::UNDEFINED;
|
||||
#endif
|
||||
dest.format = ParseSampleFormat(src, mask, &src);
|
||||
|
||||
if (!parse_sample_format(src, mask, &sample_format, &src, error))
|
||||
return false;
|
||||
|
||||
if (*src++ != ':') {
|
||||
error.Set(audio_format_domain, "Channel count missing");
|
||||
return false;
|
||||
}
|
||||
if (*src++ != ':')
|
||||
throw std::runtime_error("Channel count missing");
|
||||
|
||||
/* parse channel count */
|
||||
|
||||
if (!parse_channel_count(src, mask, &channels, &src, error))
|
||||
return false;
|
||||
dest.channels = ParseChannelCount(src, mask, &src);
|
||||
|
||||
if (*src != 0) {
|
||||
error.Format(audio_format_domain,
|
||||
"Extra data after channel count: %s", src);
|
||||
return false;
|
||||
}
|
||||
if (*src != 0)
|
||||
throw FormatRuntimeError("Extra data after channel count: %s", src);
|
||||
|
||||
dest = AudioFormat(rate, sample_format, channels);
|
||||
assert(mask
|
||||
? dest.IsMaskValid()
|
||||
: dest.IsValid());
|
||||
|
||||
return true;
|
||||
return dest;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,22 +25,21 @@
|
||||
#ifndef MPD_AUDIO_PARSER_HXX
|
||||
#define MPD_AUDIO_PARSER_HXX
|
||||
|
||||
#include "Compiler.h"
|
||||
|
||||
struct AudioFormat;
|
||||
class Error;
|
||||
|
||||
/**
|
||||
* Parses a string in the form "SAMPLE_RATE:BITS:CHANNELS" into an
|
||||
* #audio_format.
|
||||
* #AudioFormat.
|
||||
*
|
||||
* Throws #std::runtime_error on error.
|
||||
*
|
||||
* @param dest the destination #audio_format struct
|
||||
* @param src the input string
|
||||
* @param mask if true, then "*" is allowed for any number of items
|
||||
* @param error_r location to store the error occurring, or NULL to
|
||||
* ignore errors
|
||||
* @return true on success
|
||||
*/
|
||||
bool
|
||||
audio_format_parse(AudioFormat &dest, const char *src,
|
||||
bool mask, Error &error);
|
||||
gcc_pure
|
||||
AudioFormat
|
||||
ParseAudioFormat(const char *src, bool mask);
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,61 +20,43 @@
|
||||
#include "config.h"
|
||||
#include "CheckAudioFormat.hxx"
|
||||
#include "AudioFormat.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
const Domain audio_format_domain("audio_format");
|
||||
|
||||
bool
|
||||
audio_check_sample_rate(unsigned long sample_rate, Error &error)
|
||||
void
|
||||
CheckSampleRate(unsigned long sample_rate)
|
||||
{
|
||||
if (!audio_valid_sample_rate(sample_rate)) {
|
||||
error.Format(audio_format_domain,
|
||||
"Invalid sample rate: %lu", sample_rate);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!audio_valid_sample_rate(sample_rate))
|
||||
throw FormatRuntimeError("Invalid sample rate: %lu",
|
||||
sample_rate);
|
||||
}
|
||||
|
||||
bool
|
||||
audio_check_sample_format(SampleFormat sample_format, Error &error)
|
||||
void
|
||||
CheckSampleFormat(SampleFormat sample_format)
|
||||
{
|
||||
if (!audio_valid_sample_format(sample_format)) {
|
||||
error.Format(audio_format_domain,
|
||||
"Invalid sample format: %u",
|
||||
unsigned(sample_format));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!audio_valid_sample_format(sample_format))
|
||||
throw FormatRuntimeError("Invalid sample format: %u",
|
||||
unsigned(sample_format));
|
||||
}
|
||||
|
||||
bool
|
||||
audio_check_channel_count(unsigned channels, Error &error)
|
||||
void
|
||||
CheckChannelCount(unsigned channels)
|
||||
{
|
||||
if (!audio_valid_channel_count(channels)) {
|
||||
error.Format(audio_format_domain,
|
||||
"Invalid channel count: %u", channels);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!audio_valid_channel_count(channels))
|
||||
throw FormatRuntimeError("Invalid channel count: %u",
|
||||
channels);
|
||||
}
|
||||
|
||||
bool
|
||||
audio_format_init_checked(AudioFormat &af, unsigned long sample_rate,
|
||||
SampleFormat sample_format, unsigned channels,
|
||||
Error &error)
|
||||
AudioFormat
|
||||
CheckAudioFormat(unsigned long sample_rate,
|
||||
SampleFormat sample_format, unsigned channels)
|
||||
{
|
||||
if (audio_check_sample_rate(sample_rate, error) &&
|
||||
audio_check_sample_format(sample_format, error) &&
|
||||
audio_check_channel_count(channels, error)) {
|
||||
af = AudioFormat(sample_rate, sample_format, channels);
|
||||
assert(af.IsValid());
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
CheckSampleRate(sample_rate);
|
||||
CheckSampleFormat(sample_format);
|
||||
CheckChannelCount(channels);
|
||||
|
||||
return AudioFormat(sample_rate, sample_format, channels);
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,25 +22,23 @@
|
||||
|
||||
#include "AudioFormat.hxx"
|
||||
|
||||
class Error;
|
||||
void
|
||||
CheckSampleRate(unsigned long sample_rate);
|
||||
|
||||
extern const class Domain audio_format_domain;
|
||||
void
|
||||
CheckSampleFormat(SampleFormat sample_format);
|
||||
|
||||
bool
|
||||
audio_check_sample_rate(unsigned long sample_rate, Error &error);
|
||||
|
||||
bool
|
||||
audio_check_sample_format(SampleFormat sample_format, Error &error);
|
||||
|
||||
bool
|
||||
audio_check_channel_count(unsigned sample_format, Error &error);
|
||||
void
|
||||
CheckChannelCount(unsigned sample_format);
|
||||
|
||||
/**
|
||||
* Wrapper for audio_format_init(), which checks all attributes.
|
||||
* Check #AudioFormat attributes and construct an #AudioFormat
|
||||
* instance.
|
||||
*
|
||||
* Throws #std::runtime_error on error.
|
||||
*/
|
||||
bool
|
||||
audio_format_init_checked(AudioFormat &af, unsigned long sample_rate,
|
||||
SampleFormat sample_format, unsigned channels,
|
||||
Error &error);
|
||||
AudioFormat
|
||||
CheckAudioFormat(unsigned long sample_rate,
|
||||
SampleFormat sample_format, unsigned channels);
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,19 +20,10 @@
|
||||
#ifndef MPD_CHRONO_HXX
|
||||
#define MPD_CHRONO_HXX
|
||||
|
||||
#include "Compiler.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <utility>
|
||||
#include <cstdint>
|
||||
|
||||
#if defined(__GNUC__) && !GCC_CHECK_VERSION(4,7) && !defined(__clang__)
|
||||
/* std::chrono::duration operators are "constexpr" since gcc 4.7 */
|
||||
#define chrono_constexpr gcc_pure
|
||||
#else
|
||||
#define chrono_constexpr constexpr
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A time stamp within a song. Granularity is 1 millisecond and the
|
||||
* maximum value is about 49 days.
|
||||
@@ -108,11 +99,11 @@ public:
|
||||
return count() > 0;
|
||||
}
|
||||
|
||||
chrono_constexpr SongTime operator+(const SongTime &other) const {
|
||||
constexpr SongTime operator+(const SongTime &other) const {
|
||||
return SongTime(*(const Base *)this + (const Base &)other);
|
||||
}
|
||||
|
||||
chrono_constexpr SongTime operator-(const SongTime &other) const {
|
||||
constexpr SongTime operator-(const SongTime &other) const {
|
||||
return SongTime(*(const Base *)this - (const Base &)other);
|
||||
}
|
||||
};
|
||||
@@ -212,15 +203,13 @@ public:
|
||||
return count() < 0;
|
||||
}
|
||||
|
||||
chrono_constexpr SignedSongTime operator+(const SignedSongTime &other) const {
|
||||
constexpr SignedSongTime operator+(const SignedSongTime &other) const {
|
||||
return SignedSongTime(*(const Base *)this + (const Base &)other);
|
||||
}
|
||||
|
||||
chrono_constexpr SignedSongTime operator-(const SignedSongTime &other) const {
|
||||
constexpr SignedSongTime operator-(const SignedSongTime &other) const {
|
||||
return SignedSongTime(*(const Base *)this - (const Base &)other);
|
||||
}
|
||||
};
|
||||
|
||||
#undef chrono_constexpr
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -35,7 +35,9 @@
|
||||
#include "fs/Traits.hxx"
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "fs/StandardDirectory.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "util/Macros.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/OptionDef.hxx"
|
||||
#include "util/OptionParser.hxx"
|
||||
@@ -66,12 +68,12 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#define CONFIG_FILE_LOCATION "mpd\\mpd.conf"
|
||||
#define APP_CONFIG_FILE_LOCATION "conf\\mpd.conf"
|
||||
#define CONFIG_FILE_LOCATION PATH_LITERAL("mpd\\mpd.conf")
|
||||
#define APP_CONFIG_FILE_LOCATION PATH_LITERAL("conf\\mpd.conf")
|
||||
#else
|
||||
#define USER_CONFIG_FILE_LOCATION1 ".mpdconf"
|
||||
#define USER_CONFIG_FILE_LOCATION2 ".mpd/mpd.conf"
|
||||
#define USER_CONFIG_FILE_LOCATION_XDG "mpd/mpd.conf"
|
||||
#define USER_CONFIG_FILE_LOCATION1 PATH_LITERAL(".mpdconf")
|
||||
#define USER_CONFIG_FILE_LOCATION2 PATH_LITERAL(".mpd/mpd.conf")
|
||||
#define USER_CONFIG_FILE_LOCATION_XDG PATH_LITERAL("mpd/mpd.conf")
|
||||
#endif
|
||||
|
||||
static constexpr OptionDef opt_kill(
|
||||
@@ -98,40 +100,44 @@ static constexpr Domain cmdline_domain("cmdline");
|
||||
gcc_noreturn
|
||||
static void version(void)
|
||||
{
|
||||
puts("Music Player Daemon " VERSION
|
||||
printf("Music Player Daemon " VERSION
|
||||
#ifdef GIT_COMMIT
|
||||
" (" GIT_COMMIT ")"
|
||||
" (" GIT_COMMIT ")"
|
||||
#endif
|
||||
"\n"
|
||||
"\n"
|
||||
"Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
|
||||
"Copyright (C) 2008-2014 Max Kellermann <max@duempel.org>\n"
|
||||
"This is free software; see the source for copying conditions. There is NO\n"
|
||||
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
|
||||
"\n"
|
||||
"\n"
|
||||
"Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
|
||||
"Copyright (C) 2008-2015 Max Kellermann <max@duempel.org>\n"
|
||||
"This is free software; see the source for copying conditions. There is NO\n"
|
||||
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
puts("\n"
|
||||
"Database plugins:");
|
||||
"\n"
|
||||
"Database plugins:\n");
|
||||
|
||||
for (auto i = database_plugins; *i != nullptr; ++i)
|
||||
printf(" %s", (*i)->name);
|
||||
|
||||
puts("\n\n"
|
||||
"Storage plugins:");
|
||||
printf("\n\n"
|
||||
"Storage plugins:\n");
|
||||
|
||||
for (auto i = storage_plugins; *i != nullptr; ++i)
|
||||
printf(" %s", (*i)->name);
|
||||
|
||||
printf("\n"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
puts("\n\n"
|
||||
"Neighbor plugins:");
|
||||
"\n"
|
||||
"Neighbor plugins:\n");
|
||||
for (auto i = neighbor_plugins; *i != nullptr; ++i)
|
||||
printf(" %s", (*i)->name);
|
||||
|
||||
printf("\n"
|
||||
#endif
|
||||
|
||||
puts("\n\n"
|
||||
"Decoders plugins:");
|
||||
"\n"
|
||||
"Decoders plugins:\n");
|
||||
|
||||
decoder_plugins_for_each([](const DecoderPlugin &plugin){
|
||||
printf(" [%s]", plugin.name);
|
||||
@@ -141,26 +147,39 @@ static void version(void)
|
||||
for (; *suffixes != nullptr; ++suffixes)
|
||||
printf(" %s", *suffixes);
|
||||
|
||||
puts("");
|
||||
printf("\n");
|
||||
});
|
||||
|
||||
puts("\n"
|
||||
"Output plugins:");
|
||||
printf("\n"
|
||||
"Filters:\n"
|
||||
#ifdef ENABLE_LIBSAMPLERATE
|
||||
" libsamplerate"
|
||||
#endif
|
||||
#ifdef ENABLE_SOXR
|
||||
" soxr"
|
||||
#endif
|
||||
"\n\n"
|
||||
"Tag plugins:\n"
|
||||
#ifdef ENABLE_ID3TAG
|
||||
" id3tag"
|
||||
#endif
|
||||
"\n\n"
|
||||
"Output plugins:\n");
|
||||
audio_output_plugins_for_each(plugin)
|
||||
printf(" %s", plugin->name);
|
||||
puts("");
|
||||
printf("\n"
|
||||
|
||||
#ifdef ENABLE_ENCODER
|
||||
puts("\n"
|
||||
"Encoder plugins:");
|
||||
"\n"
|
||||
"Encoder plugins:\n");
|
||||
encoder_plugins_for_each(plugin)
|
||||
printf(" %s", plugin->name);
|
||||
puts("");
|
||||
printf("\n"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_ARCHIVE
|
||||
puts("\n"
|
||||
"Archive plugins:");
|
||||
"\n"
|
||||
"Archive plugins:\n");
|
||||
archive_plugins_for_each(plugin) {
|
||||
printf(" [%s]", plugin->name);
|
||||
|
||||
@@ -169,24 +188,57 @@ static void version(void)
|
||||
for (; *suffixes != nullptr; ++suffixes)
|
||||
printf(" %s", *suffixes);
|
||||
|
||||
puts("");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf(""
|
||||
#endif
|
||||
|
||||
puts("\n"
|
||||
"Input plugins:");
|
||||
"\n"
|
||||
"Input plugins:\n");
|
||||
input_plugins_for_each(plugin)
|
||||
printf(" %s", plugin->name);
|
||||
|
||||
puts("\n\n"
|
||||
"Playlist plugins:");
|
||||
printf("\n\n"
|
||||
"Playlist plugins:\n");
|
||||
playlist_plugins_for_each(plugin)
|
||||
printf(" %s", plugin->name);
|
||||
|
||||
puts("\n\n"
|
||||
"Protocols:");
|
||||
printf("\n\n"
|
||||
"Protocols:\n");
|
||||
print_supported_uri_schemes_to_fp(stdout);
|
||||
|
||||
printf("\n"
|
||||
"Other features:\n"
|
||||
#ifdef HAVE_AVAHI
|
||||
" avahi"
|
||||
#endif
|
||||
#ifdef USE_EPOLL
|
||||
" epoll"
|
||||
#endif
|
||||
#ifdef HAVE_ICONV
|
||||
" iconv"
|
||||
#endif
|
||||
#ifdef HAVE_ICU
|
||||
" icu"
|
||||
#endif
|
||||
#ifdef ENABLE_INOTIFY
|
||||
" inotify"
|
||||
#endif
|
||||
#ifdef HAVE_IPV6
|
||||
" ipv6"
|
||||
#endif
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
" systemd"
|
||||
#endif
|
||||
#ifdef HAVE_TCP
|
||||
" tcp"
|
||||
#endif
|
||||
#ifdef HAVE_UN
|
||||
" un"
|
||||
#endif
|
||||
"\n");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -206,12 +258,12 @@ static void PrintOption(const OptionDef &opt)
|
||||
gcc_noreturn
|
||||
static void help(void)
|
||||
{
|
||||
puts("Usage:\n"
|
||||
" mpd [OPTION...] [path/to/mpd.conf]\n"
|
||||
"\n"
|
||||
"Music Player Daemon - a daemon for playing music.\n"
|
||||
"\n"
|
||||
"Options:");
|
||||
printf("Usage:\n"
|
||||
" mpd [OPTION...] [path/to/mpd.conf]\n"
|
||||
"\n"
|
||||
"Music Player Daemon - a daemon for playing music.\n"
|
||||
"\n"
|
||||
"Options:\n");
|
||||
|
||||
PrintOption(opt_help);
|
||||
PrintOption(opt_kill);
|
||||
@@ -226,29 +278,23 @@ static void help(void)
|
||||
|
||||
class ConfigLoader
|
||||
{
|
||||
Error &error;
|
||||
bool result;
|
||||
public:
|
||||
ConfigLoader(Error &_error) : error(_error), result(false) { }
|
||||
|
||||
bool GetResult() const { return result; }
|
||||
|
||||
bool TryFile(const Path path);
|
||||
bool TryFile(const AllocatedPath &base_path,
|
||||
PathTraitsFS::const_pointer path);
|
||||
PathTraitsFS::const_pointer_type path);
|
||||
};
|
||||
|
||||
bool ConfigLoader::TryFile(Path path)
|
||||
{
|
||||
if (FileExists(path)) {
|
||||
result = ReadConfigFile(path, error);
|
||||
ReadConfigFile(path);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConfigLoader::TryFile(const AllocatedPath &base_path,
|
||||
PathTraitsFS::const_pointer path)
|
||||
PathTraitsFS::const_pointer_type path)
|
||||
{
|
||||
if (base_path.IsNull())
|
||||
return false;
|
||||
@@ -256,9 +302,8 @@ bool ConfigLoader::TryFile(const AllocatedPath &base_path,
|
||||
return TryFile(full_path);
|
||||
}
|
||||
|
||||
bool
|
||||
parse_cmdline(int argc, char **argv, struct options *options,
|
||||
Error &error)
|
||||
void
|
||||
ParseCommandLine(int argc, char **argv, struct options *options)
|
||||
{
|
||||
bool use_config_file = true;
|
||||
options->kill = false;
|
||||
@@ -296,9 +341,8 @@ parse_cmdline(int argc, char **argv, struct options *options,
|
||||
if (parser.CheckOption(opt_help, opt_help_alt))
|
||||
help();
|
||||
|
||||
error.Format(cmdline_domain, "invalid option: %s",
|
||||
parser.GetOption());
|
||||
return false;
|
||||
throw FormatRuntimeError("invalid option: %s",
|
||||
parser.GetOption());
|
||||
}
|
||||
|
||||
/* initialize the logging library, so the configuration file
|
||||
@@ -308,7 +352,7 @@ parse_cmdline(int argc, char **argv, struct options *options,
|
||||
if (!use_config_file) {
|
||||
LogDebug(cmdline_domain,
|
||||
"Ignoring config, using daemon defaults");
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Second pass: find non-option parameters (i.e. config file)
|
||||
@@ -320,18 +364,29 @@ parse_cmdline(int argc, char **argv, struct options *options,
|
||||
config_file = argv[i];
|
||||
continue;
|
||||
}
|
||||
error.Set(cmdline_domain, "too many arguments");
|
||||
return false;
|
||||
|
||||
throw std::runtime_error("too many arguments");
|
||||
}
|
||||
|
||||
if (config_file != nullptr) {
|
||||
/* use specified configuration file */
|
||||
return ReadConfigFile(Path::FromFS(config_file), error);
|
||||
#ifdef _UNICODE
|
||||
wchar_t buffer[MAX_PATH];
|
||||
auto result = MultiByteToWideChar(CP_ACP, 0, config_file, -1,
|
||||
buffer, ARRAY_SIZE(buffer));
|
||||
if (result <= 0)
|
||||
throw MakeLastError("MultiByteToWideChar() failed");
|
||||
|
||||
ReadConfigFile(Path::FromFS(buffer));
|
||||
#else
|
||||
ReadConfigFile(Path::FromFS(config_file));
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
/* use default configuration file path */
|
||||
|
||||
ConfigLoader loader(error);
|
||||
ConfigLoader loader;
|
||||
|
||||
bool found =
|
||||
#ifdef WIN32
|
||||
@@ -345,10 +400,6 @@ parse_cmdline(int argc, char **argv, struct options *options,
|
||||
loader.TryFile(GetHomeDir(), USER_CONFIG_FILE_LOCATION2) ||
|
||||
loader.TryFile(Path::FromFS(SYSTEM_CONFIG_FILE_LOCATION));
|
||||
#endif
|
||||
if (!found) {
|
||||
error.Set(cmdline_domain, "No configuration file found");
|
||||
return false;
|
||||
}
|
||||
|
||||
return loader.GetResult();
|
||||
if (!found)
|
||||
throw std::runtime_error("No configuration file found");
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,8 +20,6 @@
|
||||
#ifndef MPD_COMMAND_LINE_HXX
|
||||
#define MPD_COMMAND_LINE_HXX
|
||||
|
||||
class Error;
|
||||
|
||||
struct options {
|
||||
bool kill;
|
||||
bool daemon;
|
||||
@@ -29,8 +27,7 @@ struct options {
|
||||
bool verbose;
|
||||
};
|
||||
|
||||
bool
|
||||
parse_cmdline(int argc, char **argv, struct options *options,
|
||||
Error &error);
|
||||
void
|
||||
ParseCommandLine(int argc, char **argv, struct options *options);
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,34 +20,62 @@
|
||||
#ifndef COMPILER_H
|
||||
#define COMPILER_H
|
||||
|
||||
#define GCC_CHECK_VERSION(major, minor) \
|
||||
(defined(__GNUC__) && \
|
||||
(__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))
|
||||
#define GCC_MAKE_VERSION(major, minor, patchlevel) ((major) * 10000 + (minor) * 100 + patchlevel)
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define GCC_VERSION (__GNUC__ * 10000 \
|
||||
+ __GNUC_MINOR__ * 100 \
|
||||
+ __GNUC_PATCHLEVEL__)
|
||||
#define GCC_VERSION GCC_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
#else
|
||||
#define GCC_VERSION 0
|
||||
#endif
|
||||
|
||||
#ifdef __clang__
|
||||
# define CLANG_VERSION (__clang_major__ * 10000 \
|
||||
+ __clang_minor__ * 100 \
|
||||
+ __clang_patchlevel__)
|
||||
# define CLANG_VERSION GCC_MAKE_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__)
|
||||
#elif defined(__GNUC__)
|
||||
# define CLANG_VERSION 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Are we building with the specified version of gcc (not clang or any
|
||||
* other compiler) or newer?
|
||||
*/
|
||||
#define GCC_CHECK_VERSION(major, minor) \
|
||||
(CLANG_VERSION == 0 && \
|
||||
GCC_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
|
||||
|
||||
/**
|
||||
* Are we building with clang (any version) or at least the specified
|
||||
* gcc version?
|
||||
*/
|
||||
#define CLANG_OR_GCC_VERSION(major, minor) \
|
||||
(CLANG_VERSION > 0 || GCC_CHECK_VERSION(major, minor))
|
||||
|
||||
/**
|
||||
* Are we building with gcc (not clang or any other compiler) and a
|
||||
* version older than the specified one?
|
||||
*/
|
||||
#define GCC_OLDER_THAN(major, minor) \
|
||||
(GCC_VERSION > 0 && CLANG_VERSION == 0 && \
|
||||
GCC_VERSION < GCC_MAKE_VERSION(major, minor, 0))
|
||||
|
||||
#ifdef __clang__
|
||||
# if __clang_major__ < 3
|
||||
# error Sorry, your clang version is too old. You need at least version 3.1.
|
||||
# endif
|
||||
#elif defined(__GNUC__)
|
||||
# if !GCC_CHECK_VERSION(4,6)
|
||||
# error Sorry, your gcc version is too old. You need at least version 4.6.
|
||||
# if GCC_OLDER_THAN(4,9)
|
||||
# error Sorry, your gcc version is too old. You need at least version 4.9.
|
||||
# endif
|
||||
#else
|
||||
# warning Untested compiler. Use at your own risk!
|
||||
#endif
|
||||
|
||||
#if GCC_CHECK_VERSION(4,0)
|
||||
/**
|
||||
* Are we building with the specified version of clang or newer?
|
||||
*/
|
||||
#define CLANG_CHECK_VERSION(major, minor) \
|
||||
(CLANG_VERSION >= GCC_MAKE_VERSION(major, minor, 0))
|
||||
|
||||
#if CLANG_OR_GCC_VERSION(4,0)
|
||||
|
||||
/* GCC 4.x */
|
||||
|
||||
@@ -69,8 +97,6 @@
|
||||
#define gcc_likely(x) __builtin_expect (!!(x), 1)
|
||||
#define gcc_unlikely(x) __builtin_expect (!!(x), 0)
|
||||
|
||||
#define gcc_aligned(n) __attribute__((aligned(n)))
|
||||
|
||||
#define gcc_visibility_hidden __attribute__((visibility("hidden")))
|
||||
#define gcc_visibility_default __attribute__((visibility("default")))
|
||||
|
||||
@@ -98,8 +124,6 @@
|
||||
#define gcc_likely(x) (x)
|
||||
#define gcc_unlikely(x) (x)
|
||||
|
||||
#define gcc_aligned(n)
|
||||
|
||||
#define gcc_visibility_hidden
|
||||
#define gcc_visibility_default
|
||||
|
||||
@@ -107,7 +131,7 @@
|
||||
|
||||
#endif
|
||||
|
||||
#if GCC_CHECK_VERSION(4,3)
|
||||
#if CLANG_OR_GCC_VERSION(4,3)
|
||||
|
||||
#define gcc_hot __attribute__((hot))
|
||||
#define gcc_cold __attribute__((cold))
|
||||
@@ -119,7 +143,7 @@
|
||||
|
||||
#endif /* ! GCC_UNUSED >= 40300 */
|
||||
|
||||
#if GCC_CHECK_VERSION(4,6) && !defined(__clang__)
|
||||
#if GCC_CHECK_VERSION(4,6)
|
||||
#define gcc_flatten __attribute__((flatten))
|
||||
#else
|
||||
#define gcc_flatten
|
||||
@@ -128,7 +152,7 @@
|
||||
#ifndef __cplusplus
|
||||
/* plain C99 has "restrict" */
|
||||
#define gcc_restrict restrict
|
||||
#elif GCC_CHECK_VERSION(4,0)
|
||||
#elif CLANG_OR_GCC_VERSION(4,0)
|
||||
/* "__restrict__" is a GCC extension for C++ */
|
||||
#define gcc_restrict __restrict__
|
||||
#else
|
||||
@@ -136,24 +160,6 @@
|
||||
#define gcc_restrict
|
||||
#endif
|
||||
|
||||
/* C++11 features */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
/* support for C++11 "override" was added in gcc 4.7 */
|
||||
#if !defined(__clang__) && !GCC_CHECK_VERSION(4,7)
|
||||
#define override
|
||||
#define final
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || GCC_CHECK_VERSION(4,8)
|
||||
#define gcc_alignas(T, fallback) alignas(T)
|
||||
#else
|
||||
#define gcc_alignas(T, fallback) gcc_aligned(fallback)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef __has_feature
|
||||
// define dummy macro for non-clang compilers
|
||||
#define __has_feature(x) 0
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -32,9 +32,9 @@
|
||||
|
||||
struct LightSong;
|
||||
class Storage;
|
||||
class Path;
|
||||
|
||||
class DetachedSong {
|
||||
friend DetachedSong map_song_detach(const LightSong &song);
|
||||
friend DetachedSong DatabaseDetachSong(const Storage &db,
|
||||
const LightSong &song);
|
||||
|
||||
@@ -146,7 +146,9 @@ public:
|
||||
*/
|
||||
gcc_pure
|
||||
bool IsSame(const DetachedSong &other) const {
|
||||
return uri == other.uri;
|
||||
return uri == other.uri &&
|
||||
start_time == other.start_time &&
|
||||
end_time == other.end_time;
|
||||
}
|
||||
|
||||
gcc_pure gcc_nonnull_all
|
||||
@@ -188,6 +190,14 @@ public:
|
||||
tag = std::move(other.tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to the MoveTagFrom(), but move only the #TagItem
|
||||
* array.
|
||||
*/
|
||||
void MoveTagItemsFrom(DetachedSong &&other) {
|
||||
tag.MoveItemsFrom(std::move(other.tag));
|
||||
}
|
||||
|
||||
time_t GetLastModified() const {
|
||||
return mtime;
|
||||
}
|
||||
@@ -221,6 +231,11 @@ public:
|
||||
* @return true on success
|
||||
*/
|
||||
bool Update();
|
||||
|
||||
/**
|
||||
* Load #tag and #mtime from a local file.
|
||||
*/
|
||||
bool LoadFile(Path path);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,96 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "GlobalEvents.hxx"
|
||||
#include "util/Manual.hxx"
|
||||
#include "event/DeferredMonitor.hxx"
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
namespace GlobalEvents {
|
||||
class Monitor final : public DeferredMonitor {
|
||||
public:
|
||||
Monitor(EventLoop &_loop):DeferredMonitor(_loop) {}
|
||||
|
||||
protected:
|
||||
virtual void RunDeferred() override;
|
||||
};
|
||||
|
||||
static Manual<Monitor> monitor;
|
||||
|
||||
static std::atomic_uint flags;
|
||||
static Handler handlers[MAX];
|
||||
}
|
||||
|
||||
/**
|
||||
* Invoke the callback for a certain event.
|
||||
*/
|
||||
static void
|
||||
InvokeGlobalEvent(GlobalEvents::Event event)
|
||||
{
|
||||
assert((unsigned)event < GlobalEvents::MAX);
|
||||
assert(GlobalEvents::handlers[event] != nullptr);
|
||||
|
||||
GlobalEvents::handlers[event]();
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEvents::Monitor::RunDeferred()
|
||||
{
|
||||
const unsigned f = flags.exchange(0);
|
||||
|
||||
for (unsigned i = 0; i < MAX; ++i)
|
||||
if (f & (1u << i))
|
||||
/* invoke the event handler */
|
||||
InvokeGlobalEvent(Event(i));
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEvents::Initialize(EventLoop &loop)
|
||||
{
|
||||
monitor.Construct(loop);
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEvents::Deinitialize()
|
||||
{
|
||||
monitor.Destruct();
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEvents::Register(Event event, Handler callback)
|
||||
{
|
||||
assert((unsigned)event < MAX);
|
||||
assert(handlers[event] == nullptr);
|
||||
|
||||
handlers[event] = callback;
|
||||
}
|
||||
|
||||
void
|
||||
GlobalEvents::Emit(Event event)
|
||||
{
|
||||
assert((unsigned)event < MAX);
|
||||
|
||||
const unsigned mask = 1u << unsigned(event);
|
||||
if (GlobalEvents::flags.fetch_or(mask) == 0)
|
||||
monitor->Schedule();
|
||||
}
|
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_GLOBAL_EVENTS_HXX
|
||||
#define MPD_GLOBAL_EVENTS_HXX
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
/* DELETE is a WIN32 macro that poisons our namespace; this is a
|
||||
kludge to allow us to use it anyway */
|
||||
#ifdef DELETE
|
||||
#undef DELETE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class EventLoop;
|
||||
|
||||
namespace GlobalEvents {
|
||||
enum Event {
|
||||
/** an idle event was emitted */
|
||||
IDLE,
|
||||
|
||||
/** must call playlist_sync() */
|
||||
PLAYLIST,
|
||||
|
||||
/** the current song's tag has changed */
|
||||
TAG,
|
||||
|
||||
#ifdef WIN32
|
||||
/** shutdown requested */
|
||||
SHUTDOWN,
|
||||
#endif
|
||||
|
||||
MAX
|
||||
};
|
||||
|
||||
typedef void (*Handler)();
|
||||
|
||||
void Initialize(EventLoop &loop);
|
||||
|
||||
void Deinitialize();
|
||||
|
||||
void Register(Event event, Handler handler);
|
||||
|
||||
void Emit(Event event);
|
||||
}
|
||||
|
||||
#endif /* MAIN_NOTIFY_H */
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -24,8 +24,6 @@
|
||||
#include "thread/Thread.hxx"
|
||||
#include "thread/Name.hxx"
|
||||
#include "event/Loop.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "util/Error.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
@@ -74,11 +72,8 @@ io_thread_start()
|
||||
assert(io.loop != nullptr);
|
||||
assert(!io.thread.IsDefined());
|
||||
|
||||
const ScopeLock protect(io.mutex);
|
||||
|
||||
Error error;
|
||||
if (!io.thread.Start(io_thread_func, nullptr, error))
|
||||
FatalError(error);
|
||||
const std::lock_guard<Mutex> protect(io.mutex);
|
||||
io.thread.Start(io_thread_func, nullptr);
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,7 +25,7 @@
|
||||
class EventLoop;
|
||||
|
||||
void
|
||||
io_thread_init(void);
|
||||
io_thread_init();
|
||||
|
||||
void
|
||||
io_thread_start();
|
||||
@@ -36,7 +36,7 @@ io_thread_start();
|
||||
* only.
|
||||
*/
|
||||
void
|
||||
io_thread_run(void);
|
||||
io_thread_run();
|
||||
|
||||
/**
|
||||
* Ask the I/O thread to quit, but does not wait for it. Usually, you
|
||||
@@ -44,10 +44,10 @@ io_thread_run(void);
|
||||
* includes this.
|
||||
*/
|
||||
void
|
||||
io_thread_quit(void);
|
||||
io_thread_quit();
|
||||
|
||||
void
|
||||
io_thread_deinit(void);
|
||||
io_thread_deinit();
|
||||
|
||||
gcc_const
|
||||
EventLoop &
|
||||
@@ -58,6 +58,6 @@ io_thread_get();
|
||||
*/
|
||||
gcc_pure
|
||||
bool
|
||||
io_thread_inside(void);
|
||||
io_thread_inside();
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "tag/Tag.hxx"
|
||||
#include "tag/TagBuilder.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/StringView.hxx"
|
||||
#include "Log.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
@@ -76,7 +77,7 @@ icy_add_item(TagBuilder &tag, TagType type, const char *value)
|
||||
}
|
||||
|
||||
if (length > 0)
|
||||
tag.AddItem(type, value, length);
|
||||
tag.AddItem(type, {value, length});
|
||||
}
|
||||
|
||||
static void
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
56
src/Idle.cxx
56
src/Idle.cxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -24,63 +24,15 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "Idle.hxx"
|
||||
#include "GlobalEvents.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
#include <atomic>
|
||||
#include "Main.hxx"
|
||||
#include "Instance.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static std::atomic_uint idle_flags;
|
||||
|
||||
static const char *const idle_names[] = {
|
||||
"database",
|
||||
"stored_playlist",
|
||||
"playlist",
|
||||
"player",
|
||||
"mixer",
|
||||
"output",
|
||||
"options",
|
||||
"sticker",
|
||||
"update",
|
||||
"subscription",
|
||||
"message",
|
||||
"neighbor",
|
||||
"mount",
|
||||
nullptr
|
||||
};
|
||||
|
||||
void
|
||||
idle_add(unsigned flags)
|
||||
{
|
||||
assert(flags != 0);
|
||||
|
||||
unsigned old_flags = idle_flags.fetch_or(flags);
|
||||
|
||||
if ((old_flags & flags) != flags)
|
||||
GlobalEvents::Emit(GlobalEvents::IDLE);
|
||||
}
|
||||
|
||||
unsigned
|
||||
idle_get(void)
|
||||
{
|
||||
return idle_flags.exchange(0);
|
||||
}
|
||||
|
||||
const char*const*
|
||||
idle_get_names(void)
|
||||
{
|
||||
return idle_names;
|
||||
}
|
||||
|
||||
unsigned
|
||||
idle_parse_name(const char *name)
|
||||
{
|
||||
assert(name != nullptr);
|
||||
|
||||
for (unsigned i = 0; idle_names[i] != nullptr; ++i)
|
||||
if (StringEqualsCaseASCII(name, idle_names[i]))
|
||||
return 1 << i;
|
||||
|
||||
return 0;
|
||||
instance->EmitIdle(flags);
|
||||
}
|
||||
|
64
src/Idle.hxx
64
src/Idle.hxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,47 +25,7 @@
|
||||
#ifndef MPD_IDLE_HXX
|
||||
#define MPD_IDLE_HXX
|
||||
|
||||
#include "Compiler.h"
|
||||
|
||||
/** song database has been updated*/
|
||||
static constexpr unsigned IDLE_DATABASE = 0x1;
|
||||
|
||||
/** a stored playlist has been modified, created, deleted or
|
||||
renamed */
|
||||
static constexpr unsigned IDLE_STORED_PLAYLIST = 0x2;
|
||||
|
||||
/** the current playlist has been modified */
|
||||
static constexpr unsigned IDLE_PLAYLIST = 0x4;
|
||||
|
||||
/** the player state has changed: play, stop, pause, seek, ... */
|
||||
static constexpr unsigned IDLE_PLAYER = 0x8;
|
||||
|
||||
/** the volume has been modified */
|
||||
static constexpr unsigned IDLE_MIXER = 0x10;
|
||||
|
||||
/** an audio output device has been enabled or disabled */
|
||||
static constexpr unsigned IDLE_OUTPUT = 0x20;
|
||||
|
||||
/** options have changed: crossfade; random; repeat; ... */
|
||||
static constexpr unsigned IDLE_OPTIONS = 0x40;
|
||||
|
||||
/** a sticker has been modified. */
|
||||
static constexpr unsigned IDLE_STICKER = 0x80;
|
||||
|
||||
/** a database update has started or finished. */
|
||||
static constexpr unsigned IDLE_UPDATE = 0x100;
|
||||
|
||||
/** a client has subscribed or unsubscribed to/from a channel */
|
||||
static constexpr unsigned IDLE_SUBSCRIPTION = 0x200;
|
||||
|
||||
/** a message on the subscribed channel was received */
|
||||
static constexpr unsigned IDLE_MESSAGE = 0x400;
|
||||
|
||||
/** a neighbor was found or lost */
|
||||
static constexpr unsigned IDLE_NEIGHBOR = 0x800;
|
||||
|
||||
/** the mount list has changed */
|
||||
static constexpr unsigned IDLE_MOUNT = 0x1000;
|
||||
#include "IdleFlags.hxx"
|
||||
|
||||
/**
|
||||
* Adds idle flag (with bitwise "or") and queues notifications to all
|
||||
@@ -74,24 +34,4 @@ static constexpr unsigned IDLE_MOUNT = 0x1000;
|
||||
void
|
||||
idle_add(unsigned flags);
|
||||
|
||||
/**
|
||||
* Atomically reads and resets the global idle flags value.
|
||||
*/
|
||||
unsigned
|
||||
idle_get(void);
|
||||
|
||||
/**
|
||||
* Get idle names
|
||||
*/
|
||||
const char*const*
|
||||
idle_get_names(void);
|
||||
|
||||
/**
|
||||
* Parse an idle name and return its mask. Returns 0 if the given
|
||||
* name is unknown.
|
||||
*/
|
||||
gcc_nonnull_all gcc_pure
|
||||
unsigned
|
||||
idle_parse_name(const char *name);
|
||||
|
||||
#endif
|
||||
|
67
src/IdleFlags.cxx
Normal file
67
src/IdleFlags.cxx
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Support library for the "idle" command.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "IdleFlags.hxx"
|
||||
#include "util/ASCII.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
static const char *const idle_names[] = {
|
||||
"database",
|
||||
"stored_playlist",
|
||||
"playlist",
|
||||
"player",
|
||||
"mixer",
|
||||
"output",
|
||||
"options",
|
||||
"sticker",
|
||||
"update",
|
||||
"subscription",
|
||||
"message",
|
||||
"neighbor",
|
||||
"mount",
|
||||
nullptr
|
||||
};
|
||||
|
||||
const char*const*
|
||||
idle_get_names(void)
|
||||
{
|
||||
return idle_names;
|
||||
}
|
||||
|
||||
unsigned
|
||||
idle_parse_name(const char *name)
|
||||
{
|
||||
#if !CLANG_CHECK_VERSION(3,6)
|
||||
/* disabled on clang due to -Wtautological-pointer-compare */
|
||||
assert(name != nullptr);
|
||||
#endif
|
||||
|
||||
for (unsigned i = 0; idle_names[i] != nullptr; ++i)
|
||||
if (StringEqualsCaseASCII(name, idle_names[i]))
|
||||
return 1 << i;
|
||||
|
||||
return 0;
|
||||
}
|
84
src/IdleFlags.hxx
Normal file
84
src/IdleFlags.hxx
Normal file
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Support library for the "idle" command.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MPD_IDLE_FLAGS_HXX
|
||||
#define MPD_IDLE_FLAGS_HXX
|
||||
|
||||
#include "Compiler.h"
|
||||
|
||||
/** song database has been updated*/
|
||||
static constexpr unsigned IDLE_DATABASE = 0x1;
|
||||
|
||||
/** a stored playlist has been modified, created, deleted or
|
||||
renamed */
|
||||
static constexpr unsigned IDLE_STORED_PLAYLIST = 0x2;
|
||||
|
||||
/** the current playlist has been modified */
|
||||
static constexpr unsigned IDLE_PLAYLIST = 0x4;
|
||||
|
||||
/** the player state has changed: play, stop, pause, seek, ... */
|
||||
static constexpr unsigned IDLE_PLAYER = 0x8;
|
||||
|
||||
/** the volume has been modified */
|
||||
static constexpr unsigned IDLE_MIXER = 0x10;
|
||||
|
||||
/** an audio output device has been enabled or disabled */
|
||||
static constexpr unsigned IDLE_OUTPUT = 0x20;
|
||||
|
||||
/** options have changed: crossfade; random; repeat; ... */
|
||||
static constexpr unsigned IDLE_OPTIONS = 0x40;
|
||||
|
||||
/** a sticker has been modified. */
|
||||
static constexpr unsigned IDLE_STICKER = 0x80;
|
||||
|
||||
/** a database update has started or finished. */
|
||||
static constexpr unsigned IDLE_UPDATE = 0x100;
|
||||
|
||||
/** a client has subscribed or unsubscribed to/from a channel */
|
||||
static constexpr unsigned IDLE_SUBSCRIPTION = 0x200;
|
||||
|
||||
/** a message on the subscribed channel was received */
|
||||
static constexpr unsigned IDLE_MESSAGE = 0x400;
|
||||
|
||||
/** a neighbor was found or lost */
|
||||
static constexpr unsigned IDLE_NEIGHBOR = 0x800;
|
||||
|
||||
/** the mount list has changed */
|
||||
static constexpr unsigned IDLE_MOUNT = 0x1000;
|
||||
|
||||
/**
|
||||
* Get idle names
|
||||
*/
|
||||
const char*const*
|
||||
idle_get_names();
|
||||
|
||||
/**
|
||||
* Parse an idle name and return its mask. Returns 0 if the given
|
||||
* name is unknown.
|
||||
*/
|
||||
gcc_nonnull_all gcc_pure
|
||||
unsigned
|
||||
idle_parse_name(const char *name);
|
||||
|
||||
#endif
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -25,37 +25,27 @@
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "db/DatabaseError.hxx"
|
||||
#include "db/LightSong.hxx"
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
#include "sticker/StickerDatabase.hxx"
|
||||
#include "sticker/SongSticker.hxx"
|
||||
#endif
|
||||
|
||||
Database *
|
||||
Instance::GetDatabase(Error &error)
|
||||
{
|
||||
if (database == nullptr)
|
||||
error.Set(db_domain, DB_DISABLED, "No database");
|
||||
return database;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
Instance::TagModified()
|
||||
{
|
||||
partition->TagModified();
|
||||
}
|
||||
|
||||
void
|
||||
Instance::SyncWithPlayer()
|
||||
{
|
||||
partition->SyncWithPlayer();
|
||||
}
|
||||
#include <stdexcept>
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
const Database &
|
||||
Instance::GetDatabaseOrThrow() const
|
||||
{
|
||||
if (database == nullptr)
|
||||
throw DatabaseError(DatabaseErrorCode::DISABLED,
|
||||
"No database");
|
||||
|
||||
return *database;
|
||||
}
|
||||
|
||||
void
|
||||
Instance::OnDatabaseModified()
|
||||
{
|
||||
@@ -65,22 +55,24 @@ Instance::OnDatabaseModified()
|
||||
|
||||
stats_invalidate();
|
||||
partition->DatabaseModified(*database);
|
||||
idle_add(IDLE_DATABASE);
|
||||
}
|
||||
|
||||
void
|
||||
Instance::OnDatabaseSongRemoved(const LightSong &song)
|
||||
Instance::OnDatabaseSongRemoved(const char *uri)
|
||||
{
|
||||
assert(database != nullptr);
|
||||
|
||||
#ifdef ENABLE_SQLITE
|
||||
/* if the song has a sticker, remove it */
|
||||
if (sticker_enabled())
|
||||
sticker_song_delete(song);
|
||||
if (sticker_enabled()) {
|
||||
try {
|
||||
sticker_song_delete(uri);
|
||||
} catch (const std::runtime_error &) {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const auto uri = song.GetURI();
|
||||
partition->DeleteSong(uri.c_str());
|
||||
partition->StaleSong(uri);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -90,13 +82,13 @@ Instance::OnDatabaseSongRemoved(const LightSong &song)
|
||||
void
|
||||
Instance::FoundNeighbor(gcc_unused const NeighborInfo &info)
|
||||
{
|
||||
idle_add(IDLE_NEIGHBOR);
|
||||
partition->EmitIdle(IDLE_NEIGHBOR);
|
||||
}
|
||||
|
||||
void
|
||||
Instance::LostNeighbor(gcc_unused const NeighborInfo &info)
|
||||
{
|
||||
idle_add(IDLE_NEIGHBOR);
|
||||
partition->EmitIdle(IDLE_NEIGHBOR);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,6 +21,8 @@
|
||||
#define MPD_INSTANCE_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "event/Loop.hxx"
|
||||
#include "event/MaskMonitor.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
@@ -35,14 +37,22 @@ class Storage;
|
||||
class UpdateService;
|
||||
#endif
|
||||
|
||||
class EventLoop;
|
||||
class Error;
|
||||
class ClientList;
|
||||
struct Partition;
|
||||
class StateFile;
|
||||
|
||||
/**
|
||||
* A utility class which, when used as the first base class, ensures
|
||||
* that the #EventLoop gets initialized before the other base classes.
|
||||
*/
|
||||
struct EventLoopHolder {
|
||||
EventLoop event_loop;
|
||||
};
|
||||
|
||||
struct Instance final
|
||||
: EventLoopHolder
|
||||
#if defined(ENABLE_DATABASE) || defined(ENABLE_NEIGHBOR_PLUGINS)
|
||||
:
|
||||
,
|
||||
#endif
|
||||
#ifdef ENABLE_DATABASE
|
||||
public DatabaseListener
|
||||
@@ -54,7 +64,7 @@ struct Instance final
|
||||
public NeighborListener
|
||||
#endif
|
||||
{
|
||||
EventLoop *event_loop;
|
||||
MaskMonitor idle_monitor;
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
NeighborGlue *neighbors;
|
||||
@@ -67,20 +77,29 @@ struct Instance final
|
||||
* This is really a #CompositeStorage. To avoid heavy include
|
||||
* dependencies, we declare it as just #Storage.
|
||||
*/
|
||||
Storage *storage;
|
||||
Storage *storage = nullptr;
|
||||
|
||||
UpdateService *update;
|
||||
UpdateService *update = nullptr;
|
||||
#endif
|
||||
|
||||
ClientList *client_list;
|
||||
|
||||
Partition *partition;
|
||||
|
||||
Instance() {
|
||||
#ifdef ENABLE_DATABASE
|
||||
storage = nullptr;
|
||||
update = nullptr;
|
||||
#endif
|
||||
StateFile *state_file;
|
||||
|
||||
Instance()
|
||||
:idle_monitor(event_loop, BIND_THIS_METHOD(OnIdle)), state_file(nullptr) {}
|
||||
|
||||
/**
|
||||
* Initiate shutdown. Wrapper for EventLoop::Break().
|
||||
*/
|
||||
void Shutdown() {
|
||||
event_loop.Break();
|
||||
}
|
||||
|
||||
void EmitIdle(unsigned mask) {
|
||||
idle_monitor.OrMask(mask);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
@@ -89,31 +108,33 @@ struct Instance final
|
||||
* if this MPD configuration has no database (no
|
||||
* music_directory was configured).
|
||||
*/
|
||||
Database *GetDatabase(Error &error);
|
||||
Database *GetDatabase() {
|
||||
return database;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the global #Database instance. Throws
|
||||
* DatabaseError if this MPD configuration has no database (no
|
||||
* music_directory was configured).
|
||||
*/
|
||||
gcc_pure
|
||||
const Database &GetDatabaseOrThrow() const;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A tag in the play queue has been modified by the player
|
||||
* thread. Propagate the change to all subsystems.
|
||||
*/
|
||||
void TagModified();
|
||||
|
||||
/**
|
||||
* Synchronize the player with the play queue.
|
||||
*/
|
||||
void SyncWithPlayer();
|
||||
|
||||
private:
|
||||
#ifdef ENABLE_DATABASE
|
||||
virtual void OnDatabaseModified() override;
|
||||
virtual void OnDatabaseSongRemoved(const LightSong &song) override;
|
||||
void OnDatabaseModified() override;
|
||||
void OnDatabaseSongRemoved(const char *uri) override;
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
/* virtual methods from class NeighborListener */
|
||||
virtual void FoundNeighbor(const NeighborInfo &info) override;
|
||||
virtual void LostNeighbor(const NeighborInfo &info) override;
|
||||
void FoundNeighbor(const NeighborInfo &info) override;
|
||||
void LostNeighbor(const NeighborInfo &info) override;
|
||||
#endif
|
||||
|
||||
/* callback for #idle_monitor */
|
||||
void OnIdle(unsigned mask);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,11 +20,13 @@
|
||||
#include "config.h"
|
||||
#include "Listen.hxx"
|
||||
#include "client/Client.hxx"
|
||||
#include "config/ConfigData.hxx"
|
||||
#include "config/Param.hxx"
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "config/ConfigOption.hxx"
|
||||
#include "net/SocketAddress.hxx"
|
||||
#include "event/ServerSocket.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "system/Error.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "Log.hxx"
|
||||
@@ -48,73 +50,65 @@ public:
|
||||
:ServerSocket(_loop), partition(_partition) {}
|
||||
|
||||
private:
|
||||
virtual void OnAccept(int fd, const sockaddr &address,
|
||||
size_t address_length, int uid) {
|
||||
void OnAccept(int fd, SocketAddress address, int uid) override {
|
||||
client_new(GetEventLoop(), partition,
|
||||
fd, &address, address_length, uid);
|
||||
fd, address, uid);
|
||||
}
|
||||
};
|
||||
|
||||
static ClientListener *listen_socket;
|
||||
int listen_port;
|
||||
|
||||
static bool
|
||||
/**
|
||||
* Throws #std::runtime_error on error.
|
||||
*/
|
||||
static void
|
||||
listen_add_config_param(unsigned int port,
|
||||
const struct config_param *param,
|
||||
Error &error_r)
|
||||
const ConfigParam *param)
|
||||
{
|
||||
assert(param != nullptr);
|
||||
|
||||
if (0 == strcmp(param->value.c_str(), "any")) {
|
||||
return listen_socket->AddPort(port, error_r);
|
||||
listen_socket->AddPort(port);
|
||||
} else if (param->value[0] == '/' || param->value[0] == '~') {
|
||||
auto path = config_parse_path(param, error_r);
|
||||
return !path.IsNull() &&
|
||||
listen_socket->AddPath(std::move(path), error_r);
|
||||
listen_socket->AddPath(param->GetPath());
|
||||
} else {
|
||||
return listen_socket->AddHost(param->value.c_str(), port,
|
||||
error_r);
|
||||
listen_socket->AddHost(param->value.c_str(), port);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
|
||||
static bool
|
||||
listen_systemd_activation(Error &error_r)
|
||||
listen_systemd_activation()
|
||||
{
|
||||
int n = sd_listen_fds(true);
|
||||
if (n <= 0) {
|
||||
if (n < 0)
|
||||
FormatErrno(listen_domain, -n,
|
||||
"sd_listen_fds() failed");
|
||||
throw MakeErrno(-n, "sd_listen_fds() failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = SD_LISTEN_FDS_START, end = SD_LISTEN_FDS_START + n;
|
||||
i != end; ++i)
|
||||
if (!listen_socket->AddFD(i, error_r))
|
||||
return false;
|
||||
listen_socket->AddFD(i);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool
|
||||
listen_global_init(EventLoop &loop, Partition &partition, Error &error)
|
||||
void
|
||||
listen_global_init(EventLoop &loop, Partition &partition)
|
||||
{
|
||||
int port = config_get_positive(CONF_PORT, DEFAULT_PORT);
|
||||
const struct config_param *param =
|
||||
config_get_param(CONF_BIND_TO_ADDRESS);
|
||||
int port = config_get_positive(ConfigOption::PORT, DEFAULT_PORT);
|
||||
const auto *param = config_get_param(ConfigOption::BIND_TO_ADDRESS);
|
||||
|
||||
listen_socket = new ClientListener(loop, partition);
|
||||
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
if (listen_systemd_activation(error))
|
||||
return true;
|
||||
|
||||
if (error.IsDefined())
|
||||
return false;
|
||||
if (listen_systemd_activation())
|
||||
return;
|
||||
#endif
|
||||
|
||||
if (param != nullptr) {
|
||||
@@ -122,32 +116,35 @@ listen_global_init(EventLoop &loop, Partition &partition, Error &error)
|
||||
for all values */
|
||||
|
||||
do {
|
||||
if (!listen_add_config_param(port, param, error)) {
|
||||
try {
|
||||
listen_add_config_param(port, param);
|
||||
} catch (const std::runtime_error &e) {
|
||||
delete listen_socket;
|
||||
error.FormatPrefix("Failed to listen on %s (line %i): ",
|
||||
param->value.c_str(),
|
||||
param->line);
|
||||
return false;
|
||||
std::throw_with_nested(FormatRuntimeError("Failed to listen on %s (line %i)",
|
||||
param->value.c_str(),
|
||||
param->line));
|
||||
}
|
||||
} while ((param = param->next) != nullptr);
|
||||
} else {
|
||||
/* no "bind_to_address" configured, bind the
|
||||
configured port on all interfaces */
|
||||
|
||||
if (!listen_socket->AddPort(port, error)) {
|
||||
try {
|
||||
listen_socket->AddPort(port);
|
||||
} catch (const std::runtime_error &e) {
|
||||
delete listen_socket;
|
||||
error.FormatPrefix("Failed to listen on *:%d: ", port);
|
||||
return false;
|
||||
std::throw_with_nested(FormatRuntimeError("Failed to listen on *:%d: ", port));
|
||||
}
|
||||
}
|
||||
|
||||
if (!listen_socket->Open(error)) {
|
||||
try {
|
||||
listen_socket->Open();
|
||||
} catch (const std::runtime_error &e) {
|
||||
delete listen_socket;
|
||||
return false;
|
||||
throw;
|
||||
}
|
||||
|
||||
listen_port = port;
|
||||
return true;
|
||||
}
|
||||
|
||||
void listen_global_finish(void)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,14 +21,14 @@
|
||||
#define MPD_LISTEN_HXX
|
||||
|
||||
class EventLoop;
|
||||
class Error;
|
||||
struct Partition;
|
||||
|
||||
extern int listen_port;
|
||||
|
||||
bool
|
||||
listen_global_init(EventLoop &loop, Partition &partition, Error &error);
|
||||
void
|
||||
listen_global_init(EventLoop &loop, Partition &partition);
|
||||
|
||||
void listen_global_finish(void);
|
||||
void
|
||||
listen_global_finish();
|
||||
|
||||
#endif
|
||||
|
110
src/LocateUri.cxx
Normal file
110
src/LocateUri.cxx
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "LocateUri.hxx"
|
||||
#include "client/Client.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "ls.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "storage/StorageInterface.hxx"
|
||||
#endif
|
||||
|
||||
static LocatedUri
|
||||
LocateFileUri(const char *uri, const Client *client
|
||||
#ifdef ENABLE_DATABASE
|
||||
, const Storage *storage
|
||||
#endif
|
||||
)
|
||||
{
|
||||
auto path = AllocatedPath::FromUTF8Throw(uri);
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (storage != nullptr) {
|
||||
const char *suffix = storage->MapToRelativeUTF8(uri);
|
||||
if (suffix != nullptr)
|
||||
/* this path was relative to the music
|
||||
directory */
|
||||
return LocatedUri(LocatedUri::Type::RELATIVE, suffix);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (client != nullptr)
|
||||
client->AllowFile(path);
|
||||
|
||||
return LocatedUri(LocatedUri::Type::PATH, uri, std::move(path));
|
||||
}
|
||||
|
||||
static LocatedUri
|
||||
LocateAbsoluteUri(const char *uri
|
||||
#ifdef ENABLE_DATABASE
|
||||
, const Storage *storage
|
||||
#endif
|
||||
)
|
||||
{
|
||||
if (!uri_supported_scheme(uri))
|
||||
throw std::runtime_error("Unsupported URI scheme");
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (storage != nullptr) {
|
||||
const char *suffix = storage->MapToRelativeUTF8(uri);
|
||||
if (suffix != nullptr)
|
||||
return LocatedUri(LocatedUri::Type::RELATIVE, suffix);
|
||||
}
|
||||
#endif
|
||||
|
||||
return LocatedUri(LocatedUri::Type::ABSOLUTE, uri);
|
||||
}
|
||||
|
||||
LocatedUri
|
||||
LocateUri(const char *uri, const Client *client
|
||||
#ifdef ENABLE_DATABASE
|
||||
, const Storage *storage
|
||||
#endif
|
||||
)
|
||||
{
|
||||
/* skip the obsolete "file://" prefix */
|
||||
const char *path_utf8 = StringAfterPrefix(uri, "file://");
|
||||
if (path_utf8 != nullptr) {
|
||||
if (!PathTraitsUTF8::IsAbsolute(path_utf8))
|
||||
throw std::runtime_error("Malformed file:// URI");
|
||||
|
||||
return LocateFileUri(path_utf8, client
|
||||
#ifdef ENABLE_DATABASE
|
||||
, storage
|
||||
#endif
|
||||
);
|
||||
} else if (PathTraitsUTF8::IsAbsolute(uri))
|
||||
return LocateFileUri(uri, client
|
||||
#ifdef ENABLE_DATABASE
|
||||
, storage
|
||||
#endif
|
||||
);
|
||||
else if (uri_has_scheme(uri))
|
||||
return LocateAbsoluteUri(uri
|
||||
#ifdef ENABLE_DATABASE
|
||||
, storage
|
||||
#endif
|
||||
);
|
||||
else
|
||||
return LocatedUri(LocatedUri::Type::RELATIVE, uri);
|
||||
}
|
93
src/LocateUri.hxx
Normal file
93
src/LocateUri.hxx
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef MPD_LOCATE_URI_HXX
|
||||
#define MPD_LOCATE_URI_HXX
|
||||
|
||||
#include "check.h"
|
||||
#include "Compiler.h"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
/* damn you, windows.h! */
|
||||
#ifdef ABSOLUTE
|
||||
#undef ABSOLUTE
|
||||
#endif
|
||||
#ifdef RELATIVE
|
||||
#undef RELATIVE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class Client;
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
class Storage;
|
||||
#endif
|
||||
|
||||
struct LocatedUri {
|
||||
enum class Type {
|
||||
/**
|
||||
* An absolute URI with a supported scheme.
|
||||
*/
|
||||
ABSOLUTE,
|
||||
|
||||
/**
|
||||
* A relative URI path.
|
||||
*/
|
||||
RELATIVE,
|
||||
|
||||
/**
|
||||
* A local file. The #path attribute is valid.
|
||||
*/
|
||||
PATH,
|
||||
} type;
|
||||
|
||||
const char *canonical_uri;
|
||||
|
||||
/**
|
||||
* Contains the local file path if type==FILE.
|
||||
*/
|
||||
AllocatedPath path;
|
||||
|
||||
LocatedUri(Type _type, const char *_uri,
|
||||
AllocatedPath &&_path=AllocatedPath::Null())
|
||||
:type(_type), canonical_uri(_uri), path(std::move(_path)) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Classify a URI.
|
||||
*
|
||||
* Throws #std::runtime_error on error.
|
||||
*
|
||||
* @param client the #Client that is used to determine whether a local
|
||||
* file is allowed; nullptr disables the check and allows all local
|
||||
* files
|
||||
* @param storage a #Storage instance which may be used to convert
|
||||
* absolute URIs to relative ones, using Storage::MapToRelativeUTF8();
|
||||
* that feature is disabled if this parameter is nullptr
|
||||
*/
|
||||
LocatedUri
|
||||
LocateUri(const char *uri, const Client *client
|
||||
#ifdef ENABLE_DATABASE
|
||||
, const Storage *storage
|
||||
#endif
|
||||
);
|
||||
|
||||
#endif
|
78
src/Log.cxx
78
src/Log.cxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,13 +19,16 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "LogV.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
static constexpr Domain exception_domain("exception");
|
||||
|
||||
void
|
||||
LogFormatV(const Domain &domain, LogLevel level, const char *fmt, va_list ap)
|
||||
{
|
||||
@@ -89,20 +92,37 @@ FormatError(const Domain &domain, const char *fmt, ...)
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const Error &error)
|
||||
LogError(const std::exception &e)
|
||||
{
|
||||
Log(error.GetDomain(), LogLevel::ERROR, error.GetMessage());
|
||||
Log(exception_domain, LogLevel::ERROR, e.what());
|
||||
|
||||
try {
|
||||
std::rethrow_if_nested(e);
|
||||
} catch (const std::exception &nested) {
|
||||
LogError(nested, "nested");
|
||||
} catch (...) {
|
||||
Log(exception_domain, LogLevel::ERROR,
|
||||
"Unrecognized nested exception");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const Error &error, const char *msg)
|
||||
LogError(const std::exception &e, const char *msg)
|
||||
{
|
||||
LogFormat(error.GetDomain(), LogLevel::ERROR, "%s: %s",
|
||||
msg, error.GetMessage());
|
||||
FormatError(exception_domain, "%s: %s", msg, e.what());
|
||||
|
||||
try {
|
||||
std::rethrow_if_nested(e);
|
||||
} catch (const std::exception &nested) {
|
||||
LogError(nested);
|
||||
} catch (...) {
|
||||
Log(exception_domain, LogLevel::ERROR,
|
||||
"Unrecognized nested exception");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FormatError(const Error &error, const char *fmt, ...)
|
||||
FormatError(const std::exception &e, const char *fmt, ...)
|
||||
{
|
||||
char msg[1024];
|
||||
va_list ap;
|
||||
@@ -110,7 +130,45 @@ FormatError(const Error &error, const char *fmt, ...)
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
LogError(error, msg);
|
||||
LogError(e, msg);
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep)
|
||||
{
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
} catch (...) {
|
||||
Log(exception_domain, LogLevel::ERROR,
|
||||
"Unrecognized exception");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep, const char *msg)
|
||||
{
|
||||
try {
|
||||
std::rethrow_exception(ep);
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e, msg);
|
||||
} catch (...) {
|
||||
FormatError(exception_domain,
|
||||
"%s: Unrecognized exception", msg);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FormatError(const std::exception_ptr &ep, const char *fmt, ...)
|
||||
{
|
||||
char msg[1024];
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(msg, sizeof(msg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
LogError(ep, msg);
|
||||
}
|
||||
|
||||
void
|
||||
|
35
src/Log.hxx
35
src/Log.hxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -23,7 +23,8 @@
|
||||
#include "LogLevel.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
class Error;
|
||||
#include <exception>
|
||||
|
||||
class Domain;
|
||||
|
||||
void
|
||||
@@ -79,20 +80,30 @@ LogError(const Domain &domain, const char *msg)
|
||||
Log(domain, LogLevel::ERROR, msg);
|
||||
}
|
||||
|
||||
void
|
||||
LogError(const std::exception &e);
|
||||
|
||||
void
|
||||
LogError(const std::exception &e, const char *msg);
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatError(const std::exception &e, const char *fmt, ...);
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep);
|
||||
|
||||
void
|
||||
LogError(const std::exception_ptr &ep, const char *msg);
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatError(const std::exception_ptr &ep, const char *fmt, ...);
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatError(const Domain &domain, const char *fmt, ...);
|
||||
|
||||
void
|
||||
LogError(const Error &error);
|
||||
|
||||
void
|
||||
LogError(const Error &error, const char *msg);
|
||||
|
||||
gcc_printf(2,3)
|
||||
void
|
||||
FormatError(const Error &error, const char *fmt, ...);
|
||||
|
||||
void
|
||||
LogErrno(const Domain &domain, int e, const char *msg);
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -23,10 +23,6 @@
|
||||
#include "util/Domain.hxx"
|
||||
#include "util/StringUtil.hxx"
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
#include <glib.h>
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@@ -65,10 +61,6 @@ ToAndroidLogLevel(LogLevel log_level)
|
||||
|
||||
static LogLevel log_threshold = LogLevel::INFO;
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
static const char *log_charset;
|
||||
#endif
|
||||
|
||||
static bool enable_timestamp;
|
||||
|
||||
#ifdef HAVE_SYSLOG
|
||||
@@ -81,16 +73,6 @@ SetLogThreshold(LogLevel _threshold)
|
||||
log_threshold = _threshold;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
|
||||
void
|
||||
SetLogCharset(const char *_charset)
|
||||
{
|
||||
log_charset = _charset;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
EnableLogTimestamp()
|
||||
{
|
||||
@@ -175,27 +157,15 @@ LogFinishSysLog()
|
||||
static void
|
||||
FileLog(const Domain &domain, const char *message)
|
||||
{
|
||||
#ifdef HAVE_GLIB
|
||||
char *converted;
|
||||
|
||||
if (log_charset != nullptr) {
|
||||
converted = g_convert_with_fallback(message, -1,
|
||||
log_charset, "utf-8",
|
||||
nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
if (converted != nullptr)
|
||||
message = converted;
|
||||
} else
|
||||
converted = nullptr;
|
||||
#endif
|
||||
|
||||
fprintf(stderr, "%s%s: %.*s\n",
|
||||
enable_timestamp ? log_date() : "",
|
||||
domain.GetName(),
|
||||
chomp_length(message), message);
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
g_free(converted);
|
||||
#ifdef WIN32
|
||||
/* force-flush the log file, because setvbuf() does not seem
|
||||
to have an effect on WIN32 */
|
||||
fflush(stderr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -26,13 +26,6 @@
|
||||
void
|
||||
SetLogThreshold(LogLevel _threshold);
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
|
||||
void
|
||||
SetLogCharset(const char *_charset);
|
||||
|
||||
#endif
|
||||
|
||||
void
|
||||
EnableLogTimestamp();
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -21,25 +21,19 @@
|
||||
#include "LogInit.hxx"
|
||||
#include "LogBackend.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "config/ConfigData.hxx"
|
||||
#include "config/Param.hxx"
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "config/ConfigOption.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "fs/FileSystem.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
#include <glib.h>
|
||||
#endif
|
||||
#include "util/RuntimeError.hxx"
|
||||
#include "system/Error.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define LOG_LEVEL_SECURE LogLevel::INFO
|
||||
@@ -51,16 +45,16 @@ static constexpr Domain log_domain("log");
|
||||
|
||||
#ifndef ANDROID
|
||||
|
||||
static int out_fd;
|
||||
static int out_fd = -1;
|
||||
static AllocatedPath out_path = AllocatedPath::Null();
|
||||
|
||||
static void redirect_logs(int fd)
|
||||
{
|
||||
assert(fd >= 0);
|
||||
if (dup2(fd, STDOUT_FILENO) < 0)
|
||||
FatalSystemError("Failed to dup2 stdout");
|
||||
throw MakeErrno("Failed to dup2 stdout");
|
||||
if (dup2(fd, STDERR_FILENO) < 0)
|
||||
FatalSystemError("Failed to dup2 stderr");
|
||||
throw MakeErrno("Failed to dup2 stderr");
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -71,25 +65,30 @@ open_log_file(void)
|
||||
return OpenFile(out_path, O_CREAT | O_WRONLY | O_APPEND, 0666);
|
||||
}
|
||||
|
||||
static bool
|
||||
log_init_file(unsigned line, Error &error)
|
||||
static void
|
||||
log_init_file(int line)
|
||||
{
|
||||
assert(!out_path.IsNull());
|
||||
|
||||
out_fd = open_log_file();
|
||||
if (out_fd < 0) {
|
||||
#ifdef WIN32
|
||||
const std::string out_path_utf8 = out_path.ToUTF8();
|
||||
error.FormatErrno("failed to open log file \"%s\" (config line %u)",
|
||||
throw FormatRuntimeError("failed to open log file \"%s\" (config line %d)",
|
||||
out_path_utf8.c_str(), line);
|
||||
#else
|
||||
int e = errno;
|
||||
const std::string out_path_utf8 = out_path.ToUTF8();
|
||||
throw FormatErrno(e, "failed to open log file \"%s\" (config line %d)",
|
||||
out_path_utf8.c_str(), line);
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
EnableLogTimestamp();
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline LogLevel
|
||||
parse_log_level(const char *value, unsigned line)
|
||||
parse_log_level(const char *value, int line)
|
||||
{
|
||||
if (0 == strcmp(value, "default"))
|
||||
return LogLevel::DEFAULT;
|
||||
@@ -97,10 +96,9 @@ parse_log_level(const char *value, unsigned line)
|
||||
return LOG_LEVEL_SECURE;
|
||||
else if (0 == strcmp(value, "verbose"))
|
||||
return LogLevel::DEBUG;
|
||||
else {
|
||||
FormatFatalError("unknown log level \"%s\" at line %u",
|
||||
value, line);
|
||||
}
|
||||
else
|
||||
throw FormatRuntimeError("unknown log level \"%s\" at line %d",
|
||||
value, line);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -111,59 +109,44 @@ log_early_init(bool verbose)
|
||||
#ifdef ANDROID
|
||||
(void)verbose;
|
||||
#else
|
||||
/* force stderr to be line-buffered */
|
||||
setvbuf(stderr, nullptr, _IOLBF, 0);
|
||||
|
||||
if (verbose)
|
||||
SetLogThreshold(LogLevel::DEBUG);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
log_init(bool verbose, bool use_stdout, Error &error)
|
||||
void
|
||||
log_init(bool verbose, bool use_stdout)
|
||||
{
|
||||
#ifdef ANDROID
|
||||
(void)verbose;
|
||||
(void)use_stdout;
|
||||
(void)error;
|
||||
|
||||
return true;
|
||||
#else
|
||||
const struct config_param *param;
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
const char *charset;
|
||||
g_get_charset(&charset);
|
||||
SetLogCharset(charset);
|
||||
#endif
|
||||
|
||||
if (verbose)
|
||||
SetLogThreshold(LogLevel::DEBUG);
|
||||
else if ((param = config_get_param(CONF_LOG_LEVEL)) != nullptr)
|
||||
else if (const auto ¶m = config_get_param(ConfigOption::LOG_LEVEL))
|
||||
SetLogThreshold(parse_log_level(param->value.c_str(),
|
||||
param->line));
|
||||
|
||||
if (use_stdout) {
|
||||
return true;
|
||||
out_fd = STDOUT_FILENO;
|
||||
} else {
|
||||
param = config_get_param(CONF_LOG_FILE);
|
||||
const auto *param = config_get_param(ConfigOption::LOG_FILE);
|
||||
if (param == nullptr) {
|
||||
#ifdef HAVE_SYSLOG
|
||||
/* no configuration: default to syslog (if
|
||||
available) */
|
||||
LogInitSysLog();
|
||||
return true;
|
||||
#else
|
||||
error.Set(log_domain,
|
||||
"config parameter 'log_file' not found");
|
||||
return false;
|
||||
#ifndef HAVE_SYSLOG
|
||||
throw std::runtime_error("config parameter 'log_file' not found");
|
||||
#endif
|
||||
#ifdef HAVE_SYSLOG
|
||||
} else if (strcmp(param->value.c_str(), "syslog") == 0) {
|
||||
LogInitSysLog();
|
||||
return true;
|
||||
#endif
|
||||
} else {
|
||||
out_path = config_get_path(CONF_LOG_FILE, error);
|
||||
return !out_path.IsNull() &&
|
||||
log_init_file(param->line, error);
|
||||
out_path = param->GetPath();
|
||||
log_init_file(param->line);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -190,12 +173,10 @@ log_deinit(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
void setup_log_output(bool use_stdout)
|
||||
void setup_log_output()
|
||||
{
|
||||
#ifdef ANDROID
|
||||
(void)use_stdout;
|
||||
#else
|
||||
if (use_stdout)
|
||||
#ifndef ANDROID
|
||||
if (out_fd == STDOUT_FILENO)
|
||||
return;
|
||||
|
||||
fflush(nullptr);
|
||||
@@ -213,10 +194,6 @@ void setup_log_output(bool use_stdout)
|
||||
redirect_logs(out_fd);
|
||||
close(out_fd);
|
||||
out_fd = -1;
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
SetLogCharset(nullptr);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,8 +20,6 @@
|
||||
#ifndef MPD_LOG_INIT_HXX
|
||||
#define MPD_LOG_INIT_HXX
|
||||
|
||||
class Error;
|
||||
|
||||
/**
|
||||
* Configure a logging destination for daemon startup, before the
|
||||
* configuration file is read. This allows the daemon to use the
|
||||
@@ -33,14 +31,19 @@ class Error;
|
||||
void
|
||||
log_early_init(bool verbose);
|
||||
|
||||
bool
|
||||
log_init(bool verbose, bool use_stdout, Error &error);
|
||||
/**
|
||||
* Throws #std::runtime_error on error.
|
||||
*/
|
||||
void
|
||||
log_init(bool verbose, bool use_stdout);
|
||||
|
||||
void
|
||||
log_deinit(void);
|
||||
log_deinit();
|
||||
|
||||
void setup_log_output(bool use_stdout);
|
||||
void
|
||||
setup_log_output();
|
||||
|
||||
int cycle_log_files(void);
|
||||
int
|
||||
cycle_log_files();
|
||||
|
||||
#endif /* LOG_H */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
389
src/Main.cxx
389
src/Main.cxx
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -22,10 +22,9 @@
|
||||
#include "Instance.hxx"
|
||||
#include "CommandLine.hxx"
|
||||
#include "PlaylistFile.hxx"
|
||||
#include "PlaylistGlobal.hxx"
|
||||
#include "MusicChunk.hxx"
|
||||
#include "StateFile.hxx"
|
||||
#include "PlayerThread.hxx"
|
||||
#include "player/Thread.hxx"
|
||||
#include "Mapper.hxx"
|
||||
#include "Permission.hxx"
|
||||
#include "Listen.hxx"
|
||||
@@ -34,11 +33,10 @@
|
||||
#include "command/AllCommands.hxx"
|
||||
#include "Partition.hxx"
|
||||
#include "tag/TagConfig.hxx"
|
||||
#include "ReplayGainConfig.hxx"
|
||||
#include "ReplayGainGlobal.hxx"
|
||||
#include "Idle.hxx"
|
||||
#include "Log.hxx"
|
||||
#include "LogInit.hxx"
|
||||
#include "GlobalEvents.hxx"
|
||||
#include "input/Init.hxx"
|
||||
#include "event/Loop.hxx"
|
||||
#include "IOThread.hxx"
|
||||
@@ -47,23 +45,22 @@
|
||||
#include "playlist/PlaylistRegistry.hxx"
|
||||
#include "zeroconf/ZeroconfGlue.hxx"
|
||||
#include "decoder/DecoderList.hxx"
|
||||
#include "AudioConfig.hxx"
|
||||
#include "AudioParser.hxx"
|
||||
#include "pcm/PcmConvert.hxx"
|
||||
#include "unix/SignalHandlers.hxx"
|
||||
#include "unix/Daemon.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
#include "util/UriUtil.hxx"
|
||||
#include "util/Error.hxx"
|
||||
#include "util/Domain.hxx"
|
||||
#include "thread/Id.hxx"
|
||||
#include "thread/Slack.hxx"
|
||||
#include "lib/icu/Init.hxx"
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "config/ConfigData.hxx"
|
||||
#include "config/Param.hxx"
|
||||
#include "config/ConfigDefaults.hxx"
|
||||
#include "config/ConfigOption.hxx"
|
||||
#include "config/ConfigError.hxx"
|
||||
#include "Stats.hxx"
|
||||
#include "util/RuntimeError.hxx"
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
#include "unix/Daemon.hxx"
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "db/update/Service.hxx"
|
||||
@@ -99,8 +96,8 @@
|
||||
#include "org_musicpd_Bridge.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
#include <glib.h>
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
#include <systemd/sd-daemon.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
@@ -123,63 +120,56 @@
|
||||
static constexpr unsigned DEFAULT_BUFFER_SIZE = 4096;
|
||||
static constexpr unsigned DEFAULT_BUFFER_BEFORE_PLAY = 10;
|
||||
|
||||
static constexpr Domain main_domain("main");
|
||||
|
||||
#ifdef ANDROID
|
||||
Context *context;
|
||||
#endif
|
||||
|
||||
Instance *instance;
|
||||
|
||||
static StateFile *state_file;
|
||||
struct Config {
|
||||
ReplayGainConfig replay_gain;
|
||||
};
|
||||
|
||||
#ifndef ANDROID
|
||||
|
||||
static bool
|
||||
glue_daemonize_init(const struct options *options, Error &error)
|
||||
gcc_const
|
||||
static Config
|
||||
LoadConfig()
|
||||
{
|
||||
auto pid_file = config_get_path(CONF_PID_FILE, error);
|
||||
if (pid_file.IsNull() && error.IsDefined())
|
||||
return false;
|
||||
return {LoadReplayGainConfig()};
|
||||
}
|
||||
|
||||
daemonize_init(config_get_string(CONF_USER, nullptr),
|
||||
config_get_string(CONF_GROUP, nullptr),
|
||||
std::move(pid_file));
|
||||
#ifdef ENABLE_DAEMON
|
||||
|
||||
static void
|
||||
glue_daemonize_init(const struct options *options)
|
||||
{
|
||||
daemonize_init(config_get_string(ConfigOption::USER, nullptr),
|
||||
config_get_string(ConfigOption::GROUP, nullptr),
|
||||
config_get_path(ConfigOption::PID_FILE));
|
||||
|
||||
if (options->kill)
|
||||
daemonize_kill();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static bool
|
||||
glue_mapper_init(Error &error)
|
||||
static void
|
||||
glue_mapper_init()
|
||||
{
|
||||
auto playlist_dir = config_get_path(CONF_PLAYLIST_DIR, error);
|
||||
if (playlist_dir.IsNull() && error.IsDefined())
|
||||
return false;
|
||||
|
||||
mapper_init(std::move(playlist_dir));
|
||||
return true;
|
||||
mapper_init(config_get_path(ConfigOption::PLAYLIST_DIR));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
static bool
|
||||
InitStorage(Error &error)
|
||||
static void
|
||||
InitStorage()
|
||||
{
|
||||
Storage *storage = CreateConfiguredStorage(io_thread_get(), error);
|
||||
Storage *storage = CreateConfiguredStorage(io_thread_get());
|
||||
if (storage == nullptr)
|
||||
return !error.IsDefined();
|
||||
|
||||
assert(!error.IsDefined());
|
||||
return;
|
||||
|
||||
CompositeStorage *composite = new CompositeStorage();
|
||||
instance->storage = composite;
|
||||
composite->Mount("", storage);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -190,20 +180,13 @@ InitStorage(Error &error)
|
||||
static bool
|
||||
glue_db_init_and_load(void)
|
||||
{
|
||||
Error error;
|
||||
instance->database =
|
||||
CreateConfiguredDatabase(*instance->event_loop, *instance,
|
||||
error);
|
||||
if (instance->database == nullptr) {
|
||||
if (error.IsDefined())
|
||||
FatalError(error);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
CreateConfiguredDatabase(instance->event_loop, *instance);
|
||||
if (instance->database == nullptr)
|
||||
return true;
|
||||
|
||||
if (instance->database->GetPlugin().flags & DatabasePlugin::FLAG_REQUIRE_STORAGE) {
|
||||
if (!InitStorage(error))
|
||||
FatalError(error);
|
||||
InitStorage();
|
||||
|
||||
if (instance->storage == nullptr) {
|
||||
delete instance->database;
|
||||
@@ -220,14 +203,13 @@ glue_db_init_and_load(void)
|
||||
"because the database does not need it");
|
||||
}
|
||||
|
||||
if (!instance->database->Open(error))
|
||||
FatalError(error);
|
||||
instance->database->Open();
|
||||
|
||||
if (!instance->database->IsPlugin(simple_db_plugin))
|
||||
return true;
|
||||
|
||||
SimpleDatabase &db = *(SimpleDatabase *)instance->database;
|
||||
instance->update = new UpdateService(*instance->event_loop, db,
|
||||
instance->update = new UpdateService(instance->event_loop, db,
|
||||
static_cast<CompositeStorage &>(*instance->storage),
|
||||
*instance);
|
||||
|
||||
@@ -248,49 +230,41 @@ InitDatabaseAndStorage()
|
||||
* Configure and initialize the sticker subsystem.
|
||||
*/
|
||||
static void
|
||||
glue_sticker_init(void)
|
||||
glue_sticker_init()
|
||||
{
|
||||
#ifdef ENABLE_SQLITE
|
||||
Error error;
|
||||
auto sticker_file = config_get_path(CONF_STICKER_FILE, error);
|
||||
if (sticker_file.IsNull()) {
|
||||
if (error.IsDefined())
|
||||
FatalError(error);
|
||||
auto sticker_file = config_get_path(ConfigOption::STICKER_FILE);
|
||||
if (sticker_file.IsNull())
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sticker_global_init(std::move(sticker_file), error))
|
||||
FatalError(error);
|
||||
sticker_global_init(std::move(sticker_file));
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
glue_state_file_init(Error &error)
|
||||
static void
|
||||
glue_state_file_init()
|
||||
{
|
||||
auto path_fs = config_get_path(CONF_STATE_FILE, error);
|
||||
auto path_fs = config_get_path(ConfigOption::STATE_FILE);
|
||||
if (path_fs.IsNull()) {
|
||||
if (error.IsDefined())
|
||||
return false;
|
||||
|
||||
#ifdef ANDROID
|
||||
const auto cache_dir = GetUserCacheDir();
|
||||
if (cache_dir.IsNull())
|
||||
return true;
|
||||
return;
|
||||
|
||||
path_fs = AllocatedPath::Build(cache_dir, "state");
|
||||
#else
|
||||
return true;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned interval = config_get_unsigned(CONF_STATE_FILE_INTERVAL,
|
||||
StateFile::DEFAULT_INTERVAL);
|
||||
const auto interval =
|
||||
config_get_unsigned(ConfigOption::STATE_FILE_INTERVAL,
|
||||
StateFile::DEFAULT_INTERVAL);
|
||||
|
||||
state_file = new StateFile(std::move(path_fs), interval,
|
||||
*instance->partition,
|
||||
*instance->event_loop);
|
||||
state_file->Read();
|
||||
return true;
|
||||
instance->state_file = new StateFile(std::move(path_fs), interval,
|
||||
*instance->partition,
|
||||
instance->event_loop);
|
||||
instance->state_file->Read();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,12 +290,12 @@ static void winsock_init(void)
|
||||
* Initialize the decoder and player core, including the music pipe.
|
||||
*/
|
||||
static void
|
||||
initialize_decoder_and_player(void)
|
||||
initialize_decoder_and_player(const ReplayGainConfig &replay_gain_config)
|
||||
{
|
||||
const struct config_param *param;
|
||||
const ConfigParam *param;
|
||||
|
||||
size_t buffer_size;
|
||||
param = config_get_param(CONF_AUDIO_BUFFER_SIZE);
|
||||
param = config_get_param(ConfigOption::AUDIO_BUFFER_SIZE);
|
||||
if (param != nullptr) {
|
||||
char *test;
|
||||
long tmp = strtol(param->value.c_str(), &test, 10);
|
||||
@@ -342,7 +316,7 @@ initialize_decoder_and_player(void)
|
||||
(unsigned long)buffer_size);
|
||||
|
||||
float perc;
|
||||
param = config_get_param(CONF_BUFFER_BEFORE_PLAY);
|
||||
param = config_get_param(ConfigOption::BUFFER_BEFORE_PLAY);
|
||||
if (param != nullptr) {
|
||||
char *test;
|
||||
perc = strtod(param->value.c_str(), &test);
|
||||
@@ -360,45 +334,51 @@ initialize_decoder_and_player(void)
|
||||
buffered_before_play = buffered_chunks;
|
||||
|
||||
const unsigned max_length =
|
||||
config_get_positive(CONF_MAX_PLAYLIST_LENGTH,
|
||||
config_get_positive(ConfigOption::MAX_PLAYLIST_LENGTH,
|
||||
DEFAULT_PLAYLIST_MAX_LENGTH);
|
||||
|
||||
AudioFormat configured_audio_format = AudioFormat::Undefined();
|
||||
param = config_get_param(ConfigOption::AUDIO_OUTPUT_FORMAT);
|
||||
if (param != nullptr) {
|
||||
try {
|
||||
configured_audio_format = ParseAudioFormat(param->value.c_str(),
|
||||
true);
|
||||
} catch (const std::runtime_error &) {
|
||||
std::throw_with_nested(FormatRuntimeError("error parsing line %i",
|
||||
param->line));
|
||||
}
|
||||
}
|
||||
|
||||
instance->partition = new Partition(*instance,
|
||||
max_length,
|
||||
buffered_chunks,
|
||||
buffered_before_play);
|
||||
buffered_before_play,
|
||||
configured_audio_format,
|
||||
replay_gain_config);
|
||||
|
||||
try {
|
||||
param = config_get_param(ConfigOption::REPLAYGAIN);
|
||||
if (param != nullptr)
|
||||
instance->partition->replay_gain_mode =
|
||||
FromString(param->value.c_str());
|
||||
} catch (...) {
|
||||
std::throw_with_nested(FormatRuntimeError("Failed to parse line %i",
|
||||
param->line));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for GlobalEvents::IDLE.
|
||||
*/
|
||||
static void
|
||||
idle_event_emitted(void)
|
||||
void
|
||||
Instance::OnIdle(unsigned flags)
|
||||
{
|
||||
/* send "idle" notifications to all subscribed
|
||||
clients */
|
||||
unsigned flags = idle_get();
|
||||
if (flags != 0)
|
||||
instance->client_list->IdleAdd(flags);
|
||||
client_list->IdleAdd(flags);
|
||||
|
||||
if (flags & (IDLE_PLAYLIST|IDLE_PLAYER|IDLE_MIXER|IDLE_OUTPUT) &&
|
||||
state_file != nullptr)
|
||||
state_file->CheckModified();
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
/**
|
||||
* Handler for GlobalEvents::SHUTDOWN.
|
||||
*/
|
||||
static void
|
||||
shutdown_event_emitted(void)
|
||||
{
|
||||
instance->event_loop->Break();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef ANDROID
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
@@ -412,38 +392,29 @@ int main(int argc, char *argv[])
|
||||
|
||||
#endif
|
||||
|
||||
static int mpd_main_after_fork(struct options);
|
||||
static int
|
||||
mpd_main_after_fork(const Config &config);
|
||||
|
||||
#ifdef ANDROID
|
||||
static inline
|
||||
#endif
|
||||
int mpd_main(int argc, char *argv[])
|
||||
{
|
||||
try {
|
||||
struct options options;
|
||||
Error error;
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
daemonize_close_stdin();
|
||||
#endif
|
||||
|
||||
#ifndef ANDROID
|
||||
daemonize_close_stdin();
|
||||
|
||||
#ifdef HAVE_LOCALE_H
|
||||
/* initialize locale */
|
||||
setlocale(LC_CTYPE,"");
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
g_set_application_name("Music Player Daemon");
|
||||
|
||||
#if !GLIB_CHECK_VERSION(2,32,0)
|
||||
/* enable GLib's thread safety code */
|
||||
g_thread_init(nullptr);
|
||||
#endif
|
||||
setlocale(LC_COLLATE, "");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if (!IcuInit(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
IcuInit();
|
||||
|
||||
winsock_init();
|
||||
io_thread_init();
|
||||
@@ -453,47 +424,32 @@ int mpd_main(int argc, char *argv[])
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
||||
{
|
||||
const auto sdcard = Environment::getExternalStorageDirectory();
|
||||
if (!sdcard.IsNull()) {
|
||||
const auto config_path =
|
||||
AllocatedPath::Build(sdcard, "mpd.conf");
|
||||
if (FileExists(config_path) &&
|
||||
!ReadConfigFile(config_path, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
const auto sdcard = Environment::getExternalStorageDirectory();
|
||||
if (!sdcard.IsNull()) {
|
||||
const auto config_path =
|
||||
AllocatedPath::Build(sdcard, "mpd.conf");
|
||||
if (FileExists(config_path))
|
||||
ReadConfigFile(config_path);
|
||||
}
|
||||
#else
|
||||
if (!parse_cmdline(argc, argv, &options, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (!glue_daemonize_init(&options, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
ParseCommandLine(argc, argv, &options);
|
||||
#endif
|
||||
|
||||
const auto config = LoadConfig();
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
glue_daemonize_init(&options);
|
||||
#endif
|
||||
|
||||
stats_global_init();
|
||||
TagLoadConfig();
|
||||
|
||||
if (!log_init(options.verbose, options.log_stderr, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
log_init(options.verbose, options.log_stderr);
|
||||
|
||||
instance = new Instance();
|
||||
instance->event_loop = new EventLoop();
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
instance->neighbors = new NeighborGlue();
|
||||
if (!instance->neighbors->Init(io_thread_get(), *instance, error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
instance->neighbors->Init(io_thread_get(), *instance);
|
||||
|
||||
if (instance->neighbors->IsEmpty()) {
|
||||
delete instance->neighbors;
|
||||
@@ -501,18 +457,15 @@ int mpd_main(int argc, char *argv[])
|
||||
}
|
||||
#endif
|
||||
|
||||
const unsigned max_clients = config_get_positive(CONF_MAX_CONN, 10);
|
||||
const unsigned max_clients =
|
||||
config_get_positive(ConfigOption::MAX_CONN, 10);
|
||||
instance->client_list = new ClientList(max_clients);
|
||||
|
||||
initialize_decoder_and_player();
|
||||
initialize_decoder_and_player(config.replay_gain);
|
||||
|
||||
if (!listen_global_init(*instance->event_loop, *instance->partition,
|
||||
error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
listen_global_init(instance->event_loop, *instance->partition);
|
||||
|
||||
#ifndef ANDROID
|
||||
#ifdef ENABLE_DAEMON
|
||||
daemonize_set_user();
|
||||
daemonize_begin(options.daemon);
|
||||
#endif
|
||||
@@ -525,43 +478,32 @@ int mpd_main(int argc, char *argv[])
|
||||
This must be run after forking; if dispatch is called before forking,
|
||||
the child process will have a broken internal dispatch state. */
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
exit(mpd_main_after_fork(options));
|
||||
exit(mpd_main_after_fork(config));
|
||||
});
|
||||
dispatch_main();
|
||||
return EXIT_FAILURE; // unreachable, because dispatch_main never returns
|
||||
#else
|
||||
return mpd_main_after_fork(options);
|
||||
return mpd_main_after_fork(config);
|
||||
#endif
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static int mpd_main_after_fork(struct options options)
|
||||
{
|
||||
Error error;
|
||||
|
||||
GlobalEvents::Initialize(*instance->event_loop);
|
||||
GlobalEvents::Register(GlobalEvents::IDLE, idle_event_emitted);
|
||||
#ifdef WIN32
|
||||
GlobalEvents::Register(GlobalEvents::SHUTDOWN, shutdown_event_emitted);
|
||||
#endif
|
||||
|
||||
static int
|
||||
mpd_main_after_fork(const Config &config)
|
||||
try {
|
||||
ConfigureFS();
|
||||
|
||||
if (!glue_mapper_init(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
glue_mapper_init();
|
||||
|
||||
initPermissions();
|
||||
playlist_global_init();
|
||||
spl_global_init();
|
||||
#ifdef ENABLE_ARCHIVE
|
||||
archive_plugin_init_all();
|
||||
#endif
|
||||
|
||||
if (!pcm_convert_global_init(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pcm_convert_global_init();
|
||||
|
||||
decoder_plugin_init_all();
|
||||
|
||||
@@ -572,36 +514,34 @@ static int mpd_main_after_fork(struct options options)
|
||||
glue_sticker_init();
|
||||
|
||||
command_init();
|
||||
initAudioConfig();
|
||||
instance->partition->outputs.Configure(*instance->event_loop,
|
||||
|
||||
instance->partition->outputs.Configure(instance->event_loop,
|
||||
config.replay_gain,
|
||||
instance->partition->pc);
|
||||
instance->partition->UpdateEffectiveReplayGainMode();
|
||||
|
||||
client_manager_init();
|
||||
replay_gain_global_init();
|
||||
|
||||
if (!input_stream_global_init(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
input_stream_global_init();
|
||||
playlist_list_global_init();
|
||||
|
||||
#ifndef ANDROID
|
||||
#ifdef ENABLE_DAEMON
|
||||
daemonize_commit();
|
||||
#endif
|
||||
|
||||
setup_log_output(options.log_stderr);
|
||||
#ifndef ANDROID
|
||||
setup_log_output();
|
||||
|
||||
SignalHandlersInit(*instance->event_loop);
|
||||
SignalHandlersInit(instance->event_loop);
|
||||
#endif
|
||||
|
||||
io_thread_start();
|
||||
|
||||
#ifdef ENABLE_NEIGHBOR_PLUGINS
|
||||
if (instance->neighbors != nullptr &&
|
||||
!instance->neighbors->Open(error))
|
||||
FatalError(error);
|
||||
if (instance->neighbors != nullptr)
|
||||
instance->neighbors->Open();
|
||||
#endif
|
||||
|
||||
ZeroconfInit(*instance->event_loop);
|
||||
ZeroconfInit(instance->event_loop);
|
||||
|
||||
StartPlayerThread(instance->partition->pc);
|
||||
|
||||
@@ -615,25 +555,20 @@ static int mpd_main_after_fork(struct options options)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!glue_state_file_init(error)) {
|
||||
LogError(error);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
instance->partition->outputs.SetReplayGainMode(replay_gain_get_real_mode(instance->partition->playlist.queue.random));
|
||||
glue_state_file_init();
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
if (config_get_bool(CONF_AUTO_UPDATE, false)) {
|
||||
if (config_get_bool(ConfigOption::AUTO_UPDATE, false)) {
|
||||
#ifdef ENABLE_INOTIFY
|
||||
if (instance->storage != nullptr &&
|
||||
instance->update != nullptr)
|
||||
mpd_inotify_init(*instance->event_loop,
|
||||
mpd_inotify_init(instance->event_loop,
|
||||
*instance->storage,
|
||||
*instance->update,
|
||||
config_get_unsigned(CONF_AUTO_UPDATE_DEPTH,
|
||||
config_get_unsigned(ConfigOption::AUTO_UPDATE_DEPTH,
|
||||
INT_MAX));
|
||||
#else
|
||||
FormatWarning(main_domain,
|
||||
FormatWarning(config_domain,
|
||||
"inotify: auto_update was disabled. enable during compilation phase");
|
||||
#endif
|
||||
}
|
||||
@@ -643,7 +578,7 @@ static int mpd_main_after_fork(struct options options)
|
||||
|
||||
/* enable all audio outputs (if not already done by
|
||||
playlist_state_restore() */
|
||||
instance->partition->pc.UpdateAudio();
|
||||
instance->partition->pc.LockUpdateAudio();
|
||||
|
||||
#ifdef WIN32
|
||||
win32_app_started();
|
||||
@@ -653,8 +588,12 @@ static int mpd_main_after_fork(struct options options)
|
||||
a huge value to allow the kernel to reduce CPU wakeups */
|
||||
SetThreadTimerSlackMS(100);
|
||||
|
||||
#ifdef ENABLE_SYSTEMD_DAEMON
|
||||
sd_notify(0, "READY=1");
|
||||
#endif
|
||||
|
||||
/* run the main loop */
|
||||
instance->event_loop->Run();
|
||||
instance->event_loop.Run();
|
||||
|
||||
#ifdef WIN32
|
||||
win32_app_stopping();
|
||||
@@ -669,9 +608,9 @@ static int mpd_main_after_fork(struct options options)
|
||||
instance->update->CancelAllAsync();
|
||||
#endif
|
||||
|
||||
if (state_file != nullptr) {
|
||||
state_file->Write();
|
||||
delete state_file;
|
||||
if (instance->state_file != nullptr) {
|
||||
instance->state_file->Write();
|
||||
delete instance->state_file;
|
||||
}
|
||||
|
||||
instance->partition->pc.Kill();
|
||||
@@ -701,8 +640,6 @@ static int mpd_main_after_fork(struct options options)
|
||||
sticker_global_finish();
|
||||
#endif
|
||||
|
||||
GlobalEvents::Deinitialize();
|
||||
|
||||
playlist_list_global_finish();
|
||||
input_stream_global_finish();
|
||||
|
||||
@@ -710,6 +647,8 @@ static int mpd_main_after_fork(struct options options)
|
||||
mapper_finish();
|
||||
#endif
|
||||
|
||||
DeinitFS();
|
||||
|
||||
delete instance->partition;
|
||||
command_finish();
|
||||
decoder_plugin_deinit_all();
|
||||
@@ -721,12 +660,13 @@ static int mpd_main_after_fork(struct options options)
|
||||
#ifndef ANDROID
|
||||
SignalHandlersFinish();
|
||||
#endif
|
||||
delete instance->event_loop;
|
||||
delete instance;
|
||||
instance = nullptr;
|
||||
#ifndef ANDROID
|
||||
|
||||
#ifdef ENABLE_DAEMON
|
||||
daemonize_finish();
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
@@ -735,6 +675,9 @@ static int mpd_main_after_fork(struct options options)
|
||||
|
||||
log_deinit();
|
||||
return EXIT_SUCCESS;
|
||||
} catch (const std::exception &e) {
|
||||
LogError(e);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
@@ -760,7 +703,7 @@ JNIEXPORT void JNICALL
|
||||
Java_org_musicpd_Bridge_shutdown(JNIEnv *, jclass)
|
||||
{
|
||||
if (instance != nullptr)
|
||||
instance->event_loop->Break();
|
||||
instance->Shutdown();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -61,7 +61,7 @@ win32_main(int argc, char *argv[]);
|
||||
* This function should be called just before entering main loop.
|
||||
*/
|
||||
void
|
||||
win32_app_started(void);
|
||||
win32_app_started();
|
||||
|
||||
/**
|
||||
* When running as a service reports to service control manager
|
||||
@@ -71,7 +71,7 @@ win32_app_started(void);
|
||||
* This function should be called just after leaving main loop.
|
||||
*/
|
||||
void
|
||||
win32_app_stopping(void);
|
||||
win32_app_stopping();
|
||||
|
||||
#endif
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -24,9 +24,8 @@
|
||||
#include "config.h"
|
||||
#include "Mapper.hxx"
|
||||
#include "fs/AllocatedPath.hxx"
|
||||
#include "fs/Traits.hxx"
|
||||
#include "fs/Charset.hxx"
|
||||
#include "fs/CheckFile.hxx"
|
||||
#include "util/StringCompare.hxx"
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
#include "storage/StorageInterface.hxx"
|
||||
@@ -59,7 +58,8 @@ mapper_init(AllocatedPath &&_playlist_dir)
|
||||
mapper_set_playlist_dir(std::move(_playlist_dir));
|
||||
}
|
||||
|
||||
void mapper_finish(void)
|
||||
void
|
||||
mapper_finish()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -86,9 +86,9 @@ map_uri_fs(const char *uri)
|
||||
}
|
||||
|
||||
std::string
|
||||
map_fs_to_utf8(const char *path_fs)
|
||||
map_fs_to_utf8(Path path_fs)
|
||||
{
|
||||
if (PathTraitsFS::IsSeparator(path_fs[0])) {
|
||||
if (path_fs.IsAbsolute()) {
|
||||
if (instance->storage == nullptr)
|
||||
return std::string();
|
||||
|
||||
@@ -96,18 +96,20 @@ map_fs_to_utf8(const char *path_fs)
|
||||
if (music_dir_fs.IsNull())
|
||||
return std::string();
|
||||
|
||||
path_fs = music_dir_fs.RelativeFS(path_fs);
|
||||
if (path_fs == nullptr || *path_fs == 0)
|
||||
auto relative = music_dir_fs.Relative(path_fs);
|
||||
if (relative == nullptr || StringIsEmpty(relative))
|
||||
return std::string();
|
||||
|
||||
path_fs = Path::FromFS(relative);
|
||||
}
|
||||
|
||||
return PathToUTF8(path_fs);
|
||||
return path_fs.ToUTF8();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const AllocatedPath &
|
||||
map_spl_path(void)
|
||||
map_spl_path()
|
||||
{
|
||||
return playlist_dir_fs;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -30,12 +30,14 @@
|
||||
|
||||
#define PLAYLIST_FILE_SUFFIX ".m3u"
|
||||
|
||||
class Path;
|
||||
class AllocatedPath;
|
||||
|
||||
void
|
||||
mapper_init(AllocatedPath &&playlist_dir);
|
||||
|
||||
void mapper_finish(void);
|
||||
void
|
||||
mapper_finish();
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
@@ -58,7 +60,7 @@ map_uri_fs(const char *uri);
|
||||
*/
|
||||
gcc_pure
|
||||
std::string
|
||||
map_fs_to_utf8(const char *path_fs);
|
||||
map_fs_to_utf8(Path path_fs);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -67,7 +69,7 @@ map_fs_to_utf8(const char *path_fs);
|
||||
*/
|
||||
gcc_const
|
||||
const AllocatedPath &
|
||||
map_spl_path(void);
|
||||
map_spl_path();
|
||||
|
||||
/**
|
||||
* Maps a playlist name (without the ".m3u" suffix) to a file system
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,20 +20,17 @@
|
||||
#include "config.h"
|
||||
#include "MusicBuffer.hxx"
|
||||
#include "MusicChunk.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
MusicBuffer::MusicBuffer(unsigned num_chunks)
|
||||
:buffer(num_chunks) {
|
||||
if (buffer.IsOOM())
|
||||
FatalError("Failed to allocate buffer");
|
||||
}
|
||||
|
||||
MusicChunk *
|
||||
MusicBuffer::Allocate()
|
||||
{
|
||||
const ScopeLock protect(mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
return buffer.Allocate();
|
||||
}
|
||||
|
||||
@@ -42,7 +39,7 @@ MusicBuffer::Return(MusicChunk *chunk)
|
||||
{
|
||||
assert(chunk != nullptr);
|
||||
|
||||
const ScopeLock protect(mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
|
||||
if (chunk->other != nullptr) {
|
||||
assert(chunk->other->other == nullptr);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -48,7 +48,7 @@ struct MusicChunk {
|
||||
* An optional chunk which should be mixed into this chunk.
|
||||
* This is used for cross-fading.
|
||||
*/
|
||||
MusicChunk *other;
|
||||
MusicChunk *other = nullptr;
|
||||
|
||||
/**
|
||||
* The current mix ratio for cross-fading: 1.0 means play 100%
|
||||
@@ -57,7 +57,7 @@ struct MusicChunk {
|
||||
float mix_ratio;
|
||||
|
||||
/** number of bytes stored in this chunk */
|
||||
uint16_t length;
|
||||
uint16_t length = 0;
|
||||
|
||||
/** current bit rate of the source file */
|
||||
uint16_t bit_rate;
|
||||
@@ -71,7 +71,7 @@ struct MusicChunk {
|
||||
* object is owned by this chunk, and must be freed when this
|
||||
* chunk is deinitialized.
|
||||
*/
|
||||
Tag *tag;
|
||||
Tag *tag = nullptr;
|
||||
|
||||
/**
|
||||
* Replay gain information associated with this chunk.
|
||||
@@ -84,7 +84,7 @@ struct MusicChunk {
|
||||
* changed since the last chunk. The magic value 0 indicates
|
||||
* that there is no replay gain info available.
|
||||
*/
|
||||
unsigned replay_gain_serial;
|
||||
unsigned replay_gain_serial = 0;
|
||||
|
||||
/** the data (probably PCM) */
|
||||
uint8_t data[CHUNK_SIZE];
|
||||
@@ -93,14 +93,14 @@ struct MusicChunk {
|
||||
AudioFormat audio_format;
|
||||
#endif
|
||||
|
||||
MusicChunk()
|
||||
:other(nullptr),
|
||||
length(0),
|
||||
tag(nullptr),
|
||||
replay_gain_serial(0) {}
|
||||
MusicChunk() = default;
|
||||
|
||||
MusicChunk(const MusicChunk &) = delete;
|
||||
|
||||
~MusicChunk();
|
||||
|
||||
MusicChunk &operator=(const MusicChunk &) = delete;
|
||||
|
||||
bool IsEmpty() const {
|
||||
return length == 0 && tag == nullptr;
|
||||
}
|
||||
@@ -119,13 +119,10 @@ struct MusicChunk {
|
||||
* where you may write into. After you are finished, call
|
||||
* Expand().
|
||||
*
|
||||
* @param chunk the MusicChunk object
|
||||
* @param audio_format the audio format for the appended data;
|
||||
* @param af the audio format for the appended data;
|
||||
* must stay the same for the life cycle of this chunk
|
||||
* @param data_time the time within the song
|
||||
* @param bit_rate the current bit rate of the source file
|
||||
* @param max_length_r the maximum write length is returned
|
||||
* here
|
||||
* @return a writable buffer, or nullptr if the chunk is full
|
||||
*/
|
||||
WritableBuffer<void> Write(AudioFormat af,
|
||||
@@ -136,8 +133,7 @@ struct MusicChunk {
|
||||
* Increases the length of the chunk after the caller has written to
|
||||
* the buffer returned by Write().
|
||||
*
|
||||
* @param chunk the MusicChunk object
|
||||
* @param audio_format the audio format for the appended data; must
|
||||
* @param af the audio format for the appended data; must
|
||||
* stay the same for the life cycle of this chunk
|
||||
* @param length the number of bytes which were appended
|
||||
* @return true if the chunk is full
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -27,7 +27,7 @@
|
||||
bool
|
||||
MusicPipe::Contains(const MusicChunk *chunk) const
|
||||
{
|
||||
const ScopeLock protect(mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
|
||||
for (const MusicChunk *i = head; i != nullptr; i = i->next)
|
||||
if (i == chunk)
|
||||
@@ -41,7 +41,7 @@ MusicPipe::Contains(const MusicChunk *chunk) const
|
||||
MusicChunk *
|
||||
MusicPipe::Shift()
|
||||
{
|
||||
const ScopeLock protect(mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
|
||||
MusicChunk *chunk = head;
|
||||
if (chunk != nullptr) {
|
||||
@@ -87,7 +87,7 @@ MusicPipe::Push(MusicChunk *chunk)
|
||||
assert(!chunk->IsEmpty());
|
||||
assert(chunk->length == 0 || chunk->audio_format.IsValid());
|
||||
|
||||
const ScopeLock protect(mutex);
|
||||
const std::lock_guard<Mutex> protect(mutex);
|
||||
|
||||
assert(size > 0 || !audio_format.IsDefined());
|
||||
assert(!audio_format.IsDefined() ||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -38,31 +38,28 @@ class MusicBuffer;
|
||||
*/
|
||||
class MusicPipe {
|
||||
/** the first chunk */
|
||||
MusicChunk *head;
|
||||
MusicChunk *head = nullptr;
|
||||
|
||||
/** a pointer to the tail of the chunk */
|
||||
MusicChunk **tail_r;
|
||||
MusicChunk **tail_r = &head;
|
||||
|
||||
/** the current number of chunks */
|
||||
unsigned size;
|
||||
unsigned size = 0;
|
||||
|
||||
/** a mutex which protects #head and #tail_r */
|
||||
mutable Mutex mutex;
|
||||
|
||||
#ifndef NDEBUG
|
||||
AudioFormat audio_format;
|
||||
AudioFormat audio_format = AudioFormat::Undefined();
|
||||
#endif
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates a new #MusicPipe object. It is empty.
|
||||
*/
|
||||
MusicPipe()
|
||||
:head(nullptr), tail_r(&head), size(0) {
|
||||
#ifndef NDEBUG
|
||||
audio_format.Clear();
|
||||
#endif
|
||||
}
|
||||
MusicPipe() = default;
|
||||
|
||||
MusicPipe(const MusicPipe &) = delete;
|
||||
|
||||
/**
|
||||
* Frees the object. It must be empty now.
|
||||
@@ -72,6 +69,8 @@ public:
|
||||
assert(tail_r == &head);
|
||||
}
|
||||
|
||||
MusicPipe &operator=(const MusicPipe &) = delete;
|
||||
|
||||
#ifndef NDEBUG
|
||||
/**
|
||||
* Checks if the audio format if the chunk is equal to the specified
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,18 +19,66 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "Partition.hxx"
|
||||
#include "Instance.hxx"
|
||||
#include "DetachedSong.hxx"
|
||||
#include "output/MultipleOutputs.hxx"
|
||||
#include "mixer/Volume.hxx"
|
||||
#include "Idle.hxx"
|
||||
#include "GlobalEvents.hxx"
|
||||
#include "IdleFlags.hxx"
|
||||
|
||||
Partition::Partition(Instance &_instance,
|
||||
unsigned max_length,
|
||||
unsigned buffer_chunks,
|
||||
unsigned buffered_before_play,
|
||||
AudioFormat configured_audio_format,
|
||||
const ReplayGainConfig &replay_gain_config)
|
||||
:instance(_instance),
|
||||
global_events(instance.event_loop, BIND_THIS_METHOD(OnGlobalEvent)),
|
||||
playlist(max_length, *this),
|
||||
outputs(*this),
|
||||
pc(*this, outputs, buffer_chunks, buffered_before_play,
|
||||
configured_audio_format, replay_gain_config)
|
||||
{
|
||||
UpdateEffectiveReplayGainMode();
|
||||
}
|
||||
|
||||
void
|
||||
Partition::EmitIdle(unsigned mask)
|
||||
{
|
||||
instance.EmitIdle(mask);
|
||||
}
|
||||
|
||||
void
|
||||
Partition::UpdateEffectiveReplayGainMode()
|
||||
{
|
||||
auto mode = replay_gain_mode;
|
||||
if (mode == ReplayGainMode::AUTO)
|
||||
mode = playlist.queue.random
|
||||
? ReplayGainMode::TRACK
|
||||
: ReplayGainMode::ALBUM;
|
||||
|
||||
pc.LockSetReplayGainMode(mode);
|
||||
|
||||
outputs.SetReplayGainMode(mode);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
const Database *
|
||||
Partition::GetDatabase() const
|
||||
{
|
||||
return instance.GetDatabase();
|
||||
}
|
||||
|
||||
const Database &
|
||||
Partition::GetDatabaseOrThrow() const
|
||||
{
|
||||
return instance.GetDatabaseOrThrow();
|
||||
}
|
||||
|
||||
void
|
||||
Partition::DatabaseModified(const Database &db)
|
||||
{
|
||||
playlist.DatabaseModified(db);
|
||||
EmitIdle(IDLE_DATABASE);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -51,16 +99,34 @@ Partition::SyncWithPlayer()
|
||||
playlist.SyncWithPlayer(pc);
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnQueueModified()
|
||||
{
|
||||
EmitIdle(IDLE_PLAYLIST);
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnQueueOptionsChanged()
|
||||
{
|
||||
EmitIdle(IDLE_OPTIONS);
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnQueueSongStarted()
|
||||
{
|
||||
EmitIdle(IDLE_PLAYER);
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnPlayerSync()
|
||||
{
|
||||
GlobalEvents::Emit(GlobalEvents::PLAYLIST);
|
||||
EmitGlobalEvent(SYNC_WITH_PLAYER);
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnPlayerTagModified()
|
||||
{
|
||||
GlobalEvents::Emit(GlobalEvents::TAG);
|
||||
EmitGlobalEvent(TAG_MODIFIED);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -69,5 +135,15 @@ Partition::OnMixerVolumeChanged(gcc_unused Mixer &mixer, gcc_unused int volume)
|
||||
InvalidateHardwareVolume();
|
||||
|
||||
/* notify clients */
|
||||
idle_add(IDLE_MIXER);
|
||||
EmitIdle(IDLE_MIXER);
|
||||
}
|
||||
|
||||
void
|
||||
Partition::OnGlobalEvent(unsigned mask)
|
||||
{
|
||||
if ((mask & TAG_MODIFIED) != 0)
|
||||
TagModified();
|
||||
|
||||
if ((mask & SYNC_WITH_PLAYER) != 0)
|
||||
SyncWithPlayer();
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -20,11 +20,14 @@
|
||||
#ifndef MPD_PARTITION_HXX
|
||||
#define MPD_PARTITION_HXX
|
||||
|
||||
#include "event/MaskMonitor.hxx"
|
||||
#include "queue/Playlist.hxx"
|
||||
#include "queue/Listener.hxx"
|
||||
#include "output/MultipleOutputs.hxx"
|
||||
#include "mixer/Listener.hxx"
|
||||
#include "PlayerControl.hxx"
|
||||
#include "PlayerListener.hxx"
|
||||
#include "player/Control.hxx"
|
||||
#include "player/Listener.hxx"
|
||||
#include "ReplayGainMode.hxx"
|
||||
#include "Chrono.hxx"
|
||||
#include "Compiler.h"
|
||||
|
||||
@@ -36,39 +39,50 @@ class SongLoader;
|
||||
* A partition of the Music Player Daemon. It is a separate unit with
|
||||
* a playlist, a player, outputs etc.
|
||||
*/
|
||||
struct Partition final : private PlayerListener, private MixerListener {
|
||||
struct Partition final : QueueListener, PlayerListener, MixerListener {
|
||||
static constexpr unsigned TAG_MODIFIED = 0x1;
|
||||
static constexpr unsigned SYNC_WITH_PLAYER = 0x2;
|
||||
|
||||
Instance &instance;
|
||||
|
||||
MaskMonitor global_events;
|
||||
|
||||
struct playlist playlist;
|
||||
|
||||
MultipleOutputs outputs;
|
||||
|
||||
PlayerControl pc;
|
||||
|
||||
ReplayGainMode replay_gain_mode = ReplayGainMode::OFF;
|
||||
|
||||
Partition(Instance &_instance,
|
||||
unsigned max_length,
|
||||
unsigned buffer_chunks,
|
||||
unsigned buffered_before_play)
|
||||
:instance(_instance), playlist(max_length),
|
||||
outputs(*this),
|
||||
pc(*this, outputs, buffer_chunks, buffered_before_play) {}
|
||||
unsigned buffered_before_play,
|
||||
AudioFormat configured_audio_format,
|
||||
const ReplayGainConfig &replay_gain_config);
|
||||
|
||||
void EmitGlobalEvent(unsigned mask) {
|
||||
global_events.OrMask(mask);
|
||||
}
|
||||
|
||||
void EmitIdle(unsigned mask);
|
||||
|
||||
void ClearQueue() {
|
||||
playlist.Clear(pc);
|
||||
}
|
||||
|
||||
unsigned AppendURI(const SongLoader &loader,
|
||||
const char *uri_utf8,
|
||||
Error &error) {
|
||||
return playlist.AppendURI(pc, loader, uri_utf8, error);
|
||||
const char *uri_utf8) {
|
||||
return playlist.AppendURI(pc, loader, uri_utf8);
|
||||
}
|
||||
|
||||
PlaylistResult DeletePosition(unsigned position) {
|
||||
return playlist.DeletePosition(pc, position);
|
||||
void DeletePosition(unsigned position) {
|
||||
playlist.DeletePosition(pc, position);
|
||||
}
|
||||
|
||||
PlaylistResult DeleteId(unsigned id) {
|
||||
return playlist.DeleteId(pc, id);
|
||||
void DeleteId(unsigned id) {
|
||||
playlist.DeleteId(pc, id);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,60 +91,53 @@ struct Partition final : private PlayerListener, private MixerListener {
|
||||
* @param start the position of the first song to delete
|
||||
* @param end the position after the last song to delete
|
||||
*/
|
||||
PlaylistResult DeleteRange(unsigned start, unsigned end) {
|
||||
return playlist.DeleteRange(pc, start, end);
|
||||
void DeleteRange(unsigned start, unsigned end) {
|
||||
playlist.DeleteRange(pc, start, end);
|
||||
}
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
|
||||
void DeleteSong(const char *uri) {
|
||||
playlist.DeleteSong(pc, uri);
|
||||
void StaleSong(const char *uri) {
|
||||
playlist.StaleSong(pc, uri);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void Shuffle(unsigned start, unsigned end) {
|
||||
playlist.Shuffle(pc, start, end);
|
||||
}
|
||||
|
||||
PlaylistResult MoveRange(unsigned start, unsigned end, int to) {
|
||||
return playlist.MoveRange(pc, start, end, to);
|
||||
void MoveRange(unsigned start, unsigned end, int to) {
|
||||
playlist.MoveRange(pc, start, end, to);
|
||||
}
|
||||
|
||||
PlaylistResult MoveId(unsigned id, int to) {
|
||||
return playlist.MoveId(pc, id, to);
|
||||
void MoveId(unsigned id, int to) {
|
||||
playlist.MoveId(pc, id, to);
|
||||
}
|
||||
|
||||
PlaylistResult SwapPositions(unsigned song1, unsigned song2) {
|
||||
return playlist.SwapPositions(pc, song1, song2);
|
||||
void SwapPositions(unsigned song1, unsigned song2) {
|
||||
playlist.SwapPositions(pc, song1, song2);
|
||||
}
|
||||
|
||||
PlaylistResult SwapIds(unsigned id1, unsigned id2) {
|
||||
return playlist.SwapIds(pc, id1, id2);
|
||||
void SwapIds(unsigned id1, unsigned id2) {
|
||||
playlist.SwapIds(pc, id1, id2);
|
||||
}
|
||||
|
||||
PlaylistResult SetPriorityRange(unsigned start_position,
|
||||
unsigned end_position,
|
||||
uint8_t priority) {
|
||||
return playlist.SetPriorityRange(pc,
|
||||
start_position, end_position,
|
||||
priority);
|
||||
void SetPriorityRange(unsigned start_position, unsigned end_position,
|
||||
uint8_t priority) {
|
||||
playlist.SetPriorityRange(pc, start_position, end_position,
|
||||
priority);
|
||||
}
|
||||
|
||||
PlaylistResult SetPriorityId(unsigned song_id,
|
||||
uint8_t priority) {
|
||||
return playlist.SetPriorityId(pc, song_id, priority);
|
||||
void SetPriorityId(unsigned song_id, uint8_t priority) {
|
||||
playlist.SetPriorityId(pc, song_id, priority);
|
||||
}
|
||||
|
||||
void Stop() {
|
||||
playlist.Stop(pc);
|
||||
}
|
||||
|
||||
PlaylistResult PlayPosition(int position) {
|
||||
void PlayPosition(int position) {
|
||||
return playlist.PlayPosition(pc, position);
|
||||
}
|
||||
|
||||
PlaylistResult PlayId(int id) {
|
||||
void PlayId(int id) {
|
||||
return playlist.PlayId(pc, id);
|
||||
}
|
||||
|
||||
@@ -142,17 +149,16 @@ struct Partition final : private PlayerListener, private MixerListener {
|
||||
return playlist.PlayPrevious(pc);
|
||||
}
|
||||
|
||||
PlaylistResult SeekSongPosition(unsigned song_position,
|
||||
SongTime seek_time) {
|
||||
return playlist.SeekSongPosition(pc, song_position, seek_time);
|
||||
void SeekSongPosition(unsigned song_position, SongTime seek_time) {
|
||||
playlist.SeekSongPosition(pc, song_position, seek_time);
|
||||
}
|
||||
|
||||
PlaylistResult SeekSongId(unsigned song_id, SongTime seek_time) {
|
||||
return playlist.SeekSongId(pc, song_id, seek_time);
|
||||
void SeekSongId(unsigned song_id, SongTime seek_time) {
|
||||
playlist.SeekSongId(pc, song_id, seek_time);
|
||||
}
|
||||
|
||||
PlaylistResult SeekCurrent(SignedSongTime seek_time, bool relative) {
|
||||
return playlist.SeekCurrent(pc, seek_time, relative);
|
||||
void SeekCurrent(SignedSongTime seek_time, bool relative) {
|
||||
playlist.SeekCurrent(pc, seek_time, relative);
|
||||
}
|
||||
|
||||
void SetRepeat(bool new_value) {
|
||||
@@ -175,7 +181,28 @@ struct Partition final : private PlayerListener, private MixerListener {
|
||||
playlist.SetConsume(new_value);
|
||||
}
|
||||
|
||||
void SetReplayGainMode(ReplayGainMode mode) {
|
||||
replay_gain_mode = mode;
|
||||
UpdateEffectiveReplayGainMode();
|
||||
}
|
||||
|
||||
/**
|
||||
* Publishes the effective #ReplayGainMode to all subsystems.
|
||||
* #ReplayGainMode::AUTO is substituted.
|
||||
*/
|
||||
void UpdateEffectiveReplayGainMode();
|
||||
|
||||
#ifdef ENABLE_DATABASE
|
||||
/**
|
||||
* Returns the global #Database instance. May return nullptr
|
||||
* if this MPD configuration has no database (no
|
||||
* music_directory was configured).
|
||||
*/
|
||||
const Database *GetDatabase() const;
|
||||
|
||||
gcc_pure
|
||||
const Database &GetDatabaseOrThrow() const;
|
||||
|
||||
/**
|
||||
* The database has been modified. Propagate the change to
|
||||
* all subsystems.
|
||||
@@ -195,12 +222,20 @@ struct Partition final : private PlayerListener, private MixerListener {
|
||||
void SyncWithPlayer();
|
||||
|
||||
private:
|
||||
/* virtual methods from class QueueListener */
|
||||
void OnQueueModified() override;
|
||||
void OnQueueOptionsChanged() override;
|
||||
void OnQueueSongStarted() override;
|
||||
|
||||
/* virtual methods from class PlayerListener */
|
||||
virtual void OnPlayerSync() override;
|
||||
virtual void OnPlayerTagModified() override;
|
||||
void OnPlayerSync() override;
|
||||
void OnPlayerTagModified() override;
|
||||
|
||||
/* virtual methods from class MixerListener */
|
||||
virtual void OnMixerVolumeChanged(Mixer &mixer, int volume) override;
|
||||
void OnMixerVolumeChanged(Mixer &mixer, int volume) override;
|
||||
|
||||
/* callback for #global_events */
|
||||
void OnGlobalEvent(unsigned mask);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include "Permission.hxx"
|
||||
#include "config/ConfigData.hxx"
|
||||
#include "config/Param.hxx"
|
||||
#include "config/ConfigGlobal.hxx"
|
||||
#include "config/ConfigOption.hxx"
|
||||
#include "system/FatalError.hxx"
|
||||
@@ -87,12 +87,12 @@ static unsigned parsePermissions(const char *string)
|
||||
void initPermissions(void)
|
||||
{
|
||||
unsigned permission;
|
||||
const struct config_param *param;
|
||||
const ConfigParam *param;
|
||||
|
||||
permission_default = PERMISSION_READ | PERMISSION_ADD |
|
||||
PERMISSION_CONTROL | PERMISSION_ADMIN;
|
||||
|
||||
param = config_get_param(CONF_PASSWORD);
|
||||
param = config_get_param(ConfigOption::PASSWORD);
|
||||
|
||||
if (param) {
|
||||
permission_default = 0;
|
||||
@@ -118,7 +118,7 @@ void initPermissions(void)
|
||||
} while ((param = param->next) != nullptr);
|
||||
}
|
||||
|
||||
param = config_get_param(CONF_DEFAULT_PERMS);
|
||||
param = config_get_param(ConfigOption::DEFAULT_PERMS);
|
||||
|
||||
if (param)
|
||||
permission_default = parsePermissions(param->value.c_str());
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2003-2014 The Music Player Daemon Project
|
||||
* Copyright 2003-2017 The Music Player Daemon Project
|
||||
* http://www.musicpd.org
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
@@ -28,8 +28,10 @@ static constexpr unsigned PERMISSION_ADMIN = 8;
|
||||
|
||||
int getPermissionFromPassword(char const* password, unsigned* permission);
|
||||
|
||||
unsigned getDefaultPermissions(void);
|
||||
unsigned
|
||||
getDefaultPermissions();
|
||||
|
||||
void initPermissions(void);
|
||||
void
|
||||
initPermissions();
|
||||
|
||||
#endif
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user