--- 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 + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +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