1use std::{borrow::Cow, fmt, ops::{Add, BitAnd, Shl}, path::Path, sync::LazyLock};
20
21use crate::{error::{SyRes, SyslogError}, map_error_code, portable, throw_error};
22
23#[cfg(target_family = "windows")]
24pub use self::common_eventlog_items::*;
25
26#[cfg(target_family = "unix")]
27pub use self::common_syslog_items::*;
28
29#[cfg(target_family = "windows")]
30pub mod common_eventlog_items
31{
32 use std::fmt;
33
34 use windows::Win32::System::EventLog::{EVENTLOG_ERROR_TYPE, EVENTLOG_INFORMATION_TYPE, EVENTLOG_SUCCESS, EVENTLOG_WARNING_TYPE, REPORT_EVENT_TYPE};
35
36
37 #[allow(nonstandard_style)]
38 #[repr(i32)]
39 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
40 pub enum Priority
41 {
42 LOG_EMERG = 0,
44
45 LOG_ALERT = 1,
47
48 LOG_CRIT = 2,
50
51 LOG_ERR = 3,
53
54 LOG_WARNING = 4,
56
57 LOG_NOTICE = 5,
59
60 LOG_INFO = 6,
62
63 LOG_DEBUG = 7,
65 }
66
67 impl fmt::Display for Priority
68 {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
70 {
71 match self
74 {
75 Self::LOG_EMERG =>
76 write!(f, "[EMERG]"),
77 Self::LOG_ALERT =>
78 write!(f, "[ALERT]"),
79 Self::LOG_CRIT =>
80 write!(f, "[CRIT]"),
81 Self::LOG_ERR =>
82 write!(f, "[ERR]"),
83 Self::LOG_WARNING =>
84 write!(f, "[WARNING]"),
85 Self::LOG_NOTICE =>
86 write!(f, "[NOTICE]"),
87 Self::LOG_INFO =>
88 write!(f, "[INFO]"),
89 Self::LOG_DEBUG =>
90 write!(f, "[DEBUG]"),
91 }
92 }
93 }
94
95 impl From<Priority> for REPORT_EVENT_TYPE
96 {
97 fn from(value: Priority) -> Self
98 {
99 match value
100 {
101 Priority::LOG_EMERG | Priority::LOG_ALERT | Priority::LOG_CRIT =>
102 return EVENTLOG_WARNING_TYPE,
103 Priority::LOG_ERR =>
104 return EVENTLOG_ERROR_TYPE,
105 Priority::LOG_WARNING | Priority::LOG_NOTICE =>
106 return EVENTLOG_INFORMATION_TYPE,
107 Priority::LOG_INFO | Priority::LOG_DEBUG =>
108 return EVENTLOG_SUCCESS
109 }
110 }
111 }
112
113 impl Priority
114 {
115 }
143
144
145
146 bitflags! {
147 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
149 pub struct LogStat: i32
150 {
151 const LOG_PID = 1;
153
154 const LOG_CONS = 2;
157
158 const LOG_ODELAY = 0;
162
163 const LOG_NDELAY = 0;
165
166 const LOG_NOWAIT = 0;
169
170 const LOG_PERROR = 0x20;
172 }
173 }
174
175 #[cfg(feature = "build_sync")]
176 impl LogStat
177 {
178 #[inline]
179 pub(crate)
180 fn send_to_stderr(&self, msg: &str)
181 {
182 if self.intersects(LogStat::LOG_PERROR) == true
183 {
184 eprintln!("{}", msg);
185 }
186 }
187
188 #[inline]
189 pub(crate)
190 fn send_to_syscons(&self, msg_payload: &str)
191 {
192 if self.intersects(LogStat::LOG_CONS)
193 {
194 eprintln!("{}", msg_payload);
195 }
196 }
197 }
198
199 bitflags! {
200 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
203 pub struct LogFacility: i32
204 {
205 const LOG_KERN = 0;
207
208 const LOG_USER = 8;
210
211 const LOG_MAIL = 16;
213
214 const LOG_DAEMON = 24;
216
217 const LOG_AUTH = 32;
219
220 const LOG_SYSLOG = 40;
222
223 const LOG_LPR = 48;
225
226 const LOG_NEWS = 56;
228
229 const LOG_UUCP = 64;
231
232 const LOG_LOCAL0 = 128;
234
235 const LOG_LOCAL1 = 136;
237
238 const LOG_LOCAL2 = 144;
240
241 const LOG_LOCAL3 = 152;
243
244 const LOG_LOCAL4 = 160;
246
247 const LOG_LOCAL5 = 168;
249
250 const LOG_LOCAL6 = 176;
252
253 const LOG_LOCAL7 = 184;
255 }
256 }
257
258 impl LogFacility
259 {
260 pub
261 fn into_win_facility(self) -> u32
262 {
263 return self.bits() as u32 >> 3;
264 }
265 }
266
267 #[cfg(test)]
268 mod tests
269 {
270 use windows::Win32::System::EventLog::{EVENTLOG_ERROR_TYPE, EVENTLOG_INFORMATION_TYPE, EVENTLOG_SUCCESS, EVENTLOG_WARNING_TYPE, REPORT_EVENT_TYPE};
271
272 use crate::Priority;
273
274 #[test]
275 fn test_conversion_prio_to_ret()
276 {
277 assert_eq!(REPORT_EVENT_TYPE::from(Priority::LOG_EMERG), EVENTLOG_WARNING_TYPE);
278 assert_eq!(REPORT_EVENT_TYPE::from(Priority::LOG_ALERT), EVENTLOG_WARNING_TYPE);
279 assert_eq!(REPORT_EVENT_TYPE::from(Priority::LOG_CRIT), EVENTLOG_WARNING_TYPE);
280 assert_eq!(REPORT_EVENT_TYPE::from(Priority::LOG_ERR), EVENTLOG_ERROR_TYPE);
281 assert_eq!(REPORT_EVENT_TYPE::from(Priority::LOG_WARNING), EVENTLOG_INFORMATION_TYPE);
282 assert_eq!(REPORT_EVENT_TYPE::from(Priority::LOG_NOTICE), EVENTLOG_INFORMATION_TYPE);
283 assert_eq!(REPORT_EVENT_TYPE::from(Priority::LOG_INFO), EVENTLOG_SUCCESS);
284 assert_eq!(REPORT_EVENT_TYPE::from(Priority::LOG_DEBUG), EVENTLOG_SUCCESS);
285 }
286 }
287}
288
289#[cfg(target_family = "unix")]
290pub mod common_syslog_items
291{
292 use nix::libc;
293
294 use std::{fmt, str::FromStr};
295
296
297 bitflags! {
298 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
300 pub struct LogStat: libc::c_int
301 {
302 const LOG_PID = libc::LOG_PID;
304
305 const LOG_CONS = libc::LOG_CONS;
308
309 const LOG_ODELAY = libc::LOG_ODELAY;
313
314 const LOG_NDELAY = libc::LOG_NDELAY;
316
317 const LOG_NOWAIT = libc::LOG_NOWAIT;
320
321 const LOG_PERROR = 0x20;
323 }
324 }
325
326 #[cfg(feature = "build_sync")]
327 impl LogStat
328 {
329 #[inline]
330 pub(crate)
331 fn send_to_stderr(&self, msg: &str)
332 {
333 if self.intersects(LogStat::LOG_PERROR) == true
334 {
335 let stderr_lock = std::io::stderr().lock();
336 let newline = "\n";
337
338 let _ = send_to_fd(stderr_lock, msg, &newline);
339 }
340 }
341
342 #[inline]
343 pub(crate)
344 fn send_to_syscons(&self, msg_payload: &str)
345 {
346 use std::fs::File;
347 use std::os::unix::fs::OpenOptionsExt;
348
349 if self.intersects(LogStat::LOG_CONS)
350 {
351 use crate::PATH_CONSOLE;
352
353 let syscons =
354 File
355 ::options()
356 .create(false)
357 .read(false)
358 .write(true)
359 .custom_flags(libc::O_NONBLOCK | libc::O_CLOEXEC)
360 .open(*PATH_CONSOLE);
361
362 if let Ok(file) = syscons
363 {
364 let newline = "\n";
365 let _ = send_to_fd(file, msg_payload, newline);
366 }
367 }
368 }
369 }
370
371 #[allow(nonstandard_style)]
372 #[repr(i32)]
373 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
374 pub enum Priority
375 {
376 LOG_EMERG = libc::LOG_EMERG,
378
379 LOG_ALERT = libc::LOG_ALERT,
381
382 LOG_CRIT = libc::LOG_CRIT,
384
385 LOG_ERR = libc::LOG_ERR,
387
388 LOG_WARNING = libc::LOG_WARNING,
390
391 LOG_NOTICE = libc::LOG_NOTICE,
393
394 LOG_INFO = libc::LOG_INFO,
396
397 LOG_DEBUG = libc::LOG_DEBUG,
399 }
400
401 impl fmt::Display for Priority
402 {
403 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
404 {
405 match self
408 {
409 Self::LOG_EMERG =>
410 write!(f, "EMERG"),
411 Self::LOG_ALERT =>
412 write!(f, "ALERT"),
413 Self::LOG_CRIT =>
414 write!(f, "CRIT"),
415 Self::LOG_ERR =>
416 write!(f, "ERR"),
417 Self::LOG_WARNING =>
418 write!(f, "WARNING"),
419 Self::LOG_NOTICE =>
420 write!(f, "NOTICE"),
421 Self::LOG_INFO =>
422 write!(f, "INFO"),
423 Self::LOG_DEBUG =>
424 write!(f, "DEBUG"),
425 }
426 }
427 }
428
429 impl FromStr for Priority
430 {
431 type Err = SyslogError;
432
433 fn from_str(s: &str) -> Result<Self, Self::Err>
434 {
435 let ss = s.trim().to_uppercase();
436
437 match ss.as_str()
438 {
439 "LOG_EMERG" => Ok(Self::LOG_EMERG),
440 "LOG_ALERT" => Ok(Self::LOG_ALERT),
441 "LOG_CRIT" => Ok(Self::LOG_CRIT),
442 "LOG_ERR" => Ok(Self::LOG_ERR),
443 "LOG_WARNING" => Ok(Self::LOG_WARNING),
444 "LOG_NOTICE" => Ok(Self::LOG_NOTICE),
445 "LOG_INFO" => Ok(Self::LOG_INFO),
446 "LOG_DEBUG" => Ok(Self::LOG_DEBUG),
447 n =>
448 throw_error!("unknown priority: {}", n)
449 }
450
451 }
452 }
453
454 impl Priority
455 {
456
457 }
458
459 bitflags! {
460 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
463 pub struct LogFacility: libc::c_int
464 {
465 const LOG_KERN = libc::LOG_KERN;
467
468 const LOG_USER = libc::LOG_USER;
470
471 const LOG_MAIL = libc::LOG_MAIL;
473
474 const LOG_DAEMON = libc::LOG_DAEMON;
476
477 const LOG_AUTH = libc::LOG_AUTH;
479
480 const LOG_SYSLOG = libc::LOG_SYSLOG;
482
483 const LOG_LPR = libc::LOG_LPR;
485
486 const LOG_NEWS = libc::LOG_NEWS;
488
489 const LOG_UUCP = libc::LOG_UUCP;
491
492 const LOG_LOCAL0 = libc::LOG_LOCAL0;
494
495 const LOG_LOCAL1 = libc::LOG_LOCAL1;
497
498 const LOG_LOCAL2 = libc::LOG_LOCAL2;
500
501 const LOG_LOCAL3 = libc::LOG_LOCAL3;
503
504 const LOG_LOCAL4 = libc::LOG_LOCAL4;
506
507 const LOG_LOCAL5 = libc::LOG_LOCAL5;
509
510 const LOG_LOCAL6 = libc::LOG_LOCAL6;
512
513 const LOG_LOCAL7 = libc::LOG_LOCAL7;
515 }
516 }
517
518
519 impl FromStr for LogFacility
520 {
521 type Err = SyslogError;
522
523 fn from_str(s: &str) -> Result<Self, Self::Err>
524 {
525 let s_up = s.to_ascii_uppercase();
526
527 match s_up.as_str()
528 {
529 "LOG_KERN" => Ok(Self::LOG_KERN),
530 "LOG_USER" => Ok(Self::LOG_USER),
531 "LOG_MAIL" => Ok(Self::LOG_MAIL),
532 "LOG_DAEMON" => Ok(Self::LOG_DAEMON),
533 "LOG_AUTH" => Ok(Self::LOG_AUTH),
534 "LOG_SYSLOG" => Ok(Self::LOG_SYSLOG),
535 "LOG_LPR" => Ok(Self::LOG_LPR),
536 "LOG_NEWS" => Ok(Self::LOG_NEWS),
537 "LOG_UUCP" => Ok(Self::LOG_UUCP),
538 "LOG_LOCAL0" => Ok(Self::LOG_LOCAL0),
539 "LOG_LOCAL1" => Ok(Self::LOG_LOCAL1),
540 "LOG_LOCAL2" => Ok(Self::LOG_LOCAL2),
541 "LOG_LOCAL3" => Ok(Self::LOG_LOCAL3),
542 "LOG_LOCAL4" => Ok(Self::LOG_LOCAL4),
543 "LOG_LOCAL5" => Ok(Self::LOG_LOCAL5),
544 "LOG_LOCAL6" => Ok(Self::LOG_LOCAL6),
545 "LOG_LOCAL7" => Ok(Self::LOG_LOCAL7),
546 n =>
547 throw_error!("unknwon log facility: {}", n)
548 }
549 }
550 }
551
552 impl fmt::Display for LogFacility
553 {
554 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
555 {
556 match *self
557 {
558 Self::LOG_KERN =>
559 write!(f, "LOG_KERN"),
560 Self::LOG_USER =>
561 write!(f, "LOG_USER"),
562 Self::LOG_MAIL =>
563 write!(f, "LOG_MAIL"),
564 Self::LOG_DAEMON =>
565 write!(f, "LOG_DAEMON"),
566 Self::LOG_AUTH =>
567 write!(f, "LOG_AUTH"),
568 Self::LOG_SYSLOG =>
569 write!(f, "LOG_SYSLOG"),
570 Self::LOG_LPR =>
571 write!(f, "LOG_LPR"),
572 Self::LOG_NEWS =>
573 write!(f, "LOG_NEWS"),
574 Self::LOG_UUCP =>
575 write!(f, "LOG_UUCP"),
576 Self::LOG_LOCAL0 =>
577 write!(f, "LOG_LOCAL0"),
578 Self::LOG_LOCAL1 =>
579 write!(f, "LOG_LOCAL1"),
580 Self::LOG_LOCAL2 =>
581 write!(f, "LOG_LOCAL2"),
582 Self::LOG_LOCAL3 =>
583 write!(f, "LOG_LOCAL3"),
584 Self::LOG_LOCAL4 =>
585 write!(f, "LOG_LOCAL4"),
586 Self::LOG_LOCAL5 =>
587 write!(f, "LOG_LOCAL5"),
588 Self::LOG_LOCAL6 =>
589 write!(f, "LOG_LOCAL6"),
590 Self::LOG_LOCAL7 =>
591 write!(f, "LOG_LOCAL7"),
592 n =>
593 write!(f, "LOG_[{}]", n),
594 }
595 }
596 }
597
598 pub const PATH_LOG: &'static str = "/var/run/log";
600
601 pub const PATH_LOG_PRIV: &'static str = "/var/run/logpriv";
603
604 pub const PATH_OLDLOG: &'static str = "/dev/log";
606
607 pub const PATH_OSX: &'static str = "/var/run/syslog";
609
610 #[cfg(feature = "build_sync")]
619 pub(crate) mod sync_portion
620 {
621 use std::io::Write;
622 use std::io::IoSlice;
623 use crate::error::SyRes;
624 use crate::map_error_os;
625
626 pub(crate)
637 fn send_to_fd<W>(mut file_fd: W, msg: &str, newline: &str) -> SyRes<usize>
638 where W: Write
639 {
640 return
641 file_fd
642 .write_vectored(
643 &[IoSlice::new(msg.as_bytes()), IoSlice::new(newline.as_bytes())]
644 )
645 .map_err(|e|
646 map_error_os!(e, "send_to_fd() writev() failed")
647 );
648 }
649 }
650
651 use crate::{error::SyslogError, throw_error};
652
653#[cfg(feature = "build_sync")]
654 pub(crate) use self::sync_portion::*;
655
656 #[cfg(test)]
657 mod tests
658 {
659 use super::*;
660
661 #[cfg(feature = "build_sync")]
662 #[test]
663 fn test_error_message()
664 {
665 let testmsg = "this is test message!";
671 let newline = "\n";
672 let stderr_lock = std::io::stderr().lock();
673 let res = send_to_fd(stderr_lock, testmsg, &newline);
674
675 println!("res: {:?}", res);
676
677 assert_eq!(res.is_ok(), true, "err: {}", res.err().unwrap());
678
679 return;
680 }
681
682 #[test]
683 fn test_priority_shl()
684 {
685 assert_eq!((1 << 5), (1 << Priority::LOG_NOTICE));
686 }
687 }
688}
689
690pub static PATH_CONSOLE: LazyLock<&Path> = LazyLock::new(||
692 {
693 Path::new("/dev/console")
694 }
695);
696
697pub static RFC5424_MAX_DGRAM: LazyLock<usize> = LazyLock::new(||
699 {
700 portable::get_local_dgram_maxdgram() as usize
701 }
702);
703
704
705pub const MAXHOSTNAMELEN: usize = 256;
707
708pub const LOG_FACMASK: i32 = 0x03f8;
710
711pub const MAXLINE: usize = 8192;
715
716pub const RFC3164_MAX_PAYLOAD_LEN: usize = 1024;
718
719pub const WINDOWS_EVENT_REPORT_MAX_PAYLOAD_LEN: usize = 31839;
721
722#[cfg(all(feature = "udp_truncate_1024_bytes", feature = "udp_truncate_1440_bytes"))]
723compile_error!("either 'udp_truncate_1024_bytes' or 'udp_truncate_1440_bytes' should be enabled");
724
725#[cfg(feature = "udp_truncate_1024_bytes")]
727pub const RFC5424_UDP_MAX_PKT_LEN: usize = 1024;
728
729#[cfg(any(feature = "udp_truncate_1440_bytes", all(not(feature = "udp_truncate_1440_bytes"), not(feature = "udp_truncate_1024_bytes"))))]
730pub const RFC5424_UDP_MAX_PKT_LEN: usize = 2048;
731
732#[cfg(feature = "tcp_truncate_1024_bytes")]
733pub const RFC5424_TCP_MAX_PKT_LEN: usize = 1024;
734
735#[cfg(feature = "tcp_truncate_2048_bytes")]
736pub const RFC5424_TCP_MAX_PKT_LEN: usize = 2048;
737
738#[cfg(feature = "tcp_truncate_4096_bytes")]
739pub const RFC5424_TCP_MAX_PKT_LEN: usize = 4096;
740
741#[cfg(feature = "tcp_truncate_max_bytes")]
742pub const RFC5424_TCP_MAX_PKT_LEN: usize = MAXLINE;
743
744pub const RFC_MAX_APP_NAME: usize = 48;
746
747pub const IANA_PRIV_ENT_NUM: u64 = 32473;
749
750pub const NILVALUE: &'static str = "-";
752
753pub const ESC_CHAR_REPL: &'static str = "#000";
755
756pub const NILVALUE_B: &'static [u8] = b"-";
758
759pub const WSPACE: &'static str = " ";
761
762pub const OBRACE: &'static str = "[";
764
765pub const CBRACE: &'static str = "]";
767
768pub const CBRACE_SEM: &'static str = "]:";
770
771pub const QCHAR: &'static str = "\"";
773
774pub const ATSIGN: &'static str = "@";
776
777pub const EQSIGN: &'static str = "=";
779
780pub const NEXTLINE: &'static str = "\n";
782
783bitflags! {
784 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
786 pub(crate) struct LogMask: i32
787 {
788 const LOG_FACMASK = 0x3f8;
790
791 const LOG_PRIMASK = 7;
793 }
794}
795
796
797#[derive(Debug, Clone, Copy, PartialEq, Eq)]
803pub struct SyslogMsgPriFac(i32);
804
805impl fmt::Display for SyslogMsgPriFac
806{
807 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
808 {
809 write!(f, "{}", self.0)
810 }
811}
812
813impl TryFrom<i32> for SyslogMsgPriFac
814{
815 type Error = SyslogError;
816
817 fn try_from(value: i32) -> Result<Self, Self::Error>
818 {
819 if (value & !(LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK )) != 0
820 {
821 throw_error!("unknwon facility/priority: {:x}", value);
822 }
823
824 return Ok(Self(value));
825 }
826}
827
828impl TryFrom<&[u8]> for SyslogMsgPriFac
829{
830 type Error = SyslogError;
831
832 fn try_from(value: &[u8]) -> Result<Self, Self::Error>
833 {
834 let val =
835 str::from_utf8(value)
836 .map_or(
837 None,
838 |pri_str|
839 {
840 i32::from_str_radix(pri_str, 10)
841 .map_or(
842 None,
843 |val|
844 Some(val & LogMask::LOG_PRIMASK | val & LogMask::LOG_FACMASK.bits())
845 )
846 }
847 )
848 .ok_or(
849 map_error_code!(InternalError, "cannot convert to prio|facility")
850 )?;
851
852 if (val & !(LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK )) != 0
853 {
854 throw_error!("unknwon facility/priority: {:x}", val);
855 }
856
857 return Ok(Self(val));
858 }
859}
860
861impl SyslogMsgPriFac
862{
863 pub(crate)
866 fn set_facility(p: Priority, f: LogFacility) -> Self
867 {
868 return Self( p as i32 | f.bits() );
869 }
870
871 pub
873 fn get_val(&self) -> i32
874 {
875 return self.0;
876 }
877
878 pub
880 fn get_priority(&self) -> Priority
881 {
882 return Priority::from(self.0 & LogMask::LOG_PRIMASK);
883 }
884
885 pub
887 fn get_log_facility(&self) -> LogFacility
888 {
889 return LogFacility::from_bits_retain(self.0 & LogMask::LOG_FACMASK);
890 }
891}
892
893impl From<i32> for Priority
894{
895 fn from(value: i32) -> Self
896 {
897 if value == Priority::LOG_ALERT as i32
898 {
899 return Priority::LOG_ALERT;
900 }
901 else if value == Priority::LOG_CRIT as i32
902 {
903 return Priority::LOG_CRIT;
904 }
905 else if value == Priority::LOG_DEBUG as i32
906 {
907 return Priority::LOG_DEBUG;
908 }
909 else if value == Priority::LOG_EMERG as i32
910 {
911 return Priority::LOG_EMERG;
912 }
913 else if value == Priority::LOG_ERR as i32
914 {
915 return Priority::LOG_ERR;
916 }
917 else if value == Priority::LOG_INFO as i32
918 {
919 return Priority::LOG_INFO;
920 }
921 else if value == Priority::LOG_NOTICE as i32
922 {
923 return Priority::LOG_NOTICE;
924 }
925 else
926 {
927 return Priority::LOG_WARNING;
928 }
929 }
930}
931
932#[macro_export]
943macro_rules! LOG_MASK
944{
945 ($arg:expr) => (
946 (1 << ($arg))
947 )
948}
949
950#[macro_export]
960macro_rules! LOG_UPTO
961{
962 ($arg:expr) => (
963 ((1 << (($arg) + 1)) - 1)
964 )
965}
966
967impl Shl<Priority> for i32
968{
969 type Output = i32;
970
971 fn shl(self, rhs: Priority) -> i32
972 {
973 let lhs = self;
974 return lhs << rhs as i32;
975 }
976}
977
978impl BitAnd<Priority> for i32
979{
980 type Output = i32;
981
982 #[inline]
983 fn bitand(self, rhs: Priority) -> i32
984 {
985 return self & rhs as i32;
986 }
987}
988
989impl Add<Priority> for i32
990{
991 type Output = i32;
992
993 fn add(self, rhs: Priority) -> Self::Output
994 {
995 rhs as i32 + self
996 }
997}
998
999impl Add<i32> for Priority
1000{
1001 type Output = i32;
1002
1003 fn add(self, rhs: i32) -> Self::Output
1004 {
1005 self as i32 + rhs
1006 }
1007}
1008
1009impl BitAnd<LogMask> for Priority
1010{
1011 type Output = i32;
1012
1013 #[inline]
1014 fn bitand(self, rhs: LogMask) -> i32
1015 {
1016 return self as i32 & rhs.bits();
1017 }
1018}
1019
1020impl BitAnd<LogMask> for LogFacility
1021{
1022 type Output = LogFacility;
1023
1024 #[inline]
1025 fn bitand(self, rhs: LogMask) -> Self::Output
1026 {
1027 return Self::from_bits_retain(self.bits() & rhs.bits());
1028 }
1029}
1030
1031impl BitAnd<LogMask> for i32
1032{
1033 type Output = i32;
1034
1035 #[inline]
1036 fn bitand(self, rhs: LogMask) -> i32
1037 {
1038 return self & rhs.bits();
1039 }
1040}
1041
1042pub
1052fn truncate(lt: &str) -> &str
1053{
1054 let ltt =
1055 match lt.char_indices().nth(lt.len()-1)
1056 {
1057 None => lt,
1058 Some((idx, _)) => <[..idx],
1059 };
1060 return ltt;
1061}
1062
1063pub
1087fn truncate_n<'t>(lt: &'t str, n: usize) -> &'t str
1088{
1089 if lt.as_bytes().len() <= n
1090 {
1091 return lt;
1092 }
1093
1094 let mut nn: usize = 0;
1095 let mut cc = lt.chars();
1096 let mut ln: usize;
1097
1098 loop
1099 {
1100 match cc.next()
1101 {
1102 Some(r) =>
1103 {
1104 ln = r.len_utf8();
1105 nn += ln;
1106
1107 if nn == n
1108 {
1109 return <[..nn];
1110 }
1111 else if nn > n
1112 {
1113 return <[..nn-ln];
1114 }
1115 },
1116 None =>
1117 return lt,
1118 }
1119 }
1120}
1121
1122pub
1131fn check_printable(a: &str) -> SyRes<()>
1132{
1133 if a.is_empty() == true
1134 {
1135 throw_error!("empty SD value");
1136 }
1137
1138 for p in a.chars()
1139 {
1140 if p.is_ascii() == false || p.is_ascii_graphic() == false || p == '@' || p == '=' || p == ']' || p == '\"'
1141 {
1142 throw_error!("incorrect char: '{:X}' in SD value", p as u64);
1143 }
1144 }
1145
1146 return Ok(());
1147}
1148
1149
1150pub
1151fn escape_chars(st: Cow<'static, str>) -> Cow<'static, str>
1152{
1153 let mut out = String::with_capacity(st.len());
1154
1155 for c in st.chars()
1156 {
1157 if c.is_control() == true
1158 {
1159 out.push_str(ESC_CHAR_REPL);
1160 }
1161 else if c == '\"' || c == '\\' || c == ']'
1162 {
1163 out.push('\\');
1164 out.push(c);
1165 }
1166 else
1167 {
1168 out.push(c);
1169 }
1170 }
1171
1172 if st.len() == out.len()
1173 {
1174 return st;
1175 }
1176 else
1177 {
1178 return Cow::Owned(out);
1179 }
1180}
1181
1182
1183#[cfg(test)]
1184mod tests
1185{
1186 use super::*;
1187
1188 #[test]
1189 fn test_truncate()
1190 {
1191 let test = "cat\n";
1192
1193 let trunc = truncate(test);
1194
1195 assert_eq!("cat", trunc);
1196 }
1197
1198
1199
1200 #[test]
1201 fn test_truncate_n()
1202 {
1203 assert_eq!(truncate_n("abcde", 3), "abc");
1204 assert_eq!(truncate_n("ボルテ", 4), "ボ");
1205 assert_eq!(truncate_n("ボルテ", 5), "ボ");
1206 assert_eq!(truncate_n("ボルテ", 6), "ボル");
1207 assert_eq!(truncate_n("abcde", 0), "");
1208 assert_eq!(truncate_n("abcde", 5), "abcde");
1209 assert_eq!(truncate_n("abcde", 6), "abcde");
1210 assert_eq!(truncate_n("ДАТА", 3), "Д");
1211 assert_eq!(truncate_n("ДАТА", 4), "ДА");
1212 assert_eq!(truncate_n("ДАТА", 1), "");
1213 }
1214
1215}