чување c15bc34aac15891e81a82821ee93bfb0f203929f
родитељ d4ee9a453c59abeb98daede3fea017c0d6b165a0
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Sun, 28 Apr 2024 20:20:00 +0200
Add {csv-count} and {tsv-count}; set input_dirname even for stdin
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | slweb.1.in | | | 12 | ++++++++++-- |
| M | slweb.c | | | 92 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
измењених датотека: 2, додавања: 94(+), брисања: 10(-)
diff --git a/slweb.1.in b/slweb.1.in
@@ -830,7 +830,8 @@ for \fCposts/blog-post.slw\fR.
.
.IP \[bu]
.BR "TSV/CSV templating" .
-Directive \fC{tsv "\f[CI]tsvfile\fC" \f[CI]iter\fC}{/tsv}\fR marks a template.
+Directive \fC{tsv "\f[CI]tsvfile\f[CR]" \f[CI]iter\f[CR]}{/tsv}\fR marks a
+template.
Whatever is between \fC{tsv}\fR and \fC{/tsv}\fR will be processed by
.B slweb
and collected as a template. Afterwards, file \fItsvfile.tsv\fR will be read and
@@ -921,6 +922,13 @@ thousands of units sold (for $) were as follows:
.SM TSV
directives can't be nested and doing so will produce an error.
.
+.IP "" 4
+The directives \f[CR]{csv\-count "\f[CI]csvfile\f[CR]"}\fR and \f[CR]{tsv\-count
+"\f[CI]tsvfile\f[CR]"}\fR output the number of \[lq]records\[rq] in the file
+\fIcsvfile.csv\fR or \fItsvfile.tsv\fR (number of lines minus one for the header
+row).
+No newline is output following the number.
+.
.SS Special YAML variables
.
.IP \[bu] 4
@@ -1060,7 +1068,7 @@ containing a list of values to be inserted into meta tags. The first row of this
TSV file is treated as the header row and ignored. First column in this TSV file
contains the meta variable names, and the second column contains meta variable
values. For each row, a \fC<meta name="\f[CI]firstcol\fC"
-content="\f[CI]secondcol\fC">\fR is inserted, where
+content="\f[CI]secondcol\f[CR]">\fR is inserted, where
.I firstcol
is the first column, and
.I secondcol
diff --git a/slweb.c b/slweb.c
@@ -974,6 +974,11 @@ int
process_tsv(FILE* output, const u8* arg_token,
const int read_yaml_macros_and_links, const int end_tag)
{
+ u8* saveptr = NULL;
+ u8* args = NULL;
+ size_t args_len;
+ u8* args_base = NULL;
+
if (end_tag)
{
state &= ~ST_TSV_BODY;
@@ -999,20 +1004,18 @@ process_tsv(FILE* output, const u8* arg_token,
if (read_yaml_macros_and_links)
return 0;
- tsv_iter = 0;
- u8* saveptr = NULL;
- u8* args = (u8*)strtok_r((char*)arg_token, " ",
- (char**)&saveptr);
- args = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
+ tsv_iter = 0;
+ args = (u8*)strtok_r((char*)arg_token, " ", (char**)&saveptr);
+ args = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
if (!args)
exit(error(EINVAL, (u8*)"tsv: Arguments required"));
- size_t args_len = strlen((char*)args);
+ args_len = strlen((char*)args);
if (*args != '"' || *(args + args_len - 1) != '"')
exit(error(EINVAL,
(u8*)"tsv: First argument must be a string"));
if (!tsv_filename)
CALLOC(tsv_filename, u8, BUFSIZE);
- u8* args_base = (u8*)strdup((char*)args + 1);
+ args_base = (u8*)strdup((char*)args + 1);
*(args_base + strlen((char*)args_base) - 1) = 0;
snprintf(tsv_filename, BUFSIZE, "%s/%s.tsv", input_dirname,
(char*)args_base);
@@ -1032,6 +1035,72 @@ process_tsv(FILE* output, const u8* arg_token,
return 0;
}
+int
+process_tsv_count(FILE* output, const u8* arg_token,
+ const int read_yaml_macros_and_links, const int is_tsv)
+{
+ FILE* tsv = NULL;
+ u8* saveptr = NULL;
+ u8* args = NULL;
+ size_t args_len;
+ u8* args_base = NULL;
+ char* bufline = NULL;
+ size_t tsv_lines = 0;
+
+ if (read_yaml_macros_and_links)
+ return 0;
+
+ tsv_iter = 0;
+
+ args = (u8*)strtok_r((char*)arg_token, " ", (char**)&saveptr);
+ args = (u8*)strtok_r(NULL, " ", (char**)&saveptr);
+ if (!args)
+ exit(error(EINVAL, (u8*)"%csv-count: Arguments required",
+ is_tsv ? 't' : 'c'));
+ args_len = strlen((char*)args);
+ if (*args != '"' || *(args + args_len - 1) != '"')
+ exit(error(EINVAL,
+ (u8*)"%csv-count: First argument must be a string",
+ is_tsv ? 't' : 'c'));
+ if (!tsv_filename)
+ CALLOC(tsv_filename, u8, BUFSIZE);
+ args_base = (u8*)strdup((char*)args + 1);
+ *(args_base + strlen((char*)args_base) - 1) = 0;
+ snprintf(tsv_filename, BUFSIZE, "%s/%s.%csv", input_dirname,
+ (char*)args_base, is_tsv ? 't' : 'c');
+ free(args_base);
+
+ // output, tsv_filename, print_tsv_row
+ if (!(tsv = fopen(tsv_filename, "rt")))
+ exit(error(ENOENT, (u8*)"%csv-count: No such file: %s",
+ is_tsv ? 't' : 'c', tsv_filename));
+
+ CALLOC(bufline, char, BUFSIZE);
+
+ while (!feof(tsv))
+ {
+ char* eol = NULL;
+ if (!fgets(bufline, BUFSIZE, tsv))
+ break;
+ eol = strchr(bufline, '\n');
+ if (eol)
+ {
+ *eol = 0;
+ tsv_lines++;
+ }
+ }
+ fclose(tsv);
+
+ /* And take back one kadam for the header row */
+ print_output(output, "%ld", tsv_lines - 1);
+
+ free(bufline);
+ free(tsv_filename);
+ tsv_filename = NULL;
+
+ return 0;
+}
+
#define PRINTCSVIF(format, arg) \
do \
{ \
@@ -2175,9 +2244,13 @@ process_tag(FILE* output, const u8* token, const char* source_filename,
{
process_git_log(output);
}
+ else if (startswith((char*)token, "csv-count")) /* {csv-count} */
+ process_tsv_count(output, token, read_yaml_macros_and_links, 0);
else if (startswith((char*)token, "csv")) /* {csv} */
process_csv(output, token, read_yaml_macros_and_links, end_tag);
- else if (startswith((char*)token, "tsv")) /* {csv} */
+ else if (startswith((char*)token, "tsv-count")) /* {tsv-count} */
+ process_tsv_count(output, token, read_yaml_macros_and_links, 1);
+ else if (startswith((char*)token, "tsv")) /* {tsv} */
process_tsv(output, token, read_yaml_macros_and_links, end_tag);
else if (startswith((char*)token, "include")) /* {include} */
{
@@ -5630,6 +5703,9 @@ main(const int argc, const char** argv)
input = stdin;
+ CALLOC(input_dirname, char, 2);
+ *input_dirname = '.';
+
CALLOC(bufline, u8, BUFSIZE);
buffer_size = BUFSIZE;
CALLOC(buffer, u8, buffer_size);