VERSION=1.0.1
ARCHIVE=xsv-$(VERSION).tar.gz
-PCRE_CFLAGS:=$(shell pcre-config --cflags)
-PCRE_LIBS:=$(shell pcre-config --libs)
+PCRE_CFLAGS:=$(shell pcre2-config --cflags)
+PCRE_LIBS:=$(shell pcre2-config --libs8)
-CFLAGS=-O2 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Wundef -Wredundant-decls -std=gnu99 $(PCRE_CFLAGS) -DVERSION='"$(VERSION)"'
+CFLAGS=-O2 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Wundef -Wredundant-decls -Wno-pointer-sign -std=gnu99 $(PCRE_CFLAGS) -DVERSION='"$(VERSION)"'
LDLIBS=$(PCRE_LIBS)
PREFIX=/usr/local
XSV -- Swiss-Army Knife for CSV-Like Files
- (c) 2012--2013 Martin Mares <mj@ucw.cz>
+ (c) 2012--2025 Martin Mares <mj@ucw.cz>
You can use and distribute this program under the terms of GPLv2.
(or anywhere else if you override PREFIX).
The program has been tested on Linux, but it should run on an arbitrary POSIX
-system with a C99 compiler and the PCRE library. Building of the manual page
+system with a C99 compiler and the PCRE2 library. Building of the manual page
requires AsciiDoc (any reasonably recent version should work).
All bug reports and suggestions are welcome, especially when accompanied by patches.
exactly one space is used.
*-r, --regex=*'regex'::
The fields are separated by sequences of characters satisfying the given
- Perl-compatible regular expression (see *pcrepattern*(3) for a full description
+ Perl-compatible regular expression (see *pcre2pattern*(3) for a full description
of their syntax). For example, `--regex='#+'` separates fields by an arbitrary
number of hashes. Leading or trailing separators are interpreted as empty
fields (this can be overridden by *--sloppy*). This format can be used only
/*
* The Swiss-Army Knife for CSV-like Files
*
- * (c) 2012 Martin Mares <mj@ucw.cz>
+ * (c) 2012-2025 Martin Mares <mj@ucw.cz>
*/
#include <stdio.h>
#include <wchar.h>
#include <locale.h>
-#include <pcre.h>
+#define PCRE2_CODE_UNIT_WIDTH 8
+#include <pcre2.h>
#ifdef __GNUC__
#define NONRET __attribute__((noreturn))
int always_quote;
// regex backend:
- pcre *pcre;
- pcre_extra *pcre_extra;
+ pcre2_code *pcre;
+ pcre2_match_data *pcre_mdata;
// Temporary file backend:
FILE *tmp_file;
static const char *regex_set(struct format *f, char *rx)
{
- const char *err;
- int errpos;
- f->pcre = pcre_compile(rx, PCRE_DOLLAR_ENDONLY, &err, &errpos, NULL);
- if (!f->pcre)
- return err;
+ int errcode;
+ PCRE2_SIZE errpos;
+
+ f->pcre = pcre2_compile(rx, PCRE2_ZERO_TERMINATED, PCRE2_DOLLAR_ENDONLY, &errcode, &errpos, NULL);
+ if (!f->pcre) {
+ char *errmsg = xmalloc(256);
+ pcre2_get_error_message(errcode, errmsg, 256);
+ return errmsg;
+ }
+
+ pcre2_jit_compile(f->pcre, PCRE2_JIT_COMPLETE);
- f->pcre_extra = pcre_study(f->pcre, 0, &err);
- if (!f->pcre_extra)
- return err;
+ f->pcre_mdata = pcre2_match_data_create_from_pattern(f->pcre, NULL);
return NULL;
}
int i = 0;
for (;;) {
- int ovec[3];
- int err = pcre_exec(fmt->pcre, fmt->pcre_extra, (char *) c, n, i, 0, ovec, 3);
+ int err = pcre2_match(fmt->pcre, (char *) c, n, i, 0, fmt->pcre_mdata, NULL);
if (err < 0) {
- if (err != PCRE_ERROR_NOMATCH)
+ if (err != PCRE2_ERROR_NOMATCH)
warn(fmt, "PCRE matching error %d", err);
// No further occurrence of the separator: the rest is a single field
if (!fmt->sloppy || i < n) {
}
return 1;
}
+ PCRE2_SIZE *ovec = pcre2_get_ovector_pointer(fmt->pcre_mdata);
if (ovec[0] == ovec[1]) {
warn(fmt, "Regular expression matched an empty separator.");
new_field(i);