首次入库,远端 https://git.gvsds.com/GVSDS/Viper_VET 。 19 个文件全部为源码/配置,无构建产物: App/main.vp、App/lib/*.vp(VCache / VCheck / VCli / VDirs / VFs / VGuard / VGuid / VJson / VLog / VPe / VProc / VScan / __init__) 1.json、LICENSE、README.md、project.vpj、.gitignore 既有 .gitignore 已覆盖本仓的产物目录(**/output/、**/temp/、**/.tpv_build/) 与 *.exe / *.obj / *.o / *.img / *.iso / __pycache__/ / .cache/; 实测 `git add -A --dry-run` 仅 19 个文件、零产物混入,故未改动 .gitignore。
243 lines
8.1 KiB
Plaintext
243 lines
8.1 KiB
Plaintext
import t, c
|
||
from stdint import *
|
||
import stdlib
|
||
import string
|
||
import viperlib
|
||
import w32.win32file as wf
|
||
import w32.win32base as wb
|
||
|
||
|
||
# ============================================================
|
||
# VLog - 输出原语(全部人类可读日志走 stderr;stdout 只留 JSON)
|
||
#
|
||
# 本模块从原 App/main.vp 的 [stderr 日志] 段整体平移,行为不变:
|
||
# * LogStr/LogFmt1/2/3/LogFmtS1/S2/LogFmtIS 沿用原实现与固定元数转发风格;
|
||
# * 本轮新增 LogFmt4(进度行需要 4 个整数参数)与两个时间戳辅助。
|
||
#
|
||
# 日志详细度(本轮新增):模块级开关 Verbose_Enabled(0=默认安静,1=--verbose)。
|
||
# * 默认安静:只保留"启动摘要 / 心跳确认提示与失败原因 / 警告与致命错误 / 轮末一行";
|
||
# 过程细节(进度行、扫描根进出、逐条 [reject]/[pe]、逐次 --version 探测、目录表逐条
|
||
# 列举、轮末的"下轮开始")一律不输出。
|
||
# * VerboseStr / VerboseFmt1/2/3/4 / VerboseFmtS1/S2/VerboseFmtIS 是 Log* 的兄弟函数:
|
||
# 开关关闭时直接返回(不格式化、不写 stderr),打开时逐字转发给对应 Log*。
|
||
# 调用点只写 Verbose*,"开关判断"集中在本模块,不散落到各调用点。
|
||
# * 取值由 VCli 解析 --verbose 后经 SetVerbose 在**任何日志之前**设置
|
||
# (scan:App/main.vp:VCli.ParseScanArgs 之后;看门狗:confirm-watch 参数解析之后)。
|
||
# 依赖(本仓既有):
|
||
# wf.GetStdHandle(includes/w32/win32file.vp:120)、wf.WriteFile(:91)、
|
||
# wf.STD_ERROR_HANDLE(:46)、wf.STD_OUTPUT_HANDLE(:45)、wb.INVALID_HANDLE_VALUE(:9)、
|
||
# wb.GetLocalTime(includes/w32/win32base.vp:72)、wb.SystemTimeToFileTime(:74)、
|
||
# wb.FileTimeToSystemTime(:73)、wb.SYSTEMTIME(:40)、wb.FILETIME(:36)、
|
||
# viperlib.snprintf(includes/viperlib.vp:25)、string.strlen(includes/string.vp:69)。
|
||
# ============================================================
|
||
|
||
LOG_CAP: t.CDefine = 4096 # 日志格式化缓冲
|
||
|
||
Log_Buffer: bytes = None # 日志格式化缓冲(stdlib.malloc,进程生命周期)
|
||
|
||
|
||
# 字面量/已格式化字节串原样写 stderr(不自动追加换行)
|
||
def LogStr(S: str):
|
||
if S is None:
|
||
return
|
||
H: wb.HANDLE = wf.GetStdHandle(wf.STD_ERROR_HANDLE)
|
||
if H is None or H == wb.INVALID_HANDLE_VALUE:
|
||
return
|
||
n: t.CSizeT = string.strlen(S)
|
||
if n == 0:
|
||
return
|
||
bw: ULONG = 0
|
||
wf.WriteFile(H, S, ULONG(n), t.CPtr(c.Addr(bw)), None)
|
||
|
||
|
||
def LogInit() -> int:
|
||
global Log_Buffer
|
||
Log_Buffer = stdlib.malloc(LOG_CAP)
|
||
if Log_Buffer is None:
|
||
return 0
|
||
Log_Buffer[0] = 0
|
||
return 1
|
||
|
||
|
||
# 固定元数的格式化转发(非 varargs 函数 ⇒ 不引入自定义可变参数风险):
|
||
# 内部调用既有的 viperlib.snprintf,把格式化结果写 stderr。
|
||
def LogFmt1(Fmt: str, A: t.CSizeT) -> int:
|
||
if Log_Buffer is None:
|
||
return 0
|
||
viperlib.snprintf(Log_Buffer, t.CSizeT(LOG_CAP), Fmt, A)
|
||
LogStr(str(Log_Buffer))
|
||
return 1
|
||
|
||
|
||
def LogFmt2(Fmt: str, A: t.CSizeT, B: t.CSizeT) -> int:
|
||
if Log_Buffer is None:
|
||
return 0
|
||
viperlib.snprintf(Log_Buffer, t.CSizeT(LOG_CAP), Fmt, A, B)
|
||
LogStr(str(Log_Buffer))
|
||
return 1
|
||
|
||
|
||
def LogFmt3(Fmt: str, A: t.CSizeT, B: t.CSizeT, C: t.CSizeT) -> int:
|
||
if Log_Buffer is None:
|
||
return 0
|
||
viperlib.snprintf(Log_Buffer, t.CSizeT(LOG_CAP), Fmt, A, B, C)
|
||
LogStr(str(Log_Buffer))
|
||
return 1
|
||
|
||
|
||
# 需求 3:扫盘进度行需要 4 个整数(r/dir/file/cand)
|
||
def LogFmt4(Fmt: str, A: t.CSizeT, B: t.CSizeT, C: t.CSizeT, D: t.CSizeT) -> int:
|
||
if Log_Buffer is None:
|
||
return 0
|
||
viperlib.snprintf(Log_Buffer, t.CSizeT(LOG_CAP), Fmt, A, B, C, D)
|
||
LogStr(str(Log_Buffer))
|
||
return 1
|
||
|
||
|
||
def LogFmtS1(Fmt: str, A: str) -> int:
|
||
if Log_Buffer is None:
|
||
return 0
|
||
viperlib.snprintf(Log_Buffer, t.CSizeT(LOG_CAP), Fmt, A)
|
||
LogStr(str(Log_Buffer))
|
||
return 1
|
||
|
||
|
||
def LogFmtS2(Fmt: str, A: str, B: str) -> int:
|
||
if Log_Buffer is None:
|
||
return 0
|
||
viperlib.snprintf(Log_Buffer, t.CSizeT(LOG_CAP), Fmt, A, B)
|
||
LogStr(str(Log_Buffer))
|
||
return 1
|
||
|
||
|
||
def LogFmtIS(Fmt: str, A: t.CSizeT, B: str) -> int:
|
||
if Log_Buffer is None:
|
||
return 0
|
||
viperlib.snprintf(Log_Buffer, t.CSizeT(LOG_CAP), Fmt, A, B)
|
||
LogStr(str(Log_Buffer))
|
||
return 1
|
||
|
||
|
||
# ============================================================
|
||
# verbose 开关与"仅 verbose 才输出"的兄弟函数
|
||
# * 开关集中在 Verbose_Enabled 一处;调用点只写 Verbose*,不写 if。
|
||
# * 关闭时直接返回 0(连格式化都不做),打开时逐字转发给对应 Log*。
|
||
# * 返回码与 Log* 一致(1=已写出,0=未写出/失败)。
|
||
# ============================================================
|
||
|
||
Verbose_Enabled: int = 0 # 0=默认安静;1=--verbose
|
||
|
||
|
||
def SetVerbose(V: int):
|
||
global Verbose_Enabled
|
||
Verbose_Enabled = V
|
||
|
||
|
||
def VerboseOn() -> int:
|
||
return Verbose_Enabled
|
||
|
||
|
||
def VerboseStr(S: str) -> int:
|
||
if Verbose_Enabled == 0:
|
||
return 0
|
||
LogStr(S)
|
||
return 1
|
||
|
||
|
||
def VerboseFmt1(Fmt: str, A: t.CSizeT) -> int:
|
||
if Verbose_Enabled == 0:
|
||
return 0
|
||
LogFmt1(Fmt, A)
|
||
return 1
|
||
|
||
|
||
def VerboseFmt2(Fmt: str, A: t.CSizeT, B: t.CSizeT) -> int:
|
||
if Verbose_Enabled == 0:
|
||
return 0
|
||
LogFmt2(Fmt, A, B)
|
||
return 1
|
||
|
||
|
||
def VerboseFmt3(Fmt: str, A: t.CSizeT, B: t.CSizeT, C: t.CSizeT) -> int:
|
||
if Verbose_Enabled == 0:
|
||
return 0
|
||
LogFmt3(Fmt, A, B, C)
|
||
return 1
|
||
|
||
|
||
def VerboseFmt4(Fmt: str, A: t.CSizeT, B: t.CSizeT, C: t.CSizeT, D: t.CSizeT) -> int:
|
||
if Verbose_Enabled == 0:
|
||
return 0
|
||
LogFmt4(Fmt, A, B, C, D)
|
||
return 1
|
||
|
||
|
||
def VerboseFmtS1(Fmt: str, A: str) -> int:
|
||
if Verbose_Enabled == 0:
|
||
return 0
|
||
LogFmtS1(Fmt, A)
|
||
return 1
|
||
|
||
|
||
def VerboseFmtS2(Fmt: str, A: str, B: str) -> int:
|
||
if Verbose_Enabled == 0:
|
||
return 0
|
||
LogFmtS2(Fmt, A, B)
|
||
return 1
|
||
|
||
|
||
def VerboseFmtIS(Fmt: str, A: t.CSizeT, B: str) -> int:
|
||
if Verbose_Enabled == 0:
|
||
return 0
|
||
LogFmtIS(Fmt, A, B)
|
||
return 1
|
||
|
||
|
||
# stdout 原样写(scan 模式只输出 JSON)
|
||
def StdoutWrite(S: str):
|
||
if S is None:
|
||
return
|
||
H: wb.HANDLE = wf.GetStdHandle(wf.STD_OUTPUT_HANDLE)
|
||
if H is None or H == wb.INVALID_HANDLE_VALUE:
|
||
return
|
||
n: t.CSizeT = string.strlen(S)
|
||
if n == 0:
|
||
return
|
||
bw: ULONG = 0
|
||
wf.WriteFile(H, S, ULONG(n), t.CPtr(c.Addr(bw)), None)
|
||
|
||
|
||
# ============================================================
|
||
# 时间戳(需求 3:轮次开始/下轮开始)
|
||
# 用 Win32 本地时间;AddMs 通过 FILETIME(100ns) 加法后回转 SYSTEMTIME。
|
||
# 依据:wb.FILETIME 为 {dwLowDateTime,dwHighDateTime}(win32base.vp:36),
|
||
# FILETIME 单位 100ns(Win32 规范),故 AddMs*10000 为增量。
|
||
# ============================================================
|
||
|
||
def TimeStampNow(Out: bytes, Cap: int) -> int:
|
||
St: wb.SYSTEMTIME = wb.SYSTEMTIME()
|
||
wb.GetLocalTime(t.CPtr(c.Addr(St)))
|
||
viperlib.snprintf(Out, t.CSizeT(Cap), "%04u-%02u-%02u %02u:%02u:%02u",
|
||
t.CUInt32T(St.wYear), t.CUInt32T(St.wMonth), t.CUInt32T(St.wDay),
|
||
t.CUInt32T(St.wHour), t.CUInt32T(St.wMinute), t.CUInt32T(St.wSecond))
|
||
return 1
|
||
|
||
|
||
def TimeStampAfter(Out: bytes, Cap: int, AddMs: t.CSizeT) -> int:
|
||
St: wb.SYSTEMTIME = wb.SYSTEMTIME()
|
||
wb.GetLocalTime(t.CPtr(c.Addr(St)))
|
||
Ft: wb.FILETIME = wb.FILETIME()
|
||
if wb.SystemTimeToFileTime(t.CPtr(c.Addr(St)), t.CPtr(c.Addr(Ft))) == 0:
|
||
return TimeStampNow(Out, Cap)
|
||
Ticks: ULONGLONG = (ULONGLONG(Ft.dwHighDateTime) << 32) | ULONGLONG(Ft.dwLowDateTime)
|
||
Ticks = Ticks + (ULONGLONG(AddMs) * ULONGLONG(10000))
|
||
Ft.dwLowDateTime = DWORD(Ticks & ULONGLONG(0xFFFFFFFF))
|
||
Ft.dwHighDateTime = DWORD(Ticks >> 32)
|
||
St2: wb.SYSTEMTIME = wb.SYSTEMTIME()
|
||
if wb.FileTimeToSystemTime(t.CPtr(c.Addr(Ft)), t.CPtr(c.Addr(St2))) == 0:
|
||
return TimeStampNow(Out, Cap)
|
||
viperlib.snprintf(Out, t.CSizeT(Cap), "%04u-%02u-%02u %02u:%02u:%02u",
|
||
t.CUInt32T(St2.wYear), t.CUInt32T(St2.wMonth), t.CUInt32T(St2.wDay),
|
||
t.CUInt32T(St2.wHour), t.CUInt32T(St2.wMinute), t.CUInt32T(St2.wSecond))
|
||
return 1
|