Merge branch '3.0' into cpwu/3.0
This commit is contained in:
commit
18c3bbf6de
|
@ -1,21 +0,0 @@
|
|||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
vendor/
|
||||
|
||||
# Project specific files
|
||||
cmd/alert/alert
|
||||
cmd/alert/alert.log
|
||||
*.db
|
||||
*.gz
|
|
@ -1,184 +0,0 @@
|
|||
# Alert
|
||||
|
||||
The Alert application reads data from [TDEngine](https://www.taosdata.com/), calculating according to predefined rules to generate alerts, and pushes alerts to downstream applications like [AlertManager](https://github.com/prometheus/alertmanager).
|
||||
|
||||
## Install
|
||||
|
||||
### From Binary
|
||||
|
||||
Precompiled binaries is available at [taosdata website](https://www.taosdata.com/en/getting-started/), please download and unpack it by below shell command.
|
||||
|
||||
```
|
||||
$ tar -xzf tdengine-alert-$version-$OS-$ARCH.tar.gz
|
||||
```
|
||||
|
||||
If you have no TDengine server or client installed, please execute below command to install the required driver library:
|
||||
|
||||
```
|
||||
$ ./install_driver.sh
|
||||
```
|
||||
|
||||
### From Source Code
|
||||
|
||||
Two prerequisites are required to install from source.
|
||||
|
||||
1. TDEngine server or client must be installed.
|
||||
2. Latest [Go](https://golang.org) language must be installed.
|
||||
|
||||
When these two prerequisites are ready, please follow steps below to build the application:
|
||||
|
||||
```
|
||||
$ mkdir taosdata
|
||||
$ cd taosdata
|
||||
$ git clone https://github.com/taosdata/tdengine.git
|
||||
$ cd tdengine/alert/cmd/alert
|
||||
$ go build
|
||||
```
|
||||
|
||||
If `go build` fails because some of the dependency packages cannot be downloaded, please follow steps in [goproxy.io](https://goproxy.io) to configure `GOPROXY` and try `go build` again.
|
||||
|
||||
## Configure
|
||||
|
||||
The configuration file format of Alert application is standard `json`, below is its default content, please revise according to actual scenario.
|
||||
|
||||
```json
|
||||
{
|
||||
"port": 8100,
|
||||
"database": "file:alert.db",
|
||||
"tdengine": "root:taosdata@/tcp(127.0.0.1:0)/",
|
||||
"log": {
|
||||
"level": "production",
|
||||
"path": "alert.log"
|
||||
},
|
||||
"receivers": {
|
||||
"alertManager": "http://127.0.0.1:9093/api/v1/alerts",
|
||||
"console": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The use of each configuration item is:
|
||||
|
||||
* **port**: This is the `http` service port which enables other application to manage rules by `restful API`.
|
||||
* **database**: rules are stored in a `sqlite` database, this is the path of the database file (if the file does not exist, the alert application creates it automatically).
|
||||
* **tdengine**: connection string of `TDEngine` server (please refer the documentation of GO connector for the detailed format of this string), note the database name should be put in the `sql` field of a rule in most cases, thus it should NOT be included in the string.
|
||||
* **log > level**: log level, could be `production` or `debug`.
|
||||
* **log > path**: log output file path.
|
||||
* **receivers > alertManager**: the alert application pushes alerts to `AlertManager` at this URL.
|
||||
* **receivers > console**: print out alerts to console (stdout) or not.
|
||||
|
||||
When the configruation file is ready, the alert application can be started with below command (`alert.cfg` is the path of the configuration file):
|
||||
|
||||
```
|
||||
$ ./alert -cfg alert.cfg
|
||||
```
|
||||
|
||||
## Prepare an alert rule
|
||||
|
||||
From technical aspect, an alert could be defined as: query and filter recent data from `TDEngine`, and calculating out a boolean value from these data according to a formula, and trigger an alert if the boolean value last for a certain duration.
|
||||
|
||||
This is a rule example in `json` format:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "rule1",
|
||||
"sql": "select sum(col1) as sumCol1 from test.meters where ts > now - 1h group by areaid",
|
||||
"expr": "sumCol1 > 10",
|
||||
"for": "10m",
|
||||
"period": "1m",
|
||||
"labels": {
|
||||
"ruleName": "rule1"
|
||||
},
|
||||
"annotations": {
|
||||
"summary": "sum of rule {{$labels.ruleName}} of area {{$values.areaid}} is {{$values.sumCol1}}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The fields of the rule is explained below:
|
||||
|
||||
* **name**: the name of the rule, must be unique.
|
||||
* **sql**: this is the `sql` statement used to query data from `TDEngine`, columns of the query result are used in later processing, so please give the column an alias if aggregation functions are used.
|
||||
* **expr**: an expression whose result is a boolean value, arithmatic and logical calculations can be included in the expression, and builtin functions (see below) are also supported. Alerts are only triggered when the expression evaluates to `true`.
|
||||
* **for**: this item is a duration which default value is zero second. when `expr` evaluates to `true` and last at least this duration, an alert is triggered.
|
||||
* **period**: the interval for the alert application to check the rule, default is 1 minute.
|
||||
* **labels**: a label list, labels are used to generate alert information. note if the `sql` statement includes a `group by` clause, the `group by` columns are inserted into this list automatically.
|
||||
* **annotations**: the template of alert information which is in [go template](https://golang.org/pkg/text/template) syntax, labels can be referenced by `$labels.<label name>` and columns of the query result can be referenced by `$values.<column name>`.
|
||||
|
||||
### Operators
|
||||
|
||||
Operators which can be used in the `expr` field of a rule are list below, `()` can be to change precedence if default does not meet requirement.
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr> <td>Operator</td><td>Unary/Binary</td><td>Precedence</td><td>Effect</td> </tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr> <td>~</td><td>Unary</td><td>6</td><td>Bitwise Not</td> </tr>
|
||||
<tr> <td>!</td><td>Unary</td><td>6</td><td>Logical Not</td> </tr>
|
||||
<tr> <td>+</td><td>Unary</td><td>6</td><td>Positive Sign</td> </tr>
|
||||
<tr> <td>-</td><td>Unary</td><td>6</td><td>Negative Sign</td> </tr>
|
||||
<tr> <td>*</td><td>Binary</td><td>5</td><td>Multiplication</td> </tr>
|
||||
<tr> <td>/</td><td>Binary</td><td>5</td><td>Division</td> </tr>
|
||||
<tr> <td>%</td><td>Binary</td><td>5</td><td>Modulus</td> </tr>
|
||||
<tr> <td><<</td><td>Binary</td><td>5</td><td>Bitwise Left Shift</td> </tr>
|
||||
<tr> <td>>></td><td>Binary</td><td>5</td><td>Bitwise Right Shift</td> </tr>
|
||||
<tr> <td>&</td><td>Binary</td><td>5</td><td>Bitwise And</td> </tr>
|
||||
<tr> <td>+</td><td>Binary</td><td>4</td><td>Addition</td> </tr>
|
||||
<tr> <td>-</td><td>Binary</td><td>4</td><td>Subtraction</td> </tr>
|
||||
<tr> <td>|</td><td>Binary</td><td>4</td><td>Bitwise Or</td> </tr>
|
||||
<tr> <td>^</td><td>Binary</td><td>4</td><td>Bitwise Xor</td> </tr>
|
||||
<tr> <td>==</td><td>Binary</td><td>3</td><td>Equal</td> </tr>
|
||||
<tr> <td>!=</td><td>Binary</td><td>3</td><td>Not Equal</td> </tr>
|
||||
<tr> <td><</td><td>Binary</td><td>3</td><td>Less Than</td> </tr>
|
||||
<tr> <td><=</td><td>Binary</td><td>3</td><td>Less Than or Equal</td> </tr>
|
||||
<tr> <td>></td><td>Binary</td><td>3</td><td>Great Than</td> </tr>
|
||||
<tr> <td>>=</td><td>Binary</td><td>3</td><td>Great Than or Equal</td> </tr>
|
||||
<tr> <td>&&</td><td>Binary</td><td>2</td><td>Logical And</td> </tr>
|
||||
<tr> <td>||</td><td>Binary</td><td>1</td><td>Logical Or</td> </tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### Built-in Functions
|
||||
|
||||
Built-in function can be used in the `expr` field of a rule.
|
||||
|
||||
* **min**: returns the minimum one of its arguments, for example: `min(1, 2, 3)` returns `1`.
|
||||
* **max**: returns the maximum one of its arguments, for example: `max(1, 2, 3)` returns `3`.
|
||||
* **sum**: returns the sum of its arguments, for example: `sum(1, 2, 3)` returns `6`.
|
||||
* **avg**: returns the average of its arguments, for example: `avg(1, 2, 3)` returns `2`.
|
||||
* **sqrt**: returns the square root of its argument, for example: `sqrt(9)` returns `3`.
|
||||
* **ceil**: returns the minimum integer which greater or equal to its argument, for example: `ceil(9.1)` returns `10`.
|
||||
* **floor**: returns the maximum integer which lesser or equal to its argument, for example: `floor(9.9)` returns `9`.
|
||||
* **round**: round its argument to nearest integer, for examples: `round(9.9)` returns `10` and `round(9.1)` returns `9`.
|
||||
* **log**: returns the natural logarithm of its argument, for example: `log(10)` returns `2.302585`.
|
||||
* **log10**: returns base 10 logarithm of its argument, for example: `log10(10)` return `1`.
|
||||
* **abs**: returns the absolute value of its argument, for example: `abs(-1)` returns `1`.
|
||||
* **if**: if the first argument is `true` returns its second argument, and returns its third argument otherwise, for examples: `if(true, 10, 100)` returns `10` and `if(false, 10, 100)` returns `100`.
|
||||
|
||||
## Rule Management
|
||||
|
||||
* Add / Update
|
||||
|
||||
* API address: http://\<server\>:\<port\>/api/update-rule
|
||||
* Method: POST
|
||||
* Body: the rule
|
||||
* Example:curl -d '@rule.json' http://localhost:8100/api/update-rule
|
||||
|
||||
* Delete
|
||||
|
||||
* API address: http://\<server\>:\<port\>/api/delete-rule?name=\<rule name\>
|
||||
* Method:DELETE
|
||||
* Example:curl -X DELETE http://localhost:8100/api/delete-rule?name=rule1
|
||||
|
||||
* Enable / Disable
|
||||
|
||||
* API address: http://\<server\>:\<port\>/api/enable-rule?name=\<rule name\>&enable=[true | false]
|
||||
* Method POST
|
||||
* Example:curl -X POST http://localhost:8100/api/enable-rule?name=rule1&enable=true
|
||||
|
||||
* Retrieve rule list
|
||||
|
||||
* API address: http://\<server\>:\<port\>/api/list-rule
|
||||
* Method: GET
|
||||
* Example:curl http://localhost:8100/api/list-rule
|
|
@ -1,181 +0,0 @@
|
|||
# Alert
|
||||
|
||||
报警监测程序,从 [TDEngine](https://www.taosdata.com/) 读取数据后,根据预定义的规则计算和生成报警,并将它们推送到 [AlertManager](https://github.com/prometheus/alertmanager) 或其它下游应用。
|
||||
|
||||
## 安装
|
||||
|
||||
### 使用编译好的二进制文件
|
||||
|
||||
您可以从 [涛思数据](https://www.taosdata.com/cn/getting-started/) 官网下载最新的安装包。下载完成后,使用以下命令解压:
|
||||
|
||||
```
|
||||
$ tar -xzf tdengine-alert-$version-$OS-$ARCH.tar.gz
|
||||
```
|
||||
|
||||
如果您之前没有安装过 TDengine 的服务端或客户端,您需要使用下面的命令安装 TDengine 的动态库:
|
||||
|
||||
```
|
||||
$ ./install_driver.sh
|
||||
```
|
||||
|
||||
### 从源码安装
|
||||
|
||||
从源码安装需要在您用于编译的计算机上提前安装好 TDEngine 的服务端或客户端,如果您还没有安装,可以参考 TDEngine 的文档。
|
||||
|
||||
报警监测程序使用 [Go语言](https://golang.org) 开发,请安装最新版的 Go 语言编译环境。
|
||||
|
||||
```
|
||||
$ mkdir taosdata
|
||||
$ cd taosdata
|
||||
$ git clone https://github.com/taosdata/tdengine.git
|
||||
$ cd tdengine/alert/cmd/alert
|
||||
$ go build
|
||||
```
|
||||
|
||||
如果由于部分包无法下载导致 `go build` 失败,请根据 [goproxy.io](https://goproxy.io) 上的说明配置好 `GOPROXY` 再重新执行 `go build`。
|
||||
|
||||
## 配置
|
||||
|
||||
报警监测程序的配置文件采用标准`json`格式,下面是默认的文件内容,请根据实际情况修改。
|
||||
|
||||
```json
|
||||
{
|
||||
"port": 8100,
|
||||
"database": "file:alert.db",
|
||||
"tdengine": "root:taosdata@/tcp(127.0.0.1:0)/",
|
||||
"log": {
|
||||
"level": "production",
|
||||
"path": "alert.log"
|
||||
},
|
||||
"receivers": {
|
||||
"alertManager": "http://127.0.0.1:9093/api/v1/alerts",
|
||||
"console": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
* **port**:报警监测程序支持使用 `restful API` 对规则进行管理,这个参数用于配置 `http` 服务的侦听端口。
|
||||
* **database**:报警监测程序将规则保存到了一个 `sqlite` 数据库中,这个参数用于指定数据库文件的路径(不需要提前创建这个文件,如果它不存在,程序会自动创建它)。
|
||||
* **tdengine**:`TDEngine` 的连接字符串(这个字符串的详细格式说明请见 GO 连接器的文档),一般来说,数据库名应该在报警规则的 `sql` 语句中指定,所以这个字符串中 **不** 应包含数据库名。
|
||||
* **log > level**:日志的记录级别,可选 `production` 或 `debug`。
|
||||
* **log > path**:日志文件的路径。
|
||||
* **receivers > alertManager**:报警监测程序会将报警推送到 `AlertManager`,在这里指定 `AlertManager` 的接收地址。
|
||||
* **receivers > console**:是否输出到控制台 (stdout)。
|
||||
|
||||
准备好配置文件后,可使用下面的命令启动报警监测程序( `alert.cfg` 是配置文件的路径):
|
||||
|
||||
```
|
||||
$ ./alert -cfg alert.cfg
|
||||
```
|
||||
|
||||
## 编写报警规则
|
||||
|
||||
从技术角度,可以将报警描述为:从 `TDEngine` 中查询最近一段时间、符合一定过滤条件的数据,并基于这些数据根据定义好的计算方法得出一个结果,当结果符合某个条件且持续一定时间后,触发报警。
|
||||
|
||||
根据上面的描述,可以很容易的知道报警规则中需要包含的大部分信息。 以下是一个完整的报警规则,采用标准 `json` 格式:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "rule1",
|
||||
"sql": "select sum(col1) as sumCol1 from test.meters where ts > now - 1h group by areaid",
|
||||
"expr": "sumCol1 > 10",
|
||||
"for": "10m",
|
||||
"period": "1m",
|
||||
"labels": {
|
||||
"ruleName": "rule1"
|
||||
},
|
||||
"annotations": {
|
||||
"summary": "sum of rule {{$labels.ruleName}} of area {{$values.areaid}} is {{$values.sumCol1}}"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
其中:
|
||||
|
||||
* **name**:用于为规则指定一个唯一的名字。
|
||||
* **sql**:从 `TDEngine` 中查询数据时使用的 `sql` 语句,查询结果中的列将被后续计算使用,所以,如果使用了聚合函数,请为这一列指定一个别名。
|
||||
* **expr**:一个计算结果为布尔型的表达式,支持算数运算、逻辑运算,并且内置了部分函数,也可以引用查询结果中的列。 当表达式计算结果为 `true` 时,进入报警状态。
|
||||
* **for**:当表达式计算结果为 `true` 的连续时长超过这个选项时,触发报警,否则报警处于“待定”状态。默认为0,表示一旦计算结果为 `true`,立即触发报警。
|
||||
* **period**:规则的检查周期,默认1分钟。
|
||||
* **labels**:人为指定的标签列表,标签可以在生成报警信息引用。如果 `sql` 中包含 `group by` 子句,则所有用于分组的字段会被自动加入这个标签列表中。
|
||||
* **annotations**:用于定义报警信息,使用 [go template](https://golang.org/pkg/text/template) 语法,其中,可以通过 `$labels.<label name>` 引用标签,也可以通过 `$values.<column name>` 引用查询结果中的列。
|
||||
|
||||
### 运算符
|
||||
|
||||
以下是 `expr` 字段中支持的运算符,您可以使用 `()` 改变运算的优先级。
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr> <td>运算符</td><td>单目/双目</td><td>优先级</td><td>作用</td> </tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr> <td>~</td><td>单目</td><td>6</td><td>按位取反</td> </tr>
|
||||
<tr> <td>!</td><td>单目</td><td>6</td><td>逻辑非</td> </tr>
|
||||
<tr> <td>+</td><td>单目</td><td>6</td><td>正号</td> </tr>
|
||||
<tr> <td>-</td><td>单目</td><td>6</td><td>负号</td> </tr>
|
||||
<tr> <td>*</td><td>双目</td><td>5</td><td>乘法</td> </tr>
|
||||
<tr> <td>/</td><td>双目</td><td>5</td><td>除法</td> </tr>
|
||||
<tr> <td>%</td><td>双目</td><td>5</td><td>取模(余数)</td> </tr>
|
||||
<tr> <td><<</td><td>双目</td><td>5</td><td>按位左移</td> </tr>
|
||||
<tr> <td>>></td><td>双目</td><td>5</td><td>按位右移</td> </tr>
|
||||
<tr> <td>&</td><td>双目</td><td>5</td><td>按位与</td> </tr>
|
||||
<tr> <td>+</td><td>双目</td><td>4</td><td>加法</td> </tr>
|
||||
<tr> <td>-</td><td>双目</td><td>4</td><td>减法</td> </tr>
|
||||
<tr> <td>|</td><td>双目</td><td>4</td><td>按位或</td> </tr>
|
||||
<tr> <td>^</td><td>双目</td><td>4</td><td>按位异或</td> </tr>
|
||||
<tr> <td>==</td><td>双目</td><td>3</td><td>等于</td> </tr>
|
||||
<tr> <td>!=</td><td>双目</td><td>3</td><td>不等于</td> </tr>
|
||||
<tr> <td><</td><td>双目</td><td>3</td><td>小于</td> </tr>
|
||||
<tr> <td><=</td><td>双目</td><td>3</td><td>小于或等于</td> </tr>
|
||||
<tr> <td>></td><td>双目</td><td>3</td><td>大于</td> </tr>
|
||||
<tr> <td>>=</td><td>双目</td><td>3</td><td>大于或等于</td> </tr>
|
||||
<tr> <td>&&</td><td>双目</td><td>2</td><td>逻辑与</td> </tr>
|
||||
<tr> <td>||</td><td>双目</td><td>1</td><td>逻辑或</td> </tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### 内置函数
|
||||
|
||||
目前支持以下内置函数,可以在报警规则的 `expr` 字段中使用这些函数:
|
||||
|
||||
* **min**:取多个值中的最小值,例如 `min(1, 2, 3)` 返回 `1`。
|
||||
* **max**:取多个值中的最大值,例如 `max(1, 2, 3)` 返回 `3`。
|
||||
* **sum**:求和,例如 `sum(1, 2, 3)` 返回 `6`。
|
||||
* **avg**:求算术平均值,例如 `avg(1, 2, 3)` 返回 `2`。
|
||||
* **sqrt**:计算平方根,例如 `sqrt(9)` 返回 `3`。
|
||||
* **ceil**:上取整,例如 `ceil(9.1)` 返回 `10`。
|
||||
* **floor**:下取整,例如 `floor(9.9)` 返回 `9`。
|
||||
* **round**:四舍五入,例如 `round(9.9)` 返回 `10`, `round(9.1)` 返回 `9`。
|
||||
* **log**:计算自然对数,例如 `log(10)` 返回 `2.302585`。
|
||||
* **log10**:计算以10为底的对数,例如 `log10(10)` 返回 `1`。
|
||||
* **abs**:计算绝对值,例如 `abs(-1)` 返回 `1`。
|
||||
* **if**:如果第一个参数为 `true`,返回第二个参数,否则返回第三个参数,例如 `if(true, 10, 100)` 返回 `10`, `if(false, 10, 100)` 返回 `100`。
|
||||
|
||||
## 规则管理
|
||||
|
||||
* 添加或修改
|
||||
|
||||
* API地址:http://\<server\>:\<port\>/api/update-rule
|
||||
* Method:POST
|
||||
* Body:规则定义
|
||||
* 示例:curl -d '@rule.json' http://localhost:8100/api/update-rule
|
||||
|
||||
* 删除
|
||||
|
||||
* API地址:http://\<server\>:\<port\>/api/delete-rule?name=\<rule name\>
|
||||
* Method:DELETE
|
||||
* 示例:curl -X DELETE http://localhost:8100/api/delete-rule?name=rule1
|
||||
|
||||
* 挂起或恢复
|
||||
|
||||
* API地址:http://\<server\>:\<port\>/api/enable-rule?name=\<rule name\>&enable=[true | false]
|
||||
* Method:POST
|
||||
* 示例:curl -X POST http://localhost:8100/api/enable-rule?name=rule1&enable=true
|
||||
|
||||
* 获取列表
|
||||
|
||||
* API地址:http://\<server\>:\<port\>/api/list-rule
|
||||
* Method:GET
|
||||
* 示例:curl http://localhost:8100/api/list-rule
|
|
@ -1,190 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/taosdata/alert/models"
|
||||
"github.com/taosdata/alert/utils"
|
||||
"github.com/taosdata/alert/utils/log"
|
||||
)
|
||||
|
||||
func Init() error {
|
||||
if e := initRule(); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
http.HandleFunc("/api/list-rule", onListRule)
|
||||
http.HandleFunc("/api/list-alert", onListAlert)
|
||||
http.HandleFunc("/api/update-rule", onUpdateRule)
|
||||
http.HandleFunc("/api/enable-rule", onEnableRule)
|
||||
http.HandleFunc("/api/delete-rule", onDeleteRule)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Uninit() error {
|
||||
uninitRule()
|
||||
return nil
|
||||
}
|
||||
|
||||
func onListRule(w http.ResponseWriter, r *http.Request) {
|
||||
var res []*Rule
|
||||
rules.Range(func(k, v interface{}) bool {
|
||||
res = append(res, v.(*Rule))
|
||||
return true
|
||||
})
|
||||
|
||||
w.Header().Add("Content-Type", "application/json; charset=utf-8")
|
||||
json.NewEncoder(w).Encode(res)
|
||||
}
|
||||
|
||||
func onListAlert(w http.ResponseWriter, r *http.Request) {
|
||||
var alerts []*Alert
|
||||
rn := r.URL.Query().Get("rule")
|
||||
rules.Range(func(k, v interface{}) bool {
|
||||
if len(rn) > 0 && rn != k.(string) {
|
||||
return true
|
||||
}
|
||||
|
||||
rule := v.(*Rule)
|
||||
rule.Alerts.Range(func(k, v interface{}) bool {
|
||||
alert := v.(*Alert)
|
||||
// TODO: not go-routine safe
|
||||
if alert.State != AlertStateWaiting {
|
||||
alerts = append(alerts, v.(*Alert))
|
||||
}
|
||||
return true
|
||||
})
|
||||
return true
|
||||
})
|
||||
w.Header().Add("Content-Type", "application/json; charset=utf-8")
|
||||
json.NewEncoder(w).Encode(alerts)
|
||||
}
|
||||
|
||||
func onUpdateRule(w http.ResponseWriter, r *http.Request) {
|
||||
data, e := ioutil.ReadAll(r.Body)
|
||||
if e != nil {
|
||||
log.Error("failed to read request body: ", e.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
rule, e := newRule(string(data))
|
||||
if e != nil {
|
||||
log.Error("failed to parse rule: ", e.Error())
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
if e = doUpdateRule(rule, string(data)); e != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func doUpdateRule(rule *Rule, ruleStr string) error {
|
||||
if _, ok := rules.Load(rule.Name); ok {
|
||||
if len(utils.Cfg.Database) > 0 {
|
||||
e := models.UpdateRule(rule.Name, ruleStr)
|
||||
if e != nil {
|
||||
log.Errorf("[%s]: update failed: %s", rule.Name, e.Error())
|
||||
return e
|
||||
}
|
||||
}
|
||||
log.Infof("[%s]: update succeeded.", rule.Name)
|
||||
} else {
|
||||
if len(utils.Cfg.Database) > 0 {
|
||||
e := models.AddRule(&models.Rule{
|
||||
Name: rule.Name,
|
||||
Content: ruleStr,
|
||||
})
|
||||
if e != nil {
|
||||
log.Errorf("[%s]: add failed: %s", rule.Name, e.Error())
|
||||
return e
|
||||
}
|
||||
}
|
||||
log.Infof("[%s]: add succeeded.", rule.Name)
|
||||
}
|
||||
|
||||
rules.Store(rule.Name, rule)
|
||||
return nil
|
||||
}
|
||||
|
||||
func onEnableRule(w http.ResponseWriter, r *http.Request) {
|
||||
var rule *Rule
|
||||
name := r.URL.Query().Get("name")
|
||||
enable := strings.ToLower(r.URL.Query().Get("enable")) == "true"
|
||||
|
||||
if x, ok := rules.Load(name); ok {
|
||||
rule = x.(*Rule)
|
||||
} else {
|
||||
w.WriteHeader(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
if rule.isEnabled() == enable {
|
||||
return
|
||||
}
|
||||
|
||||
if len(utils.Cfg.Database) > 0 {
|
||||
if e := models.EnableRule(name, enable); e != nil {
|
||||
if enable {
|
||||
log.Errorf("[%s]: enable failed: ", name, e.Error())
|
||||
} else {
|
||||
log.Errorf("[%s]: disable failed: ", name, e.Error())
|
||||
}
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if enable {
|
||||
rule = rule.clone()
|
||||
rule.setNextRunTime(time.Now())
|
||||
rules.Store(rule.Name, rule)
|
||||
log.Infof("[%s]: enable succeeded.", name)
|
||||
} else {
|
||||
rule.setState(RuleStateDisabled)
|
||||
log.Infof("[%s]: disable succeeded.", name)
|
||||
}
|
||||
}
|
||||
|
||||
func onDeleteRule(w http.ResponseWriter, r *http.Request) {
|
||||
name := r.URL.Query().Get("name")
|
||||
if len(name) == 0 {
|
||||
return
|
||||
}
|
||||
if e := doDeleteRule(name); e != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func doDeleteRule(name string) error {
|
||||
if len(utils.Cfg.Database) > 0 {
|
||||
if e := models.DeleteRule(name); e != nil {
|
||||
log.Errorf("[%s]: delete failed: %s", name, e.Error())
|
||||
return e
|
||||
}
|
||||
}
|
||||
rules.Delete(name)
|
||||
log.Infof("[%s]: delete succeeded.", name)
|
||||
return nil
|
||||
}
|
|
@ -1,807 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package expr
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"text/scanner"
|
||||
)
|
||||
|
||||
var (
|
||||
// compile errors
|
||||
ErrorExpressionSyntax = errors.New("expression syntax error")
|
||||
ErrorUnrecognizedFunction = errors.New("unrecognized function")
|
||||
ErrorArgumentCount = errors.New("too many/few arguments")
|
||||
ErrorInvalidFloat = errors.New("invalid float")
|
||||
ErrorInvalidInteger = errors.New("invalid integer")
|
||||
|
||||
// eval errors
|
||||
ErrorUnsupportedDataType = errors.New("unsupported data type")
|
||||
ErrorInvalidOperationFloat = errors.New("invalid operation for float")
|
||||
ErrorInvalidOperationInteger = errors.New("invalid operation for integer")
|
||||
ErrorInvalidOperationBoolean = errors.New("invalid operation for boolean")
|
||||
ErrorOnlyIntegerAllowed = errors.New("only integers is allowed")
|
||||
ErrorDataTypeMismatch = errors.New("data type mismatch")
|
||||
)
|
||||
|
||||
// binary operator precedence
|
||||
// 5 * / % << >> &
|
||||
// 4 + - | ^
|
||||
// 3 == != < <= > >=
|
||||
// 2 &&
|
||||
// 1 ||
|
||||
const (
|
||||
opOr = -(iota + 1000) // ||
|
||||
opAnd // &&
|
||||
opEqual // ==
|
||||
opNotEqual // !=
|
||||
opGTE // >=
|
||||
opLTE // <=
|
||||
opLeftShift // <<
|
||||
opRightShift // >>
|
||||
)
|
||||
|
||||
type lexer struct {
|
||||
scan scanner.Scanner
|
||||
tok rune
|
||||
}
|
||||
|
||||
func (l *lexer) init(src io.Reader) {
|
||||
l.scan.Error = func(s *scanner.Scanner, msg string) {
|
||||
panic(errors.New(msg))
|
||||
}
|
||||
l.scan.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats | scanner.ScanStrings
|
||||
l.scan.Init(src)
|
||||
l.tok = l.next()
|
||||
}
|
||||
|
||||
func (l *lexer) next() rune {
|
||||
l.tok = l.scan.Scan()
|
||||
|
||||
switch l.tok {
|
||||
case '|':
|
||||
if l.scan.Peek() == '|' {
|
||||
l.tok = opOr
|
||||
l.scan.Scan()
|
||||
}
|
||||
|
||||
case '&':
|
||||
if l.scan.Peek() == '&' {
|
||||
l.tok = opAnd
|
||||
l.scan.Scan()
|
||||
}
|
||||
|
||||
case '=':
|
||||
if l.scan.Peek() == '=' {
|
||||
l.tok = opEqual
|
||||
l.scan.Scan()
|
||||
} else {
|
||||
// TODO: error
|
||||
}
|
||||
|
||||
case '!':
|
||||
if l.scan.Peek() == '=' {
|
||||
l.tok = opNotEqual
|
||||
l.scan.Scan()
|
||||
} else {
|
||||
// TODO: error
|
||||
}
|
||||
|
||||
case '<':
|
||||
if tok := l.scan.Peek(); tok == '<' {
|
||||
l.tok = opLeftShift
|
||||
l.scan.Scan()
|
||||
} else if tok == '=' {
|
||||
l.tok = opLTE
|
||||
l.scan.Scan()
|
||||
}
|
||||
|
||||
case '>':
|
||||
if tok := l.scan.Peek(); tok == '>' {
|
||||
l.tok = opRightShift
|
||||
l.scan.Scan()
|
||||
} else if tok == '=' {
|
||||
l.tok = opGTE
|
||||
l.scan.Scan()
|
||||
}
|
||||
}
|
||||
return l.tok
|
||||
}
|
||||
|
||||
func (l *lexer) token() rune {
|
||||
return l.tok
|
||||
}
|
||||
|
||||
func (l *lexer) text() string {
|
||||
switch l.tok {
|
||||
case opOr:
|
||||
return "||"
|
||||
case opAnd:
|
||||
return "&&"
|
||||
case opEqual:
|
||||
return "=="
|
||||
case opNotEqual:
|
||||
return "!="
|
||||
case opLeftShift:
|
||||
return "<<"
|
||||
case opLTE:
|
||||
return "<="
|
||||
case opRightShift:
|
||||
return ">>"
|
||||
case opGTE:
|
||||
return ">="
|
||||
default:
|
||||
return l.scan.TokenText()
|
||||
}
|
||||
}
|
||||
|
||||
type Expr interface {
|
||||
Eval(env func(string) interface{}) interface{}
|
||||
}
|
||||
|
||||
type unaryExpr struct {
|
||||
op rune
|
||||
subExpr Expr
|
||||
}
|
||||
|
||||
func (ue *unaryExpr) Eval(env func(string) interface{}) interface{} {
|
||||
val := ue.subExpr.Eval(env)
|
||||
switch v := val.(type) {
|
||||
case float64:
|
||||
if ue.op != '-' {
|
||||
panic(ErrorInvalidOperationFloat)
|
||||
}
|
||||
return -v
|
||||
case int64:
|
||||
switch ue.op {
|
||||
case '-':
|
||||
return -v
|
||||
case '~':
|
||||
return ^v
|
||||
default:
|
||||
panic(ErrorInvalidOperationInteger)
|
||||
}
|
||||
case bool:
|
||||
if ue.op != '!' {
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
return !v
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
|
||||
type binaryExpr struct {
|
||||
op rune
|
||||
lhs Expr
|
||||
rhs Expr
|
||||
}
|
||||
|
||||
func (be *binaryExpr) Eval(env func(string) interface{}) interface{} {
|
||||
lval := be.lhs.Eval(env)
|
||||
rval := be.rhs.Eval(env)
|
||||
|
||||
switch be.op {
|
||||
case '*':
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return lv * rv
|
||||
case int64:
|
||||
return lv * float64(rv)
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return float64(lv) * rv
|
||||
case int64:
|
||||
return lv * rv
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
|
||||
case '/':
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
if rv == 0 {
|
||||
return math.Inf(int(lv))
|
||||
} else {
|
||||
return lv / rv
|
||||
}
|
||||
case int64:
|
||||
if rv == 0 {
|
||||
return math.Inf(int(lv))
|
||||
} else {
|
||||
return lv / float64(rv)
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
if rv == 0 {
|
||||
return math.Inf(int(lv))
|
||||
} else {
|
||||
return float64(lv) / rv
|
||||
}
|
||||
case int64:
|
||||
if rv == 0 {
|
||||
return math.Inf(int(lv))
|
||||
} else {
|
||||
return lv / rv
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
|
||||
case '%':
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return math.Mod(lv, rv)
|
||||
case int64:
|
||||
return math.Mod(lv, float64(rv))
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return math.Mod(float64(lv), rv)
|
||||
case int64:
|
||||
if rv == 0 {
|
||||
return math.Inf(int(lv))
|
||||
} else {
|
||||
return lv % rv
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
|
||||
case opLeftShift:
|
||||
switch lv := lval.(type) {
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case int64:
|
||||
return lv << rv
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
|
||||
case opRightShift:
|
||||
switch lv := lval.(type) {
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case int64:
|
||||
return lv >> rv
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
|
||||
case '&':
|
||||
switch lv := lval.(type) {
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case int64:
|
||||
return lv & rv
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
|
||||
case '+':
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return lv + rv
|
||||
case int64:
|
||||
return lv + float64(rv)
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return float64(lv) + rv
|
||||
case int64:
|
||||
return lv + rv
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
|
||||
case '-':
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return lv - rv
|
||||
case int64:
|
||||
return lv - float64(rv)
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return float64(lv) - rv
|
||||
case int64:
|
||||
return lv - rv
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
|
||||
case '|':
|
||||
switch lv := lval.(type) {
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case int64:
|
||||
return lv | rv
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
|
||||
case '^':
|
||||
switch lv := lval.(type) {
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case int64:
|
||||
return lv ^ rv
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
|
||||
case opEqual:
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return lv == rv
|
||||
case int64:
|
||||
return lv == float64(rv)
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return float64(lv) == rv
|
||||
case int64:
|
||||
return lv == rv
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case bool:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
case int64:
|
||||
case bool:
|
||||
return lv == rv
|
||||
}
|
||||
}
|
||||
|
||||
case opNotEqual:
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return lv != rv
|
||||
case int64:
|
||||
return lv != float64(rv)
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return float64(lv) != rv
|
||||
case int64:
|
||||
return lv != rv
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case bool:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
case int64:
|
||||
case bool:
|
||||
return lv != rv
|
||||
}
|
||||
}
|
||||
|
||||
case '<':
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return lv < rv
|
||||
case int64:
|
||||
return lv < float64(rv)
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return float64(lv) < rv
|
||||
case int64:
|
||||
return lv < rv
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
|
||||
case opLTE:
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return lv <= rv
|
||||
case int64:
|
||||
return lv <= float64(rv)
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return float64(lv) <= rv
|
||||
case int64:
|
||||
return lv <= rv
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
|
||||
case '>':
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return lv > rv
|
||||
case int64:
|
||||
return lv > float64(rv)
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return float64(lv) > rv
|
||||
case int64:
|
||||
return lv > rv
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
|
||||
case opGTE:
|
||||
switch lv := lval.(type) {
|
||||
case float64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return lv >= rv
|
||||
case int64:
|
||||
return lv >= float64(rv)
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case int64:
|
||||
switch rv := rval.(type) {
|
||||
case float64:
|
||||
return float64(lv) >= rv
|
||||
case int64:
|
||||
return lv >= rv
|
||||
case bool:
|
||||
panic(ErrorDataTypeMismatch)
|
||||
}
|
||||
case bool:
|
||||
panic(ErrorInvalidOperationBoolean)
|
||||
}
|
||||
|
||||
case opAnd:
|
||||
switch lv := lval.(type) {
|
||||
case bool:
|
||||
switch rv := rval.(type) {
|
||||
case bool:
|
||||
return lv && rv
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
|
||||
case opOr:
|
||||
switch lv := lval.(type) {
|
||||
case bool:
|
||||
switch rv := rval.(type) {
|
||||
case bool:
|
||||
return lv || rv
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
default:
|
||||
panic(ErrorOnlyIntegerAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type funcExpr struct {
|
||||
name string
|
||||
args []Expr
|
||||
}
|
||||
|
||||
func (fe *funcExpr) Eval(env func(string) interface{}) interface{} {
|
||||
argv := make([]interface{}, 0, len(fe.args))
|
||||
for _, arg := range fe.args {
|
||||
argv = append(argv, arg.Eval(env))
|
||||
}
|
||||
return funcs[fe.name].call(argv)
|
||||
}
|
||||
|
||||
type floatExpr struct {
|
||||
val float64
|
||||
}
|
||||
|
||||
func (fe *floatExpr) Eval(env func(string) interface{}) interface{} {
|
||||
return fe.val
|
||||
}
|
||||
|
||||
type intExpr struct {
|
||||
val int64
|
||||
}
|
||||
|
||||
func (ie *intExpr) Eval(env func(string) interface{}) interface{} {
|
||||
return ie.val
|
||||
}
|
||||
|
||||
type boolExpr struct {
|
||||
val bool
|
||||
}
|
||||
|
||||
func (be *boolExpr) Eval(env func(string) interface{}) interface{} {
|
||||
return be.val
|
||||
}
|
||||
|
||||
type stringExpr struct {
|
||||
val string
|
||||
}
|
||||
|
||||
func (se *stringExpr) Eval(env func(string) interface{}) interface{} {
|
||||
return se.val
|
||||
}
|
||||
|
||||
type varExpr struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (ve *varExpr) Eval(env func(string) interface{}) interface{} {
|
||||
return env(ve.name)
|
||||
}
|
||||
|
||||
func Compile(src string) (expr Expr, err error) {
|
||||
defer func() {
|
||||
switch x := recover().(type) {
|
||||
case nil:
|
||||
case error:
|
||||
err = x
|
||||
default:
|
||||
}
|
||||
}()
|
||||
|
||||
lexer := lexer{}
|
||||
lexer.init(strings.NewReader(src))
|
||||
expr = parseBinary(&lexer, 0)
|
||||
if lexer.token() != scanner.EOF {
|
||||
panic(ErrorExpressionSyntax)
|
||||
}
|
||||
return expr, nil
|
||||
}
|
||||
|
||||
func precedence(op rune) int {
|
||||
switch op {
|
||||
case opOr:
|
||||
return 1
|
||||
case opAnd:
|
||||
return 2
|
||||
case opEqual, opNotEqual, '<', '>', opGTE, opLTE:
|
||||
return 3
|
||||
case '+', '-', '|', '^':
|
||||
return 4
|
||||
case '*', '/', '%', opLeftShift, opRightShift, '&':
|
||||
return 5
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// binary = unary ('+' binary)*
|
||||
func parseBinary(lexer *lexer, lastPrec int) Expr {
|
||||
lhs := parseUnary(lexer)
|
||||
|
||||
for {
|
||||
op := lexer.token()
|
||||
prec := precedence(op)
|
||||
if prec <= lastPrec {
|
||||
break
|
||||
}
|
||||
lexer.next() // consume operator
|
||||
rhs := parseBinary(lexer, prec)
|
||||
lhs = &binaryExpr{op: op, lhs: lhs, rhs: rhs}
|
||||
}
|
||||
|
||||
return lhs
|
||||
}
|
||||
|
||||
// unary = '+|-' expr | primary
|
||||
func parseUnary(lexer *lexer) Expr {
|
||||
flag := false
|
||||
for tok := lexer.token(); ; tok = lexer.next() {
|
||||
if tok == '-' {
|
||||
flag = !flag
|
||||
} else if tok != '+' {
|
||||
break
|
||||
}
|
||||
}
|
||||
if flag {
|
||||
return &unaryExpr{op: '-', subExpr: parsePrimary(lexer)}
|
||||
}
|
||||
|
||||
flag = false
|
||||
for tok := lexer.token(); tok == '!'; tok = lexer.next() {
|
||||
flag = !flag
|
||||
}
|
||||
if flag {
|
||||
return &unaryExpr{op: '!', subExpr: parsePrimary(lexer)}
|
||||
}
|
||||
|
||||
flag = false
|
||||
for tok := lexer.token(); tok == '~'; tok = lexer.next() {
|
||||
flag = !flag
|
||||
}
|
||||
if flag {
|
||||
return &unaryExpr{op: '~', subExpr: parsePrimary(lexer)}
|
||||
}
|
||||
|
||||
return parsePrimary(lexer)
|
||||
}
|
||||
|
||||
// primary = id
|
||||
// | id '(' expr ',' ... ',' expr ')'
|
||||
// | num
|
||||
// | '(' expr ')'
|
||||
func parsePrimary(lexer *lexer) Expr {
|
||||
switch lexer.token() {
|
||||
case '+', '-', '!', '~':
|
||||
return parseUnary(lexer)
|
||||
|
||||
case '(':
|
||||
lexer.next() // consume '('
|
||||
node := parseBinary(lexer, 0)
|
||||
if lexer.token() != ')' {
|
||||
panic(ErrorExpressionSyntax)
|
||||
}
|
||||
lexer.next() // consume ')'
|
||||
return node
|
||||
|
||||
case scanner.Ident:
|
||||
id := strings.ToLower(lexer.text())
|
||||
if lexer.next() != '(' {
|
||||
if id == "true" {
|
||||
return &boolExpr{val: true}
|
||||
} else if id == "false" {
|
||||
return &boolExpr{val: false}
|
||||
} else {
|
||||
return &varExpr{name: id}
|
||||
}
|
||||
}
|
||||
node := funcExpr{name: id}
|
||||
for lexer.next() != ')' {
|
||||
arg := parseBinary(lexer, 0)
|
||||
node.args = append(node.args, arg)
|
||||
if lexer.token() != ',' {
|
||||
break
|
||||
}
|
||||
}
|
||||
if lexer.token() != ')' {
|
||||
panic(ErrorExpressionSyntax)
|
||||
}
|
||||
|
||||
if fn, ok := funcs[id]; !ok {
|
||||
panic(ErrorUnrecognizedFunction)
|
||||
} else if fn.minArgs >= 0 && len(node.args) < fn.minArgs {
|
||||
panic(ErrorArgumentCount)
|
||||
} else if fn.maxArgs >= 0 && len(node.args) > fn.maxArgs {
|
||||
panic(ErrorArgumentCount)
|
||||
}
|
||||
|
||||
lexer.next() // consume it
|
||||
return &node
|
||||
|
||||
case scanner.Int:
|
||||
val, e := strconv.ParseInt(lexer.text(), 0, 64)
|
||||
if e != nil {
|
||||
panic(ErrorInvalidFloat)
|
||||
}
|
||||
lexer.next()
|
||||
return &intExpr{val: val}
|
||||
|
||||
case scanner.Float:
|
||||
val, e := strconv.ParseFloat(lexer.text(), 0)
|
||||
if e != nil {
|
||||
panic(ErrorInvalidInteger)
|
||||
}
|
||||
lexer.next()
|
||||
return &floatExpr{val: val}
|
||||
|
||||
case scanner.String:
|
||||
panic(errors.New("strings are not allowed in expression at present"))
|
||||
val := lexer.text()
|
||||
lexer.next()
|
||||
return &stringExpr{val: val}
|
||||
|
||||
default:
|
||||
panic(ErrorExpressionSyntax)
|
||||
}
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package expr
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestIntArithmetic(t *testing.T) {
|
||||
cases := []struct {
|
||||
expr string
|
||||
expected int64
|
||||
}{
|
||||
{"+10", 10},
|
||||
{"-10", -10},
|
||||
{"3 + 4 + 5 + 6 * 7 + 8", 62},
|
||||
{"3 + 4 + (5 + 6) * 7 + 8", 92},
|
||||
{"3 + 4 + (5 + 6) * 7 / 11 + 8", 22},
|
||||
{"3 + 4 + -5 * 6 / 7 % 8", 3},
|
||||
{"10 - 5", 5},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
expr, e := Compile(c.expr)
|
||||
if e != nil {
|
||||
t.Errorf("failed to compile expression '%s': %s", c.expr, e.Error())
|
||||
}
|
||||
if res := expr.Eval(nil); res.(int64) != c.expected {
|
||||
t.Errorf("result for expression '%s' is %v, but expected is %v", c.expr, res, c.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloatArithmetic(t *testing.T) {
|
||||
cases := []struct {
|
||||
expr string
|
||||
expected float64
|
||||
}{
|
||||
{"+10.5", 10.5},
|
||||
{"-10.5", -10.5},
|
||||
{"3.1 + 4.2 + 5 + 6 * 7 + 8", 62.3},
|
||||
{"3.1 + 4.2 + (5 + 6) * 7 + 8.3", 92.6},
|
||||
{"3.1 + 4.2 + (5.1 + 5.9) * 7 / 11 + 8", 22.3},
|
||||
{"3.3 + 4.2 - 4.0 * 7.5 / 3", -2.5},
|
||||
{"3.3 + 4.2 - 4 * 7.0 / 2", -6.5},
|
||||
{"3.5/2.0", 1.75},
|
||||
{"3.5/2", 1.75},
|
||||
{"7 / 3.5", 2},
|
||||
{"3.5 % 2.0", 1.5},
|
||||
{"3.5 % 2", 1.5},
|
||||
{"7 % 2.5", 2},
|
||||
{"7.3 - 2", 5.3},
|
||||
{"7 - 2.3", 4.7},
|
||||
{"1 + 1.5", 2.5},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
expr, e := Compile(c.expr)
|
||||
if e != nil {
|
||||
t.Errorf("failed to compile expression '%s': %s", c.expr, e.Error())
|
||||
}
|
||||
if res := expr.Eval(nil); res.(float64) != c.expected {
|
||||
t.Errorf("result for expression '%s' is %v, but expected is %v", c.expr, res, c.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVariable(t *testing.T) {
|
||||
variables := map[string]interface{}{
|
||||
"a": int64(6),
|
||||
"b": int64(7),
|
||||
}
|
||||
env := func(key string) interface{} {
|
||||
return variables[key]
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
expr string
|
||||
expected int64
|
||||
}{
|
||||
{"3 + 4 + (+5) + a * b + 8", 62},
|
||||
{"3 + 4 + (5 + a) * b + 8", 92},
|
||||
{"3 + 4 + (5 + a) * b / 11 + 8", 22},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
expr, e := Compile(c.expr)
|
||||
if e != nil {
|
||||
t.Errorf("failed to compile expression '%s': %s", c.expr, e.Error())
|
||||
}
|
||||
if res := expr.Eval(env); res.(int64) != c.expected {
|
||||
t.Errorf("result for expression '%s' is %v, but expected is %v", c.expr, res, c.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFunction(t *testing.T) {
|
||||
variables := map[string]interface{}{
|
||||
"a": int64(6),
|
||||
"b": 7.0,
|
||||
}
|
||||
|
||||
env := func(key string) interface{} {
|
||||
return variables[key]
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
expr string
|
||||
expected float64
|
||||
}{
|
||||
{"sum(3, 4, 5, a * b, 8)", 62},
|
||||
{"sum(3, 4, (5 + a) * b, 8)", 92},
|
||||
{"sum(3, 4, (5 + a) * b / 11, 8)", 22},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
expr, e := Compile(c.expr)
|
||||
if e != nil {
|
||||
t.Errorf("failed to compile expression '%s': %s", c.expr, e.Error())
|
||||
}
|
||||
if res := expr.Eval(env); res.(float64) != c.expected {
|
||||
t.Errorf("result for expression '%s' is %v, but expected is %v", c.expr, res, c.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLogical(t *testing.T) {
|
||||
cases := []struct {
|
||||
expr string
|
||||
expected bool
|
||||
}{
|
||||
{"true", true},
|
||||
{"false", false},
|
||||
{"true == true", true},
|
||||
{"true == false", false},
|
||||
{"true != true", false},
|
||||
{"true != false", true},
|
||||
{"5 > 3", true},
|
||||
{"5 < 3", false},
|
||||
{"5.2 > 3", true},
|
||||
{"5.2 < 3", false},
|
||||
{"5 > 3.1", true},
|
||||
{"5 < 3.1", false},
|
||||
{"5.1 > 3.3", true},
|
||||
{"5.1 < 3.3", false},
|
||||
{"5 >= 3", true},
|
||||
{"5 <= 3", false},
|
||||
{"5.2 >= 3", true},
|
||||
{"5.2 <= 3", false},
|
||||
{"5 >= 3.1", true},
|
||||
{"5 <= 3.1", false},
|
||||
{"5.1 >= 3.3", true},
|
||||
{"5.1 <= 3.3", false},
|
||||
{"5 != 3", true},
|
||||
{"5.2 != 3.2", true},
|
||||
{"5.2 != 3", true},
|
||||
{"5 != 3.2", true},
|
||||
{"5 == 3", false},
|
||||
{"5.2 == 3.2", false},
|
||||
{"5.2 == 3", false},
|
||||
{"5 == 3.2", false},
|
||||
{"!(5 > 3)", false},
|
||||
{"5>3 && 3>1", true},
|
||||
{"5<3 || 3<1", false},
|
||||
{"4<=4 || 3<1", true},
|
||||
{"4<4 || 3>=1", true},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
expr, e := Compile(c.expr)
|
||||
if e != nil {
|
||||
t.Errorf("failed to compile expression '%s': %s", c.expr, e.Error())
|
||||
}
|
||||
if res := expr.Eval(nil); res.(bool) != c.expected {
|
||||
t.Errorf("result for expression '%s' is %v, but expected is %v", c.expr, res, c.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBitwise(t *testing.T) {
|
||||
cases := []struct {
|
||||
expr string
|
||||
expected int64
|
||||
}{
|
||||
{"0x0C & 0x04", 0x04},
|
||||
{"0x08 | 0x04", 0x0C},
|
||||
{"0x0C ^ 0x04", 0x08},
|
||||
{"0x01 << 2", 0x04},
|
||||
{"0x04 >> 2", 0x01},
|
||||
{"~0x04", ^0x04},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
expr, e := Compile(c.expr)
|
||||
if e != nil {
|
||||
t.Errorf("failed to compile expression '%s': %s", c.expr, e.Error())
|
||||
}
|
||||
if res := expr.Eval(nil); res.(int64) != c.expected {
|
||||
t.Errorf("result for expression '%s' is 0x%X, but expected is 0x%X", c.expr, res, c.expected)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,213 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package expr
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
type builtInFunc struct {
|
||||
minArgs, maxArgs int
|
||||
call func([]interface{}) interface{}
|
||||
}
|
||||
|
||||
func fnMin(args []interface{}) interface{} {
|
||||
res := args[0]
|
||||
for _, arg := range args[1:] {
|
||||
switch v1 := res.(type) {
|
||||
case int64:
|
||||
switch v2 := arg.(type) {
|
||||
case int64:
|
||||
if v2 < v1 {
|
||||
res = v2
|
||||
}
|
||||
case float64:
|
||||
res = math.Min(float64(v1), v2)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
case float64:
|
||||
switch v2 := arg.(type) {
|
||||
case int64:
|
||||
res = math.Min(v1, float64(v2))
|
||||
case float64:
|
||||
res = math.Min(v1, v2)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func fnMax(args []interface{}) interface{} {
|
||||
res := args[0]
|
||||
for _, arg := range args[1:] {
|
||||
switch v1 := res.(type) {
|
||||
case int64:
|
||||
switch v2 := arg.(type) {
|
||||
case int64:
|
||||
if v2 > v1 {
|
||||
res = v2
|
||||
}
|
||||
case float64:
|
||||
res = math.Max(float64(v1), v2)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
case float64:
|
||||
switch v2 := arg.(type) {
|
||||
case int64:
|
||||
res = math.Max(v1, float64(v2))
|
||||
case float64:
|
||||
res = math.Max(v1, v2)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func fnSum(args []interface{}) interface{} {
|
||||
res := float64(0)
|
||||
for _, arg := range args {
|
||||
switch v := arg.(type) {
|
||||
case int64:
|
||||
res += float64(v)
|
||||
case float64:
|
||||
res += v
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
func fnAvg(args []interface{}) interface{} {
|
||||
return fnSum(args).(float64) / float64(len(args))
|
||||
}
|
||||
|
||||
func fnSqrt(args []interface{}) interface{} {
|
||||
switch v := args[0].(type) {
|
||||
case int64:
|
||||
return math.Sqrt(float64(v))
|
||||
case float64:
|
||||
return math.Sqrt(v)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
|
||||
func fnFloor(args []interface{}) interface{} {
|
||||
switch v := args[0].(type) {
|
||||
case int64:
|
||||
return v
|
||||
case float64:
|
||||
return math.Floor(v)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
|
||||
func fnCeil(args []interface{}) interface{} {
|
||||
switch v := args[0].(type) {
|
||||
case int64:
|
||||
return v
|
||||
case float64:
|
||||
return math.Ceil(v)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
|
||||
func fnRound(args []interface{}) interface{} {
|
||||
switch v := args[0].(type) {
|
||||
case int64:
|
||||
return v
|
||||
case float64:
|
||||
return math.Round(v)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
|
||||
func fnLog(args []interface{}) interface{} {
|
||||
switch v := args[0].(type) {
|
||||
case int64:
|
||||
return math.Log(float64(v))
|
||||
case float64:
|
||||
return math.Log(v)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
|
||||
func fnLog10(args []interface{}) interface{} {
|
||||
switch v := args[0].(type) {
|
||||
case int64:
|
||||
return math.Log10(float64(v))
|
||||
case float64:
|
||||
return math.Log10(v)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
|
||||
func fnAbs(args []interface{}) interface{} {
|
||||
switch v := args[0].(type) {
|
||||
case int64:
|
||||
if v < 0 {
|
||||
return -v
|
||||
}
|
||||
return v
|
||||
case float64:
|
||||
return math.Abs(v)
|
||||
default:
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
}
|
||||
|
||||
func fnIf(args []interface{}) interface{} {
|
||||
v, ok := args[0].(bool)
|
||||
if !ok {
|
||||
panic(ErrorUnsupportedDataType)
|
||||
}
|
||||
if v {
|
||||
return args[1]
|
||||
} else {
|
||||
return args[2]
|
||||
}
|
||||
}
|
||||
|
||||
var funcs = map[string]builtInFunc{
|
||||
"min": builtInFunc{minArgs: 1, maxArgs: -1, call: fnMin},
|
||||
"max": builtInFunc{minArgs: 1, maxArgs: -1, call: fnMax},
|
||||
"sum": builtInFunc{minArgs: 1, maxArgs: -1, call: fnSum},
|
||||
"avg": builtInFunc{minArgs: 1, maxArgs: -1, call: fnAvg},
|
||||
"sqrt": builtInFunc{minArgs: 1, maxArgs: 1, call: fnSqrt},
|
||||
"ceil": builtInFunc{minArgs: 1, maxArgs: 1, call: fnCeil},
|
||||
"floor": builtInFunc{minArgs: 1, maxArgs: 1, call: fnFloor},
|
||||
"round": builtInFunc{minArgs: 1, maxArgs: 1, call: fnRound},
|
||||
"log": builtInFunc{minArgs: 1, maxArgs: 1, call: fnLog},
|
||||
"log10": builtInFunc{minArgs: 1, maxArgs: 1, call: fnLog10},
|
||||
"abs": builtInFunc{minArgs: 1, maxArgs: 1, call: fnAbs},
|
||||
"if": builtInFunc{minArgs: 3, maxArgs: 3, call: fnIf},
|
||||
}
|
|
@ -1,344 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package expr
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMax(t *testing.T) {
|
||||
cases := []struct {
|
||||
args []interface{}
|
||||
expected float64
|
||||
}{
|
||||
{[]interface{}{int64(1), int64(2), int64(3), int64(4), int64(5)}, 5},
|
||||
{[]interface{}{int64(1), int64(2), float64(3), int64(4), float64(5)}, 5},
|
||||
{[]interface{}{int64(-1), int64(-2), float64(-3), int64(-4), float64(-5)}, -1},
|
||||
{[]interface{}{int64(-1), int64(-1), float64(-1), int64(-1), float64(-1)}, -1},
|
||||
{[]interface{}{int64(-1), int64(0), float64(-1), int64(-1), float64(-1)}, 0},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnMax(c.args)
|
||||
switch v := r.(type) {
|
||||
case int64:
|
||||
if v != int64(c.expected) {
|
||||
t.Errorf("max(%v) = %v, want %v", c.args, v, int64(c.expected))
|
||||
}
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("max(%v) = %v, want %v", c.args, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type max(%v)", c.args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMin(t *testing.T) {
|
||||
cases := []struct {
|
||||
args []interface{}
|
||||
expected float64
|
||||
}{
|
||||
{[]interface{}{int64(1), int64(2), int64(3), int64(4), int64(5)}, 1},
|
||||
{[]interface{}{int64(5), int64(4), float64(3), int64(2), float64(1)}, 1},
|
||||
{[]interface{}{int64(-1), int64(-2), float64(-3), int64(-4), float64(-5)}, -5},
|
||||
{[]interface{}{int64(-1), int64(-1), float64(-1), int64(-1), float64(-1)}, -1},
|
||||
{[]interface{}{int64(1), int64(0), float64(1), int64(1), float64(1)}, 0},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnMin(c.args)
|
||||
switch v := r.(type) {
|
||||
case int64:
|
||||
if v != int64(c.expected) {
|
||||
t.Errorf("min(%v) = %v, want %v", c.args, v, int64(c.expected))
|
||||
}
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("min(%v) = %v, want %v", c.args, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type min(%v)", c.args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSumAvg(t *testing.T) {
|
||||
cases := []struct {
|
||||
args []interface{}
|
||||
expected float64
|
||||
}{
|
||||
{[]interface{}{int64(1)}, 1},
|
||||
{[]interface{}{int64(1), int64(2), int64(3), int64(4), int64(5)}, 15},
|
||||
{[]interface{}{int64(5), int64(4), float64(3), int64(2), float64(1)}, 15},
|
||||
{[]interface{}{int64(-1), int64(-2), float64(-3), int64(-4), float64(-5)}, -15},
|
||||
{[]interface{}{int64(-1), int64(-1), float64(-1), int64(-1), float64(-1)}, -5},
|
||||
{[]interface{}{int64(1), int64(0), float64(1), int64(1), float64(1)}, 4},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnSum(c.args)
|
||||
switch v := r.(type) {
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("sum(%v) = %v, want %v", c.args, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type sum(%v)", c.args)
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnAvg(c.args)
|
||||
expected := c.expected / float64(len(c.args))
|
||||
switch v := r.(type) {
|
||||
case float64:
|
||||
if v != expected {
|
||||
t.Errorf("avg(%v) = %v, want %v", c.args, v, expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type avg(%v)", c.args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSqrt(t *testing.T) {
|
||||
cases := []struct {
|
||||
arg interface{}
|
||||
expected float64
|
||||
}{
|
||||
{int64(0), 0},
|
||||
{int64(1), 1},
|
||||
{int64(256), 16},
|
||||
{10.0, math.Sqrt(10)},
|
||||
{10000.0, math.Sqrt(10000)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnSqrt([]interface{}{c.arg})
|
||||
switch v := r.(type) {
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("sqrt(%v) = %v, want %v", c.arg, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type sqrt(%v)", c.arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestFloor(t *testing.T) {
|
||||
cases := []struct {
|
||||
arg interface{}
|
||||
expected float64
|
||||
}{
|
||||
{int64(0), 0},
|
||||
{int64(1), 1},
|
||||
{int64(-1), -1},
|
||||
{10.4, 10},
|
||||
{-10.4, -11},
|
||||
{10.8, 10},
|
||||
{-10.8, -11},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnFloor([]interface{}{c.arg})
|
||||
switch v := r.(type) {
|
||||
case int64:
|
||||
if v != int64(c.expected) {
|
||||
t.Errorf("floor(%v) = %v, want %v", c.arg, v, int64(c.expected))
|
||||
}
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("floor(%v) = %v, want %v", c.arg, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type floor(%v)", c.arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCeil(t *testing.T) {
|
||||
cases := []struct {
|
||||
arg interface{}
|
||||
expected float64
|
||||
}{
|
||||
{int64(0), 0},
|
||||
{int64(1), 1},
|
||||
{int64(-1), -1},
|
||||
{10.4, 11},
|
||||
{-10.4, -10},
|
||||
{10.8, 11},
|
||||
{-10.8, -10},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnCeil([]interface{}{c.arg})
|
||||
switch v := r.(type) {
|
||||
case int64:
|
||||
if v != int64(c.expected) {
|
||||
t.Errorf("ceil(%v) = %v, want %v", c.arg, v, int64(c.expected))
|
||||
}
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("ceil(%v) = %v, want %v", c.arg, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type ceil(%v)", c.arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRound(t *testing.T) {
|
||||
cases := []struct {
|
||||
arg interface{}
|
||||
expected float64
|
||||
}{
|
||||
{int64(0), 0},
|
||||
{int64(1), 1},
|
||||
{int64(-1), -1},
|
||||
{10.4, 10},
|
||||
{-10.4, -10},
|
||||
{10.8, 11},
|
||||
{-10.8, -11},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnRound([]interface{}{c.arg})
|
||||
switch v := r.(type) {
|
||||
case int64:
|
||||
if v != int64(c.expected) {
|
||||
t.Errorf("round(%v) = %v, want %v", c.arg, v, int64(c.expected))
|
||||
}
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("round(%v) = %v, want %v", c.arg, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type round(%v)", c.arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLog(t *testing.T) {
|
||||
cases := []struct {
|
||||
arg interface{}
|
||||
expected float64
|
||||
}{
|
||||
{int64(1), math.Log(1)},
|
||||
{0.1, math.Log(0.1)},
|
||||
{10.4, math.Log(10.4)},
|
||||
{10.8, math.Log(10.8)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnLog([]interface{}{c.arg})
|
||||
switch v := r.(type) {
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("log(%v) = %v, want %v", c.arg, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type log(%v)", c.arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLog10(t *testing.T) {
|
||||
cases := []struct {
|
||||
arg interface{}
|
||||
expected float64
|
||||
}{
|
||||
{int64(1), math.Log10(1)},
|
||||
{0.1, math.Log10(0.1)},
|
||||
{10.4, math.Log10(10.4)},
|
||||
{10.8, math.Log10(10.8)},
|
||||
{int64(100), math.Log10(100)},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnLog10([]interface{}{c.arg})
|
||||
switch v := r.(type) {
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("log10(%v) = %v, want %v", c.arg, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type log10(%v)", c.arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAbs(t *testing.T) {
|
||||
cases := []struct {
|
||||
arg interface{}
|
||||
expected float64
|
||||
}{
|
||||
{int64(1), 1},
|
||||
{int64(0), 0},
|
||||
{int64(-1), 1},
|
||||
{10.4, 10.4},
|
||||
{-10.4, 10.4},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnAbs([]interface{}{c.arg})
|
||||
switch v := r.(type) {
|
||||
case int64:
|
||||
if v != int64(c.expected) {
|
||||
t.Errorf("abs(%v) = %v, want %v", c.arg, v, int64(c.expected))
|
||||
}
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("abs(%v) = %v, want %v", c.arg, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type abs(%v)", c.arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIf(t *testing.T) {
|
||||
cases := []struct {
|
||||
args []interface{}
|
||||
expected float64
|
||||
}{
|
||||
{[]interface{}{true, int64(10), int64(20)}, 10},
|
||||
{[]interface{}{false, int64(10), int64(20)}, 20},
|
||||
{[]interface{}{true, 10.3, 20.6}, 10.3},
|
||||
{[]interface{}{false, 10.3, 20.6}, 20.6},
|
||||
{[]interface{}{true, int64(10), 20.6}, 10},
|
||||
{[]interface{}{false, int64(10), 20.6}, 20.6},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
r := fnIf(c.args)
|
||||
switch v := r.(type) {
|
||||
case int64:
|
||||
if v != int64(c.expected) {
|
||||
t.Errorf("if(%v) = %v, want %v", c.args, v, int64(c.expected))
|
||||
}
|
||||
case float64:
|
||||
if v != c.expected {
|
||||
t.Errorf("if(%v) = %v, want %v", c.args, v, c.expected)
|
||||
}
|
||||
default:
|
||||
t.Errorf("unknown result type if(%v)", c.args)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type RouteMatchCriteria struct {
|
||||
Tag string `yaml:"tag"`
|
||||
Value string `yaml:"match"`
|
||||
Re *regexp.Regexp `yaml:"-"`
|
||||
}
|
||||
|
||||
func (c *RouteMatchCriteria) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||
var v map[string]string
|
||||
if e := unmarshal(&v); e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
for k, a := range v {
|
||||
c.Tag = k
|
||||
c.Value = a
|
||||
if strings.HasPrefix(a, "re:") {
|
||||
re, e := regexp.Compile(a[3:])
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
c.Re = re
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Route struct {
|
||||
Continue bool `yaml:"continue"`
|
||||
Receiver string `yaml:"receiver"`
|
||||
GroupWait Duration `yaml:"group_wait"`
|
||||
GroupInterval Duration `yaml:"group_interval"`
|
||||
RepeatInterval Duration `yaml:"repeat_interval"`
|
||||
GroupBy []string `yaml:"group_by"`
|
||||
Match []RouteMatchCriteria `yaml:"match"`
|
||||
Routes []*Route `yaml:"routes"`
|
||||
}
|
|
@ -1,658 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"text/scanner"
|
||||
"text/template"
|
||||
"time"
|
||||
|
||||
"github.com/taosdata/alert/app/expr"
|
||||
"github.com/taosdata/alert/models"
|
||||
"github.com/taosdata/alert/utils"
|
||||
"github.com/taosdata/alert/utils/log"
|
||||
)
|
||||
|
||||
type Duration struct{ time.Duration }
|
||||
|
||||
func (d Duration) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(d.String())
|
||||
}
|
||||
|
||||
func (d *Duration) doUnmarshal(v interface{}) error {
|
||||
switch value := v.(type) {
|
||||
case float64:
|
||||
*d = Duration{time.Duration(value)}
|
||||
return nil
|
||||
case string:
|
||||
if duration, e := time.ParseDuration(value); e != nil {
|
||||
return e
|
||||
} else {
|
||||
*d = Duration{duration}
|
||||
}
|
||||
return nil
|
||||
default:
|
||||
return errors.New("invalid duration")
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Duration) UnmarshalJSON(b []byte) error {
|
||||
var v interface{}
|
||||
if e := json.Unmarshal(b, &v); e != nil {
|
||||
return e
|
||||
}
|
||||
return d.doUnmarshal(v)
|
||||
}
|
||||
|
||||
const (
|
||||
AlertStateWaiting = iota
|
||||
AlertStatePending
|
||||
AlertStateFiring
|
||||
)
|
||||
|
||||
type Alert struct {
|
||||
State uint8 `json:"-"`
|
||||
LastRefreshAt time.Time `json:"-"`
|
||||
StartsAt time.Time `json:"startsAt,omitempty"`
|
||||
EndsAt time.Time `json:"endsAt,omitempty"`
|
||||
Values map[string]interface{} `json:"values"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
Annotations map[string]string `json:"annotations"`
|
||||
}
|
||||
|
||||
func (alert *Alert) doRefresh(firing bool, rule *Rule) bool {
|
||||
switch {
|
||||
case (!firing) && (alert.State == AlertStateWaiting):
|
||||
return false
|
||||
|
||||
case (!firing) && (alert.State == AlertStatePending):
|
||||
alert.State = AlertStateWaiting
|
||||
return false
|
||||
|
||||
case (!firing) && (alert.State == AlertStateFiring):
|
||||
alert.State = AlertStateWaiting
|
||||
alert.EndsAt = time.Now()
|
||||
|
||||
case firing && (alert.State == AlertStateWaiting):
|
||||
alert.StartsAt = time.Now()
|
||||
alert.EndsAt = time.Time{}
|
||||
if rule.For.Nanoseconds() > 0 {
|
||||
alert.State = AlertStatePending
|
||||
return false
|
||||
}
|
||||
alert.State = AlertStateFiring
|
||||
|
||||
case firing && (alert.State == AlertStatePending):
|
||||
if time.Now().Sub(alert.StartsAt) < rule.For.Duration {
|
||||
return false
|
||||
}
|
||||
alert.StartsAt = alert.StartsAt.Add(rule.For.Duration)
|
||||
alert.EndsAt = time.Time{}
|
||||
alert.State = AlertStateFiring
|
||||
|
||||
case firing && (alert.State == AlertStateFiring):
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (alert *Alert) refresh(rule *Rule, values map[string]interface{}) {
|
||||
alert.LastRefreshAt = time.Now()
|
||||
|
||||
defer func() {
|
||||
switch x := recover().(type) {
|
||||
case nil:
|
||||
case error:
|
||||
rule.setState(RuleStateError)
|
||||
log.Errorf("[%s]: failed to evaluate: %s", rule.Name, x.Error())
|
||||
default:
|
||||
rule.setState(RuleStateError)
|
||||
log.Errorf("[%s]: failed to evaluate: unknown error", rule.Name)
|
||||
}
|
||||
}()
|
||||
|
||||
alert.Values = values
|
||||
res := rule.Expr.Eval(func(key string) interface{} {
|
||||
// ToLower is required as column name in result is in lower case
|
||||
i := alert.Values[strings.ToLower(key)]
|
||||
switch v := i.(type) {
|
||||
case int8:
|
||||
return int64(v)
|
||||
case int16:
|
||||
return int64(v)
|
||||
case int:
|
||||
return int64(v)
|
||||
case int32:
|
||||
return int64(v)
|
||||
case float32:
|
||||
return float64(v)
|
||||
default:
|
||||
return v
|
||||
}
|
||||
})
|
||||
|
||||
val, ok := res.(bool)
|
||||
if !ok {
|
||||
rule.setState(RuleStateError)
|
||||
log.Errorf("[%s]: result type is not bool", rule.Name)
|
||||
return
|
||||
}
|
||||
|
||||
if !alert.doRefresh(val, rule) {
|
||||
return
|
||||
}
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
alert.Annotations = map[string]string{}
|
||||
for k, v := range rule.Annotations {
|
||||
if e := v.Execute(&buf, alert); e != nil {
|
||||
log.Errorf("[%s]: failed to generate annotation '%s': %s", rule.Name, k, e.Error())
|
||||
} else {
|
||||
alert.Annotations[k] = buf.String()
|
||||
}
|
||||
buf.Reset()
|
||||
}
|
||||
|
||||
buf.Reset()
|
||||
if e := json.NewEncoder(&buf).Encode(alert); e != nil {
|
||||
log.Errorf("[%s]: failed to serialize alert to JSON: %s", rule.Name, e.Error())
|
||||
} else {
|
||||
chAlert <- buf.String()
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
RuleStateNormal = iota
|
||||
RuleStateError
|
||||
RuleStateDisabled
|
||||
RuleStateRunning = 0x04
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
Name string `json:"name"`
|
||||
State uint32 `json:"state"`
|
||||
SQL string `json:"sql"`
|
||||
GroupByCols []string `json:"-"`
|
||||
For Duration `json:"for"`
|
||||
Period Duration `json:"period"`
|
||||
NextRunTime time.Time `json:"-"`
|
||||
RawExpr string `json:"expr"`
|
||||
Expr expr.Expr `json:"-"`
|
||||
Labels map[string]string `json:"labels"`
|
||||
RawAnnotations map[string]string `json:"annotations"`
|
||||
Annotations map[string]*template.Template `json:"-"`
|
||||
Alerts sync.Map `json:"-"`
|
||||
}
|
||||
|
||||
func (rule *Rule) clone() *Rule {
|
||||
return &Rule{
|
||||
Name: rule.Name,
|
||||
State: RuleStateNormal,
|
||||
SQL: rule.SQL,
|
||||
GroupByCols: rule.GroupByCols,
|
||||
For: rule.For,
|
||||
Period: rule.Period,
|
||||
NextRunTime: time.Time{},
|
||||
RawExpr: rule.RawExpr,
|
||||
Expr: rule.Expr,
|
||||
Labels: rule.Labels,
|
||||
RawAnnotations: rule.RawAnnotations,
|
||||
Annotations: rule.Annotations,
|
||||
// don't copy alerts
|
||||
}
|
||||
}
|
||||
|
||||
func (rule *Rule) setState(s uint32) {
|
||||
for {
|
||||
old := atomic.LoadUint32(&rule.State)
|
||||
new := old&0xffffffc0 | s
|
||||
if atomic.CompareAndSwapUint32(&rule.State, old, new) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (rule *Rule) state() uint32 {
|
||||
return atomic.LoadUint32(&rule.State) & 0xffffffc0
|
||||
}
|
||||
|
||||
func (rule *Rule) isEnabled() bool {
|
||||
state := atomic.LoadUint32(&rule.State)
|
||||
return state&RuleStateDisabled == 0
|
||||
}
|
||||
|
||||
func (rule *Rule) setNextRunTime(tm time.Time) {
|
||||
rule.NextRunTime = tm.Round(rule.Period.Duration)
|
||||
if rule.NextRunTime.Before(tm) {
|
||||
rule.NextRunTime = rule.NextRunTime.Add(rule.Period.Duration)
|
||||
}
|
||||
}
|
||||
|
||||
func parseGroupBy(sql string) (cols []string, err error) {
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = e.(error)
|
||||
}
|
||||
}()
|
||||
|
||||
s := scanner.Scanner{
|
||||
Error: func(s *scanner.Scanner, msg string) {
|
||||
panic(errors.New(msg))
|
||||
},
|
||||
Mode: scanner.ScanIdents | scanner.ScanInts | scanner.ScanFloats,
|
||||
}
|
||||
|
||||
s.Init(strings.NewReader(sql))
|
||||
if s.Scan() != scanner.Ident || strings.ToLower(s.TokenText()) != "select" {
|
||||
err = errors.New("only select statement is allowed.")
|
||||
return
|
||||
}
|
||||
|
||||
hasGroupBy := false
|
||||
for t := s.Scan(); t != scanner.EOF; t = s.Scan() {
|
||||
if t != scanner.Ident {
|
||||
continue
|
||||
}
|
||||
if strings.ToLower(s.TokenText()) != "group" {
|
||||
continue
|
||||
}
|
||||
if s.Scan() != scanner.Ident {
|
||||
continue
|
||||
}
|
||||
if strings.ToLower(s.TokenText()) == "by" {
|
||||
hasGroupBy = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !hasGroupBy {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
if s.Scan() != scanner.Ident {
|
||||
err = errors.New("SQL statement syntax error.")
|
||||
return
|
||||
}
|
||||
col := strings.ToLower(s.TokenText())
|
||||
cols = append(cols, col)
|
||||
if s.Scan() != ',' {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (rule *Rule) parseGroupBy() (err error) {
|
||||
cols, e := parseGroupBy(rule.SQL)
|
||||
if e == nil {
|
||||
rule.GroupByCols = cols
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rule *Rule) getAlert(values map[string]interface{}) *Alert {
|
||||
sb := strings.Builder{}
|
||||
for _, name := range rule.GroupByCols {
|
||||
value := values[name]
|
||||
if value == nil {
|
||||
} else {
|
||||
sb.WriteString(fmt.Sprint(value))
|
||||
}
|
||||
sb.WriteByte('_')
|
||||
}
|
||||
|
||||
var alert *Alert
|
||||
key := sb.String()
|
||||
|
||||
if v, ok := rule.Alerts.Load(key); ok {
|
||||
alert = v.(*Alert)
|
||||
}
|
||||
if alert == nil {
|
||||
alert = &Alert{Labels: map[string]string{}}
|
||||
for k, v := range rule.Labels {
|
||||
alert.Labels[k] = v
|
||||
}
|
||||
for _, name := range rule.GroupByCols {
|
||||
value := values[name]
|
||||
if value == nil {
|
||||
alert.Labels[name] = ""
|
||||
} else {
|
||||
alert.Labels[name] = fmt.Sprint(value)
|
||||
}
|
||||
}
|
||||
rule.Alerts.Store(key, alert)
|
||||
}
|
||||
|
||||
return alert
|
||||
}
|
||||
|
||||
func (rule *Rule) preRun(tm time.Time) bool {
|
||||
if tm.Before(rule.NextRunTime) {
|
||||
return false
|
||||
}
|
||||
rule.setNextRunTime(tm)
|
||||
|
||||
for {
|
||||
state := atomic.LoadUint32(&rule.State)
|
||||
if state != RuleStateNormal {
|
||||
return false
|
||||
}
|
||||
if atomic.CompareAndSwapUint32(&rule.State, state, RuleStateRunning) {
|
||||
break
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (rule *Rule) run(db *sql.DB) {
|
||||
rows, e := db.Query(rule.SQL)
|
||||
if e != nil {
|
||||
log.Errorf("[%s]: failed to query TDengine: %s", rule.Name, e.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cols, e := rows.ColumnTypes()
|
||||
if e != nil {
|
||||
log.Errorf("[%s]: unable to get column information: %s", rule.Name, e.Error())
|
||||
return
|
||||
}
|
||||
|
||||
for rows.Next() {
|
||||
values := make([]interface{}, 0, len(cols))
|
||||
for range cols {
|
||||
var v interface{}
|
||||
values = append(values, &v)
|
||||
}
|
||||
rows.Scan(values...)
|
||||
|
||||
m := make(map[string]interface{})
|
||||
for i, col := range cols {
|
||||
name := strings.ToLower(col.Name())
|
||||
m[name] = *(values[i].(*interface{}))
|
||||
}
|
||||
|
||||
alert := rule.getAlert(m)
|
||||
alert.refresh(rule, m)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
rule.Alerts.Range(func(k, v interface{}) bool {
|
||||
alert := v.(*Alert)
|
||||
if now.Sub(alert.LastRefreshAt) > rule.Period.Duration*10 {
|
||||
rule.Alerts.Delete(k)
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
func (rule *Rule) postRun() {
|
||||
for {
|
||||
old := atomic.LoadUint32(&rule.State)
|
||||
new := old & ^uint32(RuleStateRunning)
|
||||
if atomic.CompareAndSwapUint32(&rule.State, old, new) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func newRule(str string) (*Rule, error) {
|
||||
rule := Rule{}
|
||||
|
||||
e := json.NewDecoder(strings.NewReader(str)).Decode(&rule)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
if rule.Period.Nanoseconds() <= 0 {
|
||||
rule.Period = Duration{time.Minute}
|
||||
}
|
||||
rule.setNextRunTime(time.Now())
|
||||
|
||||
if rule.For.Nanoseconds() < 0 {
|
||||
rule.For = Duration{0}
|
||||
}
|
||||
|
||||
if e = rule.parseGroupBy(); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
|
||||
if expr, e := expr.Compile(rule.RawExpr); e != nil {
|
||||
return nil, e
|
||||
} else {
|
||||
rule.Expr = expr
|
||||
}
|
||||
|
||||
rule.Annotations = map[string]*template.Template{}
|
||||
for k, v := range rule.RawAnnotations {
|
||||
v = reValue.ReplaceAllStringFunc(v, func(s string) string {
|
||||
// as column name in query result is always in lower case,
|
||||
// we need to convert value reference in annotations to
|
||||
// lower case
|
||||
return strings.ToLower(s)
|
||||
})
|
||||
text := "{{$labels := .Labels}}{{$values := .Values}}" + v
|
||||
tmpl, e := template.New(k).Parse(text)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
rule.Annotations[k] = tmpl
|
||||
}
|
||||
|
||||
return &rule, nil
|
||||
}
|
||||
|
||||
const (
|
||||
batchSize = 1024
|
||||
)
|
||||
|
||||
var (
|
||||
rules sync.Map
|
||||
wg sync.WaitGroup
|
||||
chStop = make(chan struct{})
|
||||
chAlert = make(chan string, batchSize)
|
||||
reValue = regexp.MustCompile(`\$values\.[_a-zA-Z0-9]+`)
|
||||
)
|
||||
|
||||
func runRules() {
|
||||
defer wg.Done()
|
||||
|
||||
db, e := sql.Open("taosSql", utils.Cfg.TDengine)
|
||||
if e != nil {
|
||||
log.Fatal("failed to connect to TDengine: ", e.Error())
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
ticker := time.NewTicker(time.Second)
|
||||
defer ticker.Stop()
|
||||
|
||||
LOOP:
|
||||
for {
|
||||
var tm time.Time
|
||||
select {
|
||||
case <-chStop:
|
||||
close(chAlert)
|
||||
break LOOP
|
||||
case tm = <-ticker.C:
|
||||
}
|
||||
|
||||
rules.Range(func(k, v interface{}) bool {
|
||||
rule := v.(*Rule)
|
||||
if !rule.preRun(tm) {
|
||||
return true
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(rule *Rule) {
|
||||
defer wg.Done()
|
||||
defer rule.postRun()
|
||||
rule.run(db)
|
||||
}(rule)
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func doPushAlerts(alerts []string) {
|
||||
defer wg.Done()
|
||||
|
||||
if len(utils.Cfg.Receivers.AlertManager) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
buf := bytes.Buffer{}
|
||||
buf.WriteByte('[')
|
||||
for i, alert := range alerts {
|
||||
if i > 0 {
|
||||
buf.WriteByte(',')
|
||||
}
|
||||
buf.WriteString(alert)
|
||||
}
|
||||
buf.WriteByte(']')
|
||||
|
||||
log.Debug(buf.String())
|
||||
|
||||
resp, e := http.DefaultClient.Post(utils.Cfg.Receivers.AlertManager, "application/json", &buf)
|
||||
if e != nil {
|
||||
log.Errorf("failed to push alerts to downstream: %s", e.Error())
|
||||
return
|
||||
}
|
||||
resp.Body.Close()
|
||||
}
|
||||
|
||||
func pushAlerts() {
|
||||
defer wg.Done()
|
||||
|
||||
ticker := time.NewTicker(time.Millisecond * 100)
|
||||
defer ticker.Stop()
|
||||
|
||||
alerts := make([]string, 0, batchSize)
|
||||
|
||||
LOOP:
|
||||
for {
|
||||
select {
|
||||
case alert := <-chAlert:
|
||||
if utils.Cfg.Receivers.Console {
|
||||
fmt.Print(alert)
|
||||
}
|
||||
if len(alert) == 0 {
|
||||
if len(alerts) > 0 {
|
||||
wg.Add(1)
|
||||
doPushAlerts(alerts)
|
||||
}
|
||||
break LOOP
|
||||
}
|
||||
if len(alerts) == batchSize {
|
||||
wg.Add(1)
|
||||
go doPushAlerts(alerts)
|
||||
alerts = make([]string, 0, batchSize)
|
||||
}
|
||||
alerts = append(alerts, alert)
|
||||
|
||||
case <-ticker.C:
|
||||
if len(alerts) > 0 {
|
||||
wg.Add(1)
|
||||
go doPushAlerts(alerts)
|
||||
alerts = make([]string, 0, batchSize)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func loadRuleFromDatabase() error {
|
||||
allRules, e := models.LoadAllRule()
|
||||
if e != nil {
|
||||
log.Error("failed to load rules from database:", e.Error())
|
||||
return e
|
||||
}
|
||||
|
||||
count := 0
|
||||
for _, r := range allRules {
|
||||
rule, e := newRule(r.Content)
|
||||
if e != nil {
|
||||
log.Errorf("[%s]: parse failed: %s", r.Name, e.Error())
|
||||
continue
|
||||
}
|
||||
if !r.Enabled {
|
||||
rule.setState(RuleStateDisabled)
|
||||
}
|
||||
rules.Store(rule.Name, rule)
|
||||
count++
|
||||
}
|
||||
log.Infof("total %d rules loaded", count)
|
||||
return nil
|
||||
}
|
||||
|
||||
func loadRuleFromFile() error {
|
||||
f, e := os.Open(utils.Cfg.RuleFile)
|
||||
if e != nil {
|
||||
log.Error("failed to load rules from file:", e.Error())
|
||||
return e
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var allRules []Rule
|
||||
e = json.NewDecoder(f).Decode(&allRules)
|
||||
if e != nil {
|
||||
log.Error("failed to parse rule file:", e.Error())
|
||||
return e
|
||||
}
|
||||
|
||||
for i := 0; i < len(allRules); i++ {
|
||||
rule := &allRules[i]
|
||||
rules.Store(rule.Name, rule)
|
||||
}
|
||||
log.Infof("total %d rules loaded", len(allRules))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func initRule() error {
|
||||
if len(utils.Cfg.Database) > 0 {
|
||||
if e := loadRuleFromDatabase(); e != nil {
|
||||
return e
|
||||
}
|
||||
} else {
|
||||
if e := loadRuleFromFile(); e != nil {
|
||||
return e
|
||||
}
|
||||
}
|
||||
|
||||
wg.Add(2)
|
||||
go runRules()
|
||||
go pushAlerts()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func uninitRule() error {
|
||||
close(chStop)
|
||||
wg.Wait()
|
||||
return nil
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/taosdata/alert/utils/log"
|
||||
)
|
||||
|
||||
func TestParseGroupBy(t *testing.T) {
|
||||
cases := []struct {
|
||||
sql string
|
||||
cols []string
|
||||
}{
|
||||
{
|
||||
sql: "select * from a",
|
||||
cols: []string{},
|
||||
},
|
||||
{
|
||||
sql: "select * from a group by abc",
|
||||
cols: []string{"abc"},
|
||||
},
|
||||
{
|
||||
sql: "select * from a group by abc, def",
|
||||
cols: []string{"abc", "def"},
|
||||
},
|
||||
{
|
||||
sql: "select * from a Group by abc, def order by abc",
|
||||
cols: []string{"abc", "def"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
cols, e := parseGroupBy(c.sql)
|
||||
if e != nil {
|
||||
t.Errorf("failed to parse sql '%s': %s", c.sql, e.Error())
|
||||
}
|
||||
for i := range cols {
|
||||
if i >= len(c.cols) {
|
||||
t.Errorf("count of group by columns of '%s' is wrong", c.sql)
|
||||
}
|
||||
if c.cols[i] != cols[i] {
|
||||
t.Errorf("wrong group by columns for '%s'", c.sql)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestManagement(t *testing.T) {
|
||||
const format = `{"name":"rule%d", "sql":"select count(*) as count from meters", "expr":"count>2"}`
|
||||
|
||||
log.Init()
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
s := fmt.Sprintf(format, i)
|
||||
rule, e := newRule(s)
|
||||
if e != nil {
|
||||
t.Errorf("failed to create rule: %s", e.Error())
|
||||
}
|
||||
e = doUpdateRule(rule, s)
|
||||
if e != nil {
|
||||
t.Errorf("failed to add or update rule: %s", e.Error())
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < 5; i++ {
|
||||
name := fmt.Sprintf("rule%d", i)
|
||||
if _, ok := rules.Load(name); !ok {
|
||||
t.Errorf("rule '%s' does not exist", name)
|
||||
}
|
||||
}
|
||||
|
||||
name := "rule1"
|
||||
if e := doDeleteRule(name); e != nil {
|
||||
t.Errorf("failed to delete rule: %s", e.Error())
|
||||
}
|
||||
|
||||
if _, ok := rules.Load(name); ok {
|
||||
t.Errorf("rule '%s' should not exist any more", name)
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"port": 8100,
|
||||
"database": "file:alert.db",
|
||||
"tdengine": "root:taosdata@/tcp(127.0.0.1:0)/",
|
||||
"log": {
|
||||
"level": "debug",
|
||||
"path": ""
|
||||
},
|
||||
"receivers": {
|
||||
"alertManager": "http://127.0.0.1:9093/api/v1/alerts",
|
||||
"console": true
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# This file is used to install TDengine client library on linux systems.
|
||||
|
||||
set -e
|
||||
#set -x
|
||||
|
||||
# -----------------------Variables definition---------------------
|
||||
script_dir=$(dirname $(readlink -f "$0"))
|
||||
# Dynamic directory
|
||||
lib_link_dir="/usr/lib"
|
||||
lib64_link_dir="/usr/lib64"
|
||||
|
||||
# Color setting
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[1;32m'
|
||||
GREEN_DARK='\033[0;32m'
|
||||
GREEN_UNDERLINE='\033[4;32m'
|
||||
NC='\033[0m'
|
||||
|
||||
csudo=""
|
||||
if command -v sudo > /dev/null; then
|
||||
csudo="sudo"
|
||||
fi
|
||||
|
||||
function install_driver() {
|
||||
echo
|
||||
if [[ -d ${lib_link_dir} && ! -e ${lib_link_dir}/libtaos.so ]]; then
|
||||
echo -e "${GREEN}Start to install TDengine client driver ...${NC}"
|
||||
${csudo} ln -s ${script_dir}/driver/libtaos.* ${lib_link_dir}/libtaos.so.1 || :
|
||||
${csudo} ln -s ${lib_link_dir}/libtaos.so.1 ${lib_link_dir}/libtaos.so || :
|
||||
|
||||
if [[ -d ${lib64_link_dir} && ! -e ${lib64_link_dir}/libtaos.so ]]; then
|
||||
${csudo} ln -s ${script_dir}/driver/libtaos.* ${lib64_link_dir}/libtaos.so.1 || :
|
||||
${csudo} ln -s ${lib64_link_dir}/libtaos.so.1 ${lib64_link_dir}/libtaos.so || :
|
||||
fi
|
||||
|
||||
echo
|
||||
echo -e "${GREEN}TDengine client driver is successfully installed!${NC}"
|
||||
else
|
||||
echo -e "${GREEN}TDengine client driver already exists, Please confirm whether the alert version matches the client driver version!${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
install_driver
|
|
@ -1,198 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/taosdata/alert/app"
|
||||
"github.com/taosdata/alert/models"
|
||||
"github.com/taosdata/alert/utils"
|
||||
"github.com/taosdata/alert/utils/log"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
_ "github.com/taosdata/driver-go/taosSql"
|
||||
)
|
||||
|
||||
type httpHandler struct {
|
||||
}
|
||||
|
||||
func (h *httpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
path := r.URL.Path
|
||||
http.DefaultServeMux.ServeHTTP(w, r)
|
||||
duration := time.Now().Sub(start)
|
||||
log.Debugf("[%s]\t%s\t%s", r.Method, path, duration)
|
||||
}
|
||||
|
||||
func serveWeb() *http.Server {
|
||||
log.Info("Listening at port: ", utils.Cfg.Port)
|
||||
|
||||
srv := &http.Server{
|
||||
Addr: ":" + strconv.Itoa(int(utils.Cfg.Port)),
|
||||
Handler: &httpHandler{},
|
||||
}
|
||||
go func() {
|
||||
if e := srv.ListenAndServe(); e != nil {
|
||||
log.Error(e.Error())
|
||||
}
|
||||
}()
|
||||
|
||||
return srv
|
||||
}
|
||||
|
||||
func copyFile(dst, src string) error {
|
||||
if dst == src {
|
||||
return nil
|
||||
}
|
||||
|
||||
in, e := os.Open(src)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer in.Close()
|
||||
|
||||
out, e := os.Create(dst)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer out.Close()
|
||||
|
||||
_, e = io.Copy(out, in)
|
||||
return e
|
||||
}
|
||||
|
||||
func doSetup(cfgPath string) error {
|
||||
exePath, e := os.Executable()
|
||||
if e != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed to get executable path: %s\n", e.Error())
|
||||
return e
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(cfgPath) {
|
||||
dir := filepath.Dir(exePath)
|
||||
cfgPath = filepath.Join(dir, cfgPath)
|
||||
}
|
||||
|
||||
e = copyFile("/etc/taos/alert.cfg", cfgPath)
|
||||
if e != nil {
|
||||
fmt.Fprintf(os.Stderr, "failed copy configuration file: %s\n", e.Error())
|
||||
return e
|
||||
}
|
||||
|
||||
f, e := os.Create("/etc/systemd/system/alert.service")
|
||||
if e != nil {
|
||||
fmt.Printf("failed to create alert service: %s\n", e.Error())
|
||||
return e
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
const content = `[Unit]
|
||||
Description=Alert (TDengine Alert Service)
|
||||
After=syslog.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
RestartSec=2s
|
||||
Type=simple
|
||||
WorkingDirectory=/var/lib/taos/
|
||||
ExecStart=%s -cfg /etc/taos/alert.cfg
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
`
|
||||
_, e = fmt.Fprintf(f, content, exePath)
|
||||
if e != nil {
|
||||
fmt.Printf("failed to create alert.service: %s\n", e.Error())
|
||||
return e
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var version = "2.0.0.1s"
|
||||
|
||||
func main() {
|
||||
var (
|
||||
cfgPath string
|
||||
setup bool
|
||||
showVersion bool
|
||||
)
|
||||
flag.StringVar(&cfgPath, "cfg", "alert.cfg", "path of configuration file")
|
||||
flag.BoolVar(&setup, "setup", false, "setup the service as a daemon")
|
||||
flag.BoolVar(&showVersion, "version", false, "show version information")
|
||||
flag.Parse()
|
||||
|
||||
if showVersion {
|
||||
fmt.Println("TDengine alert v" + version)
|
||||
return
|
||||
}
|
||||
|
||||
if setup {
|
||||
if runtime.GOOS == "linux" {
|
||||
doSetup(cfgPath)
|
||||
} else {
|
||||
fmt.Fprintln(os.Stderr, "can only run as a daemon mode in linux.")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if e := utils.LoadConfig(cfgPath); e != nil {
|
||||
fmt.Fprintln(os.Stderr, "failed to load configuration")
|
||||
return
|
||||
}
|
||||
|
||||
if e := log.Init(); e != nil {
|
||||
fmt.Fprintln(os.Stderr, "failed to initialize logger:", e.Error())
|
||||
return
|
||||
}
|
||||
defer log.Sync()
|
||||
|
||||
if e := models.Init(); e != nil {
|
||||
log.Fatal("failed to initialize database:", e.Error())
|
||||
}
|
||||
|
||||
if e := app.Init(); e != nil {
|
||||
log.Fatal("failed to initialize application:", e.Error())
|
||||
}
|
||||
// start web server
|
||||
srv := serveWeb()
|
||||
|
||||
// wait `Ctrl-C` or `Kill` to exit, `Kill` does not work on Windows
|
||||
interrupt := make(chan os.Signal)
|
||||
signal.Notify(interrupt, os.Interrupt)
|
||||
signal.Notify(interrupt, os.Kill)
|
||||
<-interrupt
|
||||
fmt.Println("'Ctrl + C' received, exiting...")
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||
srv.Shutdown(ctx)
|
||||
cancel()
|
||||
|
||||
app.Uninit()
|
||||
models.Uninit()
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"name": "CarTooFast",
|
||||
"period": "10s",
|
||||
"sql": "select avg(speed) as avgspeed from test.cars where ts > now - 5m group by id",
|
||||
"expr": "avgSpeed > 100",
|
||||
"for": "0s",
|
||||
"labels": {
|
||||
"ruleName": "CarTooFast"
|
||||
},
|
||||
"annotations": {
|
||||
"summary": "car {{$values.id}} is too fast, its average speed is {{$values.avgSpeed}}km/h"
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
module github.com/taosdata/alert
|
||||
|
||||
go 1.14
|
||||
|
||||
require (
|
||||
github.com/jmoiron/sqlx v1.2.0
|
||||
github.com/mattn/go-sqlite3 v2.0.3+incompatible
|
||||
github.com/taosdata/driver-go v0.0.0-20201113094317-050667e5b4d0
|
||||
go.uber.org/zap v1.14.1
|
||||
google.golang.org/appengine v1.6.5 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c
|
||||
)
|
|
@ -1,146 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/taosdata/alert/utils"
|
||||
"github.com/taosdata/alert/utils/log"
|
||||
)
|
||||
|
||||
var db *sqlx.DB
|
||||
|
||||
func Init() error {
|
||||
xdb, e := sqlx.Connect("sqlite3", utils.Cfg.Database)
|
||||
if e == nil {
|
||||
db = xdb
|
||||
}
|
||||
return upgrade()
|
||||
}
|
||||
|
||||
func Uninit() error {
|
||||
db.Close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func getStringOption(tx *sqlx.Tx, name string) (string, error) {
|
||||
const qs = "SELECT * FROM `option` WHERE `name`=?"
|
||||
|
||||
var (
|
||||
e error
|
||||
o struct {
|
||||
Name string `db:"name"`
|
||||
Value string `db:"value"`
|
||||
}
|
||||
)
|
||||
|
||||
if tx != nil {
|
||||
e = tx.Get(&o, qs, name)
|
||||
} else {
|
||||
e = db.Get(&o, qs, name)
|
||||
}
|
||||
|
||||
if e != nil {
|
||||
return "", e
|
||||
}
|
||||
|
||||
return o.Value, nil
|
||||
}
|
||||
|
||||
func getIntOption(tx *sqlx.Tx, name string) (int, error) {
|
||||
s, e := getStringOption(tx, name)
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
v, e := strconv.ParseInt(s, 10, 64)
|
||||
return int(v), e
|
||||
}
|
||||
|
||||
func setOption(tx *sqlx.Tx, name string, value interface{}) error {
|
||||
const qs = "REPLACE INTO `option`(`name`, `value`) VALUES(?, ?);"
|
||||
|
||||
var (
|
||||
e error
|
||||
sv string
|
||||
)
|
||||
|
||||
switch v := value.(type) {
|
||||
case time.Time:
|
||||
sv = v.Format(time.RFC3339)
|
||||
default:
|
||||
sv = fmt.Sprint(value)
|
||||
}
|
||||
|
||||
if tx != nil {
|
||||
_, e = tx.Exec(qs, name, sv)
|
||||
} else {
|
||||
_, e = db.Exec(qs, name, sv)
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
||||
|
||||
var upgradeScripts = []struct {
|
||||
ver int
|
||||
stmts []string
|
||||
}{
|
||||
{
|
||||
ver: 0,
|
||||
stmts: []string{
|
||||
"CREATE TABLE `option`( `name` VARCHAR(63) PRIMARY KEY, `value` VARCHAR(255) NOT NULL) WITHOUT ROWID;",
|
||||
"CREATE TABLE `rule`( `name` VARCHAR(63) PRIMARY KEY, `enabled` TINYINT(1) NOT NULL, `created_at` DATETIME NOT NULL, `updated_at` DATETIME NOT NULL, `content` TEXT(65535) NOT NULL);",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func upgrade() error {
|
||||
const dbVersion = "database version"
|
||||
|
||||
ver, e := getIntOption(nil, dbVersion)
|
||||
if e != nil { // regards all errors as schema not created
|
||||
ver = -1 // set ver to -1 to execute all statements
|
||||
}
|
||||
|
||||
tx, e := db.Beginx()
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
for _, us := range upgradeScripts {
|
||||
if us.ver <= ver {
|
||||
continue
|
||||
}
|
||||
log.Info("upgrading database to version: ", us.ver)
|
||||
for _, s := range us.stmts {
|
||||
if _, e = tx.Exec(s); e != nil {
|
||||
tx.Rollback()
|
||||
return e
|
||||
}
|
||||
}
|
||||
ver = us.ver
|
||||
}
|
||||
|
||||
if e = setOption(tx, dbVersion, ver); e != nil {
|
||||
tx.Rollback()
|
||||
return e
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
const (
|
||||
sqlSelectAllRule = "SELECT * FROM `rule`;"
|
||||
sqlSelectRule = "SELECT * FROM `rule` WHERE `name` = ?;"
|
||||
sqlInsertRule = "INSERT INTO `rule`(`name`, `enabled`, `created_at`, `updated_at`, `content`) VALUES(:name, :enabled, :created_at, :updated_at, :content);"
|
||||
sqlUpdateRule = "UPDATE `rule` SET `content` = :content, `updated_at` = :updated_at WHERE `name` = :name;"
|
||||
sqlEnableRule = "UPDATE `rule` SET `enabled` = :enabled, `updated_at` = :updated_at WHERE `name` = :name;"
|
||||
sqlDeleteRule = "DELETE FROM `rule` WHERE `name` = ?;"
|
||||
)
|
||||
|
||||
type Rule struct {
|
||||
Name string `db:"name"`
|
||||
Enabled bool `db:"enabled"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
Content string `db:"content"`
|
||||
}
|
||||
|
||||
func AddRule(r *Rule) error {
|
||||
r.CreatedAt = time.Now()
|
||||
r.Enabled = true
|
||||
r.UpdatedAt = r.CreatedAt
|
||||
_, e := db.NamedExec(sqlInsertRule, r)
|
||||
return e
|
||||
}
|
||||
|
||||
func UpdateRule(name string, content string) error {
|
||||
r := Rule{
|
||||
Name: name,
|
||||
UpdatedAt: time.Now(),
|
||||
Content: content,
|
||||
}
|
||||
_, e := db.NamedExec(sqlUpdateRule, &r)
|
||||
return e
|
||||
}
|
||||
|
||||
func EnableRule(name string, enabled bool) error {
|
||||
r := Rule{
|
||||
Name: name,
|
||||
Enabled: enabled,
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
|
||||
if res, e := db.NamedExec(sqlEnableRule, &r); e != nil {
|
||||
return e
|
||||
} else if n, e := res.RowsAffected(); n != 1 {
|
||||
return e
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteRule(name string) error {
|
||||
_, e := db.Exec(sqlDeleteRule, name)
|
||||
return e
|
||||
}
|
||||
|
||||
func GetRuleByName(name string) (*Rule, error) {
|
||||
r := Rule{}
|
||||
if e := db.Get(&r, sqlSelectRule, name); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func LoadAllRule() ([]Rule, error) {
|
||||
var rules []Rule
|
||||
if e := db.Select(&rules, sqlSelectAllRule); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return rules, nil
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
set -e
|
||||
|
||||
# releash.sh -c [armv6l | arm64 | amd64 | 386]
|
||||
# -o [linux | darwin | windows]
|
||||
|
||||
# set parameters by default value
|
||||
cpuType=amd64 # [armv6l | arm64 | amd64 | 386]
|
||||
osType=linux # [linux | darwin | windows]
|
||||
version=""
|
||||
verType=stable # [stable, beta]
|
||||
declare -A archMap=(["armv6l"]="arm" ["arm64"]="arm64" ["amd64"]="x64" ["386"]="x86")
|
||||
while getopts "h:c:o:n:V:" arg
|
||||
do
|
||||
case $arg in
|
||||
c)
|
||||
#echo "cpuType=$OPTARG"
|
||||
cpuType=$(echo $OPTARG)
|
||||
;;
|
||||
o)
|
||||
#echo "osType=$OPTARG"
|
||||
osType=$(echo $OPTARG)
|
||||
;;
|
||||
n)
|
||||
#echo "version=$OPTARG"
|
||||
version=$(echo $OPTARG)
|
||||
;;
|
||||
V)
|
||||
#echo "verType=$OPTARG"
|
||||
verType=$(echo $OPTARG)
|
||||
;;
|
||||
h)
|
||||
echo "Usage: `basename $0` -c [armv6l | arm64 | amd64 | 386] -o [linux | darwin | windows]"
|
||||
exit 0
|
||||
;;
|
||||
?) #unknown option
|
||||
echo "unknown argument"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ "$version" == "" ]; then
|
||||
echo "Please input the correct version!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
startdir=$(pwd)
|
||||
scriptdir=$(dirname $(readlink -f $0))
|
||||
cd ${scriptdir}/cmd/alert
|
||||
|
||||
echo "cpuType=${cpuType}"
|
||||
echo "osType=${osType}"
|
||||
echo "version=${version}"
|
||||
|
||||
GOOS=${osType} GOARCH=${cpuType} go build -ldflags '-X main.version='${version}
|
||||
|
||||
mkdir -p TDengine-alert/driver
|
||||
|
||||
cp alert alert.cfg install_driver.sh ./TDengine-alert/.
|
||||
cp ../../../debug/build/lib/libtaos.so.${version} ./TDengine-alert/driver/.
|
||||
chmod 777 ./TDengine-alert/install_driver.sh
|
||||
|
||||
tar -I 'gzip -9' -cf ${scriptdir}/TDengine-alert-${version}-${osType^}-${archMap[${cpuType}]}.tar.gz TDengine-alert/
|
||||
rm -rf ./TDengine-alert
|
||||
|
||||
|
||||
|
||||
# mv package to comminuty/release/
|
||||
pkg_name=TDengine-alert-${version}-${osType^}-${archMap[${cpuType}]}
|
||||
|
||||
if [ "$verType" == "beta" ]; then
|
||||
pkg_name=TDengine-alert-${version}-${verType}-${osType^}-${archMap[${cpuType}]}
|
||||
elif [ "$verType" == "stable" ]; then
|
||||
pkg_name=${pkg_name}
|
||||
else
|
||||
echo "unknow verType, nor stabel or beta"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ${scriptdir}/../release/
|
||||
mv ${scriptdir}/TDengine-alert-${version}-${osType^}-${archMap[${cpuType}]}.tar.gz ${pkg_name}.tar.gz
|
|
@ -1,17 +0,0 @@
|
|||
sql connect
|
||||
sleep 100
|
||||
|
||||
sql drop database if exists test
|
||||
sql create database test
|
||||
sql use test
|
||||
|
||||
print ====== create super table
|
||||
sql create table cars (ts timestamp, speed int) tags(id int)
|
||||
|
||||
print ====== create tables
|
||||
$i = 0
|
||||
while $i < 5
|
||||
$tb = car . $i
|
||||
sql create table $tb using cars tags( $i )
|
||||
$i = $i + 1
|
||||
endw
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"name": "test1",
|
||||
"period": "10s",
|
||||
"sql": "select avg(speed) as avgspeed from test.cars group by id",
|
||||
"expr": "avgSpeed >= 3",
|
||||
"for": "0s",
|
||||
"labels": {
|
||||
"ruleName": "test1"
|
||||
},
|
||||
"annotations": {
|
||||
"summary": "speed of car(id = {{$labels.id}}) is too high: {{$values.avgSpeed}}"
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
sql connect
|
||||
sleep 100
|
||||
|
||||
print ====== insert 10 records to table 0
|
||||
$i = 10
|
||||
while $i > 0
|
||||
$ms = $i . s
|
||||
sql insert into test.car0 values(now - $ms , 1)
|
||||
$i = $i - 1
|
||||
endw
|
|
@ -1,5 +0,0 @@
|
|||
sql connect
|
||||
sleep 100
|
||||
|
||||
print ====== insert another records table 0
|
||||
sql insert into test.car0 values(now , 100)
|
|
@ -1,12 +0,0 @@
|
|||
sql connect
|
||||
sleep 100
|
||||
|
||||
print ====== insert 10 records to table 0, 1, 2
|
||||
$i = 10
|
||||
while $i > 0
|
||||
$ms = $i . s
|
||||
sql insert into test.car0 values(now - $ms , 1)
|
||||
sql insert into test.car1 values(now - $ms , $i )
|
||||
sql insert into test.car2 values(now - $ms , 10)
|
||||
$i = $i - 1
|
||||
endw
|
|
@ -1,91 +0,0 @@
|
|||
# wait until $1 alerts are generates, and at most wait $2 seconds
|
||||
# return 0 if wait succeeded, 1 if wait timeout
|
||||
function waitAlert() {
|
||||
local i=0
|
||||
|
||||
while [ $i -lt $2 ]; do
|
||||
local c=$(wc -l alert.out | awk '{print $1}')
|
||||
|
||||
if [ $c -ge $1 ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
let "i=$i+1"
|
||||
sleep 1s
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# prepare environment
|
||||
kill -INT `ps aux | grep 'alert -cfg' | grep -v grep | awk '{print $2}'`
|
||||
|
||||
rm -f alert.db
|
||||
rm -f alert.out
|
||||
../cmd/alert/alert -cfg ../cmd/alert/alert.cfg > alert.out &
|
||||
|
||||
../../td/debug/build/bin/tsim -c /etc/taos -f ./prepare.sim
|
||||
|
||||
# add a rule to alert application
|
||||
curl -d '@rule.json' http://localhost:8100/api/update-rule
|
||||
|
||||
# step 1: add some data but not trigger an alert
|
||||
../../td/debug/build/bin/tsim -c /etc/taos -f ./step1.sim
|
||||
|
||||
# wait 20 seconds, should not get an alert
|
||||
waitAlert 1 20
|
||||
res=$?
|
||||
if [ $res -eq 0 ]; then
|
||||
echo 'should not have alerts here'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# step 2: trigger an alert
|
||||
../../td/debug/build/bin/tsim -c /etc/taos -f ./step2.sim
|
||||
|
||||
# wait 30 seconds for the alert
|
||||
waitAlert 1 30
|
||||
res=$?
|
||||
if [ $res -eq 1 ]; then
|
||||
echo 'there should be an alert now'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# compare whether the generate alert meet expectation
|
||||
diff <(uniq alert.out | sed -n 1p | jq -cS 'del(.startsAt, .endsAt)') <(jq -cSn '{"values":{"avgspeed":10,"id":0},"labels":{"id":"0","ruleName":"test1"},"annotations":{"summary":"speed of car(id = 0) is too high: 10"}}')
|
||||
if [ $? -ne 0 ]; then
|
||||
echo 'the generated alert does not meet expectation'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# step 3: add more data, trigger another 3 alerts
|
||||
../../td/debug/build/bin/tsim -c /etc/taos -f ./step3.sim
|
||||
|
||||
# wait 30 seconds for the alerts
|
||||
waitAlert 4 30
|
||||
res=$?
|
||||
if [ $res -eq 1 ]; then
|
||||
echo 'there should be 4 alerts now'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# compare whether the generate alert meet expectation
|
||||
diff <(uniq alert.out | sed -n 2p | jq -cS 'del(.startsAt, .endsAt)') <(jq -cSn '{"annotations":{"summary":"speed of car(id = 0) is too high: 5.714285714285714"},"labels":{"id":"0","ruleName":"test1"},"values":{"avgspeed":5.714285714285714,"id":0}}')
|
||||
if [ $? -ne 0 ]; then
|
||||
echo 'the generated alert does not meet expectation'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
diff <(uniq alert.out | sed -n 3p | jq -cS 'del(.startsAt, .endsAt)') <(jq -cSn '{"annotations":{"summary":"speed of car(id = 1) is too high: 5.5"},"labels":{"id":"1","ruleName":"test1"},"values":{"avgspeed":5.5,"id":1}}')
|
||||
if [ $? -ne 0 ]; then
|
||||
echo 'the generated alert does not meet expectation'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
diff <(uniq alert.out | sed -n 4p | jq -cS 'del(.startsAt, .endsAt)') <(jq -cSn '{"annotations":{"summary":"speed of car(id = 2) is too high: 10"},"labels":{"id":"2","ruleName":"test1"},"values":{"avgspeed":10,"id":2}}')
|
||||
if [ $? -ne 0 ]; then
|
||||
echo 'the generated alert does not meet expectation'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
kill -INT `ps aux | grep 'alert -cfg' | grep -v grep | awk '{print $2}'`
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Port uint16 `json:"port,omitempty" yaml:"port,omitempty"`
|
||||
Database string `json:"database,omitempty" yaml:"database,omitempty"`
|
||||
RuleFile string `json:"ruleFile,omitempty" yaml:"ruleFile,omitempty"`
|
||||
Log struct {
|
||||
Level string `json:"level,omitempty" yaml:"level,omitempty"`
|
||||
Path string `json:"path,omitempty" yaml:"path,omitempty"`
|
||||
} `json:"log" yaml:"log"`
|
||||
TDengine string `json:"tdengine,omitempty" yaml:"tdengine,omitempty"`
|
||||
Receivers struct {
|
||||
AlertManager string `json:"alertManager,omitempty" yaml:"alertManager,omitempty"`
|
||||
Console bool `json:"console"`
|
||||
} `json:"receivers" yaml:"receivers"`
|
||||
}
|
||||
|
||||
var Cfg Config
|
||||
|
||||
func LoadConfig(path string) error {
|
||||
f, e := os.Open(path)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
e = yaml.NewDecoder(f).Decode(&Cfg)
|
||||
if e != nil {
|
||||
f.Seek(0, 0)
|
||||
e = json.NewDecoder(f).Decode(&Cfg)
|
||||
}
|
||||
|
||||
return e
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package log
|
||||
|
||||
import (
|
||||
"github.com/taosdata/alert/utils"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var logger *zap.SugaredLogger
|
||||
|
||||
func Init() error {
|
||||
var cfg zap.Config
|
||||
|
||||
if utils.Cfg.Log.Level == "debug" {
|
||||
cfg = zap.NewDevelopmentConfig()
|
||||
} else {
|
||||
cfg = zap.NewProductionConfig()
|
||||
}
|
||||
|
||||
if len(utils.Cfg.Log.Path) > 0 {
|
||||
cfg.OutputPaths = []string{utils.Cfg.Log.Path}
|
||||
}
|
||||
|
||||
l, e := cfg.Build()
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
logger = l.Sugar()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Debug package logger
|
||||
func Debug(args ...interface{}) {
|
||||
logger.Debug(args...)
|
||||
}
|
||||
|
||||
// Debugf package logger
|
||||
func Debugf(template string, args ...interface{}) {
|
||||
logger.Debugf(template, args...)
|
||||
}
|
||||
|
||||
// Info package logger
|
||||
func Info(args ...interface{}) {
|
||||
logger.Info(args...)
|
||||
}
|
||||
|
||||
// Infof package logger
|
||||
func Infof(template string, args ...interface{}) {
|
||||
logger.Infof(template, args...)
|
||||
}
|
||||
|
||||
// Warn package logger
|
||||
func Warn(args ...interface{}) {
|
||||
logger.Warn(args...)
|
||||
}
|
||||
|
||||
// Warnf package logger
|
||||
func Warnf(template string, args ...interface{}) {
|
||||
logger.Warnf(template, args...)
|
||||
}
|
||||
|
||||
// Error package logger
|
||||
func Error(args ...interface{}) {
|
||||
logger.Error(args...)
|
||||
}
|
||||
|
||||
// Errorf package logger
|
||||
func Errorf(template string, args ...interface{}) {
|
||||
logger.Errorf(template, args...)
|
||||
}
|
||||
|
||||
// Fatal package logger
|
||||
func Fatal(args ...interface{}) {
|
||||
logger.Fatal(args...)
|
||||
}
|
||||
|
||||
// Fatalf package logger
|
||||
func Fatalf(template string, args ...interface{}) {
|
||||
logger.Fatalf(template, args...)
|
||||
}
|
||||
|
||||
// Panic package logger
|
||||
func Panic(args ...interface{}) {
|
||||
logger.Panic(args...)
|
||||
}
|
||||
|
||||
// Panicf package logger
|
||||
func Panicf(template string, args ...interface{}) {
|
||||
logger.Panicf(template, args...)
|
||||
}
|
||||
|
||||
func Sync() error {
|
||||
return logger.Sync()
|
||||
}
|
|
@ -1,230 +0,0 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8...3.20)
|
||||
PROJECT(TDengine)
|
||||
|
||||
IF (TD_ACCOUNT)
|
||||
ADD_DEFINITIONS(-D_ACCT)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_ADMIN)
|
||||
ADD_DEFINITIONS(-D_ADMIN)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_GRANT)
|
||||
ADD_DEFINITIONS(-D_GRANT)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_MQTT)
|
||||
ADD_DEFINITIONS(-D_MQTT)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_TSDB_PLUGINS)
|
||||
ADD_DEFINITIONS(-D_TSDB_PLUGINS)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_STORAGE)
|
||||
ADD_DEFINITIONS(-D_STORAGE)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_TOPIC)
|
||||
ADD_DEFINITIONS(-D_TOPIC)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_MODULE)
|
||||
ADD_DEFINITIONS(-D_MODULE)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_GODLL)
|
||||
ADD_DEFINITIONS(-D_TD_GO_DLL_)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_POWER)
|
||||
ADD_DEFINITIONS(-D_TD_POWER_)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_TQ)
|
||||
ADD_DEFINITIONS(-D_TD_TQ_)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_MEM_CHECK)
|
||||
ADD_DEFINITIONS(-DTAOS_MEM_CHECK)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_RANDOM_FILE_FAIL)
|
||||
ADD_DEFINITIONS(-DTAOS_RANDOM_FILE_FAIL)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_RANDOM_NETWORK_FAIL)
|
||||
ADD_DEFINITIONS(-DTAOS_RANDOM_NETWORK_FAIL)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_LINUX_64)
|
||||
ADD_DEFINITIONS(-D_M_X64)
|
||||
ADD_DEFINITIONS(-D_TD_LINUX_64)
|
||||
MESSAGE(STATUS "linux64 is defined")
|
||||
SET(COMMON_FLAGS "-Wall -Werror -fPIC -gdwarf-2 -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
|
||||
ADD_DEFINITIONS(-DUSE_LIBICONV)
|
||||
|
||||
IF (JEMALLOC_ENABLED)
|
||||
ADD_DEFINITIONS(-DTD_JEMALLOC_ENABLED -I${CMAKE_BINARY_DIR}/build/include -L${CMAKE_BINARY_DIR}/build/lib -Wl,-rpath,${CMAKE_BINARY_DIR}/build/lib -ljemalloc)
|
||||
ENDIF ()
|
||||
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_LINUX_32)
|
||||
ADD_DEFINITIONS(-D_TD_LINUX_32)
|
||||
ADD_DEFINITIONS(-DUSE_LIBICONV)
|
||||
MESSAGE(STATUS "linux32 is defined")
|
||||
SET(COMMON_FLAGS "-Wall -Werror -fPIC -fsigned-char -munaligned-access -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_ARM_64)
|
||||
ADD_DEFINITIONS(-D_TD_ARM_64)
|
||||
ADD_DEFINITIONS(-D_TD_ARM_)
|
||||
ADD_DEFINITIONS(-DUSE_LIBICONV)
|
||||
MESSAGE(STATUS "arm64 is defined")
|
||||
SET(COMMON_FLAGS "-Wall -Werror -fPIC -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
|
||||
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/lua/src)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_ARM_32)
|
||||
ADD_DEFINITIONS(-D_TD_ARM_32)
|
||||
ADD_DEFINITIONS(-D_TD_ARM_)
|
||||
ADD_DEFINITIONS(-DUSE_LIBICONV)
|
||||
MESSAGE(STATUS "arm32 is defined")
|
||||
SET(COMMON_FLAGS "-Wall -Werror -fPIC -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -Wno-incompatible-pointer-types ")
|
||||
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/lua/src)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_MIPS_64)
|
||||
ADD_DEFINITIONS(-D_TD_MIPS_)
|
||||
ADD_DEFINITIONS(-D_TD_MIPS_64)
|
||||
ADD_DEFINITIONS(-DUSE_LIBICONV)
|
||||
MESSAGE(STATUS "mips64 is defined")
|
||||
SET(COMMON_FLAGS "-Wall -Werror -fPIC -fsigned-char -fpack-struct=8 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_MIPS_32)
|
||||
ADD_DEFINITIONS(-D_TD_MIPS_)
|
||||
ADD_DEFINITIONS(-D_TD_MIPS_32)
|
||||
ADD_DEFINITIONS(-DUSE_LIBICONV)
|
||||
MESSAGE(STATUS "mips32 is defined")
|
||||
SET(COMMON_FLAGS "-Wall -Werror -fPIC -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_APLHINE)
|
||||
SET(COMMON_FLAGS "${COMMON_FLAGS} -largp")
|
||||
link_libraries(/usr/lib/libargp.a)
|
||||
ADD_DEFINITIONS(-D_ALPINE)
|
||||
MESSAGE(STATUS "aplhine is defined")
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_LINUX)
|
||||
ADD_DEFINITIONS(-DLINUX)
|
||||
ADD_DEFINITIONS(-D_LINUX)
|
||||
ADD_DEFINITIONS(-D_TD_LINUX)
|
||||
ADD_DEFINITIONS(-D_REENTRANT -D__USE_POSIX -D_LIBC_REENTRANT)
|
||||
|
||||
IF (TD_NINGSI_60)
|
||||
ADD_DEFINITIONS(-D_TD_NINGSI_60)
|
||||
MESSAGE(STATUS "set ningsi macro to true")
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_MEMORY_SANITIZER)
|
||||
SET(DEBUG_FLAGS "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -static-libasan -O0 -g3 -DDEBUG")
|
||||
MESSAGE(STATUS "memory sanitizer detected as true")
|
||||
ELSE ()
|
||||
SET(DEBUG_FLAGS "-O0 -g3 -DDEBUG")
|
||||
MESSAGE(STATUS "memory sanitizer detected as false")
|
||||
ENDIF ()
|
||||
SET(RELEASE_FLAGS "-O3 -Wno-error")
|
||||
|
||||
IF (${COVER} MATCHES "true")
|
||||
MESSAGE(STATUS "Test coverage mode, add extra flags")
|
||||
SET(GCC_COVERAGE_COMPILE_FLAGS "-fprofile-arcs -ftest-coverage")
|
||||
SET(GCC_COVERAGE_LINK_FLAGS "-lgcov --coverage")
|
||||
SET(COMMON_FLAGS "${COMMON_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
|
||||
ENDIF ()
|
||||
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/cJson/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/lz4/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/lua/src)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_DARWIN_64)
|
||||
ADD_DEFINITIONS(-D_TD_DARWIN_64)
|
||||
ADD_DEFINITIONS(-DDARWIN)
|
||||
ADD_DEFINITIONS(-D_REENTRANT -D__USE_POSIX -D_LIBC_REENTRANT)
|
||||
ADD_DEFINITIONS(-DUSE_LIBICONV)
|
||||
MESSAGE(STATUS "darwin64 is defined")
|
||||
IF ("${CPUTYPE}" STREQUAL "apple_m1")
|
||||
SET(COMMON_FLAGS "-Wall -Werror -Wno-missing-braces -fPIC -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
|
||||
ELSE ()
|
||||
SET(COMMON_FLAGS "-Wall -Werror -Wno-missing-braces -fPIC -msse4.2 -D_FILE_OFFSET_BITS=64 -D_LARGE_FILE")
|
||||
ENDIF ()
|
||||
IF (TD_MEMORY_SANITIZER)
|
||||
SET(DEBUG_FLAGS "-fsanitize=address -fsanitize=undefined -fno-sanitize-recover=all -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fno-sanitize=null -fno-sanitize=alignment -O0 -g3 -DDEBUG")
|
||||
ELSE ()
|
||||
SET(DEBUG_FLAGS "-O0 -g3 -DDEBUG")
|
||||
ENDIF ()
|
||||
SET(RELEASE_FLAGS "-Og")
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/cJson/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/lz4/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/lua/src)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_WINDOWS)
|
||||
ADD_DEFINITIONS(-DWINDOWS)
|
||||
ADD_DEFINITIONS(-D__CLEANUP_C)
|
||||
ADD_DEFINITIONS(-DPTW32_STATIC_LIB)
|
||||
ADD_DEFINITIONS(-DPTW32_BUILD)
|
||||
ADD_DEFINITIONS(-D_MBCS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
SET(CMAKE_GENERATOR "NMake Makefiles" CACHE INTERNAL "" FORCE)
|
||||
IF (NOT TD_GODLL)
|
||||
SET(COMMON_FLAGS "/nologo /WX /wd4018 /wd5999 /Oi /Oy- /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Gd /errorReport:prompt /analyze-")
|
||||
IF (MSVC AND (MSVC_VERSION GREATER_EQUAL 1900))
|
||||
SET(COMMON_FLAGS "${COMMON_FLAGS} /Wv:18")
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_MEMORY_SANITIZER)
|
||||
MESSAGE("memory sanitizer detected as true")
|
||||
SET(DEBUG_FLAGS "/fsanitize=address /Zi /W3 /GL")
|
||||
ELSE ()
|
||||
MESSAGE("memory sanitizer detected as false")
|
||||
SET(DEBUG_FLAGS "/Zi /W3 /GL")
|
||||
ENDIF ()
|
||||
SET(RELEASE_FLAGS "/W0 /O2 /GL") # MSVC only support O2
|
||||
ENDIF ()
|
||||
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/pthread)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/iconv)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/regex)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/wepoll/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/MsvcLibX/include)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/deps/lua/src)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_WINDOWS_64)
|
||||
ADD_DEFINITIONS(-D_M_X64)
|
||||
ADD_DEFINITIONS(-D_TD_WINDOWS_64)
|
||||
ADD_DEFINITIONS(-DUSE_LIBICONV)
|
||||
MESSAGE(STATUS "windows64 is defined")
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_WINDOWS_32)
|
||||
ADD_DEFINITIONS(-D_TD_WINDOWS_32)
|
||||
ADD_DEFINITIONS(-DUSE_LIBICONV)
|
||||
MESSAGE(STATUS "windows32 is defined")
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_LINUX)
|
||||
SET(COMMON_FLAGS "${COMMON_FLAGS} -pipe -Wshadow")
|
||||
ENDIF ()
|
||||
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/os/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/util/inc)
|
||||
INCLUDE_DIRECTORIES(${TD_COMMUNITY_DIR}/src/common/inc)
|
||||
|
||||
MESSAGE(STATUS "CMAKE_CXX_COMPILER_ID: " ${CMAKE_CXX_COMPILER_ID})
|
|
@ -1,70 +0,0 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8...3.20)
|
||||
PROJECT(TDengine)
|
||||
|
||||
SET(CMAKE_C_STANDARD 11)
|
||||
SET(CMAKE_VERBOSE_MAKEFILE ON)
|
||||
|
||||
#set output directory
|
||||
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build/lib)
|
||||
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/build/bin)
|
||||
SET(TD_TESTS_OUTPUT_DIR ${PROJECT_BINARY_DIR}/test)
|
||||
|
||||
MESSAGE(STATUS "Project source directory: " ${PROJECT_SOURCE_DIR})
|
||||
MESSAGE(STATUS "Project binary files output path: " ${PROJECT_BINARY_DIR})
|
||||
MESSAGE(STATUS "Project executable files output path: " ${EXECUTABLE_OUTPUT_PATH})
|
||||
MESSAGE(STATUS "Project library files output path: " ${LIBRARY_OUTPUT_PATH})
|
||||
|
||||
IF (TD_BUILD_JDBC)
|
||||
FIND_PROGRAM(TD_MVN_INSTALLED mvn)
|
||||
IF (TD_MVN_INSTALLED)
|
||||
MESSAGE(STATUS "MVN is installed and JDBC will be compiled")
|
||||
ELSE ()
|
||||
MESSAGE(STATUS "MVN is not installed and JDBC is not compiled")
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
||||
#
|
||||
# If need to set debug options
|
||||
# 1.Generate debug version:
|
||||
# mkdir debug; cd debug;
|
||||
# cmake -DCMAKE_BUILD_TYPE=Debug ..
|
||||
# 2.Generate release version:
|
||||
# mkdir release; cd release;
|
||||
# cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
#
|
||||
|
||||
# Set compiler options
|
||||
IF (TD_LINUX)
|
||||
SET(COMMON_C_FLAGS "${COMMON_FLAGS} -std=gnu99")
|
||||
ELSE ()
|
||||
SET(COMMON_C_FLAGS "${COMMON_FLAGS} ")
|
||||
ENDIF ()
|
||||
|
||||
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${COMMON_C_FLAGS} ${DEBUG_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${COMMON_C_FLAGS} ${RELEASE_FLAGS}")
|
||||
|
||||
# Set c++ compiler options
|
||||
IF (TD_WINDOWS)
|
||||
SET(COMMON_CXX_FLAGS "${COMMON_FLAGS} -std=c++11")
|
||||
ELSE ()
|
||||
SET(COMMON_CXX_FLAGS "${COMMON_FLAGS} -std=c++11 -Wno-unused-function")
|
||||
ENDIF ()
|
||||
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COMMON_CXX_FLAGS} ${DEBUG_FLAGS}")
|
||||
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COMMON_CXX_FLAGS} ${RELEASE_FLAGS}")
|
||||
|
||||
IF (${CMAKE_BUILD_TYPE} MATCHES "Debug")
|
||||
SET(CMAKE_BUILD_TYPE "Debug")
|
||||
MESSAGE(STATUS "Build Debug Version")
|
||||
ELSEIF (${CMAKE_BUILD_TYPE} MATCHES "Release")
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
MESSAGE(STATUS "Build Release Version")
|
||||
ELSE ()
|
||||
IF (TD_WINDOWS)
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
MESSAGE(STATUS "Build Release Version in Windows as default")
|
||||
ELSE ()
|
||||
SET(CMAKE_BUILD_TYPE "Debug")
|
||||
MESSAGE(STATUS "Build Debug Version as default")
|
||||
ENDIF()
|
||||
ENDIF ()
|
|
@ -1,102 +0,0 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8...3.20)
|
||||
PROJECT(TDengine)
|
||||
|
||||
IF (${ACCOUNT} MATCHES "true")
|
||||
SET(TD_ACCOUNT TRUE)
|
||||
MESSAGE(STATUS "Build with account plugins")
|
||||
ELSEIF (${ACCOUNT} MATCHES "false")
|
||||
SET(TD_ACCOUNT FALSE)
|
||||
MESSAGE(STATUS "Build without account plugins")
|
||||
ENDIF ()
|
||||
|
||||
IF (${TOPIC} MATCHES "true")
|
||||
SET(TD_TOPIC TRUE)
|
||||
MESSAGE(STATUS "Build with topic plugins")
|
||||
ELSEIF (${TOPIC} MATCHES "false")
|
||||
SET(TD_TOPIC FALSE)
|
||||
MESSAGE(STATUS "Build without topic plugins")
|
||||
ENDIF ()
|
||||
|
||||
IF (${TD_MODULE} MATCHES "true")
|
||||
SET(TD_MODULE TRUE)
|
||||
MESSAGE(STATUS "Build with module plugins")
|
||||
ELSEIF (${TOPIC} MATCHES "false")
|
||||
SET(TD_MODULE FALSE)
|
||||
MESSAGE(STATUS "Build without module plugins")
|
||||
ENDIF ()
|
||||
|
||||
IF (${COVER} MATCHES "true")
|
||||
SET(TD_COVER TRUE)
|
||||
MESSAGE(STATUS "Build with test coverage")
|
||||
ELSEIF (${COVER} MATCHES "false")
|
||||
SET(TD_COVER FALSE)
|
||||
MESSAGE(STATUS "Build without test coverage")
|
||||
ENDIF ()
|
||||
|
||||
IF (${PAGMODE} MATCHES "lite")
|
||||
SET(TD_PAGMODE_LITE TRUE)
|
||||
MESSAGE(STATUS "Build with pagmode lite")
|
||||
ENDIF ()
|
||||
|
||||
IF (${SOMODE} MATCHES "static")
|
||||
SET(TD_SOMODE_STATIC TRUE)
|
||||
MESSAGE(STATUS "Link so using static mode")
|
||||
ENDIF ()
|
||||
|
||||
IF (${DBNAME} MATCHES "power")
|
||||
SET(TD_POWER TRUE)
|
||||
MESSAGE(STATUS "power is true")
|
||||
ELSEIF (${DBNAME} MATCHES "tq")
|
||||
SET(TD_TQ TRUE)
|
||||
MESSAGE(STATUS "tq is true")
|
||||
ENDIF ()
|
||||
|
||||
IF (${DLLTYPE} MATCHES "go")
|
||||
SET(TD_GODLL TRUE)
|
||||
MESSAGE(STATUS "input dll type: " ${DLLTYPE})
|
||||
ENDIF ()
|
||||
|
||||
IF (${MEM_CHECK} MATCHES "true")
|
||||
SET(TD_MEM_CHECK TRUE)
|
||||
MESSAGE(STATUS "build with memory check")
|
||||
ENDIF ()
|
||||
|
||||
IF (${MQTT} MATCHES "false")
|
||||
SET(TD_MQTT FALSE)
|
||||
MESSAGE(STATUS "build without mqtt module")
|
||||
ENDIF ()
|
||||
|
||||
IF (${RANDOM_FILE_FAIL} MATCHES "true")
|
||||
SET(TD_RANDOM_FILE_FAIL TRUE)
|
||||
MESSAGE(STATUS "build with random-file-fail enabled")
|
||||
ENDIF ()
|
||||
|
||||
IF (${RANDOM_NETWORK_FAIL} MATCHES "true")
|
||||
SET(TD_RANDOM_NETWORK_FAIL TRUE)
|
||||
MESSAGE(STATUS "build with random-network-fail enabled")
|
||||
ENDIF ()
|
||||
|
||||
IF (${JEMALLOC_ENABLED} MATCHES "true")
|
||||
SET(TD_JEMALLOC_ENABLED TRUE)
|
||||
MESSAGE(STATUS "build with jemalloc enabled")
|
||||
ENDIF ()
|
||||
|
||||
SET(TD_BUILD_JDBC TRUE)
|
||||
|
||||
IF (${BUILD_JDBC} MATCHES "false")
|
||||
SET(TD_BUILD_JDBC FALSE)
|
||||
ENDIF ()
|
||||
|
||||
SET(TD_MEMORY_SANITIZER FALSE)
|
||||
IF (${MEMORY_SANITIZER} MATCHES "true")
|
||||
SET(TD_MEMORY_SANITIZER TRUE)
|
||||
ENDIF ()
|
||||
|
||||
IF (${TSZ_ENABLED} MATCHES "true")
|
||||
# define add
|
||||
MESSAGE(STATUS "build with TSZ enabled")
|
||||
ADD_DEFINITIONS(-DTD_TSZ)
|
||||
set(VAR_TSZ "TSZ" CACHE INTERNAL "global variant tsz" )
|
||||
ELSE()
|
||||
set(VAR_TSZ "" CACHE INTERNAL "global variant empty" )
|
||||
ENDIF()
|
|
@ -1,42 +0,0 @@
|
|||
IF (TD_LINUX)
|
||||
SET(TD_MAKE_INSTALL_SH "${TD_COMMUNITY_DIR}/packaging/tools/make_install.sh")
|
||||
INSTALL(CODE "MESSAGE(\"make install script: ${TD_MAKE_INSTALL_SH}\")")
|
||||
INSTALL(CODE "execute_process(COMMAND chmod 777 ${TD_MAKE_INSTALL_SH})")
|
||||
INSTALL(CODE "execute_process(COMMAND ${TD_MAKE_INSTALL_SH} ${TD_COMMUNITY_DIR} ${PROJECT_BINARY_DIR} Linux ${TD_VER_NUMBER})")
|
||||
ELSEIF (TD_WINDOWS)
|
||||
IF (TD_POWER)
|
||||
SET(CMAKE_INSTALL_PREFIX C:/PowerDB)
|
||||
ELSE ()
|
||||
SET(CMAKE_INSTALL_PREFIX C:/TDengine)
|
||||
ENDIF ()
|
||||
|
||||
INSTALL(DIRECTORY ${TD_COMMUNITY_DIR}/src/connector/go DESTINATION connector)
|
||||
INSTALL(DIRECTORY ${TD_COMMUNITY_DIR}/src/connector/nodejs DESTINATION connector)
|
||||
INSTALL(DIRECTORY ${TD_COMMUNITY_DIR}/src/connector/python DESTINATION connector)
|
||||
INSTALL(DIRECTORY ${TD_COMMUNITY_DIR}/src/connector/C\# DESTINATION connector)
|
||||
INSTALL(DIRECTORY ${TD_COMMUNITY_DIR}/tests/examples DESTINATION .)
|
||||
INSTALL(DIRECTORY ${TD_COMMUNITY_DIR}/packaging/cfg DESTINATION .)
|
||||
INSTALL(FILES ${TD_COMMUNITY_DIR}/src/inc/taos.h DESTINATION include)
|
||||
INSTALL(FILES ${TD_COMMUNITY_DIR}/src/inc/taoserror.h DESTINATION include)
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos.lib DESTINATION driver)
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos.exp DESTINATION driver)
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos.dll DESTINATION driver)
|
||||
|
||||
IF (TD_POWER)
|
||||
INSTALL(FILES ${EXECUTABLE_OUTPUT_PATH}/power.exe DESTINATION .)
|
||||
ELSE ()
|
||||
INSTALL(FILES ${EXECUTABLE_OUTPUT_PATH}/taos.exe DESTINATION .)
|
||||
INSTALL(FILES ${EXECUTABLE_OUTPUT_PATH}/taosdemo.exe DESTINATION .)
|
||||
ENDIF ()
|
||||
|
||||
#INSTALL(TARGETS taos RUNTIME DESTINATION driver)
|
||||
#INSTALL(TARGETS shell RUNTIME DESTINATION .)
|
||||
IF (TD_MVN_INSTALLED)
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos-jdbcdriver-2.0.34-dist.jar DESTINATION connector/jdbc)
|
||||
ENDIF ()
|
||||
ELSEIF (TD_DARWIN)
|
||||
SET(TD_MAKE_INSTALL_SH "${TD_COMMUNITY_DIR}/packaging/tools/make_install.sh")
|
||||
INSTALL(CODE "MESSAGE(\"make install script: ${TD_MAKE_INSTALL_SH}\")")
|
||||
INSTALL(CODE "execute_process(COMMAND chmod 777 ${TD_MAKE_INSTALL_SH})")
|
||||
INSTALL(CODE "execute_process(COMMAND ${TD_MAKE_INSTALL_SH} ${TD_COMMUNITY_DIR} ${PROJECT_BINARY_DIR} Darwin ${TD_VER_NUMBER})")
|
||||
ENDIF ()
|
|
@ -1,161 +0,0 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8...3.20)
|
||||
PROJECT(TDengine)
|
||||
|
||||
#
|
||||
# If it is a Windows operating system
|
||||
# 1.Use command line tool of VS2013 or higher version
|
||||
# mkdir build; cd build;
|
||||
# cmake -G "NMake Makefiles" ..
|
||||
# nmake install
|
||||
# 2.Use the VS development interface tool
|
||||
# mkdir build; cd build;
|
||||
# cmake -A x64 ..
|
||||
# open the file named TDengine.sln
|
||||
#
|
||||
|
||||
# Set macro definitions according to os platform
|
||||
SET(TD_LINUX FALSE)
|
||||
SET(TD_LINUX_64 FALSE)
|
||||
SET(TD_LINUX_32 FALSE)
|
||||
SET(TD_ARM_64 FALSE)
|
||||
SET(TD_ARM_32 FALSE)
|
||||
SET(TD_MIPS_64 FALSE)
|
||||
SET(TD_MIPS_32 FALSE)
|
||||
SET(TD_APLHINE FALSE)
|
||||
SET(TD_NINGSI FALSE)
|
||||
SET(TD_NINGSI_60 FALSE)
|
||||
SET(TD_NINGSI_80 FALSE)
|
||||
SET(TD_WINDOWS FALSE)
|
||||
SET(TD_WINDOWS_64 FALSE)
|
||||
SET(TD_WINDOWS_32 FALSE)
|
||||
SET(TD_DARWIN FALSE)
|
||||
SET(TD_DARWIN_64 FALSE)
|
||||
|
||||
IF (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
|
||||
#
|
||||
# Get OS information and store in variable TD_OS_INFO.
|
||||
#
|
||||
execute_process(COMMAND chmod 777 ${TD_COMMUNITY_DIR}/packaging/tools/get_os.sh)
|
||||
execute_process(COMMAND ${TD_COMMUNITY_DIR}/packaging/tools/get_os.sh "" OUTPUT_VARIABLE TD_OS_INFO)
|
||||
MESSAGE(STATUS "The current os is " ${TD_OS_INFO})
|
||||
|
||||
SET(TD_LINUX TRUE)
|
||||
IF (${CMAKE_SIZEOF_VOID_P} MATCHES 8)
|
||||
SET(TD_LINUX_64 TRUE)
|
||||
MESSAGE(STATUS "The current platform is Linux 64-bit")
|
||||
ELSEIF (${CMAKE_SIZEOF_VOID_P} MATCHES 4)
|
||||
SET(TD_LINUX_32 TRUE)
|
||||
MESSAGE(STATUS "The current platform is Linux 32-bit")
|
||||
ELSE ()
|
||||
MESSAGE(FATAL_ERROR "The current platform is Linux neither 32-bit nor 64-bit, not supported yet")
|
||||
EXIT ()
|
||||
ENDIF ()
|
||||
|
||||
IF (${TD_OS_INFO} MATCHES "Alpine")
|
||||
SET(TD_APLHINE TRUE)
|
||||
MESSAGE(STATUS "The current OS is Alpine, append extra flags")
|
||||
ENDIF()
|
||||
ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
SET(TD_DARWIN TRUE)
|
||||
IF (${CMAKE_SIZEOF_VOID_P} MATCHES 8)
|
||||
SET(TD_DARWIN_64 TRUE)
|
||||
MESSAGE(STATUS "The current platform is Darwin 64-bit")
|
||||
ELSE ()
|
||||
MESSAGE(FATAL_ERROR "The current platform is Darwin 32-bit, not supported yet")
|
||||
EXIT ()
|
||||
ENDIF ()
|
||||
ELSEIF (${CMAKE_SYSTEM_NAME} MATCHES "Windows")
|
||||
SET(TD_WINDOWS TRUE)
|
||||
IF (${CMAKE_SIZEOF_VOID_P} MATCHES 8)
|
||||
SET(TD_WINDOWS_64 TRUE)
|
||||
MESSAGE(STATUS "The current platform is Windows 64-bit")
|
||||
ELSE ()
|
||||
SET(TD_WINDOWS_32 TRUE)
|
||||
MESSAGE(STATUS "The current platform is Windows 32-bit")
|
||||
ENDIF ()
|
||||
ELSE()
|
||||
MESSAGE(FATAL_ERROR "The current platform is not Linux/Darwin/Windows, stop compile")
|
||||
EXIT ()
|
||||
ENDIF ()
|
||||
|
||||
IF ("${CPUTYPE}" STREQUAL "")
|
||||
MESSAGE(STATUS "The current platform " ${CMAKE_SYSTEM_PROCESSOR} " is detected")
|
||||
|
||||
IF (CMAKE_SYSTEM_PROCESSOR MATCHES "(amd64)|(AMD64)")
|
||||
MESSAGE(STATUS "The current platform is amd64")
|
||||
MESSAGE(STATUS "Set CPUTYPE to x64")
|
||||
SET(CPUTYPE "x64")
|
||||
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)")
|
||||
MESSAGE(STATUS "The current platform is x86")
|
||||
MESSAGE(STATUS "Set CPUTYPE to x86")
|
||||
SET(CPUTYPE "x32")
|
||||
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "armv7l")
|
||||
MESSAGE(STATUS "Set CPUTYPE to aarch32")
|
||||
SET(CPUTYPE "aarch32")
|
||||
MESSAGE(STATUS "Set CPUTYPE to aarch32")
|
||||
SET(TD_LINUX TRUE)
|
||||
SET(TD_LINUX_32 FALSE)
|
||||
SET(TD_ARM_32 TRUE)
|
||||
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
|
||||
SET(CPUTYPE "aarch64")
|
||||
MESSAGE(STATUS "Set CPUTYPE to aarch64")
|
||||
SET(TD_LINUX TRUE)
|
||||
SET(TD_LINUX_64 FALSE)
|
||||
SET(TD_ARM_64 TRUE)
|
||||
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "mips64")
|
||||
SET(CPUTYPE "mips64")
|
||||
MESSAGE(STATUS "Set CPUTYPE to mips64")
|
||||
SET(TD_LINUX TRUE)
|
||||
SET(TD_LINUX_64 FALSE)
|
||||
SET(TD_MIPS_64 TRUE)
|
||||
ELSEIF (CMAKE_SYSTEM_PROCESSOR MATCHES "arm64")
|
||||
SET(CPUTYPE "apple_m1")
|
||||
MESSAGE(STATUS "Set CPUTYPE to apple silicon m1")
|
||||
SET(TD_ARM_64 TRUE)
|
||||
ENDIF ()
|
||||
|
||||
ELSE ()
|
||||
# if generate ARM version:
|
||||
# cmake -DCPUTYPE=aarch32 .. or cmake -DCPUTYPE=aarch64
|
||||
IF (${CPUTYPE} MATCHES "aarch32")
|
||||
SET(TD_LINUX TRUE)
|
||||
SET(TD_LINUX_32 FALSE)
|
||||
SET(TD_ARM_32 TRUE)
|
||||
MESSAGE(STATUS "input cpuType: aarch32")
|
||||
ELSEIF (${CPUTYPE} MATCHES "aarch64")
|
||||
SET(TD_LINUX TRUE)
|
||||
SET(TD_LINUX_64 FALSE)
|
||||
SET(TD_ARM_64 TRUE)
|
||||
MESSAGE(STATUS "input cpuType: aarch64")
|
||||
ELSEIF (${CPUTYPE} MATCHES "mips64")
|
||||
SET(TD_LINUX TRUE)
|
||||
SET(TD_LINUX_64 FALSE)
|
||||
SET(TD_MIPS_64 TRUE)
|
||||
MESSAGE(STATUS "input cpuType: mips64")
|
||||
ELSEIF (${CPUTYPE} MATCHES "x64")
|
||||
MESSAGE(STATUS "input cpuType: x64")
|
||||
ELSEIF (${CPUTYPE} MATCHES "x86")
|
||||
MESSAGE(STATUS "input cpuType: x86")
|
||||
ELSE ()
|
||||
MESSAGE(STATUS "input cpuType unknown " ${CPUTYPE})
|
||||
ENDIF ()
|
||||
|
||||
ENDIF ()
|
||||
|
||||
# cmake -DOSTYPE=Ningsi
|
||||
IF (${OSTYPE} MATCHES "Ningsi60")
|
||||
SET(TD_NINGSI TRUE)
|
||||
SET(TD_NINGSI_60 TRUE)
|
||||
MESSAGE(STATUS "input osType: Ningsi60")
|
||||
ELSEIF (${OSTYPE} MATCHES "Ningsi80")
|
||||
SET(TD_NINGSI TRUE)
|
||||
SET(TD_NINGSI_80 TRUE)
|
||||
MESSAGE(STATUS "input osType: Ningsi80")
|
||||
ELSEIF (${OSTYPE} MATCHES "Linux")
|
||||
MESSAGE(STATUS "input osType: Linux")
|
||||
ELSEIF (${OSTYPE} MATCHES "Alpine")
|
||||
MESSAGE(STATUS "input osType: Alpine")
|
||||
SET(TD_APLHINE TRUE)
|
||||
ELSE ()
|
||||
MESSAGE(STATUS "The user specified osType is unknown: " ${OSTYPE})
|
||||
ENDIF ()
|
|
@ -1,99 +0,0 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8...3.20)
|
||||
PROJECT(TDengine)
|
||||
|
||||
IF (DEFINED VERNUMBER)
|
||||
SET(TD_VER_NUMBER ${VERNUMBER})
|
||||
ELSE ()
|
||||
SET(TD_VER_NUMBER "2.1.7.2")
|
||||
ENDIF ()
|
||||
|
||||
IF (DEFINED VERCOMPATIBLE)
|
||||
SET(TD_VER_COMPATIBLE ${VERCOMPATIBLE})
|
||||
ELSE ()
|
||||
SET(TD_VER_COMPATIBLE "2.0.0.0")
|
||||
ENDIF ()
|
||||
|
||||
find_program(HAVE_GIT NAMES git)
|
||||
|
||||
IF (DEFINED GITINFO)
|
||||
SET(TD_VER_GIT ${GITINFO})
|
||||
ELSEIF (HAVE_GIT)
|
||||
execute_process(COMMAND git log -1 --format=%H WORKING_DIRECTORY ${TD_COMMUNITY_DIR} OUTPUT_VARIABLE GIT_COMMITID)
|
||||
message(STATUS "git log result:${GIT_COMMITID}")
|
||||
IF (GIT_COMMITID)
|
||||
string (REGEX REPLACE "[\n\t\r]" "" GIT_COMMITID ${GIT_COMMITID})
|
||||
SET(TD_VER_GIT ${GIT_COMMITID})
|
||||
ELSE ()
|
||||
message(STATUS "not a git repository")
|
||||
SET(TD_VER_GIT "no git commit id")
|
||||
ENDIF ()
|
||||
ELSE ()
|
||||
message(STATUS "no git cmd")
|
||||
SET(TD_VER_GIT "no git commit id")
|
||||
ENDIF ()
|
||||
|
||||
IF (DEFINED GITINFOI)
|
||||
SET(TD_VER_GIT_INTERNAL ${GITINFOI})
|
||||
ELSEIF (HAVE_GIT)
|
||||
execute_process(COMMAND git log -1 --format=%H WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} OUTPUT_VARIABLE GIT_COMMITID)
|
||||
message(STATUS "git log result:${GIT_COMMITID}")
|
||||
IF (GIT_COMMITID)
|
||||
string (REGEX REPLACE "[\n\t\r]" "" GIT_COMMITID ${GIT_COMMITID})
|
||||
SET(TD_VER_GIT_INTERNAL ${GIT_COMMITID})
|
||||
ELSE ()
|
||||
message(STATUS "not a git repository")
|
||||
SET(TD_VER_GIT "no git commit id")
|
||||
ENDIF ()
|
||||
ELSE ()
|
||||
message(STATUS "no git cmd")
|
||||
SET(TD_VER_GIT_INTERNAL "no git commit id")
|
||||
ENDIF ()
|
||||
|
||||
IF (DEFINED VERDATE)
|
||||
SET(TD_VER_DATE ${VERDATE})
|
||||
ELSE ()
|
||||
STRING(TIMESTAMP TD_VER_DATE "%Y-%m-%d %H:%M:%S")
|
||||
ENDIF ()
|
||||
|
||||
IF (DEFINED VERTYPE)
|
||||
SET(TD_VER_VERTYPE ${VERTYPE})
|
||||
ELSE ()
|
||||
SET(TD_VER_VERTYPE "stable")
|
||||
ENDIF ()
|
||||
|
||||
IF (DEFINED CPUTYPE)
|
||||
SET(TD_VER_CPUTYPE ${CPUTYPE})
|
||||
ELSE ()
|
||||
IF (TD_WINDOWS_32)
|
||||
SET(TD_VER_CPUTYPE "x86")
|
||||
ELSEIF (TD_LINUX_32)
|
||||
SET(TD_VER_CPUTYPE "x86")
|
||||
ELSEIF (TD_ARM_32)
|
||||
SET(TD_VER_CPUTYPE "x86")
|
||||
ELSEIF (TD_MIPS_32)
|
||||
SET(TD_VER_CPUTYPE "x86")
|
||||
ELSE ()
|
||||
SET(TD_VER_CPUTYPE "x64")
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
||||
IF (DEFINED OSTYPE)
|
||||
SET(TD_VER_OSTYPE ${OSTYPE})
|
||||
ELSE ()
|
||||
SET(TD_VER_OSTYPE "Linux")
|
||||
ENDIF ()
|
||||
|
||||
MESSAGE(STATUS "============= compile version parameter information start ============= ")
|
||||
MESSAGE(STATUS "ver number:" ${TD_VER_NUMBER})
|
||||
MESSAGE(STATUS "compatible ver number:" ${TD_VER_COMPATIBLE})
|
||||
MESSAGE(STATUS "community commit id:" ${TD_VER_GIT})
|
||||
MESSAGE(STATUS "internal commit id:" ${TD_VER_GIT_INTERNAL})
|
||||
MESSAGE(STATUS "build date:" ${TD_VER_DATE})
|
||||
MESSAGE(STATUS "ver type:" ${TD_VER_VERTYPE})
|
||||
MESSAGE(STATUS "ver cpu:" ${TD_VER_CPUTYPE})
|
||||
MESSAGE(STATUS "os type:" ${TD_VER_OSTYPE})
|
||||
MESSAGE(STATUS "============= compile version parameter information end ============= ")
|
||||
|
||||
STRING(REPLACE "." "_" TD_LIB_VER_NUMBER ${TD_VER_NUMBER})
|
||||
|
||||
CONFIGURE_FILE("${TD_COMMUNITY_DIR}/src/util/src/version.c.in" "${TD_COMMUNITY_DIR}/src/util/src/version.c")
|
|
@ -1,43 +0,0 @@
|
|||
PROJECT(TDengine)
|
||||
|
||||
IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8...3.20)
|
||||
ELSE ()
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
ENDIF ()
|
||||
|
||||
ADD_SUBDIRECTORY(zlib-1.2.11)
|
||||
ADD_SUBDIRECTORY(pthread)
|
||||
ADD_SUBDIRECTORY(regex)
|
||||
ADD_SUBDIRECTORY(iconv)
|
||||
ADD_SUBDIRECTORY(lz4)
|
||||
ADD_SUBDIRECTORY(cJson)
|
||||
ADD_SUBDIRECTORY(wepoll)
|
||||
ADD_SUBDIRECTORY(MsvcLibX)
|
||||
ADD_SUBDIRECTORY(rmonotonic)
|
||||
ADD_SUBDIRECTORY(lua)
|
||||
|
||||
IF (TD_LINUX AND TD_MQTT)
|
||||
ADD_SUBDIRECTORY(MQTT-C)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_DARWIN AND TD_MQTT)
|
||||
ADD_SUBDIRECTORY(MQTT-C)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_LINUX_64 AND JEMALLOC_ENABLED)
|
||||
MESSAGE("setup deps/jemalloc, current source dir:" ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
MESSAGE("binary dir:" ${CMAKE_BINARY_DIR})
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(jemalloc
|
||||
PREFIX "jemalloc"
|
||||
SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/jemalloc
|
||||
BUILD_IN_SOURCE 1
|
||||
CONFIGURE_COMMAND ./autogen.sh COMMAND ./configure --prefix=${CMAKE_BINARY_DIR}/build/
|
||||
BUILD_COMMAND ${MAKE}
|
||||
)
|
||||
ENDIF ()
|
||||
|
||||
IF (${TSZ_ENABLED} MATCHES "true")
|
||||
ADD_SUBDIRECTORY(TSZ)
|
||||
ENDIF()
|
|
@ -1,80 +0,0 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8...3.20)
|
||||
|
||||
# MQTT-C build options
|
||||
option(MQTT_C_OpenSSL_SUPPORT "Build MQTT-C with OpenSSL support?" OFF)
|
||||
option(MQTT_C_MbedTLS_SUPPORT "Build MQTT-C with mbed TLS support?" OFF)
|
||||
option(MQTT_C_EXAMPLES "Build MQTT-C examples?" ON)
|
||||
option(MQTT_C_TESTS "Build MQTT-C tests?" OFF)
|
||||
|
||||
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
# MQTT-C library
|
||||
ADD_LIBRARY(mqttc STATIC
|
||||
src/mqtt_pal.c
|
||||
src/mqtt.c
|
||||
)
|
||||
TARGET_INCLUDE_DIRECTORIES(mqttc PUBLIC include)
|
||||
target_link_libraries(mqttc PUBLIC
|
||||
$<$<C_COMPILER_ID:MSVS>:ws2_32>
|
||||
)
|
||||
|
||||
|
||||
# Configure with OpenSSL support
|
||||
if(MQTT_C_OpenSSL_SUPPORT)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
target_link_libraries(mqttc INTERFACE OpenSSL::SSL)
|
||||
target_compile_definitions(mqttc PUBLIC MQTT_USE_BIO)
|
||||
endif()
|
||||
|
||||
# Configure with mbed TLS support
|
||||
if(MQTT_C_MbedTLS_SUPPORT)
|
||||
find_package(MbedTLS REQUIRED)
|
||||
TARGET_INCLUDE_DIRECTORIES(mqttc PUBLIC ${MBEDTLS_INCLUDE_DIRS})
|
||||
target_link_libraries(mqttc INTERFACE ${MBEDTLS_LIBRARY})
|
||||
target_compile_definitions(mqttc PUBLIC MQTT_USE_MBEDTLS)
|
||||
endif()
|
||||
|
||||
# Build examples
|
||||
if(MQTT_C_EXAMPLES)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(MQTT_C_OpenSSL_SUPPORT)
|
||||
add_executable(bio_publisher examples/bio_publisher.c)
|
||||
target_link_libraries(bio_publisher Threads::Threads mqttc)
|
||||
|
||||
add_executable(openssl_publisher examples/openssl_publisher.c)
|
||||
target_link_libraries(openssl_publisher Threads::Threads mqttc)
|
||||
elseif(MQTT_C_MbedTLS_SUPPORT)
|
||||
add_executable(mbedtls_publisher examples/mbedtls_publisher.c)
|
||||
target_link_libraries(mbedtls_publisher Threads::Threads mqttc ${MBEDX509_LIBRARY} ${MBEDCRYPTO_LIBRARY})
|
||||
else()
|
||||
add_executable(simple_publisher examples/simple_publisher.c)
|
||||
target_link_libraries(simple_publisher Threads::Threads mqttc)
|
||||
|
||||
add_executable(simple_subscriber examples/simple_subscriber.c)
|
||||
target_link_libraries(simple_subscriber Threads::Threads mqttc)
|
||||
|
||||
add_executable(reconnect_subscriber examples/reconnect_subscriber.c)
|
||||
target_link_libraries(reconnect_subscriber Threads::Threads mqttc)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Build tests
|
||||
if(MQTT_C_TESTS)
|
||||
find_path(CMOCKA_INCLUDE_DIR cmocka.h)
|
||||
find_library(CMOCKA_LIBRARY cmocka)
|
||||
if((NOT CMOCKA_INCLUDE_DIR) OR (NOT CMOCKA_LIBRARY))
|
||||
message(FATAL_ERROR "Failed to find cmocka! Add cmocka's install prefix to CMAKE_PREFIX_PATH to resolve this error.")
|
||||
endif()
|
||||
|
||||
add_executable(tests tests.c)
|
||||
target_link_libraries(tests ${CMOCKA_LIBRARY} mqttc)
|
||||
TARGET_INCLUDE_DIRECTORIES(tests PRIVATE ${CMOCKA_INCLUDE_DIR})
|
||||
endif()
|
||||
|
||||
# Install includes and library
|
||||
# install(TARGETS mqttc
|
||||
# DESTINATION lib
|
||||
# )
|
||||
# install(DIRECTORY include/
|
||||
# DESTINATION include)
|
File diff suppressed because it is too large
Load Diff
|
@ -1,21 +0,0 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2018 Liam Bindle
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -1,108 +0,0 @@
|
|||
<p align="right">
|
||||
<a href="https://github.com/LiamBindle/MQTT-C/stargazers"><img src="https://img.shields.io/github/stars/LiamBindle/MQTT-C.svg?style=social&label=Star" style="margin-left:5em"></a>
|
||||
<a href="https://github.com/LiamBindle/MQTT-C/network/members"><img src="https://img.shields.io/github/forks/LiamBindle/MQTT-C.svg?style=social&label=Fork"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img width="70%" src="docs/mqtt-c-logo.png"><br>
|
||||
<a href="https://liambindle.ca/MQTT-C"><img src="https://img.shields.io/badge/docs-passing-brightgreen.svg"></a>
|
||||
<a href="https://github.com/LiamBindle/MQTT-C/issues"><img src="https://img.shields.io/badge/Maintained%3F-yes-green.svg"></a>
|
||||
<a href="https://GitHub.com/LiamBindle/MQTT-C/issues/"><img src="https://img.shields.io/github/issues/LiamBindle/MQTT-C.svg"></a>
|
||||
<a href="https://github.com/LiamBindle/MQTT-C/issues"><img src="https://img.shields.io/github/issues-closed/LiamBindle/MQTT-C.svg"></a>
|
||||
<a href="https://github.com/LiamBindle/MQTT-C/blob/master/LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg"></a>
|
||||
</p>
|
||||
|
||||
#
|
||||
|
||||
MQTT-C is an [MQTT v3.1.1](http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html)
|
||||
client written in C. MQTT is a lightweight publisher-subscriber-based messaging protocol that is
|
||||
commonly used in IoT and networking applications where high-latency and low data-rate links
|
||||
are expected. The purpose of MQTT-C is to provide a **portable** MQTT client, **written in C**,
|
||||
for embedded systems and PC's alike. MQTT-C does this by providing a transparent Platform
|
||||
Abstraction Layer (PAL) which makes porting to new platforms easy. MQTT-C is completely
|
||||
thread-safe but can also run perfectly fine on single-threaded systems making MQTT-C
|
||||
well-suited for embedded systems and microcontrollers. Finally, MQTT-C is small; there are only
|
||||
two source files totalling less than 2000 lines.
|
||||
|
||||
#### A note from the author
|
||||
It's been great to hear about all the places MQTT-C is being used! Please don't hesitate
|
||||
to get in touch with me or submit issues on GitHub!
|
||||
|
||||
## Getting Started
|
||||
To use MQTT-C you first instantiate a `struct mqtt_client` and initialize it by calling
|
||||
@ref mqtt_init.
|
||||
```c
|
||||
struct mqtt_client client; /* instantiate the client */
|
||||
mqtt_init(&client, ...); /* initialize the client */
|
||||
```
|
||||
Once your client is initialized you need to connect to an MQTT broker.
|
||||
```c
|
||||
mqtt_connect(&client, ...); /* send a connection request to the broker. */
|
||||
```
|
||||
At this point the client is ready to use! For example, we can subscribe to a topic like so:
|
||||
```c
|
||||
/* subscribe to "toaster/temperature" with a max QoS level of 0 */
|
||||
mqtt_subscribe(&client, "toaster/temperature", 0);
|
||||
```
|
||||
And we can publish to a topic like so:
|
||||
```c
|
||||
/* publish coffee temperature with a QoS level of 1 */
|
||||
int temperature = 67;
|
||||
mqtt_publish(&client, "coffee/temperature", &temperature, sizeof(int), MQTT_PUBLISH_QOS_1);
|
||||
```
|
||||
Those are the basics! From here the [examples](https://github.com/LiamBindle/MQTT-C/tree/master/examples) and [API documentation](https://liambindle.ca/MQTT-C/group__api.html) are good places to get started.
|
||||
|
||||
## Building
|
||||
There are **only two source files** that need to be built, `mqtt.c` and `mqtt_pal.c`.
|
||||
These files are ANSI C (C89) compatible, and should compile with any C compiler.
|
||||
|
||||
Then, simply <code>\#include <mqtt.h></code>.
|
||||
|
||||
Alternatively, you can build MQTT-C with CMake or the provided Makefile. These are provided for convenience.
|
||||
|
||||
## Documentation
|
||||
Pre-built documentation can be found here: [https://liambindle.ca/MQTT-C](https://liambindle.ca/MQTT-C). Be sure to check out the [examples](https://github.com/LiamBindle/MQTT-C/tree/master/examples) too.
|
||||
|
||||
The @ref api documentation contains all the documentation application programmers should need.
|
||||
The @ref pal documentation contains everything you should need to port MQTT-C to a new platform,
|
||||
and the other modules contain documentation for MQTT-C developers.
|
||||
|
||||
## Testing and Building the Tests
|
||||
The MQTT-C unit tests use the [cmocka unit testing framework](https://cmocka.org/).
|
||||
Therefore, [cmocka](https://cmocka.org/) *must* be installed on your machine to build and run
|
||||
the unit tests. For convenience, a simple `"makefile"` is included to build the unit tests and
|
||||
examples on UNIX-like machines. The unit tests and examples can be built as follows:
|
||||
```bash
|
||||
$ make all
|
||||
```
|
||||
The unit tests and examples will be built in the `"bin/"` directory. The unit tests can be run
|
||||
like so:
|
||||
```bash
|
||||
$ ./bin/tests [address [port]]
|
||||
```
|
||||
Note that the \c address and \c port arguments are both optional to specify the location of the
|
||||
MQTT broker that is to be used for the tests. If no \c address is given then the
|
||||
[Mosquitto MQTT Test Server](https://test.mosquitto.org/) will be used. If no \c port is given,
|
||||
port 1883 will be used.
|
||||
|
||||
## Portability
|
||||
MQTT-C provides a transparent platform abstraction layer (PAL) in `mqtt_pal.h` and `mqtt_pal.c`.
|
||||
These files declare and implement the types and calls that MQTT-C requires. Refer to
|
||||
@ref pal for the complete documentation of the PAL.
|
||||
|
||||
## Contributing
|
||||
Please feel free to submit issues and pull-requests [here](https://github.com/LiamBindle/MQTT-C).
|
||||
When submitting a pull-request please ensure you have *fully documented* your changes and
|
||||
added the appropriate unit tests.
|
||||
|
||||
|
||||
## License
|
||||
This project is licensed under the [MIT License](https://opensource.org/licenses/MIT). See the
|
||||
`"LICENSE"` file for more details.
|
||||
|
||||
## Authors
|
||||
MQTT-C was initially developed as a CMPT 434 (Winter Term, 2018) final project at the University of
|
||||
Saskatchewan by:
|
||||
- **Liam Bindle**
|
||||
- **Demilade Adeoye**
|
||||
|
|
@ -1,156 +0,0 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/bio_sockets.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function that would be called whenever a PUBLISH is received.
|
||||
*
|
||||
* @note This function is not used in this example.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, BIO* sockfd, pthread_t *client_daemon);
|
||||
|
||||
/**
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
|
||||
/* Load OpenSSL */
|
||||
SSL_load_error_strings();
|
||||
ERR_load_BIO_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
|
||||
/* get address (argv[1] if present) */
|
||||
if (argc > 1) {
|
||||
addr = argv[1];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
port = argv[2];
|
||||
} else {
|
||||
port = "1883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 3) {
|
||||
topic = argv[3];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* open the non-blocking TCP socket (connecting to the broker) */
|
||||
BIO* sockfd = open_nb_socket(addr, port);
|
||||
|
||||
if (sockfd == NULL) {
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
|
||||
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
|
||||
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
|
||||
mqtt_connect(&client, "publishing_client", NULL, NULL, 0, NULL, NULL, 0, 400);
|
||||
|
||||
/* check that we don't have any errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s is ready to begin publishing the time.\n", argv[0]);
|
||||
printf("Press ENTER to publish the current time.\n");
|
||||
printf("Press CTRL-D (or any other key) to exit.\n\n");
|
||||
while(fgetc(stdin) == '\n') {
|
||||
/* get the current time */
|
||||
time_t timer;
|
||||
time(&timer);
|
||||
struct tm* tm_info = localtime(&timer);
|
||||
char timebuf[26];
|
||||
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
/* print a message */
|
||||
char application_message[256];
|
||||
snprintf(application_message, sizeof(application_message), "The time is %s", timebuf);
|
||||
printf("%s published : \"%s\"", argv[0], application_message);
|
||||
|
||||
/* publish the time */
|
||||
mqtt_publish(&client, topic, application_message, strlen(application_message) + 1, MQTT_PUBLISH_QOS_2);
|
||||
|
||||
/* check for errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, &client_daemon);
|
||||
}
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
|
||||
}
|
||||
|
||||
void exit_example(int status, BIO* sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (sockfd != NULL) BIO_free_all(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* not used in this example */
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,163 +0,0 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/mbedtls_sockets.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function that would be called whenever a PUBLISH is received.
|
||||
*
|
||||
* @note This function is not used in this example.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, mqtt_pal_socket_handle sockfd, pthread_t *client_daemon);
|
||||
|
||||
/**
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
const char* ca_file;
|
||||
|
||||
struct mbedtls_context ctx;
|
||||
mqtt_pal_socket_handle sockfd;
|
||||
|
||||
if (argc > 1) {
|
||||
ca_file = argv[1];
|
||||
} else {
|
||||
printf("error: path to the CA certificate to use\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* get address (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
addr = argv[2];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[3] if present) */
|
||||
if (argc > 3) {
|
||||
port = argv[3];
|
||||
} else {
|
||||
port = "8883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 4) {
|
||||
topic = argv[4];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* open the non-blocking TCP socket (connecting to the broker) */
|
||||
open_nb_socket(&ctx, addr, port, ca_file);
|
||||
sockfd = &ctx.ssl_ctx;
|
||||
|
||||
if (sockfd == NULL) {
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
|
||||
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
|
||||
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
|
||||
mqtt_connect(&client, "publishing_client", NULL, NULL, 0, NULL, NULL, 0, 400);
|
||||
|
||||
/* check that we don't have any errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s is ready to begin publishing the time.\n", argv[0]);
|
||||
printf("Press ENTER to publish the current time.\n");
|
||||
printf("Press CTRL-D (or any other key) to exit.\n\n");
|
||||
while(fgetc(stdin) == '\n') {
|
||||
/* get the current time */
|
||||
time_t timer;
|
||||
time(&timer);
|
||||
struct tm* tm_info = localtime(&timer);
|
||||
char timebuf[26];
|
||||
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
/* print a message */
|
||||
char application_message[256];
|
||||
snprintf(application_message, sizeof(application_message), "The time is %s", timebuf);
|
||||
printf("%s published : \"%s\"", argv[0], application_message);
|
||||
|
||||
/* publish the time */
|
||||
mqtt_publish(&client, topic, application_message, strlen(application_message) + 1, MQTT_PUBLISH_QOS_2);
|
||||
|
||||
/* check for errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, &client_daemon);
|
||||
}
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
|
||||
}
|
||||
|
||||
void exit_example(int status, mqtt_pal_socket_handle sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
mbedtls_ssl_free(sockfd);
|
||||
/* XXX free the rest of contexts */
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* not used in this example */
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/openssl_sockets.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function that would be called whenever a PUBLISH is received.
|
||||
*
|
||||
* @note This function is not used in this example.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, BIO* sockfd, pthread_t *client_daemon);
|
||||
|
||||
/**
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
const char* ca_file;
|
||||
|
||||
/* Load OpenSSL */
|
||||
SSL_load_error_strings();
|
||||
ERR_load_BIO_strings();
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_library_init();
|
||||
|
||||
SSL_CTX* ssl_ctx;
|
||||
BIO* sockfd;
|
||||
|
||||
if (argc > 1) {
|
||||
ca_file = argv[1];
|
||||
} else {
|
||||
printf("error: path to the CA certificate to use\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* get address (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
addr = argv[2];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[3] if present) */
|
||||
if (argc > 3) {
|
||||
port = argv[3];
|
||||
} else {
|
||||
port = "8883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 4) {
|
||||
topic = argv[4];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* open the non-blocking TCP socket (connecting to the broker) */
|
||||
open_nb_socket(&sockfd, &ssl_ctx, addr, port, ca_file, NULL);
|
||||
|
||||
if (sockfd == NULL) {
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
|
||||
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
|
||||
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
|
||||
mqtt_connect(&client, "publishing_client", NULL, NULL, 0, NULL, NULL, 0, 400);
|
||||
|
||||
/* check that we don't have any errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s is ready to begin publishing the time.\n", argv[0]);
|
||||
printf("Press ENTER to publish the current time.\n");
|
||||
printf("Press CTRL-D (or any other key) to exit.\n\n");
|
||||
while(fgetc(stdin) == '\n') {
|
||||
/* get the current time */
|
||||
time_t timer;
|
||||
time(&timer);
|
||||
struct tm* tm_info = localtime(&timer);
|
||||
char timebuf[26];
|
||||
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
/* print a message */
|
||||
char application_message[256];
|
||||
snprintf(application_message, sizeof(application_message), "The time is %s", timebuf);
|
||||
printf("%s published : \"%s\"", argv[0], application_message);
|
||||
|
||||
/* publish the time */
|
||||
mqtt_publish(&client, topic, application_message, strlen(application_message) + 1, MQTT_PUBLISH_QOS_2);
|
||||
|
||||
/* check for errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, &client_daemon);
|
||||
}
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
|
||||
}
|
||||
|
||||
void exit_example(int status, BIO* sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (sockfd != NULL) BIO_free_all(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* not used in this example */
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,199 +0,0 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* A simple subscriber program that performs automatic reconnections.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/posix_sockets.h"
|
||||
|
||||
/**
|
||||
* @brief A structure that I will use to keep track of some data needed
|
||||
* to setup the connection to the broker.
|
||||
*
|
||||
* An instance of this struct will be created in my \c main(). Then, whenever
|
||||
* \ref reconnect_client is called, this instance will be passed.
|
||||
*/
|
||||
struct reconnect_state_t {
|
||||
const char* hostname;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
uint8_t* sendbuf;
|
||||
size_t sendbufsz;
|
||||
uint8_t* recvbuf;
|
||||
size_t recvbufsz;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief My reconnect callback. It will reestablish the connection whenever
|
||||
* an error occurs.
|
||||
*/
|
||||
void reconnect_client(struct mqtt_client* client, void **reconnect_state_vptr);
|
||||
|
||||
/**
|
||||
* @brief The function will be called whenever a PUBLISH message is received.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon);
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
|
||||
/* get address (argv[1] if present) */
|
||||
if (argc > 1) {
|
||||
addr = argv[1];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
port = argv[2];
|
||||
} else {
|
||||
port = "1883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 3) {
|
||||
topic = argv[3];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* build the reconnect_state structure which will be passed to reconnect */
|
||||
struct reconnect_state_t reconnect_state;
|
||||
reconnect_state.hostname = addr;
|
||||
reconnect_state.port = port;
|
||||
reconnect_state.topic = topic;
|
||||
uint8_t sendbuf[2048];
|
||||
uint8_t recvbuf[1024];
|
||||
reconnect_state.sendbuf = sendbuf;
|
||||
reconnect_state.sendbufsz = sizeof(sendbuf);
|
||||
reconnect_state.recvbuf = recvbuf;
|
||||
reconnect_state.recvbufsz = sizeof(recvbuf);
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
|
||||
mqtt_init_reconnect(&client,
|
||||
reconnect_client, &reconnect_state,
|
||||
publish_callback
|
||||
);
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, -1, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s listening for '%s' messages.\n", argv[0], topic);
|
||||
printf("Press ENTER to inject an error.\n");
|
||||
printf("Press CTRL-D to exit.\n\n");
|
||||
|
||||
/* block */
|
||||
while(fgetc(stdin) != EOF) {
|
||||
printf("Injecting error: \"MQTT_ERROR_SOCKET_ERROR\"\n");
|
||||
client.error = MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, client.socketfd, &client_daemon);
|
||||
}
|
||||
|
||||
void reconnect_client(struct mqtt_client* client, void **reconnect_state_vptr)
|
||||
{
|
||||
struct reconnect_state_t *reconnect_state = *((struct reconnect_state_t**) reconnect_state_vptr);
|
||||
|
||||
/* Close the clients socket if this isn't the initial reconnect call */
|
||||
if (client->error != MQTT_ERROR_INITIAL_RECONNECT) {
|
||||
close(client->socketfd);
|
||||
}
|
||||
|
||||
/* Perform error handling here. */
|
||||
if (client->error != MQTT_ERROR_INITIAL_RECONNECT) {
|
||||
printf("reconnect_client: called while client was in error state \"%s\"\n",
|
||||
mqtt_error_str(client->error)
|
||||
);
|
||||
}
|
||||
|
||||
/* Open a new socket. */
|
||||
int sockfd = open_nb_socket(reconnect_state->hostname, reconnect_state->port);
|
||||
if (sockfd == -1) {
|
||||
perror("Failed to open socket: ");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* Reinitialize the client. */
|
||||
mqtt_reinit(client, sockfd,
|
||||
reconnect_state->sendbuf, reconnect_state->sendbufsz,
|
||||
reconnect_state->recvbuf, reconnect_state->recvbufsz
|
||||
);
|
||||
|
||||
/* Create an anonymous session */
|
||||
const char* client_id = NULL;
|
||||
/* Ensure we have a clean session */
|
||||
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
|
||||
/* Send connection request to the broker. */
|
||||
mqtt_connect(client, client_id, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
|
||||
|
||||
/* Subscribe to the topic. */
|
||||
mqtt_subscribe(client, reconnect_state->topic, 0);
|
||||
}
|
||||
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (sockfd != -1) close(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* note that published->topic_name is NOT null-terminated (here we'll change it to a c-string) */
|
||||
char* topic_name = (char*) malloc(published->topic_name_size + 1);
|
||||
memcpy(topic_name, published->topic_name, published->topic_name_size);
|
||||
topic_name[published->topic_name_size] = '\0';
|
||||
|
||||
printf("Received publish('%s'): %s\n", topic_name, (const char*) published->application_message);
|
||||
|
||||
free(topic_name);
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,157 +0,0 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/posix_sockets.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function that would be called whenever a PUBLISH is received.
|
||||
*
|
||||
* @note This function is not used in this example.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon);
|
||||
|
||||
/**
|
||||
* A simple program to that publishes the current time whenever ENTER is pressed.
|
||||
*/
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
|
||||
/* get address (argv[1] if present) */
|
||||
if (argc > 1) {
|
||||
addr = argv[1];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
port = argv[2];
|
||||
} else {
|
||||
port = "1883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 3) {
|
||||
topic = argv[3];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* open the non-blocking TCP socket (connecting to the broker) */
|
||||
int sockfd = open_nb_socket(addr, port);
|
||||
|
||||
if (sockfd == -1) {
|
||||
perror("Failed to open socket: ");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
|
||||
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
|
||||
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
|
||||
/* Create an anonymous session */
|
||||
const char* client_id = NULL;
|
||||
/* Ensure we have a clean session */
|
||||
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
|
||||
/* Send connection request to the broker. */
|
||||
mqtt_connect(&client, client_id, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
|
||||
|
||||
/* check that we don't have any errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s is ready to begin publishing the time.\n", argv[0]);
|
||||
printf("Press ENTER to publish the current time.\n");
|
||||
printf("Press CTRL-D (or any other key) to exit.\n\n");
|
||||
while(fgetc(stdin) == '\n') {
|
||||
/* get the current time */
|
||||
time_t timer;
|
||||
time(&timer);
|
||||
struct tm* tm_info = localtime(&timer);
|
||||
char timebuf[26];
|
||||
strftime(timebuf, 26, "%Y-%m-%d %H:%M:%S", tm_info);
|
||||
|
||||
/* print a message */
|
||||
char application_message[256];
|
||||
snprintf(application_message, sizeof(application_message), "The time is %s", timebuf);
|
||||
printf("%s published : \"%s\"", argv[0], application_message);
|
||||
|
||||
/* publish the time */
|
||||
mqtt_publish(&client, topic, application_message, strlen(application_message) + 1, MQTT_PUBLISH_QOS_0);
|
||||
|
||||
/* check for errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, &client_daemon);
|
||||
}
|
||||
}
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
|
||||
}
|
||||
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (sockfd != -1) close(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* not used in this example */
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
|
||||
/**
|
||||
* @file
|
||||
* A simple program that subscribes to a topic.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <mqtt.h>
|
||||
#include "templates/posix_sockets.h"
|
||||
|
||||
|
||||
/**
|
||||
* @brief The function will be called whenever a PUBLISH message is received.
|
||||
*/
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published);
|
||||
|
||||
/**
|
||||
* @brief The client's refresher. This function triggers back-end routines to
|
||||
* handle ingress/egress traffic to the broker.
|
||||
*
|
||||
* @note All this function needs to do is call \ref __mqtt_recv and
|
||||
* \ref __mqtt_send every so often. I've picked 100 ms meaning that
|
||||
* client ingress/egress traffic will be handled every 100 ms.
|
||||
*/
|
||||
void* client_refresher(void* client);
|
||||
|
||||
/**
|
||||
* @brief Safelty closes the \p sockfd and cancels the \p client_daemon before \c exit.
|
||||
*/
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon);
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
const char* addr;
|
||||
const char* port;
|
||||
const char* topic;
|
||||
|
||||
/* get address (argv[1] if present) */
|
||||
if (argc > 1) {
|
||||
addr = argv[1];
|
||||
} else {
|
||||
addr = "test.mosquitto.org";
|
||||
}
|
||||
|
||||
/* get port number (argv[2] if present) */
|
||||
if (argc > 2) {
|
||||
port = argv[2];
|
||||
} else {
|
||||
port = "1883";
|
||||
}
|
||||
|
||||
/* get the topic name to publish */
|
||||
if (argc > 3) {
|
||||
topic = argv[3];
|
||||
} else {
|
||||
topic = "datetime";
|
||||
}
|
||||
|
||||
/* open the non-blocking TCP socket (connecting to the broker) */
|
||||
int sockfd = open_nb_socket(addr, port);
|
||||
|
||||
if (sockfd == -1) {
|
||||
perror("Failed to open socket: ");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* setup a client */
|
||||
struct mqtt_client client;
|
||||
uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */
|
||||
uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */
|
||||
mqtt_init(&client, sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback);
|
||||
/* Create an anonymous session */
|
||||
const char* client_id = NULL;
|
||||
/* Ensure we have a clean session */
|
||||
uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;
|
||||
/* Send connection request to the broker. */
|
||||
mqtt_connect(&client, client_id, NULL, NULL, 0, NULL, NULL, connect_flags, 400);
|
||||
|
||||
/* check that we don't have any errors */
|
||||
if (client.error != MQTT_OK) {
|
||||
fprintf(stderr, "error: %s\n", mqtt_error_str(client.error));
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
}
|
||||
|
||||
/* start a thread to refresh the client (handle egress and ingree client traffic) */
|
||||
pthread_t client_daemon;
|
||||
if(pthread_create(&client_daemon, NULL, client_refresher, &client)) {
|
||||
fprintf(stderr, "Failed to start client daemon.\n");
|
||||
exit_example(EXIT_FAILURE, sockfd, NULL);
|
||||
|
||||
}
|
||||
|
||||
/* subscribe */
|
||||
mqtt_subscribe(&client, topic, 0);
|
||||
|
||||
/* start publishing the time */
|
||||
printf("%s listening for '%s' messages.\n", argv[0], topic);
|
||||
printf("Press CTRL-D to exit.\n\n");
|
||||
|
||||
/* block */
|
||||
while(fgetc(stdin) != EOF);
|
||||
|
||||
/* disconnect */
|
||||
printf("\n%s disconnecting from %s\n", argv[0], addr);
|
||||
sleep(1);
|
||||
|
||||
/* exit */
|
||||
exit_example(EXIT_SUCCESS, sockfd, &client_daemon);
|
||||
}
|
||||
|
||||
void exit_example(int status, int sockfd, pthread_t *client_daemon)
|
||||
{
|
||||
if (sockfd != -1) close(sockfd);
|
||||
if (client_daemon != NULL) pthread_cancel(*client_daemon);
|
||||
exit(status);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void publish_callback(void** unused, struct mqtt_response_publish *published)
|
||||
{
|
||||
/* note that published->topic_name is NOT null-terminated (here we'll change it to a c-string) */
|
||||
char* topic_name = (char*) malloc(published->topic_name_size + 1);
|
||||
memcpy(topic_name, published->topic_name, published->topic_name_size);
|
||||
topic_name[published->topic_name_size] = '\0';
|
||||
|
||||
printf("Received publish('%s'): %s\n", topic_name, (const char*) published->application_message);
|
||||
|
||||
free(topic_name);
|
||||
}
|
||||
|
||||
void* client_refresher(void* client)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
mqtt_sync((struct mqtt_client*) client);
|
||||
usleep(100000U);
|
||||
}
|
||||
return NULL;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
#ifndef __BIO_SOCKET_TEMPLATE_H__
|
||||
#define __BIO_SOCKET_TEMPLATE_H__
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
/*
|
||||
A template for opening a non-blocking BIO socket.
|
||||
*/
|
||||
BIO* open_nb_socket(const char* addr, const char* port) {
|
||||
BIO* bio = BIO_new_connect(addr);
|
||||
BIO_set_nbio(bio, 1);
|
||||
BIO_set_conn_port(bio, port);
|
||||
|
||||
/* timeout after 10 seconds */
|
||||
int start_time = time(NULL);
|
||||
while(BIO_do_connect(bio) == 0 && (int)time(NULL) - start_time < 10);
|
||||
|
||||
if (BIO_do_connect(bio) <= 0) {
|
||||
fprintf(stderr, "Failed to open socket: BIO_do_connect returned <= 0\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return bio;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,145 +0,0 @@
|
|||
#ifndef __MBEDTLS_SOCKET_TEMPLATE_H__
|
||||
#define __MBEDTLS_SOCKET_TEMPLATE_H__
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <mbedtls/error.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/net_sockets.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
#if !defined(MBEDTLS_NET_POLL_READ)
|
||||
/* compat for older mbedtls */
|
||||
#define MBEDTLS_NET_POLL_READ 1
|
||||
#define MBEDTLS_NET_POLL_WRITE 1
|
||||
|
||||
int
|
||||
mbedtls_net_poll(mbedtls_net_context * ctx, uint32_t rw, uint32_t timeout)
|
||||
{
|
||||
/* XXX this is not ideal but good enough for an example */
|
||||
usleep(300);
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct mbedtls_context {
|
||||
mbedtls_net_context net_ctx;
|
||||
mbedtls_ssl_context ssl_ctx;
|
||||
mbedtls_ssl_config ssl_conf;
|
||||
mbedtls_x509_crt ca_crt;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
};
|
||||
|
||||
void failed(const char *fn, int rv) {
|
||||
char buf[100];
|
||||
mbedtls_strerror(rv, buf, sizeof(buf));
|
||||
printf("%s failed with %x (%s)\n", fn, -rv, buf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void cert_verify_failed(uint32_t rv) {
|
||||
char buf[512];
|
||||
mbedtls_x509_crt_verify_info(buf, sizeof(buf), "\t", rv);
|
||||
printf("Certificate verification failed (%0" PRIx32 ")\n%s\n", rv, buf);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
A template for opening a non-blocking mbed TLS connection.
|
||||
*/
|
||||
void open_nb_socket(struct mbedtls_context *ctx,
|
||||
const char *hostname,
|
||||
const char *port,
|
||||
const char *ca_file) {
|
||||
const unsigned char *additional = (const unsigned char *)"MQTT-C";
|
||||
size_t additional_len = 6;
|
||||
int rv;
|
||||
|
||||
mbedtls_net_context *net_ctx = &ctx->net_ctx;
|
||||
mbedtls_ssl_context *ssl_ctx = &ctx->ssl_ctx;
|
||||
mbedtls_ssl_config *ssl_conf = &ctx->ssl_conf;
|
||||
mbedtls_x509_crt *ca_crt = &ctx->ca_crt;
|
||||
mbedtls_entropy_context *entropy = &ctx->entropy;
|
||||
mbedtls_ctr_drbg_context *ctr_drbg = &ctx->ctr_drbg;
|
||||
|
||||
mbedtls_entropy_init(entropy);
|
||||
mbedtls_ctr_drbg_init(ctr_drbg);
|
||||
rv = mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy,
|
||||
additional, additional_len);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_ctr_drbg_seed", rv);
|
||||
}
|
||||
|
||||
mbedtls_x509_crt_init(ca_crt);
|
||||
rv = mbedtls_x509_crt_parse_file(ca_crt, ca_file);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_x509_crt_parse_file", rv);
|
||||
}
|
||||
|
||||
mbedtls_ssl_config_init(ssl_conf);
|
||||
rv = mbedtls_ssl_config_defaults(ssl_conf, MBEDTLS_SSL_IS_CLIENT,
|
||||
MBEDTLS_SSL_TRANSPORT_STREAM,
|
||||
MBEDTLS_SSL_PRESET_DEFAULT);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_ssl_config_defaults", rv);
|
||||
}
|
||||
mbedtls_ssl_conf_ca_chain(ssl_conf, ca_crt, NULL);
|
||||
mbedtls_ssl_conf_authmode(ssl_conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
|
||||
mbedtls_ssl_conf_rng(ssl_conf, mbedtls_ctr_drbg_random, ctr_drbg);
|
||||
|
||||
mbedtls_net_init(net_ctx);
|
||||
rv = mbedtls_net_connect(net_ctx, hostname, port, MBEDTLS_NET_PROTO_TCP);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_net_connect", rv);
|
||||
}
|
||||
rv = mbedtls_net_set_nonblock(net_ctx);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_net_set_nonblock", rv);
|
||||
}
|
||||
|
||||
mbedtls_ssl_init(ssl_ctx);
|
||||
rv = mbedtls_ssl_setup(ssl_ctx, ssl_conf);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_ssl_setup", rv);
|
||||
}
|
||||
rv = mbedtls_ssl_set_hostname(ssl_ctx, hostname);
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_ssl_set_hostname", rv);
|
||||
}
|
||||
mbedtls_ssl_set_bio(ssl_ctx, net_ctx,
|
||||
mbedtls_net_send, mbedtls_net_recv, NULL);
|
||||
|
||||
for (;;) {
|
||||
rv = mbedtls_ssl_handshake(ssl_ctx);
|
||||
uint32_t want = 0;
|
||||
if (rv == MBEDTLS_ERR_SSL_WANT_READ) {
|
||||
want |= MBEDTLS_NET_POLL_READ;
|
||||
} else if (rv == MBEDTLS_ERR_SSL_WANT_WRITE) {
|
||||
want |= MBEDTLS_NET_POLL_WRITE;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
rv = mbedtls_net_poll(net_ctx, want, -1);
|
||||
if (rv < 0) {
|
||||
failed("mbedtls_net_poll", rv);
|
||||
}
|
||||
}
|
||||
if (rv != 0) {
|
||||
failed("mbedtls_ssl_handshake", rv);
|
||||
}
|
||||
uint32_t result = mbedtls_ssl_get_verify_result(ssl_ctx);
|
||||
if (result != 0) {
|
||||
if (result == (uint32_t)-1) {
|
||||
failed("mbedtls_ssl_get_verify_result", result);
|
||||
} else {
|
||||
cert_verify_failed(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,52 +0,0 @@
|
|||
#ifndef __OPENSSL_SOCKET_TEMPLATE_H__
|
||||
#define __OPENSSL_SOCKET_TEMPLATE_H__
|
||||
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
/*
|
||||
A template for opening a non-blocking OpenSSL connection.
|
||||
*/
|
||||
void open_nb_socket(BIO** bio, SSL_CTX** ssl_ctx, const char* addr, const char* port, const char* ca_file, const char* ca_path) {
|
||||
*ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
SSL* ssl;
|
||||
|
||||
/* load certificate */
|
||||
if (!SSL_CTX_load_verify_locations(*ssl_ctx, ca_file, ca_path)) {
|
||||
printf("error: failed to load certificate\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* open BIO socket */
|
||||
*bio = BIO_new_ssl_connect(*ssl_ctx);
|
||||
BIO_get_ssl(*bio, &ssl);
|
||||
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
|
||||
BIO_set_conn_hostname(*bio, addr);
|
||||
BIO_set_nbio(*bio, 1);
|
||||
BIO_set_conn_port(*bio, port);
|
||||
|
||||
/* wait for connect with 10 second timeout */
|
||||
int start_time = time(NULL);
|
||||
int do_connect_rv = BIO_do_connect(*bio);
|
||||
while(do_connect_rv <= 0 && BIO_should_retry(*bio) && (int)time(NULL) - start_time < 10) {
|
||||
do_connect_rv = BIO_do_connect(*bio);
|
||||
}
|
||||
if (do_connect_rv <= 0) {
|
||||
printf("error: %s\n", ERR_reason_error_string(ERR_get_error()));
|
||||
BIO_free_all(*bio);
|
||||
SSL_CTX_free(*ssl_ctx);
|
||||
*bio = NULL;
|
||||
*ssl_ctx=NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
/* verify certificate */
|
||||
if (SSL_get_verify_result(ssl) != X509_V_OK) {
|
||||
/* Handle the failed verification */
|
||||
printf("error: x509 certificate verification failed\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -1,59 +0,0 @@
|
|||
#ifndef __POSIX_SOCKET_TEMPLATE_H__
|
||||
#define __POSIX_SOCKET_TEMPLATE_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#if !defined(WIN32)
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
|
||||
/*
|
||||
A template for opening a non-blocking POSIX socket.
|
||||
*/
|
||||
int open_nb_socket(const char* addr, const char* port) {
|
||||
struct addrinfo hints = {0};
|
||||
|
||||
hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6 */
|
||||
hints.ai_socktype = SOCK_STREAM; /* Must be TCP */
|
||||
int sockfd = -1;
|
||||
int rv;
|
||||
struct addrinfo *p, *servinfo;
|
||||
|
||||
/* get address information */
|
||||
rv = getaddrinfo(addr, port, &hints, &servinfo);
|
||||
if(rv != 0) {
|
||||
fprintf(stderr, "Failed to open socket (getaddrinfo): %s\n", gai_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* open the first possible socket */
|
||||
for(p = servinfo; p != NULL; p = p->ai_next) {
|
||||
sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
|
||||
if (sockfd == -1) continue;
|
||||
|
||||
/* connect to server */
|
||||
rv = connect(sockfd, servinfo->ai_addr, servinfo->ai_addrlen);
|
||||
if(rv == -1) continue;
|
||||
break;
|
||||
}
|
||||
|
||||
/* free servinfo */
|
||||
freeaddrinfo(servinfo);
|
||||
|
||||
/* make non-blocking */
|
||||
#if !defined(WIN32)
|
||||
if (sockfd != -1) fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL) | O_NONBLOCK);
|
||||
#else
|
||||
if (sockfd != INVALID_SOCKET) {
|
||||
int iMode = 1;
|
||||
ioctlsocket(sockfd, FIONBIO, &iMode);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* return the new socket fd */
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,157 +0,0 @@
|
|||
#ifndef __MQTT_PAL_H__
|
||||
#define __MQTT_PAL_H__
|
||||
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright(c) 2018 Liam Bindle
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Includes/supports the types/calls required by the MQTT-C client.
|
||||
*
|
||||
* @note This is the \em only file included in mqtt.h, and mqtt.c. It is therefore
|
||||
* responsible for including/supporting all the required types and calls.
|
||||
*
|
||||
* @defgroup pal Platform abstraction layer
|
||||
* @brief Documentation of the types and calls required to port MQTT-C to a new platform.
|
||||
*
|
||||
* mqtt_pal.h is the \em only header file included in mqtt.c. Therefore, to port MQTT-C to a
|
||||
* new platform the following types, functions, constants, and macros must be defined in
|
||||
* mqtt_pal.h:
|
||||
* - Types:
|
||||
* - \c size_t, \c ssize_t
|
||||
* - \c uint8_t, \c uint16_t, \c uint32_t
|
||||
* - \c va_list
|
||||
* - \c mqtt_pal_time_t : return type of \c MQTT_PAL_TIME()
|
||||
* - \c mqtt_pal_mutex_t : type of the argument that is passed to \c MQTT_PAL_MUTEX_LOCK and
|
||||
* \c MQTT_PAL_MUTEX_RELEASE
|
||||
* - Functions:
|
||||
* - \c memcpy, \c strlen
|
||||
* - \c va_start, \c va_arg, \c va_end
|
||||
* - Constants:
|
||||
* - \c INT_MIN
|
||||
*
|
||||
* Additionally, three macro's are required:
|
||||
* - \c MQTT_PAL_HTONS(s) : host-to-network endian conversion for uint16_t.
|
||||
* - \c MQTT_PAL_NTOHS(s) : network-to-host endian conversion for uint16_t.
|
||||
* - \c MQTT_PAL_TIME() : returns [type: \c mqtt_pal_time_t] current time in seconds.
|
||||
* - \c MQTT_PAL_MUTEX_LOCK(mtx_pointer) : macro that locks the mutex pointed to by \c mtx_pointer.
|
||||
* - \c MQTT_PAL_MUTEX_RELEASE(mtx_pointer) : macro that unlocks the mutex pointed to by
|
||||
* \c mtx_pointer.
|
||||
*
|
||||
* Lastly, \ref mqtt_pal_sendall and \ref mqtt_pal_recvall, must be implemented in mqtt_pal.c
|
||||
* for sending and receiving data using the platforms socket calls.
|
||||
*/
|
||||
|
||||
|
||||
/* UNIX-like platform support */
|
||||
#if defined(__unix__) || defined(__APPLE__)
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#define MQTT_PAL_HTONS(s) htons(s)
|
||||
#define MQTT_PAL_NTOHS(s) ntohs(s)
|
||||
|
||||
#define MQTT_PAL_TIME() time(NULL)
|
||||
|
||||
typedef time_t mqtt_pal_time_t;
|
||||
typedef pthread_mutex_t mqtt_pal_mutex_t;
|
||||
|
||||
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) pthread_mutex_init(mtx_ptr, NULL)
|
||||
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) pthread_mutex_lock(mtx_ptr)
|
||||
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) pthread_mutex_unlock(mtx_ptr)
|
||||
|
||||
#ifndef MQTT_USE_CUSTOM_SOCKET_HANDLE
|
||||
#ifdef MQTT_USE_MBEDTLS
|
||||
struct mbedtls_ssl_context;
|
||||
typedef struct mbedtls_ssl_context *mqtt_pal_socket_handle;
|
||||
#elif defined(MQTT_USE_BIO)
|
||||
#include <openssl/bio.h>
|
||||
typedef BIO* mqtt_pal_socket_handle;
|
||||
#else
|
||||
typedef int mqtt_pal_socket_handle;
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(_MSC_VER)
|
||||
#include <limits.h>
|
||||
#include <windows.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include <winsock2.h>
|
||||
|
||||
typedef SSIZE_T ssize_t;
|
||||
#define MQTT_PAL_HTONS(s) htons(s)
|
||||
#define MQTT_PAL_NTOHS(s) ntohs(s)
|
||||
|
||||
#define MQTT_PAL_TIME() time(NULL)
|
||||
|
||||
typedef time_t mqtt_pal_time_t;
|
||||
typedef CRITICAL_SECTION mqtt_pal_mutex_t;
|
||||
|
||||
#define MQTT_PAL_MUTEX_INIT(mtx_ptr) InitializeCriticalSection(mtx_ptr)
|
||||
#define MQTT_PAL_MUTEX_LOCK(mtx_ptr) EnterCriticalSection(mtx_ptr)
|
||||
#define MQTT_PAL_MUTEX_UNLOCK(mtx_ptr) LeaveCriticalSection(mtx_ptr)
|
||||
|
||||
|
||||
#ifndef MQTT_USE_CUSTOM_SOCKET_HANDLE
|
||||
#ifdef MQTT_USE_BIO
|
||||
#include <openssl/bio.h>
|
||||
typedef BIO* mqtt_pal_socket_handle;
|
||||
#else
|
||||
typedef SOCKET mqtt_pal_socket_handle;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Sends all the bytes in a buffer.
|
||||
* @ingroup pal
|
||||
*
|
||||
* @param[in] fd The file-descriptor (or handle) of the socket.
|
||||
* @param[in] buf A pointer to the first byte in the buffer to send.
|
||||
* @param[in] len The number of bytes to send (starting at \p buf).
|
||||
* @param[in] flags Flags which are passed to the underlying socket.
|
||||
*
|
||||
* @returns The number of bytes sent if successful, an \ref MQTTErrors otherwise.
|
||||
*/
|
||||
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags);
|
||||
|
||||
/**
|
||||
* @brief Non-blocking receive all the byte available.
|
||||
* @ingroup pal
|
||||
*
|
||||
* @param[in] fd The file-descriptor (or handle) of the socket.
|
||||
* @param[in] buf A pointer to the receive buffer.
|
||||
* @param[in] bufsz The max number of bytes that can be put into \p buf.
|
||||
* @param[in] flags Flags which are passed to the underlying socket.
|
||||
*
|
||||
* @returns The number of bytes received if successful, an \ref MQTTErrors otherwise.
|
||||
*/
|
||||
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags);
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,203 +0,0 @@
|
|||
/*
|
||||
MIT License
|
||||
|
||||
Copyright(c) 2018 Liam Bindle
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files(the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions :
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <mqtt.h>
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Implements @ref mqtt_pal_sendall and @ref mqtt_pal_recvall and
|
||||
* any platform-specific helpers you'd like.
|
||||
* @cond Doxygen_Suppress
|
||||
*/
|
||||
|
||||
|
||||
#ifdef MQTT_USE_MBEDTLS
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
|
||||
size_t sent = 0;
|
||||
while(sent < len) {
|
||||
int rv = mbedtls_ssl_write(fd, buf + sent, len - sent);
|
||||
if (rv < 0) {
|
||||
if (rv == MBEDTLS_ERR_SSL_WANT_READ ||
|
||||
rv == MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|
||||
|| rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|
||||
|| rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
|
||||
#endif
|
||||
) {
|
||||
/* should call mbedtls_ssl_writer later again */
|
||||
break;
|
||||
}
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
sent += (size_t) rv;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
|
||||
const void *const start = buf;
|
||||
int rv;
|
||||
do {
|
||||
rv = mbedtls_ssl_read(fd, buf, bufsz);
|
||||
if (rv < 0) {
|
||||
if (rv == MBEDTLS_ERR_SSL_WANT_READ ||
|
||||
rv == MBEDTLS_ERR_SSL_WANT_WRITE
|
||||
#if defined(MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS)
|
||||
|| rv == MBEDTLS_ERR_SSL_ASYNC_IN_PROGRESS
|
||||
#endif
|
||||
#if defined(MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS)
|
||||
|| rv == MBEDTLS_ERR_SSL_CRYPTO_IN_PROGRESS
|
||||
#endif
|
||||
) {
|
||||
/* should call mbedtls_ssl_read later again */
|
||||
break;
|
||||
}
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
buf = (char*)buf + rv;
|
||||
bufsz -= rv;
|
||||
} while (rv > 0);
|
||||
|
||||
return buf - start;
|
||||
}
|
||||
|
||||
#elif defined(MQTT_USE_BIO)
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/err.h>
|
||||
|
||||
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
|
||||
size_t sent = 0;
|
||||
while(sent < len) {
|
||||
int tmp = BIO_write(fd, buf + sent, len - sent);
|
||||
if (tmp > 0) {
|
||||
sent += (size_t) tmp;
|
||||
} else if (tmp <= 0 && !BIO_should_retry(fd)) {
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
|
||||
const void *const start = buf;
|
||||
int rv;
|
||||
do {
|
||||
rv = BIO_read(fd, buf, bufsz);
|
||||
if (rv > 0) {
|
||||
/* successfully read bytes from the socket */
|
||||
buf += rv;
|
||||
bufsz -= rv;
|
||||
} else if (!BIO_should_retry(fd)) {
|
||||
/* an error occurred that wasn't "nothing to read". */
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
} while (!BIO_should_read(fd));
|
||||
|
||||
return (ssize_t)(buf - start);
|
||||
}
|
||||
|
||||
#elif defined(__unix__) || defined(__APPLE__)
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
|
||||
size_t sent = 0;
|
||||
while(sent < len) {
|
||||
ssize_t tmp = send(fd, buf + sent, len - sent, flags);
|
||||
if (tmp < 1) {
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
sent += (size_t) tmp;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
|
||||
const void *const start = buf;
|
||||
ssize_t rv;
|
||||
do {
|
||||
rv = recv(fd, buf, bufsz, flags);
|
||||
if (rv > 0) {
|
||||
/* successfully read bytes from the socket */
|
||||
buf += rv;
|
||||
bufsz -= rv;
|
||||
} else if (rv < 0 && errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
/* an error occurred that wasn't "nothing to read". */
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
} while (rv > 0);
|
||||
|
||||
return buf - start;
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER)
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
ssize_t mqtt_pal_sendall(mqtt_pal_socket_handle fd, const void* buf, size_t len, int flags) {
|
||||
size_t sent = 0;
|
||||
while(sent < len) {
|
||||
ssize_t tmp = send(fd, (char*)buf + sent, len - sent, flags);
|
||||
if (tmp < 1) {
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
sent += (size_t) tmp;
|
||||
}
|
||||
return sent;
|
||||
}
|
||||
|
||||
ssize_t mqtt_pal_recvall(mqtt_pal_socket_handle fd, void* buf, size_t bufsz, int flags) {
|
||||
const char *const start = buf;
|
||||
ssize_t rv;
|
||||
do {
|
||||
rv = recv(fd, buf, bufsz, flags);
|
||||
if (rv > 0) {
|
||||
/* successfully read bytes from the socket */
|
||||
buf = (char*)buf + rv;
|
||||
bufsz -= rv;
|
||||
} else if (rv < 0) {
|
||||
int err = WSAGetLastError();
|
||||
if (err != WSAEWOULDBLOCK) {
|
||||
/* an error occurred that wasn't "nothing to read". */
|
||||
return MQTT_ERROR_SOCKET_ERROR;
|
||||
}
|
||||
}
|
||||
} while (rv > 0);
|
||||
|
||||
return (ssize_t)((char*)buf - start);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error No PAL!
|
||||
|
||||
#endif
|
||||
|
||||
/** @endcond */
|
File diff suppressed because it is too large
Load Diff
|
@ -1,13 +0,0 @@
|
|||
PROJECT(TDengine)
|
||||
|
||||
IF (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8...3.20)
|
||||
ELSE ()
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_WINDOWS)
|
||||
INCLUDE_DIRECTORIES(include)
|
||||
AUX_SOURCE_DIRECTORY(src SRC)
|
||||
ADD_LIBRARY(MsvcLibXw ${SRC})
|
||||
ENDIF ()
|
|
@ -1,206 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: debugm.h *
|
||||
* *
|
||||
* Description: Debug macros *
|
||||
* *
|
||||
* Notes: Macros inspired by my Tcl/Bash/Batch debugging libraries. *
|
||||
* The idea is to output the function call stack, indenting *
|
||||
* subroutines proportionally to the call depth. *
|
||||
* To ease reading the output, it must look like real C code.*
|
||||
* *
|
||||
* DEBUG_GLOBALS Define global variables used by macros below: *
|
||||
* int iDebug = FALSE; Global variable enabling debug output if TRUE.*
|
||||
* int iIndent = 0; Global variable controlling debug indentation.*
|
||||
* *
|
||||
* DEBUG_PRINTF((format, ...)) Print a debug string if debug is on. *
|
||||
* The double parenthesis are necessary *
|
||||
* because C90 does not support macros *
|
||||
* with variable list of arguments. *
|
||||
* DEBUG_ENTER((format, ...)) Print a function name and arguments. *
|
||||
* Increase indentation of further calls.*
|
||||
* It's the caller's responsibility to *
|
||||
* format the routine name and arguments.*
|
||||
* DEBUG_LEAVE((format, ...)) Print a function return value. *
|
||||
* Decrease indentation of further calls.*
|
||||
* It's the caller's responsibility to *
|
||||
* format the return instruction & value.*
|
||||
* *
|
||||
* Any call to DEBUG_ENTER MUST be matched by one call to *
|
||||
* DEBUG_LEAVE or RETURN_... when the function returns. * *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-01-16 JFL jf.larvoire@hp.com created this file. *
|
||||
* 2012-02-03 JFL Renamed DEBUG_IF_IS_ON DEBUG_CODE_IF_ON. *
|
||||
* Renamed file from debug.h to debugm.h because of a file *
|
||||
* name collision with another library on my PC. *
|
||||
* 2014-02-10 JFL Added macros for an extra debug mode. *
|
||||
* 2014-07-02 JFL renamed macro RETURN() as RETURN_CONST(), and defined *
|
||||
* new macro RETURN() to return nothing. *
|
||||
* Idem for RETURN_COMMENT() as RETURN_CONST_COMMENT(). *
|
||||
* 2016-09-09 JFL Flush every DEBUG_PRINTF output, to make sure to see *
|
||||
* every debug string printed before a program crash. *
|
||||
* 2016-09-13 JFL Added macros DEBUG_WSTR2NEWUTF8() and DEBUG_FREEUTF8(). *
|
||||
* 2016-10-04 JFL Added macros DEBUG_OFF(), DEBUG_MORE(), DEBUG_LESS(). *
|
||||
* Allow using DEBUG_ON()/MORE()/LESS()/OFF() in release mode.
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _DEBUGM_H
|
||||
#define _DEBUGM_H 1
|
||||
|
||||
#include <stdio.h> /* Macros use printf */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4127) /* Avoid warnings on while(0) below */
|
||||
#endif
|
||||
|
||||
#define DEBUG_DO(code) do {code} while (0)
|
||||
#define DEBUG_DO_NOTHING() do {} while (0)
|
||||
|
||||
/* Conditional compilation based on Microsoft's standard _DEBUG definition */
|
||||
#if defined(_DEBUG)
|
||||
|
||||
#define DEBUG_VERSION " Debug"
|
||||
|
||||
#define DEBUG_GLOBALS \
|
||||
int iDebug = 0; /* Global variable enabling debug output if TRUE. */ \
|
||||
int iIndent = 0; /* Global variable controlling debug indentation. */
|
||||
|
||||
extern int iDebug; /* Global variable enabling of disabling debug messages */
|
||||
#define DEBUG_ON() iDebug = 1 /* Turn debug mode on */
|
||||
#define DEBUG_MORE() iDebug += 1 /* Increase the debug level */
|
||||
#define DEBUG_LESS() iDebug -= 1 /* Decrease the debug level */
|
||||
#define DEBUG_OFF() iDebug = 0 /* Turn debug mode off */
|
||||
#define DEBUG_IS_ON() (iDebug > 0) /* Check if the debug mode is enabled */
|
||||
#define XDEBUG_ON() iDebug = 2 /* Turn extra debug mode on. Same as calling DEBUG_MORE() twice. */
|
||||
#define XDEBUG_IS_ON() (iDebug > 1) /* Check if the extra debug mode is enabled */
|
||||
|
||||
#define DEBUG_CODE(code) code /* Code included in the _DEBUG version only */
|
||||
#define DEBUG_CODE_IF_ON(code) DEBUG_CODE(if (DEBUG_IS_ON()) {code}) /*
|
||||
Debug code executed if debug mode is on */
|
||||
#define XDEBUG_CODE_IF_ON(code) DEBUG_CODE(if (XDEBUG_IS_ON()) {code}) /*
|
||||
Debug code executed if extra debug mode is on */
|
||||
|
||||
extern int iIndent; /* Debug messages indentation */
|
||||
#define DEBUG_INDENT_STEP 2 /* How many spaces to add for each indentation level */
|
||||
#define DEBUG_PRINT_INDENT() printf("%*s", iIndent, "")
|
||||
|
||||
/* Debug code, conditionally printing a string based on global variable 'debug' */
|
||||
/* The enter and leave variants print, then respectively increase or decrease indentation,
|
||||
to make recursive calls easier to review. */
|
||||
#define DEBUG_FPRINTF(args) DEBUG_DO(if (DEBUG_IS_ON()) {DEBUG_PRINT_INDENT(); fprintf args;})
|
||||
#define DEBUG_PRINTF(args) DEBUG_DO(if (DEBUG_IS_ON()) {DEBUG_PRINT_INDENT(); printf args; fflush(stdout);})
|
||||
#define XDEBUG_PRINTF(args) DEBUG_DO(if (XDEBUG_IS_ON()) {DEBUG_PRINT_INDENT(); printf args; fflush(stdout);})
|
||||
#define DEBUG_ENTER(args) DEBUG_DO(DEBUG_PRINTF(args); iIndent += DEBUG_INDENT_STEP;)
|
||||
#define DEBUG_LEAVE(args) DEBUG_DO(DEBUG_PRINTF(args); iIndent -= DEBUG_INDENT_STEP;)
|
||||
|
||||
#define DEBUG_RETURN_INT(i, comment) DEBUG_DO(int DEBUG_i = (i); \
|
||||
DEBUG_LEAVE(("return %d; // " comment "\n", DEBUG_i)); return DEBUG_i;)
|
||||
|
||||
/* print return instruction and decrease indent */
|
||||
#define RETURN() DEBUG_DO(DEBUG_LEAVE(("return;\n")); return;)
|
||||
#define RETURN_CONST(value) DEBUG_DO(DEBUG_LEAVE(("return %s;\n", #value)); return value;)
|
||||
#define RETURN_INT(i) DEBUG_DO(int DEBUG_i = (i); \
|
||||
DEBUG_LEAVE(("return %d;\n", DEBUG_i)); return DEBUG_i;)
|
||||
#define RETURN_STRING(s) DEBUG_DO(char *DEBUG_s = (s); \
|
||||
DEBUG_LEAVE(("return \"%s\";\n", DEBUG_s)); return DEBUG_s;)
|
||||
#define RETURN_CHAR(c) DEBUG_DO(char DEBUG_c = (c); \
|
||||
DEBUG_LEAVE(("return '%c';\n", DEBUG_c)); return DEBUG_c;)
|
||||
#define RETURN_BOOL(b) DEBUG_DO(int DEBUG_b = (b); \
|
||||
DEBUG_LEAVE(("return %s;\n", DEBUG_b ? "TRUE" : "FALSE")); return DEBUG_b;)
|
||||
|
||||
#define RETURN_COMMENT(args) DEBUG_DO(DEBUG_LEAVE(("return; // ")); \
|
||||
if (DEBUG_IS_ON()) printf args; return;)
|
||||
#define RETURN_CONST_COMMENT(value, args) DEBUG_DO(DEBUG_LEAVE(("return %s; // ", #value)); \
|
||||
if (DEBUG_IS_ON()) printf args; return value;)
|
||||
#define RETURN_INT_COMMENT(i, args) DEBUG_DO(int DEBUG_i = (i); \
|
||||
DEBUG_LEAVE(("return %d; // ", DEBUG_i)); if (DEBUG_IS_ON()) printf args; return DEBUG_i;)
|
||||
#define RETURN_BOOL_COMMENT(b, args) DEBUG_DO(int DEBUG_b = (b); \
|
||||
DEBUG_LEAVE(("return %s; // ", DEBUG_b ? "TRUE" : "FALSE")); if (DEBUG_IS_ON()) printf args; return DEBUG_b;)
|
||||
|
||||
#else /* !defined(_DEBUG) */
|
||||
|
||||
#define DEBUG_VERSION "" /* Non debug version: Simply don't say it */
|
||||
|
||||
#define DEBUG_GLOBALS
|
||||
|
||||
#define DEBUG_ON() (void)0
|
||||
#define DEBUG_MORE() (void)0
|
||||
#define DEBUG_LESS() (void)0
|
||||
#define DEBUG_OFF() (void)0
|
||||
#define DEBUG_IS_ON() 0
|
||||
#define XDEBUG_IS_ON() 0
|
||||
#define DEBUG_CODE(code) /* Code included in _DEBUG version only */
|
||||
#define DEBUG_CODE_IF_ON(code) /* Code included in _DEBUG version only */
|
||||
#define XDEBUG_CODE_IF_ON(code) /* Code included in _DEBUG version only */
|
||||
|
||||
#define DEBUG_PRINT_INDENT() DEBUG_DO_NOTHING() /* Print call-depth spaces */
|
||||
|
||||
#define DEBUG_FPRINTF(args) DEBUG_DO_NOTHING() /* Print a debug string to a stream */
|
||||
#define DEBUG_PRINTF(args) DEBUG_DO_NOTHING() /* Print a debug string to stdout */
|
||||
#define XDEBUG_PRINTF(args) DEBUG_DO_NOTHING() /* Print an extra debug string to stdout */
|
||||
#define DEBUG_ENTER(args) DEBUG_DO_NOTHING() /* Print and increase indent */
|
||||
#define DEBUG_LEAVE(args) DEBUG_DO_NOTHING() /* Print and decrease indent */
|
||||
|
||||
#define DEBUG_RETURN_INT(i, comment) return(i)
|
||||
|
||||
/* print return instruction and decrease indent */
|
||||
#define RETURN() return
|
||||
#define RETURN_CONST(value) return(value)
|
||||
#define RETURN_INT(i) return(i)
|
||||
#define RETURN_STRING(s) return(s)
|
||||
#define RETURN_CHAR(c) return(c)
|
||||
#define RETURN_BOOL(b) return(b)
|
||||
|
||||
#define RETURN_COMMENT(args) return
|
||||
#define RETURN_CONST_COMMENT(value, args) return(value)
|
||||
#define RETURN_INT_COMMENT(i, args) return(i)
|
||||
#define RETURN_BOOL_COMMENT(b, args) return(b)
|
||||
|
||||
#endif /* defined(_DEBUG) */
|
||||
|
||||
#define STRINGIZE(s) #s /* Convert a macro name to a string */
|
||||
#define VALUEIZE(s) STRINGIZE(s) /* Convert a macro value to a string */
|
||||
#define MACRODEF(s) "#define " #s " " STRINGIZE(s)
|
||||
|
||||
/* Display a macro name and value. */
|
||||
#define DEBUG_PRINT_MACRO(name) DEBUG_DO( \
|
||||
const char *pszName = #name; /* Don't use STRINGIZE because we're already inside a macro */ \
|
||||
const char *pszValue = STRINGIZE(name); /* Don't use VALUEIZE because we're already inside a macro */ \
|
||||
DEBUG_PRINT_INDENT(); \
|
||||
if (strcmp(pszName, pszValue)) { \
|
||||
printf("#define %s %s\n", pszName, pszValue); \
|
||||
} else { /* Not 100% certain, but most likely. */ \
|
||||
printf("#undef %s\n", pszName); \
|
||||
} \
|
||||
)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/* Helper macros for displaying Unicode strings */
|
||||
#define DEBUG_WSTR2UTF8(from, to, toSize) DEBUG_CODE( \
|
||||
WideCharToMultiByte(CP_UTF8, 0, from, lstrlenW(from)+1, to, toSize, NULL, NULL); \
|
||||
)
|
||||
|
||||
/* Dynamically allocate a new buffer, then convert a Unicode string to UTF-8 */
|
||||
/* The dynamic allocation is useful in modules using lots of UTF-16 pathnames.
|
||||
This avoids having many local buffers of length UTF8_PATH_MAX, which may
|
||||
make the stack grow too large and overflow. */
|
||||
#define DEBUG_WSTR2NEWUTF8(pwStr, pUtf8) \
|
||||
DEBUG_CODE( \
|
||||
do { \
|
||||
int nUtf8 = (int)lstrlenW(pwStr) * 2 + 1; \
|
||||
pUtf8 = malloc(nUtf8); \
|
||||
DEBUG_WSTR2UTF8(pwStr, pUtf8, nUtf8); \
|
||||
} while (0); \
|
||||
) /* DEBUG_FREE(pUtf8) MUST be used to free the UTF-8 string after use, else there will be a memory leak */
|
||||
|
||||
#define DEBUG_FREEUTF8(pUtf8) DEBUG_CODE(free(pUtf8))
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
#endif /* !defined(_DEBUGM_H) */
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: direct.h *
|
||||
* *
|
||||
* Description: MsvcLibX extensions to direct.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-03-24 JFL Created this file, with content moved from unistd.h. *
|
||||
* 2015-11-15 JFL Visual Studio 2015 moved this file to the Windows Kit UCRT.
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVCLIBX_DIRECT_H
|
||||
#define _MSVCLIBX_DIRECT_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include <direct.h> /* Include MSVC's own <direct.h> file */
|
||||
|
||||
#undef mkdir /* This MSVC macro is incompatible with mkdir() function in unistd.h */
|
||||
|
||||
#endif /* defined(_MSVCLIBX_DIRECT_H) */
|
||||
|
|
@ -1,282 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: dirent.h *
|
||||
* *
|
||||
* Description: DOS/WIN32 port of standard C library's dirent.h. *
|
||||
* *
|
||||
* Notes: There are also remains of an OS/2 implementation here. *
|
||||
* This code did work c. 1990, in an OS/2 1.3 port of dirc.c.*
|
||||
* It's not maintained anymore, and unlikely to still work. *
|
||||
* Left in as a historic reference, in the very unlikely *
|
||||
* case somebody wants to revive it. *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-01-09 JFL Created this file, based on dirc and other programs. *
|
||||
* 2013-03-09 JFL Rewrote the stat/fstat/lstat and fseeko/ftello definitions*
|
||||
* based on _FILE_OFFSET_BITS, _LARGEFILE_SOURCE, and *
|
||||
* _LARGEFILE_SOURCE64 definitions. *
|
||||
* 2014-02-06 JFL Moved stat extensions to statx.h. *
|
||||
* 2014-02-27 JFL Use a WIN32_FIND_DATAW in Windows, to support UTF-8 names.*
|
||||
* 2014-03-20 JFL Restructured Windows opendir and readdir functions into *
|
||||
* Wide and MultiByte versions, and changed the Unicode and *
|
||||
* Ansi versions to macros. *
|
||||
* 2014-06-06 JFL Fixed macro _D_EXACT_NAMLEN(). *
|
||||
* 2015-12-07 JFL Added the conditional definition of symlink constants, so *
|
||||
* that our code builds even in XP and older Windows SDKs. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _DIRENT_H
|
||||
#define _DIRENT_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#define _DIRENT_FOR_DOS_WINDOWS /* Uniquely identify this module */
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <time.h>
|
||||
#include <sys/types.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifndef ENAMETOOLONG /* Not defined in DOS' errno.h */
|
||||
#define ENAMETOOLONG 38
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Macros to extract size information from a struct dirent */
|
||||
#define _D_EXACT_NAMLEN(d) (strlen((d)->d_name)) /* Name length, not including NUL */
|
||||
|
||||
#define _DIRENT_HAVE_D_TYPE /* We commit to providing this field */
|
||||
|
||||
/************************ MS-DOS-specific definitions ************************/
|
||||
|
||||
#ifdef _MSDOS /* Automatically defined when targeting an MS-DOS application */
|
||||
|
||||
#include <dos.h>
|
||||
|
||||
#define NAME_MAX 12
|
||||
|
||||
#pragma pack(1)
|
||||
struct _fileinfo { /* MS-DOS structure returning file search results */
|
||||
uint8_t fiReserved[21];
|
||||
uint8_t fiAttribute; /* Attributes of file found */
|
||||
uint16_t fiFileTime; /* Time of last write */
|
||||
uint16_t fiFileDate; /* Time of last write */
|
||||
uint32_t fiSize; /* File Size */
|
||||
char fiFileName[13]; /* File name and extension */
|
||||
};
|
||||
#pragma pack()
|
||||
typedef struct _fileinfo fileinfo;
|
||||
|
||||
#pragma pack(1)
|
||||
struct dirent { /* Standard C library structure returning directory entries. */
|
||||
/* Standard fields */
|
||||
_ino_t d_ino; /* We don't need it, but it's required by the spec */
|
||||
unsigned char d_type; /* File type. Values defined in macros DT_xxxx */
|
||||
/* unsigned char d_namlen; /* File name length, not including NUL */
|
||||
/* OS-specific extensions (allowed by the Posix specification) */
|
||||
/* Matches exactly the struc _fileinfo above, to avoid doing any copying */
|
||||
uint8_t d_reserved[21];
|
||||
uint8_t d_attribs; /* Attribute of file found */
|
||||
uint16_t d_time; /* Time of last write */
|
||||
uint16_t d_date; /* Time of last write */
|
||||
uint32_t d_filesize; /* File Size */
|
||||
/* Standard field: The file name, which must be last in the dirent structure */
|
||||
char d_name[NAME_MAX+1]; /* Null-terminated file name. Must be last */
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
#pragma pack(1)
|
||||
struct _dirhandle { /* Private structure, not for use by users */
|
||||
struct dirent sDirent;
|
||||
/* char dta_buf[128]; /* Protection area, in case MS-DOS uses the whole DTA, and not just the struct _fileinfo ahead of it. */
|
||||
char wildcards[4]; /* Leave room for the "\*.*" that we append initially. This field MUST follow sDirent. */
|
||||
char first; /* Tracks if this is the first search call */
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
/* Macros to extract size information from a struct dirent */
|
||||
#define _D_ALLOC_NAMLEN(d) 13 /* Upper bound of the block size to alloc for a name */
|
||||
|
||||
/* MS-DOS compatible functions for searching with a specific attribute */
|
||||
int srch1st(char *pszFile, uint16_t wAttr, fileinfo *pFI); /* Search first matching file */
|
||||
int srchnext(fileinfo *pFI); /* Search next matching file */
|
||||
#define DOS_SEARCH_FUNCTIONS_DEFINED 1
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
/************************ Win32-specific definitions *************************/
|
||||
|
||||
#ifdef _WIN32 /* Automatically defined when targeting a Win32 application */
|
||||
|
||||
#ifndef WINVER
|
||||
#define WINVER 0x0400
|
||||
#endif
|
||||
|
||||
#include <dos.h>
|
||||
#include <windows.h>
|
||||
|
||||
/* Add symlink definitions, that may be missing in XP and older Windows SDKs */
|
||||
#ifndef IO_REPARSE_TAG_SYMLINK
|
||||
#define IO_REPARSE_TAG_SYMLINK 0xA000000CL
|
||||
#endif
|
||||
#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
|
||||
#define SYMBOLIC_LINK_FLAG_DIRECTORY 1
|
||||
#endif
|
||||
#ifndef FSCTL_SET_REPARSE_POINT
|
||||
#define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
|
||||
#endif
|
||||
#ifndef FSCTL_GET_REPARSE_POINT
|
||||
#define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
|
||||
#endif
|
||||
#ifndef FSCTL_DELETE_REPARSE_POINT
|
||||
#define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
|
||||
#endif
|
||||
|
||||
#define NAME_MAX (4 * FILENAME_MAX) /* Worst case using UTF-8 encoding: 4 bytes/WCHAR */
|
||||
|
||||
struct dirent { /* Structure used to return information about directory entries. */
|
||||
/* OS-specific extensions */
|
||||
uint32_t d_attribs;
|
||||
uint32_t d_ReparseTag;
|
||||
FILETIME d_CreationTime;
|
||||
FILETIME d_LastAccessTime;
|
||||
FILETIME d_LastWriteTime;
|
||||
uint64_t d_filesize;
|
||||
char d_shortname[14*sizeof(WCHAR)];
|
||||
/* Standard fields */
|
||||
_ino_t d_ino; /* We don't need it, but it's required by the spec */
|
||||
unsigned char d_type; /* File type. Values defined in macros DT_xxxx */
|
||||
/* unsigned char d_namlen; /* File name length, not including NUL */
|
||||
char d_name[(NAME_MAX+1)*sizeof(WCHAR)]; /* Null-terminated file name */
|
||||
};
|
||||
|
||||
struct _dirhandle { /* Private structure, not for use by users */
|
||||
struct dirent sDirent;
|
||||
WCHAR wszDirName[MAX_PATH+1]; /* Null-terminated directory name */
|
||||
HANDLE hFindFile; /* Search handle */
|
||||
WIN32_FIND_DATAW wfd; /* Where Win32 will store the file information */
|
||||
};
|
||||
|
||||
/* Macros to extract size information from a struct dirent */
|
||||
#define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN(d)+1) /* Upper bound of the block size to alloc for a name */
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
/************************* OS/2-specific definitions *************************/
|
||||
|
||||
#ifdef _OS2 /* Automatically defined when targeting an OS/2 application? */
|
||||
|
||||
#include <dos.h>
|
||||
|
||||
#define INCL_DOSFILEMGR
|
||||
#define INCL_DOSMISC
|
||||
#define INCL_VIO
|
||||
#include "os2.h"
|
||||
|
||||
#define NAME_MAX CCHMAXPATHCOMP
|
||||
|
||||
struct dirent { /* Structure used to return information about directory entries. */
|
||||
_ino_t d_ino; /* We don't need it, but it's required by the spec */
|
||||
/* Non standard extensions, to ease adapting old DOS/WIN32 apps */
|
||||
uintmax_t d_filesize; /* File size */
|
||||
uint16_t time; /* MS-DOS time */
|
||||
uint16_t date; /* MS-DOS date */
|
||||
uint8_t attribs; /* Attributes, the MS-DOS way */
|
||||
/* Standard fields */
|
||||
unsigned char d_type; /* File type. Values defined in macros DT_xxxx */
|
||||
/* unsigned char d_namlen; /* File name length, not including NUL */
|
||||
char d_name[NAME_MAX+1]; /* Null-terminated file name. Must be last */
|
||||
};
|
||||
|
||||
struct _dirhandle { /* Private structure, not for use by users */
|
||||
struct dirent sDirent;
|
||||
short hDir; /* Directory handle */
|
||||
FILEFINDBUF buf; /* Where OS/2 will store the file information */
|
||||
};
|
||||
|
||||
/* Macros to extract size information from a struct dirent */
|
||||
#define _D_ALLOC_NAMLEN(d) (_D_EXACT_NAMLEN(d)+1) /* Upper bound of the block size to alloc for a name */
|
||||
|
||||
#endif /* defined(_OS2) */
|
||||
|
||||
/********************** End of OS-specific definitions ***********************/
|
||||
|
||||
typedef struct _dirhandle DIR; /* Directory enumerator handle */
|
||||
typedef struct dirent _dirent; /* Directory entry */
|
||||
|
||||
#define MAXNAMELEN NAME_MAX /* Alias used by some Unix versions */
|
||||
|
||||
/* File types for struct dirent d_type. Must match the S_IFMT field in sys/stat.h. */
|
||||
#define DT_UNKNOWN 0
|
||||
#define DT_FIFO 1 /* Fifo (not used in DOS/Windows dirs) */
|
||||
#define DT_CHR 2 /* Character device (not used in DOS/Windows) */
|
||||
#define DT_DIR 4 /* Directory */
|
||||
#define DT_BLK 6 /* Block device (not used in DOS/Windows) */
|
||||
#define DT_REG 8 /* Normal file */
|
||||
#define DT_LNK 10 /* Symbolic link */
|
||||
#define DT_SOCK 12 /* Socket (not used in DOS/Windows dirs) */
|
||||
#define DT_VOLID 15 /* Volume ID (non-standard extension for MS-DOS FAT) */
|
||||
|
||||
/* Functions operating on directories */
|
||||
#if defined(_MSDOS)
|
||||
|
||||
extern DIR *opendir(const char *name); /* Open a directory */
|
||||
extern int closedir(DIR *pDir); /* Close the directory. Return 0 if successful, -1 if not. */
|
||||
extern _dirent *readdir(DIR *pDir); /* Read a directory entry. Return pDirEnt, or NULL for EOF or error. */
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define opendir opendirU
|
||||
#define readdir readdirU
|
||||
#define scandir scandirU
|
||||
#else /* _ANSI_SOURCE */
|
||||
#define opendir opendirA
|
||||
#define readdir readdirA
|
||||
#define scandir scandirA
|
||||
#endif
|
||||
extern DIR *opendirW(const WCHAR *name); /* Open a directory - Wide char version */
|
||||
extern DIR *opendirM(const char *name, UINT cp); /* Open a directory - MultiByte char version */
|
||||
#define opendirA(name) opendirM(name, CP_ACP) /* Open a directory - ANSI version */
|
||||
#define opendirU(name) opendirM(name, CP_UTF8) /* Open a directory - UTF-8 version */
|
||||
extern int closedir(DIR *pDir); /* Close the directory. Return 0 if successful, -1 if not. */
|
||||
extern _dirent *readdirW(DIR *pDir); /* Read a directory entry. Return pDirEnt, or NULL for EOF or error. */
|
||||
extern _dirent *readdirM(DIR *pDir, UINT cp); /* Read a directory entry. Return pDirEnt, or NULL for EOF or error. */
|
||||
#define readdirA(pDir) readdirM(pDir, CP_ACP) /* Read a directory entry. Return pDirEnt, or NULL for EOF or error. */
|
||||
#define readdirU(pDir) readdirM(pDir, CP_UTF8) /* Read a directory entry. Return pDirEnt, or NULL for EOF or error. */
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
/* extern int readdir_r(DIR *pDir, _dirent *__entry, _dirent **__result); /* Reentrant readdir */
|
||||
/* extern void rewinddir(DIR *pDir); /* Rewind DIRP to the beginning of the directory. */
|
||||
/* extern void seekdir(DIR *pDir, long lPos); /* Seek to position POS on DIRP. */
|
||||
/* extern long telldir(DIR *pDir); /* Return the current position of DIRP. */
|
||||
/* extern int dirfd(DIR *pDir); /* Return the file descriptor used by DIRP. */
|
||||
|
||||
/* Scan the directory dir, calling cbSelect() on each directory entry.
|
||||
Entries for which cbSelect() returns nonzero are individually malloc'd,
|
||||
sorted using qsort with cbCompare(), and collected in a malloc'd array in
|
||||
*namelist. Returns the number of entries selected, or -1 on error. */
|
||||
extern int scandir(const char *dir,
|
||||
_dirent ***namelist,
|
||||
int (*cbSelect) (const _dirent *),
|
||||
int (__cdecl *cbCompare) (const _dirent **,
|
||||
const _dirent **));
|
||||
|
||||
/* Function to compare two `struct dirent's alphabetically. */
|
||||
extern int __cdecl alphasort (const _dirent **ppDE1, const _dirent **ppDEe2);
|
||||
/* extern int versionsort (const _dirent **ppDE1, const _dirent **ppDEe2); */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* defined(_DIRENT_H) */
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: error.h *
|
||||
* *
|
||||
* Description: DOS/WIN32 port of the GNU CoreUtils library error funct. *
|
||||
* *
|
||||
* Notes: Gotcha: *
|
||||
* The Windows SDK also contains a file called error.h *
|
||||
* See C:\Program Files\Microsoft SDKs\Windows\v7.0\INCLUDE *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-10-21 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _ERROR_H_
|
||||
#define _ERROR_H_
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
extern void error(int status, int errnum, const char *format, ...);
|
||||
|
||||
#endif
|
|
@ -1,30 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: fadvise.h *
|
||||
* *
|
||||
* Description: WIN32 makeshift version of Coreutils' fadvise.h. *
|
||||
* *
|
||||
* Notes: Gives hints to the kernel about future uses of a file. *
|
||||
* Define constants, and replace functions by void macros. *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-10-17 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
enum fadvice_t {
|
||||
FADVISE_NORMAL,
|
||||
FADVISE_SEQUENTIAL,
|
||||
FADVISE_NOREUSE,
|
||||
FADVISE_DONTNEED,
|
||||
FADVISE_WILLNEED,
|
||||
FADVISE_RANDOM
|
||||
};
|
||||
|
||||
/* void fdadvise(int fd, off_t offset, off_t len, fadvice_t advice) */
|
||||
#define fdadvise(fd, offset, len, advice)
|
||||
|
||||
/* void fadvise(FILE *fp, fadvice_t advice) */
|
||||
#define fadvise(fp, advice)
|
|
@ -1,40 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: fcntl.h *
|
||||
* *
|
||||
* Description: MsvcLibX extensions to fcntl.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2017-02-16 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2017 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVCLIBX_FCNTL_H
|
||||
#define _MSVCLIBX_FCNTL_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include <fcntl.h> /* Include MSVC's own <fcntl.h> file */
|
||||
|
||||
/* Microsoft defines _open() in io.h */
|
||||
#include <io.h>
|
||||
|
||||
#if defined(_MSDOS)
|
||||
#define open _open
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
extern int openA(const char *, int, ...); /* MsvcLibX ANSI version of open */
|
||||
extern int openU(const char *, int, ...); /* MsvcLibX UTF-8 version of open */
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define open openU
|
||||
#else /* _ANSI_SOURCE */
|
||||
#define open openA
|
||||
#endif /* defined(_UTF8_SOURCE) */
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
#endif /* defined(_MSVCLIBX_FCNTL_H) */
|
|
@ -1,50 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: fnmatch.h *
|
||||
* *
|
||||
* Description: DOS/WIN32 port of standard C library's fnmatch.h. *
|
||||
* *
|
||||
* Notes: Reference for fnmatch and glob: *
|
||||
* http://www.cs.utah.edu/dept/old/texinfo/glibc-manual-0.02/library_9.html *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-01-17 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _FNMATCH_H
|
||||
#define _FNMATCH_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Bits set in the FLAGS argument to fnmatch() */
|
||||
#define FNM_PATHNAME 0x01 /* Wildcards don't match '/' or '\\' */
|
||||
#define FNM_FILE_NAME FNM_PATHNAME /* Equivalent GNU name */
|
||||
#define FNM_NOESCAPE 0x02 /* Backslashes don't quote special chars (Irrelevant in DOS/Windows) */
|
||||
#define FNM_PERIOD 0x04 /* Wildcards don't match leading dots */
|
||||
#define FNM_LEADING_DIR 0x08 /* Match up to the first '/' or '\\' */
|
||||
#define FNM_CASEFOLD 0x10 /* Case-insentitive comparison */
|
||||
|
||||
/* Values returned by fnmatch() */
|
||||
#define FNM_MATCH 0 /* Non standard, but makes fnmatch.c more readable */
|
||||
#define FNM_NOMATCH 1
|
||||
|
||||
/* Value returned by fnmatch() if unsupported */
|
||||
#define FNM_NOSYS (-1)
|
||||
|
||||
/* Match NAME against the filename pattern PATTERN,
|
||||
returning zero if it matches, FNM_NOMATCH if not. */
|
||||
extern int fnmatch(const char *pszPattern, const char *pszName, int iFlags);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !defined(_FNMATCH_H) */
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/*-
|
||||
* Copyright (c) 2000 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Dieter Baron and Thomas Klausner.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $
|
||||
*/
|
||||
|
||||
#ifndef _GETOPT_H_
|
||||
#define _GETOPT_H_
|
||||
|
||||
/*
|
||||
* Gnu like getopt_long() and BSD4.4 getsubopt()/optreset extensions
|
||||
*/
|
||||
#define no_argument 0
|
||||
#define required_argument 1
|
||||
#define optional_argument 2
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct option {
|
||||
/* name of long option */
|
||||
const char *name;
|
||||
/*
|
||||
* one of no_argument, required_argument, and optional_argument:
|
||||
* whether option takes an argument
|
||||
*/
|
||||
int has_arg;
|
||||
/* if not NULL, set *flag to val when option found */
|
||||
int *flag;
|
||||
/* if flag not NULL, value to set *flag to; else return value */
|
||||
int val;
|
||||
};
|
||||
|
||||
int getopt_long(int, char * const *, const char *,
|
||||
const struct option *, int *);
|
||||
|
||||
extern int optreset;
|
||||
extern char *optarg;
|
||||
extern int opterr;
|
||||
extern int optind;
|
||||
extern int optopt;
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* !_GETOPT_H_ */
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename iconv.h *
|
||||
* *
|
||||
* Description: WIN32 port of standard C library's iconv() *
|
||||
* *
|
||||
* Notes: Define here a number of routines, that will eventually *
|
||||
* be used by iconv(). *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-02-27 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _ICONV_H
|
||||
#define _ICONV_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(_MSDOS)
|
||||
|
||||
/* Count the number of characters (not bytes!) in a string */
|
||||
/* For now, assume the # of characters is the same as the # of bytes */
|
||||
/* TO DO: Add support for DOS code pages! */
|
||||
#define CountCharacters(string, cp) (int)strlen(string)
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
int ConvertString(char *buf, size_t nBytes, UINT cpFrom, UINT cpTo, LPCSTR lpDefaultChar);
|
||||
int CountCharacters(const char *string, UINT cp);
|
||||
char *DupAndConvert(const char *string, UINT cpFrom, UINT cpTo, LPCSTR lpDefaultChar);
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
#endif /* !defined(_ICONV_H) */
|
||||
|
|
@ -1,314 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename inttypes.h *
|
||||
* *
|
||||
* Description ISO C9x compliant inttypes.h for Microsoft Visual Studio *
|
||||
* *
|
||||
* Notes TO DO: Move imaxdiv to its own C file. *
|
||||
* *
|
||||
* History *
|
||||
* 2014-02-07 JFL Added definitions for PRIdMAX and PRIiMAX. *
|
||||
* 2016-01-07 JFL Restructured and improved support for MS-DOS. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_INTTYPES_H_
|
||||
#define _MSC_INTTYPES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* 7.8 Format conversion of integer types */
|
||||
|
||||
typedef struct {
|
||||
intmax_t quot;
|
||||
intmax_t rem;
|
||||
} imaxdiv_t;
|
||||
|
||||
/* 7.8.1 Macros for format specifiers */
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) /* [ See footnote 185 at page 198 */
|
||||
|
||||
#if defined(_WIN64)
|
||||
#define __I64_PREFIX "I64"
|
||||
#define __I32_PREFIX "I32"
|
||||
#define __PTR_PREFIX "I64"
|
||||
#define __MAX_PREFIX "I64"
|
||||
#elif defined(_WIN32)
|
||||
#define __I64_PREFIX "I64"
|
||||
#define __I32_PREFIX "I32"
|
||||
#define __PTR_PREFIX "I32"
|
||||
#define __MAX_PREFIX "I64"
|
||||
#elif defined(_MSDOS)
|
||||
#define __I64_PREFIX "ll" /* MSVC 1.5 actually ignores the second l */
|
||||
#define __I32_PREFIX "l"
|
||||
#if defined(_M_I86CM) || defined(_M_I86LM) || defined(_M_I86HM) /* Long pointer memory models */
|
||||
#define __PTR_PREFIX "l"
|
||||
#else /* Short pointer memory models */
|
||||
#define __PTR_PREFIX ""
|
||||
#endif
|
||||
#define __MAX_PREFIX "l"
|
||||
#endif
|
||||
|
||||
/* printf macros for integers */
|
||||
#define PRId8 "d"
|
||||
#define PRIi8 "i"
|
||||
#define PRIo8 "o"
|
||||
#define PRIu8 "u"
|
||||
#define PRIx8 "x"
|
||||
#define PRIX8 "X"
|
||||
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIXLEAST8 "X"
|
||||
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIiFAST8 "i"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
|
||||
#define PRIdLEAST16 PRId16
|
||||
#define PRIiLEAST16 PRIi16
|
||||
#define PRIoLEAST16 PRIo16
|
||||
#define PRIuLEAST16 PRIu16
|
||||
#define PRIxLEAST16 PRIx16
|
||||
#define PRIXLEAST16 PRIX16
|
||||
|
||||
#define PRIdFAST16 PRId16
|
||||
#define PRIiFAST16 PRIi16
|
||||
#define PRIoFAST16 PRIo16
|
||||
#define PRIuFAST16 PRIu16
|
||||
#define PRIxFAST16 PRIx16
|
||||
#define PRIXFAST16 PRIX16
|
||||
|
||||
#define PRId32 __I32_PREFIX "d"
|
||||
#define PRIi32 __I32_PREFIX "i"
|
||||
#define PRIo32 __I32_PREFIX "o"
|
||||
#define PRIu32 __I32_PREFIX "u"
|
||||
#define PRIx32 __I32_PREFIX "x"
|
||||
#define PRIX32 __I32_PREFIX "X"
|
||||
|
||||
#define PRIdLEAST32 PRId32
|
||||
#define PRIiLEAST32 PRIi32
|
||||
#define PRIoLEAST32 PRIo32
|
||||
#define PRIuLEAST32 PRIu32
|
||||
#define PRIxLEAST32 PRIx32
|
||||
#define PRIXLEAST32 PRIX32
|
||||
|
||||
#define PRIdFAST32 PRId32
|
||||
#define PRIiFAST32 PRIi32
|
||||
#define PRIoFAST32 PRIo32
|
||||
#define PRIuFAST32 PRIu32
|
||||
#define PRIxFAST32 PRIx32
|
||||
#define PRIXFAST32 PRIX32
|
||||
|
||||
#define PRId64 __I64_PREFIX "d"
|
||||
#define PRIi64 __I64_PREFIX "i"
|
||||
#define PRIo64 __I64_PREFIX "o"
|
||||
#define PRIu64 __I64_PREFIX "u"
|
||||
#define PRIx64 __I64_PREFIX "x"
|
||||
#define PRIX64 __I64_PREFIX "X"
|
||||
|
||||
#define PRIdLEAST64 PRId64
|
||||
#define PRIiLEAST64 PRIi64
|
||||
#define PRIoLEAST64 PRIo64
|
||||
#define PRIuLEAST64 PRIu64
|
||||
#define PRIxLEAST64 PRIx64
|
||||
#define PRIXLEAST64 PRIX64
|
||||
|
||||
#define PRIdFAST64 PRId64
|
||||
#define PRIiFAST64 PRIi64
|
||||
#define PRIoFAST64 PRIo64
|
||||
#define PRIuFAST64 PRIu64
|
||||
#define PRIxFAST64 PRIx64
|
||||
#define PRIXFAST64 PRIX64
|
||||
|
||||
#define PRIdMAX __MAX_PREFIX "d"
|
||||
#define PRIiMAX __MAX_PREFIX "i"
|
||||
#define PRIoMAX __MAX_PREFIX "o"
|
||||
#define PRIuMAX __MAX_PREFIX "u"
|
||||
#define PRIxMAX __MAX_PREFIX "x"
|
||||
#define PRIXMAX __MAX_PREFIX "X"
|
||||
|
||||
#define PRIdPTR __PTR_PREFIX "d"
|
||||
#define PRIiPTR __PTR_PREFIX "i"
|
||||
#define PRIoPTR __PTR_PREFIX "o"
|
||||
#define PRIuPTR __PTR_PREFIX "u"
|
||||
#define PRIxPTR __PTR_PREFIX "x"
|
||||
#define PRIXPTR __PTR_PREFIX "X"
|
||||
|
||||
/* scanf macros for integers */
|
||||
#define SCNd8 "d"
|
||||
#define SCNi8 "i"
|
||||
#define SCNo8 "o"
|
||||
#define SCNu8 "u"
|
||||
#define SCNx8 "x"
|
||||
#define SCNX8 "X"
|
||||
|
||||
#define SCNdLEAST8 SCNd8
|
||||
#define SCNiLEAST8 SCNi8
|
||||
#define SCNoLEAST8 SCNo8
|
||||
#define SCNuLEAST8 SCNu8
|
||||
#define SCNxLEAST8 SCNx8
|
||||
#define SCNXLEAST8 SCNX8
|
||||
|
||||
#define SCNdFAST8 SCNd8
|
||||
#define SCNiFAST8 SCNi8
|
||||
#define SCNoFAST8 SCNo8
|
||||
#define SCNuFAST8 SCNu8
|
||||
#define SCNxFAST8 SCNx8
|
||||
#define SCNXFAST8 SCNX8
|
||||
|
||||
#define SCNd16 "hd"
|
||||
#define SCNi16 "hi"
|
||||
#define SCNo16 "ho"
|
||||
#define SCNu16 "hu"
|
||||
#define SCNx16 "hx"
|
||||
#define SCNX16 "hX"
|
||||
|
||||
#define SCNdLEAST16 SCNd16
|
||||
#define SCNiLEAST16 SCNi16
|
||||
#define SCNoLEAST16 SCNo16
|
||||
#define SCNuLEAST16 SCNu16
|
||||
#define SCNxLEAST16 SCNx16
|
||||
#define SCNXLEAST16 SCNX16
|
||||
|
||||
#define SCNdFAST16 SCNd16
|
||||
#define SCNiFAST16 SCNi16
|
||||
#define SCNoFAST16 SCNo16
|
||||
#define SCNuFAST16 SCNu16
|
||||
#define SCNxFAST16 SCNx16
|
||||
#define SCNXFAST16 SCNX16
|
||||
|
||||
#define SCNd32 __I32_PREFIX "d"
|
||||
#define SCNi32 __I32_PREFIX "i"
|
||||
#define SCNo32 __I32_PREFIX "o"
|
||||
#define SCNu32 __I32_PREFIX "u"
|
||||
#define SCNx32 __I32_PREFIX "x"
|
||||
#define SCNX32 __I32_PREFIX "X"
|
||||
|
||||
#define SCNdLEAST32 SCNd32
|
||||
#define SCNiLEAST32 SCNi32
|
||||
#define SCNoLEAST32 SCNo32
|
||||
#define SCNuLEAST32 SCNu32
|
||||
#define SCNxLEAST32 SCNx32
|
||||
#define SCNXLEAST32 SCNX32
|
||||
|
||||
#define SCNdFAST32 SCNd32
|
||||
#define SCNiFAST32 SCNi32
|
||||
#define SCNoFAST32 SCNo32
|
||||
#define SCNuFAST32 SCNu32
|
||||
#define SCNxFAST32 SCNx32
|
||||
#define SCNXFAST32 SCNX32
|
||||
|
||||
#define SCNd64 __I64_PREFIX "d"
|
||||
#define SCNi64 __I64_PREFIX "i"
|
||||
#define SCNo64 __I64_PREFIX "o"
|
||||
#define SCNu64 __I64_PREFIX "u"
|
||||
#define SCNx64 __I64_PREFIX "x"
|
||||
#define SCNX64 __I64_PREFIX "X"
|
||||
|
||||
#define SCNdLEAST64 SCNd64
|
||||
#define SCNiLEAST64 SCNi64
|
||||
#define SCNoLEAST64 SCNo64
|
||||
#define SCNuLEAST64 SCNu64
|
||||
#define SCNxLEAST64 SCNx64
|
||||
#define SCNXLEAST64 SCNX64
|
||||
|
||||
#define SCNdFAST64 SCNd64
|
||||
#define SCNiFAST64 SCNi64
|
||||
#define SCNoFAST64 SCNo64
|
||||
#define SCNuFAST64 SCNu64
|
||||
#define SCNxFAST64 SCNx64
|
||||
#define SCNXFAST64 SCNX64
|
||||
|
||||
#define SCNdMAX __MAX_PREFIX "d"
|
||||
#define SCNiMAX __MAX_PREFIX "i"
|
||||
#define SCNoMAX __MAX_PREFIX "o"
|
||||
#define SCNuMAX __MAX_PREFIX "u"
|
||||
#define SCNxMAX __MAX_PREFIX "x"
|
||||
#define SCNXMAX __MAX_PREFIX "X"
|
||||
|
||||
#define SCNdPTR __PTR_PREFIX "d"
|
||||
#define SCNiPTR __PTR_PREFIX "i"
|
||||
#define SCNoPTR __PTR_PREFIX "o"
|
||||
#define SCNuPTR __PTR_PREFIX "u"
|
||||
#define SCNxPTR __PTR_PREFIX "x"
|
||||
#define SCNXPTR __PTR_PREFIX "X"
|
||||
|
||||
#endif /* __STDC_FORMAT_MACROS ] */
|
||||
|
||||
/* 7.8.2 Functions for greatest-width integer types */
|
||||
|
||||
/* 7.8.2.1 imaxabs() */
|
||||
#if defined(_WIN32)
|
||||
#define imaxabs _abs64
|
||||
#elif defined(_MSDOS)
|
||||
#define imaxabs abs
|
||||
#endif
|
||||
|
||||
/* 7.8.2.2 imaxdiv() */
|
||||
|
||||
/* This is modified version of div() function from Microsoft's div.c found */
|
||||
/* in %MSVC.NET%\crt\src\div.c */
|
||||
#if defined(_MSDOS) && !defined(STATIC_IMAXDIV) && !defined(__cplusplus)
|
||||
/* MSVC 1.52 compiler for MS-DOS does not support inline for C */
|
||||
extern imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom);
|
||||
#else
|
||||
#ifdef STATIC_IMAXDIV /* [ */
|
||||
static
|
||||
#else /* STATIC_IMAXDIV ][ */
|
||||
_inline
|
||||
#endif /* STATIC_IMAXDIV ] */
|
||||
imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) {
|
||||
imaxdiv_t result;
|
||||
|
||||
result.quot = numer / denom;
|
||||
result.rem = numer % denom;
|
||||
|
||||
if (numer < 0 && result.rem > 0) {
|
||||
/* did division wrong; must fix up */
|
||||
++result.quot;
|
||||
result.rem -= denom;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif /* defined(_MSDOS) && !defined(STATIC_IMAXDIV) && !defined(__cplusplus) */
|
||||
|
||||
/* 7.8.2.3 strtoimax() and strtoumax() */
|
||||
#if defined(_WIN32)
|
||||
#define strtoimax _strtoi64
|
||||
#define strtoumax _strtoui64
|
||||
#elif defined(_MSDOS)
|
||||
#define strtoimax strtol
|
||||
#define strtoumax strtoul
|
||||
#endif
|
||||
|
||||
/* 7.8.2.4 wcstoimax() and wcstoumax() */
|
||||
#if defined(_WIN32)
|
||||
#define wcstoimax _wcstoi64
|
||||
#define wcstoumax _wcstoui64
|
||||
#elif defined(_MSDOS)
|
||||
#define wcstoimax wcstol
|
||||
#define wcstoumax wcstoul
|
||||
#endif
|
||||
|
||||
#endif /* _MSC_INTTYPES_H_ */
|
|
@ -1,22 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: libgen.h *
|
||||
* *
|
||||
* Description: DOS/WIN32 port of standard C library's libgen.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2016-09-08 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _LIBGEN_H
|
||||
#define _LIBGEN_H
|
||||
|
||||
char *basename(char *pszPathname); /* Modifies pathname; Not thread-safe */
|
||||
char *dirname(char *pszPathname); /* Modifies pathname; Not thread-safe */
|
||||
|
||||
#endif /* !defined(_LIBGEN_H) */
|
|
@ -1,54 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: limits.h *
|
||||
* *
|
||||
* Description: MsvcLibX extensions to limits.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-06-30 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVCLIBX_LIMITS_H
|
||||
#define _MSVCLIBX_LIMITS_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include <limits.h> /* Include MSVC's own <limits.h> file */
|
||||
|
||||
/************************ MS-DOS-specific definitions ************************/
|
||||
|
||||
#ifdef _MSDOS /* Automatically defined when targeting an MS-DOS application */
|
||||
|
||||
#define PATH_MAX 255 /* Many APIs actually limit it to 128 bytes, but longer paths paths are legal. */
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
/************************ Win32-specific definitions *************************/
|
||||
|
||||
#ifdef _WIN32 /* Automatically defined when targeting a Win32 application */
|
||||
|
||||
#undef PATH_MAX
|
||||
|
||||
#define ANSI_PATH_MAX 260 /* Number of ANSI characters, including final NUL ( = Windef.h MAX_PATH) */
|
||||
#define UNICODE_PATH_MAX 32768 /* Number of Unicode characters, including final NUL */
|
||||
#define UTF8_PATH_MAX (4 * UNICODE_PATH_MAX) /* Worst UTF-8 case is 4 bytes / Unicode char */
|
||||
|
||||
#define PATH_MAX UNICODE_PATH_MAX /* MsvcLibX uses Unicode internally for file management */
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
/************************* OS/2-specific definitions *************************/
|
||||
|
||||
#ifdef _OS2 /* Automatically defined when targeting an OS/2 application? */
|
||||
|
||||
#endif /* defined(_OS2) */
|
||||
|
||||
/********************** End of OS-specific definitions ***********************/
|
||||
|
||||
#endif /* defined(_MSVCLIBX_LIMITS_H) */
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: netdb.h *
|
||||
* *
|
||||
* Description: Network definitions *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-01-24 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _NETDB_H
|
||||
#define _NETDB_H 1
|
||||
|
||||
/* Absolute file name for network data base files. */
|
||||
#define _PATH_HOSTS "C:/Windows/System32/drivers/etc/hosts"
|
||||
#define _PATH_NETWORKS "C:/Windows/System32/drivers/etc/networks"
|
||||
#define _PATH_PROTOCOLS "C:/Windows/System32/drivers/etc/protocols"
|
||||
#define _PATH_SERVICES "C:/Windows/System32/drivers/etc/services"
|
||||
|
||||
#endif /* _NETDB_H */
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: process.h *
|
||||
* *
|
||||
* Description: MsvcLibX extensions to process.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-03-27 JFL Created this file. *
|
||||
* 2015-11-15 JFL Visual Studio 2015 moved this file to the Windows Kit UCRT.
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVCLIBX_PROCESS_H
|
||||
#define _MSVCLIBX_PROCESS_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include <process.h> /* Include MSVC's own <process.h> file */
|
||||
|
||||
#if defined(_WIN32)
|
||||
extern intptr_t _spawnvpU(int iMode, const char *pszCommand, char *const *argv);
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define _spawnvp _spawnvpU
|
||||
#else /* _ANSI_SOURCE */
|
||||
#define _spawnvp _spawnvp
|
||||
#endif /* defined(_UTF8_SOURCE) */
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
#endif /* defined(_MSVCLIBX_PROCESS_H) */
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
#ifndef _HSREGEX_H_
|
||||
#define _HSREGEX_H_
|
||||
#ifndef _HSREGEX_H
|
||||
#define _HSREGEX_H /* never again */
|
||||
|
||||
#include <sys/types.h> /* JFL 2012-01-24 Added definition of types used below */
|
||||
#pragma comment( lib, "regex.lib" )
|
||||
|
||||
/* ========= begin header generated by ././mkh ========= */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* === regex2.h === */
|
||||
#ifdef WIN32
|
||||
#define API_EXPORT(type) __declspec(dllexport) type __stdcall
|
||||
#elif defined(__GNUC__) && __GNUC__ >= 4
|
||||
#define API_EXPORT(type) __attribute__ ((visibility("default"))) type
|
||||
#else
|
||||
#define API_EXPORT(type) type
|
||||
#endif
|
||||
|
||||
typedef off_t regoff_t;
|
||||
typedef struct {
|
||||
int re_magic;
|
||||
size_t re_nsub; /* number of parenthesized subexpressions */
|
||||
const char *re_endp; /* end pointer for REG_PEND */
|
||||
struct re_guts *re_g; /* none of your business :-) */
|
||||
} regex_t;
|
||||
typedef struct {
|
||||
regoff_t rm_so; /* start of match */
|
||||
regoff_t rm_eo; /* end of match */
|
||||
} regmatch_t;
|
||||
|
||||
|
||||
/* === regcomp.c === */
|
||||
API_EXPORT(int) regcomp(regex_t *, const char *, int);
|
||||
#define REG_BASIC 0000
|
||||
#define REG_EXTENDED 0001
|
||||
#define REG_ICASE 0002
|
||||
#define REG_NOSUB 0004
|
||||
#define REG_NEWLINE 0010
|
||||
#define REG_NOSPEC 0020
|
||||
#define REG_PEND 0040
|
||||
#define REG_DUMP 0200
|
||||
|
||||
|
||||
/* === regerror.c === */
|
||||
#define REG_OKAY 0
|
||||
#define REG_NOMATCH 1
|
||||
#define REG_BADPAT 2
|
||||
#define REG_ECOLLATE 3
|
||||
#define REG_ECTYPE 4
|
||||
#define REG_EESCAPE 5
|
||||
#define REG_ESUBREG 6
|
||||
#define REG_EBRACK 7
|
||||
#define REG_EPAREN 8
|
||||
#define REG_EBRACE 9
|
||||
#define REG_BADBR 10
|
||||
#define REG_ERANGE 11
|
||||
#define REG_ESPACE 12
|
||||
#define REG_BADRPT 13
|
||||
#define REG_EMPTY 14
|
||||
#define REG_ASSERT 15
|
||||
#define REG_INVARG 16
|
||||
#define REG_ATOI 255 /* convert name to number (!) */
|
||||
#define REG_ITOA 0400 /* convert number to name (!) */
|
||||
API_EXPORT(size_t) regerror(int, const regex_t *, char *, size_t);
|
||||
|
||||
|
||||
/* === regexec.c === */
|
||||
API_EXPORT(int) regexec(const regex_t *, const char *, size_t, regmatch_t [], int);
|
||||
#define REG_NOTBOL 00001
|
||||
#define REG_NOTEOL 00002
|
||||
#define REG_STARTEND 00004
|
||||
#define REG_TRACE 00400 /* tracing of execution */
|
||||
#define REG_LARGE 01000 /* force large representation */
|
||||
#define REG_BACKR 02000 /* force use of backref code */
|
||||
|
||||
|
||||
/* === regfree.c === */
|
||||
API_EXPORT(void) regfree(regex_t *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
/* ========= end header generated by ././mkh ========= */
|
||||
#endif
|
||||
#endif
|
|
@ -1,125 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: reparsept.h *
|
||||
* *
|
||||
* Description: Definitions for WIN32 reparse points. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-02-28 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
/* Reparse point iocontrol data buffer */
|
||||
/* See http://msdn.microsoft.com/en-us/library/cc232006.aspx */
|
||||
/* and http://msdn.microsoft.com/en-us/library/cc232007.aspx */
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/* NTFS reparse point definitions */
|
||||
|
||||
/* Constants from http://msdn.microsoft.com/en-us/library/dd541667.aspx */
|
||||
/* Some, but not all, of them also defined in recent versions of winnt.h. */
|
||||
/* Since the list varies a lot, redefine them one by one as needed */
|
||||
|
||||
#ifndef IO_REPARSE_TAG_RESERVED_ZERO
|
||||
#define IO_REPARSE_TAG_RESERVED_ZERO 0x00000000 /* Reserved reparse tag value */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_RESERVED_ONE
|
||||
#define IO_REPARSE_TAG_RESERVED_ONE 0x00000001 /* Reserved reparse tag value */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_MOUNT_POINT
|
||||
#define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 /* Used for mount point support */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_HSM
|
||||
#define IO_REPARSE_TAG_HSM 0xC0000004 /* Obsolete. Used by legacy Hierarchical Storage Manager Product */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_DRIVER_EXTENDER
|
||||
#define IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005 /* Home server drive extender */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_HSM2
|
||||
#define IO_REPARSE_TAG_HSM2 0x80000006 /* Obsolete. Used by legacy Hierarchical Storage Manager Product */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_SIS
|
||||
#define IO_REPARSE_TAG_SIS 0x80000007 /* Used by single-instance storage (SIS) filter driver. Server-side interpretation only, not meaningful over the wire */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_WIM
|
||||
#define IO_REPARSE_TAG_WIM 0x80000008 /* Mounted Windows boot Image File? */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_CSV
|
||||
#define IO_REPARSE_TAG_CSV 0x80000009 /* Cluster Shared Volume? */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_DFS
|
||||
#define IO_REPARSE_TAG_DFS 0x8000000A /* Used by the DFS filter. The DFS is described in the Distributed File System (DFS): Referral Protocol Specification [MS-DFSC]. Server-side interpretation only, not meaningful over the wire */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_FILTER_MANAGER
|
||||
#define IO_REPARSE_TAG_FILTER_MANAGER 0x8000000B /* Used by filter manager test harness */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_SYMLINK
|
||||
#define IO_REPARSE_TAG_SYMLINK 0xA000000C /* Used for symbolic link support */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_DFSR
|
||||
#define IO_REPARSE_TAG_DFSR 0x80000012 /* Used by the DFS filter. The DFS is described in [MS-DFSC]. Server-side interpretation only, not meaningful over the wire */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_DEDUP
|
||||
#define IO_REPARSE_TAG_DEDUP 0x80000013 /* Mounted deduplicated volume? */
|
||||
#endif
|
||||
#ifndef IO_REPARSE_TAG_NFS
|
||||
#define IO_REPARSE_TAG_NFS 0x80000014 /* Mounted NFS share? */
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define IO_REPARSE_TAG_DRIVER_EXTENDER 0x80000005 /* Home server drive extender */
|
||||
#define IO_REPARSE_TAG_FILTER_MANAGER 0x8000000B /* Used by filter manager test harness */
|
||||
#endif
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct _REPARSE_READ_BUFFER {
|
||||
DWORD ReparseTag;
|
||||
WORD ReparseDataLength;
|
||||
WORD Reserved;
|
||||
UCHAR DataBuffer[1];
|
||||
} REPARSE_READ_BUFFER, *PREPARSE_READ_BUFFER;
|
||||
#define REPARSE_READ_BUFFER_HEADER_SIZE (sizeof(REPARSE_READ_BUFFER) - sizeof(UCHAR))
|
||||
|
||||
typedef struct _REPARSE_SYMLINK_READ_BUFFER {
|
||||
DWORD ReparseTag;
|
||||
WORD ReparseDataLength;
|
||||
WORD Reserved;
|
||||
WORD SubstituteNameOffset;
|
||||
WORD SubstituteNameLength;
|
||||
WORD PrintNameOffset;
|
||||
WORD PrintNameLength;
|
||||
ULONG Flags;
|
||||
WCHAR PathBuffer[1];
|
||||
} SYMLINK_READ_BUFFER, *PSYMLINK_READ_BUFFER;
|
||||
#define SYMLINK_READ_BUFFER_HEADER_SIZE (sizeof(SYMLINK_READ_BUFFER) - sizeof(WCHAR))
|
||||
|
||||
typedef struct _REPARSE_MOUNTPOINT_READ_BUFFER {
|
||||
DWORD ReparseTag;
|
||||
WORD ReparseDataLength;
|
||||
WORD Reserved;
|
||||
WORD SubstituteNameOffset;
|
||||
WORD SubstituteNameLength;
|
||||
WORD PrintNameOffset;
|
||||
WORD PrintNameLength;
|
||||
WCHAR PathBuffer[1];
|
||||
} MOUNTPOINT_READ_BUFFER, *PMOUNTPOINT_READ_BUFFER;
|
||||
#define MOUNTPOINT_READ_BUFFER_HEADER_SIZE (sizeof(MOUNTPOINT_READ_BUFFER) - sizeof(WCHAR))
|
||||
|
||||
typedef struct _REPARSE_MOUNTPOINT_WRITE_BUFFER {
|
||||
DWORD ReparseTag;
|
||||
DWORD ReparseDataLength;
|
||||
WORD Reserved;
|
||||
WORD ReparseTargetLength;
|
||||
WORD ReparseTargetMaximumLength;
|
||||
WORD Reserved1;
|
||||
WCHAR ReparseTarget[1];
|
||||
} MOUNTPOINT_WRITE_BUFFER, *PMOUNTPOINT_WRITE_BUFFER;
|
||||
#define MOUNTPOINT_WRITE_BUFFER_HEADER_SIZE (sizeof(MOUNTPOINT_WRITE_BUFFER) - sizeof(WCHAR))
|
||||
#pragma pack()
|
||||
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: stdbool.h *
|
||||
* *
|
||||
* Description: Standard boolean definitions *
|
||||
* *
|
||||
* Notes: Set standard values. May need to be adapted for C++? *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-10-17 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _STDBOOL_H
|
||||
#define _STDBOOL_H
|
||||
|
||||
/* #define bool int /* Spec says _Bool */
|
||||
typedef int bool;
|
||||
#define true 1
|
||||
#define false 0
|
||||
#define __bool_true_false_are_defined 1
|
||||
|
||||
#endif
|
|
@ -1,322 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename stdint.h *
|
||||
* *
|
||||
* Description ISO C9x compliant stdint.h for Microsoft Visual Studio *
|
||||
* *
|
||||
* Notes *
|
||||
* *
|
||||
* ISO C9x compliant stdint.h for Microsoft Visual Studio *
|
||||
* Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 *
|
||||
* *
|
||||
* Copyright (c) 2006-2008 Alexander Chemeris *
|
||||
* *
|
||||
* Redistribution and use in source and binary forms, with or without *
|
||||
* modification, are permitted provided that the following conditions are met: *
|
||||
* *
|
||||
* 1. Redistributions of source code must retain the above copyright notice, *
|
||||
* this list of conditions and the following disclaimer. *
|
||||
* *
|
||||
* 2. Redistributions in binary form must reproduce the above copyright *
|
||||
* notice, this list of conditions and the following disclaimer in the *
|
||||
* documentation and/or other materials provided with the distribution. *
|
||||
* *
|
||||
* 3. The name of the author may be used to endorse or promote products *
|
||||
* derived from this software without specific prior written permission. *
|
||||
* *
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED*
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO *
|
||||
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, *
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,*
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; *
|
||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, *
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR *
|
||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
|
||||
* *
|
||||
* History *
|
||||
* 2008-07-17 AC Initial implementation by Alexander Chemeris. *
|
||||
* 2011-05-23 JFL Added support for 16-bits compilers for MS-DOS. *
|
||||
* 2011-05-28 JFL Added support for 16-bits compilers for MS-DOS. *
|
||||
* 2012-01-18 JFL Added error messages if target is not DOS or Windows. *
|
||||
* 2015-12-04 JFL Define _UINTPTR_T_DEFINED to tell MSVC99 it's done already*
|
||||
* *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#error "Use this header only with Microsoft Visual C++ compilers!"
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifndef _MSC_STDINT_H_
|
||||
#define _MSC_STDINT_H_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
/*
|
||||
// For Visual Studio 6 in C++ mode wrap <wchar.h> include with 'extern "C++" {}'
|
||||
// or compiler give many errors like this:
|
||||
// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
|
||||
*/
|
||||
/* 2015-12-04 JFL Bug fix: With VS14/VC19, MSVC's wchar.h includes inttypes.h,
|
||||
which in turn includes this stdint.h, causing loop issues */
|
||||
#if (_MSC_VER < 1900) && defined(_WIN32) /* Both WIN32 and WIN64 */
|
||||
# if (_MSC_VER < 1300) && defined(__cplusplus)
|
||||
extern "C++" {
|
||||
# endif
|
||||
# include <wchar.h>
|
||||
# if (_MSC_VER < 1300) && defined(__cplusplus)
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* Define _W64 macros to mark types changing their size, like intptr_t. */
|
||||
#ifndef _W64
|
||||
# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||
# define _W64 __w64
|
||||
# else
|
||||
# define _W64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* 7.18.1 Integer types */
|
||||
|
||||
#ifndef _INTEGRAL_MAX_BITS
|
||||
#define _INTEGRAL_MAX_BITS 32
|
||||
#endif
|
||||
|
||||
/* 7.18.1.1 Exact-width integer types */
|
||||
#if defined(_WIN32) /* Both WIN32 and WIN64 */
|
||||
typedef __int8 int8_t;
|
||||
typedef __int16 int16_t;
|
||||
typedef __int32 int32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef unsigned __int16 uint16_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#elif defined(_MSDOS) /* MS-DOS */
|
||||
typedef char int8_t;
|
||||
typedef short int16_t;
|
||||
typedef long int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned long uint32_t;
|
||||
#else
|
||||
#error "I don't know what the integer types are in this case!"
|
||||
#endif
|
||||
|
||||
/* 7.18.1.2 Minimum-width integer types */
|
||||
typedef int8_t int_least8_t;
|
||||
typedef int16_t int_least16_t;
|
||||
typedef int32_t int_least32_t;
|
||||
#ifdef LLONG_MAX
|
||||
typedef int64_t int_least64_t;
|
||||
#endif
|
||||
typedef uint8_t uint_least8_t;
|
||||
typedef uint16_t uint_least16_t;
|
||||
typedef uint32_t uint_least32_t;
|
||||
#ifdef LLONG_MAX
|
||||
typedef uint64_t uint_least64_t;
|
||||
#endif
|
||||
|
||||
/* 7.18.1.3 Fastest minimum-width integer types */
|
||||
typedef int8_t int_fast8_t;
|
||||
typedef int16_t int_fast16_t;
|
||||
typedef int32_t int_fast32_t;
|
||||
#ifdef LLONG_MAX
|
||||
typedef int64_t int_fast64_t;
|
||||
#endif
|
||||
typedef uint8_t uint_fast8_t;
|
||||
typedef uint16_t uint_fast16_t;
|
||||
typedef uint32_t uint_fast32_t;
|
||||
#ifdef LLONG_MAX
|
||||
typedef uint64_t uint_fast64_t;
|
||||
#endif
|
||||
|
||||
/* 7.18.1.4 Integer types capable of holding object pointers */
|
||||
#if defined(_WIN64) /* _WIN64 */
|
||||
# define _POINTER_BITS 64
|
||||
typedef __int64 intptr_t;
|
||||
typedef unsigned __int64 uintptr_t;
|
||||
#elif defined(_WIN32) /* _WIN32 */
|
||||
# define _POINTER_BITS 32
|
||||
typedef _W64 int intptr_t;
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#elif defined(_MSDOS) /* _MSDOS */
|
||||
# if defined(_M_I86TM) || defined(_M_I86SM) /* Tiny or short memory models */
|
||||
# define _POINTER_BITS 16
|
||||
typedef int intptr_t;
|
||||
typedef unsigned int uintptr_t;
|
||||
# else /* Compact, medium, large or huge memory models */
|
||||
# define _POINTER_BITS 32
|
||||
typedef long intptr_t;
|
||||
typedef unsigned long uintptr_t;
|
||||
# endif
|
||||
#else
|
||||
#error "I don't know what the pointer types are in this case!"
|
||||
#endif /* _WIN64 */
|
||||
#define _INTPTR_T_DEFINED
|
||||
#define _UINTPTR_T_DEFINED /* Prevent MSVC99 from redefining it */
|
||||
|
||||
/* 7.18.1.5 Greatest-width integer types */
|
||||
#ifdef LLONG_MAX
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
#else
|
||||
typedef int32_t intmax_t;
|
||||
typedef uint32_t uintmax_t;
|
||||
#endif
|
||||
|
||||
|
||||
/* 7.18.2 Limits of specified-width integer types */
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) /* See footnote 220 at page 257 and footnote 221 at page 259 */
|
||||
|
||||
#ifdef _MSDOS
|
||||
#define _I8_MIN SCHAR_MIN /* minimum signed 8 bit value */
|
||||
#define _I8_MAX SCHAR_MAX /* maximum signed 8 bit value */
|
||||
#define _UI8_MAX UCHAR_MAX /* maximum unsigned 8 bit value */
|
||||
|
||||
#define _I16_MIN SHRT_MIN /* minimum signed 16 bit value */
|
||||
#define _I16_MAX SHRT_MAX /* maximum signed 16 bit value */
|
||||
#define _UI16_MAX USHRT_MAX /* maximum unsigned 16 bit value */
|
||||
|
||||
#define _I32_MIN LONG_MIN /* minimum signed 32 bit value */
|
||||
#define _I32_MAX LONG_MAX /* maximum signed 32 bit value */
|
||||
#define _UI32_MAX ULONG_MAX /* maximum unsigned 32 bit value */
|
||||
#endif
|
||||
|
||||
/* 7.18.2.1 Limits of exact-width integer types */
|
||||
#define INT8_MIN ((int8_t)_I8_MIN)
|
||||
#define INT8_MAX _I8_MAX
|
||||
#define INT16_MIN ((int16_t)_I16_MIN)
|
||||
#define INT16_MAX _I16_MAX
|
||||
#define INT32_MIN ((int32_t)_I32_MIN)
|
||||
#define INT32_MAX _I32_MAX
|
||||
#ifdef LLONG_MAX
|
||||
#define INT64_MIN ((int64_t)_I64_MIN)
|
||||
#define INT64_MAX _I64_MAX
|
||||
#endif
|
||||
#define UINT8_MAX _UI8_MAX
|
||||
#define UINT16_MAX _UI16_MAX
|
||||
#define UINT32_MAX _UI32_MAX
|
||||
#ifdef LLONG_MAX
|
||||
#define UINT64_MAX _UI64_MAX
|
||||
#endif
|
||||
|
||||
/* 7.18.2.2 Limits of minimum-width integer types */
|
||||
#define INT_LEAST8_MIN INT8_MIN
|
||||
#define INT_LEAST8_MAX INT8_MAX
|
||||
#define INT_LEAST16_MIN INT16_MIN
|
||||
#define INT_LEAST16_MAX INT16_MAX
|
||||
#define INT_LEAST32_MIN INT32_MIN
|
||||
#define INT_LEAST32_MAX INT32_MAX
|
||||
#ifdef LLONG_MAX
|
||||
#define INT_LEAST64_MIN INT64_MIN
|
||||
#define INT_LEAST64_MAX INT64_MAX
|
||||
#endif
|
||||
#define UINT_LEAST8_MAX UINT8_MAX
|
||||
#define UINT_LEAST16_MAX UINT16_MAX
|
||||
#define UINT_LEAST32_MAX UINT32_MAX
|
||||
#ifdef LLONG_MAX
|
||||
#define UINT_LEAST64_MAX UINT64_MAX
|
||||
#endif
|
||||
|
||||
/* 7.18.2.3 Limits of fastest minimum-width integer types */
|
||||
#define INT_FAST8_MIN INT8_MIN
|
||||
#define INT_FAST8_MAX INT8_MAX
|
||||
#define INT_FAST16_MIN INT16_MIN
|
||||
#define INT_FAST16_MAX INT16_MAX
|
||||
#define INT_FAST32_MIN INT32_MIN
|
||||
#define INT_FAST32_MAX INT32_MAX
|
||||
#ifdef LLONG_MAX
|
||||
#define INT_FAST64_MIN INT64_MIN
|
||||
#define INT_FAST64_MAX INT64_MAX
|
||||
#endif
|
||||
#define UINT_FAST8_MAX UINT8_MAX
|
||||
#define UINT_FAST16_MAX UINT16_MAX
|
||||
#define UINT_FAST32_MAX UINT32_MAX
|
||||
#ifdef LLONG_MAX
|
||||
#define UINT_FAST64_MAX UINT64_MAX
|
||||
#endif
|
||||
|
||||
/* 7.18.2.4 Limits of integer types capable of holding object pointers */
|
||||
#define INTPTR_MIN INT##_POINTER_BITS##MIN
|
||||
#define INTPTR_MAX INT##_POINTER_BITS##_MAX
|
||||
#define UINTPTR_MAX UINT##_POINTER_BITS##_MAX
|
||||
|
||||
/* 7.18.2.5 Limits of greatest-width integer types */
|
||||
#ifdef LLONG_MAX
|
||||
#define INTMAX_MIN INT64_MIN
|
||||
#define INTMAX_MAX INT64_MAX
|
||||
#define UINTMAX_MAX UINT64_MAX
|
||||
#else
|
||||
#define INTMAX_MIN INT32_MIN
|
||||
#define INTMAX_MAX INT32_MAX
|
||||
#define UINTMAX_MAX UINT32_MAX
|
||||
#endif
|
||||
|
||||
/* 7.18.3 Limits of other integer types */
|
||||
#define PTRDIFF_MIN _I##_POINTER_BITS##_MIN
|
||||
#define PTRDIFF_MAX _I##_POINTER_BITS##_MAX
|
||||
|
||||
#define SIG_ATOMIC_MIN INT_MIN
|
||||
#define SIG_ATOMIC_MAX INT_MAX
|
||||
|
||||
#ifndef SIZE_MAX
|
||||
# define SIZE_MAX _UI##_POINTER_BITS##_MAX
|
||||
#endif
|
||||
|
||||
/* WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h> */
|
||||
#ifndef WCHAR_MIN
|
||||
# define WCHAR_MIN 0
|
||||
#endif
|
||||
#ifndef WCHAR_MAX
|
||||
# define WCHAR_MAX _UI16_MAX
|
||||
#endif
|
||||
|
||||
#define WINT_MIN 0
|
||||
#define WINT_MAX _UI16_MAX
|
||||
|
||||
#endif /* __STDC_LIMIT_MACROS */
|
||||
|
||||
|
||||
/* 7.18.4 Limits of other integer types */
|
||||
|
||||
#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) /* See footnote 224 at page 260 */
|
||||
|
||||
/* 7.18.4.1 Macros for minimum-width integer constants */
|
||||
|
||||
#define INT8_C(val) val##i8
|
||||
#define INT16_C(val) val##i16
|
||||
#define INT32_C(val) val##i32
|
||||
#ifdef LLONG_MAX
|
||||
#define INT64_C(val) val##i64
|
||||
#endif
|
||||
|
||||
#define UINT8_C(val) val##ui8
|
||||
#define UINT16_C(val) val##ui16
|
||||
#define UINT32_C(val) val##ui32
|
||||
#ifdef LLONG_MAX
|
||||
#define UINT64_C(val) val##ui64
|
||||
#endif
|
||||
|
||||
/* 7.18.4.2 Macros for greatest-width integer constants */
|
||||
#ifdef LLONG_MAX
|
||||
#define INTMAX_C INT64_C
|
||||
#define UINTMAX_C UINT64_C
|
||||
#else
|
||||
#define INTMAX_C INT32_C
|
||||
#define UINTMAX_C UINT32_C
|
||||
#endif
|
||||
|
||||
#endif /* __STDC_CONSTANT_MACROS */
|
||||
|
||||
|
||||
#endif /* _MSC_STDINT_H_ */
|
|
@ -1,125 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: stdio.h *
|
||||
* *
|
||||
* Description: MsvcLibX extensions to stdio.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-06-03 JFL Created this file. *
|
||||
* 2015-11-15 JFL Visual Studio 2015 moved this file to the Windows Kit UCRT.
|
||||
* 2015-12-09 JFL Alias fputs to fputsU, and vfprintf to vfprintfU. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVCLIBX_stdio_H
|
||||
#define _MSVCLIBX_stdio_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include <stdio.h> /* Include MSVC's own <stdio.h> file */
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define snprintf _snprintf /* This one _is_ standard */
|
||||
#define popen _popen /* This one _is_ standard */
|
||||
#define pclose _pclose /* This one _is_ standard */
|
||||
|
||||
/************************ MS-DOS-specific definitions ************************/
|
||||
|
||||
#ifdef _MSDOS /* Automatically defined when targeting an MS-DOS application */
|
||||
|
||||
/* Define functions fseeko and ftello */
|
||||
#if defined(_LARGEFILE_SOURCE)
|
||||
#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
|
||||
/* TO DO: Windows 95 has extended functions for handling 64-bits files sizes */
|
||||
#else
|
||||
#endif
|
||||
/* For now, use the MSVC 32-bits functions in all cases */
|
||||
#define fseeko fseek
|
||||
#define ftello ftell
|
||||
#endif
|
||||
|
||||
/* Define standard 64-bits functions */
|
||||
#if defined(_LARGEFILE_SOURCE64)
|
||||
#define fseeko64 _fseek
|
||||
#define ftello64 _ftell
|
||||
#endif
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
/************************ Win32-specific definitions *************************/
|
||||
|
||||
#ifdef _WIN32 /* Automatically defined when targeting a Win32 application */
|
||||
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define vfprintf vfprintfU /* For outputing UTF-8 strings */
|
||||
#define fprintf fprintfU /* For outputing UTF-8 strings */
|
||||
#define printf printfU /* For outputing UTF-8 strings */
|
||||
#define fputs fputsU /* For outputing UTF-8 strings */
|
||||
/* The UTF-8 output routines are defined in iconv.c */
|
||||
extern int vfprintfU(FILE *f, const char *pszFormat, va_list vl);
|
||||
extern int fprintfU(FILE *f, const char *pszFormat, ...);
|
||||
extern int printfU(const char *pszFormat, ...);
|
||||
extern int fputsU(const char *buf, FILE *f);
|
||||
extern UINT codePage;
|
||||
#endif
|
||||
|
||||
/* Define functions fseeko and ftello */
|
||||
#if defined(_LARGEFILE_SOURCE)
|
||||
#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
|
||||
#define fseeko _fseeki64 /* _CONCAT(_fseeki64,_NS_SUFFIX) */
|
||||
#define ftello _ftelli64 /* _CONCAT(_ftelli64,_NS_SUFFIX) */
|
||||
#else
|
||||
#define fseeko fseek
|
||||
#define ftello ftell
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Define standard 64-bits functions */
|
||||
#if defined(_LARGEFILE_SOURCE64)
|
||||
#define fseeko64 _fseeki64 /* _CONCAT(_fseeki64,_NS_SUFFIX) */
|
||||
#define ftello64 _ftelli64 /* _CONCAT(_ftelli64,_NS_SUFFIX) */
|
||||
#endif
|
||||
|
||||
#define fileno _fileno /* Avoid a warning about the deprecated name */
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
/************************* OS/2-specific definitions *************************/
|
||||
|
||||
#ifdef _OS2 /* Automatically defined when targeting an OS/2 application? */
|
||||
|
||||
/* Define functions fseeko and ftello */
|
||||
#if defined(_LARGEFILE_SOURCE)
|
||||
#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
|
||||
#else
|
||||
#endif
|
||||
#define fseeko fseek
|
||||
#define ftello ftell
|
||||
#endif
|
||||
|
||||
/* Define standard 64-bits functions */
|
||||
#if defined(_LARGEFILE_SOURCE64)
|
||||
/* For now, hide the fact that DOS does not support 64-bits lengths */
|
||||
#define fseeko64 _fseek
|
||||
#define ftello64 _ftell
|
||||
#endif
|
||||
|
||||
#endif /* defined(_OS2) */
|
||||
|
||||
/********************** End of OS-specific definitions ***********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* defined(_MSVCLIBX_stdio_H) */
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: stdlib.h *
|
||||
* *
|
||||
* Description: MsvcLibX extensions to stdlib.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2016-09-13 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVCLIBX_stdlib_H
|
||||
#define _MSVCLIBX_stdlib_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include <stdlib.h> /* Include MSVC's own <stdlib.h> file */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/************************ MS-DOS-specific definitions ************************/
|
||||
|
||||
#ifdef _MSDOS /* Automatically defined when targeting an MS-DOS application */
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
/************************ Win32-specific definitions *************************/
|
||||
|
||||
#ifdef _WIN32 /* Automatically defined when targeting a Win32 application */
|
||||
|
||||
extern char *_fullpathU(char *absPath, const char *relPath, size_t maxLength);
|
||||
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define _fullpath _fullpathU /* For processing UTF-8 pathnames */
|
||||
#endif
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
/********************** End of OS-specific definitions ***********************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* defined(_MSVCLIBX_stdlib_H) */
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
/* CoreUtils global system configuration definitions */
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: time.h *
|
||||
* *
|
||||
* Description: MsvcLibX extensions to time.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-06-04 JFL Created this file. *
|
||||
* 2015-11-15 JFL Visual Studio 2015 moved this file to the Windows Kit UCRT.
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVCLIBX_TIME_H
|
||||
#define _MSVCLIBX_TIME_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include <winsock2.h>
|
||||
#include <time.h> /* Include MSVC's own <time.h> file */
|
||||
|
||||
|
||||
#ifdef _MSDOS
|
||||
|
||||
/* Check for the definition of _STRUCT_TIMESPEC before using clock_gettime().
|
||||
If it's not defined, use time() instead, which is supported by all OSs. */
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "sys\msvcTime.h" /* for struct timespec */
|
||||
|
||||
typedef int clockid_t;
|
||||
/* Supported values for clockid_t */
|
||||
#define CLOCK_REALTIME 0
|
||||
#define CLOCK_MONOTONIC 1
|
||||
|
||||
int clock_gettime(clockid_t clock_id, struct timespec *tp);
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
#endif /* defined(_MSVCLIBX_TIME_H) */
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: unistd.h *
|
||||
* *
|
||||
* Description: DOS/WIN32 port of standard C library's unistd.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-01-18 JFL Created this file. *
|
||||
* 2012-10-17 JFL Added standard functions getcwd, chdir, getpid, access. *
|
||||
* Added Microsoft-specific functions getdrive, chdrive. *
|
||||
* 2013-03-27 JFL Updated getpid() and added getppid(). *
|
||||
* 2014-02-03 JFL Added readlink(). *
|
||||
* 2014-03-20 JFL Restructured Windows link management functions into Wide *
|
||||
* and MultiByte versions, and changed the Unicode and Ansi *
|
||||
* versions to macros. *
|
||||
* 2014-06-30 JFL Moved PATH_MAX definition to limits.h. *
|
||||
* 2016-08-25 JFL Implemented ResolveLinksA(). *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _UNISTD_H
|
||||
#define _UNISTD_H
|
||||
|
||||
#ifndef _MSC_VER
|
||||
#error This include file is designed for use with the Microsoft C tools only.
|
||||
#endif
|
||||
|
||||
#include "msvclibx.h" /* Generate a library search record to load MsvcLibX.lib. */
|
||||
#include "sys/msvcTypes.h" /* Define pid_t and getppid(). */
|
||||
#include "msvcDirent.h" /* Define pid_t and getppid(). */
|
||||
#include <direct.h> /* For functions like _chdir() and _getcwd() */
|
||||
#include <process.h> /* For _getpid() */
|
||||
|
||||
/* Microsoft tools think these are non standard, but they are standard! */
|
||||
/* #define getcwd _getcwd */
|
||||
/* #define chdir _chdir */
|
||||
/* Actually use the improved versions in MsvcLibX */
|
||||
#undef getcwd /* MSVC _does_ define a getcwd macro, in addition to the getcwd function! */
|
||||
#if defined(_MSDOS)
|
||||
#define getcwd(path, size) _getcwd(path, (int)(size)) /* Use MSVC LIB's own, changing argument 2 type */
|
||||
#elif defined(_WIN32)
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define getcwd getcwdU
|
||||
#define _getdcwd _getdcwdU
|
||||
#define chdir chdirU
|
||||
#else /* _ANSI_SOURCE */
|
||||
#define getcwd getcwdA
|
||||
#define _getdcwd _getdcwdA
|
||||
#define chdir chdirA
|
||||
#endif
|
||||
char *getcwdA(char *buf, size_t bufSize); /* Can't use the getcwd name, as MSVC has an incompatible prototype for it */
|
||||
char *_getdcwdA(int iDrive, char *buf, int iBuflen);
|
||||
char *getcwdU(char *buf, size_t bufSize); /* Can't use the getcwd name, as MSVC has an incompatible prototype for it */
|
||||
char *_getdcwdU(int iDrive, char *buf, int iBuflen);
|
||||
#endif /* defined(_MSDOS) */
|
||||
int chdir(const char *path);
|
||||
|
||||
/* These are non standard indeed, but the leading _ is annoying */
|
||||
#define getdrive _getdrive
|
||||
#define chdrive _chdrive
|
||||
|
||||
#include <io.h> /* For low level I/O functions like read() & write() */
|
||||
|
||||
/* Microsoft tools think access is non standard, but it is standard! */
|
||||
#if defined(_MSDOS)
|
||||
#define access _access
|
||||
#elif defined(_WIN32)
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define access _accessU
|
||||
int _accessU(const char *pszFilename, int iAccessMode);
|
||||
#else /* _ANSI_SOURCE */
|
||||
#define access _access
|
||||
#endif
|
||||
#endif
|
||||
#define F_OK 0 /* test for the existence of the file */
|
||||
#define X_OK 1 /* test for execute permission */
|
||||
#define R_OK 2 /* test for read permission */
|
||||
#define W_OK 4 /* test for read permission */
|
||||
|
||||
/* getpid() and getppid() */
|
||||
#define getpid() ((pid_t)(_getpid()))
|
||||
pid_t getppid(void); /* Get parent PID */
|
||||
/* Contrary to in Unix, the above functions can fail in Windows. In this case they return INVALID_PID. */
|
||||
#define INVALID_PID ((pid_t)-1L)
|
||||
|
||||
/* Path management */
|
||||
#if defined(_WIN32)
|
||||
#define realpath realpathU
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
// #define realpath realpathU
|
||||
#define CompactPath CompactPathU
|
||||
#else /* _ANSI_SOURCE */
|
||||
// #define realpath realpathA
|
||||
#define CompactPath CompactPathA
|
||||
#endif
|
||||
#endif /* defined(_WIN32) */
|
||||
char *realpath(const char *path, char *buf); /* Posix routine, normally defined in stdlib.h. Output buf must contain PATH_MAX bytes */
|
||||
int CompactPath(const char *path, char *outbuf, size_t bufsize); /* A proprietary subroutine, that cleans up . and .. parts. */
|
||||
|
||||
/* Signed size type */
|
||||
#ifndef _SSIZE_T_DEFINED
|
||||
#if defined(_MSDOS)
|
||||
typedef int ssize_t;
|
||||
#elif defined(_WIN32)
|
||||
#include <stdint.h>
|
||||
#ifdef _WIN64
|
||||
typedef __int64 ssize_t;
|
||||
#else
|
||||
typedef _W64 int ssize_t;
|
||||
#endif /* defined(_WIN64) */
|
||||
#endif /* defined(_WIN32) */
|
||||
#define _SSIZE_T_DEFINED
|
||||
#endif /* !_SSIZE_T_DEFINED */
|
||||
|
||||
/* Link management functions */
|
||||
#if defined(_WIN32)
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define readlink readlinkU
|
||||
#define symlink symlinkU
|
||||
#define symlinkd symlinkdU
|
||||
#define junction junctionU
|
||||
#define GetReparseTag GetReparseTagU
|
||||
#define ResolveLinks ResolveLinksU
|
||||
#else /* _ANSI_SOURCE */
|
||||
#define readlink readlinkA
|
||||
#define symlink symlinkA
|
||||
#define symlinkd symlinkdA
|
||||
#define junction junctionA
|
||||
#define GetReparseTag GetReparseTagA
|
||||
#define ResolveLinks ResolveLinksA
|
||||
#endif
|
||||
ssize_t readlinkW(const WCHAR *path, WCHAR *buf, size_t bufsiz); /* Posix routine readlink - Wide char version */
|
||||
ssize_t readlinkM(const char *path, char *buf, size_t bufsiz, UINT cp); /* Posix routine readlink - Multibyte char version */
|
||||
#define readlinkA(path, buf, bufsiz) readlinkM(path, buf, bufsiz, CP_ACP) /* Posix routine readlink - ANSI version */
|
||||
#define readlinkU(path, buf, bufsiz) readlinkM(path, buf, bufsiz, CP_UTF8) /* Posix routine readlink - UTF-8 version */
|
||||
int symlinkW(const WCHAR *targetname, const WCHAR *newlinkname); /* Posix routine symlink - Wide char version */
|
||||
int symlinkM(const char *targetname, const char *newlinkname, UINT cp); /* Posix routine symlink - Multibyte char version */
|
||||
#define symlinkA(target, newlink) symlinkM(target, newlink, CP_ACP) /* Posix routine symlink - ANSI version */
|
||||
#define symlinkU(target, newlink) symlinkM(target, newlink, CP_UTF8) /* Posix routine symlink - UTF-8 version */
|
||||
int symlinkdW(const WCHAR *targetname, const WCHAR *newlinkname); /* MsvcLibX Create an NTFS symlinkd - Wide char version */
|
||||
int symlinkdM(const char *targetname, const char *newlinkname, UINT cp); /* MsvcLibX Create an NTFS symlinkd - Multibyte char version */
|
||||
#define symlinkdA(target, newlink) symlinkdM(target, newlink, CP_ACP) /* MsvcLibX Create an NTFS symlinkd - ANSI version */
|
||||
#define symlinkdU(target, newlink) symlinkdM(target, newlink, CP_UTF8) /* MsvcLibX Create an NTFS symlinkd - UTF-8 version */
|
||||
int junctionW(const WCHAR *targetname, const WCHAR *junctionName); /* MsvcLibX Create an NTFS junction - Wide char version */
|
||||
int junctionM(const char *targetname, const char *junctionName, UINT cp); /* MsvcLibX Create an NTFS junction - Multibyte char version */
|
||||
#define junctionA(target, newjunc) junctionM(target, newjunc, CP_ACP) /* MsvcLibX Create an NTFS junction - ANSI version */
|
||||
#define junctionU(target, newjunc) junctionM(target, newjunc, CP_UTF8) /* MsvcLibX Create an NTFS junction - UTF-8 version */
|
||||
DWORD GetReparseTagW(const WCHAR *path); /* MsvcLibX Get a Repase Point tag - Wide char version */
|
||||
DWORD GetReparseTagM(const char *path, UINT cp); /* MsvcLibX Get a Repase Point tag - MultiByte char version */
|
||||
#define GetReparseTagA(path) GetReparseTagM(path, CP_ACP) /* MsvcLibX Get a Repase Point tag - ANSI version */
|
||||
#define GetReparseTagU(path) GetReparseTagM(path, CP_UTF8) /* MsvcLibX Get a Repase Point tag - ANSI version */
|
||||
int ResolveLinksA(const char *path, char *buf, size_t bufsize); /* Resolve pathnames with symlinks, symlinkds, and junctions */
|
||||
int ResolveLinksU(const char *path, char *buf, size_t bufsize); /* Resolve pathnames with symlinks, symlinkds, and junctions */
|
||||
#ifndef ELOOP
|
||||
/*
|
||||
// Unix defines ELOOP as errno 40.
|
||||
// MS Visual C++ 1.52 for DOS is standard up to errno 34, then diverges up to errno 36.
|
||||
// Many errnos within the list are actually unused, and for them _sys_errlist[] = "".
|
||||
// MS Visual C++ 9 for Windows is standard up to errno 34, then diverges up to errno 43.
|
||||
// Also MSVC9 does not define errno:
|
||||
// 15 // The posix standard ENOTBLK "Block device required"
|
||||
// 26 // The posix standard ETXTBSY "Text file busy"
|
||||
// 35 // Positioned between standard ERANGE and EDEADLK
|
||||
// 37 // Positioned between standard EDEADLK and ENAMETOOLONG
|
||||
// 43 // Positioned last, after standard ENOTEMPTY
|
||||
// The _sys_errlist[] pointer for all the above points to a single string "Unknown error".
|
||||
*/
|
||||
#define ELOOP 35 /* Using the first available slot */ /* Update _sys_errlist[ELOOP] accordingly in any routine that generates ELOOP! */
|
||||
#endif /* !defined(ELOOP) */
|
||||
#define SYMLOOP_MAX 31 /* Maximum depth of symbolic name resolution, to avoid stack overflows. Windows is documented to allow 31: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365460(v=vs.85).aspx */
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
/* Standard file descriptor numbers, for low level I/O functions */
|
||||
#define STDIN_FILENO 0 /* Standard input file number */
|
||||
#define STDOUT_FILENO 1 /* Standard output file number */
|
||||
#define STDERR_FILENO 2 /* Standard error file number */
|
||||
|
||||
#endif /* _UNISTD_H */
|
||||
|
|
@ -1,86 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: utime.h *
|
||||
* *
|
||||
* Description: DOS/WIN32 adaptation of standard C library's utime.h. *
|
||||
* *
|
||||
* Notes: The Unix standard now standardizes utime.h location in *
|
||||
* the include directory itself. *
|
||||
* Microsoft put it in the include/sys subdirectory. *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-12-13 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVXLIBX_UTIME_H
|
||||
#define _MSVXLIBX_UTIME_H
|
||||
|
||||
/* In MS-DOS, simply use MSVC's sys/utime.h. */
|
||||
|
||||
#ifdef _MSDOS
|
||||
|
||||
#include <sys/utime.h>
|
||||
|
||||
#define lutime utime /* There are no links in MS-DOS, so lutime() is the same as utime() */
|
||||
|
||||
#endif /* _MSDOS */
|
||||
|
||||
|
||||
/* In Windows, we use MSVC's sys/utime.h, but redefine the utime*() functions. */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include "msvclibx.h" /* Generate a library search record to load MsvcLibX.lib. */
|
||||
|
||||
/* Save the initial definition and value of __STDC__ */
|
||||
#ifdef __STDC__
|
||||
#define _UTIME__STDC__WAS_DEFINED 1
|
||||
#pragma push_macro("__STDC__")
|
||||
#undef __STDC__
|
||||
#else
|
||||
#define _UTIME__STDC__WAS_DEFINED 0
|
||||
#endif
|
||||
|
||||
#define __STDC__ 1 /* Prevents <sys/utime.h> from defining structures and functions without _ */
|
||||
|
||||
#include <sys/utime.h>
|
||||
|
||||
#ifdef _USE_32BIT_TIME_T
|
||||
#define utimbuf __utimbuf32
|
||||
#define utime _utime32x
|
||||
#error "32-bits time_t not supported in MsvcLibX' utime."
|
||||
#else
|
||||
#define utimbuf __utimbuf64
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define utime utimeU
|
||||
#define lutime lutimeU
|
||||
#else /* _ANSI_SOURCE */
|
||||
#define utime utimeA
|
||||
#define lutime lutimeA
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Our redefinition in utime.c */
|
||||
int utimeA(const char * pszFilename, const struct utimbuf * pUtimbuf);
|
||||
int lutimeA(const char * pszFilename, const struct utimbuf * pUtimbuf);
|
||||
int utimeU(const char * pszFilename, const struct utimbuf * pUtimbuf);
|
||||
int lutimeU(const char * pszFilename, const struct utimbuf * pUtimbuf);
|
||||
int utimeW(const WCHAR * pszFilename, const struct utimbuf * pUtimbuf);
|
||||
int lutimeW(const WCHAR * pszFilename, const struct utimbuf * pUtimbuf);
|
||||
int futime(int fd, const struct utimbuf * pUtimbuf);
|
||||
|
||||
#undef __STDC__
|
||||
|
||||
/* Restore the initial definition and value of __STDC__ */
|
||||
#if _UTIME__STDC__WAS_DEFINED
|
||||
#pragma pop_macro("__STDC__")
|
||||
#endif
|
||||
#undef _UTIME__STDC__WAS_DEFINED
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#endif /* _MSVXLIBX_UTIME_H */
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: windows.h *
|
||||
* *
|
||||
* Description: Define MsvcLibX' extensions to the WIN32 API functions *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2016-09-12 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVCLIBX_WINDOWS_H
|
||||
#define _MSVCLIBX_WINDOWS_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h> /* Include Windows SDK's own windows.h */
|
||||
|
||||
/****************** Define UTF-8 versions of WIN32 routines ******************/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DWORD WINAPI GetFileAttributesU(LPCTSTR lpFileName);
|
||||
BOOL WINAPI GetFileAttributesExU(LPCTSTR lpFileName, GET_FILEEX_INFO_LEVELS fInfoLevelId, LPVOID lpFileInformation);
|
||||
DWORD WINAPI GetFullPathNameU(LPCTSTR lpName, DWORD nBufferLength, LPTSTR lpBuf, LPTSTR *lpFilePart);
|
||||
DWORD WINAPI GetLongPathNameU(LPCTSTR lpShortName, LPTSTR lpBuf, DWORD nBufferLength);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
/********** Redefine the legacy names to point to the UTF-8 version **********/
|
||||
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
|
||||
#undef GetFileAttributes
|
||||
#define GetFileAttributes GetFileAttributesU
|
||||
|
||||
#undef GetFileAttributesEx
|
||||
#define GetFileAttributesEx GetFileAttributesExU
|
||||
|
||||
#undef GetFullPathName
|
||||
#define GetFullPathName GetFullPathNameU
|
||||
|
||||
#undef GetLongPathName
|
||||
#define GetLongPathName GetLongPathNameU
|
||||
|
||||
#endif /* defined(_UTF8_SOURCE) ... */
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
#endif /* defined(_MSVCLIBX_WINDOWS_H) */
|
|
@ -1,19 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: error.h *
|
||||
* *
|
||||
* Description: DOS/WIN32 port of the GNU CoreUtils library xfreopen func.*
|
||||
* *
|
||||
* Notes: msvclibx: Implement using freopen or _setmode. *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-02-10 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#include "msvclibx.h" /* Generate a library search record to load MsvcLibX.lib. */
|
||||
|
||||
extern FILE *xfreopen(const char *filename, const char *mode, FILE *stream);
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename MsvcLibX.h *
|
||||
* *
|
||||
* Description MsvcLibX-specific definitions *
|
||||
* *
|
||||
* Notes Generates a library search record to load MsvcLibX.lib. *
|
||||
* *
|
||||
* History: *
|
||||
* 2013 JFL Created this file. *
|
||||
* 2014-05-30 JFL Added macros to work around the lack of a #include_next. *
|
||||
* 2015-11-15 JFL Added macro UCRT_INCLUDE_FILE for Visual Studio 2015. *
|
||||
* 2016-09-15 JFL Added macro WINSDK_INCLUDE_FILE for Windows SDK. *
|
||||
* 2016-09-20 JFL Added workaround preventing warnings in WIN95 builds. *
|
||||
* 2016-09-28 JFL Can also be included by MS' Resource Compiler. *
|
||||
* 2017-02-05 JFL Changed the UTF-8 programs initialization method. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
/* Generate a library search record to load MsvcLibX.lib */
|
||||
|
||||
#ifndef _MSVCLIBX_H_
|
||||
#define _MSVCLIBX_H_
|
||||
|
||||
#if !(defined(_MSC_VER) || defined(RC_INVOKED))
|
||||
#error The msvclibx library is designed for use with the Microsoft Visual C/C++ tools only.
|
||||
#endif
|
||||
|
||||
/* Compute the OS-specific suffix */
|
||||
#if defined(_WIN64)
|
||||
# define _MSVCLIBX_LIB_OS_SUFFIX "w64"
|
||||
#elif defined(_WIN95)
|
||||
# define _MSVCLIBX_LIB_OS_SUFFIX "w95"
|
||||
#elif defined(_WIN32)
|
||||
# define _MSVCLIBX_LIB_OS_SUFFIX "w32"
|
||||
#elif defined(_MSDOS)
|
||||
# if defined(_M_I86TM)
|
||||
# define _MSVCLIBX_LIB_OS_SUFFIX "dt"
|
||||
# elif defined(_M_I86SM)
|
||||
# define _MSVCLIBX_LIB_OS_SUFFIX "ds"
|
||||
# elif defined(_M_I86LM)
|
||||
# define _MSVCLIBX_LIB_OS_SUFFIX "dl"
|
||||
# else
|
||||
# error No msvclibx.lib version yet for this DOS memory model.
|
||||
# endif
|
||||
#else
|
||||
# error No msvclibx.lib version for this target OS.
|
||||
#endif
|
||||
|
||||
/* Compute the debug-mode-specific suffix */
|
||||
#if defined(_DEBUG)
|
||||
# define _MSVCLIBX_LIB_DBG_SUFFIX "d"
|
||||
#else
|
||||
# define _MSVCLIBX_LIB_DBG_SUFFIX ""
|
||||
#endif
|
||||
|
||||
/* Generate the OS-and-debug-mode-specific library name */
|
||||
#define _MSVCLIBX_LIB "MsvcLibX" _MSVCLIBX_LIB_OS_SUFFIX _MSVCLIBX_LIB_DBG_SUFFIX ".lib"
|
||||
//#pragma message("Adding pragma comment(lib, \"" _MSVCLIBX_LIB "\")")
|
||||
//#pragma comment(lib, _MSVCLIBX_LIB)
|
||||
|
||||
/* Library-specific routine used internally by many standard routines */
|
||||
#if defined(_WIN32)
|
||||
extern int Win32ErrorToErrno(); /* Converts the last WIN32 error to a Posix error code */
|
||||
#ifndef ELOOP /* Defined in VS10's errno.h, but not in VS9 */
|
||||
#define ELOOP 114
|
||||
#endif
|
||||
/* Convert an ANSI or UTF-8 or OEM pathname to a Unicode string. Defined in mb2wpath.c. */
|
||||
typedef unsigned int UINT; /* Defined in windef.h */
|
||||
typedef const char* LPCSTR; /* Defined in winnt.h */
|
||||
#ifndef _WCHAR_T_DEFINED
|
||||
typedef unsigned short wchar_t; /* Defined in crtdefs.h */
|
||||
#define _WCHAR_T_DEFINED
|
||||
#endif
|
||||
typedef wchar_t* LPWSTR; /* Defined in winnt.h */
|
||||
extern int MultiByteToWidePath(UINT nCodePage, LPCSTR pszName, LPWSTR pwszName, int nWideBufSize);
|
||||
#endif
|
||||
/* Count the number of elements in an array */
|
||||
#define COUNTOF(array) (sizeof(array)/sizeof(array[0]))
|
||||
|
||||
/* Workaround for missing __pragma() directive in old versions of Visual Studio */
|
||||
#if defined(_WIN32) && defined(_MSC_VER) && (_MSC_VER <= 1400) /* For Visual C++ versions up to Visual Studio 2005 */
|
||||
#define __pragma(x)
|
||||
#endif /* (_MSC_VER <= 1400) */
|
||||
|
||||
/* Macros for working around the lack of a #include_next directive */
|
||||
#define MSVCLIBX_CONCAT1(a,b) a##b /* Concatenate the raw arguments */
|
||||
#define MSVCLIBX_CONCAT(a,b) MSVCLIBX_CONCAT1(a,b) /* Substitute the arguments, then concatenate the values */
|
||||
#define MSVCLIBX_STRINGIZE1(x) #x /* Convert the raw argument to a string */
|
||||
#define MSVCLIBX_STRINGIZE(x) MSVCLIBX_STRINGIZE1(x) /* Substitute the argument, then convert its value to a string */
|
||||
/* Up to VS2013, both kinds of include files were in the same directory. Then in VS2015, they were split in two dirs. */
|
||||
#define MSVC_INCLUDE_FILE(relpath) MSVCLIBX_STRINGIZE(MSVCLIBX_CONCAT(MSVCINCLUDE,MSVCLIBX_CONCAT(/,relpath))) /* C compiler include files */
|
||||
#define UCRT_INCLUDE_FILE(relpath) MSVCLIBX_STRINGIZE(MSVCLIBX_CONCAT(UCRTINCLUDE,MSVCLIBX_CONCAT(/,relpath))) /* C runtime library include files */
|
||||
#define WINSDK_INCLUDE_FILE(relpath) MSVCLIBX_STRINGIZE(MSVCLIBX_CONCAT(WSDKINCLUDE,MSVCLIBX_CONCAT(/,relpath))) /* Windows SDK include files */
|
||||
|
||||
/* Support for external linker symbols */
|
||||
#if defined(_WIN64)
|
||||
#define PUBLIC_SYMBOL_NAME(s) s
|
||||
#else /* _MSDOS or _WIN32 */
|
||||
#define PUBLIC_SYMBOL_NAME(s) _##s
|
||||
#endif
|
||||
|
||||
/* Support for UTF-8 command lines */
|
||||
#if defined(_WIN32)
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
/* Force linking in MsvcLibX' UTF-8 initialization module */
|
||||
#pragma comment(linker, "/include:" MSVCLIBX_STRINGIZE(PUBLIC_SYMBOL_NAME(_initU)))
|
||||
#endif /* defined(_UTF8_SOURCE) ... */
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
/* Prevent an incompatibility with <winsock.h>. See MsvcLibX' "sys/time.h" for explanations. */
|
||||
#define _WINSOCKAPI_ /* Prevent the inclusion of winsock.h in windows.h */
|
||||
|
||||
#endif /* _MSVCLIBX_H_ */
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename sys/param.h *
|
||||
* *
|
||||
* Description DOS/WIN32 port of standard C library's sys/param.h. *
|
||||
* *
|
||||
* Notes *
|
||||
* *
|
||||
* History *
|
||||
* 2014-06-10 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _SYS_PARAM_H
|
||||
#define _SYS_PARAM_H
|
||||
|
||||
|
||||
#ifdef _MSDOS
|
||||
|
||||
#define _POSIX_ARG_MAX 127 /* Maximum command line size */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/* #include MSVC_INCLUDE_FILE(sys\param.h) /* Include MSVC's own <sys/param.h> file */
|
||||
|
||||
#define _POSIX_ARG_MAX 8191
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
#endif /* !defined(_SYS_PARAM_H) */
|
||||
|
|
@ -1,422 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: stat.h *
|
||||
* *
|
||||
* Description: MsvcLibX extensions to sys/stat.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-02-06 JFL Moved stat extensions from dirent.h. *
|
||||
* 2014-02-26 JFL Added proprietary routines for managing file times. *
|
||||
* 2014-03-24 JFL Added a mechanism to also include MSVC's own sys/stat.h. *
|
||||
* Renamed this file from statx.h to sys/stat.h. *
|
||||
* 2014-05-27 JFL Added dummy definitions for S_TYPEISSHM() & S_TYPEISTMO().*
|
||||
* 2014-06-03 JFL Moved struct timespec definition to sys/time.h. *
|
||||
* 2014-06-06 JFL Moved mode_t & off*_t definition to sys/types.h. *
|
||||
* Moved fseeko* & ftello* functions definitions to stdio.h. *
|
||||
* 2014-06-24 JFL Added fstat and fstat64 external references. *
|
||||
* 2015-11-15 JFL Visual Studio 2015 moved this file to the Windows Kit UCRT.
|
||||
* 2016-09-15 JFL Fixed a warning in Visual Studio 2015. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVCLIBX_STAT_H
|
||||
#define _MSVCLIBX_STAT_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include "sys/msvcTypes.h"
|
||||
#include <sys/stat.h> /* Include MSVC's own <sys/stat.h> file */
|
||||
#include "msvcDirent.h" /* For dirent2stat() arguments definitions */
|
||||
#include "msvcTime.h" /* for time_t definition */
|
||||
#include "sys/msvcTime.h" /* for timespec definition */
|
||||
/* Include MsvcLibX's <direct.h> override, to avoid conflict with the standard mkdir defined here,
|
||||
should <direct.h> be manually included later on in the C source */
|
||||
#include <direct.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/************************ MS-DOS-specific definitions ************************/
|
||||
|
||||
#ifdef _MSDOS /* Automatically defined when targeting an MS-DOS application */
|
||||
|
||||
/* Define stat and fstat to use 32 or 64 file lengths, as defined by _FILE_OFFSET_BITS */
|
||||
/* #undef stat /* Not normally defined by MSVC */
|
||||
/* #undef fstat /* Not normally defined by MSVC */
|
||||
#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
|
||||
/* TO DO: Windows 95 has extended functions for handling 64-bits files sizes */
|
||||
#else
|
||||
#endif
|
||||
/* For now, use the MSVC 32-bits functions in all cases */
|
||||
#define stat _stat
|
||||
#define fstat _fstat
|
||||
#define lstat stat
|
||||
|
||||
/* Define standard 64-bits structures and functions */
|
||||
#if defined(_LARGEFILE_SOURCE64)
|
||||
/* For now, hide the fact that DOS does not support 64-bits lengths */
|
||||
#define off64_t _off_t
|
||||
#define stat64 _stat
|
||||
#define fstat64 _fstat
|
||||
#define lstat64 stat64
|
||||
#endif
|
||||
|
||||
/* Proprietary function for recovering available infos without calling stat */
|
||||
extern int dirent2stat(struct dirent *pDE, struct _stat *pStat);
|
||||
#define dirent2stat64 dirent2stat /* The current versions are the same */
|
||||
#define _DIRENT2STAT_DEFINED 1
|
||||
|
||||
/* MS-DOS always reports local file times. MsvcLibX DOS version generates a
|
||||
pseudo GMT time for files using mktime(), which can then be undone by localtime(). */
|
||||
#define LocalFileTime localtime
|
||||
|
||||
/* Proprietary function for converting a DOS date/time to a Posix time_t */
|
||||
extern time_t Filetime2Timet(uint16_t date, uint16_t time);
|
||||
/* Proprietary function for generating a string with the local file time, in the ISO 8601 date/time format */
|
||||
extern char *Filetime2String(uint16_t date, uint16_t time, char *pBuf, size_t nBufSize);
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
/************************ Win32-specific definitions *************************/
|
||||
|
||||
#ifdef _WIN32 /* Automatically defined when targeting a Win32 application */
|
||||
|
||||
/* Visual C++ sys/stat.h defines a series of _statXY functions and structures:
|
||||
XY = 32 st_*time is 32-bits __time32_t & st_size is 32-bits _off_t
|
||||
XY = 32i64 st_*time is 32-bits __time32_t & st_size is 64-bits __int64
|
||||
XY = 64i32 st_*time is 64-bits __time64_t & st_size is 32-bits _off_t
|
||||
XY = 64 st_*time is 64-bits __time64_t & st_size is 64-bits __int64
|
||||
Then it defines additional _statZ macros generating _statXY, based on:
|
||||
XY = 32 if _USE_32BIT_TIME_T defined & Z is ""
|
||||
XY = 32i64 if _USE_32BIT_TIME_T defined & Z is i64
|
||||
XY = 64i32 if _USE_32BIT_TIME_T undefined & Z is ""
|
||||
XY = 64 if _USE_32BIT_TIME_T undefined & Z is i64
|
||||
Special case: In 64-bits windows, _USE_32BIT_TIME_T defined is ignored and #undef(ined)
|
||||
*/
|
||||
|
||||
/* Define stat and fstat to use 32 or 64 file lengths, as defined by _FILE_OFFSET_BITS */
|
||||
/* #undef stat /* Not normally defined by MSVC */
|
||||
/* #undef fstat /* Not normally defined by MSVC */
|
||||
|
||||
#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
|
||||
#define _STAT_FILE_SIZE 64
|
||||
#define _STAT_SUFFIX i64
|
||||
#else
|
||||
#define _STAT_FILE_SIZE 32
|
||||
#define _STAT_SUFFIX
|
||||
#endif
|
||||
|
||||
#define _USE_EXTENDED_STAT_STRUCT 1
|
||||
|
||||
#define _VALUEOF(a) a /* Get the token value */
|
||||
#define _CONCAT2T(a,b) a##b /* Concatenate two tokens (does not expand their values) */
|
||||
#define _CONCAT3T(a,b,c) a##b##c /* Concatenate three tokens (does not expand their values) */
|
||||
#define _CONCAT4T(a,b,c,d) a##b##c##d /* Concatenate four tokens (does not expand their values) */
|
||||
#define _CONCAT(a,b) _CONCAT2T(a,b) /* Concatenate two tokens values */
|
||||
#define _CONCAT3(a,b,c) _CONCAT3T(a,b,c) /* Concatenate three tokens values */
|
||||
#define _CONCAT4(a,b,c,d) _CONCAT4T(a,b,c,d) /* Concatenate four tokens values */
|
||||
#define _CON_STAT_CAT1(pre,post) pre##stat##post
|
||||
#define _CON_STAT_CAT(pre,post) _CON_STAT_CAT1(pre,post)
|
||||
|
||||
/* Define what stat, fstat, lstat, stat64 macros would be,
|
||||
if we were to use MSVC's own stat structures and routines */
|
||||
/* Avoid concatenating tokens _stat and _fstat, as these are already macros
|
||||
that would be expanded, and we do not want this as this stage. */
|
||||
#define _MSVC_stat _CON_STAT_CAT(_ , _STAT_SUFFIX)
|
||||
#define _MSVC_fstat _CON_STAT_CAT(_f, _STAT_SUFFIX)
|
||||
#define _MSVC_lstat _CON_STAT_CAT(_l, _STAT_SUFFIX)
|
||||
#define _MSVC_stat64 _CON_STAT_CAT(_ , i64)
|
||||
#define _MSVC_lstat64 _CON_STAT_CAT(_l, i64)
|
||||
|
||||
#ifdef _USE_32BIT_TIME_T
|
||||
#define _lstat _lstat32
|
||||
#define _lstati64 _lstat32i64
|
||||
#define _lstat_ns _lstat32_ns
|
||||
#define _lstati64_ns _lstat32i64_ns
|
||||
#else
|
||||
#define _lstat _lstat64i32
|
||||
#define _lstati64 _lstat64
|
||||
#define _lstat_ns _lstat64i32_ns
|
||||
#define _lstati64_ns _lstat64_ns
|
||||
#endif
|
||||
|
||||
#if !_USE_EXTENDED_STAT_STRUCT
|
||||
#define _NS_SUFFIX
|
||||
#else /* _USE_EXTENDED_STAT_STRUCT */
|
||||
#define _MSVCLIBX_STAT_DEFINED 1
|
||||
#define _NS_SUFFIX _ns
|
||||
/* Define what stat, fstat, lstat, stat64 macros and structures would be,
|
||||
if we were to use MsvcLibX extended stat structures and routines */
|
||||
#define _LIBX_stat _CONCAT(_MSVC_stat,_ns)
|
||||
#define _LIBX_stat64 _CONCAT(_MSVC_stat64,_ns)
|
||||
#include "msvcDebugm.h"
|
||||
#pragma message("Defining type struct " VALUEIZE(_LIBX_stat))
|
||||
struct _LIBX_stat {
|
||||
/* MSVC standard stat structure fields */
|
||||
_dev_t st_dev;
|
||||
_ino_t st_ino;
|
||||
unsigned short st_mode;
|
||||
short st_nlink;
|
||||
short st_uid;
|
||||
short st_gid;
|
||||
_dev_t st_rdev;
|
||||
off_t st_size;
|
||||
/* End of MSVC standard stat structure fields */
|
||||
struct timespec st_ctim; /* File creation date/time, w. ns resolution */
|
||||
struct timespec st_mtim; /* File modification date/time, w. ns resolution */
|
||||
struct timespec st_atim; /* File access date/time, w. ns resolution */
|
||||
unsigned int st_Win32Attrs; /* Win32 file attributes */
|
||||
unsigned int st_ReparseTag; /* Reparse point tag */
|
||||
};
|
||||
/* Compatibility with old Unix fields */
|
||||
#define st_ctime st_ctim.tv_sec
|
||||
#define st_mtime st_mtim.tv_sec
|
||||
#define st_atime st_atim.tv_sec
|
||||
/* Compatibility with intermediate Unix fields */
|
||||
#define st_ctimensec st_ctim.tv_nsec /* Nanosecond part of the file creation time */
|
||||
#define st_mtimensec st_mtim.tv_nsec /* Nanosecond part of the file modification time */
|
||||
#define st_atimensec st_atim.tv_nsec /* Nanosecond part of the file access time */
|
||||
|
||||
#if (_STAT_FILE_SIZE != 64) /* Else it's the same as struct stat */
|
||||
#pragma message("Defining type struct " VALUEIZE(_LIBX_stat64))
|
||||
struct _LIBX_stat64 {
|
||||
/* MSVC standard stat structure fields */
|
||||
_dev_t st_dev;
|
||||
_ino_t st_ino;
|
||||
unsigned short st_mode;
|
||||
short st_nlink;
|
||||
short st_uid;
|
||||
short st_gid;
|
||||
_dev_t st_rdev;
|
||||
off64_t st_size;
|
||||
/* End of MSVC standard stat structure fields */
|
||||
struct timespec st_ctim; /* File creation date/time, w. ns resolution */
|
||||
struct timespec st_mtim; /* File modification date/time, w. ns resolution */
|
||||
struct timespec st_atim; /* File access date/time, w. ns resolution */
|
||||
unsigned int st_Win32Attrs; /* Win32 file attributes */
|
||||
unsigned int st_ReparseTag; /* Reparse point tag */
|
||||
};
|
||||
#endif
|
||||
#endif /* !_USE_EXTENDED_STAT_STRUCT */
|
||||
|
||||
/* Define standard stat, fstat, lstat macros */
|
||||
#define stat _CONCAT(_MSVC_stat,_NS_SUFFIX)
|
||||
#define fstat _CONCAT(_MSVC_fstat,_NS_SUFFIX)
|
||||
#define lstat _CONCAT(_MSVC_lstat,_NS_SUFFIX)
|
||||
|
||||
/* Reference standard stat, fstat, lstat functions that we redefine */
|
||||
#if _USE_EXTENDED_STAT_STRUCT /* Else we'll use MSVC's version */
|
||||
extern int stat(const char *path, struct stat *buf);
|
||||
extern int fstat(int nFile, struct stat *buf);
|
||||
#endif
|
||||
extern int lstat(const char *path, struct stat *buf);
|
||||
|
||||
/* Define standard 64-bits macros and functions */
|
||||
#if defined(_LARGEFILE_SOURCE64)
|
||||
#define stat64 _CONCAT(_stati64,_NS_SUFFIX)
|
||||
#define fstat64 _CONCAT(_fstati64,_NS_SUFFIX)
|
||||
#define lstat64 _CONCAT(_lstati64,_NS_SUFFIX)
|
||||
|
||||
#if (_STAT_FILE_SIZE != 64) /* Else they're the same as functions stat & lstat */
|
||||
#if _USE_EXTENDED_STAT_STRUCT /* Else we'll use MSVC's version */
|
||||
extern int stat64(const char *path, struct stat64 *buf);
|
||||
extern int fstat64(int nFile, struct stat *buf);
|
||||
#endif
|
||||
extern int lstat64(const char *path, struct stat64 *buf);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Proprietary function for recovering dirent infos without calling stat */
|
||||
/* Note: MSDOS has a single stat version, and its dirent2stat implementation is in dirent.c */
|
||||
#ifdef _USE_32BIT_TIME_T
|
||||
#if (_STAT_FILE_SIZE != 64) /* Else if _STAT_FILE_SIZE=64, then struct _stat32_ns isn't defined */
|
||||
extern int _CONCAT(_dirent2_stat32,_NS_SUFFIX)(struct dirent *pDE, struct _CONCAT(_stat32,_NS_SUFFIX) *pStat);
|
||||
#endif
|
||||
extern int _CONCAT(_dirent2_stat32i64,_NS_SUFFIX)(struct dirent *pDE, struct _CONCAT(_stat32i64,_NS_SUFFIX) *pStat);
|
||||
#else
|
||||
#if (_STAT_FILE_SIZE != 64) /* Else if _STAT_FILE_SIZE=64, then struct _stat64i32_ns isn't defined */
|
||||
extern int _CONCAT(_dirent2_stat64i32,_NS_SUFFIX)(struct dirent *pDE, struct _CONCAT(_stat64i32,_NS_SUFFIX) *pStat);
|
||||
#endif
|
||||
extern int _CONCAT(_dirent2_stat64,_NS_SUFFIX)(struct dirent *pDE, struct _CONCAT(_stat64,_NS_SUFFIX) *pStat);
|
||||
#endif
|
||||
#define dirent2stat _CONCAT(_dirent2,stat)
|
||||
#define _DIRENT2STAT_DEFINED 1
|
||||
|
||||
#define unlink _CONCAT(_unlink_, stat)
|
||||
#define rmdir _CONCAT(_rmdir_, stat)
|
||||
extern int unlink(const char *path);
|
||||
extern int rmdir(const char *path);
|
||||
|
||||
/* Proprietary function for generating a printable local file time,
|
||||
using Windows' specific algorithm, to match cmd.exe dir output. */
|
||||
extern struct tm *LocalFileTime(const time_t *pt);
|
||||
|
||||
/* Proprietary function for converting a Win32 FILETIME to a Posix time_t */
|
||||
extern time_t Filetime2Timet(const FILETIME *pFT);
|
||||
/* Proprietary function for converting a Posix time_t to a Win32 FILETIME */
|
||||
extern void Timet2Filetime(time_t s, FILETIME *pFT);
|
||||
|
||||
/* Proprietary function for converting a Win32 FILETIME to a Posix {time_t,nanosecond} */
|
||||
extern void Filetime2Timespec(const FILETIME *pFT, struct timespec *pTS);
|
||||
/* Proprietary function for converting a Posix {time_t,nanosecond} to a Win32 FILETIME */
|
||||
extern void Timespec2Filetime(const struct timespec *pTS, FILETIME *pFT);
|
||||
|
||||
/* Proprietary function for generating a string with the local file time, in the ISO 8601 date/time format */
|
||||
extern char *Filetime2String(const FILETIME *pFT, char *pBuf, size_t nBufSize);
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
/************************* OS/2-specific definitions *************************/
|
||||
|
||||
#ifdef _OS2 /* Automatically defined when targeting an OS/2 application? */
|
||||
|
||||
/* Define stat and fstat to use 32 or 64 file lengths, as defined by _FILE_OFFSET_BITS */
|
||||
/* #undef stat /* Not normally defined by MSVC */
|
||||
/* #undef fstat /* Not normally defined by MSVC */
|
||||
#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
|
||||
/* TO DO: Windows 95 has extended functions for handling 64-bits files sizes */
|
||||
#else
|
||||
#endif
|
||||
/* For now, use the MSVC 32-bits functions in all cases */
|
||||
#define off_t _off_t
|
||||
#define stat _stat
|
||||
#define fstat _fstat
|
||||
#define lstat stat
|
||||
|
||||
/* Define standard 64-bits functions */
|
||||
#if defined(_LARGEFILE_SOURCE64)
|
||||
/* For now, hide the fact that DOS does not support 64-bits lengths */
|
||||
#define off64_t _off_t
|
||||
#define stat64 _stat
|
||||
#define fstat64 _fstat
|
||||
#define lstat64 stat64
|
||||
#endif
|
||||
|
||||
/* Proprietary function for recovering available infos without calling stat */
|
||||
/* extern int dirent2stat(struct dirent *pDE, struct _stat *pStat); */
|
||||
/* #define dirent2stat64 dirent2stat /* The current versions are the same */
|
||||
/* #define _DIRENT2STAT_DEFINED 1 */
|
||||
|
||||
/* To do: Check if OS/2 uses local or GMT times, and implement LocalFileTime() if needed. */
|
||||
#define LocalFileTime localtime
|
||||
|
||||
#endif /* defined(_OS2) */
|
||||
|
||||
/********************** End of OS-specific definitions ***********************/
|
||||
|
||||
#define lchmod chmod /* MSVC is buggy and chmod() applies to the link itself */
|
||||
|
||||
/* Structure stat standard st_mode values not defined in DOS/Windows' sys/stat.h */
|
||||
/* Must match the d_type field types in dirent.h. */
|
||||
/* #define S_IFMT 0xF000 /* Mask for the 4-bit file type */
|
||||
#define S_IFIFO 0x1000 /* FIFO */
|
||||
/* #define S_IFCHR 0x2000 /* Character device */
|
||||
/* #define S_IFDIR 0x4000 /* Directory */
|
||||
#define S_IFBLK 0x6000 /* Block device */
|
||||
/* #define S_IFREG 0x8000 /* Regular file */
|
||||
#define S_IFLNK 0xA000 /* Symbolic link */
|
||||
#define S_IFSOCK 0xC000 /* Socket */
|
||||
|
||||
/* Structure stat standard st_mode type test macros */
|
||||
/* The existence of these macros can be used to test for the OS support of the feature */
|
||||
#define S_ISTYPE(m, TYPE) ((m & S_IFMT) == TYPE)
|
||||
/* Both DOS and Windows support these file types */
|
||||
#define S_ISCHR(m) S_ISTYPE(m, S_IFCHR) /* Test for a character device */
|
||||
#define S_ISDIR(m) S_ISTYPE(m, S_IFDIR) /* Test for a directory */
|
||||
#define S_ISREG(m) S_ISTYPE(m, S_IFREG) /* Test for a regular file */
|
||||
#ifdef _WIN32 /* Only Windows supports these */
|
||||
#define S_ISLNK(m) S_ISTYPE(m, S_IFLNK) /* Test for a symbolic link */
|
||||
#endif
|
||||
#if 0 /* Only Unix supports these? At least MsvcLibX does not support them now. */
|
||||
#define S_ISBLK(m) S_ISTYPE(m, S_IFBLK) /* Test for a block device */
|
||||
#define S_ISFIFO(m) S_ISTYPE(m, S_IFIFO) /* Test for a pipe or FIFO */
|
||||
#define S_ISSOCK(m) S_ISTYPE(m, S_IFSOCK) /* Test for a socket */
|
||||
#endif
|
||||
|
||||
#define S_ISBLK(m) 0 /* Test for a block device */
|
||||
#define S_ISCTG(m) 0 /* Test for a high performance ("contiguous data") file */
|
||||
#define S_ISDOOR(m) 0 /* Test for a door */
|
||||
#define S_ISFIFO(m) 0 /* Test for a pipe or FIFO */
|
||||
#define S_ISMPB(m) 0 /* Test for a multiplexed block device */
|
||||
#define S_ISMPC(m) 0 /* Test for a multiplexed character device */
|
||||
#define S_ISNWK(m) 0 /* Test for a network special file (HP-UX) */
|
||||
#define S_ISPORT(m) 0 /* Test for a port */
|
||||
#define S_ISSOCK(m) 0 /* Test for a socket */
|
||||
#define S_ISWHT(m) 0 /* Test for a whiteout (4.4BSD) */
|
||||
|
||||
|
||||
/* Other optional file types that some operating systems support */
|
||||
#define S_TYPEISMQ(pStat) 0 /* Test for a message queue */
|
||||
#define S_TYPEISSEM(pStat) 0 /* Test for a semaphore */
|
||||
#define S_TYPEISSHM(pStat) 0 /* Test for a shared memory object */
|
||||
#define S_TYPEISTMO(pStat) 0 /* Test for a typed memory object */
|
||||
|
||||
/* Structure stat standard st_mode flags */
|
||||
#define S_ISUID 04000 /* Set UID bit */
|
||||
#define S_ISGID 02000 /* Set-group-ID bit */
|
||||
#define S_ISVTX 01000 /* Sticky bit */
|
||||
|
||||
#define S_IRWXU 0700 /* Mask for file owner permissions */
|
||||
#define S_IRUSR 0400 /* Owner has read permission. Alias S_IREAD */
|
||||
#define S_IWUSR 0200 /* Owner has write permission. Alias S_IWRITE */
|
||||
#define S_IXUSR 0100 /* Owner has execute permission. Alias S_IEXEC */
|
||||
|
||||
#define S_IRWXG 070 /* Mask for group permissions */
|
||||
#define S_IRGRP 040 /* Group has read permission */
|
||||
#define S_IWGRP 020 /* Group has write permission */
|
||||
#define S_IXGRP 010 /* Group has execute permission */
|
||||
|
||||
#define S_IRWXO 07 /* Mask for permissions for others (not in group) */
|
||||
#define S_IROTH 04 /* Others have read permission */
|
||||
#define S_IWOTH 02 /* Others have write permission */
|
||||
#define S_IXOTH 01 /* Others have execute permission */
|
||||
|
||||
#define S_IRWXUGO 00777 /* S_IRWXU|S_IRWXG|S_IRWXO */
|
||||
#define S_IALLUGO 07777 /* S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO */
|
||||
#define S_IRUGO 00444 /* S_IRUSR|S_IRGRP|S_IROTH */
|
||||
#define S_IWUGO 00222 /* S_IWUSR|S_IWGRP|S_IWOTH */
|
||||
#define S_IXUGO 00111 /* S_IXUSR|S_IXGRP|S_IXOTH */
|
||||
|
||||
/* Structure stat extensions for DOS/Windows file attributes */
|
||||
#define S_IFVOLID 0xF000 /* Volume ID pseudo-file, defined in FAT root dir */
|
||||
#define S_ISVOLID(m) S_ISTYPE(m, S_IFVOLID) /* Test for a FAT volume ID */
|
||||
#define S_HIDDEN 01 /* Reuse permissions bit not used in DOS/Windows */
|
||||
#define S_ARCHIVE 02 /* Reuse permissions bit not used in DOS/Windows */
|
||||
#define S_SYSTEM 04 /* Reuse permissions bit not used in DOS/Windows */
|
||||
#define S_COMPRESSED 010 /* Reuse permissions bit not used in DOS/Windows */
|
||||
#define S_ENCRYPTED 020 /* Reuse permissions bit not used in DOS/Windows */
|
||||
#define S_NOT_CONTENT_INDEXED 040 /* Reuse permissions bit not used in DOS/Windows */
|
||||
#define S_OFFLINE 01000 /* Reuse sticky bit, not used in DOS/Windows */
|
||||
#define S_SPARSE_FILE 02000 /* Reuse GID bit, not used in DOS/Windows */
|
||||
#define S_MOUNT_POINT 04000 /* Reuse UID bit, not used in DOS/Windows */
|
||||
/* #define S_TEMPORARY /* Reuse UID bit, not used in DOS/Windows */
|
||||
/* #define S_VIRTUAL /* No bit left for this one */
|
||||
|
||||
#if defined(_MSDOS)
|
||||
#define _mkdirx(path, mode) _mkdir(path)
|
||||
#elif defined(_WIN32)
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define _mkdirx(path, mode) mkdirU(path, mode)
|
||||
#else /* _ANSI_SOURCE */
|
||||
#define _mkdirx(path, mode) mkdirA(path, mode)
|
||||
#endif /* defined(_UTF8_SOURCE) */
|
||||
extern int mkdirU(const char *path, mode_t mode);
|
||||
extern int mkdirA(const char *path, mode_t mode);
|
||||
#endif /* defined(_MSDOS) */
|
||||
#define mkdir(path, mode) _mkdirx(path, mode)
|
||||
|
||||
/* Special values for futimens() and utimensat(). Must not be in [0...((10^9)-1)] */
|
||||
#define UTIME_NOW 1000000001
|
||||
#define UTIME_OMIT 1000000002
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* defined(_MSVCLIBX_STAT_H) */
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename sys/time.h *
|
||||
* *
|
||||
* Description DOS/WIN32 port of standard C library's sys/time.h. *
|
||||
* *
|
||||
* Notes MUST be included before any direct or indirect inclusion *
|
||||
* of <windows.h>, as this sys/time.h file has a definition *
|
||||
* of struct timeval conflicting with that in <winsock.h>, *
|
||||
* and as a workaround it defines _WINSOCKAPI_ to prevent *
|
||||
* <windows.h> from loading <winsock.h>. *
|
||||
* *
|
||||
* The same conflict exists with <winsock2.h>, but this one *
|
||||
* is not loaded automatically, and hence should not be *
|
||||
* visible to Unix apps built with the MsvcLibX library. *
|
||||
* *
|
||||
* History *
|
||||
* 2014-02-11 JFL Created this file. *
|
||||
* 2014-05-30 JFL Added the workaround for the conflict with <winsock.h>. *
|
||||
* 2014-06-03 JFL Moved struct timespec definition from sys/stat.h. *
|
||||
* Added macros TIMEVAL_TO_TIMESPEC & TIMESPEC_TO_TIMEVAL. *
|
||||
* 2016-07-06 JFL Avoid error if winsocks2.h has been previously included. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#include <time.h> /* for time_t definition */
|
||||
|
||||
#ifndef _SYS_TIME_H
|
||||
#define _SYS_TIME_H
|
||||
|
||||
#ifdef _MSDOS
|
||||
/* MS-DOS only has a 2-second resolution on file times.
|
||||
Use the existence of macro _STRUCT_TIMEVAL to test if it's possible
|
||||
to use utimes(), else use utime(), which is supported by all OSs */
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/* There's a conflict with the timeval definition in winsock.h, which uses
|
||||
a long instead of a time_t for tv_sec. See:
|
||||
C:\Pgm64\Microsoft SDKs\Windows\v7.0\INCLUDE\winsock.h
|
||||
*/
|
||||
#define _WINSOCKAPI_ /* Prevent the inclusion of winsock.h in windows.h */
|
||||
/* Could also #define WIN32_LEAN_AND_MEAN /* Avoid including many optional Windows features, including winsock.h */
|
||||
|
||||
#include <windows.h> /* For WCHAR */
|
||||
|
||||
#ifndef _STRUCT_TIMEVAL
|
||||
#define _STRUCT_TIMEVAL 1
|
||||
|
||||
#ifndef _WINSOCK2API_ /* Prevent compilation errors if winsocks2.h has been previously included */
|
||||
/* A time value with microsecond precision */
|
||||
struct timeval {
|
||||
time_t tv_sec; /* Seconds */
|
||||
int tv_usec; /* Signed count of microseconds */
|
||||
};
|
||||
#endif /* _WINSOCK2API */
|
||||
|
||||
#endif /* !defined(_STRUCT_TIMEVAL) */
|
||||
|
||||
/* 2015-12-04 JFL Bug fix: With VS14/VC19, the UCRT defines timespec, with a long tv_nsec */
|
||||
#ifndef _UCRT
|
||||
#ifndef _STRUCT_TIMESPEC
|
||||
#define _STRUCT_TIMESPEC
|
||||
|
||||
/* A time value with nanosecond precision */
|
||||
struct timespec {
|
||||
time_t tv_sec; /* Seconds */
|
||||
int tv_nsec; /* Signed count of nanoseconds */
|
||||
};
|
||||
#define _TIMESPEC_DEFINED /* Some packages test this before redefining it */
|
||||
|
||||
#endif /* !defined(_STRUCT_TIMESPEC) */
|
||||
#endif /* !defined(_UCRT) */
|
||||
|
||||
#define TIMEVAL_TO_TIMESPEC(ptv, pts) { \
|
||||
(pts)->tv_sec = (ptv)->tv_sec; \
|
||||
(pts)->tv_nsec = (ptv)->tv_usec * 1000; \
|
||||
}
|
||||
#define TIMESPEC_TO_TIMEVAL(ptv, pts) { \
|
||||
(ptv)->tv_sec = (pts)->tv_sec; \
|
||||
(ptv)->tv_usec = (pts)->tv_nsec / 1000; \
|
||||
}
|
||||
|
||||
/* Change the file access time to tvp[0] and its modification time to tvp[1]. */
|
||||
int utimesA(const char *file, const struct timeval tvp[2]);
|
||||
int utimesU(const char *file, const struct timeval tvp[2]);
|
||||
int utimesW(const WCHAR *file, const struct timeval tvp[2]);
|
||||
|
||||
/* Same as 'utimes', but does not follow symbolic links. */
|
||||
int lutimesA(const char *path, const struct timeval tvp[2]);
|
||||
int lutimesU(const char *path, const struct timeval tvp[2]);
|
||||
int lutimesW(const WCHAR *path, const struct timeval tvp[2]);
|
||||
|
||||
/* Same as 'utimes', but takes an open file descriptor instead of a name. */
|
||||
int futimes(int fd, const struct timeval tvp[2]);
|
||||
|
||||
#if defined(_UTF8_SOURCE) || defined(_BSD_SOURCE) || defined(_GNU_SOURCE)
|
||||
#define utimes utimesU
|
||||
#define lutimes lutimesU
|
||||
#else /* _ANSI_SOURCE */
|
||||
#define utimes utimesA
|
||||
#define lutimes lutimesA
|
||||
#endif
|
||||
|
||||
/* Get the current date and time into a struct timeval */
|
||||
int gettimeofday(struct timeval *ptv, void *pTimeZone);
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
#endif /* !defined(_SYS_TIME_H) */
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: sys/utsname.h *
|
||||
* *
|
||||
* Description: Defines structure utsname and function uname(). *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-05-30 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _SYS_UTSNAME_H
|
||||
#define _SYS_UTSNAME_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
struct utsname {
|
||||
char *sysname; /* Name of this implementation of the operating system */
|
||||
char *nodename; /* Name of this node on the network */
|
||||
char *release; /* Current release level of this implementation */
|
||||
char *version; /* Current version level of this release */
|
||||
char *machine; /* Name of the hardware type on which the system is running */
|
||||
};
|
||||
|
||||
int uname(struct utsname *);
|
||||
|
||||
#endif /* _SYS_UTSNAME_H */
|
|
@ -1,99 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: sys/types.h *
|
||||
* *
|
||||
* Description: Add missing definitions in MSVC's sys/types.h. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-05-26 JFL Created this file. *
|
||||
* 2014-06-06 JFL Moved mode_t & off*_t definitions here, from sys\stat.h. *
|
||||
* 2015-11-15 JFL Visual Studio 2015 moved this file to the Windows Kit UCRT.
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifndef _MSVCLIBX_SYS_TYPES_H
|
||||
#define _MSVCLIBX_SYS_TYPES_H 1
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include <sys\types.h> /* Include MSVC's own <sys/types.h> file */
|
||||
|
||||
/************************ MS-DOS-specific definitions ************************/
|
||||
|
||||
#ifdef _MSDOS /* Automatically defined when targeting an MS-DOS application */
|
||||
|
||||
|
||||
|
||||
/* File offset type */
|
||||
/* For now, use the MSVC 32-bits functions in all cases */
|
||||
#define off_t _off_t
|
||||
|
||||
typedef int pid_t; /* The pid is the PSP segment. MSVC's process.h defines it as int. */
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
/************************ Win32-specific definitions *************************/
|
||||
|
||||
#ifdef _WIN32 /* Automatically defined when targeting a Win32 application */
|
||||
|
||||
/* File offset types */
|
||||
#define off64_t __int64 /* Don't use a typedef because MSVC's _fseeki64 doesn't like it */
|
||||
|
||||
#if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
|
||||
#define off_t off64_t
|
||||
#else
|
||||
#define off_t _off_t
|
||||
#endif
|
||||
|
||||
typedef unsigned long DWORD; /* Don't include <windows.h> to get DWORD definition, as this draws too much,
|
||||
including things we want to override in other parts of MsvcLibX */
|
||||
|
||||
typedef DWORD pid_t; /* Windows defines it as a DWORD */
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
||||
/************************* OS/2-specific definitions *************************/
|
||||
|
||||
#ifdef _OS2 /* Automatically defined when targeting an OS/2 application? */
|
||||
|
||||
/* File offset type */
|
||||
/* For now, use the MSVC 32-bits functions in all cases */
|
||||
#define off_t _off_t
|
||||
|
||||
|
||||
#endif /* defined(_OS2) */
|
||||
|
||||
/********************** End of OS-specific definitions ***********************/
|
||||
|
||||
/* Signed size type */
|
||||
#ifndef _SSIZE_T_DEFINED
|
||||
#if defined(_MSDOS)
|
||||
typedef int ssize_t;
|
||||
#elif defined(_WIN32)
|
||||
#include <stdint.h>
|
||||
#ifdef _WIN64
|
||||
typedef __int64 ssize_t;
|
||||
#else
|
||||
typedef _W64 int ssize_t;
|
||||
#endif /* defined(_WIN64) */
|
||||
#endif /* defined(_WIN32) */
|
||||
#define _SSIZE_T_DEFINED
|
||||
#endif /* !_SSIZE_T_DEFINED */
|
||||
|
||||
/* MsvcLibX handles uid_t and gid_t in pwd.c and grp.c */
|
||||
typedef int gid_t;
|
||||
typedef int uid_t;
|
||||
|
||||
/* MsvcLibX uses mode_t in sys/stat.h */
|
||||
typedef int mode_t;
|
||||
#define HAVE_MODE_T
|
||||
|
||||
/* File link counts type (not used by MsvcLibX so far) */
|
||||
typedef int nlink_t; /* Is short in some Unix versions */
|
||||
|
||||
#endif /* !defined(_MSVCLIBX_SYS_TYPES_H) */
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename GetFileAttributes.c *
|
||||
* *
|
||||
* Description: UTF-8 version of WIN32's GetFileAttributes() *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2016-09-12 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifdef _WIN32 /* Automatically defined when targeting a Win32 application */
|
||||
|
||||
#include <windows.h> /* Also includes MsvcLibX' WIN32 UTF-8 extensions */
|
||||
#include "msvcLimits.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
* *
|
||||
| Function: GetFileAttributesU |
|
||||
| |
|
||||
| Description: Get atributes for a UTF-8 path. |
|
||||
| |
|
||||
| Parameters: See WIN32's GetFileAttributes() |
|
||||
| |
|
||||
| Return value: The file attributes flags |
|
||||
| |
|
||||
| Notes: |
|
||||
| |
|
||||
| History: |
|
||||
| 2014-07-02 JFL Created this routine |
|
||||
* *
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
DWORD WINAPI GetFileAttributesU(LPCTSTR lpFileName) {
|
||||
WCHAR *pwszName;
|
||||
DWORD dwAttrs;
|
||||
int n;
|
||||
|
||||
/* Allocate a buffer large enough for any Unicode pathname */
|
||||
pwszName = (void *)LocalAlloc(LMEM_FIXED, UNICODE_PATH_MAX * sizeof(WCHAR));
|
||||
if (!pwszName) return 0;
|
||||
|
||||
/* Convert the pathname to a unicode string, with the proper extension prefixes if it's longer than 260 bytes */
|
||||
n = MultiByteToWidePath(CP_UTF8, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
lpFileName, /* lpMultiByteStr, */
|
||||
pwszName, /* lpWideCharStr, */
|
||||
UNICODE_PATH_MAX /* cchWideChar, */
|
||||
);
|
||||
if (!n) {
|
||||
LocalFree((HLOCAL)pwszName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the file attributes, using the Unicode version of the function */
|
||||
dwAttrs = GetFileAttributesW(pwszName);
|
||||
|
||||
/* Cleanup and return */
|
||||
LocalFree((HLOCAL)pwszName);
|
||||
return dwAttrs;
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename GetFileAttributesEx.c *
|
||||
* *
|
||||
* Description: UTF-8 version of WIN32's GetFileAttributesEx() *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2016-09-12 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifdef _WIN32 /* Automatically defined when targeting a Win32 application */
|
||||
|
||||
#include <windows.h> /* Also includes MsvcLibX' WIN32 UTF-8 extensions */
|
||||
#include "msvcLimits.h"
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
* *
|
||||
| Function: GetFileAttributesExU |
|
||||
| |
|
||||
| Description: Get file information for a UTF-8 pathname. |
|
||||
| |
|
||||
| Parameters: See WIN32's GetFileAttributesEx() |
|
||||
| |
|
||||
| Return value: 1 = done, or 0 if error |
|
||||
| |
|
||||
| Notes: Sets the file length, dates, attributes, etc. |
|
||||
| |
|
||||
| History: |
|
||||
| 2016-09-12 JFL Created this routine. |
|
||||
* *
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
BOOL WINAPI GetFileAttributesExU(
|
||||
LPCTSTR lpFileName,
|
||||
GET_FILEEX_INFO_LEVELS fInfoLevelId,
|
||||
LPVOID lpFileInformation
|
||||
) {
|
||||
WIN32_FILE_ATTRIBUTE_DATA *lpFileData = lpFileInformation;
|
||||
WCHAR *pwszName;
|
||||
BOOL bDone;
|
||||
int n;
|
||||
|
||||
/* Allocate a buffer large enough for any Unicode pathname */
|
||||
pwszName = (void *)LocalAlloc(LMEM_FIXED, UNICODE_PATH_MAX * sizeof(WCHAR));
|
||||
if (!pwszName) return 0;
|
||||
|
||||
/* Convert the pathname to a unicode string, with the proper extension prefixes if it's longer than 260 bytes */
|
||||
n = MultiByteToWidePath(CP_UTF8, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
lpFileName, /* lpMultiByteStr, */
|
||||
pwszName, /* lpWideCharStr, */
|
||||
UNICODE_PATH_MAX /* cchWideChar, */
|
||||
);
|
||||
if (!n) {
|
||||
LocalFree((HLOCAL)pwszName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Get the file information, using the Unicode version of the function */
|
||||
bDone = GetFileAttributesExW(pwszName, fInfoLevelId, lpFileData);
|
||||
|
||||
/* Cleanup and return */
|
||||
LocalFree((HLOCAL)pwszName);
|
||||
return bDone;
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename GetFullPathName.c *
|
||||
* *
|
||||
* Description: UTF-8 version of WIN32's GetFullPathName() *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2016-09-12 JFL Created this file, from the routine in truename.c. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifdef _WIN32 /* Automatically defined when targeting a Win32 application */
|
||||
|
||||
#include <windows.h> /* Also includes MsvcLibX' WIN32 UTF-8 extensions */
|
||||
#include "msvcLimits.h"
|
||||
#include "msvcDebugm.h" /* MsvcLibX debugging macros */
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
* *
|
||||
| Function: GetFullPathNameU |
|
||||
| |
|
||||
| Description: Get the absolute pathname for a relative UTF-8 path. |
|
||||
| |
|
||||
| Parameters: See WIN32's GetFullPathName() |
|
||||
| |
|
||||
| Return value: The length of the full pathname, or 0 if error |
|
||||
| |
|
||||
| Notes: Warning: Windows' GetFullPathname trims trailing dots and |
|
||||
| spaces from the path. |
|
||||
| This derived function reproduces the bug. |
|
||||
| The caller MUST add trailing dots & spaces back if needed.|
|
||||
| |
|
||||
| History: |
|
||||
| 2014-02-07 JFL Created this routine. |
|
||||
* *
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
DWORD WINAPI GetFullPathNameU(LPCTSTR lpName, DWORD nBufferLength, LPTSTR lpBuf, LPTSTR *lpFilePart) {
|
||||
WCHAR wszName[MAX_PATH];
|
||||
WCHAR wszBuf[MAX_PATH];
|
||||
char szName[MAX_PATH*4]; /* Worst case for UTF-8 is 4 bytes/Unicode character */
|
||||
int n;
|
||||
DWORD dwResult;
|
||||
WCHAR *wlpFilePart;
|
||||
|
||||
DEBUG_ENTER(("GetFullPathNameU(\"%s\", %d, %p, %p);\n", lpName, nBufferLength, lpBuf, lpFilePart));
|
||||
|
||||
n = MultiByteToWideChar(CP_UTF8, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
0, /* dwFlags, */
|
||||
lpName, /* lpMultiByteStr, */
|
||||
lstrlen(lpName)+1, /* cbMultiByte, */
|
||||
wszName, /* lpWideCharStr, */
|
||||
MAX_PATH /* cchWideChar, */
|
||||
);
|
||||
if (!n) RETURN_INT_COMMENT(0, ("Failed to convert the name to Unicode\n"));
|
||||
|
||||
dwResult = GetFullPathNameW(wszName, MAX_PATH, wszBuf, &wlpFilePart);
|
||||
if (!dwResult) RETURN_INT_COMMENT(0, ("GetFullPathNameW() failed\n"));
|
||||
|
||||
/* nRead = UnicodeToBytes(pwStr, len, buf, bufsize); */
|
||||
n = WideCharToMultiByte(CP_UTF8, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
0, /* dwFlags, */
|
||||
wszBuf, /* lpWideCharStr, */
|
||||
(int)dwResult + 1, /* cchWideChar, */
|
||||
lpBuf, /* lpMultiByteStr, */
|
||||
(int)nBufferLength, /* cbMultiByte, */
|
||||
NULL, /* lpDefaultChar, */
|
||||
NULL /* lpUsedDefaultChar */
|
||||
);
|
||||
if (!n) RETURN_INT_COMMENT(0, ("Failed to convert the full name from Unicode\n"));
|
||||
|
||||
if (lpFilePart) { /* Convert the file part, and get the length of the converted string */
|
||||
int m; /* Length of the converted string */
|
||||
m = WideCharToMultiByte(CP_UTF8, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
0, /* dwFlags, */
|
||||
wlpFilePart, /* lpWideCharStr, */
|
||||
lstrlenW(wlpFilePart), /* cchWideChar, */
|
||||
szName, /* lpMultiByteStr, */
|
||||
sizeof(szName), /* cbMultiByte, */
|
||||
NULL, /* lpDefaultChar, */
|
||||
NULL /* lpUsedDefaultChar */
|
||||
);
|
||||
/* (n-1) is the length of the full UTF-8 pathname */
|
||||
/* So ((n-1) - m) is the offset of the file part in the full UTF-8 pathname */
|
||||
*lpFilePart = lpBuf + (n - 1) - m;
|
||||
}
|
||||
|
||||
RETURN_INT_COMMENT(n-1, ("\"%s\" \"%s\"\n", lpBuf, lpFilePart?*lpFilePart:"(NULL)"));
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename GetLongPathName.c *
|
||||
* *
|
||||
* Description: UTF-8 version of WIN32's GetLongPathName() *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2016-09-12 JFL Created this file, from the routine in truename.c. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifdef _WIN32 /* Automatically defined when targeting a Win32 application */
|
||||
|
||||
#include <windows.h> /* Also includes MsvcLibX' WIN32 UTF-8 extensions */
|
||||
#include "msvcLimits.h"
|
||||
#include "msvcDebugm.h" /* MsvcLibX debugging macros */
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
* *
|
||||
| Function: GetLongPathNameU |
|
||||
| |
|
||||
| Description: Get the long pathname for a short UTF-8 path. |
|
||||
| |
|
||||
| Parameters: See WIN32's GetLongPathName() |
|
||||
| |
|
||||
| Return value: The length of the full pathname, or 0 if error |
|
||||
| |
|
||||
| Notes: |
|
||||
| |
|
||||
| History: |
|
||||
| 2015-12-18 JFL Created this routine. |
|
||||
* *
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
DWORD WINAPI GetLongPathNameU(LPCTSTR lpShortName, LPTSTR lpBuf, DWORD nBufferLength) {
|
||||
WCHAR wszShortName[MAX_PATH];
|
||||
WCHAR wszBuf[MAX_PATH];
|
||||
int n;
|
||||
DWORD dwResult;
|
||||
|
||||
DEBUG_ENTER(("GetLongPathNameU(\"%s\", %p, %d);\n", lpShortName, lpBuf, nBufferLength));
|
||||
|
||||
n = MultiByteToWideChar(CP_UTF8, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
0, /* dwFlags, */
|
||||
lpShortName, /* lpMultiByteStr, */
|
||||
lstrlen(lpShortName)+1, /* cbMultiByte, */
|
||||
wszShortName, /* lpWideCharStr, */
|
||||
MAX_PATH /* cchWideChar, */
|
||||
);
|
||||
if (!n) RETURN_INT_COMMENT(0, ("Failed to convert the short name to Unicode\n"));
|
||||
|
||||
dwResult = GetLongPathNameW(wszShortName, wszBuf, MAX_PATH);
|
||||
if (!dwResult) RETURN_INT_COMMENT(0, ("GetLongPathNameW() failed\n"));
|
||||
|
||||
/* nRead = UnicodeToBytes(pwStr, len, buf, bufsize); */
|
||||
n = WideCharToMultiByte(CP_UTF8, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
0, /* dwFlags, */
|
||||
wszBuf, /* lpWideCharStr, */
|
||||
(int)dwResult + 1, /* cchWideChar, */
|
||||
lpBuf, /* lpMultiByteStr, */
|
||||
(int)nBufferLength, /* cbMultiByte, */
|
||||
NULL, /* lpDefaultChar, */
|
||||
NULL /* lpUsedDefaultChar */
|
||||
);
|
||||
if (!n) RETURN_INT_COMMENT(0, ("Failed to convert the Long name from Unicode\n"));
|
||||
|
||||
RETURN_INT_COMMENT(n-1, ("\"%s\"\n", lpBuf));
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename access.c *
|
||||
* *
|
||||
* Description: WIN32 UTF-8 version of access *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-03-24 JFL Created this module. *
|
||||
* 2014-07-02 JFL Added support for pathnames >= 260 characters. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS 1 /* Avoid Visual C++ security warnings */
|
||||
|
||||
#include <errno.h>
|
||||
#include <io.h>
|
||||
#include "msvcStdio.h"
|
||||
#include "msvclibx.h"
|
||||
#include "msvcDebugm.h"
|
||||
#include "msvcLimits.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
* *
|
||||
| Function access |
|
||||
| |
|
||||
| Description UTF-8 version of access |
|
||||
| |
|
||||
| Parameters char *pszName File name |
|
||||
| int iMode Access mode to test |
|
||||
| |
|
||||
| Returns File handle |
|
||||
| |
|
||||
| Notes |
|
||||
| |
|
||||
| History |
|
||||
| 2014-03-24 JFL Created this routine. |
|
||||
| 2014-07-02 JFL Added support for pathnames >= 260 characters. |
|
||||
* *
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int _accessU(const char *pszName, int iMode) {
|
||||
WCHAR wszName[PATH_MAX];
|
||||
int n;
|
||||
|
||||
/* Convert the pathname to a unicode string, with the proper extension prefixes if it's longer than 260 bytes */
|
||||
n = MultiByteToWidePath(CP_UTF8, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
pszName, /* lpMultiByteStr, */
|
||||
wszName, /* lpWideCharStr, */
|
||||
COUNTOF(wszName) /* cchWideChar, */
|
||||
);
|
||||
if (!n) {
|
||||
errno = Win32ErrorToErrno();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return _waccess(wszName, iMode);
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename basename.c *
|
||||
* *
|
||||
* Description Get the file name part of a file pathname *
|
||||
* *
|
||||
* Notes Uses a static buffer in some cases. Not thread safe! *
|
||||
* Posix spec authorizes this, and also authorizes to modify *
|
||||
* the input string, which we do. => Always do an strdup() *
|
||||
* before calling basename(), and call basename(copy). *
|
||||
* *
|
||||
* History *
|
||||
* 2016-09-08 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS 1 /* Avoid Visual C++ 2005 security warnings */
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include "msvcStdlib.h"
|
||||
#include "msvcLibgen.h"
|
||||
#include "msvcLimits.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
char *basename(char *pszPathname) {
|
||||
char *pszPath = pszPathname;
|
||||
size_t len;
|
||||
char *pc;
|
||||
char *pc2;
|
||||
|
||||
/* A NULL pathname is assumed to refer to the current directory */
|
||||
if (!pszPathname) return ".";
|
||||
/* Skip the drive if present */
|
||||
len = strlen(pszPathname);
|
||||
if ((len >= 2) && (pszPathname[1] == ':')) {
|
||||
pszPath += 2;
|
||||
len -= 2;
|
||||
}
|
||||
if (!len) return ".";
|
||||
/* Remove trailing path separators */
|
||||
while ((len > 1) && ((pszPath[len-1] == '\\') || (pszPath[len-1] == '/'))) {
|
||||
pszPath[--len] = '\0';
|
||||
}
|
||||
/* Find the beginning of the file name */
|
||||
pc = strrchr(pszPath, '\\');
|
||||
pc2 = strrchr(pszPath, '/');
|
||||
if (pc2 > pc) pc = pc2;
|
||||
if (pc) pc += 1; else pc = pszPath;
|
||||
if (!*pc) return pszPath; /* No file name left. This is the root directory */
|
||||
/* Done */
|
||||
return pc;
|
||||
}
|
|
@ -1,149 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename chdir.c *
|
||||
* *
|
||||
* Description: WIN32 port of standard C library's chdir() *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-02-28 JFL Created this module. *
|
||||
* 2014-07-02 JFL Added support for pathnames >= 260 characters. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#define _UTF8_SOURCE /* Generate the UTF-8 version of routines */
|
||||
|
||||
/* Microsoft C libraries include files */
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
/* MsvcLibX library extensions */
|
||||
#include "msvcStdio.h"
|
||||
#include "msvcUnistd.h"
|
||||
#include "msvcIconv.h"
|
||||
#include "msvcDebugm.h"
|
||||
#include "msvcLimits.h"
|
||||
#include "sys/msvcTypes.h"
|
||||
|
||||
#if defined(_MSDOS)
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
| *
|
||||
| Function: chdir |
|
||||
| |
|
||||
| Description: Change directory, overcoming the 64-character DOS limit |
|
||||
| |
|
||||
| Parameters: char *pszDir Target directory pathname |
|
||||
| |
|
||||
| Returns: 0=Done; Else OS error code. |
|
||||
| |
|
||||
| Notes: Unfortunately this works only in a DOS box within Win9X. |
|
||||
| |
|
||||
| History: |
|
||||
| 2000-12-04 JFL Initial implementation. |
|
||||
* *
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int chdir(const char *pszDir)
|
||||
{
|
||||
char szBuf[64];
|
||||
char *pszBuf = szBuf;
|
||||
char *pc;
|
||||
int iDirLen;
|
||||
int iStrLen;
|
||||
int iErr = 0;
|
||||
|
||||
iDirLen = strlen(pszDir);
|
||||
/* Copy the drive letter if specified, and leave it ahead of the buffer. */
|
||||
if ((iDirLen>2) && (pszDir[1]==':'))
|
||||
{
|
||||
szBuf[0] = pszDir[0];
|
||||
szBuf[1] = ':';
|
||||
pszDir += 2;
|
||||
pszBuf += 2;
|
||||
}
|
||||
/* Repeat relative moves down the directory tree */
|
||||
while (iDirLen > 60)
|
||||
{
|
||||
pc = strchr(pszDir+45, '\\'); /* There has to be one in segment [45:60]. */
|
||||
iStrLen = pc-pszDir; /* Segment length */
|
||||
strncpy(pszBuf, pszDir, iStrLen); /* Copy until the \ found */
|
||||
pszBuf[iStrLen] = '\0';
|
||||
iErr = chdir(szBuf);
|
||||
if (iErr) return iErr;
|
||||
pszDir += iStrLen+1;
|
||||
iDirLen -= iStrLen+1;
|
||||
} ;
|
||||
|
||||
if (iDirLen)
|
||||
{
|
||||
strcpy(pszBuf, pszDir);
|
||||
iErr = chdir(szBuf);
|
||||
}
|
||||
|
||||
return iErr;
|
||||
}
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
|
||||
#if defined(_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
* *
|
||||
| Function: chdir |
|
||||
| |
|
||||
| Description: Set the current directory, encoded in UTF-8 |
|
||||
| |
|
||||
| Parameters: const char *pszDir Target directory pathname |
|
||||
| |
|
||||
| Returns: 0=Done; Else OS error code. |
|
||||
| |
|
||||
| History: |
|
||||
| 2014-02-28 JFL Created this routine |
|
||||
| 2014-07-02 JFL Added support for pathnames >= 260 characters. |
|
||||
* *
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
int chdirA(const char *pszDir) {
|
||||
WCHAR wszDir[PATH_MAX];
|
||||
BOOL bDone;
|
||||
int n;
|
||||
DEBUG_PRINTF(("chdir(\"%s\");\n", pszDir));
|
||||
/* Convert the pathname to a unicode string, with the proper extension prefixes if it's longer than 260 bytes */
|
||||
n = MultiByteToWidePath(CP_ACP, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
pszDir, /* lpMultiByteStr, */
|
||||
wszDir, /* lpWideCharStr, */
|
||||
COUNTOF(wszDir) /* cchWideChar, */
|
||||
);
|
||||
bDone = SetCurrentDirectoryW(wszDir);
|
||||
if (!bDone) {
|
||||
errno = Win32ErrorToErrno();
|
||||
}
|
||||
return bDone ? 0 : -1;
|
||||
}
|
||||
|
||||
int chdirU(const char *pszDir) {
|
||||
WCHAR wszDir[PATH_MAX];
|
||||
BOOL bDone;
|
||||
int n;
|
||||
DEBUG_PRINTF(("chdir(\"%s\");\n", pszDir));
|
||||
/* Convert the pathname to a unicode string, with the proper extension prefixes if it's longer than 260 bytes */
|
||||
n = MultiByteToWidePath(CP_UTF8, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
pszDir, /* lpMultiByteStr, */
|
||||
wszDir, /* lpWideCharStr, */
|
||||
COUNTOF(wszDir) /* cchWideChar, */
|
||||
);
|
||||
bDone = SetCurrentDirectoryW(wszDir);
|
||||
if (!bDone) {
|
||||
errno = Win32ErrorToErrno();
|
||||
}
|
||||
return bDone ? 0 : -1;
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
|
@ -1,89 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: clock_gettime.c *
|
||||
* *
|
||||
* Description: WIN32 port of standard C library's clock_gettime(). *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-06-04 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
#ifdef _MSDOS
|
||||
|
||||
/* Check for the definition of _STRUCT_TIMESPEC before using clock_gettime().
|
||||
If it's not defined, use time() instead, which is supported by all OSs. */
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN /* Avoid lots of unnecessary inclusions */
|
||||
#include <windows.h>
|
||||
#include "msvcTime.h"
|
||||
#include "sys/msvcStat.h" /* For MsvcLibX's Filetime2Timespec */
|
||||
|
||||
#define MS_PER_SEC 1000ULL // MS = milliseconds
|
||||
#define US_PER_MS 1000ULL // US = microseconds
|
||||
#define HNS_PER_US 10ULL // HNS = hundred-nanoseconds (e.g., 1 hns = 100 ns)
|
||||
#define NS_PER_US 1000ULL
|
||||
|
||||
#define HNS_PER_SEC (MS_PER_SEC * US_PER_MS * HNS_PER_US)
|
||||
#define NS_PER_HNS (100ULL) // NS = nanoseconds
|
||||
#define NS_PER_SEC (MS_PER_SEC * US_PER_MS * NS_PER_US)
|
||||
|
||||
int clock_gettime_monotonic(struct timespec *tv) {
|
||||
static LARGE_INTEGER ticksPerSec;
|
||||
LARGE_INTEGER ticks;
|
||||
double seconds;
|
||||
|
||||
if (!ticksPerSec.QuadPart) {
|
||||
QueryPerformanceFrequency(&ticksPerSec);
|
||||
if (!ticksPerSec.QuadPart) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
QueryPerformanceCounter(&ticks);
|
||||
|
||||
seconds = (double) ticks.QuadPart / (double) ticksPerSec.QuadPart;
|
||||
tv->tv_sec = (time_t)seconds;
|
||||
tv->tv_nsec = (long)((ULONGLONG)(seconds * NS_PER_SEC) % NS_PER_SEC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_gettime_realtime(struct timespec *pTS) {
|
||||
FILETIME ft;
|
||||
|
||||
GetSystemTimeAsFileTime(&ft);
|
||||
Filetime2Timespec(&ft, pTS);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int clock_gettime(clockid_t clock_id, struct timespec *pTS) {
|
||||
if (clock_id == CLOCK_MONOTONIC) {
|
||||
return clock_gettime_monotonic(pTS);
|
||||
} else if (clock_id == CLOCK_REALTIME) {
|
||||
return clock_gettime_realtime(pTS);
|
||||
}
|
||||
|
||||
errno = ENOTSUP;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) */
|
|
@ -1,23 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: debugv.c *
|
||||
* *
|
||||
* Description: Define debug variables used by MsvcLibX.lib in debug mode *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2013-03-27 JFL jf.larvoire@hp.com created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#include "msvcDebugm.h"
|
||||
|
||||
#if defined(_DEBUG)
|
||||
|
||||
DEBUG_GLOBALS
|
||||
|
||||
#endif /* !defined(_DEBUG) */
|
||||
|
|
@ -1,709 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: dirent.c *
|
||||
* *
|
||||
* Description: DOS/WIN32 port of standard C library's dirent.h functions *
|
||||
* *
|
||||
* Notes: TO DO: Make Wide & MultiByte versions of scandir 4 Windows*
|
||||
* *
|
||||
* There are also remains of an OS/2 implementation here. *
|
||||
* It's not maintained anymore. Left in as a historic *
|
||||
* reference, in the unlikely case somebody needs it. *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-01-09 JFL Created this file, based on dirc and other programs. *
|
||||
* 2012-01-19 JFL Added standard errno management. *
|
||||
* 2012-05-22 JFL Fixed a bug in the DOS version, which failed if the *
|
||||
* directory name was longer than 12 bytes. *
|
||||
* 2012-05-23 JFL Fixed opendir to return errors as per the C lib spec. *
|
||||
* 2013-02-12 JFL Added code to filter reparse points, and keep only *
|
||||
* real junctions and symlinks. *
|
||||
* 2013-02-13 JFL Moved dirent2stat() to lstat.c, as there must actually *
|
||||
* be 4 WIN32 versions, for the four versions of struct stat.*
|
||||
* 2013-02-26 JFL Moved the proprietary file time management routines to *
|
||||
* the new filetime.c module. *
|
||||
* 2014-02-27 JFL Changed the WIN32 output name encoding to UTF-8. *
|
||||
* 2014-03-20 JFL Restructured Windows opendir and readdir functions into *
|
||||
* Wide and MultiByte versions, and changed the Unicode and *
|
||||
* Ansi versions to macros. *
|
||||
* 2014-03-24 JFL Renamed "statx.h" as the standard <sys/stat.h>. *
|
||||
* 2015-12-14 JFL Bug fix: WIN32 readdirW always read the root on "D:". *
|
||||
* Bug fix: DOS opendir failed on root dirs, like "D:\". *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS 1 /* Avoid Visual C++ security warnings */
|
||||
|
||||
#define _UTF8_SOURCE /* Generate the UTF-8 version of WIN32 printf & scandir */
|
||||
|
||||
#include "msvcDirent.h" /* Include our associated .h, in the same dir as this .c. Do not use <>. */
|
||||
#ifndef _DIRENT_FOR_DOS_WINDOWS
|
||||
#error "This requires MsvcLibX own version of dirent.h for DOS/Windows"
|
||||
#endif
|
||||
/* Microsoft C libraries include files */
|
||||
#include <io.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <memory.h>
|
||||
#include <errno.h>
|
||||
/* MsvcLibX library extensions */
|
||||
#include "msvcUnistd.h" /* For readlink() */
|
||||
#include "sys/msvcStat.h" /* For Filetime2String() */
|
||||
#include "msvcDebugm.h" /* Use our house debugging framework */
|
||||
#include "msvcLimits.h" /* Use our house debugging framework */
|
||||
|
||||
/*****************************************************************************\
|
||||
* *
|
||||
* MS_DOS Version *
|
||||
* *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifdef _MSDOS
|
||||
|
||||
#define OFFSET_OF(pointer) ((uint16_t)(uint32_t)(void far *)pointer)
|
||||
#define SEGMENT_OF(pointer) ((uint16_t)(((uint32_t)(void far *)pointer) >> 16))
|
||||
|
||||
void put_dta(char *p_dta) { /* Set the MS-DOS Disk Transfer Address */
|
||||
union REGS inreg;
|
||||
union REGS outreg;
|
||||
struct SREGS sregs;
|
||||
|
||||
inreg.h.ah = 0x1a;
|
||||
inreg.x.dx = OFFSET_OF(p_dta);
|
||||
sregs.ds = SEGMENT_OF(p_dta);
|
||||
|
||||
intdosx(&inreg, &outreg, &sregs);
|
||||
}
|
||||
|
||||
#define CF 0x0001 /* Carry flag bit mask */
|
||||
|
||||
int get_file_attributes(const char *name, unsigned *pAttr) { /* Get File Attributes */
|
||||
union REGS inreg;
|
||||
union REGS outreg;
|
||||
struct SREGS sregs;
|
||||
|
||||
inreg.x.ax = 0x4300;
|
||||
inreg.x.dx = OFFSET_OF(name);
|
||||
sregs.ds = SEGMENT_OF(name);
|
||||
|
||||
intdosx(&inreg, &outreg, &sregs);
|
||||
|
||||
if (CF & outreg.x.cflag) {
|
||||
errno = outreg.x.ax;
|
||||
return errno;
|
||||
}
|
||||
|
||||
*pAttr = outreg.x.cx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Workaround for a VMWare player shared folders bug:
|
||||
DOS function 4e (search next) sometimes returns several times the same entry. */
|
||||
static fileinfo previousFI;
|
||||
#ifdef _DEBUG
|
||||
static int report_workaround(char *s) {
|
||||
DEBUG_PRINTF((s));
|
||||
return 1;
|
||||
}
|
||||
#define REPORT_WORKAROUND(args) report_workaround args
|
||||
#else
|
||||
#define REPORT_WORKAROUND(args) 1
|
||||
#endif
|
||||
|
||||
int srch1st(char *pszFile, uint16_t wAttr, fileinfo *pInfo) { /* Search first matching file */
|
||||
union REGS inreg;
|
||||
union REGS outreg;
|
||||
struct SREGS sregs;
|
||||
|
||||
DEBUG_ENTER(("srch1st(\"%s\", 0x%04X, 0x%p);\n", pszFile, wAttr, pInfo));
|
||||
|
||||
/* Make sure the DTA is assigned before calling DOS functions 4E and 4F */
|
||||
put_dta((char *)pInfo);
|
||||
|
||||
inreg.h.ah = 0x4e;
|
||||
inreg.x.cx = wAttr;
|
||||
inreg.x.dx = OFFSET_OF(pszFile);
|
||||
sregs.ds = SEGMENT_OF(pszFile);
|
||||
|
||||
intdosx(&inreg, &outreg, &sregs);
|
||||
|
||||
if (CF & outreg.x.cflag) {
|
||||
DEBUG_LEAVE(("return %d; // DOS error code\n", outreg.x.ax));
|
||||
return (int)(outreg.x.ax);
|
||||
}
|
||||
|
||||
previousFI = *pInfo; /* Save it for the workaround for the VMWare player bug */
|
||||
|
||||
DEBUG_LEAVE(("return 0; // Success\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srchnext(fileinfo *pInfo) { /* Search next matching file */
|
||||
union REGS inreg;
|
||||
union REGS outreg;
|
||||
|
||||
DEBUG_ENTER(("srchnext(0x%p);\n", pInfo));
|
||||
|
||||
/* Make sure the DTA is assigned before calling DOS functions 4E and 4F */
|
||||
put_dta((char *)pInfo);
|
||||
|
||||
inreg.h.ah = 0x4f;
|
||||
|
||||
do {
|
||||
intdos(&inreg, &outreg);
|
||||
|
||||
if (CF & outreg.x.cflag) {
|
||||
DEBUG_LEAVE(("return %d; // DOS error code\n", outreg.x.ax));
|
||||
return(outreg.x.ax);
|
||||
}
|
||||
} while ((!strncmp(previousFI.fiFileName, pInfo->fiFileName, sizeof(previousFI)))
|
||||
&& REPORT_WORKAROUND(("// Skipped one duplicate entry\n")));
|
||||
|
||||
previousFI = *pInfo; /* Save it for the workaround for the VMWare player bug */
|
||||
|
||||
DEBUG_LEAVE(("return 0; // Success\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
DIR *opendir(const char *name) { /* Open a directory */
|
||||
DIR *pDir = NULL;
|
||||
size_t lName;
|
||||
unsigned attr;
|
||||
char *pszWildCards = "\\*.*";
|
||||
char *pszCopy;
|
||||
DEBUG_ENTER(("opendir(\"%s\");\n", name));
|
||||
lName = strlen(name);
|
||||
if (lName == 0) {
|
||||
opendir_noent:
|
||||
errno = ENOENT;
|
||||
opendir_failed:
|
||||
if (!_sys_errlist[ENOTDIR][0]) _sys_errlist[ENOTDIR] = "Not a directory"; /* Workaround for the missing entry in MSVC list */
|
||||
if (pDir) free(pDir);
|
||||
DEBUG_LEAVE(("return NULL; // errno=%d - %s\n", errno, strerror(errno)));
|
||||
return NULL;
|
||||
}
|
||||
pDir = (DIR *)malloc(sizeof(DIR) + lName + 5); /* + 5 for wildcards suffix */
|
||||
if (!pDir) goto opendir_failed;
|
||||
/* Work on a copy of the directory name */
|
||||
pszCopy = (char *)(pDir + 1);
|
||||
strcpy(pszCopy, name);
|
||||
/* First change: Except for the root, Remove the trailing \s, which confuses get_file_attributes() */
|
||||
while ((lName > 1) && (name[lName-1] == '\\') && (name[lName-2] != ':')) pszCopy[--lName] = '\0';
|
||||
if (get_file_attributes(pszCopy, &attr)) goto opendir_noent;
|
||||
if (!(attr & _A_SUBDIR)) {
|
||||
errno = ENOTDIR;
|
||||
goto opendir_failed;
|
||||
}
|
||||
if (name[lName-1] == '\\') pszWildCards += 1; /* Avoid duplicating the \ */
|
||||
strcpy(pszCopy+lName, pszWildCards);
|
||||
pDir->first = 1;
|
||||
DEBUG_LEAVE(("return 0x%p;\n", pDir));
|
||||
return pDir;
|
||||
}
|
||||
|
||||
int closedir(DIR *pDir) { /* Close the directory. Return 0 if successful, -1 if not. */
|
||||
DEBUG_PRINTF(("closedir(0x%p);\n", pDir));
|
||||
if (pDir) free(pDir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_dirent *readdir(DIR *pDir) { /* Read a directory entry. Return pDir, or NULL for EOF or error. */
|
||||
int iErr;
|
||||
_dirent *pDirent = &pDir->sDirent;
|
||||
fileinfo *pFI = (fileinfo *)(pDirent->d_reserved); /* Address of the fileinfo structure embedded there */
|
||||
#ifdef _DEBUG
|
||||
char szTime[40];
|
||||
#endif
|
||||
|
||||
DEBUG_ENTER(("readdir(0x%p);\n", pDir));
|
||||
if (pDir->first) { /* First search */
|
||||
iErr = srch1st((char *)(pDir+1), 0x3F, pFI);
|
||||
pDir->first = 0;
|
||||
} else {
|
||||
iErr = srchnext(pFI);
|
||||
}
|
||||
if (!iErr) {
|
||||
pDirent->d_type = DT_REG; /* A normal file by default */
|
||||
if (pDirent->d_attribs & _A_SUBDIR) pDirent->d_type = DT_DIR; /* Subdirectory */
|
||||
if (pDirent->d_attribs & _A_VOLID) pDirent->d_type = DT_VOLID; /* Volume ID file */
|
||||
DEBUG_LEAVE(("return 0x%p; // %s %02X %10ld %s\n",
|
||||
pDirent,
|
||||
Filetime2String(pDirent->d_date, pDirent->d_time, szTime, sizeof(szTime)),
|
||||
pDirent->d_attribs,
|
||||
pDirent->d_filesize,
|
||||
pDirent->d_name));
|
||||
return &pDir->sDirent;
|
||||
}
|
||||
switch (iErr) { /* Correct a few errors that do not map well to C library errors */
|
||||
case ESRCH: iErr = ENOTDIR; break;
|
||||
case EXDEV: iErr = 0; break; /* End of files is NOT an error */
|
||||
}
|
||||
if (iErr) {
|
||||
errno = iErr; /* MS-DOS' errno.h maps C-library errnos to DOS' errors */
|
||||
DEBUG_LEAVE(("return NULL; // errno=%d - %s\n", errno, strerror(errno)));
|
||||
} else {
|
||||
DEBUG_LEAVE(("return NULL; // End of directory\n"));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
/*****************************************************************************\
|
||||
* *
|
||||
* WIN32 Version *
|
||||
* *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/* Requires including windows.h and especially the kernel section */
|
||||
|
||||
DIR *opendirW(const WCHAR *wszName) { /* Open a directory - Wide char version */
|
||||
DIR *pDir;
|
||||
int err;
|
||||
DWORD dw;
|
||||
DEBUG_CODE(
|
||||
char szUtf8[UTF8_PATH_MAX];
|
||||
)
|
||||
|
||||
DEBUG_WSTR2UTF8(wszName, szUtf8, sizeof(szUtf8));
|
||||
DEBUG_ENTER(("opendir(\"%s\");\n", szUtf8));
|
||||
|
||||
dw = GetFileAttributesW(wszName);
|
||||
err = 0;
|
||||
if (dw == INVALID_FILE_ATTRIBUTES) {
|
||||
err = errno = Win32ErrorToErrno();
|
||||
} else {
|
||||
if (!(dw & _A_SUBDIR)) {
|
||||
err = errno = ENOTDIR;
|
||||
}
|
||||
}
|
||||
if (err) {
|
||||
RETURN_CONST_COMMENT(NULL, ("errno=%d - %s\n", errno, strerror(errno)));
|
||||
}
|
||||
if (lstrlenW(wszName) >= sizeof(pDir->wszDirName)) {
|
||||
errno = ENAMETOOLONG;
|
||||
RETURN_CONST_COMMENT(NULL, ("errno=%d - %s\n", errno, strerror(errno)));
|
||||
}
|
||||
pDir = malloc(sizeof(DIR));
|
||||
if (!pDir) {
|
||||
errno = ENOMEM;
|
||||
RETURN_CONST_COMMENT(NULL, ("errno=%d - %s\n", errno, strerror(errno)));
|
||||
}
|
||||
pDir->hFindFile = INVALID_HANDLE_VALUE;
|
||||
lstrcpyW(pDir->wszDirName, wszName);
|
||||
DEBUG_LEAVE(("return 0x%p; // Success\n", pDir));
|
||||
return pDir;
|
||||
}
|
||||
|
||||
DIR *opendirM(const char *name, UINT cp) { /* Open a directory - MultiByte char version */
|
||||
WCHAR wszName[PATH_MAX];
|
||||
int n;
|
||||
|
||||
/* Convert the pathname to a unicode string, with the proper extension prefixes if it's longer than 260 bytes */
|
||||
n = MultiByteToWidePath(cp, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
name, /* lpMultiByteStr, */
|
||||
wszName, /* lpWideCharStr, */
|
||||
COUNTOF(wszName) /* cchWideChar, */
|
||||
);
|
||||
if (!n) {
|
||||
errno = Win32ErrorToErrno();
|
||||
DEBUG_PRINTF(("opendirM(\"%s\"); // Can't convert name to Unicode: errno=%d - %s\n", name, errno, strerror(errno)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return opendirW(wszName);
|
||||
}
|
||||
|
||||
int closedir(DIR *pDir) { /* Close the directory. Return 0 if successful, -1 if not. */
|
||||
DEBUG_PRINTF(("closedir(0x%p);\n", pDir));
|
||||
if (pDir) {
|
||||
if (pDir->hFindFile != INVALID_HANDLE_VALUE) FindClose(pDir->hFindFile);
|
||||
pDir->hFindFile = INVALID_HANDLE_VALUE;
|
||||
free(pDir);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read a directory entry. Return pDir, or NULL for EOF or error. Wide char version. */
|
||||
_dirent *readdirW(DIR *pDir) {
|
||||
int iErr = 0;
|
||||
_dirent *pDirent = &pDir->sDirent;
|
||||
int bIsJunction = FALSE;
|
||||
int bIsMountPoint = FALSE;
|
||||
DWORD dwTag = 0; /* Reparse points tag */
|
||||
DWORD dwAttr;
|
||||
int n;
|
||||
DEBUG_CODE(
|
||||
char szTime[40];
|
||||
char szUtf8[UTF8_PATH_MAX];
|
||||
)
|
||||
|
||||
DEBUG_ENTER(("readdir(0x%p);\n", pDir));
|
||||
|
||||
if (pDir->hFindFile == INVALID_HANDLE_VALUE) {
|
||||
WCHAR wszPattern[MAX_PATH+5];
|
||||
lstrcpyW(wszPattern, pDir->wszDirName);
|
||||
n = lstrlenW(wszPattern);
|
||||
if (n && (wszPattern[n-1] != L'\\') && (wszPattern[n-1] != L':')) wszPattern[n++] = L'\\';
|
||||
lstrcpyW(wszPattern+n, L"*.*");
|
||||
pDir->hFindFile = FindFirstFileW(wszPattern, &pDir->wfd);
|
||||
if (pDir->hFindFile == INVALID_HANDLE_VALUE) {
|
||||
iErr = Win32ErrorToErrno();
|
||||
if (!iErr) iErr = ENOENT;
|
||||
}
|
||||
} else {
|
||||
iErr = !FindNextFileW(pDir->hFindFile, &pDir->wfd);
|
||||
if (iErr) {
|
||||
iErr = Win32ErrorToErrno();
|
||||
if (!iErr) iErr = ENOENT;
|
||||
}
|
||||
}
|
||||
if (iErr) {
|
||||
switch (iErr) { /* Correct a few errors that do not map well to C library errors */
|
||||
case ESRCH: iErr = ENOTDIR; break;
|
||||
case EXDEV: iErr = 0; break; /* End of files is NOT an error */
|
||||
}
|
||||
if (iErr) {
|
||||
errno = iErr; /* Windows' errno.h maps C-library errnos to Windows' errors */
|
||||
DEBUG_LEAVE(("return NULL; // errno=%d - %s\n", errno, strerror(errno)));
|
||||
} else {
|
||||
DEBUG_LEAVE(("return NULL; // End of directory\n"));
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set the standard fields */
|
||||
lstrcpyW((WCHAR *)(pDirent->d_name), pDir->wfd.cFileName);
|
||||
dwAttr = pDir->wfd.dwFileAttributes;
|
||||
check_attr_again:
|
||||
if (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT) {
|
||||
/* JUNCTIONs and SYMLINKDs both have the FILE_ATTRIBUTE_DIRECTORY flag also set.
|
||||
// Test the FILE_ATTRIBUTE_REPARSE_POINT flag first, to make sure they're seen as symbolic links.
|
||||
//
|
||||
// All symlinks are reparse points, but not all reparse points are symlinks. */
|
||||
dwTag = pDir->wfd.dwReserved0; /* No need to call GetReparseTag(), we got it already. */
|
||||
switch (dwTag) {
|
||||
case IO_REPARSE_TAG_MOUNT_POINT: /* NTFS junction or mount point */
|
||||
{ /* We must read the link to distinguish junctions from mount points. */
|
||||
WCHAR wszPath[PATH_MAX];
|
||||
WCHAR wszBuf[PATH_MAX];
|
||||
ssize_t n = lstrlenW(pDir->wszDirName);
|
||||
if ((n + 1 + lstrlenW(pDir->wfd.cFileName)) >= PATH_MAX) {
|
||||
errno = ENAMETOOLONG; /* DIRNAME\LINKNAME won't fit in wszPath[] */
|
||||
DEBUG_LEAVE(("return NULL; // errno=%d - %s\n", errno, strerror(errno)));
|
||||
}
|
||||
bIsMountPoint = TRUE;
|
||||
lstrcpyW(wszPath, pDir->wszDirName);
|
||||
if (n && (wszPath[n-1] != L'\\')) wszPath[n++] = L'\\';
|
||||
lstrcpyW(wszPath+n, pDir->wfd.cFileName);
|
||||
n = readlinkW(wszPath, wszBuf, COUNTOF(wszBuf));
|
||||
/* Junction targets are absolute pathnames, starting with a drive letter. Ex: C: */
|
||||
/* readlink() fails if the reparse point does not target a valid pathname */
|
||||
if (n < 0) goto this_is_not_a_symlink; /* This is not a junction. */
|
||||
bIsJunction = TRUE; /* Else this is a junction. Fall through to the symlink case. */
|
||||
}
|
||||
case IO_REPARSE_TAG_SYMLINK: /* NTFS symbolic link */
|
||||
pDirent->d_type = DT_LNK; /* Symbolic link */
|
||||
break;
|
||||
default: /* Anything else is definitely not like a Unix symlink */
|
||||
this_is_not_a_symlink:
|
||||
dwAttr &= ~FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
goto check_attr_again;
|
||||
}
|
||||
} else if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
|
||||
pDirent->d_type = DT_DIR; /* Subdirectory */
|
||||
else if (dwAttr & FILE_ATTRIBUTE_DEVICE)
|
||||
pDirent->d_type = DT_CHR; /* Device (we don't know if character or block) */
|
||||
else
|
||||
pDirent->d_type = DT_REG; /* A normal file by default */
|
||||
|
||||
/* Set the OS-specific extensions */
|
||||
lstrcpyW((WCHAR *)(pDirent->d_shortname), pDir->wfd.cAlternateFileName);
|
||||
pDirent->d_attribs = dwAttr;
|
||||
pDirent->d_ReparseTag = dwTag;
|
||||
pDirent->d_CreationTime = pDir->wfd.ftCreationTime;
|
||||
pDirent->d_LastAccessTime = pDir->wfd.ftLastAccessTime;
|
||||
pDirent->d_LastWriteTime = pDir->wfd.ftLastWriteTime;
|
||||
(*(ULARGE_INTEGER *)&(pDirent->d_filesize)).LowPart = pDir->wfd.nFileSizeLow;
|
||||
(*(ULARGE_INTEGER *)&(pDirent->d_filesize)).HighPart = pDir->wfd.nFileSizeHigh;
|
||||
|
||||
DEBUG_WSTR2UTF8((WCHAR *)(pDirent->d_name), szUtf8, sizeof(szUtf8));
|
||||
DEBUG_LEAVE(("return 0x%p; // %s 0x%05X %10lld %s\n",
|
||||
pDirent,
|
||||
Filetime2String(&pDirent->d_LastWriteTime, szTime, sizeof(szTime)),
|
||||
(int)(pDirent->d_attribs),
|
||||
pDirent->d_filesize,
|
||||
szUtf8));
|
||||
return &(pDir->sDirent);
|
||||
}
|
||||
|
||||
/* Read a directory entry. Return pDir, or NULL for EOF or error. MultiByte char version. */
|
||||
_dirent *readdirM(DIR *pDir, UINT cp) {
|
||||
_dirent *pDirent;
|
||||
int n;
|
||||
char *pszDefaultChar;
|
||||
|
||||
pDirent = readdirW(pDir);
|
||||
if (!pDirent) return NULL;
|
||||
|
||||
/* Convert the name field back to MultiByte encoding */
|
||||
pszDefaultChar = (cp == CP_UTF8) ? NULL : "?";
|
||||
n = WideCharToMultiByte(cp, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
0, /* dwFlags, */
|
||||
pDir->wfd.cFileName, /* lpWideCharStr, */
|
||||
lstrlenW(pDir->wfd.cFileName)+1, /* cchWideChar, */
|
||||
pDirent->d_name, /* lpMultiByteStr, */
|
||||
sizeof(pDirent->d_name), /* cbMultiByte, */
|
||||
pszDefaultChar, /* lpDefaultChar, */
|
||||
NULL /* lpUsedDefaultChar */
|
||||
);
|
||||
if (!n) {
|
||||
errno = Win32ErrorToErrno();
|
||||
DEBUG_PRINTF(("readdirM(0x%p); // Error converting name back from Unicode. errno=%d - %s\n", pDir, errno, strerror(errno)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Convert the short name field back to MultiByte encoding */
|
||||
n = WideCharToMultiByte(cp, /* CodePage, (CP_ACP, CP_OEMCP, CP_UTF8, ...) */
|
||||
0, /* dwFlags, */
|
||||
pDir->wfd.cAlternateFileName, /* lpWideCharStr, */
|
||||
lstrlenW(pDir->wfd.cAlternateFileName)+1, /* cchWideChar, */
|
||||
pDirent->d_shortname, /* lpMultiByteStr, */
|
||||
sizeof(pDirent->d_shortname), /* cbMultiByte, */
|
||||
pszDefaultChar, /* lpDefaultChar, */
|
||||
NULL /* lpUsedDefaultChar */
|
||||
);
|
||||
if (!n) {
|
||||
errno = Win32ErrorToErrno();
|
||||
DEBUG_PRINTF(("readdirM(0x%p); // Error converting short name back from Unicode. errno=%d - %s\n", pDir, errno, strerror(errno)));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pDirent;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************\
|
||||
* *
|
||||
* OS/2 1.x Version *
|
||||
* *
|
||||
\*****************************************************************************/
|
||||
|
||||
#ifdef _OS2
|
||||
|
||||
/* Requires including os2.h at the beginning of this file, and before that
|
||||
defining the INCL_DOSFILEMGR constant to enable the necessary section */
|
||||
|
||||
int SetDirent(DIR *pDir) { /* Convert the FILEFINDBUF to a dirent structure */
|
||||
char *pc;
|
||||
_dirent *pDirent = &pDir->sDirent;
|
||||
FILEFINDBUF *pbuf = &pDir->buf;
|
||||
|
||||
pbuf->achName[pbuf->cchName] = '\0';
|
||||
pc = strrchr(pbuf->achName, '\\'); /* Directory separator character */
|
||||
if (!pc)
|
||||
pc = &pbuf->achName[0];
|
||||
else
|
||||
pc += 1; /* Skip the \ */
|
||||
|
||||
pDirent->d_name = malloc(strlen(pc)+1);
|
||||
if (!pDirent->d_name) return ENOMEM;
|
||||
strcpy(pDirent->d_name, pc);
|
||||
pDirent->attribs = pbuf->attrFile;
|
||||
pDirent->d_type = Atype2Dtype(pDirent->attribs);
|
||||
pDirent->time = *(uint16_t *)&pbuf->ftimeLastWrite;
|
||||
pDirent->date = *(uint16_t *)&pbuf->fdateLastWrite;
|
||||
pDirent->filesize = pbuf->cbFile;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srch1st(char *pszFile, uint8_t bAttrReq, uint8_t bAttrCmp, DIR *pDir) { /* Search first matching file */
|
||||
int n;
|
||||
int err;
|
||||
|
||||
pDir->hDir = -1;
|
||||
|
||||
n = 1; /* Get one file */
|
||||
err = DosFindFirst2(pszFile, &pDir->hDir, bAttrReq & 0x7F, &pDir->buf,
|
||||
sizeof(FILEFINDBUF), &n, FIL_STANDARD, 0L);
|
||||
if (err || !n) return 1;
|
||||
|
||||
return SetDirent(pDir);
|
||||
}
|
||||
|
||||
int srchnext(DIR *pDir) { /* Search next matching file */
|
||||
int n;
|
||||
int err;
|
||||
|
||||
n = 1; /* Get one file */
|
||||
err = DosFindNext(pDir->hDir, &pDir->buf, sizeof(FILEFINDBUF), &n);
|
||||
if (err || !n) return 1;
|
||||
|
||||
return SetDirent(&buf);
|
||||
}
|
||||
|
||||
int srchdone(DIR *pDir) {
|
||||
int err;
|
||||
|
||||
err = DosFindClose(pDir->hDir);
|
||||
pDir->hDir = -1;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
DIR *opendir(const char *name) { /* Open a directory */
|
||||
DIR *pDir;
|
||||
DEBUG_ENTER(("opendir(\"%s\");\n", name));
|
||||
err = _access(name, 0);
|
||||
/* To do: Get the file attributes, and check that it's a directory */
|
||||
if (err) {
|
||||
DEBUG_LEAVE(("return NULL; // errno=%d - %s\n", errno, strerror(errno)));
|
||||
return NULL;
|
||||
}
|
||||
pDir = malloc(sizeof(DIR));
|
||||
if (pDir) {
|
||||
pDir->hDir = -1;
|
||||
pDir->bAttrReq = _A_HIDDEN | _A_SYSTEM | _A_SUBDIR;
|
||||
pDir->bAttrCmp = 0;
|
||||
strcpy(pDir->sDirent.d_name, name);
|
||||
}
|
||||
DEBUG_LEAVE(("return 0x%p;\n", pDir));
|
||||
return pDir;
|
||||
}
|
||||
|
||||
int closedir(DIR *pDir) { /* Close the directory. Return 0 if successful, -1 if not. */
|
||||
DEBUG_PRINTF(("closedir(0x%p);\n", pDir));
|
||||
if (pDir) {
|
||||
srchdone(pDir);
|
||||
free(pDir);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
_dirent *readdir(DIR *pDir) { /* Read a directory entry. Return pDir, or NULL for EOF or error. */
|
||||
int iErr;
|
||||
DEBUG_ENTER(("readdir(0x%p);\n", pDir));
|
||||
if (pDir->hDir == -1) {
|
||||
iErr = srch1st(pDir->sDirent.d_name, pDir->bAttrReq, pDir->bAttrCmp, pDir);
|
||||
} else {
|
||||
iErr = srchnext(pDir);
|
||||
}
|
||||
if (iErr) {
|
||||
DEBUG_LEAVE(("return NULL; // OS/2 found nothing\n",
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG_LEAVE(("return 0x%p; // OS/2 found: %04X %04X %02X %10lld %s\n",
|
||||
&pDir->sDirent
|
||||
(int)(pDirent->time),
|
||||
(int)(pDirent->date),
|
||||
(int)(pDirent->attribs),
|
||||
pDirent->filesize,
|
||||
pDirent->d_name));
|
||||
|
||||
|
||||
return &pDir->sDirent;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*****************************************************************************\
|
||||
* *
|
||||
* End of OS-specific opendir/readdir/closedir versions *
|
||||
* *
|
||||
\*****************************************************************************/
|
||||
|
||||
/*****************************************************************************\
|
||||
* *
|
||||
* Function: scandir *
|
||||
* *
|
||||
* Description: Select entries in a directory *
|
||||
* *
|
||||
* Arguments: const char *name Directory name *
|
||||
* _dirent ***namelist where to store the result array *
|
||||
* int (*cbSelect)() Selection callback function *
|
||||
* int (*cbCompare)() Comparison function for sorting it *
|
||||
* *
|
||||
* Return value: # of entries in the array, or -1 if error. *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-01-11 JFL Initial implementation *
|
||||
* *
|
||||
\*****************************************************************************/
|
||||
|
||||
#pragma warning(disable:4706) /* Ignore the "assignment within conditional expression" warning */
|
||||
int scandir(const char *pszName,
|
||||
_dirent ***resultList,
|
||||
int (*cbSelect) (const _dirent *),
|
||||
int (__cdecl *cbCompare) (const _dirent **,
|
||||
const _dirent **)) {
|
||||
int n = 0;
|
||||
DIR *pDir;
|
||||
_dirent *pDirent;
|
||||
_dirent *pDirent2;
|
||||
_dirent **pList = NULL;
|
||||
_dirent **pList2;
|
||||
|
||||
DEBUG_ENTER(("scandir(\"%s\", 0x%p, 0x%p, 0x%p);\n", pszName, resultList, cbSelect, cbCompare));
|
||||
|
||||
pDir = opendir(pszName);
|
||||
if (!pDir) {
|
||||
DEBUG_LEAVE(("return -1; // errno=%d\n", errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (pDirent = readdir(pDir)) {
|
||||
if (cbSelect && !cbSelect(pDirent)) continue; /* We don't want this one. Continue search. */
|
||||
/* OK, we've selected this one. So append a copy of this _dirent to the list. */
|
||||
n += 1;
|
||||
pList2 = (_dirent **)realloc(pList, n * sizeof(_dirent *));
|
||||
pDirent2 = malloc(sizeof(_dirent));
|
||||
if (!pList2 || !pDirent2) {
|
||||
if (pDirent2) free(pDirent2);
|
||||
for (n-=1; n>0; ) free(pList[--n]);
|
||||
/* errno = ENOMEM; /* Out of memory. Should already be set by malloc failure */
|
||||
DEBUG_LEAVE(("return -1; // errno=%d\n", errno));
|
||||
return -1;
|
||||
}
|
||||
*pDirent2 = *pDirent;
|
||||
pList = pList2;
|
||||
pList[n-1] = pDirent2;
|
||||
}
|
||||
|
||||
closedir(pDir);
|
||||
|
||||
/* 2016-09-23 JFL I don't understand why this warning still fires, so leaving it enabled for now */
|
||||
#ifdef M_I86TM /* This warning appears only when compiling for the DOS tiny memory model ?!? */
|
||||
/* #pragma warning(disable:4220) /* Ignore the "varargs matches remaining parameters" warning */
|
||||
#endif
|
||||
if (cbCompare) qsort(pList, n, sizeof(_dirent *), cbCompare);
|
||||
#ifdef M_I86TM
|
||||
#pragma warning(default:4220) /* Ignore the "varargs matches remaining parameters" warning */
|
||||
#endif
|
||||
*resultList = pList;
|
||||
DEBUG_LEAVE(("return %d;\n", n));
|
||||
return n;
|
||||
}
|
||||
#pragma warning(default:4706)
|
||||
|
||||
int __cdecl alphasort(const _dirent **ppDE1, const _dirent **ppDE2) {
|
||||
int ret;
|
||||
/* Sort names a-la Windows, that is case insensitive */
|
||||
ret = _strnicmp((*ppDE1)->d_name, (*ppDE2)->d_name, NAME_MAX);
|
||||
if (ret) return ret;
|
||||
/* For the remote chance that we're accessing a Unix share */
|
||||
ret = _strnicmp((*ppDE1)->d_name, (*ppDE2)->d_name, NAME_MAX);
|
||||
if (ret) return ret;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename dirname.c *
|
||||
* *
|
||||
* Description Get the parent directory name of a file pathname *
|
||||
* *
|
||||
* Notes Uses a static buffer in some cases. Not thread safe! *
|
||||
* Posix spec authorizes this, and also authorizes to modify *
|
||||
* the input string, which we do. => Always do an strdup() *
|
||||
* before calling dirname(), and call dirname(copy). *
|
||||
* *
|
||||
* History *
|
||||
* 2016-09-08 JFL Created this file. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#include "msvclibx.h"
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS 1 /* Avoid Visual C++ 2005 security warnings */
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include "msvcLibgen.h"
|
||||
#include "msvcLimits.h"
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
char szLastDriveDirName[4] = "C:.";
|
||||
|
||||
char *dirname(char *pszPathname) {
|
||||
char *pszPath = pszPathname;
|
||||
size_t len;
|
||||
char *pc;
|
||||
char *pc2;
|
||||
|
||||
/* A NULL pathname is assumed to refer to the current directory */
|
||||
if (!pszPathname) return szLastDriveDirName + 2; /* "." */
|
||||
/* Skip the drive if present */
|
||||
len = strlen(pszPathname);
|
||||
if (!len) return szLastDriveDirName + 2; /* "." */
|
||||
if ((len >= 2) && (pszPathname[1] == ':')) {
|
||||
pszPath += 2;
|
||||
len -= 2;
|
||||
if (!len) {
|
||||
szLastDriveDirName[0] = pszPathname[0]; /* Warning: Not thread safe! */
|
||||
return szLastDriveDirName; /* "D:." */
|
||||
}
|
||||
}
|
||||
/* Remove trailing path separators */
|
||||
while ((len > 1) && ((pszPath[len-1] == '\\') || (pszPath[len-1] == '/'))) {
|
||||
pszPath[--len] = '\0';
|
||||
}
|
||||
/* Remove the file name */
|
||||
pc = strrchr(pszPath, '\\');
|
||||
pc2 = strrchr(pszPath, '/');
|
||||
if (pc2 > pc) pc = pc2;
|
||||
if (pc) pc += 1; else pc = pszPath;
|
||||
*pc = '\0';
|
||||
len = pc - pszPath;
|
||||
if (!len) {
|
||||
strcpy(pc, "."); /* Yes, the spec says that the dirname of .. is . */
|
||||
len = 1;
|
||||
}
|
||||
/* Remove trailing path separators */
|
||||
while ((len > 1) && ((pszPath[len-1] == '\\') || (pszPath[len-1] == '/'))) {
|
||||
pszPath[--len] = '\0';
|
||||
}
|
||||
/* Done */
|
||||
return pszPathname;
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename err2errno.c *
|
||||
* *
|
||||
* Description: Convert a WIN32 error to a Unix errno *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-02-17 JFL Created this module. *
|
||||
* 2016-10-05 JFL Fixed compatibility with Visual Studio 2003 and older. *
|
||||
* Removed a few useless special cases, and added EZERO case.*
|
||||
* Make sure the global errno is _not_ changed by this funct.*
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
/* Microsoft C libraries include files */
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
/* MsvcLibX library extensions */
|
||||
#include "msvcDebugm.h"
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
* *
|
||||
| Function: Win32ErrorToErrno |
|
||||
| |
|
||||
| Description: Convert a Win32 system error code to a Posix errno |
|
||||
| |
|
||||
| Parameters: DWORD dwError The Win32 error code |
|
||||
| |
|
||||
| Returns: The corresponding Posix errno |
|
||||
| |
|
||||
| Notes: There's no 1-to-1 correspondance between Windows and |
|
||||
| Posix errors. This routine attempts to convert codes for |
|
||||
| the most likely errors for MsvcLibX. |
|
||||
| Please add those you encounter, that end up in the |
|
||||
| default category, and incorrectly return EIO by default. |
|
||||
| |
|
||||
| Does not change errno. (Contrary to _dosmaperr, etc) |
|
||||
| You must set errno thereafter if desired. |
|
||||
| |
|
||||
| History: |
|
||||
| 2014-02-05 JFL Created this routine |
|
||||
| 2014-03-05 JFL Added the default call to _get_errno_from_oserr(). |
|
||||
| 2015-12-07 JFL Use the new error conversion routine name in the UCRT. |
|
||||
* *
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
#if defined(_UCRT) /* Visual Studio 14 and later */
|
||||
#define _get_errno_from_oserr __acrt_errno_from_os_error /* The name changed in the UCRT */
|
||||
#endif
|
||||
|
||||
#if (_MSC_VER < 1400) /* Anything older than Visual Studio 8 (= VS 2003 and older) */
|
||||
#pragma message("Defining our own _get_errno_from_oserr()")
|
||||
extern void __cdecl _dosmaperr(unsigned long);
|
||||
int _get_errno_from_oserr(unsigned long dwErr) {
|
||||
_dosmaperr(dwErr); /* Sets errno from WIN32 error */
|
||||
return errno;
|
||||
}
|
||||
#else
|
||||
/* Equivalent function in MSVC library. Does not know about symlink errors. */
|
||||
extern int __cdecl _get_errno_from_oserr(unsigned long oserrno);
|
||||
#endif
|
||||
|
||||
int Win32ErrorToErrno() {
|
||||
DWORD dwError = GetLastError();
|
||||
|
||||
DEBUG_CODE({
|
||||
LPVOID lpMsgBuf;
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf, 0, NULL);
|
||||
DEBUG_PRINTF(("// Win32 error %d (0x%X): %s", dwError, dwError, lpMsgBuf ? lpMsgBuf : "Unknown\n"));
|
||||
LocalFree( lpMsgBuf );
|
||||
});
|
||||
|
||||
switch (dwError) {
|
||||
case ERROR_SUCCESS:
|
||||
return 0;
|
||||
case ERROR_PRIVILEGE_NOT_HELD: /* Not running with the SE_CREATE_SYMBOLIC_LINK_NAME privilege */
|
||||
case ERROR_REPARSE_ATTRIBUTE_CONFLICT:
|
||||
return EACCES;
|
||||
case ERROR_INSUFFICIENT_BUFFER:
|
||||
return E2BIG;
|
||||
case ERROR_FILE_EXISTS:
|
||||
case ERROR_ALREADY_EXISTS:
|
||||
return EEXIST;
|
||||
case ERROR_WRITE_PROTECT:
|
||||
return EROFS;
|
||||
case ERROR_HANDLE_DISK_FULL:
|
||||
return ENOSPC;
|
||||
case ERROR_NOT_A_REPARSE_POINT:
|
||||
case ERROR_REPARSE_TAG_MISMATCH:
|
||||
case ERROR_INVALID_FLAGS:
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
return EINVAL;
|
||||
case ERROR_INVALID_REPARSE_DATA:
|
||||
case ERROR_REPARSE_TAG_INVALID:
|
||||
return EBADF; /* Not supposed to happen in Posix OSs, but may happen when experimenting with junction() IOCTLs. */
|
||||
case ERROR_NO_UNICODE_TRANSLATION:
|
||||
return EILSEQ;
|
||||
default: {
|
||||
int errno0, errno1;
|
||||
errno0 = errno; /* Preserve the initial errno */
|
||||
errno1 = _get_errno_from_oserr(dwError); /* Let MSVC library decide. May change errno. */
|
||||
errno = errno0; /* Restore the initial errno */
|
||||
return errno1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* _WIN32 */
|
||||
|
|
@ -1,261 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename filetime.c *
|
||||
* *
|
||||
* Description: MsvcLibX internal routines for managing file times *
|
||||
* *
|
||||
* Notes: *
|
||||
* *
|
||||
* History: *
|
||||
* 2014-02-26 JFL Created this module. *
|
||||
* 2014-03-24 JFL Renamed "statx.h" as the standard <sys/stat.h>. *
|
||||
* 2014-07-03 JFL Filetime2String: Output time with <EFBFBD>s precision if possib. *
|
||||
* 2016-09-13 JFL Fixed a warning. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#define _CRT_SECURE_NO_WARNINGS 1 /* Avoid Visual C++ security warnings */
|
||||
|
||||
#include "msvcTime.h" /* Define time_t */
|
||||
#include "sys/msvcStat.h"
|
||||
|
||||
#ifdef _MSDOS
|
||||
|
||||
/*
|
||||
Convert a DOS date/time to a Unix time_t
|
||||
DOS dates start from January 1, 1980. DOS times have a 2-second resolution.
|
||||
A Unix time_t is the number of 1-second intervals since January 1, 1970.
|
||||
time_ts are expressed in the GMT time zone. DOS times in the current local time.
|
||||
*/
|
||||
time_t Filetime2Timet(uint16_t date, uint16_t time) {
|
||||
unsigned int year, month, day, hour, minute, second;
|
||||
struct tm stm;
|
||||
|
||||
/* Decode fields */
|
||||
year = 1980 + ((date & 0xFE00) >> 9);
|
||||
month = (date & 0x1E0) >> 5;
|
||||
day = date & 0x1F;
|
||||
hour = (time & 0xF800) >> 11;
|
||||
minute = (time & 0x7E0) >> 5;
|
||||
second = 2 * (time & 0x1F);
|
||||
|
||||
stm.tm_year = (int)year - 1900;
|
||||
stm.tm_mon = (int)month - 1;
|
||||
stm.tm_mday = (int)day;
|
||||
stm.tm_hour = (int)hour;
|
||||
stm.tm_min = (int)minute;
|
||||
stm.tm_sec = (int)second;
|
||||
stm.tm_isdst = -1; /* Let mktime decide if DST is in effect or not */
|
||||
|
||||
return mktime(&stm);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Older version of the same, trying to generate the time_t manually.
|
||||
Did not handle DST well */
|
||||
time_t Filetime2Timet(uint16_t date, uint16_t time) {
|
||||
unsigned int year, month, day, hour, minute, second;
|
||||
unsigned int olympiads; /* 4-year periods */
|
||||
unsigned long t = 0;
|
||||
|
||||
/* Decode fields */
|
||||
year = 1980 + ((date & 0xFE00) >> 9);
|
||||
month = (date & 0x1E0) >> 5;
|
||||
day = date & 0x1F;
|
||||
hour = (time & 0xF800) >> 11;
|
||||
minute = (time & 0x7E0) >> 5;
|
||||
second = 2 * (time & 0x1F);
|
||||
|
||||
/* Count days */
|
||||
year -= 1970; /* Start of Unix time_t epoch */
|
||||
olympiads = year / 4;
|
||||
year = year % 4;
|
||||
t = olympiads * (365 + 365 + 366 + 365);
|
||||
switch (year) {
|
||||
case 3: t += 366;
|
||||
case 2: t += 365;
|
||||
case 1: t += 365;
|
||||
}
|
||||
switch (month) {
|
||||
case 12: t += 30;
|
||||
case 11: t += 31;
|
||||
case 10: t += 30;
|
||||
case 9: t += 31;
|
||||
case 8: t += 31;
|
||||
case 7: t += 30;
|
||||
case 6: t += 31;
|
||||
case 5: t += 30;
|
||||
case 4: t += 31;
|
||||
case 3: t += (year == 2) ? 29 : 28;
|
||||
case 2: t += 31;
|
||||
}
|
||||
t += day-1;
|
||||
|
||||
/* Count seconds */
|
||||
t *= 24;
|
||||
t += hour;
|
||||
t *= 60;
|
||||
t += minute;
|
||||
t *= 60;
|
||||
t += second;
|
||||
|
||||
/* Correct for the timezone (As DOS returns local times, but time_t is UTC-based) */
|
||||
t += timezone;
|
||||
|
||||
/* Still need correction for DST */
|
||||
|
||||
return (time_t)t;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Generate a string with the local file time, in the ISO 8601 date/time format */
|
||||
char *Filetime2String(uint16_t date, uint16_t time, char *pBuf, size_t nBufSize) {
|
||||
unsigned int year, month, day, hour, minute, second;
|
||||
|
||||
/* Decode fields */
|
||||
year = 1980 + ((date & 0xFE00) >> 9);
|
||||
month = (date & 0x1E0) >> 5;
|
||||
day = date & 0x1F;
|
||||
hour = (time & 0xF800) >> 11;
|
||||
minute = (time & 0x7E0) >> 5;
|
||||
second = 2 * (time & 0x1F);
|
||||
|
||||
if (nBufSize >= 20) {
|
||||
sprintf(pBuf, "%04d-%02d-%02d %02d:%02d:%02d", year, month, day, hour, minute, second);
|
||||
} else {
|
||||
return "Buffer too small";
|
||||
}
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
#endif /* defined(_MSDOS) */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/*---------------------------------------------------------------------------*\
|
||||
* *
|
||||
| Function: LocalFileTime |
|
||||
| |
|
||||
| Description: Convert a file GMT time to the local struct tm to display |
|
||||
| |
|
||||
| Parameters: const time_t *t The file GMT time_t |
|
||||
| |
|
||||
| Returns: struct tm * |
|
||||
| |
|
||||
| Notes: This routine is a replacement for Posix' localtime(), |
|
||||
| using Windows' specific algorithm for generating local |
|
||||
| file times. |
|
||||
| |
|
||||
| Windows displays file times based on the current |
|
||||
| difference between the local time and GMT. |
|
||||
| Linux displays file times as the local time when the |
|
||||
| the file was created. |
|
||||
| The two times shown may be different if DST was different |
|
||||
| then and now. (Ex: Displaying in winter the date/time of |
|
||||
| a file created the previous summer.) |
|
||||
| The advantage of Windows' method is that apparent |
|
||||
| relative times will always be correct, even for files |
|
||||
| created around the winter/summer time transitions. |
|
||||
| The advantage of Linux method is that the time displayed |
|
||||
| for a file never changes. The drawback is that files |
|
||||
| created 1 hour apart around the Winter/summer time |
|
||||
| transition may be shown with the exact same time. |
|
||||
| |
|
||||
| History: |
|
||||
| 2014-02-26 JFL Created this routine |
|
||||
* *
|
||||
\*---------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
Convert a Windows FILETIME to a Unix time_t.
|
||||
A FILETIME is the number of 100-nanosecond intervals since January 1, 1601.
|
||||
A time_t is the number of 1-second intervals since January 1, 1970.
|
||||
Both Windows and Linux file times are expressed in the GMT time zone.
|
||||
*/
|
||||
time_t Filetime2Timet(const FILETIME *pFT) {
|
||||
ULARGE_INTEGER ull;
|
||||
ull.LowPart = pFT->dwLowDateTime;
|
||||
ull.HighPart = pFT->dwHighDateTime;
|
||||
return ull.QuadPart / 10000000ULL - 11644473600ULL;
|
||||
}
|
||||
|
||||
/* Convert a Unix time_t to a Windows FILETIME */
|
||||
void Timet2Filetime(time_t t, FILETIME *pFT) {
|
||||
ULARGE_INTEGER ull;
|
||||
ull.QuadPart = (t * 10000000ULL) + 116444736000000000ULL;
|
||||
pFT->dwLowDateTime = ull.LowPart;
|
||||
pFT->dwHighDateTime = ull.HighPart;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
Convert a Windows FILETIME to a Unix struct timespec.
|
||||
A FILETIME is the number of 100-nanosecond intervals since January 1, 1601.
|
||||
A struct timespec contains a time_t and a number of nanoseconds.
|
||||
Both Windows and Linux file times are expressed in the GMT time zone.
|
||||
*/
|
||||
void Filetime2Timespec(const FILETIME *pFT, struct timespec *pTS) {
|
||||
ULARGE_INTEGER ull;
|
||||
ull.LowPart = pFT->dwLowDateTime;
|
||||
ull.HighPart = pFT->dwHighDateTime;
|
||||
pTS->tv_sec = (time_t)(ull.QuadPart / 10000000ULL - 11644473600ULL);
|
||||
pTS->tv_nsec = (int)(ull.QuadPart % 10000000ULL) * 100;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert a Unix time_t to a Windows FILETIME */
|
||||
void Timespec2Filetime(const struct timespec *pTS, FILETIME *pFT) {
|
||||
ULARGE_INTEGER ull;
|
||||
ull.QuadPart = (pTS->tv_sec * 10000000ULL) + 116444736000000000ULL + (pTS->tv_nsec / 100);
|
||||
pFT->dwLowDateTime = ull.LowPart;
|
||||
pFT->dwHighDateTime = ull.HighPart;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Convert a file GMT time to a struct tm with the local time to display */
|
||||
struct tm *LocalFileTime(const time_t *pt) {
|
||||
FILETIME ft, lft;
|
||||
time_t lt;
|
||||
|
||||
Timet2Filetime(*pt, &ft);
|
||||
FileTimeToLocalFileTime(&ft, &lft);
|
||||
lt = Filetime2Timet(&lft);
|
||||
return gmtime(<);
|
||||
}
|
||||
|
||||
/* Generate a string with the local file time, in the ISO 8601 date/time format */
|
||||
/* 2014-07-03 Output time with <20>s precision if possible */
|
||||
char *Filetime2String(const FILETIME *pFT, char *pBuf, size_t nBufSize) {
|
||||
FILETIME lft;
|
||||
SYSTEMTIME sTime;
|
||||
|
||||
FileTimeToLocalFileTime(pFT, &lft);
|
||||
FileTimeToSystemTime(&lft, &sTime);
|
||||
if (nBufSize >= 20) {
|
||||
wsprintf(pBuf, "%04d-%02d-%02d %02d:%02d:%02d", sTime.wYear, sTime.wMonth, sTime.wDay,
|
||||
sTime.wHour, sTime.wMinute, sTime.wSecond);
|
||||
if (nBufSize >= 27) {
|
||||
ULARGE_INTEGER uli;
|
||||
int iFraction; /* Fraction of a second */
|
||||
uli.LowPart = lft.dwLowDateTime;
|
||||
uli.HighPart = lft.dwHighDateTime;
|
||||
iFraction = (int)(uli.QuadPart % 10000000); /* FILETIME has 100ns resolution */
|
||||
iFraction /= 10; /* Convert 100ns resolution to 1<>s resolution */
|
||||
wsprintf(pBuf+19, ".%06d", iFraction);
|
||||
} else if (nBufSize >= 24) {
|
||||
wsprintf(pBuf+19, ".%03d", sTime.wMilliseconds);
|
||||
}
|
||||
} else {
|
||||
return NULL; /* Buffer too small */
|
||||
}
|
||||
return pBuf;
|
||||
}
|
||||
|
||||
#endif /* defined(_WIN32) */
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
/*****************************************************************************\
|
||||
* *
|
||||
* Filename: fnmatch.c *
|
||||
* *
|
||||
* Description: DOS/WIN32 port of standard C library's fnmatch() *
|
||||
* *
|
||||
* Notes: TO DO: Manage FNM_PATHNAME, FNM_PERIOD, FNM_LEADING_DIR. *
|
||||
* *
|
||||
* History: *
|
||||
* 2012-01-17 JFL Created this file. *
|
||||
* 2013-03-10 JFL In DOS/Windows, the pattern "*.*" actually means "*". *
|
||||
* 2014-02-13 JFL Removed warnings. *
|
||||
* 2014-02-14 JFL In DOS/Windows, the pattern "*." means no extension. *
|
||||
* 2014-02-17 JFL Wildcards match the empty string. *
|
||||
* 2014-02-20 JFL Fixed "*." pattern matching. *
|
||||
* 2014-02-28 JFL Added support for UTF-8 pathnames. *
|
||||
* 2014-03-05 JFL In debug mode, hide recursive calls. *
|
||||
* *
|
||||
* Copyright 2016 Hewlett Packard Enterprise Development LP *
|
||||
* Licensed under the Apache 2.0 license - www.apache.org/licenses/LICENSE-2.0 *
|
||||
\*****************************************************************************/
|
||||
|
||||
#define _UTF8_SOURCE /* Generate the UTF-8 version of routines */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "msvcFnmatch.h" /* Include our associated .h, in the same dir as this .c. Do not use <>. */
|
||||
#include "msvcDebugm.h"
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#pragma warning(disable:4706) /* Ignore the "assignment within conditional expression" warning */
|
||||
int fnmatch(const char *pszPattern, const char *pszName, int iFlags) {
|
||||
char cp, cn;
|
||||
size_t l;
|
||||
const char *pc;
|
||||
int iErr;
|
||||
DEBUG_CODE(
|
||||
int iHideRecursions = FALSE;
|
||||
)
|
||||
|
||||
DEBUG_ENTER(("fnmatch(\"%s\", \"%s\", 0x%x);\n", pszPattern, pszName, iFlags));
|
||||
|
||||
DEBUG_CODE(if(DEBUG_IS_ON() && !XDEBUG_IS_ON()) iHideRecursions = TRUE;)
|
||||
|
||||
/* Special case in DOS/Windows: "*.*" will actually match any name, even without a dot */
|
||||
if (!strcmp(pszPattern, "*.*")) pszPattern = "*";
|
||||
|
||||
/* Special case in DOS/Windows: "anything." means anything without extension */
|
||||
l = strlen(pszPattern);
|
||||
if (l && (pszPattern[l-1] == '.')) {
|
||||
int i;
|
||||
int lName = (int)strlen(pszName);
|
||||
/* First eliminate the case of forbidden extensions <==> A '.' anywhere before the last character */
|
||||
for (i=0; i<(lName-1); i++) { /* Search for a '.' in the name */
|
||||
if (pszName[i] == '.') RETURN_CONST_COMMENT(FNM_NOMATCH, ("Forbidden extension found\n"));
|
||||
}
|
||||
/* If the name doesn't end with a dot, Remove the pattern's trailing '.' */
|
||||
if (lName && (pszName[lName-1] != '.')) {
|
||||
char *pszPattern2;
|
||||
pszPattern2 = _strdup(pszPattern);
|
||||
pszPattern2[--l] = '\0';
|
||||
/* Recursively do the pattern matching with the new pattern */
|
||||
DEBUG_CODE(if (iHideRecursions) iDebug -= 1;)
|
||||
iErr = fnmatch(pszPattern2, pszName, iFlags);
|
||||
DEBUG_CODE(if (iHideRecursions) iDebug += 1;)
|
||||
free(pszPattern2);
|
||||
RETURN_INT(iErr);
|
||||
}
|
||||
}
|
||||
|
||||
for ( ; (cp = *pszPattern) && (cn = *pszName); pszPattern++, pszName++) {
|
||||
XDEBUG_PRINTF(("// cp='%c' cn='%c'\n", cp, cn));
|
||||
switch (cp) {
|
||||
case '?':
|
||||
if (cn == '.') RETURN_CONST_COMMENT(FNM_NOMATCH, ("? does not match a .\n"));
|
||||
break; /* Anything else matches. Continue analysing the pattern. */
|
||||
case '*':
|
||||
cp = *(++pszPattern);
|
||||
if (!cp) RETURN_CONST_COMMENT(FNM_MATCH, ("'*' matches whatever remains in the string\n"));
|
||||
for ( ; cn = *pszName; pszName++) {
|
||||
DEBUG_CODE(if (iHideRecursions) iDebug -= 1;)
|
||||
iErr = fnmatch(pszPattern, pszName, iFlags);
|
||||
DEBUG_CODE(if (iHideRecursions) iDebug += 1;)
|
||||
if (iErr == FNM_MATCH) RETURN_CONST(FNM_MATCH);
|
||||
}
|
||||
RETURN_CONST_COMMENT(FNM_NOMATCH, ("No tail string matches the remainder of the pattern\n"));
|
||||
default:
|
||||
if (iFlags & FNM_CASEFOLD) {
|
||||
cp = (char)toupper(cp);
|
||||
cn = (char)toupper(cn);
|
||||
}
|
||||
if (cp != cn) RETURN_CONST_COMMENT(FNM_NOMATCH, ("Character mismatch\n"));
|
||||
break; /* The character matches. Continue analysing the pattern. */
|
||||
}
|
||||
}
|
||||
/* '*' and '?' match the empty string */
|
||||
if (*pszPattern && !*pszName) {
|
||||
int bOnlyWildCards = TRUE;
|
||||
for (pc=pszPattern; cp=*pc; pc++) {
|
||||
if ((cp != '*') && (cp != '?')) {
|
||||
bOnlyWildCards = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bOnlyWildCards) {
|
||||
RETURN_CONST_COMMENT(FNM_MATCH, ("WildCards match the empty string\n"));
|
||||
}
|
||||
}
|
||||
|
||||
/* Special case in DOS/Windows: trailing dot allowed in pattern */
|
||||
if ((*pszPattern == '.') && (!*(pszPattern+1)) && (!*pszName)) RETURN_CONST_COMMENT(FNM_MATCH, ("trailing dot matches empty string\n"));
|
||||
|
||||
if (*pszPattern || *pszName) RETURN_CONST_COMMENT(FNM_NOMATCH, ("Something remains that did not match\n"));
|
||||
|
||||
RETURN_CONST_COMMENT(FNM_MATCH, ("Complete match\n"));
|
||||
}
|
||||
#pragma warning(default:4706)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue