fix auth; update deps

This commit is contained in:
Aine
2024-07-03 12:21:47 +03:00
parent f91691bc7c
commit bf89b8fe1b
158 changed files with 356812 additions and 167974 deletions
+13 -13
View File
@@ -12,16 +12,16 @@ require (
github.com/emersion/go-sasl v0.0.0-20231106173351-e73c9f7bad43
github.com/emersion/go-smtp v0.21.2
github.com/fsnotify/fsnotify v1.7.0
github.com/gabriel-vasile/mimetype v1.4.3
github.com/getsentry/sentry-go v0.27.0
github.com/gabriel-vasile/mimetype v1.4.4
github.com/getsentry/sentry-go v0.28.1
github.com/jhillyerd/enmime v1.2.0
github.com/kvannotten/mailstrip v0.0.0-20200711213611-0002f5c0467e
github.com/lib/pq v1.10.9
github.com/mcnijman/go-emailaddress v1.1.1
github.com/mileusna/crontab v1.2.0
github.com/raja/argon2pw v1.0.2-0.20210910183755-a391af63bd39
github.com/rs/zerolog v1.32.0
gitlab.com/etke.cc/go/env v1.1.0
github.com/rs/zerolog v1.33.0
gitlab.com/etke.cc/go/env v1.2.0
gitlab.com/etke.cc/go/fswatcher v1.0.0
gitlab.com/etke.cc/go/healthchecks/v2 v2.2.0
gitlab.com/etke.cc/go/mxidwc v1.0.0
@@ -29,9 +29,9 @@ require (
gitlab.com/etke.cc/go/secgen v1.2.0
gitlab.com/etke.cc/go/validator v1.0.7
gitlab.com/etke.cc/linkpearl v0.0.0-20240425105001-435ae2720365
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
maunium.net/go/mautrix v0.18.1
modernc.org/sqlite v1.29.10
modernc.org/sqlite v1.30.1
)
require (
@@ -57,15 +57,15 @@ require (
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/yuin/goldmark v1.7.1 // indirect
github.com/yuin/goldmark v1.7.4 // indirect
gitlab.com/etke.cc/go/trysmtp v1.1.3 // indirect
go.mau.fi/util v0.4.2 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
go.mau.fi/util v0.5.0 // indirect
golang.org/x/crypto v0.24.0 // indirect
golang.org/x/net v0.26.0 // indirect
golang.org/x/sys v0.21.0 // indirect
golang.org/x/text v0.16.0 // indirect
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect
modernc.org/libc v1.50.7 // indirect
modernc.org/libc v1.54.1 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/strutil v1.2.0 // indirect
+36 -36
View File
@@ -22,10 +22,10 @@ github.com/emersion/go-smtp v0.21.2 h1:OLDgvZKuofk4em9fT5tFG5j4jE1/hXnX75UMvcrL4
github.com/emersion/go-smtp v0.21.2/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps=
github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k=
github.com/getsentry/sentry-go v0.28.1/go.mod h1:1fQZ+7l7eeJ3wYi82q5Hg8GqAPgefRq+FP/QhafYVgg=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-test/deep v1.1.0 h1:WOcxcdHcvdgThNXjw0t76K42FXTU7HpNQWHpA2HHNlg=
@@ -84,8 +84,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rs/xid v1.5.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.32.0 h1:keLypqrlIjaFsbmJOBdB/qvyF8KEtCWHwobLp5l/mQ0=
github.com/rs/zerolog v1.32.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/rs/zerolog v1.33.0 h1:1cU2KZkvPxNyfgEmhHAz/1A9Bz+llsdYzklWFzgp0r8=
github.com/rs/zerolog v1.33.0/go.mod h1:/7mN4D5sKwJLZQ2b/znpjC3/GQWY/xaDXUM0kKWRHss=
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf h1:pvbZ0lM0XWPBqUKqFU8cmavspvIl9nulOYwdy6IFRRo=
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf/go.mod h1:RJID2RhlZKId02nZ62WenDCkgHFerpIOmW0iT7GKmXM=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
@@ -100,10 +100,10 @@ github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/yuin/goldmark v1.7.1 h1:3bajkSilaCbjdKVsKdZjZCLBNPL9pYzrCakKaf4U49U=
github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
gitlab.com/etke.cc/go/env v1.1.0 h1:nbMhZkMu6C8lysRlb5siIiylWuyVkGAgEvwWEqz/82o=
gitlab.com/etke.cc/go/env v1.1.0/go.mod h1:e1l4RM5MA1sc0R1w/RBDAESWRwgo5cOG9gx8BKUn2C4=
github.com/yuin/goldmark v1.7.4 h1:BDXOHExt+A7gwPCJgPIIq7ENvceR7we7rOS9TNoLZeg=
github.com/yuin/goldmark v1.7.4/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
gitlab.com/etke.cc/go/env v1.2.0 h1:mPCk9GTQn5D/HQ9T+nP5OuCSyidgmllDM4OnV9n9UNY=
gitlab.com/etke.cc/go/env v1.2.0/go.mod h1:e1l4RM5MA1sc0R1w/RBDAESWRwgo5cOG9gx8BKUn2C4=
gitlab.com/etke.cc/go/fswatcher v1.0.0 h1:uyiVn+1NVCjOLZrXSZouIDBDZBMwVipS4oYuvAFpPzo=
gitlab.com/etke.cc/go/fswatcher v1.0.0/go.mod h1:MqTOxyhXfvaVZQUL9/Ksbl2ow1PTBVu3eqIldvMq0RE=
gitlab.com/etke.cc/go/healthchecks/v2 v2.2.0 h1:7Y0qm8OAqeJApDNNfGSeA6WFF60q/394gMKinZNbSWE=
@@ -120,47 +120,47 @@ gitlab.com/etke.cc/go/validator v1.0.7 h1:4BGDTa9x68vJhbyn7m8W2yX+2Nb5im9+JLRrgo
gitlab.com/etke.cc/go/validator v1.0.7/go.mod h1:Id0SxRj0J3IPhiKlj0w1plxVLZfHlkwipn7HfRZsDts=
gitlab.com/etke.cc/linkpearl v0.0.0-20240425105001-435ae2720365 h1:MZnAxKJ5Bwv6ZHfC+HUEQyTDC0HPXVB8Q63ISkZ1lHo=
gitlab.com/etke.cc/linkpearl v0.0.0-20240425105001-435ae2720365/go.mod h1:onM3Tge1SUII+oda91/ThDvVvMhkPiSRJ7EOsC2g0yc=
go.mau.fi/util v0.4.2 h1:RR3TOcRHmCF9Bx/3YG4S65MYfa+nV6/rn8qBWW4Mi30=
go.mau.fi/util v0.4.2/go.mod h1:PlAVfUUcPyHPrwnvjkJM9UFcPE7qGPDJqk+Oufa1Gtw=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
go.mau.fi/util v0.5.0 h1:8yELAl+1CDRrwGe9NUmREgVclSs26Z68pTWePHVxuDo=
go.mau.fi/util v0.5.0/go.mod h1:DsJzUrJAG53lCZnnYvq9/mOyLuPScWwYhvETiTrpdP4=
golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
golang.org/x/mod v0.18.0 h1:5+9lSbEzPSdWkH32vYPBwEpX8KwDbM52Ud9xBUvNlb0=
golang.org/x/mod v0.18.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20180911220305-26e67e76b6c3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA=
golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
maunium.net/go/mautrix v0.18.1 h1:a6mUsJixegBNTXUoqC5RQ9gsumIPzKvCubKwF+zmCt4=
maunium.net/go/mautrix v0.18.1/go.mod h1:2oHaq792cSXFGvxLvYw3Gf1L4WVVP4KZcYys5HVk/h8=
modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk=
modernc.org/cc/v4 v4.21.2/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.17.7 h1:+MG+Np7uYtsuPvtoH3KtZ1+pqNiJAOqqqVIxggE1iIo=
modernc.org/ccgo/v4 v4.17.7/go.mod h1:x87xuLLXuJv3Nn5ULTUqJn/HsTMMMiT1Eavo6rz1NiY=
modernc.org/cc/v4 v4.21.4 h1:3Be/Rdo1fpr8GrQ7IVw9OHtplU4gWbb+wNgeoBMmGLQ=
modernc.org/cc/v4 v4.21.4/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
modernc.org/ccgo/v4 v4.19.0 h1:f9K5VdC0nVhHKTFMvhjtZ8TbRgFQbASvE5yO1zs8eC0=
modernc.org/ccgo/v4 v4.19.0/go.mod h1:CfpAl+673iXNwMG/aqcQn+vDcu4Es/YLya7+9RHjTa4=
modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b h1:BnN1t+pb1cy61zbvSUV7SeI0PwosMhlAEi/vBY4qxp8=
modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
modernc.org/libc v1.50.7 h1:25+61e/ZI1e53ynk8dvS/BvWie3lIJPR1KVlTdGkkCg=
modernc.org/libc v1.50.7/go.mod h1:8lr2m1THY5Z3ikGyUc3JhLEQg1oaIBz/AQixw8/eksQ=
modernc.org/libc v1.54.1 h1:5vzs86ANQehsFZXqjxUam20JwgK2eODTOcGMIWcCdg4=
modernc.org/libc v1.54.1/go.mod h1:B0D6klDmSmnq26T1iocn9kzyX6NtbzjuI3+oX/xfvng=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
@@ -169,8 +169,8 @@ modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
modernc.org/sqlite v1.29.10 h1:3u93dz83myFnMilBGCOLbr+HjklS6+5rJLx4q86RDAg=
modernc.org/sqlite v1.29.10/go.mod h1:ItX2a1OVGgNsFh6Dv60JQvGfJfTPHPVpV6DF59akYOA=
modernc.org/sqlite v1.30.1 h1:YFhPVfu2iIgUf9kuA1CR7iiHdcEEsI2i+yjRYHscyxk=
modernc.org/sqlite v1.30.1/go.mod h1:DUmsiWQDaAvU4abhc/N+djlom/L2o8f7gZ95RCvyoLU=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
+13 -1
View File
@@ -10,6 +10,7 @@ import (
"strconv"
"github.com/emersion/go-msgauth/dkim"
"github.com/emersion/go-sasl"
"github.com/emersion/go-smtp"
"github.com/jhillyerd/enmime"
"github.com/rs/zerolog"
@@ -51,7 +52,18 @@ type session struct {
fromRoom id.RoomID
}
func (s *session) AuthPlain(username, password string) error {
func (s *session) AuthMechanisms() []string {
return []string{sasl.Plain}
}
//nolint:unparam // it's a part of the interface
func (s *session) Auth(_ string) (sasl.Server, error) {
return sasl.NewPlainServer(func(identity, username, password string) error {
return s.authPlain(identity, username, password)
}), nil
}
func (s *session) authPlain(_, username, password string) error {
addr := s.conn.Conn().RemoteAddr()
if s.bot.IsBanned(s.ctx, addr) {
return ErrBanned
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2018-2020 Gabriel Vasile
Copyright (c) 2018 Gabriel Vasile
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
-3
View File
@@ -16,9 +16,6 @@
<a href="https://goreportcard.com/report/github.com/gabriel-vasile/mimetype">
<img alt="Go report card" src="https://goreportcard.com/badge/github.com/gabriel-vasile/mimetype">
</a>
<a href="https://codecov.io/gh/gabriel-vasile/mimetype">
<img alt="Code coverage" src="https://codecov.io/gh/gabriel-vasile/mimetype/branch/master/graph/badge.svg?token=qcfJF1kkl2"/>
</a>
<a href="LICENSE">
<img alt="License" src="https://img.shields.io/badge/License-MIT-green.svg">
</a>
+74 -37
View File
@@ -3,6 +3,7 @@ package magic
import (
"bytes"
"encoding/binary"
"strconv"
)
var (
@@ -74,51 +75,87 @@ func CRX(raw []byte, limit uint32) bool {
}
// Tar matches a (t)ape (ar)chive file.
// Tar files are divided into 512 bytes records. First record contains a 257
// bytes header padded with NUL.
func Tar(raw []byte, _ uint32) bool {
// The "magic" header field for files in in UStar (POSIX IEEE P1003.1) archives
// has the prefix "ustar". The values of the remaining bytes in this field vary
// by archiver implementation.
if len(raw) >= 512 && bytes.HasPrefix(raw[257:], []byte{0x75, 0x73, 0x74, 0x61, 0x72}) {
return true
}
const sizeRecord = 512
if len(raw) < 256 {
// The structure of a tar header:
// type TarHeader struct {
// Name [100]byte
// Mode [8]byte
// Uid [8]byte
// Gid [8]byte
// Size [12]byte
// Mtime [12]byte
// Chksum [8]byte
// Linkflag byte
// Linkname [100]byte
// Magic [8]byte
// Uname [32]byte
// Gname [32]byte
// Devmajor [8]byte
// Devminor [8]byte
// }
if len(raw) < sizeRecord {
return false
}
raw = raw[:sizeRecord]
// First 100 bytes of the header represent the file name.
// Check if file looks like Gentoo GLEP binary package.
if bytes.Contains(raw[:100], []byte("/gpkg-1\x00")) {
return false
}
// The older v7 format has no "magic" field, and therefore must be identified
// with heuristics based on legal ranges of values for other header fields:
// https://www.nationalarchives.gov.uk/PRONOM/Format/proFormatSearch.aspx?status=detailReport&id=385&strPageToDisplay=signatures
rules := []struct {
min, max uint8
i int
}{
{0x21, 0xEF, 0},
{0x30, 0x37, 105},
{0x20, 0x37, 106},
{0x00, 0x00, 107},
{0x30, 0x37, 113},
{0x20, 0x37, 114},
{0x00, 0x00, 115},
{0x30, 0x37, 121},
{0x20, 0x37, 122},
{0x00, 0x00, 123},
{0x30, 0x37, 134},
{0x30, 0x37, 146},
{0x30, 0x37, 153},
{0x00, 0x37, 154},
// Get the checksum recorded into the file.
recsum, err := tarParseOctal(raw[148:156])
if err != nil {
return false
}
for _, r := range rules {
if raw[r.i] < r.min || raw[r.i] > r.max {
return false
}
sum1, sum2 := tarChksum(raw)
return recsum == sum1 || recsum == sum2
}
// tarParseOctal converts octal string to decimal int.
func tarParseOctal(b []byte) (int64, error) {
// Because unused fields are filled with NULs, we need to skip leading NULs.
// Fields may also be padded with spaces or NULs.
// So we remove leading and trailing NULs and spaces to be sure.
b = bytes.Trim(b, " \x00")
if len(b) == 0 {
return 0, nil
}
x, err := strconv.ParseUint(tarParseString(b), 8, 64)
if err != nil {
return 0, err
}
return int64(x), nil
}
// tarParseString converts a NUL ended bytes slice to a string.
func tarParseString(b []byte) string {
if i := bytes.IndexByte(b, 0); i >= 0 {
return string(b[:i])
}
return string(b)
}
for _, i := range []uint8{135, 147, 155} {
if raw[i] != 0x00 && raw[i] != 0x20 {
return false
// tarChksum computes the checksum for the header block b.
// The actual checksum is written to same b block after it has been calculated.
// Before calculation the bytes from b reserved for checksum have placeholder
// value of ASCII space 0x20.
// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
// signed byte values. We compute and return both.
func tarChksum(b []byte) (unsigned, signed int64) {
for i, c := range b {
if 148 <= i && i < 156 {
c = ' ' // Treat the checksum field itself as all spaces.
}
unsigned += int64(c)
signed += int64(int8(c))
}
return true
return unsigned, signed
}
+4 -1
View File
@@ -153,8 +153,11 @@ func ftyp(sigs ...[]byte) Detector {
if len(raw) < 12 {
return false
}
if !bytes.Equal(raw[4:8], []byte("ftyp")) {
return false
}
for _, s := range sigs {
if bytes.Equal(raw[4:12], append([]byte("ftyp"), s...)) {
if bytes.Equal(raw[8:12], s) {
return true
}
}
+25 -19
View File
@@ -1,7 +1,6 @@
package magic
import (
"bufio"
"bytes"
"strings"
"time"
@@ -234,9 +233,10 @@ func GeoJSON(raw []byte, limit uint32) bool {
// types.
func NdJSON(raw []byte, limit uint32) bool {
lCount, hasObjOrArr := 0, false
sc := bufio.NewScanner(dropLastLine(raw, limit))
for sc.Scan() {
l := sc.Bytes()
raw = dropLastLine(raw, limit)
var l []byte
for len(raw) != 0 {
l, raw = scanLine(raw)
// Empty lines are allowed in NDJSON.
if l = trimRWS(trimLWS(l)); len(l) == 0 {
continue
@@ -301,20 +301,15 @@ func Svg(raw []byte, limit uint32) bool {
}
// Srt matches a SubRip file.
func Srt(in []byte, _ uint32) bool {
s := bufio.NewScanner(bytes.NewReader(in))
if !s.Scan() {
return false
}
// First line must be 1.
if s.Text() != "1" {
return false
}
func Srt(raw []byte, _ uint32) bool {
line, raw := scanLine(raw)
if !s.Scan() {
// First line must be 1.
if string(line) != "1" {
return false
}
secondLine := s.Text()
line, raw = scanLine(raw)
secondLine := string(line)
// Timestamp format (e.g: 00:02:16,612 --> 00:02:19,376) limits secondLine
// length to exactly 29 characters.
if len(secondLine) != 29 {
@@ -325,14 +320,12 @@ func Srt(in []byte, _ uint32) bool {
if strings.Contains(secondLine, ".") {
return false
}
// For Go <1.17, comma is not recognised as a decimal separator by `time.Parse`.
secondLine = strings.ReplaceAll(secondLine, ",", ".")
// Second line must be a time range.
ts := strings.Split(secondLine, " --> ")
if len(ts) != 2 {
return false
}
const layout = "15:04:05.000"
const layout = "15:04:05,000"
t0, err := time.Parse(layout, ts[0])
if err != nil {
return false
@@ -345,8 +338,9 @@ func Srt(in []byte, _ uint32) bool {
return false
}
line, _ = scanLine(raw)
// A third line must exist and not be empty. This is the actual subtitle text.
return s.Scan() && len(s.Bytes()) != 0
return len(line) != 0
}
// Vtt matches a Web Video Text Tracks (WebVTT) file. See
@@ -373,3 +367,15 @@ func Vtt(raw []byte, limit uint32) bool {
return bytes.Equal(raw, []byte{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) || // UTF-8 BOM and "WEBVTT"
bytes.Equal(raw, []byte{0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) // "WEBVTT"
}
// dropCR drops a terminal \r from the data.
func dropCR(data []byte) []byte {
if len(data) > 0 && data[len(data)-1] == '\r' {
return data[0 : len(data)-1]
}
return data
}
func scanLine(b []byte) (line, remainder []byte) {
line, remainder, _ = bytes.Cut(b, []byte("\n"))
return dropCR(line), remainder
}
+8 -14
View File
@@ -18,7 +18,7 @@ func Tsv(raw []byte, limit uint32) bool {
}
func sv(in []byte, comma rune, limit uint32) bool {
r := csv.NewReader(dropLastLine(in, limit))
r := csv.NewReader(bytes.NewReader(dropLastLine(in, limit)))
r.Comma = comma
r.ReuseRecord = true
r.LazyQuotes = true
@@ -44,20 +44,14 @@ func sv(in []byte, comma rune, limit uint32) bool {
// mimetype limits itself to ReadLimit bytes when performing a detection.
// This means, for file formats like CSV for NDJSON, the last line of the input
// can be an incomplete line.
func dropLastLine(b []byte, cutAt uint32) io.Reader {
if cutAt == 0 {
return bytes.NewReader(b)
func dropLastLine(b []byte, readLimit uint32) []byte {
if readLimit == 0 || uint32(len(b)) < readLimit {
return b
}
if uint32(len(b)) >= cutAt {
for i := cutAt - 1; i > 0; i-- {
if b[i] == '\n' {
return bytes.NewReader(b[:i])
}
for i := len(b) - 1; i > 0; i-- {
if b[i] == '\n' {
return b[:i]
}
// No newline was found between the 0 index and cutAt.
return bytes.NewReader(b[:cutAt])
}
return bytes.NewReader(b)
return b
}
+5 -3
View File
@@ -7,14 +7,15 @@ package mimetype
import (
"io"
"io/ioutil"
"mime"
"os"
"sync/atomic"
)
var defaultLimit uint32 = 3072
// readLimit is the maximum number of bytes from the input used when detecting.
var readLimit uint32 = 3072
var readLimit uint32 = defaultLimit
// Detect returns the MIME type found from the provided byte slice.
//
@@ -48,7 +49,7 @@ func DetectReader(r io.Reader) (*MIME, error) {
// Using atomic because readLimit can be written at the same time in other goroutine.
l := atomic.LoadUint32(&readLimit)
if l == 0 {
in, err = ioutil.ReadAll(r)
in, err = io.ReadAll(r)
if err != nil {
return errMIME, err
}
@@ -103,6 +104,7 @@ func EqualsAny(s string, mimes ...string) bool {
// SetLimit sets the maximum number of bytes read from input when detecting the MIME type.
// Increasing the limit provides better detection for file formats which store
// their magical numbers towards the end of the file: docx, pptx, xlsx, etc.
// During detection data is read in a single block of size limit, i.e. it is not buffered.
// A limit of 0 means the whole input file will be used.
func SetLimit(limit uint32) {
// Using atomic because readLimit can be read at the same time in other goroutine.
+29
View File
@@ -1,5 +1,34 @@
# Changelog
## 0.28.1
The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.28.1.
### Bug Fixes
- Implement `http.ResponseWriter` to hook into various parts of the response process ([#837](https://github.com/getsentry/sentry-go/pull/837))
## 0.28.0
The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.28.0.
### Features
- Add a `Fiber` performance tracing & error reporting integration ([#795](https://github.com/getsentry/sentry-go/pull/795))
- Add performance tracing to the `Echo` integration ([#722](https://github.com/getsentry/sentry-go/pull/722))
- Add performance tracing to the `FastHTTP` integration ([#732](https://github.com/getsentry/sentry-go/pull/723))
- Add performance tracing to the `Iris` integration ([#809](https://github.com/getsentry/sentry-go/pull/809))
- Add performance tracing to the `Negroni` integration ([#808](https://github.com/getsentry/sentry-go/pull/808))
- Add `FailureIssueThreshold` & `RecoveryThreshold` to `MonitorConfig` ([#775](https://github.com/getsentry/sentry-go/pull/775))
- Use `errors.Unwrap()` to create exception groups ([#792](https://github.com/getsentry/sentry-go/pull/792))
- Add support for matching on strings for `ClientOptions.IgnoreErrors` & `ClientOptions.IgnoreTransactions` ([#819](https://github.com/getsentry/sentry-go/pull/819))
- Add `http.request.method` attribute for performance span data ([#786](https://github.com/getsentry/sentry-go/pull/786))
- Accept `interface{}` for span data values ([#784](https://github.com/getsentry/sentry-go/pull/784))
### Bug Fixes
- Fix missing stack trace for parsing error in `logrusentry` ([#689](https://github.com/getsentry/sentry-go/pull/689))
## 0.27.0
The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.27.0.
-2
View File
@@ -13,7 +13,6 @@
[![Build Status](https://github.com/getsentry/sentry-go/workflows/go-workflow/badge.svg)](https://github.com/getsentry/sentry-go/actions?query=workflow%3Ago-workflow)
[![Go Report Card](https://goreportcard.com/badge/github.com/getsentry/sentry-go)](https://goreportcard.com/report/github.com/getsentry/sentry-go)
[![Discord](https://img.shields.io/discord/621778831602221064)](https://discord.gg/Ww9hbqr)
[![GoDoc](https://godoc.org/github.com/getsentry/sentry-go?status.svg)](https://godoc.org/github.com/getsentry/sentry-go)
[![go.dev](https://img.shields.io/badge/go.dev-pkg-007d9c.svg?style=flat)](https://pkg.go.dev/github.com/getsentry/sentry-go)
`sentry-go` provides a Sentry client implementation for the Go programming
@@ -85,7 +84,6 @@ checkout the official documentation:
- [Bug Tracker](https://github.com/getsentry/sentry-go/issues)
- [GitHub Project](https://github.com/getsentry/sentry-go)
- [![GoDoc](https://godoc.org/github.com/getsentry/sentry-go?status.svg)](https://godoc.org/github.com/getsentry/sentry-go)
- [![go.dev](https://img.shields.io/badge/go.dev-pkg-007d9c.svg?style=flat)](https://pkg.go.dev/github.com/getsentry/sentry-go)
- [![Documentation](https://img.shields.io/badge/documentation-sentry.io-green.svg)](https://docs.sentry.io/platforms/go/)
- [![Discussions](https://img.shields.io/github/discussions/getsentry/sentry-go.svg)](https://github.com/getsentry/sentry-go/discussions)
+4
View File
@@ -87,6 +87,10 @@ type MonitorConfig struct { //nolint: maligned // prefer readability over optima
// A tz database string representing the timezone which the monitor's execution schedule is in.
// See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
Timezone string `json:"timezone,omitempty"`
// The number of consecutive failed check-ins it takes before an issue is created.
FailureIssueThreshold int64 `json:"failure_issue_threshold,omitempty"`
// The number of consecutive OK check-ins it takes before an issue is resolved.
RecoveryThreshold int64 `json:"recovery_threshold,omitempty"`
}
type CheckIn struct { //nolint: maligned // prefer readability over optimal memory layout
+1 -2
View File
@@ -90,11 +90,10 @@ func NewDsn(rawURL string) (*Dsn, error) {
// Port
var port int
if parsedURL.Port() != "" {
parsedPort, err := strconv.Atoi(parsedURL.Port())
port, err = strconv.Atoi(parsedURL.Port())
if err != nil {
return nil, &DsnParseError{"invalid port"}
}
port = parsedPort
} else {
port = scheme.defaultPort()
}
+2 -2
View File
@@ -140,7 +140,7 @@ func (iei *ignoreErrorsIntegration) processor(event *Event, _ *EventHint) *Event
for _, suspect := range suspects {
for _, pattern := range iei.ignoreErrors {
if pattern.Match([]byte(suspect)) {
if pattern.Match([]byte(suspect)) || strings.Contains(suspect, pattern.String()) {
Logger.Printf("Event dropped due to being matched by `IgnoreErrors` option."+
"| Value matched: %s | Filter used: %s", suspect, pattern)
return nil
@@ -202,7 +202,7 @@ func (iei *ignoreTransactionsIntegration) processor(event *Event, _ *EventHint)
}
for _, pattern := range iei.ignoreTransactions {
if pattern.Match([]byte(suspect)) {
if pattern.Match([]byte(suspect)) || strings.Contains(suspect, pattern.String()) {
Logger.Printf("Transaction dropped due to being matched by `IgnoreTransactions` option."+
"| Value matched: %s | Filter used: %s", suspect, pattern)
return nil
+64 -28
View File
@@ -3,6 +3,7 @@ package sentry
import (
"context"
"encoding/json"
"errors"
"fmt"
"net"
"net/http"
@@ -24,6 +25,9 @@ const profileType = "profile"
// checkInType is the type of a check in event.
const checkInType = "check_in"
// metricType is the type of a metric event.
const metricType = "statsd"
// Level marks the severity of the event.
type Level string
@@ -36,15 +40,6 @@ const (
LevelFatal Level = "fatal"
)
func getSensitiveHeaders() map[string]bool {
return map[string]bool{
"Authorization": true,
"Cookie": true,
"X-Forwarded-For": true,
"X-Real-Ip": true,
}
}
// SdkInfo contains all metadata about about the SDK being used.
type SdkInfo struct {
Name string `json:"name,omitempty"`
@@ -170,6 +165,13 @@ type Request struct {
Env map[string]string `json:"env,omitempty"`
}
var sensitiveHeaders = map[string]struct{}{
"Authorization": {},
"Cookie": {},
"X-Forwarded-For": {},
"X-Real-Ip": {},
}
// NewRequest returns a new Sentry Request from the given http.Request.
//
// NewRequest avoids operations that depend on network access. In particular, it
@@ -200,7 +202,6 @@ func NewRequest(r *http.Request) *Request {
env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port}
}
} else {
sensitiveHeaders := getSensitiveHeaders()
for k, v := range r.Header {
if _, ok := sensitiveHeaders[k]; !ok {
headers[k] = strings.Join(v, ",")
@@ -222,11 +223,15 @@ func NewRequest(r *http.Request) *Request {
// Mechanism is the mechanism by which an exception was generated and handled.
type Mechanism struct {
Type string `json:"type,omitempty"`
Description string `json:"description,omitempty"`
HelpLink string `json:"help_link,omitempty"`
Handled *bool `json:"handled,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
Type string `json:"type,omitempty"`
Description string `json:"description,omitempty"`
HelpLink string `json:"help_link,omitempty"`
Source string `json:"source,omitempty"`
Handled *bool `json:"handled,omitempty"`
ParentID *int `json:"parent_id,omitempty"`
ExceptionID int `json:"exception_id"`
IsExceptionGroup bool `json:"is_exception_group,omitempty"`
Data map[string]any `json:"data,omitempty"`
}
// SetUnhandled indicates that the exception is an unhandled exception, i.e.
@@ -318,6 +323,7 @@ type Event struct {
Exception []Exception `json:"exception,omitempty"`
DebugMeta *DebugMeta `json:"debug_meta,omitempty"`
Attachments []*Attachment `json:"-"`
Metrics []Metric `json:"-"`
// The fields below are only relevant for transactions.
@@ -339,27 +345,43 @@ type Event struct {
// SetException appends the unwrapped errors to the event's exception list.
//
// maxErrorDepth is the maximum depth of the error chain we will look
// into while unwrapping the errors.
// into while unwrapping the errors. If maxErrorDepth is -1, we will
// unwrap all errors in the chain.
func (e *Event) SetException(exception error, maxErrorDepth int) {
err := exception
if err == nil {
if exception == nil {
return
}
for i := 0; i < maxErrorDepth && err != nil; i++ {
err := exception
for i := 0; err != nil && (i < maxErrorDepth || maxErrorDepth == -1); i++ {
// Add the current error to the exception slice with its details
e.Exception = append(e.Exception, Exception{
Value: err.Error(),
Type: reflect.TypeOf(err).String(),
Stacktrace: ExtractStacktrace(err),
})
switch previous := err.(type) {
case interface{ Unwrap() error }:
err = previous.Unwrap()
case interface{ Cause() error }:
err = previous.Cause()
default:
err = nil
// Attempt to unwrap the error using the standard library's Unwrap method.
// If errors.Unwrap returns nil, it means either there is no error to unwrap,
// or the error does not implement the Unwrap method.
unwrappedErr := errors.Unwrap(err)
if unwrappedErr != nil {
// The error was successfully unwrapped using the standard library's Unwrap method.
err = unwrappedErr
continue
}
cause, ok := err.(interface{ Cause() error })
if !ok {
// We cannot unwrap the error further.
break
}
// The error implements the Cause method, indicating it may have been wrapped
// using the github.com/pkg/errors package.
err = cause.Cause()
}
// Add a trace of the current stack to the most recent error in a chain if
@@ -370,8 +392,23 @@ func (e *Event) SetException(exception error, maxErrorDepth int) {
e.Exception[0].Stacktrace = NewStacktrace()
}
if len(e.Exception) <= 1 {
return
}
// event.Exception should be sorted such that the most recent error is last.
reverse(e.Exception)
for i := range e.Exception {
e.Exception[i].Mechanism = &Mechanism{
IsExceptionGroup: true,
ExceptionID: i,
}
if i == 0 {
continue
}
e.Exception[i].Mechanism.ParentID = Pointer(i - 1)
}
}
// TODO: Event.Contexts map[string]interface{} => map[string]EventContext,
@@ -492,13 +529,12 @@ func (e *Event) checkInMarshalJSON() ([]byte, error) {
// NewEvent creates a new Event.
func NewEvent() *Event {
event := Event{
return &Event{
Contexts: make(map[string]Context),
Extra: make(map[string]interface{}),
Tags: make(map[string]string),
Modules: make(map[string]string),
}
return &event
}
// Thread specifies threads that were running at the time of an event.
+8 -9
View File
@@ -32,15 +32,14 @@ var knownCategories = map[Category]struct{}{
// String returns the category formatted for debugging.
func (c Category) String() string {
switch c {
case "":
if c == "" {
return "CategoryAll"
default:
caser := cases.Title(language.English)
rv := "Category"
for _, w := range strings.Fields(string(c)) {
rv += caser.String(w)
}
return rv
}
caser := cases.Title(language.English)
rv := "Category"
for _, w := range strings.Fields(string(c)) {
rv += caser.String(w)
}
return rv
}
+427
View File
@@ -0,0 +1,427 @@
package sentry
import (
"fmt"
"hash/crc32"
"math"
"regexp"
"sort"
"strings"
)
type (
NumberOrString interface {
int | string
}
void struct{}
)
var (
member void
keyRegex = regexp.MustCompile(`[^a-zA-Z0-9_/.-]+`)
valueRegex = regexp.MustCompile(`[^\w\d\s_:/@\.{}\[\]$-]+`)
unitRegex = regexp.MustCompile(`[^a-z]+`)
)
type MetricUnit struct {
unit string
}
func (m MetricUnit) toString() string {
return m.unit
}
func NanoSecond() MetricUnit {
return MetricUnit{
"nanosecond",
}
}
func MicroSecond() MetricUnit {
return MetricUnit{
"microsecond",
}
}
func MilliSecond() MetricUnit {
return MetricUnit{
"millisecond",
}
}
func Second() MetricUnit {
return MetricUnit{
"second",
}
}
func Minute() MetricUnit {
return MetricUnit{
"minute",
}
}
func Hour() MetricUnit {
return MetricUnit{
"hour",
}
}
func Day() MetricUnit {
return MetricUnit{
"day",
}
}
func Week() MetricUnit {
return MetricUnit{
"week",
}
}
func Bit() MetricUnit {
return MetricUnit{
"bit",
}
}
func Byte() MetricUnit {
return MetricUnit{
"byte",
}
}
func KiloByte() MetricUnit {
return MetricUnit{
"kilobyte",
}
}
func KibiByte() MetricUnit {
return MetricUnit{
"kibibyte",
}
}
func MegaByte() MetricUnit {
return MetricUnit{
"megabyte",
}
}
func MebiByte() MetricUnit {
return MetricUnit{
"mebibyte",
}
}
func GigaByte() MetricUnit {
return MetricUnit{
"gigabyte",
}
}
func GibiByte() MetricUnit {
return MetricUnit{
"gibibyte",
}
}
func TeraByte() MetricUnit {
return MetricUnit{
"terabyte",
}
}
func TebiByte() MetricUnit {
return MetricUnit{
"tebibyte",
}
}
func PetaByte() MetricUnit {
return MetricUnit{
"petabyte",
}
}
func PebiByte() MetricUnit {
return MetricUnit{
"pebibyte",
}
}
func ExaByte() MetricUnit {
return MetricUnit{
"exabyte",
}
}
func ExbiByte() MetricUnit {
return MetricUnit{
"exbibyte",
}
}
func Ratio() MetricUnit {
return MetricUnit{
"ratio",
}
}
func Percent() MetricUnit {
return MetricUnit{
"percent",
}
}
func CustomUnit(unit string) MetricUnit {
return MetricUnit{
unitRegex.ReplaceAllString(unit, ""),
}
}
type Metric interface {
GetType() string
GetTags() map[string]string
GetKey() string
GetUnit() string
GetTimestamp() int64
SerializeValue() string
SerializeTags() string
}
type abstractMetric struct {
key string
unit MetricUnit
tags map[string]string
// A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC).
timestamp int64
}
func (am abstractMetric) GetTags() map[string]string {
return am.tags
}
func (am abstractMetric) GetKey() string {
return am.key
}
func (am abstractMetric) GetUnit() string {
return am.unit.toString()
}
func (am abstractMetric) GetTimestamp() int64 {
return am.timestamp
}
func (am abstractMetric) SerializeTags() string {
var sb strings.Builder
values := make([]string, 0, len(am.tags))
for k := range am.tags {
values = append(values, k)
}
sortSlice(values)
for _, key := range values {
val := sanitizeValue(am.tags[key])
key = sanitizeKey(key)
sb.WriteString(fmt.Sprintf("%s:%s,", key, val))
}
s := sb.String()
if len(s) > 0 {
s = s[:len(s)-1]
}
return s
}
// Counter Metric.
type CounterMetric struct {
value float64
abstractMetric
}
func (c *CounterMetric) Add(value float64) {
c.value += value
}
func (c CounterMetric) GetType() string {
return "c"
}
func (c CounterMetric) SerializeValue() string {
return fmt.Sprintf(":%v", c.value)
}
// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC).
func NewCounterMetric(key string, unit MetricUnit, tags map[string]string, timestamp int64, value float64) CounterMetric {
am := abstractMetric{
key,
unit,
tags,
timestamp,
}
return CounterMetric{
value,
am,
}
}
// Distribution Metric.
type DistributionMetric struct {
values []float64
abstractMetric
}
func (d *DistributionMetric) Add(value float64) {
d.values = append(d.values, value)
}
func (d DistributionMetric) GetType() string {
return "d"
}
func (d DistributionMetric) SerializeValue() string {
var sb strings.Builder
for _, el := range d.values {
sb.WriteString(fmt.Sprintf(":%v", el))
}
return sb.String()
}
// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC).
func NewDistributionMetric(key string, unit MetricUnit, tags map[string]string, timestamp int64, value float64) DistributionMetric {
am := abstractMetric{
key,
unit,
tags,
timestamp,
}
return DistributionMetric{
[]float64{value},
am,
}
}
// Gauge Metric.
type GaugeMetric struct {
last float64
min float64
max float64
sum float64
count float64
abstractMetric
}
func (g *GaugeMetric) Add(value float64) {
g.last = value
g.min = math.Min(g.min, value)
g.max = math.Max(g.max, value)
g.sum += value
g.count++
}
func (g GaugeMetric) GetType() string {
return "g"
}
func (g GaugeMetric) SerializeValue() string {
return fmt.Sprintf(":%v:%v:%v:%v:%v", g.last, g.min, g.max, g.sum, g.count)
}
// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC).
func NewGaugeMetric(key string, unit MetricUnit, tags map[string]string, timestamp int64, value float64) GaugeMetric {
am := abstractMetric{
key,
unit,
tags,
timestamp,
}
return GaugeMetric{
value, // last
value, // min
value, // max
value, // sum
value, // count
am,
}
}
// Set Metric.
type SetMetric[T NumberOrString] struct {
values map[T]void
abstractMetric
}
func (s *SetMetric[T]) Add(value T) {
s.values[value] = member
}
func (s SetMetric[T]) GetType() string {
return "s"
}
func (s SetMetric[T]) SerializeValue() string {
_hash := func(s string) uint32 {
return crc32.ChecksumIEEE([]byte(s))
}
values := make([]T, 0, len(s.values))
for k := range s.values {
values = append(values, k)
}
sortSlice(values)
var sb strings.Builder
for _, el := range values {
switch any(el).(type) {
case int:
sb.WriteString(fmt.Sprintf(":%v", el))
case string:
s := fmt.Sprintf("%v", el)
sb.WriteString(fmt.Sprintf(":%d", _hash(s)))
}
}
return sb.String()
}
// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC).
func NewSetMetric[T NumberOrString](key string, unit MetricUnit, tags map[string]string, timestamp int64, value T) SetMetric[T] {
am := abstractMetric{
key,
unit,
tags,
timestamp,
}
return SetMetric[T]{
map[T]void{
value: member,
},
am,
}
}
func sanitizeKey(s string) string {
return keyRegex.ReplaceAllString(s, "_")
}
func sanitizeValue(s string) string {
return valueRegex.ReplaceAllString(s, "")
}
type Ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string
}
func sortSlice[T Ordered](s []T) {
sort.Slice(s, func(i, j int) bool {
return s[i] < s[j]
})
}
+11 -12
View File
@@ -6,7 +6,7 @@ import (
)
// The version of the SDK.
const SDKVersion = "0.27.0"
const SDKVersion = "0.28.1"
// apiVersion is the minimum version of the Sentry API compatible with the
// sentry-go SDK.
@@ -72,18 +72,17 @@ func Recover() *EventID {
// RecoverWithContext captures a panic and passes relevant context object.
func RecoverWithContext(ctx context.Context) *EventID {
if err := recover(); err != nil {
var hub *Hub
if HasHubOnContext(ctx) {
hub = GetHubFromContext(ctx)
} else {
hub = CurrentHub()
}
return hub.RecoverWithContext(ctx, err)
err := recover()
if err == nil {
return nil
}
return nil
hub := GetHubFromContext(ctx)
if hub == nil {
hub = CurrentHub()
}
return hub.RecoverWithContext(ctx, err)
}
// WithScope is a shorthand for CurrentHub().WithScope.
+20 -15
View File
@@ -7,8 +7,8 @@ import (
// Checks whether the transaction should be profiled (according to ProfilesSampleRate)
// and starts a profiler if so.
func (span *Span) sampleTransactionProfile() {
var sampleRate = span.clientOptions().ProfilesSampleRate
func (s *Span) sampleTransactionProfile() {
var sampleRate = s.clientOptions().ProfilesSampleRate
switch {
case sampleRate < 0.0 || sampleRate > 1.0:
Logger.Printf("Skipping transaction profiling: ProfilesSampleRate out of range [0.0, 1.0]: %f\n", sampleRate)
@@ -19,7 +19,7 @@ func (span *Span) sampleTransactionProfile() {
if globalProfiler == nil {
Logger.Println("Skipping transaction profiling: the profiler couldn't be started")
} else {
span.collectProfile = collectTransactionProfile
s.collectProfile = collectTransactionProfile
}
}
}
@@ -69,22 +69,27 @@ func (info *profileInfo) UpdateFromEvent(event *Event) {
info.Dist = event.Dist
info.Transaction.ID = event.EventID
getStringFromContext := func(context map[string]interface{}, originalValue, key string) string {
v, ok := context[key]
if !ok {
return originalValue
}
if s, ok := v.(string); ok {
return s
}
return originalValue
}
if runtimeContext, ok := event.Contexts["runtime"]; ok {
if value, ok := runtimeContext["name"]; !ok {
info.Runtime.Name = value.(string)
}
if value, ok := runtimeContext["version"]; !ok {
info.Runtime.Version = value.(string)
}
info.Runtime.Name = getStringFromContext(runtimeContext, info.Runtime.Name, "name")
info.Runtime.Version = getStringFromContext(runtimeContext, info.Runtime.Version, "version")
}
if osContext, ok := event.Contexts["os"]; ok {
if value, ok := osContext["name"]; !ok {
info.OS.Name = value.(string)
}
info.OS.Name = getStringFromContext(osContext, info.OS.Name, "name")
}
if deviceContext, ok := event.Contexts["device"]; ok {
if value, ok := deviceContext["arch"]; !ok {
info.Device.Architecture = value.(string)
}
info.Device.Architecture = getStringFromContext(deviceContext, info.Device.Architecture, "arch")
}
}
+7 -3
View File
@@ -169,11 +169,11 @@ func StartSpan(ctx context.Context, operation string, options ...SpanOption) *Sp
span.Sampled = span.sample()
span.recorder = &spanRecorder{}
if hasParent {
span.recorder = parent.spanRecorder()
} else {
span.recorder = &spanRecorder{}
}
span.recorder.record(&span)
hub := hubFromContext(ctx)
@@ -226,7 +226,11 @@ func (s *Span) SetTag(name, value string) {
// SetData sets a data on the span. It is recommended to use SetData instead of
// accessing the data map directly as SetData takes care of initializing the map
// when necessary.
func (s *Span) SetData(name, value string) {
func (s *Span) SetData(name string, value interface{}) {
if value == nil {
return
}
s.mu.Lock()
defer s.mu.Unlock()
+98 -10
View File
@@ -2,6 +2,7 @@ package sentry
import (
"bytes"
"context"
"crypto/tls"
"encoding/json"
"errors"
@@ -94,6 +95,55 @@ func getRequestBodyFromEvent(event *Event) []byte {
return nil
}
func marshalMetrics(metrics []Metric) []byte {
var b bytes.Buffer
for i, metric := range metrics {
b.WriteString(metric.GetKey())
if unit := metric.GetUnit(); unit != "" {
b.WriteString(fmt.Sprintf("@%s", unit))
}
b.WriteString(fmt.Sprintf("%s|%s", metric.SerializeValue(), metric.GetType()))
if serializedTags := metric.SerializeTags(); serializedTags != "" {
b.WriteString(fmt.Sprintf("|#%s", serializedTags))
}
b.WriteString(fmt.Sprintf("|T%d", metric.GetTimestamp()))
if i < len(metrics)-1 {
b.WriteString("\n")
}
}
return b.Bytes()
}
func encodeMetric(enc *json.Encoder, b io.Writer, metrics []Metric) error {
body := marshalMetrics(metrics)
// Item header
err := enc.Encode(struct {
Type string `json:"type"`
Length int `json:"length"`
}{
Type: metricType,
Length: len(body),
})
if err != nil {
return err
}
// metric payload
if _, err = b.Write(body); err != nil {
return err
}
// "Envelopes should be terminated with a trailing newline."
//
// [1]: https://develop.sentry.dev/sdk/envelopes/#envelopes
if _, err := b.Write([]byte("\n")); err != nil {
return err
}
return err
}
func encodeAttachment(enc *json.Encoder, b io.Writer, attachment *Attachment) error {
// Attachment header
err := enc.Encode(struct {
@@ -175,11 +225,15 @@ func envelopeFromBody(event *Event, dsn *Dsn, sentAt time.Time, body json.RawMes
return nil, err
}
if event.Type == transactionType || event.Type == checkInType {
switch event.Type {
case transactionType, checkInType:
err = encodeEnvelopeItem(enc, event.Type, body)
} else {
case metricType:
err = encodeMetric(enc, &b, event.Metrics)
default:
err = encodeEnvelopeItem(enc, eventType, body)
}
if err != nil {
return nil, err
}
@@ -206,7 +260,7 @@ func envelopeFromBody(event *Event, dsn *Dsn, sentAt time.Time, body json.RawMes
return &b, nil
}
func getRequestFromEvent(event *Event, dsn *Dsn) (r *http.Request, err error) {
func getRequestFromEvent(ctx context.Context, event *Event, dsn *Dsn) (r *http.Request, err error) {
defer func() {
if r != nil {
r.Header.Set("User-Agent", fmt.Sprintf("%s/%s", event.Sdk.Name, event.Sdk.Version))
@@ -233,7 +287,13 @@ func getRequestFromEvent(event *Event, dsn *Dsn) (r *http.Request, err error) {
if err != nil {
return nil, err
}
return http.NewRequest(
if ctx == nil {
ctx = context.Background()
}
return http.NewRequestWithContext(
ctx,
http.MethodPost,
dsn.GetAPIURL().String(),
envelope,
@@ -344,8 +404,13 @@ func (t *HTTPTransport) Configure(options ClientOptions) {
})
}
// SendEvent assembles a new packet out of Event and sends it to remote server.
// SendEvent assembles a new packet out of Event and sends it to the remote server.
func (t *HTTPTransport) SendEvent(event *Event) {
t.SendEventWithContext(context.Background(), event)
}
// SendEventWithContext assembles a new packet out of Event and sends it to the remote server.
func (t *HTTPTransport) SendEventWithContext(ctx context.Context, event *Event) {
if t.dsn == nil {
return
}
@@ -356,7 +421,7 @@ func (t *HTTPTransport) SendEvent(event *Event) {
return
}
request, err := getRequestFromEvent(event, t.dsn)
request, err := getRequestFromEvent(ctx, event, t.dsn)
if err != nil {
return
}
@@ -478,6 +543,13 @@ func (t *HTTPTransport) worker() {
Logger.Printf("There was an issue with sending an event: %v", err)
continue
}
if response.StatusCode >= 400 && response.StatusCode <= 599 {
b, err := io.ReadAll(response.Body)
if err != nil {
Logger.Printf("Error while reading response code: %v", err)
}
Logger.Printf("Sending %s failed with the following error: %s", eventType, string(b))
}
t.mu.Lock()
t.limits.Merge(ratelimit.FromResponse(response))
t.mu.Unlock()
@@ -567,8 +639,13 @@ func (t *HTTPSyncTransport) Configure(options ClientOptions) {
}
}
// SendEvent assembles a new packet out of Event and sends it to remote server.
// SendEvent assembles a new packet out of Event and sends it to the remote server.
func (t *HTTPSyncTransport) SendEvent(event *Event) {
t.SendEventWithContext(context.Background(), event)
}
// SendEventWithContext assembles a new packet out of Event and sends it to the remote server.
func (t *HTTPSyncTransport) SendEventWithContext(ctx context.Context, event *Event) {
if t.dsn == nil {
return
}
@@ -577,15 +654,18 @@ func (t *HTTPSyncTransport) SendEvent(event *Event) {
return
}
request, err := getRequestFromEvent(event, t.dsn)
request, err := getRequestFromEvent(ctx, event, t.dsn)
if err != nil {
return
}
var eventType string
if event.Type == transactionType {
switch {
case event.Type == transactionType:
eventType = "transaction"
} else {
case event.Type == metricType:
eventType = metricType
default:
eventType = fmt.Sprintf("%s event", event.Level)
}
Logger.Printf(
@@ -601,6 +681,14 @@ func (t *HTTPSyncTransport) SendEvent(event *Event) {
Logger.Printf("There was an issue with sending an event: %v", err)
return
}
if response.StatusCode >= 400 && response.StatusCode <= 599 {
b, err := io.ReadAll(response.Body)
if err != nil {
Logger.Printf("Error while reading response code: %v", err)
}
Logger.Printf("Sending %s failed with the following error: %s", eventType, string(b))
}
t.mu.Lock()
t.limits.Merge(ratelimit.FromResponse(response))
t.mu.Unlock()
+4
View File
@@ -112,3 +112,7 @@ func revisionFromBuildInfo(info *debug.BuildInfo) string {
return ""
}
func Pointer[T any](v T) *T {
return &v
}
+7 -11
View File
@@ -60,7 +60,7 @@ func main() {
// Output: {"time":1516134303,"level":"debug","message":"hello world"}
```
> Note: By default log writes to `os.Stderr`
> Note: The default log level for `log.Print` is *debug*
> Note: The default log level for `log.Print` is *trace*
### Contextual Logging
@@ -412,15 +412,7 @@ Equivalent of `Lshortfile`:
```go
zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
short := file
for i := len(file) - 1; i > 0; i-- {
if file[i] == '/' {
short = file[i+1:]
break
}
}
file = short
return file + ":" + strconv.Itoa(line)
return filepath.Base(file) + ":" + strconv.Itoa(line)
}
log.Logger = log.With().Caller().Logger()
log.Info().Msg("hello world")
@@ -646,10 +638,14 @@ Some settings can be changed and will be applied to all loggers:
* `zerolog.LevelFieldName`: Can be set to customize level field name.
* `zerolog.MessageFieldName`: Can be set to customize message field name.
* `zerolog.ErrorFieldName`: Can be set to customize `Err` field name.
* `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with `zerolog.TimeFormatUnix`, `zerolog.TimeFormatUnixMs` or `zerolog.TimeFormatUnixMicro`, times are formated as UNIX timestamp.
* `zerolog.TimeFieldFormat`: Can be set to customize `Time` field value formatting. If set with `zerolog.TimeFormatUnix`, `zerolog.TimeFormatUnixMs` or `zerolog.TimeFormatUnixMicro`, times are formatted as UNIX timestamp.
* `zerolog.DurationFieldUnit`: Can be set to customize the unit for time.Duration type fields added by `Dur` (default: `time.Millisecond`).
* `zerolog.DurationFieldInteger`: If set to `true`, `Dur` fields are formatted as integers instead of floats (default: `false`).
* `zerolog.ErrorHandler`: Called whenever zerolog fails to write an event on its output. If not set, an error is printed on the stderr. This handler must be thread safe and non-blocking.
* `zerolog.FloatingPointPrecision`: If set to a value other than -1, controls the number
of digits when formatting float numbers in JSON. See
[strconv.FormatFloat](https://pkg.go.dev/strconv#FormatFloat)
for more details.
## Field Types
+3 -3
View File
@@ -183,13 +183,13 @@ func (a *Array) Uint64(i uint64) *Array {
// Float32 appends f as a float32 to the array.
func (a *Array) Float32(f float32) *Array {
a.buf = enc.AppendFloat32(enc.AppendArrayDelim(a.buf), f)
a.buf = enc.AppendFloat32(enc.AppendArrayDelim(a.buf), f, FloatingPointPrecision)
return a
}
// Float64 appends f as a float64 to the array.
func (a *Array) Float64(f float64) *Array {
a.buf = enc.AppendFloat64(enc.AppendArrayDelim(a.buf), f)
a.buf = enc.AppendFloat64(enc.AppendArrayDelim(a.buf), f, FloatingPointPrecision)
return a
}
@@ -201,7 +201,7 @@ func (a *Array) Time(t time.Time) *Array {
// Dur appends d to the array.
func (a *Array) Dur(d time.Duration) *Array {
a.buf = enc.AppendDuration(enc.AppendArrayDelim(a.buf), d, DurationFieldUnit, DurationFieldInteger)
a.buf = enc.AppendDuration(enc.AppendArrayDelim(a.buf), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
return a
}
+71 -20
View File
@@ -28,6 +28,8 @@ const (
colorBold = 1
colorDarkGray = 90
unknownLevel = "???"
)
var (
@@ -57,12 +59,21 @@ type ConsoleWriter struct {
// TimeFormat specifies the format for timestamp in output.
TimeFormat string
// TimeLocation tells ConsoleWriters default FormatTimestamp
// how to localize the time.
TimeLocation *time.Location
// PartsOrder defines the order of parts in output.
PartsOrder []string
// PartsExclude defines parts to not display in output.
PartsExclude []string
// FieldsOrder defines the order of contextual fields in output.
FieldsOrder []string
fieldIsOrdered map[string]int
// FieldsExclude defines contextual fields to not display in output.
FieldsExclude []string
@@ -83,9 +94,9 @@ type ConsoleWriter struct {
// NewConsoleWriter creates and initializes a new ConsoleWriter.
func NewConsoleWriter(options ...func(w *ConsoleWriter)) ConsoleWriter {
w := ConsoleWriter{
Out: os.Stdout,
TimeFormat: consoleDefaultTimeFormat,
PartsOrder: consoleDefaultPartsOrder(),
Out: os.Stdout,
TimeFormat: consoleDefaultTimeFormat,
PartsOrder: consoleDefaultPartsOrder(),
}
for _, opt := range options {
@@ -185,7 +196,12 @@ func (w ConsoleWriter) writeFields(evt map[string]interface{}, buf *bytes.Buffer
}
fields = append(fields, field)
}
sort.Strings(fields)
if len(w.FieldsOrder) > 0 {
w.orderFields(fields)
} else {
sort.Strings(fields)
}
// Write space only if something has already been written to the buffer, and if there are fields.
if buf.Len() > 0 && len(fields) > 0 {
@@ -284,7 +300,7 @@ func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]interface{},
}
case TimestampFieldName:
if w.FormatTimestamp == nil {
f = consoleDefaultFormatTimestamp(w.TimeFormat, w.NoColor)
f = consoleDefaultFormatTimestamp(w.TimeFormat, w.TimeLocation, w.NoColor)
} else {
f = w.FormatTimestamp
}
@@ -318,6 +334,32 @@ func (w ConsoleWriter) writePart(buf *bytes.Buffer, evt map[string]interface{},
}
}
// orderFields takes an array of field names and an array representing field order
// and returns an array with any ordered fields at the beginning, in order,
// and the remaining fields after in their original order.
func (w ConsoleWriter) orderFields(fields []string) {
if w.fieldIsOrdered == nil {
w.fieldIsOrdered = make(map[string]int)
for i, fieldName := range w.FieldsOrder {
w.fieldIsOrdered[fieldName] = i
}
}
sort.Slice(fields, func(i, j int) bool {
ii, iOrdered := w.fieldIsOrdered[fields[i]]
jj, jOrdered := w.fieldIsOrdered[fields[j]]
if iOrdered && jOrdered {
return ii < jj
}
if iOrdered {
return true
}
if jOrdered {
return false
}
return fields[i] < fields[j]
})
}
// needsQuote returns true when the string s should be quoted in output.
func needsQuote(s string) bool {
for i := range s {
@@ -352,19 +394,23 @@ func consoleDefaultPartsOrder() []string {
}
}
func consoleDefaultFormatTimestamp(timeFormat string, noColor bool) Formatter {
func consoleDefaultFormatTimestamp(timeFormat string, location *time.Location, noColor bool) Formatter {
if timeFormat == "" {
timeFormat = consoleDefaultTimeFormat
}
if location == nil {
location = time.Local
}
return func(i interface{}) string {
t := "<nil>"
switch tt := i.(type) {
case string:
ts, err := time.ParseInLocation(TimeFieldFormat, tt, time.Local)
ts, err := time.ParseInLocation(TimeFieldFormat, tt, location)
if err != nil {
t = tt
} else {
t = ts.Local().Format(timeFormat)
t = ts.In(location).Format(timeFormat)
}
case json.Number:
i, err := tt.Int64()
@@ -385,32 +431,37 @@ func consoleDefaultFormatTimestamp(timeFormat string, noColor bool) Formatter {
}
ts := time.Unix(sec, nsec)
t = ts.Format(timeFormat)
t = ts.In(location).Format(timeFormat)
}
}
return colorize(t, colorDarkGray, noColor)
}
}
func stripLevel(ll string) string {
if len(ll) == 0 {
return unknownLevel
}
if len(ll) > 3 {
ll = ll[:3]
}
return strings.ToUpper(ll)
}
func consoleDefaultFormatLevel(noColor bool) Formatter {
return func(i interface{}) string {
var l string
if ll, ok := i.(string); ok {
level, _ := ParseLevel(ll)
fl, ok := FormattedLevels[level]
if ok {
l = colorize(fl, LevelColors[level], noColor)
} else {
l = strings.ToUpper(ll)[0:3]
}
} else {
if i == nil {
l = "???"
} else {
l = strings.ToUpper(fmt.Sprintf("%s", i))[0:3]
return colorize(fl, LevelColors[level], noColor)
}
return stripLevel(ll)
}
return l
if i == nil {
return unknownLevel
}
return stripLevel(fmt.Sprintf("%s", i))
}
}
+14 -8
View File
@@ -325,25 +325,25 @@ func (c Context) Uints64(key string, i []uint64) Context {
// Float32 adds the field key with f as a float32 to the logger context.
func (c Context) Float32(key string, f float32) Context {
c.l.context = enc.AppendFloat32(enc.AppendKey(c.l.context, key), f)
c.l.context = enc.AppendFloat32(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
return c
}
// Floats32 adds the field key with f as a []float32 to the logger context.
func (c Context) Floats32(key string, f []float32) Context {
c.l.context = enc.AppendFloats32(enc.AppendKey(c.l.context, key), f)
c.l.context = enc.AppendFloats32(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
return c
}
// Float64 adds the field key with f as a float64 to the logger context.
func (c Context) Float64(key string, f float64) Context {
c.l.context = enc.AppendFloat64(enc.AppendKey(c.l.context, key), f)
c.l.context = enc.AppendFloat64(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
return c
}
// Floats64 adds the field key with f as a []float64 to the logger context.
func (c Context) Floats64(key string, f []float64) Context {
c.l.context = enc.AppendFloats64(enc.AppendKey(c.l.context, key), f)
c.l.context = enc.AppendFloats64(enc.AppendKey(c.l.context, key), f, FloatingPointPrecision)
return c
}
@@ -365,13 +365,13 @@ func (c Context) Timestamp() Context {
return c
}
// Time adds the field key with t formated as string using zerolog.TimeFieldFormat.
// Time adds the field key with t formatted as string using zerolog.TimeFieldFormat.
func (c Context) Time(key string, t time.Time) Context {
c.l.context = enc.AppendTime(enc.AppendKey(c.l.context, key), t, TimeFieldFormat)
return c
}
// Times adds the field key with t formated as string using zerolog.TimeFieldFormat.
// Times adds the field key with t formatted as string using zerolog.TimeFieldFormat.
func (c Context) Times(key string, t []time.Time) Context {
c.l.context = enc.AppendTimes(enc.AppendKey(c.l.context, key), t, TimeFieldFormat)
return c
@@ -379,13 +379,13 @@ func (c Context) Times(key string, t []time.Time) Context {
// Dur adds the fields key with d divided by unit and stored as a float.
func (c Context) Dur(key string, d time.Duration) Context {
c.l.context = enc.AppendDuration(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger)
c.l.context = enc.AppendDuration(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
return c
}
// Durs adds the fields key with d divided by unit and stored as a float.
func (c Context) Durs(key string, d []time.Duration) Context {
c.l.context = enc.AppendDurations(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger)
c.l.context = enc.AppendDurations(enc.AppendKey(c.l.context, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
return c
}
@@ -409,6 +409,12 @@ func (c Context) Any(key string, i interface{}) Context {
return c.Interface(key, i)
}
// Reset removes all the context fields.
func (c Context) Reset() Context {
c.l.context = enc.AppendBeginMarker(make([]byte, 0, 500))
return c
}
type callerHook struct {
callerSkipFrameCount int
}
+6 -6
View File
@@ -13,13 +13,13 @@ type encoder interface {
AppendBool(dst []byte, val bool) []byte
AppendBools(dst []byte, vals []bool) []byte
AppendBytes(dst, s []byte) []byte
AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte
AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool) []byte
AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, precision int) []byte
AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, precision int) []byte
AppendEndMarker(dst []byte) []byte
AppendFloat32(dst []byte, val float32) []byte
AppendFloat64(dst []byte, val float64) []byte
AppendFloats32(dst []byte, vals []float32) []byte
AppendFloats64(dst []byte, vals []float64) []byte
AppendFloat32(dst []byte, val float32, precision int) []byte
AppendFloat64(dst []byte, val float64, precision int) []byte
AppendFloats32(dst []byte, vals []float32, precision int) []byte
AppendFloats64(dst []byte, vals []float64, precision int) []byte
AppendHex(dst, s []byte) []byte
AppendIPAddr(dst []byte, ip net.IP) []byte
AppendIPPrefix(dst []byte, pfx net.IPNet) []byte
+7 -7
View File
@@ -644,7 +644,7 @@ func (e *Event) Float32(key string, f float32) *Event {
if e == nil {
return e
}
e.buf = enc.AppendFloat32(enc.AppendKey(e.buf, key), f)
e.buf = enc.AppendFloat32(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
return e
}
@@ -653,7 +653,7 @@ func (e *Event) Floats32(key string, f []float32) *Event {
if e == nil {
return e
}
e.buf = enc.AppendFloats32(enc.AppendKey(e.buf, key), f)
e.buf = enc.AppendFloats32(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
return e
}
@@ -662,7 +662,7 @@ func (e *Event) Float64(key string, f float64) *Event {
if e == nil {
return e
}
e.buf = enc.AppendFloat64(enc.AppendKey(e.buf, key), f)
e.buf = enc.AppendFloat64(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
return e
}
@@ -671,7 +671,7 @@ func (e *Event) Floats64(key string, f []float64) *Event {
if e == nil {
return e
}
e.buf = enc.AppendFloats64(enc.AppendKey(e.buf, key), f)
e.buf = enc.AppendFloats64(enc.AppendKey(e.buf, key), f, FloatingPointPrecision)
return e
}
@@ -713,7 +713,7 @@ func (e *Event) Dur(key string, d time.Duration) *Event {
if e == nil {
return e
}
e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger)
e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
return e
}
@@ -724,7 +724,7 @@ func (e *Event) Durs(key string, d []time.Duration) *Event {
if e == nil {
return e
}
e.buf = enc.AppendDurations(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger)
e.buf = enc.AppendDurations(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
return e
}
@@ -739,7 +739,7 @@ func (e *Event) TimeDiff(key string, t time.Time, start time.Time) *Event {
if t.After(start) {
d = t.Sub(start)
}
e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger)
e.buf = enc.AppendDuration(enc.AppendKey(e.buf, key), d, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
return e
}
+9 -9
View File
@@ -139,13 +139,13 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
case uint64:
dst = enc.AppendUint64(dst, val)
case float32:
dst = enc.AppendFloat32(dst, val)
dst = enc.AppendFloat32(dst, val, FloatingPointPrecision)
case float64:
dst = enc.AppendFloat64(dst, val)
dst = enc.AppendFloat64(dst, val, FloatingPointPrecision)
case time.Time:
dst = enc.AppendTime(dst, val, TimeFieldFormat)
case time.Duration:
dst = enc.AppendDuration(dst, val, DurationFieldUnit, DurationFieldInteger)
dst = enc.AppendDuration(dst, val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
case *string:
if val != nil {
dst = enc.AppendString(dst, *val)
@@ -220,13 +220,13 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
}
case *float32:
if val != nil {
dst = enc.AppendFloat32(dst, *val)
dst = enc.AppendFloat32(dst, *val, FloatingPointPrecision)
} else {
dst = enc.AppendNil(dst)
}
case *float64:
if val != nil {
dst = enc.AppendFloat64(dst, *val)
dst = enc.AppendFloat64(dst, *val, FloatingPointPrecision)
} else {
dst = enc.AppendNil(dst)
}
@@ -238,7 +238,7 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
}
case *time.Duration:
if val != nil {
dst = enc.AppendDuration(dst, *val, DurationFieldUnit, DurationFieldInteger)
dst = enc.AppendDuration(dst, *val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
} else {
dst = enc.AppendNil(dst)
}
@@ -267,13 +267,13 @@ func appendFieldList(dst []byte, kvList []interface{}, stack bool) []byte {
case []uint64:
dst = enc.AppendUints64(dst, val)
case []float32:
dst = enc.AppendFloats32(dst, val)
dst = enc.AppendFloats32(dst, val, FloatingPointPrecision)
case []float64:
dst = enc.AppendFloats64(dst, val)
dst = enc.AppendFloats64(dst, val, FloatingPointPrecision)
case []time.Time:
dst = enc.AppendTimes(dst, val, TimeFieldFormat)
case []time.Duration:
dst = enc.AppendDurations(dst, val, DurationFieldUnit, DurationFieldInteger)
dst = enc.AppendDurations(dst, val, DurationFieldUnit, DurationFieldInteger, FloatingPointPrecision)
case nil:
dst = enc.AppendNil(dst)
case net.IP:
+22 -2
View File
@@ -1,6 +1,7 @@
package zerolog
import (
"bytes"
"encoding/json"
"strconv"
"sync/atomic"
@@ -81,8 +82,22 @@ var (
}
// InterfaceMarshalFunc allows customization of interface marshaling.
// Default: "encoding/json.Marshal"
InterfaceMarshalFunc = json.Marshal
// Default: "encoding/json.Marshal" with disabled HTML escaping
InterfaceMarshalFunc = func(v interface{}) ([]byte, error) {
var buf bytes.Buffer
encoder := json.NewEncoder(&buf)
encoder.SetEscapeHTML(false)
err := encoder.Encode(v)
if err != nil {
return nil, err
}
b := buf.Bytes()
if len(b) > 0 {
// Remove trailing \n which is added by Encode.
return b[:len(b)-1], nil
}
return b, nil
}
// TimeFieldFormat defines the time format of the Time field type. If set to
// TimeFormatUnix, TimeFormatUnixMs, TimeFormatUnixMicro or TimeFormatUnixNano, the time is formatted as a UNIX
@@ -136,6 +151,11 @@ var (
// TriggerLevelWriterBufferReuseLimit is a limit in bytes that a buffer is dropped
// from the TriggerLevelWriter buffer pool if the buffer grows above the limit.
TriggerLevelWriterBufferReuseLimit = 64 * 1024
// FloatingPointPrecision, if set to a value other than -1, controls the number
// of digits when formatting float numbers in JSON. See strconv.FormatFloat for
// more details.
FloatingPointPrecision = -1
)
var (
+1 -1
View File
@@ -95,7 +95,7 @@ func decodeFloat(src *bufio.Reader) (float64, int) {
switch minor {
case additionalTypeFloat16:
panic(fmt.Errorf("float16 is not suppported in decodeFloat"))
panic(fmt.Errorf("float16 is not supported in decodeFloat"))
case additionalTypeFloat32:
pb := readNBytes(src, 4)
+5 -5
View File
@@ -29,7 +29,7 @@ func (e Encoder) appendFloatTimestamp(dst []byte, t time.Time) []byte {
nanos := t.Nanosecond()
var val float64
val = float64(secs)*1.0 + float64(nanos)*1e-9
return e.AppendFloat64(dst, val)
return e.AppendFloat64(dst, val, -1)
}
// AppendTime encodes and adds a timestamp to the dst byte array.
@@ -64,17 +64,17 @@ func (e Encoder) AppendTimes(dst []byte, vals []time.Time, unused string) []byte
// AppendDuration encodes and adds a duration to the dst byte array.
// useInt field indicates whether to store the duration as seconds (integer) or
// as seconds+nanoseconds (float).
func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte {
func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, unused int) []byte {
if useInt {
return e.AppendInt64(dst, int64(d/unit))
}
return e.AppendFloat64(dst, float64(d)/float64(unit))
return e.AppendFloat64(dst, float64(d)/float64(unit), unused)
}
// AppendDurations encodes and adds an array of durations to the dst byte array.
// useInt field indicates whether to store the duration as seconds (integer) or
// as seconds+nanoseconds (float).
func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool) []byte {
func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, unused int) []byte {
major := majorTypeArray
l := len(vals)
if l == 0 {
@@ -87,7 +87,7 @@ func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Dur
dst = appendCborTypePrefix(dst, major, uint64(l))
}
for _, d := range vals {
dst = e.AppendDuration(dst, d, unit, useInt)
dst = e.AppendDuration(dst, d, unit, useInt, unused)
}
return dst
}
+6 -6
View File
@@ -352,7 +352,7 @@ func (e Encoder) AppendUints64(dst []byte, vals []uint64) []byte {
}
// AppendFloat32 encodes and inserts a single precision float value into the dst byte array.
func (Encoder) AppendFloat32(dst []byte, val float32) []byte {
func (Encoder) AppendFloat32(dst []byte, val float32, unused int) []byte {
switch {
case math.IsNaN(float64(val)):
return append(dst, "\xfa\x7f\xc0\x00\x00"...)
@@ -372,7 +372,7 @@ func (Encoder) AppendFloat32(dst []byte, val float32) []byte {
}
// AppendFloats32 encodes and inserts an array of single precision float value into the dst byte array.
func (e Encoder) AppendFloats32(dst []byte, vals []float32) []byte {
func (e Encoder) AppendFloats32(dst []byte, vals []float32, unused int) []byte {
major := majorTypeArray
l := len(vals)
if l == 0 {
@@ -385,13 +385,13 @@ func (e Encoder) AppendFloats32(dst []byte, vals []float32) []byte {
dst = appendCborTypePrefix(dst, major, uint64(l))
}
for _, v := range vals {
dst = e.AppendFloat32(dst, v)
dst = e.AppendFloat32(dst, v, unused)
}
return dst
}
// AppendFloat64 encodes and inserts a double precision float value into the dst byte array.
func (Encoder) AppendFloat64(dst []byte, val float64) []byte {
func (Encoder) AppendFloat64(dst []byte, val float64, unused int) []byte {
switch {
case math.IsNaN(val):
return append(dst, "\xfb\x7f\xf8\x00\x00\x00\x00\x00\x00"...)
@@ -412,7 +412,7 @@ func (Encoder) AppendFloat64(dst []byte, val float64) []byte {
}
// AppendFloats64 encodes and inserts an array of double precision float values into the dst byte array.
func (e Encoder) AppendFloats64(dst []byte, vals []float64) []byte {
func (e Encoder) AppendFloats64(dst []byte, vals []float64, unused int) []byte {
major := majorTypeArray
l := len(vals)
if l == 0 {
@@ -425,7 +425,7 @@ func (e Encoder) AppendFloats64(dst []byte, vals []float64) []byte {
dst = appendCborTypePrefix(dst, major, uint64(l))
}
for _, v := range vals {
dst = e.AppendFloat64(dst, v)
dst = e.AppendFloat64(dst, v, unused)
}
return dst
}
+5 -5
View File
@@ -88,24 +88,24 @@ func appendUnixNanoTimes(dst []byte, vals []time.Time, div int64) []byte {
// AppendDuration formats the input duration with the given unit & format
// and appends the encoded string to the input byte slice.
func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool) []byte {
func (e Encoder) AppendDuration(dst []byte, d time.Duration, unit time.Duration, useInt bool, precision int) []byte {
if useInt {
return strconv.AppendInt(dst, int64(d/unit), 10)
}
return e.AppendFloat64(dst, float64(d)/float64(unit))
return e.AppendFloat64(dst, float64(d)/float64(unit), precision)
}
// AppendDurations formats the input durations with the given unit & format
// and appends the encoded string list to the input byte slice.
func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool) []byte {
func (e Encoder) AppendDurations(dst []byte, vals []time.Duration, unit time.Duration, useInt bool, precision int) []byte {
if len(vals) == 0 {
return append(dst, '[', ']')
}
dst = append(dst, '[')
dst = e.AppendDuration(dst, vals[0], unit, useInt)
dst = e.AppendDuration(dst, vals[0], unit, useInt, precision)
if len(vals) > 1 {
for _, d := range vals[1:] {
dst = e.AppendDuration(append(dst, ','), d, unit, useInt)
dst = e.AppendDuration(append(dst, ','), d, unit, useInt, precision)
}
}
dst = append(dst, ']')
+33 -12
View File
@@ -299,7 +299,7 @@ func (Encoder) AppendUints64(dst []byte, vals []uint64) []byte {
return dst
}
func appendFloat(dst []byte, val float64, bitSize int) []byte {
func appendFloat(dst []byte, val float64, bitSize, precision int) []byte {
// JSON does not permit NaN or Infinity. A typical JSON encoder would fail
// with an error, but a logging library wants the data to get through so we
// make a tradeoff and store those types as string.
@@ -311,26 +311,47 @@ func appendFloat(dst []byte, val float64, bitSize int) []byte {
case math.IsInf(val, -1):
return append(dst, `"-Inf"`...)
}
return strconv.AppendFloat(dst, val, 'f', -1, bitSize)
// convert as if by es6 number to string conversion
// see also https://cs.opensource.google/go/go/+/refs/tags/go1.20.3:src/encoding/json/encode.go;l=573
strFmt := byte('f')
// If precision is set to a value other than -1, we always just format the float using that precision.
if precision == -1 {
// Use float32 comparisons for underlying float32 value to get precise cutoffs right.
if abs := math.Abs(val); abs != 0 {
if bitSize == 64 && (abs < 1e-6 || abs >= 1e21) || bitSize == 32 && (float32(abs) < 1e-6 || float32(abs) >= 1e21) {
strFmt = 'e'
}
}
}
dst = strconv.AppendFloat(dst, val, strFmt, precision, bitSize)
if strFmt == 'e' {
// Clean up e-09 to e-9
n := len(dst)
if n >= 4 && dst[n-4] == 'e' && dst[n-3] == '-' && dst[n-2] == '0' {
dst[n-2] = dst[n-1]
dst = dst[:n-1]
}
}
return dst
}
// AppendFloat32 converts the input float32 to a string and
// appends the encoded string to the input byte slice.
func (Encoder) AppendFloat32(dst []byte, val float32) []byte {
return appendFloat(dst, float64(val), 32)
func (Encoder) AppendFloat32(dst []byte, val float32, precision int) []byte {
return appendFloat(dst, float64(val), 32, precision)
}
// AppendFloats32 encodes the input float32s to json and
// appends the encoded string list to the input byte slice.
func (Encoder) AppendFloats32(dst []byte, vals []float32) []byte {
func (Encoder) AppendFloats32(dst []byte, vals []float32, precision int) []byte {
if len(vals) == 0 {
return append(dst, '[', ']')
}
dst = append(dst, '[')
dst = appendFloat(dst, float64(vals[0]), 32)
dst = appendFloat(dst, float64(vals[0]), 32, precision)
if len(vals) > 1 {
for _, val := range vals[1:] {
dst = appendFloat(append(dst, ','), float64(val), 32)
dst = appendFloat(append(dst, ','), float64(val), 32, precision)
}
}
dst = append(dst, ']')
@@ -339,21 +360,21 @@ func (Encoder) AppendFloats32(dst []byte, vals []float32) []byte {
// AppendFloat64 converts the input float64 to a string and
// appends the encoded string to the input byte slice.
func (Encoder) AppendFloat64(dst []byte, val float64) []byte {
return appendFloat(dst, val, 64)
func (Encoder) AppendFloat64(dst []byte, val float64, precision int) []byte {
return appendFloat(dst, val, 64, precision)
}
// AppendFloats64 encodes the input float64s to json and
// appends the encoded string list to the input byte slice.
func (Encoder) AppendFloats64(dst []byte, vals []float64) []byte {
func (Encoder) AppendFloats64(dst []byte, vals []float64, precision int) []byte {
if len(vals) == 0 {
return append(dst, '[', ']')
}
dst = append(dst, '[')
dst = appendFloat(dst, vals[0], 64)
dst = appendFloat(dst, vals[0], 64, precision)
if len(vals) > 1 {
for _, val := range vals[1:] {
dst = appendFloat(append(dst, ','), val, 64)
dst = appendFloat(append(dst, ','), val, 64, precision)
}
}
dst = append(dst, ']')
+1 -1
View File
@@ -24,7 +24,7 @@
//
// Sub-loggers let you chain loggers with additional context:
//
// sublogger := log.With().Str("component": "foo").Logger()
// sublogger := log.With().Str("component", "foo").Logger()
// sublogger.Info().Msg("hello world")
// // Output: {"time":1494567715,"level":"info","message":"hello world","component":"foo"}
//
+1 -1
View File
@@ -84,7 +84,7 @@ func (s *BurstSampler) Sample(lvl Level) bool {
}
func (s *BurstSampler) inc() uint32 {
now := time.Now().UnixNano()
now := TimestampFunc().UnixNano()
resetAt := atomic.LoadInt64(&s.resetAt)
var c uint32
if now > resetAt {
+3 -2
View File
@@ -46,10 +46,11 @@ func (s *strikethroughParser) Trigger() []byte {
func (s *strikethroughParser) Parse(parent gast.Node, block text.Reader, pc parser.Context) gast.Node {
before := block.PrecendingCharacter()
line, segment := block.PeekLine()
node := parser.ScanDelimiter(line, before, 2, defaultStrikethroughDelimiterProcessor)
if node == nil {
node := parser.ScanDelimiter(line, before, 1, defaultStrikethroughDelimiterProcessor)
if node == nil || node.OriginalLength > 2 || before == '~' {
return nil
}
node.Segment = segment.WithStop(segment.Start + node.OriginalLength)
block.Advance(node.OriginalLength)
pc.PushDelimiter(node)
+3 -3
View File
@@ -492,7 +492,7 @@ func (r *TableHTMLRenderer) renderTableCell(
tag = "th"
}
if entering {
fmt.Fprintf(w, "<%s", tag)
_, _ = fmt.Fprintf(w, "<%s", tag)
if n.Alignment != ast.AlignNone {
amethod := r.TableConfig.TableCellAlignMethod
if amethod == TableCellAlignDefault {
@@ -505,7 +505,7 @@ func (r *TableHTMLRenderer) renderTableCell(
switch amethod {
case TableCellAlignAttribute:
if _, ok := n.AttributeString("align"); !ok { // Skip align render if overridden
fmt.Fprintf(w, ` align="%s"`, n.Alignment.String())
_, _ = fmt.Fprintf(w, ` align="%s"`, n.Alignment.String())
}
case TableCellAlignStyle:
v, ok := n.AttributeString("style")
@@ -528,7 +528,7 @@ func (r *TableHTMLRenderer) renderTableCell(
}
_ = w.WriteByte('>')
} else {
fmt.Fprintf(w, "</%s>\n", tag)
_, _ = fmt.Fprintf(w, "</%s>\n", tag)
}
return gast.WalkContinue, nil
}
+2 -1
View File
@@ -2,12 +2,13 @@
package goldmark
import (
"io"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/renderer"
"github.com/yuin/goldmark/renderer/html"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
"io"
)
// DefaultParser returns a new Parser that is configured by default values.
+46 -7
View File
@@ -126,13 +126,13 @@ func (s *linkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.N
if line[0] == '!' {
if len(line) > 1 && line[1] == '[' {
block.Advance(1)
pc.Set(linkBottom, pc.LastDelimiter())
pushLinkBottom(pc)
return processLinkLabelOpen(block, segment.Start+1, true, pc)
}
return nil
}
if line[0] == '[' {
pc.Set(linkBottom, pc.LastDelimiter())
pushLinkBottom(pc)
return processLinkLabelOpen(block, segment.Start, false, pc)
}
@@ -143,6 +143,7 @@ func (s *linkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.N
}
last := tlist.(*linkLabelState).Last
if last == nil {
_ = popLinkBottom(pc)
return nil
}
block.Advance(1)
@@ -151,11 +152,13 @@ func (s *linkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.N
// > A link label can have at most 999 characters inside the square brackets.
if linkLabelStateLength(tlist.(*linkLabelState)) > 998 {
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
_ = popLinkBottom(pc)
return nil
}
if !last.IsImage && s.containsLink(last) { // a link in a link text is not allowed
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
_ = popLinkBottom(pc)
return nil
}
@@ -169,6 +172,7 @@ func (s *linkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.N
link, hasValue = s.parseReferenceLink(parent, last, block, pc)
if link == nil && hasValue {
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
_ = popLinkBottom(pc)
return nil
}
}
@@ -182,12 +186,14 @@ func (s *linkParser) Parse(parent ast.Node, block text.Reader, pc Context) ast.N
// > A link label can have at most 999 characters inside the square brackets.
if len(maybeReference) > 999 {
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
_ = popLinkBottom(pc)
return nil
}
ref, ok := pc.Reference(util.ToLinkReference(maybeReference))
if !ok {
ast.MergeOrReplaceTextSegment(last.Parent(), last, last.Segment)
_ = popLinkBottom(pc)
return nil
}
link = ast.NewLink()
@@ -230,11 +236,7 @@ func processLinkLabelOpen(block text.Reader, pos int, isImage bool, pc Context)
}
func (s *linkParser) processLinkLabel(parent ast.Node, link *ast.Link, last *linkLabelState, pc Context) {
var bottom ast.Node
if v := pc.Get(linkBottom); v != nil {
bottom = v.(ast.Node)
}
pc.Set(linkBottom, nil)
bottom := popLinkBottom(pc)
ProcessDelimiters(bottom, pc)
for c := last.NextSibling(); c != nil; {
next := c.NextSibling()
@@ -395,6 +397,43 @@ func parseLinkTitle(block text.Reader) ([]byte, bool) {
return nil, false
}
func pushLinkBottom(pc Context) {
bottoms := pc.Get(linkBottom)
b := pc.LastDelimiter()
if bottoms == nil {
pc.Set(linkBottom, b)
return
}
if s, ok := bottoms.([]ast.Node); ok {
pc.Set(linkBottom, append(s, b))
return
}
pc.Set(linkBottom, []ast.Node{bottoms.(ast.Node), b})
}
func popLinkBottom(pc Context) ast.Node {
bottoms := pc.Get(linkBottom)
if bottoms == nil {
return nil
}
if v, ok := bottoms.(ast.Node); ok {
pc.Set(linkBottom, nil)
return v
}
s := bottoms.([]ast.Node)
v := s[len(s)-1]
n := s[0 : len(s)-1]
switch len(n) {
case 0:
pc.Set(linkBottom, nil)
case 1:
pc.Set(linkBottom, n[0])
default:
pc.Set(linkBottom, s[0:len(s)-1])
}
return v
}
func (s *linkParser) CloseBlock(parent ast.Node, block text.Reader, pc Context) {
pc.Set(linkBottom, nil)
tlist := pc.Get(linkLabelStateKey)
+19 -19
View File
@@ -445,7 +445,7 @@ func (r *Renderer) renderList(w util.BufWriter, source []byte, node ast.Node, en
_ = w.WriteByte('<')
_, _ = w.WriteString(tag)
if n.IsOrdered() && n.Start != 1 {
fmt.Fprintf(w, " start=\"%d\"", n.Start)
_, _ = fmt.Fprintf(w, " start=\"%d\"", n.Start)
}
if n.Attributes() != nil {
RenderAttributes(w, n, ListAttributeFilter)
@@ -680,7 +680,7 @@ func (r *Renderer) renderImage(w util.BufWriter, source []byte, node ast.Node, e
_, _ = w.Write(util.EscapeHTML(util.URLEscape(n.Destination, true)))
}
_, _ = w.WriteString(`" alt="`)
_, _ = w.Write(nodeToHTMLText(n, source))
r.renderAttribute(w, source, n)
_ = w.WriteByte('"')
if n.Title != nil {
_, _ = w.WriteString(` title="`)
@@ -770,6 +770,23 @@ func (r *Renderer) renderString(w util.BufWriter, source []byte, node ast.Node,
return ast.WalkContinue, nil
}
func (r *Renderer) renderAttribute(w util.BufWriter, source []byte, n ast.Node) {
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
if s, ok := c.(*ast.String); ok {
_, _ = r.renderString(w, source, s, true)
} else if t, ok := c.(*ast.String); ok {
_, _ = r.renderText(w, source, t, true)
} else if !c.HasChildren() {
r.Writer.Write(w, c.Text(source))
if t, ok := c.(*ast.Text); ok && t.SoftLineBreak() {
_ = w.WriteByte('\n')
}
} else {
r.renderAttribute(w, source, c)
}
}
}
var dataPrefix = []byte("data-")
// RenderAttributes renders given node's attributes.
@@ -1007,20 +1024,3 @@ func IsDangerousURL(url []byte) bool {
return hasPrefix(url, bJs) || hasPrefix(url, bVb) ||
hasPrefix(url, bFile) || hasPrefix(url, bData)
}
func nodeToHTMLText(n ast.Node, source []byte) []byte {
var buf bytes.Buffer
for c := n.FirstChild(); c != nil; c = c.NextSibling() {
if s, ok := c.(*ast.String); ok && s.IsCode() {
buf.Write(s.Text(source))
} else if !c.HasChildren() {
buf.Write(util.EscapeHTML(c.Text(source)))
if t, ok := c.(*ast.Text); ok && t.SoftLineBreak() {
buf.WriteByte('\n')
}
} else {
buf.Write(nodeToHTMLText(c, source))
}
}
return buf.Bytes()
}
+13 -9
View File
@@ -1,11 +1,15 @@
lint:
image: registry.gitlab.com/etke.cc/base
script:
- golangci-lint run ./...
stages:
- test
- release
default:
image: registry.gitlab.com/etke.cc/base/build
unit:
image: registry.gitlab.com/etke.cc/base
test:
stage: test
script:
- go test -coverprofile=cover.out ./...
- go tool cover -func=cover.out
- rm -f cover.out
- just lint
- just test
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- /root/cache/
+144
View File
@@ -0,0 +1,144 @@
run:
concurrency: 4
timeout: 30m
issues-exit-code: 1
tests: true
build-tags: []
skip-dirs-use-default: true
skip-files: []
modules-download-mode: readonly
output:
formats:
- format: colored-line-number
print-issued-lines: true
print-linter-name: true
sort-results: true
linters-settings:
decorder:
dec-order:
- const
- var
- type
- func
dogsled:
max-blank-identifiers: 3
errcheck:
check-type-assertions: true
check-blank: true
errchkjson:
report-no-exported: true
exhaustive:
check:
- switch
- map
default-signifies-exhaustive: true
gocognit:
min-complexity: 15
nestif:
min-complexity: 5
gocritic:
enabled-tags:
- diagnostic
- style
- performance
gofmt:
simplify: true
rewrite-rules:
- pattern: 'interface{}'
replacement: 'any'
- pattern: 'a[b:len(a)]'
replacement: 'a[b:]'
gofumpt:
extra-rules: true
grouper:
const-require-single-const: true
import-require-single-import: true
var-require-single-var: true
misspell:
locale: US
usestdlibvars:
time-month: true
time-layout: true
crypto-hash: true
default-rpc-path: true
sql-isolation-level: true
tls-signature-scheme: true
constant-kind: true
unparam:
check-exported: true
linters:
disable-all: false
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- decorder
- dogsled
- dupl
- dupword
- durationcheck
- errcheck
- errchkjson
- errname
- errorlint
- exhaustive
- exportloopref
- forcetypeassert
- gocognit
- gocritic
- gocyclo
- gofmt
- gofumpt
- goimports
- gosec
- gosimple
- gosmopolitan
- govet
- ineffassign
- makezero
- mirror
- misspell
- nestif
- nolintlint
- prealloc
- predeclared
- revive
- sqlclosecheck
- staticcheck
- unconvert
- unparam
- unused
- usestdlibvars
- wastedassign
fast: false
issues:
exclude-dirs:
- mocks
exclude-files:
- dotenv/parser.go
exclude-rules:
- path: _test\.go
linters:
- gocyclo
- gocognit
- errcheck
- dupl
- gosec
- linters:
- staticcheck
text: "SA9003:"
- linters:
- lll
source: "^//go:generate "
- linters:
- revive
text: "returns unexported type"
max-issues-per-linter: 0
max-same-issues: 0
new: false
+5
View File
@@ -2,12 +2,17 @@
Simple go environment variables reader, for env-based configs
Automatically loads .env file if exists
```go
env.SetPrefix("app") // all env vars should start with APP_
login := env.String("matrix.login", "none") // export APP_MATRIX_LOGIN=buscarron
enabled := env.Bool("form.enabled") // export APP_FORM_ENABLED=1
size := env.Int("cache.size", 1000) // export APP_CACHE_SIZE=500
slice := env.Slice("form.fields") // export APP_FORM_FIELDS="one two three"
// need to load custom env file?
dotenv.Load(".env.dev", ".env.local")
```
see more in godoc
+43
View File
@@ -0,0 +1,43 @@
package dotenv
import (
"errors"
"os"
)
// EnvFile is the default file to load
const EnvFile = ".env"
// Load loads the EnvFile and additional files
func Load(additionalFiles ...string) {
files := []string{EnvFile}
if len(additionalFiles) > 0 {
files = append(files, additionalFiles...)
}
for _, file := range files {
loadFile(file) //nolint:errcheck // ignore error
}
}
func loadFile(file string) error {
if _, err := os.Stat(".env"); errors.Is(err, os.ErrNotExist) {
return nil
}
contents, err := os.ReadFile(file)
if err != nil {
return err
}
contentsMap := make(map[string]string)
if err := parseBytes(contents, contentsMap); err != nil {
return err
}
for key, value := range contentsMap {
os.Setenv(key, value)
}
return nil
}
+273
View File
@@ -0,0 +1,273 @@
package dotenv
// This file is modified version of github.com/joho/godotenv/parser.go
// The original file is licensed under MIT License
import (
"bytes"
"errors"
"fmt"
"regexp"
"strings"
"unicode"
)
const (
charComment = '#'
prefixSingleQuote = '\''
prefixDoubleQuote = '"'
exportPrefix = "export"
)
func parseBytes(src []byte, out map[string]string) error {
src = bytes.ReplaceAll(src, []byte("\r\n"), []byte("\n"))
cutset := src
for {
cutset = getStatementStart(cutset)
if cutset == nil {
// reached end of file
break
}
key, left, err := locateKeyName(cutset)
if err != nil {
return err
}
value, left, err := extractVarValue(left, out)
if err != nil {
return err
}
out[key] = value
cutset = left
}
return nil
}
// getStatementPosition returns position of statement begin.
//
// It skips any comment line or non-whitespace character.
func getStatementStart(src []byte) []byte {
pos := indexOfNonSpaceChar(src)
if pos == -1 {
return nil
}
src = src[pos:]
if src[0] != charComment {
return src
}
// skip comment section
pos = bytes.IndexFunc(src, isCharFunc('\n'))
if pos == -1 {
return nil
}
return getStatementStart(src[pos:])
}
// locateKeyName locates and parses key name and returns rest of slice
func locateKeyName(src []byte) (key string, cutset []byte, err error) {
// trim "export" and space at beginning
src = bytes.TrimLeftFunc(src, isSpace)
if bytes.HasPrefix(src, []byte(exportPrefix)) {
trimmed := bytes.TrimPrefix(src, []byte(exportPrefix))
if bytes.IndexFunc(trimmed, isSpace) == 0 {
src = bytes.TrimLeftFunc(trimmed, isSpace)
}
}
// locate key name end and validate it in single loop
offset := 0
loop:
for i, char := range src {
rchar := rune(char)
if isSpace(rchar) {
continue
}
switch char {
case '=', ':':
// library also supports yaml-style value declaration
key = string(src[0:i])
offset = i + 1
break loop
case '_':
default:
// variable name should match [A-Za-z0-9_.]
if unicode.IsLetter(rchar) || unicode.IsNumber(rchar) || rchar == '.' {
continue
}
return "", nil, fmt.Errorf(
`unexpected character %q in variable name near %q`,
string(char), string(src))
}
}
if len(src) == 0 {
return "", nil, errors.New("zero length string")
}
// trim whitespace
key = strings.TrimRightFunc(key, unicode.IsSpace)
cutset = bytes.TrimLeftFunc(src[offset:], isSpace)
return key, cutset, nil
}
// extractVarValue extracts variable value and returns rest of slice
func extractVarValue(src []byte, vars map[string]string) (value string, rest []byte, err error) {
quote, hasPrefix := hasQuotePrefix(src)
if !hasPrefix {
// unquoted value - read until end of line
endOfLine := bytes.IndexFunc(src, isLineEnd)
// Hit EOF without a trailing newline
if endOfLine == -1 {
endOfLine = len(src)
if endOfLine == 0 {
return "", nil, nil
}
}
// Convert line to rune away to do accurate countback of runes
line := []rune(string(src[0:endOfLine]))
// Assume end of line is end of var
endOfVar := len(line)
if endOfVar == 0 {
return "", src[endOfLine:], nil
}
// Work backwards to check if the line ends in whitespace then
// a comment (ie asdasd # some comment)
for i := endOfVar - 1; i >= 0; i-- {
if line[i] == charComment && i > 0 {
if isSpace(line[i-1]) {
endOfVar = i
break
}
}
}
trimmed := strings.TrimFunc(string(line[0:endOfVar]), isSpace)
return expandVariables(trimmed, vars), src[endOfLine:], nil
}
// lookup quoted string terminator
for i := 1; i < len(src); i++ {
if char := src[i]; char != quote {
continue
}
// skip escaped quote symbol (\" or \', depends on quote)
if prevChar := src[i-1]; prevChar == '\\' {
continue
}
// trim quotes
trimFunc := isCharFunc(rune(quote))
value = string(bytes.TrimLeftFunc(bytes.TrimRightFunc(src[0:i], trimFunc), trimFunc))
if quote == prefixDoubleQuote {
// unescape newlines for double quote (this is compat feature)
// and expand environment variables
value = expandVariables(expandEscapes(value), vars)
}
return value, src[i+1:], nil
}
// return formatted error if quoted string is not terminated
valEndIndex := bytes.IndexFunc(src, isCharFunc('\n'))
if valEndIndex == -1 {
valEndIndex = len(src)
}
return "", nil, fmt.Errorf("unterminated quoted value %s", src[:valEndIndex])
}
func expandEscapes(str string) string {
out := escapeRegex.ReplaceAllStringFunc(str, func(match string) string {
c := strings.TrimPrefix(match, `\`)
switch c {
case "n":
return "\n"
case "r":
return "\r"
default:
return match
}
})
return unescapeCharsRegex.ReplaceAllString(out, "$1")
}
func indexOfNonSpaceChar(src []byte) int {
return bytes.IndexFunc(src, func(r rune) bool {
return !unicode.IsSpace(r)
})
}
// hasQuotePrefix reports whether charset starts with single or double quote and returns quote character
func hasQuotePrefix(src []byte) (prefix byte, isQuored bool) {
if len(src) == 0 {
return 0, false
}
switch prefix := src[0]; prefix {
case prefixDoubleQuote, prefixSingleQuote:
return prefix, true
default:
return 0, false
}
}
func isCharFunc(char rune) func(rune) bool {
return func(v rune) bool {
return v == char
}
}
// isSpace reports whether the rune is a space character but not line break character
//
// this differs from unicode.IsSpace, which also applies line break as space
func isSpace(r rune) bool {
switch r {
case '\t', '\v', '\f', '\r', ' ', 0x85, 0xA0:
return true
}
return false
}
func isLineEnd(r rune) bool {
if r == '\n' || r == '\r' {
return true
}
return false
}
var (
escapeRegex = regexp.MustCompile(`\\.`)
expandVarRegex = regexp.MustCompile(`(\\)?(\$)(\()?\{?([A-Z0-9_]+)?\}?`)
unescapeCharsRegex = regexp.MustCompile(`\\([^$])`)
)
func expandVariables(v string, m map[string]string) string {
return expandVarRegex.ReplaceAllStringFunc(v, func(s string) string {
submatch := expandVarRegex.FindStringSubmatch(s)
if submatch == nil {
return s
}
if submatch[1] == "\\" || submatch[2] == "(" {
return submatch[0][1:]
} else if submatch[4] != "" {
return m[submatch[4]]
}
return s
})
}
+6
View File
@@ -4,10 +4,16 @@ import (
"os"
"strconv"
"strings"
"gitlab.com/etke.cc/go/env/dotenv"
)
var envprefix string
func init() {
dotenv.Load()
}
// SetPrefix sets prefix for all env vars
func SetPrefix(prefix string) {
envprefix = prefix
+22
View File
@@ -0,0 +1,22 @@
# show help by default
default:
@just --list --justfile {{ justfile() }}
# update go deps
update *flags:
go get {{flags}} .
go mod tidy
# run linter
lint:
golangci-lint run ./...
# automatically fix liter issues
lintfix:
golangci-lint run --fix ./...
# run unit tests
test:
@go test -cover -coverprofile=cover.out -coverpkg=./... -covermode=set ./...
@go tool cover -func=cover.out
-@rm -f cover.out
+6
View File
@@ -104,6 +104,8 @@ type Database struct {
Dialect Dialect
UpgradeTable UpgradeTable
txnCtxKey contextKey
IgnoreForeignTables bool
IgnoreUnsupportedDatabase bool
}
@@ -132,6 +134,8 @@ func (db *Database) Child(versionTable string, upgradeTable UpgradeTable, log Da
Log: log,
Dialect: db.Dialect,
txnCtxKey: db.txnCtxKey,
IgnoreForeignTables: true,
IgnoreUnsupportedDatabase: db.IgnoreUnsupportedDatabase,
}
@@ -149,6 +153,8 @@ func NewWithDB(db *sql.DB, rawDialect string) (*Database, error) {
IgnoreForeignTables: true,
VersionTable: "version",
txnCtxKey: contextKey(nextContextKeyDatabaseTransaction.Add(1)),
}
wrappedDB.LoggingDB.UnderlyingExecable = db
wrappedDB.LoggingDB.db = wrappedDB
+2 -1
View File
@@ -4,6 +4,7 @@ import (
"database/sql/driver"
"encoding/json"
"fmt"
"unsafe"
)
// JSON is a utility type for using arbitrary JSON data as values in database Exec and Scan calls.
@@ -29,7 +30,7 @@ func (j JSON) Value() (driver.Value, error) {
return nil, nil
}
v, err := json.Marshal(j.Data)
return string(v), err
return unsafe.String(unsafe.SliceData(v), len(v)), err
}
// JSONPtr is a convenience function for wrapping a pointer to a value in the JSON utility, but removing typed nils
+2 -2
View File
@@ -2,8 +2,8 @@
CREATE TABLE foo (
-- only: postgres
key BIGINT PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
-- only: sqlite
key INTEGER PRIMARY KEY,
-- only: sqlite (line commented)
-- key INTEGER PRIMARY KEY,
data JSONB NOT NULL
);
@@ -8,4 +8,3 @@ CREATE FUNCTION delete_data() RETURNS TRIGGER LANGUAGE plpgsql AS $$ BEGIN
DELETE FROM test WHERE key <= NEW.data->>'index';
RETURN NEW;
END $$;
-- end only postgres
@@ -7,4 +7,3 @@ CREATE TABLE foo (
CREATE TRIGGER test AFTER INSERT ON foo WHEN NEW.data->>'action' = 'delete' BEGIN
DELETE FROM test WHERE key <= NEW.data->>'index';
END;
-- end only sqlite
+13 -7
View File
@@ -12,6 +12,7 @@ import (
"errors"
"fmt"
"runtime"
"sync/atomic"
"time"
"github.com/rs/zerolog"
@@ -26,13 +27,18 @@ var (
ErrTxnCommit = fmt.Errorf("%w: commit", ErrTxn)
)
type contextKey int
type contextKey int64
const (
ContextKeyDatabaseTransaction contextKey = iota
ContextKeyDoTxnCallerSkip
ContextKeyDoTxnCallerSkip contextKey = 1
)
var nextContextKeyDatabaseTransaction atomic.Uint64
func init() {
nextContextKeyDatabaseTransaction.Store(1 << 61)
}
func (db *Database) Exec(ctx context.Context, query string, args ...any) (sql.Result, error) {
return db.Conn(ctx).ExecContext(ctx, query, args...)
}
@@ -56,7 +62,7 @@ func (db *Database) DoTxn(ctx context.Context, opts *sql.TxOptions, fn func(ctx
if ctx == nil {
panic("DoTxn() called with nil ctx")
}
if ctx.Value(ContextKeyDatabaseTransaction) != nil {
if ctx.Value(db.txnCtxKey) != nil {
zerolog.Ctx(ctx).Trace().Msg("Already in a transaction, not creating a new one")
return fn(ctx)
}
@@ -82,7 +88,7 @@ func (db *Database) DoTxn(ctx context.Context, opts *sql.TxOptions, fn func(ctx
select {
case <-ticker.C:
slowLog.Warn().
Dur("duration_seconds", time.Since(start)).
Float64("duration_seconds", time.Since(start).Seconds()).
Msg("Transaction still running")
case <-deadlockCh:
return
@@ -106,7 +112,7 @@ func (db *Database) DoTxn(ctx context.Context, opts *sql.TxOptions, fn func(ctx
log.Trace().Msg("Transaction started")
tx.noTotalLog = true
ctx = log.WithContext(ctx)
ctx = context.WithValue(ctx, ContextKeyDatabaseTransaction, tx)
ctx = context.WithValue(ctx, db.txnCtxKey, tx)
err = fn(ctx)
if err != nil {
log.Trace().Err(err).Msg("Database transaction failed, rolling back")
@@ -131,7 +137,7 @@ func (db *Database) Conn(ctx context.Context) Execable {
if ctx == nil {
panic("Conn() called with nil ctx")
}
txn, ok := ctx.Value(ContextKeyDatabaseTransaction).(Transaction)
txn, ok := ctx.Value(db.txnCtxKey).(Transaction)
if ok {
return txn
}
+48 -29
View File
@@ -121,40 +121,38 @@ func parseFileHeader(file []byte) (from, to, compat int, message string, txn boo
// -- only: sqlite for next 123 lines
//
// If the single-line limit is on the second line of the file, the whole file is limited to that dialect.
var dialectLineFilter = regexp.MustCompile(`^\s*-- only: (postgres|sqlite)(?: for next (\d+) lines| until "(end) only")?`)
//
// If the filter ends with `(lines commented)`, then ALL lines chosen by the filter will be uncommented.
var dialectLineFilter = regexp.MustCompile(`^\s*-- only: (postgres|sqlite)(?: for next (\d+) lines| until "(end) only")?(?: \(lines? (commented)\))?`)
// Constants used to make parseDialectFilter clearer
const (
skipUntilEndTag = -1
skipNothing = 0
skipCurrentLine = 1
skipNextLine = 2
skipNextLine = 1
)
func (db *Database) parseDialectFilter(line []byte) (int, error) {
func (db *Database) parseDialectFilter(line []byte) (dialect Dialect, lineCount int, uncomment bool, err error) {
match := dialectLineFilter.FindSubmatch(line)
if match == nil {
return skipNothing, nil
return
}
dialect, err := ParseDialect(string(match[1]))
dialect, err = ParseDialect(string(match[1]))
if err != nil {
return skipNothing, err
} else if dialect == db.Dialect {
// Skip the dialect filter line
return skipCurrentLine, nil
} else if bytes.Equal(match[3], []byte("end")) {
return skipUntilEndTag, nil
} else if len(match[2]) == 0 {
// Skip the dialect filter and the next line
return skipNextLine, nil
} else {
// Parse number of lines to skip, add 1 for current line
lineCount, err := strconv.Atoi(string(match[2]))
if err != nil {
return skipNothing, fmt.Errorf("invalid line count '%s': %w", match[2], err)
}
return skipCurrentLine + lineCount, nil
return
}
uncomment = bytes.Equal(match[4], []byte("commented"))
if bytes.Equal(match[3], []byte("end")) {
lineCount = skipUntilEndTag
} else if len(match[2]) == 0 {
lineCount = skipNextLine
} else {
lineCount, err = strconv.Atoi(string(match[2]))
if err != nil {
err = fmt.Errorf("invalid line count %q: %w", match[2], err)
}
}
return
}
var endLineFilter = regexp.MustCompile(`^\s*-- end only (postgres|sqlite)$`)
@@ -162,15 +160,16 @@ var endLineFilter = regexp.MustCompile(`^\s*-- end only (postgres|sqlite)$`)
func (db *Database) filterSQLUpgrade(lines [][]byte) (string, error) {
output := make([][]byte, 0, len(lines))
for i := 0; i < len(lines); i++ {
skipLines, err := db.parseDialectFilter(lines[i])
dialect, lineCount, uncomment, err := db.parseDialectFilter(lines[i])
if err != nil {
return "", err
} else if skipLines > 0 {
// Current line is implicitly skipped, so reduce one here
i += skipLines - 1
} else if skipLines == skipUntilEndTag {
} else if lineCount == skipNothing {
output = append(output, lines[i])
} else if lineCount == skipUntilEndTag {
startedAt := i
startedAtMatch := dialectLineFilter.FindSubmatch(lines[startedAt])
// Skip filter start line
i++
for ; i < len(lines); i++ {
if match := endLineFilter.FindSubmatch(lines[i]); match != nil {
if !bytes.Equal(match[1], startedAtMatch[1]) {
@@ -178,12 +177,32 @@ func (db *Database) filterSQLUpgrade(lines [][]byte) (string, error) {
}
break
}
if dialect == db.Dialect {
if uncomment {
output = append(output, bytes.TrimPrefix(lines[i], []byte("--")))
} else {
output = append(output, lines[i])
}
}
}
if i == len(lines) {
return "", fmt.Errorf(`didn't get end tag matching start %q at line %d`, string(startedAtMatch[1]), startedAt)
}
} else if dialect != db.Dialect {
i += lineCount
} else {
output = append(output, lines[i])
// Skip current line, uncomment the specified number of lines
i++
targetI := i + lineCount
for ; i < targetI; i++ {
if uncomment {
output = append(output, bytes.TrimPrefix(lines[i], []byte("--")))
} else {
output = append(output, lines[i])
}
}
// Decrement counter to avoid skipping the next line
i--
}
}
return string(bytes.Join(output, []byte("\n"))), nil
@@ -191,7 +210,7 @@ func (db *Database) filterSQLUpgrade(lines [][]byte) (string, error) {
func sqlUpgradeFunc(fileName string, lines [][]byte) upgradeFunc {
return func(ctx context.Context, db *Database) error {
if skip, err := db.parseDialectFilter(lines[0]); err == nil && skip == skipNextLine {
if dialect, skip, _, err := db.parseDialectFilter(lines[0]); err == nil && skip == skipNextLine && dialect != db.Dialect {
return nil
} else if upgradeSQL, err := db.filterSQLUpgrade(lines); err != nil {
panic(fmt.Errorf("failed to parse upgrade %s: %w", fileName, err))
+8
View File
@@ -904,6 +904,10 @@ func (k *skECDSAPublicKey) Verify(data []byte, sig *Signature) error {
return errors.New("ssh: signature did not verify")
}
func (k *skECDSAPublicKey) CryptoPublicKey() crypto.PublicKey {
return &k.PublicKey
}
type skEd25519PublicKey struct {
// application is a URL-like string, typically "ssh:" for SSH.
// see openssh/PROTOCOL.u2f for details.
@@ -1000,6 +1004,10 @@ func (k *skEd25519PublicKey) Verify(data []byte, sig *Signature) error {
return nil
}
func (k *skEd25519PublicKey) CryptoPublicKey() crypto.PublicKey {
return k.PublicKey
}
// NewSignerFromKey takes an *rsa.PrivateKey, *dsa.PrivateKey,
// *ecdsa.PrivateKey or any other crypto.Signer and returns a
// corresponding Signer instance. ECDSA keys must use P-256, P-384 or
+30
View File
@@ -462,6 +462,24 @@ func (p *PartialSuccessError) Error() string {
// It is returned in ServerAuthError.Errors from NewServerConn.
var ErrNoAuth = errors.New("ssh: no auth passed yet")
// BannerError is an error that can be returned by authentication handlers in
// ServerConfig to send a banner message to the client.
type BannerError struct {
Err error
Message string
}
func (b *BannerError) Unwrap() error {
return b.Err
}
func (b *BannerError) Error() string {
if b.Err == nil {
return b.Message
}
return b.Err.Error()
}
func (s *connection) serverAuthenticate(config *ServerConfig) (*Permissions, error) {
sessionID := s.transport.getSessionID()
var cache pubKeyCache
@@ -734,6 +752,18 @@ userAuthLoop:
config.AuthLogCallback(s, userAuthReq.Method, authErr)
}
var bannerErr *BannerError
if errors.As(authErr, &bannerErr) {
if bannerErr.Message != "" {
bannerMsg := &userAuthBannerMsg{
Message: bannerErr.Message,
}
if err := s.transport.writePacket(Marshal(bannerMsg)); err != nil {
return nil, err
}
}
}
if authErr == nil {
break userAuthLoop
}
+3 -1
View File
@@ -22,10 +22,12 @@ func Sort[S ~[]E, E constraints.Ordered](x S) {
// SortFunc sorts the slice x in ascending order as determined by the cmp
// function. This sort is not guaranteed to be stable.
// cmp(a, b) should return a negative number when a < b, a positive number when
// a > b and zero when a == b.
// a > b and zero when a == b or when a is not comparable to b in the sense
// of the formal definition of Strict Weak Ordering.
//
// SortFunc requires that cmp is a strict weak ordering.
// See https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings.
// To indicate 'uncomparable', return 0 from the function.
func SortFunc[S ~[]E, E any](x S, cmp func(a, b E) int) {
n := len(x)
pdqsortCmpFunc(x, 0, n, bits.Len(uint(n)), cmp)
+2
View File
@@ -263,6 +263,7 @@ struct ltchars {
#include <linux/sched.h>
#include <linux/seccomp.h>
#include <linux/serial.h>
#include <linux/sock_diag.h>
#include <linux/sockios.h>
#include <linux/taskstats.h>
#include <linux/tipc.h>
@@ -549,6 +550,7 @@ ccflags="$@"
$2 !~ "NLA_TYPE_MASK" &&
$2 !~ /^RTC_VL_(ACCURACY|BACKUP|DATA)/ &&
$2 ~ /^(NETLINK|NLM|NLMSG|NLA|IFA|IFAN|RT|RTC|RTCF|RTN|RTPROT|RTNH|ARPHRD|ETH_P|NETNSA)_/ ||
$2 ~ /^SOCK_|SK_DIAG_|SKNLGRP_$/ ||
$2 ~ /^FIORDCHK$/ ||
$2 ~ /^SIOC/ ||
$2 ~ /^TIOC/ ||
+18 -2
View File
@@ -502,6 +502,7 @@ const (
BPF_IMM = 0x0
BPF_IND = 0x40
BPF_JA = 0x0
BPF_JCOND = 0xe0
BPF_JEQ = 0x10
BPF_JGE = 0x30
BPF_JGT = 0x20
@@ -657,6 +658,9 @@ const (
CAN_NPROTO = 0x8
CAN_RAW = 0x1
CAN_RAW_FILTER_MAX = 0x200
CAN_RAW_XL_VCID_RX_FILTER = 0x4
CAN_RAW_XL_VCID_TX_PASS = 0x2
CAN_RAW_XL_VCID_TX_SET = 0x1
CAN_RTR_FLAG = 0x40000000
CAN_SFF_ID_BITS = 0xb
CAN_SFF_MASK = 0x7ff
@@ -1339,6 +1343,7 @@ const (
F_OFD_SETLK = 0x25
F_OFD_SETLKW = 0x26
F_OK = 0x0
F_SEAL_EXEC = 0x20
F_SEAL_FUTURE_WRITE = 0x10
F_SEAL_GROW = 0x4
F_SEAL_SEAL = 0x1
@@ -1627,6 +1632,7 @@ const (
IP_FREEBIND = 0xf
IP_HDRINCL = 0x3
IP_IPSEC_POLICY = 0x10
IP_LOCAL_PORT_RANGE = 0x33
IP_MAXPACKET = 0xffff
IP_MAX_MEMBERSHIPS = 0x14
IP_MF = 0x2000
@@ -1653,6 +1659,7 @@ const (
IP_PMTUDISC_OMIT = 0x5
IP_PMTUDISC_PROBE = 0x3
IP_PMTUDISC_WANT = 0x1
IP_PROTOCOL = 0x34
IP_RECVERR = 0xb
IP_RECVERR_RFC4884 = 0x1a
IP_RECVFRAGSIZE = 0x19
@@ -2169,7 +2176,7 @@ const (
NFT_SECMARK_CTX_MAXLEN = 0x100
NFT_SET_MAXNAMELEN = 0x100
NFT_SOCKET_MAX = 0x3
NFT_TABLE_F_MASK = 0x3
NFT_TABLE_F_MASK = 0x7
NFT_TABLE_MAXNAMELEN = 0x100
NFT_TRACETYPE_MAX = 0x3
NFT_TUNNEL_F_MASK = 0x7
@@ -2403,6 +2410,7 @@ const (
PERF_RECORD_MISC_USER = 0x2
PERF_SAMPLE_BRANCH_PLM_ALL = 0x7
PERF_SAMPLE_WEIGHT_TYPE = 0x1004000
PID_FS_MAGIC = 0x50494446
PIPEFS_MAGIC = 0x50495045
PPPIOCGNPMODE = 0xc008744c
PPPIOCNEWUNIT = 0xc004743e
@@ -2896,8 +2904,9 @@ const (
RWF_APPEND = 0x10
RWF_DSYNC = 0x2
RWF_HIPRI = 0x1
RWF_NOAPPEND = 0x20
RWF_NOWAIT = 0x8
RWF_SUPPORTED = 0x1f
RWF_SUPPORTED = 0x3f
RWF_SYNC = 0x4
RWF_WRITE_LIFE_NOT_SET = 0x0
SCHED_BATCH = 0x3
@@ -2918,7 +2927,9 @@ const (
SCHED_RESET_ON_FORK = 0x40000000
SCHED_RR = 0x2
SCM_CREDENTIALS = 0x2
SCM_PIDFD = 0x4
SCM_RIGHTS = 0x1
SCM_SECURITY = 0x3
SCM_TIMESTAMP = 0x1d
SC_LOG_FLUSH = 0x100000
SECCOMP_ADDFD_FLAG_SEND = 0x2
@@ -3051,6 +3062,8 @@ const (
SIOCSMIIREG = 0x8949
SIOCSRARP = 0x8962
SIOCWANDEV = 0x894a
SK_DIAG_BPF_STORAGE_MAX = 0x3
SK_DIAG_BPF_STORAGE_REQ_MAX = 0x1
SMACK_MAGIC = 0x43415d53
SMART_AUTOSAVE = 0xd2
SMART_AUTO_OFFLINE = 0xdb
@@ -3071,6 +3084,8 @@ const (
SOCKFS_MAGIC = 0x534f434b
SOCK_BUF_LOCK_MASK = 0x3
SOCK_DCCP = 0x6
SOCK_DESTROY = 0x15
SOCK_DIAG_BY_FAMILY = 0x14
SOCK_IOC_TYPE = 0x89
SOCK_PACKET = 0xa
SOCK_RAW = 0x3
@@ -3260,6 +3275,7 @@ const (
TCP_MAX_WINSHIFT = 0xe
TCP_MD5SIG = 0xe
TCP_MD5SIG_EXT = 0x20
TCP_MD5SIG_FLAG_IFINDEX = 0x2
TCP_MD5SIG_FLAG_PREFIX = 0x1
TCP_MD5SIG_MAXKEYLEN = 0x50
TCP_MSS = 0x200
+1
View File
@@ -118,6 +118,7 @@ const (
IXOFF = 0x1000
IXON = 0x400
MAP_32BIT = 0x40
MAP_ABOVE4G = 0x80
MAP_ANON = 0x20
MAP_ANONYMOUS = 0x20
MAP_DENYWRITE = 0x800
+1
View File
@@ -118,6 +118,7 @@ const (
IXOFF = 0x1000
IXON = 0x400
MAP_32BIT = 0x40
MAP_ABOVE4G = 0x80
MAP_ANON = 0x20
MAP_ANONYMOUS = 0x20
MAP_DENYWRITE = 0x800
+1
View File
@@ -87,6 +87,7 @@ const (
FICLONE = 0x40049409
FICLONERANGE = 0x4020940d
FLUSHO = 0x1000
FPMR_MAGIC = 0x46504d52
FPSIMD_MAGIC = 0x46508001
FS_IOC_ENABLE_VERITY = 0x40806685
FS_IOC_GETFLAGS = 0x80086601
+34 -3
View File
@@ -4605,7 +4605,7 @@ const (
NL80211_ATTR_MAC_HINT = 0xc8
NL80211_ATTR_MAC_MASK = 0xd7
NL80211_ATTR_MAX_AP_ASSOC_STA = 0xca
NL80211_ATTR_MAX = 0x149
NL80211_ATTR_MAX = 0x14a
NL80211_ATTR_MAX_CRIT_PROT_DURATION = 0xb4
NL80211_ATTR_MAX_CSA_COUNTERS = 0xce
NL80211_ATTR_MAX_MATCH_SETS = 0x85
@@ -5209,7 +5209,7 @@ const (
NL80211_FREQUENCY_ATTR_GO_CONCURRENT = 0xf
NL80211_FREQUENCY_ATTR_INDOOR_ONLY = 0xe
NL80211_FREQUENCY_ATTR_IR_CONCURRENT = 0xf
NL80211_FREQUENCY_ATTR_MAX = 0x1f
NL80211_FREQUENCY_ATTR_MAX = 0x20
NL80211_FREQUENCY_ATTR_MAX_TX_POWER = 0x6
NL80211_FREQUENCY_ATTR_NO_10MHZ = 0x11
NL80211_FREQUENCY_ATTR_NO_160MHZ = 0xc
@@ -5703,7 +5703,7 @@ const (
NL80211_STA_FLAG_ASSOCIATED = 0x7
NL80211_STA_FLAG_AUTHENTICATED = 0x5
NL80211_STA_FLAG_AUTHORIZED = 0x1
NL80211_STA_FLAG_MAX = 0x7
NL80211_STA_FLAG_MAX = 0x8
NL80211_STA_FLAG_MAX_OLD_API = 0x6
NL80211_STA_FLAG_MFP = 0x4
NL80211_STA_FLAG_SHORT_PREAMBLE = 0x2
@@ -6001,3 +6001,34 @@ type CachestatRange struct {
Off uint64
Len uint64
}
const (
SK_MEMINFO_RMEM_ALLOC = 0x0
SK_MEMINFO_RCVBUF = 0x1
SK_MEMINFO_WMEM_ALLOC = 0x2
SK_MEMINFO_SNDBUF = 0x3
SK_MEMINFO_FWD_ALLOC = 0x4
SK_MEMINFO_WMEM_QUEUED = 0x5
SK_MEMINFO_OPTMEM = 0x6
SK_MEMINFO_BACKLOG = 0x7
SK_MEMINFO_DROPS = 0x8
SK_MEMINFO_VARS = 0x9
SKNLGRP_NONE = 0x0
SKNLGRP_INET_TCP_DESTROY = 0x1
SKNLGRP_INET_UDP_DESTROY = 0x2
SKNLGRP_INET6_TCP_DESTROY = 0x3
SKNLGRP_INET6_UDP_DESTROY = 0x4
SK_DIAG_BPF_STORAGE_REQ_NONE = 0x0
SK_DIAG_BPF_STORAGE_REQ_MAP_FD = 0x1
SK_DIAG_BPF_STORAGE_REP_NONE = 0x0
SK_DIAG_BPF_STORAGE = 0x1
SK_DIAG_BPF_STORAGE_NONE = 0x0
SK_DIAG_BPF_STORAGE_PAD = 0x1
SK_DIAG_BPF_STORAGE_MAP_ID = 0x2
SK_DIAG_BPF_STORAGE_MAP_VALUE = 0x3
)
type SockDiagReq struct {
Family uint8
Protocol uint8
}
+1
View File
@@ -68,6 +68,7 @@ type UserInfo10 struct {
//sys NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) = netapi32.NetUserGetInfo
//sys NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (neterr error) = netapi32.NetGetJoinInformation
//sys NetApiBufferFree(buf *byte) (neterr error) = netapi32.NetApiBufferFree
//sys NetUserEnum(serverName *uint16, level uint32, filter uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32, resumeHandle *uint32) (neterr error) = netapi32.NetUserEnum
const (
// do not reorder
+9
View File
@@ -401,6 +401,7 @@ var (
procTransmitFile = modmswsock.NewProc("TransmitFile")
procNetApiBufferFree = modnetapi32.NewProc("NetApiBufferFree")
procNetGetJoinInformation = modnetapi32.NewProc("NetGetJoinInformation")
procNetUserEnum = modnetapi32.NewProc("NetUserEnum")
procNetUserGetInfo = modnetapi32.NewProc("NetUserGetInfo")
procNtCreateFile = modntdll.NewProc("NtCreateFile")
procNtCreateNamedPipeFile = modntdll.NewProc("NtCreateNamedPipeFile")
@@ -3486,6 +3487,14 @@ func NetGetJoinInformation(server *uint16, name **uint16, bufType *uint32) (nete
return
}
func NetUserEnum(serverName *uint16, level uint32, filter uint32, buf **byte, prefMaxLen uint32, entriesRead *uint32, totalEntries *uint32, resumeHandle *uint32) (neterr error) {
r0, _, _ := syscall.Syscall9(procNetUserEnum.Addr(), 8, uintptr(unsafe.Pointer(serverName)), uintptr(level), uintptr(filter), uintptr(unsafe.Pointer(buf)), uintptr(prefMaxLen), uintptr(unsafe.Pointer(entriesRead)), uintptr(unsafe.Pointer(totalEntries)), uintptr(unsafe.Pointer(resumeHandle)), 0)
if r0 != 0 {
neterr = syscall.Errno(r0)
}
return
}
func NetUserGetInfo(serverName *uint16, userName *uint16, level uint32, buf **byte) (neterr error) {
r0, _, _ := syscall.Syscall6(procNetUserGetInfo.Addr(), 4, uintptr(unsafe.Pointer(serverName)), uintptr(unsafe.Pointer(userName)), uintptr(level), uintptr(unsafe.Pointer(buf)), 0, 0)
if r0 != 0 {
+1
View File
@@ -15,5 +15,6 @@ Jan Mercl <0xjnml@gmail.com>
Jason DeBettencourt <jasond17@gmail.com>
Koichi Shiraishi <zchee.io@gmail.com>
Marius Orcsik <marius@federated.id>
Patricio Whittingslow <graded.sp@gmail.com>
Scot C Bontrager <scot@indievisible.org>
Steffen Butzer <steffen(dot)butzer@outlook.com>
+3
View File
@@ -8,12 +8,15 @@
Dan Kortschak <dan@kortschak.io>
Dan Peterson <danp@danp.net>
Bjørn Wiegell <bj.wiegell@gmail.com>
Fabrice Colliot <f.colliot@gmail.com>
Jaap Aarts <jaap.aarts1@gmail.com>
Jan Mercl <0xjnml@gmail.com>
Jason DeBettencourt <jasond17@gmail.com>
Koichi Shiraishi <zchee.io@gmail.com>
Marius Orcsik <marius@federated.id>
Patricio Whittingslow <graded.sp@gmail.com>
Scot C Bontrager <scot@indievisible.org>
Steffen Butzer <steffen(dot)butzer@outlook.com>
W. Michael Petullo <mike@flyn.org>
ZHU Zijia <piggynl@outlook.com>
+564 -1
View File
@@ -9,6 +9,9 @@ SHELL=/bin/bash -o pipefail
DIR = /tmp/libc
TAR = musl-7ada6dde6f9dc6a2836c3d92c2f762d35fd229e0.tar.gz
URL = https://git.musl-libc.org/cgit/musl/snapshot/$(TAR)
UCRT_386 = libc_windows_386.go
UCRT_AMD64 = libc_windows_amd64.go
UCRT_ARM64 = libc_windows_arm64.go
all: editor
golint 2>&1
@@ -33,7 +36,7 @@ download:
edit:
@touch log
@if [ -f "Session.vim" ]; then novim -S & else novim -p Makefile all_musl_test.go generator.go libc.go libc_musl.go & fi
@if [ -f "Session.vim" ]; then novim -S & else novim -p Makefile all_windows_test.go generator.go libc.go libc_windows*.go & fi
editor:
gofmt -l -s -w *.go 2>&1 | tee log-editor
@@ -41,6 +44,566 @@ editor:
go install -v 2>&1 | tee -a log-editor
go build -o /dev/null generator*.go
ucrt:
make ucrt_amd64 ucrt_arm64 ucrt_386
go build -v ./... 2>&1 | tee -a log-generate
GOOS=darwin go build -v ./... 2>&1 | tee -a log-generate
git status
ucrt_amd64:
echo -n > log-generate
( ccgo -v4 \
--cpp=$(shell which x86_64-w64-mingw32-gcc) \
--goos=windows \
--goarch=amd64 \
--package-name libc \
--prefix-external=X \
--prefix-field=F \
--prefix-static-internal=_ \
--prefix-static-none=_ \
--prefix-tagged-struct=T \
--prefix-tagged-union=T \
--prefix-typename=T \
--winapi-test panic \
--winapi=ctype.h \
--winapi=float.h \
--winapi=io.h \
--winapi=libucrt.c \
--winapi=locale.h \
--winapi=malloc.h \
--winapi=math.h \
--winapi=process.h \
--winapi=types.h \
--winapi=stat.h \
--winapi=stdio.h \
--winapi=stdlib.h \
--winapi=string.h \
--winapi=time.h \
--winapi=timeb.h \
--winapi=wchar.h \
--winapi=winbase.h \
-build-lines=" " \
-eval-all-macros \
-hide __acrt_iob_func \
-hide __create_locale \
-hide __free_locale \
-hide __get_current_locale \
-hide __iob_func \
-hide __lock_fhandle \
-hide __sep__ \
-hide __updatetlocinfo \
-hide __updatetmbcinfo \
-hide _beginthread \
-hide _beginthreadex \
-hide _endthreadex \
-hide _errno \
-hide _filbuf \
-hide _flsbuf \
-hide _get_amblksiz \
-hide _get_osplatform \
-hide _get_osver \
-hide _get_output_format \
-hide _get_sbh_threshold \
-hide _get_winmajor \
-hide _get_winminor \
-hide _get_winver \
-hide _heapadd \
-hide _heapset \
-hide _heapused \
-hide _matherr \
-hide _onexit \
-hide _set_amblksiz \
-hide _set_malloc_crt_max_wait \
-hide _set_output_format \
-hide _set_sbh_threshold \
-hide _strcmpi \
-hide _strnset_l \
-hide _strset_l \
-hide _unlock_fhandle \
-hide _wcsncpy_l \
-hide _wctime \
-hide _wctime_s \
-hide _wgetdcwd_nolock \
-hide _wgetenv \
-hide _wputenv \
-hide access \
-hide at_quick_exit \
-hide atexit \
-hide chdir \
-hide exit \
-hide lldiv \
-hide qsort \
-hide chmod \
-hide chsize \
-hide close \
-hide creat \
-hide cwait \
-hide dup \
-hide dup2 \
-hide eof \
-hide execv \
-hide execve \
-hide execvp \
-hide execvpe \
-hide fcloseall \
-hide fdopen \
-hide fgetchar \
-hide fgetpos64 \
-hide filelength \
-hide fileno \
-hide flushall \
-hide fopen64 \
-hide fpreset \
-hide fputchar \
-hide fsetpos64 \
-hide ftime \
-hide fwide \
-hide getcwd \
-hide getpid \
-hide getw \
-hide isatty \
-hide itoa \
-hide lltoa \
-hide lltow \
-hide locking \
-hide lseek \
-hide lseek64 \
-hide ltoa \
-hide memccpy \
-hide memicmp \
-hide mempcpy \
-hide mkdir \
-hide mkstemp \
-hide mktemp \
-hide onexit \
-hide putenv \
-hide putw \
-hide read \
-hide rmdir \
-hide rmtmp \
-hide setmode \
-hide spawnv \
-hide spawnve \
-hide spawnvp \
-hide spawnvpe \
-hide strcasecmp \
-hide strcmpi \
-hide strdup \
-hide stricmp \
-hide strlwr \
-hide strlwr_l \
-hide strncasecmp \
-hide strnicmp \
-hide strnset \
-hide strrev \
-hide strset \
-hide strtok_r \
-hide strupr \
-hide swab \
-hide tell \
-hide tempnam \
-hide tzset \
-hide ulltoa \
-hide ulltow \
-hide ultoa \
-hide umask \
-hide unlink \
-hide wcsdup \
-hide wcsicmp \
-hide wcsicoll \
-hide wcslwr \
-hide wcsnicmp \
-hide wcsnset \
-hide wcsrev \
-hide wcsset \
-hide wcsupr \
-hide wmemchr \
-hide wmemcmp \
-hide wmemcpy \
-hide wmemmove \
-hide wmempcpy \
-hide wmemset \
-hide write \
-hide wtoll \
-ignore-link-errors \
-import syscall \
-keep-strings \
-o $(UCRT_AMD64) \
libucrt.c \
|| true ) 2>&1 | tee -a log-generate
sed -i '/"modernc.org\/libc"/d' $(UCRT_AMD64)
sed -i 's/\<libc\>\.//g' $(UCRT_AMD64)
GOOS=windows GOARCH=amd64 go build -v ./... 2>&1 | tee -a log-generate
ucrt_arm64:
echo -n > log-generate
( ccgo -v4 \
--cpp=$(shell which x86_64-w64-mingw32-gcc) \
--goos=windows \
--goarch=amd64 \
--package-name libc \
--prefix-external=X \
--prefix-field=F \
--prefix-static-internal=_ \
--prefix-static-none=_ \
--prefix-tagged-struct=T \
--prefix-tagged-union=T \
--prefix-typename=T \
--winapi-test panic \
--winapi=ctype.h \
--winapi=float.h \
--winapi=io.h \
--winapi=libucrt.c \
--winapi=locale.h \
--winapi=malloc.h \
--winapi=math.h \
--winapi=process.h \
--winapi=types.h \
--winapi=stat.h \
--winapi=stdio.h \
--winapi=stdlib.h \
--winapi=string.h \
--winapi=time.h \
--winapi=timeb.h \
--winapi=wchar.h \
--winapi=winbase.h \
-build-lines=" " \
-eval-all-macros \
-hide __acrt_iob_func \
-hide _errno \
-hide _wgetenv \
-hide _wputenv \
-hide exit \
-hide lldiv \
-hide qsort \
-hide __sep__ \
-hide __create_locale \
-hide __free_locale \
-hide __get_current_locale \
-hide __iob_func \
-hide __lock_fhandle \
-hide __updatetlocinfo \
-hide __updatetmbcinfo \
-hide _beginthread \
-hide _beginthreadex \
-hide _endthreadex \
-hide _filbuf \
-hide _flsbuf \
-hide _get_amblksiz \
-hide _get_osplatform \
-hide _get_osver \
-hide _get_output_format \
-hide _get_sbh_threshold \
-hide _get_winmajor \
-hide _get_winminor \
-hide _get_winver \
-hide _heapadd \
-hide _heapset \
-hide _heapused \
-hide _matherr \
-hide _onexit \
-hide _set_amblksiz \
-hide _set_malloc_crt_max_wait \
-hide _set_output_format \
-hide _set_sbh_threshold \
-hide _strcmpi \
-hide _strnset_l \
-hide _strset_l \
-hide _unlock_fhandle \
-hide _wcsncpy_l \
-hide _wctime \
-hide _wctime_s \
-hide _wgetdcwd_nolock \
-hide access \
-hide at_quick_exit \
-hide atexit \
-hide chdir \
-hide chmod \
-hide chsize \
-hide close \
-hide creat \
-hide cwait \
-hide dup \
-hide dup2 \
-hide eof \
-hide execv \
-hide execve \
-hide execvp \
-hide execvpe \
-hide fcloseall \
-hide fdopen \
-hide fgetchar \
-hide fgetpos64 \
-hide filelength \
-hide fileno \
-hide flushall \
-hide fopen64 \
-hide fpreset \
-hide fputchar \
-hide fsetpos64 \
-hide ftime \
-hide fwide \
-hide getcwd \
-hide getpid \
-hide getw \
-hide isatty \
-hide itoa \
-hide lltoa \
-hide lltow \
-hide locking \
-hide lseek \
-hide lseek64 \
-hide ltoa \
-hide memccpy \
-hide memicmp \
-hide mempcpy \
-hide mkdir \
-hide mkstemp \
-hide mktemp \
-hide onexit \
-hide putenv \
-hide putw \
-hide read \
-hide rmdir \
-hide rmtmp \
-hide setmode \
-hide spawnv \
-hide spawnve \
-hide spawnvp \
-hide spawnvpe \
-hide strcasecmp \
-hide strcmpi \
-hide strdup \
-hide stricmp \
-hide strlwr \
-hide strlwr_l \
-hide strncasecmp \
-hide strnicmp \
-hide strnset \
-hide strrev \
-hide strset \
-hide strtok_r \
-hide strupr \
-hide swab \
-hide tell \
-hide tempnam \
-hide tzset \
-hide ulltoa \
-hide ulltow \
-hide ultoa \
-hide umask \
-hide unlink \
-hide wcsdup \
-hide wcsicmp \
-hide wcsicoll \
-hide wcslwr \
-hide wcsnicmp \
-hide wcsnset \
-hide wcsrev \
-hide wcsset \
-hide wcsupr \
-hide wmemchr \
-hide wmemcmp \
-hide wmemcpy \
-hide wmemmove \
-hide wmempcpy \
-hide wmemset \
-hide write \
-hide wtoll \
-ignore-link-errors \
-import syscall \
-keep-strings \
-o $(UCRT_ARM64) \
libucrt.c \
|| true ) 2>&1 | tee -a log-generate
sed -i '/"modernc.org\/libc"/d' $(UCRT_ARM64)
sed -i 's/\<libc\>\.//g' $(UCRT_ARM64)
GOOS=windows GOARCH=arm64 go build -v ./... 2>&1 | tee -a log-generate
ucrt_386:
echo -n > log-generate
( ccgo -v4 \
--cpp=$(shell which i686-w64-mingw32-gcc) \
--goos=windows \
--goarch=386 \
--package-name libc \
--prefix-external=X \
--prefix-field=F \
--prefix-static-internal=_ \
--prefix-static-none=_ \
--prefix-tagged-struct=T \
--prefix-tagged-union=T \
--prefix-typename=T \
--winapi-test panic \
--winapi=ctype.h \
--winapi=float.h \
--winapi=io.h \
--winapi=libucrt.c \
--winapi=locale.h \
--winapi=malloc.h \
--winapi=math.h \
--winapi=process.h \
--winapi=types.h \
--winapi=stat.h \
--winapi=stdio.h \
--winapi=stdlib.h \
--winapi=string.h \
--winapi=time.h \
--winapi=timeb.h \
--winapi=wchar.h \
--winapi=winbase.h \
-build-lines=" " \
-eval-all-macros \
-hide __acrt_iob_func \
-hide _errno \
-hide _wgetenv \
-hide _wputenv \
-hide exit \
-hide lldiv \
-hide qsort \
-hide __sep__ \
-hide __create_locale \
-hide __free_locale \
-hide __get_current_locale \
-hide __lock_fhandle \
-hide __updatetlocinfo \
-hide __updatetmbcinfo \
-hide _beginthread \
-hide _beginthreadex \
-hide _endthreadex \
-hide _filbuf \
-hide _flsbuf \
-hide _get_amblksiz \
-hide _get_osplatform \
-hide _get_osver \
-hide _get_output_format \
-hide _get_sbh_threshold \
-hide _get_winmajor \
-hide _get_winminor \
-hide _get_winver \
-hide _heapadd \
-hide _heapset \
-hide _heapused \
-hide _matherr \
-hide _onexit \
-hide _set_amblksiz \
-hide _set_malloc_crt_max_wait \
-hide _set_output_format \
-hide _set_sbh_threshold \
-hide _strcmpi \
-hide _strnset_l \
-hide _strset_l \
-hide _unlock_fhandle \
-hide _wcsncpy_l \
-hide _wctime \
-hide _wctime_s \
-hide _wgetdcwd_nolock \
-hide access \
-hide at_quick_exit \
-hide atexit \
-hide chdir \
-hide chmod \
-hide chsize \
-hide close \
-hide creat \
-hide cwait \
-hide dup \
-hide dup2 \
-hide eof \
-hide execv \
-hide execve \
-hide execvp \
-hide execvpe \
-hide fcloseall \
-hide fdopen \
-hide fgetchar \
-hide fgetpos64 \
-hide filelength \
-hide fileno \
-hide flushall \
-hide fopen64 \
-hide fpreset \
-hide fputchar \
-hide fsetpos64 \
-hide ftime \
-hide fwide \
-hide getcwd \
-hide getpid \
-hide getw \
-hide isatty \
-hide itoa \
-hide lltoa \
-hide lltow \
-hide locking \
-hide lseek \
-hide lseek64 \
-hide ltoa \
-hide memccpy \
-hide memicmp \
-hide mempcpy \
-hide mkdir \
-hide mkstemp \
-hide mktemp \
-hide onexit \
-hide putenv \
-hide putw \
-hide read \
-hide rmdir \
-hide rmtmp \
-hide setmode \
-hide spawnv \
-hide spawnve \
-hide spawnvp \
-hide spawnvpe \
-hide strcasecmp \
-hide strcmpi \
-hide strdup \
-hide stricmp \
-hide strlwr \
-hide strlwr_l \
-hide strncasecmp \
-hide strnicmp \
-hide strnset \
-hide strrev \
-hide strset \
-hide strtok_r \
-hide strupr \
-hide swab \
-hide tell \
-hide tempnam \
-hide tzset \
-hide ulltoa \
-hide ulltow \
-hide ultoa \
-hide umask \
-hide unlink \
-hide wcsdup \
-hide wcsicmp \
-hide wcsicoll \
-hide wcslwr \
-hide wcsnicmp \
-hide wcsnset \
-hide wcsrev \
-hide wcsset \
-hide wcsupr \
-hide wmemchr \
-hide wmemcmp \
-hide wmemcpy \
-hide wmemmove \
-hide wmempcpy \
-hide wmemset \
-hide write \
-hide wtoll \
-ignore-link-errors \
-import syscall \
-keep-strings \
-o $(UCRT_386) \
libucrt.c \
|| true ) 2>&1 | tee -a log-generate
sed -i '/"modernc.org\/libc"/d' $(UCRT_386)
sed -i 's/\<libc\>\.//g' $(UCRT_386)
GOOS=windows GOARCH=386 go build -v ./... 2>&1 | tee -a log-generate
generate: download
mkdir -p $(DIR) || true
rm -rf $(DIR)/*
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (amd64 || loong64)
//go:build linux && (amd64 || arm64 || loong64)
package libc // import "modernc.org/libc"
+95
View File
@@ -0,0 +1,95 @@
// Copyright 202 The Libc Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package libc // import "modernc.org/libc"
import (
"fmt"
"os"
"path/filepath"
"runtime"
"runtime/debug"
"strings"
"unsafe"
)
const (
heapAlign = 16
heapGuard = 16
)
const FALSE = 0
const TRUE = 1
var (
pid = fmt.Sprintf("[%v %v] ", os.Getpid(), filepath.Base(os.Args[0]))
)
func origin(skip int) string {
pc, fn, fl, _ := runtime.Caller(skip)
f := runtime.FuncForPC(pc)
var fns string
if f != nil {
fns = f.Name()
if x := strings.LastIndex(fns, "."); x > 0 {
fns = fns[x+1:]
}
}
return fmt.Sprintf("%s:%d:%s", filepath.Base(fn), fl, fns)
}
func trc(s string, args ...interface{}) string { //TODO-
switch {
case s == "":
s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
default:
s = fmt.Sprintf(s, args...)
}
r := fmt.Sprintf("%s: TRC %s (%v:)", origin(2), s, origin(3))
fmt.Fprintf(os.Stdout, "%s %s\n", pid, r)
os.Stdout.Sync()
return r
}
func todo(s string, args ...interface{}) string { //TODO-
switch {
case s == "":
s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
default:
s = fmt.Sprintf(s, args...)
}
r := fmt.Sprintf("%s %s: TODOTODO %s (%v:)", pid, origin(2), s, origin(3)) //TODOOK
if dmesgs {
dmesg("%s", r)
}
fmt.Fprintf(os.Stdout, "%s\n", r)
fmt.Fprintf(os.Stdout, "%s\n", debug.Stack()) //TODO-
os.Stdout.Sync()
os.Exit(1)
panic("unrechable")
}
type sorter struct {
len int
base uintptr
sz uintptr
f func(*TLS, uintptr, uintptr) int32
t *TLS
}
func (s *sorter) Len() int { return s.len }
func (s *sorter) Less(i, j int) bool {
return s.f(s.t, s.base+uintptr(i)*s.sz, s.base+uintptr(j)*s.sz) < 0
}
func (s *sorter) Swap(i, j int) {
p := s.base + uintptr(i)*s.sz
q := s.base + uintptr(j)*s.sz
for i := 0; i < int(s.sz); i++ {
*(*byte)(unsafe.Pointer(p)), *(*byte)(unsafe.Pointer(q)) = *(*byte)(unsafe.Pointer(q)), *(*byte)(unsafe.Pointer(p))
p++
q++
}
}
+6 -6
View File
@@ -2,13 +2,13 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (amd64 || loong64)
//go:build linux && (amd64 || arm64 || loong64)
package libc // import "modernc.org/libc/v2"
package libc // import "modernc.org/libc"
import (
"math"
"math/bits"
mbits "math/bits"
"sync/atomic"
"unsafe"
)
@@ -41,15 +41,15 @@ func a_store_16(addr uintptr, val uint16) {
// static inline int a_ctz_l(unsigned long x)
func _a_ctz_l(tls *TLS, x ulong) int32 {
if unsafe.Sizeof(x) == 8 {
return int32(bits.TrailingZeros64(x))
return int32(mbits.TrailingZeros64(x))
}
return int32(bits.TrailingZeros32(uint32(x)))
return int32(mbits.TrailingZeros32(uint32(x)))
}
// static inline int a_ctz_64(uint64_t x)
func _a_ctz_64(tls *TLS, x uint64) int32 {
return int32(bits.TrailingZeros64(x))
return int32(mbits.TrailingZeros64(x))
}
func AtomicAddFloat32(addr *float32, delta float32) (new float32) {
+4 -4
View File
@@ -1,9 +1,9 @@
{
"autogen": "linux/(amd64|loong64)",
"autogen": "linux/(amd64|arm64|loong64)",
"autoupdate": "",
"autotag": "darwin/(amd64|arm64)|freebsd/(amd64|arm64)|linux/(386|amd64|arm|arm64|loong64|ppc64le|riscv64|s390x)|openbsd/(386|amd64|arm64)|windows/(amd64|arm64)",
"autotag": "darwin/(amd64|arm64)|freebsd/(amd64|arm64)|linux/(386|amd64|arm|arm64|loong64|ppc64le|riscv64|s390x)|openbsd/(386|amd64|arm64)|windows/(amd64|arm64|386)",
"download": [
{"re": "linux/(amd64|loong64)", "files": ["https://git.musl-libc.org/cgit/musl/snapshot/musl-7ada6dde6f9dc6a2836c3d92c2f762d35fd229e0.tar.gz"]}
{"re": "linux/(amd64|arm64|loong64)", "files": ["https://git.musl-libc.org/cgit/musl/snapshot/musl-7ada6dde6f9dc6a2836c3d92c2f762d35fd229e0.tar.gz"]}
],
"test": "darwin/(amd64|arm64)|freebsd/(amd64|arm64)|linux/(386|amd64|arm|arm64|loong64|ppc64le|riscv64|s390x)|openbsd/(386|amd64|arm64)|windows/(amd64|arm64)"
"test": "darwin/(amd64|arm64)|freebsd/(amd64|arm64)|linux/(386|amd64|arm|arm64|loong64|ppc64le|riscv64|s390x)|openbsd/(386|amd64|arm64)|windows/(amd64|arm64|386)"
}
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (amd64 || loong64)
//go:build linux && (amd64 || arm64 || loong64)
package libc // import "modernc.org/libc"
+1 -1
View File
@@ -1,6 +1,6 @@
// Code generated by 'go generate' - DO NOT EDIT.
//go:build !(linux && (amd64 || loong64))
//go:build !(linux && (amd64 || arm64 || loong64))
package libc // import "modernc.org/libc"
+1212 -1213
View File
File diff suppressed because one or more lines are too long
+154129
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+7 -3
View File
@@ -10,7 +10,6 @@ package libc // import "modernc.org/libc"
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
)
@@ -18,7 +17,6 @@ import (
const dmesgs = true
var (
pid = fmt.Sprintf("[%v %v] ", os.Getpid(), filepath.Base(os.Args[0]))
logf *os.File
)
@@ -28,7 +26,7 @@ func init() {
panic(err.Error())
}
dmesg("%v", time.Now())
dmesg("==== dmesg init() %v", time.Now())
}
func dmesg(s string, args ...interface{}) {
@@ -43,3 +41,9 @@ func dmesg(s string, args ...interface{}) {
fmt.Fprintln(logf, s)
}
}
func dmesgFinish() {
dmesg("==== dmesgFinish() %v", time.Now())
logf.Sync()
logf.Close()
}
+1 -161
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !(linux && (amd64 || loong64))
//go:build !((linux && (amd64 || arm64 || loong64)) || windows)
package libc // import "modernc.org/libc"
@@ -13,7 +13,6 @@ import (
"path/filepath"
"reflect"
"runtime"
"runtime/debug"
"sort"
"strconv"
"strings"
@@ -62,50 +61,6 @@ func init() {
}
}
func origin(skip int) string {
pc, fn, fl, _ := runtime.Caller(skip)
f := runtime.FuncForPC(pc)
var fns string
if f != nil {
fns = f.Name()
if x := strings.LastIndex(fns, "."); x > 0 {
fns = fns[x+1:]
}
}
return fmt.Sprintf("%s:%d:%s", filepath.Base(fn), fl, fns)
}
func trc(s string, args ...interface{}) string { //TODO-
switch {
case s == "":
s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
default:
s = fmt.Sprintf(s, args...)
}
r := fmt.Sprintf("%s: TRC %s", origin(2), s)
fmt.Fprintf(os.Stdout, "%s\n", r)
os.Stdout.Sync()
return r
}
func todo(s string, args ...interface{}) string { //TODO-
switch {
case s == "":
s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
default:
s = fmt.Sprintf(s, args...)
}
r := fmt.Sprintf("%s: TODOTODO %s", origin(2), s) //TODOOK
if dmesgs {
dmesg("%s", r)
}
fmt.Fprintf(os.Stdout, "%s\n", r)
fmt.Fprintf(os.Stdout, "%s\n", debug.Stack()) //TODO-
os.Stdout.Sync()
os.Exit(1)
panic("unrechable")
}
var coverPCs [1]uintptr //TODO not concurrent safe
func Cover() {
@@ -481,97 +436,6 @@ func VaOther(app *uintptr, sz uint64) (r uintptr) {
return r
}
func VaInt32(app *uintptr) int32 {
ap := *(*uintptr)(unsafe.Pointer(app))
if ap == 0 {
return 0
}
ap = roundup(ap, 8)
v := int32(*(*int64)(unsafe.Pointer(ap)))
ap += 8
*(*uintptr)(unsafe.Pointer(app)) = ap
return v
}
func VaUint32(app *uintptr) uint32 {
ap := *(*uintptr)(unsafe.Pointer(app))
if ap == 0 {
return 0
}
ap = roundup(ap, 8)
v := uint32(*(*uint64)(unsafe.Pointer(ap)))
ap += 8
*(*uintptr)(unsafe.Pointer(app)) = ap
return v
}
func VaInt64(app *uintptr) int64 {
ap := *(*uintptr)(unsafe.Pointer(app))
if ap == 0 {
return 0
}
ap = roundup(ap, 8)
v := *(*int64)(unsafe.Pointer(ap))
ap += 8
*(*uintptr)(unsafe.Pointer(app)) = ap
return v
}
func VaUint64(app *uintptr) uint64 {
ap := *(*uintptr)(unsafe.Pointer(app))
if ap == 0 {
return 0
}
ap = roundup(ap, 8)
v := *(*uint64)(unsafe.Pointer(ap))
ap += 8
*(*uintptr)(unsafe.Pointer(app)) = ap
return v
}
func VaFloat32(app *uintptr) float32 {
ap := *(*uintptr)(unsafe.Pointer(app))
if ap == 0 {
return 0
}
ap = roundup(ap, 8)
v := *(*float64)(unsafe.Pointer(ap))
ap += 8
*(*uintptr)(unsafe.Pointer(app)) = ap
return float32(v)
}
func VaFloat64(app *uintptr) float64 {
ap := *(*uintptr)(unsafe.Pointer(app))
if ap == 0 {
return 0
}
ap = roundup(ap, 8)
v := *(*float64)(unsafe.Pointer(ap))
ap += 8
*(*uintptr)(unsafe.Pointer(app)) = ap
return v
}
func VaUintptr(app *uintptr) uintptr {
ap := *(*uintptr)(unsafe.Pointer(app))
if ap == 0 {
return 0
}
ap = roundup(ap, 8)
v := *(*uintptr)(unsafe.Pointer(ap))
ap += 8
*(*uintptr)(unsafe.Pointer(app)) = ap
return v
}
func getVaList(va uintptr) []string {
r := []string{}
@@ -637,30 +501,6 @@ func Bool64(b bool) int64 {
return 0
}
type sorter struct {
len int
base uintptr
sz uintptr
f func(*TLS, uintptr, uintptr) int32
t *TLS
}
func (s *sorter) Len() int { return s.len }
func (s *sorter) Less(i, j int) bool {
return s.f(s.t, s.base+uintptr(i)*s.sz, s.base+uintptr(j)*s.sz) < 0
}
func (s *sorter) Swap(i, j int) {
p := uintptr(s.base + uintptr(i)*s.sz)
q := uintptr(s.base + uintptr(j)*s.sz)
for i := 0; i < int(s.sz); i++ {
*(*byte)(unsafe.Pointer(p)), *(*byte)(unsafe.Pointer(q)) = *(*byte)(unsafe.Pointer(q)), *(*byte)(unsafe.Pointer(p))
p++
q++
}
}
func CString(s string) (uintptr, error) {
n := len(s)
p := Xmalloc(nil, types.Size_t(n)+1)
-69
View File
@@ -1,69 +0,0 @@
// Copyright 2023 The Libc Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (amd64 || loong64)
package libc // import "modernc.org/libc"
import (
"fmt"
"os"
"path/filepath"
"runtime"
"strings"
)
// origin returns caller's short position, skipping skip frames.
func origin(skip int) string {
pc, fn, fl, _ := runtime.Caller(skip)
f := runtime.FuncForPC(pc)
var fns string
if f != nil {
fns = f.Name()
if x := strings.LastIndex(fns, "."); x > 0 {
fns = fns[x+1:]
}
if strings.HasPrefix(fns, "func") {
num := true
for _, c := range fns[len("func"):] {
if c < '0' || c > '9' {
num = false
break
}
}
if num {
return origin(skip + 2)
}
}
}
return fmt.Sprintf("%s:%d:%s", filepath.Base(fn), fl, fns)
}
// todo prints and return caller's position and an optional message tagged with TODO. Output goes to stderr.
func todo(s string, args ...interface{}) string {
switch {
case s == "":
s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
default:
s = fmt.Sprintf(s, args...)
}
r := fmt.Sprintf("%s\n\tTODO %s", origin(2), s)
// fmt.Fprintf(os.Stderr, "%s\n", r)
// os.Stdout.Sync()
return r
}
// trc prints and return caller's position and an optional message tagged with TRC. Output goes to stderr.
func trc(s string, args ...interface{}) string {
switch {
case s == "":
s = fmt.Sprintf(strings.Repeat("%v ", len(args)), args...)
default:
s = fmt.Sprintf(s, args...)
}
r := fmt.Sprintf("%s: TRC %s", origin(2), s)
fmt.Fprintf(os.Stderr, "%s\n", r)
os.Stderr.Sync()
return r
}
+1 -1
View File
@@ -6,7 +6,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !(linux && (amd64 || loong64))
//go:build !(linux && (amd64 || arm64 || loong64))
package libc // import "modernc.org/libc"
+11 -377
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !(linux && (amd64 || loong64))
//go:build !((linux && (amd64 || arm64 || loong64)) || windows)
//go.generate echo package libc > ccgo.go
//go:generate go fmt ./...
@@ -51,7 +51,7 @@ type (
)
var (
allocMu sync.Mutex
allocatorMu sync.Mutex
environInitialized bool
isWindows bool
ungetcMu sync.Mutex
@@ -174,6 +174,7 @@ func exit(t *TLS, status int32, audit bool) {
func X_exit(_ *TLS, status int32) {
if dmesgs {
dmesg("%v: EXIT %v", origin(1), status)
dmesgFinish()
}
os.Exit(int(status))
}
@@ -510,13 +511,6 @@ func X__isnanl(t *TLS, arg float64) int32 {
return Xisnanl(t, arg)
}
func Xvfprintf(t *TLS, stream, format, ap uintptr) int32 {
if __ccgo_strace {
trc("t=%v ap=%v, (%v:)", t, ap, origin(2))
}
return Xfprintf(t, stream, format, ap)
}
// int __builtin_popcount (unsigned int x)
func X__builtin_popcount(t *TLS, x uint32) int32 {
if __ccgo_strace {
@@ -735,19 +729,6 @@ func AtomicStoreNUint16(ptr uintptr, val uint16, memorder int32) {
a_store_16(ptr, val)
}
// int sprintf(char *str, const char *format, ...);
func Xsprintf(t *TLS, str, format, args uintptr) (r int32) {
if __ccgo_strace {
trc("t=%v args=%v, (%v:)", t, args, origin(2))
defer func() { trc("-> %v", r) }()
}
b := printf(format, args)
r = int32(len(b))
copy((*RawMem)(unsafe.Pointer(str))[:r:r], b)
*(*byte)(unsafe.Pointer(str + uintptr(r))) = 0
return int32(len(b))
}
// int __builtin___sprintf_chk (char *s, int flag, size_t os, const char *fmt, ...);
func X__builtin___sprintf_chk(t *TLS, s uintptr, flag int32, os types.Size_t, format, args uintptr) (r int32) {
if __ccgo_strace {
@@ -795,14 +776,6 @@ func Xvprintf(t *TLS, s, ap uintptr) int32 {
return Xprintf(t, s, ap)
}
// int vsprintf(char *str, const char *format, va_list ap);
func Xvsprintf(t *TLS, str, format, va uintptr) int32 {
if __ccgo_strace {
trc("t=%v va=%v, (%v:)", t, va, origin(2))
}
return Xsprintf(t, str, format, va)
}
// int vsnprintf(char *str, size_t size, const char *format, va_list ap);
func Xvsnprintf(t *TLS, str uintptr, size types.Size_t, format, va uintptr) int32 {
if __ccgo_strace {
@@ -886,15 +859,6 @@ func Xstrcspn(t *TLS, s, reject uintptr) (r types.Size_t) {
}
}
// int printf(const char *format, ...);
func Xprintf(t *TLS, format, args uintptr) int32 {
if __ccgo_strace {
trc("t=%v args=%v, (%v:)", t, args, origin(2))
}
n, _ := write(printf(format, args))
return int32(n)
}
// int snprintf(char *str, size_t size, const char *format, ...);
func Xsnprintf(t *TLS, str uintptr, size types.Size_t, format, args uintptr) (r int32) {
if __ccgo_strace {
@@ -995,206 +959,14 @@ func X__builtin_llabs(tls *TLS, a int64) int64 {
return Xllabs(tls, a)
}
func Xacos(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Acos(x)
}
func Xacosh(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Acosh(x)
}
func Xasin(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Asin(x)
}
func Xasinh(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Asinh(x)
}
func Xatan(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Atan(x)
}
func Xatan2(t *TLS, x, y float64) float64 {
if __ccgo_strace {
trc("t=%v y=%v, (%v:)", t, y, origin(2))
}
return math.Atan2(x, y)
}
func Xatanh(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Atanh(x)
}
func Xceil(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Ceil(x)
}
func Xceilf(t *TLS, x float32) float32 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return float32(math.Ceil(float64(x)))
}
func Xcopysign(t *TLS, x, y float64) float64 {
if __ccgo_strace {
trc("t=%v y=%v, (%v:)", t, y, origin(2))
}
return math.Copysign(x, y)
}
func Xcopysignf(t *TLS, x, y float32) float32 {
if __ccgo_strace {
trc("t=%v y=%v, (%v:)", t, y, origin(2))
}
return float32(math.Copysign(float64(x), float64(y)))
}
func Xcos(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Cos(x)
}
func Xcosf(t *TLS, x float32) float32 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return float32(math.Cos(float64(x)))
}
func Xcosh(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Cosh(x)
}
func Xexp(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Exp(x)
}
func Xfabs(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Abs(x)
}
func Xfabsf(t *TLS, x float32) float32 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return float32(math.Abs(float64(x)))
}
func Xfloor(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Floor(x)
}
func Xfmod(t *TLS, x, y float64) float64 {
if __ccgo_strace {
trc("t=%v y=%v, (%v:)", t, y, origin(2))
}
return math.Mod(x, y)
}
func Xhypot(t *TLS, x, y float64) float64 {
if __ccgo_strace {
trc("t=%v y=%v, (%v:)", t, y, origin(2))
}
return math.Hypot(x, y)
}
func Xisnan(t *TLS, x float64) int32 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return X__builtin_isnan(t, x)
}
func Xisnanf(t *TLS, x float32) int32 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return Bool32(math.IsNaN(float64(x)))
}
func Xisnanl(t *TLS, x float64) int32 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return Bool32(math.IsNaN(x))
} // ccgo has to handle long double as double as Go does not support long double.
func Xldexp(t *TLS, x float64, exp int32) float64 {
if __ccgo_strace {
trc("t=%v x=%v exp=%v, (%v:)", t, x, exp, origin(2))
}
return math.Ldexp(x, int(exp))
}
func Xlog(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Log(x)
}
func Xlog10(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Log10(x)
func X__builtin_hypot(t *TLS, x float64, y float64) (r float64) {
return Xhypot(t, x, y)
}
func X__builtin_log2(t *TLS, x float64) float64 {
return Xlog2(t, x)
}
func Xlog2(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Log2(x)
}
func Xround(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Round(x)
}
func X__builtin_round(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
@@ -1202,13 +974,6 @@ func X__builtin_round(t *TLS, x float64) float64 {
return math.Round(x)
}
func Xroundf(t *TLS, x float32) float32 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return float32(math.Round(float64(x)))
}
func X__builtin_roundf(t *TLS, x float32) float32 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
@@ -1216,55 +981,6 @@ func X__builtin_roundf(t *TLS, x float32) float32 {
return float32(math.Round(float64(x)))
}
func Xsin(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Sin(x)
}
func Xsinf(t *TLS, x float32) float32 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return float32(math.Sin(float64(x)))
}
func Xsinh(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Sinh(x)
}
func Xsqrt(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Sqrt(x)
}
func Xtan(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Tan(x)
}
func Xtanh(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Tanh(x)
}
func Xtrunc(t *TLS, x float64) float64 {
if __ccgo_strace {
trc("t=%v x=%v, (%v:)", t, x, origin(2))
}
return math.Trunc(x)
}
var nextRand = uint64(1)
// int rand(void);
@@ -1276,35 +992,6 @@ func Xrand(t *TLS) int32 {
return int32(uint32(nextRand / (math.MaxUint32 + 1) % math.MaxInt32))
}
func Xpow(t *TLS, x, y float64) float64 {
if __ccgo_strace {
trc("t=%v y=%v, (%v:)", t, y, origin(2))
}
r := math.Pow(x, y)
if x > 0 && r == 1 && y >= -1.0000000000000000715e-18 && y < -1e-30 {
r = 0.9999999999999999
}
return r
}
func Xfrexp(t *TLS, x float64, exp uintptr) float64 {
if __ccgo_strace {
trc("t=%v x=%v exp=%v, (%v:)", t, x, exp, origin(2))
}
f, e := math.Frexp(x)
*(*int32)(unsafe.Pointer(exp)) = int32(e)
return f
}
func Xmodf(t *TLS, x float64, iptr uintptr) float64 {
if __ccgo_strace {
trc("t=%v x=%v iptr=%v, (%v:)", t, x, iptr, origin(2))
}
i, f := math.Modf(x)
*(*float64)(unsafe.Pointer(iptr)) = i
return f
}
// char *strncpy(char *dest, const char *src, size_t n)
func Xstrncpy(t *TLS, dest, src uintptr, n types.Size_t) (r uintptr) {
if __ccgo_strace {
@@ -2403,76 +2090,23 @@ func Xffs(tls *TLS, i int32) (r int32) {
return int32(mbits.TrailingZeros32(uint32(i))) + 1
}
var _toint5 = Float32FromInt32(1) / Float32FromFloat32(1.1920928955078125e-07)
func X__builtin_rintf(tls *TLS, x float32) (r float32) {
return Xrintf(tls, x)
}
func Xrintf(tls *TLS, x float32) (r float32) {
if __ccgo_strace {
trc("tls=%v x=%v, (%v:)", tls, x, origin(2))
defer func() { trc("-> %v", r) }()
}
bp := tls.Alloc(16)
defer tls.Free(16)
var e, s int32
var y float32
var v1 float32
var _ /* u at bp+0 */ struct {
Fi [0]uint32
Ff float32
}
_, _, _, _ = e, s, y, v1
*(*struct {
Fi [0]uint32
Ff float32
})(unsafe.Pointer(bp)) = struct {
Fi [0]uint32
Ff float32
}{}
*(*float32)(unsafe.Pointer(bp)) = x
e = int32(*(*uint32)(unsafe.Pointer(bp)) >> int32(23) & uint32(0xff))
s = int32(*(*uint32)(unsafe.Pointer(bp)) >> int32(31))
if e >= Int32FromInt32(0x7f)+Int32FromInt32(23) {
return x
}
if s != 0 {
y = x - _toint5 + _toint5
} else {
y = x + _toint5 - _toint5
}
if y == Float32FromInt32(0) {
if s != 0 {
v1 = -Float32FromFloat32(0)
} else {
v1 = Float32FromFloat32(0)
}
return v1
}
return y
}
func X__builtin_lrintf(tls *TLS, x float32) (r long) {
return Xlrintf(tls, x)
}
func Xlrintf(tls *TLS, x float32) (r long) {
if __ccgo_strace {
trc("tls=%v x=%v, (%v:)", tls, x, origin(2))
defer func() { trc("-> %v", r) }()
}
return long(Xrintf(tls, x))
}
func X__builtin_lrint(tls *TLS, x float64) (r long) {
return Xlrint(tls, x)
}
func Xlrint(tls *TLS, x float64) (r long) {
if __ccgo_strace {
trc("tls=%v x=%v, (%v:)", tls, x, origin(2))
defer func() { trc("-> %v", r) }()
func Xprintf(t *TLS, format, va uintptr) int32 {
n, err := os.Stdout.Write(printf(format, va))
if err != nil {
return -1
}
return long(Xrint(tls, x))
return int32(n)
}
+1 -2
View File
@@ -2,8 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build 386 || arm
// +build 386 arm
//go:build !windows && (386 || arm)
package libc // import "modernc.org/libc"
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build ((amd64 || loong64) && !linux) || arm64 || ppc64le || riscv64 || s390x || mips64le
//go:build !windows && (((amd64 || arm64 || loong64) && !linux) || ppc64le || riscv64 || s390x || mips64le)
package libc // import "modernc.org/libc"
+2
View File
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !(linux && arm64)
package libc // import "modernc.org/libc"
import (
+14 -2
View File
@@ -55,6 +55,10 @@ type (
ulong = types.User_ulong_t
)
type pthreadAttr struct {
detachState int32
}
// // Keep these outside of the var block otherwise go generate will miss them.
var X__stderrp = Xstdout
var X__stdinp = Xstdin
@@ -452,9 +456,11 @@ func Xsysconf(t *TLS, name int32) long {
return long(unix.Getpagesize())
case unistd.X_SC_NPROCESSORS_ONLN:
return long(runtime.NumCPU())
case unistd.X_SC_GETPW_R_SIZE_MAX:
return 128
}
panic(todo(""))
panic(todo("", name))
}
// int close(int fd);
@@ -2158,7 +2164,7 @@ func X__ccgo_pthreadAttrGetDetachState(tls *TLS, a uintptr) int32 {
if __ccgo_strace {
trc("tls=%v a=%v, (%v:)", tls, a, origin(2))
}
panic(todo(""))
return (*pthreadAttr)(unsafe.Pointer(a)).detachState
}
func Xpthread_attr_getdetachstate(tls *TLS, a uintptr, state uintptr) int32 {
@@ -2498,3 +2504,9 @@ func Xsetrlimit(t *TLS, resource int32, rlim uintptr) int32 {
return 0
}
func X__fpclassifyd(tls *TLS, x float64) (r int32) {
return X__fpclassify(tls, x)
}
var Xin6addr_any = in6_addr{}
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build !(linux && (amd64 || loong64))
//go:build !(linux && (amd64 || arm64 || loong64))
package libc // import "modernc.org/libc"
-729
View File
@@ -1,729 +0,0 @@
// Copyright 2020 The Libc Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package libc // import "modernc.org/libc"
import (
"os"
"strings"
gotime "time"
"unsafe"
"golang.org/x/sys/unix"
"modernc.org/libc/errno"
"modernc.org/libc/fcntl"
"modernc.org/libc/signal"
"modernc.org/libc/stdio"
"modernc.org/libc/sys/stat"
"modernc.org/libc/sys/types"
"modernc.org/libc/time"
)
var (
startTime = gotime.Now() // For clock(3)
)
// int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
func Xsigaction(t *TLS, signum int32, act, oldact uintptr) int32 {
if __ccgo_strace {
trc("t=%v signum=%v oldact=%v, (%v:)", t, signum, oldact, origin(2))
}
// musl/src/internal/ksigaction.h
//
// struct k_sigaction {
// void (*handler)(int);
// unsigned long flags;
// void (*restorer)(void);
// unsigned mask[2];
// };
type k_sigaction struct {
handler uintptr
flags ulong
restorer uintptr
mask [2]uint32
}
var kact, koldact uintptr
if act != 0 {
sz := int(unsafe.Sizeof(k_sigaction{}))
kact = t.Alloc(sz)
defer t.Free(sz)
*(*k_sigaction)(unsafe.Pointer(kact)) = k_sigaction{
handler: (*signal.Sigaction)(unsafe.Pointer(act)).F__sigaction_handler.Fsa_handler,
flags: ulong((*signal.Sigaction)(unsafe.Pointer(act)).Fsa_flags),
restorer: (*signal.Sigaction)(unsafe.Pointer(act)).Fsa_restorer,
}
Xmemcpy(t, kact+unsafe.Offsetof(k_sigaction{}.mask), act+unsafe.Offsetof(signal.Sigaction{}.Fsa_mask), types.Size_t(unsafe.Sizeof(k_sigaction{}.mask)))
}
if oldact != 0 {
panic(todo(""))
}
if _, _, err := unix.Syscall6(unix.SYS_RT_SIGACTION, uintptr(signum), kact, koldact, unsafe.Sizeof(k_sigaction{}.mask), 0, 0); err != 0 {
t.setErrno(err)
return -1
}
if oldact != 0 {
panic(todo(""))
}
return 0
}
// int lstat(const char *pathname, struct stat *statbuf);
func Xlstat64(t *TLS, pathname, statbuf uintptr) int32 {
if __ccgo_strace {
trc("t=%v statbuf=%v, (%v:)", t, statbuf, origin(2))
}
if err := unix.Lstat(GoString(pathname), (*unix.Stat_t)(unsafe.Pointer(statbuf))); err != nil {
if dmesgs {
dmesg("%v: %q: %v", origin(1), GoString(pathname), err)
}
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %q: ok", origin(1), GoString(pathname))
}
return 0
}
// int stat(const char *pathname, struct stat *statbuf);
func Xstat64(t *TLS, pathname, statbuf uintptr) int32 {
if __ccgo_strace {
trc("t=%v statbuf=%v, (%v:)", t, statbuf, origin(2))
}
if err := unix.Fstatat(unix.AT_FDCWD, GoString(pathname), (*unix.Stat_t)(unsafe.Pointer(statbuf)), 0); err != nil {
if dmesgs {
dmesg("%v: %q: %v", origin(1), GoString(pathname), err)
}
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %q: ok", origin(1), GoString(pathname))
}
return 0
}
// int unlink(const char *pathname);
func Xunlink(t *TLS, pathname uintptr) int32 {
if __ccgo_strace {
trc("t=%v pathname=%v, (%v:)", t, pathname, origin(2))
}
if err := unix.Unlinkat(unix.AT_FDCWD, GoString(pathname), 0); err != nil {
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %q: ok", origin(1), GoString(pathname))
}
return 0
}
// int access(const char *pathname, int mode);
func Xaccess(t *TLS, pathname uintptr, mode int32) int32 {
if __ccgo_strace {
trc("t=%v pathname=%v mode=%v, (%v:)", t, pathname, mode, origin(2))
}
if err := unix.Faccessat(unix.AT_FDCWD, GoString(pathname), uint32(mode), 0); err != nil {
if dmesgs {
dmesg("%v: %q: %v", origin(1), GoString(pathname), err)
}
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %q %#o: ok", origin(1), GoString(pathname), mode)
}
return 0
}
// off64_t lseek64(int fd, off64_t offset, int whence);
func Xlseek64(t *TLS, fd int32, offset types.Off_t, whence int32) types.Off_t {
if __ccgo_strace {
trc("t=%v fd=%v offset=%v whence=%v, (%v:)", t, fd, offset, whence, origin(2))
}
n, _, err := unix.Syscall(unix.SYS_LSEEK, uintptr(fd), uintptr(offset), uintptr(whence))
if err != 0 {
if dmesgs {
dmesg("%v: fd %v, off %#x, whence %v: %v", origin(1), fd, offset, whenceStr(whence), err)
}
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: fd %v, off %#x, whence %v: %#x", origin(1), fd, offset, whenceStr(whence), n)
}
return types.Off_t(n)
}
// int fstat(int fd, struct stat *statbuf);
func Xfstat64(t *TLS, fd int32, statbuf uintptr) int32 {
if __ccgo_strace {
trc("t=%v fd=%v statbuf=%v, (%v:)", t, fd, statbuf, origin(2))
}
if _, _, err := unix.Syscall(unix.SYS_FSTAT, uintptr(fd), statbuf, 0); err != 0 {
if dmesgs {
dmesg("%v: fd %d: %v", origin(1), fd, err)
}
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %d size %#x: ok\n%+v", origin(1), fd, (*stat.Stat)(unsafe.Pointer(statbuf)).Fst_size, (*stat.Stat)(unsafe.Pointer(statbuf)))
}
return 0
}
// int ftruncate(int fd, off_t length);
func Xftruncate64(t *TLS, fd int32, length types.Off_t) int32 {
if __ccgo_strace {
trc("t=%v fd=%v length=%v, (%v:)", t, fd, length, origin(2))
}
if _, _, err := unix.Syscall(unix.SYS_FTRUNCATE, uintptr(fd), uintptr(length), 0); err != 0 {
if dmesgs {
dmesg("%v: fd %d: %v", origin(1), fd, err)
}
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %d %#x: ok", origin(1), fd, length)
}
return 0
}
// int fcntl(int fd, int cmd, ... /* arg */ );
func Xfcntl64(t *TLS, fd, cmd int32, args uintptr) int32 {
if __ccgo_strace {
trc("t=%v cmd=%v args=%v, (%v:)", t, cmd, args, origin(2))
}
var arg uintptr
if args != 0 {
arg = *(*uintptr)(unsafe.Pointer(args))
}
if cmd == fcntl.F_SETFL {
arg |= unix.O_LARGEFILE
}
n, _, err := unix.Syscall(unix.SYS_FCNTL, uintptr(fd), uintptr(cmd), arg)
if err != 0 {
if dmesgs {
dmesg("%v: fd %v cmd %v", origin(1), fcntlCmdStr(fd), cmd)
}
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %d %s %#x: %d", origin(1), fd, fcntlCmdStr(cmd), arg, n)
}
return int32(n)
}
// int rmdir(const char *pathname);
func Xrmdir(t *TLS, pathname uintptr) int32 {
if __ccgo_strace {
trc("t=%v pathname=%v, (%v:)", t, pathname, origin(2))
}
if err := unix.Rmdir(GoString(pathname)); err != nil {
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %q: ok", origin(1), GoString(pathname))
}
return 0
}
// int rename(const char *oldpath, const char *newpath);
func Xrename(t *TLS, oldpath, newpath uintptr) int32 {
if __ccgo_strace {
trc("t=%v newpath=%v, (%v:)", t, newpath, origin(2))
}
if err := unix.Rename(GoString(oldpath), GoString(newpath)); err != nil {
t.setErrno(err)
return -1
}
return 0
}
// int mknod(const char *pathname, mode_t mode, dev_t dev);
func Xmknod(t *TLS, pathname uintptr, mode types.Mode_t, dev types.Dev_t) int32 {
if __ccgo_strace {
trc("t=%v pathname=%v mode=%v dev=%v, (%v:)", t, pathname, mode, dev, origin(2))
}
panic(todo(""))
}
// int chown(const char *pathname, uid_t owner, gid_t group);
func Xchown(t *TLS, pathname uintptr, owner types.Uid_t, group types.Gid_t) int32 {
if __ccgo_strace {
trc("t=%v pathname=%v owner=%v group=%v, (%v:)", t, pathname, owner, group, origin(2))
}
if err := unix.Chown(GoString(pathname), int(owner), int(group)); err != nil {
t.setErrno(err)
return -1
}
return 0
}
// int link(const char *oldpath, const char *newpath);
func Xlink(t *TLS, oldpath, newpath uintptr) int32 {
if __ccgo_strace {
trc("t=%v newpath=%v, (%v:)", t, newpath, origin(2))
}
panic(todo(""))
}
// int pipe(int pipefd[2]);
func Xpipe(t *TLS, pipefd uintptr) int32 {
if __ccgo_strace {
trc("t=%v pipefd=%v, (%v:)", t, pipefd, origin(2))
}
if _, _, err := unix.Syscall(unix.SYS_PIPE2, pipefd, 0, 0); err != 0 {
t.setErrno(err)
return -1
}
return 0
}
// int dup2(int oldfd, int newfd);
func Xdup2(t *TLS, oldfd, newfd int32) int32 {
if __ccgo_strace {
trc("t=%v newfd=%v, (%v:)", t, newfd, origin(2))
}
panic(todo(""))
}
// int getrlimit(int resource, struct rlimit *rlim);
func Xgetrlimit64(t *TLS, resource int32, rlim uintptr) int32 {
if __ccgo_strace {
trc("t=%v resource=%v rlim=%v, (%v:)", t, resource, rlim, origin(2))
}
if _, _, err := unix.Syscall(unix.SYS_GETRLIMIT, uintptr(resource), uintptr(rlim), 0); err != 0 {
t.setErrno(err)
return -1
}
return 0
}
// ssize_t readlink(const char *restrict path, char *restrict buf, size_t bufsize);
func Xreadlink(t *TLS, path, buf uintptr, bufsize types.Size_t) types.Ssize_t {
if __ccgo_strace {
trc("t=%v buf=%v bufsize=%v, (%v:)", t, buf, bufsize, origin(2))
}
n, err := unix.Readlink(GoString(path), GoBytes(buf, int(bufsize)))
if err != nil {
t.setErrno(err)
return -1
}
return types.Ssize_t(n)
}
// FILE *fopen64(const char *pathname, const char *mode);
func Xfopen64(t *TLS, pathname, mode uintptr) uintptr {
if __ccgo_strace {
trc("t=%v mode=%v, (%v:)", t, mode, origin(2))
}
m := strings.ReplaceAll(GoString(mode), "b", "")
var flags int
switch m {
case "r":
flags = os.O_RDONLY
case "r+":
flags = os.O_RDWR
case "w":
flags = os.O_WRONLY | os.O_CREATE | os.O_TRUNC
case "w+":
flags = os.O_RDWR | os.O_CREATE | os.O_TRUNC
case "a":
flags = os.O_WRONLY | os.O_CREATE | os.O_APPEND
case "a+":
flags = os.O_RDWR | os.O_CREATE | os.O_APPEND
default:
panic(m)
}
//TODO- flags |= fcntl.O_LARGEFILE
fd, err := unix.Openat(unix.AT_FDCWD, GoString(pathname), flags, 0666)
if err != nil {
t.setErrno(err)
return 0
}
if p := newFile(t, int32(fd)); p != 0 {
return p
}
Xclose(t, int32(fd))
t.setErrno(errno.ENOMEM)
return 0
}
// int mkdir(const char *path, mode_t mode);
func Xmkdir(t *TLS, path uintptr, mode types.Mode_t) int32 {
if __ccgo_strace {
trc("t=%v path=%v mode=%v, (%v:)", t, path, mode, origin(2))
}
if err := unix.Mkdir(GoString(path), uint32(mode)); err != nil {
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %q: ok", origin(1), GoString(path))
}
return 0
}
// void *mremap(void *old_address, size_t old_size, size_t new_size, int flags, ... /* void *new_address */);
func Xmremap(t *TLS, old_address uintptr, old_size, new_size types.Size_t, flags int32, args uintptr) uintptr {
if __ccgo_strace {
trc("t=%v old_address=%v new_size=%v flags=%v args=%v, (%v:)", t, old_address, new_size, flags, args, origin(2))
}
var arg uintptr
if args != 0 {
arg = *(*uintptr)(unsafe.Pointer(args))
}
data, _, err := unix.Syscall6(unix.SYS_MREMAP, old_address, uintptr(old_size), uintptr(new_size), uintptr(flags), arg, 0)
if err != 0 {
if dmesgs {
dmesg("%v: %v", origin(1), err)
}
t.setErrno(err)
return ^uintptr(0) // (void*)-1
}
if dmesgs {
dmesg("%v: %#x", origin(1), data)
}
return data
}
func Xmmap(t *TLS, addr uintptr, length types.Size_t, prot, flags, fd int32, offset types.Off_t) uintptr {
if __ccgo_strace {
trc("t=%v addr=%v length=%v fd=%v offset=%v, (%v:)", t, addr, length, fd, offset, origin(2))
}
return Xmmap64(t, addr, length, prot, flags, fd, offset)
}
// void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
func Xmmap64(t *TLS, addr uintptr, length types.Size_t, prot, flags, fd int32, offset types.Off_t) uintptr {
if __ccgo_strace {
trc("t=%v addr=%v length=%v fd=%v offset=%v, (%v:)", t, addr, length, fd, offset, origin(2))
}
data, _, err := unix.Syscall6(unix.SYS_MMAP, addr, uintptr(length), uintptr(prot), uintptr(flags), uintptr(fd), uintptr(offset))
if err != 0 {
if dmesgs {
dmesg("%v: %v", origin(1), err)
}
t.setErrno(err)
return ^uintptr(0) // (void*)-1
}
if dmesgs {
dmesg("%v: %#x", origin(1), data)
}
return data
}
// int symlink(const char *target, const char *linkpath);
func Xsymlink(t *TLS, target, linkpath uintptr) int32 {
if __ccgo_strace {
trc("t=%v linkpath=%v, (%v:)", t, linkpath, origin(2))
}
if err := unix.Symlink(GoString(target), GoString(linkpath)); err != nil {
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %q %q: ok", origin(1), GoString(target), GoString(linkpath))
}
return 0
}
// int chmod(const char *pathname, mode_t mode)
func Xchmod(t *TLS, pathname uintptr, mode types.Mode_t) int32 {
if __ccgo_strace {
trc("t=%v pathname=%v mode=%v, (%v:)", t, pathname, mode, origin(2))
}
if err := unix.Chmod(GoString(pathname), uint32(mode)); err != nil {
t.setErrno(err)
return -1
}
if dmesgs {
dmesg("%v: %q %#o: ok", origin(1), GoString(pathname), mode)
}
return 0
}
// time_t time(time_t *tloc);
func Xtime(t *TLS, tloc uintptr) types.Time_t {
if __ccgo_strace {
trc("t=%v tloc=%v, (%v:)", t, tloc, origin(2))
}
n := gotime.Now().UTC().Unix()
if tloc != 0 {
*(*types.Time_t)(unsafe.Pointer(tloc)) = types.Time_t(n)
}
return types.Time_t(n)
}
// int utimes(const char *filename, const struct timeval times[2]);
func Xutimes(t *TLS, filename, times uintptr) int32 {
if __ccgo_strace {
trc("t=%v times=%v, (%v:)", t, times, origin(2))
}
var tv []unix.Timeval
if times != 0 {
tv = make([]unix.Timeval, 2)
*(*[2]unix.Timeval)(unsafe.Pointer(&tv[0])) = *(*[2]unix.Timeval)(unsafe.Pointer(times))
}
if err := unix.Utimes(GoString(filename), tv); err != nil {
t.setErrno(err)
return -1
}
if times != 0 {
*(*[2]unix.Timeval)(unsafe.Pointer(times)) = *(*[2]unix.Timeval)(unsafe.Pointer(&tv[0]))
}
if dmesgs {
dmesg("%v: %q: ok", origin(1), GoString(filename))
}
return 0
}
// int utime(const char *filename, const struct utimbuf *times);
func Xutime(t *TLS, filename, times uintptr) int32 {
if __ccgo_strace {
trc("t=%v times=%v, (%v:)", t, times, origin(2))
}
if times == 0 {
return Xutimes(t, filename, 0)
}
if err := unix.Utime(GoString(filename), (*unix.Utimbuf)(unsafe.Pointer(times))); err != nil {
t.setErrno(err)
return -1
}
return 0
}
// unsigned int alarm(unsigned int seconds);
func Xalarm(t *TLS, seconds uint32) uint32 {
if __ccgo_strace {
trc("t=%v seconds=%v, (%v:)", t, seconds, origin(2))
}
panic(todo(""))
}
// int setrlimit(int resource, const struct rlimit *rlim);
func Xsetrlimit64(t *TLS, resource int32, rlim uintptr) int32 {
if __ccgo_strace {
trc("t=%v resource=%v rlim=%v, (%v:)", t, resource, rlim, origin(2))
}
if _, _, err := unix.Syscall(unix.SYS_SETRLIMIT, uintptr(resource), uintptr(rlim), 0); err != 0 {
t.setErrno(err)
return -1
}
return 0
}
func AtomicLoadNUint8(ptr uintptr, memorder int32) uint8 {
return byte(a_load_8(ptr))
}
var _table1 = [384]int32{
129: int32(1),
130: int32(2),
131: int32(3),
132: int32(4),
133: int32(5),
134: int32(6),
135: int32(7),
136: int32(8),
137: int32(9),
138: int32(10),
139: int32(11),
140: int32(12),
141: int32(13),
142: int32(14),
143: int32(15),
144: int32(16),
145: int32(17),
146: int32(18),
147: int32(19),
148: int32(20),
149: int32(21),
150: int32(22),
151: int32(23),
152: int32(24),
153: int32(25),
154: int32(26),
155: int32(27),
156: int32(28),
157: int32(29),
158: int32(30),
159: int32(31),
160: int32(32),
161: int32(33),
162: int32(34),
163: int32(35),
164: int32(36),
165: int32(37),
166: int32(38),
167: int32(39),
168: int32(40),
169: int32(41),
170: int32(42),
171: int32(43),
172: int32(44),
173: int32(45),
174: int32(46),
175: int32(47),
176: int32(48),
177: int32(49),
178: int32(50),
179: int32(51),
180: int32(52),
181: int32(53),
182: int32(54),
183: int32(55),
184: int32(56),
185: int32(57),
186: int32(58),
187: int32(59),
188: int32(60),
189: int32(61),
190: int32(62),
191: int32(63),
192: int32(64),
193: int32('a'),
194: int32('b'),
195: int32('c'),
196: int32('d'),
197: int32('e'),
198: int32('f'),
199: int32('g'),
200: int32('h'),
201: int32('i'),
202: int32('j'),
203: int32('k'),
204: int32('l'),
205: int32('m'),
206: int32('n'),
207: int32('o'),
208: int32('p'),
209: int32('q'),
210: int32('r'),
211: int32('s'),
212: int32('t'),
213: int32('u'),
214: int32('v'),
215: int32('w'),
216: int32('x'),
217: int32('y'),
218: int32('z'),
219: int32(91),
220: int32(92),
221: int32(93),
222: int32(94),
223: int32(95),
224: int32(96),
225: int32('a'),
226: int32('b'),
227: int32('c'),
228: int32('d'),
229: int32('e'),
230: int32('f'),
231: int32('g'),
232: int32('h'),
233: int32('i'),
234: int32('j'),
235: int32('k'),
236: int32('l'),
237: int32('m'),
238: int32('n'),
239: int32('o'),
240: int32('p'),
241: int32('q'),
242: int32('r'),
243: int32('s'),
244: int32('t'),
245: int32('u'),
246: int32('v'),
247: int32('w'),
248: int32('x'),
249: int32('y'),
250: int32('z'),
251: int32(123),
252: int32(124),
253: int32(125),
254: int32(126),
255: int32(127),
}
var _ptable1 = uintptr(unsafe.Pointer(&_table1)) + uintptr(128)*4
func X__ctype_tolower_loc(tls *TLS) (r uintptr) {
if __ccgo_strace {
trc("tls=%v, (%v:)", tls, origin(2))
defer func() { trc("-> %v", r) }()
}
return uintptr(unsafe.Pointer(&_ptable1))
}
type Tin6_addr = struct {
F__in6_union struct {
F__s6_addr16 [0][8]uint16
F__s6_addr32 [0][4]uint32
F__s6_addr [16]uint8
}
}
var Xin6addr_any = Tin6_addr{}
func Xrewinddir(tls *TLS, f uintptr) {
if __ccgo_strace {
trc("tls=%v f=%v, (%v:)", tls, f, origin(2))
}
Xfseek(tls, f, 0, stdio.SEEK_SET)
}
// clock_t clock(void);
func Xclock(t *TLS) time.Clock_t {
if __ccgo_strace {
trc("t=%v, (%v:)", t, origin(2))
}
return time.Clock_t(gotime.Since(startTime) * gotime.Duration(time.CLOCKS_PER_SEC) / gotime.Second)
}
const __NFDBITS = 64
func X__fdelt_chk(tls *TLS, d int64) (r int64) {
if __ccgo_strace {
trc("tls=%v d=%v, (%v:)", tls, d, origin(2))
defer func() { trc("-> %v", r) }()
}
return d / __NFDBITS
}
+48 -13
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && (amd64 || loong64)
//go:build linux && (amd64 || arm64 || loong64)
//go:generate go run generator.go
@@ -128,11 +128,6 @@ import (
"modernc.org/memory"
)
const (
heapAlign = 16
heapGuard = 16
)
var (
_ error = (*MemAuditError)(nil)
@@ -278,15 +273,18 @@ type TLS struct {
allocaStack []int
allocas []uintptr
jumpBuffers []uintptr
pendingSignals chan os.Signal
pthread uintptr // *t__pthread
pthreadCleanupItems []pthreadCleanupItem
pthreadKeyValues map[Tpthread_key_t]uintptr
sigHandlers map[int32]uintptr
sp int
stack []tlsStackSlot
ID int32
ownsPthread bool
checkSignals bool
ownsPthread bool
}
var __ccgo_environOnce sync.Once
@@ -311,6 +309,7 @@ func NewTLS() (r *TLS) {
ID: id,
ownsPthread: true,
pthread: pthread,
sigHandlers: map[int32]uintptr{},
}
}
@@ -404,6 +403,29 @@ func (tls *TLS) Alloc(n0 int) (r uintptr) {
func (tls *TLS) Free(n int) {
//TODO shrink stacks if possible. Tcl is currently against.
tls.sp--
if !tls.checkSignals {
return
}
select {
case sig := <-tls.pendingSignals:
signum := int32(sig.(syscall.Signal))
h, ok := tls.sigHandlers[signum]
if !ok {
break
}
switch h {
case SIG_DFL:
// nop
case SIG_IGN:
// nop
default:
(*(*func(*TLS, int32))(unsafe.Pointer(&struct{ uintptr }{h})))(tls, signum)
}
default:
// nop
}
}
func (tls *TLS) alloca(n Tsize_t) (r uintptr) {
@@ -475,6 +497,10 @@ func Xexit(tls *TLS, code int32) {
for _, v := range atExit {
v()
}
atExitHandlersMu.Lock()
for _, v := range atExitHandlers {
(*(*func(*TLS))(unsafe.Pointer(&struct{ uintptr }{v})))(tls)
}
os.Exit(int(code))
}
@@ -647,24 +673,33 @@ func Xfork(t *TLS) int32 {
const SIG_DFL = 0
const SIG_IGN = 1
var sigHandlers = map[int32]uintptr{}
func Xsignal(tls *TLS, signum int32, handler uintptr) (r uintptr) {
r, sigHandlers[signum] = sigHandlers[signum], handler
sigHandlers[signum] = handler
r, tls.sigHandlers[signum] = tls.sigHandlers[signum], handler
switch handler {
case SIG_DFL:
gosignal.Reset(syscall.Signal(signum))
case SIG_IGN:
gosignal.Ignore(syscall.Signal(signum))
default:
panic(todo(""))
if tls.pendingSignals == nil {
tls.pendingSignals = make(chan os.Signal, 3)
tls.checkSignals = true
}
gosignal.Notify(tls.pendingSignals, syscall.Signal(signum))
}
return r
}
var (
atExitHandlersMu sync.Mutex
atExitHandlers []uintptr
)
func Xatexit(tls *TLS, func_ uintptr) (r int32) {
return -1
atExitHandlersMu.Lock()
atExitHandlers = append(atExitHandlers, func_)
atExitHandlersMu.Unlock()
return 0
}
var __sync_synchronize_dummy int32
+1 -3
View File
@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build linux && amd64
package libc // import "modernc.org/libc
package libc // import "modernc.org/libc"
import (
"golang.org/x/sys/unix"
+29
View File
@@ -0,0 +1,29 @@
// Copyright 2023 The Libc Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package libc // import "modernc.org/libc"
import (
"golang.org/x/sys/unix"
)
type long = int64
type ulong = uint64
// RawMem represents the biggest byte array the runtime can handle
type RawMem [1<<50 - 1]byte
// int renameat2(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, unsigned int flags);
func Xrenameat2(t *TLS, olddirfd int32, oldpath uintptr, newdirfd int32, newpath uintptr, flags int32) int32 {
if __ccgo_strace {
trc("t=%v olddirfd=%v oldpath=%v newdirfd=%v newpath=%v flags=%v, (%v:)", t, olddirfd, oldpath, newdirfd, newpath, flags, origin(2))
}
if _, _, err := unix.Syscall6(unix.SYS_RENAMEAT2, uintptr(olddirfd), oldpath, uintptr(newdirfd), newpath, uintptr(flags), 0); err != 0 {
t.setErrno(int32(err))
return -1
}
return 0
}
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package libc // import "modernc.org/libc
package libc // import "modernc.org/libc"
import (
"golang.org/x/sys/unix"
+1 -3
View File
@@ -2,9 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build unix && !(linux && (amd64 || loong64))
// +build unix
// +build !linux !amd64,!loong64
//go:build unix && !(linux && (amd64 || arm64 || loong64))
package libc // import "modernc.org/libc"
+1 -1
View File
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build unix && !illumos && !(linux && (amd64 || loong64)) && !openbsd
//go:build unix && !illumos && !(linux && (amd64 || arm64 || loong64)) && !openbsd
package libc // import "modernc.org/libc"
+1423 -7242
View File
File diff suppressed because it is too large Load Diff
+12165 -697
View File
File diff suppressed because it is too large Load Diff
+12086 -594
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More