1use std::{borrow::Cow, fmt, ops::{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
430 impl Priority
431 {
432
433 }
434
435 bitflags! {
436 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
439 pub struct LogFacility: libc::c_int
440 {
441 const LOG_KERN = libc::LOG_KERN;
443
444 const LOG_USER = libc::LOG_USER;
446
447 const LOG_MAIL = libc::LOG_MAIL;
449
450 const LOG_DAEMON = libc::LOG_DAEMON;
452
453 const LOG_AUTH = libc::LOG_AUTH;
455
456 const LOG_SYSLOG = libc::LOG_SYSLOG;
458
459 const LOG_LPR = libc::LOG_LPR;
461
462 const LOG_NEWS = libc::LOG_NEWS;
464
465 const LOG_UUCP = libc::LOG_UUCP;
467
468 const LOG_LOCAL0 = libc::LOG_LOCAL0;
470
471 const LOG_LOCAL1 = libc::LOG_LOCAL1;
473
474 const LOG_LOCAL2 = libc::LOG_LOCAL2;
476
477 const LOG_LOCAL3 = libc::LOG_LOCAL3;
479
480 const LOG_LOCAL4 = libc::LOG_LOCAL4;
482
483 const LOG_LOCAL5 = libc::LOG_LOCAL5;
485
486 const LOG_LOCAL6 = libc::LOG_LOCAL6;
488
489 const LOG_LOCAL7 = libc::LOG_LOCAL7;
491 }
492 }
493
494
495 impl FromStr for LogFacility
496 {
497 type Err = SyslogError;
498
499 fn from_str(s: &str) -> Result<Self, Self::Err>
500 {
501 let s_up = s.to_ascii_uppercase();
502
503 match s_up.as_str()
504 {
505 "LOG_KERN" => Ok(Self::LOG_KERN),
506 "LOG_USER" => Ok(Self::LOG_USER),
507 "LOG_MAIL" => Ok(Self::LOG_MAIL),
508 "LOG_DAEMON" => Ok(Self::LOG_DAEMON),
509 "LOG_AUTH" => Ok(Self::LOG_AUTH),
510 "LOG_SYSLOG" => Ok(Self::LOG_SYSLOG),
511 "LOG_LPR" => Ok(Self::LOG_LPR),
512 "LOG_NEWS" => Ok(Self::LOG_NEWS),
513 "LOG_UUCP" => Ok(Self::LOG_UUCP),
514 "LOG_LOCAL0" => Ok(Self::LOG_LOCAL0),
515 "LOG_LOCAL1" => Ok(Self::LOG_LOCAL1),
516 "LOG_LOCAL2" => Ok(Self::LOG_LOCAL2),
517 "LOG_LOCAL3" => Ok(Self::LOG_LOCAL3),
518 "LOG_LOCAL4" => Ok(Self::LOG_LOCAL4),
519 "LOG_LOCAL5" => Ok(Self::LOG_LOCAL5),
520 "LOG_LOCAL6" => Ok(Self::LOG_LOCAL6),
521 "LOG_LOCAL7" => Ok(Self::LOG_LOCAL7),
522 n =>
523 throw_error!("unknwon log facility: {}", n)
524 }
525 }
526 }
527
528 impl fmt::Display for LogFacility
529 {
530 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
531 {
532 match *self
533 {
534 Self::LOG_KERN =>
535 write!(f, "LOG_KERN"),
536 Self::LOG_USER =>
537 write!(f, "LOG_USER"),
538 Self::LOG_MAIL =>
539 write!(f, "LOG_MAIL"),
540 Self::LOG_DAEMON =>
541 write!(f, "LOG_DAEMON"),
542 Self::LOG_AUTH =>
543 write!(f, "LOG_AUTH"),
544 Self::LOG_SYSLOG =>
545 write!(f, "LOG_SYSLOG"),
546 Self::LOG_LPR =>
547 write!(f, "LOG_LPR"),
548 Self::LOG_NEWS =>
549 write!(f, "LOG_NEWS"),
550 Self::LOG_UUCP =>
551 write!(f, "LOG_UUCP"),
552 Self::LOG_LOCAL0 =>
553 write!(f, "LOG_LOCAL0"),
554 Self::LOG_LOCAL1 =>
555 write!(f, "LOG_LOCAL1"),
556 Self::LOG_LOCAL2 =>
557 write!(f, "LOG_LOCAL2"),
558 Self::LOG_LOCAL3 =>
559 write!(f, "LOG_LOCAL3"),
560 Self::LOG_LOCAL4 =>
561 write!(f, "LOG_LOCAL4"),
562 Self::LOG_LOCAL5 =>
563 write!(f, "LOG_LOCAL5"),
564 Self::LOG_LOCAL6 =>
565 write!(f, "LOG_LOCAL6"),
566 Self::LOG_LOCAL7 =>
567 write!(f, "LOG_LOCAL7"),
568 n =>
569 write!(f, "LOG_[{}]", n),
570 }
571 }
572 }
573
574 pub const PATH_LOG: &'static str = "/var/run/log";
576
577 pub const PATH_LOG_PRIV: &'static str = "/var/run/logpriv";
579
580 pub const PATH_OLDLOG: &'static str = "/dev/log";
582
583 pub const PATH_OSX: &'static str = "/var/run/syslog";
585
586 #[cfg(feature = "build_sync")]
595 pub(crate) mod sync_portion
596 {
597 use std::io::Write;
598 use std::io::IoSlice;
599 use crate::error::SyRes;
600 use crate::map_error_os;
601
602 pub(crate)
613 fn send_to_fd<W>(mut file_fd: W, msg: &str, newline: &str) -> SyRes<usize>
614 where W: Write
615 {
616 return
617 file_fd
618 .write_vectored(
619 &[IoSlice::new(msg.as_bytes()), IoSlice::new(newline.as_bytes())]
620 )
621 .map_err(|e|
622 map_error_os!(e, "send_to_fd() writev() failed")
623 );
624 }
625 }
626
627 use crate::{error::SyslogError, throw_error};
628
629#[cfg(feature = "build_sync")]
630 pub(crate) use self::sync_portion::*;
631
632 #[cfg(test)]
633 mod tests
634 {
635 use super::*;
636
637 #[cfg(feature = "build_sync")]
638 #[test]
639 fn test_error_message()
640 {
641 let testmsg = "this is test message!";
647 let newline = "\n";
648 let stderr_lock = std::io::stderr().lock();
649 let res = send_to_fd(stderr_lock, testmsg, &newline);
650
651 println!("res: {:?}", res);
652
653 assert_eq!(res.is_ok(), true, "err: {}", res.err().unwrap());
654
655 return;
656 }
657
658 #[test]
659 fn test_priority_shl()
660 {
661 assert_eq!((1 << 5), (1 << Priority::LOG_NOTICE));
662 }
663 }
664}
665
666pub static PATH_CONSOLE: LazyLock<&Path> = LazyLock::new(||
668 {
669 Path::new("/dev/console")
670 }
671);
672
673pub static RFC5424_MAX_DGRAM: LazyLock<usize> = LazyLock::new(||
675 {
676 portable::get_local_dgram_maxdgram() as usize
677 }
678);
679
680
681pub const MAXHOSTNAMELEN: usize = 256;
683
684pub const LOG_FACMASK: i32 = 0x03f8;
686
687pub const MAXLINE: usize = 8192;
691
692pub const RFC3164_MAX_PAYLOAD_LEN: usize = 1024;
694
695pub const WINDOWS_EVENT_REPORT_MAX_PAYLOAD_LEN: usize = 31839;
697
698#[cfg(all(feature = "udp_truncate_1024_bytes", feature = "udp_truncate_1440_bytes"))]
699compile_error!("either 'udp_truncate_1024_bytes' or 'udp_truncate_1440_bytes' should be enabled");
700
701#[cfg(feature = "udp_truncate_1024_bytes")]
703pub const RFC5424_UDP_MAX_PKT_LEN: usize = 1024;
704
705#[cfg(any(feature = "udp_truncate_1440_bytes", all(not(feature = "udp_truncate_1440_bytes"), not(feature = "udp_truncate_1024_bytes"))))]
706pub const RFC5424_UDP_MAX_PKT_LEN: usize = 2048;
707
708#[cfg(feature = "tcp_truncate_1024_bytes")]
709pub const RFC5424_TCP_MAX_PKT_LEN: usize = 1024;
710
711#[cfg(feature = "tcp_truncate_2048_bytes")]
712pub const RFC5424_TCP_MAX_PKT_LEN: usize = 2048;
713
714#[cfg(feature = "tcp_truncate_4096_bytes")]
715pub const RFC5424_TCP_MAX_PKT_LEN: usize = 4096;
716
717#[cfg(feature = "tcp_truncate_max_bytes")]
718pub const RFC5424_TCP_MAX_PKT_LEN: usize = MAXLINE;
719
720pub const RFC_MAX_APP_NAME: usize = 48;
722
723pub const IANA_PRIV_ENT_NUM: u64 = 32473;
725
726pub const NILVALUE: &'static str = "-";
728
729pub const ESC_CHAR_REPL: &'static str = "#000";
731
732pub const NILVALUE_B: &'static [u8] = b"-";
734
735pub const WSPACE: &'static str = " ";
737
738pub const OBRACE: &'static str = "[";
740
741pub const CBRACE: &'static str = "]";
743
744pub const CBRACE_SEM: &'static str = "]:";
746
747pub const QCHAR: &'static str = "\"";
749
750pub const ATSIGN: &'static str = "@";
752
753pub const EQSIGN: &'static str = "=";
755
756pub const NEXTLINE: &'static str = "\n";
758
759bitflags! {
760 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
762 pub(crate) struct LogMask: i32
763 {
764 const LOG_FACMASK = 0x3f8;
766
767 const LOG_PRIMASK = 7;
769 }
770}
771
772#[derive(Debug, Clone, Copy, PartialEq, Eq)]
778pub struct SyslogMsgPriFac(i32);
779
780impl fmt::Display for SyslogMsgPriFac
781{
782 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
783 {
784 write!(f, "{}", self.0)
785 }
786}
787
788impl TryFrom<i32> for SyslogMsgPriFac
789{
790 type Error = SyslogError;
791
792 fn try_from(value: i32) -> Result<Self, Self::Error>
793 {
794 if (value & !(LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK )) != 0
795 {
796 throw_error!("unknwon facility/priority: {:x}", value);
797 }
798
799 return Ok(Self(value));
800 }
801}
802
803impl TryFrom<&[u8]> for SyslogMsgPriFac
804{
805 type Error = SyslogError;
806
807 fn try_from(value: &[u8]) -> Result<Self, Self::Error>
808 {
809 let val =
810 str::from_utf8(value)
811 .map_or(
812 None,
813 |pri_str|
814 {
815 i32::from_str_radix(pri_str, 10)
816 .map_or(
817 None,
818 |val|
819 Some(val & LogMask::LOG_PRIMASK | val & LogMask::LOG_FACMASK.bits())
820 )
821 }
822 )
823 .ok_or(
824 map_error_code!(InternalError, "cannot convert to prio|facility")
825 )?;
826
827 if (val & !(LogMask::LOG_PRIMASK | LogMask::LOG_FACMASK )) != 0
828 {
829 throw_error!("unknwon facility/priority: {:x}", val);
830 }
831
832 return Ok(Self(val));
833 }
834}
835
836impl SyslogMsgPriFac
837{
838 pub(crate)
841 fn set_facility(p: Priority, f: LogFacility) -> Self
842 {
843 return Self( p as i32 | f.bits() );
844 }
845
846 pub
848 fn get_val(&self) -> i32
849 {
850 return self.0;
851 }
852
853 pub
855 fn get_priority(&self) -> Priority
856 {
857 return Priority::from(self.0 & LogMask::LOG_PRIMASK);
858 }
859
860 pub
862 fn get_log_facility(&self) -> LogFacility
863 {
864 return LogFacility::from_bits_retain(self.0 & LogMask::LOG_FACMASK);
865 }
866}
867
868impl From<i32> for Priority
869{
870 fn from(value: i32) -> Self
871 {
872 if value == Priority::LOG_ALERT as i32
873 {
874 return Priority::LOG_ALERT;
875 }
876 else if value == Priority::LOG_CRIT as i32
877 {
878 return Priority::LOG_CRIT;
879 }
880 else if value == Priority::LOG_DEBUG as i32
881 {
882 return Priority::LOG_DEBUG;
883 }
884 else if value == Priority::LOG_EMERG as i32
885 {
886 return Priority::LOG_EMERG;
887 }
888 else if value == Priority::LOG_ERR as i32
889 {
890 return Priority::LOG_ERR;
891 }
892 else if value == Priority::LOG_INFO as i32
893 {
894 return Priority::LOG_INFO;
895 }
896 else if value == Priority::LOG_NOTICE as i32
897 {
898 return Priority::LOG_NOTICE;
899 }
900 else
901 {
902 return Priority::LOG_WARNING;
903 }
904 }
905}
906
907#[macro_export]
918macro_rules! LOG_MASK
919{
920 ($arg:expr) => (
921 (1 << ($arg))
922 )
923}
924
925#[macro_export]
935macro_rules! LOG_UPTO
936{
937 ($arg:expr) => (
938 ((1 << (($arg) + 1)) - 1)
939 )
940}
941
942impl Shl<Priority> for i32
943{
944 type Output = i32;
945
946 fn shl(self, rhs: Priority) -> i32
947 {
948 let lhs = self;
949 return lhs << rhs as i32;
950 }
951}
952
953impl BitAnd<Priority> for i32
954{
955 type Output = i32;
956
957 #[inline]
958 fn bitand(self, rhs: Priority) -> i32
959 {
960 return self & rhs as i32;
961 }
962}
963
964impl BitAnd<LogMask> for Priority
965{
966 type Output = i32;
967
968 #[inline]
969 fn bitand(self, rhs: LogMask) -> i32
970 {
971 return self as i32 & rhs.bits();
972 }
973}
974
975impl BitAnd<LogMask> for LogFacility
976{
977 type Output = LogFacility;
978
979 #[inline]
980 fn bitand(self, rhs: LogMask) -> Self::Output
981 {
982 return Self::from_bits_retain(self.bits() & rhs.bits());
983 }
984}
985
986impl BitAnd<LogMask> for i32
987{
988 type Output = i32;
989
990 #[inline]
991 fn bitand(self, rhs: LogMask) -> i32
992 {
993 return self & rhs.bits();
994 }
995}
996
997pub
1007fn truncate(lt: &str) -> &str
1008{
1009 let ltt =
1010 match lt.char_indices().nth(lt.len()-1)
1011 {
1012 None => lt,
1013 Some((idx, _)) => <[..idx],
1014 };
1015 return ltt;
1016}
1017
1018pub
1042fn truncate_n<'t>(lt: &'t str, n: usize) -> &'t str
1043{
1044 if lt.as_bytes().len() <= n
1045 {
1046 return lt;
1047 }
1048
1049 let mut nn: usize = 0;
1050 let mut cc = lt.chars();
1051 let mut ln: usize;
1052
1053 loop
1054 {
1055 match cc.next()
1056 {
1057 Some(r) =>
1058 {
1059 ln = r.len_utf8();
1060 nn += ln;
1061
1062 if nn == n
1063 {
1064 return <[..nn];
1065 }
1066 else if nn > n
1067 {
1068 return <[..nn-ln];
1069 }
1070 },
1071 None =>
1072 return lt,
1073 }
1074 }
1075}
1076
1077pub
1086fn check_printable(a: &str) -> SyRes<()>
1087{
1088 if a.is_empty() == true
1089 {
1090 throw_error!("empty SD value");
1091 }
1092
1093 for p in a.chars()
1094 {
1095 if p.is_ascii() == false || p.is_ascii_graphic() == false || p == '@' || p == '=' || p == ']' || p == '\"'
1096 {
1097 throw_error!("incorrect char: '{:X}' in SD value", p as u64);
1098 }
1099 }
1100
1101 return Ok(());
1102}
1103
1104
1105pub
1106fn escape_chars(st: Cow<'static, str>) -> Cow<'static, str>
1107{
1108 let mut out = String::with_capacity(st.len());
1109
1110 for c in st.chars()
1111 {
1112 if c.is_control() == true
1113 {
1114 out.push_str(ESC_CHAR_REPL);
1115 }
1116 else if c == '\"' || c == '\\' || c == ']'
1117 {
1118 out.push('\\');
1119 out.push(c);
1120 }
1121 else
1122 {
1123 out.push(c);
1124 }
1125 }
1126
1127 if st.len() == out.len()
1128 {
1129 return st;
1130 }
1131 else
1132 {
1133 return Cow::Owned(out);
1134 }
1135}
1136
1137
1138#[cfg(test)]
1139mod tests
1140{
1141 use super::*;
1142
1143 #[test]
1144 fn test_truncate()
1145 {
1146 let test = "cat\n";
1147
1148 let trunc = truncate(test);
1149
1150 assert_eq!("cat", trunc);
1151 }
1152
1153
1154
1155 #[test]
1156 fn test_truncate_n()
1157 {
1158 assert_eq!(truncate_n("abcde", 3), "abc");
1159 assert_eq!(truncate_n("ボルテ", 4), "ボ");
1160 assert_eq!(truncate_n("ボルテ", 5), "ボ");
1161 assert_eq!(truncate_n("ボルテ", 6), "ボル");
1162 assert_eq!(truncate_n("abcde", 0), "");
1163 assert_eq!(truncate_n("abcde", 5), "abcde");
1164 assert_eq!(truncate_n("abcde", 6), "abcde");
1165 assert_eq!(truncate_n("ДАТА", 3), "Д");
1166 assert_eq!(truncate_n("ДАТА", 4), "ДА");
1167 assert_eq!(truncate_n("ДАТА", 1), "");
1168 }
1169
1170}