关于Snapman

Help >
关于Snapman

一、Snapman软件主页

    主页：http://www.snapman.xyz，包括最新版本的安装包，各种介绍和使用教程

二、软件简介

    feiren工作室主要研究人类意识原理、智能提高以及减少团队合作中资源、意识损耗的方法和工具，Snapman是这个研究中的第一款工具。Snapman是Windows下一款易用的电子表格软件，采用C/S架构，数据存储在服务端，专门用来多人协同工作的表格工具。在这里，你可以轻松制作各类常用表格，随时共享工作数据和进度，让团队协作变的更加简单高效。

下面是功能说明：

1、软件截图

2、信息收集，该软件适合于收集各种数据信息

3、模板定制，类似于Excel的电子表格可以制作各种表格模板

4、工作管理，适合于团队中各种各样的工作规范管理

5、协作办公，特别适合于多人团队共同完成同一个事情提高工作效率

6、文件共享，可以在表格里实现文件共享功能

7、图片分享，可以在表格里实现图片分享功能

8、数据运算，可以使用Exprtk脚本对数据进行运算

9、二次开发，可以使用C语言脚本进行业务开发

10、分布式运行，适合于各种业务的分布式运行控制功能

11、开放式的数据存储结构，开放式软件接口，易于与其他系统集成

Snapman系统的特点是：

1、软件小巧轻快，启动速度超快，基本不占用多大的资源，也不依赖其他软件系统；

2、所见即所得，编辑的内容可当信息存储、可以当规则使用、也可以当自动化控制逻辑；

3、数据类型简单，整形、浮点、文本、图片、文件等，没有数据库那么繁琐的类型设定，也没有很繁琐的长度设定；

4、系统集合了Exprtk脚本，可以高效对数据进行运算；

5、系统集合了TCC编译器，可以运行C语言脚本，除去固定的1秒多钟编译时间，脚本运行速度比java和C#快，比微软VC++编译出来代码的执行速度慢；

6、一个地方开发整个系统运行，或者业务分模块大家协作完成，不需要SVN；

Copyright ? 2017. All rights reserved.


V1.3更新记录

Help >
V1.3更新记录

2017-4-3：发布V1.0.0.0版本

2017-5-8：修改行、列、全选加锁后单元格还是可以编辑的bug

2017-5-9：添加内容筛选过滤功能

2017-5-20：添加排序功能

2017-5-25：添加TCC脚本和Exprtk运算脚本功能

2017-5-31：内部版本V1.1

2017-6-9：添加按钮功能

2017-6-10：添加下拉框功能

2017-6-15：添加分布式运行能运行TCC脚本和Exprtk脚本功能

2017-6-17：添加按钮、下拉框、勾选框的脚本事件

2017-6-18：添加按钮、下拉框、勾选框、进度条数据可编辑功能

2017-6-25：添加表格初始化、关闭脚本事件

2017-6-27：添加Exprtk、TCC脚本文法分析并代码变色功能

2017-6-29：添加Exprtk、TCC脚本关键字、函数、结构体提示功能

2017-6-30：内部版本V1.2

2017-7-4：添加文本内容也可以弹框编辑功能

2017-7-6：添加选择脚本内容可以多行添加或减少tab键功能

2017-7-8：添加单元格内容可以隐藏或显示功能功能

2017-7-11：添加TCC脚本控制函数：获取单元格的矩形位置、设置表格滚动条位置、保证指定单元格是可视的、获取单元格隐藏状态、设置单元格是否隐藏

2017-7-15：发布V1.3版本

2017-7-20：添加Exprtk脚本的字符串转换数字函数、数字转换字符串函数、字符串小写转大写函数、字符串大写转小写函数、获取单元格字符串函数、设置单元格字符串函数、保存当前脚本所在电子表格函数、获取当前计算机的毫秒函数


软件安装

Help >
软件安装

一、下载合适的安装版本

    网址：http://www.snapman.xyz，建议下载最新64位的版本：snapman_setup64_enterprise_v1.3.exe，64位版本可以拥有更快的执行速度和更高的内存供脚本执行时使用；

二、运行安装程序

选择安装目录 ，点击下一步：

选择是否创建开始菜单，然后点击下一步：

选择是否创建桌面快捷方式，然后点击下一步：

点击Install安装程序：

等待安装完，点击Finish完成安装：

三、企业版服务端软件注册

1、如果是企业版，启动SnapmanServer.exe服务端程序，在服务端黑框里会提示软件未注册，程序不能使用但会在安装目录生成一个License.key文件

2、将License.key发给Snapman销售经理，如果已经购买销售经理会给大家生成一个License.lic发回去

3、请将License.lic文件放到Snapman安装目录，重启SnapmanServer.exe服务端程序程序就可以正常使用了


Snapman服务端

Help >
Snapman服务端

一、Snapman服务端

    Snapman服务端在安装Snapman软件一起自带，是一个小巧的控制台程序SnapmanServer.exe；它分为2个版本：个人版和企业版；个人版为免费软件仅允许个人交流学习使用，服务端最多支持3个用户连接使用；企业版为授权收费软件。

二、服务器启动

要使系统工作首先需要启动服务，服务器程序是SnapmanServer.exe，在windows开始菜单下找到Snapman文件夹，在文件夹下面可以找到SnapmanServer.exe启动程序，点击程序可以启动服务，正常启动的服务如下图：

三、服务端说明

SnapmanServer.exe作为表格服务器为管理用户登录、退出，组合、协调大家的编辑动作，保存数据文件、附件文件，控制自动化分发，控制脚本运行等提供服务 ；它包括：服务IP端口配置、用户管理配置、服务系统配置三方面。


1、服务IP端口配置

Help > Snapman服务端 >
1、服务IP端口配置

1、服务IP端口配置

     在Snapman软件安装目录下找到文件ServerConfig.json，如下图：

用记事本打开ServerConfig.json文件，修改监听的IP地址和端口：

如果IP地址为：""，则默认监听机器所有IP地址；配置完成后保存，重启SnapmanServer服务；则客户端可以填写IP和端口进行登录了，如下图：


2、用户管理配置

Help > Snapman服务端 >
2、用户管理配置

2、用户管理配置（必须）

     添加删除用户只能在服务端手工配置，在Snapman软件安装目录下找到UserConfig.json文件：

用记事本打开UserConfig.json文件，添加或删除用户，如下图：

修改后直接保存文件，不需要重启服务，修改就已经生效。


3、服务系统配置

Help > Snapman服务端 >
3、服务系统配置

3、服务系统配置

     A、工作目录配置

用记事本打开软件安装目录下的ServerConfig.json文件，修改工作目录，包括附件存放目录和文件存放目录：

注：a、附件存放目录为空则默认为安装目录的AttachmentRoot文件夹下
b、文件存放目录为空则默认为安装目录的Root文件夹下

B、是否允许客户端命令行启用配置（非必须）

如下设置为true时，则允许客户端使用命令行执行，否则不允许

特别说明，上面所有配置需重启服务才生效，配置文件遵循JSON文件格式规范，请严格按照规范格式配置。JSON格式说明请参考： http://www.json.org/


Snapman客户端

Help >
Snapman客户端

一、Snapman客户端

    Snapman客户端是Snapman.exe，在windows开始菜单下找到Snapman文件夹，在文件夹下面可以找到Snapman.exe启动程序，点击程序可以启动：

二、Snapman客户端说明

Snapman.exe虽然代码量很大，但是由于没有怎么使用其他代码和库，所以所有代码都是有效代码编译出来的程序非常小才几百K，启动非常快速也不占用其他资源。并且具有自动记录IP、端口、账号、密码，下次自动登录功能，大大减少我们没意义的重复工作。


1、界面介绍

Help > Snapman客户端 >
1、界面介绍

1、界面介绍

    Snapman客户端从上到下从左到右包括6部分：用户登录栏、工程树工具条、工程树、电子表格工具条、电子表格标签栏、电子表格工作区；如下图：


2、服务登录

Help > Snapman客户端 >
2、服务登录

2、服务登录

    登录：第一次启动Snapman客户端，会自动弹出登录对话框让用户输入服务器的IP、端口、用户名称、密码登录服务器。

切换服务器或用户：点击用户登录栏的登陆按钮切换服务器或用户。

退出登录：点击用户登录栏的退出按钮可以退出用户登录。

自动登录：每一次成功登录系统会自动记录登录信息，下一次启动程序会实现自动登录。


3、文件管理

Help > Snapman客户端 >
3、文件管理

3、文件管理

    工程树列表了服务器中所有表格文件和文件夹，所有文件、文件夹都是系统中所有用户共享的，所有工程树修改动作都会即时同步到系统所有登录的用户界面，工程树包括下面操作：

1、新建文件（快捷键ctrl + g）

选择需要创建文件的节点，点击新建文件或右键菜单的新建文件，可以新建一个文件，新建的文件会按照名称次序排序，创建的文件会即时同步到服务器和登录的所有人中，所有人都可以同时看到新文件。

2、新建文件夹（快捷键ctrl + f）

选择需要创建文件的节点，点击新建文件夹或右键菜单的新建文件夹，可以新建一个文件夹，新建的文件夹会按照名称次序排序（先文件夹再文件），创建的文件夹会即时同步到服务器和登录的所有人中，所有人都可以同时看到新文件夹。

3、复制（快捷键ctrl + c）

选择需要复制的文件或文件夹节点（可以多选按住shift或ctrl建，同时鼠标点击选择文件），点击复制文件按钮或右键菜单复制，将文件或文件夹记录为复制的状态。

4、剪切（快捷键ctrl + x）

选择需要剪切的文件或文件夹节点（可以多选按住shift或ctrl建，同时鼠标点击选择文件），点击剪切文件按钮或右键菜单剪切，将文件或文件夹记录为剪切的状态。

5、粘贴（快捷键ctrl + v）

选择需要粘贴的节点，点击粘贴按钮或右键菜单粘贴，如果文件标记为复制状态则复制一份到指定目录，如果为剪切状态则先关闭所有用户打开的被剪切的文档，然后将文件或文件夹移动到指定节点。

6、重命名（快捷键F2）

选择需要重命名的文件或文件夹节点，点击重命名按钮或右键菜单重命名，将名称变为可编辑状态，输入新名称进行重命名。

7、删除（快捷键Delete）

选择需要重命名的文件或文件夹节点（可以多选按住shift或ctrl建，同时鼠标点击选择文件），点击删除按钮或右键菜单删除，弹出提示确认是否真的删除，确认后将删除文件或文件夹。

8、刷新（快捷键F5）

点击刷新按钮，可以将工程树目录刷新为服务器最新状态。

9、打开文件（快捷键回车）

在工程树选择文件（可以多选按住shift或ctrl建，同时鼠标点击选择文件），鼠标双击、也可以选择文件后按回车，打开选择的所有文件

10、文件权限

在工程树选择文件或文件夹，单击鼠标右键弹出右键菜单中选择权限，可以设置文件或文件夹权限

如下弹出的对话框设置用户权限，只有文件创建者可以设置权限，设置权限后文件或文件夹只有设置的人可见，多个人使用分号“；”分割：如果设置为空则默认内容对所有人可见


4、表格编辑

Help > Snapman客户端 >
4、表格编辑

4、表格编辑

    一、工具条按钮说明

    1、工具条往前翻页，由于电子表格工具条按钮太多，需要分成多页显示，所以包括往前翻页按钮

    2、工具条往后翻页，由于电子表格工具条按钮太多，需要分成多页显示，所以包括往后翻页按钮

    3、设置字体名称

    4、设置字体大小

    5、设置字体粗体（快捷键ctrl + b）

    6、设置字体斜体（快捷键ctrl + i）

    7、设置字体下划线（快捷键ctrl + u）

    8、设置字体删除线（快捷键ctrl + d）

    9、设置单元格边框

    边框宽度设置：

    10、设置单元格边框颜色，只有下次设置边框才会生效

    11、设置字体颜色

    12、设置填充颜色

    13、设置内容对齐方式

    14、合并表格\取消合并表格

    15、跨行合并表格\取消合并表格

    16、将单元设置为按钮\取消按钮

按钮单元格的选择和普通单元格不同，单击鼠标左键如果移动距离小于5像素那么为按钮点击事件，如果大于5像素则转变为选择单元格

17、将单元格设置为下拉框\取消下拉框

    18、设置单元格为勾选框\取消勾选框

    选择勾选框的单元格，按住ctrl键同时点击鼠标左键可以将选择的勾选框状态改变；直接输入0或1；

    19、设置进度条

    选择进度条的单元格，按住ctrl键同时点击鼠标左键可以改变进度条的进度，或者按住ctrl键同时点击鼠标左键然后拖动可以连续改变进度条进度；直接输入0到100的数；

    20、设置单元格为TCC脚本框\取消TCC脚本框

    21、设置单元格为打分控件\取消打分控件

22、分布式任务运行模板

    分布式任务运行模板主要是用来让不同用户、不同机器同时或串行执行不同的任务，并监控任务运行进度、显示任务运行时消息，最终获取执行的结果文件和日志文件

    23、设置单元格锁定\解锁

    设置单元格为可以或不可以编辑

    24、格式刷

    25、自动换行

26、隐藏\显示单元格内容

    27、将内容按照升序排序

    28、将内容按照降序排序

    29、内容过滤

    30、软件版本说明

    二、表格菜单说明

    1、剪切（快捷键ctrl + x）

    2、复制（快捷键ctrl + c）

    3、粘贴（快捷键ctrl + v）

    4、插入行/列

    5、插入2行/列

    6、恢复宽高

    7、删除

8、编辑，包括：全选按钮、按钮、图片、勾选框、下拉框、文本框、Exprtk脚本、TCC脚本的编辑

    三、表格隐藏功能说明

    1、保存表格文件（快捷键ctrl + s）

    2、改变行高

    3、改变列宽

    4、粘贴图片（快捷键ctrl + v）

    在windows的explore选择图片后复制、或者在其他画图软件复制图片，然后在软件表格中按ctrl+v粘贴，可以将图片粘贴到软件中，效果如下：

    注：软件将图片按照选择的列数排，粘贴满一行后继续往下一行粘贴

    5、粘贴文件（快捷键ctrl + v）

    在windows的explore选择文件后复制，然后在软件表格中按ctrl+v粘贴，可以将文件粘贴到软件中，效果如下：

    注：软件将文件按照选择的列数排，粘贴满继续往下一行粘贴

    6、查找（快捷键ctrl + f）

    7、替换（快捷键ctrl + h）

    8、全选（快捷键ctrl + a）

    9、上下左右（快捷键上下左右）

    10、上下翻页（快捷键pg up和pg dn）

    11、定位最开始和最后（快捷键home和end）

    12、撤销（快捷键ctrl + z）

    13、重做（快捷键ctrl + y）

    14、屏幕截图（快捷键ctrl + p）

    15、隐藏软件屏幕截图（快捷键ctrl + o）

    16、内容每一行前面添加tab（快捷键tab）

    17、减少内容每一行前面的tab（快捷键shift + tab）

    18、双击表格右边尽头的空白区域可以添加列

    19、双击表格下面尽头的空白区域可以添加行

    20、如果在文本编辑时候第一个输入等号：'='，就变成了编辑Exprtk脚本

21、运行表格中的Exprtk脚本和TCC脚本（快捷键F5）

22、删除Exprtk脚本和TCC脚本运行时的打印，显示脚本内容（快捷键F4）

23、在工程树上进行复制可以得到电子表格或文件夹的相对路径，只需要在表格或文本框直接粘贴即可（快捷键ctrl + c）

22、在电子表格可以复制选择的单元格位置，用来给TCC脚本函数传递单元格位置信息（快捷键ctrl + l）

23、设置电子表格TCC代码的编辑权限和打开关闭事件代码，首先点击单元格全选按钮，在右键菜单选择编辑，弹出权限事件脚本设置对话框

不包括四部分：1、设置TCC代码编辑权限（用分号分割";"），不设置默认为所有人可编辑；2、选择事件编辑脚本，包括：初始化和关闭2个事件；3、电子表格编辑内容是否可以保存，默认为可以保存；4、第四部分为事件的TCC脚本编写，写完保存后，在电子表格的打开或者关闭时候会执行脚本


5、组件介绍

Help > Snapman客户端 >
5、组件介绍

5、组件介绍

    Snapman电子表格的单元格是由各种组件组成，包括下面组件：文本框（默认都是它），图标图片，文件，按钮，状态按钮，下拉框，勾选框，进度条，打分控件，Exprtk脚本，TCC脚本；每一种组件代表一种不同的数据存储、操作方法和呈现方式。


文本框

Help > Snapman客户端 > 5、组件介绍 >
文本框

文本框介绍

    Snapman单元格默认都是文本类型数据；文本框数据有三种保存类型：字符串、整形、双精度浮点类型；

一、字符串类型数据赋值方法：

1、 在Snapman界面上文本框编辑的都是以字符串类型保存，包括：在电子表格直接输入的编辑、右键菜单编辑弹出文本编辑对话框2种方式

2、Exprtk脚本的赋值方法

A、每个单元格被抽象为一个列字母加行号加下划线的变量，直接给它赋值就可以设置字符串数据，

如：A2_ := '世界你好。'; //意思是给第1行第2列的单元格赋值为'世界你好。'的字符串

也可以用这个变量将值取出来，如：A3_ := A2_; //意思是给第1行第2列的单元格的值赋给 第1行第3列的单元格

B、使用Exprtk的内置函数set_赋值，使用get_函数获取值，如：

set_( 1, 2, '你好世界' ); //意思是给第1行第2列的单元格赋值为你好世界

var d :=get_ ( 1, 2); //意思是获取第1行第2列的单元格字符串赋给d变量

3、TCC脚本的赋值方法，有2个函数可以获取、设置单元格的字符串值：

wchar_t * SnapmanCellGetText( void * g,int row,int col )；

int SnapmanCellSetText( void * g,int row,int col,wchar_t * data )；

二、整形类型数据赋值方法：

只有TCC脚本的赋值方法，包括下面2个函数可以获取、设置单元格的整形数值：

int SnapmanCellGetInt( void *g,int row,int col)；

int SnapmanCellSetInt( void *g,int row,int col,int data )；

三、双精度浮点类型数据赋值方法：

1、Exprtk脚本的单元格赋值方法

A、每个单元格被抽象为一个列字母加行号的变量，直接给它赋值就可以设置浮点型数据，如：

A2 := 15.67; //意思是给第1行第2列的单元格赋值为15.67

B3 := A2; //意思是给第2行第3列的单元格赋值为第1行第2列的单元格的值

B、使用Exprtk的内置函数set赋值，使用get函数获取值，如：

set( 1, 2, 15.67 ); //意思是给第1行第2列的单元格赋值为15.67

var d :=get ( 1, 2); //意思是获取第1行第2列的单元格值赋给d变量

2、TCC脚本的单元格赋值方法，有2个函数可以获取、设置单元格的双精度浮点类型值：

double SnapmanCellGetDouble( void * g,int row,int col )；

int SnapmanCellSetDouble( void * g,int row,int col,double data )；

特别说明：

1、单元格文本类型数据虽然有3种存储类型，但是在获取使用的时候会自然进行转化（只是需要消耗一点性能），比如：设置字符串为'156.34'，获取整形时是156，获取双精度浮点类型是：156.34；如果赋值的字符串不是数字，获取出来的整形和浮点型都是0。

2、只要是存储在文本节点的数据都可以用上面方法进行赋值和获取，如：图标图片文件的路径、按钮的标题、状态按钮的状态、下拉框选择的内容、勾选框的打勾状态、进度条的进度、打分控件的分数、Exprtk和TCC打印的内容。


图标图片

Help > Snapman客户端 > 5、组件介绍 >
图标图片

图标图片介绍

    一、Snapman单元格也可以显示图标图片，其设置方法为：

1、Snapman自带的截图功能（快捷键ctrl + o, ctrl + p），截完的图片自然粘贴到单元格上

2、网页或图片编辑软件复制的图片，在电子表格里粘贴

3、在windows的explore选择图片文件后复制，然后粘贴到电子表格里（可以实现多张图片的一次粘贴）

    注：如果是多张图片Snapman将图片按照选择的列数排，粘贴满一行后继续往下一行粘贴

4、TCC脚本的赋值方法：

int SnapmanCellSetFile( void * g,int row,int col,wchar_t * path )； //path为本地文件绝对路径，当文件为图标图片时单元格设置为图标图片类型

注：当图片为16X16或者32X32的图标时，系统自动将图片类型变为图标类型

二、Snapman图标图片单元格有一个TCC脚本的点击事件，当用户鼠标单击图片时会触发

选择图片单元格，右键点击右键菜单的编辑，弹出图片点击事件脚本编辑对话框：

事件函数说明：void OnPictureClick(void *g, int row, int col)；OnPictureClick为事件函数名称，g变量为当前图片所在电子表格指针，row为点击图片的行号，col为点击图片的列号，在事件函数体可以写一些需要做的事情，比如给某些单元格赋值等等。

脚本样例：

如果点击了图片，那么打开24.testcaseData的电子表格先删除所有数据，然后给1到25行1到5列的单元格赋值，最后保存关闭该电子表格退出：

【代码可以在《TCC脚本》章节获取】

注：在事件里调用的wPrint和Print函数在事件脚本执行结束会以对话框方式弹出来。


文件

Help > Snapman客户端 > 5、组件介绍 >
文件

文件介绍

    一、Snapman单元格也可以存储文件类型数据，其设置方法为：

1、在windows的explore选择图片文件后复制，然后粘贴到电子表格里（可以实现多文件的一次粘贴）

    注：如果是多文件，Snapman将文件按照选择的列数排，粘贴满一行后继续往下一行粘贴

2、TCC脚本的赋值方法：

int SnapmanCellSetFile( void * g,int row,int col,wchar_t * path )； //path为本地文件绝对路径

二、文件的打开，双击文件单元格，Snapman会自动选择对应类型的软件打开文件

三 、文件缓存，打开的文件会缓存在Snapman安装目录的AttachmentRootApps下


按钮

Help > Snapman客户端 > 5、组件介绍 >
按钮

按钮介绍

    一、Snapman单元格也可以是按钮，其设置方法为：

1、选择需要变为按钮的单元格，在表格工具条上有 [image] 按钮，点击一下此单元格就变为按钮

如果进行第二次点击则此单元格又变回普通单元格

2、TCC脚本的设置方法，有如下四个相关函数：

//1、第一个函数将不是按钮的单元格设置为按钮，并设置器标题为text；如果已经是按钮则仅设置标题

int SnapmanCellSetButton(void *g,int row,int col,wchar_t *text)

//2、第二个函数获取按钮的标题，如果不是按钮或没有标题则返回NULL

wchar_t * SnapmanCellGetButton(void *g,int row,int col)

//3、每个按钮都是由三张图片和标题组成（三张图片是：默认图片、鼠标进入图片、鼠标点击图片），第三个函数设置按钮的图片
int SnapmanCellSetButtonImage(void *g,int row,int col,SnapmanButtonImage *buttonImage)

//4、第四个函数获取按钮的图片
SnapmanButtonImage SnapmanCellGetButtonImage(void *g,int row,int col)

二、 Snapman按钮单元格的选择方法和其他单元格不同

单击鼠标左键如果移动距离小于5像素松开那么为按钮点击事件，如果大于5像素则转变为选择单元格

三、 Snapman按钮有一个TCC脚本的点击事件，当用户鼠标单击按钮时会触发

选择按钮单元格，右键点击右键菜单的编辑，弹出按钮点击事件脚本编辑对话框，如下面实现提单功能：

在此对话框中除了可以编写按钮点击事件，还可以设置三张图片和按钮标题


状态按钮

Help > Snapman客户端 > 5、组件介绍 >
状态按钮

状态按钮介绍

    一、Snapman单元格也可以是状态按钮，其必须是在分布式模板中使用，控制应用程序的启动和停止，其设置方法为：

1、选择某单元格，在表格工具条上有 [image] 按钮，点击一下此从此单元格开始将会产生11行13列的分布式运行模板，此模板的第二列就是状态按钮

2、TCC脚本 的设置方法，有如下三个相关函数：

//1、第一个函数从某个单元格开始设置为分布式运行模板

int SnapmanCellSetApplicationRunTemplate(void *g,int row,int col)

//2、第二个函数是设置分布式按钮的状态，0是停止运行，1是开始运行
int SnapmanCellSetRunState(void *g,int row,int col,int state)

//3、第三个函数获取分布式按钮的当前状态
int SnapmanCellGetRunState(void *g,int row,int col)

二、状态按钮状态改变后保存，在服务端就是开始下发暂停或启动运行命令给相应用户的客户端，相应客户端接收到命令后会立刻执行并返回结果

三、脚本样例：

设置一个分布式模板，创建了2条TCC脚本命令让执行此函数的用户执行脚本

【代码可以在《TCC脚本》章节获取】


下拉框

Help > Snapman客户端 > 5、组件介绍 >
下拉框

下拉框介绍

    一、Snapman单元格也可以是下拉框，其设置方法为：

1、选择需要变为下拉框的单元格，在表格工具条上有 [image] 按钮，点击一下此单元格就变为下拉框

如果进行第二次点击则此单元格又变回普通单元格

2、TCC脚本的设置方法，有如下四个相关函数：

//1、第一个函数将不是下拉框的单元格设置为下拉框，并设置下拉列表为pList（用‘\n’分割）；如果已经是下拉框则仅设置下拉列表

int SnapmanCellSetCombo(void *g,int row,int col,wchar_t *pList)

//2、第二个函数获取下拉框的选择项，如果不是下拉框或者没有选择内容则返回NULL

wchar_t * SnapmanCellGetCombo(void *g,int row,int col)

//3、第三个函数设置下拉框选择第几项

int SnapmanCellSetComboIndex(void *g,int row,int col,int index)

//4、第四个函数获取下拉框当前选中的是第几项
int SnapmanCellGetComboIndex( void *g, int row, int col)

3、在事件编辑对话框设置它的下拉列表

三、 Snapman下拉框有一个TCC脚本的选择内容变更事件，当用户选择了内容时候会触发执行

选择下拉框单元格，右键点击右键菜单的编辑，弹出事件脚本编辑对话框，如下例子：

设置完后可以下拉框中进行字体选择，当选择字体后会弹出消息提示框提示Hello


勾选框

Help > Snapman客户端 > 5、组件介绍 >
勾选框

勾选框介绍

    一、Snapman单元格也可以是勾选框，其设置方法为：

1、选择需要变为勾选框的单元格，在表格工具条上有 [image] 按钮，点击一下此单元格就变为勾选框

如果进行第二次点击则此单元格又变回普通单元格

2、TCC脚本的设置方法，有如下2个相关函数：

//1、第一个函数获取勾选框的选择状态，1是选择，0是没有选择

int SnapmanCellGetCheck(void *g,int row,int col)

//2、第二个函数先将单元格设置为勾选框，然后设置勾选框的勾选状态

int SnapmanCellSetCheck(void *g,int row,int col,int check)

二、 Snapman勾选框的勾选\取消勾选

    选择勾选框的单元格，按住ctrl键同时点击鼠标左键可以将选择的勾选框状态改变；直接输入0或1；

三、 Snapman勾选框有一个TCC脚本的勾选事件，当用户改变勾选状态时会触发

选择勾选框单元格，右键点击右键菜单的编辑，弹出勾选事件脚本编辑对话框，如下：


进度条

Help > Snapman客户端 > 5、组件介绍 >
进度条

进度条介绍

    一、Snapman单元格也可以是进度条，其设置方法为：

1、选择需要变为进度条的单元格，在表格工具条上有 [image] 按钮，点击一下此单元格就变为进度条

如果进行第二次点击则此单元格又变回普通单元格

2、TCC脚本的设置方法，有如下2个相关函数：

//1、第一个函数获取进度条的进度状态，范围在0-100

int SnapmanCellGetProgress(void *g,int row,int col)

//2、第二个函数先将单元格设置为进度条，然后设置进度条进度状态

int SnapmanCellSetProgress(void *g,int row, int col, int progress)

二 、 Snapman进度条进度改变

    选择进度条的单元格，按住ctrl键同时点击鼠标左键可以改变进度条的进度，或者按住ctrl键同时点击鼠标左键然后拖动可以连续改变进度条进度；直接输入0到100的数；

三 、 Snapman进度条有一个TCC脚本的改变进度事件，当用户手工改变进度时候会触发执行

选择进度条单元格，右键点击右键菜单的编辑，弹出事件脚本编辑对话框，如下例子：


打分控件

Help > Snapman客户端 > 5、组件介绍 >
打分控件

打分控件介绍

    一、 Snapman单元格也可以是打分控件，其设置方法为：

1、选择需要变为打分控件的单元格，在表格工具条上有 [image] 按钮，点击一下此单元格就变为打分控件

如果进行第二次点击则此单元格又变回普通单元格

2、TCC脚本的设置方法，有如下2个相关函数：

//1、第一个函数获取打分控件所打的分数，范围在0-100

intSnapmanCellGetMark(void *g,int row, int col)

//2、第二个函数先将单元格设置为打分控件，然后设置打分控件分数

int SnapmanCellSetMark (void *g, int row, intcol,intmark)

二、Snapman打分控件分数改变

     选择打分控件的单元格，按住ctrl键同时点击鼠标左键可以改变打分控件的分数，或者按住ctrl键同时点击鼠标左键然后拖动可以连续改变打分控件的分数；直接输入0到100的数；

三 、 Snapman打分控件有一个TCC脚本的改变分数事件，当用户手工改变分数时候会触发执行

选择打分控件单元格，右键点击右键菜单的编辑，弹出事件脚本编辑对话框，如下例子：


Exprtk脚本

Help > Snapman客户端 > 5、组件介绍 >
Exprtk脚本

Exprtk脚本介绍

    一、Exprtk脚本是Snapman集合的数据运算脚本，

其设置方法为：在普通单元输入‘=’系统将会将该单元格改变成Exprtk脚本单元格

二、Exprtk脚本功能简介

这是一个非常强大的脚本包括完成的算术逻辑运算、完整的流程控制，拥有变量、数组、字符串等，还有很多高效的内置函数；

Exprtk的网址是： http://www.partow.net/programming/exprtk/

三、Exprtk脚本编辑

可以在表格上直接编辑，也可以使用右键菜单编辑命令在弹出的窗口上编辑。脚本编辑自带语法高亮、关键字提示功能。

四、Snapman对Exprtk的扩展

Exprtk可以操作脚本所在表格中的所有单元格数据内容

1、数字变量：

Snapman默认将所有单元格定义为数字变量，可以取它的值也可以给它赋值；

规则为：列字母加行号数字；

如：A1，就代表了第一列第一行单元格的数字变量

其他用户定义的变量请不要定义为：字母加数字形式，否则系统变量重复定义，导致出错

2、字符串变量：

Snapman默认将所有单元格定义为字符串变量，可以取它的值也可以给它赋值；

规则为：列字母加行号数字加下划线；

如：A1_，就代表了第一列第一行单元格的字符串变量

其他用户定义的变量请不要定义为：字母加数字加下划线形式，否则系统变量重复定义，导致出错

3、函数扩展：

double tostring(string str); //将字符串转换成数字

string tonumber(double data); //将数字转换成字符串

string toupper(string str); //将字符串转换成大写

string tolower(string str); //将字符串转换成小写

string get_(introw,int col); //获取表格中指定行列单元格的字符串

voidset_(int row,int col,string str ); //设置表格中指定行列单元格的字符串

double get(int row,int col ); //获取表格中指定行列单元格的数字

voidset(introw,int col,double data ); //设置表格中指定行列单元格的数字

void save (); //保存当前电子表格

voidsleep(double n ); //休眠n毫秒

void setprogress(doublen); //设置进度条的进度为n

double gettickcount( ); //获取当前时间的毫秒数

五、Exprtk脚本的执行

打开带有Exprtk脚本的电子表格，用快捷键F5,可以运行表格中所有脚本，用快捷键F4可以清除脚本运行的打印内容显示脚本内容


TCC脚本

Help > Snapman客户端 > 5、组件介绍 >
TCC脚本

TCC脚本介绍

    一、Snapman单元格也可以是TCC脚本，其设置方法为：

1、选择需要变为按钮的单元格，在表格工具条上有 [image] 按钮，点击一下此单元格就变为TCC脚本

如果进行第二次点击则此单元格又变回普通单元格

2、用TCC脚本的设置方法，有如下四个相关函数：

//1、第一个函数将不是TCC脚本的单元格设置为TCC脚本，并设置其脚本内容；如果已经是按钮则仅设置其脚本内容

int SnapmanCellSetTccScript(void *g,int row,int col,wchar_t *script)

//2、第二个函数获取脚本内容（所有脚本除TCC外还可以获取Exprtk脚本），如果没有脚本则返回NULL

wchar_t * SnapmanCellGetScript(void *g,int row,int col)

二、TCC脚本功能简介

TCC是Tiny C Compiler的简称，是一个C语言的编译器。TCC脚本就是C语言脚本，支持C99的C语言标准。

TCC的网址是：

https://bellard.org/tcc/

https://bellard.org/tcc/tcc-doc.html

三、TCC脚本编辑

可以在表格上直接编辑，也可以使用右键菜单编辑命令在弹出的窗口上编辑。脚本编辑自带语法高亮、关键字提示功能。

四、TCC脚本的执行

打开带有Exprtk脚本的电子表格，用快捷键F5,可以运行表格中所有脚本，用快捷键F4可以清除脚本运行的打印内容显示脚本内容

五、Snapman对TCC的扩展

可以参考附件：Snapman.h ，这里面集合了TCC可操作所有Snapman的功能。

六、TCC的自动化测试脚本

可以参考附件：SnapmanTestcase.c ，这里面集合了Snapman对TCC扩展所有功能的自动化测试用例。


6、Exprtk语法

Help > Snapman客户端 >
6、Exprtk语法

Exprtk脚本是一个非常强大的脚本包括完成的算术逻辑运算、完整的流程控制，拥有变量、数组、字符串等，还有很多高效的内置函数； Exprtk的网址是：http://www.partow.net/programming/exprtk/

Exprtk脚本详细介绍，对原始涉及C++开发部分内容有删除，原始请参考： https://github.com/ArashPartow/exprtk

C++ Mathematical Expression Toolkit Library Documentation

  Section 00 - Introduction
  Section 01 - Capabilities
  Section 02 - Example Expressions
  Section 03 - Copyright Notice
  Section 04 - Built-In Operations & Functions
  Section 05 - Fundamental Types
  Section 06 - Compilation Options
  Section 07 - Expression Structures
  Section 08 - Variable, Vector & String Definition
  Section 09 - Vector Processing
  Section 10 - Expression Dependents
  Section 11 - Hierarchies Of Symbol Tables
  Section 12 - Unknown Unknowns
  Section 13 - Enabling & Disabling Features
  Section 14 - Expression Return Values
  Section 15 - Compilation Errors
  Section 16 - Runtime Library Packages
  Section 17 - Benchmarking
  Section 18 - Exprtk Notes
  Section 19 - Language Structure

[SECTION 00 - INTRODUCTION]
The C++ Mathematical Expression  Toolkit Library (ExprTk) is  a simple
to  use,   easy  to   integrate  and   extremely  efficient   run-time
mathematical  expression parsing  and evaluation  engine. The  parsing
engine  supports numerous  forms  of  functional and  logic processing
semantics and is easily extensible.

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 01 - CAPABILITIES]
The  ExprTk expression  evaluator supports  the following  fundamental
arithmetic operations, functions and processes:

 (00) Types:           Scalar, Vector, String

 (01) Basic operators: +, -, *, /, %, ^

 (02) Assignment:      :=, +=, -=, *=, /=, %=

 (03) Equalities &
      Inequalities:    =, ==, <>, !=, <, <=, >, >=

 (04) Logic operators: and, mand, mor, nand, nor, not, or, shl, shr,
                       xnor, xor, true, false

 (05) Functions:       abs, avg, ceil, clamp, equal, erf, erfc,  exp,
                       expm1, floor, frac,  log, log10, log1p,  log2,
                       logn,  max,  min,  mul,  ncdf,  nequal,  root,
                       round, roundn, sgn, sqrt, sum, swap, trunc

 (06) Trigonometry:    acos, acosh, asin, asinh, atan, atanh,  atan2,
                       cos,  cosh, cot,  csc, sec,  sin, sinc,  sinh,
                       tan, tanh, hypot, rad2deg, deg2grad,  deg2rad,
                       grad2deg

 (07) Control
      structures:      if-then-else, ternary conditional, switch-case,
                       return-statement

 (08) Loop statements: while, for, repeat-until, break, continue

 (09) String
      processing:      in, like, ilike, concatenation

 (10) Optimisations:   constant-folding, simple strength reduction and
                       dead code elimination

 (11) Calculus:        numerical integration and differentiation

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 02 - EXAMPLE EXPRESSIONS]
The following is  a short listing  of infix format  based mathematical
expressions that can be parsed and evaluated using the ExprTk library.

  (01) sqrt(1 - (3 / x^2))
  (02) clamp(-1, sin(2 * pi * x) + cos(y / 2 * pi), +1)
  (03) sin(2.34e-3 * x)
  (04) if(((x[2] + 2) == 3) and ((y + 5) <= 9),1 + w, 2 / z)
  (05) inrange(-2,m,+2) == if(({-2 <= m} and [m <= +2]),1,0)
  (06) ({1/1}*[1/2]+(1/3))-{1/4}^[1/5]+(1/6)-({1/7}+[1/8]*(1/9))
  (07) a * exp(2.2 / 3.3 * t) + c
  (08) z := x + sin(2.567 * pi / y)
  (09) u := 2.123 * {pi * z} / (w := x + cos(y / pi))
  (10) 2x + 3y + 4z + 5w == 2 * x + 3 * y + 4 * z + 5 * w
  (11) 3(x + y) / 2.9 + 1.234e+12 == 3 * (x + y) / 2.9 + 1.234e+12
  (12) (x + y)3.3 + 1 / 4.5 == [x + y] * 3.3 + 1 / 4.5
  (13) (x + y[i])z + 1.1 / 2.7 == (x + y[i]) * z + 1.1 / 2.7
  (14) (sin(x / pi) cos(2y) + 1) == (sin(x / pi) * cos(2 * y) + 1)
  (15) 75x^17 + 25.1x^5 - 35x^4 - 15.2x^3 + 40x^2 - 15.3x + 1
  (16) (avg(x,y) <= x + y ? x - y : x * y) + 2.345 * pi / x
  (17) while (x <= 100) { x -= 1; }
  (18) x <= 'abc123' and (y in 'AString') or ('1x2y3z' != z)
  (19) ((x + 'abc') like '*123*') or ('a123b' ilike y)
  (20) sgn(+1.2^3.4z / -5.6y) <= {-7.8^9 / -10.11x }

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 03 - COPYRIGHT NOTICE]
Free  use  of  the  C++  Mathematical  Expression  Toolkit  Library is
permitted under the guidelines and in accordance with the most current
version of the MIT License.

http://www.opensource.org/licenses/MIT

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 04 - BUILT-IN OPERATIONS & FUNCTIONS]

(0) Arithmetic & Assignment Operators
+----------+---------------------------------------------------------+
| OPERATOR | DEFINITION                                              |
+----------+---------------------------------------------------------+
|  +       | Addition between x and y.  (eg: x + y)                  |
+----------+---------------------------------------------------------+
|  -       | Subtraction between x and y.  (eg: x - y)               |
+----------+---------------------------------------------------------+
|  *       | Multiplication between x and y.  (eg: x * y)            |
+----------+---------------------------------------------------------+
|  /       | Division between x and y.  (eg: x / y)                  |
+----------+---------------------------------------------------------+
|  %       | Modulus of x with respect to y.  (eg: x % y)            |
+----------+---------------------------------------------------------+
|  ^       | x to the power of y.  (eg: x ^ y)                       |
+----------+---------------------------------------------------------+
|  :=      | Assign the value of x to y. Where y is either a variable|
|          | or vector type.  (eg: y := x)                           |
+----------+---------------------------------------------------------+
|  +=      | Increment x by the value of the expression on the right |
|          | hand side. Where x is either a variable or vector type. |
|          | (eg: x += abs(y - z))                                   |
+----------+---------------------------------------------------------+
|  -=      | Decrement x by the value of the expression on the right |
|          | hand side. Where x is either a variable or vector type. |
|          | (eg: x[i] -= abs(y + z))                                |
+----------+---------------------------------------------------------+
|  *=      | Assign the multiplication of x by the value of the      |
|          | expression on the righthand side to x. Where x is either|
|          | a variable or vector type.                              |
|          | (eg: x *= abs(y / z))                                   |
+----------+---------------------------------------------------------+
|  /=      | Assign the division of x by the value of the expression |
|          | on the right-hand side to x. Where x is either a        |
|          | variable or vector type.  (eg: x[i + j] /= abs(y * z))  |
+----------+---------------------------------------------------------+
|  %=      | Assign x modulo the value of the expression on the right|
|          | hand side to x. Where x is either a variable or vector  |
|          | type.  (eg: x[2] %= y ^ 2)                              |
+----------+---------------------------------------------------------+

(1) Equalities & Inequalities
+----------+---------------------------------------------------------+
| OPERATOR | DEFINITION                                              |
+----------+---------------------------------------------------------+
| == or =  | True only if x is strictly equal to y. (eg: x == y)     |
+----------+---------------------------------------------------------+
| <> or != | True only if x does not equal y. (eg: x <> y or x != y) |
+----------+---------------------------------------------------------+
|  <       | True only if x is less than y. (eg: x < y)              |
+----------+---------------------------------------------------------+
|  <=      | True only if x is less than or equal to y. (eg: x <= y) |
+----------+---------------------------------------------------------+
|  >       | True only if x is greater than y. (eg: x > y)           |
+----------+---------------------------------------------------------+
|  >=      | True only if x greater than or equal to y. (eg: x >= y) |
+----------+---------------------------------------------------------+

(2) Boolean Operations
+----------+---------------------------------------------------------+
| OPERATOR | DEFINITION                                              |
+----------+---------------------------------------------------------+
| true     | True state or any value other than zero (typically 1).  |
+----------+---------------------------------------------------------+
| false    | False state, value of zero.                             |
+----------+---------------------------------------------------------+
| and      | Logical AND, True only if x and y are both true.        |
|          | (eg: x and y)                                           |
+----------+---------------------------------------------------------+
| mand     | Multi-input logical AND, True only if all inputs are    |
|          | true. Left to right short-circuiting of expressions.    |
|          | (eg: mand(x > y, z < w, u or v, w and x))               |
+----------+---------------------------------------------------------+
| mor      | Multi-input logical OR, True if at least one of the     |
|          | inputs are true. Left to right short-circuiting of      |
|          | expressions.  (eg: mor(x > y, z < w, u or v, w and x))  |
+----------+---------------------------------------------------------+
| nand     | Logical NAND, True only if either x or y is false.      |
|          | (eg: x nand y)                                          |
+----------+---------------------------------------------------------+
| nor      | Logical NOR, True only if the result of x or y is false |
|          | (eg: x nor y)                                           |
+----------+---------------------------------------------------------+
| not      | Logical NOT, Negate the logical sense of the input.     |
|          | (eg: not(x and y) == x nand y)                          |
+----------+---------------------------------------------------------+
| or       | Logical OR, True if either x or y is true. (eg: x or y) |
+----------+---------------------------------------------------------+
| xor      | Logical XOR, True only if the logical states of x and y |
|          | differ.  (eg: x xor y)                                  |
+----------+---------------------------------------------------------+
| xnor     | Logical XNOR, True iff the biconditional of x and y is  |
|          | satisfied.  (eg: x xnor y)                              |
+----------+---------------------------------------------------------+
| &        | Similar to AND but with left to right expression short  |
|          | circuiting optimisation.  (eg: (x & y) == (y and x))    |
+----------+---------------------------------------------------------+
| |        | Similar to OR but with left to right expression short   |
|          | circuiting optimisation.  (eg: (x | y) == (y or x))     |
+----------+---------------------------------------------------------+

(3) General Purpose Functions
+----------+---------------------------------------------------------+
| FUNCTION | DEFINITION                                              |
+----------+---------------------------------------------------------+
| abs      | Absolute value of x.  (eg: abs(x))                      |
+----------+---------------------------------------------------------+
| avg      | Average of all the inputs.                              |
|          | (eg: avg(x,y,z,w,u,v) == (x + y + z + w + u + v) / 6)   |
+----------+---------------------------------------------------------+
| ceil     | Smallest integer that is greater than or equal to x.    |
+----------+---------------------------------------------------------+
| clamp    | Clamp x in range between r0 and r1, where r0 < r1.      |
|          | (eg: clamp(r0,x,r1))                                    |
+----------+---------------------------------------------------------+
| equal    | Equality test between x and y using normalized epsilon  |
+----------+---------------------------------------------------------+
| erf      | Error function of x.  (eg: erf(x))                      |
+----------+---------------------------------------------------------+
| erfc     | Complimentary error function of x.  (eg: erfc(x))       |
+----------+---------------------------------------------------------+
| exp      | e to the power of x.  (eg: exp(x))                      |
+----------+---------------------------------------------------------+
| expm1    | e to the power of x minus 1, where x is very small.     |
|          | (eg: expm1(x))                                          |
+----------+---------------------------------------------------------+
| floor    | Largest integer that is less than or equal to x.        |
|          | (eg: floor(x))                                          |
+----------+---------------------------------------------------------+
| frac     | Fractional portion of x.  (eg: frac(x))                 |
+----------+---------------------------------------------------------+
| hypot    | Hypotenuse of x and y (eg: hypot(x,y) = sqrt(x*x + y*y))|
+----------+---------------------------------------------------------+
| iclamp   | Inverse-clamp x outside of the range r0 and r1. Where   |
|          | r0 < r1. If x is within the range it will snap to the   |
|          | closest bound. (eg: iclamp(r0,x,r1)                     |
+----------+---------------------------------------------------------+
| inrange  | In-range returns 'true' when x is within the range r0   |
|          | and r1. Where r0 < r1.  (eg: inrange(r0,x,r1)           |
+----------+---------------------------------------------------------+
| log      | Natural logarithm of x.  (eg: log(x))                   |
+----------+---------------------------------------------------------+
| log10    | Base 10 logarithm of x.  (eg: log10(x))                 |
+----------+---------------------------------------------------------+
| log1p    | Natural logarithm of 1 + x, where x is very small.      |
|          | (eg: log1p(x))                                          |
+----------+---------------------------------------------------------+
| log2     | Base 2 logarithm of x.  (eg: log2(x))                   |
+----------+---------------------------------------------------------+
| logn     | Base N logarithm of x. where n is a positive integer.   |
|          | (eg: logn(x,8))                                         |
+----------+---------------------------------------------------------+
| max      | Largest value of all the inputs. (eg: max(x,y,z,w,u,v)) |
+----------+---------------------------------------------------------+
| min      | Smallest value of all the inputs. (eg: min(x,y,z,w,u))  |
+----------+---------------------------------------------------------+
| mul      | Product of all the inputs.                              |
|          | (eg: mul(x,y,z,w,u,v,t) == (x * y * z * w * u * v * t)) |
+----------+---------------------------------------------------------+
| ncdf     | Normal cumulative distribution function.  (eg: ncdf(x)) |
+----------+---------------------------------------------------------+
| nequal   | Not-equal test between x and y using normalized epsilon |
+----------+---------------------------------------------------------+
| pow      | x to the power of y.  (eg: pow(x,y) == x ^ y)           |
+----------+---------------------------------------------------------+
| root     | Nth-Root of x. where n is a positive integer.           |
|          | (eg: root(x,3) == x^(1/3))                              |
+----------+---------------------------------------------------------+
| round    | Round x to the nearest integer.  (eg: round(x))         |
+----------+---------------------------------------------------------+
| roundn   | Round x to n decimal places  (eg: roundn(x,3))          |
|          | where n > 0 and is an integer.                          |
|          | (eg: roundn(1.2345678,4) == 1.2346)                     |
+----------+---------------------------------------------------------+
| sgn      | Sign of x, -1 where x < 0, +1 where x > 0, else zero.   |
|          | (eg: sgn(x))                                            |
+----------+---------------------------------------------------------+
| sqrt     | Square root of x, where x >= 0.  (eg: sqrt(x))          |
+----------+---------------------------------------------------------+
| sum      | Sum of all the inputs.                                  |
|          | (eg: sum(x,y,z,w,u,v,t) == (x + y + z + w + u + v + t)) |
+----------+---------------------------------------------------------+
| swap     | Swap the values of the variables x and y and return the |
| <=>      | current value of y.  (eg: swap(x,y) or x <=> y)         |
+----------+---------------------------------------------------------+
| trunc    | Integer portion of x.  (eg: trunc(x))                   |
+----------+---------------------------------------------------------+

(4) Trigonometry Functions
+----------+---------------------------------------------------------+
| FUNCTION | DEFINITION                                              |
+----------+---------------------------------------------------------+
| acos     | Arc cosine of x expressed in radians. Interval [-1,+1]  |
|          | (eg: acos(x))                                           |
+----------+---------------------------------------------------------+
| acosh    | Inverse hyperbolic cosine of x expressed in radians.    |
|          | (eg: acosh(x))                                          |
+----------+---------------------------------------------------------+
| asin     | Arc sine of x expressed in radians. Interval [-1,+1]    |
|          | (eg: asin(x))                                           |
+----------+---------------------------------------------------------+
| asinh    | Inverse hyperbolic sine of x expressed in radians.      |
|          | (eg: asinh(x))                                          |
+----------+---------------------------------------------------------+
| atan     | Arc tangent of x expressed in radians. Interval [-1,+1] |
|          | (eg: atan(x))                                           |
+----------+---------------------------------------------------------+
| atan2    | Arc tangent of (x / y) expressed in radians. [-pi,+pi]  |
|          | eg: atan2(x,y)                                          |
+----------+---------------------------------------------------------+
| atanh    | Inverse hyperbolic tangent of x expressed in radians.   |
|          | (eg: atanh(x))                                          |
+----------+---------------------------------------------------------+
| cos      | Cosine of x.  (eg: cos(x))                              |
+----------+---------------------------------------------------------+
| cosh     | Hyperbolic cosine of x.  (eg: cosh(x))                  |
+----------+---------------------------------------------------------+
| cot      | Cotangent of x.  (eg: cot(x))                           |
+----------+---------------------------------------------------------+
| csc      | Cosecant of x.  (eg: csc(x))                            |
+----------+---------------------------------------------------------+
| sec      | Secant of x.  (eg: sec(x))                              |
+----------+---------------------------------------------------------+
| sin      | Sine of x.  (eg: sin(x))                                |
+----------+---------------------------------------------------------+
| sinc     | Sine cardinal of x.  (eg: sinc(x))                      |
+----------+---------------------------------------------------------+
| sinh     | Hyperbolic sine of x.  (eg: sinh(x))                    |
+----------+---------------------------------------------------------+
| tan      | Tangent of x.  (eg: tan(x))                             |
+----------+---------------------------------------------------------+
| tanh     | Hyperbolic tangent of x.  (eg: tanh(x))                 |
+----------+---------------------------------------------------------+
| deg2rad  | Convert x from degrees to radians.  (eg: deg2rad(x))    |
+----------+---------------------------------------------------------+
| deg2grad | Convert x from degrees to gradians.  (eg: deg2grad(x))  |
+----------+---------------------------------------------------------+
| rad2deg  | Convert x from radians to degrees.  (eg: rad2deg(x))    |
+----------+---------------------------------------------------------+
| grad2deg | Convert x from gradians to degrees.  (eg: grad2deg(x))  |
+----------+---------------------------------------------------------+

(5) String Processing
+----------+---------------------------------------------------------+
| FUNCTION | DEFINITION                                              |
+----------+---------------------------------------------------------+
|  = , ==  | All common equality/inequality operators are applicable |
|  !=, <>  | to strings and are applied in a case sensitive manner.  |
|  <=, >=  | In the following example x, y and z are of type string. |
|  < , >   | (eg: not((x <= 'AbC') and ('1x2y3z' <> y)) or (z == x)  |
+----------+---------------------------------------------------------+
| in       | True only if x is a substring of y.                     |
|          | (eg: x in y or 'abc' in 'abcdefgh')                     |
+----------+---------------------------------------------------------+
| like     | True only if the string x matches the pattern y.        |
|          | Available wildcard characters are '*' and '?' denoting  |
|          | zero or more and zero or one matches respectively.      |
|          | (eg: x like y or 'abcdefgh' like 'a?d*h')               |
+----------+---------------------------------------------------------+
| ilike    | True only if the string x matches the pattern y in a    |
|          | case insensitive manner. Available wildcard characters  |
|          | are '*' and '?' denoting zero or more and zero or one   |
|          | matches respectively.                                   |
|          | (eg: x ilike y or 'a1B2c3D4e5F6g7H' ilike 'a?d*h')      |
+----------+---------------------------------------------------------+
| [r0:r1]  | The closed interval [r0,r1] of the specified string.    |
|          | eg: Given a string x with a value of 'abcdefgh' then:   |
|          | 1. x[1:4] == 'bcde'                                     |
|          | 2. x[ :5] == x[:5] == 'abcdef'                          |
|          | 3. x[3: ] == x[3:] =='cdefgh'                           |
|          | 4. x[ : ] == x[:] == 'abcdefgh'                         |
|          | 5. x[4/2:3+2] == x[2:5] == 'cdef'                       |
|          |                                                         |
|          | Note: Both r0 and r1 are assumed to be integers, where  |
|          | r0 <= r1. They may also be the result of an expression, |
|          | in the event they have fractional components truncation |
|          | will be performed. (eg: 1.67 --> 1)                     |
+----------+---------------------------------------------------------+
|  :=      | Assign the value of x to y. Where y is a mutable string |
|          | or string range and x is either a string or a string    |
|          | range. eg:                                              |
|          | 1. y := x                                               |
|          | 2. y := 'abc'                                           |
|          | 3. y := x[:i + j]                                       |
|          | 4. y := '0123456789'[2:7]                               |
|          | 5. y := '0123456789'[2i + 1:7]                          |
|          | 6. y := (x := '0123456789'[2:7])                        |
|          | 7. y[i:j] := x                                          |
|          | 8. y[i:j] := (x + 'abcdefg'[8 / 4:5])[m:n]              |
|          |                                                         |
|          | Note: For options 7 and 8 the shorter of the two ranges |
|          | will denote the number characters that are to be copied.|
+----------+---------------------------------------------------------+
|  +       | Concatenation of x and y. Where x and y are strings or  |
|          | string ranges. eg                                       |
|          | 1. x + y                                                |
|          | 2. x + 'abc'                                            |
|          | 3. x + y[:i + j]                                        |
|          | 4. x[i:j] + y[2:3] + '0123456789'[2:7]                  |
|          | 5. 'abc' + x + y                                        |
|          | 6. 'abc' + '1234567'                                    |
|          | 7. (x + 'a1B2c3D4' + y)[i:2j]                           |
+----------+---------------------------------------------------------+
|  +=      | Append to x the value of y. Where x is a mutable string |
|          | and y is either a string or a string range. eg:         |
|          | 1. x += y                                               |
|          | 2. x += 'abc'                                           |
|          | 3. x += y[:i + j] + 'abc'                               |
|          | 4. x += '0123456789'[2:7]                               |
+----------+---------------------------------------------------------+
| <=>      | Swap the values of x and y. Where x and y are mutable   |
|          | strings.  (eg: x <=> y)                                 |
+----------+---------------------------------------------------------+
| []       | The string size operator returns the size of the string |
|          | being actioned.                                         |
|          | eg:                                                     |
|          | 1. 'abc'[] == 3                                         |
|          | 2. var max_str_length := max(s0[],s1[],s2[],s3[])       |
|          | 3. ('abc' + 'xyz')[] == 6                               |
|          | 4. (('abc' + 'xyz')[1:4])[] == 4                        |
+----------+---------------------------------------------------------+

(6) Control Structures
+----------+---------------------------------------------------------+
|STRUCTURE | DEFINITION                                              |
+----------+---------------------------------------------------------+
| if       | If x is true then return y else return z.               |
|          | eg:                                                     |
|          | 1. if (x, y, z)                                         |
|          | 2. if ((x + 1) > 2y, z + 1, w / v)                      |
|          | 3. if (x > y) z;                                        |
|          | 4. if (x <= 2*y) { z + w };                             |
+----------+---------------------------------------------------------+
| if-else  | The if-else/else-if statement. Subject to the condition |
|          | branch the statement will return either the value of the|
|          | consequent or the alternative branch.                   |
|          | eg:                                                     |
|          | 1. if (x > y) z; else w;                                |
|          | 2. if (x > y) z; else if (w != u) v;                    |
|          | 3. if (x < y) {z; w + 1;} else u;                       |
|          | 4. if ((x != y) and (z > w))                            |
|          |    {                                                    |
|          |      y := sin(x) / u;                                   |
|          |      z := w + 1;                                        |
|          |    }                                                    |
|          |    else if (x > (z + 1))                                |
|          |    {                                                    |
|          |      w := abs (x - y) + z;                              |
|          |      u := (x + 1) > 2y ? 2u : 3u;                       |
|          |    }                                                    |
+----------+---------------------------------------------------------+
| switch   | The first true case condition that is encountered will  |
|          | determine the result of the switch. If none of the case |
|          | conditions hold true, the default action is assumed as  |
|          | the final return value. This is sometimes also known as |
|          | a multi-way branch mechanism.                           |
|          | eg:                                                     |
|          | switch                                                  |
|          | {                                                       |
|          |   case x > (y + z) : 2 * x / abs(y - z);                |
|          |   case x < 3       : sin(x + y);                        |
|          |   default          : 1 + x;                             |
|          | }                                                       |
+----------+---------------------------------------------------------+
| while    | The structure will repeatedly evaluate the internal     |
|          | statement(s) 'while' the condition is true. The final   |
|          | statement in the final iteration will be used as the    |
|          | return value of the loop.                               |
|          | eg:                                                     |
|          | while ((x -= 1) > 0)                                    |
|          | {                                                       |
|          |   y := x + z;                                           |
|          |   w := u + y;                                           |
|          | }                                                       |
+----------+---------------------------------------------------------+
| repeat/  | The structure will repeatedly evaluate the internal     |
| until    | statement(s) 'until' the condition is true. The final   |
|          | statement in the final iteration will be used as the    |
|          | return value of the loop.                               |
|          | eg:                                                     |
|          | repeat                                                  |
|          |   y := x + z;                                           |
|          |   w := u + y;                                           |
|          | until ((x += 1) > 100)                                  |
+----------+---------------------------------------------------------+
| for      | The structure will repeatedly evaluate the internal     |
|          | statement(s) while the condition is true. On each loop  |
|          | iteration, an 'incrementing' expression is evaluated.   |
|          | The conditional is mandatory whereas the initialiser    |
|          | and incrementing expressions are optional.              |
|          | eg:                                                     |
|          | for (var x := 0; (x < n) and (x != y); x += 1)          |
|          | {                                                       |
|          |   y := y + x / 2 - z;                                   |
|          |   w := u + y;                                           |
|          | }                                                       |
+----------+---------------------------------------------------------+
| break    | Break terminates the execution of the nearest enclosed  |
| break[]  | loop, allowing for the execution to continue on external|
|          | to the loop. The default break statement will set the   |
|          | return value of the loop to NaN, where as the return    |
|          | based form will set the value to that of the break      |
|          | expression.                                             |
|          | eg:                                                     |
|          | while ((i += 1) < 10)                                   |
|          | {                                                       |
|          |   if (i < 5)                                            |
|          |     j -= i + 2;                                         |
|          |   else if (i % 2 == 0)                                  |
|          |     break;                                              |
|          |   else                                                  |
|          |     break[2i + 3];                                      |
|          | }                                                       |
+----------+---------------------------------------------------------+
| continue | Continue results in the remaining portion of the nearest|
|          | enclosing loop body to be skipped.                      |
|          | eg:                                                     |
|          | for (var i := 0; i < 10; i += 1)                        |
|          | {                                                       |
|          |   if (i < 5)                                            |
|          |     continue;                                           |
|          |   j -= i + 2;                                           |
|          | }                                                       |
+----------+---------------------------------------------------------+
| return   | Return immediately from within the current expression.  |
|          | With the option of passing back a variable number of    |
|          | values (scalar, vector or string). eg:                  |
|          | 1. return [1];                                          |
|          | 2. return [x, 'abx'];                                   |
|          | 3. return [x, x + y,'abx'];                             |
|          | 4. return [];                                           |
|          | 5. if (x < y)                                           |
|          |     return [x, x - y, 'result-set1', 123.456];          |
|          |    else                                                 |
|          |     return [y, x + y, 'result-set2'];                   |
+----------+---------------------------------------------------------+
| ?:       | Ternary conditional statement, similar to that of the   |
|          | above denoted if-statement.                             |
|          | eg:                                                     |
|          | 1. x ? y : z                                            |
|          | 2. x + 1 > 2y ? z + 1 : (w / v)                         |
|          | 3. min(x,y) > z ? (x < y + 1) ? x : y : (w * v)         |
+----------+---------------------------------------------------------+
| ~        | Evaluate each sub-expression, then return as the result |
|          | the value of the last sub-expression. This is sometimes |
|          | known as multiple sequence point evaluation.            |
|          | eg:                                                     |
|          | ~(i := x + 1, j := y / z, k := sin(w/u)) == (sin(w/u))) |
|          | ~{i := x + 1; j := y / z; k := sin(w/u)} == (sin(w/u))) |
+----------+---------------------------------------------------------+
| [*]      | Evaluate any consequent for which its case statement is |
|          | true. The return value will be either zero or the result|
|          | of the last consequent to have been evaluated.          |
|          | eg:                                                     |
|          | [*]                                                     |
|          | {                                                       |
|          |   case (x + 1) > (y - 2)    : x := z / 2 + sin(y / pi); |
|          |   case (x + 2) < abs(y + 3) : w / 4 + min(5y,9);        |
|          |   case (x + 3) == (y * 4)   : y := abs(z / 6) + 7y;     |
|          | }                                                       |
+----------+---------------------------------------------------------+
| []       | The vector size operator returns the size of the vector |
|          | being actioned.                                         |
|          | eg:                                                     |
|          | 1. v[]                                                  |
|          | 2. max_size := max(v0[],v1[],v2[],v3[])                 |
+----------+---------------------------------------------------------+

Note: In  the  tables  above, the  symbols x, y, z, w, u  and v  where
appropriate may represent any of one the following:

   1. Literal numeric/string value
   2. A variable
   3. A vector element
   4. A vector
   5. A string
   6. An expression comprised of [1], [2] or [3] (eg: 2 + x / vec[3])

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 05 - FUNDAMENTAL TYPES]
ExprTk supports three fundamental types which can be used freely in
expressions. The types are as follows:

   (1) Scalar
   (2) Vector
   (3) String

(1) Scalar Type
The scalar type  is a singular  numeric value. The  underlying type is
that used  to specialize  the ExprTk  components (float,  double, long
double, MPFR et al).

(2) Vector Type
The vector type is a fixed size sequence of contiguous scalar  values.
A  vector  can be  indexed  resulting in  a  scalar value.  Operations
between a vector and scalar will result in a vector with a size  equal
to that  of the  original vector,  whereas operations  between vectors
will result in a  vector of size equal  to that of the  smaller of the
two. In both mentioned cases, the operations will occur element-wise.

(3) String Type
The string type is a variable length sequence of 8-bit chars.  Strings
can be  assigned and  concatenated to  one another,  they can  also be
manipulated via sub-ranges using the range definition syntax.  Strings
however can not interact with scalar or vector types.

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 06 - COMPILATION OPTIONS]
The exprtk::parser  when being  instantiated takes  as input  a set of
options  to be  used during  the compilation  process of  expressions.
An  example instantiation  of exprtk::parser  where only  the  joiner,
commutative and strength reduction options are enabled is as  follows:

   typedef exprtk::parser<NumericType>::settings_t settings_t;

   std::size_t compile_options = settings_t::e_joiner            +
                                 settings_t::e_commutative_check +
                                 settings_t::e_strength_reduction;

   parser_t parser(compile_options);

Currently  seven  types of  compile  time options  are  supported, and
enabled by default. The options and their explanations are as follows:

   (1) Replacer
   (2) Joiner
   (3) Numeric Check
   (4) Bracket Check
   (5) Sequence Check
   (6) Commutative Check
   (7) Strength Reduction Check

(1) Replacer (e_replacer)
Enable replacement of specific  tokens with other tokens.  For example
the token  "true" of  type symbol  will be  replaced with  the numeric
token of value one.

   (a) (x < y) == true   --->  (x < y) == 1
   (b) false == (x > y)  --->  0 == (x > y)

(2) Joiner (e_joiner)
Enable  joining  of  multi-character  operators  that  may  have  been
incorrectly  disjoint in the  string  representation  of the specified
expression. For example the consecutive tokens of ">" "=" will  become
">=" representing  the "greater  than or  equal to"  operator. If  not
properly resolved the  original form will  cause a compilation  error.
The  following  is  a listing  of the  scenarios that  the joiner  can
handle:

   (a) '>' '='  --->  '>='  (gte)
   (b) '<' '='  --->  '<='  (lte)
   (c) '=' '='  --->  '=='  (equal)
   (d) '!' '='  --->  '!='  (not-equal)
   (e) '<' '>'  --->  '<>'  (not-equal)
   (f) ':' '='  --->  ':='  (assignment)
   (g) '+' '='  --->  '+='  (addition assignment)
   (h) '-' '='  --->  '-='  (subtraction assignment)
   (i) '*' '='  --->  '*='  (multiplication assignment)
   (j) '/' '='  --->  '/='  (division assignment)
   (k) '%' '='  --->  '%='  (modulo assignment)
   (l) '+' '-'  --->  '-'   (subtraction)
   (m) '-' '+'  --->  '-'   (subtraction)
   (n) '-' '-'  --->  '+'   (addition)
   (o) '<=' '>' --->  '<=>' (swap)

An example of the transformation that takes place is as follows:

   (a) (x > = y) and (z ! = w)  --->  (x >= y) and (z != w)

(3) Numeric Check (e_numeric_check)
Enable validation of tokens representing numeric types so as to  catch
any errors prior  to the costly  process of the  main compilation step
commencing.

(4) Bracket Check (e_bracket_check)
Enable  the  check for  validating  the ordering  of  brackets in  the
specified expression.

(5) Sequence Check (e_sequence_check)
Enable the  check for  validating that  sequences of  either pairs  or
triplets of tokens make sense.  For example the following sequence  of
tokens when encountered will raise an error:

   (a) (x + * 3)  --->  sequence error

(6) Commutative Check (e_commutative_check)
Enable the check that will transform sequences of pairs of tokens that
imply a multiplication operation.  The following are some  examples of
such transformations:

   (a) 2x             --->  2 * x
   (b) 25x^3          --->  25 * x^3
   (c) 3(x + 1)       --->  3 * (x + 1)
   (d) (x + 1)4       --->  (x + 1) * 4
   (e) 5foo(x,y)      --->  5 * foo(x,y)
   (f) foo(x,y)6 + 1  --->  foo(x,y) * 6 + 1
   (g) (4((2x)3))     --->  4 * ((2 * x) * 3)
   (h) w(x) + (y)z    --->  w * x + y * z

(7) Strength Reduction Check (e_strength_reduction)
Enable  the  use  of  strength  reduction  optimisations  during   the
compilation  process.  In  ExprTk  strength  reduction   optimisations
predominantly involve  transforming sub-expressions  into other  forms
that  are algebraically  equivalent yet  less costly  to compute.  The
following are examples of the various transformations that can occur:

   (a) (x / y) / z        --->  x / (y * z)
   (b) (x / y) / (z / w)  --->  (x * w) / (y * z)
   (c) (2 * x) - (2 * y)  --->  2 * (x - y)
   (d) (2 / x) / (3 / y)  --->  (2 / 3) / (x * y)
   (e) (2 * x) * (3 * y)  --->  (2 * 3) * (x * y)

Note:
When using  strength reduction  in conjunction  with expressions whose
inputs or sub-expressions may result  in values nearing either of  the
bounds of the underlying numeric  type (eg: double), there may  be the
possibility of a decrease in the precision of results.

In  the following  example the  given expression  which represents  an
attempt at computing the average  between x and y will  be transformed
as follows:

   (0.5 * x) + (y * 0.5) ---> 0.5 * (x + y)

There  may be  situations where  the above  transformation will  cause
numerical overflows and  that the original  form of the  expression is
desired over the strength reduced form. In these situations it is best
to turn off strength reduction optimisations  or to use a type with  a
larger numerical bound.

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 07 - EXPRESSION STRUCTURES]
Exprtk supports mathematical expressions in numerous forms based on  a
simple  imperative  programming  model. This  section  will  cover the
following  topics  related  to general  structure  and  programming of
expression using ExprTk:

   (1) Multi-Statement Expressions
   (2) Statements And Side-Effects
   (3) Conditional Statements
   (4) Special Functions

(1) Multi-Statement Expressions
Expressions in ExprTk can be  comprised of one more statements,  which
may  sometimes  be  called  sub-expressions.  The  following  are  two
examples of expressions stored  in std::string variables, the  first a
single statement and the second a multi-statement expression:

   std::string single_statement = " z := x + y ";

   std::string multi_statement  = " var temp := x; "
                                  " x := y + z;    "
                                  " y := temp;     ";

In a  multi-statement expression,  the final  statement will determine
the overall result of the expression. In the following multi-statement
expression, the result of the expression when evaluated will be '2.3',
which will also be the value stored in the 'y' variable.

   z := x + y;
   y := 2.3;

As  demonstrated  in  the  expression  above,  statements  within   an
expression are  separated using  the semi-colon  ';' operator.  In the
event  two  statements are  not  separated by  a  semi-colon, and  the
implied multiplication  feature is  active (enabled  by default),  the
compiler  will  assume  a  multiplication  operation  between  the two
statements.

In the following example we have a multi-statement expression composed
of two variable definitions and initialisations for variables x and  y
and two seemingly separate mathematical operations.

   var x:= 2;
   var y:= 3;
   x + 1
   y * 2

However the result of  the expression will not  be 6 as may  have been
assumed based on  the calculation of  'y * 2',  but rather the  result
will be 8. This  is because the compiler  will have conjoined the  two
mathematical statements into one  via a multiplication operation.  The
expression when compiled will actually evaluate as the following:

   var x:= 2;
   var y:= 3;
   x + 1 * y * 2;   // 2 + 1 * 3 * 2 == 8

In ExprTk any valid statement  will itself return a value.  This value
can  further  be  used  in  conjunction  with  other  statements. This
includes language structures such as if-statements, loops (for, while)
and the switch statement. Typically the last statement executed in the
given construct  (conditional, loop  etc), will  be the  value that is
returned.

In the following example, the  return value of the expression  will be
11, which is the sum of the variable 'x' and the final value  computed
within the loop body on its last iteration:

   var x := 1;
   x + for (var i := x; i < 10; i += 1)
       {
         i / 2;
         i + 1;
       }

(2) Statements And Side-Effects
Statements themselves may have side effects, which in-turn effect  the
proceeding statements in multi-statement expressions.

A statement is said  to have a side-effect  if it causes the  state of
the  expression to  change in  some way  -  this  includes but  is not
limited to the  modification of the  state of external  variables used
within the expression. Currently  the following actions being  present
in a statement will cause it to have a side-effect:

   (a) Assignment operation (explicit or potentially)
   (b) Invoking a user-defined function that has side-effects

The following are examples of expressions where the side-effect status
of the statements (or sub-exressions) within the expressions have been
noted:

  +-+----------------------+------------------------------+
  |#|      Expression      |      Side Effect Status      |
  +-+----------------------+------------------------------+
  |0| x + y                | False                        |
  +-+----------------------+------------------------------+
  |1| z := x + y           | True - Due to assignment     |
  +-+----------------------+------------------------------+
  |2| abs(x - y)           | False                        |
  +-+----------------------+------------------------------+
  |3| abs(x - y);          | False                        |
  | | z := (x += y);       | True - Due to assignments    |
  +-+----------------------+------------------------------+
  |4| abs(x - y);          | False                        |
  | | z := (x += y);       | True - Due to assignments    |
  +-+----------------------+------------------------------+
  |5| var t := abs(x - y); | True - Due to initialisation |
  | | t + x;               | False                        |
  | | z := (x += y);       | True - Due to assignments    |
  +-+----------------------+------------------------------+
  |6| foo(x - y)           | True - user defined function |
  +-+----------------------+------------------------------+

Note: In example 6 from the above set, it is assumed the user  defined
function foo has been registered  as having a side_effect. By  default
all user defined  functions are assumed  to have side-effects,  unless
they are  configured in  their constructors  to not  have side-effects
using   the   'disable_has_side_effects'  free   function.   For  more
information review  Section 15 - User Defined Functions  sub-section 7
Function Side-Effects.

At this point we  can see that there  will be expressions composed  of
certain kinds  of statements  that when  executed will  not effect the
nature  of the  expression's  result.  These statements  are typically
called 'dead code'.  These statements though  not effecting the  final
result will still be executed and as such they will consume processing
time that could otherwise be saved. As such ExprTk attempts to  detect
and remove such statements from expressions.

The  'Dead  Code  Elimination' (DCE)  optimisation  process,  which is
enabled by default, will remove any statements that are determined  to
not have a side effect in a multi-statement expression, excluding  the
final or last statement.

By default the final statement in an expression will always be present
regardless of  its side-effect  status, as  it is  the statement whose
value will be used as the result of the expression.

In order to further explain the actions taken during the DCE  process,
lets review the following expression:

   var x := 2;      // Statement 1
   var y := x + 2;  // Statement 2
   x + y;           // Statement 3
   y := x + 3y;     // Statement 4
   x - y;           // Statement 5

The above expression has five statements.  Three of them (1, 2 and  4)
actively have side-effects. The first two are variable declaration and
initialisations, where as the third is due to an assignment operation.
There  are  two  statements (3  and 5),  that do  not explicitly  have
side-effects, however the latter, statement 5, is the final  statement
in the expression and hence will be assumed to have a side-effect.

During compilation when the DCE  optimisation is applied to the  above
expression, statement 3 will be removed from the expression, as it has
no  bearing  on  the  final result  of  expression,  the  rest of  the
statements will all remain. The optimised form of the expression is as
follows:

   var x := 2;      // Statement 1
   var y := x + 2;  // Statement 2
   y := x + 3y;     // Statement 3
   x - y;           // Statement 4

(3) Conditional Statements (If-Then-Else)
ExprTk support two forms  of conditional branching or  otherwise known
as  if-statements.  The  first  form,  is  a  simple  function   based
conditional  statement, that  takes exactly  three input  expressions:
condition, consequent  and alternative.  The following  is an  example
expression that utilizes the function based if-statement.

   x := if (y < z, y + 1, 2* z)

In the  example above,  if the  condition 'y  < z'  is true,  then the
consequent 'y + 1' will be evaluated, its value will be  returned  and
subsequently assigned to the  variable 'x'. Otherwise the  alternative
'2 *  z' will  be evaluated  and its  value will  be returned. This is
essentially the  simplest form of  an if-then-else statement. A simple
variation of  the expression  where the  value of  the if-statement is
used within another statement is as follows:

   x := 3 * if (y < z, y + 1, 2* z) / 2

The second form of if-statement resembles the standard syntax found in
most imperative languages. There are two variations of the statement:

   (a) If-Statement
   (b) If-Then-Else Statement

(a) If-Statement
This version  of the  conditional statement  returns the  value of the
consequent expression when the  condition expression is true,  else it
will return a quiet NaN value as its result.

   Example 1:
   x := if (y < z) y + 3;

   Example 2:
   x := if (y < z)
        {
          y + 3
        }

The two  example expressions  above are  equivalent. If  the condition
'y < z' is true, the  'x' variable will be  assigned the value of  the
consequent 'y + 3', otherwise it  will be assigned the value of  quiet
NaN.  As  previously  discussed,  if-statements  are  value  returning
constructs, and if  not properly terminated  using a semi-colon,  will
end-up  combining  with  the  next  statement  via  a   multiplication
operation. The following example will NOT result in the expected value
of 'w + x' being returned:

   x := if (y < z) y + 3  // missing semi-colon ';'
   w + x

When the  above supposed  multi-statement expression  is compiled, the
expression  will  have  a  multiplication  inserted  between  the  two
'intended' statements resulting in the unanticipated expression:

   x := (if (y < z) y + 3) * w + x

The  solution  to  the  above situation  is  to  simply  terminate the
conditional statement with a semi-colon as follows:

   x := if (y < z) y + 3;
   w + x

(b) If-Then-Else Statement
The second variation of  the if-statement is to  allow for the use  of
Else and If-Else cascading statements. Examples of such statements are
as follows:

   Example 1:           Example 2:
   if (x < y)           if (x < y)
     z := x + 3;        {
   else                   y := z + x;
     y := x - z;          z := x + 3;
                        }
                        else
                          y := x - z;

   Example 3:           Example 4:
   if (x > y + 1)       if (2 * x < max(y,3))
     y := abs(x - z);   {
   else                   y := z + x;
   {                      z := x + 3;
     y := z + x;        }
     z := x + 3;        else if (2y - z)
   };                     y := x - z;

   Example 5:           Example 6:
   if (x < y)           if (x < y or (x + z) > y)
     z := x + 3;        {
   else if (2y != z)      z := x + 3;
   {                      y := x - z;
     z := x + 3;        }
     y := x - z;        else if (abs(2y - z) >= 3)
   }                       y := x - z;
   else                 else
     x * x;             {
                           z := abs(x * x);
                           x * y * z;
                        };

In  the case  where  there  is no  final else  statement and  the flow
through the conditional  arrives at this  final point, the  same rules
apply to this form of if-statement as to the previous. That is a quiet
NaN will be  returned as the  result of the  if-statement. Furthermore
the same requirements of  terminating the statement with  a semi-colon
apply.

(4) Special Functions
The purpose  of special  functions in  ExprTk is  to provide  compiler
generated equivalents of common mathematical expressions which can  be
invoked by  using the  'special function'  syntax (eg:  $f12(x,y,z) or
$f82(x,y,z,w)).

Special functions dramatically decrease  the total evaluation time  of
expressions which would otherwise  have been written using  the common
form by reducing the total number  of nodes in the evaluation tree  of
an  expression  and  by  also  leveraging  the  compiler's  ability to
correctly optimize such expressions for a given architecture.

          3-Parameter                       4-Parameter
 +-------------+-------------+    +--------------+------------------+
 |  Prototype  |  Operation  |    |  Prototype   |    Operation     |
 +-------------+-------------+    +--------------+------------------+
   $f00(x,y,z) | (x + y) / z       $f48(x,y,z,w) | x + ((y + z) / w)
   $f01(x,y,z) | (x + y) * z       $f49(x,y,z,w) | x + ((y + z) * w)
   $f02(x,y,z) | (x + y) - z       $f50(x,y,z,w) | x + ((y - z) / w)
   $f03(x,y,z) | (x + y) + z       $f51(x,y,z,w) | x + ((y - z) * w)
   $f04(x,y,z) | (x - y) + z       $f52(x,y,z,w) | x + ((y * z) / w)
   $f05(x,y,z) | (x - y) / z       $f53(x,y,z,w) | x + ((y * z) * w)
   $f06(x,y,z) | (x - y) * z       $f54(x,y,z,w) | x + ((y / z) + w)
   $f07(x,y,z) | (x * y) + z       $f55(x,y,z,w) | x + ((y / z) / w)
   $f08(x,y,z) | (x * y) - z       $f56(x,y,z,w) | x + ((y / z) * w)
   $f09(x,y,z) | (x * y) / z       $f57(x,y,z,w) | x - ((y + z) / w)
   $f10(x,y,z) | (x * y) * z       $f58(x,y,z,w) | x - ((y + z) * w)
   $f11(x,y,z) | (x / y) + z       $f59(x,y,z,w) | x - ((y - z) / w)
   $f12(x,y,z) | (x / y) - z       $f60(x,y,z,w) | x - ((y - z) * w)
   $f13(x,y,z) | (x / y) / z       $f61(x,y,z,w) | x - ((y * z) / w)
   $f14(x,y,z) | (x / y) * z       $f62(x,y,z,w) | x - ((y * z) * w)
   $f15(x,y,z) | x / (y + z)       $f63(x,y,z,w) | x - ((y / z) / w)
   $f16(x,y,z) | x / (y - z)       $f64(x,y,z,w) | x - ((y / z) * w)
   $f17(x,y,z) | x / (y * z)       $f65(x,y,z,w) | ((x + y) * z) - w
   $f18(x,y,z) | x / (y / z)       $f66(x,y,z,w) | ((x - y) * z) - w
   $f19(x,y,z) | x * (y + z)       $f67(x,y,z,w) | ((x * y) * z) - w
   $f20(x,y,z) | x * (y - z)       $f68(x,y,z,w) | ((x / y) * z) - w
   $f21(x,y,z) | x * (y * z)       $f69(x,y,z,w) | ((x + y) / z) - w
   $f22(x,y,z) | x * (y / z)       $f70(x,y,z,w) | ((x - y) / z) - w
   $f23(x,y,z) | x - (y + z)       $f71(x,y,z,w) | ((x * y) / z) - w
   $f24(x,y,z) | x - (y - z)       $f72(x,y,z,w) | ((x / y) / z) - w
   $f25(x,y,z) | x - (y / z)       $f73(x,y,z,w) | (x * y) + (z * w)
   $f26(x,y,z) | x - (y * z)       $f74(x,y,z,w) | (x * y) - (z * w)
   $f27(x,y,z) | x + (y * z)       $f75(x,y,z,w) | (x * y) + (z / w)
   $f28(x,y,z) | x + (y / z)       $f76(x,y,z,w) | (x * y) - (z / w)
   $f29(x,y,z) | x + (y + z)       $f77(x,y,z,w) | (x / y) + (z / w)
   $f30(x,y,z) | x + (y - z)       $f78(x,y,z,w) | (x / y) - (z / w)
   $f31(x,y,z) | x * y^2 + z       $f79(x,y,z,w) | (x / y) - (z * w)
   $f32(x,y,z) | x * y^3 + z       $f80(x,y,z,w) | x / (y + (z * w))
   $f33(x,y,z) | x * y^4 + z       $f81(x,y,z,w) | x / (y - (z * w))
   $f34(x,y,z) | x * y^5 + z       $f82(x,y,z,w) | x * (y + (z * w))
   $f35(x,y,z) | x * y^6 + z       $f83(x,y,z,w) | x * (y - (z * w))
   $f36(x,y,z) | x * y^7 + z       $f84(x,y,z,w) | x*y^2 + z*w^2
   $f37(x,y,z) | x * y^8 + z       $f85(x,y,z,w) | x*y^3 + z*w^3
   $f38(x,y,z) | x * y^9 + z       $f86(x,y,z,w) | x*y^4 + z*w^4
   $f39(x,y,z) | x * log(y)+z      $f87(x,y,z,w) | x*y^5 + z*w^5
   $f40(x,y,z) | x * log(y)-z      $f88(x,y,z,w) | x*y^6 + z*w^6
   $f41(x,y,z) | x * log10(y)+z    $f89(x,y,z,w) | x*y^7 + z*w^7
   $f42(x,y,z) | x * log10(y)-z    $f90(x,y,z,w) | x*y^8 + z*w^8
   $f43(x,y,z) | x * sin(y)+z      $f91(x,y,z,w) | x*y^9 + z*w^9
   $f44(x,y,z) | x * sin(y)-z      $f92(x,y,z,w) | (x and y) ? z : w
   $f45(x,y,z) | x * cos(y)+z      $f93(x,y,z,w) | (x or  y) ? z : w
   $f46(x,y,z) | x * cos(y)-z      $f94(x,y,z,w) | (x <   y) ? z : w
   $f47(x,y,z) | x ? y : z         $f95(x,y,z,w) | (x <=  y) ? z : w
                                   $f96(x,y,z,w) | (x >   y) ? z : w
                                   $f97(x,y,z,w) | (x >=  y) ? z : w
                                   $f98(x,y,z,w) | (x ==  y) ? z : w
                                   $f99(x,y,z,w) | x*sin(y)+z*cos(w)

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 08 - VARIABLE, VECTOR & STRING DEFINITION]
ExprTk supports the definition of expression local variables,  vectors
and  strings.  The definitions  must  be unique  as  shadowing is  not
allowed and object life-times are based on scope. Definitions use  the
following general form:

   var <name> := <initialiser>;

(1) Variable Definition
Variables are  of numeric  type denoting  a single  value. They can be
explicitly initialised to a value, otherwise they will be defaulted to
zero. The following are examples of variable definitions:

   (a) Initialise x to zero
       var x;

   (b) Initialise y to three
       var y := 3;

   (c) Initialise z to the expression
       var z := if (max(1,x + y) > 2,w,v);

(2) Vector Definition
Vectors are arrays of a common numeric type. The elements in a  vector
can be explicitly initialised, otherwise they will all be defaulted to
zero. The following are examples of vector definitions:

   (a) Initialise all values to zero
       var x[3];

   (b) Initialise all values to zero
       var x[3] := {};

   (c) Initialise all values to given expression
       var x[3] := [123 + 3y + sin(w/z)];

   (d) Initialise the first two values, all other elements to zero
       var x[3] := { 1 + x[2], sin(y[0] / x[]) + 3 };

   (e) Initialise the first three (all) values
       var x[3] := { 1, 2, 3 };

   (f) Initialise vector from a vector
       var x[4] := { 1, 2, 3, 4 };
       var y[3] := x;

   (g) Initialise vector from a smaller vector
       var x[3] := { 1, 2, 3 };
       var y[5] := x;   // 1, 2, 3, ??, ??

   (h) Non-initialised vector
       var x[3] := null; // ?? ?? ??

   (i) Error as there are too many initialisers
       var x[3] := { 1, 2, 3, 4 };

   (j) Error as a vector of size zero is not allowed.
       var x[0];

(3) String Definition
Strings are sequences comprised of 8-bit characters. They can only be
defined  with an explicit  initialisation  value. The  following  are
examples of string variable definitions:

   (a) Initialise to a string
       var x := 'abc';

   (b) Initialise to a string expression
       var x := 'abc' + '123';

   (c) Initialise to a string range
       var x := 'abc123'[2:4];

   (d) Initialise to another string variable
       var x := 'abc';
       var y := x;

   (e) Initialise to another string variable range
       var x := 'abc123';
       var y := x[2:4];

   (f) Initialise to a string expression
       var x := 'abc';
       var y := x + '123';

   (g) Initialise to a string expression range
       var x := 'abc';
       var y := (x + '123')[1:3];

(4) Return Value
Variable and vector  definitions have a  return value. In  the case of
variable definitions, the value  to which the variable  is initialised
will be returned. Where as for vectors, the value of the first element
(eg: v[0]) will be returned.

   8 == ((var x := 7;) + 1)
   4 == (var y[3] := {4, 5, 6};)

(5) Variable/Vector Assignment
The value of a variable can be assigned to a vector and a vector or  a
vector expression can be assigned to a variable.

  (a) Variable To Vector:
      Every element of the vector is assigned the value of the variable
      or expression.
      var x    := 3;
      var y[3] := { 1, 2, 3 };
      y := x + 1;

  (b) Vector To Variable:
      The variable is assigned the value of the first element of the
      vector (aka vec[0])
      var x    := 3;
      var y[3] := { 1, 2, 3 };
      x := y + 1;

Note: During the expression  compilation phase, tokens are  classified
based on the following priorities:

   (a) Reserved keywords or operators (+, -, and, or, etc)
   (b) Base functions (abs, sin, cos, min, max etc)
   (c) Symbol table variables
   (d) Expression local defined variables
   (e) Symbol table functions
   (f) Unknown symbol resolver based variables

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 09 - VECTOR PROCESSING]
ExprTk  provides  support  for   various  forms  of  vector   oriented
arithmetic, inequalities and  processing. The various  supported pairs
are as follows:

   (a) vector and vector (eg: v0 + v1)
   (b) vector and scalar (eg: v  + 33)
   (c) scalar and vector (eg: 22 *  v)

The following is a list of operations that can be used in  conjunction
with vectors:

   (a) Arithmetic:       +, -, *, /, %
   (b) Exponentiation:   vector ^ scalar
   (c) Assignment:       :=, +=, -=, *=, /=, %=, <=>
   (d) Inequalities:     <, <=, >, >=, ==, =, equal
   (e) Boolean logic:    and, nand, nor, or, xnor, xor
   (f) Unary operations:
       abs, acos, acosh, asin, asinh, atan, atanh, ceil, cos,  cosh,
       cot, csc,  deg2grad, deg2rad,  erf, erfc,  exp, expm1, floor,
       frac, grad2deg, log, log10, log1p, log2, rad2deg, round, sec,
       sgn, sin, sinc, sinh, sqrt, swap, tan, tanh, trunc
   (g) Aggregate and Reduce operations:
       avg, max, min, mul,  dot, dotk, sum, sumk,  count, all_true,
       all_false, any_true, any_false
   (h) Transformation operations:
       copy, rotate-left/right, shift-left/right, sort, nth_element
   (i) BLAS-L1:
       axpy, axpby, axpyz, axpbyz, axpbz

Note: When one of  the above  described operations  is being performed
between two  vectors, the  operation will  only span  the size  of the
smallest vector.  The elements  of the  larger vector  outside of  the
range will  not be included. The  operation  itself will  be processed
element-wise over values the smaller of the two ranges.

The  following  simple  example  demonstrates  the  vector  processing
capabilities by computing the dot-product of the vectors v0 and v1 and
then assigning it to the variable v0dotv1:

   var v0[3] := { 1, 2, 3 };
   var v1[3] := { 4, 5, 6 };
   var v0dotv1 := sum(v0 * v1);

The following is a for-loop based implementation that is equivalent to
the previously mentioned dot-product computation expression:

   var v0[3] := { 1, 2, 3 };
   var v1[3] := { 4, 5, 6 };
   var v0dotv1;

   for (var i := 0; i < min(v0[],v1[]); i += 1)
   {
     v0dotv1 += (v0[i] * v1[i]);
   }

Note: When  the aggregate or reduction  operations denoted  above  are
used  in conjunction with a  vector or  vector  expression, the return
value is not a vector but rather a single value.

   var x[3] := { 1, 2, 3 };

   sum(x)      ==  6
   sum(1 + 2x) == 15
   avg(3x + 1) ==  7
   min(1 / x)  == (1 / 3)
   max(x / 2)  == (3 / 2)
   sum(x > 0 and x < 5) == x[]

When utilizing external user defined  vectors via the symbol table  as
opposed to expression local defined vectors, the typical  'add_vector'
method from the symbol table will register the entirety of the  vector
that is passed. The following example attempts to evaluate the sum  of
elements of  the external  user defined  vector within  a typical  yet
trivial expression:

   std::string reduce_program = " sum(2 * v + 1) ";

   std::vector<T> v0 { T(1.1), T(2.2), ..... , T(99.99) };

   symbol_table_t symbol_table;
   symbol_table.add_vector("v",v);

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   parser_t parser;
   parser.compile(reduce_program,expression);

   T sum = expression.value();

For the most part, this is  a very common use-case. However there  may
be situations where one may want to evaluate the same vector  oriented
expression many times over, but using different vectors or sub  ranges
of the same vector of the same size to that of the original upon every
evaluation.

The usual solution is to  either recompile the expression for  the new
vector instance, or to  copy the contents from  the new vector to  the
symbol table registered vector  and then perform the  evaluation. When
the  vectors are  large or  the re-evaluation  attempts are  numerous,
these  solutions  can  become  rather  time  consuming  and  generally
inefficient.

   std::vector<T> v1 { T(2.2), T(2.2), ..... , T(2.2) };
   std::vector<T> v2 { T(3.3), T(3.3), ..... , T(3.3) };
   std::vector<T> v3 { T(4.4), T(4.4), ..... , T(4.4) };

   std::vector<std::vector<T>> vv { v1, v2, v3 };
   ...
   T sum = T(0);

   for (auto& new_vec : vv)
   {
      v = new_vec; // update vector
      sum += expression.value();
   }

A  solution  to  the  above  'efficiency'  problem,  is  to  use   the
exprtk::vector_view  object. The  vector_view is  instantiated with  a
size and backing based upon a vector. Upon evaluations if the  backing
needs  to  be  'updated' to  either another  vector or  sub-range, the
vector_view instance  can be  efficiently rebased,  and the expression
evaluated as normal.

   exprtk::vector_view<T> view = exprtk::make_vector_view(v, v.size());

   symbol_table_t symbol_table;
   symbol_table.add_vector("v",view);

   ...

   T sum = T(0);

   for (auto& new_vec : vv)
   {
      view.rebase(new_vec.data()); // update vector
      sum += expression.value();
   }

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 10 - EXPRESSION DEPENDENTS]
Any  expression  that  is  not  a  literal  (aka  constant)  will have
dependencies. The types of  'dependencies' an expression can  have are
as follows:

   (a) Variables
   (b) Vectors
   (c) Strings
   (d) Functions
   (e) Assignments

In  the  following  example the  denoted  expression  has its  various
dependencies listed:

   z := abs(x + sin(2 * pi / y))

   (a) Variables:   x, y, z and pi
   (b) Functions:   abs, sin
   (c) Assignments: z

ExprTk allows for  the derivation of  expression dependencies via  the
'dependent_entity_collector'  (DEC).  When  activated  either  through
'compile_options' at the construction  of the parser or  through calls
to enabler methods just prior to compilation, the DEC will proceed  to
collect any  of the  relevant types  that are  encountered during  the
parsing  phase.   Once  the   compilation  process   has  successfully
completed, the  caller can  then obtain  a list  of symbols  and their
associated types from the DEC.

The kinds of  questions one can  ask regarding the  dependent entities
within an expression are as follows:

  * What user defined variables, vectors or strings are used?
  * What functions or custom user functions are used?
  * Which variables, vectors or strings have values assigned to them?

The following example demonstrates usage of the DEC in determining the
dependents of the given expression:

   typedef typename parser_t::
      dependent_entity_collector::symbol_t symbol_t;

   std::string expression_string =
                  "z := abs(x + sin(2 * pi / y))";

   T x,y,z;

   parser_t parser;
   symbol_table_t symbol_table;

   symbol_table.add_variable("x",x);
   symbol_table.add_variable("y",y);
   symbol_table.add_variable("z",z);

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   //Collect only variable and function symbols
   parser.dec().collect_variables() = true;
   parser.dec().collect_functions() = true;

   if (!parser.compile(expression_string,expression))
   {
      // error....
   }

   std::deque<symbol_t> symbol_list;

   parser.dec().symbols(symbol_list);

   for (std::size_t i = 0; i < symbol_list.size(); ++i)
   {
      symbol_t& symbol = symbol_list[i];

      switch (symbol.second)
      {
         case parser_t::e_st_variable : ... break;
         case parser_t::e_st_vector   : ... break;
         case parser_t::e_st_string   : ... break;
         case parser_t::e_st_function : ... break;
      }
   }

Note: The 'symbol_t' type is a std::pair comprising of the symbol name
(std::string) and the associated type of the symbol as denoted by  the
cases in the switch statement.

Having  particular  symbols  (variable  or  function)  present  in  an
expression is one form of dependency. Another and just as  interesting
and important type of  dependency is that of  assignments. Assignments
are the set of dependent symbols that 'may' have their values modified
within an expression. The following are example expressions and  their
associated assignments:

       Assignments   Expression
   (1) x             x := y + z
   (2) x, y          x += y += z
   (3) x, y, z       x := y += sin(z := w + 2)
   (4) w, z          if (x > y, z := x + 2, w := 'A String')
   (5) None          x + y + z

Note: In expression 4, both variables 'z' and 'w' are denoted as being
assignments even though only one of  them can ever be modified at  the
time of evaluation. Furthermore the determination of which of the  two
variables the  modification will  occur upon  can only  be known  with
certainty at evaluation time and not beforehand, hence both are listed
as being candidates for assignment.

The following builds upon the previous example demonstrating the usage
of the DEC in determining the 'assignments' of the given expression:

   //Collect assignments
   parser.dec().collect_assignments() = true;

   if (!parser.compile(expression_string,expression))
   {
      // error....
   }

   std::deque<symbol_t> symbol_list;

   parser.dec().assignment_symbols(symbol_list);

   for (std::size_t i = 0; i < symbol_list.size(); ++i)
   {
      symbol_t& symbol = symbol_list[i];

      switch (symbol.second)
      {
         case parser_t::e_st_variable : ... break;
         case parser_t::e_st_vector   : ... break;
         case parser_t::e_st_string   : ... break;
      }
   }

Note: The assignments will only consist of variable types and as  such
will not contain symbols denoting functions.

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 11 - HIERARCHIES OF SYMBOL TABLES]
Most situations will only require a single symbol_table instance to be
associated with a given expression instance.

However as an expression can have more than one symbol table  instance
associated  with  itself,  when  building  more  complex  systems that
utilize many expressions  where each can  in turn utilize  one or more
variables  from  a  large set  of  potential  variables, functions  or
constants, it becomes evident  that grouping variables into  layers of
symbol_tables will simplify and streamline the overall process.

A suggested hierarchy of symbol tables is as follows:

   (a) Global constant value symbol table
   (b) Global non side-effect functions symbol table
   (c) Global variable symbol table
   (d) Expression specific variable symbol table

(a) Global constant value symbol table
This symbol table will  contain constant variables denoting  immutable
values. These variables can be made available to all expressions,  and
in turn expressions  will assume the  values themselves will  never be
modified for the  duration of the  process run-time. Examples  of such
variables are:

   (1) pi or e
   (2) speed_of_light
   (3) avogadro_number
   (4) num_cpus

(b) Global non side-effect functions symbol table
This symbol table will contain  only user defined functions that  will
not incur any side-effects that are visible to any of the  expressions
that invoke  them. These  functions will  be thread-safe  or threading
invariant and will not maintain any form of state between invocations.
Examples of such functions are:

   (1) calc_volume_of_sphere(r)
   (2) distance(x0,y0,x1,y1)

(c) Global variable symbol table
This symbol table  will contain variables  that will be  accessible to
all associated expressions  and will not  be specific or  exclusive to
any one expression. This variant  differs from (a) in that  the values
of the  variables can  change (or  be updated)  between evaluations of
expressions  -   but  through   properly  scheduled   evaluations  are
guaranteed  to never  change during  the evaluation  of any  dependent
expressions. Furthermore it  is assumed that  these variables will  be
used in a  read-only context and  that no expressions  will attempt to
modify these variables via assignments or other means.

   (1) price_of_stock_xyz
   (2) outside_temperature or inside_temperature
   (3) fuel_in_tank
   (4) num_customers_in_store
   (5) num_items_on_shelf

(d) Expression specific variable symbol table
This  symbol_table  is  the most  common form,  and is  used to  store
variables that are specific and exclusive to a particular  expression.
That is to say references  to variables in this symbol_table  will not
be  part of  another expression.  Though it  may be  possible to  have
expressions that  contain the  variables with  the same  name, in that
case those variables will be distinctly different. Which would mean if
a particular  expression were  to be  compiled twice,  each expression
would have its  own unique symbol_table  which in turn  would have its
own instances of those variables. Examples of such variables could be:

   (1) x or y
   (2) customer_name

The  following is  a diagram  depicting the  possible version  of the
denoted symbol table hierarchies. In the diagram there are two  unique
expressions, each of  which have a  reference to the  Global constant,
functions and variables symbol tables and an exclusive reference to  a
local symbol table.

  +-------------------------+    +-------------------------+
  |     Global Constants    |    |     Global Functions    |
  |       Symbol Table      |    |       Symbol Table      |
  +----o--o-----------------+    +--------------------o----+
       |  |                                           |
       |  |                                           +-------+
       |  +------------------->----------------------------+  |
       |         +----------------------------+            |  |
       |         |      Global Variables      |            |  |
       |  +------o        Symbol Table        o-----+      |  V
       |  |      +----------------------------+     |      |  |
       |  |                                         |      |  |
       |  | +----------------+   +----------------+ |      |  |
       |  | | Symbol Table 0 |   | Symbol Table 1 | |      V  |
       |  | +--o-------------+   +--o-------------+ |      |  |
       |  |    |                    |               |      |  |
       |  |    |                    |               |      |  |
    +--V--V----V---------+        +-V---------------V--+   |  |
    |    Expression 0    |        |    Expression 1    |<--+--+
    |  '2 * sin(x) - y'  |        |  'k + abs(x - y)'  |
    +--------------------+        +--------------------+

Bringing  all of  the above  together, in  the following  example the
hierarchy  of  symbol  tables  are  instantiated  and  initialised. An
expression that makes use of various elements of each symbol table  is
then compiled and later on evaluated:

   typedef exprtk::symbol_table<double> symbol_table_t;
   typedef exprtk::expression<double>     expression_t;

   // Setup global constants symbol table
   symbol_table_t glbl_const_symbol_table;
   glbl_const_symbtab.add_constants(); // pi, epsilon and inf
   glbl_const_symbtab.add_constant("speed_of_light",299e6);
   glbl_const_symbtab.add_constant("avogadro_number",6e23);

   // Setup global function symbol table
   symbol_table_t glbl_funcs_symbol_table;
   glbl_func_symbtab.add_function('distance',distance);
   glbl_func_symbtab.add_function('calc_spherevol',calc_sphrvol);

   ......

   // Setup global variable symbol table
   symbol_table_t glbl_variable_symbol_table;
   glbl_variable_symbtab.add_variable('temp_outside',thermo.outside);
   glbl_variable_symbtab.add_variable('temp_inside' ,thermo.inside );
   glbl_variable_symbtab.add_variable('num_cstmrs',store.num_cstmrs);

   ......

   double x,y,z;

   // Setup expression specific symbol table
   symbol_table_t symbol_table;
   symbol_table.add_variable('x',x);
   symbol_table.add_variable('y',y);
   symbol_table.add_variable('z',z);

   expression_t expression;

   // Register the various symbol tables
   expression
      .register_symbol_table(symbol_table);

   expression
      .register_symbol_table(glbl_funcs_symbol_table);

   expression
      .register_symbol_table(glbl_const_symbol_table);

   expression
      .register_symbol_table(glbl_variable_symbol_table);

   std::string expression_str =
      "abs(temp_inside - temp_outside) + 2 * speed_of_light / x";

   parser_t parser;
   parser.compile(expression_str,expression);

   ......

   while (keep_evaluating)
   {
     ....

     T result = expression.value();

     ....
   }

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 12 - UNKNOWN UNKNOWNS]
In this section  we will discuss  the process of  handling expressions
with a mix of known and unknown variables. Initially a discussion into
the types of expressions that exist will be provided, then a series of
possible solutions will be presented for each scenario.

When parsing an expression, there  may be situations where one  is not
fully  aware  of what  if  any variables  will  be used  prior  to the
expression being compiled.

This can become problematic, as in the default scenario it is  assumed
the symbol_table that is registered with the expression instance  will
already  posses  the  externally  available  variables,  functions and
constants needed during the compilation of the expression.

In the event there are symbols in the expression that can't be  mapped
to   either   a  reserved   word,   or  located   in   the  associated
symbol_table(s), an "Undefined  symbol" error will  be raised and  the
compilation process will fail.

The numerous  scenarios that  can occur  when compiling  an expression
with ExprTk generally fall into one of the following three categories:

   (a) No external variables
   (b) Predetermined set of external variables
   (c) Unknown set of variables

(a) No external variables
These  are  expressions that  contain  no external  variables  but may
contain  local  variables.  As  local  variables  cannot  be  accessed
externally from the  expression, it is  assumed that such  expressions
will not have  a need for  a symbol_table and  furthermore expressions
which  don't  make  use of  functions that  have side-effects  will be
evaluated completely at  compile time resulting  in a constant  return
value. The following are examples of such expressions:

   (1) 1 + 2
   (2) var x := 3; 2 * x - 3
   (3) var x := 3; var y := abs(x - 8); x - y / 7

(b) Predetermined set of external variables
These  are  expressions  that are  comprised  of  externally available
variables  and functions  and will  only compile  successfully if  the
symbols that  correspond to  the variables  and functions  are already
defined in their associated symbol_table(s).  This is by far the  most
common scenario when using ExprTk.

As an example, one may have three external variables: x, y and z which
have been registered with  the associated symbol_table, and  will then
need to compile  and evaluate expressions  comprised of any  subset of
these  three  variables. The  following  are a  few  examples of  such
expressions:

   (1) 1 + x
   (2) x / y
   (3) 2 * x * y / z

In  this  scenario   one  can  use   the  'dependent_entity_collector'
component as described in [Section  16] to further determine which  of
the registered variables were  actually used in the  given expression.
As  an example  once the  set of  utilized  variables  are known,  any
further 'attention'  can be  restricted to  only those  variables when
evaluating the expression. This can be quite useful when dealing  with
expressions that can draw from a set of hundreds or even thousands  of
variables.

(c) Unknown set of variables
These are  expressions that  are comprised  of symbols  other than the
standard ExprTk reserved words or what has been registered with  their
associated symbol_table, and will normally fail compilation due to the
associated symbol_table not having a  reference to them. As such  this
scenario can be  seen as a  combination of scenario  B, where one  may
have a symbol_table with registered variables, but would also like  to
handle  the  situation  of  variables  that  aren't  present  in  said
symbol_table.

When dealing with expressions of category (c), one must perform all of
the following:

   (1) Determine the variables used in the expression
   (2) Populate a symbol_table(s) with the entities from (1)
   (3) Compile the expression
   (4) Provide a means by which the entities from (1) can be modified

Depending on the nature of processing,  steps (1) and (2) can be  done
either independently of each other or combined into one. The following
example  will  initially  look  at  solving  the  problem  of  unknown
variables with the  latter method using  the 'unknown_symbol_resolver'
component.

   typedef exprtk::symbol_table<T> symbol_table_t;
   typedef exprtk::expression<T>     expression_t;
   typedef exprtk::parser<T>             parser_t;

   symbol_table_t unknown_var_symbol_table;

   symbol_table_t symbol_table;
   symbol_table.add_variable("x",x);
   symbol_table.add_variable("y",y);

   expression_t expression;
   expression.register_symbol_table(unknown_var_symbol_table);
   expression.register_symbol_table(symbol_table);

   parser_t parser;
   parser.enable_unknown_symbol_resolver();

   std::string expression_str = "x + abs(y / 3k) * z + 2";

   parser.compile(expression_str,expression);

In the  example above,  the symbols  'k' and  'z' will  be treated  as
unknown symbols. The  parser in the  example is set  to handle unknown
symbols using the built-in default unknown_symbol_resolver (USR).  The
default  USR  will  automatically resolve  any  unknown  symbols as  a
variable (scalar type). The new variables will be added to the primary
symbol_table,  which in  this case  is the  'unknown_var_symbol_table'
instance.  Once  the  compilation  has  completed  successfully,   the
variables that were resolved  during compilation can be  accessed from
the   primary   symbol_table   using   the   'get_variable_list'   and
'variable_ref' methods and then if needed can be modified  accordingly
after which the expression itself can be evaluated.

   std::vector<std::string> variable_list;

   unknown_var_symbol_table.get_variable_list(variable_list);

   for (auto& var_name : variable_list)
   {
      T& v = symbol_table.variable_ref(var_name);

      v = ...;
   }

   ...

   expression.value();

Note:  As  previously  mentioned the  default  USR  will automatically
assume any unknown symbol to be a valid scalar variable, and will then
proceed to add said symbol  as a variable to the  primary symbol_table
of the associated expression during the compilation process. However a
problem that may arise, is  that expressions that are parsed  with the
USR enabled,  but contain  'typos' or  otherwise syntactic  errors may
inadvertently compile successfully due to the simplistic nature of the
default USR. The following are some example expressions:

   (1) 1 + abz(x + 1)
   (2) sine(y / 2) - coz(3x)

The two  expressions above contain misspelt  symbols (abz,  sine, coz)
which if implied  multiplications and default  USR are enabled  during
compilation will result in them being assumed to be valid 'variables',
which obviously is  not the intended  outcome by the  user. A possible
solution to this  problem is for  one to implement  their own specific
USR that will perform a user defined business logic in determining  if
an encountered unknown symbol should be treated as a variable or if it
should raise a compilation error. The following example demonstrates a
simple user defined USR:

   typedef exprtk::symbol_table<T> symbol_table_t;
   typedef exprtk::expression<T>     expression_t;
   typedef exprtk::parser<T>             parser_t;

   template <typename T>
   struct my_usr : public parser_t::unknown_symbol_resolver
   {
      typedef typename parser_t::unknown_symbol_resolver usr_t;

      bool process(const std::string& unknown_symbol,
                   typename usr_t::usr_symbol_type& st,
                   T& default_value,
                   std::string& error_message)
      {
         if (0 != unknown_symbol.find("var_"))
         {
            error_message = "Invalid symbol: " + unknown_symbol;
            return false;
         }

         st = usr_t::e_usr_variable_type;
         default_value = T(123.123);

         return true;
      }
   };

   ...

   symbol_table_t unknown_var_symbol_table;

   symbol_table_t symbol_table;
   symbol_table.add_variable("x",x);
   symbol_table.add_variable("y",y);

   expression_t expression;
   expression.register_symbol_table(unknown_var_symbol_table);
   expression.register_symbol_table(symbol_table);

   my_usr<T> musr;

   parser_t parser;
   parser.enable_unknown_symbol_resolver(&musr);

   std::string expression_str = "var_x + abs(var_y - 3) * var_z";

   parser.compile(expression_str,expression);

In  the  example  above,  a user  specified  USR  is  defined, and  is
registered with the parser  enabling the USR functionality.  Then when
an unknown symbol is  encountered during the compilation  process, the
USR's process method will be invoked. The USR in the example will only
'accept' unknown symbols that have  a prefix of 'var_' as  being valid
variables,  all other  unknown symbols  will result  in a  compilation
error being raised.

In the example above  the callback of the  USR that is invoked  during
the unknown symbol resolution process only allows for scalar variables
to be defined and resolved -  as that is the simplest and  most common
form.

There  is  also  an  extended version  of  the  callback  that can  be
overridden that will allow for  more control and choice over  the type
of symbol being  resolved. The following  is an example  definition of
said extended callback:

   template <typename T>
   struct my_usr : public parser_t::unknown_symbol_resolver
   {
     typedef typename parser_t::unknown_symbol_resolver usr_t;

     my_usr()
     : usr_t(usr_t::e_usrmode_extended)
     {}

     virtual bool process(const std::string& unknown_symbol,
                          symbol_table_t&      symbol_table,
                          std::string&        error_message)
     {
        bool result = false;

        if (0 == unknown_symbol.find("var_"))
        {
           // Default value of zero
           result = symbol_table.create_variable(unknown_symbol,0);

           if (!result)
           {
              error_message = "Failed to create variable...";
           }
        }
        else if (0 == unknown_symbol.find("str_"))
        {
           // Default value of empty string
           result = symbol_table.create_stringvar(unknown_symbol,"");

           if (!result)
           {
              error_message = "Failed to create string variable...";
           }
        }
        else
           error_message = "Indeterminable symbol type.";

        return result;
     }
   };

In the  example above,  the USR  callback when  invoked will  pass the
primary symbol table associated with the expression being parsed.  The
symbol  resolution  business  logic  can  then  determine  under  what
conditions  a  symbol will  be  resolved including  its  type (scalar,
string, vector etc) and default value. When the callback  successfully
returns  the  symbol  parsing and  resolution  process  will again  be
executed by the parser. The idea here is that given the primary symbol
table will now have the previously detected unknown symbol registered,
it will be correctly resolved  and the general parsing processing  can
then resume as per normal.

Note: In order to have the USR's extended mode callback be invoked  It
is  necessary to  pass the  e_usrmode_extended enum  value during  the
constructor of the user defined USR.

Note: The primary symbol table  for an expression is the  first symbol
table to be registered with that instance of the expression.

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 13 - ENABLING & DISABLING FEATURES]
The parser can be configured via its settings instance to either allow
or  disallow certain  features that  are available  within the  ExprTk
grammar. The features fall  into one  of the following six categories:

   (1) Base Functions
   (2) Control Flow Structures
   (3) Logical Operators
   (4) Arithmetic Operators
   (5) Inequality Operators
   (6) Assignment Operators

(1) Base Functions
The list of available base functions is as follows:

   abs, acos, acosh, asin,  asinh, atan, atanh, atan2,  avg, ceil,
   clamp,  cos,  cosh, cot,  csc,  equal, erf,  erfc,  exp, expm1,
   floor,  frac,  hypot,  iclamp, like,  log,  log10,  log2, logn,
   log1p, mand, max, min, mod,  mor, mul, ncdf, pow, root,  round,
   roundn, sec, sgn, sin, sinc, sinh, sqrt, sum, swap, tan,  tanh,
   trunc, not_equal, inrange, deg2grad, deg2rad, rad2deg, grad2deg

The above mentioned base functions  can be either enabled or  disabled
'all' at once, as is demonstrated below:

    parser_t parser;
    expression_t expression;

    parser.settings().disable_all_base_functions();

    parser
      .compile("2 * abs(2 - 3)",expression); // compilation failure

    parser.settings().enable_all_base_functions();

    parser
      .compile("2 * abs(2 - 3)",expression); // compilation success

One can also enable or disable specific base functions. The  following
example  demonstrates  the disabling  of  the trigonometric  functions
'sin' and 'cos':

    parser_t parser;
    expression_t expression;

    parser.settings()
      .disable_base_function(settings_t::e_bf_sin)
      .disable_base_function(settings_t::e_bf_cos);

    parser
      .compile("(sin(x) / cos(x)) == tan(x)",expression); // failure

    parser.settings()
      .enable_base_function(settings_t::e_bf_sin)
      .enable_base_function(settings_t::e_bf_cos);

    parser
      .compile("(sin(x) / cos(x)) == tan(x)",expression); // success

(2) Control Flow Structures
The list of available control flow structures is as follows:

   (a) If or If-Else
   (b) Switch statement
   (c) For Loop
   (d) While Loop
   (e) Repeat Loop

The  above  mentioned  control flow structures  can be  either enabled
or disabled 'all' at once, as is demonstrated below:

    parser_t parser;
    expression_t expression;

    std::string program =
       " var x := 0;                      "
       " for (var i := 0; i < 10; i += 1) "
       " {                                "
       "   x += i;                        "
       " }                                ";

    parser.settings().disable_all_control_structures();

    parser
      .compile(program,expression); // compilation failure

    parser.settings().enable_all_control_structures();

    parser
      .compile(program,expression); // compilation success

One can also enable or  disable specific control flow structures.  The
following example demonstrates the  disabling of the for-loop  control
flow structure:

    parser_t parser;
    expression_t expression;

    std::string program =
       " var x := 0;                      "
       " for (var i := 0; i < 10; i += 1) "
       " {                                "
       "   x += i;                        "
       " }                                ";

    parser.settings()
      .disable_control_structure(settings_t::e_ctrl_for_loop);

    parser
      .compile(program,expression); // failure

    parser.settings()
      .enable_control_structure(settings_t::e_ctrl_for_loop);

    parser
      .compile(program,expression); // success

(3) Logical Operators
The list of available logical operators is as follows:

   and, nand, nor, not, or, xnor, xor, &, |

The  above  mentioned  logical  operators  can  be  either  enabled or
disabled 'all' at once, as is demonstrated below:

    parser_t parser;
    expression_t expression;

    parser.settings().disable_all_logic_ops();

    parser
      .compile("1 or not(0 and 1)",expression); // compilation failure

    parser.settings().enable_all_logic_ops();

    parser
      .compile("1 or not(0 and 1)",expression); // compilation success

One  can  also  enable  or  disable  specific  logical  operators. The
following  example  demonstrates  the disabling  of the  'and' logical
operator:

    parser_t parser;
    expression_t expression;

    parser.settings()
      .disable_logic_operation(settings_t::e_logic_and);

    parser
      .compile("1 or not(0 and 1)",expression); // failure

    parser.settings()
      .enable_logic_operation(settings_t::e_logic_and);

    parser
      .compile("1 or not(0 and 1)",expression); // success

(4) Arithmetic Operators
The list of available arithmetic operators is as follows:

   +, -, *, /, %, ^

The  above mentioned  arithmetic operators  can be  either enabled  or
disabled 'all' at once, as is demonstrated below:

    parser_t parser;
    expression_t expression;

    parser.settings().disable_all_arithmetic_ops();

    parser
      .compile("1 + 2 / 3",expression); // compilation failure

    parser.settings().enable_all_arithmetic_ops();

    parser
      .compile("1 + 2 / 3",expression); // compilation success

One  can also  enable or  disable specific  arithmetic operators.  The
following  example  demonstrates  the disabling  of  the  addition '+'
arithmetic operator:

    parser_t parser;
    expression_t expression;

    parser.settings()
      .disable_arithmetic_operation(settings_t::e_arith_add);

    parser
      .compile("1 + 2 / 3",expression); // failure

    parser.settings()
      .enable_arithmetic_operation(settings_t::e_arith_add);

    parser
      .compile("1 + 2 / 3",expression); // success

(5) Inequality Operators
The list of available inequality operators is as follows:

   <, <=, >, >=, ==, =, != <>

The  above mentioned  inequality operators  can be  either enabled  or
disabled 'all' at once, as is demonstrated below:

    parser_t parser;
    expression_t expression;

    parser.settings().disable_all_inequality_ops();

    parser
      .compile("1 < 3",expression); // compilation failure

    parser.settings().enable_all_inequality_ops();

    parser
      .compile("1 < 3",expression); // compilation success

One  can also  enable or  disable specific  inequality operators.  The
following  example demonstrates  the disabling  of  the  less-than '<'
inequality operator:

    parser_t parser;
    expression_t expression;

    parser.settings()
      .disable_inequality_operation(settings_t::e_ineq_lt);

    parser
      .compile("1 < 3",expression); // failure

    parser.settings()
      .enable_inequality_operation(settings_t::e_ineq_lt);

    parser
      .compile("1 < 3",expression); // success

(6) Assignment Operators
The list of available assignment operators is as follows:

   :=, +=, -=, *=, /=, %=

The  above mentioned  assignment operators  can be  either enabled  or
disabled 'all' at once, as is demonstrated below:

    parser_t parser;
    expression_t expression;
    symbol_table_t symbol_table;

    T x = T(0);

    symbol_table.add_variable("x",x);

    expression.register_symbol_table(symbol_table);

    parser.settings().disable_all_assignment_ops();

    parser
      .compile("x := 3",expression); // compilation failure

    parser.settings().enable_all_assignment_ops();

    parser
      .compile("x := 3",expression); // compilation success

One  can also  enable or  disable specific  assignment operators.  The
following  example demonstrates  the  disabling  of the  '+=' addition
assignment operator:

    parser_t parser;
    expression_t expression;
    symbol_table_t symbol_table;

    T x = T(0);

    symbol_table.add_variable("x",x);

    expression.register_symbol_table(symbol_table);

    parser.settings()
      .disable_assignment_operation(settings_t::e_assign_addass);

    parser
      .compile("x += 3",expression); // failure

    parser.settings()
      .enable_assignment_operation(settings_t::e_assign_addass);

    parser
      .compile("x += 3",expression); // success

Note: In the event of a base function being disabled, one can redefine
the  base  function  using  the  standard  custom  function definition
process. In the  following example the 'sin' function is disabled then
redefined as a function taking degree input.

    template <typename T>
    struct sine_deg : public exprtk::ifunction<T>
    {
       sine_deg() : exprtk::ifunction<T>(1) {}

       inline T operator()(const T& v)
       {
          const T pi = exprtk::details::numeric::constant::pi;
          return std::sin((v * T(pi)) / T(180));
       }
    };

    ...

    typedef exprtk::symbol_table<T> symbol_table_t;
    typedef exprtk::expression<T>     expression_t;
    typedef exprtk::parser<T>             parser_t;

    typedef typename parser_t::settings_store settings_t;

    sine_deg<T> sine;

    symbol_table.add_reserved_function("sin",sine);

    expression_t expression;

    expression.register_symbol_table(symbol_table);

    parser_t parser;

    parser.settings()
       .disable_base_function(settings_t::e_bf_sin);

    parser.compile("1 + sin(30)",expression);

In the example above, the custom 'sin' function is registered with the
symbol_table using the method 'add_reserved_function'. This is done so
as to bypass the checks for reserved words that are carried out on the
provided symbol names when calling the standard 'add_function' method.
Normally if  a user  specified symbol  name conflicts  with any of the
ExprTk reserved words, the add_function call will fail.

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 14 - EXPRESSION RETURN VALUES]
ExprTk expressions can return immediately from any point by  utilizing
the return call. Furthermore the  return call can be used  to transfer
out multiple return values from within the expression.

If an expression evaluation exits using a return point, the result  of
the call to the 'value' method will be NaN, and it's expected that the
return values will be available from the results_context.

In  the  following example  there  are  three  return  points  in  the
expression.  If  neither  of  the  return  points  are  hit,  then the
expression will return normally.

   std::string expression_string =
                  " if (x < y)                                   "
                  "   return [x + 1,'return-call 1'];            "
                  " else if (x > y)                              "
                  "   return [y / 2, y + 1, 'return-call 2'];    "
                  " else if (equal(x,y))                         "
                  "   x + y;                                     "
                  " return [x, y, x + y, x - y, 'return-call 3'] ";

   typedef exprtk::symbol_table<double> symbol_table_t;
   typedef exprtk::expression<double>     expression_t;
   typedef exprtk::parser<double>             parser_t;

   symbol_table_t symbol_table;
   expression_t   expression;
   parser_t       parser;

   double x = 0;
   double y = 0;

   symbol_table.add_variable("x",x);
   symbol_table.add_variable("y",y);

   expression.register_symbol_table(symbol_table);

   parser.compile(expression_string,expression);

   T result = expression.value();

   if (expression.results().count())
   {
      typedef exprtk::results_context<T> results_context_t;
      typedef typename results_context_t::type_store_t type_t;
      typedef typename type_t::scalar_view scalar_t;
      typedef typename type_t::vector_view vector_t;
      typedef typename type_t::string_view string_t;

      const results_context_t& results = expression.results();

      for (std::size_t i = 0; i < results.count(); ++i)
      {
         type_t t = results[i];

         switch (t.type)
         {
            case type_t::e_scalar : ...
                                    break;

            case type_t::e_vector : ...
                                    break;

            case type_t::e_string : ...
                                    break;

            default               : continue;
         }
   }

Note: Processing of the return results is similar to that of the
generic function call parameters.

It is however recommended that if there is to be only a single flow of
execution  through  the  expression,  that  the  simpler  approach  of
registering external variables of appropriate type be used.

This method simply requires the variables that are to hold the various
results that are to be computed within the expression to be registered
with an associated symbol_table  instance. Then within the  expression
itself  to  have  the result  variables  be  assigned the  appropriate
values.

   typedef exprtk::symbol_table<double> symbol_table_t;
   typedef exprtk::expression<double>     expression_t;
   typedef exprtk::parser<double>             parser_t;

   std::string expression_string =
                  " var x := 123.456;     "
                  " var s := 'ijk';       "
                  " result0 := x + 78.90; "
                  " result1 := s + '123'  ";

   double      result0;
   std::string result1;

   symbol_table_t symbol_table;
   symbol_table.add_variable ("result0",result0);
   symbol_table.add_stringvar("result1",result1);

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   parser_t parser;
   parser.compile(expression_string,expression);

   expression.value();

   printf("Result0: %15.5f\n",result0        );
   printf("Result1: %s\n"    ,result1.c_str());

In the example above, the expression will compute two results. As such
two result variables are defined to hold the values named result0  and
result1 respectively. The first is of scalar type (double), the second
is of  string type.  Once the  expression has  been evaluated, the two
variables will have been updated  with the new result values,  and can
then be further utilized from within the calling program.

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 15 - COMPILATION ERRORS]
When attempting to compile  a malformed or otherwise  erroneous ExprTk
expression, the  compilation process  will result  in an  error, as is
indicated  by  the  'compile'  method  returning  a  false  value.   A
diagnostic indicating the first error encountered and its cause can be
obtained by  invoking the  'error' method,  as is  demonstrated in the
following example:

   if (!parser.compile(expression_string,expression))
   {
      printf("Error: %s\n", parser.error().c_str());
      return false;
   }

Any error(s) resulting from a failed compilation will be stored in the
parser instance until the next time a compilation is performed. Before
then errors can be enumerated  in the order they occurred  by invoking
the 'get_error' method which itself will return a 'parser_error' type.
A parser_error object will contain an error diagnostic, an error  mode
(or class), and the character position of the error in the  expression
string. The following example demonstrates the enumeration of error(s)
in the event of a failed compilation.

   if (!parser.compile(expression_string,expression))
   {
      for (std::size_t i = 0; i < parser.error_count(); ++i)
      {
         typedef exprtk::parser_error::type error_t;

         error_t error = parser.get_error(i);

         printf("Error[%02d] Position: %02d Type: [%14s] Msg: %s\n",
                i,
                error.token.position,
                exprtk::parser_error::to_str(error.mode).c_str(),
                error.diagnostic.c_str());
      }

      return false;
   }

Assuming the  following expression '2 + (3 / log(1 + x))' which uses a
variable named 'x'  that has not been registered  with the appropriate
symbol_table  instance and  is not  a locally  defined variable,  once
compiled the  above denoted post compilation error handling code shall
produce the following output:

  Error: ERR184 - Undefined symbol: 'x'
  Error[00] Pos:17 Type:[Syntax] Msg: ERR184 - Undefined symbol: 'x'

For  expressions  comprised  of  multiple  lines,  the  error position
provided in the  parser_error object can  be converted into  a pair of
line and column numbers by invoking the 'update_error' function as  is
demonstrated by the following example:

   if (!parser.compile(program_str,expression))
   {
      for (std::size_t i = 0; i < parser.error_count(); ++i)
      {
         typedef exprtk::parser_error::type error_t;

         error_t error = parser.get_error(i);

         exprtk::parser_error::update_error(error,program_str);

         printf("Error[%02d] at line: %d column: %d\n",
                i,
                error.line_no,
                error.column_no);
      }

      return false;
   }

Note: There are five  distinct error modes in  ExprTk which denote the
class of an error. These classes are as follows:

   (a) Syntax
   (b) Token
   (c) Numeric
   (d) Symbol Table
   (e) Lexer

(a) Syntax Errors
These are errors  related to invalid  syntax found within  the denoted
expression. Examples are invalid sequences of operators and variables,
incorrect number  of parameters  to functions,  invalid conditional or
loop structures and invalid use of keywords.

   eg:  'for := sin(x,y,z) + 2 * equal > until[2 - x,3]'

(b) Token Errors
Errors in this class relate to  token level errors detected by one  or
more of the following checkers:

   (1) Bracket Checker
   (2) Numeric Checker
   (3) Sequence Checker

(c) Numeric Errors
This class of  error is related  to conversion of  numeric values from
their  string form  to the  underlying numerical  type (float,  double
etc).

(d) Symbol Table Errors
This is the class of errors related to failures when interacting  with
the registered symbol_table instance. Errors such as not being able to
find,  within  the  symbol_table,  symbols  representing  variables or
functions, to being unable to create new variables in the symbol_table
via the 'unknown symbol resolver' mechanism.

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 16 - RUNTIME LIBRARY PACKAGES]
ExprTk   contains   a   set  of   simple   extensions,   that  provide
functionalities  beyond  basic numerical  calculations.  Currently the
available packages are:

  +---+--------------------+-----------------------------------+
  | # |    Package Name    |          Namespace/Type           |
  +---+--------------------+-----------------------------------+
  | 1 | Basic I/O          | exprtk::rtl::io::package<T>       |
  | 2 | File I/O           | exprtk::rtl::io::file::package<T> |
  | 3 | Vector Operations  | exprtk::rtl::vecops::package<T>   |
  +---+--------------------+-----------------------------------+

In order to make the  features of a specific package  available within
an  expression,  an instance  of  the package  must  be added  to  the
expression's associated  symbol table.  In the  following example, the
file I/O package is made available for the given expression:

   typedef exprtk::symbol_table<T> symbol_table_t;
   typedef exprtk::expression<T>     expression_t;
   typedef exprtk::parser<T>             parser_t;

   exprtk::rtl::io::file::package<T> fileio_package;

   std::string expression_string =
      " var file_name := 'file.txt';        "
      " var stream    := null;              "
      "                                     "
      " stream := open(file_name,'w');      "
      "                                     "
      " write(stream,'Hello world....\n');  "
      "                                     "
      " close(stream);                      "
      "                                     ";

   symbol_table_t symbol_table;
   symbol_table.add_package(fileio_package);

   expression_t expression;
   expression.register_symbol_table(symbol_table);

   parser_t parser;
   parser.compile(expression_string,expression);

   expression.value();

(1) Basic I/O functions:

   (a) print
   (b) println

(2) File I/O functions:

   (a) open    (b) close
   (c) write   (d) read
   (e) getline (f) eof

(3) Vector Operations functions:

   (a) all_true    (b) all_false
   (c) any_true    (d) any_false
   (e) count       (f) copy
   (g) rotate-left (h) rotate-right
   (i) shift-left  (j) shift-right
   (k) sort        (l) nth_element
   (m) iota        (n) sumk
   (o) axpy        (p) axpby
   (q) axpyz       (r) axpbyz
   (s) axpbz       (t) dot
   (u) dotk

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 17 - BENCHMARKING]
As part of the ExprTk package there is an expression benchmark utility
named 'exprtk_benchmark'. The utility attempts to determine expression
evaluation  speed (or  rate of  evaluations -  evals  per  second), by
evaluating each expression numerous times and mutating the  underlying
variables  of  the  expression between  each  evaluation.  The utility
assumes any  valid ExprTk  expression (containing  conditionals, loops
etc), however  it will  only make  use of  a predefined  set of scalar
variables, namely: a, b, c, x, y, z and w. That being said expressions
themselves  can  contain any  number  of local  variables,  vectors or
strings. There are two modes of operation:

   (1) Default
   (2) User Specified Expressions

(1) Default
The default mode is  enabled simply by executing  the exprtk_benchmark
binary with no command line parameters. In this mode a predefined  set
of expressions will be evaluated in three phases:

   (a) ExprTk evaluation
   (b) Native evaluation
   (c) ExprTk parse

In the first two  phases (a and b)  a list of predefined  (hard-coded)
expressions  will  be  evaluated using  both  ExprTk  and native  mode
implementations.  This  is  done so  as  to  compare evaluation  times
between ExprTk and native implementations. The set of expressions used
are as follows:

   (01) (y + x)
   (02) 2 * (y + x)
   (03) (2 * y + 2 * x)
   (04) ((1.23 * x^2) / y) - 123.123
   (05) (y + x / y) * (x - y / x)
   (06) x / ((x + y) + (x - y)) / y
   (07) 1 - ((x * y) + (y / x)) - 3
   (08) (5.5 + x) + (2 * x - 2 / 3 * y) * (x / 3 + y / 4) + (y + 7.7)
   (09) 1.1x^1 + 2.2y^2 - 3.3x^3 + 4.4y^15 - 5.5x^23 + 6.6y^55
   (10) sin(2 * x) + cos(pi / y)
   (11) 1 - sin(2 * x) + cos(pi / y)
   (12) sqrt(111.111 - sin(2 * x) + cos(pi / y) / 333.333)
   (13) (x^2 / sin(2 * pi / y)) - x / 2
   (14) x + (cos(y - sin(2 / x * pi)) - sin(x - cos(2 * y / pi))) - y
   (15) clamp(-1.0, sin(2 * pi * x) + cos(y / 2 * pi), +1.0)
   (16) max(3.33, min(sqrt(1 - sin(2 * x) + cos(pi / y) / 3), 1.11))
   (17) if((y + (x * 2.2)) <= (x + y + 1.1), x - y, x*y) + 2 * pi / x

The  third  and  final  phase  (c),  is  used  to  determine   average
compilation rates  (compiles per  second) for  expressions of  varying
complexity. Each expression is compiled 100K times and the average for
each expression is output.

(2) User Specified Expressions
In this mode two parameters are passed to the utility via the  command
line:

   (a) A name of a text file containing one expression per line
   (b) An integer representing the number of evaluations per expression

An  example execution  of the  benchmark utility  in this  mode is  as
follows:

   ./exprtk_benchmark my_expressions.txt 1000000

The  above  invocation  will  load  the  expressions  from  the   file
'my_expressions.txt' and will then proceed to evaluate each expression
one million  times, varying  the above  mentioned variables  (x, y,  z
etc.) between each evaluation, and at the end of each expression round
a print out of  running times, result of a single evaluation and total
sum of results is provided as demonstrated below:

   Expression 1 of 7 4.770 ns 47700 ns  ( 9370368.0) '((((x+y)+z)))'
   Expression 2 of 7 4.750 ns 47500 ns  ( 1123455.9) '((((x+y)-z)))'
   Expression 3 of 7 4.766 ns 47659 ns  (21635410.7) '((((x+y)*z)))'
   Expression 4 of 7 5.662 ns 56619 ns  ( 1272454.9) '((((x+y)/z)))'
   Expression 5 of 7 4.950 ns 49500 ns  ( 4123455.9) '((((x-y)+z)))'
   Expression 6 of 7 7.581 ns 75810 ns  (-4123455.9) '((((x-y)-z)))'
   Expression 7 of 7 4.801 ns 48010 ns  (       0.0) '((((x-y)*z)))'

The benchmark utility can be very useful when investigating evaluation
efficiency  issues with  ExprTk or  simply during  the prototyping  of
expressions. As an example, lets take the following expression:

   1 / sqrt(2x) * e^(3y)

Let's say we would like to determine which sub-part of the  expression
takes the  most time  to evaluate  and perhaps  attempt to  rework the
expression based on the results. In order to do this we will create  a
text file  called 'test.txt'  and then  proceed to  make some educated
guesses  about  how  to  break   the  expression  up  into  its   more
'interesting' sub-parts which we will  then add as one expression  per
line to the file. An example breakdown may be as follows:

   1 / sqrt(2x) * e^(3y)
   1 / sqrt(2x)
   e^(3y)

The  benchmark with  the given  file, where  each expression  will be
evaluated 100K times can be executed as follows:

   ./exprtk_benchmark test.txt 100000
   Expr 1 of 3 90.340 ns 9034000 ns (296417859.3) '1/sqrt(2x)*e^(3y)'
   Expr 2 of 3 11.100 ns 1109999 ns (    44267.3) '1/sqrt(2x)'
   Expr 3 of 3 77.830 ns 7783000 ns (615985286.6) 'e^(3y)'
   [*] Number Of Evals:         300000
   [*] Total Time:              0.018sec
   [*] Total Single Eval Time:  0.000ms

From the results above we conclude that the third expression  (e^(3y))
consumes the largest amount of time. The variable 'e', as used in both
the  benchmark  and  in the  expression,  is  an approximation  of the
transcendental mathematical constant e (2.71828182845904...) hence the
sub-expression  should perhaps be  modified  to use the generally more
efficient built-in 'exp' function.

   ./exprtk_benchmark test.txt 1000000
   Expr 1 of 5 86.563 ns 8656300ns (296417859.6) '1/sqrt(2x)*e^(3y)'
   Expr 2 of 5 40.506 ns 4050600ns (296417859.6) '1/sqrt(2x)*exp(3y)'
   Expr 3 of 5 14.248 ns 1424799ns (    44267.2) '1/sqrt(2x)'
   Expr 4 of 5 88.840 ns 8884000ns (615985286.9) 'e^(3y)'
   Expr 5 of 5 29.267 ns 2926699ns (615985286.9) 'exp(3y)'
   [*] Number Of Evals:        5000000
   [*] Total Time:             0.260sec
   [*] Total Single Eval Time: 0.000ms

The above output demonstrates the  results from  making the previously
mentioned modification to the expression. As can be seen the new  form
of the expression using the 'exp' function reduces the evaluation time
by over 50%, in other words increases the evaluation rate by two fold.

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 18 - EXPRTK NOTES]
The following is a list of facts and suggestions one may want to take
into account when using ExprTk:

 (00) Precision  and performance  of expression  evaluations are  the
      dominant principles of the ExprTk library.

 (01) ExprTk  uses a  rudimentary imperative  programming model  with
      syntax based  on languages  such as  Pascal and  C. Furthermore
      ExprTk  is  an LL(2)  type  grammar and  is  processed using  a
      recursive descent parsing algorithm.

 (02) Supported types are float, double, long double and MPFR/GMP.

 (03) Standard mathematical operator precedence is applied (BEDMAS).

 (04) Results of expressions that are deemed as being 'valid' are  to
      exist within the set of Real numbers. All other results will be
      of the value: Not-A-Number (NaN).

 (05) Supported   user  defined   types   are   numeric  and   string
      variables, numeric vectors and functions.

 (06) All  reserved words,  keywords, variable,  vector, string   and
      function names are case-insensitive.

 (07) Variable, vector, string variable and function names must begin
      with  a letter  (A-Z or  a-z), then  can be  comprised of  any
      combination of letters, digits,  underscores and dots. (eg:  x,
      var1 or power_func99, person.age, item.size.0)

 (08) Expression lengths and sub-expression lists are limited only by
      storage capacity.

 (09) The  life-time of  objects registered  with or  created from  a
      specific symbol-table must span  at least the life-time  of the
      compiled expressions which utilize objects, such as  variables,
      of that  symbol-table, otherwise  the result  will be undefined
      behavior.

 (10) Equal  and  Nequal  are  normalised-epsilon  equality routines,
      which use epsilons of 0.0000000001 and 0.000001 for double  and
      float types respectively.

 (11) All trigonometric functions  assume radian input  unless stated
      otherwise.

 (12) Expressions may contain  white-space characters such  as space,
      tabs, new-lines, control-feed et al.
      ('\n', '\r', '\t', '\b', '\v', '\f')

 (13) Strings may be comprised of any combination of letters, digits
      special characters including (~!@#$%^&*()[]|=+ ,./?<>;:"`~_) or
      hexadecimal escaped sequences (eg: \0x30) and must be enclosed
      with single-quotes.
      eg: 'Frankly my dear, \0x49 do n0t give a damn!'

 (14) User defined  normal functions  can have  up to  20 parameters,
      where as  user defined  generic-functions and  vararg-functions
      can have an unlimited number of parameters.

 (15) The inbuilt polynomial functions can be at most of degree 12.

 (16) Where appropriate constant folding optimisations may be applied.
      (eg: The expression '2 + (3 - (x / y))' becomes '5 - (x / y)')

 (17) If the strength reduction compilation option has been enabled,
      then where applicable strength reduction optimisations may be
      applied.

 (18) String  processing capabilities  are available  by default.  To
      turn them  off, the  following needs  to be  defined at compile
      time: exprtk_disable_string_capabilities

 (19) Composited functions can call themselves or any other functions
      that have been defined prior to their own definition.

 (20) Recursive calls made from within composited functions will have
      a stack size bound by the stack of the executing architecture.

 (21) User  defined functions  by default  are assumed  to have  side
      effects. As such an "all constant parameter" invocation of such
      functions wont result in constant folding. If the function  has
      no side effects then that  can be noted during the  constructor
      of  the  ifunction  allowing it  to  be  constant folded  where
      appropriate.

 (22) The entity relationship between symbol_table and an  expression
      is many-to-many. However the intended 'typical' use-case  where
      possible, is to have a single symbol table manage the  variable
      and function requirements of multiple expressions.

 (23) The common use-case  for an expression  is to have  it compiled
      only  ONCE  and  then subsequently  have it  evaluated multiple
      times. An extremely  inefficient and suboptimal  approach would
      be to recompile an expression  from its string form every  time
      it requires evaluating.

 (24) It is  strongly recommended  that  the  return value  of method
      invocations from  the parser  and symbol_table  types be  taken
      into account. Specifically the  'compile' method of the  parser
      and the 'add_xxx'  set of methods  of the symbol_table  as they
      denote either the success or failure state of the invoked call.
      Continued processing from  a failed  state without having first
      rectified the underlying issue  will in turn result  in further
      failures and undefined behaviours.

 (25) The following are examples of compliant floating point value
      representations:

      (1) 12345         (5) -123.456
      (2) +123.456e+12  (6) 123.456E-12
      (3) +012.045e+07  (7) .1234
      (4) 123.456f      (8) -321.654E+3L

 (26) Expressions may contain any of the following comment styles:

      (1) // .... \n
      (2) #  .... \n
      (3) /* .... */

 (27) The  'null'  value  type  is  a  special  non-zero  type   that
      incorporates specific semantics when undergoing operations with
      the standard numeric type. The following is a list of type  and
      boolean results associated with the use of 'null':

      (1) null  +,-,*,/,%  x    --> x
      (2) x     +,-,*,/,%  null --> x
      (3) null  +,-,*,/,%  null --> null
      (4) null     ==      null --> true
      (5) null     ==      x    --> true
      (6) x        ==      null --> true
      (7) x        !=      null --> false
      (8) null     !=      null --> false
      (9) null     !=      x    --> false

 (28) The following is a list  of reserved words and symbols  used by
      ExprTk. Attempting to  add a variable  or custom function  to a
      symbol table using any of  the reserved words will result  in a
      failure.

      abs, acos, acosh, and, asin, asinh, atan, atan2, atanh, avg,
      break, case,  ceil, clamp,  continue, cosh,  cos, cot,  csc,
      default,  deg2grad, deg2rad,  else, equal,  erfc, erf,  exp,
      expm1, false, floor, for, frac, grad2deg, hypot, iclamp, if,
      ilike, in, inrange, in, like, log, log10, log1p, log2, logn,
      mand,  max,  min,  mod,  mor,  mul,  nand,  ncdf,  nor, not,
      not_equal,  not,  null, or,  pow,  rad2deg, repeat,  return,
      root, roundn, round,  sec, sgn, shl,  shr, sinc, sinh,  sin,
      sqrt, sum, swap, switch, tanh, tan, true, trunc, until, var,
      while, xnor, xor, xor

 (29) Every valid ExprTk statement is a "value returning" expression.
      Unlike some languages that limit the types of expressions  that
      can be  performed in  certain situations,  in ExprTk  any valid
      expression can be used in any "value consuming" context. eg:

      var y := 3;
      for (var x := switch
                    {
                      case 1  :  7;
                      case 2  : -1 + ~{var x{};};
                      default :  y > 2 ? 3 : 4;
                    };
           x != while (y > 0) { y -= 1; };
           x -= {
                  if (min(x,y) < 2 * max(x,y))
                    x + 2;
                  else
                    x + y - 3;
                }
          )
      {
        (x + y) / (x - y);
      }

 (30) It is recommended when prototyping expressions that the  ExprTk
      REPL be utilised, as it supports all the features available  in
      the library,  including complete  error analysis,  benchmarking
      and   dependency   dumps    etc   which   allows    for   rapid
      coding/prototyping  and  debug  cycles  without  the  hassle of
      having to  recompile test  programs with  expressions that have
      been hard-coded. It's also a  good source of truth for  how the
      library's various features can be applied.

 (31) For performance considerations,  one should assume  the actions
      of expression, symbol  table and parser  instance instantiation
      and destruction, and the expression compilation process  itself
      to be of high latency. Hence none of them should be part of any
      performance  critical  code  paths, and  should  instead  occur
      entirely either before or after such code paths.

 (32) Before jumping in and using ExprTk, do take the time to  peruse
      the documentation and all of the examples, both in the main and
      the extras  distributions. Having  an informed  general view of
      what can and  can't be done,  and how something  should be done
      with ExprTk, will  likely result in  a far more  productive and
      enjoyable programming experience.

     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

[SECTION 19 - LANGUAGE STRUCTURE]
The following  are the  various language  structures available  within
ExprTk and their structural representations.

   (00) If Statement
   (01) Else Statement
   (02) Ternary Statement
   (03) While Loop
   (04) Repeat Until Loop
   (05) For Loop
   (06) Switch Statement
   (07) Multi Subexpression Statement
   (08) Multi Case-Consequent Statement
   (09) Variable Definition Statement
   (10) Vector Definition Statement
   (11) String Definition Statement
   (12) Range Statement
   (13) Return Statement

(00) - If Statement
+-------------------------------------------------------------+
|                                                             |
|   [if] ---> [(] ---> [condition] -+-> [,] -+                |
|                                   |        |                |
|   +---------------<---------------+        |                |
|   |                                        |                |
|   |  +------------------<------------------+                |
|   |  |                                                      |
|   |  +--> [consequent] ---> [,] ---> [alternative] ---> [)] |
|   |                                                         |
|   +--> [)] --+-> [{] ---> [expression*] ---> [}] --+        |
|              |                                     |        |
|              |                +---------<----------+        |
|   +----<-----+                |                             |
|   |                           v                             |
|   +--> [consequent] --> [;] -{*}-> [else-statement]         |
|                                                             |
+-------------------------------------------------------------+

(01) - Else Statement
+-------------------------------------------------------------+
|                                                             |
|   [else] -+-> [alternative] ---> [;]                        |
|           |                                                 |
|           +--> [{] ---> [expression*] ---> [}]              |
|           |                                                 |
|           +--> [if-statement]                               |
|                                                             |
+-------------------------------------------------------------+

(02) - Ternary Statement
+-------------------------------------------------------------+
|                                                             |
|   [condition] ---> [?] ---> [consequent] ---> [:] --+       |
|                                                     |       |
|   +------------------------<------------------------+       |
|   |                                                         |
|   +--> [alternative] --> [;]                                |
|                                                             |
+-------------------------------------------------------------+

(03) - While Loop
+-------------------------------------------------------------+
|                                                             |
|   [while] ---> [(] ---> [condition] ---> [)] ---+           |
|                                                 |           |
|   +----------------------<----------------------+           |
|   |                                                         |
|   +--> [{] ---> [expression*] ---> [}]                      |
|                                                             |
+-------------------------------------------------------------+

(04) - Repeat Until Loop
+-------------------------------------------------------------+
|                                                             |
|   [repeat] ---> [expression*] ---+                          |
|                                  |                          |
|   +--------------<---------------+                          |
|   |                                                         |
|   +--> [until] ---> [(] ---> [condition] --->[)]            |
|                                                             |
+-------------------------------------------------------------+

(05) - For Loop
+-------------------------------------------------------------+
|                                                             |
|   [for] ---> [(] -+-> [initialise expression] --+--+        |
|                   |                             |  |        |
|                   +------------->---------------+  v        |
|                                                    |        |
|   +-----------------------<------------------------+        |
|   |                                                         |
|   +--> [;] -+-> [condition] -+-> [;] ---+                   |
|             |                |          |                   |
|             +------->--------+          v                   |
|                                         |                   |
|   +------------------<---------+--------+                   |
|   |                            |                            |
|   +--> [increment expression] -+-> [)] --+                  |
|                                          |                  |
|   +------------------<-------------------+                  |
|   |                                                         |
|   +--> [{] ---> [expression*] ---> [}]                      |
|                                                             |
+-------------------------------------------------------------+

(06) - Switch Statement
+-------------------------------------------------------------+
|                                                             |
|   [switch] ---> [{] ---+                                    |
|                        |                                    |
|   +---------<----------+-----------<-----------+            |
|   |                                            |            |
|   +--> [case] ---> [condition] ---> [:] ---+   |            |
|                                            |   |            |
|   +-------------------<--------------------+   |            |
|   |                                            |            |
|   +--> [consequent] ---> [;] --------->--------+            |
|   |                                            |            |
|   |                                            |            |
|   +--> [default] ---> [consequent] ---> [;] ---+            |
|   |                                            |            |
|   +---------------------<----------------------+            |
|   |                                                         |
|   +--> [}]                                                  |
|                                                             |
+-------------------------------------------------------------+

(07) - Multi Subexpression Statement
+-------------------------------------------------------------+
|                                                             |
|                   +--------------<---------------+          |
|                   |                              |          |
|   [~] ---> [{\(] -+-> [expression] -+-> [;\,] ---+          |
|                                     |                       |
|   +----------------<----------------+                       |
|   |                                                         |
|   +--> [}\)]                                                |
|                                                             |
+-------------------------------------------------------------+

(08) - Multi Case-Consequent Statement
+-------------------------------------------------------------+
|                                                             |
|   [[*]] ---> [{] ---+                                       |
|                     |                                       |
|   +--------<--------+--------------<----------+             |
|   |                                           |             |
|   +--> [case] ---> [condition] ---> [:] ---+  |             |
|                                            |  |             |
|   +-------------------<--------------------+  |             |
|   |                                           |             |
|   +--> [consequent] ---> [;] ---+------>------+             |
|                                 |                           |
|                                 +--> [}]                    |
|                                                             |
+-------------------------------------------------------------+

(09) - Variable Definition Statement
+-------------------------------------------------------------+
|                                                             |
|   [var] ---> [symbol] -+-> [:=] -+-> [expression] -+-> [;]  |
|                        |         |                 |        |
|                        |         +-----> [{}] -->--+        |
|                        |                           |        |
|                        +------------->-------------+        |
|                                                             |
+-------------------------------------------------------------+

(10) - Vector Definition Statement
+-------------------------------------------------------------+
|                                                             |
|   [var] ---> [symbol] ---> [[] ---> [constant] ---> []] --+ |
|                                                           | |
|   +---------------------------<---------------------------+ |
|   |                                                         |
|   |                   +--------->---------+                 |
|   |                   |                   |                 |
|   +--> [:=] ---> [{] -+-+-> [expression] -+-> [}] ---> [;]  |
|                         |                 |                 |
|                         +--<--- [,] <-----+                 |
|                                                             |
+-------------------------------------------------------------+

(11) - String Definition Statement
+-------------------------------------------------------------+
|                                                             |
|   [var] --> [symbol] --> [:=] --> [str-expression] ---> [;] |
|                                                             |
+-------------------------------------------------------------+

(12) - Range Statement
+-------------------------------------------------------------+
|                                                             |
|      +-------->--------+                                    |
|      |                 |                                    |
| [[] -+-> [expression] -+-> [:] -+-> [expression] -+--> []]  |
|                                 |                 |         |
|                                 +-------->--------+         |
|                                                             |
+-------------------------------------------------------------+

(13) - Return Statement
+-------------------------------------------------------------+
|                                                             |
|   [return] ---> [[] -+-> [expression] -+-> []] ---> [;]     |
|                      |                 |                    |
|                      +--<--- [,] <-----+                    |
|                                                             |
+-------------------------------------------------------------+


7、TCC语法

Help > Snapman客户端 >
7、TCC语法

Snapman系统使用TCC脚本作为系统默认开发语言，TCC就是Tiny C Compiler是一个C语言的编译器，支持C99的C语言标准。

一、TCC脚本的特性是：

1、编译速度超快，几万行甚至十几万行C语言代码能在几秒内编译完成，普通的1000行以下代码能在150毫秒内编译完成。

2、执行速度超快，TCC先将C语言脚本编译成内存可执行代码然后再去执行；除去固定的编译时间，执行速度非常快，能秒杀一切脚本语言，比java和C#语言都快很多，基本能追赶微软VC++编译出来代码的执行速度。

3、TCC脚本能申请内存、文件操作、动态库加载、调用数据库、调用显卡等所有计算机资源；可以和VC++一样进行大数据量和超大数据量数据分析处理，加上Snapman软件脚本代码一次编写，整个计算机系统资源都可以分布式运行的特性，非常适合大量数据的运算处理。

4、自带的库在Snapman安装目录的include下，功能非常丰富，包括：标准C函数、标准windows API函数等；也可以在下面添加自己业务相关的库，扩展性很强。

5、TCC脚本的Snapman库是include下的Snapman.h文件，只要在Snapman中 写的TCC脚本默认都加载了Snapman.h文件，可以操作Snapman的大部分功能。

6、Snapman中写TCC脚本实现了代码变色和关键字提示，包括直接编辑代码和打开脚本编辑对话框编辑

7、Snapman非常适合将一个大功能分成不同模块让不同的人去实现，不需要SVN，合作效率非常高。

8、Snapman的脚本运行快捷键是F5，没有暂停功能，运行后在代码单元格会覆盖了运行打印的消息，可以用F4快捷键清除

二、TCC的相关资料：

https://bellard.org/tcc/

https://bellard.org/tcc/tcc-doc.html

三、C语言概要

1、基本语法

2、数据类型

3、变量

4、常量

5、存储类

6、运算符

7、判断

8、循环

9、函数

10、作用域规则

11、数组

12、指针

13、函数指针与回调函数

14、字符串

15、结构体

16、共用体

17、位域

18、typedef

19、输入输出

20、文件读写

21、预处理器

22、头文件

23、强制类型转换

24、错误处理

25、递归

26、可变参数

27、内存管理

28、命令行参数

四、具体的学习教程可参考

http://www.runoob.com/cprogramming/c-basic-syntax.html

五、C语言代码样例

题目：有五个学生，每个学生有3门课的成绩，从键盘输入以上数据（包括学生号，姓名，三门课成绩），计算出平均成绩，况原有的数据和计算出的平均分数存放在磁盘文件"stud"中。

程序分析：无。

程序源代码：

实例

// Created by www.runoob.com on 15/11/9.
// Copyright ? 2015年 菜鸟教程. All rights reserved.
//
#include<stdio.h>
#include<stdlib.h>
typedef struct
{
    int ID;
   int math;
   int English;
   int C;
   int avargrade;
   char name[20];
}Stu;
int main()
{
    FILE*fp;
    Stu stu[5];
    int i,avargrade=0;
    printf("请输入5个同学的信息：学生号，姓名，3门成绩:\n");
    for(i=0;i<5;i++)
    {
       scanf("%d %s %d %d %d",&(stu[i].ID),stu[i].name,&(stu[i].math),&(stu[i].English),&(stu[i].C));
       stu[i].avargrade=(stu[i].math+stu[i].English+stu[i].C)/3;
    }
    if((fp=fopen("stud","w"))==NULL)
    {
       printf("error :cannot open file!\n");
       exit(0);
    }
    for(i=0;i<5;i++)
       fprintf(fp,"%d %s %d %d %d %d\n",stu[i].ID,stu[i].name,stu[i].math,stu[i].English, stu[i].C,stu[i].avargrade);
    fclose(fp);
    // system("pause");
    return 0;
}

以上实例运行输出结果后：

请输入5个同学的信息：学生号，姓名，3门成绩:
1 a 60 70 80
2 b 60 80 90
3 c 59 39 89
4 e 56 88 98
5 d 43 88 78

打开 stud文件，内容如下

1 a 60 70 80 70
2 b 60 80 90 76
3 c 59 39 89 62
4 e 56 88 98 80
5 d 43 88 78 69


脚本执行性能

Help >
脚本执行性能

作为Snapman精挑细选的2个驱动脚本，其运算性能非常关键，下面我们看一下2个脚本的运行性能表现


Exprtk脚本性能

Help > 脚本执行性能 >
Exprtk脚本性能

Exprtk脚本主要是用来进行数据运算的，我们设计一些很复杂的公式进行100万次运算，看看其性能表现：

按F5运行，其结果果然不出所望，运行如此复杂的脚本需要的时间居然只需要1.2秒。

作为对比，我们拿VS的C#语言编写同样的运算代码运行作为对比：

运行结果：

结果发现Exprtk执行的效率比C#执行效率只是慢了一点点。


TCC脚本性能

Help > 脚本执行性能 >
TCC脚本性能

Snapman集合了TCC编译器可以直接编译执行C语言脚本，其脚本执行效率和C#编译程序进行效率对比，包括下面4方面：

1、函数执行效率

2、数字转换成字符串

3、字符串的叠加

4、MD5算法

这是C#代码：

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Collections;

namespace TestEfficiency
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        int fibonacci(int n)
        {
            if (n == 1 || n == 2)
                return 1;
            return fibonacci(n - 1) + fibonacci(n - 2);
        }
        string numberConvert()
        {
            string result = "";
            for (int i = 0; i < 14000000; i++ )
            {
                result = i.ToString();
            }
            return result;
        }
        string stringAppend()
        {
            string conc = "StringBuilder sb = new StringBuilder(1024);";
            StringBuilder sb = new StringBuilder(1024);
            for (int i = 0; i < 1400; i++)
            {
                sb = new StringBuilder(1024);
                for (int j = 0; j < 10000; j++ )
                {
                    sb.Append(conc);
                }
            }
            return sb.ToString();
        }
        public class MD5
        {
            //static state variables
            private static UInt32 A;
            private static UInt32 B;
            private static UInt32 C;
            private static UInt32 D;

            //number of bits to rotate in tranforming
            private const int S11 = 7;
            private const int S12 = 12;
            private const int S13 = 17;
            private const int S14 = 22;
            private const int S21 = 5;
            private const int S22 = 9;
            private const int S23 = 14;
            private const int S24 = 20;
            private const int S31 = 4;
            private const int S32 = 11;
            private const int S33 = 16;
            private const int S34 = 23;
            private const int S41 = 6;
            private const int S42 = 10;
            private const int S43 = 15;
            private const int S44 = 21;

            /* F, G, H and I are basic MD5 functions.
             * 四个非线性函数:
             *
             * F(X,Y,Z) =(X&Y)|((~X)&Z)
             * G(X,Y,Z) =(X&Z)|(Y&(~Z))
             * H(X,Y,Z) =X^Y^Z
             * I(X,Y,Z)=Y^(X|(~Z))
             *
             * （&与，|或，~非，^异或）
             */
            private static UInt32 F(UInt32 x, UInt32 y, UInt32 z)
            {
                return (x & y) | ((~x) & z);
            }
            private static UInt32 G(UInt32 x, UInt32 y, UInt32 z)
            {
                return (x & z) | (y & (~z));
            }
            private static UInt32 H(UInt32 x, UInt32 y, UInt32 z)
            {
                return x ^ y ^ z;
            }
            private static UInt32 I(UInt32 x, UInt32 y, UInt32 z)
            {
                return y ^ (x | (~z));
            }

            /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
             * Rotation is separate from addition to prevent recomputation.
             */
            private static void FF(ref UInt32 a, UInt32 b, UInt32 c, UInt32 d, UInt32 mj, int s, UInt32 ti)
            {
                a = a + F(b, c, d) + mj + ti;
                a = a << s | a >> (32 - s);
                a += b;
            }
            private static void GG(ref UInt32 a, UInt32 b, UInt32 c, UInt32 d, UInt32 mj, int s, UInt32 ti)
            {
                a = a + G(b, c, d) + mj + ti;
                a = a << s | a >> (32 - s);
                a += b;
            }
            private static void HH(ref UInt32 a, UInt32 b, UInt32 c, UInt32 d, UInt32 mj, int s, UInt32 ti)
            {
                a = a + H(b, c, d) + mj + ti;
                a = a << s | a >> (32 - s);
                a += b;
            }
            private static void II(ref UInt32 a, UInt32 b, UInt32 c, UInt32 d, UInt32 mj, int s, UInt32 ti)
            {
                a = a + I(b, c, d) + mj + ti;
                a = a << s | a >> (32 - s);
                a += b;
            }

            private static void MD5_Init()
            {
                A = 0x67452301;　//in memory, this is 0x01234567
                B = 0xefcdab89;　//in memory, this is 0x89abcdef
                C = 0x98badcfe;　//in memory, this is 0xfedcba98
                D = 0x10325476;　//in memory, this is 0x76543210
            }

            private static UInt32[] MD5_Append(byte[] input)
            {
                int zeros = 0;
                int ones = 1;
                int size = 0;
                int n = input.Length;
                int m = n % 64;
                if (m < 56)
                {
                    zeros = 55 - m;
                    size = n - m + 64;
                }
                else if (m == 56)
                {
                    zeros = 0;
                    ones = 0;
                    size = n + 8;
                }
                else
                {
                    zeros = 63 - m + 56;
                    size = n + 64 - m + 64;
                }

                ArrayList bs = new ArrayList(input);
                if (ones == 1)
                {
                    bs.Add((byte)0x80); // 0x80 = $10000000
                }
                for (int i = 0; i < zeros; i++)
                {
                    bs.Add((byte)0);
                }

                UInt64 N = (UInt64)n * 8;
                byte h1 = (byte)(N & 0xFF);
                byte h2 = (byte)((N >> 8) & 0xFF);
                byte h3 = (byte)((N >> 16) & 0xFF);
                byte h4 = (byte)((N >> 24) & 0xFF);
                byte h5 = (byte)((N >> 32) & 0xFF);
                byte h6 = (byte)((N >> 40) & 0xFF);
                byte h7 = (byte)((N >> 48) & 0xFF);
                byte h8 = (byte)(N >> 56);
                bs.Add(h1);
                bs.Add(h2);
                bs.Add(h3);
                bs.Add(h4);
                bs.Add(h5);
                bs.Add(h6);
                bs.Add(h7);
                bs.Add(h8);
                byte[] ts = (byte[])bs.ToArray(typeof(byte));

                /* Decodes input (byte[]) into output (UInt32[]). Assumes len is
                 * a multiple of 4.
                 */
                UInt32[] output = new UInt32[size / 4];
                for (Int64 i = 0, j = 0; i < size; j++, i += 4)
                {
                    output[j] = (UInt32)(ts[i] | ts[i + 1] << 8 | ts[i + 2] << 16 | ts[i + 3] << 24);
                }
                return output;
            }
            private static UInt32[] MD5_Trasform(UInt32[] x)
            {

                UInt32 a, b, c, d;

                for (int k = 0; k < x.Length; k += 16)
                {
                    a = A;
                    b = B;
                    c = C;
                    d = D;

                    /* Round 1 */
                    FF(ref a, b, c, d, x[k + 0], S11, 0xd76aa478); /* 1 */
                    FF(ref d, a, b, c, x[k + 1], S12, 0xe8c7b756); /* 2 */
                    FF(ref c, d, a, b, x[k + 2], S13, 0x242070db); /* 3 */
                    FF(ref b, c, d, a, x[k + 3], S14, 0xc1bdceee); /* 4 */
                    FF(ref a, b, c, d, x[k + 4], S11, 0xf57c0faf); /* 5 */
                    FF(ref d, a, b, c, x[k + 5], S12, 0x4787c62a); /* 6 */
                    FF(ref c, d, a, b, x[k + 6], S13, 0xa8304613); /* 7 */
                    FF(ref b, c, d, a, x[k + 7], S14, 0xfd469501); /* 8 */
                    FF(ref a, b, c, d, x[k + 8], S11, 0x698098d8); /* 9 */
                    FF(ref d, a, b, c, x[k + 9], S12, 0x8b44f7af); /* 10 */
                    FF(ref c, d, a, b, x[k + 10], S13, 0xffff5bb1); /* 11 */
                    FF(ref b, c, d, a, x[k + 11], S14, 0x895cd7be); /* 12 */
                    FF(ref a, b, c, d, x[k + 12], S11, 0x6b901122); /* 13 */
                    FF(ref d, a, b, c, x[k + 13], S12, 0xfd987193); /* 14 */
                    FF(ref c, d, a, b, x[k + 14], S13, 0xa679438e); /* 15 */
                    FF(ref b, c, d, a, x[k + 15], S14, 0x49b40821); /* 16 */

                    /* Round 2 */
                    GG(ref a, b, c, d, x[k + 1], S21, 0xf61e2562); /* 17 */
                    GG(ref d, a, b, c, x[k + 6], S22, 0xc040b340); /* 18 */
                    GG(ref c, d, a, b, x[k + 11], S23, 0x265e5a51); /* 19 */
                    GG(ref b, c, d, a, x[k + 0], S24, 0xe9b6c7aa); /* 20 */
                    GG(ref a, b, c, d, x[k + 5], S21, 0xd62f105d); /* 21 */
                    GG(ref d, a, b, c, x[k + 10], S22, 0x2441453); /* 22 */
                    GG(ref c, d, a, b, x[k + 15], S23, 0xd8a1e681); /* 23 */
                    GG(ref b, c, d, a, x[k + 4], S24, 0xe7d3fbc8); /* 24 */
                    GG(ref a, b, c, d, x[k + 9], S21, 0x21e1cde6); /* 25 */
                    GG(ref d, a, b, c, x[k + 14], S22, 0xc33707d6); /* 26 */
                    GG(ref c, d, a, b, x[k + 3], S23, 0xf4d50d87); /* 27 */
                    GG(ref b, c, d, a, x[k + 8], S24, 0x455a14ed); /* 28 */
                    GG(ref a, b, c, d, x[k + 13], S21, 0xa9e3e905); /* 29 */
                    GG(ref d, a, b, c, x[k + 2], S22, 0xfcefa3f8); /* 30 */
                    GG(ref c, d, a, b, x[k + 7], S23, 0x676f02d9); /* 31 */
                    GG(ref b, c, d, a, x[k + 12], S24, 0x8d2a4c8a); /* 32 */

                    /* Round 3 */
                    HH(ref a, b, c, d, x[k + 5], S31, 0xfffa3942); /* 33 */
                    HH(ref d, a, b, c, x[k + 8], S32, 0x8771f681); /* 34 */
                    HH(ref c, d, a, b, x[k + 11], S33, 0x6d9d6122); /* 35 */
                    HH(ref b, c, d, a, x[k + 14], S34, 0xfde5380c); /* 36 */
                    HH(ref a, b, c, d, x[k + 1], S31, 0xa4beea44); /* 37 */
                    HH(ref d, a, b, c, x[k + 4], S32, 0x4bdecfa9); /* 38 */
                    HH(ref c, d, a, b, x[k + 7], S33, 0xf6bb4b60); /* 39 */
                    HH(ref b, c, d, a, x[k + 10], S34, 0xbebfbc70); /* 40 */
                    HH(ref a, b, c, d, x[k + 13], S31, 0x289b7ec6); /* 41 */
                    HH(ref d, a, b, c, x[k + 0], S32, 0xeaa127fa); /* 42 */
                    HH(ref c, d, a, b, x[k + 3], S33, 0xd4ef3085); /* 43 */
                    HH(ref b, c, d, a, x[k + 6], S34, 0x4881d05); /* 44 */
                    HH(ref a, b, c, d, x[k + 9], S31, 0xd9d4d039); /* 45 */
                    HH(ref d, a, b, c, x[k + 12], S32, 0xe6db99e5); /* 46 */
                    HH(ref c, d, a, b, x[k + 15], S33, 0x1fa27cf8); /* 47 */
                    HH(ref b, c, d, a, x[k + 2], S34, 0xc4ac5665); /* 48 */

                    /* Round 4 */
                    II(ref a, b, c, d, x[k + 0], S41, 0xf4292244); /* 49 */
                    II(ref d, a, b, c, x[k + 7], S42, 0x432aff97); /* 50 */
                    II(ref c, d, a, b, x[k + 14], S43, 0xab9423a7); /* 51 */
                    II(ref b, c, d, a, x[k + 5], S44, 0xfc93a039); /* 52 */
                    II(ref a, b, c, d, x[k + 12], S41, 0x655b59c3); /* 53 */
                    II(ref d, a, b, c, x[k + 3], S42, 0x8f0ccc92); /* 54 */
                    II(ref c, d, a, b, x[k + 10], S43, 0xffeff47d); /* 55 */
                    II(ref b, c, d, a, x[k + 1], S44, 0x85845dd1); /* 56 */
                    II(ref a, b, c, d, x[k + 8], S41, 0x6fa87e4f); /* 57 */
                    II(ref d, a, b, c, x[k + 15], S42, 0xfe2ce6e0); /* 58 */
                    II(ref c, d, a, b, x[k + 6], S43, 0xa3014314); /* 59 */
                    II(ref b, c, d, a, x[k + 13], S44, 0x4e0811a1); /* 60 */
                    II(ref a, b, c, d, x[k + 4], S41, 0xf7537e82); /* 61 */
                    II(ref d, a, b, c, x[k + 11], S42, 0xbd3af235); /* 62 */
                    II(ref c, d, a, b, x[k + 2], S43, 0x2ad7d2bb); /* 63 */
                    II(ref b, c, d, a, x[k + 9], S44, 0xeb86d391); /* 64 */

                    A += a;
                    B += b;
                    C += c;
                    D += d;
                }
                return new UInt32[] { A, B, C, D };
            }
            public static byte[] MD5Array(byte[] input)
            {
                MD5_Init();
                UInt32[] block = MD5_Append(input);
                UInt32[] bits = MD5_Trasform(block);

                /* Encodes bits (UInt32[]) into output (byte[]). Assumes len is
                 * a multiple of 4.
                   */
                byte[] output = new byte[bits.Length * 4];
                for (int i = 0, j = 0; i < bits.Length; i++, j += 4)
                {
                    output[j] = (byte)(bits[i] & 0xff);
                    output[j + 1] = (byte)((bits[i] >> 8) & 0xff);
                    output[j + 2] = (byte)((bits[i] >> 16) & 0xff);
                    output[j + 3] = (byte)((bits[i] >> 24) & 0xff);
                }
                return output;
            }

            public static string ArrayToHexString(byte[] array, bool uppercase)
            {
                string hexString = "";
                string format = "x2";
                if (uppercase)
                {
                    format = "X2";
                }
                foreach (byte b in array)
                {
                    hexString += b.ToString(format);
                }
                return hexString;
            }

            public static string MDString(string message)
            {
                char[] c = message.ToCharArray();
                byte[] b = new byte[c.Length];
                for (int i = 0; i < c.Length; i++)
                {
                    b[i] = (byte)c[i];
                }
                byte[] digest = MD5Array(b);
                return ArrayToHexString(digest, false);
            }
        }
        string testMd5()
        {

            string conc = "StringBuilder sb = new StringBuilder(1024);StringBuilder sb = new StringBuilder(1024);StringBuilder sb = new StringBuilder(1024);StringBuilder sb = new StringBuilder(1024);";
            conc = conc + conc + conc + conc + conc + conc + conc + conc;
            string about = "";
            for (int i = 0; i < 100000; i++ )
            {
               about = MD5.MDString(conc);
            }
            return about;
        }
        private void button1_Click(object sender, EventArgs e)
        {
            DateTime fbeforDT = System.DateTime.Now;
            fibonacci(45);
            DateTime fafterDT = System.DateTime.Now;
            TimeSpan ts = fafterDT.Subtract(fbeforDT);
            textBox1.Text = string.Format("fibonacci spend: {0}ms.", ts.TotalMilliseconds);

            DateTime nbeforDT = System.DateTime.Now;
            numberConvert();
            DateTime nafterDT = System.DateTime.Now;
            TimeSpan nts = nafterDT.Subtract(nbeforDT);
            textBox2.Text = string.Format("numberConvert spend: {0}ms.", nts.TotalMilliseconds);

            DateTime sbeforDT = System.DateTime.Now;
            stringAppend();
            DateTime safterDT = System.DateTime.Now;
            TimeSpan sts = safterDT.Subtract(sbeforDT);
            textBox3.Text = string.Format("stringAppend spend: {0}ms.", sts.TotalMilliseconds);

            DateTime mbeforDT = System.DateTime.Now;
            testMd5();
            DateTime mafterDT = System.DateTime.Now;
            TimeSpan mts = mafterDT.Subtract(mbeforDT);
            textBox4.Text = string.Format("testMd5 spend: {0}ms.", mts.TotalMilliseconds);

        }
    }

}

这是C#编译出来Release的页面：

这是Snapman系统中写的TCC脚本代码：

int fibonacci(int n)
{
    if(n==1||n==2)
        return 1;
    return fibonacci(n-1) + fibonacci(n-2);
}
char* numberConvert()
{
    char* result = (char*)malloc(128);
    for (int i = 0; i < 14000000; i++ )
    {
        itoa(i,result,10);
    }
    return result;
}
char* stringAppend()
{
    char* conc = "StringBuilder sb = new StringBuilder(1024);";
    char* sb = (char*)malloc(1024);
    int len = 1024, cl = strlen(conc), curlen = 0;
    for (int i = 0; i < 1400; i++)
    {
        free(sb);
        len = 1024;
        curlen = 0;
        sb = (char*)malloc(1024);
        for(int j = 0; j < 10000; j++)
        {
            if(curlen + cl > len)
            {
                sb = (char*)realloc(sb,len*2);
                len *= 2;
            }
            memcpy(sb+curlen,conc,cl);
            curlen += cl;
        }
    }
    sb[curlen] = 0;
    return sb;
}

#define S11 7
#define S12 12
#define S13 17
#define S14 22
#define S21 5
#define S22 9
#define S23 14
#define S24 20
#define S31 4
#define S32 11
#define S33 16
#define S34 23
#define S41 6
#define S42 10
#define S43 15
#define S44 21

static unsigned char PADDING[64] = {
    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

#define   F(x, y, z) (((x) & (y)) | ((~x) & (z)))
#define   G(x, y, z) (((x) & (z)) | ((y) & (~z)))
#define   H(x, y, z) ((x) ^ (y) ^ (z))
#define   I(x, y, z) ((y) ^ ((x) | (~z)))

#define   ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))

#define   FF(a, b, c, d, x, s, ac) {   (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac);   (a) = ROTATE_LEFT ((a), (s));   (a) += (b);   }
#define   GG(a, b, c, d, x, s, ac) {   (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac);   (a) = ROTATE_LEFT ((a), (s));   (a) += (b);   }
#define   HH(a, b, c, d, x, s, ac) {   (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac);   (a) = ROTATE_LEFT ((a), (s));   (a) += (b);   }
#define   II(a, b, c, d, x, s, ac) {   (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac);   (a) = ROTATE_LEFT ((a), (s));   (a) += (b); }

typedef unsigned char *POINTER;
typedef unsigned short int UINT2;
typedef unsigned long int UINT4;
typedef struct
{
    UINT4 state[4];
    UINT4 count[2];
    unsigned char buffer[64];
} MD5_CTX;

void Encode(unsigned char *output, UINT4 *input, unsigned int len)
{
    unsigned int i, j;

    for (i = 0, j = 0; j < len; i++, j += 4) {
        output[j]   = (unsigned char)(input[i] & 0xff);
        output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
        output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
        output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
    }
}

void Decode(UINT4 *output, unsigned char *input, unsigned int len)
{
    unsigned int i, j;

    for (i = 0, j = 0; j < len; i++, j += 4)
    {
        output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
            (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
    }
}

void MD5Transform (UINT4 state[4], unsigned char block[64])
{
    UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
    Decode (x, block, 64);
    FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
    FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
    FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
    FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
    FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
    FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
    FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
    FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
    FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
    FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
    FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
    FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
    FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
    FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
    FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
    FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
    GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
    GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
    GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
    GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
    GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
    GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
    GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
    GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
    GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
    GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
    GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
    GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
    GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
    GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
    GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
    GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
    HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
    HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
    HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
    HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
    HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
    HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
    HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
    HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
    HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
    HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
    HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
    HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
    HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
    HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
    HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
    HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
    II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
    II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
    II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
    II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
    II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
    II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
    II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
    II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
    II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
    II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
    II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
    II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
    II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
    II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
    II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
    II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
    state[0] += a;
    state[1] += b;
    state[2] += c;
    state[3] += d;
    memset ((POINTER)x, 0, sizeof (x));
}

void MD5Init(MD5_CTX *context)
{
    context->count[0] = context->count[1] = 0;
    context->state[0] = 0x67452301;
    context->state[1] = 0xefcdab89;
    context->state[2] = 0x98badcfe;
    context->state[3] = 0x10325476;
}

void MD5Update(MD5_CTX *context, unsigned char *input, unsigned int inputLen)
{
    unsigned int i, index, partLen;

    index = (unsigned int)((context->count[0] >> 3) & 0x3F);
    if ((context->count[0] += ((UINT4)inputLen << 3))    < ((UINT4)inputLen << 3))
        context->count[1]++;
    context->count[1] += ((UINT4)inputLen >> 29);
    partLen = 64 - index;
    if (inputLen >= partLen)
    {
        memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
        MD5Transform(context->state, context->buffer);

        for (i = partLen; i + 63 < inputLen; i += 64)
            MD5Transform (context->state, &input[i]);
        index = 0;
    }
    else
    {
        i = 0;
    }

    memcpy((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
}

void MD5Final(unsigned char digest[16], MD5_CTX *context)
{
    unsigned char bits[8];
    unsigned int index, padLen;

    Encode (bits, context->count, 8);
    index = (unsigned int)((context->count[0] >> 3) & 0x3f);
    padLen = (index < 56) ? (56 - index) : (120 - index);
    MD5Update (context, PADDING, padLen);
    MD5Update (context, bits, 8);
    Encode (digest, context->state, 16);
    memset ((POINTER)context, 0, sizeof (*context));
}

void MD5Digest(char *pszInput, unsigned long nInputSize, char *pszOutPut)
{
    MD5_CTX context;
    unsigned int len = strlen (pszInput);
    MD5Init (&context);
    MD5Update (&context, (unsigned char *)pszInput, len);
    MD5Final ((unsigned char *)pszOutPut, &context);
}

char* MD5Buffer( const char *pszInput, UINT nInputSize )
{
    char    szDigest[16];
    char*   szResult = (char*)malloc(56);
    memset(szResult,0,56);
    MD5_CTX context;
    MD5Init (&context);
    MD5Update (&context, (unsigned char *)pszInput, nInputSize);
    MD5Final ((unsigned char *)szDigest, &context);
    int i;
    for (i=0;i<16;i++) sprintf (szResult+strlen(szResult),"%02X",(unsigned char)szDigest[i]);
    return szResult;
}
char* testMd5()
{
    char* conc = "StringBuilder sb = new StringBuilder(1024);StringBuilder sb = new StringBuilder(1024);StringBuilder sb = new StringBuilder(1024);StringBuilder sb = new StringBuilder(1024);";
    char* p = (char*)malloc(2048);
    char* about = NULL;
    int len = 0;
    memset(p,0,2048);
    strcat(p,conc);
    strcat(p,conc);
    strcat(p,conc);
    strcat(p,conc);
    strcat(p,conc);
    strcat(p,conc);
    strcat(p,conc);
    strcat(p,conc);
    len = strlen(p);
    for (int i = 0; i < 100000; i++ )
    {
        if(about)free(about);
        about = MD5Buffer(p,len);
    }
    return about;
}
void main()
{
    int starTicc = GetTickCount();
    fibonacci(45);
    wPrint(L"fibonacci spend: %dms",GetTickCount() - starTicc);

    starTicc = GetTickCount();
    free(numberConvert());
    wPrint(L"numberConvert spend: %dms",GetTickCount() - starTicc);

    starTicc = GetTickCount();
    free(stringAppend());
    wPrint(L"stringAppend spend: %dms",GetTickCount() - starTicc);

    starTicc = GetTickCount();
    free(testMd5());
    wPrint(L"testMd5 spend: %dms",GetTickCount() - starTicc);
}

这是Snapman页面：

两种代码的设计和实现方法完全一样，其运行结果对比：

C#执行结果：

Snapman执行结果：

结论：

1、函数执行C#要比Snapman慢一些

2、数字转换C#要比Snapman慢一倍多

3、字符串叠加C#使用了最高效的StringBuilder，执行速度和Snapman差不多

4、执行Md5算法，C#就要比Snapman慢了11倍

所以Snapman的脚本运行速度是非常快速的。


Exprtk函数

Help >
Exprtk函数

Exprtk的功能函数


abs

Help > Exprtk函数 >
abs

abs ： Absolute value of x.

eg: abs(x)


avg

Help > Exprtk函数 >
avg

avg ：Average of all the inputs.

eg: avg(x,y,z,w,u,v) == (x + y + z + w + u + v) / 6


ceil

Help > Exprtk函数 >
ceil

ceil ：Smallest integer that is greater than or equal to x.

eg: ceil(x)


clamp

Help > Exprtk函数 >
clamp

clamp ： Clamp x in range between r0 and r1, where r0 < r1.

eg: clamp(r0,x,r1)


equal

Help > Exprtk函数 >
equal

equal : Equality test between x and y using normalized epsilon

eg : equal(x,y)


erf

Help > Exprtk函数 >
erf

erf : Error function of x.

eg: erf(x)


erfc

Help > Exprtk函数 >
erfc

erfc : Complimentary error function of x.

eg: erfc(x)


exp

Help > Exprtk函数 >
exp

exp : e to the power of x.

eg: exp(x)


expm1

Help > Exprtk函数 >
expm1

expm1 : e to the power of x minus 1, where x is very small.

eg: expm1(x)


floor

Help > Exprtk函数 >
floor

floor : Largest integer that is less than or equal to x.

eg: floor(x)


frac

Help > Exprtk函数 >
frac

frac : Fractional portion of x.

eg: frac(x)


hypot

Help > Exprtk函数 >
hypot

hypot : Hypotenuse of x and y

eg: hypot(x,y) = sqrt(x*x + y*y)


iclamp

Help > Exprtk函数 >
iclamp

iclamp : Inverse-clamp x outside of the range r0 and r1. Where r0 < r1. If x is within the range it will snap to the closest bound.

eg: iclamp(r0,x,r1)


inrange

Help > Exprtk函数 >
inrange

inrange : In-range returns 'true' when x is within the range r0 and r1. Where r0 < r1.

eg: inrange(r0,x,r1)


log

Help > Exprtk函数 >
log

log : Natural logarithm of x.

eg: log(x)


log10

Help > Exprtk函数 >
log10

log10 : Base 10 logarithm of x.

eg: log10(x)


log1p

Help > Exprtk函数 >
log1p

log1p : Natural logarithm of 1 + x, where x is very small.

eg: log1p(x)


log2

Help > Exprtk函数 >
log2

log2 : Base 2 logarithm of x.

eg: log2(x)


logn

Help > Exprtk函数 >
logn

logn : Base N logarithm of x. where n is a positive integer.

eg: logn(x,8)


max

Help > Exprtk函数 >
max

max : Largest value of all the inputs.

eg: max(x,y,z,w,u,v)


min

Help > Exprtk函数 >
min

min : Smallest value of all the inputs.

eg: min(x,y,z,w,u)


mul

Help > Exprtk函数 >
mul

mul : Product of all the inputs.

eg: mul(x,y,z,w,u,v,t) == (x * y * z * w * u * v * t)


ncdf

Help > Exprtk函数 >
ncdf

ncdf : Normal cumulative distribution function.

eg: ncdf(x)


nequal

Help > Exprtk函数 >
nequal

nequal : Not-equal test between x and y using normalized epsilon

eg : nequal (x,y)


pow

Help > Exprtk函数 >
pow

pow : x to the power of y.

eg: pow(x,y) == x ^ y


root

Help > Exprtk函数 >
root

root : Nth-Root of x. where n is a positive integer.

eg: root(x,3) == x^(1/3)


round

Help > Exprtk函数 >
round

round : Round x to the nearest integer.

eg: round(x)


roundn

Help > Exprtk函数 >
roundn

roundn : Round x to n decimal places (eg: roundn(x,3)) where n > 0 and is an integer.

eg: roundn(1.2345678,4) == 1.2346


sgn

Help > Exprtk函数 >
sgn

sgn : Sign of x, -1 where x < 0, +1 where x > 0, else zero.

eg: sgn(x)


sqrt

Help > Exprtk函数 >
sqrt

sqrt : Square root of x, where x >= 0.

eg: sqrt(x)


sum

Help > Exprtk函数 >
sum

sum : Sum of all the inputs.

eg: sum(x,y,z,w,u,v,t) == (x + y + z + w + u + v + t)


swap

Help > Exprtk函数 >
swap

swap : <=>, Swap the values of the variables x and y and return the current value of y.

eg: swap(x,y) or x <=> y


trunc

Help > Exprtk函数 >
trunc

trunc : Integer portion of x.

eg: trunc(x)


acos

Help > Exprtk函数 >
acos

acos : Arc cosine of x expressed in radians. Interval [-1,+1]

eg: acos(x)


acosh

Help > Exprtk函数 >
acosh

acosh : Inverse hyperbolic cosine of x expressed in radians.

eg: acosh(x)


asin

Help > Exprtk函数 >
asin

asin : Arc sine of x expressed in radians. Interval [-1,+1]

eg: asin(x)


asinh

Help > Exprtk函数 >
asinh

asinh : Inverse hyperbolic sine of x expressed in radians.

eg: asinh(x)


atan

Help > Exprtk函数 >
atan

atan : Arc tangent of x expressed in radians. Interval [-1,+1]

eg: atan(x)


atan2

Help > Exprtk函数 >
atan2

atan2 : Arc tangent of (x / y) expressed in radians. [-pi,+pi]

eg: atan2(x,y)


atanh

Help > Exprtk函数 >
atanh

atanh : Inverse hyperbolic tangent of x expressed in radians.

eg: atanh(x)


cos

Help > Exprtk函数 >
cos

cos : Cosine of x.

eg: cos(x)


cosh

Help > Exprtk函数 >
cosh

cosh : Hyperbolic cosine of x.

eg: cosh(x)


cot

Help > Exprtk函数 >
cot

cot : Cotangent of x.

eg: cot(x)


csc

Help > Exprtk函数 >
csc

csc : Cosecant of x.

eg: csc(x)


sec

Help > Exprtk函数 >
sec

sec : Secant of x.

eg: sec(x)


sin

Help > Exprtk函数 >
sin

sin : Sine of x.

eg: sin(x)


sinc

Help > Exprtk函数 >
sinc

sinc : Sine cardinal of x.

eg: sinc(x)


sinh

Help > Exprtk函数 >
sinh

sinh : Hyperbolic sine of x.

eg: sinh(x)


tan

Help > Exprtk函数 >
tan

tan : Tangent of x.

eg: tan(x)


tanh

Help > Exprtk函数 >
tanh

tanh : Hyperbolic tangent of x.

eg: tanh(x)


deg2rad

Help > Exprtk函数 >
deg2rad

deg2rad : Convert x from degrees to radians.

eg: deg2rad(x)


deg2grad

Help > Exprtk函数 >
deg2grad

deg2grad : Convert x from degrees to gradians.

eg: deg2grad(x)


rad2deg

Help > Exprtk函数 >
rad2deg

rad2deg : Convert x from radians to degrees.

eg: rad2deg(x)


grad2deg

Help > Exprtk函数 >
grad2deg

grad2deg : Convert x from gradians to degrees.

eg: grad2deg(x)


in

Help > Exprtk函数 >
in

in : True only if x is a substring of y.

eg: x in y or 'abc' in 'abcdefgh'


like

Help > Exprtk函数 >
like

like : True only if the string x matches the pattern y.Available wildcard characters are '*' and '?' denoting zero or more and zero or one matches respectively.

eg: x like y or 'abcdefgh' like 'a?d*h'


ilike

Help > Exprtk函数 >
ilike

ilike : True only if the string x matches the pattern y in a case insensitive manner. Available wildcard characters are '*' and '?' denoting zero or more and zero or one matches respectively.

eg: x ilike y or 'a1B2c3D4e5F6g7H' ilike 'a?d*h'


tostring

Help > Exprtk函数 >
tostring
tostring : double tostring(string str); //将字符串转换成数字


tonumber

Help > Exprtk函数 >
tonumber
tonumber : string tonumber(double data); //将数字转换成字符串


toupper

Help > Exprtk函数 >
toupper

toupper : string toupper(string str); //将字符串转换成大写


tolower

Help > Exprtk函数 >
tolower

tolower : string tolower(string str); //将字符串转换成小写


setprogress

Help > Exprtk函数 >
setprogress

setprogress : void setprogress(doublen); //设置进度条的进度为n


get_

Help > Exprtk函数 >
get_
get_ : string get_(introw,int col); //获取表格中指定行列单元格的字符串


set_

Help > Exprtk函数 >
set_

set_ : void set_(int row,int col,string str ); //设置表格中指定行列单元格的字符串


get

Help > Exprtk函数 >
get

get : double get(int row,int col ); //获取表格中指定行列单元格的数字


set

Help > Exprtk函数 >
set
set : void set(introw,int col,double data ); //设置表格中指定行列单元格的数字


save

Help > Exprtk函数 >
save

save : void save (); //保存当前电子表格


sleep

Help > Exprtk函数 >
sleep

sleep : void sleep(double n ); //休眠n毫秒


gettickcount

Help > Exprtk函数 >
gettickcount
gettickcount : double gettickcount( ); //获取当前时间的毫秒数


TCC语言函数库

Help >
TCC语言函数库

TCC语言的标准头文件及函数说明


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <float.h>

简介

C 标准库的 float.h 头文件包含了一组与浮点值相关的依赖于平台的常量。这些常量是由 ANSI C 提出的，这让程序更具有可移植性。在讲解这些常量之前，最好先弄清楚浮点数是由下面四个元素组成的：

组件 | 组件描述
S | 符号 ( +/- )
b | 指数表示的基数，2 表示二进制，10 表示十进制，16 表示十六进制，等等...
e | 指数，一个介于最小值 emin 和最大值 emax 之间的整数。
p | 精度，基数 b 的有效位数

基于以上 4 个组成部分，一个浮点数的值如下：

floating-point = ( S ) p x be

或

floating-point = (+/-) precision x baseexponent

库宏

下面的值是特定实现的，且是通过 #define 指令来定义的，这些值都不得低于下边所给出的值。请注意，所有的实例 FLT 是指类型 float，DBL 是指类型 double，LDBL 是指类型 long double。

宏 | 描述
FLT_ROUNDS 定义浮点加法的舍入模式，它可以是下列任何一个值：

  • -1 - 无法确定

  • 0 - 趋向于零

  • 1 - 去最近的值

  • 2 - 趋向于正无穷

  • 3 - 趋向于负无穷

FLT_RADIX 2 | 这个宏定义了指数表示的基数。基数 2 表示二进制，基数 10 表示十进制，基数 16 表示十六进制。

FLT_MANT_DIG

DBL_MANT_DIG

LDBL_MANT_DIG

 这些宏定义了 FLT_RADIX 基数中的位数。

FLT_DIG 6

DBL_DIG 10

LDBL_DIG 10

 这些宏定义了舍入后不会改变表示的十进制数字的最大值（基数 10）。

FLT_MIN_EXP

DBL_MIN_EXP

LDBL_MIN_EXP

 这些宏定义了基数为 FLT_RADIX 时的指数的最小负整数值。

FLT_MIN_10_EXP -37

DBL_MIN_10_EXP -37

LDBL_MIN_10_EXP -37

 这些宏定义了基数为 10 时的指数的最小负整数值。

FLT_MAX_EXP

DBL_MAX_EXP

LDBL_MAX_EXP

 这些宏定义了基数为 FLT_RADIX 时的指数的最大整数值。

FLT_MAX_10_EXP +37

DBL_MAX_10_EXP +37

LDBL_MAX_10_EXP +37

 这些宏定义了基数为 10 时的指数的最大整数值。

FLT_MAX 1E+37

DBL_MAX 1E+37

LDBL_MAX 1E+37

 这些宏定义最大的有限浮点值。

FLT_EPSILON 1E-5

DBL_EPSILON 1E-9

LDBL_EPSILON 1E-9

 这些宏定义了可表示的最小有效数字。

FLT_MIN 1E-37

DBL_MIN 1E-37

LDBL_MIN 1E-37

 这些宏定义了最小的浮点值。

实例

下面的实例演示了 float.h 文件中定义的一些常量的使用。

#include <stdio.h>
#include <float.h>

int main()
{
   printf("The maximum value of float = %.10e\n", FLT_MAX);
   printf("The minimum value of float = %.10e\n", FLT_MIN);

   printf("The number of digits in the number = %.10e\n", FLT_MANT_DIG);
}

让我们编译和运行上面的程序，这将产生下列结果：

The maximum value of float = 3.4028234664e+38
The minimum value of float = 1.1754943508e-38
The number of digits in the number = 7.2996655210e-312


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <ctype.h>

简介

C 标准库的 ctype.h 头文件提供了一些函数，可用于测试和映射字符。

这些函数接受 int 作为参数，它的值必须是 EOF 或表示为一个无符号字符。

如果参数 c 满足描述的条件，则这些函数返回非零（true）。如果参数 c 不满足描述的条件，则这些函数返回零。

库函数

下面列出了头文件 ctype.h 中定义的函数：

序号 | 函数 & 描述
1 | int isalnum(int c) 该函数检查所传的字符是否是字母和数字。
2 | int isalpha(int c) 该函数检查所传的字符是否是字母。
3 | int iscntrl(int c) 该函数检查所传的字符是否是控制字符。
4 | int isdigit(int c) 该函数检查所传的字符是否是十进制数字。
5 | int isgraph(int c) 该函数检查所传的字符是否有图形表示法。
6 | int islower(int c) 该函数检查所传的字符是否是小写字母。
7 | int isprint(int c) 该函数检查所传的字符是否是可打印的。
8 | int ispunct(int c) 该函数检查所传的字符是否是标点符号字符。
9 | int isspace(int c) 该函数检查所传的字符是否是空白字符。
10 | int isupper(int c) 该函数检查所传的字符是否是大写字母。
11 | int isxdigit(int c) 该函数检查所传的字符是否是十六进制数字。

标准库还包含了两个转换函数，它们接受并返回一个 "int"

序号 | 函数 & 描述
1 | int tolower(int c) 该函数把大写字母转换为小写字母。
2 | int toupper(int c) 该函数把小写字母转换为大写字母。

字符类

序号 | 字符类 & 描述
1 | 数字 完整的数字集合 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }
2 | 十六进制数字 集合 { 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f }
3 | 小写字母 集合 { a b c d e f g h i j k l m n o p q r s t u v w x y z }
4 | 大写字母 集合 {A B C D E F G H I J K L M N O P Q R S T U V W X Y Z }
5 | 字母 小写字母和大写字母的集合
6 | 字母数字字符 数字、小写字母和大写字母的集合
7 | 标点符号字符 集合 ! " # $ % & ' ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ ` { | } ~
8 | 图形字符 字母数字字符和标点符号字符的集合
9 | 空格字符 制表符、换行符、垂直制表符、换页符、回车符、空格符的集合。
10 | 可打印字符 字母数字字符、标点符号字符和空格字符的集合。
11 | 控制字符 在 ASCII 编码中，这些字符的八进制代码是从 000 到 037，以及 177（DEL）。
12 | 空白字符 包括空格符和制表符。
13 | 字母字符 小写字母和大写字母的集合。


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <limits.h>

简介

limits.h 头文件决定了各种变量类型的各种属性。定义在该头文件中的宏限制了各种变量类型（比如 char、int 和 long）的值。

这些限制指定了变量不能存储任何超出这些限制的值，例如一个无符号可以存储的最大值是 255。

库宏

下面的值是特定实现的，且是通过 #define 指令来定义的，这些值都不得低于下边所给出的值。

宏 | 值 | 描述
CHAR_BIT | 8 | 定义一个字节的比特数。
SCHAR_MIN | -128 | 定义一个有符号字符的最小值。
SCHAR_MAX | 127 | 定义一个有符号字符的最大值。
UCHAR_MAX | 255 | 定义一个无符号字符的最大值。
CHAR_MIN | 0 | 定义类型 char 的最小值，如果 char 表示负值，则它的值等于 SCHAR_MIN，否则等于 0。
CHAR_MAX | 127 | 定义类型 char 的最大值，如果 char 表示负值，则它的值等于 SCHAR_MAX，否则等于 UCHAR_MAX。
MB_LEN_MAX | 1 | 定义多字节字符中的最大字节数。
SHRT_MIN | -32768 | 定义一个短整型的最小值。
SHRT_MAX | +32767 | 定义一个短整型的最大值。
USHRT_MAX | 65535 | 定义一个无符号短整型的最大值。
INT_MIN | -32768 | 定义一个整型的最小值。
INT_MAX | +32767 | 定义一个整型的最大值。
UINT_MAX | 65535 | 定义一个无符号整型的最大值。
LONG_MIN | -2147483648 | 定义一个长整型的最小值。
LONG_MAX | +2147483647 | 定义一个长整型的最大值。
ULONG_MAX | 4294967295 | 定义一个无符号长整型的最大值。

实例

下面的实例演示了 limit.h 文件中定义的一些常量的使用。

#include <stdio.h>
#include <limits.h>

int main()
{

   printf("The number of bits in a byte %d\n", CHAR_BIT);

   printf("The minimum value of SIGNED CHAR = %d\n", SCHAR_MIN);
   printf("The maximum value of SIGNED CHAR = %d\n", SCHAR_MAX);
   printf("The maximum value of UNSIGNED CHAR = %d\n", UCHAR_MAX);

   printf("The minimum value of SHORT INT = %d\n", SHRT_MIN);
   printf("The maximum value of SHORT INT = %d\n", SHRT_MAX);

   printf("The minimum value of INT = %d\n", INT_MIN);
   printf("The maximum value of INT = %d\n", INT_MAX);

   printf("The minimum value of CHAR = %d\n", CHAR_MIN);
   printf("The maximum value of CHAR = %d\n", CHAR_MAX);

   printf("The minimum value of LONG = %ld\n", LONG_MIN);
   printf("The maximum value of LONG = %ld\n", LONG_MAX);

   return(0);
}

让我们编译和运行上面的程序，这将产生下列结果：

The number of bits in a byte 8
The minimum value of SIGNED CHAR = -128
The maximum value of SIGNED CHAR = 127
The maximum value of UNSIGNED CHAR = 255
The minimum value of SHORT INT = -32768
The maximum value of SHORT INT = 32767
The minimum value of INT = -32768
The maximum value of INT = 32767
The minimum value of CHAR = -128
The maximum value of CHAR = 127
The minimum value of LONG = -2147483648
The maximum value of LONG = 2147483647


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <locale.h>

简介

locale.h 头文件定义了特定地域的设置，比如日期格式和货币符号。接下来我们将介绍一些宏，以及一个重要的结构 struct lconv 和两个重要的函数。

库宏

下面列出了头文件 locale.h 中定义的宏，这些宏将在下列的两个函数中使用：

序号 | 宏 & 描述
1 | LC_ALL 设置下面的所有选项。
2 | LC_COLLATE 影响 strcoll 和 strxfrm 函数。
3 | LC_CTYPE 影响所有字符函数。
4 | LC_MONETARY 影响 localeconv 函数提供的货币信息。
5 | LC_NUMERIC 影响 localeconv 函数提供的小数点格式化和信息。
6 | LC_TIME 影响 strftime 函数。

库函数

下面列出了头文件 locale.h 中定义的函数：

序号 | 函数 & 描述
1 | char *setlocale(int category, const char *locale) 设置或读取地域化信息。
2 | struct lconv *localeconv(void) 设置或读取地域化信息。

库结构

typedef struct {
   char *decimal_point;
   char *thousands_sep;
   char *grouping;
   char *int_curr_symbol;
   char *currency_symbol;
   char *mon_decimal_point;
   char *mon_thousands_sep;
   char *mon_grouping;
   char *positive_sign;
   char *negative_sign;
   char int_frac_digits;
   char frac_digits;
   char p_cs_precedes;
   char p_sep_by_space;
   char n_cs_precedes;
   char n_sep_by_space;
   char p_sign_posn;
   char n_sign_posn;
} lconv

以下是各字段的描述：

序号 | 字段 & 描述
1 | decimal_point 用于非货币值的小数点字符。
2 | thousands_sep 用于非货币值的千位分隔符。
3 | grouping 一个表示非货币量中每组数字大小的字符串。每个字符代表一个整数值，每个整数指定当前组的位数。值为 0 意味着前一个值将应用于剩余的分组。
4 | int_curr_symbol 国际货币符号使用的字符串。前三个字符是由 ISO 4217:1987 指定的，第四个字符用于分隔货币符号和货币量。
5 | currency_symbol 用于货币的本地符号。
6 | mon_decimal_point 用于货币值的小数点字符。
7 | mon_thousands_sep 用于货币值的千位分隔符。
8 | mon_grouping 一个表示货币值中每组数字大小的字符串。每个字符代表一个整数值，每个整数指定当前组的位数。值为 0 意味着前一个值将应用于剩余的分组。
9 | positive_sign 用于正货币值的字符。
10 | negative_sign 用于负货币值的字符。
11 | int_frac_digits 国际货币值中小数点后要显示的位数。
12 | frac_digits 货币值中小数点后要显示的位数。
13 | p_cs_precedes 如果等于 1，则 currency_symbol 出现在正货币值之前。如果等于 0，则 currency_symbol 出现在正货币值之后。
14 | p_sep_by_space 如果等于 1，则 currency_symbol 和正货币值之间使用空格分隔。如果等于 0，则 currency_symbol 和正货币值之间不使用空格分隔。
15 | n_cs_precedes 如果等于 1，则 currency_symbol 出现在负货币值之前。如果等于 0，则 currency_symbol 出现在负货币值之后。
16 | n_sep_by_space 如果等于 1，则 currency_symbol 和负货币值之间使用空格分隔。如果等于 0，则 currency_symbol 和负货币值之间不使用空格分隔。
17 | p_sign_posn 表示正货币值中正号的位置。
18 | n_sign_posn 表示负货币值中负号的位置。

下面的值用于 p_sign_posn 和 n_sign_posn:

值 | 描述
0 | 封装值和 currency_symbol 的括号。
1 | 放置在值和 currency_symbol 之前的符号。
2 | 放置在值和 currency_symbol 之后的符号。
3 | 紧挨着放置在值和 currency_symbol 之前的符号。
4 | 紧挨着放置在值和 currency_symbol 之后的符号。


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <math.h>

简介

math.h 头文件定义了各种数学函数和一个宏。在这个库中所有可用的功能都带有一个 double 类型的参数，且都返回 double 类型的结果。

库宏

下面是这个库中定义的唯一的一个宏：

序号 | 宏 & 描述
1 | HUGE_VAL 当函数的结果不可以表示为浮点数时。如果是因为结果的幅度太大以致于无法表示，则函数会设置 errno 为 ERANGE 来表示范围错误，并返回一个由宏 HUGE_VAL 或者它的否定（- HUGE_VAL）命名的一个特定的很大的值。 如果结果的幅度太小，则会返回零值。在这种情况下，error 可能会被设置为 ERANGE，也有可能不会被设置为 ERANGE。

库函数

下面列出了头文件 math.h 中定义的函数：

序号 函数 & 描述
1 double acos(double x)
返回以弧度表示的 x 的反余弦。
2 double asin(double x)
返回以弧度表示的 x 的反正弦。
3 double atan(double x)
返回以弧度表示的 x 的反正切。
4 double atan2(double y, double x)
返回以弧度表示的 y/x 的反正切。y 和 x 的值的符号决定了正确的象限。
5 double cos(double x)
返回弧度角 x 的余弦。
6 double cosh(double x)
返回 x 的双曲余弦。
7 double sin(double x)
返回弧度角 x 的正弦。
8 double sinh(double x)
返回 x 的双曲正弦。
9 double tanh(double x)
返回 x 的双曲正切。
10 double exp(double x)
返回 e 的 x 次幂的值。
11 double frexp(double x, int *exponent)
把浮点数 x 分解成尾数和指数。返回值是尾数，并将指数存入 exponent 中。所得的值是 x = mantissa * 2 ^ exponent。
12 double ldexp(double x, int exponent)
返回 x 乘以 2 的 exponent 次幂。
13 double log(double x)
返回 x 的自然对数（基数为 e 的对数）。
14 double log10(double x)
返回 x 的常用对数（基数为 10 的对数）。
15 double modf(double x, double *integer)
返回值为小数部分（小数点后的部分），并设置 integer 为整数部分。
16 double pow(double x, double y)
返回 x 的 y 次幂。
17 double sqrt(double x)
返回 x 的平方根。
18 double ceil(double x)
返回大于或等于 x 的最小的整数值。
19 double fabs(double x)
返回 x 的绝对值。
20 double floor(double x)
返回小于或等于 x 的最大的整数值。
21 double fmod(double x, double y)
返回 x 除以 y 的余数。


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <stdarg.h>

简介

stdarg.h 头文件定义了一个变量类型 va_list 和三个宏，这三个宏可用于在参数个数未知（即参数个数可变）时获取函数中的参数。

可变参数的函数通在参数列表的末尾是使用省略号(,...)定义的。

库变量

下面是头文件 stdarg.h 中定义的变量类型：

序号 | 变量 & 描述
1 | va_list 这是一个适用于 va_start()、va_arg() 和 va_end() 这三个宏存储信息的类型。

库宏

下面是头文件 stdarg.h 中定义的宏：

序号 | 宏 & 描述
1 | void va_start(va_list ap, last_arg) 这个宏初始化 ap 变量，它与 va_arg 和 va_end 宏是一起使用的。last_arg 是最后一个传递给函数的已知的固定参数，即省略号之前的参数。
2 | type va_arg(va_list ap, type) 这个宏检索函数参数列表中类型为 type 的下一个参数。
3 | void va_end(va_list ap) 这个宏允许使用了 va_start 宏的带有可变参数的函数返回。如果在从函数返回之前没有调用 va_end，则结果为未定义。


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <stddef.h>

简介

stddef .h 头文件定义了各种变量类型和宏。这些定义中的大部分也出现在其它头文件中。

库变量

下面是头文件 stddef.h 中定义的变量类型：

序号 | 变量 & 描述
1 | ptrdiff_t 这是有符号整数类型，它是两个指针相减的结果。
2 | size_t 这是无符号整数类型，它是 sizeof 关键字的结果。
3 | wchar_t 这是一个宽字符常量大小的整数类型。

库宏

下面是头文件 stddef.h 中定义的宏：

序号 | 宏 & 描述
1 | NULL 这个宏是一个空指针常量的值。
2 | offsetof(type, member-designator) 这会生成一个类型为 size_t 的整型常量，它是一个结构成员相对于结构开头的字节偏移量。成员是由 member-designator 给定的，结构的名称是在 type 中给定的。


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <stdio.h>

简介

stdio .h 头文件定义了三个变量类型、一些宏和各种函数来执行输入和输出。

库变量

下面是头文件 stdio.h 中定义的变量类型：

序号 | 变量 & 描述
1 | size_t 这是无符号整数类型，它是 sizeof 关键字的结果。
2 | FILE 这是一个适合存储文件流信息的对象类型。
3 | fpos_t 这是一个适合存储文件中任何位置的对象类型。

库宏

下面是头文件 stdio.h 中定义的宏：

序号 | 宏 & 描述
1 | NULL 这个宏是一个空指针常量的值。
2 | _IOFBF、_IOLBF 和 _IONBF 这些宏扩展了带有特定值的整型常量表达式，并适用于 setvbuf 函数的第三个参数。
3 | BUFSIZ 这个宏是一个整数，该整数代表了 setbuf 函数使用的缓冲区大小。
4 | EOF 这个宏是一个表示已经到达文件结束的负整数。
5 | FOPEN_MAX 这个宏是一个整数，该整数代表了系统可以同时打开的文件数量。
6 | FILENAME_MAX 这个宏是一个整数，该整数代表了字符数组可以存储的文件名的最大长度。如果实现没有任何限制，则该值应为推荐的最大值。
7 | L_tmpnam 这个宏是一个整数，该整数代表了字符数组可以存储的由 tmpnam 函数创建的临时文件名的最大长度。
8 | SEEK_CUR、SEEK_END 和 SEEK_SET 这些宏是在These macros are used in the fseek 函数中使用，用于在一个文件中定位不同的位置。
9 | TMP_MAX 这个宏是 tmpnam 函数可生成的独特文件名的最大数量。
10 | stderr、stdin 和 stdout 这些宏是指向 FILE 类型的指针，分别对应于标准错误、标准输入和标准输出流。

库函数

下面是头文件 stdio.h 中定义的函数：

为了更好地理解函数，请按照下面的序列学习这些函数，因为第一个函数中创建的文件会在后续的函数中使用到。
序号 | 函数 & 描述
1 | int fclose(FILE *stream) 关闭流 stream。刷新所有的缓冲区。
2 | void clearerr(FILE *stream) 清除给定流 stream 的文件结束和错误标识符。
3 | int feof(FILE *stream) 测试给定流 stream 的文件结束标识符。
4 | int ferror(FILE *stream) 测试给定流 stream 的错误标识符。
5 | int fflush(FILE *stream) 刷新流 stream 的输出缓冲区。
6 | int fgetpos(FILE *stream, fpos_t *pos) 获取流 stream 的当前文件位置，并把它写入到 pos。
7 | FILE *fopen(const char *filename, const char *mode) 使用给定的模式 mode 打开 filename 所指向的文件。
8 | size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) 从给定流 stream 读取数据到 ptr 所指向的数组中。
9 | FILE *freopen(const char *filename, const char *mode, FILE *stream) 把一个新的文件名 filename 与给定的打开的流 stream 关联，同时关闭流中的旧文件。
10 | int fseek(FILE *stream, long int offset, int whence) 设置流 stream 的文件位置为给定的偏移 offset，参数 offset 意味着从给定的 whence 位置查找的字节数。
11 | int fsetpos(FILE *stream, const fpos_t *pos) 设置给定流 stream 的文件位置为给定的位置。参数 pos 是由函数 fgetpos 给定的位置。
12 | long int ftell(FILE *stream) 返回给定流 stream 的当前文件位置。
13 | size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 把 ptr 所指向的数组中的数据写入到给定流 stream 中。
14 | int remove(const char *filename) 删除给定的文件名 filename，以便它不再被访问。
15 | int rename(const char *old_filename, const char *new_filename) 把 old_filename 所指向的文件名改为 new_filename。
16 | void rewind(FILE *stream) 设置文件位置为给定流 stream 的文件的开头。
17 | void setbuf(FILE *stream, char *buffer) 定义流 stream 应如何缓冲。
18 | int setvbuf(FILE *stream, char *buffer, int mode, size_t size) 另一个定义流 stream 应如何缓冲的函数。
19 | FILE *tmpfile(void) 以二进制更新模式(wb+)创建临时文件。
20 | char *tmpnam(char *str) 生成并返回一个有效的临时文件名，该文件名之前是不存在的。
21 | int fprintf(FILE *stream, const char *format, ...) 发送格式化输出到流 stream 中。
22 | int printf(const char *format, ...) 发送格式化输出到标准输出 stdout。
23 | int sprintf(char *str, const char *format, ...) 发送格式化输出到字符串。
24 | int vfprintf(FILE *stream, const char *format, va_list arg) 使用参数列表发送格式化输出到流 stream 中。
25 | int vprintf(const char *format, va_list arg) 使用参数列表发送格式化输出到标准输出 stdout。
26 | int vsprintf(char *str, const char *format, va_list arg) 使用参数列表发送格式化输出到字符串。
27 | int fscanf(FILE *stream, const char *format, ...) 从流 stream 读取格式化输入。
28 | int scanf(const char *format, ...) 从标准输入 stdin 读取格式化输入。
29 | int sscanf(const char *str, const char *format, ...) 从字符串读取格式化输入。
30 | int fgetc(FILE *stream) 从指定的流 stream 获取下一个字符（一个无符号字符），并把位置标识符往前移动。
31 | char *fgets(char *str, int n, FILE *stream) 从指定的流 stream 读取一行，并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时，或者读取到换行符时，或者到达文件末尾时，它会停止，具体视情况而定。
32 | int fputc(int char, FILE *stream) 把参数 char 指定的字符（一个无符号字符）写入到指定的流 stream 中，并把位置标识符往前移动。
33 | int fputs(const char *str, FILE *stream) 把字符串写入到指定的流 stream 中，但不包括空字符。
34 | int getc(FILE *stream) 从指定的流 stream 获取下一个字符（一个无符号字符），并把位置标识符往前移动。
35 | int getchar(void) 从标准输入 stdin 获取一个字符（一个无符号字符）。
36 | char *gets(char *str) 从标准输入 stdin 读取一行，并把它存储在 str 所指向的字符串中。当读取到换行符时，或者到达文件末尾时，它会停止，具体视情况而定。
37 | int putc(int char, FILE *stream) 把参数 char 指定的字符（一个无符号字符）写入到指定的流 stream 中，并把位置标识符往前移动。
38 | int putchar(int char) 把参数 char 指定的字符（一个无符号字符）写入到标准输出 stdout 中。
39 | int puts(const char *str) 把一个字符串写入到标准输出 stdout，直到空字符，但不包括空字符。换行符会被追加到输出中。
40 | int ungetc(int char, FILE *stream) 把字符 char（一个无符号字符）推入到指定的流 stream 中，以便它是下一个被读取到的字符。
41 | void perror(const char *str) 把一个描述性错误消息输出到标准错误 stderr。首先输出字符串 str，后跟一个冒号，然后是一个空格。


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <stdlib.h>

简介

stdlib .h 头文件定义了四个变量类型、一些宏和各种通用工具函数。

库变量

下面是头文件 stdlib.h 中定义的变量类型：

序号 | 变量 & 描述
1 | size_t 这是无符号整数类型，它是 sizeof 关键字的结果。
2 | wchar_t 这是一个宽字符常量大小的整数类型。
3 | div_t 这是 div 函数返回的结构。
4 | ldiv_t 这是 ldiv 函数返回的结构。

库宏

下面是头文件 stdlib.h 中定义的宏：

序号 | 宏 & 描述
1 | NULL 这个宏是一个空指针常量的值。
2 | EXIT_FAILURE 这是 exit 函数失败时要返回的值。
3 | EXIT_SUCCESS 这是 exit 函数成功时要返回的值。
4 | RAND_MAX 这个宏是 rand 函数返回的最大值。
5 | MB_CUR_MAX 这个宏表示在多字节字符集中的最大字符数，不能大于 MB_LEN_MAX。

库函数

下面是头文件 stdlib.h 中定义的函数：

序号 | 函数 & 描述
1 | double atof(const char *str) 把参数 str 所指向的字符串转换为一个浮点数（类型为 double 型）。
2 | int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数（类型为 int 型）。
3 | long int atol(const char *str) 把参数 str 所指向的字符串转换为一个长整数（类型为 long int 型）。
4 | double strtod(const char *str, char **endptr) 把参数 str 所指向的字符串转换为一个浮点数（类型为 double 型）。
5 | long int strtol(const char *str, char **endptr, int base) 把参数 str 所指向的字符串转换为一个长整数（类型为 long int 型）。
6 | unsigned long int strtoul(const char *str, char **endptr, int base) 把参数 str 所指向的字符串转换为一个无符号长整数（类型为 unsigned long int 型）。
7 | void *calloc(size_t nitems, size_t size) 分配所需的内存空间，并返回一个指向它的指针。
8 | void free(void *ptr) 释放之前调用 calloc、malloc 或 realloc 所分配的内存空间。
9 | void *malloc(size_t size) 分配所需的内存空间，并返回一个指向它的指针。
10 | void *realloc(void *ptr, size_t size) 尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。
11 | void abort(void) 使一个异常程序终止。
12 | int atexit(void (*func)(void)) 当程序正常终止时，调用指定的函数 func。
13 | void exit(int status) 使程序正常终止。
14 | char *getenv(const char *name) 搜索 name 所指向的环境字符串，并返回相关的值给字符串。
15 | int system(const char *string) 由 string 指定的命令传给要被命令处理器执行的主机环境。
16 | void *bsearch(const void *key, const void *base, size_t nitems, size_t size, int (*compar)(const void *, const void *)) 执行二分查找。
17 | void qsort(void *base, size_t nitems, size_t size, int (*compar)(const void *, const void*)) 数组排序。
18 | int abs(int x) 返回 x 的绝对值。
19 | div_t div(int numer, int denom) 分子除以分母。
20 | long int labs(long int x) 返回 x 的绝对值。
21 | ldiv_t ldiv(long int numer, long int denom) 分子除以分母。
22 | int rand(void) 返回一个范围在 0 到 RAND_MAX 之间的伪随机数。
23 | void srand(unsigned int seed) 该函数播种由函数 rand 使用的随机数发生器。
24 | int mblen(const char *str, size_t n) 返回参数 str 所指向的多字节字符的长度。
25 | size_t mbstowcs(schar_t *pwcs, const char *str, size_t n) 把参数 str 所指向的多字节字符的字符串转换为参数 pwcs 所指向的数组。
26 | int mbtowc(whcar_t *pwc, const char *str, size_t n) 检查参数 str 所指向的多字节字符。
27 | size_t wcstombs(char *str, const wchar_t *pwcs, size_t n) 把数组 pwcs 中存储的编码转换为多字节字符，并把它们存储在字符串 str 中。
28 | int wctomb(char *str, wchar_t wchar) 检查对应于参数 wchar 所给出的多字节字符的编码。


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <string.h>

简介

string .h 头文件定义了一个变量类型、一个宏和各种操作字符数组的函数。

库变量

下面是头文件 string.h 中定义的变量类型：

序号 | 变量 & 描述
1 | size_t 这是无符号整数类型，它是 sizeof 关键字的结果。

库宏

下面是头文件 string.h 中定义的宏：

序号 | 宏 & 描述
1 | NULL 这个宏是一个空指针常量的值。

库函数

下面是头文件 string.h 中定义的函数：

序号 | 函数 & 描述
1 | void *memchr(const void *str, int c, size_t n) 在参数 str 所指向的字符串的前 n 个字节中搜索第一次出现字符 c（一个无符号字符）的位置。
2 | int memcmp(const void *str1, const void *str2, size_t n) 把 str1 和 str2 的前 n 个字节进行比较。
3 | void *memcpy(void *dest, const void *src, size_t n) 从 src 复制 n 个字符到 dest。
4 | void *memmove(void *dest, const void *src, size_t n) 另一个用于从 str2 复制 n 个字符到 str1 的函数。
5 | void *memset(void *str, int c, size_t n) 复制字符 c（一个无符号字符）到参数 str 所指向的字符串的前 n 个字符。
6 | char *strcat(char *dest, const char *src) 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。
7 | char *strncat(char *dest, const char *src, size_t n) 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾，直到 n 字符长度为止。
8 | char *strchr(const char *str, int c) 在参数 str 所指向的字符串中搜索第一次出现字符 c（一个无符号字符）的位置。
9 | int strcmp(const char *str1, const char *str2) 把 str1 所指向的字符串和 str2 所指向的字符串进行比较。
10 | int strncmp(const char *str1, const char *str2, size_t n) 把 str1 和 str2 进行比较，最多比较前 n 个字节。
11 | int strcoll(const char *str1, const char *str2) 把 str1 和 str2 进行比较，结果取决于 LC_COLLATE 的位置设置。
12 | char *strcpy(char *dest, const char *src) 把 src 所指向的字符串复制到 dest。
13 | char *strncpy(char *dest, const char *src, size_t n) 把 src 所指向的字符串复制到 dest，最多复制 n 个字符。
14 | size_t strcspn(const char *str1, const char *str2) 检索字符串 str1 开头连续有几个字符都不含字符串 str2 中的字符。
15 | char *strerror(int errnum) 从内部数组中搜索错误号 errnum，并返回一个指向错误消息字符串的指针。
16 | size_t strlen(const char *str) 计算字符串 str 的长度，直到空结束字符，但不包括空结束字符。
17 | char *strpbrk(const char *str1, const char *str2) 检索字符串 str1 中第一个匹配字符串 str2 中字符的字符，不包含空结束字符。也就是说，依次检验字符串 str1 中的字符，当被检验字符在字符串 str2 中也包含时，则停止检验，并返回该字符位置。
18 | char *strrchr(const char *str, int c) 在参数 str 所指向的字符串中搜索最后一次出现字符 c（一个无符号字符）的位置。
19 | size_t strspn(const char *str1, const char *str2) 检索字符串 str1 中第一个不在字符串 str2 中出现的字符下标。
20 | char *strstr(const char *haystack, const char *needle) 在字符串 haystack 中查找第一次出现字符串 needle（不包含空结束字符）的位置。
21 | char *strtok(char *str, const char *delim) 分解字符串 str 为一组字符串，delim 为分隔符。
22 | size_t strxfrm(char *dest, const char *src, size_t n) 根据程序当前的区域选项中的 LC_COLLATE 来转换字符串 src 的前 n 个字符，并把它们放置在字符串 dest 中。


C 标准库 -

Help > TCC语言函数库 >
C 标准库 -

C 标准库 - <time.h>

简介

time.h 头文件定义了四个变量类型、两个宏和各种操作日期和时间的函数。

库变量

下面是头文件 time.h 中定义的变量类型：

序号 | 变量 & 描述
1 | size_t 是无符号整数类型，它是 sizeof 关键字的结果。
2 | clock_t 这是一个适合存储处理器时间的类型。
3 | time_t is 这是一个适合存储日历时间类型。
4 | struct tm 这是一个用来保存时间和日期的结构。

tm 结构的定义如下：

struct tm {
   int tm_sec;         /* 秒，范围从 0 到 59		*/
   int tm_min;         /* 分，范围从 0 到 59		*/
   int tm_hour;        /* 小时，范围从 0 到 23		*/
   int tm_mday;        /* 一月中的第几天，范围从 1 到 31	*/
   int tm_mon;         /* 月，范围从 0 到 11		*/
   int tm_year;        /* 自 1900 年起的年数		*/
   int tm_wday;        /* 一周中的第几天，范围从 0 到 6	*/
   int tm_yday;        /* 一年中的第几天，范围从 0 到 365	*/
   int tm_isdst;       /* 夏令时				*/
};

库宏

下面是头文件 time.h 中定义的宏：

序号 | 宏 & 描述
1 | NULL 这个宏是一个空指针常量的值。
2 | CLOCKS_PER_SEC 这个宏表示每秒的处理器时钟个数。

库函数

下面是头文件 time.h 中定义的函数：

序号 | 函数 & 描述
1 | char *asctime(const struct tm *timeptr) 返回一个指向字符串的指针，它代表了结构 timeptr 的日期和时间。
2 | clock_t clock(void) 返回程序执行起（一般为程序的开头），处理器时钟所使用的时间。
3 | char *ctime(const time_t *timer) 返回一个表示当地时间的字符串，当地时间是基于参数 timer。
4 | double difftime(time_t time1, time_t time2) 返回 time1 和 time2 之间相差的秒数 (time1-time2)。
5 | struct tm *gmtime(const time_t *timer) timer 的值被分解为 tm 结构，并用协调世界时（UTC）也被称为格林尼治标准时间（GMT）表示。
6 | struct tm *localtime(const time_t *timer) timer 的值被分解为 tm 结构，并用本地时区表示。
7 | time_t mktime(struct tm *timeptr) 把 timeptr 所指向的结构转换为一个依据本地时区的 time_t 值。
8 | size_t strftime(char *str, size_t maxsize, const char *format, const struct tm *timeptr) 根据 format 中定义的格式化规则，格式化结构 timeptr 表示的时间，并把它存储在 str 中。
9 | time_t time(time_t *timer) 计算当前日历时间，并把它编码成 time_t 格式。


系统功能函数

Help >
系统功能函数

Snapman系统功能函数是TCC脚本的封装，封装了Snapman系统手工操作的绝大部分功能；在系统里TCC脚本中调用这些函数可以实现几乎手工可以实现的功能，以方便实现系统自动化。


枚举

Help > 系统功能函数 >
枚举

枚举定义了操作Snapman表格的一组常量


GridCellLineEnm

Help > 系统功能函数 > 枚举 >
GridCellLineEnm

GridCellLineEnm枚举定义单元格边框的类型，定义如下：

enum GridCellLineEnm
{
GRIDCELLLINE_BOTTOM, //底边框
GRIDCELLLINE_TOP, //上边框
 GRIDCELLLINE_LEFT, //左边框
 GRIDCELLLINE_RIGHT, //右边框
 GRIDCELLLINE_NONE, //无边框
 GRIDCELLLINE_ALL, //全边框
 GRIDCELLLINE_FRAME, //外边框边框
 GRIDCELLLINE_BOLDFRAME //粗外边框边框
};


GridCellTypeEnm

Help > 系统功能函数 > 枚举 >
GridCellTypeEnm

GridCellTypeEnm枚举定义单元格的内容类型，定义如下：

enum GridCellTypeEnm
{
GRIDCELLTYPE_TEXT = 0, //文本框
GRIDCELLTYPE_PICTURE = 1, //图片
GRIDCELLTYPE_COMBOBOX = 2, //下拉框
GRIDCELLTYPE_FILE = 3, //文件
GRIDCELLTYPE_CHECK = 4, //勾选框
GRIDCELLTYPE_PROGRESS = 5, //进度条
GRIDCELLTYPE_ICON = 6, //图标
GRIDCELLTYPE_STATEBUTTON = 7, //分布式状态按钮
GRIDCELLTYPE_EXPRTK_SCRIPT = 8, //Exprtk脚本
GRIDCELLTYPE_TCC_SCRIPT = 9, //TCC脚本
GRIDCELLTYPE_BUTTON = 10, //按钮
};


GridAppEnm

Help > 系统功能函数 > 枚举 >
GridAppEnm

GridAppEnm枚举定义分布式程序的运行状态，定义如下：

enum GridAppEnm
{
GRIDAPP_STOP = 0,
//APP在停止状态
GRIDAPP_START= 1,
//APP在运行状态
};


结构体

Help > 系统功能函数 >
结构体

结构体定义了操作Snapman表格的类型封装


SnapmanFont

Help > 系统功能函数 > 结构体 >
SnapmanFont

SnapmanFont定义了字体，结构如下：

typedef struct SnapmanFont
{
    wchar_t facename[256];             //字体名称
    int height;                        //字体的高度
    int weight;                        //粗体：0非粗体，600、900为粗体
    int italic;                        //斜体
    int underline;                     //下划线
    int strikeout;                     //删除线
}SnapmanFont;


SnapmanBorderLine

Help > 系统功能函数 > 结构体 >
SnapmanBorderLine

SnapmanBorderLine定义了边框线，结构如下：

typedef struct SnapmanBorderLine
{
    int type;                          //线型类型，如下定义
    int width;                         //线宽度
    int color;                         //线条颜色，RGB颜色，如红色为：RGB(255,0,0)
}SnapmanBorderLine;

线型类型：
PS_SOLID       = 0; {实线}
PS_DASH        = 1; {段线; 要求笔宽<=1}
PS_DOT         = 2; {点线; 要求笔宽<=1}
PS_DASHDOT     = 3; {线、点; 要求笔宽<=1}
PS_DASHDOTDOT  = 4; {线、点、点; 要求笔宽<=1}
PS_NULL        = 5; {不可见}
PS_INSIDEFRAME = 6; {实线; 但笔宽是向里扩展}


SnapmanCombine

Help > 系统功能函数 > 结构体 >
SnapmanCombine

SnapmanCombine定义了单元格合并信息，结构如下：

typedef struct SnapmanCombine
{
    int row;                           //开始行
    int col;                           //开始列
    int endrow;                        //结束行
    int endcol;                        //结束列
}SnapmanCombine;


SnapmanButtonImage

Help > 系统功能函数 > 结构体 >
SnapmanButtonImage

SnapmanButtonImage定义了按钮图片信息，结构如下：

typedef struct SnapmanButtonImage
{
    wchar_t *strBackgroundImage;       //默认背景图片路径
    wchar_t *strEnterImage;            //鼠标进入图片路径
    wchar_t *strPressImage;            //鼠标点击图片路径
}SnapmanButtonImage;


系统函数

Help > 系统功能函数 >
系统函数

封装了一些C语言常用的


wPrint

Help > 系统功能函数 > 系统函数 >
wPrint

void wPrint(const wchar_t *format,...);

函数名称：    wPrint

函数作用：    将信息打印到当前单元格上，在事件中是弹出对话框提示

函数参数：    根wprintf一样

函数返回值：  无

函数特别说明：无

函数样例：    无


L

Help > 系统功能函数 > 系统函数 >
L

wchar_t *L(char *p);

函数名称：    L

函数作用：    将Ansi编码的字符串转换成Unicode编码的字符串

函数参数：    P为Ansi编码的字符串，如果P为NULL，则不进行任何操作直接返回NULL

函数返回值：  Unicode编码的字符串，此字符串为Snapman系统申请的内存，需要调用SnapmanCleanUp()释放内存；如果脚本不进行释放，则系统在运行完脚本后统一回收内存

函数特别说明：如果字符串带有中文，请使用函数L("中文");如果没有可以使用系统操作L""

函数样例：

void TestL()

{

    wchar_t *strUnicode = L("Unicode");

    wPrint(strUnicode);

    SnapmanCleanUp();

}


S

Help > 系统功能函数 > 系统函数 >
S

char *S(wchar_t *p);

函数名称：    S

函数作用：    将Unicode编码的字符串转换成Ansi编码的字符串

函数参数：    P为Unicode编码的字符串，如果P为NULL，则不进行任何操作直接返回NULL

函数返回值：  Ansi编码的字符串，此字符串为Snapman系统申请的内存，需要调用SnapmanCleanUp()释放内存；如果脚本不进行释放，则系统在运行完脚本后统一回收内存

函数特别说明：无

函数样例：

void TestL()

{

    char *strAnsi = S(L"Ansi");

    Print(strAnsi);

    SnapmanCleanUp();

}


Print

Help > 系统功能函数 > 系统函数 >
Print

void Print(const char *format,...);

函数名称：    Print

函数作用：    将信息打印到当前单元格上，在事件中是弹出对话框提示

函数参数：    根printf一样

函数返回值：  无

函数特别说明：无

函数样例：    无


strclone

Help > 系统功能函数 > 系统函数 >
strclone

wchar_t *strclone(wchar_t *str)

函数名称：    strclone

函数作用：    克隆字符串

函数参数：    str需要克隆的原始字符串

函数返回值：  克隆出来的字符串

函数特别说明：最后需要调用SnapmanCleanUp函数释放内存

函数样例：

void Teststrclone()

{

    //1、字符串克隆

    wchar_t *strClone = strclone(L("习近平会见日本首相安倍晋三"));

    //2、将整形数字转换成Unicode类型的字符串

    wchar_t *strInt = itostr(398);

    //3、将双精度类型的数字转换成Unicode类型的字符串

    wchar_t *strDouble = dtostr(546546.786321354152);

    //4、将Unicode字符串转换成整形数字

    int k = strtoi(L"1278");

    //5、将Unicode字符串转换成双精度类型数字

    double d = strtod(L"147.786321354152");

    //6、将两个Unicode字符串连接成另外一个大字符串

    wchar_t *strConcat = concat(strClone,strInt);

    //7、将三个个Unicode字符串连接成另外一个大字符串

    wchar_t *strConcat1 = concat1(strClone,strInt,strDouble);

    //8、将四个Unicode字符串连接成另外一个大字符串

    wchar_t *strConcat2 = concat2(strClone,strInt,L",",strDouble);

    //11、打印

    wPrint(strClone);

    wPrint(strInt);

    wPrint(strDouble);

    wPrint(L"%d",k);

    wPrint(L"%.12f",d);

    wPrint(strConcat);

    wPrint(strConcat1);

    wPrint(strConcat2);

    //12、一次释放上面所有申请的内存

    SnapmanCleanUp();

}


itostr

Help > 系统功能函数 > 系统函数 >
itostr

wchar_t *itostr(int d);

函数名称：    itostr

函数作用：    将整数转换成字符串

函数参数：    d整数

函数返回值：  整数转换后的字符串

函数特别说明：最后需要调用SnapmanCleanUp函数释放内存

函数样例：参考Teststrclone用例


dtostr

Help > 系统功能函数 > 系统函数 >
dtostr

wchar_t *dtostr(double d);

函数名称：    dtostr

函数作用：    将浮点数转换成字符串

函数参数：    d浮点数

函数返回值：  浮点数转换后的字符串

函数特别说明：最后需要调用SnapmanCleanUp函数释放内存

函数样例：参考Teststrclone用例


strtoi

Help > 系统功能函数 > 系统函数 >
strtoi

int strtoi(wchar_t *str);

函数名称：    strtoi

函数作用：    将字符串转换成整数

函数参数：    str是字符串

函数返回值：  转换后的整数

函数特别说明：无

函数样例：参考Teststrclone用例


strtod

Help > 系统功能函数 > 系统函数 >
strtod

double strtod(wchar_t *str);

函数名称：    strtod

函数作用：    将字符串转换成浮点数

函数参数：    str是字符串

函数返回值：  转换后的浮点数

函数特别说明：无

函数样例：参考Teststrclone用例


concat2

Help > 系统功能函数 > 系统函数 >
concat2

wchar_t *concat2(wchar_t *str1,wchar_t *str2);

函数名称：    concat2

函数作用：    申请一块内存将字符串str1和字符串str2链接到一起

函数参数：    str1是字符串1，str2字符串2

函数返回值：  链接后的新字符串

函数特别说明：无

函数样例：参考Teststrclone用例


concat3

Help > 系统功能函数 > 系统函数 >
concat3

wchar_t *concat3(wchar_t *str1,wchar_t *str2,wchar_t *str3);

函数名称：    concat3

函数作用：    申请一块内存将字符串str1、str2、str3链接到一起

函数参数：    str1是字符串1，str2字符串2，str3字符串3

函数返回值：  链接后的新字符串

函数特别说明：无

函数样例：参考Teststrclone用例


concat4

Help > 系统功能函数 > 系统函数 >
concat4

wchar_t *concat4(wchar_t *str1,wchar_t *str2,wchar_t *str3,wchar_t *str4);

函数名称：    concat4

函数作用：    申请一块内存将字符串str1、str2、str3、str4链接到一起

函数参数：    str1是字符串1，str2字符串2，str3字符串3，str4字符串4

函数返回值：  链接后的新字符串

函数特别说明：无

函数样例：参考Teststrclone用例


getAppPath

Help > 系统功能函数 > 系统函数 >
getAppPath

wchar_t *getAppPath()

函数名称：    getAppPath

函数作用：    获取应用程序所在路径

函数参数：    无

函数返回值：  程序路径指针

函数特别说明：无

函数样例：无


Date

Help > 系统功能函数 > 系统函数 >
Date
wchar_t *Date();
函数名称： Date
函数作用： 获取当前日期
函数参数： 无
函数返回值： 日期字符串，需要用SnapmanFree释放
函数特别说明：无
函数样例：无


Time

Help > 系统功能函数 > 系统函数 >
Time
wchar_t *Time();
函数名称： Time
函数作用： 获取当前时间
函数参数： 无
函数返回值： 时间字符串，需要用SnapmanFree释放
函数特别说明：无
函数样例：无


DateTime

Help > 系统功能函数 > 系统函数 >
DateTime
wchar_t *DateTime();
函数名称： DateTime
函数作用： 获取当前日期和时间
函数参数： 无
函数返回值： 日期时间字符串，需要用SnapmanFree释放
函数特别说明：无
函数样例：无


DiffDay

Help > 系统功能函数 > 系统函数 >
DiffDay
int DiffDay(wchar_t *d1, wchar_t *d2);
函数名称： DiffDay
函数作用： 计算2个日期相差的天数
函数参数： d1为第一个日期，d2为第二个日期,格式都是xxx-xx-xx（年-月-日）
函数返回值： 两个日期相差的天数
函数特别说明：无
函数样例：无


AddDay

Help > 系统功能函数 > 系统函数 >
AddDay
wchar_t* AddDay(wchar_t *day,int nday);
函数名称： AddDay
函数作用： 计算一个日期加上nday天后的日期
函数参数： day为指定日期，格式都是xxx-xx-xx（年-月-日），nday为需要加上的天数
函数返回值： 新的日期，需要用SnapmanFree释放
函数特别说明：无
函数样例：无


AddWorkingDay

Help > 系统功能函数 > 系统函数 >
AddWorkingDay
wchar_t* AddWorkingDay(wchar_t *day,int nday);
函数名称： AddWorkingDay
函数作用： 计算一个日期加上nday个工作日后的日期（除去周六周天）
函数参数： day为指定日期，格式都是xxx-xx-xx（年-月-日），nday为需要加上的天数
函数返回值： 新的日期，需要用SnapmanFree释放
函数特别说明：无
函数样例：无


InsertMap

Help > 系统功能函数 > 系统函数 >
InsertMap
void *InsertMap(void *m,wchar_t *key,void *value);
函数名称： InsertMap
函数作用： 如果m为NULL则创建一个字符串索引的map对象，然后往m里面插入key、value键值对
函数参数： m为map对象，如果不存在则创建，key、value为键值对
函数返回值： 返回m或者新创建的map对象指针
函数特别说明：无
函数样例：无


FindMap

Help > 系统功能函数 > 系统函数 >
FindMap
void *FindMap(void *m,wchar_t *key);
函数名称： FindMap
函数作用： 查找map对象中key键对应的值
函数参数： m为map对象，key为需要查找的键
函数返回值： 存在返回值的指针，否则返回NULL
函数特别说明：无
函数样例：无


ClearMap

Help > 系统功能函数 > 系统函数 >
ClearMap
void ClearMap(void *m);
函数名称： ClearMap
函数作用： 清理map中的所有数据
函数参数： m为map对象
函数返回值： 无
函数特别说明：无
函数样例：无


GetMapSize

Help > 系统功能函数 > 系统函数 >
GetMapSize
int GetMapSize(void *m);
函数名称： GetMapSize
函数作用： 获取map的大小
函数参数： m为map对象
函数返回值： map的大小
函数特别说明：无
函数样例：无


ForeachMap

Help > 系统功能函数 > 系统函数 >
ForeachMap
Pair *ForeachMap(void *m);
函数名称： ForeachMap
函数作用： 从map中获取一个键值对对象，并将下标移动到下一个键值对上
函数参数： m为map对象
函数返回值： Pair键值对对象指针，不需要释放；如果内部下标已经移动到末尾，则返回NULLPair定义：
typedef struct Pair
{
wchar_t *key;
void *value;
}Pair;
函数特别说明：在每次InsertMap的时候会将下标移动到开头，或者使用ResetForeachMap也可以将下标移动到开头
函数样例：无


ResetForeachMap

Help > 系统功能函数 > 系统函数 >
ResetForeachMap
void ResetForeachMap(void *m);
函数名称： ResetForeachMap
函数作用： 将下标移动到map的开头
函数参数： m为map对象
函数返回值： 无
函数特别说明：无
函数样例：无


RForeachMap

Help > 系统功能函数 > 系统函数 >
RForeachMap
Pair *RForeachMap(void *m);
函数名称： RForeachMap
函数作用： 从map中反向获取一个键值对对象，并将反向下标移动到上一个键值对上（跟正向下标互不干扰）
函数参数： m为map对象
函数返回值： Pair键值对对象指针，不需要释放；如果内部反向下标已经移动到开头，则返回NULL；Pair定义：
typedef struct Pair
{
wchar_t *key;
void *value;
}Pair;
函数特别说明：在每次InsertMap的时候会将反向下标移动到末尾，或者使用ResetRForeachMap也可以将反向下标移动到末尾
函数样例：无


ResetRForeachMap

Help > 系统功能函数 > 系统函数 >
ResetRForeachMap
void ResetRForeachMap(void *m);
函数名称： ResetRForeachMap
函数作用： 将反向下标移动到末尾
函数参数： m为map对象
函数返回值： 无
函数特别说明：无
函数样例：无


EraseMap

Help > 系统功能函数 > 系统函数 >
EraseMap
void EraseMap(void *m,wchar_t *key);
函数名称： EraseMap
函数作用： 删除map中一个键值对数据
函数参数： m为map对象，key为需要删除键值对的索引
函数返回值： 无
函数特别说明：无
函数样例：无


InsertiMap

Help > 系统功能函数 > 系统函数 >
InsertiMap
void *InsertiMap(void *m,int key,void *value);
函数名称： InsertiMap
函数作用： 如果m为NULL则创建一个字符串索引的map对象，然后往m里面插入key、value键值对
函数参数： m为map对象，如果不存在则创建，key、value为键值对
函数返回值： 返回m或者新创建的map对象指针
函数特别说明：无
函数样例：无


FindiMap

Help > 系统功能函数 > 系统函数 >
FindiMap
void *FindiMap(void *m,int key);
函数名称： FindiMap
函数作用： 查找map对象中key键对应的值
函数参数： m为map对象，key为需要查找的键
函数返回值： 存在返回值的指针，否则返回NULL
函数特别说明：无
函数样例：无


CleariMap

Help > 系统功能函数 > 系统函数 >
CleariMap
void CleariMap(void *m);
函数名称： CleariMap
函数作用： 清理map中的所有数据
函数参数： m为map对象
函数返回值： 无
函数特别说明：无
函数样例：无


GetiMapSize

Help > 系统功能函数 > 系统函数 >
GetiMapSize
int GetiMapSize(void *m);
函数名称： GetiMapSize
函数作用： 获取map的大小
函数参数： m为map对象
函数返回值： map的大小
函数特别说明：无
函数样例：无


ForeachiMap

Help > 系统功能函数 > 系统函数 >
ForeachiMap
iPair *ForeachiMap(void *m);
函数名称： ForeachiMap
函数作用： 从map中获取一个键值对对象，并将下标移动到下一个键值对上
函数参数： m为map对象
函数返回值： iPair键值对对象指针，不需要释放；如果内部下标已经移动到末尾，则返回NULL；iPair定义：
typedef struct iPair
{
int key;
void *value;
}iPair;
函数特别说明：在每次InsertiMap的时候会将下标移动到开头，或者使用ResetForeachiMap也可以将下标移动到开头
函数样例：无


ResetForeachiMap

Help > 系统功能函数 > 系统函数 >
ResetForeachiMap
void ResetForeachiMap(void *m);
函数名称： ResetForeachiMap
函数作用： 将下标移动到map的开头
函数参数： m为map对象
函数返回值： 无
函数特别说明：无
函数样例：无


RForeachiMap

Help > 系统功能函数 > 系统函数 >
RForeachiMap
iPair *RForeachiMap(void *m);
函数名称： RForeachiMap
函数作用： 从map中反向获取一个键值对对象，并将反向下标移动到上一个键值对上（跟正向下标互不干扰）
函数参数： m为map对象
函数返回值： iPair键值对对象指针，不需要释放；如果内部反向下标已经移动到开头，则返回NULL；iPair定义：
typedef struct iPair
{
int key;
void *value;
}iPair;
函数特别说明：在每次InsertiMap的时候会将反向下标移动到末尾，或者使用ResetRForeachMap也可以将反向下标移动到末尾
函数样例：无


ResetRForeachiMap

Help > 系统功能函数 > 系统函数 >
ResetRForeachiMap
void ResetRForeachiMap(void *m);
函数名称： ResetRForeachiMap
函数作用： 将反向下标移动到末尾
函数参数： m为map对象
函数返回值： 无
函数特别说明：无
函数样例：无


EraseiMap

Help > 系统功能函数 > 系统函数 >
EraseiMap
void EraseiMap(void *m,int key);
函数名称： EraseiMap
函数作用： 删除map中一个键值对数据
函数参数： m为map对象，key为需要删除键值对的索引
函数返回值： 无
函数特别说明：无
函数样例：无


系统操作

Help > 系统功能函数 >
系统操作

封装了一些Snapman系统级函数


SnapmanCleanUp

Help > 系统功能函数 > 系统操作 >
SnapmanCleanUp

void SnapmanCleanUp();

函数名称：    SnapmanCleanUp

函数作用：    一次释放所有由Snapman函数接口申请的内存，释放后前面由Snapman接口返回的wchar_t*指针都不可用

函数参数：    无

函数返回值：  无

函数特别说明：Snapmn系统总共有10个函数会申请内存（10个函数具体可以参考样例），调用这些函数需要调用SnapmanCleanUp()释放内存（这些返回值不能使用free释放内存）；如果脚本不进行释放，则系统在运行完脚本后统一回收内存

函数样例：

void TestSnapmanCleanUp()//下面所有的函数是Snapman系统产生多余内存的函数

{

    //1、获取文件列表

    wchar_t *strFiles = SnapmanGetFiles(L("\\01.公司规范"));

    //2、获取文件夹列表

    wchar_t *strFolders = SnapmanGetFolders(L("\\04.开发管理"));

    //3、将整形数字转换成Unicode类型的字符串

    wchar_t *strInt = itostr(398);

    //4、将双精度类型的数字转换成Unicode类型的字符串

    wchar_t *strDouble = dtostr(546546.786321354152);

    //5、将两个Unicode字符串连接成另外一个大字符串

    wchar_t *strConcat = concat(strFiles,strFolders);

    //6、将三个个Unicode字符串连接成另外一个大字符串

    wchar_t *strConcat1 = concat1(strFiles,strFolders,strInt);

    //7、将四个Unicode字符串连接成另外一个大字符串

    wchar_t *strConcat2 = concat2(strFiles,strFolders,strInt,strDouble);

    //8、将Ansi编码字符串转换成Unicode编码字符串

    wchar_t *strUnicode = L("Unicode");

    //9、将Unicode编码字符串转换成Ansi编码字符串

    char *strAnsi = S(L"Ansi");

    //10、字符串克隆

    wchar_t *strClone = strclone(strConcat);

    //11、打印

    wPrint(strFiles);

    wPrint(strFolders);

    wPrint(strInt);

    wPrint(strDouble);

    wPrint(strConcat);

    wPrint(strConcat1);

    wPrint(strConcat2);

    wPrint(strUnicode);

    Print(strAnsi);

    wPrint(strClone);

    //12、一次释放上面所有申请的内存

    SnapmanCleanUp();

}


SnapmanFree

Help > 系统功能函数 > 系统操作 >
SnapmanFree

void SnapmanFree(void *p);

函数名称：    SnapmanFree

函数作用：    释放一个Snapman函数申请的内存

函数参数：    p需要释放的内存指针

函数返回值：  无

函数特别说明：SnapmanCleanUp一次释放所有由Snapman申请的内存，SnapmanFree一次只释放一个内存

函数样例：    无


SnapmanRunFile

Help > 系统功能函数 > 系统操作 >
SnapmanRunFile

int SnapmanRunFile(wchar_t *path)；

函数名称：    SnapmanRunFile

函数作用：    运行指定的表格文件

函数参数：    path为表格文件路径

函数返回值：  0或1，如果path指定的表格存在则运行表格然后返回1（不管表格里面有没有可以直接运行的脚本），如果文件不存在则返回0

函数特别说明：无

函数样例：

void TestSnapmanRunFile()

{

    int iResult = SnapmanRunFile(L("\\08.TccTestcase\\01.testcase"));

    if(iResult==1)

    {

        wPrint(L("Run file successful."));

    }else

    {

        wPrint(L("Can not find grid file:'\\08.TccTestcase\\01.testcase'."));

    }

    SnapmanCleanUp();

}


SnapmanGetUserName

Help > 系统功能函数 > 系统操作 >
SnapmanGetUserName

wchar_t *SnapmanGetUserName();

函数名称：    SnapmanGetUserName

函数作用：    获取当前登录的用户名称

函数参数：    无

函数返回值：  用户名称

函数特别说明：此函数返回值不需要释放内存

函数样例：

void TestSnapmanGetUserName()

{

    wchar_t *pUserName = SnapmanGetUserName();

    wPrint(L("Current user is: %s."),pUserName);

}


SnapmanGetServerIP

Help > 系统功能函数 > 系统操作 >
SnapmanGetServerIP

wchar_t *SnapmanGetServerIP()

函数名称：    SnapmanGetServerIP

函数作用：    获取当前登录的服务器IP地址

函数参数：    无

函数返回值：  服务器IP地址

函数特别说明：此函数返回值不需要释放内存

函数样例：

void TestSnapmanGetServerIP()

{

    wchar_t *pServerIp = SnapmanGetServerIP();

    wPrint(L("Current server ip is: %s."),pServerIp);

}


SnapmanGetServerPort

Help > 系统功能函数 > 系统操作 >
SnapmanGetServerPort

int SnapmanGetServerPort()

函数名称：    SnapmanGetServerPort

函数作用：    获取当前登录的服务器端口

函数参数：    无

函数返回值：  服务器端口

函数特别说明：无

函数样例：

void TestSnapmanGetServerPort()

{

    int iServerPort = SnapmanGetServerPort();

    wPrint(L("Current server port is: %d."),iServerPort);

}


SnapmanCreateGrid

Help > 系统功能函数 > 系统操作 >
SnapmanCreateGrid

int SnapmanCreateGrid(wchar_t *path)

函数名称：    SnapmanCreateGrid

函数作用：    创建表格文件

函数参数：    path为指定的文件路径和名称，如：\\01.公司规范\\01.公司规范

函数返回值：  0或1，如果文件或文件夹已经存在直接返回1，不存在创建成功返回1，如果失败则返回0

函数特别说明：在同一级目录下文件夹和文件不能同名，创建的文件和文件夹会按照名称进行排序

函数样例：

void TestSnapmanCreateGrid()

{

    int iResult = SnapmanCreateGrid(L("\\08.TccTestcase\\03.testcase_CreateFolder\\03.testcase_CreateFile"));

    if(iResult==1)

    {

        wPrint(L("Create file successful."));

    }else

    {

        wPrint(L("Create file error."));

    }

}


SnapmanCreateFolder

Help > 系统功能函数 > 系统操作 >
SnapmanCreateFolder

int SnapmanCreateFolder(wchar_t *path)

函数名称：    SnapmanCreateFolder

函数作用：    创建文件夹

函数参数：    path为指定的文件夹路径和名称，如：\\06.项目培训\\技能培训

函数返回值：  0或1，如果文件或文件夹已经存在直接返回1，不存在创建成功返回1，如果失败则返回0

函数特别说明：在同一级目录下文件夹和文件不能同名，创建的文件和文件夹会按照名称进行排序

函数样例：

void TestSnapmanCreateFolder()

{

    int iResult = SnapmanCreateFolder(L("\\08.TccTestcase\\03.testcase_CreateFolder"));

    if(iResult==1)

    {

        wPrint(L("Create folder successful."));

    }else

    {

        wPrint(L("Create folder error."));

    }

}


SnapmanCopy

Help > 系统功能函数 > 系统操作 >
SnapmanCopy

int SnapmanCopy(wchar_t *path)

函数名称：    SnapmanCopy

函数作用：    复制指定的文件或者文件夹

函数参数：    path为指定的文件或文件夹路径和名称

函数返回值：  0或1，如果文件或文件夹存在返回1，不存在则返回0

函数特别说明：复制函数在全程序中有效，直到遇到下一个复制或剪切

函数样例：

void TestSnapmanCopy()

{

    int iResult = SnapmanCopy(L("\\08.TccTestcase\\03.testcase_CreateFolder\\03.testcase_CreateFile"));

    if(iResult==1)

    {

        wPrint(L("Copy successful."));

    }else

    {

        wPrint(L("Copy error."));

    }

}


SnapmanCut

Help > 系统功能函数 > 系统操作 >
SnapmanCut

int SnapmanCut(wchar_t *path)

函数名称：    SnapmanCut

函数作用：    剪切指定的文件或者文件夹

函数参数：    path为指定的文件或文件夹路径和名称

函数返回值：  0或1，如果文件或文件夹存在返回1，不存在则返回0

函数特别说明：剪切函数在全程序中有效，直到遇到下一个复制或剪切；剪切的文件或文件夹在粘贴后会删除原始文件

函数样例：

void TestSnapmanCut()

{

    int iResult = SnapmanCut(L("\\08.TccTestcase\\03.testcase_CreateFolder"));

    if(iResult==1)

    {

        wPrint(L("Cut successful."));

    }else

    {

        wPrint(L("Cut error."));

    }

}


SnapmanPaste

Help > 系统功能函数 > 系统操作 >
SnapmanPaste

int SnapmanPaste(wchar_t *path)

函数名称：    SnapmanPaste

函数作用：    将剪切或复制的文件或者文件夹粘贴到指定路径下

函数参数：    path为剪切或复制的文件或文件夹需要粘贴的路径，可以为文件夹或文件路径，如果为文件路径则自动取其文件夹路径

函数返回值：  0或1，如果粘贴成功返回1，否则返回0

函数特别说明：无

函数样例：

void TestSnapmanPaste()

{

    int iResult = SnapmanCopy(L("\\08.TccTestcase\\03.testcase"));

    if(iResult==1)

    {

        wPrint(L("Copy successful."));

        if(SnapmanPaste(L("\\08.TccTestcase\\03.testcase_CreateFolder"))==1)

        {

            wPrint(L("Paste successful."));

        }else

        {

            wPrint(L("Paste error."));

        }

    }else

    {

        wPrint(L("Copy error."));

    }

}


SnapmanRename

Help > 系统功能函数 > 系统操作 >
SnapmanRename

int SnapmanRename(wchar_t *path,wchar_t *newname)

函数名称：    SnapmanRename

函数作用：    将指定的文件或者文件夹重命名

函数参数：    path为指定的文件或文件夹路径，newname为新文件或文件夹名称

函数返回值：  0或1，如果重命名成功返回1，否则返回0

函数特别说明：新名称不允许有下面字符：\|?<>/:*"，并且不能以.为结尾;如果新名称文件或文件夹已经存在则返回0

函数样例：

void TestSnapmanRename()

{

    int iResult = SnapmanRename(L("\\08.TccTestcase\\03.testcase_CreateFolder"),L("04.testcase_CreateFolder_Rename"));

    if(iResult==1)

    {

        wPrint(L("Rename successful."));

    }else

    {

        wPrint(L("Rename error."));

    }

}


SnapmanDelete

Help > 系统功能函数 > 系统操作 >
SnapmanDelete

int SnapmanDelete(wchar_t *path)

函数名称：    SnapmanDelete

函数作用：    将指定的文件或者文件夹删除

函数参数：    path需要删除的文件或文件夹路径

函数返回值：  0或1，如果删除成功返回1，否则返回0

函数特别说明：删除操作没有可恢复的手段，所以慎重使用

函数样例：

void TestSnapmanDelete()

{

    int iResult = SnapmanDelete(L("\\08.TccTestcase\\04.testcase_CreateFolder_Rename"));

    if(iResult==1)

    {

        wPrint(L("Delete successful."));

    }else

    {

        wPrint(L("Delete error."));

    }

}


SnapmanGetFolders

Help > 系统功能函数 > 系统操作 >
SnapmanGetFolders

wchar_t *SnapmanGetFolders(wchar_t *path)

函数名称：    SnapmanGetFolders

函数作用：    获取指定文件夹下面的所有的文件夹名称

函数参数：    path为指定的文件夹路径，只能是文件夹，其他路径会出错返回0

函数返回值：  如果成功获取则返回所有文件夹名称（使用|分割）,如果失败则返回NULL

函数特别说明：成功返回的结果需要使用TestSnapmanCleanUp进行释放

函数样例：

void TestSnapmanGetFolders()

{

    wchar_t *strFolders = SnapmanGetFolders(L("\\04.开发管理"));

    if(strFolders)

    {

        wchar_t *strFolder = wcstok(strFolders,L"|");

        while(strFolder)

        {

            wPrint(strFolder);

            strFolder = wcstok(NULL,L"|");

        }

        wPrint(L("Get folders successful."));

    }else

    {

        wPrint(L("Get folders error."));

    }

}


SnapmanGetFiles

Help > 系统功能函数 > 系统操作 >
SnapmanGetFiles

wchar_t *SnapmanGetFiles(wchar_t *path)

函数名称：    SnapmanGetFiles

函数作用：    获取指定文件夹下面的所有的文件名称

函数参数：    path为指定的文件夹路径，只能是文件夹，其他路径会出错返回0

函数返回值：  如果成功获取则返回所有文件名称（使用|分割）,如果失败则返回NULL

函数特别说明：成功返回的结果需要使用TestSnapmanCleanUp进行释放

函数样例：

void TestSnapmanGetFiles()

{

    wchar_t *strFiles = SnapmanGetFiles(L("\\01.公司规范"));

    if(strFiles)

    {

        wchar_t *strFile = wcstok(strFiles,L"|");

        while(strFile)

        {

            wPrint(strFile);

            strFile = wcstok(NULL,L"|");

        }

        wPrint(L("Get files successful."));

    }else

    {

        wPrint(L("Get files error."));

    }

}


SnapmanFindFile

Help > 系统功能函数 > 系统操作 >
SnapmanFindFile

int SnapmanFindFile(wchar_t *path)

函数名称：    SnapmanFindFile

函数作用：    查找指定路径的文件或文件夹是否存在

函数参数：    path为指定的文件或文件夹路径

函数返回值：  0或1，如果存在返回1，否则返回0

函数特别说明：无

函数样例：

void TestSnapmanFindFile()

{

    int iResult = SnapmanFindFile(L("\\08.TccTestcase\\03.testcase"));

    if(iResult==1)

    {

        wPrint(L("File is exsist."));

    }else

    {

        wPrint(L("File is not exsist."));

    }

}


SnapmanShowProgress

Help > 系统功能函数 > 系统操作 >
SnapmanShowProgress

int SnapmanShowProgress()

函数名称：    SnapmanShowProgress

函数作用：    显示全局进度条

函数参数：    无

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：如果进度条已经隐藏，则会重新创建进度条：所有数据恢复默认值，进度条总大小为100，当前进度为0；否则直接显示

函数样例：

void TestSnapmanProgress()

{

    //1、显示进度条

    SnapmanShowProgress();

    //2、设置进度条的当前值为0

    SnapmanSetProgress(0);

    //3、添加进度条的总数,默认有100加上500，最大值为600

    SnapmanAddProgress(500);

    //4、执行代码

    for(int i = 1; i <= 600; i++)

    {

        SnapmanProgressTicc();

        Sleep(10);

    }

    //5、隐藏进度条

    SnapmanHideProgress();

}


SnapmanSetProgress

Help > 系统功能函数 > 系统操作 >
SnapmanSetProgress

int SnapmanSetProgress(int n)

函数名称：    SnapmanSetProgress

函数作用：    设置进度条的当前位置

函数参数：    n为需要设置进度条当前值

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：进度条在显示状态下才有效

函数样例：如上


SnapmanHideProgress

Help > 系统功能函数 > 系统操作 >
SnapmanHideProgress

int SnapmanHideProgress()

函数名称：    SnapmanHideProgress

函数作用：    隐藏进度条

函数参数：    无

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：隐藏并释放进度条内存

函数样例：如上


SnapmanAddProgress

Help > 系统功能函数 > 系统操作 >
SnapmanAddProgress

int SnapmanAddProgress(int t)

函数名称：    SnapmanAddProgress

函数作用：    往进度条最大值上添加t

函数参数：    无

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：进度条在显示状态下才有效；进度条默认最大值大小为100，如果需要减小可以设置为负数

函数样例：如上


SnapmanProgressTicc

Help > 系统功能函数 > 系统操作 >
SnapmanProgressTicc

int SnapmanProgressTicc()

函数名称：    SnapmanProgressTicc

函数作用：    进度条累加1并显示

函数参数：    无

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：进度条在显示状态下才有效

函数样例：如上


SnapmanProccessMessage

Help > 系统功能函数 > 系统操作 >
SnapmanProccessMessage

int SnapmanProccessMessage(int nTimeout);

函数名称：    SnapmanProccessMessage

函数作用：    花nTimeout的事件处理windows消息，调用此函数线程会堵塞

函数参数：    nTimeout需要等待的事件，单位毫秒

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：最后需要调用SnapmanCleanUp函数释放内存

函数样例：参考TestSnapmanCellSetApplicationRunTemplate用例


表格操作

Help > 系统功能函数 >
表格操作

封装了一些Snapman电子表格操作的函数


SnapmanOpenGrid

Help > 系统功能函数 > 表格操作 >
SnapmanOpenGrid

int SnapmanOpenGrid(wchar_t *path)

函数名称：    SnapmanOpenGrid

函数作用：    打开表格，和工程树操作的打开表格一样

函数参数：    path为表格路径

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：

void TestSnapmanOpenGrid()

{

    int flag = 0;

    if(SnapmanOpenGrid(L("\\08.TccTestcase\\01.testcase")))

    {

        flag = 1;

        wPrint(L("已经打开测试用例：01.testcase"));

    }else

    {

        wPrint(L("打开测试用例失败：01.testcase"));

    }

    if(SnapmanOpenGrid(L("\\08.TccTestcase\\02.testcase")))

    {

        flag = flag | 2;

        wPrint(L("已经打开测试用例：02.testcase"));

    }else

    {

        wPrint(L("打开测试用例失败：02.testcase"));

    }

    Sleep(2000);

    if(flag&1)

    {

        SnapmanCloseGrid(L("\\08.TccTestcase\\01.testcase"));

    }

    if(flag&2)

    {

        SnapmanCloseGrid(L("\\08.TccTestcase\\02.testcase"));

    }

    SnapmanCleanUp();

}


SnapmanSaveFile

Help > 系统功能函数 > 表格操作 >
SnapmanSaveFile

int SnapmanSaveFile(wchar_t *path)

函数名称：    SnapmanSaveFile

函数作用：    保存表格

函数参数：    path为表格路径

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：可以保存已经打开的文件或者在内存中打开的文件，如果未打开或者没有修改的表格返回0

函数样例：

void TestSnapmanSaveFile()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\23.testcaseData"));

    if(g)

    {

        SnapmanGridDelete(g,0,0,0,0);

        for(int row = 1; row < 25; row++)

        {

            for(int col = 1; col < 5; col++)

            {

                SnapmanCellSetInt(g,row,col,row + col);

            }

        }

        SnapmanSaveFile(L("\\08.TccTestcase\\23.testcaseData"));

        SnapmanCloseGrid(L("\\08.TccTestcase\\23.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanCloseGrid

Help > 系统功能函数 > 表格操作 >
SnapmanCloseGrid

int SnapmanCloseGrid(wchar_t *path)

函数名称：    SnapmanCloseGrid

函数作用：    关闭表格

函数参数：    path为表格路径

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：由于脚本运行时需要用到本表格中很多内容，当前运行的脚本指针不能被关闭，包括在脚本中启动的其他脚本也不应该关闭正在运行的脚本表格

函数样例：参考TestSnapmanOpenGrid用例


SnapmanGetGrid

Help > 系统功能函数 > 表格操作 >
SnapmanGetGrid

void *SnapmanGetGrid(wchar_t *path)

函数名称：    SnapmanGetGrid

函数作用：    获取表格文件指针，如果文件已经打开则从打开文件获取指针，如果没有则在内存中打开指针

函数参数：    path为表格路径

函数返回值：  成功返回表格指针，失败返回NULL

函数特别说明：指针无需释放，脚本运行完自动释放；当前脚本文件所在指针已经作为全局变量 this，脚本不需要获取此指针

函数样例：参考TestSnapmanSaveFile用例


SnapmanGridSave

Help > 系统功能函数 > 表格操作 >
SnapmanGridSave

int SnapmanGridSave(void *g)

函数名称：    SnapmanGridSave

函数作用：    用文件指针来保存文件

函数参数：    g为表格文件指针

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：

void TestSnapmanGridSave()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\23.testcaseData"));

    if(g)

    {

        SnapmanGridDelete(g,0,0,0,0);

        for(int row = 1; row < 25; row++)

        {

            for(int col = 1; col < 5; col++)

            {

                SnapmanCellSetInt(g,row,col,row + col);

            }

        }

        SnapmanGridSave(g);

        SnapmanCloseGrid(L("\\08.TccTestcase\\23.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanGridDataCommit

Help > 系统功能函数 > 表格操作 >
SnapmanGridDataCommit

int SnapmanGridDataCommit(void *g)

函数名称：    SnapmanGridDataCommit

函数作用：    为了提高效率SnapmanCellSetInt、SnapmanCellSetDouble、SnapmanCellSetText函数的结果文件不会即时更新到文件内存，使用SnapmanGridDataCommit可以批量更新数据到文件内存

函数参数：    g为表格文件指针

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：在批量调用SnapmanCellSetInt、SnapmanCellSetDouble、SnapmanCellSetText后应该紧接着调用SnapmanGridDataCommit更新；当调用SnapmanGridSave、SnapmanSaveFile保存或脚本运行完也会自动调用SnapmanGridDataCommit函数，但此时数据可能存在错乱

函数样例：

void TestSnapmanGridDataCommit()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        SnapmanGridDelete(g,0,0,0,0);

        for(int row = 1; row < 25; row++)

        {

            for(int col = 1; col < 5; col++)

            {

                SnapmanCellSetInt(g,row,col,row + col);

            }

            SnapmanGridDataCommit(g);

            SnapmanProccessMessage(200);

        }

        SnapmanGridSave(g);

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanGridGetTotalRow

Help > 系统功能函数 > 表格操作 >
SnapmanGridGetTotalRow

int SnapmanGridGetTotalRow(void *g)

函数名称：    SnapmanGridGetTotalRow

函数作用：    获取表格有数据的最大行数

函数参数：    g为表格文件指针

函数返回值：  返回有数据的最大行数

函数特别说明：无

函数样例：

void TestSnapmanGridGetTotalRow()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        wPrint(L("表格24.testcaseData的总行数是: %d"),SnapmanGridGetTotalRow(g));

        wPrint(L("表格24.testcaseData的总列数是: %d"),SnapmanGridGetTotalColumn(g));

        wPrint(L("表格24.testcaseData的第一列的行数是: %d"),SnapmanGridGetRowCount(g,1));

        wPrint(L("表格24.testcaseData的第一行的列数是: %d"),SnapmanGridGetColumnCount(g,1));

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanGridGetTotalColumn

Help > 系统功能函数 > 表格操作 >
SnapmanGridGetTotalColumn

int SnapmanGridGetTotalColumn(void *g)

函数名称：    SnapmanGridGetTotalColumn

函数作用：    获取表格有数据的最大列数

函数参数：    g为表格文件指针

函数返回值：  返回有数据的最大列数

函数特别说明：无

函数样例：参考TestSnapmanGridGetTotalRow用例


SnapmanGridGetRowCount

Help > 系统功能函数 > 表格操作 >
SnapmanGridGetRowCount

int SnapmanGridGetRowCount(void *g,int col)

函数名称：    SnapmanGridGetRowCount

函数作用：    获取表格col列有数据的最大行数

函数参数：    g为表格文件指针

函数返回值：  返回col列有数据的最大行数

函数特别说明：无

函数样例：参考TestSnapmanGridGetTotalRow用例


SnapmanGridGetColumnCount

Help > 系统功能函数 > 表格操作 >
SnapmanGridGetColumnCount

int SnapmanGridGetColumnCount(void *g,int row)

函数名称：    SnapmanGridGetColumnCount

函数作用：    获取表格row行有数据的最大列数

函数参数：    g为表格文件指针

函数返回值：  返回row行有数据的最大列数

函数特别说明：无

函数样例：参考TestSnapmanGridGetTotalRow用例


SnapmanGridGetTotalDataRow

Help > 系统功能函数 > 表格操作 >
SnapmanGridGetTotalDataRow
int SnapmanGridGetTotalDataRow(void *g)
函数名称： SnapmanGridGetTotalDataRow
函数作用： 获取表格有文本内容数据的最大行数
函数参数： g为表格文件指针
函数返回值： 返回表格有文本内容数据的最大行数
函数特别说明：无
函数样例：无


SnapmanGridGetTotalDataColumn

Help > 系统功能函数 > 表格操作 >
SnapmanGridGetTotalDataColumn
int SnapmanGridGetTotalDataColumn(void *g)
函数名称： SnapmanGridGetTotalDataColumn
函数作用： 获取表格有文本内容数据的最大列数
函数参数： g为表格文件指针
函数返回值： 返回表格有文本内容数据的最大列数
函数特别说明：无
函数样例：无


SnapmanGridGetDataRowCount

Help > 系统功能函数 > 表格操作 >
SnapmanGridGetDataRowCount
int SnapmanGridGetDataRowCount(void *g,int col)
函数名称： SnapmanGridGetDataRowCount
函数作用： 获取表格col列有文本内容数据的最大行数
函数参数： g为表格文件指针，col指定的列
函数返回值： 返回表格col列有文本内容数据的最大行数
函数特别说明：无
函数样例：无


SnapmanGridGetDataColumnCount

Help > 系统功能函数 > 表格操作 >
SnapmanGridGetDataColumnCount
int SnapmanGridGetDataColumnCount(void *g,int row)
函数名称： SnapmanGridGetDataColumnCount
函数作用： 获取表格row行有文本内容数据的最大列数
函数参数： g为表格文件指针，row指定的行
函数返回值： 返回row行有文本内容数据的最大列数
函数特别说明：无
函数样例：无


SnapmanGridCut

Help > 系统功能函数 > 表格操作 >
SnapmanGridCut

int SnapmanGridCut(void *g,int row,int col,int endrow,int endcol)

函数名称：    SnapmanGridCut

函数作用：    剪切表格数据，包括：全表格剪切、行剪切、列剪切、区域选择剪切

函数参数：    g为表格文件指针，row为开始行、col为开始列、endrow为结束行、endcol为结束列；row为0代表选择列，col为0代表选择行，row、col都为0代表表格全选

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanGridCopy用例


SnapmanGridCopy

Help > 系统功能函数 > 表格操作 >
SnapmanGridCopy

int SnapmanGridCopy(void *g,int row,int col,int endrow,int endcol)

函数名称：    SnapmanGridCopy

函数作用：    复制表格数据，包括：全表格复制、行复制、列复制、区域选择复制

函数参数：    g为表格文件指针，row为开始行、col为开始列、endrow为结束行、endcol为结束列；row为0代表选择列，col为0代表选择行，row、col都为0代表表格全选；结束行、列必须大于等于开始行、列

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：

void TestSnapmanGridCopy()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        if(SnapmanGridCopy(g,0,1,0,2)==1)

        {

            if(SnapmanGridPaste(g,0,8,0,9)==1)

            {

                wPrint(L("复制并粘贴表格数据成功."));

            }else

            {

                wPrint(L("复制的粘贴表格数据失败."));

            }

        }else

        {

            wPrint(L("复制表格数据失败."));

        }

        if(SnapmanGridCut(g,0,3,0,4)==1)

        {

            if(SnapmanGridPaste(g,0,4,0,5)==1)

            {

                wPrint(L("剪切并粘贴表格数据成功."));

            }else

            {

                wPrint(L("剪切的粘贴表格数据失败."));

            }

        }else

        {

            wPrint(L("剪切表格数据失败."));

        }

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanGridPaste

Help > 系统功能函数 > 表格操作 >
SnapmanGridPaste

int SnapmanGridPaste(void *g,int row,int col,int endrow,int endcol)

函数名称：    SnapmanGridPaste

函数作用：    粘贴表格数据，包括：文件粘贴、图片粘贴、全表格粘贴、行粘贴、列粘贴、区域选择粘贴

函数参数：    g为表格文件指针，row为开始行、col为开始列、endrow为结束行、endcol为结束列；row为0代表选择列，col为0代表选择行，row、col都为0代表表格全选

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：1、只能粘贴Excel的文本数据内容，不能粘贴它的式样和控件；

              2、文件粘贴可以在windows文件管理器中复制，然后粘贴到表格里，粘贴时候以表格选择的列数为计数，粘贴满第一行往第二行粘贴

              3、在windows操作系统中复制的图片可以粘贴到表格中来，系统自带截图工具，ctrl + p为截图，ctrl + o为隐藏本软件再截图

函数样例：参考TestSnapmanGridCopy用例


SnapmanGridInsertRow

Help > 系统功能函数 > 表格操作 >
SnapmanGridInsertRow

int SnapmanGridInsertRow(void *g,int row,int n)

函数名称：    SnapmanGridInsertRow

函数作用：    在指定row的上面，插入n行

函数参数：    g为表格文件指针，row为指定行（必须大于0），n为指定插入的行数（必须大于0）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：插入的行会自动计算每个单元格数据，包括：row和row-1行的单元格属性相同进行复制，row和row-1行单元格处在同一个合并单元格则新的行加入合并单元格

函数样例：

void TestSnapmanGridInsertRow()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        if(SnapmanGridInsertRow(g,3,1)==1)

        {

            wPrint(L("在第三行前面插入一行成功."));

        }else

        {

            wPrint(L("在第三行前面插入一行失败."));

        }

        if(SnapmanGridInsertColumn(g,3,1)==1)

        {

            wPrint(L("在第三列前面插入一列成功."));

        }else

        {

            wPrint(L("在第三列前面插入一列失败."));

        }

        if(SnapmanGridDeleteRow(g,3,3)==1)

        {

            wPrint(L("删除第三行成功."));

        }else

        {

            wPrint(L("删除第三行失败."));

        }

        if(SnapmanGridDeleteColumn(g,3,3)==1)

        {

            wPrint(L("删除第三列成功."));

        }else

        {

            wPrint(L("删除第三列失败."));

        }

        if(SnapmanGridDelete(g,1,1,3,4)==1)

        {

            wPrint(L("删除第一行第一列到第三行第四列的数据成功."));

        }else

        {

            wPrint(L("删除第一行第一列到第三行第四列的数据失败."));

        }

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanGridInsertColumn

Help > 系统功能函数 > 表格操作 >
SnapmanGridInsertColumn

int SnapmanGridInsertColumn(void *g,int col,int n)

函数名称：    SnapmanGridInsertColumn

函数作用：    在指定col的前面，插入n列

函数参数：    g为表格文件指针，col为指定列（必须大于0），n为指定插入的列数（必须大于0）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：插入的列会自动计算每个单元格数据，包括：col和col-1列的单元格属性相同进行复制，col和col-1列单元格处在同一个合并单元格则新的列加入合并单元格

函数样例：参考TestSnapmanGridInsertRow用例


SnapmanGridDeleteRow

Help > 系统功能函数 > 表格操作 >
SnapmanGridDeleteRow

int SnapmanGridDeleteRow(void *g,int row,int endrow)

函数名称：    SnapmanGridDeleteRow

函数作用：    删除从第row行到第endrow行的数据

函数参数：    g为表格文件指针，row为需要删除的开始行（包含，必须大于0），endrow为需要删除的结束行（包含，必须大于0）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：如果row等于0则删除所有

函数样例：参考TestSnapmanGridInsertRow用例


SnapmanGridDeleteColumn

Help > 系统功能函数 > 表格操作 >
SnapmanGridDeleteColumn

int SnapmanGridDeleteColumn(void *g,int col,int endcol)

函数名称：    SnapmanGridInsertColumn

函数作用：    删除从第col列到第endrow列的数据

函数参数：    g为表格文件指针，col为需要删除的开始列（包含，必须大于0），endcol为需要删除的结束列（包含，必须大于0）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：如果col等于0则删除所有

函数样例：参考TestSnapmanGridInsertRow用例


SnapmanGridDelete

Help > 系统功能函数 > 表格操作 >
SnapmanGridDelete

int SnapmanGridDelete(void *g,int row,int col,int endrow,int endcol)

函数名称：    SnapmanGridDelete

函数作用：    删除从第row行col列到endrow行endcol列的单元格数据

函数参数：    g为表格文件指针，row为开始行（包含），col为开始列（包含），endrow为结束行（包含），endcol为结束列（包含）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：如果row为0则删除col到endcol列，如果col为0则删除row到endrow行，如果row和col都为0则删除表格所有数据

函数样例：参考TestSnapmanGridInsertRow用例


SnapmanGridGetRowHeight

Help > 系统功能函数 > 表格操作 >
SnapmanGridGetRowHeight

int SnapmanGridGetRowHeight(void *g,int row)

函数名称：    SnapmanGridGetRowHeight

函数作用：    获取指定row行的高度

函数参数：    g为表格文件指针，row为指定行（必须大于等于0）

函数返回值：  指定行的高度

函数特别说明：如果row为0则返回系统行的高度

函数样例：

void TestSnapmanGridGetRowHeight()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        if(SnapmanGridSetRowHeight(g,3,35)==1)

        {

            wPrint(L("设置第三行高度为35成功."));

        }else

        {

            wPrint(L("设置第三行高度为35失败."));

        }

        wPrint(L("现在获取第三行的高度为：%d."),SnapmanGridGetRowHeight(g,3));

        if(SnapmanGridSetColumnWidth(g,3,35)==1)

        {

            wPrint(L("设置第三列宽度为35成功."));

        }else

        {

            wPrint(L("设置第三列宽度为35失败."));

        }

        wPrint(L("现在获取第三列的宽度为：%d."),SnapmanGridGetColumnWidth(g,3));

        if(SnapmanGridRestoreRowHeight(g,3,3)==1)

        {

            wPrint(L("恢复第三行到第三行的默认高度成功."));

        }else

        {

            wPrint(L("恢复第三行到第三行的默认高度失败."));

        }

        wPrint(L("现在获取第三行的高度为：%d."),SnapmanGridGetRowHeight(g,3));

        if(SnapmanGridRestoreColumnWidth(g,3,3)==1)

        {

            wPrint(L("恢复第三列到第三列的默认宽度成功."));

        }else

        {

            wPrint(L("恢复第三列到第三列的默认宽度失败."));

        }

        wPrint(L("现在获取第三列的宽度为：%d."),SnapmanGridGetColumnWidth(g,3));

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanGridSetRowHeight

Help > 系统功能函数 > 表格操作 >
SnapmanGridSetRowHeight

int SnapmanGridSetRowHeight(void *g,int row,int height)

函数名称：    SnapmanGridSetRowHeight

函数作用：    设置指定row行的高度

函数参数：    g为表格文件指针，row为指定行（必须大于0）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanGridGetRowHeight用例


SnapmanGridRestoreRowHeight

Help > 系统功能函数 > 表格操作 >
SnapmanGridRestoreRowHeight

int SnapmanGridRestoreRowHeight(void *g,int row,int endrow)

函数名称：    SnapmanGridRestoreRowHeight

函数作用：    将row到endrow行的高度恢复默认高度

函数参数：    g为表格文件指针，row为开始行（包含，必须大于0），endrow为结束行（包含，必须大于0）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanGridGetRowHeight用例


SnapmanGridGetColumnWidth

Help > 系统功能函数 > 表格操作 >
SnapmanGridGetColumnWidth

int SnapmanGridGetColumnWidth(void *g,int col)

函数名称：    SnapmanGridGetColumnWidth

函数作用：    获取指定col列的宽度

函数参数：    g为表格文件指针，col为指定列（必须大于等于0）

函数返回值：  指定列宽度

函数特别说明：如果col为0则返回系统列的宽度

函数样例：参考TestSnapmanGridGetRowHeight用例


SnapmanGridSetColumnWidth

Help > 系统功能函数 > 表格操作 >
SnapmanGridSetColumnWidth

int SnapmanGridSetColumnWidth(void *g,int col,int width)

函数名称：    SnapmanGridSetColumnWidth

函数作用：    设置指定col列的宽度

函数参数：    g为表格文件指针，col为指定列（必须大于0）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanGridGetRowHeight用例


SnapmanGridRestoreColumnWidth

Help > 系统功能函数 > 表格操作 >
SnapmanGridRestoreColumnWidth

int SnapmanGridRestoreColumnWidth(void *g,int col,int endcol)

函数名称：    SnapmanGridRestoreColumnWidth

函数作用：    将col到endcol列的宽度恢复默认宽度

函数参数：    g为表格文件指针，col为开始列（包含，必须大于0），endcol为结束列（包含，必须大于0）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanGridGetRowHeight用例


SnapmanUploadFile

Help > 系统功能函数 > 表格操作 >
SnapmanUploadFile

int SnapmanUploadFile(wchar_t *localFilePath,wchar_t *ServerSavePath)

函数名称：    SnapmanUploadFile

函数作用：    上传本地文件到服务器目标附件目录

函数参数：    localFilePath本地文件所在全路径（绝对路径），ServerSavePath目标存放目录（服务器相对路径）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：

void TestSnapmanUploadFile()

{

    if(SnapmanDownloadFile(L"\\08.TccTestcase\\16.testcaseData\\Program.cs",L"c:\\Program.cs"))

    {

        wPrint(L("从服务器下载文件：Program.cs，成功."));

    }else

    {

        wPrint(L("从服务器下载文件：Program.cs，失败."));

    }

    if(SnapmanUploadFile(L"c:\\Program.cs",L"\\08.TccTestcase\\17.testcaseData\\Program1.cs"))

    {

        wPrint(L("上传文件到服务器：Program1.cs，成功."));

    }else

    {

        wPrint(L("上传文件到服务器：Program1.cs，失败."));

    }

    if(SnapmanDownloadFile(L"\\08.TccTestcase\\17.testcaseData\\Program1.cs",L"c:\\Program2.cs"))

    {

        wPrint(L("从服务器下载文件：Program2.cs，成功."));

    }else

    {

        wPrint(L("从服务器下载文件：Program2.cs，失败."));

    }

}


SnapmanDownloadFile

Help > 系统功能函数 > 表格操作 >
SnapmanDownloadFile

int SnapmanDownloadFile(wchar_t *serverFilePath,wchar_t *localSavePath)

函数名称：    SnapmanDownloadFile

函数作用：    从服务器下载文件到本地

函数参数：    serverFilePath服务器存放文件路径（相对路径），本地文件存放全路径（绝对路径）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanUploadFile用例


单元格操作

Help > 系统功能函数 >
单元格操作

封装了一些Snapman电子表格中单元格操作的函数


SnapmanCellGetType

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetType

int SnapmanCellGetType(void *g,int row,int col)

函数名称：    SnapmanCellGetType

函数作用：    获取单元格的类型

函数参数：    g为表格文件指针，row为指定行，col为指定列

函数返回值：  单元格的类型，包括：

            enum GridCellTypeEnm

            {

                GRIDCELLTYPE_TEXT      = 0,         //文本类型

                GRIDCELLTYPE_PICTURE   = 1,         //图片类型

                GRIDCELLTYPE_COMBOBOX  = 2,          //下拉框类型

                GRIDCELLTYPE_FILE      = 3,         //文件类型

                GRIDCELLTYPE_CHECK     = 4,           //勾选框类型

                GRIDCELLTYPE_PROGRESS       = 5,   //进度条类型

                GRIDCELLTYPE_ICON           = 6,   //图标类型

                GRIDCELLTYPE_STATEBUTTON    = 7,   //分布式状态按钮类型

                GRIDCELLTYPE_EXPRTK_SCRIPT  = 8,   //Exprtk脚本类型

                GRIDCELLTYPE_TCC_SCRIPT     = 9,   //TCC脚本类型

                GRIDCELLTYPE_BUTTON         = 10,  //按钮类型

            };

函数特别说明：默认为文本类型

函数样例：

void TestSnapmanCellGetType()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        wchar_t cellType[][54] = {L"GRIDCELLTYPE_TEXT",L"GRIDCELLTYPE_PICTURE",L"GRIDCELLTYPE_COMBOBOX",L"GRIDCELLTYPE_FILE",L"GRIDCELLTYPE_CHECK",L"GRIDCELLTYPE_PROGRESS",

        L"GRIDCELLTYPE_ICON",L"GRIDCELLTYPE_STATEBUTTON",L"GRIDCELLTYPE_EXPRTK_SCRIPT",L"GRIDCELLTYPE_TCC_SCRIPT",L"GRIDCELLTYPE_BUTTON"};

        wPrint(L("获取一行一列单元格的类型为：%s"),cellType[SnapmanCellGetType(g,1,1)]);

        for(int r = 10; r < 15; r++)

        {

            for(int c = 1; c <= 4; c++)

            {

                SnapmanCellSetInt(g,r,c,r%2==0?r:c);

                wPrint(L("设置整形后%d行%d列的值为：%d"),r,c,SnapmanCellGetInt(g,r,c));

                SnapmanCellSetText(g,r,c,L("妈咪哄"));

                wPrint(L("设置文本后%d行%d列的值为：%s"),r,c,SnapmanCellGetText(g,r,c));

                SnapmanCellSetDouble(g,r,c,(duble)r/c);

                wPrint(L("设置浮点数后%d行%d列的值为：%f"),r,c,SnapmanCellGetDouble(g,r,c));

            }

            wPrint(L"");

        }

        SnapmanGridDataCommit(g); //将数据更新到文件内存

        SnapmanGridSave(g);       //将数据保存到磁盘

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanCellGetFont

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetFont

SnapmanFont SnapmanCellGetFont(void *g,int row,int col)

函数名称：    SnapmanCellGetFont

函数作用：    获取指定单元格的字体

函数参数：    g为表格文件指针，row为指定行（必须大于等于0），col为指定列（必须大于等于0）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：SnapmanFont结构如下：

            typedef struct SnapmanFont

            {

                wchar_t facename[256];//字体名称，默认为宋体

                int height;//大小，默认为12

                int weight;//600和900为粗体，0为正常字体，默认为0

                int italic;//1为斜体，默认为0

                int underline;//1为下划线，默认为0

                int strikeout;//1为删除线，默认为0

            }SnapmanFont;

函数样例：

void TestSnapmanCellGetFont()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        int fontColor = 0;

        SnapmanFont font = SnapmanCellGetFont(g,1,1);

        wPrint(L("设置第一行第一列单元格原始字体为：字体名称-%s,大小-%d,粗体-%d，斜体-%d，下划线-%d，删除线-%d."),

        font.facename,font.height,font.weight,font.italic,font.underline,font.strikeout);

        wcscpy(font.facename,L("华文彩云"));//设置新字体名称为华文彩云

        font.height = 16;//设置新字体大小为16像素

        font.weight = 900;//设置新字体为粗体

        font.italic = 1;//设置新字体为斜体

        font.underline = 1;//设置新字体为下划线

        font.strikeout = 1;//设置新字体为删除线

        if(SnapmanCellSetFont(g,1,1,&font)==1)

        {

            wPrint(L("设置第一行第一列单元格的字体成功."));

        }else

        {

            wPrint(L("设置第一行第一列单元格的字体失败."));

        }

        fontColor = SnapmanCellGetFontColor(g,1,1);

        wPrint(L("设置第一行第一列单元格的字体字体颜色为： %d."),fontColor);

        if(SnapmanCellSetFontColor(g,1,1,RGB(0,255,0))==1)

        {

            wPrint(L("设置第一行第一列单元格的字体颜色为绿色成功."));

        }else

        {

            wPrint(L("设置第一行第一列单元格的字体颜色为绿色失败."));

        }

        SnapmanGridSave(g);

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanCellSetFont

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetFont

int SnapmanCellSetFont(void *g,int row,int col,SnapmanFont *font)

函数名称：    SnapmanCellSetFont

函数作用：    设置单元格字体

函数参数：    g为表格文件指针，row为指定行（必须大于等于0），col为指定列（必须大于等于0），font为需要设置字体的指针

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetFont用例


SnapmanCellGetFontColor

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetFontColor

int SnapmanCellGetFontColor(void *g,int row,int col)

函数名称：    SnapmanCellGetFontColor

函数作用：    获取单元格字体颜色

函数参数：    g为表格文件指针，row为指定行（必须大于等于0），col为指定列（必须大于等于0）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetFont用例


SnapmanCellSetFontColor

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetFontColor

int SnapmanCellSetFontColor(void *g,int row,int col,int color)

函数名称：    SnapmanCellSetFont

函数作用：    设置单元格字体颜色

函数参数：    g为表格文件指针，row为指定行（必须大于等于0），col为指定列（必须大于等于0），color为需要设置字体的颜色

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetFont用例


SnapmanCellSetLineColor

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetLineColor

int SnapmanCellSetLineColor(void *g,int color)

函数名称：    SnapmanCellSetLineColor

函数作用：    设置单元格边框颜色

函数参数：    g为表格文件指针，color为需要设置边框的颜色

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：

void TestSnapmanCellGetFont()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        SnapmanBorderLine rightLine, bottomLine;

        if(SnapmanCellSetLineColor(g,RGB(255,255,0))==1)

        {

            wPrint(L("设置单元格边框颜色成功."));

        }else

        {

            wPrint(L("设置单元格边框颜色失败."));

        }

        if(SnapmanCellSetLineWidth(g,2)==1)

        {

            wPrint(L("设置单元格边框宽度成功."));

        }else

        {

            wPrint(L("设置单元格边框宽度失败."));

        }

        if(SnapmanCellSetLineType(g,2,2,3,3,GRIDCELLLINE_FRAME)==1)

        {

            wPrint(L("设置单元格边框成功."));

        }else

        {

            wPrint(L("设置单元格边框失败."));

        }

        rightLine  = SnapmanCellGetRightLine(g,3,3);

        bottomLine = SnapmanCellGetRightLine(g,3,3);

        wPrint(L("第三行第三列的单元格右边框为：类型-%d，宽度-%d，颜色-%d"),rightLine.type,rightLine.width,rightLine.color);

        wPrint(L("第三行第三列的单元格下边框为：类型-%d，宽度-%d，颜色-%d"),bottomLine.type,bottomLine.width,bottomLine.color);

        SnapmanGridSave(g);

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanCellSetLineWidth

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetLineWidth

int SnapmanCellSetLineWidth(void *g,int width)

函数名称：    SnapmanCellSetLineWidth

函数作用：    设置单元格边框的宽度

函数参数：    g为表格文件指针，width为宽度

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetLineColor用例


SnapmanCellSetLineType

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetLineType

int SnapmanCellSetLineType(void *g,int row,int col,int endrow,int endcol,int type)

函数名称：    SnapmanCellSetLineType

函数作用：    设置单元格边框

函数参数：    g为表格文件指针，row为开始行（包含），col为开始列（包含），endrow为结束行（包含），endcol为结束列（包含），type为边框类型

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：边框类型包括如下类型：

            enum GridCellLineEnm

            {

                GRIDCELLLINE_BOTTOM,    //底边框

                GRIDCELLLINE_TOP,       //上边框

                GRIDCELLLINE_LEFT,      //左边框

                GRIDCELLLINE_RIGHT,     //右边框

                GRIDCELLLINE_NONE,      //无边框

                GRIDCELLLINE_ALL,       //全边框

                GRIDCELLLINE_FRAME,     //外边框

                GRIDCELLLINE_BOLDFRAME  //粗外边框

            };

函数样例：参考TestSnapmanCellSetLineColor用例


SnapmanCellGetRightLine

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetRightLine

SnapmanBorderLine SnapmanCellGetRightLine(void *g,int row,int col)

函数名称：    SnapmanCellGetRightLine

函数作用：    获取单元格右边框线条

函数参数：    g为表格文件指针，row为指定行，col为指定列

函数返回值：  SnapmanBorderLine为存储边框数据的结构，结构如下：

            typedef struct SnapmanBorderLine

            {

                int type;      //线条类型，0是实现，1是虚线

                int width;     //宽度

                int color;     //颜色

            }SnapmanBorderLine;

函数特别说明：无

函数样例：参考TestSnapmanCellSetLineColor用例


SnapmanCellGetBottomLine

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetBottomLine

SnapmanBorderLine SnapmanCellGetBottomLine(void *g,int row,int col)

函数名称：    SnapmanCellGetBottomLine

函数作用：    获取单元格下边框线条

函数参数：    g为表格文件指针，row为指定行，col为指定列

函数返回值：  边框数据的结构

函数特别说明：无

函数样例：参考TestSnapmanCellSetLineColor用例


SnapmanCellGetBackgoundColor

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetBackgoundColor

int SnapmanCellGetBackgoundColor(void *g,int row,int col)

函数名称：    SnapmanCellGetBackgoundColor

函数作用：    获取单元格背景颜色

函数参数：    g为表格文件指针，row为指定行，col为指定列

函数返回值：  背景颜色

函数特别说明：无

函数样例：

void TestSnapmanCellGetBackgoundColor()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        if(SnapmanCellSetBackgoundColor(g,3,3,RGB(133,0,0))==1)

        {

            wPrint(L("设置单元格背景颜色成功."));

        }else

        {

            wPrint(L("设置单元格背景颜色失败."));

        }

        wPrint(L("获取第三行第三列的单元格背景颜色为：%d"),SnapmanCellGetBackgoundColor(g,3,3));

        if(SnapmanCellSetAlign(g,3,3,DT_CENTER|DT_VCENTER)==1)

        {

            wPrint(L("设置单元格对齐方式成功."));

        }else

        {

            wPrint(L("设置单元格对齐方式失败."));

        }

        wPrint(L("获取第三行第三列的单元格对齐方式为：%d"),SnapmanCellGetAlign(g,3,3));

        SnapmanGridSave(g);

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanCellSetBackgoundColor

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetBackgoundColor

int SnapmanCellSetBackgoundColor(void *g,int row,int col,int color)

函数名称：    SnapmanCellSetBackgoundColor

函数作用：    设置单元格背景颜色

函数参数：    g为表格文件指针，row为指定行，col为指定列，color为颜色

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetBackgoundColor用例


SnapmanCellSetBackgoundLafer

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetBackgoundLafer

int SnapmanCellSetBackgoundLafer(void  *g, int   row, int  col, wchar_t *text )

函数名称：    SnapmanCellSetBackgoundLafer
函数作用：    设置单元格背景为lafer背景
函数参数：    g为表格文件指针，row为指定行，col为指定列，text为json格式的lafer文法字符串
函数返回值：  0或1，成功返回1，否则返回0
函数特别说明：lafer文法为2种：一种为数字形式的代表颜色；一种为数组形式，包括如下的18种绘制要素：
  1、线型:[0,0,1,1]说明：1线型，2宽度，3颜色
  2、画刷:[1,1]
  3、字体:[2,0],[2,大小，黑体，斜体,下划线，中划线，字体名称]
  4、点：[3,0,0,颜色]
  5、线：[4,0,0,0,0]
  6、矩形;[5,0,0,0,0,0],说明：0是标记，1是类型-0画线1填充2画线并且填充，2-5是两个点
  7、圆角矩形;[6,0,0,0,0,0,0,0]
  8、圆;[7,0,0,0,0,1]
  9、多边形：[8,1,0,0,0,0,1,1,22,22,66,66],说明：0是标记，1是类型-0画线1填充2画线并且填充，后面都是点
  10、渐变矩形:[9,0,0,0,0,0,0,1],说明：1是方向:0代表水平、1代表竖直，2-5是矩形，6开始颜色，7结束颜色
  11、文本;[10,0,0，""]说明：1、2是左上角xy，3是文本
  12、在矩形绘制文本：[11,0,0,0,0,""]
  13、图片:[12,0,0,0,0，"XX.jpg"]
  14、图片:[13,"XX.jpg",w,h]
  15、绘制不换行的内容：[14,"","",[13,"XX.jpg"]]
  16、透明矩形：[15,Color,Alpha,x,y,x1,y1]
  17、绘制图片：[16,x,y,"xx.jpg"]
  18、平滑多边形：[17,1,0,0,0,0,1,1,22,22,66,66],说明：0是标记，1是类型-0画线1填充2画线并且填充，后面都是点
    如：[[0,0,1,13421772],[1,#FFFFFF],[5,2,0,0,1,1]],包括3个绘制要素1设置线型，2设置填充颜色，3绘制一个矩形
函数样例：无


SnapmanCellGetAlign

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetAlign

int SnapmanCellGetAlign(void *g,int row,int col)

函数名称：    SnapmanCellGetAlign

函数作用：    获取单元格对齐方式

函数参数：    g为表格文件指针，row为指定行，col为指定列

函数返回值：  单元格对齐方式

函数特别说明：对齐方式有如下组合,包括水平对齐和竖直对齐，使用&判断，使用|组合设置

            #define DT_TOP                      0x00000000

            #define DT_LEFT                     0x00000000

            #define DT_CENTER                   0x00000001

            #define DT_RIGHT                    0x00000002

            #define DT_VCENTER                  0x00000004

            #define DT_BOTTOM                   0x00000008

函数样例：参考TestSnapmanCellSetBackgoundColor用例


SnapmanCellSetAlign

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetAlign

int SnapmanCellSetAlign(void *g,int row,int col,int align)

函数名称：    SnapmanCellSetAlign

函数作用：    设置单元格对齐方式

函数参数：    g为表格文件指针，row为指定行，col为指定列，align单元格对齐方式

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetBackgoundColor用例


SnapmanCellGetCombine

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetCombine

SnapmanCombine SnapmanCellGetCombine(void *g,int row,int col)

函数名称：    SnapmanCellGetCombine

函数作用：    获取单元格合并信息

函数参数：    g为表格文件指针，row为指定行，col为指定列

函数返回值：  SnapmanCombine合并信息，结构为：

            typedef struct SnapmanCombine

            {

                int row;       //合并单元格开始行

                int col;       //合并单元格开始列

                int endrow;        //合并单元格结束行

                int endcol;        //合并单元格结束列

            }SnapmanCombine;

函数特别说明：如果没有合并信息则返回的开始行、列，结束行、列都为0

函数样例：

void TestSnapmanCellGetCombine()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        SnapmanCombine rCombine;

        if(SnapmanCellSetCombine(g,5,1,6,4)==1)

        {

            wPrint(L("设置单元格合并成功."));

        }else

        {

            wPrint(L("设置单元格合并失败."));

        }

        rCombine = SnapmanCellGetCombine(g,6,3);

        wPrint(L("获取六行三列单元格的合并信息为：开始行-%d，开始列-%d，结束行-%d，结束列-%d"),rCombine.row,rCombine.col,rCombine.endrow,rCombine.endcol);

        if(SnapmanCellSetCrossCombine(g,7,1,9,4)==1)

        {

            wPrint(L("设置单元格跨行合并成功."));

        }else

        {

            wPrint(L("设置单元格跨行合并失败."));

        }

        rCombine = SnapmanCellGetCombine(g,8,4);

        wPrint(L("获取八行四列单元格的合并信息为：开始行-%d，开始列-%d，结束行-%d，结束列-%d"),rCombine.row,rCombine.col,rCombine.endrow,rCombine.endcol);

        SnapmanGridSave(g);

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanCellSetCombine

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetCombine

int SnapmanCellSetCombine(void *g,int row,int col,int endrow,int endcol)

函数名称：    SnapmanCellSetCombine

函数作用：    设置单元格合并或者取消合并

函数参数：    g为表格文件指针，row为开始行（包含），col为开始列（包含），endrow为结束行（包含），endcol为结束列（包含）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：当选择的单元格有合并单元格则取消合并，否则设置合并

函数样例：参考TestSnapmanCellGetCombine用例


SnapmanCellSetCrossCombine

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetCrossCombine

int SnapmanCellSetCrossCombine(void *g,int row,int col,int endrow,int endcol)

函数名称：    SnapmanCellSetCrossCombine

函数作用：    设置单元格跨行合并或者取消合并

函数参数：    g为表格文件指针，row为开始行（包含），col为开始列（包含），endrow为结束行（包含），endcol为结束列（包含）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：当选择的单元格有合并单元格则取消合并，否则设置跨行合并

函数样例：参考TestSnapmanCellGetCombine用例


SnapmanCellGetText

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetText

wchar_t * SnapmanCellGetText(void *g,int row,int col)

函数名称：    SnapmanCellGetText

函数作用：    获取单元格的文本数据，如果不是文本则转换成文本

函数参数：    g为表格文件指针，row为指定行（必须大于等于0），col为指定列（必须大于等于0）

函数返回值：  文本字符串

函数特别说明：无

函数样例：参考TestSnapmanCellGetType用例


SnapmanCellSetText

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetText

int SnapmanCellSetText(void *g,int row,int col,wchar_t *text)

函数名称：    SnapmanCellSetText

函数作用：    设置单元格数据为文本数据

函数参数：    g为表格文件指针，row为指定行（必须大于等于0），col为指定列（必须大于等于0），data为需要设置的数据

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：调用此方法不会将数据更新到文件内存中，如果需要更新进去需要调用SnapmanGridDataCommit函数；当调用SnapmanGridSave、SnapmanSaveFile保存或脚本运行完也会自动调用SnapmanGridDataCommit函数，但此时数据可能存在错乱

函数样例：参考TestSnapmanCellGetType用例


SnapmanCellGetDouble

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetDouble

double SnapmanCellGetDouble(void *g,int row,int col)

函数名称：    SnapmanCellGetDouble

函数作用：    获取单元格的浮点型数据，如果不是浮点型则转换成浮点型

函数参数：    g为表格文件指针，row为指定行（必须大于等于0），col为指定列（必须大于等于0）

函数返回值：  浮点型数值

函数特别说明：无

函数样例：参考TestSnapmanCellGetType用例


SnapmanCellSetDouble

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetDouble

int SnapmanCellSetDouble(void *g,int row,int col,double data)

函数名称：    SnapmanCellSetDouble

函数作用：    设置单元格数据为浮点型数据

函数参数：    g为表格文件指针，row为指定行（必须大于等于0），col为指定列（必须大于等于0），data为需要设置的数据

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：调用此方法不会将数据更新到文件内存中，如果需要更新进去需要调用SnapmanGridDataCommit函数；当调用SnapmanGridSave、SnapmanSaveFile保存或脚本运行完也会自动调用SnapmanGridDataCommit函数，但此时数据可能存在错乱

函数样例：参考TestSnapmanCellGetType用例


SnapmanCellGetInt

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetInt

int SnapmanCellGetInt(void *g,int row,int col)

函数名称：    SnapmanCellGetText

函数作用：    获取单元格的整形数字，如果不是整形则转换成整形

函数参数：    g为表格文件指针，row为指定行（必须大于等于0），col为指定列（必须大于等于0）

函数返回值：  整形数值

函数特别说明：无

函数样例：参考TestSnapmanCellGetType用例


SnapmanCellSetInt

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetInt

int SnapmanCellSetInt(void *g,int row,int col,int data)

函数名称：    SnapmanCellSetInt

函数作用：    设置单元格数据为整形数据

函数参数：    g为表格文件指针，row为指定行（必须大于等于0），col为指定列（必须大于等于0），data为需要设置的数据

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：调用此方法不会将数据更新到文件内存中，如果需要更新进去需要调用SnapmanGridDataCommit函数；当调用SnapmanGridSave、SnapmanSaveFile保存或脚本运行完也会自动调用SnapmanGridDataCommit函数，但此时数据可能存在错乱

函数样例：参考TestSnapmanCellGetType用例


SnapmanCellGetScript

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetScript

wchar_t * SnapmanCellGetScript(void *g,int row,int col)

函数名称：    SnapmanCellGetScript

函数作用：    获取单元格脚本，包括：TCC、Exprtk和各种控件事件脚本，如果没有脚本则返回NULL

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  单元格脚本内容，如果没有脚本则返回NULL

函数特别说明：无

函数样例：

void TestSnapmanCellGetScript()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        wchar_t *pCheckScript  = L"void OnCheckClick(void *g, int row, int col,int check){\n\tMessageBox(NULL,\"Hello world.\",\"Hello\",MB_OK);\n}";

        wchar_t *pTccScript    = L"void main(){\n\twPrint(L(\"Hello world\"));\n}";

        wchar_t *pExprtkScript = L"a21_:='Hello dida';";

        //1、首选设置单元格为选择框

        SnapmanCellSetCheck(g,17,1,0);

        //2、设置按钮脚本

        if(SnapmanCellSetScript(g,17,1,pCheckScript)==1)

        {

            wPrint(L("设置选择框脚本成功."));

        }else

        {

            wPrint(L("设置选择框脚本失败."));

        }

        //3、设置为TCC

        if(SnapmanCellSetTccScript(g,18,1,pTccScript)==1)

        {

            wPrint(L("设置TCC脚本成功."));

        }else

        {

            wPrint(L("设置TCC脚本失败."));

        }

        //4、设置为Exprtk

        if(SnapmanCellSetExprtkScript(g,19,1,pExprtkScript)==1)

        {

            wPrint(L("设置Exprtk脚本成功."));

        }else

        {

            wPrint(L("设置Exprtk脚本失败."));

        }

        wPrint(L("设置Exprtk脚本后19行1列的脚本为：%s"),SnapmanCellGetScript(g,19,1));

        //5、运行脚本

        SnapmanRunFile(L("\\08.TccTestcase\\24.testcaseData"));

        SnapmanGridSave(g);

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanCellSetScript

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetScript

int SnapmanCellSetScript(void *g,int row,int col,wchar_t *script)

函数名称：    SnapmanCellSetScript

函数作用：    设置单元格各种控件的事件脚本，如果单元格没有事件则脚本无效

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），script为需要设置的脚本内容

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellGetScript用例


SnapmanCellSetExprtkScript

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetExprtkScript

int SnapmanCellSetExprtkScript(void *g,int row,int col,wchar_t *script)

函数名称：    SnapmanCellSetExprtkScript

函数作用：    设置单元格Exprtk脚本内容，如果不是Exprtk类型则设置Exprtk类型

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），script为需要设置的脚本内容

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellGetScript用例


SnapmanCellSetTccScript

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetTccScript

int SnapmanCellSetTccScript(void *g,int row,int col,wchar_t *script)

函数名称：    SnapmanCellSetTccScript

函数作用：    设置单元格TTC脚本内容，如果不是TCC类型则设置TCC类型

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），script为需要设置的脚本内容

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellGetScript用例


SnapmanCellGetCheck

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetCheck

int SnapmanCellGetCheck(void *g,int row,int col)

函数名称：    SnapmanCellGetCheck

函数作用：    获取单元格勾选信息，只有单元格为勾选框可以生效，否则返回0

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  如果是勾选框并且勾选了返回1，否则返回0

函数特别说明：无

函数样例：

void TestSnapmanCellGetCheck()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        if(SnapmanCellSetCheck(g,17,1,1)==1)

        {

            wPrint(L("设置勾选框成功."));

        }else

        {

            wPrint(L("设置勾选框失败."));

        }

        wPrint(L("第17行1列单元格的勾选状态为：%d"),SnapmanCellGetCheck(g,17,1));

        if(SnapmanCellSetProgress(g,26,1,50)==1)

        {

            wPrint(L("设置进度条成功."));

        }else

        {

            wPrint(L("设置进度条失败."));

        }

        wPrint(L("第26行1列单元格的进度条进度为：%d%%"),SnapmanCellGetProgress(g,26,1));

        if(SnapmanCellSetLock(g,27,1,1)==1)

        {

            wPrint(L("设置单元格加锁成功."));

        }else

        {

            wPrint(L("设置单元格加锁失败."));

        }

        wPrint(L("第27行1列单元格的加锁状态为：%d"),SnapmanCellGetLock(g,27,1));

        SnapmanCellSetText(g,28,1,L("autoline为自动换行状态：1自动换行、0不自动换行"));

        SnapmanGridDataCommit(g);//将SnapmanCellSetText设置的数据更新到文件内存中

        if(SnapmanCellSetAutoLine(g,28,1,1)==1)

        {

            wPrint(L("设置单元格自动换行成功."));

        }else

        {

            wPrint(L("设置单元格自动换行失败."));

        }

        wPrint(L("第28行1列单元格的自动换行状态为：%d"),SnapmanCellGetAutoLine(g,28,1));

        if(SnapmanCellSetFile(g,29,1,L("c:\\Program2.cs"))==1)

        {

            wPrint(L("设置单元格文件成功."));

        }else

        {

            wPrint(L("设置单元格文件失败."));

        }

        SnapmanGridSave(g);

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanCellSetCheck

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetCheck

int SnapmanCellSetCheck(void *g,int row,int col,int check)

函数名称：    SnapmanCellSetCheck

函数作用：    设置单元格勾选状态，如果单元格不是勾选框，则将单元格设置为勾选框

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），check为勾选状态：1为勾选，0为不勾选

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellGetCheck用例


SnapmanCellGetProgress

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetProgress

int SnapmanCellGetProgress(void *g,int row,int col)

函数名称：    SnapmanCellGetProgress

函数作用：    获取单元格进度条进度，只有单元格为进度条时生效，否则返回0

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  如果单元格是进度条则返回当前进度数据（范围0-100），否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellGetCheck用例


SnapmanCellSetProgress

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetProgress

int SnapmanCellSetProgress(void *g,int row,int col,int progress)

函数名称：    SnapmanCellSetProgress

函数作用：    设置单元格进度条进度，如果单元格不是进度条，则将单元格设置为进度条

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），progress为进度条进度范围为0-100

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellGetCheck用例


SnapmanCellGetLock

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetLock

int SnapmanCellGetLock(void *g,int row,int col)

函数名称：    SnapmanCellGetLock

函数作用：    获取单元格加锁状态

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  如果单元格已经加锁返回1，否则返回0

函数特别说明：单元格加锁后无法进行编辑

函数样例：参考TestSnapmanCellGetCheck用例


SnapmanCellSetLock

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetLock

int SnapmanCellSetLock(void *g,int row,int col,int lock)

函数名称：    SnapmanCellSetLock

函数作用：    设置单元格加锁状态

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），lock为加锁状态：1是加锁、0为非加锁

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellGetCheck用例


SnapmanCellGetAutoLine

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetAutoLine

int SnapmanCellGetAutoLine(void *g,int row,int col)

函数名称：    SnapmanCellGetAutoLine

函数作用：    获取单元格是否自动换行

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  如果是自动换行返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellGetCheck用例


SnapmanCellSetAutoLine

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetAutoLine

int SnapmanCellSetAutoLine(void *g,int row,int col,int autoline)

函数名称：    SnapmanCellSetAutoLine

函数作用：    设置单元格自动换行状态

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），autoline为自动换行状态：1自动换行、0不自动换行

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellGetCheck用例


SnapmanCellGetButton

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetButton

wchar_t * SnapmanCellGetButton(void *g,int row,int col)

函数名称：    SnapmanCellGetButton

函数作用：    获取按钮显示名称

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  成功返回按钮显示名称，否则返回NULL

函数特别说明：无

函数样例：参考TestSnapmanCellSetButton用例


SnapmanCellSetButton

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetButton

int SnapmanCellSetButton(void *g,int row,int col,wchar_t *text)

函数名称：    SnapmanCellSetButton

函数作用：    设置单元格为按钮，并设置其按钮显示名称

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），text按钮显示名称

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：如单元格本身为按钮则设置按钮显示名称，否则先设置为按钮再设置其显示名称

函数样例：

void TestSnapmanCellSetButton()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        wchar_t *appPath = getAppPath();

        SnapmanButtonImage buttonImage,retButtonImage;

        if(SnapmanCellSetButton(g,30,1,L("开心按钮"))==1)

        {

            wPrint(L("设置按钮成功."));

        }else

        {

            wPrint(L("设置按钮失败."));

        }

        wPrint(L("第30行1列单元格的按钮显示名称为：%s"),SnapmanCellGetButton(g,30,1));

        buttonImage.strBackgroundImage = concat(appPath,L("Icon\\Replace-1.png"));

        buttonImage.strEnterImage      = concat(appPath,L("Icon\\Replace-2.png"));

        buttonImage.strPressImage      = concat(appPath,L("Icon\\Replace-3.png"));

        SnapmanCellSetButton(g,31,1,L"");

        if(SnapmanCellSetButtonImage(g,31,1,&buttonImage)==1)

        {

            wPrint(L("设置按钮成功."));

        }else

        {

            wPrint(L("设置按钮失败."));

        }

        retButtonImage = SnapmanCellGetButtonImage(g,31,1);

        wPrint(L("第30行1列单元格的按钮：背景-%s，鼠标进入背景-%s，鼠标点击背景-%s"),retButtonImage.strBackgroundImage,retButtonImage.strEnterImage,retButtonImage.strPressImage);

        if(SnapmanCellSetCombo(g,32,1,L("宋体\n幼圆\n楷体\n仿宋"))==1)

        {

            wPrint(L("设置下拉框成功."));

        }else

        {

            wPrint(L("设置下拉框失败."));

        }

        wPrint(SnapmanCellGetCombo(g,32,1));

        if(SnapmanCellSetComboIndex(g,32,1,3)==1)

        {

            wPrint(L("设置下拉框索引成功."));

        }else

        {

            wPrint(L("设置下拉框索引失败."));

        }

        wPrint(L("第32行1列单元格下拉框的索引是：%d"),SnapmanCellGetComboIndex(g,32,1));

        if(SnapmanCellSetMark(g,33,1,85)==1)

        {

            wPrint(L("设置打分控件成功."));

        }else

        {

            wPrint(L("设置打分控件失败."));

        }

        wPrint(L("第33行1列单元格打分控件分数是：%d"),SnapmanCellGetMark(g,32,1));

        SnapmanGridSave(g);

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanCellGetButtonImage

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetButtonImage

SnapmanButtonImage SnapmanCellGetButtonImage(void *g,int row,int col)

函数名称：    SnapmanCellGetButtonImage

函数作用：    获取按钮背景、鼠标进入背景、鼠标点击背景

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  返回SnapmanButtonImage结构，失败结构体属性为NULL，返回结构体特别说明：

            typedef struct SnapmanButtonImage

            {

                wchar_t *strBackgroundImage;   //如果设置默认背景图片(服务器相对路径)则返回路径指针（不需要释放），否则返回NULL

                wchar_t *strEnterImage;            //如果设置鼠标进入背景图片(服务器相对路径)则返回路径指针（不需要释放），否则返回NULL

                wchar_t *strPressImage;            //如果设置鼠标点击背景图片(服务器相对路径)则返回路径指针（不需要释放），否则返回NULL

            }SnapmanButtonImage;

函数特别说明：无

函数样例：参考TestSnapmanCellSetButton用例


SnapmanCellSetButtonImage

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetButtonImage

int SnapmanCellSetButtonImage(void *g,int row,int col,SnapmanButtonImage *buttonImage)

函数名称：    SnapmanCellSetButtonImage

函数作用：    设置按钮背景、鼠标进入背景、鼠标点击背景

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），buttonImage为保存保存背景的结构，定义为：

            typedef struct SnapmanButtonImage

            {

                wchar_t *strBackgroundImage;   //默认背景图片路径，本地绝对路径

                wchar_t *strEnterImage;            //鼠标进入背景图片路径，本地绝对路径

                wchar_t *strPressImage;            //鼠标点击背景图片路径，本地绝对路径

            }SnapmanButtonImage;

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetButton用例


SnapmanCellGetCombo

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetCombo

wchar_t *SnapmanCellGetCombo(void *g,int row,int col)

函数名称：    SnapmanCellGetCombo

函数作用：    获取单元格下拉选择框的下拉列表文本

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  成功返回下拉列表文本，否则返回NULL

函数特别说明：无

函数样例：参考TestSnapmanCellSetButton用例


SnapmanCellSetCombo

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetCombo

int SnapmanCellSetCombo(void *g,int row,int col,wchar_t *pList)

函数名称：    SnapmanCellSetCombo

函数作用：    设置单元格为下拉选择框，并设置下拉列表文本

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），pList为下拉列表文本

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetButton用例


SnapmanCellGetComboIndex

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetComboIndex

int SnapmanCellGetComboIndex(void *g,int row,int col)

函数名称：    SnapmanCellGetComboIndex

函数作用：    获取单元格下拉选择框的选择索引

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  如果下拉选择框有选择文本返回对于索引，如果没有或获取失败返回-1

函数特别说明：无

函数样例：参考TestSnapmanCellSetButton用例


SnapmanCellSetComboIndex

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetComboIndex

int SnapmanCellSetComboIndex(void *g,int row,int col,int index)

函数名称：    SnapmanCellSetComboIndex

函数作用：    设置单元格下拉选择框的选择索引，设置后会自动运算下拉框文本

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），index为需要选择项的索引范围:[0,下拉列表项的最大个数)

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetButton用例


SnapmanCellGetMark

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetMark

int SnapmanCellGetMark(void *g,int row,int col)

函数名称：    SnapmanCellGetMark

函数作用：    获取单元格打分控件的分数

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  成功返回分数，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetButton用例


SnapmanCellSetMark

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetMark

int SnapmanCellSetMark(void *g,int row,int col,int mark)

函数名称：    SnapmanCellSetMark

函数作用：    设置单元格为打分控件，并设置其分数

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），mark为分数

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetButton用例


SnapmanCellSetFile

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetFile

int SnapmanCellSetFile(void *g,int row,int col,wchar_t *path)

函数名称：    SnapmanCellSetFile

函数作用：    设置单元格文件数据，如果单元格为非文件类型则设置为文件类型

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），path为本机文件（不能是文件夹，文件必须存在否则失败）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：设置时候文件会拷贝到软件的附件目录，当表格保存时候会将文件上传到服务器附件目录

函数样例：参考TestSnapmanCellGetCheck用例


SnapmanCellGetFile

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetFile
wchar_t * SnapmanCellGetFile(void *g,int row,int col)
函数名称： SnapmanCellGetFile
函数作用： 获取单元格文件的相对路径
函数参数： g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）
函数返回值： 如果单元格是文件时返回相对路径，否则返回NULL
函数特别说明：无
函数样例：无


SnapmanCellGetPicture

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetPicture
wchar_t * SnapmanCellGetPicture(void *g,int row,int col)
函数名称： SnapmanCellGetPicture
函数作用： 获取单元格图片的相对路径
函数参数： g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）
函数返回值： 如果单元格是图片时返回相对路径，否则返回NULL
函数特别说明：无
函数样例：无


SnapmanCellSetPicture

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetPicture
int SnapmanCellSetPicture(void *g,int row,int col,wchar_t *path)
函数名称： SnapmanCellSetPicture
函数作用： 设置单元格图片数据，如果单元格为非图片类型则设置为图片类型
函数参数： g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），path为本机图片路径（文件必须存在否则失败）
函数返回值： 0或1，成功返回1，否则返回0
函数特别说明：设置时候文件会拷贝到软件的附件目录，当表格保存时候会将文件上传到服务器附件目录
函数样例：无


SnapmanCellSetHide

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetHide
int SnapmanCellSetHide(void *g,int row,int col,int bHide)
函数名称： SnapmanCellSetHide
函数作用： 设置单元格的隐藏状态
函数参数： g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），bHide是否隐藏（1是隐藏，0是不隐藏）
函数返回值： 0或1，成功返回1，否则返回0
函数特别说明：无
函数样例：无


SnapmanCellGetHide

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetHide
int SnapmanCellGetHide(void *g,int row,int col)
函数名称： SnapmanCellGetHide
函数作用： 获取单元格的隐藏状态
函数参数： g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）
函数返回值： 隐藏是1，不隐藏是0
函数特别说明：无
函数样例：无


SnapmanCellSortAscend

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSortAscend

int SnapmanCellSortAscend(void *g,int row,int col,int endrow,int endcol,int expand)

函数名称：    SnapmanCellSortAscend

函数作用：    对选择的单元格按照升序排序

函数参数：    g为表格文件指针，row为开始行（包含），col为开始列（包含），endrow为结束行（包含），endcol为结束列（包含），expand为是以扩展区域排序还是当前区域排序

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：

void TestSnapmanCellSortAscend()

{

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\24.testcaseData"));

    if(g)

    {

        SnapmanCellSortDescend(g,12,5,14,5,0);

        SnapmanCellSortDescend(g,15,5,17,5,1);

        SnapmanCellSortAscend(g,12,3,14,3,0);

        SnapmanCellSortAscend(g,15,2,17,2,1);

        SnapmanGridSave(g);

        SnapmanCloseGrid(L("\\08.TccTestcase\\24.testcaseData"));

    }

    SnapmanCleanUp();

}


SnapmanCellSortDescend

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSortDescend

int SnapmanCellSortDescend(void *g,int row,int col,int endrow,int endcol,int expand)

函数名称：    SnapmanCellGetComboIndex

函数作用：    对选择的单元格按照降序排序

函数参数：    g为表格文件指针，row为开始行（包含），col为开始列（包含），endrow为结束行（包含），endcol为结束列（包含），expand为是以扩展区域排序还是当前区域排序

函数返回值：  如果下拉选择框有选择文本返回对于索引，如果没有或获取失败返回-1

函数特别说明：无

函数样例：参考TestSnapmanCellSortAscend用例


SnapmanCellSetApplicationRunTemplate

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetApplicationRunTemplate

int SnapmanCellSetApplicationRunTemplate(void *g,int row,int col)

函数名称：    SnapmanCellSetApplicationRunTemplate

函数作用：    设置分布式运行模板

函数参数：    g为表格文件指针，row为开始行（包含），col为开始列（包含）

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：

void TestSnapmanCellSetApplicationRunTemplate()

{

    wchar_t *pScript = L"void main()

    {

        for(int i = 0; i <= 100; i+=2)

        {

            SnapmanSendProgress(i);

            SnapmanSendRunMessage(concat1(L\"Application Running \",itostr(i),L\"%...\"));

            SnapmanProccessMessage(100);

        }

        SnapmanSendRunMessage(L(\"Application Completed.\"));

        SnapmanSendLogFile(L(\"c:\\\\Program2.cs\"));

        SnapmanSendResultFile(L(\"c:\\\\Program2.cs\"));

        SnapmanSendAppCompleted(1);

        SnapmanCleanUp();

    }";

    int ret = SnapmanOpenGrid(L("\\08.TccTestcase\\25.testcaseData"));

    void *g = SnapmanGetGrid(L("\\08.TccTestcase\\25.testcaseData"));

    if(g)

    {

        if(SnapmanCellSetApplicationRunTemplate(g,0,0)==1)

        {

            wPrint(L("设置分布式运行模板成功."));

        }else

        {

            wPrint(L("设置分布式运行模板失败."));

        }

        SnapmanCellSetRunState(g,2,2,1);

        SnapmanCellSetRunState(g,3,2,1);

        SnapmanCellSetText(g,2,3,SnapmanGetUserName());

        SnapmanCellSetText(g,2,4,L"1");

        SnapmanCellSetText(g,2,5,L"tcc");

        SnapmanCellSetTccScript(g,2,6,pScript);

        SnapmanCellSetText(g,3,3,SnapmanGetUserName());

        SnapmanCellSetText(g,3,4,L"2");

        SnapmanCellSetText(g,3,5,L"tcc");

        SnapmanCellSetTccScript(g,3,6,pScript);

        SnapmanGridDataCommit(g);

        SnapmanGridSave(g);

    }

    SnapmanCleanUp();

}


SnapmanCellGetRunState

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetRunState

int SnapmanCellGetRunState(void *g,int row,int col)

函数名称：    SnapmanCellGetRunState

函数作用：    获取分布式运行按钮的状态

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）

函数返回值：  GRIDAPP_STOP是停止，GRIDAPP_START是运行

函数特别说明：无

函数样例：参考TestSnapmanCellSetApplicationRunTemplate用例


SnapmanCellSetRunState

Help > 系统功能函数 > 单元格操作 >
SnapmanCellSetRunState

int SnapmanCellSetRunState(void *g,int row,int col,int state)

函数名称：    SnapmanCellSetRunState

函数作用：    设置分布式运行按钮的状态

函数参数：    g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），state按钮状态：GRIDAPP_STOP停止、GRIDAPP_START是运行

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetApplicationRunTemplate用例


SnapmanCellClear

Help > 系统功能函数 > 单元格操作 >
SnapmanCellClear
int SnapmanCellClear(void *g,int row,int col)
函数名称： SnapmanCellClear
函数作用： 清除单元格所有数据
函数参数： g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）
函数返回值： 0或1，成功返回1，否则返回0
函数特别说明：无
函数样例：无


SnapmanCellClearData

Help > 系统功能函数 > 单元格操作 >
SnapmanCellClearData
int SnapmanCellClearData(void *g,int row,int col)
函数名称： SnapmanCellClearData
函数作用： 清除单元格文本数据
函数参数： g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）
函数返回值： 0或1，成功返回1，否则返回0
函数特别说明：无
函数样例：无


SnapmanCellIsEmpty

Help > 系统功能函数 > 单元格操作 >
SnapmanCellIsEmpty
int SnapmanCellIsEmpty(void *g,int row,int col)
函数名称： SnapmanCellIsEmpty
函数作用： 获取单元格文本数据是否为空
函数参数： g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）
函数返回值： 如果为空返回1，否则返回0
函数特别说明：无
函数样例：无


SnapmanCellGetRect

Help > 系统功能函数 > 单元格操作 >
SnapmanCellGetRect
RECT SnapmanCellGetRect(void *g,int row,int col)
函数名称： SnapmanCellGetRect
函数作用： 获取单元格格在表格中的矩形位置
函数参数： g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0）
函数返回值： 返回单元格矩形
函数特别说明：无
函数样例：无


SnapmanCellScrollTo

Help > 系统功能函数 > 单元格操作 >
SnapmanCellScrollTo
int SnapmanCellScrollTo(void *g,int x,int y)
函数名称： SnapmanCellScrollTo
函数作用： 将电子表格滚动条滚到x和y的位置，从0开始
函数参数： g为表格文件指针，x为水平位置（必须大于等于0），col为垂直位置（必须大于等于0）
函数返回值： 如果为空返回1，否则返回0
函数特别说明：无
函数样例：无


SnapmanCellMakeVisible

Help > 系统功能函数 > 单元格操作 >
SnapmanCellMakeVisible
int SnapmanCellMakeVisible(void *g, int row,int col,int endrow,int endcol)
函数名称： SnapmanCellMakeVisible
函数作用： 设置指定的单元格在可视范围内
函数参数： g为表格文件指针，row为指定行（必须大于0），col为指定列（必须大于0），endrow为结束行（必须大于等于row），endcol为结束列（必须大于等于col）
函数返回值： 如果为空返回1，否则返回0
函数特别说明：无
函数样例：无


分布式消息回传

Help > 系统功能函数 >
分布式消息回传

封装了一些Snapman分布式模板相关的函数


SnapmanSendProgress

Help > 系统功能函数 > 分布式消息回传 >
SnapmanSendProgress

int SnapmanSendProgress(int nProgress);

函数名称：    SnapmanSendProgress

函数作用：    发送进度状态

函数参数：    nProgress当前进度，范围是0-100

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetApplicationRunTemplate用例


SnapmanSendRunMessage

Help > 系统功能函数 > 分布式消息回传 >
SnapmanSendRunMessage

int SnapmanSendRunMessage(const wchar_t *strMessage);

函数名称：    SnapmanSendRunMessage

函数作用：    发送运行时消息

函数参数：    strMessage为运行时消息

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetApplicationRunTemplate用例


SnapmanSendLogFile

Help > 系统功能函数 > 分布式消息回传 >
SnapmanSendLogFile

int SnapmanSendLogFile(const wchar_t *strLogFilePath);

函数名称：    SnapmanSendLogFile

函数作用：    发送运行的日志文件

函数参数：    strLogFilePath日志文件的绝对路径

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetApplicationRunTemplate用例


SnapmanSendResultFile

Help > 系统功能函数 > 分布式消息回传 >
SnapmanSendResultFile

int SnapmanSendResultFile(const wchar_t *strResultFilePath);

函数名称：    SnapmanSendResultFile

函数作用：    发送结果文件

函数参数：    strResultFilePath结果文件的绝对路径

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetApplicationRunTemplate用例


SnapmanSendAppCompleted

Help > 系统功能函数 > 分布式消息回传 >
SnapmanSendAppCompleted

int SnapmanSendAppCompleted(int bSuccess);

函数名称：    SnapmanSendAppCompleted

函数作用：    发送运行完成状态，释放服务器监控资源

函数参数：    bSuccess运行结果是否成功

函数返回值：  0或1，成功返回1，否则返回0

函数特别说明：无

函数样例：参考TestSnapmanCellSetApplicationRunTemplate用例


分布式开发

Help >
分布式开发
22、分布式任务运行模板

    分布式任务运行模板主要是用来让不同用户、不同机器同时或串行执行不同的任务，并监控任务运行进度、显示任务运行时消息，最终获取执行的结果文件和日志文件

分布式任务运行模板包括13列：

1、第一列为选择列，勾选框选择后对第二列的操作只要是勾选的行都会同时进行

2、第二列为操作列，可以启动运行或停止运行，方法是先选择需要操作的单元格，按住ctrl键然后点击鼠标左键可以改变状态

3、第三列为执行者列，填入需要执行的人（只有此人在线才能运行否则执行失败），只要此人在线服务器会将任务分发到此人客户端执行任务

4、第四列为次序列，如果次序相同则认为并发执行，如果任务次序不相同则按从小到大的次序进行执行

5、第五列为执行程序列，填入需要执行的程序路径或命令（需要自己保证执行者机器部署了指定的程序），特殊命令包括：

A、tcc，此任务为运行TCC脚本，在运行参数写TCC脚本

B、exprtk，此任务为运行Exprtk脚本，在运行参数写Exprtk脚本

C、runfile，此任务为运行电子表格脚本，在运行参数写需要运行的电子表格的相对路径

D、upload，此任务为上传一个文件到服务器，在运行参数写2个路径：第一个为本地文件绝对路径（包括文件名），第二个为服务器的相对路径（包括文件名），使用空格分隔，如果路径带有空格使用双引号‘“’将路径包起来

E、download，此任务为下载一个文件到运行机器，在运行参数写2个路径：第一个为服务器的相对路径（包括文件名），第二个为本地文件绝对路径（包括文件名），使用空格分隔，如果路径带有空格使用双引号‘“’将路径包起来

F、cmd，此任务为运行dos命令，在运行参数写需要运行的命令及参数

6、第六列为运行参数列，写入程序运行需要的参数

7、第七列为启动者列，程序记录了任务是由谁启动的，从此列开始到后面所有列都不可以编辑，是由运行程序自动上报或记录的信息

8、第八列为执行进度列，记录了当前程序运行的进度

9、第九列为任务开始时间列，记录了程序开始运行的时间

10、第十列为结束时间列，记录了程序运行结束的时间

11、第十一列为运行时消息列，记录了程序在运行过程中上报的消息

12、第十二列为日志文件列，记录了程序运行的日志文件（如果有上报的话）

13、第十三列为结果文件列，记录了程序运行出来的结果文件（如果有上报的话）


1、分布式dos命令

Help > 分布式开发 >
1、分布式dos命令
1、分布式dos命令

    在执行程序列写上cmd，在运行参数写需要运行的命令及参数，可以运行dos命令，运行后打印的消息会显示在运行时消息列，如：


2、分布式文件上传下载

Help > 分布式开发 >
2、分布式文件上传下载
2、分布式文件上传下载

    A、文件上传：在执行程序列写上upload，在运行参数写本地文件路径和服务器文件路径使用空格分开（如果路径带有空格使用双引号‘"’将路径包起来），可以上传文件到服务器保存，运行后在运行时消息列会显示文件上传是否成功，如：

特别说明：上传文件的服务器存放路径默认在AttachmentRoot下，如果指定的文件夹如例子的data不存在则会自动创建（可以创建多层目录）

在服务器保存的文件：

    B、文件下载：在执行程序列写上download，在运行参数写服务器文件路径和本地文件路径使用空格分开（如果路径带有空格使用双引号‘"’将路径包起来），可以从服务器下载文件到本地磁盘，运行后在运行时消息列会显示文件下载是否成功，如：


3、分布式应用程序

Help > 分布式开发 >
3、分布式应用程序
2、分布式应用程序

    在执行程序列写上应用程序的绝对路径（必须保证分发给的执行机器有部署此程序），在运行参数写需要的参数，可以启动程序运行，运行时消息列会打印程序上报的运行时消息，日志文件列显示应用程序上报的日志文件，结果文件列显示应用程序上报的结果文件，如下面为一个程序分发到三个人的机器并发执行：

如下为将程序分发到三个人的机器串行执行：

下面是继承了分布式运行接口的RunApp.exe程序界面

下面代码是C++应用程序和Snapman分布式系统对接的接口，利用此接口用户自己开发的程序可以对接到Snapman的分布式系统中，上报进度、消息、日志文件、结果文件、设置单元格数据、、字体、格式、运行结果等：

#include "stdafx.h"
#include <Windows.h>
#include <string>
#include<time.h>
using namespace std;

HWND hWindSnapman = NULL;
int nFiledIndex = 0;
const int SNAPMAN_APP_PROGRESS = 0;
const int SNAPMAN_APP_MESSAGE = 1;
const int SNAPMAN_APP_LOGFILE = 2;
const int SNAPMAN_APP_RESULTFILE = 3;
const int SNAPMAN_APP_COMPLETE = 4;
const int SNAPMAN_APP_CELLDATA = 5;
const int SNAPMAN_APP_CELLFONTCOLOR = 6;
const int SNAPMAN_APP_CELLBACKCOLOR = 7;
void SnapmanSendProgress(int nProgress)//上报当前任务的进度信息
{
 wchar_t buffer[1024] = {0};
 wsprintf(buffer,L"%d %d",nFiledIndex,nProgress);
 SendMessage(hWindSnapman, WM_SETTEXT, (WPARAM)SNAPMAN_APP_PROGRESS, (LPARAM)buffer);
}

void SnapmanSendMessage(const wstring &strMessage) //发送任务的运行时信息
{
 wchar_t buffer[1024] = {0};
 wsprintf(buffer,L"%d %s",nFiledIndex,strMessage.c_str());
 SendMessage(hWindSnapman, WM_SETTEXT, (WPARAM)SNAPMAN_APP_MESSAGE, (LPARAM)buffer);
}

void SnapmanSendLogFile(const wstring &strLogFilePath) //发送日志文件
{
 wchar_t buffer[1024] = {0};
 wsprintf(buffer,L"%d %s",nFiledIndex,strLogFilePath.c_str());
 SendMessage(hWindSnapman, WM_SETTEXT, (WPARAM)SNAPMAN_APP_LOGFILE, (LPARAM)buffer);
}

void SnapmanSendResultFile(const wstring &strResultFilePath) //发送结果文件
{
 wchar_t buffer[1024] = {0};
 wsprintf(buffer,L"%d %s",nFiledIndex,strResultFilePath.c_str());
 SendMessage(hWindSnapman, WM_SETTEXT, (WPARAM)SNAPMAN_APP_RESULTFILE, (LPARAM)buffer);
}

void SnapmanSendCellData(int nRow, int nCol,const wstring &strData) //改变某个单元格的数据
{
 wchar_t buffer[1024] = {0};
 wsprintf(buffer,L"%d %d %d %s",nFiledIndex,nRow,nCol,strData.c_str());
 SendMessage(hWindSnapman, WM_SETTEXT, (WPARAM)SNAPMAN_APP_CELLDATA, (LPARAM)buffer);
}

void SnapmanSendCellFontColor(int nRow, int nCol,int nColor) //改变某个单元格的文本颜色
{
 wchar_t buffer[1024] = {0};
 wsprintf(buffer,L"%d %d %d %d",nFiledIndex,nRow,nCol,nColor);
 SendMessage(hWindSnapman, WM_SETTEXT, (WPARAM)SNAPMAN_APP_CELLFONTCOLOR, (LPARAM)buffer);
}

void SnapmanSendCellBackColor(int nRow, int nCol,int nColor) //改变某个单元格的背景颜色
{
 wchar_t buffer[1024] = {0};
 wsprintf(buffer,L"%d %d %d %d",nFiledIndex,nRow,nCol,nColor);
 SendMessage(hWindSnapman, WM_SETTEXT, (WPARAM)SNAPMAN_APP_CELLBACKCOLOR, (LPARAM)buffer);
}

void SnapmanSendAppCompleted(bool bSuccess) //发送应用运行完成消息
{
 wchar_t buffer[1024] = {0};
 wsprintf(buffer,L"%d %d",nFiledIndex,bSuccess);
 SendMessage(hWindSnapman, WM_SETTEXT, (WPARAM)SNAPMAN_APP_COMPLETE, (LPARAM)buffer);
}

int SnapmanMain(_TCHAR *argv);

int _tmain(int argc, _TCHAR* argv[])
{
 wprintf(L"%s\n",argv[0]);
 hWindSnapman = (HWND)_wtoi(argv[1]);      //保存Snapman主窗体的句柄
 nFiledIndex  = _wtoi(argv[2]);            //保存当前任务的全局ID
 return SnapmanMain(argc>=4?argv[3]:NULL);
}

int SnapmanMain(_TCHAR *argv)
{
 return 0;
}


4、分布式Exprtk脚本

Help > 分布式开发 >
4、分布式Exprtk脚本
4、分布式Exprtk脚本

    在执行程序列写上exprtk，将运行参数变成Exprtk脚本框写入需要执行的Exprtk脚本，可以运行Exprtk脚本，运行后运行时消息列会显示是否执行成功，如：

如上例子将一个计算任务分成2份，让2个用户去并发进行运算。


5、分布式Tcc脚本

Help > 分布式开发 >
5、分布式Tcc脚本
5、分布式Tcc脚本

    在执行程序列写上tcc，将运行参数变成Tcc脚本框写入需要执行的Tcc脚本，可以运行Tcc脚本，运行后运行时消息列会显示是否执行成功，如：

如上例子将一个计算任务分成2份，让2个用户去并发进行运算。


6、分布式运行表格脚本

Help > 分布式开发 >
6、分布式运行表格脚本
6、分布式运行表格脚本

     在执行程序列写上runfile ，将运行参数写上需要运行的表格路径，可以运行表格脚本，运行后运行时消息列会显示是否执行成功，如：

如上例子将2个包含大量运算的模块分到2个用户去并发进行计算。


高级开发样例

Help >
高级开发样例

下面介绍一些Snapman系统的高级开发样例


花季项目管理系统开发

Help > 高级开发样例 >
花季项目管理系统开发

snapman是一个简单而强大的团队协作软件，在上面的信息可以是数据、可以是规则、也可以是自动化代码；最重要的它是一个可以开发的协作平台，所有信息都可以作用到所有人或机器上，大大减少了工作的复杂度。软件开发项目是人类工程中对人力、脑力的配合度要求最高的项目。所以高智商的人才开发出各种项目定义实施流程：PMBOK、CMMI、IPD、SCRUM、XP等，这些流程的实施离不开各种强大的信息系统。但是这些系统只适合于大公司大流程，到单个的项目组级别很难为项目具体的特点做适配，随心所欲的更改。比如做10个项目要开发出10个软件版本这是基本不可能的事情。下面我们看看一个人如何在短短的三天内开发一个软件项目管理系统，短时间为每个项目开发一个适配的系统，将不可能变为可能。

一个软件项目包括：市场、客户需求、设计、开发、测试、版本发布、财务回款、软件维护等过程。我们今天设计的花季项目管理系统只包含：设计、开发、测试、版本发布的核心部分。花季项目管理系统组成包括：

1、项目信息和团队信息

2、设计及计划安排信息

3、员工每天工作日报

4、问题单提单与跟踪

5、员工工作绩效考评

项目中每个环节相互联系并紧密依赖：建立一个项目和团队，按照需求进行系统设计及每天每个员工的工作安排，员工每天按照计划进行工作并进行日报报告，MDE对Story功能进行验收和工作考评，测试人员的问题提单，开发人员对问题进行修复，直到版本成功发布，最终项目完成后系统和项目经理对员工进行评价考核。这个系统总共花费3天大部分时间在业务设计上，代码实现只花了一天多一点点：

一、首选是数据存储部分，如下创建五张表：花季项目信息、花季计划信息、花季工作日报、花季问题跟踪、花季员工考评；这五张表只用来存储数据，不涉及任何 代码，所以业务设计好后，每张表花了5-8分钟来实现

01.花季项目信息，这张表包括：项目的相关信息、需求任务书、项目附件、必要的团队成员、角色及其主管；这张表直接由PM手工维护，这里面的信息由后面的工作表格进行使用。

02.花季计划信息，这张表包括：项目的各个关键里程碑时间点，项目的工作点数和每人每天的平均点数（使用点数可以衡量一个模块的复杂难易程度从而安排不同级别员工的工作），每员工每天的工作内容及完成状态；这张表直接由PM、SE、MDE、TC维护，这里面的信息由后面的工作表格进行使用。

03.花季工作日报，这张表包括：每天每个员工的工作完成状态、今天的总结和明天的计划，员工主管对员工今天工作完成的验收及质量考核；这张表由：01.花季我的日报、01.花季日报审核，2张表自动维护。

04.花季问题跟踪，这张表包括：测试人员提单的问题要素、跟踪状态和开发人员的分析及修复状态；这张表由：03.花季我的问题、04.花季我的测试，2张表自动维护。

05.花季员工考评，这张表包括：每个员工的工作状态、工作质量、工作态度、主管的考核等；这张表由：02.花季团队考评、01.花季日报审核，2张表自动维护。

二、其次是员工工作部分，如下创建四张表：花季我的日报、花季我的任务、花季我的问题、花季我的测试；这4张表是员工每天需要完成的工作。这几张表涉及界面设计和代码控制，界面设计总共花了半个小时，代码控制每张表花了不到1个小时。

01.花季我的日报，这张表包括：项目信息、员工今天的工作点数、完成进度、今天总结、明天计划、工作相关的图片和附件。事件包括：

A、初始化事件，自动获取项目信息、如果今天已经写过日报取今天日报呈现出来，事件代码：

int GetDaily(void *g,wchar_t *date,wchar_t *name)
{
    int row = 4;
    wchar_t *d,*n;
    while(1)
    {
        d = SnapmanCellGetText(g,row,2);
        n = SnapmanCellGetText(g,row,3);
        if(!d||!n)break;
        if(wcsicmp(d,date)==0&&wcsicmp(n,name)==0)return row;
        row++;
    }
    return 0;
}
wchar_t * GetUserManager(void *g,wchar_t *name)
{
    int row = 18;
    int col = 2;
    wchar_t *manager = NULL, *strName = NULL;
    while(1)
    {
        strName = SnapmanCellGetText(g,row,2);
        if(!strName || wcslen(strName)==0)break;
        if(wcsicmp(name,strName)==0)
        {
            manager = SnapmanCellGetText(g,row,13);
            break;
        }
        row++;
    }
    return manager;
}

void OnInitialize(void *g)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gDaily   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\03.花季工作日报"));
    if(gProject&&gDaily)
    {
        int row = GetDaily(gDaily,Date(),SnapmanGetUserName());
        if(row > 0)
        {
            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gDaily,row,4));
            SnapmanCellSetProgress(g,6,10,SnapmanCellGetInt(gDaily,row,5));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gDaily,row,6));
            SnapmanCellSetText(g,14,3,SnapmanCellGetText(gDaily,row,7));
            SnapmanCellSetFile(g,21,10,SnapmanCellGetFile(gDaily,row,10));
            SnapmanCellSetPicture(g,21,3,SnapmanCellGetPicture(gDaily,row,9));
        }
        SnapmanCellSetLock(g,4,3,0);
        SnapmanCellSetLock(g,4,10,0);
        SnapmanCellSetLock(g,5,3,0);
        SnapmanCellSetLock(g,5,10,0);
        SnapmanCellSetText(g,4,3,Date());
        SnapmanCellSetText(g,4,10,SnapmanCellGetText(gProject,3,3));
        SnapmanCellSetText(g,5,3,SnapmanGetUserName());
        SnapmanCellSetText(g,5,10,GetUserManager(gProject,SnapmanGetUserName()));
        SnapmanCellSetLock(g,4,3,1);
        SnapmanCellSetLock(g,4,10,1);
        SnapmanCellSetLock(g,5,3,1);
        SnapmanCellSetLock(g,5,10,1);
    }
    SnapmanCleanUp();
}

B、取昨天日报按钮事件，事件代码：

#include "time.h"
int GetLastDaily(void *g,wchar_t *date,wchar_t *name)
{
    int row = SnapmanGridGetDataRowCount(g,2);
    wchar_t *d,*n;
    while(row >= 4)
    {
        d = SnapmanCellGetText(g,row,2);
        n = SnapmanCellGetText(g,row,3);
        if(d&&n)
        {
            if(wcsicmp(d,date)!=0&&wcsicmp(n,name)==0)return row;
        }
        row--;
    }
    return 0;
}

void OnButtonClick(void *g, int row, int col)
{
    void *gDaily   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\03.花季工作日报"));
    if(gDaily)
    {
        int row = GetLastDaily(gDaily,Date(),SnapmanGetUserName());
        if(row > 0)
        {
            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gDaily,row,4));
            SnapmanCellSetProgress(g,6,10,SnapmanCellGetInt(gDaily,row,5));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gDaily,row,6));
            SnapmanCellSetText(g,14,3,SnapmanCellGetText(gDaily,row,7));
            SnapmanCellSetFile(g,21,10,SnapmanCellGetFile(gDaily,row,10));
            SnapmanCellSetPicture(g,21,3,SnapmanCellGetPicture(gDaily,row,9));
            MessageBox(SnapmanWnd,"日报获取成功！","获取日报",MB_OK);
        }else
        {
            MessageBox(SnapmanWnd,"找不到昨天的日报！","获取日报",MB_OK);
        }
    }
}

C、提交日报按钮事件 ，事件代码：

int GetDaily(void *g,wchar_t *date,wchar_t *name)
{
    int row = 4;
    wchar_t *d,*n;
    while(1)
    {
        d = SnapmanCellGetText(g,row,2);
        n = SnapmanCellGetText(g,row,3);
        if(!d||!n)break;
        if(wcsicmp(d,date)==0&&wcsicmp(n,name)==0)return row;
        row++;
    }
    return 0;
}
void OnButtonClick(void *g, int row, int col)
{
    void *gDaily   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\03.花季工作日报"));
    if(gDaily)
    {
        wchar_t *strWorkPoint = SnapmanCellGetText(g,6,3);
        wchar_t *strWorkload  = SnapmanCellGetText(g,7,3);
        wchar_t *strPlanTomorrow = SnapmanCellGetText(g,14,3);
        if(!strWorkPoint || *strWorkPoint==0)
        {
            MessageBox(SnapmanWnd,"请填写工作点数！","提交日报",MB_OK);
            return;
        }
        if(!strWorkload || *strWorkload==0)
        {
            MessageBox(SnapmanWnd,"请填写今天工作总结！","提交日报",MB_OK);
            return;
        }
        if(!strPlanTomorrow || *strPlanTomorrow==0)
        {
            MessageBox(SnapmanWnd,"请填写明天工作计划！","提交日报",MB_OK);
            return;
        }
        int row = GetDaily(gDaily,Date(),SnapmanGetUserName());
        if(row > 0)
        {
            SnapmanCellSetText(gDaily,row,4,SnapmanCellGetText(g,6,3));
            SnapmanCellSetInt(gDaily,row,5,SnapmanCellGetInt(g,6,10));
            SnapmanCellSetText(gDaily,row,6,SnapmanCellGetText(g,7,3));
            SnapmanCellSetText(gDaily,row,7,SnapmanCellGetText(g,14,3));
            SnapmanCellSetText(gDaily,row,8,DateTime());
            SnapmanCellSetFile(gDaily,row,10,SnapmanCellGetFile(g,21,10));
            SnapmanCellSetPicture(gDaily,row,9,SnapmanCellGetPicture(g,21,3));
        }else
        {
            int maxRow = SnapmanGridGetDataRowCount(gDaily,2) + 1;

            SnapmanCellSetText(gDaily,maxRow,1,itostr(maxRow-3));
            SnapmanCellSetText(gDaily,maxRow,2,Date());
            SnapmanCellSetText(gDaily,maxRow,3,SnapmanGetUserName());
            SnapmanCellSetText(gDaily,maxRow,4,SnapmanCellGetText(g,6,3));
            SnapmanCellSetInt(gDaily,maxRow,5,SnapmanCellGetInt(g,6,10));
            SnapmanCellSetText(gDaily,maxRow,6,SnapmanCellGetText(g,7,3));
            SnapmanCellSetText(gDaily,maxRow,7,SnapmanCellGetText(g,14,3));
            SnapmanCellSetText(gDaily,maxRow,8,DateTime());
            SnapmanCellSetFile(gDaily,maxRow,10,SnapmanCellGetFile(g,21,10));
            SnapmanCellSetPicture(gDaily,maxRow,9,SnapmanCellGetPicture(g,21,3));
        }
        if(SnapmanGridSave(gDaily))
        {
            MessageBox(SnapmanWnd,"日报提交成功！","提交日报",MB_OK);
        }
    }
    SnapmanCleanUp();
}

D、最终代码写完后将表格设置为不可以保存状态，这样表格就只能用来工作而不能用来存储数据，这样每个人写的日报就不会产生相互影响

02.花季我的任务，这张表包括：项目信息、员工前面未完成工作的统计、今天任务信息、今天任务完成状况。事件包括：

A、初始化事件，自动获取项目信息、自动计算员工前面未完成的工作，自动获取今天分配的任务，获取员工已经提交的任务信息，事件代码：

//一、获取日期和名字所在任务的行号
int GetPlanning(void *g,wchar_t *date,wchar_t *name)
{
    int row = 17;
    wchar_t *d,*n;
    while(1)
    {
        d = SnapmanCellGetText(g,row,6);
        n = SnapmanCellGetText(g,row,12);
        if(!d||!n)break;
        if(wcsicmp(d,date)==0&&wcsicmp(n,name)==0)return row;
        row++;
    }
    return 0;
}
//二、获用名字获取其主管名称
wchar_t * GetUserManager(void *g,wchar_t *name)
{
    int row = 18;
    int col = 2;
    wchar_t *manager = NULL, *strName = NULL;
    while(1)
    {
        strName = SnapmanCellGetText(g,row,2);
        if(!strName || wcslen(strName)==0)break;
        if(wcsicmp(name,strName)==0)
        {
            manager = SnapmanCellGetText(g,row,13);
            break;
        }
        row++;
    }
    return manager;
}
//三、设置用户信息
void SetUserInfo(void *g,void *gProject)
{
    SnapmanCellSetLock(g,4,3,0);
    SnapmanCellSetLock(g,4,10,0);
    SnapmanCellSetLock(g,5,3,0);
    SnapmanCellSetLock(g,5,10,0);
    SnapmanCellSetText(g,4,3,Date());
    SnapmanCellSetText(g,4,10,SnapmanCellGetText(gProject,3,3));
    SnapmanCellSetText(g,5,3,SnapmanGetUserName());
    SnapmanCellSetText(g,5,10,GetUserManager(gProject,SnapmanGetUserName()));
    SnapmanCellSetLock(g,4,3,1);
    SnapmanCellSetLock(g,4,10,1);
    SnapmanCellSetLock(g,5,3,1);
    SnapmanCellSetLock(g,5,10,1);
}
//四、设置计划信息
void SetPlanningInfo(void *g,void *gPlanning,int row)
{
    //1、设置今天需要完成的计划任务
    SnapmanCellSetLock(g,7,5,0);
    SnapmanCellSetLock(g,9,5,0);
    SnapmanCellSetLock(g,11,5,0);
    SnapmanCellSetLock(g,13,5,0);
    SnapmanCellSetLock(g,14,5,0);
    SnapmanCellSetText(g,7,5,SnapmanCellGetText(gPlanning,row,2));
    SnapmanCellSetText(g,9,5,SnapmanCellGetText(gPlanning,row,3));
    SnapmanCellSetText(g,11,5,SnapmanCellGetText(gPlanning,row,4));
    SnapmanCellSetText(g,13,5,SnapmanCellGetText(gPlanning,row,5));
    SnapmanCellSetText(g,14,5,SnapmanCellGetText(gPlanning,row,6));
    SnapmanCellSetLock(g,7,5,1);
    SnapmanCellSetLock(g,9,5,1);
    SnapmanCellSetLock(g,11,5,1);
    SnapmanCellSetLock(g,13,5,1);
    SnapmanCellSetLock(g,14,5,1);
    //2、设置今天任务完成状态
    SnapmanCellSetText(g,18,3,SnapmanCellGetText(gPlanning,row,8));
    SnapmanCellSetText(g,20,3,SnapmanCellGetText(gPlanning,row,9));
    SnapmanCellSetText(g,22,3,SnapmanCellGetText(gPlanning,row,10));
    SnapmanCellSetText(g,24,3,SnapmanCellGetText(gPlanning,row,11));
    SnapmanCellSetProgress(g,26,3,SnapmanCellGetInt(gPlanning,row,7));
    SnapmanCellSetText(g,29,3,SnapmanCellGetText(gPlanning,row,14));
}
//五、计算并设置未完成工作
void SetUnfinishedInfo(void *g,void *gPlanning)
{
    int nUnfinished = 0,nProgress = 0;
    wchar_t *d,*n;
    wchar_t *today  =  SnapmanCellGetText(g,4,3);
    wchar_t *name  =  SnapmanCellGetText(g,5,3);
    if(!today||!name)return;
    int nTotalPlanning = SnapmanGridGetDataRowCount(gPlanning,1);
    for(int row = 17; row <= nTotalPlanning; row++)
    {
        d = SnapmanCellGetText(gPlanning,row,6);
        n = SnapmanCellGetText(gPlanning,row,12);
        nProgress = SnapmanCellGetInt(gPlanning,row,7);
        if(d&&n&&nProgress!=100&&wcsicmp(d,today)<0&&wcsicmp(n,name)==0)nUnfinished++;
    }
    if(nUnfinished > 0)
    {
        SnapmanCellSetText(g,6,3,concat3(L("前面您还有"),itostr(nUnfinished),L("天工作未正常完成，请取上一天任务完成它。")));
    }else
    {
        SnapmanCellSetText(g,6,3,L("您前面的工作都正常完成了，好棒哦！"));
    }

}
//六、表格初始化事件函数
void OnInitialize(void *g)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gPlanning   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\02.花季计划信息"));
    if(gProject&&gPlanning)
    {
        int row = GetPlanning(gPlanning,Date(),SnapmanGetUserName());
        if(row > 0)
        {
            SetPlanningInfo(g,gPlanning,row);
        }else
        {
            Print("今天暂时没有您的任务，请好好休息一下哦！");
        }
        SetUserInfo(g,gProject);
        SetUnfinishedInfo(g,gPlanning);
    }
    SnapmanCleanUp();
}

B、取上一天任务按钮事件，事件代码：

//一、获取日期和名字所在任务的行号
int GetLastDayPlanning(void *g,wchar_t *date,wchar_t *name)
{
    int row = 17,result = 0;
    wchar_t *d,*n,*l = NULL;
    while(1)
    {
        d = SnapmanCellGetText(g,row,6);
        n = SnapmanCellGetText(g,row,12);
        if(!d||!n)break;
        if(wcsicmp(d,date)<0&&wcsicmp(n,name)==0)
        {
            if(!l||wcsicmp(d,l)>0)
            {
                result = row;
                l = d;
            }
        }
        row++;
    }
    return result;
}
//二、获用名字获取其主管名称
wchar_t * GetUserManager(void *g,wchar_t *name)
{
    int row = 18;
    int col = 2;
    wchar_t *manager = NULL, *strName = NULL;
    while(1)
    {
        strName = SnapmanCellGetText(g,row,2);
        if(!strName || wcslen(strName)==0)break;
        if(wcsicmp(name,strName)==0)
        {
            manager = SnapmanCellGetText(g,row,13);
            break;
        }
        row++;
    }
    return manager;
}
//四、设置计划信息
void SetPlanningInfo(void *g,void *gPlanning,int row)
{
    //1、设置今天需要完成的计划任务
    SnapmanCellSetLock(g,4,3,0);
    SnapmanCellSetLock(g,7,5,0);
    SnapmanCellSetLock(g,9,5,0);
    SnapmanCellSetLock(g,11,5,0);
    SnapmanCellSetLock(g,13,5,0);
    SnapmanCellSetLock(g,14,5,0);
    SnapmanCellSetText(g,4,3,SnapmanCellGetText(gPlanning,row,6));
    SnapmanCellSetText(g,7,5,SnapmanCellGetText(gPlanning,row,2));
    SnapmanCellSetText(g,9,5,SnapmanCellGetText(gPlanning,row,3));
    SnapmanCellSetText(g,11,5,SnapmanCellGetText(gPlanning,row,4));
    SnapmanCellSetText(g,13,5,SnapmanCellGetText(gPlanning,row,5));
    SnapmanCellSetText(g,14,5,SnapmanCellGetText(gPlanning,row,6));
    SnapmanCellSetLock(g,4,3,1);
    SnapmanCellSetLock(g,7,5,1);
    SnapmanCellSetLock(g,9,5,1);
    SnapmanCellSetLock(g,11,5,1);
    SnapmanCellSetLock(g,13,5,1);
    SnapmanCellSetLock(g,14,5,1);
    //2、设置今天任务完成状态
    SnapmanCellSetText(g,18,3,SnapmanCellGetText(gPlanning,row,8));
    SnapmanCellSetText(g,20,3,SnapmanCellGetText(gPlanning,row,9));
    SnapmanCellSetText(g,22,3,SnapmanCellGetText(gPlanning,row,10));
    SnapmanCellSetText(g,24,3,SnapmanCellGetText(gPlanning,row,11));
    SnapmanCellSetProgress(g,26,3,SnapmanCellGetInt(gPlanning,row,7));
    SnapmanCellSetText(g,29,3,SnapmanCellGetText(gPlanning,row,14));
}
//五、计算并设置未完成工作
void SetUnfinishedInfo(void *g,void *gPlanning)
{
    int nUnfinished = 0,nProgress = 0;
    wchar_t *d,*n;
    wchar_t *today  =  SnapmanCellGetText(g,4,3);
    wchar_t *name  =  SnapmanCellGetText(g,5,3);
    if(!today||!name)return;
    int nTotalPlanning = SnapmanGridGetDataRowCount(gPlanning,1);
    for(int row = 17; row <= nTotalPlanning; row++)
    {
        d = SnapmanCellGetText(gPlanning,row,6);
        n = SnapmanCellGetText(gPlanning,row,12);
        nProgress = SnapmanCellGetInt(gPlanning,row,7);
        if(d&&n&&nProgress!=100&&wcsicmp(d,today)<0&&wcsicmp(n,name)==0)nUnfinished++;
    }
    if(nUnfinished > 0)
    {
        SnapmanCellSetText(g,6,3,concat3(L("前面您还有"),itostr(nUnfinished),L("天工作未正常完成，请取上一天任务完成它。")));
    }else
    {
        SnapmanCellSetText(g,6,3,L("您前面的工作都正常完成了，好棒哦！"));
    }

}
//六、按钮事件函数
void OnButtonClick(void *g, int row, int col)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gPlanning   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\02.花季计划信息"));
    if(gProject&&gPlanning)
    {
        int row = GetLastDayPlanning(gPlanning,SnapmanCellGetText(g,4,3),SnapmanCellGetText(g,5,3));
        if(row > 0)
        {
            SetPlanningInfo(g,gPlanning,row);
            SetUnfinishedInfo(g,gPlanning);
        }else
        {
            Print("没能找到上一天的任务哦！");
        }
    }
    SnapmanCleanUp();
}

C、取下一天任务按钮事件，事件代码：

//一、获取日期和名字所在任务的行号
int GetNextDayPlanning(void *g,wchar_t *date,wchar_t *name)
{
    int row = 17,result = 0;
    wchar_t *d,*n,*l = NULL;
    while(1)
    {
        d = SnapmanCellGetText(g,row,6);
        n = SnapmanCellGetText(g,row,12);
        if(!d||!n)break;
        if(wcsicmp(d,date)>0&&wcsicmp(n,name)==0)
        {
            if(!l||wcsicmp(d,l)<0)
            {
                result = row;
                l = d;
            }
        }
        row++;
    }
    return result;
}
//二、获用名字获取其主管名称
wchar_t * GetUserManager(void *g,wchar_t *name)
{
    int row = 18;
    int col = 2;
    wchar_t *manager = NULL, *strName = NULL;
    while(1)
    {
        strName = SnapmanCellGetText(g,row,2);
        if(!strName || wcslen(strName)==0)break;
        if(wcsicmp(name,strName)==0)
        {
            manager = SnapmanCellGetText(g,row,13);
            break;
        }
        row++;
    }
    return manager;
}
//四、设置计划信息
void SetPlanningInfo(void *g,void *gPlanning,int row)
{
    //1、设置今天需要完成的计划任务
    SnapmanCellSetLock(g,4,3,0);
    SnapmanCellSetLock(g,7,5,0);
    SnapmanCellSetLock(g,9,5,0);
    SnapmanCellSetLock(g,11,5,0);
    SnapmanCellSetLock(g,13,5,0);
    SnapmanCellSetLock(g,14,5,0);
    SnapmanCellSetText(g,4,3,SnapmanCellGetText(gPlanning,row,6));
    SnapmanCellSetText(g,7,5,SnapmanCellGetText(gPlanning,row,2));
    SnapmanCellSetText(g,9,5,SnapmanCellGetText(gPlanning,row,3));
    SnapmanCellSetText(g,11,5,SnapmanCellGetText(gPlanning,row,4));
    SnapmanCellSetText(g,13,5,SnapmanCellGetText(gPlanning,row,5));
    SnapmanCellSetText(g,14,5,SnapmanCellGetText(gPlanning,row,6));
    SnapmanCellSetLock(g,4,3,1);
    SnapmanCellSetLock(g,7,5,1);
    SnapmanCellSetLock(g,9,5,1);
    SnapmanCellSetLock(g,11,5,1);
    SnapmanCellSetLock(g,13,5,1);
    SnapmanCellSetLock(g,14,5,1);
    //2、设置今天任务完成状态
    SnapmanCellSetText(g,18,3,SnapmanCellGetText(gPlanning,row,8));
    SnapmanCellSetText(g,20,3,SnapmanCellGetText(gPlanning,row,9));
    SnapmanCellSetText(g,22,3,SnapmanCellGetText(gPlanning,row,10));
    SnapmanCellSetText(g,24,3,SnapmanCellGetText(gPlanning,row,11));
    SnapmanCellSetProgress(g,26,3,SnapmanCellGetInt(gPlanning,row,7));
    SnapmanCellSetText(g,29,3,SnapmanCellGetText(gPlanning,row,14));
}
//五、计算并设置未完成工作
void SetUnfinishedInfo(void *g,void *gPlanning)
{
    int nUnfinished = 0,nProgress = 0;
    wchar_t *d,*n;
    wchar_t *today  =  SnapmanCellGetText(g,4,3);
    wchar_t *name  =  SnapmanCellGetText(g,5,3);
    if(!today||!name)return;
    int nTotalPlanning = SnapmanGridGetDataRowCount(gPlanning,1);
    for(int row = 17; row <= nTotalPlanning; row++)
    {
        d = SnapmanCellGetText(gPlanning,row,6);
        n = SnapmanCellGetText(gPlanning,row,12);
        nProgress = SnapmanCellGetInt(gPlanning,row,7);
        if(d&&n&&nProgress!=100&&wcsicmp(d,today)<0&&wcsicmp(n,name)==0)nUnfinished++;
    }
    if(nUnfinished > 0)
    {
        SnapmanCellSetText(g,6,3,concat3(L("前面您还有"),itostr(nUnfinished),L("天工作未正常完成，请取上一天任务完成它。")));
    }else
    {
        SnapmanCellSetText(g,6,3,L("您前面的工作都正常完成了，好棒哦！"));
    }

}
//六、按钮事件函数
void OnButtonClick(void *g, int row, int col)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gPlanning   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\02.花季计划信息"));
    if(gProject&&gPlanning)
    {
        int row = GetNextDayPlanning(gPlanning,SnapmanCellGetText(g,4,3),SnapmanCellGetText(g,5,3));
        if(row > 0)
        {
            SetPlanningInfo(g,gPlanning,row);
            SetUnfinishedInfo(g,gPlanning);
        }else
        {
            Print("下一天没有安排任务哦！终于可以休息一下叻！");
        }
    }
    SnapmanCleanUp();
}

D、提交任务进度按钮事件，事件代码：

//一、获取日期和名字所在任务的行号
int GetPlanning(void *g,wchar_t *date,wchar_t *name)
{
    int row = 17;
    wchar_t *d,*n;
    while(1)
    {
        d = SnapmanCellGetText(g,row,6);
        n = SnapmanCellGetText(g,row,12);
        if(!d||!n)break;
        if(wcsicmp(d,date)==0&&wcsicmp(n,name)==0)return row;
        row++;
    }
    return 0;
}

//四、设置计划信息
void SavePlanningInfo(void *g,void *gPlanning,int row)
{
    //2、设置今天任务完成状态
    SnapmanCellSetText(gPlanning,row,8,SnapmanCellGetText(g,18,3));
    SnapmanCellSetText(gPlanning,row,9,SnapmanCellGetText(g,20,3));
    SnapmanCellSetText(gPlanning,row,10,SnapmanCellGetText(g,22,3));
    SnapmanCellSetText(gPlanning,row,11,SnapmanCellGetText(g,24,3));
    SnapmanCellSetProgress(gPlanning,row,7,SnapmanCellGetInt(g,26,3));
    SnapmanCellSetText(gPlanning,row,14,SnapmanCellGetText(g,29,3));
    SnapmanGridSave(gPlanning);
}

//六、表格初始化事件函数
void OnButtonClick(void *g, int row, int col)
{
    void *gPlanning   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\02.花季计划信息"));
    if(gPlanning)
    {
        wchar_t *today  =  SnapmanCellGetText(g,4,3);
        wchar_t *name  =  SnapmanCellGetText(g,5,3);
        int row = GetPlanning(gPlanning,today,name);
        if(row > 0)
        {
            SavePlanningInfo(g,gPlanning,row);
        }else
        {
            Print("今天暂时没有您的任务，请好好休息一下哦！");
        }
    }
    SnapmanCleanUp();
}

E、最终代码写完后将表格设置为不可以保存状态，这样表格就只能用来工作而不能用来存储数据，这样每个人写的任务进度就不会产生相互影响

03.花季我的问题，这张表包括：项目信息、我的问题单列表、当前选择问题信息、此问题的处理情况。事件包括：

A、初始化事件，自动获取项目信息、我的问题单列表、当前选择的问题信息展示、此问题的处理情况，问题还分为开发人员问题和测试人员问题侧重不同，事件代码：

wchar_t *GetDevTestProblemList(void *g,wchar_t *name)
{
    wchar_t *result = NULL,*n,*t;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = 4;row <= maxrow; row++)
    {
        t = SnapmanCellGetText(g,row,7);
        n = SnapmanCellGetText(g,row,13);
        if(n&&(0==wcsicmp(name,n)||0==wcsicmp(t,name)))//开发或测试人员的都列上了
        {
            if(result==NULL)
            {
                result = SnapmanCellGetText(g,row,1);
            }else
            {
                result = concat3(result,L"\n",SnapmanCellGetText(g,row,1));
            }
        }
    }
    return result;
}
int GetLastDevRow(void *g,wchar_t *name)
{
    wchar_t *n;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = maxrow;row >= 4; row--)
    {
        n = SnapmanCellGetText(g,row,13);
        if(n&&0==wcsicmp(name,n))
        {
            return row;
        }
    }
    return 0;
}

//二、获用名字获取其主管名称
wchar_t * GetUserManager(void *g,wchar_t *name)
{
    int row = 18;
    int col = 2;
    wchar_t *manager = NULL, *strName = NULL;
    while(1)
    {
        strName = SnapmanCellGetText(g,row,2);
        if(!strName || wcslen(strName)==0)break;
        if(wcsicmp(name,strName)==0)
        {
            manager = SnapmanCellGetText(g,row,13);
            break;
        }
        row++;
    }
    return manager;
}
//三、设置用户信息
void SetUserInfo(void *g,void *gProject)
{
    SnapmanCellSetLock(g,4,3,0);
    SnapmanCellSetLock(g,4,10,0);
    SnapmanCellSetLock(g,5,3,0);
    SnapmanCellSetLock(g,5,10,0);
    SnapmanCellSetText(g,4,3,Date());
    SnapmanCellSetText(g,4,10,SnapmanCellGetText(gProject,3,3));
    SnapmanCellSetText(g,5,3,SnapmanGetUserName());
    SnapmanCellSetText(g,5,10,GetUserManager(gProject,SnapmanGetUserName()));
    SnapmanCellSetLock(g,4,3,1);
    SnapmanCellSetLock(g,4,10,1);
    SnapmanCellSetLock(g,5,3,1);
    SnapmanCellSetLock(g,5,10,1);
}

void SetProblemInfo(void *g,void *gProblem,int row)
{
    if(row > 0)
    {
        if(0==wcsicmp(SnapmanGetUserName(),SnapmanCellGetText(gProblem,row,7)))//是测试人员
        {
            SnapmanCellSetLock(g,6,3,0);
            SnapmanCellSetLock(g,6,10,0);
            SnapmanCellSetLock(g,7,3,0);
            SnapmanCellSetLock(g,8,3,0);
            SnapmanCellSetLock(g,10,3,0);
            SnapmanCellSetLock(g,23,3,0);
            SnapmanCellSetLock(g,23,10,0);

            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gProblem,row,1));
            SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,7));
            SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
            SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
            SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
            SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
            SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));

            SnapmanCellSetLock(g,6,3,1);
            SnapmanCellSetLock(g,6,10,1);
            SnapmanCellSetLock(g,7,3,1);;
            SnapmanCellSetLock(g,8,3,1);
            SnapmanCellSetLock(g,10,3,1);
            SnapmanCellSetLock(g,23,3,1);
            SnapmanCellSetLock(g,23,10,1);

            SnapmanCellSetText(g,34,3,SnapmanCellGetText(gProblem,row,10));
            SnapmanCellSetText(g,47,3,SnapmanCellGetText(gProblem,row,11));
            SnapmanCellSetText(g,47,10,SnapmanCellGetText(gProblem,row,12));
            SnapmanCellSetText(g,48,3,SnapmanCellGetText(gProblem,row,14));

            SnapmanCellSetBackgoundColor(g,34,3,14806254);
            SnapmanCellSetBackgoundColor(g,47,3,14806254);
            SnapmanCellSetBackgoundColor(g,47,10,14806254);
            SnapmanCellSetBackgoundColor(g,48,3,14806254);

            SnapmanCellSetLock(g,34,3,1);
            SnapmanCellSetLock(g,47,3,1);
            SnapmanCellSetLock(g,47,10,1);
            SnapmanCellSetLock(g,48,3,1);

        }else//是开发人员
        {
            SnapmanCellSetLock(g,6,3,0);
            SnapmanCellSetLock(g,6,10,0);
            SnapmanCellSetLock(g,7,3,0);
            SnapmanCellSetLock(g,8,3,0);
            SnapmanCellSetLock(g,10,3,0);
            SnapmanCellSetLock(g,23,3,0);
            SnapmanCellSetLock(g,23,10,0);

            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gProblem,row,1));
            SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,7));
            SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
            SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
            SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
            SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
            SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));

            SnapmanCellSetLock(g,6,3,1);
            SnapmanCellSetLock(g,6,10,1);
            SnapmanCellSetLock(g,7,3,1);;
            SnapmanCellSetLock(g,8,3,1);
            SnapmanCellSetLock(g,10,3,1);
            SnapmanCellSetLock(g,23,3,1);
            SnapmanCellSetLock(g,23,10,1);

            SnapmanCellSetLock(g,34,3,1);
            SnapmanCellSetLock(g,47,3,1);
            SnapmanCellSetLock(g,47,10,1);
            SnapmanCellSetLock(g,48,3,1);

            SnapmanCellSetText(g,34,3,SnapmanCellGetText(gProblem,row,10));
            SnapmanCellSetText(g,47,3,SnapmanCellGetText(gProblem,row,11));
            SnapmanCellSetText(g,47,10,SnapmanCellGetText(gProblem,row,12));
            SnapmanCellSetText(g,48,3,SnapmanCellGetText(gProblem,row,14));
        }
    }
}
void OnInitialize(void *g)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gProblem = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    if(gProject&&gProblem)
    {
        SnapmanCellSetCombo(g,6,3,GetDevTestProblemList(gProblem,SnapmanGetUserName()));
        SetProblemInfo(g,gProblem,GetLastDevRow(gProblem,SnapmanGetUserName()));
        SetUserInfo(g,gProject);
    }
    SnapmanCleanUp();
}

B、我的问题单下拉框的选择事件，获取当前问题信息展示、此问题的处理情况，事件代码：

int GetProblemRow(void *g,wchar_t *Index)
{
    wchar_t *n;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = 4;row <= maxrow; row++)
    {
        n = SnapmanCellGetText(g,row,1);
        if(n&&0==wcsicmp(Index,n))
        {
            return row;
        }
    }
    return 0;
}

void SetProblemInfo(void *g,void *gProblem,int row)
{
    if(row > 0)
    {
        if(0==wcsicmp(SnapmanGetUserName(),SnapmanCellGetText(gProblem,row,7)))//是测试人员
        {
            SnapmanCellSetLock(g,6,10,0);
            SnapmanCellSetLock(g,7,3,0);
            SnapmanCellSetLock(g,8,3,0);
            SnapmanCellSetLock(g,10,3,0);
            SnapmanCellSetLock(g,23,3,0);
            SnapmanCellSetLock(g,23,10,0);

            SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,7));
            SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
            SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
            SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
            SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
            SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));

            SnapmanCellSetLock(g,6,10,1);
            SnapmanCellSetLock(g,7,3,1);;
            SnapmanCellSetLock(g,8,3,1);
            SnapmanCellSetLock(g,10,3,1);
            SnapmanCellSetLock(g,23,3,1);
            SnapmanCellSetLock(g,23,10,1);

            SnapmanCellSetText(g,34,3,SnapmanCellGetText(gProblem,row,10));
            SnapmanCellSetText(g,47,3,SnapmanCellGetText(gProblem,row,11));
            SnapmanCellSetText(g,47,10,SnapmanCellGetText(gProblem,row,12));
            SnapmanCellSetText(g,48,3,SnapmanCellGetText(gProblem,row,14));

            SnapmanCellSetBackgoundColor(g,34,3,14806254);
            SnapmanCellSetBackgoundColor(g,47,3,14806254);
            SnapmanCellSetBackgoundColor(g,47,10,14806254);
            SnapmanCellSetBackgoundColor(g,48,3,14806254);

            SnapmanCellSetLock(g,34,3,1);
            SnapmanCellSetLock(g,47,3,1);
            SnapmanCellSetLock(g,47,10,1);
            SnapmanCellSetLock(g,48,3,1);

        }else//是开发人员
        {
            SnapmanCellSetLock(g,6,3,0);
            SnapmanCellSetLock(g,6,10,0);
            SnapmanCellSetLock(g,7,3,0);
            SnapmanCellSetLock(g,8,3,0);
            SnapmanCellSetLock(g,10,3,0);
            SnapmanCellSetLock(g,23,3,0);
            SnapmanCellSetLock(g,23,10,0);

            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gProblem,row,1));
            SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,7));
            SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
            SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
            SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
            SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
            SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));

            SnapmanCellSetLock(g,6,3,1);
            SnapmanCellSetLock(g,6,10,1);
            SnapmanCellSetLock(g,7,3,1);;
            SnapmanCellSetLock(g,8,3,1);
            SnapmanCellSetLock(g,10,3,1);
            SnapmanCellSetLock(g,23,3,1);
            SnapmanCellSetLock(g,23,10,1);

            SnapmanCellSetLock(g,34,3,1);
            SnapmanCellSetLock(g,47,3,1);
            SnapmanCellSetLock(g,47,10,1);
            SnapmanCellSetLock(g,48,3,1);

            SnapmanCellSetText(g,34,3,SnapmanCellGetText(gProblem,row,10));
            SnapmanCellSetText(g,47,3,SnapmanCellGetText(gProblem,row,11));
            SnapmanCellSetText(g,47,10,SnapmanCellGetText(gProblem,row,12));
            SnapmanCellSetText(g,48,3,SnapmanCellGetText(gProblem,row,14));
        }
    }
}

void OnComboChanged(void *g, int row, int col,wchar_t *text)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gProblem = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    if(gProject&&gProblem)
    {
        SetProblemInfo(g,gProblem,GetProblemRow(gProblem,text));
    }
}

C、取上一个问题按钮事件，获取上一个问题信息展示、此问题处理状况，事件代码：

int GetLastDevRow(void *g,wchar_t *name)
{
    wchar_t *n;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = maxrow;row >= 4; row--)
    {
        n = SnapmanCellGetText(g,row,13);
        if(n&&0==wcsicmp(name,n))
        {
            return row;
        }
    }
    return 0;
}

int GetPrevDevRow(void *g,wchar_t *name,wchar_t *curIndex)
{
    if(curIndex==NULL||curIndex[0]==0)
    {
        return GetLastDevRow(g,name);
    }else
    {
        int result = 0;
        wchar_t *n,*d,*l = NULL;
        int maxrow = SnapmanGridGetTotalDataRow(g);
        for(int row = maxrow;row >= 4; row--)
        {
            n = SnapmanCellGetText(g,row,13);
            d = SnapmanCellGetText(g,row,1);
            if(n&&0==wcsicmp(name,n)&& d && wcsicmp(d,curIndex) < 0)
            {
                if(!l||wcsicmp(d,l)>0)
                {
                    result = row;
                    l = d;
                }
            }
        }
        return result;
    }
}

void SetProblemInfo(void *g,void *gProblem,int row)
{
    if(row > 0)
    {
        if(0==wcsicmp(SnapmanGetUserName(),SnapmanCellGetText(gProblem,row,7)))//是测试人员
        {
            SnapmanCellSetLock(g,6,3,0);
            SnapmanCellSetLock(g,6,10,0);
            SnapmanCellSetLock(g,7,3,0);
            SnapmanCellSetLock(g,8,3,0);
            SnapmanCellSetLock(g,10,3,0);
            SnapmanCellSetLock(g,23,3,0);
            SnapmanCellSetLock(g,23,10,0);

            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gProblem,row,1));
            SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,7));
            SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
            SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
            SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
            SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
            SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));

            SnapmanCellSetLock(g,6,3,1);
            SnapmanCellSetLock(g,6,10,1);
            SnapmanCellSetLock(g,7,3,1);;
            SnapmanCellSetLock(g,8,3,1);
            SnapmanCellSetLock(g,10,3,1);
            SnapmanCellSetLock(g,23,3,1);
            SnapmanCellSetLock(g,23,10,1);

            SnapmanCellSetText(g,34,3,SnapmanCellGetText(gProblem,row,10));
            SnapmanCellSetText(g,47,3,SnapmanCellGetText(gProblem,row,11));
            SnapmanCellSetText(g,47,10,SnapmanCellGetText(gProblem,row,12));
            SnapmanCellSetText(g,48,3,SnapmanCellGetText(gProblem,row,14));

            SnapmanCellSetBackgoundColor(g,34,3,14806254);
            SnapmanCellSetBackgoundColor(g,47,3,14806254);
            SnapmanCellSetBackgoundColor(g,47,10,14806254);
            SnapmanCellSetBackgoundColor(g,48,3,14806254);

            SnapmanCellSetLock(g,34,3,1);
            SnapmanCellSetLock(g,47,3,1);
            SnapmanCellSetLock(g,47,10,1);
            SnapmanCellSetLock(g,48,3,1);

        }else//是开发人员
        {
            SnapmanCellSetLock(g,6,3,0);
            SnapmanCellSetLock(g,6,10,0);
            SnapmanCellSetLock(g,7,3,0);
            SnapmanCellSetLock(g,8,3,0);
            SnapmanCellSetLock(g,10,3,0);
            SnapmanCellSetLock(g,23,3,0);
            SnapmanCellSetLock(g,23,10,0);

            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gProblem,row,1));
            SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,7));
            SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
            SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
            SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
            SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
            SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));

            SnapmanCellSetLock(g,6,3,1);
            SnapmanCellSetLock(g,6,10,1);
            SnapmanCellSetLock(g,7,3,1);;
            SnapmanCellSetLock(g,8,3,1);
            SnapmanCellSetLock(g,10,3,1);
            SnapmanCellSetLock(g,23,3,1);
            SnapmanCellSetLock(g,23,10,1);

            SnapmanCellSetLock(g,34,3,1);
            SnapmanCellSetLock(g,47,3,1);
            SnapmanCellSetLock(g,47,10,1);
            SnapmanCellSetLock(g,48,3,1);

            SnapmanCellSetText(g,34,3,SnapmanCellGetText(gProblem,row,10));
            SnapmanCellSetText(g,47,3,SnapmanCellGetText(gProblem,row,11));
            SnapmanCellSetText(g,47,10,SnapmanCellGetText(gProblem,row,12));
            SnapmanCellSetText(g,48,3,SnapmanCellGetText(gProblem,row,14));
        }
    }else
    {
        Print("没有上一个问题咯！");
    }
}

//六、按钮事件函数
void OnButtonClick(void *g, int row, int col)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gProblem = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    if(gProject&&gProblem)
    {
        SetProblemInfo(g,gProblem,GetPrevDevRow(gProblem,SnapmanGetUserName(),SnapmanCellGetText(g,6,3)));
    }
    SnapmanCleanUp();
}

D、取下一个问题按钮事件，获取下一个问题信息展示、此问题处理状况，事件代码：

int GetLastDevRow(void *g,wchar_t *name)
{
    wchar_t *n;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = maxrow;row >= 4; row--)
    {
        n = SnapmanCellGetText(g,row,13);
        if(n&&0==wcsicmp(name,n))
        {
            return row;
        }
    }
    return 0;
}

int GetNextDevRow(void *g,wchar_t *name,wchar_t *curIndex)
{
    if(curIndex==NULL||curIndex[0]==0)
    {
        return GetLastDevRow(g,name);
    }else
    {
        int result = 0;
        wchar_t *n,*d,*l = NULL;
        int maxrow = SnapmanGridGetTotalDataRow(g);
        for(int row = maxrow;row >= 4; row--)
        {
            n = SnapmanCellGetText(g,row,13);
            d = SnapmanCellGetText(g,row,1);
            if(n&&0==wcsicmp(name,n)&& d && wcsicmp(d,curIndex) > 0)
            {
                if(!l||wcsicmp(d,l)<0)
                {
                    result = row;
                    l = d;
                }
            }
        }
        return result;
    }
}

void SetProblemInfo(void *g,void *gProblem,int row)
{
    if(row > 0)
    {
        if(0==wcsicmp(SnapmanGetUserName(),SnapmanCellGetText(gProblem,row,7)))//是测试人员
        {
            SnapmanCellSetLock(g,6,3,0);
            SnapmanCellSetLock(g,6,10,0);
            SnapmanCellSetLock(g,7,3,0);
            SnapmanCellSetLock(g,8,3,0);
            SnapmanCellSetLock(g,10,3,0);
            SnapmanCellSetLock(g,23,3,0);
            SnapmanCellSetLock(g,23,10,0);

            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gProblem,row,1));
            SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,7));
            SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
            SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
            SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
            SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
            SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));

            SnapmanCellSetLock(g,6,3,1);
            SnapmanCellSetLock(g,6,10,1);
            SnapmanCellSetLock(g,7,3,1);;
            SnapmanCellSetLock(g,8,3,1);
            SnapmanCellSetLock(g,10,3,1);
            SnapmanCellSetLock(g,23,3,1);
            SnapmanCellSetLock(g,23,10,1);

            SnapmanCellSetText(g,34,3,SnapmanCellGetText(gProblem,row,10));
            SnapmanCellSetText(g,47,3,SnapmanCellGetText(gProblem,row,11));
            SnapmanCellSetText(g,47,10,SnapmanCellGetText(gProblem,row,12));
            SnapmanCellSetText(g,48,3,SnapmanCellGetText(gProblem,row,14));

            SnapmanCellSetBackgoundColor(g,34,3,14806254);
            SnapmanCellSetBackgoundColor(g,47,3,14806254);
            SnapmanCellSetBackgoundColor(g,47,10,14806254);
            SnapmanCellSetBackgoundColor(g,48,3,14806254);

            SnapmanCellSetLock(g,34,3,1);
            SnapmanCellSetLock(g,47,3,1);
            SnapmanCellSetLock(g,47,10,1);
            SnapmanCellSetLock(g,48,3,1);

        }else//是开发人员
        {
            SnapmanCellSetLock(g,6,3,0);
            SnapmanCellSetLock(g,6,10,0);
            SnapmanCellSetLock(g,7,3,0);
            SnapmanCellSetLock(g,8,3,0);
            SnapmanCellSetLock(g,10,3,0);
            SnapmanCellSetLock(g,23,3,0);
            SnapmanCellSetLock(g,23,10,0);

            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gProblem,row,1));
            SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,7));
            SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
            SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
            SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
            SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
            SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));

            SnapmanCellSetLock(g,6,3,1);
            SnapmanCellSetLock(g,6,10,1);
            SnapmanCellSetLock(g,7,3,1);;
            SnapmanCellSetLock(g,8,3,1);
            SnapmanCellSetLock(g,10,3,1);
            SnapmanCellSetLock(g,23,3,1);
            SnapmanCellSetLock(g,23,10,1);

            SnapmanCellSetLock(g,34,3,1);
            SnapmanCellSetLock(g,47,3,1);
            SnapmanCellSetLock(g,47,10,1);
            SnapmanCellSetLock(g,48,3,1);

            SnapmanCellSetText(g,34,3,SnapmanCellGetText(gProblem,row,10));
            SnapmanCellSetText(g,47,3,SnapmanCellGetText(gProblem,row,11));
            SnapmanCellSetText(g,47,10,SnapmanCellGetText(gProblem,row,12));
            SnapmanCellSetText(g,48,3,SnapmanCellGetText(gProblem,row,14));
        }
    }else
    {
        Print("没有下一个问题咯！");
    }
}

//六、按钮事件函数
void OnButtonClick(void *g, int row, int col)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gProblem = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    if(gProject&&gProblem)
    {
        SetProblemInfo(g,gProblem,GetNextDevRow(gProblem,SnapmanGetUserName(),SnapmanCellGetText(g,6,3)));
    }
    SnapmanCleanUp();
}

E、提交问题进度按钮事件，事件代码：

int GetProblemRow(void *g,wchar_t *Index)
{
    wchar_t *n;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = 4;row <= maxrow; row++)
    {
        n = SnapmanCellGetText(g,row,1);
        if(n&&0==wcsicmp(Index,n))
        {
            return row;
        }
    }
    return 0;
}
void SaveProblemProgress(void *g,void *gProblem)
{
    wchar_t *d = SnapmanCellGetText(g,6,3);
    if(d&&d[0]!=0)
    {
        int row = GetProblemRow(gProblem,d);
        if(0==wcsicmp(SnapmanGetUserName(),SnapmanCellGetText(gProblem,row,7)))//是测试人员
        {
            if(SnapmanCellIsEmpty(g,7,10))
            {
                Print("请填写问题状态！");
            }else
            {
                SnapmanCellSetText(gProblem,row,9,SnapmanCellGetText(g,7,10));
                SnapmanGridSave(gProblem);
                Print("问题进度提交成功！");
            }
        }else if(row>0)//是开发人员
        {
            if(SnapmanCellIsEmpty(g,7,10))
            {
                Print("请填写问题状态！");
            }else if(SnapmanCellIsEmpty(g,34,3))
            {
                Print("请填写问题分析！");
            }else if(SnapmanCellIsEmpty(g,47,3))
            {
                Print("请填写修复时间！");
            }else if(SnapmanCellIsEmpty(g,47,10))
            {
                Print("请填写修复版本！");
            }else
            {
                SnapmanCellSetText(gProblem,row,9,SnapmanCellGetText(g,7,10));
                SnapmanCellSetText(gProblem,row,10,SnapmanCellGetText(g,34,3));
                SnapmanCellSetText(gProblem,row,11,SnapmanCellGetText(g,47,3));
                SnapmanCellSetText(gProblem,row,12,SnapmanCellGetText(g,47,10));
                SnapmanCellSetText(gProblem,row,14,SnapmanCellGetText(g,48,3));
                SnapmanGridSave(gProblem);
                Print("问题进度提交成功！");
            }
        }else
        {
            wPrint(L("问题列表中找不到问题单号为：%s"),d);
        }
    }else
    {
        Print("请选择问题单号！");
    }
}

//六、按钮事件函数
void OnButtonClick(void *g, int row, int col)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gProblem = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    if(gProject&&gProblem)
    {
        SaveProblemProgress(g,gProblem);
    }
    SnapmanCleanUp();
}

F、最终代码写完后将表格设置为不可以保存状态，这样表格就只能用来工作而不能用来存储数据，这样每个人写的问题处理进度就不会产生相互影响

04.花季我的测试，这张表包括：测试人员提单的问题要素、跟踪状态和开发人员的分析及修复状态；这张表由：03.花季我的问题、04.花季我的测试，2张表自动维护。

A、初始化事件，自动获取项目信息、我的问题单列表、当前选择的问题信息展示，事件代码：

wchar_t *GetUserProblemList(void *g,wchar_t *name)
{
    wchar_t *result = NULL,*n;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = 4;row <= maxrow; row++)
    {
        n = SnapmanCellGetText(g,row,7);
        if(n&&0==wcsicmp(name,n))
        {
            if(result==NULL)
            {
                result = n;
            }else
            {
                result = concat3(result,L"\n",n);
            }
        }
    }
    return result;
}
wchar_t *GetDevList(void *g)
{
    wchar_t *result = NULL,*n;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = 18;row <= maxrow; row++)
    {
        n = SnapmanCellGetText(g,row,2);
        if(n&&n[0]!=0)
        {
            if(result==NULL)
            {
                result = n;
            }else
            {
                result = concat3(result,L"\n",n);
            }
        }
    }
    return result;
}
//二、获用名字获取其主管名称
wchar_t * GetUserManager(void *g,wchar_t *name)
{
    int row = 18;
    int col = 2;
    wchar_t *manager = NULL, *strName = NULL;
    while(1)
    {
        strName = SnapmanCellGetText(g,row,2);
        if(!strName || wcslen(strName)==0)break;
        if(wcsicmp(name,strName)==0)
        {
            manager = SnapmanCellGetText(g,row,13);
            break;
        }
        row++;
    }
    return manager;
}
//三、设置用户信息
void SetUserInfo(void *g,void *gProject)
{
    SnapmanCellSetLock(g,4,3,0);
    SnapmanCellSetLock(g,4,10,0);
    SnapmanCellSetLock(g,5,3,0);
    SnapmanCellSetLock(g,5,10,0);
    SnapmanCellSetText(g,4,3,Date());
    SnapmanCellSetText(g,4,10,SnapmanCellGetText(gProject,3,3));
    SnapmanCellSetText(g,5,3,SnapmanGetUserName());
    SnapmanCellSetText(g,5,10,GetUserManager(gProject,SnapmanGetUserName()));
    SnapmanCellSetLock(g,4,3,1);
    SnapmanCellSetLock(g,4,10,1);
    SnapmanCellSetLock(g,5,3,1);
    SnapmanCellSetLock(g,5,10,1);
}
void OnInitialize(void *g)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gProblem = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    if(gProject&&gProblem)
    {
        SnapmanCellSetCombo(g,6,3,GetUserProblemList(g,SnapmanGetUserName()));
        SnapmanCellSetCombo(g,7,3,GetDevList(gProject));
        SetUserInfo(g,gProject);

    }
}

B、我的问题单下拉框的选择事件，获取当前问题信息展示，事件代码：

int GetProblemRow(void *g,wchar_t *Index)
{
    wchar_t *n;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = 4;row <= maxrow; row++)
    {
        n = SnapmanCellGetText(g,row,1);
        if(n&&0==wcsicmp(Index,n))
        {
            return row;
        }
    }
    return 0;
}

void SetProblemInfo(void *g,void *gProblem,int row)
{
    if(row > 0)
    {
        if(0==wcsicmp(SnapmanGetUserName(),SnapmanCellGetText(gProblem,row,7)))//是测试人员
        {
            SnapmanCellSetLock(g,6,10,0);
            SnapmanCellSetLock(g,7,3,0);
            SnapmanCellSetLock(g,8,3,0);
            SnapmanCellSetLock(g,10,3,0);
            SnapmanCellSetLock(g,23,3,0);
            SnapmanCellSetLock(g,23,10,0);

            SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,7));
            SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
            SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
            SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
            SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
            SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));

            SnapmanCellSetLock(g,6,10,1);
            SnapmanCellSetLock(g,7,3,1);;
            SnapmanCellSetLock(g,8,3,1);
            SnapmanCellSetLock(g,10,3,1);
            SnapmanCellSetLock(g,23,3,1);
            SnapmanCellSetLock(g,23,10,1);

            SnapmanCellSetText(g,34,3,SnapmanCellGetText(gProblem,row,10));
            SnapmanCellSetText(g,47,3,SnapmanCellGetText(gProblem,row,11));
            SnapmanCellSetText(g,47,10,SnapmanCellGetText(gProblem,row,12));
            SnapmanCellSetText(g,48,3,SnapmanCellGetText(gProblem,row,14));

            SnapmanCellSetBackgoundColor(g,34,3,14806254);
            SnapmanCellSetBackgoundColor(g,47,3,14806254);
            SnapmanCellSetBackgoundColor(g,47,10,14806254);
            SnapmanCellSetBackgoundColor(g,48,3,14806254);

            SnapmanCellSetLock(g,34,3,1);
            SnapmanCellSetLock(g,47,3,1);
            SnapmanCellSetLock(g,47,10,1);
            SnapmanCellSetLock(g,48,3,1);

        }else//是开发人员
        {
            SnapmanCellSetLock(g,6,3,0);
            SnapmanCellSetLock(g,6,10,0);
            SnapmanCellSetLock(g,7,3,0);
            SnapmanCellSetLock(g,8,3,0);
            SnapmanCellSetLock(g,10,3,0);
            SnapmanCellSetLock(g,23,3,0);
            SnapmanCellSetLock(g,23,10,0);

            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gProblem,row,1));
            SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,7));
            SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
            SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
            SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
            SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
            SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));

            SnapmanCellSetLock(g,6,3,1);
            SnapmanCellSetLock(g,6,10,1);
            SnapmanCellSetLock(g,7,3,1);;
            SnapmanCellSetLock(g,8,3,1);
            SnapmanCellSetLock(g,10,3,1);
            SnapmanCellSetLock(g,23,3,1);
            SnapmanCellSetLock(g,23,10,1);

            SnapmanCellSetLock(g,34,3,1);
            SnapmanCellSetLock(g,47,3,1);
            SnapmanCellSetLock(g,47,10,1);
            SnapmanCellSetLock(g,48,3,1);

            SnapmanCellSetText(g,34,3,SnapmanCellGetText(gProblem,row,10));
            SnapmanCellSetText(g,47,3,SnapmanCellGetText(gProblem,row,11));
            SnapmanCellSetText(g,47,10,SnapmanCellGetText(gProblem,row,12));
            SnapmanCellSetText(g,48,3,SnapmanCellGetText(gProblem,row,14));
        }
    }
}

void OnComboChanged(void *g, int row, int col,wchar_t *text)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gProblem = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    if(gProject&&gProblem)
    {
        SetProblemInfo(g,gProblem,GetProblemRow(gProblem,text));
    }
}

C、取上一个问题按钮事件，获取上一个问题信息展示，事件代码：

//一、获取日期和名字所在任务的行号
int GetPrevProblem(void *g,int index,wchar_t *name)
{
    wchar_t *n = NULL;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = maxrow;row >= 4; row--)
    {
        n = SnapmanCellGetText(g,row,7);
        if(n&&0==wcsicmp(name,n))
        {
            if(index==0)
            {
                return row;
            }else if(SnapmanCellGetInt(g,row,1)<index)
            {
                return row;
            }
        }
    }
    return 0;
}
void SetProblemInfo(void *g,void *gProblem,int row)
{
    SnapmanCellSetText(g,6,3,SnapmanCellGetText(gProblem,row,1));
    SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
    SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,13));
    SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
    SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
    SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
    SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
    SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));
}
//六、按钮事件函数
void OnButtonClick(void *g, int row, int col)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gProblem   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    if(gProject&&gProblem)
    {
        int row = GetPrevProblem(gProblem,SnapmanCellGetInt(g,6,3),SnapmanCellGetText(g,5,3));
        if(row > 0)
        {
            SetProblemInfo(g,gProblem,row);
        }else
        {
            Print("找不到上一个问题单了哦！");
        }
    }
    SnapmanCleanUp();
}

D、取下一个问题按钮事件，获取下一个问题信息展示，事件代码：

//一、获取日期和名字所在任务的行号
int GetNextProblem(void *g,int index,wchar_t *name)
{
    wchar_t *n = NULL;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    for(int row = maxrow;row >= 4; row--)
    {
        n = SnapmanCellGetText(g,row,7);
        if(n&&0==wcsicmp(name,n))
        {
            if(index==0)
            {
                return row;
            }else if(SnapmanCellGetInt(g,row,1)>index)
            {
                return row;
            }
        }
    }
    return 0;
}
void SetProblemInfo(void *g,void *gProblem,int row)
{
    SnapmanCellSetText(g,6,3,SnapmanCellGetText(gProblem,row,1));
    SnapmanCellSetText(g,6,10,SnapmanCellGetText(gProblem,row,8));
    SnapmanCellSetText(g,7,3,SnapmanCellGetText(gProblem,row,13));
    SnapmanCellSetText(g,7,10,SnapmanCellGetText(gProblem,row,9));
    SnapmanCellSetText(g,8,3,SnapmanCellGetText(gProblem,row,2));
    SnapmanCellSetText(g,10,3,SnapmanCellGetText(gProblem,row,3));
    SnapmanCellSetPicture(g,23,3,SnapmanCellGetPicture(gProblem,row,4));
    SnapmanCellSetFile(g,23,10,SnapmanCellGetFile(gProblem,row,5));
}
//六、按钮事件函数
void OnButtonClick(void *g, int row, int col)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gProblem   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    if(gProject&&gProblem)
    {
        int row = GetNextProblem(gProblem,SnapmanCellGetInt(g,6,3),SnapmanCellGetText(g,5,3));
        if(row > 0)
        {
            SetProblemInfo(g,gProblem,row);
        }else
        {
            Print("找不到下一个问题单了哦！");
        }
    }
    SnapmanCleanUp();
}

E、提交问题单按钮事件，事件代码：

//一、获取日期和名字所在任务的行号
int GetProblemRow(void *g,int index)
{
    wchar_t *n = NULL;
    int maxrow = SnapmanGridGetTotalDataRow(g);
    if(index > 0)
    {
        for(int row = maxrow;row >= 4; row--)
        {
            if(SnapmanCellGetInt(g,row,1)==index)
            {
                return row;
            }
        }
    }
    return maxrow + 1;
}
void SetProblemInfo(void *g,void *gProblem,int row)
{
    SnapmanCellSetInt(gProblem,row,1,row - 3);
    SnapmanCellSetText(gProblem,row,8,SnapmanCellGetText(g,6,10));
    SnapmanCellSetText(gProblem,row,13,SnapmanCellGetText(g,7,3));
    SnapmanCellSetText(gProblem,row,9,SnapmanCellGetText(g,7,10));
    SnapmanCellSetText(gProblem,row,2,SnapmanCellGetText(g,8,3));
    SnapmanCellSetText(gProblem,row,3,SnapmanCellGetText(g,10,3));
    SnapmanCellSetPicture(gProblem,row,4,SnapmanCellGetPicture(g,23,3));
    SnapmanCellSetFile(gProblem,row,5,SnapmanCellGetFile(g,23,10));
    SnapmanCellSetText(gProblem,row,6,DateTime());
    SnapmanCellSetText(gProblem,row,7,SnapmanGetUserName());
    SnapmanGridSave(gProblem);
    //清空问题单
    SnapmanCellClearData(g,6,3);
    SnapmanCellClearData(g,6,10);
    SnapmanCellClearData(g,7,3);
    SnapmanCellClearData(g,7,10);
    SnapmanCellClearData(g,8,3);
    SnapmanCellClearData(g,10,3);
    SnapmanCellClearData(g,23,3);
    SnapmanCellClearData(g,23,10);

}
//六、按钮事件函数
void OnButtonClick(void *g, int row, int col)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gProblem   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    int row = 0, rego = 1;
    if(gProject&&gProblem)
    {
        wchar_t *text1 = SnapmanCellGetText(g,6,10);
        wchar_t *text2 = SnapmanCellGetText(g,7,3);
        wchar_t *text3 = SnapmanCellGetText(g,7,10);
        wchar_t *text4 = SnapmanCellGetText(g,8,3);
        wchar_t *text5 = SnapmanCellGetText(g,10,3);
        if(!text1||text1[0]==0)
        {
            rego = 0;
            Print("请选择问题级别！");
        }else if(!text2||text2[0]==0)
        {
            rego = 0;
            Print("请选择开发人员！");
        }else if(!text3||text3[0]==0)
        {
            rego = 0;
            Print("请选择问题状态！");
        }else if(!text4||text4[0]==0)
        {
            rego = 0;
            Print("请填写问题相关Story！");
        }else if(!text5||text5[0]==0)
        {
            rego = 0;
            Print("请填写问题描述！");
        }
        if(rego)
        {
            row = GetProblemRow(gProblem,SnapmanCellGetInt(g,6,3));
            SetProblemInfo(g,gProblem,row);
            Print("问题单已经成功提交!");
        }
    }
    SnapmanCleanUp();
}

F、最终代码写完后将表格设置为不可以保存状态，这样表格就只能用来工作而不能用来存储数据，这样每个人写的问题单就不会产生相互影响

三、再次是领导主管的工作部分，如下创建三张表：花季日报审核、花季团队考评、花季项目进度。这几张表涉及界面设计和代码控制，界面设计总共花了20多分钟，代码控制每张表花了不到1个小时。

01.花季日报审核，这张表包括：项目信息、员工列表、当前选择员工的日报、主管的考评信息（每天的考核分数纳入到最终的考核成绩里）。事件包括：

A、初始化事件，自动获取项目信息、员工列表、当前选择员工的日报、考评信息，事件代码：

wchar_t* GetEmployee(void *g,void *m,wchar_t *date,wchar_t *name)
{
    int row = 4;
    wchar_t *d,*n,*result = NULL,*manager;
    while(1)
    {
        d = SnapmanCellGetText(g,row,2);
        n = SnapmanCellGetText(g,row,3);
        if(!d||!n)break;
        if(wcsicmp(date,d)==0)
        {
            manager = FindMap(m,n);
            if(manager&&wcsicmp(manager,name)==0)
            {
                if(!result)
                {
                    result = n;
                }else
                {
                    result = concat3(result,L"\n",n);
                }
            }
        }
        row++;
    }
    return result;
}
void * GetUserManager(void *g)
{
    int row = 18;
    int maxRow = SnapmanGridGetTotalDataRow(g);
    wchar_t *strName = NULL, *strManager = NULL;
    void *result = NULL;
    for(; row <= maxRow; row++)
    {
        strName = SnapmanCellGetText(g,row,2);
        strManager = SnapmanCellGetText(g,row,13);
        if(strName && strManager)
        {
            result = InsertMap(result,strName,strManager);
        }
    }
    return result;
}

int GetDailyRow(void *g,wchar_t *user,wchar_t *time)
{
    int row = 4;
    wchar_t *d,*n;
    while(1)
    {
        d = SnapmanCellGetText(g,row,2);
        n = SnapmanCellGetText(g,row,3);
        if(!d||!n)break;
        if(wcsicmp(time,d)==0&&wcsicmp(n,user)==0)return row;
        row++;
    }
    return 0;
}

void OnInitialize(void *g)
{
    int row = 0;
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gDaily   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\03.花季工作日报"));
    if(gProject&&gDaily)
    {
        SnapmanCellSetLock(g,4,3,0);
        SnapmanCellSetLock(g,4,10,0);
        SnapmanCellSetLock(g,5,10,0);
        SnapmanCellSetText(g,4,3,Date());
        SnapmanCellSetText(g,4,10,SnapmanCellGetText(gProject,3,3));
        SnapmanCellSetCombo(g,5,3,GetEmployee(gDaily,GetUserManager(gProject),Date(),SnapmanGetUserName()));
        SnapmanCellSetText(g,5,10,SnapmanGetUserName());
        SnapmanCellSetLock(g,4,3,1);
        SnapmanCellSetLock(g,4,10,1);
        SnapmanCellSetLock(g,5,10,1);

        SnapmanCellSetComboIndex(g,5,3,0);
        row = GetDailyRow(gDaily,SnapmanCellGetText(g,5,3),Date());
        if(row > 0)
        {
            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gDaily,row,4));
            SnapmanCellSetProgress(g,6,10,SnapmanCellGetInt(gDaily,row,5));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gDaily,row,6));
            SnapmanCellSetText(g,14,3,SnapmanCellGetText(gDaily,row,7));
            SnapmanCellSetFile(g,21,10,SnapmanCellGetFile(gDaily,row,10));
            SnapmanCellSetPicture(g,21,3,SnapmanCellGetPicture(gDaily,row,9));

            SnapmanCellSetText(g,28,3,SnapmanCellGetText(gDaily,row,11));
            SnapmanCellSetText(g,36,3,SnapmanCellGetText(gDaily,row,12));
        }else
        {
            Print("没有用户日报。");
        }

    }
    SnapmanCleanUp();
}

B、员工选择下拉框的选择事件，获取当前选择员工的日报、考评信息，事件代码：

int GetDailyRow(void *g,wchar_t *user,wchar_t *time)
{
    int row = 4;
    wchar_t *d,*n;
    while(1)
    {
        d = SnapmanCellGetText(g,row,2);
        n = SnapmanCellGetText(g,row,3);
        if(!d||!n)break;
        if(wcsicmp(time,d)==0&&wcsicmp(n,user)==0)return row;
        row++;
    }
    return 0;
}

void OnComboChanged(void *g, int row, int col,wchar_t *text)
{

    int row = 0;
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gDaily   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\03.花季工作日报"));
    if(gProject&&gDaily)
    {
        row = GetDailyRow(gDaily,text,Date());
        if(row > 0)
        {
            SnapmanCellSetText(g,6,3,SnapmanCellGetText(gDaily,row,4));
            SnapmanCellSetProgress(g,6,10,SnapmanCellGetInt(gDaily,row,5));
            SnapmanCellSetText(g,7,3,SnapmanCellGetText(gDaily,row,6));
            SnapmanCellSetText(g,14,3,SnapmanCellGetText(gDaily,row,7));
            SnapmanCellSetFile(g,21,10,SnapmanCellGetFile(gDaily,row,10));
            SnapmanCellSetPicture(g,21,3,SnapmanCellGetPicture(gDaily,row,9));

            SnapmanCellSetText(g,28,3,SnapmanCellGetText(gDaily,row,11));
            SnapmanCellSetText(g,36,3,SnapmanCellGetText(gDaily,row,12));
        }else
        {
            Print("找不到用户日报。");
        }

    }
    SnapmanCleanUp();
}

C、提交日报考评按钮事件，事件代码：

int GetDailyRow(void *g,wchar_t *user,wchar_t *time)
{
    int row = 4;
    wchar_t *d,*n;
    while(1)
    {
        d = SnapmanCellGetText(g,row,2);
        n = SnapmanCellGetText(g,row,3);
        if(!d||!n)break;
        if(wcsicmp(time,d)==0&&wcsicmp(n,user)==0)return row;
        row++;
    }
    return 0;
}

void OnButtonClick(void *g, int row, int col)
{
    if(!SnapmanCellIsEmpty(g,28,3))
    {
        void *gDaily   = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\03.花季工作日报"));
        int row = GetDailyRow(gDaily,SnapmanCellGetText(g,5,3),Date());
        SnapmanCellSetText(gDaily,row,11,SnapmanCellGetText(g,28,3));
        SnapmanCellSetText(gDaily,row,12,SnapmanCellGetText(g,36,3));
        SnapmanCellSetText(gDaily,row,13,DateTime());
        SnapmanCellSetText(gDaily,row,14,SnapmanGetUserName());
        SnapmanGridSave(gDaily);
        Print("日报考评提交成功！");
    }else
    {
        Print("请填写主管考评。");
    }
    SnapmanCleanUp();
}

D、最终代码写完后将表格设置为不可以保存状态，这样表格就只能用来工作而不能用来存储数据，这样每个人写的日报审核就不会产生相互影响

02.花季团队考评，这张表包括：项目信息、员工今天的工作点数、完成进度、今天总结、明天计划、工作相关的图片和附件。事件包括：

A、初始化事件，自动获取项目信息、员工列表、自动计算选择员工的工作完成状态、日报考评信息、工作得分和工作考评级别、获取主管考评信息，事件代码：

wchar_t* GetEmployee(void *m,wchar_t *name)
{
    Pair *p = ForeachMap(m);
    wchar_t *result = NULL;
    while(p)
    {
        if(wcsicmp(name,(wchar_t*)p->value)==0)
        {
            if(!result)
            {
                result = (wchar_t*)p->key;
            }else
            {
                result = concat3(result,L"\n",(wchar_t*)p->key);
            }
        }
        p = ForeachMap(m);
    }
    return result;
}

void * GetUserManager(void *g)
{
    int row = 18;
    int maxRow = SnapmanGridGetTotalDataRow(g);
    wchar_t *strName = NULL, *strManager = NULL;
    void *result = NULL;
    for(; row <= maxRow; row++)
    {
        strName = SnapmanCellGetText(g,row,2);
        strManager = SnapmanCellGetText(g,row,13);
        if(strName && strManager)
        {
            result = InsertMap(result,strName,strManager);
        }
    }
    return result;
}

int GetEvaluationRow(void *g,wchar_t *user,wchar_t *time)
{
    int row = 4;
    int maxRow = SnapmanGridGetTotalDataRow(g);
    wchar_t *d,*n;
    for(; row <= maxRow; row++)
    {
        d = SnapmanCellGetText(g,row,3);
        n = SnapmanCellGetText(g,row,2);
        if(d&&n&&wcsicmp(time,d)==0&&wcsicmp(n,user)==0)return row;
    }
    return 0;
}
wchar_t *GetEvaluationLevel(int score)
{
    wchar_t *result = L("A");
    if(score>=90)
    {
        result[0] = 'S';
    }else if(score>=80)
    {
        result[0] = 'A';
    }else if(score>=70)
    {
        result[0] = 'B';
    }else if(score>=60)
    {
        result[0] = 'C';
    }else
    {
        result[0] = 'D';
    }
    return result;
}

int GetProblemPoint(wchar_t *level)
{
    if(wcsicmp(level,L("致命"))==0)
    {
        return 10;
    }else if(wcsicmp(level,L("严重"))==0)
    {
        return 6;
    }else if(wcsicmp(level,L("一般"))==0)
    {
        return 2;
    }else if(wcsicmp(level,L("提示"))==0)
    {
        return 1;
    }else
    {
        return 0;
    }
}

void CalcEmployeeScope(void *g,void* gEvaluation,wchar_t *user)
{
    void *gPlan     = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\02.花季计划信息"));
    void *gProblem  = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    void *gDaily    = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\03.花季工作日报"));
    int row  = 17, totalPoint = 0, pTotalPoint = 0,dTotalPoint = 0, nTaskCount = 0 , nFinish = 0, nScore = 0;
    int erow = SnapmanGridGetTotalDataRow(gPlan);
    int uFinishPoint = 0, uUnfinishRation = 0, uProblemPoint = 0, uProblemCount = 0;
    int uDailyPoinnt = 0, uDailyRatio = 15;
    int uManagerScore = 0, uManagerRatio = 15;
    int uWorkingScore = 0, uFinalScore = 0;
    //1、先运行计划中的工作进度
    for(; row <= erow; row++)
    {
        if(wcsicmp(user,SnapmanCellGetText(gPlan,row,12))==0)//找到员工对应的任务
        {
            if(wcsicmp(Date(),SnapmanCellGetText(gPlan,row,6)) >= 0)//只计算已经到期的任务
            {
                uFinishPoint += SnapmanCellGetInt(gPlan,row,5) * SnapmanCellGetInt(gPlan,row,7) / 100;//累加完成的点数
                totalPoint += SnapmanCellGetInt(gPlan,row,5);//点数累加
                nFinish    += SnapmanCellGetInt(gPlan,row,7);//进度累加
                nTaskCount++;//个数累加
            }
        }
    }
    if(nTaskCount)
    {
        uUnfinishRation = nFinish/nTaskCount-100;
    }
    SnapmanCellSetInt(g,6,3,uFinishPoint);                            //设置工作完成点数
    SnapmanCellSetText(g,6,10,concat2(itostr(uUnfinishRation),L"%")); //设置进度偏差

    //2、问题单考评
    nTaskCount = 0;
    for(row = 4,erow = SnapmanGridGetTotalDataRow(gProblem); row <= erow; row++)
    {
        if(wcsicmp(user,SnapmanCellGetText(gProblem,row,13))==0)//找到员工对应的任务
        {
            pTotalPoint += GetProblemPoint(SnapmanCellGetText(gProblem,row,8));//点数累加
            nTaskCount++;//个数累加
        }
    }
    SnapmanCellSetInt(g,7,3,pTotalPoint);    //设置问题单点数
    SnapmanCellSetInt(g,7,10,nTaskCount);   //设置问题单个数

    //3、运算日报考评
    nScore = nTaskCount = 0;
    for(row = 4,erow = SnapmanGridGetTotalDataRow(gDaily); row <= erow; row++)
    {
        if(wcsicmp(user,SnapmanCellGetText(gDaily,row,3))==0)//找到员工对应的任务
        {
            dTotalPoint += SnapmanCellGetInt(gDaily,row,4);//点数累加
            nScore     += SnapmanCellGetInt(gDaily,row,4) * SnapmanCellGetInt(gDaily,row,12);//考评分数累加
            nTaskCount++;//个数累加
        }
    }
    if(nTaskCount)
    {
        uDailyPoinnt = nScore / dTotalPoint;
        uDailyRatio  = SnapmanCellGetInt(g,8,10);
    }
    SnapmanCellSetInt(g,8,3,uDailyPoinnt);                            //设置日报考评分数

    //4、运算工作得分和工作级别
    uManagerScore = SnapmanCellGetInt(g,23,3);
    uManagerRatio = SnapmanCellGetInt(g,23,10);

    uWorkingScore = (uFinishPoint - totalPoint + uFinishPoint - pTotalPoint) * (100 - uDailyRatio) / totalPoint + uDailyPoinnt * uDailyRatio / 100;
    uFinalScore   = (uFinishPoint - totalPoint + uFinishPoint - pTotalPoint) * (100 - uDailyRatio - uManagerRatio) / totalPoint + uDailyPoinnt * uDailyRatio / 100 + uManagerScore * uManagerRatio/100;

    SnapmanCellSetInt(g,9,3,uWorkingScore);                            //设置工作得分
    SnapmanCellSetText(g,9,10,GetEvaluationLevel(uWorkingScore));      //设置工作考评级别
    SnapmanCellSetInt(g,25,3,uFinalScore);                             //设置最终得分
    SnapmanCellSetText(g,25,10,GetEvaluationLevel(uFinalScore));       //设置最终考评级别

}

void SetEmployeeChange(void *g,void *gEvaluation,wchar_t *user)
{
    if(user==NULL||wcslen(user)==0)return;
    int row = GetEvaluationRow(gEvaluation,user,Date());
    if(row > 0)
    {
        SnapmanCellSetText(g,6,3,SnapmanCellGetText(gEvaluation,row,4));//完成工作点数
        SnapmanCellSetText(g,6,10,SnapmanCellGetText(gEvaluation,row,5));//进度偏差
        SnapmanCellSetText(g,7,3,SnapmanCellGetText(gEvaluation,row,6));//问题单点数
        SnapmanCellSetText(g,7,10,SnapmanCellGetText(gEvaluation,row,7));//问题单总数
        SnapmanCellSetText(g,8,3,SnapmanCellGetText(gEvaluation,row,8));//日报总分
        SnapmanCellSetText(g,9,3,SnapmanCellGetText(gEvaluation,row,9));//工作得分
        SnapmanCellSetText(g,10,3,SnapmanCellGetText(gEvaluation,row,10));//主管评语
        SnapmanCellSetText(g,23,3,SnapmanCellGetText(gEvaluation,row,11));//主管打分
        SnapmanCellSetText(g,25,3,SnapmanCellGetText(gEvaluation,row,13));//最终分数
        SnapmanCellSetText(g,25,10,SnapmanCellGetText(gEvaluation,row,14));//考评级别
        SnapmanCellSetText(g,9,10,GetEvaluationLevel(SnapmanCellGetInt(gEvaluation,row,9)));//工作考评级别
    }else
    {
        CalcEmployeeScope(g,gEvaluation,user);
    }
}
void OnInitialize(void *g)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gEvaluation  = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\05.花季员工考评"));
    if(gProject&&gEvaluation)
    {
        SnapmanCellSetLock(g,4,3,0);
        SnapmanCellSetLock(g,4,10,0);
        SnapmanCellSetLock(g,5,10,0);
        SnapmanCellSetText(g,4,3,Date());
        SnapmanCellSetText(g,4,10,SnapmanCellGetText(gProject,3,3));
        SnapmanCellSetCombo(g,5,3,GetEmployee(GetUserManager(gProject),SnapmanGetUserName()));
        SnapmanCellSetText(g,5,10,SnapmanGetUserName());
        SnapmanCellSetLock(g,4,3,1);
        SnapmanCellSetLock(g,4,10,1);
        SnapmanCellSetLock(g,5,10,1);

        SnapmanCellSetComboIndex(g,5,3,0);
        SetEmployeeChange(g,gEvaluation,SnapmanCellGetText(g,5,3));

    }
    SnapmanCleanUp();
}

B、员工选择下拉框的选择事件，获取当前选择员工的工作完成状态、日报考评信息、工作得分和工作考评级别、获取主管考评信息，事件代码：

wchar_t* GetEmployee(void *m,wchar_t *name)
{
    Pair *p = ForeachMap(m);
    wchar_t *result = NULL;
    while(p)
    {
        if(wcsicmp(name,(wchar_t*)p->value)==0)
        {
            if(!result)
            {
                result = (wchar_t*)p->key;
            }else
            {
                result = concat3(result,L"\n",(wchar_t*)p->key);
            }
        }
        p = ForeachMap(m);
    }
    return result;
}

void * GetUserManager(void *g)
{
    int row = 18;
    int maxRow = SnapmanGridGetTotalDataRow(g);
    wchar_t *strName = NULL, *strManager = NULL;
    void *result = NULL;
    for(; row <= maxRow; row++)
    {
        strName = SnapmanCellGetText(g,row,2);
        strManager = SnapmanCellGetText(g,row,13);
        if(strName && strManager)
        {
            result = InsertMap(result,strName,strManager);
        }
    }
    return result;
}

int GetEvaluationRow(void *g,wchar_t *user,wchar_t *time)
{
    int row = 4;
    int maxRow = SnapmanGridGetTotalDataRow(g);
    wchar_t *d,*n;
    for(; row <= maxRow; row++)
    {
        d = SnapmanCellGetText(g,row,3);
        n = SnapmanCellGetText(g,row,2);
        if(d&&n&&wcsicmp(time,d)==0&&wcsicmp(n,user)==0)return row;
    }
    return 0;
}
wchar_t *GetEvaluationLevel(int score)
{
    wchar_t *result = L("A");
    if(score>=90)
    {
        result[0] = 'S';
    }else if(score>=80)
    {
        result[0] = 'A';
    }else if(score>=70)
    {
        result[0] = 'B';
    }else if(score>=60)
    {
        result[0] = 'C';
    }else
    {
        result[0] = 'D';
    }
    return result;
}

int GetProblemPoint(wchar_t *level)
{
    if(wcsicmp(level,L("致命"))==0)
    {
        return 10;
    }else if(wcsicmp(level,L("严重"))==0)
    {
        return 6;
    }else if(wcsicmp(level,L("一般"))==0)
    {
        return 2;
    }else if(wcsicmp(level,L("提示"))==0)
    {
        return 1;
    }else
    {
        return 0;
    }
}

void CalcEmployeeScope(void *g,void* gEvaluation,wchar_t *user)
{
    void *gPlan     = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\02.花季计划信息"));
    void *gProblem  = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    void *gDaily    = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\03.花季工作日报"));
    int row  = 17, totalPoint = 0, pTotalPoint = 0,dTotalPoint = 0, nTaskCount = 0 , nFinish = 0, nScore = 0;
    int erow = SnapmanGridGetTotalDataRow(gPlan);
    int uFinishPoint = 0, uUnfinishRation = 0, uProblemPoint = 0, uProblemCount = 0;
    int uDailyPoinnt = 0, uDailyRatio = 15;
    int uManagerScore = 0, uManagerRatio = 15;
    int uWorkingScore = 0, uFinalScore = 0;
    //1、先运行计划中的工作进度
    for(; row <= erow; row++)
    {
        if(wcsicmp(user,SnapmanCellGetText(gPlan,row,12))==0)//找到员工对应的任务
        {
            if(wcsicmp(Date(),SnapmanCellGetText(gPlan,row,6)) >= 0)//只计算已经到期的任务
            {
                uFinishPoint += SnapmanCellGetInt(gPlan,row,5) * SnapmanCellGetInt(gPlan,row,7) / 100;//累加完成的点数
                totalPoint += SnapmanCellGetInt(gPlan,row,5);//点数累加
                nFinish    += SnapmanCellGetInt(gPlan,row,7);//进度累加
                nTaskCount++;//个数累加
            }
        }
    }
    if(nTaskCount)
    {
        uUnfinishRation = nFinish/nTaskCount-100;
    }
    SnapmanCellSetInt(g,6,3,uFinishPoint);                            //设置工作完成点数
    SnapmanCellSetText(g,6,10,concat2(itostr(uUnfinishRation),L"%")); //设置进度偏差

    //2、问题单考评
    nTaskCount = 0;
    for(row = 4,erow = SnapmanGridGetTotalDataRow(gProblem); row <= erow; row++)
    {
        if(wcsicmp(user,SnapmanCellGetText(gProblem,row,13))==0)//找到员工对应的任务
        {
            pTotalPoint += GetProblemPoint(SnapmanCellGetText(gProblem,row,8));//点数累加
            nTaskCount++;//个数累加
        }
    }
    SnapmanCellSetInt(g,7,3,pTotalPoint);    //设置问题单点数
    SnapmanCellSetInt(g,7,10,nTaskCount);   //设置问题单个数

    //3、运算日报考评
    nScore = nTaskCount = 0;
    for(row = 4,erow = SnapmanGridGetTotalDataRow(gDaily); row <= erow; row++)
    {
        if(wcsicmp(user,SnapmanCellGetText(gDaily,row,3))==0)//找到员工对应的任务
        {
            dTotalPoint += SnapmanCellGetInt(gDaily,row,4);//点数累加
            nScore     += SnapmanCellGetInt(gDaily,row,4) * SnapmanCellGetInt(gDaily,row,12);//考评分数累加
            nTaskCount++;//个数累加
        }
    }
    if(nTaskCount)
    {
        uDailyPoinnt = nScore / dTotalPoint;
        uDailyRatio  = SnapmanCellGetInt(g,8,10);
    }
    SnapmanCellSetInt(g,8,3,uDailyPoinnt);                            //设置日报考评分数

    //4、运算工作得分和工作级别
    uManagerScore = SnapmanCellGetInt(g,23,3);
    uManagerRatio = SnapmanCellGetInt(g,23,10);
    Print("%d",uDailyPoinnt * uDailyRatio / 100);
    uWorkingScore = (uFinishPoint - totalPoint + uFinishPoint - pTotalPoint) * (100 - uDailyRatio) / totalPoint + uDailyPoinnt * uDailyRatio / 100;
    uFinalScore   = (uFinishPoint - totalPoint + uFinishPoint - pTotalPoint) * (100 - uDailyRatio - uManagerRatio) / totalPoint + uDailyPoinnt * uDailyRatio / 100 + uManagerScore * uManagerRatio/100;

    SnapmanCellSetInt(g,9,3,uWorkingScore);                            //设置工作得分
    SnapmanCellSetText(g,9,10,GetEvaluationLevel(uWorkingScore));      //设置工作考评级别
    SnapmanCellSetInt(g,25,3,uFinalScore);                             //设置最终得分
    SnapmanCellSetText(g,25,10,GetEvaluationLevel(uFinalScore));       //设置最终考评级别

}

void SetEmployeeChange(void *g,void *gEvaluation,wchar_t *user)
{
    if(user==NULL||wcslen(user)==0)return;
    int row = GetEvaluationRow(gEvaluation,user,Date());
    if(row > 0)
    {
        SnapmanCellSetText(g,6,3,SnapmanCellGetText(gEvaluation,row,4));//完成工作点数
        SnapmanCellSetText(g,6,10,SnapmanCellGetText(gEvaluation,row,5));//进度偏差
        SnapmanCellSetText(g,7,3,SnapmanCellGetText(gEvaluation,row,6));//问题单点数
        SnapmanCellSetText(g,7,10,SnapmanCellGetText(gEvaluation,row,7));//问题单总数
        SnapmanCellSetText(g,8,3,SnapmanCellGetText(gEvaluation,row,8));//日报总分
        SnapmanCellSetText(g,9,3,SnapmanCellGetText(gEvaluation,row,9));//工作得分
        SnapmanCellSetText(g,10,3,SnapmanCellGetText(gEvaluation,row,10));//主管评语
        SnapmanCellSetText(g,23,3,SnapmanCellGetText(gEvaluation,row,11));//主管打分
        SnapmanCellSetText(g,25,3,SnapmanCellGetText(gEvaluation,row,13));//最终分数
        SnapmanCellSetText(g,25,10,SnapmanCellGetText(gEvaluation,row,14));//考评级别
        SnapmanCellSetText(g,9,10,GetEvaluationLevel(SnapmanCellGetInt(gEvaluation,row,9)));//工作考评级别
    }else
    {
        CalcEmployeeScope(g,gEvaluation,user);
    }
}
void OnComboChanged(void *g, int row, int col,wchar_t *text)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
    void *gEvaluation  = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\05.花季员工考评"));
    if(gProject&&gEvaluation)
    {
        SetEmployeeChange(g,gEvaluation,text);
    }
    SnapmanCleanUp();
}

C、提交员工考评按钮事件，并最终计算员工的考评级别，事件代码：

wchar_t* GetEmployee(void *m,wchar_t *name)
{
    Pair *p = ForeachMap(m);
    wchar_t *result = NULL;
    while(p)
    {
        if(wcsicmp(name,(wchar_t*)p->value)==0)
        {
            if(!result)
            {
                result = (wchar_t*)p->key;
            }else
            {
                result = concat3(result,L"\n",(wchar_t*)p->key);
            }
        }
        p = ForeachMap(m);
    }
    return result;
}

void * GetUserManager(void *g)
{
    int row = 18;
    int maxRow = SnapmanGridGetTotalDataRow(g);
    wchar_t *strName = NULL, *strManager = NULL;
    void *result = NULL;
    for(; row <= maxRow; row++)
    {
        strName = SnapmanCellGetText(g,row,2);
        strManager = SnapmanCellGetText(g,row,13);
        if(strName && strManager)
        {
            result = InsertMap(result,strName,strManager);
        }
    }
    return result;
}

int GetEvaluationRow(void *g,wchar_t *user,wchar_t *time)
{
    int row = 4;
    int maxRow = SnapmanGridGetTotalDataRow(g);
    wchar_t *d,*n;
    for(; row <= maxRow; row++)
    {
        d = SnapmanCellGetText(g,row,3);
        n = SnapmanCellGetText(g,row,2);
        if(d&&n&&wcsicmp(time,d)==0&&wcsicmp(n,user)==0)return row;
    }
    return 0;
}
wchar_t *GetEvaluationLevel(int score)
{
    wchar_t *result = L("A");
    if(score>=90)
    {
        result[0] = 'S';
    }else if(score>=80)
    {
        result[0] = 'A';
    }else if(score>=70)
    {
        result[0] = 'B';
    }else if(score>=60)
    {
        result[0] = 'C';
    }else
    {
        result[0] = 'D';
    }
    return result;
}

int GetProblemPoint(wchar_t *level)
{
    if(wcsicmp(level,L("致命"))==0)
    {
        return 10;
    }else if(wcsicmp(level,L("严重"))==0)
    {
        return 6;
    }else if(wcsicmp(level,L("一般"))==0)
    {
        return 2;
    }else if(wcsicmp(level,L("提示"))==0)
    {
        return 1;
    }else
    {
        return 0;
    }
}

void CalcEmployeeScope(void *g,void* gEvaluation,wchar_t *user)
{
    void *gPlan     = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\02.花季计划信息"));
    void *gProblem  = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\04.花季问题跟踪"));
    void *gDaily    = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\03.花季工作日报"));
    int row  = 17, totalPoint = 0, pTotalPoint = 0,dTotalPoint = 0, nTaskCount = 0 , nFinish = 0, nScore = 0;
    int erow = SnapmanGridGetTotalDataRow(gPlan);
    int uFinishPoint = 0, uUnfinishRation = 0, uProblemPoint = 0, uProblemCount = 0;
    int uDailyPoinnt = 0, uDailyRatio = 15;
    int uManagerScore = 0, uManagerRatio = 15;
    int uWorkingScore = 0, uFinalScore = 0;
    //1、先运行计划中的工作进度
    for(; row <= erow; row++)
    {
        if(wcsicmp(user,SnapmanCellGetText(gPlan,row,12))==0)//找到员工对应的任务
        {
            if(wcsicmp(Date(),SnapmanCellGetText(gPlan,row,6)) >= 0)//只计算已经到期的任务
            {
                uFinishPoint += SnapmanCellGetInt(gPlan,row,5) * SnapmanCellGetInt(gPlan,row,7) / 100;//累加完成的点数
                totalPoint += SnapmanCellGetInt(gPlan,row,5);//点数累加
                nFinish    += SnapmanCellGetInt(gPlan,row,7);//进度累加
                nTaskCount++;//个数累加
            }
        }
    }
    if(nTaskCount)
    {
        uUnfinishRation = nFinish/nTaskCount-100;
    }
    SnapmanCellSetInt(g,6,3,uFinishPoint);                            //设置工作完成点数
    SnapmanCellSetText(g,6,10,concat2(itostr(uUnfinishRation),L"%")); //设置进度偏差

    //2、问题单考评
    nTaskCount = 0;
    for(row = 4,erow = SnapmanGridGetTotalDataRow(gProblem); row <= erow; row++)
    {
        if(wcsicmp(user,SnapmanCellGetText(gProblem,row,13))==0)//找到员工对应的任务
        {
            pTotalPoint += GetProblemPoint(SnapmanCellGetText(gProblem,row,8));//点数累加
            nTaskCount++;//个数累加
        }
    }
    SnapmanCellSetInt(g,7,3,pTotalPoint);    //设置问题单点数
    SnapmanCellSetInt(g,7,10,nTaskCount);   //设置问题单个数

    //3、运算日报考评
    nScore = nTaskCount = 0;
    for(row = 4,erow = SnapmanGridGetTotalDataRow(gDaily); row <= erow; row++)
    {
        if(wcsicmp(user,SnapmanCellGetText(gDaily,row,3))==0)//找到员工对应的任务
        {
            dTotalPoint += SnapmanCellGetInt(gDaily,row,4);//点数累加
            nScore     += SnapmanCellGetInt(gDaily,row,4) * SnapmanCellGetInt(gDaily,row,12);//考评分数累加
            nTaskCount++;//个数累加
        }
    }
    if(nTaskCount)
    {
        uDailyPoinnt = nScore / dTotalPoint;
        uDailyRatio  = SnapmanCellGetInt(g,8,10);
    }
    SnapmanCellSetInt(g,8,3,uDailyPoinnt);                            //设置日报考评分数

    //4、运算工作得分和工作级别
    uManagerScore = SnapmanCellGetInt(g,23,3);
    uManagerRatio = SnapmanCellGetInt(g,23,10);

    uWorkingScore = (uFinishPoint - totalPoint + uFinishPoint - pTotalPoint) * (100 - uDailyRatio) / totalPoint + uDailyPoinnt * uDailyRatio / 100;
    uFinalScore   = (uFinishPoint - totalPoint + uFinishPoint - pTotalPoint) * (100 - uDailyRatio - uManagerRatio) / totalPoint + uDailyPoinnt * uDailyRatio / 100 + uManagerScore * uManagerRatio/100;

    SnapmanCellSetInt(g,9,3,uWorkingScore);                            //设置工作得分
    SnapmanCellSetText(g,9,10,GetEvaluationLevel(uWorkingScore));      //设置工作考评级别
    SnapmanCellSetInt(g,25,3,uFinalScore);                             //设置最终得分
    SnapmanCellSetText(g,25,10,GetEvaluationLevel(uFinalScore));       //设置最终考评级别

}

int SetEmployeeChange(void *g,void *gEvaluation,wchar_t *user)
{
    if(user==NULL||wcslen(user)==0)return 0;
    int row = GetEvaluationRow(gEvaluation,user,Date());
    if(row > 0)
    {
        SnapmanCellSetText(g,6,3,SnapmanCellGetText(gEvaluation,row,4));//完成工作点数
        SnapmanCellSetText(g,6,10,SnapmanCellGetText(gEvaluation,row,5));//进度偏差
        SnapmanCellSetText(g,7,3,SnapmanCellGetText(gEvaluation,row,6));//问题单点数
        SnapmanCellSetText(g,7,10,SnapmanCellGetText(gEvaluation,row,7));//问题单总数
        SnapmanCellSetText(g,8,3,SnapmanCellGetText(gEvaluation,row,8));//日报总分
        SnapmanCellSetText(g,9,3,SnapmanCellGetText(gEvaluation,row,9));//工作得分
        SnapmanCellSetText(g,10,3,SnapmanCellGetText(gEvaluation,row,10));//主管评语
        SnapmanCellSetText(g,23,3,SnapmanCellGetText(gEvaluation,row,11));//主管打分
        SnapmanCellSetText(g,25,3,SnapmanCellGetText(gEvaluation,row,13));//最终分数
        SnapmanCellSetText(g,25,10,SnapmanCellGetText(gEvaluation,row,14));//考评级别
        SnapmanCellSetText(g,9,10,GetEvaluationLevel(SnapmanCellGetInt(gEvaluation,row,9)));//工作考评级别
    }
    CalcEmployeeScope(g,gEvaluation,user);
    return row;
}

void SaveEvaluation(void *g,void *gEvaluation,int row)
{
    if(row==0)row = SnapmanGridGetTotalDataRow(gEvaluation) + 1;
    SnapmanCellSetInt(gEvaluation,row,1,row-3);                        //设置序号
    SnapmanCellSetText(gEvaluation,row,2,SnapmanCellGetText(g,5,3));   //设置考评员工
    SnapmanCellSetText(gEvaluation,row,3,Date());                      //设置考评时间
    SnapmanCellSetText(gEvaluation,row,4,SnapmanCellGetText(g,6,3));   //完成工作点数
    SnapmanCellSetText(gEvaluation,row,5,SnapmanCellGetText(g,6,10));  //进度偏差
    SnapmanCellSetText(gEvaluation,row,6,SnapmanCellGetText(g,7,3));   //问题单点数
    SnapmanCellSetText(gEvaluation,row,7,SnapmanCellGetText(g,7,10));  //问题单总数
    SnapmanCellSetText(gEvaluation,row,8,SnapmanCellGetText(g,8,3));   //日报总分
    SnapmanCellSetText(gEvaluation,row,9,SnapmanCellGetText(g,9,3));   //工作得分
    SnapmanCellSetText(gEvaluation,row,10,SnapmanCellGetText(g,10,3)); //主管评语
    SnapmanCellSetText(gEvaluation,row,11,SnapmanCellGetText(g,23,3)); //主管打分
    SnapmanCellSetText(gEvaluation,row,12,SnapmanGetUserName());       //设置主管
    SnapmanCellSetText(gEvaluation,row,13,SnapmanCellGetText(g,25,3)); //最终分数
    SnapmanCellSetText(gEvaluation,row,14,SnapmanCellGetText(g,25,10));//考评级别
    SnapmanGridSave(gEvaluation);
    Print("员工考评提交成功。");
}

void OnButtonClick(void *g, int row, int col)
{
    if(SnapmanCellIsEmpty(g,10,3))
    {
        Print("请填写主管评语哦。");
        return;
    }else if(SnapmanCellIsEmpty(g,23,3))
    {
        Print("请填写主管打分。");
        return;
    }else
    {
        void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\01.花季项目信息"));
        void *gEvaluation  = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\05.花季员工考评"));
        if(gProject&&gEvaluation)
        {
            SaveEvaluation(g,gEvaluation,SetEmployeeChange(g,gEvaluation,SnapmanCellGetText(g,5,3)));
        }
        SnapmanCleanUp();
    }
}

D、最终代码写完后将表格设置为不可以保存状态，这样表格就只能用来工作而不能用来存储数据，这样每个人写的员工考评就不会产生相互影响

03.花季项目进度，这张表包括：设计、开发、测试、版本发布进展，项目总体进展和预计项目完成时间。事件包括：

A、初始化事件，自动获计算设计、开发、测试、版本发布进展，项目总体进展和预计项目完成时间，事件代码：

void SetProjectInfo(void *g,void *gProject)
{
    wchar_t *strProgress = NULL, *strDiff = NULL, *strStep = NULL;
    wchar_t *strStep1 = L("设计");
    wchar_t *strStep2 = L("开发");
    wchar_t *strStep3 = L("测试");
    wchar_t *strStep4 = L("版本发布");
    wchar_t *strStarTime = SnapmanCellGetText(gProject,4,3);
    char buffer[1024] = {0};
    int index = 0;
    double nd[4] = {0};//总进度
    double id[4] = {0};//到今天个数
    double td[4] = {0};//总个数
    double nto = 0,ito = 0,tto = 0;
    int srow = 4;
    for(int row = SnapmanGridGetTotalDataRow(gProject); row >= 17; row--)
    {
        strStep = SnapmanCellGetText(gProject,row,2);
        if(wcsicmp(strStep,strStep1)==0)
        {
            index = 0;
        }else if(wcsicmp(strStep,strStep2)==0)
        {
            index = 1;
        }else if(wcsicmp(strStep,strStep3)==0)
        {
            index = 2;
        }else
        {
            index = 3;
        }

        if(wcsicmp(Date(),SnapmanCellGetText(gProject,row,6)) >= 0)
        {
            tto++;
            td[index]++;
        }
        nd[index] += SnapmanCellGetInt(gProject,row,7);
        nto += SnapmanCellGetInt(gProject,row,7);
        id[index]++;
        ito++;
    }
    for(int i = 0; i < 4; i++)
    {
        if(id[i]==0)
        {
            SnapmanCellSetText(g,srow,5,L" -");
        }else
        {
            sprintf(buffer," %.1f",nd[i]/id[i]);
            SnapmanCellSetText(g,srow,5,concat2(L(buffer),L"%"));
        }
        if(td[i]==0)
        {
            SnapmanCellSetText(g,srow+1,5,L" -");
        }else
        {
            sprintf(buffer," %.1f",(nd[i]-td[i]*100)/td[i]);
            SnapmanCellSetText(g,srow+1,5,concat2(L(buffer),L"%"));
        }
        srow += 2;
    }
    if(ito==0)
    {
        SnapmanCellSetText(g,12,4,L" -");
    }else
    {
        sprintf(buffer,"%.1f",nto/ito);
        SnapmanCellSetText(g,12,4,concat2(L(buffer),L"%"));
    }
    if(tto==0)
    {
        SnapmanCellSetText(g,12,11,L" -");
    }else
    {
        sprintf(buffer," %.1f",(nto-tto*100)/tto);
        SnapmanCellSetText(g,12,11,concat2(L(buffer),L"%"));
    }
    SnapmanCellSetText(g,16,4,SnapmanCellGetText(gProject,8,3));

    if(strStarTime==NULL||wcslen(strStarTime)==0)
    {
        SnapmanCellSetText(g,16,11,L" -");
    }else
    {
        int n = DiffDay(Date(),strStarTime);
        int d = ito==0?0:(int)((1-nto/ito/100) * n);
        if(d < 0)d = 0;
        SnapmanCellSetText(g,16,11,AddDay(SnapmanCellGetText(gProject,8,3),d));
    }
}

void OnInitialize(void *g)
{
    void *gProject = SnapmanGetGrid(L("\\花季项目管理系统\\Data\\02.花季计划信息"));
    if(gProject)
    {
        SetProjectInfo(g,gProject);
    }
}

四、结论：就这样一个比较完整的项目管理系统就开发完成了，系统花了不到2天进行业务设计花了1天多一点进行事件代码开发；虽然有70%代码是重复的单不影响执行性能；Snapman将系统开发工作降低到业务设计量的工作直接超过了开发工作量。


系统授权

Help >
系统授权

一、软件下载

软件版本（先启动服务端再启动客户端，登陆默认账号：admin，默认密码：123456）：

    1、Snapman 2017夏季个人版，服务器最多可供三个人同时连接使用

32位下载地址： snapman_setup32_personaledition_v1.3.exe

    2、Snapman 2017夏季企业版，基础套餐包含12用户并发使用

32位下载地址： snapman_setup32_enterpriseedition_v1.3.exe

    3、其他需要增加用户的版本请联系销售经理获取

二、软件授权与价格

Snapman2017夏季试用版可以试用半年，仅允许个人交流学习使用；Snapman2017夏季企业版，授权给包括企业机关团体使用，采用服务端收费客户端免费的原则，价格如下：

    1、Snapman 2017夏季企业版基础价格3000元人民币，每增加一个并发用户费用为250元人民币

    2、联系方式：

    Snapman销售经理：陈经理

    手机：15829623857

    Email：feirench@gmail.com

    支付宝账号：feirench@gmail.com