2 * coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
3 * Understanding is not required. Only obedience.
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, version 3 of the License ONLY.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 public import chibackend
.sqbase
;
20 public import chibackend
.decode
;
21 public import chibackend
.parse
;
22 public import chibackend
.mfilter
;
23 public import chibackend
.mbuilder
;
25 private import iv
.strex
;
26 private import iv
.vfs
.util
;
28 public import iv
.dynstring
: DynStr
= dynstring
;
31 // ////////////////////////////////////////////////////////////////////////// //
34 // this marks the buffer as "opaque", so GC won't scan its contents
35 // this is to avoid false positives in GC
37 public void markGCOpaque (const(void)[] buf) /*nothrow @trusted*/ {
38 import core.memory : GC;
39 if (buf !is null && buf.length != 0 && GC.addrOf(buf.ptr)) {
40 { import core.stdc.stdio : stderr, fprintf; fprintf(stderr, "X000!\n"); }
41 GC.setAttr(buf.ptr, GC.BlkAttr.NO_SCAN/*|GC.BlkAttr.NO_INTERIOR*/);
42 { import core.stdc.stdio : stderr, fprintf; fprintf(stderr, "X001!\n"); }
48 public __gshared string chiroCLIMailPath
= "~/Mail";
50 public void chiroParseCommonCLIArgs (ref string
[] args
) {
51 for (usize idx
= 1; idx
< args
.length
; ) {
52 string arg
= args
[idx
];
53 if (arg
.length
== 0) { ++idx
; continue; }
54 if (arg
== "--") break;
57 if (arg
== "--mailpath") {
59 if (idx
+1 >= args
.length
) throw new Exception("\"--mailpath\" expects argument");
60 chiroCLIMailPath
= args
[idx
+1];
61 } else if (arg
.strEquCI("--nocompress")) {
62 ChiroCompressionLevel
= 0;
63 } else if (arg
.strEquCI("--max")) {
64 ChiroCompressionLevel
= 666;
65 } else if (arg
.length
== 2 && arg
[0] == '-' && arg
[1] >= '0' && arg
[1] <= '9') {
66 ChiroCompressionLevel
= arg
[1]-'0';
71 foreach (usize c
; idx
+argcount
..args
.length
) args
[c
-argcount
] = args
[c
];
72 args
.length
-= argcount
;
75 if (chiroCLIMailPath
.length
== 0) {
76 chiroCLIMailPath
= "./";
77 } else if (chiroCLIMailPath
[0] == '~') {
78 char[] dpath
= new char[chiroCLIMailPath
.length
+4096];
79 dpath
= expandTilde(dpath
, chiroCLIMailPath
);
80 while (dpath
.length
> 1 && dpath
[$-1] == '/') dpath
= dpath
[0..$-1];
82 chiroCLIMailPath
= cast(string
)dpath
; // it is safe to cast here
83 } else if (chiroCLIMailPath
[$-1] == '/') {
84 chiroCLIMailPath
~= '/';
89 // ////////////////////////////////////////////////////////////////////////// //
90 public string
SysTimeToRFCString() (in auto ref Imp
!"std.datetime".SysTime tm
) {
93 //Sun, 7 Dec 2014 16:04:04 +0200
94 immutable string
[7] daysOfWeekNames
= ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
95 immutable string
[12] monthNames
= ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
97 string
tzstr (Duration utcOffset
) {
98 import std
.format
: format
;
99 immutable absOffset
= abs(utcOffset
);
102 absOffset
.split
!("hours", "minutes")(hours
, minutes
);
103 return format(utcOffset
< Duration
.zero ?
"-%02d%02d" : "+%02d%02d", hours
, minutes
);
107 import std
.format
: format
;
108 auto dateTime
= cast(DateTime
)tm
;
109 return "%s, %d %s %d %02d:%02d:%02d %s".format(
110 daysOfWeekNames
[dateTime
.dayOfWeek
],
112 monthNames
[dateTime
.month
-1],
119 } catch (Exception e
) {
120 assert(0, "format() threw.");
125 // ////////////////////////////////////////////////////////////////////////// //
126 // simple exponential running average
127 struct RunningAverageExp
{
129 double mFadeoff
= 0.1; // 10%
130 double mCurrValue
= 0.0;
131 ulong mStartTime
= 0;
134 uint mProgTrh
= 1024;
135 ulong mTimerNextUpdate
= 0;
137 public nothrow @trusted @nogc:
138 this (const double aFadeoff
) { pragma(inline
, true);mFadeoff
= aFadeoff
; }
140 void reset () { pragma(inline
, true);mCurrValue
= 0.0; }
142 @property double fadeoff () const pure { pragma(inline
, true);return mFadeoff
; }
143 @property void fadeoff (const double aFadeoff
) { pragma(inline
, true);mFadeoff
= aFadeoff
; }
145 void update (const double newValue
) { pragma(inline
, true);mCurrValue
= mFadeoff
*newValue
+(1.0-mFadeoff
)*mCurrValue
; }
147 @property double value () const pure { pragma(inline
, true);return mCurrValue
; }
148 @property void value (const double aValue
) { pragma(inline
, true);mCurrValue
= aValue
; }
150 @property uint uintValue () const pure { pragma(inline
, true);return cast(uint)mCurrValue
; }
152 void startTimer (uint total
) {
153 mStartTime
= GetTickCount();
157 mTimerNextUpdate
= 0;
160 @property uint progressThreshold () const pure { pragma(inline
, true); return mProgTrh
; }
161 @property void progressThreshold (uint trh
) { pragma(inline
, true); mProgTrh
= trh
; }
163 @property uint timerTotal () const pure { pragma(inline
, true); return mTotal
; }
164 @property void timerTotal (uint total
) { pragma(inline
, true); mTotal
= total
; }
166 // returns `true` if it is time to show progress
167 bool updateProcessed (uint count
, bool delta
=true) {
168 if (!count
) return false;
169 immutable uint prev
= mProcessed
;
170 if (delta
) mProcessed
+= count
; else mProcessed
= count
;
171 if (mProgTrh
== 0 || prev
== 0) return true;
172 return (prev
/mProgTrh
!= mProcessed
/mProgTrh
);
176 void getTimeETA() (out uint time
, out uint eta
, out uint curr
, out uint total
, out uint percent
, ulong ctime
=ulong.max
) {
177 if (ctime
== ulong.max
) ctime
= GetTickCount();
178 immutable uint secs
= cast(uint)(ctime
-mStartTime
);
180 if (secs
&& mTotal
&& mProcessed
) {
182 eta
= cast(uint)(cast(ulong)secs
*mTotal
/mProcessed
);
183 if (mCurrValue
< eta
) mCurrValue
= eta
;
185 if (mCurrValue
< eta
) mCurrValue
= eta
;
187 eta
= cast(uint)mCurrValue
;
191 percent
= (mTotal ?
cast(uint)(cast(ulong)mProcessed
*100U/mTotal
) : 0U);
194 bool updateProcessedWithProgress (uint count
, bool delta
=true, bool forceWrite
=false, bool writeNL
=false) {
195 if (!updateProcessed(count
, delta
)) {
196 if (!forceWrite
) return false;
199 immutable ctime
= GetTickCount();
200 if (!forceWrite
&& mTimerNextUpdate
> ctime
) return false;
201 mTimerNextUpdate
= ctime
+1;
203 uint secs
, eta
, curr
, tot
, prc
;
204 getTimeETA(out secs
, out eta
, out curr
, out tot
, out prc
, ctime
);
206 char[128] buf
= void;
209 import core
.stdc
.stdio
: snprintf
;
210 auto len
= snprintf(buf
.ptr
, buf
.length
, "\r%s[%u/%u] %3u%%", (writeNL ?
"".ptr
: " ".ptr
), curr
, tot
, prc
);
211 extractHMS(secs
, out h
, out m
, out s
);
212 if (len
< buf
.length
) len
+= snprintf(buf
.ptr
+len
, buf
.length
-len
, " %02u:%02u:%02u", h
, m
, s
);
213 extractHMS(eta
, out h
, out m
, out s
);
214 if (len
< buf
.length
) len
+= snprintf(buf
.ptr
+len
, buf
.length
-len
, " %02u:%02u:%02u", h
, m
, s
);
215 if (len
< buf
.length
) len
+= snprintf(buf
.ptr
+len
, buf
.length
-len
, "\x1b[K%c", (writeNL ?
'\n' : '\r'));
217 import core
.sys
.posix
.unistd
: write
, STDOUT_FILENO
;
218 write(STDOUT_FILENO
, buf
.ptr
, cast(usize
)len
);
223 static extractHMS (uint secs
, out uint h
, out uint m
, out uint s
) {
224 s
= secs
%60; secs
/= 60;
225 m
= secs
%60; secs
/= 60;
229 static ulong GetTickCount() () {
231 immutable MonoTime ctt
= MonoTime
.currTime
;
232 return cast(ulong)ctt
.ticks
/cast(ulong)ctt
.ticksPerSecond
;