-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
### Added - Documentation on the header. - Several assertions on test_xlsx_load_sheet(). - README.md - LICENSE ### Changed - Some variables were renamed to reflect Excel naming. - Error codes so they are unique. - xlsx_read_cell() return. Now returns 1 or 0 depending on success or failure. - Some code style towards simpleness.
- Loading branch information
1 parent
a9fdb14
commit 59059f6
Showing
18 changed files
with
577 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.idea/ | ||
_in/ | ||
cmake-build-debug/ | ||
cmake-build-debug-mingw/ | ||
doc/ | ||
temp/ | ||
!temp/keep | ||
PROGRAMMERNOTES.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
cmake_minimum_required(VERSION 3.9) | ||
project(porcupine C) | ||
project(xlsx_drone C) | ||
|
||
set(CMAKE_C_STANDARD 11) | ||
|
||
add_library(porcupine SHARED ext/miniz.h ext/zip.c ext/zip.h ext/sxmlc.c ext/sxmlc.h ext/sxmlsearch.c ext/sxmlsearch.h src/library.c src/library.h) | ||
add_library(xlsx_drone SHARED ext/miniz.h ext/zip.c ext/zip.h ext/sxmlc.c ext/sxmlc.h ext/sxmlsearch.c ext/sxmlsearch.h src/xlsx_drone.c src/xlsx_drone.h) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
Copyright 2021 Damián M. G. | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated | ||
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the | ||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit | ||
persons to whom the Software is furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the | ||
Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE | ||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR | ||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
# xlsx_drone | ||
|
||
 | ||
 | ||
 | ||
|
||
Fast _Microsoft Excel's_ **\*.xlsx** reader. | ||
|
||
## Table of contents | ||
|
||
* [Features](#features) | ||
* [Installation](#installation) | ||
* [Usage](#usage) | ||
* [Essential](#essential) | ||
* [Extended](#extended) | ||
* [Project Status](#project-status) | ||
* [Credits & Thanks](#credits--thanks) | ||
* [License](#license) | ||
|
||
## Features | ||
|
||
* Doesn't use any external application to parse them. | ||
* Focus on speed over functionality. | ||
* Simple interface. | ||
* UTF-8 support. | ||
|
||
## Installation | ||
|
||
Straightforward copy and paste of the _src_ and _ext_ folders into your project root folder and `#include "xlsx_drone.h"` in your source code. It's understandable that you might want to accommodate files differently, just note that _xlsx_drone.h_ calls its deppendencies with relative paths: | ||
|
||
```c | ||
// external libraries | ||
#include "../ext/zip.h" | ||
#include "../ext/sxmlc.h" | ||
#include "../ext/sxmlsearch.h" | ||
``` | ||
|
||
..., you might want to modify that according to your needs. | ||
|
||
**NOTE**: You'll also find several dynamic library releases inside the _share_ folder for the current version that could be of usage. | ||
|
||
## Usage | ||
|
||
### Essential | ||
|
||
```c | ||
// open *.xlsx | ||
xlsx_workbook_t wb; | ||
xlsx_open("foo.xlsx", &wb); | ||
// load sheet | ||
xlsx_sheet_t *sheet_1 = xlsx_load_sheet(&wb, 1, NULL); | ||
// read cell | ||
xlsx_cell_t cell_data_holder; | ||
xlsx_read_cell(sheet_1, 4, "B", &cell_data_holder); | ||
// inspect result | ||
switch(cell_data_holder.value_type) { | ||
case XLSX_POINTER_TO_CHAR: | ||
printf("Cell 4B has value: %s", cell_data_holder.value.pointer_to_char_value); | ||
break; | ||
case XLSX_INT: | ||
printf("Cell 4B has value: %d", cell_data_holder.value.int_value); | ||
break; | ||
case XLSX_LONG_LONG: | ||
printf("Cell 4B has value: %lld", cell_data_holder.value.long_long_value); | ||
break; | ||
case XLSX_DOUBLE: | ||
printf("Cell 4B has value: %f", cell_data_holder.value.double_value); | ||
break; | ||
default: | ||
printf("Cell 4B has no value"); | ||
} | ||
// you can also inspect the cell category | ||
int cell_category = cell_data_holder.style->related_category | ||
``` | ||
...which is one of: | ||
```c | ||
typedef enum xlsx_cell_category { | ||
XLSX_NUMBER, // int, long long, or double | ||
XLSX_TEXT, // string | ||
XLSX_DATE, // int | ||
XLSX_TIME, // double | ||
XLSX_DATE_TIME, // double | ||
XLSX_UNKNOWN | ||
} xlsx_cell_category; | ||
``` | ||
|
||
...which is a summary of what can be set in Excel: | ||
|
||
 | ||
|
||
Note that: | ||
|
||
* _XLSX_TIME_ category is represented as a double between 0 and 1. | ||
* _XLSX_DATE_ category is represented as an int that stars with 1 for the first day of 1900 and raises until the last day of 9999. Values that fall out of the range are represented as text (string) although they will be pointed as _XLSX_DATE_ if the cell has that category manually fixed. | ||
* _XLSX_DATE_TIME_ category is a combination of XLSX_TIME and XLSX_DATE. | ||
|
||
### Extended | ||
|
||
This section shows brief descriptions of extra features of the library. | ||
|
||
```c | ||
// sets on and off errors printing in stdout (default: on (1)) | ||
void xlsx_set_print_err_messages(int flag); | ||
// inspect xlsx_errno to know what happened after some function fails | ||
int xlsx_get_xlsx_errno(void); | ||
|
||
// if memory is of your concern, you can unload any loaded sheet if it's of no use | ||
void xlsx_unload_sheet(xlsx_sheet_t *sheet); | ||
``` | ||
The rest of the public functions will return 0 or NULL if fail, and 1 or a valid pointer for success. When they return 0 or NULL, you can check `xlsx_errno` and compare it against the respective error values of the function. | ||
**For full documentation of the API, check _src/xlsx_drone.h_.** | ||
## Project Status | ||
- [x] Reading capabilities for ASCII | ||
- [x] Reading capabilities for UTF-8 | ||
- [ ] Writting capabilities (WIP) | ||
## Credits & Thanks | ||
* Matthieu Labas for [**sxmlc**](http://sxmlc.sourceforge.net/). | ||
* Kuba Podgórski for [**zip**](https://github.com/kuba--/zip). | ||
## License | ||
#### [MIT](TODO: ...) | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,186 @@ | ||
desc 'compile & run the unit tests' | ||
=begin | ||
TASKS | ||
=end | ||
|
||
desc 'compile(x86) & run the unit tests' | ||
task :ct do | ||
build_unit_tests() | ||
run_unit_tests() | ||
if(build_unit_tests()) | ||
run_unit_tests() | ||
end | ||
end | ||
|
||
desc 'compile unit tests' | ||
desc 'compile(x64) & run the unit tests' | ||
task :ct_64 do | ||
if(build_unit_tests(_64: true)) | ||
run_unit_tests() | ||
end | ||
end | ||
|
||
desc 'compile(x86) unit tests' | ||
task :c do | ||
build_unit_tests() | ||
end | ||
|
||
desc 'compile(x64) unit tests' | ||
task :c_64 do | ||
build_unit_tests(_64: true) | ||
end | ||
|
||
desc 'run the unit tests' | ||
task :t do | ||
run_unit_tests() | ||
end | ||
|
||
def build_unit_tests | ||
desc 'clear unit tests' | ||
task :clear_ut do | ||
clear_unit_tests() | ||
end | ||
|
||
# you will execute this before every new version release | ||
desc 'perform measures & produce badges metadata' | ||
task :badges do | ||
# not important if compiled with x86 or x64 | ||
if(build_unit_tests(coverage: true)) | ||
# if tests don't pass, code coverage will lie since code next to the problem isn't executed. In that case it's better to leave the last measure | ||
if(run_unit_tests()) | ||
measure_code_coverage() | ||
create_test_suite_badge(pass: true) | ||
else | ||
create_test_suite_badge(pass: false) | ||
end | ||
measure_test_assertions() | ||
end | ||
end | ||
|
||
|
||
=begin | ||
FUNCTIONS | ||
=end | ||
|
||
# @param _64 [boolean], @param coverage [boolean] | ||
# The binary files with 0 bytes fill the purpose of showing if the exe was compiled with x86 or x64 compiler. | ||
def build_unit_tests(_64: false, coverage: false) | ||
command = [] | ||
command << gcc = 'gcc' | ||
command << debug = '-ggdb' # leave empty if the target exe hasn't the purpose of debugging | ||
if(_64) | ||
File.delete('temp/x64') rescue nil | ||
# locally using mingw compiler that comes packed with RubyInstaller 2.7 (version 10.2) | ||
command << gcc = 'C:/Ruby27-x64/msys64/mingw64/bin/gcc.exe' | ||
else | ||
File.delete('temp/x86') rescue nil | ||
# locally using mingw compiler downloaded from official website (version 9.2) | ||
command << gcc = 'gcc' | ||
end | ||
command << debug = '-ggdb' # prepare exe for debugging purpose (gdb) | ||
if(coverage) | ||
command << coverage = '--coverage' # code coverage support (gcov) | ||
end | ||
command << standard = '-std=c11' | ||
command << warnings = '-w' # libraries use to throw some warnings | ||
command << preprocessing = '-D UNITY_INCLUDE_DOUBLE -D UNITY_SUPPORT_64' # double & long long support | ||
command << directories_included_for_headers_search = '-I ext/ -I src/' | ||
command << source_files = 'ext/zip.c ext/sxmlc.c ext/sxmlsearch.c src/library.c ext/unity.c src/library.test.c' | ||
command << output = '-o bin/unit_tests.exe' | ||
system(command.join(' ')) | ||
command << directories_included_for_headers_search = '-I ext/ -I src/ -I test/' | ||
command << source_files = 'ext/zip.c ext/sxmlc.c ext/sxmlsearch.c src/xlsx_drone.c ext/unity.c test/xlsx_drone.test.c' | ||
command << output = '-o temp/unit_tests.exe' | ||
# output command to trigger | ||
puts command.join(' ') | ||
# will return true if were no problems | ||
if(system(command.join(' '))) | ||
print("\nCompile successful") | ||
if(_64) | ||
File.open('temp/x64', 'wb') {|f|} | ||
print("(x64).\n\n") | ||
else | ||
File.open('temp/x86', 'wb') {|f|} | ||
print("(x86).\n\n") | ||
end | ||
true | ||
else | ||
puts("\nCompile failed.") | ||
false | ||
end | ||
end | ||
|
||
# @return [boolean] | ||
def run_unit_tests | ||
system("bin/unit_tests") | ||
end | ||
result = system("temp/unit_tests") | ||
puts() | ||
result | ||
end | ||
|
||
def clear_unit_tests | ||
File.delete('temp/unit_tests.exe') rescue nil | ||
File.delete('temp/x86') rescue nil | ||
File.delete('temp/x64') rescue nil | ||
puts('Clear completed.') | ||
end | ||
|
||
# Executes gcov for the library source code according to the test suite. Prepares a JSON to be consumed by shields.io and then shown in README.md. | ||
def measure_code_coverage | ||
# at this point *.gcda & *.gcno files gets generated in project root dir | ||
temp_gcov_path = 'temp/gcov.txt' | ||
system("gcov -o . src/xlsx_drone.c > #{temp_gcov_path}") | ||
# that generated several *.gcov files, what matters is the command output | ||
covered = \ | ||
File.open(temp_gcov_path) do |f| | ||
f.read.match(/executed:(\d+[.,]?\d{0,2}%)/).[](1).sub(/,/, '.') # i.e.: "32.43%" | ||
end | ||
# create the *.json file rdy to be consumed by shields.io | ||
require 'json' | ||
# inquire matching color according to the amount of code covered | ||
color = \ | ||
case (covered.to_f) | ||
when (80..100) | ||
'brightgreen' | ||
when (60..80) | ||
'green' | ||
when (40..60) | ||
'yellowgreen' | ||
else | ||
'orange' | ||
end | ||
# produce the json string | ||
json = { | ||
'schemaVersion': 1, | ||
'label': 'coverage', | ||
'message': covered, | ||
'color': color | ||
}.to_json | ||
# write the file | ||
File.open('data/shields/gcov.json', 'w:utf-8:utf-8') {|f| f.write(json)} | ||
# remove garbage | ||
require 'fileutils' | ||
FileUtils.remove(Dir['*.{gcda,gcno,gcov}'] << temp_gcov_path, force: true) | ||
# provide some output | ||
puts("Done. Code coverage: #{covered}.") | ||
end | ||
|
||
# Measure the amount of test assertions written and produce a JSON file rdy to be consumed by shields.io. | ||
def measure_test_assertions | ||
# collect the data | ||
assertions = File.open('test/xlsx_drone.test.c') {|f| f.read.scan(/TEST_ASSERT/).size.to_s} | ||
# produce the json string | ||
require 'json' | ||
json = { | ||
'schemaVersion': 1, | ||
'label': 'test assertions', | ||
'message': assertions, | ||
'color': 'informational' | ||
}.to_json | ||
# write the file | ||
File.open('data/shields/assertions.json', 'w:utf-8:utf-8') {|f| f.write(json)} | ||
# provide some output | ||
puts("Assertions: #{assertions}.") | ||
end | ||
|
||
# @param pass [boolean] | ||
def create_test_suite_badge(pass:) | ||
# produce the json string | ||
require 'json' | ||
json = { | ||
'schemaVersion': 1, | ||
'label': 'test suite', | ||
'message': pass ? 'pass' : 'fail', | ||
'color': pass ? 'brightgreen' : 'red' | ||
}.to_json | ||
# write the file | ||
File.open('data/shields/test_suite.json', 'w:utf-8:utf-8') {|f| f.write(json)} | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
Rem comiple unit_tests.exe | ||
cmd /c rake c | ||
Rem run the gdbserver | ||
start gdbserver localhost:2159 bin/unit_tests.exe | ||
start gdbserver localhost:2159 test/unit_tests.exe |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.