Merge branch '3.0' into feature/TD-14761

This commit is contained in:
WANG MINGMING 2022-06-14 11:34:18 +08:00 committed by GitHub
commit 64dca74a54
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1600 changed files with 8784 additions and 251542 deletions

21
2.0/alert/.gitignore vendored
View File

@ -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

View File

@ -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
* Examplecurl -d '@rule.json' http://localhost:8100/api/update-rule
* Delete
* API address: http://\<server\>:\<port\>/api/delete-rule?name=\<rule name\>
* MethodDELETE
* Examplecurl -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
* Examplecurl -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
* Examplecurl http://localhost:8100/api/list-rule

View File

@ -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
* MethodPOST
* Body规则定义
* 示例curl -d '@rule.json' http://localhost:8100/api/update-rule
* 删除
* API地址http://\<server\>:\<port\>/api/delete-rule?name=\<rule name\>
* MethodDELETE
* 示例curl -X DELETE http://localhost:8100/api/delete-rule?name=rule1
* 挂起或恢复
* API地址http://\<server\>:\<port\>/api/enable-rule?name=\<rule name\>&enable=[true | false]
* MethodPOST
* 示例curl -X POST http://localhost:8100/api/enable-rule?name=rule1&enable=true
* 获取列表
* API地址http://\<server\>:\<port\>/api/list-rule
* MethodGET
* 示例curl http://localhost:8100/api/list-rule

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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)
}
}
}

View File

@ -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},
}

View File

@ -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)
}
}
}

View File

@ -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"`
}

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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
}
}

View File

@ -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

View File

@ -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()
}

View File

@ -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"
}
}

View File

@ -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
)

View File

@ -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()
}

View File

@ -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
}

View File

@ -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

View File

@ -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

View File

@ -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}}"
}
}

View File

@ -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

View File

@ -1,5 +0,0 @@
sql connect
sleep 100
print ====== insert another records table 0
sql insert into test.car0 values(now , 100)

View File

@ -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

View File

@ -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}'`

View File

@ -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
}

View File

@ -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()
}

View File

@ -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})

View File

@ -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 ()

View File

@ -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()

View File

@ -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 ()

View File

@ -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 ()

View File

@ -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")

View File

@ -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()

View File

@ -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

View File

@ -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.

View File

@ -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**

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 ()

View File

@ -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) */

View File

@ -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) */

View File

@ -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) */

View File

@ -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

View File

@ -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)

View File

@ -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) */

View File

@ -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) */

View File

@ -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_ */

View File

@ -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) */

View File

@ -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_ */

View File

@ -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) */

View File

@ -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) */

View File

@ -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 */

View File

@ -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) */

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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_ */

View File

@ -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) */

View File

@ -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) */

View File

@ -1,2 +0,0 @@
/* CoreUtils global system configuration definitions */

View File

@ -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) */

View File

@ -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 */

View File

@ -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 */

View File

@ -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) */

View File

@ -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);

View File

@ -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_ */

View File

@ -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) */

View File

@ -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) */

View File

@ -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) */

View File

@ -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 */

View File

@ -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) */

View File

@ -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) */

View File

@ -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) */

View File

@ -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) */

View File

@ -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) */

View File

@ -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) */

View File

@ -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;
}

View File

@ -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) */

View File

@ -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) */

View File

@ -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) */

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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 */

View File

@ -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(&lt);
}
/* 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) */

View File

@ -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