├── .gitignore ├── AUTHORS ├── COPYING ├── ChangeLog ├── INSTALL ├── Makefile.am ├── Makefile.in ├── NEWS ├── README ├── aclocal.m4 ├── bin ├── gitlog2changelog.py └── reqReport.bat ├── compile ├── config.guess ├── config.h.in ├── config.sub ├── configure ├── configure.ac ├── depcomp ├── dev ├── README-cross-libs.txt ├── TEMPLATE.rqtf ├── TODO ├── req.config ├── req.creator ├── req.files ├── req.includes └── win32env ├── docs ├── Makefile ├── SPEC.docx ├── TEST.txt ├── capture.html ├── capture.md ├── download │ ├── req-v1.0.zip │ ├── req-v1.1.zip │ ├── req-v1.2.0.zip │ ├── reqflow-1.3.0-setup.exe │ ├── reqflow-1.3.1-setup.exe │ ├── reqflow-1.3.2-setup.exe │ ├── reqflow-1.3.3-setup.exe │ ├── reqflow-1.3.4-setup.exe │ ├── reqflow-1.4.0-setup.exe │ ├── reqflow-1.4.1-setup.exe │ ├── reqflow-1.4.2 │ ├── reqflow-1.4.2-setup.exe │ ├── reqflow-1.5.0-setup.exe │ └── reqflow-v1.2.1.zip ├── footer.html ├── gen_menu.sh ├── header.html ├── index.html ├── index.md ├── reqReport.html ├── style.css └── stylesheet.css ├── install-sh ├── missing ├── reqflow.iss.in ├── src ├── .gitignore ├── Makefile ├── ReqDocumentDocx.cpp ├── ReqDocumentDocx.h ├── ReqDocumentHtml.cpp ├── ReqDocumentHtml.h ├── ReqDocumentPdf.cpp ├── ReqDocumentPdf.h ├── ReqDocumentTxt.cpp ├── ReqDocumentTxt.h ├── StringIt.cpp ├── StringIt.h ├── config.h.in ├── dateTools.cpp ├── dateTools.h ├── global.h ├── logging.cpp ├── logging.h ├── main.cpp ├── main_pdf.cpp ├── main_regex.c ├── main_testStringCompare.cpp ├── main_unzip.c ├── main_xml.c ├── parseConfig.cpp ├── parseConfig.h ├── renderingHtml.cpp ├── renderingHtml.h ├── req.cpp ├── req.h ├── stringTools.cpp └── stringTools.h ├── test-driver └── test ├── .gitignore ├── Makefile.am ├── Makefile.in ├── README.txt ├── SPEC-with-table.docx ├── SPEC-with-table.ref ├── SPEC-with-table.req ├── SPEC-with-table.test ├── SPEC.docx ├── SPEC.html ├── SPEC.pdf ├── TEST-sort.txt ├── TEST.html ├── TEST.txt ├── TEST2.html ├── conf.req ├── docx_rev_marks.docx ├── docx_rev_marks.req ├── envtest.in ├── functions ├── html.req ├── html2.req ├── pdf.req ├── req-same-line.stdout.ref ├── req-same-line.test ├── req-stat-docx-rm.stdout.ref ├── req-stat-docx-rm.test ├── req-stat-html2.stdout.ref ├── req-stat-html2.test ├── req-stat-sort.stdout.ref ├── req-stat-sort.test ├── req-stat-stdin.stderr.ref ├── req-stat-stdin.stdout.ref ├── req-stat-stdin.test ├── req-stat.stderr.ref ├── req-stat.stdout.ref ├── req-stat.test ├── req-trac-html.stderr.ref ├── req-trac-html.stdout.ref ├── req-trac-html.test ├── req-trac-pdf.stderr.ref ├── req-trac-pdf.stdout.ref ├── req-trac-pdf.test ├── req-trac.stderr.ref ├── req-trac.stdout.ref ├── req-trac.test ├── rfc2246-spec.pdf ├── rfc2246-test.txt ├── rfc2246.req ├── same-line-spec.txt ├── same-line-test.txt ├── same-line.req ├── t_capture_algorithm ├── t_capture_algorithm.ref ├── t_end_req ├── t_end_req.ref ├── t_multi_doc ├── t_multi_doc.stdout.ref ├── t_second_doc └── t_second_doc.ref /.gitignore: -------------------------------------------------------------------------------- 1 | # temporary files 2 | *~ 3 | *.swp 4 | 5 | # ignore compilation files 6 | *.o 7 | *.gcno 8 | *.gcda 9 | *.gcov 10 | 11 | # ignore binaries 12 | /req 13 | /*.exe 14 | /main_* 15 | 16 | # ignore ./configure generated files 17 | /src/config.h 18 | Makefile 19 | /.deps/ 20 | /stamp-h1 21 | 22 | # ignore Autotools generated files 23 | /autom4te.cache/ 24 | /autoscan.log 25 | /configure.scan 26 | /config.log 27 | /config.status 28 | 29 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Reqflow development by: 2 | Frederic Hoerni 3 | 4 | Other contributors: 5 | Clément David 6 | Albert ARIBAUD (3ADEV) 7 | Henri GEIST 8 | Rolland Dudemaine 9 | 10 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | # Manage configure options 2 | AM_CPPFLAGS=-Wall 3 | AM_CFLAGS=-Wall 4 | AM_CXXFLAGS=-Wall 5 | AM_LDFLAGS= 6 | 7 | if GCOV_ENABLED 8 | AM_CFLAGS += -O0 -g3 -fprofile-arcs -ftest-coverage 9 | AM_CXXFLAGS += -O0 -g3 -fprofile-arcs -ftest-coverage 10 | AM_LDFLAGS += -lgcov 11 | endif 12 | 13 | if GPROF_ENABLED 14 | AM_CFLAGS += -O0 -g3 -pg -fprofile-arcs 15 | AM_CXXFLAGS += -O0 -g3 -pg -fprofile-arcs 16 | AM_LDFLAGS += -pg -lgcov 17 | endif 18 | 19 | if WINDOWS 20 | AM_CFLAGS += -static -static-libgcc 21 | AM_CFLAGS += -DZIP_EXTERN= -DZLIB_INTERNAL -DLIBXML_STATIC -DPCRE_STATIC -Dpoppler_cpp_EXPORTS 22 | 23 | AM_CXXFLAGS += -static -static-libgcc 24 | AM_CXXFLAGS += -DZIP_EXTERN= -DZLIB_INTERNAL -DLIBXML_STATIC -DPCRE_STATIC -Dpoppler_cpp_EXPORTS 25 | endif 26 | 27 | 28 | # Main program 29 | bin_PROGRAMS = reqflow 30 | reqflow_SOURCES = src/main.cpp \ 31 | src/logging.cpp \ 32 | src/dateTools.cpp \ 33 | src/parseConfig.cpp \ 34 | src/req.cpp \ 35 | src/ReqDocumentTxt.cpp \ 36 | src/ReqDocumentDocx.cpp \ 37 | src/ReqDocumentHtml.cpp \ 38 | src/stringTools.cpp \ 39 | src/renderingHtml.cpp \ 40 | src/ReqDocumentPdf.cpp 41 | 42 | reqflow_CPPFLAGS = @ZIP_CFLAGS@ @XML_CFLAGS@ @POPPLER_CFLAGS@ @PCRE_CFLAGS@ 43 | reqflow_LDADD = @ZIP_LIBS@ @XML_LIBS@ @POPPLER_LIBS@ @PCRE_LIBS@ 44 | 45 | # specific subdirs 46 | SUBDIRS = test 47 | 48 | # data 49 | dist_pkgdata_DATA = README COPYING NEWS ChangeLog AUTHORS 50 | 51 | # it will re-generate the ChangeLog file 52 | dist-hook: bin/gitlog2changelog.py 53 | bin/gitlog2changelog.py 54 | 55 | # Test sub-programs (will not be packaged) 56 | main_pdf_SOURCES = src/main_pdf.cpp 57 | main_pdf_CPPFLAGS = @POPPLER_CFLAGS@ 58 | main_pdf_LDADD = @POPPLER_LIBS@ 59 | 60 | main_regex_SOURCES = src/main_regex.c 61 | main_regex_CPPFLAGS = @PCRE_CFLAGS@ 62 | main_regex_LDADD = @PCRE_LIBS@ 63 | 64 | main_unzip_SOURCES = src/main_unzip.c 65 | main_unzip_CPPFLAGS = @ZIP_CFLAGS@ 66 | main_unzip_LDADD = @ZIP_LIBS@ 67 | 68 | main_xml_SOURCES = src/main_xml.c 69 | main_xml_CPPFLAGS = @XML_CFLAGS@ 70 | main_xml_LDADD = @XML_LIBS@ 71 | 72 | main_testStringCompare_SOURCES = src/main_testStringCompare.cpp \ 73 | src/stringTools.cpp 74 | main_testStringCompare_CPPFLAGS = @PCRE_CFLAGS@ 75 | main_testStringCompare_LDADD = @PCRE_LIBS@ 76 | 77 | noinst_PROGRAMS = main_pdf main_regex main_unzip main_xml main_testStringCompare 78 | 79 | # Windows installer 80 | if WINDOWS 81 | all-local: @PACKAGE_TARNAME@-@VERSION@-setup$(EXEEXT) 82 | 83 | @PACKAGE_TARNAME@-@VERSION@-setup$(EXEEXT): reqflow.iss reqflow$(EXEEXT) 84 | @STRIP@ reqflow$(EXEEXT) 85 | $(WINE) "@ISCC@" /q /dMyAppName=@PACKAGE_NAME@ /dMyAppVersion=@PACKAGE_VERSION@ /dMyAppExeName=reqflow$(EXEEXT) /f@PACKAGE_TARNAME@-@VERSION@-setup $< 86 | endif 87 | 88 | clean-local: 89 | rm -f @PACKAGE_TARNAME@-@VERSION@-setup$(EXEEXT) 90 | rm -f src/*.gcno src/*.gcda *.*.gcov 91 | 92 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Reqflow 1.6.0, 11 Mar 2019 2 | - Option -type accepts only the following arguments: txt, odt, docx, xml, html, pdf 3 | - When file type detection is based on the filename extension: 4 | * the detection is case insensitive 5 | * the known extensions are those accepted by -type, and "htm" 6 | * text is the default (when the extension is unkown) 7 | 8 | Reqflow 1.5.3, 2 Oct 2018 9 | - file extensions .ad, .adoc, .asc, .asciidoc, .md known as text documents 10 | 11 | Reqflow 1.5.2, 31 Oct 2017 12 | - option -end-req for marking end of text of a requirement 13 | - fix detection of duplicate reqs with -prefix-req 14 | - docx: ignore 'fallback', to prevent duplicates 15 | 16 | Reqflow 1.5.1, 13 Feb 2017 17 | - improve acquisition in HTML documents 18 | - fix analysis of second document when first document has -stop-after 19 | - option -prefix-req for prefixing acquired requirements 20 | 21 | Reqflow 1.5.0, 22 Nov 2016 22 | 23 | - resolve environment variable in .req config file: syntax $x or ${x} 24 | - fix buffer overflow in testRegex 25 | - fix acquisition of requirements wrt stop condition (docx) 26 | 27 | Reqflow 1.4.2, 13 Jun 2015 28 | 29 | - fix bug in capture of requirements from odt documents 30 | 31 | Reqflow 1.4.1, 8 Dec 2014 32 | 33 | - fix missing escaping of some HTML parts (HTML output format only) 34 | 35 | 36 | Reqflow 1.4.0, 30 Oct 2014 37 | 38 | - keep document order for the requirements. alphanumeric order is still 39 | possible with --sort in the .req file. 40 | 41 | Reqflow 1.3.4, 31 Jul 2014 42 | 43 | - [Windows only] fix multiple additions of reqflow path to system path 44 | when installed several times 45 | 46 | Reqflow 1.3.3, 16 May 2014 47 | 48 | - handle refs on same line as requirement 49 | - read config file from stdin if '-' 50 | - display all errors in the html report 51 | 52 | Reqflow 1.3.2 53 | 54 | - Executable renamed from 'req' to 'reqflow' 55 | - Fix acquisition of docx with deleted or moved text 56 | (tracked changes, revision marks) 57 | 58 | 59 | Reqflow v1.3.0, 6 Apr 2014 60 | 61 | direct opening of config file 62 | -type option in config file 63 | Windows installer 64 | 65 | 66 | Reqflow v1.2.1, 5 Mar 2014 67 | 68 | Capture text of requirements: req review 69 | Name reqflow 70 | 71 | 72 | Req v1.2, 19 Feb 2014 73 | 74 | Support for input documents HTML 75 | Support for input documents PDF on Windows 76 | HTML report: CSS styles improved 77 | 78 | 79 | Req v1.1 80 | 81 | Support for input documents ODT 82 | Configuration file syntax: keywords "define", "document" 83 | Config Option -nocov 84 | 85 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | 2 | This is Reqflow, a requirement traceability tool. 3 | 4 | See the file NEWS for the user-visible changes from previous releases. 5 | 6 | For general building and installation instructions, see the file INSTALL. 7 | 8 | Reqflow is free software. See the file COPYING for copying conditions. 9 | 10 | 11 | Overview 12 | -------- 13 | 14 | Reqflow is a free and open-source tool for tracing requirements across 15 | documents. 16 | 17 | To launch Reqflow: 18 | - create a file with a .req extension, as follows, 19 | - double-click it, 20 | - this will generate an HTML report and open it. 21 | 22 | Sample file 'test.req' 23 | 24 | define ALPHANUM [-a-zA-Z0-9_] 25 | define REQ_PATTERN "REQ_ALPHANUM+" 26 | define TST_PATTERN "TST_ALPHANUM+" 27 | define REF_PATTERN "Ref: (ALPHANUM+)" 28 | 29 | document SPEC -path SPEC.pdf -req REQ_PATTERN -stop-after Annex 30 | 31 | document TEST -path TEST.docx 32 | -req TST_PATTERN 33 | -ref REF_PATTERN 34 | -stop-after Annex 35 | -nocov 36 | 37 | 38 | Documentation and Downloading 39 | ----------------------------- 40 | 41 | See: http://goeb.github.io/reqflow 42 | 43 | 44 | System-specific Notes 45 | --------------------- 46 | 47 | Reqflow can be cross-compiled using the Mingw GNU toolchain. 48 | See dev/README-cross-libs.txt for guidance. 49 | 50 | -------------------------------------------------------------------------------- /bin/gitlog2changelog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # Copyright 2008 Marcus D. Hanwell 3 | # Distributed under the terms of the GNU General Public License v2 or later 4 | 5 | import string, re, os 6 | 7 | # Execute git log with the desired command line options. 8 | fin = os.popen('git log --summary --stat --no-merges --date=short', 'r') 9 | # Create a ChangeLog file in the current directory. 10 | fout = open('ChangeLog', 'w') 11 | 12 | # Set up the loop variables in order to locate the blocks we want 13 | authorFound = False 14 | dateFound = False 15 | messageFound = False 16 | filesFound = False 17 | message = "" 18 | messageNL = False 19 | files = "" 20 | prevAuthorLine = "" 21 | 22 | # The main part of the loop 23 | for line in fin: 24 | # The commit line marks the start of a new commit object. 25 | if string.find(line, 'commit') >= 0: 26 | # Start all over again... 27 | authorFound = False 28 | dateFound = False 29 | messageFound = False 30 | messageNL = False 31 | message = "" 32 | filesFound = False 33 | files = "" 34 | continue 35 | # Match the author line and extract the part we want 36 | elif re.match('Author:', line) >=0: 37 | authorList = re.split(': ', line, 1) 38 | author = authorList[1] 39 | author = author[0:len(author)-1] 40 | authorFound = True 41 | # Match the date line 42 | elif re.match('Date:', line) >= 0: 43 | dateList = re.split(': ', line, 1) 44 | date = dateList[1] 45 | date = date[0:len(date)-1] 46 | dateFound = True 47 | # The svn-id lines are ignored 48 | elif re.match(' git-svn-id:', line) >= 0: 49 | continue 50 | # The sign off line is ignored too 51 | elif re.search('Signed-off-by', line) >= 0: 52 | continue 53 | # Extract the actual commit message for this commit 54 | elif authorFound & dateFound & messageFound == False: 55 | # Find the commit message if we can 56 | if len(line) == 1: 57 | if messageNL: 58 | messageFound = True 59 | else: 60 | messageNL = True 61 | elif len(line) == 4: 62 | messageFound = True 63 | else: 64 | if len(message) == 0: 65 | message = message + line.strip() 66 | else: 67 | message = message + " " + line.strip() 68 | # If this line is hit all of the files have been stored for this commit 69 | elif re.search('files changed', line) >= 0: 70 | filesFound = True 71 | continue 72 | # Collect the files for this commit. FIXME: Still need to add +/- to files 73 | elif authorFound & dateFound & messageFound: 74 | fileList = re.split(' \| ', line, 2) 75 | if len(fileList) > 1: 76 | if len(files) > 0: 77 | files = files + ", " + fileList[0].strip() 78 | else: 79 | files = fileList[0].strip() 80 | # All of the parts of the commit have been found - write out the entry 81 | if authorFound & dateFound & messageFound & filesFound: 82 | # First the author line, only outputted if it is the first for that 83 | # author on this day 84 | authorLine = date + " " + author 85 | if len(prevAuthorLine) == 0: 86 | fout.write(authorLine + "\n") 87 | elif authorLine == prevAuthorLine: 88 | pass 89 | else: 90 | fout.write("\n" + authorLine + "\n") 91 | 92 | # Assemble the actual commit message line(s) and limit the line length 93 | # to 80 characters. 94 | commitLine = "* " + files + ": " + message 95 | i = 0 96 | commit = "" 97 | while i < len(commitLine): 98 | if len(commitLine) < i + 78: 99 | commit = commit + "\n " + commitLine[i:len(commitLine)] 100 | break 101 | index = commitLine.rfind(' ', i, i+78) 102 | if index > i: 103 | commit = commit + "\n " + commitLine[i:index] 104 | i = index+1 105 | else: 106 | commit = commit + "\n " + commitLine[i:78] 107 | i = i+79 108 | 109 | # Write out the commit line 110 | fout.write(commit + "\n") 111 | 112 | #Now reset all the variables ready for a new commit block. 113 | authorFound = False 114 | dateFound = False 115 | messageFound = False 116 | messageNL = False 117 | message = "" 118 | filesFound = False 119 | files = "" 120 | prevAuthorLine = authorLine 121 | 122 | # Close the input and output lines now that we are finished. 123 | fin.close() 124 | fout.close() 125 | -------------------------------------------------------------------------------- /bin/reqReport.bat: -------------------------------------------------------------------------------- 1 | 2 | req trac -x html -c conf.req > reqReport.html 3 | start reqReport.html 4 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for compilers which do not understand '-c -o'. 3 | 4 | scriptversion=2012-10-14.11; # UTC 5 | 6 | # Copyright (C) 1999-2014 Free Software Foundation, Inc. 7 | # Written by Tom Tromey . 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | # This file is maintained in Automake, please report 28 | # bugs to or send patches to 29 | # . 30 | 31 | nl=' 32 | ' 33 | 34 | # We need space, tab and new line, in precisely that order. Quoting is 35 | # there to prevent tools from complaining about whitespace usage. 36 | IFS=" "" $nl" 37 | 38 | file_conv= 39 | 40 | # func_file_conv build_file lazy 41 | # Convert a $build file to $host form and store it in $file 42 | # Currently only supports Windows hosts. If the determined conversion 43 | # type is listed in (the comma separated) LAZY, no conversion will 44 | # take place. 45 | func_file_conv () 46 | { 47 | file=$1 48 | case $file in 49 | / | /[!/]*) # absolute file, and not a UNC file 50 | if test -z "$file_conv"; then 51 | # lazily determine how to convert abs files 52 | case `uname -s` in 53 | MINGW*) 54 | file_conv=mingw 55 | ;; 56 | CYGWIN*) 57 | file_conv=cygwin 58 | ;; 59 | *) 60 | file_conv=wine 61 | ;; 62 | esac 63 | fi 64 | case $file_conv/,$2, in 65 | *,$file_conv,*) 66 | ;; 67 | mingw/*) 68 | file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` 69 | ;; 70 | cygwin/*) 71 | file=`cygpath -m "$file" || echo "$file"` 72 | ;; 73 | wine/*) 74 | file=`winepath -w "$file" || echo "$file"` 75 | ;; 76 | esac 77 | ;; 78 | esac 79 | } 80 | 81 | # func_cl_dashL linkdir 82 | # Make cl look for libraries in LINKDIR 83 | func_cl_dashL () 84 | { 85 | func_file_conv "$1" 86 | if test -z "$lib_path"; then 87 | lib_path=$file 88 | else 89 | lib_path="$lib_path;$file" 90 | fi 91 | linker_opts="$linker_opts -LIBPATH:$file" 92 | } 93 | 94 | # func_cl_dashl library 95 | # Do a library search-path lookup for cl 96 | func_cl_dashl () 97 | { 98 | lib=$1 99 | found=no 100 | save_IFS=$IFS 101 | IFS=';' 102 | for dir in $lib_path $LIB 103 | do 104 | IFS=$save_IFS 105 | if $shared && test -f "$dir/$lib.dll.lib"; then 106 | found=yes 107 | lib=$dir/$lib.dll.lib 108 | break 109 | fi 110 | if test -f "$dir/$lib.lib"; then 111 | found=yes 112 | lib=$dir/$lib.lib 113 | break 114 | fi 115 | if test -f "$dir/lib$lib.a"; then 116 | found=yes 117 | lib=$dir/lib$lib.a 118 | break 119 | fi 120 | done 121 | IFS=$save_IFS 122 | 123 | if test "$found" != yes; then 124 | lib=$lib.lib 125 | fi 126 | } 127 | 128 | # func_cl_wrapper cl arg... 129 | # Adjust compile command to suit cl 130 | func_cl_wrapper () 131 | { 132 | # Assume a capable shell 133 | lib_path= 134 | shared=: 135 | linker_opts= 136 | for arg 137 | do 138 | if test -n "$eat"; then 139 | eat= 140 | else 141 | case $1 in 142 | -o) 143 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 144 | eat=1 145 | case $2 in 146 | *.o | *.[oO][bB][jJ]) 147 | func_file_conv "$2" 148 | set x "$@" -Fo"$file" 149 | shift 150 | ;; 151 | *) 152 | func_file_conv "$2" 153 | set x "$@" -Fe"$file" 154 | shift 155 | ;; 156 | esac 157 | ;; 158 | -I) 159 | eat=1 160 | func_file_conv "$2" mingw 161 | set x "$@" -I"$file" 162 | shift 163 | ;; 164 | -I*) 165 | func_file_conv "${1#-I}" mingw 166 | set x "$@" -I"$file" 167 | shift 168 | ;; 169 | -l) 170 | eat=1 171 | func_cl_dashl "$2" 172 | set x "$@" "$lib" 173 | shift 174 | ;; 175 | -l*) 176 | func_cl_dashl "${1#-l}" 177 | set x "$@" "$lib" 178 | shift 179 | ;; 180 | -L) 181 | eat=1 182 | func_cl_dashL "$2" 183 | ;; 184 | -L*) 185 | func_cl_dashL "${1#-L}" 186 | ;; 187 | -static) 188 | shared=false 189 | ;; 190 | -Wl,*) 191 | arg=${1#-Wl,} 192 | save_ifs="$IFS"; IFS=',' 193 | for flag in $arg; do 194 | IFS="$save_ifs" 195 | linker_opts="$linker_opts $flag" 196 | done 197 | IFS="$save_ifs" 198 | ;; 199 | -Xlinker) 200 | eat=1 201 | linker_opts="$linker_opts $2" 202 | ;; 203 | -*) 204 | set x "$@" "$1" 205 | shift 206 | ;; 207 | *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) 208 | func_file_conv "$1" 209 | set x "$@" -Tp"$file" 210 | shift 211 | ;; 212 | *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) 213 | func_file_conv "$1" mingw 214 | set x "$@" "$file" 215 | shift 216 | ;; 217 | *) 218 | set x "$@" "$1" 219 | shift 220 | ;; 221 | esac 222 | fi 223 | shift 224 | done 225 | if test -n "$linker_opts"; then 226 | linker_opts="-link$linker_opts" 227 | fi 228 | exec "$@" $linker_opts 229 | exit 1 230 | } 231 | 232 | eat= 233 | 234 | case $1 in 235 | '') 236 | echo "$0: No command. Try '$0 --help' for more information." 1>&2 237 | exit 1; 238 | ;; 239 | -h | --h*) 240 | cat <<\EOF 241 | Usage: compile [--help] [--version] PROGRAM [ARGS] 242 | 243 | Wrapper for compilers which do not understand '-c -o'. 244 | Remove '-o dest.o' from ARGS, run PROGRAM with the remaining 245 | arguments, and rename the output as expected. 246 | 247 | If you are trying to build a whole package this is not the 248 | right script to run: please start by reading the file 'INSTALL'. 249 | 250 | Report bugs to . 251 | EOF 252 | exit $? 253 | ;; 254 | -v | --v*) 255 | echo "compile $scriptversion" 256 | exit $? 257 | ;; 258 | cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) 259 | func_cl_wrapper "$@" # Doesn't return... 260 | ;; 261 | esac 262 | 263 | ofile= 264 | cfile= 265 | 266 | for arg 267 | do 268 | if test -n "$eat"; then 269 | eat= 270 | else 271 | case $1 in 272 | -o) 273 | # configure might choose to run compile as 'compile cc -o foo foo.c'. 274 | # So we strip '-o arg' only if arg is an object. 275 | eat=1 276 | case $2 in 277 | *.o | *.obj) 278 | ofile=$2 279 | ;; 280 | *) 281 | set x "$@" -o "$2" 282 | shift 283 | ;; 284 | esac 285 | ;; 286 | *.c) 287 | cfile=$1 288 | set x "$@" "$1" 289 | shift 290 | ;; 291 | *) 292 | set x "$@" "$1" 293 | shift 294 | ;; 295 | esac 296 | fi 297 | shift 298 | done 299 | 300 | if test -z "$ofile" || test -z "$cfile"; then 301 | # If no '-o' option was seen then we might have been invoked from a 302 | # pattern rule where we don't need one. That is ok -- this is a 303 | # normal compilation that the losing compiler can handle. If no 304 | # '.c' file was seen then we are probably linking. That is also 305 | # ok. 306 | exec "$@" 307 | fi 308 | 309 | # Name of file we expect compiler to create. 310 | cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` 311 | 312 | # Create the lock directory. 313 | # Note: use '[/\\:.-]' here to ensure that we don't use the same name 314 | # that we are using for the .o file. Also, base the name on the expected 315 | # object file name, since that is what matters with a parallel build. 316 | lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d 317 | while true; do 318 | if mkdir "$lockdir" >/dev/null 2>&1; then 319 | break 320 | fi 321 | sleep 1 322 | done 323 | # FIXME: race condition here if user kills between mkdir and trap. 324 | trap "rmdir '$lockdir'; exit 1" 1 2 15 325 | 326 | # Run the compile. 327 | "$@" 328 | ret=$? 329 | 330 | if test -f "$cofile"; then 331 | test "$cofile" = "$ofile" || mv "$cofile" "$ofile" 332 | elif test -f "${cofile}bj"; then 333 | test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" 334 | fi 335 | 336 | rmdir "$lockdir" 337 | exit $ret 338 | 339 | # Local Variables: 340 | # mode: shell-script 341 | # sh-indentation: 2 342 | # eval: (add-hook 'write-file-hooks 'time-stamp) 343 | # time-stamp-start: "scriptversion=" 344 | # time-stamp-format: "%:y-%02m-%02d.%02H" 345 | # time-stamp-time-zone: "UTC" 346 | # time-stamp-end: "; # UTC" 347 | # End: 348 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #undef HAVE_FCNTL_H 5 | 6 | /* Define to 1 if you have the `gettimeofday' function. */ 7 | #undef HAVE_GETTIMEOFDAY 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_INTTYPES_H 11 | 12 | /* Define to 1 if you have the `localtime_r' function. */ 13 | #undef HAVE_LOCALTIME_R 14 | 15 | /* Define to 1 if your system has a GNU libc compatible `malloc' function, and 16 | to 0 otherwise. */ 17 | #undef HAVE_MALLOC 18 | 19 | /* Define to 1 if you have the header file. */ 20 | #undef HAVE_MEMORY_H 21 | 22 | /* Define to 1 if you have the `regcomp' function. */ 23 | #undef HAVE_REGCOMP 24 | 25 | /* Define to 1 if you have the header file. */ 26 | #undef HAVE_STDINT_H 27 | 28 | /* Define to 1 if you have the header file. */ 29 | #undef HAVE_STDLIB_H 30 | 31 | /* Define to 1 if you have the `strcasecmp' function. */ 32 | #undef HAVE_STRCASECMP 33 | 34 | /* Define to 1 if you have the `strchr' function. */ 35 | #undef HAVE_STRCHR 36 | 37 | /* Define to 1 if you have the `strerror' function. */ 38 | #undef HAVE_STRERROR 39 | 40 | /* Define to 1 if you have the header file. */ 41 | #undef HAVE_STRINGS_H 42 | 43 | /* Define to 1 if you have the header file. */ 44 | #undef HAVE_STRING_H 45 | 46 | /* Define to 1 if you have the `strstr' function. */ 47 | #undef HAVE_STRSTR 48 | 49 | /* Define to 1 if you have the `strtoul' function. */ 50 | #undef HAVE_STRTOUL 51 | 52 | /* Define to 1 if you have the header file. */ 53 | #undef HAVE_SYS_STAT_H 54 | 55 | /* Define to 1 if you have the header file. */ 56 | #undef HAVE_SYS_TIME_H 57 | 58 | /* Define to 1 if you have the header file. */ 59 | #undef HAVE_SYS_TYPES_H 60 | 61 | /* Define to 1 if you have the header file. */ 62 | #undef HAVE_UNISTD_H 63 | 64 | /* Define to 1 if the system has the type `_Bool'. */ 65 | #undef HAVE__BOOL 66 | 67 | /* Name of package */ 68 | #undef PACKAGE 69 | 70 | /* Define to the address where bug reports for this package should be sent. */ 71 | #undef PACKAGE_BUGREPORT 72 | 73 | /* Define to the full name of this package. */ 74 | #undef PACKAGE_NAME 75 | 76 | /* Define to the full name and version of this package. */ 77 | #undef PACKAGE_STRING 78 | 79 | /* Define to the one symbol short name of this package. */ 80 | #undef PACKAGE_TARNAME 81 | 82 | /* Define to the home page for this package. */ 83 | #undef PACKAGE_URL 84 | 85 | /* Define to the version of this package. */ 86 | #undef PACKAGE_VERSION 87 | 88 | /* Define to 1 if you have the ANSI C header files. */ 89 | #undef STDC_HEADERS 90 | 91 | /* Version number of package */ 92 | #undef VERSION 93 | 94 | /* Define to `__inline__' or `__inline' if that's what the C compiler 95 | calls it, or to nothing if 'inline' is not supported under any name. */ 96 | #ifndef __cplusplus 97 | #undef inline 98 | #endif 99 | 100 | /* Define to rpl_malloc if the replacement function should be used. */ 101 | #undef malloc 102 | 103 | /* Define to `int' if does not define. */ 104 | #undef mode_t 105 | 106 | /* Define to `unsigned int' if does not define. */ 107 | #undef size_t 108 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_PREREQ([2.63]) 5 | AC_INIT([Reqflow], [1.6.0], [], [reqflow], [http://goeb.github.io/reqflow]) 6 | AC_CONFIG_HEADERS([src/config.h]) 7 | AC_CANONICAL_TARGET 8 | AM_INIT_AUTOMAKE([-Wall -Werror subdir-objects]) 9 | 10 | # Set a OS specific settings 11 | WINDOWS=no 12 | MINGW=no 13 | CYGWIN=no 14 | case $target_os in 15 | *linux*) 16 | ;; 17 | *darwin*) 18 | ;; 19 | GNU/kFreeBSD) 20 | ;; 21 | *mingw*) 22 | WINDOWS=yes 23 | MINGW=yes 24 | ;; 25 | *cygwin*) 26 | WINDOWS=yes 27 | CYGWIN=yes 28 | ;; 29 | GNU) 30 | ;; 31 | esac 32 | AM_CONDITIONAL(WINDOWS, test x$WINDOWS = xyes) 33 | AM_CONDITIONAL(CYGWIN, test x$MINGW = xyes) 34 | AM_CONDITIONAL(MINGW, test x$MINGW = xyes) 35 | 36 | # Checks for programs. 37 | AC_PROG_CXX 38 | AC_PROG_CC 39 | AM_PROG_CC_C_O 40 | 41 | # Checks for external libraries. 42 | PKG_PROG_PKG_CONFIG() 43 | if test x$WINDOWS = xyes; then 44 | PKG_CONFIG="$PKG_CONFIG --static" 45 | fi 46 | PKG_CHECK_MODULES(ZIP, libzip) 47 | PKG_CHECK_MODULES(XML, libxml-2.0) 48 | PKG_CHECK_MODULES(POPPLER, [poppler-cpp]) 49 | PKG_CHECK_MODULES(PCRE, [libpcreposix]) 50 | 51 | AC_ARG_ENABLE([gcov], 52 | [AS_HELP_STRING([--enable-gcov], 53 | [Enable test suite code coverage])]) 54 | AM_CONDITIONAL([GCOV_ENABLED],[test x$enable_gcov = xyes]) 55 | AC_ARG_ENABLE([gprof], 56 | [AS_HELP_STRING([--enable-gprof], 57 | [Enable test suite code profiling])]) 58 | AM_CONDITIONAL([GPROF_ENABLED],[test x$enable_gprof = xyes]) 59 | if test x$WINDOWS = xyes; then 60 | AC_ARG_VAR([WINE], [Wine translator, used to run Inno Setup]) 61 | AC_CHECK_PROG(WINE, wine, wine) 62 | if test -z "$WINE" ; then 63 | AC_MSG_ERROR([Please install wine before cross-compiling.]) 64 | fi 65 | 66 | ISCC="$(find ~/.wine/drive_c -type f -name ISCC.exe)" 67 | if test -z "$ISCC" ; then 68 | AC_MSG_ERROR([Please install Inno Setup into wine before cross-compiling.]) 69 | fi 70 | AC_SUBST(ISCC) 71 | fi 72 | 73 | # Checks for header files. 74 | AC_CHECK_HEADERS([fcntl.h stdint.h stdlib.h string.h sys/time.h unistd.h]) 75 | 76 | # Checks for typedefs, structures, and compiler characteristics. 77 | AC_C_INLINE 78 | AC_TYPE_MODE_T 79 | AC_TYPE_SIZE_T 80 | 81 | # Checks for library functions. 82 | AC_CHECK_FUNCS([gettimeofday localtime regcomp strcasecmp strchr strerror strstr strtoul]) 83 | 84 | AC_CONFIG_FILES([Makefile test/Makefile test/envtest reqflow.iss]) 85 | AC_OUTPUT 86 | 87 | -------------------------------------------------------------------------------- /dev/README-cross-libs.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Platform for building Windows release from my Linux host 4 | (Frederic Hoerni, 22 Nov 2016) 5 | 6 | This README shortly explains how I have setup on my platform 7 | the cross-compiled libraries needed for Reqflow. 8 | 9 | My development platform is a Linux Mint 32 bit host. 10 | 11 | See also the script win32env in the same directory, that refers to these 12 | libraries for building Reqflow. 13 | 14 | ## Linux packages 15 | 16 | gcc-mingw-w64-i686 17 | win-iconv-mingw-w64-dev 18 | 19 | ## libpcre 20 | 21 | LIBPCRE=$HOME/Downloads/pcre-8.34/.libs 22 | 23 | Built with: 24 | 25 | $ ./configure --host=i586-mingw32msvc CFLAGS=-DPCRE_STATIC --enable-shared=no 26 | 27 | 28 | ## libxml2 29 | 30 | LIBXML=$HOME/Downloads/libxml2-2.9.1 31 | 32 | Built with: 33 | 34 | $ ./configure --host=i586-mingw32msvc --without-http --without-python --without-ftp 35 | 36 | 37 | ## libzip 38 | 39 | LIBZIP=$HOME/Downloads/libzip-0.11.2 40 | 41 | Built with: 42 | 43 | $ ./configure --host=i586-mingw32msvc LIBS=$HOME/Downloads/zlib-1.2.8/libz.a --with-zlib=$HOME/Downloads/zlib-1.2.8 44 | 45 | 46 | ## zlib 47 | 48 | LIBZ=$HOME/Downloads/zlib-1.2.8 49 | 50 | 51 | ## poppler 52 | LIBPOPPLER=$HOME/win32libs/poppler-0.24.5 53 | 54 | Built with: 55 | 56 | ./configure --host=i686-w64-mingw32 --prefix=/home/fred/win32libs/poppler-0.48.0 --disable-libopenjpeg --disable-libtiff --disable-libcurl --disable-libjpeg --disable-libpng --disable-splash-output --disable-cairo-output --disable-poppler-glib --disable-gtk-doc-html --disable-poppler-qt4 --disable-poppler-qt5 --disable-gtk-test --without-x FREETYPE_CFLAGS=-I/home/fred/win32libs/freetype-2.5.2/include FREETYPE_LIBS=-L/home/fred/win32libs/freetype-2.5.2/lib -lfreetype 57 | 58 | 59 | ## Inno Setup 60 | 61 | Inno Setup installed on my Linux host via wine. 62 | 63 | 64 | -------------------------------------------------------------------------------- /dev/TEMPLATE.rqtf: -------------------------------------------------------------------------------- 1 | # sample file from another tool 2 | 3 | [Files] 4 | Names=Document1 5 | 6 | [Document1] 7 | GraphicPosition=1950@1070 8 | Type=Text 9 | Path=document 10 | 11 | -------------------------------------------------------------------------------- /dev/TODO: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8. latin1/utf8 (dans le .conf) 5 | 6 | 9. -prefix dans le .conf 7 | 8 | 10. enable multi -req options in conf file 9 | 10 | addFile x -path x.txt -req 1. -req 2. etc. 11 | 12 | 12. document made of several files (recursive search in sub-directories 13 | 14 | 13. deal with filename in cp1252 and HTMl in utf8 15 | 16 | 14. enable export format semi-colon separated value (scsv) 17 | -------------------------------------------------------------------------------- /dev/req.config: -------------------------------------------------------------------------------- 1 | // ADD PREDEFINED MACROS HERE! 2 | -------------------------------------------------------------------------------- /dev/req.creator: -------------------------------------------------------------------------------- 1 | [General] 2 | -------------------------------------------------------------------------------- /dev/req.files: -------------------------------------------------------------------------------- 1 | ../src/dateTools.cpp 2 | ../src/dateTools.h 3 | ../src/global.h 4 | ../src/logging.cpp 5 | ../src/logging.h 6 | ../src/main.cpp 7 | ../src/parseConfig.cpp 8 | ../src/parseConfig.h 9 | ../src/pdf.cpp 10 | ../src/regex.c 11 | ../src/renderingHtml.cpp 12 | ../src/renderingHtml.h 13 | ../src/req.cpp 14 | ../src/req.h 15 | ../src/ReqDocumentDocx.cpp 16 | ../src/ReqDocumentDocx.h 17 | ../src/ReqDocumentPdf.cpp 18 | ../src/ReqDocumentPdf.h 19 | ../src/ReqDocumentTxt.cpp 20 | ../src/ReqDocumentTxt.h 21 | ../src/unzip.c 22 | ../src/xml.c 23 | ../src/ReqDocumentHtml.h 24 | ../src/ReqDocumentHtml.cpp 25 | ../src/stringTools.h 26 | ../src/stringIt.h 27 | ../src/stringTools.cpp 28 | ../src/StringIt.h 29 | ../src/StringIt.cpp 30 | -------------------------------------------------------------------------------- /dev/req.includes: -------------------------------------------------------------------------------- 1 | ../src 2 | ../build_linux86/src 3 | -------------------------------------------------------------------------------- /dev/win32env: -------------------------------------------------------------------------------- 1 | 2 | WIN32LIBS=$HOME/win32libs 3 | 4 | export PCRE_CFLAGS="-I$WIN32LIBS/include -DPCRE_STATIC" 5 | export PCRE_LIBS="-L$WIN32LIBS/lib -lpcreposix -lpcre" 6 | 7 | export XML_CFLAGS="-DLIBXML_STATIC -I$WIN32LIBS/include/libxml2" 8 | export XML_LIBS="-L$WIN32LIBS/lib -lxml2" 9 | 10 | export ZIP_CFLAGS="-DZLIB_INTERNAL -DZIP_EXTERN= -I$WIN32LIBS/include -I$WIN32LIBS/lib/libzip/include" 11 | export ZIP_LIBS="-L$WIN32LIBS/lib -lzip -lz" 12 | 13 | export POPPLER_CFLAGS="-I$WIN32LIBS/include -Dpoppler_cpp_EXPORTS" 14 | export POPPLER_LIBS="-L$WIN32LIBS/lib -lpoppler-cpp -lpoppler -liconv" 15 | 16 | export LDFLAGS="-lws2_32 -lgdi32 -Wl,-Bstatic" 17 | 18 | set -e 19 | cd ../build_win 20 | ../configure --host=i686-w64-mingw32 --prefix=/tmp/reqflow-mingw32 21 | make 22 | make check 23 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Generate HTML pages with a menu 2 | 3 | SRCS += index.md 4 | SRCS += capture.md 5 | 6 | BUILD_DIR=. 7 | 8 | HTMLS = $(SRCS:%.md=%.html) 9 | 10 | DEPENDS = header.html footer.html gen_menu.sh 11 | 12 | all: $(HTMLS) 13 | 14 | %.html: %.md $(DEPENDS) $(SRCS) 15 | sh gen_menu.sh --header header.html --footer footer.html --page $< -- $(SRCS) > $@ 16 | 17 | clean: 18 | rm $(HTMLS) 19 | -------------------------------------------------------------------------------- /docs/SPEC.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/SPEC.docx -------------------------------------------------------------------------------- /docs/TEST.txt: -------------------------------------------------------------------------------- 1 | 2 | # Test plan: 3 | 4 | ## Tests cases 5 | 6 | T_01 7 | Send command printf --help 8 | Check that the result is a help message. 9 | Ref: PRINTF_01, PRINTF_01a, PRINTF_01b 10 | Ref: PRINTF_333 11 | 12 | 13 | T_02 14 | Send command `printf "(%04d%-4s)\n" 33 aa` 15 | Check that the result is: (0033aa ) 16 | Check that the exit code is zero. 17 | Ref: PRINTF_02 18 | Ref: PRINTF_03, PRINTF_03a, PRINTF_03b 19 | 20 | 21 | T_05 22 | Send command printf x%r 23 | Check that an error is raised and that the exit code is 1 24 | Ref: PRINTF_03 25 | 26 | T_21 27 | Send command `which printf` 28 | Check that printf is installed in /usr/bin/printf 29 | Ref: PRINTF_06, PRINTF_12 30 | Ref: PRINTF_15 31 | 32 | T_22 33 | This is test 22. 34 | Ref: PRINTF_15 35 | Ref: PRINTF_20 36 | 37 | ## Annex: summary of tests 38 | 39 | T_01 40 | T_02 41 | T_05 42 | T_21 43 | 44 | 45 | -------------------------------------------------------------------------------- /docs/capture.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Capture Algorithm 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 |
14 | 24 |
25 |

Capture Algorithm

26 |

Reqflow parses documents sequentially and works line by line.

27 |

Reqflow considers the following as a single line:

28 |
    29 |
  • a line of a raw text or PDF document
  • 30 |
  • a <p> paragraph of an XML based document (HTML, docx, odt)
  • 31 |
32 |

Reqflow expects the document to be structured as a sequence of requirements with mixed text, where a requirement REQ is structured as follows:

33 |
REQ        := LINE_REQ
34 |               [ LINES_TEXT ]
35 |               [ REFS ]
36 | 
37 | LINE_REQ   := REQ_ID [ REFS ]
38 | 
39 | REQ_ID     := the unique identifier of the requirement
40 | 
41 | LINES_TEXT := some text, on one or more lines
42 | 
43 | REFS       := REF [ REF ... ]
44 | 
45 | REF        := the unique identifier of a reference
46 | 
47 |

As a result:

48 |
    49 |
  • a REQ_ID is always before its REF.
  • 50 |
  • a REF is always associated to the REQ_ID before it
  • 51 |
52 |

The Reqflow parameters are as follows:

53 |
    54 |
  • -req tells how to capture the REQ. Parentheses may be used to identify REQ inside a broader expression. 55 |
      56 |
    • Eg: <(REQ_[-a-zA-Z_0-9]*)> for matching <REQ_123> and extracting REQ_123
    • 57 |
  • 58 |
  • -ref tells how to capture the REFS. Parentheses may be used to identify one or more REFS inside a broader expression. 59 |
      60 |
    • Eg: Ref:[, ]*(REF_[0-9]+) for matching Ref: REF_01, REF_02, REF_03 and extracting REF_01, REF_02, REF_03
    • 61 |
    • Eg: REF_[0-9]+ for matching REF_01, and extracting the same.
    • 62 |
  • 63 |
  • -end-req tells where the capture of the text of the requirement shall end
  • 64 |
65 |
66 |
67 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /docs/capture.md: -------------------------------------------------------------------------------- 1 | 2 | # Capture Algorithm 3 | 4 | Reqflow parses documents sequentially and works line by line. 5 | 6 | Reqflow considers the following as a single line: 7 | 8 | * a line of a raw text or PDF document 9 | * a `

` paragraph of an XML based document (HTML, docx, odt) 10 | 11 | Reqflow expects the document to be structured as a sequence of requirements with mixed text, where a requirement REQ is structured as follows: 12 | 13 | 14 | ``` 15 | REQ := LINE_REQ 16 | [ LINES_TEXT ] 17 | [ REFS ] 18 | 19 | LINE_REQ := REQ_ID [ REFS ] 20 | 21 | REQ_ID := the unique identifier of the requirement 22 | 23 | LINES_TEXT := some text, on one or more lines 24 | 25 | REFS := REF [ REF ... ] 26 | 27 | REF := the unique identifier of a reference 28 | 29 | ``` 30 | 31 | As a result: 32 | 33 | * a REQ_ID is always before its REF. 34 | * a REF is always associated to the REQ_ID before it 35 | 36 | 37 | The Reqflow parameters are as follows: 38 | 39 | * `-req` tells how to capture the REQ. Parentheses may be used to identify REQ inside a broader expression. 40 | * Eg: `<(REQ_[-a-zA-Z_0-9]*)>` for matching `` and extracting `REQ_123` 41 | * `-ref` tells how to capture the REFS. Parentheses may be used to identify one or more REFS inside a broader expression. 42 | * Eg: `Ref:[, ]*(REF_[0-9]+)` for matching `Ref: REF_01, REF_02, REF_03` and extracting `REF_01`, `REF_02`, `REF_03` 43 | * Eg: `REF_[0-9]+` for matching `REF_01`, and extracting the same. 44 | * `-end-req` tells where the capture of the text of the requirement shall end 45 | 46 | 47 | -------------------------------------------------------------------------------- /docs/download/req-v1.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/req-v1.0.zip -------------------------------------------------------------------------------- /docs/download/req-v1.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/req-v1.1.zip -------------------------------------------------------------------------------- /docs/download/req-v1.2.0.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/req-v1.2.0.zip -------------------------------------------------------------------------------- /docs/download/reqflow-1.3.0-setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-1.3.0-setup.exe -------------------------------------------------------------------------------- /docs/download/reqflow-1.3.1-setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-1.3.1-setup.exe -------------------------------------------------------------------------------- /docs/download/reqflow-1.3.2-setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-1.3.2-setup.exe -------------------------------------------------------------------------------- /docs/download/reqflow-1.3.3-setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-1.3.3-setup.exe -------------------------------------------------------------------------------- /docs/download/reqflow-1.3.4-setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-1.3.4-setup.exe -------------------------------------------------------------------------------- /docs/download/reqflow-1.4.0-setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-1.4.0-setup.exe -------------------------------------------------------------------------------- /docs/download/reqflow-1.4.1-setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-1.4.1-setup.exe -------------------------------------------------------------------------------- /docs/download/reqflow-1.4.2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-1.4.2 -------------------------------------------------------------------------------- /docs/download/reqflow-1.4.2-setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-1.4.2-setup.exe -------------------------------------------------------------------------------- /docs/download/reqflow-1.5.0-setup.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-1.5.0-setup.exe -------------------------------------------------------------------------------- /docs/download/reqflow-v1.2.1.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/docs/download/reqflow-v1.2.1.zip -------------------------------------------------------------------------------- /docs/footer.html: -------------------------------------------------------------------------------- 1 | 2 |

7 | 8 | 9 | -------------------------------------------------------------------------------- /docs/gen_menu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | usage() { 4 | echo "usage: gen_menu.sh --header --footer --page

-- ..." 5 | echo "" 6 | echo "Generate an HTML page from a header, footer, main contents page, and" 7 | echo "generate a menu that links to other pages ..." 8 | echo "" 9 | echo " --page

Select file

for the main contents of the page." 10 | echo "" 11 | echo " ... All the pages used for generating the menu." 12 | echo " The page

should generally be in this list." 13 | exit 1 14 | } 15 | 16 | get_title() { 17 | file="$1" 18 | extension=`echo $file | sed -e "s/.*\.//"` 19 | if [ "$extension" != "md" ]; then 20 | echo "Unsupported extension '$extension' (supported: md)" 21 | exit 1 22 | fi 23 | TITLE=`grep -m 1 "^#" "$file" | pandoc | grep "^;;" -e "s;.*>;;"` 24 | printf "$TITLE" 25 | } 26 | 27 | # generate menu with entries h2 in the same page 28 | generate_menu_L2() { 29 | currentFile="$1" 30 | echo "

" 37 | } 38 | 39 | # generate_menu current-page all-pages ... 40 | generate_menu() { 41 | currentFile="$1" 42 | shift 43 | 44 | echo "" 66 | } 67 | 68 | # main ################## 69 | 70 | while [ "$1" != "--" -a "$1" != "" ]; do 71 | case "$1" in 72 | --header) HEADER="$2"; shift 2;; 73 | --footer) FOOTER="$2"; shift 2;; 74 | --page) PAGE="$2"; shift 2;; 75 | esac 76 | done 77 | 78 | shift # remove the -- 79 | 80 | if [ -z "$HEADER" ]; then usage; fi 81 | if [ -z "$FOOTER" ]; then usage; fi 82 | if [ -z "$PAGE" ]; then usage; fi 83 | 84 | # start outputting HTML 85 | 86 | TITLE=`grep -m 1 "^#" "$PAGE" | pandoc | grep "^;;" -e "s;.*>;;"` 87 | sed -e "s;__TITLE__;$TITLE;g" < "$HEADER" 88 | 89 | generate_menu "$PAGE" $@ 90 | 91 | # generate contents 92 | echo "
" 93 | pandoc < $PAGE 94 | echo "
" 95 | 96 | sed -e "s;__DATE__;`date '+%e %b %Y'`;" < "$FOOTER" 97 | -------------------------------------------------------------------------------- /docs/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | __TITLE__ 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 |
14 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Reqflow 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 |
13 |
14 | 33 |
34 |

Reqflow

35 |

Reqflow is a free and open-source tool for traceability of requirements across documents, designed to analyse documents with speed and efficiency.

36 |

News

37 |
    38 |
  • 11 Mar 2019: Reqflow v1.6.0 (see Changes)
  • 39 |
  • 2 Oct 2018: Reqflow v1.5.3
  • 40 |
  • 31 Oct 2017 Reqflow v1.5.2
  • 41 |
  • 13 Feb 2017 Reqflow v1.5.1
  • 42 |
  • 22 Nov 2016: Reqflow v1.5.0
  • 43 |
44 |

Supported Formats

45 |

Input formats

46 |
    47 |
  • docx (Open Xml)
  • 48 |
  • odt (Open Document)
  • 49 |
  • HTML
  • 50 |
  • PDF
  • 51 |
  • text (default)
  • 52 |
53 |

Output formats

54 |
    55 |
  • text
  • 56 |
  • CSV
  • 57 |
  • HTML
  • 58 |
59 |

Example of Report

60 |

No screenshot, but an example: reqReport.html

61 |

Download

62 |

Linux

63 |

Build From Source :

64 |
git clone https://github.com/goeb/reqflow.git
 65 | cd reqflow
 66 | ./configure
 67 | make
 68 | cd test && ../reqflow stat -s
69 |

Windows

70 |

Latest stable:

71 | 74 |

Previous versions:

75 | 80 |

Usage

81 |
Usage: 1. reqflow <command> [<options>] [<args>]
 82 |        2. reqflow <config-file>
 83 | 
 84 | 
 85 | 1. reqflow <command> [<options>] [<args>]
 86 | 
 87 | Commands:
 88 | 
 89 |     stat [doc ...]  Print the status of requirements in all documents or the
 90 |                     given documents. Without additionnal option, only
 91 |                     unresolved coverage issues are reported.
 92 |          -s         Print a one-line summary for each document.
 93 |          -v         Print the status of all requirements.
 94 |                     Status codes:
 95 | 
 96 |                       'U'  Uncovered
 97 | 
 98 |     trac [doc ...]  Print the traceability matrix of the requirements 
 99 |                     (A covered by B).
100 |          [-r]       Print the reverse traceability matrix (A covers B).
101 |          [-x <fmt>] Select export format: text (default), csv, html.
102 |                     If format 'html' is chosen, -r is ignored, as both foward
103 |                     and reverse traceability matrices are displayed.
104 | 
105 |     review          Print the requirements with their text.
106 |          [-f | -r]  Print also traceability (forward or backward)
107 |          [-x <fmt>] Choose format: txt, csv.
108 | 
109 |     config          Print the list of configured documents.
110 | 
111 |     debug <file>    Dump text extracted from file (debug purpose).
112 | 
113 |     regex <pattern> [<text>]
114 |                     Test regex given by <pattern> applied on <text>.
115 |                     If <text> is omitted, then the text is read from stdin.
116 | 
117 |     version
118 |     help
119 | 
120 | Options:
121 |     -c <config>  Select configuration file. Defaults to 'conf.req'.
122 |     -o <file>    Output to file instead of stdout.
123 |                  Not supported for commands 'config', debug' and 'regex'.
124 | 
125 | 2. reqflow <config>
126 | This is equivalent to:
127 |     reqflow trac -c <config> -x html -o <outfile> && start <outfile>
128 | 
129 | Purpose: This usage is suitable for double-cliking on the config file.
130 | Note: <config> must be different from the commands of use case 1.
131 |

Sample Configuration File

132 |

conf.req

133 |
# document <document-id> -path <document-path> -req <pattern> \
134 | #          [-stop-after <pattern>] [-ref <pattern>] [-start-after <pattern>] \
135 | #          [-nocov]
136 | #
137 | # <pattern> must be a Perl Compatible Regular Expression (PCRE)
138 | # -req indicates how the requirements must be captured
139 | # -ref indicates how the referenced requirements must be captured
140 | # 
141 | # Keyword 'define' may be used to define values:
142 | # 
143 | #   define PATH
144 | #   document x -path PATH/x.txt
145 | #   document y -path PATH/y.txt
146 | 
147 | document SPEC -path SPEC.docx -req REQ_[-a-zA-Z0-9_]* -stop-after Annex
148 | document TEST -path TEST.txt \
149 |     -req T_[-a-zA-Z0-9_]* \
150 |     -ref "Ref:  *(.*)" \
151 |     -stop-after "Annex" \
152 |     -start-after "Tests cases" \
153 |     -nocov -sort alphanum
154 | 
155 | # CSS for HTML output (optional)
156 | htmlcss style.css
157 |

Configuration Reference

158 |

A configuration file contains directives:

159 |
    160 |
  • document: document to be analysed (at least 1)
  • 161 |
  • define: expression that can be reused within the configuration file (zero or more)
  • 162 |
  • htmlcss: CSS file to be used for HTML output (zero or one)
  • 163 |
164 |

General syntax:

165 |
    166 |
  • Parameters with spaces must be enclosed by quotes. Eg: “Some file.docx”
  • 167 |
  • Directives can be spanned on several lines ending with backslash (\)
  • 168 |
  • Escape character (for quotes, etc.): backslash (\)
  • 169 |
170 |

Directive define

171 |

Define a variable.

172 |

Syntax:

173 |
define NAME PATTERN
174 |

Example:

175 |
define ALPHANUM [-a-zA-Z0-9_]
176 | document X -path /path/to/x -req REQ_ALPHANUM
177 |

Directive document

178 |

Start a document description.

179 |

Syntax:

180 |
document NAME PARAMETERS ...
181 |

Parameters:

182 |
    183 |
  • -end-req Indicate the end of the text of a requirement. This is used when you run reqflow review. Note that the capture of requirements identifiers takes precedence over this option: a requirement id will automatically put an end to the text of the previous requirement.

  • 184 |
  • -nocov Do not report uncovered requirements (useful for-top level documents).

  • 185 |
  • -path Path to the file.

  • 186 |
  • -ref Pattern for capturing references identifiers (regular expression).

  • 187 |
  • -prefix-req Add this prefix to captured requirements to obtain the final requirements identifiers (useful to avoid conflicts when different documents use the same requirements identifiers)

  • 188 |
  • -req Pattern for capturing requirements identifiers (regular expression).

  • 189 |
  • -sort Sort method when listing requirements: document (same order as the are in the document) or alphanum (alphanumeric order).

  • 190 |
  • -start-after Start capturing requirements after this pattern (regular expression).

  • 191 |
  • -stop-after Stop capturing requirements after this pattern (regular expression).

  • 192 |
  • -type Type of the document, overriding the file extension. One of: txt, docx, odt, xml, pdf.

  • 193 |
194 |

Directive htmlcss

195 |

Indicate a CSS file for HTML output (generated with command-line option -x html).

196 |

Example:

197 |
htmlcss style.css
198 |

Generated HTML:

199 |
<link href="style.css" rel="stylesheet" type="text/css"/>
200 |

Example of CSS file

201 |

If no htmlcss is given, a default embedded CSS stylesheet is used.

202 |

Environment Variables

203 |

Environment variables can be inserted in the configuration file, using a dollar sign ($) prefix.

204 |

Example:

205 |
document SPEC -path $DOCUMENT -req REQ_[-a-zA-Z0-9_]*
206 | # or
207 | document SPEC -path ${DOCUMENT} -req REQ_[-a-zA-Z0-9_]*
208 |

External Dependencies

209 |
    210 |
  • libz, libzip
  • 211 |
  • libxml2
  • 212 |
  • libpoppler, libpoppler-cpp
  • 213 |
  • libpcreposix, libpcre
  • 214 |
215 |

The Windows release includes these as static libraries.

216 |

License GPLv2+

217 |

Reqflow Copyright (C) 2014 Frederic Hoerni

218 |

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

219 |

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

220 |
221 |
222 | 227 | 228 | 229 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | 2 | # Reqflow 3 | 4 | Reqflow is a free and open-source tool for traceability of requirements across documents, designed to analyse documents with speed and efficiency. 5 | 6 | ## News 7 | 8 | - 11 Mar 2019: Reqflow v1.6.0 (see [Changes](https://raw.githubusercontent.com/goeb/reqflow/master/NEWS)) 9 | - 2 Oct 2018: Reqflow v1.5.3 10 | - 31 Oct 2017 Reqflow v1.5.2 11 | - 13 Feb 2017 Reqflow v1.5.1 12 | - 22 Nov 2016: Reqflow v1.5.0 13 | 14 | 15 | ## Supported Formats 16 | 17 | ### Input formats 18 | 19 | - docx (Open Xml) 20 | - odt (Open Document) 21 | - HTML 22 | - PDF 23 | - text (default) 24 | 25 | ### Output formats 26 | 27 | - text 28 | - CSV 29 | - HTML 30 | 31 | ## Example of Report 32 | 33 | No screenshot, but an example: [reqReport.html](reqReport.html) 34 | 35 | ## Download 36 | 37 | ### Linux 38 | 39 | Build From Source : 40 | 41 | git clone https://github.com/goeb/reqflow.git 42 | cd reqflow 43 | ./configure 44 | make 45 | cd test && ../reqflow stat -s 46 | 47 | ### Windows 48 | 49 | Latest stable: 50 | 51 | * [reqflow-1.6.0-setup.exe](https://github.com/goeb/reqflow/releases/download/v1.6.0/reqflow-1.6.0-setup.exe) 52 | 53 | 54 | Previous versions: 55 | 56 | * [reqflow-1.5.1-setup.exe](https://github.com/goeb/reqflow/releases/download/v1.5.1/reqflow-1.5.1-setup.exe) 57 | * [reqflow-1.5.2-setup.exe](https://github.com/goeb/reqflow/releases/download/v1.5.2/reqflow-1.5.2-setup.exe) 58 | * [reqflow-1.5.3-setup.exe](https://github.com/goeb/reqflow/releases/download/v1.5.3/reqflow-1.5.3-setup.exe) 59 | 60 | ## Usage 61 | 62 | ``` 63 | Usage: 1. reqflow [] [] 64 | 2. reqflow 65 | 66 | 67 | 1. reqflow [] [] 68 | 69 | Commands: 70 | 71 | stat [doc ...] Print the status of requirements in all documents or the 72 | given documents. Without additionnal option, only 73 | unresolved coverage issues are reported. 74 | -s Print a one-line summary for each document. 75 | -v Print the status of all requirements. 76 | Status codes: 77 | 78 | 'U' Uncovered 79 | 80 | trac [doc ...] Print the traceability matrix of the requirements 81 | (A covered by B). 82 | [-r] Print the reverse traceability matrix (A covers B). 83 | [-x ] Select export format: text (default), csv, html. 84 | If format 'html' is chosen, -r is ignored, as both foward 85 | and reverse traceability matrices are displayed. 86 | 87 | review Print the requirements with their text. 88 | [-f | -r] Print also traceability (forward or backward) 89 | [-x ] Choose format: txt, csv. 90 | 91 | config Print the list of configured documents. 92 | 93 | debug Dump text extracted from file (debug purpose). 94 | 95 | regex [] 96 | Test regex given by applied on . 97 | If is omitted, then the text is read from stdin. 98 | 99 | version 100 | help 101 | 102 | Options: 103 | -c Select configuration file. Defaults to 'conf.req'. 104 | -o Output to file instead of stdout. 105 | Not supported for commands 'config', debug' and 'regex'. 106 | 107 | 2. reqflow 108 | This is equivalent to: 109 | reqflow trac -c -x html -o && start 110 | 111 | Purpose: This usage is suitable for double-cliking on the config file. 112 | Note: must be different from the commands of use case 1. 113 | ``` 114 | 115 | ## Sample Configuration File 116 | 117 | `conf.req` 118 | 119 | ``` 120 | # document -path -req \ 121 | # [-stop-after ] [-ref ] [-start-after ] \ 122 | # [-nocov] 123 | # 124 | # must be a Perl Compatible Regular Expression (PCRE) 125 | # -req indicates how the requirements must be captured 126 | # -ref indicates how the referenced requirements must be captured 127 | # 128 | # Keyword 'define' may be used to define values: 129 | # 130 | # define PATH 131 | # document x -path PATH/x.txt 132 | # document y -path PATH/y.txt 133 | 134 | document SPEC -path SPEC.docx -req REQ_[-a-zA-Z0-9_]* -stop-after Annex 135 | document TEST -path TEST.txt \ 136 | -req T_[-a-zA-Z0-9_]* \ 137 | -ref "Ref: *(.*)" \ 138 | -stop-after "Annex" \ 139 | -start-after "Tests cases" \ 140 | -nocov -sort alphanum 141 | 142 | # CSS for HTML output (optional) 143 | htmlcss style.css 144 | ``` 145 | 146 | ## Configuration Reference 147 | 148 | A configuration file contains directives: 149 | 150 | - `document`: document to be analysed (at least 1) 151 | - `define`: expression that can be reused within the configuration file (zero or more) 152 | - `htmlcss`: CSS file to be used for HTML output (zero or one) 153 | 154 | General syntax: 155 | 156 | - Parameters with spaces must be enclosed by quotes. Eg: "Some file.docx" 157 | - Directives can be spanned on several lines ending with backslash (`\`) 158 | - Escape character (for quotes, etc.): backslash (`\`) 159 | 160 | ### Directive `define` 161 | 162 | Define a variable. 163 | 164 | Syntax: 165 | ``` 166 | define NAME PATTERN 167 | ``` 168 | 169 | Example: 170 | 171 | define ALPHANUM [-a-zA-Z0-9_] 172 | document X -path /path/to/x -req REQ_ALPHANUM 173 | 174 | ### Directive `document` 175 | 176 | Start a document description. 177 | 178 | Syntax: 179 | ``` 180 | document NAME PARAMETERS ... 181 | ``` 182 | 183 | Parameters: 184 | 185 | - `-end-req` Indicate the end of the text of a requirement. This is used when you run `reqflow review`. Note that the capture of requirements identifiers takes precedence over this option: a requirement id will automatically put an end to the text of the previous requirement. 186 | 187 | - `-nocov` Do not report uncovered requirements (useful for-top level documents). 188 | 189 | - `-path` Path to the file. 190 | 191 | - `-ref` Pattern for capturing references identifiers (regular expression). 192 | 193 | - `-prefix-req` Add this prefix to captured requirements to obtain the final requirements identifiers (useful to avoid conflicts when different documents use the same requirements identifiers) 194 | 195 | - `-req` Pattern for capturing requirements identifiers (regular expression). 196 | 197 | - `-sort` Sort method when listing requirements: `document` (same order as the are in the document) or `alphanum` (alphanumeric order). 198 | 199 | - `-start-after` Start capturing requirements after this pattern (regular expression). 200 | 201 | - `-stop-after` Stop capturing requirements after this pattern (regular expression). 202 | 203 | - `-type` Type of the document, overriding the file extension. One of: `txt`, `docx`, `odt`, `xml`, `pdf`. 204 | 205 | ### Directive `htmlcss` 206 | 207 | Indicate a CSS file for HTML output (generated with command-line option `-x html`). 208 | 209 | Example: 210 | 211 | ``` 212 | htmlcss style.css 213 | ``` 214 | 215 | Generated HTML: 216 | 217 | ``` 218 | 219 | ``` 220 | 221 | [Example of CSS file](stylesheet.css) 222 | 223 | If no `htmlcss` is given, a default embedded CSS stylesheet is used. 224 | 225 | ## Environment Variables 226 | 227 | Environment variables can be inserted in the configuration file, using a dollar sign ($) prefix. 228 | 229 | Example: 230 | 231 | ``` 232 | document SPEC -path $DOCUMENT -req REQ_[-a-zA-Z0-9_]* 233 | # or 234 | document SPEC -path ${DOCUMENT} -req REQ_[-a-zA-Z0-9_]* 235 | ``` 236 | 237 | 238 | 239 | 240 | 241 | ## External Dependencies 242 | 243 | - libz, libzip 244 | - libxml2 245 | - libpoppler, libpoppler-cpp 246 | - libpcreposix, libpcre 247 | 248 | The Windows release includes these as static libraries. 249 | 250 | 251 | ## License GPLv2+ 252 | 253 | Reqflow 254 | Copyright (C) 2014 Frederic Hoerni 255 | 256 | This program is free software; you can redistribute it and/or modify 257 | it under the terms of the GNU General Public License as published by 258 | the Free Software Foundation; either version 2 of the License, or 259 | (at your option) any later version. 260 | 261 | This program is distributed in the hope that it will be useful, 262 | but WITHOUT ANY WARRANTY; without even the implied warranty of 263 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 264 | GNU General Public License for more details. 265 | 266 | -------------------------------------------------------------------------------- /docs/reqReport.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Requirements Traceability 4 | 5 | 29 | 30 | 31 |

Requirements Traceability

32 |
33 | 34 | 37 | 38 |
DocumentsCoverage (%)Req CoveredReq TotalDocument Path
SPEC7779SPEC.docx
TESTnocovnocov5TEST.txt
Total7779

SPEC

Path: SPEC.docx
Requirements: 9
Covered: 7 (77%)
39 |

Errors

40 |
SPEC:PRINTF_15: Duplicate requirement: also defined in 'SPEC.docx' 41 | SPEC:SYS_155: Undefined requirement, referenced by: PRINTF_01 42 |
43 |

Dependencies for: SPEC

44 |
Upstream DocumentsDownstream Documents
-> SPEC->TEST
45 |

Forward Coverage for: SPEC

46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 |
RequirementsDescendantsDownstream Documents
PRINTF_01T_01TEST
PRINTF_02T_02TEST
PRINTF_03T_02TEST
PRINTF_03T_05TEST
PRINTF_05
PRINTF_06T_21TEST
PRINTF_12T_21TEST
PRINTF_14
PRINTF_15T_21TEST
PRINTF_15T_22TEST
PRINTF_20T_22TEST
59 |

Reverse Coverage for: SPEC

60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |
RequirementsOriginsUpstream Documents
PRINTF_01SYS_155Undefined
PRINTF_02
PRINTF_03
PRINTF_05
PRINTF_06
PRINTF_12
PRINTF_14
PRINTF_15
PRINTF_20
71 |

TEST

Path: TEST.txt
Requirements: 5
72 |

Errors

73 |
TEST:PRINTF_01a: Undefined requirement, referenced by: T_01 74 | TEST:PRINTF_01b: Undefined requirement, referenced by: T_01 75 | TEST:PRINTF_333: Undefined requirement, referenced by: T_01 76 | TEST:PRINTF_03a: Undefined requirement, referenced by: T_02 77 | TEST:PRINTF_03b: Undefined requirement, referenced by: T_02 78 |
79 |

Dependencies for: TEST

80 |
Upstream DocumentsDownstream Documents
SPEC
-> TEST->
81 |

Forward Coverage for: TEST

82 |
No forward tracebility configured (-nocov flag).

Reverse Coverage for: TEST

83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 |
RequirementsOriginsUpstream Documents
T_01PRINTF_01SPEC
T_01PRINTF_01aUndefined
T_01PRINTF_01bUndefined
T_01PRINTF_333Undefined
T_02PRINTF_02SPEC
T_02PRINTF_03SPEC
T_02PRINTF_03aUndefined
T_02PRINTF_03bUndefined
T_05PRINTF_03SPEC
T_21PRINTF_06SPEC
T_21PRINTF_12SPEC
T_21PRINTF_15SPEC
T_22PRINTF_15SPEC
T_22PRINTF_20SPEC
99 | 100 |

Errors

101 |
All Error(s): 7 102 | SPEC:PRINTF_15: Duplicate requirement: also defined in 'SPEC.docx' 103 | SPEC:SYS_155: Undefined requirement, referenced by: PRINTF_01 104 | TEST:PRINTF_01a: Undefined requirement, referenced by: T_01 105 | TEST:PRINTF_01b: Undefined requirement, referenced by: T_01 106 | TEST:PRINTF_333: Undefined requirement, referenced by: T_01 107 | TEST:PRINTF_03a: Undefined requirement, referenced by: T_02 108 | TEST:PRINTF_03b: Undefined requirement, referenced by: T_02 109 |
110 |
111 |

112 |
113 | -------------------------------------------------------------------------------- /docs/style.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | color: black; 4 | background-color: #eeeee6; 5 | margin-top: 0; 6 | font-family: Verdana,sans-serif; 7 | font-size: small; 8 | vertical-align: top; 9 | } 10 | a[href], a[href]:link { 11 | color:blue; 12 | text-decoration: none; 13 | } 14 | a[href]:hover { 15 | color:blue; 16 | text-decoration: underline; 17 | } 18 | 19 | h2 { 20 | border-bottom: 1px solid #DDD; 21 | } 22 | h2:before { 23 | content: '■ '; 24 | position: relative; 25 | bottom: .1em; 26 | color: #666; 27 | } 28 | .menu { 29 | float: left; 30 | margin: 0; 31 | padding: 0; 32 | width: 208px; 33 | font-size: medium; 34 | } 35 | ul, li { 36 | margin-right: 0; 37 | padding-right: 0; 38 | } 39 | .menu li { 40 | list-style: none outside none; 41 | font-weight: 600; 42 | padding: 0; 43 | padding-top: 0.5em; 44 | } 45 | .menu ul { 46 | padding: 0; 47 | } 48 | .menu_level2 li { 49 | font-weight: normal; 50 | font-size: 80%; 51 | margin-left: 20px; 52 | padding: 0; 53 | } 54 | .contents h1 { 55 | font-size: 36px; 56 | padding-top: 0; 57 | margin-top: 0; 58 | } 59 | .contents h2 { 60 | font-size: 18px; 61 | padding-top: 0; 62 | margin-top: 2em; 63 | } 64 | 65 | .contents h3 { 66 | font-size: 15px; 67 | } 68 | 69 | .contents { 70 | margin: 0; 71 | margin-bottom: 1em; 72 | float: right; 73 | background-color: white; 74 | border: solid 1px #ccc; 75 | padding: 1.5em; 76 | width: 660px; 77 | font-size: 14px; 78 | } 79 | li.active { 80 | color: #4E443C; 81 | } 82 | .header { 83 | padding-top: 15px; 84 | margin: 0 auto; 85 | width: 940px; 86 | } 87 | .header_text { 88 | padding-left: 1em; 89 | font-size: 150%; 90 | } 91 | img { 92 | border: 0; 93 | } 94 | div.header img { 95 | vertical-align: middle; 96 | } 97 | .page { 98 | margin: 0 auto; 99 | width: 940px; 100 | } 101 | .footer { 102 | margin 1em; 103 | padding: 1em; 104 | clear: both; 105 | color: grey; 106 | text-align: center; 107 | } 108 | .footer { 109 | margin-top: 1em; 110 | /*border-top: 1px solid #ddd;*/ 111 | } 112 | pre code { 113 | background-color: #EEFFCC; 114 | display: block; 115 | border-top: 1px solid #ccc; 116 | border-bottom: 1px solid #ccc; 117 | border-right: 0; 118 | border-left: 0; 119 | border-radius: 0; 120 | line-height: normal; 121 | } 122 | .tag, code { 123 | background-color: #eee; 124 | border: 1px solid #bbb; 125 | padding: 0.1em 0.5em 0.1em 0.5em; /* top right bottom left */ 126 | border-radius: 5px; 127 | line-height: 1.8em; 128 | } 129 | 130 | blockquote { 131 | background-color: #EEE; 132 | padding: 0.5em; 133 | padding-top: 1px; 134 | padding-bottom: 2px; 135 | border: 1px solid #AAA; 136 | margin: 0; 137 | font-size: 80%; 138 | } 139 | blockquote p, blockquote ul { 140 | padding-top: 0; 141 | padding-bottom: 0; 142 | margin: 0; 143 | } 144 | em { 145 | font-weight: bold; 146 | font-style: normal; 147 | } 148 | -------------------------------------------------------------------------------- /docs/stylesheet.css: -------------------------------------------------------------------------------- 1 | body { font-family: Verdana,sans-serif; } 2 | h1 { border-bottom: 1px #bbb solid; margin-top: 15px;} 3 | a[href], a[href]:link { color: blue; text-decoration: none; } 4 | a[href]:hover { color: blue; text-decoration: underline; } 5 | .r_footer { font-size: small; font-family: monospace; color: grey; } 6 | .r_document_summary { font-size: small; } 7 | .r_errors { border: 1px solid #BBB; white-space: pre; font-family: monospace; color: red; padding: 0.5em; background-color: #FDD;} 8 | .r_errors_summary { padding: 1em; font-size: 200%; position: absolute; right: 15px; top: 20px; background-color: #FDD; border: solid black;} 9 | .r_main { position: relative; } 10 | .r_warning { background-color: #FBB; } 11 | .r_samereq { color: grey; } 12 | .r_no_error { color: grey; } 13 | .r_nocov {color: grey;} 14 | table { border-collapse:collapse; } 15 | td.r_summary { text-align:right; border-bottom: 1px grey solid; padding-left: 1em; } 16 | td.r_summary_l { text-align:left; border-bottom: 1px grey solid; padding-left: 1em; } 17 | th.r_summary { text-align:center; padding-left: 1em; } 18 | td.r_matrix { text-align:left; border: 1px grey solid; padding-left: 1em; } 19 | th.r_matrix { text-align:left; padding-left: 1em; } 20 | td.r_upstream { border: 1px solid grey; padding: 1em;} 21 | td.r_downstream { border: 1px solid grey; padding: 1em; } 22 | .r_no_coverage { color: grey; } -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common wrapper for a few potentially missing GNU programs. 3 | 4 | scriptversion=2013-10-28.13; # UTC 5 | 6 | # Copyright (C) 1996-2014 Free Software Foundation, Inc. 7 | # Originally written by Fran,cois Pinard , 1996. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program. If not, see . 21 | 22 | # As a special exception to the GNU General Public License, if you 23 | # distribute this file as part of a program that contains a 24 | # configuration script generated by Autoconf, you may include it under 25 | # the same distribution terms that you use for the rest of that program. 26 | 27 | if test $# -eq 0; then 28 | echo 1>&2 "Try '$0 --help' for more information" 29 | exit 1 30 | fi 31 | 32 | case $1 in 33 | 34 | --is-lightweight) 35 | # Used by our autoconf macros to check whether the available missing 36 | # script is modern enough. 37 | exit 0 38 | ;; 39 | 40 | --run) 41 | # Back-compat with the calling convention used by older automake. 42 | shift 43 | ;; 44 | 45 | -h|--h|--he|--hel|--help) 46 | echo "\ 47 | $0 [OPTION]... PROGRAM [ARGUMENT]... 48 | 49 | Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due 50 | to PROGRAM being missing or too old. 51 | 52 | Options: 53 | -h, --help display this help and exit 54 | -v, --version output version information and exit 55 | 56 | Supported PROGRAM values: 57 | aclocal autoconf autoheader autom4te automake makeinfo 58 | bison yacc flex lex help2man 59 | 60 | Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 61 | 'g' are ignored when checking the name. 62 | 63 | Send bug reports to ." 64 | exit $? 65 | ;; 66 | 67 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 68 | echo "missing $scriptversion (GNU Automake)" 69 | exit $? 70 | ;; 71 | 72 | -*) 73 | echo 1>&2 "$0: unknown '$1' option" 74 | echo 1>&2 "Try '$0 --help' for more information" 75 | exit 1 76 | ;; 77 | 78 | esac 79 | 80 | # Run the given program, remember its exit status. 81 | "$@"; st=$? 82 | 83 | # If it succeeded, we are done. 84 | test $st -eq 0 && exit 0 85 | 86 | # Also exit now if we it failed (or wasn't found), and '--version' was 87 | # passed; such an option is passed most likely to detect whether the 88 | # program is present and works. 89 | case $2 in --version|--help) exit $st;; esac 90 | 91 | # Exit code 63 means version mismatch. This often happens when the user 92 | # tries to use an ancient version of a tool on a file that requires a 93 | # minimum version. 94 | if test $st -eq 63; then 95 | msg="probably too old" 96 | elif test $st -eq 127; then 97 | # Program was missing. 98 | msg="missing on your system" 99 | else 100 | # Program was found and executed, but failed. Give up. 101 | exit $st 102 | fi 103 | 104 | perl_URL=http://www.perl.org/ 105 | flex_URL=http://flex.sourceforge.net/ 106 | gnu_software_URL=http://www.gnu.org/software 107 | 108 | program_details () 109 | { 110 | case $1 in 111 | aclocal|automake) 112 | echo "The '$1' program is part of the GNU Automake package:" 113 | echo "<$gnu_software_URL/automake>" 114 | echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" 115 | echo "<$gnu_software_URL/autoconf>" 116 | echo "<$gnu_software_URL/m4/>" 117 | echo "<$perl_URL>" 118 | ;; 119 | autoconf|autom4te|autoheader) 120 | echo "The '$1' program is part of the GNU Autoconf package:" 121 | echo "<$gnu_software_URL/autoconf/>" 122 | echo "It also requires GNU m4 and Perl in order to run:" 123 | echo "<$gnu_software_URL/m4/>" 124 | echo "<$perl_URL>" 125 | ;; 126 | esac 127 | } 128 | 129 | give_advice () 130 | { 131 | # Normalize program name to check for. 132 | normalized_program=`echo "$1" | sed ' 133 | s/^gnu-//; t 134 | s/^gnu//; t 135 | s/^g//; t'` 136 | 137 | printf '%s\n' "'$1' is $msg." 138 | 139 | configure_deps="'configure.ac' or m4 files included by 'configure.ac'" 140 | case $normalized_program in 141 | autoconf*) 142 | echo "You should only need it if you modified 'configure.ac'," 143 | echo "or m4 files included by it." 144 | program_details 'autoconf' 145 | ;; 146 | autoheader*) 147 | echo "You should only need it if you modified 'acconfig.h' or" 148 | echo "$configure_deps." 149 | program_details 'autoheader' 150 | ;; 151 | automake*) 152 | echo "You should only need it if you modified 'Makefile.am' or" 153 | echo "$configure_deps." 154 | program_details 'automake' 155 | ;; 156 | aclocal*) 157 | echo "You should only need it if you modified 'acinclude.m4' or" 158 | echo "$configure_deps." 159 | program_details 'aclocal' 160 | ;; 161 | autom4te*) 162 | echo "You might have modified some maintainer files that require" 163 | echo "the 'autom4te' program to be rebuilt." 164 | program_details 'autom4te' 165 | ;; 166 | bison*|yacc*) 167 | echo "You should only need it if you modified a '.y' file." 168 | echo "You may want to install the GNU Bison package:" 169 | echo "<$gnu_software_URL/bison/>" 170 | ;; 171 | lex*|flex*) 172 | echo "You should only need it if you modified a '.l' file." 173 | echo "You may want to install the Fast Lexical Analyzer package:" 174 | echo "<$flex_URL>" 175 | ;; 176 | help2man*) 177 | echo "You should only need it if you modified a dependency" \ 178 | "of a man page." 179 | echo "You may want to install the GNU Help2man package:" 180 | echo "<$gnu_software_URL/help2man/>" 181 | ;; 182 | makeinfo*) 183 | echo "You should only need it if you modified a '.texi' file, or" 184 | echo "any other file indirectly affecting the aspect of the manual." 185 | echo "You might want to install the Texinfo package:" 186 | echo "<$gnu_software_URL/texinfo/>" 187 | echo "The spurious makeinfo call might also be the consequence of" 188 | echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" 189 | echo "want to install GNU make:" 190 | echo "<$gnu_software_URL/make/>" 191 | ;; 192 | *) 193 | echo "You might have modified some files without having the proper" 194 | echo "tools for further handling them. Check the 'README' file, it" 195 | echo "often tells you about the needed prerequisites for installing" 196 | echo "this package. You may also peek at any GNU archive site, in" 197 | echo "case some other package contains this missing '$1' program." 198 | ;; 199 | esac 200 | } 201 | 202 | give_advice "$1" | sed -e '1s/^/WARNING: /' \ 203 | -e '2,$s/^/ /' >&2 204 | 205 | # Propagate the correct exit status (expected to be 127 for a program 206 | # not found, 63 for a program that failed due to version mismatch). 207 | exit $st 208 | 209 | # Local variables: 210 | # eval: (add-hook 'write-file-hooks 'time-stamp) 211 | # time-stamp-start: "scriptversion=" 212 | # time-stamp-format: "%:y-%02m-%02d.%02H" 213 | # time-stamp-time-zone: "UTC" 214 | # time-stamp-end: "; # UTC" 215 | # End: 216 | -------------------------------------------------------------------------------- /reqflow.iss.in: -------------------------------------------------------------------------------- 1 | ; Script generated by the Inno Setup Script Wizard. 2 | ; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES! 3 | 4 | #define MyAppName "Reqflow" 5 | #define MyAppVersion "@VERSION@" 6 | #define MyAppPublisher "Frederic Hoerni" 7 | #define MyAppURL "http://goeb.github.io/reqflow" 8 | #define MyAppExeName "reqflow.exe" 9 | 10 | [Setup] 11 | ; NOTE: The value of AppId uniquely identifies this application. 12 | ; Do not use the same AppId value in installers for other applications. 13 | ; (To generate a new GUID, click Tools | Generate GUID inside the IDE.) 14 | AppId={{9C26518E-614F-4CEB-BAC9-CCC42D7BAF6D} 15 | AppName={#MyAppName} 16 | AppVersion={#MyAppVersion} 17 | ;AppVerName={#MyAppName} {#MyAppVersion} 18 | AppPublisher={#MyAppPublisher} 19 | AppPublisherURL={#MyAppURL} 20 | AppSupportURL={#MyAppURL} 21 | AppUpdatesURL={#MyAppURL} 22 | DefaultDirName={pf}\{#MyAppName} 23 | DefaultGroupName={#MyAppName} 24 | DisableProgramGroupPage=yes 25 | LicenseFile=@srcdir@\COPYING 26 | OutputDir=. 27 | OutputBaseFilename=setup 28 | Compression=lzma 29 | SolidCompression=yes 30 | 31 | [Languages] 32 | Name: "english"; MessagesFile: "compiler:Default.isl" 33 | 34 | [Files] 35 | Source: "reqflow.exe"; DestDir: "{app}"; Flags: ignoreversion 36 | Source: "@srcdir@\README"; DestName: "README.txt"; DestDir: "{app}"; Flags: ignoreversion 37 | Source: "@srcdir@\COPYING"; DestDir: "{app}"; Flags: ignoreversion 38 | Source: "@srcdir@\NEWS"; DestDir: "{app}"; Flags: ignoreversion 39 | Source: "@srcdir@\ChangeLog"; DestDir: "{app}"; Flags: ignoreversion 40 | Source: "@srcdir@\AUTHORS"; DestDir: "{app}"; Flags: ignoreversion 41 | Source: "@srcdir@\test\*.test"; DestDir: "{app}\test"; Flags: ignoreversion 42 | Source: "@srcdir@\test\*.ref"; DestDir: "{app}\test"; Flags: ignoreversion 43 | Source: "@srcdir@\test\*.req"; DestDir: "{app}\test"; Flags: ignoreversion 44 | Source: "@srcdir@\test\*.pdf"; DestDir: "{app}\test"; Flags: ignoreversion 45 | Source: "@srcdir@\test\*.docx"; DestDir: "{app}\test"; Flags: ignoreversion 46 | Source: "@srcdir@\test\*.txt"; DestDir: "{app}\test"; Flags: ignoreversion 47 | Source: "@srcdir@\test\*.html"; DestDir: "{app}\test"; Flags: ignoreversion 48 | ; NOTE: Don't use "Flags: ignoreversion" on any shared system files 49 | 50 | [Icons] 51 | Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" 52 | 53 | [Run] 54 | Filename: "{app}\README.txt"; Description: "View the README file"; Flags: postinstall shellexec skipifsilent 55 | 56 | #define KeyPath "SYSTEM\CurrentControlSet\Control\Session Manager\Environment" 57 | 58 | 59 | [Registry] 60 | ; associate .req files with reqflow 61 | Root: HKCR; Subkey: ".req"; ValueType: string; ValueName: ""; ValueData: "Reqflow"; Flags: uninsdeletevalue 62 | Root: HKCR; Subkey: "Reqflow"; ValueType: string; ValueName: ""; ValueData: "Reqflow File"; Flags: uninsdeletekey 63 | Root: HKCR; Subkey: "Reqflow\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\REQFLOW.EXE,0" 64 | Root: HKCR; Subkey: "Reqflow\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\REQFLOW.EXE"" ""%1""" 65 | 66 | ; set reqflow in the PATH 67 | Root: HKLM; Subkey: "SYSTEM\CurrentControlSet\Control\Session Manager\Environment"; ValueType: expandsz; ValueName: "Path"; ValueData: "{olddata};{app}"; Check: NeedsAddPath(ExpandConstant('{app}')) 68 | 69 | [Code] 70 | 71 | function NeedsAddPath(Param: string): boolean; 72 | var 73 | OrigPath: string; 74 | begin 75 | if not RegQueryStringValue(HKEY_LOCAL_MACHINE, 76 | '{#KeyPath}', 77 | 'Path', OrigPath) 78 | then begin 79 | Result := True; 80 | exit; 81 | end; 82 | // look for the path with leading and trailing semicolon 83 | // Pos() returns 0 if not found 84 | Result := Pos(';' + Param + ';', ';' + OrigPath + ';') = 0; 85 | end; 86 | 87 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | /.deps/ 2 | /.dirstamp 3 | /stamp-h1 4 | 5 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | 2 | 3 | xml: xml.c 4 | gcc -o $@ xml.c $$(xml2-config --cflags) $$(xml2-config --libs) 5 | -------------------------------------------------------------------------------- /src/ReqDocumentDocx.cpp: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | #include "config.h" 15 | 16 | #include 17 | #include 18 | 19 | #include "ReqDocumentDocx.h" 20 | #include "logging.h" 21 | #include "parseConfig.h" 22 | 23 | /** Analyse a node of the document 24 | * 25 | * @return 26 | * 0 : ok, continue 27 | * -1 : stop reached, do not continue 28 | */ 29 | int ReqDocumentDocxXml::loadDocxXmlNode(xmlDocPtr doc, xmlNode *node, bool debug) 30 | { 31 | // textInParagraphCurrent consolidated over recursive calls 32 | std::string nodeName; 33 | 34 | if (node->type == XML_ELEMENT_NODE) { 35 | if (0 == strcmp((char*)node->name, "pStyle")) { 36 | xmlAttr* attribute = node->properties; 37 | while(attribute && attribute->name && attribute->children) 38 | { 39 | xmlChar* style = xmlNodeListGetString(node->doc, attribute->children, 1); 40 | LOG_DEBUG("style: %s", (char*)style); 41 | 42 | xmlFree(style); 43 | attribute = attribute->next; 44 | } 45 | // TODO take benefit of styles in the future 46 | } else if (0 == strcmp((char*)node->name, "del")) return 0; // ignore deleted text (revision marks) 47 | else if (0 == strcmp((char*)node->name, "moveFrom")) return 0; // ignore deleted text (revision marks) 48 | 49 | // When OOXML AlternateContent is encountered, we decide to ignore the Fallback part. 50 | // This prevents duplicated requirements in some documents. 51 | // Typical structure: 52 | // 53 | // ... 54 | // ... 55 | // 56 | else if (0 == strcmp((char*)node->name, "Fallback")) return 0; // ignore fallback 57 | 58 | 59 | LOG_DEBUG("node: %s", (char*)node->name); 60 | nodeName = (char*)node->name; 61 | 62 | xmlNode *subnode = NULL; 63 | for (subnode = node->children; subnode; subnode = subnode->next) { 64 | 65 | // recursively go down the xml structure 66 | int ret = loadDocxXmlNode(doc, subnode, debug); 67 | if (ret == -1) return -1; // STOP reached 68 | } 69 | 70 | } else if (XML_TEXT_NODE == node->type) { 71 | xmlChar *text; 72 | text = xmlNodeGetContent(node); 73 | LOG_DEBUG("text size: %zd bytes", strlen((char*)text)); 74 | LOG_DEBUG("text: %s", (char*)text); 75 | 76 | textInParagraphCurrent += (char*)text; 77 | 78 | LOG_DEBUG("textInParagraphCurrent: %s", textInParagraphCurrent.c_str()); 79 | 80 | xmlFree(text); 81 | } 82 | 83 | 84 | if (nodeName =="p" && !textInParagraphCurrent.empty()) { 85 | if (debug) { 86 | dumpText(textInParagraphCurrent.c_str()); 87 | 88 | } else { 89 | // process text of paragraph 90 | BlockStatus status = processBlock(textInParagraphCurrent); 91 | if (status == STOP_REACHED) return -1; 92 | } 93 | 94 | textInParagraphCurrent.clear(); 95 | 96 | } else if (nodeName =="document" || nodeName =="document-content") { 97 | // end of document 98 | finalizeCurrentReq(); 99 | } 100 | return 0; 101 | } 102 | 103 | 104 | int ReqDocumentDocxXml::loadRequirements(bool debug) 105 | { 106 | const char *xml; 107 | int r = loadFile(fileConfig->realpath.c_str(), &xml); 108 | if (r <= 0) { 109 | PUSH_ERROR(fileConfig->id, "", "Cannot read file (or empty): %s", fileConfig->realpath.c_str()); 110 | return -1; 111 | } 112 | loadContents(xml, r, debug); 113 | free((void*)xml); 114 | return 0; 115 | } 116 | 117 | int ReqDocumentDocxXml::loadContents(const char *xml, size_t size, bool debug) 118 | { 119 | init(); 120 | 121 | xmlDocPtr document; 122 | xmlNode *root; 123 | 124 | document = xmlReadMemory(xml, size, 0, 0, 0); 125 | root = xmlDocGetRootElement(document); 126 | 127 | return loadDocxXmlNode(document, root, debug); 128 | } 129 | 130 | int ReqDocumentDocx::loadRequirements(bool debug) 131 | { 132 | init(); 133 | 134 | LOG_DEBUG("loadDocx: %s", fileConfig->realpath.c_str()); 135 | int err; 136 | 137 | struct zip *zipFile = zip_open(fileConfig->realpath.c_str(), 0, &err); 138 | if (!zipFile) { 139 | PUSH_ERROR(fileConfig->id, "", "Cannot open file: %s", fileConfig->realpath.c_str()); 140 | return -1; 141 | } 142 | 143 | const char *CONTENTS = "word/document.xml"; 144 | int i = zip_name_locate(zipFile, CONTENTS, 0); 145 | if (i < 0) { 146 | // I suppose here something to be confirmed (or not): 147 | // MS Word 2010 stores OpenDocument files with suffix .docx. 148 | // So we cannot say at first sight if a docx is an OpenXml or an OpenDocument. 149 | // Therefore we try OpenXml first (by looking at word/document.xml) 150 | // and in case of failure, we try OpenDocument (by looking at content.xml) 151 | 152 | // From a wikipedia page I see that I am probably wrong. 153 | // If so, this second try should be removed. 154 | LOG_DEBUG("Not a Open XML document (missing word/document.xml). Trying Open Document."); 155 | const char *OPEN_DOC_CONTENTS = "content.xml"; 156 | i = zip_name_locate(zipFile, OPEN_DOC_CONTENTS, 0); 157 | if (i < 0) { 158 | PUSH_ERROR(fileConfig->id, "", "Not a valid docx document: %s", fileConfig->realpath.c_str()); 159 | zip_close(zipFile); 160 | return -1; 161 | } 162 | } 163 | 164 | std::string contents; // buffer for loading the XML contents 165 | struct zip_file *fileInZip = zip_fopen_index(zipFile, i, 0); 166 | if (fileInZip) { 167 | const int BUF_SIZ = 4096; 168 | char buffer[BUF_SIZ]; 169 | int r; 170 | while ( (r = zip_fread(fileInZip, buffer, BUF_SIZ)) > 0) { 171 | contents.append(buffer, r); 172 | } 173 | LOG_DEBUG("%s:%s: %zd bytes", fileConfig->path.c_str(), CONTENTS, contents.size()); 174 | 175 | zip_fclose(fileInZip); 176 | } else { 177 | PUSH_ERROR(fileConfig->id, "", "Cannot open file %d in zip: %s", i, fileConfig->realpath.c_str()); 178 | } 179 | zip_close(zipFile); 180 | 181 | // parse the XML 182 | ReqDocumentDocxXml docXml(*fileConfig); 183 | return docXml.loadContents(contents.data(),contents.size(), debug); 184 | } 185 | -------------------------------------------------------------------------------- /src/ReqDocumentDocx.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef _importerDocx_h 16 | #define _importerDocx_h 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "req.h" 23 | 24 | /* The classes here manage the analysis of documents: 25 | * - OpenXml (Office Open XML, OOXML) 26 | * - OpenDocument 27 | * 28 | */ 29 | 30 | class ReqDocumentDocx: public ReqDocument { 31 | public: 32 | ReqDocumentDocx(ReqFileConfig &c) {fileConfig = &c;} 33 | int loadRequirements(bool debug); 34 | }; 35 | 36 | class ReqDocumentDocxXml: public ReqDocument { 37 | public: 38 | ReqDocumentDocxXml(ReqFileConfig &c) {fileConfig = &c;} 39 | int loadRequirements(bool debug); 40 | int loadContents(const char *xml, size_t size, bool debug); 41 | 42 | private: 43 | std::string contents; 44 | int loadDocxXmlNode(xmlDocPtr doc, xmlNode *node, bool debug); 45 | std::string textInParagraphCurrent; 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /src/ReqDocumentHtml.cpp: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | #include "config.h" 15 | 16 | #include 17 | #include "ReqDocumentHtml.h" 18 | #include "logging.h" 19 | #include "parseConfig.h" 20 | #include "stringTools.h" 21 | 22 | /** 23 | * @param[in/out] text 24 | */ 25 | BlockStatus ReqDocumentHtml::processParagraph(std::string &text, bool inParagaph, bool debug) 26 | { 27 | LOG_DEBUG("processParagraph: inParagaph=%d", inParagaph); 28 | LOG_DEBUG("processParagraph: text=%s", text.c_str()); 29 | 30 | BlockStatus s = REQ_OK; 31 | 32 | if (debug) { 33 | dumpText(text.c_str()); 34 | } else { 35 | // process text of paragraph 36 | if (inParagaph) s = processBlock(text); 37 | else { 38 | // process line per line 39 | LOG_DEBUG("processParagraph line per line, size=%zd", text.size()); 40 | size_t pos0 = 0; 41 | while (pos0 < text.size()) { 42 | std::string line; 43 | size_t pos1 = text.find('\n', pos0); 44 | if (pos1 == std::string::npos) { 45 | // take last line 46 | line = text.substr(pos0); 47 | pos0 = text.size(); // stop the loop 48 | } else { 49 | line = text.substr(pos0, pos1-pos0); 50 | pos0 = pos1 + 1; 51 | } 52 | 53 | s = processBlock(line); 54 | if (s == STOP_REACHED) break; 55 | } 56 | } 57 | } 58 | 59 | text.clear(); 60 | return s; 61 | } 62 | 63 | const char *HtmlParagraphBoundaries[] = { 64 | // some HTML block level elements 65 | "address", 66 | "article", 67 | "aside", 68 | "blockquote", 69 | "dd", 70 | "div", 71 | "dl", 72 | "fieldset", 73 | "figcaption", 74 | "figure", 75 | "footer", 76 | "form", 77 | "h1", 78 | "h2", 79 | "h3", 80 | "h4", 81 | "h5", 82 | "h6", 83 | "header", 84 | "hgroup", 85 | "hr", 86 | "li", 87 | "main", 88 | "ol", 89 | "output" , 90 | "p", 91 | "section", 92 | "table", 93 | "tfoot", 94 | "ul", 95 | // other elements 96 | "td", 97 | NULL // the list must end with NULL 98 | }; 99 | 100 | /** Tell if a HTML node name is considered as a paragraph boundary 101 | */ 102 | static bool isParagraphBoundary(const std::string &nodeName) 103 | { 104 | const char **ptr = HtmlParagraphBoundaries; 105 | while (*ptr) { 106 | if (nodeName == *ptr) return true; 107 | ptr++; 108 | } 109 | return false; 110 | } 111 | 112 | /** Parsing is done as follows: 113 | * - if inside a

, process paragraph as a whole 114 | * - else, process line per line 115 | */ 116 | BlockStatus ReqDocumentHtml::loadHtmlNode(xmlDocPtr doc, xmlNode *a_node, bool inParagraph, bool debug) 117 | { 118 | LOG_FUNC(); 119 | xmlNode *currentNode = NULL; 120 | BlockStatus s; 121 | 122 | // currentText consolidated over recursive calls 123 | 124 | LOG_DEBUG("loadHtmlNode: inParagraph=%d", inParagraph); 125 | for (currentNode = a_node; currentNode; currentNode = currentNode->next) { 126 | std::string nodeName; 127 | if (currentNode->name) nodeName = (char*)currentNode->name; 128 | 129 | if (nodeName == "body") { 130 | if (!fileConfig->startAfterRegex) acquisitionStarted = true; 131 | 132 | } else if (nodeName == "br") { 133 | // stay in the same paragraph 134 | // add a newline 135 | currentText += "\n"; 136 | 137 | } else if (isParagraphBoundary(nodeName)) { 138 | if (!currentText.empty()) { 139 | // process previous text (that was not in a paragraph) 140 | s = processParagraph(currentText, false, debug); 141 | if (s == STOP_REACHED) return STOP_REACHED; 142 | } 143 | inParagraph = true; 144 | } 145 | 146 | if (currentNode->type == XML_ELEMENT_NODE) { 147 | // recurse through children 148 | LOG_DEBUG("node: %s", (char*)currentNode->name); 149 | s = loadHtmlNode(doc, currentNode->children, inParagraph, debug); 150 | if (s == STOP_REACHED) return STOP_REACHED; 151 | 152 | if (!currentText.empty() && isParagraphBoundary(nodeName)) { 153 | // process this paragraph 154 | s = processParagraph(currentText, true, debug); 155 | if (s == STOP_REACHED) return STOP_REACHED; 156 | 157 | } else if (!currentText.empty() && nodeName == "body") { 158 | // process the text that was in no paragraph 159 | s = processParagraph(currentText, false, debug); 160 | if (s == STOP_REACHED) return STOP_REACHED; 161 | finalizeCurrentReq(); 162 | } 163 | 164 | } else if (XML_TEXT_NODE == currentNode->type) { 165 | // accumulate text in current paragraph 166 | xmlChar *text; 167 | text = xmlNodeGetContent(currentNode); 168 | LOG_DEBUG("text size: %zd bytes", strlen((char*)text)); 169 | //LOG_DEBUG("text: %s", (char*)text); 170 | 171 | currentText += (char*)text; 172 | 173 | //LOG_DEBUG("textInParagraphCurrent: [%s]", currentText.c_str()); 174 | 175 | xmlFree(text); 176 | } 177 | } 178 | return REQ_OK; 179 | } 180 | 181 | 182 | int ReqDocumentHtml::loadRequirements(bool debug) 183 | { 184 | xmlDocPtr pDoc = 0; 185 | xmlNodePtr pRoot = 0; 186 | 187 | LOG_DEBUG("htmlParseFile(%s)...", fileConfig->realpath.c_str()); 188 | pDoc = htmlParseFile(fileConfig->realpath.c_str(), (const char*)"utf-8"); // TODO support other than UTF-8 189 | 190 | if (!pDoc) { 191 | PUSH_ERROR(fileConfig->id, "", "Cannot open/parse HTML file: %s", fileConfig->realpath.c_str()); 192 | return -1; 193 | } 194 | pRoot = xmlDocGetRootElement(pDoc); 195 | 196 | if (!pRoot) { 197 | PUSH_ERROR(fileConfig->id, "", "Cannot get Root of HTML file: %s", fileConfig->realpath.c_str()); 198 | return -1; 199 | } 200 | 201 | return loadHtmlNode(pDoc, pRoot, false, debug); 202 | } 203 | 204 | void ReqDocumentHtml::init() 205 | { 206 | acquisitionStarted = false; // should become true in 207 | currentRequirement = ""; 208 | } 209 | 210 | -------------------------------------------------------------------------------- /src/ReqDocumentHtml.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef _importerHtml_h 16 | #define _importerHtml_h 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include "req.h" 23 | 24 | 25 | class ReqDocumentHtml: public ReqDocument { 26 | public: 27 | ReqDocumentHtml(ReqFileConfig &c) {fileConfig = &c;} 28 | int loadRequirements(bool debug); 29 | BlockStatus processParagraph(std::string &text, bool inParagaph, bool debug); 30 | BlockStatus loadHtmlNode(xmlDocPtr doc, xmlNode *a_node, bool inParagraph, bool debug); 31 | void init(); 32 | private: 33 | std::string currentText; 34 | }; 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/ReqDocumentPdf.cpp: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | #include "config.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | typedef std::vector byte_array; 21 | 22 | 23 | #include "ReqDocumentPdf.h" 24 | #include "logging.h" 25 | #include "req.h" 26 | 27 | int ReqDocumentPdf::loadRequirements(bool debug) 28 | { 29 | LOG_DEBUG("ReqDocumentPdf::loadRequirements: %s", fileConfig->path.c_str()); 30 | init(); 31 | 32 | poppler::document *doc = poppler::document::load_from_file(fileConfig->realpath.c_str()); 33 | if (!doc) { 34 | PUSH_ERROR(fileConfig->id, "", "Cannot open file: %s", fileConfig->realpath.c_str()); 35 | return -1; 36 | } 37 | const int pagesNbr = doc->pages(); 38 | LOG_DEBUG("loadPdf: page count: %d", pagesNbr); 39 | 40 | for (int i = 0; i < pagesNbr; ++i) { 41 | LOG_DEBUG("page %d", i+1); 42 | // process the lines 43 | std::string pageLines; 44 | 45 | switch(fileConfig->encoding) { 46 | case LATIN1: 47 | pageLines = doc->create_page(i)->text().to_latin1(); 48 | break; 49 | case UTF8: 50 | default: 51 | { 52 | byte_array pageText = doc->create_page(i)->text().to_utf8(); 53 | pageLines.assign(pageText.begin(), pageText.end()); 54 | break; 55 | } 56 | } 57 | 58 | // process one line at a time 59 | const char *startOfLine = pageLines.c_str(); 60 | const char *endOfLine = 0; 61 | while (startOfLine) { 62 | endOfLine = strstr(startOfLine, "\n"); 63 | int length = 0; 64 | if (endOfLine) length = endOfLine - startOfLine; 65 | else length = strlen(startOfLine); 66 | 67 | std::string line; 68 | line.assign(startOfLine, length); 69 | 70 | if (debug) { 71 | dumpText(line.c_str()); 72 | 73 | } else { 74 | BlockStatus status = processBlock(line); 75 | if (status == STOP_REACHED) { 76 | delete doc; 77 | return 0; 78 | } 79 | } 80 | 81 | if (!endOfLine) break; 82 | if (endOfLine == startOfLine + strlen(startOfLine) - 1) break; 83 | startOfLine = endOfLine + 1; 84 | } 85 | } 86 | finalizeCurrentReq(); 87 | 88 | delete doc; 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /src/ReqDocumentPdf.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef _importerPdf_h 16 | #define _importerPdf_h 17 | 18 | #include "req.h" 19 | 20 | class ReqDocumentPdf: public ReqDocument { 21 | public: 22 | ReqDocumentPdf(ReqFileConfig &c) {fileConfig = &c;} 23 | int loadRequirements(bool debug); 24 | }; 25 | 26 | 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/ReqDocumentTxt.cpp: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | #include "config.h" 15 | 16 | #include 17 | #include 18 | 19 | #include "ReqDocumentTxt.h" 20 | #include "logging.h" 21 | #include "req.h" 22 | 23 | int ReqDocumentTxt::loadRequirements(bool debug) 24 | { 25 | init(); 26 | 27 | LOG_DEBUG("loadText: %s", fileConfig->realpath.c_str()); 28 | const int LINE_SIZE_MAX = 4096; 29 | char line[LINE_SIZE_MAX]; 30 | 31 | std::ifstream ifs(fileConfig->realpath.c_str(), std::ifstream::in); 32 | 33 | currentRequirement = ""; 34 | 35 | if (!ifs.good()) { 36 | PUSH_ERROR(fileConfig->id, "", "Cannot open file '%s': %s", fileConfig->realpath.c_str(), strerror(errno)); 37 | return -1; 38 | } 39 | 40 | int linenum = 1; 41 | while (ifs.getline(line, LINE_SIZE_MAX)) { // stop if line too long 42 | if (debug) { 43 | printf("%s", line); 44 | 45 | } else { 46 | std::string L = line; 47 | BlockStatus status = processBlock(L); 48 | if (status == STOP_REACHED) return 0; 49 | } 50 | linenum++; 51 | } 52 | if (!ifs.eof()) { 53 | PUSH_ERROR(fileConfig->id, "", "Line too long in file '%s': %d (max size=%d)", fileConfig->path.c_str(), linenum, LINE_SIZE_MAX); 54 | } 55 | finalizeCurrentReq(); 56 | 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /src/ReqDocumentTxt.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef _importerTxt_h 16 | #define _importerTxt_h 17 | 18 | #include "req.h" 19 | 20 | 21 | class ReqDocumentTxt: public ReqDocument { 22 | public: 23 | ReqDocumentTxt(ReqFileConfig &c) {fileConfig = &c;} 24 | int loadRequirements(bool debug); 25 | }; 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /src/StringIt.cpp: -------------------------------------------------------------------------------- 1 | /* Reqflw 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | #include "config.h" 15 | 16 | #include 17 | 18 | #include "StringIt.h" 19 | 20 | 21 | StringIt::StringIt(const std::string &str, const char *separator, int opts = 0) : currentString(str) 22 | { 23 | options(opts); 24 | currentPosition = 0; 25 | 26 | } 27 | 28 | std::string StringIt::next(const char *alternateSeparator) 29 | { 30 | 31 | } 32 | -------------------------------------------------------------------------------- /src/StringIt.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | /** String Iterator 16 | * 17 | */ 18 | 19 | #ifndef _stringIt_h 20 | #define _stringIt_h 21 | 22 | #include 23 | 24 | 25 | 26 | class StringIt { 27 | public: 28 | enum Options { 29 | COLLAPSE_SEP, // multiple consecutive separators are to be considered as one 30 | ANY_SEP = 2, // each of the characters in the 'separator' is a separator 31 | // otherwise the separator is a multi-character separator 32 | }; 33 | StringIt(); 34 | StringIt(const std::string& str, const char *separator, int opts = 0); 35 | std::string next(const char *alternateSeparator = 0); 36 | private: 37 | const std::string ¤tString; 38 | size_t currentPosition; 39 | int options; 40 | const char *separator; 41 | }; 42 | 43 | 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/config.h.in: -------------------------------------------------------------------------------- 1 | /* src/config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define to 1 if you have the header file. */ 4 | #undef HAVE_FCNTL_H 5 | 6 | /* Define to 1 if you have the `gettimeofday' function. */ 7 | #undef HAVE_GETTIMEOFDAY 8 | 9 | /* Define to 1 if you have the header file. */ 10 | #undef HAVE_INTTYPES_H 11 | 12 | /* Define to 1 if you have the `localtime' function. */ 13 | #undef HAVE_LOCALTIME 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #undef HAVE_MEMORY_H 17 | 18 | /* Define to 1 if you have the `regcomp' function. */ 19 | #undef HAVE_REGCOMP 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_STDINT_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_STDLIB_H 26 | 27 | /* Define to 1 if you have the `strcasecmp' function. */ 28 | #undef HAVE_STRCASECMP 29 | 30 | /* Define to 1 if you have the `strchr' function. */ 31 | #undef HAVE_STRCHR 32 | 33 | /* Define to 1 if you have the `strerror' function. */ 34 | #undef HAVE_STRERROR 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #undef HAVE_STRINGS_H 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #undef HAVE_STRING_H 41 | 42 | /* Define to 1 if you have the `strstr' function. */ 43 | #undef HAVE_STRSTR 44 | 45 | /* Define to 1 if you have the `strtoul' function. */ 46 | #undef HAVE_STRTOUL 47 | 48 | /* Define to 1 if you have the header file. */ 49 | #undef HAVE_SYS_STAT_H 50 | 51 | /* Define to 1 if you have the header file. */ 52 | #undef HAVE_SYS_TIME_H 53 | 54 | /* Define to 1 if you have the header file. */ 55 | #undef HAVE_SYS_TYPES_H 56 | 57 | /* Define to 1 if you have the header file. */ 58 | #undef HAVE_UNISTD_H 59 | 60 | /* Name of package */ 61 | #undef PACKAGE 62 | 63 | /* Define to the address where bug reports for this package should be sent. */ 64 | #undef PACKAGE_BUGREPORT 65 | 66 | /* Define to the full name of this package. */ 67 | #undef PACKAGE_NAME 68 | 69 | /* Define to the full name and version of this package. */ 70 | #undef PACKAGE_STRING 71 | 72 | /* Define to the one symbol short name of this package. */ 73 | #undef PACKAGE_TARNAME 74 | 75 | /* Define to the home page for this package. */ 76 | #undef PACKAGE_URL 77 | 78 | /* Define to the version of this package. */ 79 | #undef PACKAGE_VERSION 80 | 81 | /* Define to 1 if you have the ANSI C header files. */ 82 | #undef STDC_HEADERS 83 | 84 | /* Version number of package */ 85 | #undef VERSION 86 | 87 | /* Define to `__inline__' or `__inline' if that's what the C compiler 88 | calls it, or to nothing if 'inline' is not supported under any name. */ 89 | #ifndef __cplusplus 90 | #undef inline 91 | #endif 92 | 93 | /* Define to `int' if does not define. */ 94 | #undef mode_t 95 | 96 | /* Define to `unsigned int' if does not define. */ 97 | #undef size_t 98 | -------------------------------------------------------------------------------- /src/dateTools.cpp: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | #include "config.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "global.h" 21 | #include "dateTools.h" 22 | 23 | std::string epochToString(time_t t) 24 | { 25 | struct tm *tmp; 26 | tmp = localtime(&t); 27 | char datetime[100+1]; // should be enough 28 | strftime(datetime, sizeof(datetime)-1, "%d %b %Y, %H:%M:%S", tmp); 29 | 30 | return std::string(datetime); 31 | } 32 | 33 | /** Return the duration since that time 34 | * @return "x days", or "x months", or "x hours", etc. 35 | */ 36 | std::string epochToStringDelta(time_t t) 37 | { 38 | char datetime[100+1]; // should be enough 39 | //strftime(datetime, sizeof(datetime)-1, "%Y-%m-%d %H:%M:%S", tmp); 40 | time_t delta = time(0) - t; 41 | if (delta < 60) snprintf(datetime, sizeof(datetime)-1, "%ld %s", delta, _("s")); 42 | else if (delta < 60*60) snprintf(datetime, sizeof(datetime)-1, "%ld %s", delta/60, _("min")); 43 | else if (delta < 60*60*24) snprintf(datetime, sizeof(datetime)-1, "%ld %s", delta/60/60, _("h")); 44 | else if (delta < 60*60*24*31) snprintf(datetime, sizeof(datetime)-1, "%ld %s", delta/60/60/24, _("day")); 45 | else if (delta < 60*60*24*365) snprintf(datetime, sizeof(datetime)-1, "%ld %s", delta/60/60/24/30, _("month")); 46 | else if (delta > 0) snprintf(datetime, sizeof(datetime)-1, "%ld %s", delta/60/60/24/30/365, _("year")); 47 | else return epochToString(t); 48 | 49 | 50 | return std::string(datetime); 51 | } 52 | 53 | std::string getDatetime() 54 | { 55 | struct tm *date; 56 | struct timeval tv; 57 | gettimeofday(&tv, 0); 58 | date = localtime(&tv.tv_sec); 59 | //int milliseconds = tv.tv_usec / 1000; 60 | char buffer[100]; 61 | sprintf(buffer, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d", date->tm_year + 1900, 62 | date->tm_mon + 1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec); 63 | return buffer; 64 | } 65 | 66 | /** Return timestamp suitable for a file path 67 | * Format: 20141231-235959 68 | */ 69 | std::string getDatetimePath() 70 | { 71 | struct tm *date; 72 | struct timeval tv; 73 | gettimeofday(&tv, 0); 74 | date = localtime(&tv.tv_sec); 75 | //int milliseconds = tv.tv_usec / 1000; 76 | char buffer[100]; 77 | sprintf(buffer, "%.4d%.2d%.2d-%.2d%.2d%.2d", date->tm_year + 1900, 78 | date->tm_mon + 1, date->tm_mday, date->tm_hour, date->tm_min, date->tm_sec); 79 | return buffer; 80 | } 81 | -------------------------------------------------------------------------------- /src/dateTools.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef _dateTools_h 16 | #define _dateTools_h 17 | 18 | #include 19 | 20 | std::string epochToString(time_t t); 21 | std::string epochToStringDelta(time_t t); 22 | std::string getDatetime(); 23 | std::string getDatetimePath(); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /src/global.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef _global_h 16 | #define _global_h 17 | 18 | // prepare for gettext 19 | #define _(String) (String) 20 | 21 | #define FOREACH(var, container) for (var=container.begin(); var!= container.end(); var++) 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /src/logging.cpp: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | #include "config.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "logging.h" 21 | 22 | bool doPrint(enum LogLevel msgLevel) 23 | { 24 | const char *envLevel = getenv("REQ_DEBUG"); 25 | enum LogLevel policy = LL_INFO; // default value 26 | if (envLevel) { 27 | if (0 == strcmp(envLevel, "FATAL")) policy = LL_FATAL; 28 | else if (0 == strcmp(envLevel, "ERROR")) policy = LL_ERROR; 29 | else if (0 == strcmp(envLevel, "INFO")) policy = LL_INFO; 30 | else if (0 == strcmp(envLevel, "DEBUG")) policy = LL_DEBUG; 31 | else policy = LL_INFO; 32 | } 33 | return (policy >= msgLevel); 34 | } 35 | 36 | FILE *FD_OUT = stdout; // default is stdout 37 | 38 | void initOutputFd(const char *file) 39 | { 40 | FD_OUT = fopen(file, "wb"); 41 | if (NULL == FD_OUT) { 42 | LOG_DEBUG("Could not open file '%s', %s", file, strerror(errno)); 43 | exit(1); 44 | } 45 | } 46 | 47 | void closeOutputFd() 48 | { 49 | fclose(FD_OUT); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/logging.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef _logging_h 16 | #define _logging_h 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | #include 25 | 26 | #include "dateTools.h" 27 | 28 | enum LogLevel { 29 | LL_FATAL, 30 | LL_ERROR, 31 | LL_INFO, 32 | LL_DEBUG 33 | }; 34 | 35 | extern FILE *FD_OUT; 36 | #define OUTPUT(...) fprintf(FD_OUT, __VA_ARGS__) 37 | 38 | void initOutputFd(const char *file); 39 | void closeOutputFd(); 40 | bool doPrint(enum LogLevel msgLevel); 41 | 42 | 43 | #define LOG_ERROR(...) do { if (doPrint(LL_ERROR)) { LOG("ERROR", __VA_ARGS__); } } while (0) 44 | #define LOG_INFO(...) do { if (doPrint(LL_INFO)) { LOG("INFO ", __VA_ARGS__); } } while (0) 45 | #define LOG_DEBUG(...) do { if (doPrint(LL_DEBUG)) { LOG("DEBUG", __VA_ARGS__); } } while (0) 46 | 47 | #define LOG(_level, ...) if (doPrint(LL_DEBUG)) LOG_FULL(_level, __FILE__, __LINE__, __VA_ARGS__); \ 48 | else { LOG_SHORT(_level, __VA_ARGS__); } 49 | 50 | #define LOG_FULL(_level, _file, _line, ...) do { \ 51 | fprintf(stderr, "%s %s %s:%d ", getDatetime().c_str(), _level, _file, _line); \ 52 | fprintf(stderr, __VA_ARGS__); \ 53 | fprintf(stderr, "\n"); \ 54 | } while (0) 55 | 56 | #define LOG_SHORT(_level, ...) do { \ 57 | fprintf(stderr, "%s ", _level); \ 58 | fprintf(stderr, __VA_ARGS__); \ 59 | fprintf(stderr, "\n"); \ 60 | } while (0) 61 | 62 | 63 | 64 | class FuncScope { 65 | public: 66 | FuncScope(const char *file, int line, const char *name) { 67 | funcName = name; if (doPrint(LL_DEBUG)) { LOG_FULL("FUNC ", file, line, "Entering %s...", funcName); } 68 | } 69 | ~FuncScope() { if (doPrint(LL_DEBUG)) { LOG("FUNC ", "Leaving %s...", funcName); } } 70 | private: 71 | const char *funcName; 72 | }; 73 | 74 | #define LOG_FUNC() FuncScope __fs(__FILE__, __LINE__, __func__); 75 | 76 | 77 | #endif 78 | -------------------------------------------------------------------------------- /src/main_pdf.cpp: -------------------------------------------------------------------------------- 1 | 2 | // g++ pdf.cpp -lpoppler-cpp 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | using namespace std; 9 | 10 | int main(int argc, char **argv) 11 | { 12 | poppler::document *doc = poppler::document::load_from_file(argv[1]); 13 | const int pagesNbr = doc->pages(); 14 | cout << "page count: " << pagesNbr << endl; 15 | 16 | for (int i = 0; i < pagesNbr; ++i) 17 | cout << doc->create_page(i)->text().to_latin1().c_str() << endl; 18 | } 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/main_regex.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void usage() 9 | { 10 | printf("Usage: regex \n"); 11 | exit(1); 12 | } 13 | int main(int argc, char *argv[]) 14 | { 15 | if (argc < 3) usage(); 16 | 17 | regex_t regex; 18 | int reti; 19 | char msgbuf[100]; 20 | 21 | /* Compile regular expression */ 22 | reti = regcomp(®ex, argv[1], 0); 23 | if (reti) { 24 | fprintf(stderr, "Could not compile regex\n"); 25 | exit(1); 26 | } 27 | 28 | /* Execute regular expression */ 29 | 30 | const int N = 5; 31 | regmatch_t pmatch[N]; 32 | 33 | char buffer[256]; 34 | const char *text = argv[2]; 35 | reti = regexec(®ex, text, N, pmatch, 0); 36 | int i; 37 | for (i=0; i<100; i++) reti = regexec(®ex, text, N, pmatch, 0); 38 | 39 | 40 | 41 | if (!reti) { 42 | puts("Match: \n"); 43 | int i; 44 | for (i=0; i 3 | #include 4 | 5 | #include "stringTools.h" 6 | 7 | void test(const char *s1, const char *s2) 8 | { 9 | 10 | stringCompare S; 11 | printf("lessThan(%s, %s) = %d\n", s1, s2, S(s1, s2)); 12 | } 13 | 14 | int main() 15 | { 16 | std::map m; 17 | 18 | //test("p3.1.10", "p3.1.10a"); 19 | //test("p3.1.10a", "p3.1.10"); 20 | 21 | m["p2.10"] = 0; 22 | m["p2.1"] = 0; 23 | m["p3.1.9"] = 0; 24 | m["p3.1.10"] = 0; 25 | m["p3.1.10a"] = 0; 26 | m["p3.2"] = 0; 27 | m["p2.2"] = 0; 28 | m["p2.2.1"] = 0; 29 | m["p2.1.1"] = 0; 30 | m["p2.1.2"] = 0; 31 | 32 | printf("size: %zd\n", m.size()); 33 | 34 | std::map::iterator i; 35 | for (i = m.begin(); i != m.end(); i++) { 36 | printf("%s\n", i->first.c_str()); 37 | } 38 | 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /src/main_unzip.c: -------------------------------------------------------------------------------- 1 | 2 | /* gcc unzip.c -lzip */ 3 | #include 4 | #include 5 | #include 6 | 7 | int main(int argc, char **argv) { 8 | struct zip *zip_file; 9 | struct zip_file *file_in_zip; 10 | int err; 11 | int files_total; 12 | int r; 13 | char buffer[10000]; 14 | 15 | if (argc < 2) { 16 | fprintf(stderr,"usage: %s \n",argv[0]); 17 | return -1; 18 | }; 19 | 20 | zip_file = zip_open(argv[1], 0, &err); 21 | if (!zip_file) { 22 | fprintf(stderr,"Error: can't open file %s\n",argv[1]); 23 | return -1; 24 | }; 25 | 26 | files_total = zip_get_num_files(zip_file); 27 | printf("%d files\n", files_total); 28 | 29 | int i = 0; 30 | for (i = 0; i 0) { 36 | printf("read %d bytes...\n", r); 37 | } 38 | zip_fclose(file_in_zip); 39 | } else { 40 | fprintf(stderr,"Error: can't open file %d in zip\n", i); 41 | } 42 | } 43 | zip_close(zip_file); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/main_xml.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /** 8 | * print_element_names: 9 | * @a_node: the initial xml node to consider. 10 | * 11 | * Prints the names of the all the xml elements 12 | * that are siblings or children of a given xml node. 13 | */ 14 | static void print_element_names(xmlDocPtr doc, xmlNode * a_node) 15 | { 16 | xmlNode *cur_node = NULL; 17 | 18 | for (cur_node = a_node; cur_node; cur_node = cur_node->next) { 19 | if (cur_node->type == XML_ELEMENT_NODE) { 20 | printf("node type: Element, name: %s\n", cur_node->name); 21 | } else if (XML_TEXT_NODE == cur_node->type) { 22 | xmlChar *key; 23 | //key = xmlNodeListGetString(doc, cur_node, 1); 24 | key = xmlNodeListGetRawString(doc, cur_node, 1); 25 | printf("text node: %s\n", key); 26 | xmlFree(key); 27 | } 28 | 29 | print_element_names(doc, cur_node->children); 30 | } 31 | } 32 | int main(int argc, char **argv) 33 | { 34 | LIBXML_TEST_VERSION 35 | char *filename; 36 | 37 | if (argc < 2) { 38 | fprintf(stderr, "Usage: %s filename.xml\n", argv[0]); 39 | return 1; 40 | } 41 | filename = argv[1]; 42 | 43 | xmlDocPtr document; 44 | xmlNode *root, *first_child, *node; 45 | 46 | document = xmlReadFile(filename, NULL, 0); 47 | root = xmlDocGetRootElement(document); 48 | 49 | print_element_names(document, root); 50 | 51 | fprintf(stdout, "Root is <%s> (%i)\n", root->name, root->type); 52 | first_child = root->children; 53 | for (node = first_child; node; node = node->next) { 54 | fprintf(stdout, "\t Child is <%s> (%i)\n", node->name, node->type); 55 | } 56 | fprintf(stdout, "...\n"); 57 | return 0; 58 | } 59 | -------------------------------------------------------------------------------- /src/parseConfig.cpp: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | #include "config.h" 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | 28 | #include "parseConfig.h" 29 | #include "logging.h" 30 | #include "global.h" 31 | 32 | /** Parse a text buffer and return a list of lines of tokens 33 | * 34 | * The syntax is: 35 | * text := line * 36 | * line := token * [ '\\' '\n' line ] * 37 | * token := simple-token | double-quote-token | boundary-token 38 | * simple-token := [^ \t\n\r"] * 39 | * double-quote-token := '"' [^"] * '"' 40 | * boundary-token := '<' boundary '\n' any-text '\n' boundary 41 | */ 42 | std::list > parseConfigTokens(const char *buf, size_t len) 43 | { 44 | std::list > linesOftokens; 45 | size_t i = 0; 46 | enum State { 47 | P_READY, 48 | P_IN_DOUBLE_QUOTES, 49 | P_IN_BACKSLASH, 50 | P_IN_COMMENT, 51 | P_IN_BACKSLASH_IN_DOUBLE_QUOTES, 52 | P_IN_BOUNDARY_HEADER, 53 | P_IN_BOUNDARY 54 | }; 55 | enum State state = P_READY; 56 | std::string token; // current token 57 | std::list line; // current line 58 | std::string boundary; 59 | std::string boundedText; 60 | bool tokenPending = false; 61 | 62 | for (i=0; i 0) { linesOftokens.push_back(line); line.clear(); } 68 | state = P_READY; 69 | } 70 | break; 71 | 72 | case P_IN_BACKSLASH: 73 | if (c == '\n') { // new line escaped 74 | // nothing particular here, continue on next line 75 | state = P_READY; 76 | } else if (c == '\r') { // ignore this 77 | 78 | } else { 79 | tokenPending = true; 80 | token += c; 81 | state = P_READY; 82 | } 83 | break; 84 | 85 | case P_IN_DOUBLE_QUOTES: 86 | if (c == '\\') { 87 | state = P_IN_BACKSLASH_IN_DOUBLE_QUOTES; 88 | } else if (c == '"') { 89 | // end of double-quoted string 90 | 91 | state = P_READY; 92 | } else token += c; 93 | break; 94 | case P_IN_BACKSLASH_IN_DOUBLE_QUOTES: 95 | token += c; 96 | state = P_IN_DOUBLE_QUOTES; 97 | break; 98 | case P_IN_BOUNDARY_HEADER: 99 | if (c == '\n') { 100 | state = P_IN_BOUNDARY; 101 | boundary.insert(0, "\n"); // add a \n at the beginning 102 | boundedText.clear(); 103 | } else if (isblank(c)) continue; // ignore blanks 104 | else { 105 | boundary += c; 106 | } 107 | break; 108 | case P_IN_BOUNDARY: 109 | // check if boundary was reached 110 | if (boundedText.size() >= boundary.size()) { // leading \n already added 111 | size_t bsize = boundary.size(); 112 | size_t offset = boundedText.size() - bsize; 113 | if (0 == boundedText.compare(offset, bsize, boundary)) { 114 | // boundary found 115 | // substract the boundary fro the text 116 | boundedText = boundedText.substr(0, offset); 117 | state = P_READY; 118 | line.push_back(boundedText); 119 | boundedText.clear(); 120 | linesOftokens.push_back(line); 121 | line.clear(); 122 | tokenPending = false; 123 | } 124 | } 125 | // accumulate character if still in same state 126 | if (state == P_IN_BOUNDARY) boundedText += c; 127 | 128 | break; 129 | case P_READY: 130 | default: 131 | if (c == '\n') { 132 | if (tokenPending) { line.push_back(token); token.clear(); tokenPending = false;} 133 | if (line.size() > 0) { linesOftokens.push_back(line); line.clear(); } 134 | } else if (c == ' ' || c == '\t' || c == '\r') { 135 | // current toke is done (because c is a token delimiter) 136 | if (tokenPending) { line.push_back(token); token.clear(); tokenPending = false;} 137 | } else if (c == '#') { 138 | if (tokenPending) { line.push_back(token); token.clear(); tokenPending = false;} 139 | state = P_IN_COMMENT; 140 | } else if (c == '\\') { 141 | state = P_IN_BACKSLASH; 142 | } else if (c == '"') { 143 | tokenPending = true; 144 | state = P_IN_DOUBLE_QUOTES; 145 | } else if (c == '<') { 146 | tokenPending = true; 147 | state = P_IN_BOUNDARY_HEADER; 148 | boundary.clear(); 149 | } else if (c == '\r') { 150 | // ignore 151 | } else { 152 | tokenPending = true; 153 | token += c; 154 | } 155 | break; 156 | } 157 | } 158 | // purge remaininig token and line 159 | if (tokenPending) line.push_back(token); 160 | if (line.size() > 0) linesOftokens.push_back(line); 161 | 162 | return linesOftokens; 163 | } 164 | 165 | // DEPRECATED 166 | // Allocate a buffer (malloc) and load a file into this buffer. 167 | // @return the number of bytes read (that is also the size of the buffer) 168 | // -1 in case of error 169 | // If the file is empty, 0 is returned and the buffer is not allocated. 170 | // It is up to the caller to free the buffer (if the return value is > 0). 171 | int loadFile(const char *filepath, const char **data) 172 | { 173 | //LOG_DEBUG("Loading file '%s'...", filepath); 174 | *data = 0; 175 | FILE *f = fopen(filepath, "rb"); 176 | if (NULL == f) { 177 | LOG_DEBUG("Could not open file '%s', %s", filepath, strerror(errno)); 178 | return -1; 179 | } 180 | // else continue and parse the file 181 | 182 | int r = fseek(f, 0, SEEK_END); // go to the end of the file 183 | if (r != 0) { 184 | LOG_ERROR("could not fseek(%s): %s", filepath, strerror(errno)); 185 | fclose(f); 186 | return -1; 187 | } 188 | long filesize = ftell(f); 189 | if (filesize > 4*1024*1024) { // max 4 MByte 190 | LOG_ERROR("loadFile: file '%s'' over-sized (%ld bytes)", filepath, filesize); 191 | fclose(f); 192 | return -1; 193 | } 194 | 195 | if (0 == filesize) { 196 | // the file is empty 197 | fclose(f); 198 | return 0; 199 | } 200 | 201 | rewind(f); 202 | char *buffer = (char *)malloc(filesize+1); // allow +1 for terminating null char 203 | long n = fread(buffer, 1, filesize, f); 204 | if (n != filesize) { 205 | LOG_ERROR("fread(%s): short read. feof=%d, ferror=%d", filepath, feof(f), ferror(f)); 206 | fclose(f); 207 | free(buffer); 208 | return -1; 209 | } 210 | buffer[filesize] = 0; 211 | *data = buffer; 212 | fclose(f); 213 | return n; 214 | } 215 | 216 | // Load the contents of a file in string 217 | // @return the number of bytes read (that is also the size of the buffer) 218 | // -1 in case of error 219 | int loadFile(const char *filepath, std::string &contents) 220 | { 221 | if (0 == strcmp(filepath, "-")) { 222 | std::string line; 223 | while (getline(std::cin, line)) { 224 | if (contents.size()) contents += "\n"; 225 | contents += line; 226 | } 227 | 228 | } else { 229 | std::ifstream f; 230 | f.open(filepath, std::ios::in | std::ios::binary); 231 | 232 | if (!f) { 233 | LOG_ERROR("Cannot open file '%s': %s", filepath, strerror(errno)); 234 | return -1; 235 | } 236 | 237 | f.seekg(0, std::ios::end); 238 | contents.resize(f.tellg()); 239 | f.seekg(0, std::ios::beg); 240 | f.read(&contents[0], contents.size()); 241 | if (f.bad()) { 242 | LOG_ERROR("Read error '%s': %s", filepath, strerror(errno)); 243 | return -1; 244 | } 245 | } 246 | return contents.size(); 247 | } 248 | 249 | 250 | /** Write a string to a file 251 | * 252 | * @return 253 | * 0 if success 254 | * <0 if error 255 | */ 256 | int writeToFile(const char *filepath, const std::string &data) 257 | { 258 | return writeToFile(filepath, data.data(), data.size()); 259 | } 260 | 261 | int writeToFile(const char *filepath, const char *data, size_t len) 262 | { 263 | int result = 0; 264 | mode_t mode = O_CREAT | O_TRUNC | O_WRONLY; 265 | int flags = S_IRUSR; 266 | #if defined(_WIN32) 267 | mode |= O_BINARY; 268 | flags |= S_IWUSR; 269 | #endif 270 | 271 | std::string tmp = filepath; 272 | tmp += ".tmp"; 273 | int f = open(tmp.c_str(), mode, flags); 274 | if (-1 == f) { 275 | LOG_ERROR("Could not create file '%s', (%d) %s", tmp.c_str(), errno, strerror(errno)); 276 | return -1; 277 | } 278 | 279 | if (len > 0) { 280 | size_t n = write(f, data, len); 281 | if (n != len) { 282 | LOG_ERROR("Could not write all data, incomplete file '%s': (%d) %s", 283 | filepath, errno, strerror(errno)); 284 | return -1; 285 | } 286 | } 287 | 288 | close(f); 289 | 290 | #if defined(_WIN32) 291 | _unlink(filepath); 292 | #endif 293 | 294 | int r = rename(tmp.c_str(), filepath); 295 | if (r != 0) { 296 | LOG_ERROR("Cannot rename '%s' -> '%s': (%d) %s", tmp.c_str(), filepath, errno, strerror(errno)); 297 | return -1; 298 | } 299 | 300 | return result; 301 | } 302 | -------------------------------------------------------------------------------- /src/parseConfig.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef _parseConfig_h 16 | #define _parseConfig_h 17 | 18 | #include 19 | #include 20 | #include 21 | 22 | std::list > parseConfigTokens(const char *buf, size_t len); 23 | 24 | int loadFile(const char *filepath, const char **data); 25 | int loadFile(const char *filepath, std::string &contents); 26 | int writeToFile(const char *filepath, const std::string &data); 27 | int writeToFile(const char *filepath, const char *data, size_t len); 28 | 29 | std::string serializeSimpleToken(const std::string token); 30 | std::string serializeProperty(const std::string &key, const std::list &values); 31 | std::string doubleQuote(const std::string &input); 32 | std::string popListToken(std::list &tokens); 33 | std::string serializeTokens(const std::list > &linesOfTokens); 34 | 35 | 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/renderingHtml.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef _renderingHtml_h 16 | #define _renderingHtml_h 17 | 18 | #include 19 | #include 20 | 21 | #include "req.h" 22 | 23 | 24 | void htmlRender(const std::string &cmdline, int argc, const char **argv); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/req.h: -------------------------------------------------------------------------------- 1 | /* Reqflow 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | 15 | #ifndef _req_h 16 | #define _req_h 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #include "stringTools.h" 25 | 26 | #define DEFAULT_CONF "conf.req" 27 | 28 | enum Encoding { UTF8, LATIN1 }; 29 | enum BlockStatus { NOT_STARTED, STOP_REACHED, REQ_OK }; 30 | enum ReqSorting { SORT_DOCUMENT, SORT_ALPHANUMERIC }; 31 | 32 | struct Requirement; 33 | 34 | enum ReqFileType { RF_TEXT, RF_ODT, RF_DOCX, RF_XSLX, RF_DOCX_XML, RF_HTML, RF_PDF, RF_UNKNOWN }; 35 | 36 | 37 | /** Functor for comparing requirements 38 | * 39 | * Usable in std::sort or containers std::set and std::map. 40 | */ 41 | struct ReqCompare 42 | { 43 | bool operator()(const Requirement *a, const Requirement *b) const; 44 | }; 45 | 46 | struct ReqFileConfig { 47 | std::string id; 48 | std::string path; // path setup in .req file 49 | std::string realpath; // path computed relatively to the dir of .req file 50 | std::string reqPattern; 51 | regex_t *reqRegex; 52 | std::string refPattern; 53 | regex_t *refRegex; 54 | std::string startAfter; 55 | regex_t *startAfterRegex; 56 | std::string stopAfter; 57 | regex_t *stopAfterRegex; 58 | std::map endReq; 59 | std::map endReqStyle; 60 | ReqFileType type; // this is the type as specified via option "-type" 61 | std::string prefixReq; 62 | enum SortMode { SORT_DOCUMENT_ORDER, SORT_ALPHANUMERIC_ORDER, SORT_UNKNOWN }; 63 | SortMode sortMode; 64 | 65 | // for dependency graph 66 | std::set upstreamDocuments; 67 | std::set downstreamDocuments; 68 | 69 | // pointers to requirements stored in the global map 'Requirements' 70 | // TODO replace by a std::set and have the compare function 71 | // chose either document order or alphanumeric order 72 | std::set requirements; // use a map to keep them sorted 73 | int nTotalRequirements; 74 | int nCoveredRequirements; 75 | Encoding encoding; 76 | 77 | // indicate if no coverage check should be done on this document 78 | // ie: no forward traceability is printed and no uncovered status neither 79 | bool nocov; 80 | 81 | 82 | ReqFileConfig(): reqRegex(0), refRegex(0), startAfterRegex(0), stopAfterRegex(0), type(RF_UNKNOWN), 83 | nTotalRequirements(0), nCoveredRequirements(0), encoding(UTF8), nocov(false) {} 84 | static ReqFileType getFileTypeByExtension(const std::string &extension); 85 | static ReqFileType getFileTypeByCode(const std::string &code); 86 | static std::string getFileTypeCodes(); 87 | 88 | SortMode getSortMode(const std::string &text); 89 | 90 | ReqFileType getFileType(); 91 | }; 92 | 93 | struct Requirement { 94 | std::string id; 95 | int seqnum; // sequence number in document order 96 | ReqFileConfig *parentDocument; 97 | std::set covers; 98 | std::set coveredBy; 99 | std::string text; 100 | }; 101 | 102 | /* Optional CSS file for html output */ 103 | extern std::string htmlcss; 104 | 105 | extern std::map ReqConfig; 106 | // storage for all requirements 107 | // this storage needs not be sorted in a specific manner 108 | // pointers to the requirements are also kept in the ReqFileConfig objects 109 | extern std::map Requirements; 110 | extern std::map > > Errors; // errors indexed by file 111 | extern int ReqTotal; 112 | extern int ReqCovered; 113 | 114 | int getErrorNumber(); 115 | int hasErrors(const std::string &file); 116 | 117 | class ReqDocument { 118 | public: 119 | ReqDocument() { reqSeqnum = 0; } 120 | virtual int loadRequirements(bool debug) = 0; 121 | BlockStatus processBlock(std::string &text); 122 | void finalizeCurrentReq(); 123 | protected: 124 | virtual void init(); 125 | bool acquisitionStarted; // indicate if the parsing passed the point after which requirement may be acquired 126 | std::string currentRequirement; 127 | std::string textOfCurrentReq; 128 | std::string currentText; 129 | ReqFileConfig *fileConfig; 130 | int reqSeqnum; // last sequence number used for a requirement 131 | }; 132 | 133 | #define BF_SZ 1024 134 | #define PUSH_ERROR(_file, _req, ...) do { \ 135 | char buffer[BF_SZ]; \ 136 | snprintf(buffer, BF_SZ, __VA_ARGS__); \ 137 | Errors[_file].push_back(std::make_pair(_req, buffer)); \ 138 | } while(0) 139 | 140 | enum PolicyEraseExtracted { ERASE_NONE, ERASE_ALL, ERASE_LAST }; 141 | 142 | // exported functions 143 | 144 | void dumpText(const char *text); 145 | void printErrors(); 146 | Requirement *getRequirement(std::string id); 147 | ReqFileConfig *getDocument(std::string docId); 148 | void consolidateCoverage(); 149 | void checkUndefinedRequirements(); 150 | std::string extractPattern(regex_t *regex, std::string &text, PolicyEraseExtracted erase = ERASE_NONE); 151 | std::set extractAllPatterns(regex_t *regex, std::string &text); 152 | 153 | void computeGlobalStatistics(); 154 | 155 | 156 | #endif 157 | -------------------------------------------------------------------------------- /src/stringTools.cpp: -------------------------------------------------------------------------------- 1 | /* Reqflw 2 | * Copyright (C) 2014 Frederic Hoerni 3 | * 4 | * This program is free software; you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation; either version 2 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | */ 14 | #include "config.h" 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | 21 | #include "stringTools.h" 22 | #include "global.h" 23 | 24 | 25 | /** Remove characters at the end of string 26 | */ 27 | void trimRight(std::string &s, const char *c) 28 | { 29 | size_t i = s.size()-1; 30 | while ( (i>=0) && strchr(c, s[i]) ) i--; 31 | 32 | if (i < 0) s = ""; 33 | else s = s.substr(0, i+1); 34 | } 35 | 36 | /** Remove characters at the beginning of string 37 | */ 38 | void trimLeft(std::string &s, const char* c) 39 | { 40 | size_t i = 0; 41 | while ( (s.size() > i) && strchr(c, s[i]) ) i++; 42 | 43 | if (i >= s.size()) s = ""; 44 | else s = s.substr(i); 45 | } 46 | 47 | void trim(std::string &s, const char *c) 48 | { 49 | trimLeft(s, c); 50 | trimRight(s, c); 51 | } 52 | 53 | void trimBlanks(std::string &s) 54 | { 55 | trimLeft(s, "\n\t\r "); 56 | trimRight(s, "\n\t\r "); 57 | } 58 | 59 | void trimExtension(std::string &s) 60 | { 61 | size_t i = s.find_last_of('.'); 62 | if (i != std::string::npos) s = s.substr(0, i); 63 | } 64 | 65 | std::string pop(std::list & L) 66 | { 67 | std::string token = ""; 68 | if (!L.empty()) { 69 | token = L.front(); 70 | L.pop_front(); 71 | } 72 | return token; 73 | } 74 | 75 | 76 | std::vector split(const std::string &s, const char *c, int limit) 77 | { 78 | // use limit = -1 for no limit (almost) 79 | std::vector tokens; 80 | size_t found; 81 | 82 | int index = 0; 83 | found = s.find_first_of(c, index); 84 | while ( (found != std::string::npos) && (limit != 0) ) 85 | { 86 | tokens.push_back(s.substr(index, found-index)); 87 | 88 | index = found + 1; 89 | found = s.find_first_of(c, index); 90 | limit --; 91 | } 92 | tokens.push_back(s.substr(index)); 93 | 94 | return tokens; 95 | } 96 | 97 | std::string join(const std::list &items, const char *separator) 98 | { 99 | std::string out; 100 | std::list::const_iterator i; 101 | FOREACH(i, items) { 102 | if (i != items.begin()) out += separator; 103 | out += (*i); 104 | } 105 | return out; 106 | } 107 | 108 | /** basename / -> "" 109 | * basename . -> . 110 | * basename "" -> "" 111 | * basename a/b/c -> c 112 | * basename a/b/c/ -> c 113 | */ 114 | std::string getBasename(const std::string &path) 115 | { 116 | if (path.empty()) return ""; 117 | size_t i; 118 | #if defined(_WIN32) 119 | i = path.find_last_of("/\\"); 120 | #else 121 | i = path.find_last_of("/"); 122 | #endif 123 | if (i == std::string::npos) return path; 124 | else if (i == path.size()-1) return getBasename(path.substr(0, path.size()-1)); 125 | else return path.substr(i+1); 126 | } 127 | 128 | /** dirname 129 | * "" -> . 130 | * a/b/c -> /a/b 131 | * a/b/c/ -> /a/b 132 | */ 133 | std::string getDirname(std::string path) 134 | { 135 | if (path.empty()) return "."; 136 | size_t i; 137 | #if defined(_WIN32) 138 | const char *dirsep = "/\\"; 139 | #else 140 | const char *dirsep = "/"; 141 | #endif 142 | i = path.find_last_of(dirsep); 143 | if (i > 0 && i == path.size()-1) { 144 | // case /a/b/c/ 145 | // remove the last / and do again 146 | i = path.find_last_of(dirsep, path.size()-2); 147 | } 148 | if (i == std::string::npos) return "."; 149 | else if (i == 0) return "/"; 150 | else return path.substr(0, i); 151 | } 152 | 153 | bool isPathAbsolute(const std::string &path) 154 | { 155 | #if defined(_WIN32) 156 | if (path.size() && path[0] == '\\') return true; 157 | if (path.find(":\\") != path.npos) return true; 158 | #else 159 | if (path.size() && path[0] == '/') return true; 160 | #endif 161 | return false; 162 | } 163 | 164 | std::string replaceAll(const std::string &in, char c, const char *replaceBy) 165 | { 166 | std::string out; 167 | size_t len = in.size(); 168 | size_t i = 0; 169 | size_t savedOffset = 0; 170 | while (i < len) { 171 | if (in[i] == c) { 172 | if (savedOffset < i) out += in.substr(savedOffset, i-savedOffset); 173 | out += replaceBy; 174 | savedOffset = i+1; 175 | } 176 | i++; 177 | } 178 | if (savedOffset < i) out += in.substr(savedOffset, i-savedOffset); 179 | return out; 180 | } 181 | 182 | /** Compare 2 strings in order to have the following ordering: 183 | * REQ_1.1 184 | * REQ_1.2 185 | * REQ_1.10 186 | * REQ_3.1.1 187 | * REQ_3.17 188 | * 189 | */ 190 | bool stringCompare::operator()(const std::string &s1, const std::string &s2) const 191 | { 192 | enum mode_t { STRING, NUMBER } mode = STRING; 193 | const char *l = s1.c_str(); 194 | const char *r = s2.c_str(); 195 | 196 | while (*l && *r) { 197 | if (mode == STRING) { 198 | while (*l && *r) { 199 | // check if this are digit characters 200 | const int l_digit = isdigit(*l); 201 | const int r_digit = isdigit(*r); 202 | // if both characters are digits, we continue in NUMBER mode 203 | if (l_digit && r_digit) { 204 | mode = NUMBER; 205 | break; 206 | } 207 | // if only the left character is a digit, we have a result 208 | if (l_digit) return true; 209 | // if only the right character is a digit, we have a result 210 | if (r_digit) return false; 211 | 212 | // if they differ we have a result 213 | if (*l < *r) return true; 214 | else if (*l > *r) return false; 215 | // otherwise process the next characters 216 | l++; 217 | r++; 218 | } 219 | } else { // mode==NUMBER 220 | // get the left number 221 | char *end; 222 | unsigned long l_int = strtoul(l, &end, 0); 223 | l = end; 224 | 225 | // get the right number 226 | unsigned long r_int = strtoul(r, &end, 0); 227 | r = end; 228 | 229 | // if the difference is not equal to zero, we have a comparison result 230 | if (l_int < r_int) return true; 231 | else if (l_int > r_int) return false; 232 | 233 | // otherwise we process the next substring in STRING mode 234 | mode = STRING; 235 | } 236 | } 237 | 238 | if (*r) return true; 239 | return false; 240 | } 241 | 242 | /** Double quoting is needed when the string contains: 243 | * a " character 244 | * \n or \r 245 | * a comma , 246 | */ 247 | std::string escapeCsv(const std::string &input) 248 | { 249 | if (input.find_first_of("\n\r\",") == std::string::npos) return input; // no need for quotes 250 | 251 | size_t n = input.size(); 252 | std::string result = "\""; 253 | 254 | size_t i; 255 | for (i=0; i 19 | #include 20 | #include 21 | #include 22 | 23 | void trimLeft(std::string & s, const char *c); 24 | void trimRight(std::string &s, const char *c); 25 | void trim(std::string &s, const char *c); 26 | void trimBlanks(std::string &s); 27 | void trimExtension(std::string &s); 28 | 29 | std::string pop(std::list & L); 30 | std::vector split(const std::string &s, const char *c, int limit = -1); 31 | 32 | std::string join(const std::list &items, const char *separator); 33 | std::string getBasename(const std::string &path); 34 | std::string getDirname(std::string path); 35 | bool isPathAbsolute(const std::string &path); 36 | std::string replaceAll(const std::string &in, char c, const char *replaceBy); 37 | bool stringLessThan(std::string const &s1, std::string const &s2); 38 | struct stringCompare 39 | { 40 | bool operator()(const std::string &s1, const std::string &s2) const; 41 | }; 42 | std::string escapeCsv(const std::string &input); 43 | 44 | 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /test-driver: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # test-driver - basic testsuite driver script. 3 | 4 | scriptversion=2013-07-13.22; # UTC 5 | 6 | # Copyright (C) 2011-2014 Free Software Foundation, Inc. 7 | # 8 | # This program is free software; you can redistribute it and/or modify 9 | # it under the terms of the GNU General Public License as published by 10 | # the Free Software Foundation; either version 2, or (at your option) 11 | # any later version. 12 | # 13 | # This program is distributed in the hope that it will be useful, 14 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | # GNU General Public License for more details. 17 | # 18 | # You should have received a copy of the GNU General Public License 19 | # along with this program. If not, see . 20 | 21 | # As a special exception to the GNU General Public License, if you 22 | # distribute this file as part of a program that contains a 23 | # configuration script generated by Autoconf, you may include it under 24 | # the same distribution terms that you use for the rest of that program. 25 | 26 | # This file is maintained in Automake, please report 27 | # bugs to or send patches to 28 | # . 29 | 30 | # Make unconditional expansion of undefined variables an error. This 31 | # helps a lot in preventing typo-related bugs. 32 | set -u 33 | 34 | usage_error () 35 | { 36 | echo "$0: $*" >&2 37 | print_usage >&2 38 | exit 2 39 | } 40 | 41 | print_usage () 42 | { 43 | cat <$log_file 2>&1 108 | estatus=$? 109 | 110 | if test $enable_hard_errors = no && test $estatus -eq 99; then 111 | tweaked_estatus=1 112 | else 113 | tweaked_estatus=$estatus 114 | fi 115 | 116 | case $tweaked_estatus:$expect_failure in 117 | 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;; 118 | 0:*) col=$grn res=PASS recheck=no gcopy=no;; 119 | 77:*) col=$blu res=SKIP recheck=no gcopy=yes;; 120 | 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;; 121 | *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;; 122 | *:*) col=$red res=FAIL recheck=yes gcopy=yes;; 123 | esac 124 | 125 | # Report the test outcome and exit status in the logs, so that one can 126 | # know whether the test passed or failed simply by looking at the '.log' 127 | # file, without the need of also peaking into the corresponding '.trs' 128 | # file (automake bug#11814). 129 | echo "$res $test_name (exit status: $estatus)" >>$log_file 130 | 131 | # Report outcome to console. 132 | echo "${col}${res}${std}: $test_name" 133 | 134 | # Register the test result, and other relevant metadata. 135 | echo ":test-result: $res" > $trs_file 136 | echo ":global-test-result: $res" >> $trs_file 137 | echo ":recheck: $recheck" >> $trs_file 138 | echo ":copy-in-global-log: $gcopy" >> $trs_file 139 | 140 | # Local Variables: 141 | # mode: shell-script 142 | # sh-indentation: 2 143 | # eval: (add-hook 'write-file-hooks 'time-stamp) 144 | # time-stamp-start: "scriptversion=" 145 | # time-stamp-format: "%:y-%02m-%02d.%02H" 146 | # time-stamp-time-zone: "UTC" 147 | # time-stamp-end: "; # UTC" 148 | # End: 149 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | *.out 2 | *.log 3 | *.trs 4 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | # Enable parallel tests 2 | TESTS = req-trac.test \ 3 | req-stat.test \ 4 | req-stat-stdin.test \ 5 | req-trac-pdf.test \ 6 | req-trac-html.test \ 7 | req-stat-html2.test \ 8 | req-stat-docx-rm.test \ 9 | req-same-line.test \ 10 | req-stat-sort.test \ 11 | SPEC-with-table.test \ 12 | t_second_doc \ 13 | t_end_req \ 14 | t_multi_doc \ 15 | t_capture_algorithm 16 | 17 | # include the tests on the distribution 18 | EXTRA_DIST = . 19 | # cleanup tests results before including 20 | dist-hook: 21 | rm -f $(distdir)/.git* $(distdir)/*~ $(distdir)/*.out 22 | 23 | clean-local: 24 | rm -f *.out 25 | -------------------------------------------------------------------------------- /test/README.txt: -------------------------------------------------------------------------------- 1 | 2 | Tests scripts must be named : T_ID := "t_" 3 | (eg: t_second_doc) 4 | 5 | Execution of a test must produce a T_ID ".out" (merging of stdout and stderr). 6 | 7 | The verdict is computed by comparing T_ID ".out" and T_ID ".ref" 8 | 9 | 10 | -------------------------------------------------------------------------------- /test/SPEC-with-table.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/test/SPEC-with-table.docx -------------------------------------------------------------------------------- /test/SPEC-with-table.ref: -------------------------------------------------------------------------------- 1 | REQFLOW trac 2 | 3 | Requirements of SPEC Requirements Downstream 4 | -------------------------------------------------------------------------------------------------------------------- 5 | REQ_PRINTF_01 6 | REQ_PRINTF_02 7 | REQ_PRINTF_03 8 | REQFLOW stat 9 | U REQ_PRINTF_01 10 | U REQ_PRINTF_02 11 | U REQ_PRINTF_03 12 | REQFLOW review 13 | REQ_PRINTF_01 14 | Ref: SYS_155 15 | printf –help shall display a help message and exit 16 | 17 | REQ_PRINTF_02 18 | The FORMAT parameter shall control the output as in C printf. 19 | 20 | REQ_PRINTF_03 21 | The exit code of printf shall be: 22 | - zero if no error occurs 23 | - 1 if the FORMAT has an invalid syntax 24 | 25 | -------------------------------------------------------------------------------- /test/SPEC-with-table.req: -------------------------------------------------------------------------------- 1 | 2 | document SPEC 3 | -path SPEC-with-table.docx 4 | -req REQ_.* 5 | 6 | -------------------------------------------------------------------------------- /test/SPEC-with-table.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . ./envtest 3 | T=SPEC-with-table 4 | echo "REQFLOW trac" > $T.out 5 | $REQFLOW trac -c $TEST_ORIGIN/$T.req >> $T.out 2>&1 6 | echo "REQFLOW stat" >> $T.out 7 | $REQFLOW stat -c $TEST_ORIGIN/$T.req >> $T.out 2>&1 8 | echo "REQFLOW review" >> $T.out 9 | $REQFLOW review -c $TEST_ORIGIN/$T.req >> $T.out 2>&1 10 | diff -w $T.out $TEST_ORIGIN/$T.ref 11 | -------------------------------------------------------------------------------- /test/SPEC.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/test/SPEC.docx -------------------------------------------------------------------------------- /test/SPEC.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 22 | 23 | 24 |

    25 |
  1. Specification of the Globulus system

    26 |
27 |
    28 |
  1. Overview

    29 |
30 |

Globulus does this and that.

31 |



32 |

33 |
    34 |
  1. Requirements

    35 |
36 |


37 |

38 |

REQ_01

39 |

Globulus shall have 3 40 | legs:

41 |
    42 |
  • one for walking

    43 |
  • one for standing

    44 |
  • one for jumping

    45 |
46 |

Ref: SYS_155

47 |


48 |

49 |

REQ_02

50 |

At night Globulus shall 51 | switch to standby mode.

52 |


53 |

54 |


55 |

56 |

REQ_03

57 |

Globulus shall not make 58 | noise.

59 |


60 |

61 |


62 |

63 |
    64 |
  1. Annexe

    65 |
66 |

Summary of 67 | requirements:

68 |

69 | REQ_01

70 |

REQ_02

71 |

REQ_03

72 |


73 |

74 |


75 |

76 | 77 | -------------------------------------------------------------------------------- /test/SPEC.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/test/SPEC.pdf -------------------------------------------------------------------------------- /test/TEST-sort.txt: -------------------------------------------------------------------------------- 1 | 2 | # Test plan: 3 | 4 | ## Tests cases 5 | 6 | T_01 7 | Send command printf --help 8 | Check that the result is a help message. 9 | Ref: PRINTF_01, PRINTF_01a, PRINTF_01b 10 | Ref: PRINTF_333 11 | 12 | 13 | T_02 14 | Send command `printf "(%04d%-4s)\n" 33 aa` 15 | Check that the result is: (0033aa ) 16 | Check that the exit code is zero. 17 | Ref: PRINTF_02 18 | Ref: PRINTF_03, PRINTF_03a, PRINTF_03b 19 | 20 | 21 | T_05 22 | Send command printf x%r 23 | Check that an error is raised and that the exit code is 1 24 | Ref: PRINTF_03 25 | 26 | T_04 27 | xxx 28 | xxx2 29 | 30 | T_21 31 | Send command `which printf` 32 | Check that printf is installed in /usr/bin/printf 33 | Ref: PRINTF_06, PRINTF_12 34 | Ref: PRINTF_15 35 | 36 | T_22 37 | This is test 22. 38 | Ref: PRINTF_15 39 | Ref: PRINTF_20 40 | 41 | ## Annex: summary of tests 42 | 43 | T_01 44 | T_02 45 | T_05 46 | T_21 47 | 48 | 49 | -------------------------------------------------------------------------------- /test/TEST.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 17 | 18 | 19 |
20 | # Test plan:
21 | 
22 | ## Tests cases
23 | 
24 | T_01
25 |     do this 01
26 |     do that 01
27 |     check this 01
28 |     check that 01
29 | Ref: REQ_01
30 | Ref: REQ_02
31 | Ref: REQ_333
32 | 
33 | 
34 | T_02
35 |     do this 02
36 |     do that 02
37 |     check this 02
38 |     check that 02
39 | Ref: REQ_01
40 | 
41 | T_05
42 |     do this 05
43 |     do that 05
44 |     check this 05
45 |     check that 05
46 | Ref: REQ_03
47 | 
48 | T_21
49 |     this test is an extra test...
50 |     yyy
51 | 
52 | 
53 | ## Annex: summary of tests
54 | 
55 | 	T_01
56 | 	T_02
57 | 	T_05
58 | 
59 | 
60 | 61 | -------------------------------------------------------------------------------- /test/TEST.txt: -------------------------------------------------------------------------------- 1 | 2 | # Test plan: 3 | 4 | ## Tests cases 5 | 6 | T_01 7 | Send command printf --help 8 | Check that the result is a help message. 9 | Ref: PRINTF_01, PRINTF_01a, PRINTF_01b 10 | Ref: PRINTF_333 11 | 12 | 13 | T_02 14 | Send command `printf "(%04d%-4s)\n" 33 aa` 15 | Check that the result is: (0033aa ) 16 | Check that the exit code is zero. 17 | Ref: PRINTF_02 18 | Ref: PRINTF_03, PRINTF_03a, PRINTF_03b 19 | 20 | 21 | T_05 22 | Send command printf x%r 23 | Check that an error is raised and that the exit code is 1 24 | Ref: PRINTF_03 25 | 26 | T_21 27 | Send command `which printf` 28 | Check that printf is installed in /usr/bin/printf 29 | Ref: PRINTF_06, PRINTF_12 30 | Ref: PRINTF_15 31 | 32 | T_22 33 | This is test 22. 34 | Ref: PRINTF_15 35 | Ref: PRINTF_20 36 | 37 | ## Annex: summary of tests 38 | 39 | T_01 40 | T_02 41 | T_05 42 | T_21 43 | 44 | 45 | -------------------------------------------------------------------------------- /test/TEST2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |

TST_0001

6 | some text... 7 | 8 | 9 | 10 |
x1x2
x1x2
11 |

TST_0002

12 | some text... 13 |

TST_0003

14 | some text... 15 |

TST_0004

16 | some text... 17 | 18 | 19 | -------------------------------------------------------------------------------- /test/conf.req: -------------------------------------------------------------------------------- 1 | 2 | define REQ_PATTERN PRINTF_[-a-zA-Z0-9_]* 3 | define ALPHANUM [-a-zA-Z0-9_] 4 | document SPEC 5 | -path SPEC.docx 6 | -req REQ_PATTERN 7 | -stop-after Annexe -ref "Ref: +(.*)" 8 | -end-req-style toto -end-req tutu 9 | -sort alphanum 10 | 11 | document TEST -path TEST.txt 12 | -req T_[-a-zA-Z0-9_]* 13 | -ref "Ref:[, ]*(ALPHANUM+)" 14 | -stop-after "Annex" 15 | -start-after "Tests cases" 16 | -nocov 17 | -sort document 18 | 19 | # -type txt 20 | # -prefix SPEC- 21 | 22 | -------------------------------------------------------------------------------- /test/docx_rev_marks.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/test/docx_rev_marks.docx -------------------------------------------------------------------------------- /test/docx_rev_marks.req: -------------------------------------------------------------------------------- 1 | 2 | document SPEC 3 | -path docx_rev_marks.docx 4 | -req REQ_.* 5 | 6 | -------------------------------------------------------------------------------- /test/envtest.in: -------------------------------------------------------------------------------- 1 | export TEST_ORIGIN=@srcdir@ 2 | if [ x@EXEEXT@ = x.exe ]; then WINE=wine 3 | else WINE=""; fi 4 | export REQFLOW="$WINE ../reqflow@EXEEXT@" 5 | 6 | # test fails at first error 7 | set -e 8 | -------------------------------------------------------------------------------- /test/functions: -------------------------------------------------------------------------------- 1 | 2 | test_run() { 3 | echo ">>>" $* | sed -e "s!$REQFLOW! REQFLOW!" >> $T.out 4 | # separate, then merge stdout and stderr, in order 5 | # to have a deterministic order of lines 6 | eval "$* > $T.stdout 2>$T.stderr" 7 | cat $T.stderr $T.stdout >> $T.out 8 | echo >> $T.out 9 | } 10 | 11 | -------------------------------------------------------------------------------- /test/html.req: -------------------------------------------------------------------------------- 1 | 2 | define ALPHANUM [-a-zA-Z0-9_] 3 | 4 | document SPEC -path SPEC.html -req REQ_ALPHANUM* -stop-after Annexe -ref "Ref: +(.*)" 5 | 6 | document TEST -path TEST.html \ 7 | -req T_ALPHANUM* \ 8 | -ref "Ref: *(ALPHANUM*)" \ 9 | -stop-after "Annex" \ 10 | -start-after "Tests cases" \ 11 | -nocov 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/html2.req: -------------------------------------------------------------------------------- 1 | 2 | document TEST -path TEST2.html \ 3 | -req T_[0-9]+ \ 4 | -nocov 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/pdf.req: -------------------------------------------------------------------------------- 1 | define ALPHANUM [-a-zA-Z0-9_] 2 | 3 | document SPEC -path SPEC.pdf -req PRINTF_[-a-zA-Z0-9_]* -stop-after Annex 4 | 5 | document TEST -path TEST.txt \ 6 | -req T_[-a-zA-Z0-9_]* \ 7 | -ref "Ref:[ ,]*(ALPHANUM+)" \ 8 | -stop-after Annex 9 | 10 | -------------------------------------------------------------------------------- /test/req-same-line.stdout.ref: -------------------------------------------------------------------------------- 1 | 2 | Requirements of TEST Requirements Upstream 3 | -------------------------------------------------------------------------------------------------------------------- 4 | TEST_01 REQ_101 5 | TEST_02 REQ_102 6 | TEST_03 REQ_103 7 | TEST_04 REQ_101 8 | TEST_04 REQ_102 9 | TEST_04 REQ_103 10 | TEST_04 REQ_104 11 | REQ_101 12 | Lorem ipsum dolor sit amet, consectetur 13 | 14 | REQ_102 15 | Duis aute irure dolor 16 | nulla pariatur. Excepteur 17 | 18 | REQ_103 19 | insula, dives opum Priami dum regna manebant, 20 | nunc tantum 21 | 22 | REQ_104 23 | exercitation ullamco laboris nisi ut aliquip ex ea commodo 24 | incididunt ut labore et dolore magna 25 | 26 | TEST_01 27 | Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor 28 | incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr 29 | ud exercitation ullamco laboris nisi ut aliquip ex ea commodo. (Ref: ) 30 | 31 | TEST_02 32 | Duis aute irure dolor in reprehenderit. (Ref: ) 33 | 34 | TEST_03 35 | Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 36 | fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in c 37 | ulpa qui officia deserunt mollit anim id est laborum. (Ref: ) 38 | 39 | TEST_04 40 | Prototype (Ref: , , , , ) 41 | 42 | -------------------------------------------------------------------------------- /test/req-same-line.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . ./envtest 3 | T=req-same-line 4 | $REQFLOW trac -c $TEST_ORIGIN/same-line.req -r TEST > $T.stdout.out 2>&1 5 | $REQFLOW review -c $TEST_ORIGIN/same-line.req >> $T.stdout.out 2>&1 6 | diff -w $T.stdout.out $TEST_ORIGIN/$T.stdout.ref 7 | -------------------------------------------------------------------------------- /test/req-stat-docx-rm.stdout.ref: -------------------------------------------------------------------------------- 1 | U REQ_001 2 | U REQ_003 3 | U REQ_044 4 | -------------------------------------------------------------------------------- /test/req-stat-docx-rm.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . ./envtest 3 | T=req-stat-docx-rm 4 | $REQFLOW stat -c $TEST_ORIGIN/docx_rev_marks.req > $T.stdout.out 2> $T.stderr.out 5 | diff -w $T.stdout.out $TEST_ORIGIN/$T.stdout.ref 6 | echo -n > $T.stderr.ref 7 | diff -w $T.stderr.out $T.stderr.ref 8 | -------------------------------------------------------------------------------- /test/req-stat-html2.stdout.ref: -------------------------------------------------------------------------------- 1 | U T_0001 2 | U T_0002 3 | U T_0003 4 | U T_0004 5 | -------------------------------------------------------------------------------- /test/req-stat-html2.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . ./envtest 3 | T=req-stat-html2 4 | 5 | $REQFLOW stat -c $TEST_ORIGIN/html2.req > $T.out 2> $T.err 6 | 7 | diff -w $T.out $TEST_ORIGIN/$T.stdout.ref 8 | -------------------------------------------------------------------------------- /test/req-stat-sort.stdout.ref: -------------------------------------------------------------------------------- 1 | req-stat-sort step 1 (sort document order) 2 | U T_01 3 | U T_02 4 | U T_05 5 | U T_04 6 | U T_21 7 | U T_22 8 | req-stat-sort step 2 (sort default order) 9 | U T_01 10 | U T_02 11 | U T_05 12 | U T_04 13 | U T_21 14 | U T_22 15 | req-stat-sort step 3 (sort alphanum order) 16 | U T_01 17 | U T_02 18 | U T_04 19 | U T_05 20 | U T_21 21 | U T_22 22 | -------------------------------------------------------------------------------- /test/req-stat-sort.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . ./envtest 3 | T=req-stat-sort 4 | echo "$T step 1 (sort document order)" > $T.stdout.out 5 | $REQFLOW stat -c - << EOF >> $T.stdout.out 2> $T.stderr.out 6 | define ALPHANUM [-a-zA-Z0-9_] 7 | document TEST_sort_document -path $srcdir/TEST-sort.txt 8 | -req T_[-a-zA-Z0-9_]* 9 | -stop-after "Annex" 10 | -start-after "Tests cases" 11 | -sort document 12 | EOF 13 | echo "$T step 2 (sort default order)" >> $T.stdout.out 14 | $REQFLOW stat -c - << EOF >> $T.stdout.out 2>> $T.stderr.out 15 | define ALPHANUM [-a-zA-Z0-9_] 16 | document TEST_sort_document -path $srcdir/TEST-sort.txt 17 | -req T_[-a-zA-Z0-9_]* 18 | -stop-after "Annex" 19 | -start-after "Tests cases" 20 | EOF 21 | echo "$T step 3 (sort alphanum order)" >> $T.stdout.out 22 | $REQFLOW stat -c - << EOF >> $T.stdout.out 2>> $T.stderr.out 23 | define ALPHANUM [-a-zA-Z0-9_] 24 | document TEST_sort_document -path $srcdir/TEST-sort.txt 25 | -req T_[-a-zA-Z0-9_]* 26 | -stop-after "Annex" 27 | -start-after "Tests cases" 28 | -sort alphanum 29 | EOF 30 | 31 | diff -w $T.stdout.out $TEST_ORIGIN/$T.stdout.ref 32 | echo -n > $T.stderr.ref 33 | diff -w $T.stderr.out $T.stderr.ref 34 | -------------------------------------------------------------------------------- /test/req-stat-stdin.stderr.ref: -------------------------------------------------------------------------------- 1 | Error(s): 7 2 | SPEC:PRINTF_15: Duplicate requirement: also defined in 'SPEC.docx' 3 | SPEC:SYS_155: Undefined requirement, referenced by: PRINTF_01 4 | TEST:PRINTF_01a: Undefined requirement, referenced by: T_01 5 | TEST:PRINTF_01b: Undefined requirement, referenced by: T_01 6 | TEST:PRINTF_333: Undefined requirement, referenced by: T_01 7 | TEST:PRINTF_03a: Undefined requirement, referenced by: T_02 8 | TEST:PRINTF_03b: Undefined requirement, referenced by: T_02 9 | -------------------------------------------------------------------------------- /test/req-stat-stdin.stdout.ref: -------------------------------------------------------------------------------- 1 | Document % covered / total 2 | ---------------------------------------------------------------------- 3 | SPEC 77% 7 / 9 SPEC.docx 4 | TEST nocov nocov / 5 TEST.txt 5 | Total 77% 7 / 9 6 | -------------------------------------------------------------------------------- /test/req-stat-stdin.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . ./envtest 3 | . $srcdir/functions 4 | 5 | T=req-stat-stdin 6 | TEST_DIR=$PWD 7 | if [ "." != "$TEST_ORIGIN" ]; then 8 | # if the current dir is not the source test dir, copy files locally 9 | cp $TEST_ORIGIN/SPEC.docx . 10 | cp $TEST_ORIGIN/TEST.txt . 11 | fi 12 | 13 | test_run ! $REQFLOW stat -s -c - << EOF 14 | define REQ_PATTERN PRINTF_[-a-zA-Z0-9_]* 15 | define ALPHANUM [-a-zA-Z0-9_] 16 | document SPEC 17 | -path SPEC.docx 18 | -req REQ_PATTERN 19 | -stop-after Annexe -ref "Ref: +(.*)" 20 | -end-req-style toto -end-req tutu 21 | 22 | document TEST -path TEST.txt 23 | -req T_[-a-zA-Z0-9_]* 24 | -ref "Ref:[, ]*(ALPHANUM+)" 25 | -stop-after "Annex" 26 | -start-after "Tests cases" 27 | -nocov 28 | 29 | EOF 30 | 31 | cd $TEST_DIR 32 | diff -w $T.stdout $TEST_ORIGIN/$T.stdout.ref 33 | diff -w $T.stderr $TEST_ORIGIN/$T.stderr.ref 34 | -------------------------------------------------------------------------------- /test/req-stat.stderr.ref: -------------------------------------------------------------------------------- 1 | Error(s): 7 2 | SPEC:PRINTF_15: Duplicate requirement: also defined in 'SPEC.docx' 3 | SPEC:SYS_155: Undefined requirement, referenced by: PRINTF_01 4 | TEST:PRINTF_01a: Undefined requirement, referenced by: T_01 5 | TEST:PRINTF_01b: Undefined requirement, referenced by: T_01 6 | TEST:PRINTF_333: Undefined requirement, referenced by: T_01 7 | TEST:PRINTF_03a: Undefined requirement, referenced by: T_02 8 | TEST:PRINTF_03b: Undefined requirement, referenced by: T_02 9 | -------------------------------------------------------------------------------- /test/req-stat.stdout.ref: -------------------------------------------------------------------------------- 1 | Document % covered / total 2 | ---------------------------------------------------------------------- 3 | SPEC 77% 7 / 9 SPEC.docx 4 | TEST nocov nocov / 5 TEST.txt 5 | Total 77% 7 / 9 6 | -------------------------------------------------------------------------------- /test/req-stat.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . ./envtest 3 | . $srcdir/functions 4 | 5 | T=req-stat 6 | 7 | test_run ! $REQFLOW stat -s -c $TEST_ORIGIN/conf.req 8 | 9 | diff -w $T.stdout $TEST_ORIGIN/$T.stdout.ref 10 | diff -w $T.stderr $TEST_ORIGIN/$T.stderr.ref 11 | -------------------------------------------------------------------------------- /test/req-trac-html.stderr.ref: -------------------------------------------------------------------------------- 1 | Error(s): 2 2 | SPEC:SYS_155: Undefined requirement, referenced by: REQ_01 3 | TEST:REQ_333: Undefined requirement, referenced by: T_01 4 | -------------------------------------------------------------------------------- /test/req-trac-html.stdout.ref: -------------------------------------------------------------------------------- 1 | 2 | Requirements of SPEC Requirements Downstream 3 | -------------------------------------------------------------------------------------------------------------------- 4 | REQ_01 T_01 5 | REQ_01 T_02 6 | REQ_02 T_01 7 | REQ_03 T_05 8 | 9 | Requirements of TEST Requirements Downstream 10 | -------------------------------------------------------------------------------------------------------------------- 11 | T_01 12 | T_02 13 | T_05 14 | T_21 15 | -------------------------------------------------------------------------------- /test/req-trac-html.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . ./envtest 3 | . $srcdir/functions 4 | 5 | T=req-trac-html 6 | 7 | test_run ! $REQFLOW trac -c $TEST_ORIGIN/html.req 8 | 9 | diff -w $T.stdout $TEST_ORIGIN/$T.stdout.ref 10 | diff -w $T.stderr $TEST_ORIGIN/$T.stderr.ref 11 | -------------------------------------------------------------------------------- /test/req-trac-pdf.stderr.ref: -------------------------------------------------------------------------------- 1 | Error(s): 10 2 | TEST:PRINTF_01a: Undefined requirement, referenced by: T_01 3 | TEST:PRINTF_01b: Undefined requirement, referenced by: T_01 4 | TEST:PRINTF_333: Undefined requirement, referenced by: T_01 5 | TEST:PRINTF_03a: Undefined requirement, referenced by: T_02 6 | TEST:PRINTF_03b: Undefined requirement, referenced by: T_02 7 | TEST:PRINTF_06: Undefined requirement, referenced by: T_21 8 | TEST:PRINTF_12: Undefined requirement, referenced by: T_21 9 | TEST:PRINTF_15: Undefined requirement, referenced by: T_21 10 | TEST:PRINTF_15: Undefined requirement, referenced by: T_22 11 | TEST:PRINTF_20: Undefined requirement, referenced by: T_22 12 | -------------------------------------------------------------------------------- /test/req-trac-pdf.stdout.ref: -------------------------------------------------------------------------------- 1 | 2 | Requirements of SPEC Requirements Downstream 3 | -------------------------------------------------------------------------------------------------------------------- 4 | PRINTF_01 T_01 5 | PRINTF_02 T_02 6 | PRINTF_03 T_02 7 | PRINTF_03 T_05 8 | 9 | Requirements of TEST Requirements Downstream 10 | -------------------------------------------------------------------------------------------------------------------- 11 | T_01 12 | T_02 13 | T_05 14 | T_21 15 | T_22 16 | -------------------------------------------------------------------------------- /test/req-trac-pdf.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . ./envtest 3 | . $srcdir/functions 4 | 5 | T=req-trac-pdf 6 | 7 | test_run ! $REQFLOW trac -c $TEST_ORIGIN/pdf.req 8 | 9 | diff -w $T.stdout $TEST_ORIGIN/$T.stdout.ref 10 | diff -w $T.stderr $TEST_ORIGIN/$T.stderr.ref 11 | -------------------------------------------------------------------------------- /test/req-trac.stderr.ref: -------------------------------------------------------------------------------- 1 | Error(s): 7 2 | SPEC:PRINTF_15: Duplicate requirement: also defined in 'SPEC.docx' 3 | SPEC:SYS_155: Undefined requirement, referenced by: PRINTF_01 4 | TEST:PRINTF_01a: Undefined requirement, referenced by: T_01 5 | TEST:PRINTF_01b: Undefined requirement, referenced by: T_01 6 | TEST:PRINTF_333: Undefined requirement, referenced by: T_01 7 | TEST:PRINTF_03a: Undefined requirement, referenced by: T_02 8 | TEST:PRINTF_03b: Undefined requirement, referenced by: T_02 9 | -------------------------------------------------------------------------------- /test/req-trac.stdout.ref: -------------------------------------------------------------------------------- 1 | 2 | Requirements of SPEC Requirements Downstream 3 | -------------------------------------------------------------------------------------------------------------------- 4 | PRINTF_01 T_01 5 | PRINTF_02 T_02 6 | PRINTF_03 T_02 7 | PRINTF_03 T_05 8 | PRINTF_05 9 | PRINTF_06 T_21 10 | PRINTF_12 T_21 11 | PRINTF_14 12 | PRINTF_15 T_21 13 | PRINTF_15 T_22 14 | PRINTF_20 T_22 15 | 16 | Requirements of TEST Requirements Downstream 17 | -------------------------------------------------------------------------------------------------------------------- 18 | T_01 19 | T_02 20 | T_05 21 | T_21 22 | T_22 23 | -------------------------------------------------------------------------------- /test/req-trac.test: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . ./envtest 3 | . $srcdir/functions 4 | 5 | T=req-trac 6 | 7 | test_run ! $REQFLOW trac -c $TEST_ORIGIN/conf.req 8 | 9 | diff -w $T.stdout $TEST_ORIGIN/$T.stdout.ref 10 | diff -w $T.stderr $TEST_ORIGIN/$T.stderr.ref 11 | 12 | -------------------------------------------------------------------------------- /test/rfc2246-spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/goeb/reqflow/ca9434cb5c26e9a830eaba34cf71b53b1433cb19/test/rfc2246-spec.pdf -------------------------------------------------------------------------------- /test/rfc2246-test.txt: -------------------------------------------------------------------------------- 1 | 2 | Test Plan for RFC1950 3 | --------------------- 4 | 5 | T_01 6 | test Application data protocol... 7 | 8 | Ref: 10. Application data protocol 9 | 10 | T_02 11 | Support vectors. 12 | 13 | Ref: 4.3. Vectors 14 | -------------------------------------------------------------------------------- /test/rfc2246.req: -------------------------------------------------------------------------------- 1 | 2 | document RFC2246-pdf -path rfc2246-spec.pdf -req ^[1-9A-Z][0-9]*\\.[^\\r]* -start-after "Full Copyright Statement" 3 | document TEST-RFC2246 -path rfc2246-test.txt -req T_.* -ref "Ref: *(.*)" -nocov 4 | 5 | 6 | -------------------------------------------------------------------------------- /test/same-line-spec.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | REQ_101 4 | Lorem ipsum dolor sit amet, consectetur 5 | 6 | REQ_102 7 | Duis aute irure dolor 8 | nulla pariatur. Excepteur 9 | 10 | REQ_103 11 | insula, dives opum Priami dum regna manebant, 12 | nunc tantum 13 | 14 | REQ_104 15 | exercitation ullamco laboris nisi ut aliquip ex ea commodo 16 | incididunt ut labore et dolore magna 17 | 18 | -------------------------------------------------------------------------------- /test/same-line-test.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | TEST_01: Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor 4 | incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostr 5 | ud exercitation ullamco laboris nisi ut aliquip ex ea commodo. (Ref: REQ_101) 6 | TEST_02: Duis aute irure dolor in reprehenderit. (Ref: REQ_102) 7 | TEST_03: Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu 8 | fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in c 9 | ulpa qui officia deserunt mollit anim id est laborum. (Ref: REQ_103) 10 | 11 | TEST_04: Prototype (Ref: REQ_101, REQ_102, REQ_103, REQ_103, REQ_104) 12 | -------------------------------------------------------------------------------- /test/same-line.req: -------------------------------------------------------------------------------- 1 | 2 | define NUM [0-9] 3 | define REQ_PATTERN "(REQ_NUM+)" 4 | define TST_PATTERN "(TEST_NUM+) *: *" 5 | define REF_PATTERN "Ref:[, ]+(REQ_NUM+)" 6 | 7 | document SPEC -path same-line-spec.txt -req REQ_PATTERN 8 | 9 | document TEST -path same-line-test.txt 10 | -req TST_PATTERN 11 | -ref REF_PATTERN 12 | 13 | -------------------------------------------------------------------------------- /test/t_capture_algorithm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Test the capture algorithm 4 | . ./envtest 5 | . $srcdir/functions 6 | 7 | T=$(basename $0) 8 | 9 | # Create a etxt document for testing 10 | create_document() { 11 | cat > $T.document << EOF 12 | # Title... 13 | 14 | ## SYS requirements 15 | SYS_155 16 | SYS_158 17 | SYS_159 18 | SYS_721 19 | SYS_722 20 | 21 | ## Requirements PART1 22 | REQ alone ont its line, REFS with "Ref:" marker, before or after the text. 23 | 24 | PRINTF_01 25 | printf –help shall display a help message and exit. 26 | Ref: SYS_155 27 | 28 | PRINTF_02 29 | Ref: SYS_158 30 | Ref: SYS_159 31 | The FORMAT parameter shall control the output as in C printf. 32 | 33 | PRINTF_03 34 | The exit code of printf shall be: 35 | - zero if no error occurs 36 | - 1 if the FORMAT has an invalid syntax 37 | Ref: SYS_721, SYS_722 38 | 39 | 40 | ## Requirements PART2 41 | REQ and REFS on same line 42 | 43 | REQ: PRINTF_01, Ref: SYS_155 44 | printf –help shall display a help message and exit. 45 | 46 | REQ: PRINTF_02, Ref: SYS_158, SYS_159 47 | The FORMAT parameter shall control the output as in C printf. 48 | 49 | REQ: PRINTF_03, Ref: SYS_721, SYS_722 50 | The exit code of printf shall be: 51 | - zero if no error occurs 52 | - 1 if the FORMAT has an invalid syntax 53 | 54 | 55 | ## Requirements PART3 56 | REFS on separate lines 57 | 58 | PRINTF_01 59 | printf –help shall display a help message and exit. 60 | SYS_155 61 | 62 | PRINTF_02 63 | SYS_158 64 | SYS_159 65 | The FORMAT parameter shall control the output as in C printf. 66 | 67 | PRINTF_03 68 | The exit code of printf shall be: 69 | - zero if no error occurs 70 | - 1 if the FORMAT has an invalid syntax 71 | SYS_721 72 | SYS_722 73 | 74 | EOF 75 | } 76 | 77 | create_document 78 | 79 | test_run $REQFLOW trac -r -c - << EOF 80 | 81 | document SYS -path $T.document -stop-after PART1 -req SYS_[0-9]+ 82 | document SPEC1 -path $T.document -prefix-req SPEC1_ -start-after PART1 -stop-after PART2 -req PRINTF_[0-9]+ -ref "Ref:[, ]*(SYS_[0-9]+)" 83 | document SPEC2 -path $T.document -prefix-req SPEC2_ -start-after PART2 -stop-after PART3 -req PRINTF_[0-9]+ -ref "Ref:[, ]*(SYS_[0-9]+)" 84 | document SPEC3 -path $T.document -prefix-req SPEC3_ -start-after PART3 -req PRINTF_[0-9]+ -ref "SYS_[0-9]+" 85 | 86 | EOF 87 | 88 | diff -w $T.stdout $srcdir/$T.ref 89 | -------------------------------------------------------------------------------- /test/t_capture_algorithm.ref: -------------------------------------------------------------------------------- 1 | 2 | Requirements of SPEC1 Requirements Upstream 3 | -------------------------------------------------------------------------------------------------------------------- 4 | SPEC1_PRINTF_01 SYS_155 5 | SPEC1_PRINTF_02 SYS_158 6 | SPEC1_PRINTF_02 SYS_159 7 | SPEC1_PRINTF_03 SYS_721 8 | SPEC1_PRINTF_03 SYS_722 9 | 10 | Requirements of SPEC2 Requirements Upstream 11 | -------------------------------------------------------------------------------------------------------------------- 12 | SPEC2_PRINTF_01 SYS_155 13 | SPEC2_PRINTF_02 SYS_158 14 | SPEC2_PRINTF_02 SYS_159 15 | SPEC2_PRINTF_03 SYS_721 16 | SPEC2_PRINTF_03 SYS_722 17 | 18 | Requirements of SPEC3 Requirements Upstream 19 | -------------------------------------------------------------------------------------------------------------------- 20 | SPEC3_PRINTF_01 SYS_155 21 | SPEC3_PRINTF_02 SYS_158 22 | SPEC3_PRINTF_02 SYS_159 23 | SPEC3_PRINTF_03 SYS_721 24 | SPEC3_PRINTF_03 SYS_722 25 | 26 | Requirements of SYS Requirements Upstream 27 | -------------------------------------------------------------------------------------------------------------------- 28 | SYS_155 29 | SYS_158 30 | SYS_159 31 | SYS_721 32 | SYS_722 33 | -------------------------------------------------------------------------------- /test/t_end_req: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Test -end-req functionality 4 | . ./envtest 5 | . $srcdir/functions 6 | 7 | T=$(basename $0) 8 | 9 | if [ "." != "$srcdir" ]; then 10 | # copy input files locally so that their path does not depend on $srcdir 11 | cp -f $srcdir/SPEC.docx . 12 | cp -f $srcdir/SPEC.html . 13 | cp -f $srcdir/SPEC.pdf . 14 | cp -f $srcdir/TEST.txt . 15 | fi 16 | 17 | 18 | # build .req file 19 | 20 | cat << EOF > $T.req 21 | 22 | document SPEC_docx -path SPEC.docx -prefix-req SPEC_docx_ -stop-after Annex -req PRINTF_[-a-zA-Z0-9_]* -end-req Ref: 23 | document SPEC_html -path SPEC.html -prefix-req SPEC_html_ -stop-after Annex -req REQ_[-a-zA-Z0-9_]* -end-req Ref: 24 | document SPEC_pdf -path SPEC.pdf -prefix-req SPEC_pdf_ -stop-after Annex -req PRINTF_[-a-zA-Z0-9_]* -end-req Ref: 25 | document TEST_txt -path TEST.txt -stop-after Annex -req T_[-a-zA-Z0-9_]* -end-req Ref: 26 | 27 | 28 | EOF 29 | 30 | echo -n > $T.out 31 | 32 | test_run ! $REQFLOW review -c $T.req 33 | 34 | diff -w $T.out $srcdir/$T.ref 35 | -------------------------------------------------------------------------------- /test/t_end_req.ref: -------------------------------------------------------------------------------- 1 | >>> ! REQFLOW review -c t_end_req.req 2 | Error(s): 1 3 | SPEC_docx:SPEC_docx_PRINTF_15: Duplicate requirement: also defined in 'SPEC.docx' 4 | SPEC_docx_PRINTF_01 5 | printf –help shall display a help message and exit. 6 | 7 | SPEC_docx_PRINTF_02 8 | The FORMAT parameter shall control the output as in C printf. 9 | 10 | SPEC_docx_PRINTF_03 11 | The exit code of printf shall be: 12 | - zero if no error occurs 13 | - 1 if the FORMAT has an invalid syntax 14 | 15 | SPEC_docx_PRINTF_05 16 | This is requirement 5. 17 | 18 | SPEC_docx_PRINTF_06 19 | This is requirement 6. 20 | 21 | SPEC_docx_PRINTF_12 22 | This is requirement 12. 23 | 24 | SPEC_docx_PRINTF_14 25 | This is requirement 14. 26 | 27 | SPEC_docx_PRINTF_15 28 | 29 | SPEC_docx_PRINTF_20 30 | This is requirement 20. 31 | 32 | SPEC_html_REQ_01 33 | Globulus shall have 3 34 | legs: 35 | 36 | 37 | 38 | one for walking 39 | 40 | 41 | one for standing 42 | 43 | 44 | one for jumping 45 | 46 | SPEC_html_REQ_02 47 | At night Globulus shall 48 | switch to standby mode. 49 | 50 | SPEC_html_REQ_03 51 | Globulus shall not make 52 | noise. 53 | 54 | SPEC_pdf_PRINTF_01 55 | printf –help shall display a help message and exit. 56 | 57 | SPEC_pdf_PRINTF_02 58 | The FORMAT parameter shall control the output as in C printf. 59 | 60 | SPEC_pdf_PRINTF_03 61 | The exit code of printf shall be: 62 | - zero if no error occurs 63 | - 1 if the FORMAT has an invalid syntax 64 | 65 | T_01 66 | Send command printf --help 67 | Check that the result is a help message. 68 | 69 | T_02 70 | Send command `printf "(%04d%-4s)\n" 33 aa` 71 | Check that the result is: (0033aa ) 72 | Check that the exit code is zero. 73 | 74 | T_05 75 | Send command printf x%r 76 | Check that an error is raised and that the exit code is 1 77 | 78 | T_21 79 | Send command `which printf` 80 | Check that printf is installed in /usr/bin/printf 81 | 82 | T_22 83 | This is test 22. 84 | 85 | 86 | -------------------------------------------------------------------------------- /test/t_multi_doc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Test reqflow with several upstream and dowstream documents 4 | # 5 | . ./envtest 6 | . $srcdir/functions 7 | 8 | T=$(basename $0) 9 | 10 | init_test_documents() { 11 | for upstream in A B; do 12 | cat > doc_upstream_$upstream.txt << EOF 13 | Doc $upstream 14 | REQ_${upstream}_01 15 | requirements ${upstream}/01 16 | REQ_${upstream}_02 17 | requirements ${upstream}/02 18 | EOF 19 | done 20 | 21 | for downstream in 1 2; do 22 | cat > doc_downstream_${downstream}.txt << EOF 23 | Doc downstream_${downstream} 24 | TST_${downstream}_01 25 | description of test ${downstream}/01 26 | ref: REQ_A_0${downstream} 27 | TST_${downstream}_02 28 | description of test ${downstream}/02 29 | ref: REQ_B_0${downstream} 30 | EOF 31 | done 32 | } 33 | 34 | init_test_documents 35 | 36 | $REQFLOW trac -v -c - << EOF > $T.stdout.out 2> $T.stderr.out 37 | document UP_1 -path doc_upstream_A.txt -req REQ_[A-Z0-9_]* 38 | document UP_2 -path doc_upstream_B.txt -req REQ_[A-Z0-9_]* 39 | document DOWN_1 -path doc_downstream_1.txt -req TST_[A-Z0-9_]* -ref REQ_[A-Z0-9_]* -nocov 40 | document DOWN_2 -path doc_downstream_2.txt -req TST_[A-Z0-9_]* -ref REQ_[A-Z0-9_]* -nocov 41 | EOF 42 | 43 | diff -w $T.stdout.out $TEST_ORIGIN/$T.stdout.ref 44 | -------------------------------------------------------------------------------- /test/t_multi_doc.stdout.ref: -------------------------------------------------------------------------------- 1 | 2 | Requirements of DOWN_1 Requirements Downstream Document 3 | -------------------------------------------------------------------------------------------------------------------- 4 | TST_1_01 5 | TST_1_02 6 | 7 | Requirements of DOWN_2 Requirements Downstream Document 8 | -------------------------------------------------------------------------------------------------------------------- 9 | TST_2_01 10 | TST_2_02 11 | 12 | Requirements of UP_1 Requirements Downstream Document 13 | -------------------------------------------------------------------------------------------------------------------- 14 | REQ_A_01 TST_1_01 DOWN_1 15 | REQ_A_02 TST_2_01 DOWN_2 16 | 17 | Requirements of UP_2 Requirements Downstream Document 18 | -------------------------------------------------------------------------------------------------------------------- 19 | REQ_B_01 TST_1_02 DOWN_1 20 | REQ_B_02 TST_2_02 DOWN_2 21 | -------------------------------------------------------------------------------- /test/t_second_doc: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Test that if .req file has 2 documents, with -stop-after statements, 4 | # then both documents are correctly analysed 5 | . ./envtest 6 | . $srcdir/functions 7 | 8 | T=$(basename $0) 9 | 10 | if [ "." != "$srcdir" ]; then 11 | # copy input files locally so that their path does not depend on $srcdir 12 | cp -f $srcdir/SPEC.docx . 13 | fi 14 | 15 | # build .req file 16 | 17 | cat << EOF > $T.req 18 | 19 | document SPEC1 -path SPEC.docx -prefix-req SPEC1_ -stop-after Annex -req PRINTF_[-a-zA-Z0-9_]* 20 | document SPEC2 -path SPEC.docx -prefix-req SPEC2_ -stop-after Annex -req PRINTF_[-a-zA-Z0-9_]* 21 | 22 | EOF 23 | 24 | set -x 25 | echo -n > $T.out 26 | test_run ! $REQFLOW stat -s -c $T.req 27 | test_run ! $REQFLOW trac -c $T.req 28 | 29 | diff -w $T.out $srcdir/$T.ref 30 | -------------------------------------------------------------------------------- /test/t_second_doc.ref: -------------------------------------------------------------------------------- 1 | >>> ! REQFLOW stat -s -c t_second_doc.req 2 | Error(s): 2 3 | SPEC1:SPEC1_PRINTF_15: Duplicate requirement: also defined in 'SPEC.docx' 4 | SPEC2:SPEC2_PRINTF_15: Duplicate requirement: also defined in 'SPEC.docx' 5 | Document % covered / total 6 | ---------------------------------------------------------------------- 7 | SPEC1 0% 0 / 9 SPEC.docx 8 | SPEC2 0% 0 / 9 SPEC.docx 9 | Total 0% 0 / 18 10 | 11 | >>> ! REQFLOW trac -c t_second_doc.req 12 | Error(s): 2 13 | SPEC1:SPEC1_PRINTF_15: Duplicate requirement: also defined in 'SPEC.docx' 14 | SPEC2:SPEC2_PRINTF_15: Duplicate requirement: also defined in 'SPEC.docx' 15 | 16 | Requirements of SPEC1 Requirements Downstream 17 | -------------------------------------------------------------------------------------------------------------------- 18 | SPEC1_PRINTF_01 19 | SPEC1_PRINTF_02 20 | SPEC1_PRINTF_03 21 | SPEC1_PRINTF_05 22 | SPEC1_PRINTF_06 23 | SPEC1_PRINTF_12 24 | SPEC1_PRINTF_14 25 | SPEC1_PRINTF_15 26 | SPEC1_PRINTF_20 27 | 28 | Requirements of SPEC2 Requirements Downstream 29 | -------------------------------------------------------------------------------------------------------------------- 30 | SPEC2_PRINTF_01 31 | SPEC2_PRINTF_02 32 | SPEC2_PRINTF_03 33 | SPEC2_PRINTF_05 34 | SPEC2_PRINTF_06 35 | SPEC2_PRINTF_12 36 | SPEC2_PRINTF_14 37 | SPEC2_PRINTF_15 38 | SPEC2_PRINTF_20 39 | 40 | --------------------------------------------------------------------------------