gv/gv-3.6.3-security.patch

941 lines
29 KiB
Diff

--- src/Makefile.am
+++ src/Makefile.am 2008-03-27 14:10:24.644359171 +0100
@@ -123,6 +123,7 @@ gv_SOURCES = Aaa.c \
save.h \
scale.c \
scale.h \
+ secscanf.c \
gv_signal.c \
gv_signal.h \
version.c \
--- src/Makefile.in
+++ src/Makefile.in 2008-03-27 14:18:31.898867989 +0100
@@ -79,13 +79,13 @@ am__gv_SOURCES_DIST = Aaa.c Aaa_bison.c
options_gs.c options_gs.h options_gv.c options_gv.h \
options_setup.c options_setup.h paths.h process.c process.h \
popup.c popup.h ps.c ps.h resource.c resource.h save.c save.h \
- scale.c scale.h gv_signal.c gv_signal.h version.c version.h \
- versionp.h widgets_misc.c widgets_misc.h zoom.c zoom.h stdc.h \
- Aaa_intern.h Aaa.h AaaP.h d_memdebug.h d_aaa_xtmem.h \
- d_fs_xtmem.h d_gv_mem.h d_gv_xtmem.h d_proc_xtmem.h d_ps_mem.h \
- d_ps_xtmem.h gv_message.h types.h Scrollbar.c Scrollbar.h \
- ScrollbarP.h setenv.c setenv.h getenv.c d_mem.c d_mem.h \
- d_xtmem.c d_xtmem.h
+ scale.c scale.h secscanf.c gv_signal.c gv_signal.h version.c \
+ version.h versionp.h widgets_misc.c widgets_misc.h zoom.c \
+ zoom.h stdc.h Aaa_intern.h Aaa.h AaaP.h d_memdebug.h \
+ d_aaa_xtmem.h d_fs_xtmem.h d_gv_mem.h d_gv_xtmem.h \
+ d_proc_xtmem.h d_ps_mem.h d_ps_xtmem.h gv_message.h types.h \
+ Scrollbar.c Scrollbar.h ScrollbarP.h setenv.c setenv.h \
+ getenv.c d_mem.c d_mem.h d_xtmem.c d_xtmem.h
@USE_SCROLLBAR_CODE_TRUE@am__objects_1 = Scrollbar.$(OBJEXT)
@USE_SETENV_CODE_TRUE@am__objects_2 = setenv.$(OBJEXT) \
@USE_SETENV_CODE_TRUE@ getenv.$(OBJEXT)
@@ -103,9 +103,9 @@ am_gv_OBJECTS = Aaa.$(OBJEXT) Aaa_bison.
options_fs.$(OBJEXT) options_gs.$(OBJEXT) options_gv.$(OBJEXT) \
options_setup.$(OBJEXT) process.$(OBJEXT) popup.$(OBJEXT) \
ps.$(OBJEXT) resource.$(OBJEXT) save.$(OBJEXT) scale.$(OBJEXT) \
- gv_signal.$(OBJEXT) version.$(OBJEXT) widgets_misc.$(OBJEXT) \
- zoom.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
- $(am__objects_3)
+ secscanf.$(OBJEXT) gv_signal.$(OBJEXT) version.$(OBJEXT) \
+ widgets_misc.$(OBJEXT) zoom.$(OBJEXT) $(am__objects_1) \
+ $(am__objects_2) $(am__objects_3)
gv_OBJECTS = $(am_gv_OBJECTS)
gv_LDADD = $(LDADD)
gv_DEPENDENCIES = $(top_srcdir)/lib/libgnu.a
@@ -261,8 +261,8 @@ sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
-dist_pkglib_DATA = gv_system.ad gv_user.ad gv_class.ad gv_spartan.dat gv_user_res.dat gv_copyright.dat gv_widgetless.dat
-appdefaultsdir = /etc/X11/app-defaults
+dist_pkglib_DATA = gv_system.ad gv_user.ad gv_class.ad gv_spartan.dat gv_user_res.dat gv_copyright.dat
+appdefaultsdir = $(pkglibdir)
appdefaults_DATA = GV
EXTRA_DIST = ad2c gv_font_res.dat gv_layout_res.dat gv_misc_res.dat Aaa_bison.yacc \
gv_current.xbm gv_doc.xbm gv_empty.xbm gv_even.xbm gv_icon.xbm gv_odd.xbm \
@@ -303,9 +303,9 @@ gv_SOURCES = Aaa.c Aaa_bison.c Aaa_bison
options_gs.c options_gs.h options_gv.c options_gv.h \
options_setup.c options_setup.h paths.h process.c process.h \
popup.c popup.h ps.c ps.h resource.c resource.h save.c save.h \
- scale.c scale.h gv_signal.c gv_signal.h version.c version.h \
- versionp.h widgets_misc.c widgets_misc.h zoom.c zoom.h \
- message.h stdc.h Aaa_intern.h Aaa.h AaaP.h d_memdebug.h \
+ scale.c scale.h secscanf.c gv_signal.c gv_signal.h version.c \
+ version.h versionp.h widgets_misc.c widgets_misc.h zoom.c \
+ zoom.h message.h stdc.h Aaa_intern.h Aaa.h AaaP.h d_memdebug.h \
d_aaa_xtmem.h d_fs_xtmem.h d_gv_mem.h d_gv_xtmem.h \
d_proc_xtmem.h d_ps_mem.h d_ps_xtmem.h gv_message.h types.h \
$(am__append_1) $(am__append_2) $(am__append_3)
@@ -436,6 +436,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resource.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/save.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/scale.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/secscanf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/setenv.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/widgets_misc.Po@am__quote@
@@ -746,7 +747,7 @@ $(srcdir)/gv_make_res.dat :
@echo "GV.useBackingPixmap: $(USE_BACKING_PIXMAP)" >> $(srcdir)/gv_make_res.dat
@echo "GV*dirs: Home\n\\" >> $(srcdir)/gv_make_res.dat
@echo " Tmp\n\\" >> $(srcdir)/gv_make_res.dat
- @echo " /usr/share/doc\n\\" >> $(srcdir)/gv_make_res.dat
+ @echo " /usr/doc\n\\" >> $(srcdir)/gv_make_res.dat
@echo " /usr/local/doc" >> $(srcdir)/gv_make_res.dat
@echo "GV*filter: no .*" >> $(srcdir)/gv_make_res.dat
@echo "GV*filters: None\n\\" >> $(srcdir)/gv_make_res.dat
--- src/ps.c
+++ src/ps.c 2008-03-27 14:20:04.186703895 +0100
@@ -93,6 +93,10 @@ extern Media *gv_medias;
#define memset(a,b,c) bzero(a,c)
#endif
+extern int sec_sscanf(const char *, const char *, ...);
+
+
+
/* We use this helper function for providing proper */
/* case and colon :-) insensitive DSC matching */
static int dsc_strncmp(s1, s2, n)
@@ -464,7 +468,7 @@ unc_ok:
doc = (struct document *) PS_malloc(sizeof(struct document));
CHECK_MALLOCED(doc);
memset(doc, 0, sizeof(struct document));
- sscanf(line, "%*s %256s", text);
+ sec_sscanf(line, "%*s %256s", text);
/*###jp###*/
/*doc->epsf = iscomment(text, "EPSF-");*/
doc->epsf = iscomment(text, "EPSF");
@@ -560,11 +564,11 @@ scan_ok:
} else if (doc->date == NULL && iscomment(line+2, "CreationDate:")) {
doc->date = gettextline(line+length("%%CreationDate:"));
} else if (bb_set == NONE && iscomment(line+2, "BoundingBox:")) {
- sscanf(line+length("%%BoundingBox:"), "%256s", text);
+ sec_sscanf(line+length("%%BoundingBox:"), "%256s", text);
if (strcmp(text, "(atend)") == 0) {
bb_set = ATEND;
} else {
- if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
+ if (sec_sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
&(doc->boundingbox[LLX]),
&(doc->boundingbox[LLY]),
&(doc->boundingbox[URX]),
@@ -572,7 +576,7 @@ scan_ok:
bb_set = 1;
else {
float fllx, flly, furx, fury;
- if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
+ if (sec_sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
&fllx, &flly, &furx, &fury) == 4) {
bb_set = 1;
doc->boundingbox[LLX] = fllx;
@@ -592,7 +596,7 @@ scan_ok:
}
} else if (orientation_set == NONE &&
iscomment(line+2, "Orientation:")) {
- sscanf(line+length("%%Orientation:"), "%256s", text);
+ sec_sscanf(line+length("%%Orientation:"), "%256s", text);
if (strcmp(text, "(atend)") == 0) {
orientation_set = ATEND;
} else if (strcmp(text, "Portrait") == 0) {
@@ -603,7 +607,7 @@ scan_ok:
orientation_set = 1;
}
} else if (page_order_set == NONE && iscomment(line+2, "PageOrder:")) {
- sscanf(line+length("%%PageOrder:"), "%256s", text);
+ sec_sscanf(line+length("%%PageOrder:"), "%256s", text);
if (strcmp(text, "(atend)") == 0) {
page_order_set = ATEND;
} else if (strcmp(text, "Ascend") == 0) {
@@ -617,11 +621,11 @@ scan_ok:
page_order_set = 1;
}
} else if (pages_set == NONE && iscomment(line+2, "Pages:")) {
- sscanf(line+length("%%Pages:"), "%256s", text);
+ sec_sscanf(line+length("%%Pages:"), "%256s", text);
if (strcmp(text, "(atend)") == 0) {
pages_set = ATEND;
} else {
- switch (sscanf(line+length("%%Pages:"), "%d %d",
+ switch (sec_sscanf(line+length("%%Pages:"), "%d %d",
&maxpages, &i)) {
case 2:
if (page_order_set == NONE) {
@@ -653,7 +657,7 @@ scan_ok:
doc->media[0].name = ps_gettext(line+length("%%DocumentMedia:"),
&next_char);
if (doc->media[0].name != NULL) {
- if (sscanf(next_char, "%f %f", &w, &h) == 2) {
+ if (sec_sscanf(next_char, "%f %f", &w, &h) == 2) {
doc->media[0].width = w + 0.5;
doc->media[0].height = h + 0.5;
}
@@ -674,7 +678,7 @@ scan_ok:
doc->media[doc->nummedia].name = ps_gettext(line+length("%%+"),
&next_char);
if (doc->media[doc->nummedia].name != NULL) {
- if (sscanf(next_char, "%f %f", &w, &h) == 2) {
+ if (sec_sscanf(next_char, "%f %f", &w, &h) == 2) {
doc->media[doc->nummedia].width = w + 0.5;
doc->media[doc->nummedia].height = h + 0.5;
}
@@ -837,7 +841,7 @@ scan_ok:
/* Do nothing */
} else if (doc->default_page_orientation == NONE &&
iscomment(line+2, "PageOrientation:")) {
- sscanf(line+length("%%PageOrientation:"), "%256s", text);
+ sec_sscanf(line+length("%%PageOrientation:"), "%256s", text);
if (strcmp(text, "Portrait") == 0) {
doc->default_page_orientation = PORTRAIT;
} else if (strcmp(text, "Landscape") == 0) {
@@ -856,7 +860,7 @@ scan_ok:
PS_free(cp);
} else if (page_bb_set == NONE &&
iscomment(line+2, "PageBoundingBox:")) {
- if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
+ if (sec_sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
&(doc->default_page_boundingbox[LLX]),
&(doc->default_page_boundingbox[LLY]),
&(doc->default_page_boundingbox[URX]),
@@ -864,7 +868,7 @@ scan_ok:
page_bb_set = 1;
else {
float fllx, flly, furx, fury;
- if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
+ if (sec_sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
&fllx, &flly, &furx, &fury) == 4) {
page_bb_set = 1;
doc->default_page_boundingbox[LLX] = fllx;
@@ -959,7 +963,7 @@ scan_ok:
/* Do nothing */
} else if (doc->default_page_orientation == NONE &&
iscomment(line+2, "PageOrientation:")) {
- sscanf(line+length("%%PageOrientation:"), "%256s", text);
+ sec_sscanf(line+length("%%PageOrientation:"), "%256s", text);
if (strcmp(text, "Portrait") == 0) {
doc->default_page_orientation = PORTRAIT;
} else if (strcmp(text, "Landscape") == 0) {
@@ -982,7 +986,7 @@ scan_ok:
PS_free(cp);
} else if (page_bb_set == NONE &&
iscomment(line+2, "PageBoundingBox:")) {
- if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
+ if (sec_sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
&(doc->default_page_boundingbox[LLX]),
&(doc->default_page_boundingbox[LLY]),
&(doc->default_page_boundingbox[URX]),
@@ -990,7 +994,7 @@ scan_ok:
page_bb_set = 1;
else {
float fllx, flly, furx, fury;
- if (sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
+ if (sec_sscanf(line+length("%%PageBoundingBox:"), "%f %f %f %f",
&fllx, &flly, &furx, &fury) == 4) {
page_bb_set = 1;
doc->default_page_boundingbox[LLX] = fllx;
@@ -1058,7 +1062,7 @@ newpage:
CHECK_MALLOCED(doc->pages);
}
label = ps_gettext(line+length("%%Page:"), &next_char);
- if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
+ if (sec_sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
if (nextpage == 1) {
ignore = thispage != 1;
}
@@ -1096,7 +1100,7 @@ continuepage:
/* Do nothing */
} else if (doc->pages[doc->numpages].orientation == NONE &&
iscomment(line+2, "PageOrientation:")) {
- sscanf(line+length("%%PageOrientation:"), "%256s", text);
+ sec_sscanf(line+length("%%PageOrientation:"), "%256s", text);
if (strcmp(text, "Portrait") == 0) {
doc->pages[doc->numpages].orientation = PORTRAIT;
} else if (strcmp(text, "Landscape") == 0) {
@@ -1128,11 +1132,11 @@ continuepage:
PS_free(cp);
} else if ((page_bb_set == NONE || page_bb_set == ATEND) &&
iscomment(line+2, "PageBoundingBox:")) {
- sscanf(line+length("%%PageBoundingBox:"), "%256s", text);
+ sec_sscanf(line+length("%%PageBoundingBox:"), "%256s", text);
if (strcmp(text, "(atend)") == 0) {
page_bb_set = ATEND;
} else {
- if (sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
+ if (sec_sscanf(line+length("%%PageBoundingBox:"), "%d %d %d %d",
&(doc->pages[doc->numpages].boundingbox[LLX]),
&(doc->pages[doc->numpages].boundingbox[LLY]),
&(doc->pages[doc->numpages].boundingbox[URX]),
@@ -1142,7 +1146,7 @@ continuepage:
}
else {
float fllx, flly, furx, fury;
- if (sscanf(line+length("%%PageBoundingBox:"),
+ if (sec_sscanf(line+length("%%PageBoundingBox:"),
"%f %f %f %f",
&fllx, &flly, &furx, &fury) == 4) {
if (page_bb_set == NONE) page_bb_set = 1;
@@ -1193,7 +1197,7 @@ continuepage:
/* Do nothing */
} else if (iscomment(line+2, "Page:")) {
PS_free(ps_gettext(line+length("%%Page:"), &next_char));
- if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
+ if (sec_sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
if (!ignore && thispage == nextpage) {
if (doc->numpages > 0) {
doc->pages[doc->numpages-1].end = position;
@@ -1220,13 +1224,13 @@ continuepage:
doc->begintrailer = position;
section_len = line_len;
} else if (bb_set == ATEND && iscomment(line+2, "BoundingBox:")) {
- if (sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
+ if (sec_sscanf(line+length("%%BoundingBox:"), "%d %d %d %d",
&(doc->boundingbox[LLX]),
&(doc->boundingbox[LLY]),
&(doc->boundingbox[URX]),
&(doc->boundingbox[URY])) != 4) {
float fllx, flly, furx, fury;
- if (sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
+ if (sec_sscanf(line+length("%%BoundingBox:"), "%f %f %f %f",
&fllx, &flly, &furx, &fury) == 4) {
doc->boundingbox[LLX] = fllx;
doc->boundingbox[LLY] = flly;
@@ -1244,14 +1248,14 @@ continuepage:
}
} else if (orientation_set == ATEND &&
iscomment(line+2, "Orientation:")) {
- sscanf(line+length("%%Orientation:"), "%256s", text);
+ sec_sscanf(line+length("%%Orientation:"), "%256s", text);
if (strcmp(text, "Portrait") == 0) {
doc->orientation = PORTRAIT;
} else if (strcmp(text, "Landscape") == 0) {
doc->orientation = LANDSCAPE;
}
} else if (page_order_set == ATEND && iscomment(line+2, "PageOrder:")) {
- sscanf(line+length("%%PageOrder:"), "%256s", text);
+ sec_sscanf(line+length("%%PageOrder:"), "%256s", text);
if (strcmp(text, "Ascend") == 0) {
doc->pageorder = ASCEND;
} else if (strcmp(text, "Descend") == 0) {
@@ -1260,7 +1264,7 @@ continuepage:
doc->pageorder = SPECIAL;
}
} else if (pages_set == ATEND && iscomment(line+2, "Pages:")) {
- if (sscanf(line+length("%%Pages:"), "%*u %d", &i) == 1) {
+ if (sec_sscanf(line+length("%%Pages:"), "%*u %d", &i) == 1) {
if (page_order_set == NONE) {
if (i == -1) doc->pageorder = DESCEND;
else if (i == 0) doc->pageorder = SPECIAL;
@@ -1286,7 +1290,7 @@ continuepage:
preread = 0;
if (DSCcomment(line) && iscomment(line+2, "Page:")) {
PS_free(ps_gettext(line+length("%%Page:"), &next_char));
- if (sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
+ if (sec_sscanf(next_char, "%d", &thispage) != 1) thispage = 0;
if (!ignore && thispage == nextpage) {
if (doc->numpages > 0) {
doc->pages[doc->numpages-1].end = position;
@@ -1825,7 +1829,7 @@ static char * readline (fd, lineP, posit
INFMESSAGE(encountered "BeginData:")
if (FD_LINE_LEN > 100) FD_BUF[100] = '\0';
text[0] = '\0';
- if (sscanf(line+length("%%BeginData:"), "%d %*s %100s", &num, text) >= 1) {
+ if (sec_sscanf(line+length("%%BeginData:"), "%d %*s %100s", &num, text) >= 1) {
if (strcmp(text, "Lines") == 0) {
INFIMESSAGE(number of lines to skip:,num)
while (num) {
@@ -1849,7 +1853,7 @@ static char * readline (fd, lineP, posit
else if IS_BEGIN("Binary:") {
int num;
INFMESSAGE(encountered "BeginBinary:")
- if (sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
+ if (sec_sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
int read_chunk_size = LINE_CHUNK_SIZE;
INFIMESSAGE(number of chars to skip:,num)
while (num>0) {
@@ -1924,7 +1928,7 @@ pscopyuntil(fd, to, begin, end, comment)
INFMESSAGE(encountered "BeginData:")
if (FD_LINE_LEN > 100) FD_BUF[100] = '\0';
text[0] = '\0';
- if (sscanf(line+length("%%BeginData:"), "%d %*s %100s", &num, text) >= 1) {
+ if (sec_sscanf(line+length("%%BeginData:"), "%d %*s %100s", &num, text) >= 1) {
if (strcmp(text, "Lines") == 0) {
INFIMESSAGE(number of lines:,num)
while (num) {
@@ -1947,7 +1951,7 @@ pscopyuntil(fd, to, begin, end, comment)
else if IS_BEGIN("Binary:") {
int num;
INFMESSAGE(encountered "BeginBinary:")
- if (sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
+ if (sec_sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
int read_chunk_size = LINE_CHUNK_SIZE;
INFIMESSAGE(number of chars:,num)
while (num>0) {
@@ -2021,12 +2025,12 @@ pscopydoc(dest_file,src_filename,d,pagel
PS_free(comment);
continue;
}
- sscanf(comment+length("%%Pages:"), "%256s", text);
+ sec_sscanf(comment+length("%%Pages:"), "%256s", text);
if (strcmp(text, "(atend)") == 0) {
fputs(comment, dest_file);
pages_atend = True;
} else {
- switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
+ switch (sec_sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
case 1:
fprintf(dest_file, "%%%%Pages: %d %d\n", pages, i);
break;
@@ -2061,7 +2065,7 @@ pscopydoc(dest_file,src_filename,d,pagel
PS_free(comment);
continue;
}
- switch (sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
+ switch (sec_sscanf(comment+length("%%Pages:"), "%*d %d", &i)) {
case 1:
fprintf(dest_file, "%%%%Pages: %d %d\n", pages, i);
break;
--- src/secscanf.c
+++ src/secscanf.c 2002-09-20 13:54:53.000000000 +0200
@@ -0,0 +1,540 @@
+/*
+ * Secure sscanf - sscanf with an additional size argument for string
+ * arguments. All format specifiers should work as in the standard
+ * scanf - except for those writing to a string buffer provided by the
+ * caller. These specifiers take an additional argument of type size_t
+ * that specifies the size of the buffer.
+ *
+ * Copyright (C) 2002, Olaf Kirch <okir@suse.de>
+ */
+
+#define _GNU_SOURCE
+
+#include <sys/param.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+
+enum {
+ CONV_ANY,
+ CONV_STR,
+ CONV_NUM,
+ CONV_INTEGER,
+ CONV_FLOAT,
+ CONV_POINTER,
+};
+
+enum {
+ SIZE_ANY,
+ SIZE_SHORT,
+ SIZE_LONG,
+ SIZE_QUAD,
+};
+
+union scan_value {
+ const char * v_string;
+ long long v_signed;
+ unsigned long long v_integer;
+ long double v_double;
+ void * v_pointer;
+};
+
+
+static int process_number(union scan_value *vp, const char **sp, char fmt);
+static int process_char_class(const char **, const char **, int);
+
+static inline int
+set_conv_type(int *type, int new_type)
+{
+ switch (*type) {
+ case CONV_ANY:
+ break;
+ case CONV_NUM:
+ if (new_type == CONV_INTEGER
+ || new_type == CONV_FLOAT
+ || new_type == CONV_POINTER)
+ break;
+ /* fallthru */
+ default:
+ if (*type != new_type)
+ return 0;
+ break;
+ }
+
+ *type = new_type;
+ return 1;
+}
+
+int
+sec_sscanf(const char *s, const char *fmt, ...)
+{
+ const char *begin = s;
+ int num_fields = 0, fmt_empty = 1;
+ va_list ap;
+
+ va_start(ap, fmt);
+ while (*fmt) {
+ union scan_value value;
+ const char *pre_space_skip,
+ *value_begin;
+ int assign = 1, allocate = 0,
+ conv_type = CONV_ANY,
+ conv_size = SIZE_ANY,
+ field_width = -1,
+ nul_terminated = 1;
+ char c;
+
+ c = *fmt++;
+ if (isspace(c)) {
+ while (isspace(*s))
+ s++;
+ continue;
+ }
+
+ fmt_empty = 0;
+ if (c != '%') {
+ if (c != *s)
+ goto stop;
+ s++;
+ continue;
+ }
+
+ /* Each % directive implicitly skips white space
+ * except for the %c case */
+ pre_space_skip = s;
+ while (isspace(*s))
+ s++;
+
+ while (1) {
+ int type = CONV_ANY, size = SIZE_ANY;
+
+ switch (*fmt) {
+ case '*':
+ assign = 0;
+ break;
+ case 'a':
+ type = CONV_STR;
+ allocate = 1;
+ break;
+ case 'h':
+ type = CONV_INTEGER;
+ size = SIZE_SHORT;
+ break;
+ case 'l':
+ type = CONV_NUM;
+ size = SIZE_LONG;
+ break;
+ case 'L':
+ case 'q':
+ type = CONV_NUM;
+ size = SIZE_QUAD;
+ break;
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ field_width = strtol(fmt, (char **) &fmt, 10);
+ fmt--;
+ break;
+ default:
+ goto flags_done;
+ }
+
+ if (!set_conv_type(&conv_type, type))
+ goto stop;
+
+ if (size != SIZE_ANY) {
+ if (size == SIZE_LONG && conv_size == SIZE_LONG)
+ conv_size = SIZE_QUAD;
+ else
+ conv_size = size;
+ }
+
+ fmt++;
+ }
+
+ flags_done:
+ value_begin = s;
+
+ switch (*fmt++) {
+ case '%':
+ if (*s == '\0')
+ goto eof;
+ if (*s != '%')
+ goto stop;
+ continue;
+ case '[':
+ value.v_string = s;
+ if (!set_conv_type(&conv_type, CONV_STR)
+ || !process_char_class(&fmt, &s, field_width))
+ goto stop;
+ break;
+ case 's':
+ value.v_string = s;
+ if (!set_conv_type(&conv_type, CONV_STR))
+ goto stop;
+ while (*s && !isspace(*s) && field_width-- != 0)
+ s++;
+ break;
+ case 'c':
+ if (!set_conv_type(&conv_type, CONV_STR))
+ goto stop;
+ value.v_string = s = value_begin = pre_space_skip;
+
+ if (field_width < 0)
+ s++;
+ else while (*s && field_width--)
+ s++;
+ nul_terminated = 0;
+ break;
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ if (!set_conv_type(&conv_type, CONV_INTEGER)
+ || !process_number(&value, &s, fmt[-1]))
+ goto stop;
+ break;
+ case 'p':
+ if (!set_conv_type(&conv_type, CONV_POINTER)
+ || !process_number(&value, &s, fmt[-1]))
+ goto stop;
+ break;
+ case 'f':
+ case 'g':
+ case 'e':
+ case 'E':
+ if (!set_conv_type(&conv_type, CONV_FLOAT)
+ || !process_number(&value, &s, fmt[-1]))
+ goto stop;
+ break;
+ case 'n':
+ if (!set_conv_type(&conv_type, CONV_INTEGER))
+ goto stop;
+ value.v_signed = (s - begin);
+ break;
+ default:
+ goto stop;
+ }
+
+ /* We've consumed what we need to consume. Now copy */
+ if (!assign)
+ continue;
+
+ /* Make sure we've consumed at least *something* */
+ if (s == value_begin)
+ goto eof;
+
+ /* Deal with a conversion flag */
+ if (conv_type == CONV_STR && allocate) {
+ value.v_pointer = strndup(value.v_string, s - value.v_string);
+ conv_type = CONV_POINTER;
+ allocate = 0;
+ }
+
+ switch (conv_type) {
+ case CONV_STR:
+ {
+ const char *string = value.v_string;
+ char *buf;
+ size_t size;
+
+ if (string == NULL)
+ goto stop;
+ buf = va_arg(ap, char *);
+ size = va_arg(ap, size_t) - nul_terminated;
+ if (size > s - string)
+ size = s - string;
+ strncpy(buf, string, size);
+ if (nul_terminated)
+ buf[size] = '\0';
+ }
+ break;
+
+ case CONV_POINTER:
+ {
+ void **ptr;
+
+ ptr = va_arg(ap, void **);
+ *ptr = value.v_pointer;
+ }
+ break;
+ case CONV_INTEGER:
+ {
+ void *ptr;
+
+ ptr = va_arg(ap, void *);
+ switch (conv_size) {
+ case SIZE_SHORT:
+ *(short *) ptr = value.v_integer;
+ break;
+ case SIZE_ANY:
+ *(int *) ptr = value.v_integer;
+ break;
+ case SIZE_LONG:
+ *(long *) ptr = value.v_integer;
+ break;
+ case SIZE_QUAD:
+ *(long long *) ptr = value.v_integer;
+ break;
+ default:
+ goto stop;
+ }
+ }
+ break;
+ case CONV_FLOAT:
+ {
+ void *ptr;
+
+ ptr = va_arg(ap, void *);
+ switch (conv_size) {
+ case SIZE_ANY:
+ *(float *) ptr = value.v_double;
+ break;
+ case SIZE_LONG:
+ *(double *) ptr = value.v_double;
+ break;
+ case SIZE_QUAD:
+ *(long double *) ptr = value.v_double;
+ break;
+ default:
+ goto stop;
+ }
+ }
+ break;
+ default:
+ goto stop;
+ }
+
+ num_fields++;
+ }
+
+stop: return num_fields;
+
+eof: if (num_fields)
+ return num_fields;
+ return EOF;
+}
+
+static int
+process_number(union scan_value *vp, const char **sp, char fmt)
+{
+ const char *s = *sp;
+
+ switch (fmt) {
+ case 'd':
+ vp->v_signed = strtoll(s, (char **) sp, 10);
+ break;
+ case 'i':
+ vp->v_signed = strtoll(s, (char **) sp, 0);
+ break;
+ case 'o':
+ vp->v_integer = strtoull(s, (char **) sp, 8);
+ break;
+ case 'u':
+ vp->v_integer = strtoull(s, (char **) sp, 10);
+ break;
+ case 'x':
+ case 'X':
+ vp->v_integer = strtoull(s, (char **) sp, 16);
+ break;
+ case 'p':
+ vp->v_pointer = (void *) strtoull(s, (char **) sp, 0);
+ break;
+ case 'f':
+ case 'g':
+ case 'e':
+ case 'E':
+ vp->v_double = strtold(s, (char **) sp);
+ break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+process_char_class(const char **fmt, const char **sp, int width)
+{
+ unsigned char *s, c, prev_char = 0;
+ unsigned char table[255];
+ int val = 1;
+
+ s = (unsigned char *) *fmt;
+ if (*s == '^') {
+ memset(table, 1, sizeof(table));
+ val = 0;
+ s++;
+ } else {
+ memset(table, 0, sizeof(table));
+ val = 1;
+ }
+ /* First character in set is closing bracket means add it to the
+ * set of characters */
+ if ((c = *s) == ']') {
+ table[c] = val;
+ prev_char = c;
+ s++;
+ }
+
+ /* Any other closing bracket finishes off the set */
+ while ((c = *s++) != ']') {
+ if (prev_char) {
+ if (c == '-' && *s != '\0' && *s != ']') {
+ c = *s++;
+ } else {
+ //table[prev_char] = val;
+ prev_char = '\0';
+ }
+ }
+
+ if (c == '\0')
+ return 0;
+
+ if (prev_char) {
+ while (prev_char < c)
+ table[prev_char++] = val;
+ }
+ table[c] = val;
+ prev_char = c;
+ }
+ *fmt = (char *) s;
+
+#if 0
+ {
+ int n;
+
+ printf("char class=");
+ for (n = 0; n < 255; n++)
+ if (table[n])
+ printf(isprint(n)? "%c" : "\\%03o", n);
+ printf("\n");
+ }
+#endif
+
+ s = (unsigned char *) *sp;
+ while ((c = *s) != '\0' && table[c] && width--)
+ s++;
+
+ *sp = (char *) s;
+ return 1;
+}
+
+#ifdef TEST
+static int verify(const char *fmt, const char *s);
+static int verify_s(const char *fmt, const char *s);
+
+enum { S, I, L, F, D, P };
+
+int
+main(int argc, char **argv)
+{
+ verify("%d %d", "12 13");
+ verify("%d-%d", "12 13");
+ verify("%d-%d", "12-13");
+ verify("%u %u", "12 13");
+ verify("%o %o", "12 13");
+ verify("%x %x", "12 13");
+ verify("%X %X", "12 13");
+ verify("%hd %hd", "12 13");
+ verify("%ld %ld", "12 13");
+ verify("%lld %lld", "12 13");
+ verify("%Ld %Ld", "12 13");
+ verify("%qd %qd", "12 13");
+ verify("%f %f", "12 13");
+ verify("%lf %lf", "12 13");
+ verify("%Lf %Lf", "12 13");
+ verify("%qf %qf", "12 13");
+ verify("%*d-%d", "12-13");
+ verify("%*s %d", "12 13");
+ verify("%p", "0xdeadbeef");
+ verify("%*[a-e] %x", "deadbeef feeb");
+ verify("%*[a-f] %x", "deadbeef feeb");
+ verify("%*[^g-z] %x", "deadbeef feeb");
+ verify("%*[^ g-z] %x", "deadbeef feeb");
+ verify("%*[^ g-z-] %x", "dead-beef feeb");
+ verify("%*5s %d", "toast123 456");
+ verify("", "lalla");
+ verify("%u", "");
+
+ verify_s("%s", "aa bb");
+ verify_s("%s %s", "aa bb");
+ verify_s("%[a-z] %s", "aa bb");
+ verify_s("%c %s", "aa bb");
+ verify_s("%2c %s", " aa bb");
+ verify_s("%20c %s", " aa bb");
+
+ return 0;
+}
+
+static int
+verify(const char *fmt, const char *s)
+{
+ union scan_value vals[5], vals_ref[5], *v;
+ int n, m;
+
+ memset(vals, 0xe5, sizeof(vals));
+ memset(vals_ref, 0xe5, sizeof(vals_ref));
+
+ v = vals;
+ n = sec_sscanf(s, fmt, v + 0, v + 1, v + 2, v + 3, v + 4);
+
+ v = vals_ref;
+ m = sscanf(s, fmt, v + 0, v + 1, v + 2, v + 3, v + 4);
+
+ if (m != n) {
+ printf("FAILED: fmt=\"%s\"\n"
+ " str=\"%s\"\n"
+ " sec_scanf returns %d, sscanf returns %d\n",
+ fmt, s, n, m);
+ return 0;
+ }
+
+ if (memcmp(vals, vals_ref, sizeof(vals))) {
+ printf("FAILED: fmt=\"%s\"\n"
+ " str=\"%s\"\n"
+ " data differs!\n",
+ fmt, s);
+ printf("0x%Lx != 0x%Lx\n", vals[0].v_integer, vals_ref[0].v_integer);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+verify_s(const char *fmt, const char *s)
+{
+ char buf[3][256], buf_ref[3][256];
+ int n, m;
+
+ memset(buf, 0xe5, sizeof(buf));
+ memset(buf_ref, 0xe5, sizeof(buf_ref));
+
+ n = sec_sscanf(s, fmt, buf, sizeof(buf[0]), buf + 1, sizeof(buf[1]), buf + 2, sizeof(buf[2]));
+
+ m = sscanf(s, fmt, buf_ref, buf_ref + 1, buf_ref + 2);
+
+ if (m != n) {
+ printf("FAILED: fmt=\"%s\"\n"
+ " str=\"%s\"\n"
+ " sec_scanf returns %d, sscanf returns %d\n",
+ fmt, s, n, m);
+ return 0;
+ }
+
+ if (memcmp(buf, buf_ref, sizeof(buf))) {
+ printf("FAILED: fmt=\"%s\"\n"
+ " str=\"%s\"\n"
+ " data differs!\n",
+ fmt, s);
+ printf("%s != %s\n", buf[0], buf_ref[0]);
+ return 0;
+ }
+
+ return 1;
+}
+#endif