diff --git a/compiler.h b/compiler.h index ddad832..e2eb55a 100644 --- a/compiler.h +++ b/compiler.h @@ -191,11 +191,18 @@ // __strout: Argument idx (counted left to right from 1) is a non-NULL string the function writes // Currently we can't tell the compiler that the output will be 0-terminated. #define __strout(idx) __attribute__((nonnull(idx),__access(write_only,idx))) +// __strout_ornull: Argument idx (counted left to right from 1) is a string the function writes (may be NULL) +// Currently we can't tell the compiler that the output will be 0-terminated. +#define __strout_ornull(idx) __attribute__((__access(write_only,idx))) // __strnout: Argument idx (counted left to right from 1) is a non-NULL string the function writes, buffer size given in szidx'th function argument (in array elements, not necessarily bytes) // Currently we can't tell the compiler that the output will be 0-terminated. #define __strnout(idx,szidx) __attribute__((nonnull(idx),__access3(write_only,idx,szidx))) // __bufout: Argument idx (counted left to right from 1) is a non-NULL buffer the function writes, buffer size given in szidx'th function argument (in array elements, not necessarily bytes) #define __bufout(bufidx,szidx) __attribute__((nonnull(bufidx),__access3(write_only,bufidx,szidx))) +// __retarg: Returns value in argument idx (counted left to right from 1) which must be non-NULL +#define __retarg(bufidx) __attribute__((nonnull(bufidx),__access(write_only,bufidx))) +// __retarg_ornull: Returns value in argument idx (counted left to right from 1) which can be NULL +#define __retarg_ornull(bufidx) __attribute__((__access(write_only,bufidx))) // __strinout: Argument idx (counted left to right from 1) is a non-NULL string the function reads and writes // Currently we can't tell the compiler that the output will be 0-terminated. #define __strinout(idx) __attribute__((nonnull(idx),__access(read_write,idx),null_terminated_string_arg(idx))) diff --git a/textcode.h b/textcode.h index e49b068..485b58f 100644 --- a/textcode.h +++ b/textcode.h @@ -3,6 +3,7 @@ #define TEXTCODE_H #include +#include #ifdef __cplusplus extern "C" { @@ -11,120 +12,125 @@ extern "C" { /* These take len bytes from src and write them in encoded form to * dest (if dest != NULL), returning the number of bytes written. */ -/* dietlibc defines these in sys/cdefs.h, which is included from stddef.h */ -#ifndef __readmemsz__ -#define __readmemsz__(a,b) -#endif - -#ifndef __writemem__ -#define __writemem__(a) -#endif - /* Needs len/3*4 bytes */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_uuencoded(char* dest,const char* src,size_t len); /* Needs len/3*4 bytes */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_base64(char* dest,const char* src,size_t len); -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_base64url(char* dest,const char* src,size_t len); /* Worst case: len*3 */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_quotedprintable(char* dest,const char* src,size_t len); /* Worst case: len*3 */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_quotedprintable2(char* dest,const char* src,size_t len,const char* escapeme); /* Worst case: len*3 */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_urlencoded(char* dest,const char* src,size_t len); /* Worst case: len*3 */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_urlencoded2(char* dest,const char* src,size_t len,const char* escapeme); /* Worst case: len*2 */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_yenc(char* dest,const char* src,size_t len); /* Needs len*2 bytes */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_hexdump(char* dest,const char* src,size_t len); /* Change '<' to '<' and '&' to '&' and '\n' to '
'; worst case: len*5 */ /* This is meant for outputting text that goes between tags */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_html(char* dest,const char* src,size_t len); /* Change '<' to '<' and '&' to '&' and '"' to '"'; worst case: len*6 */ /* This is meant for outputting text that goes in a tag argument between double quotes*/ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_html_tagarg(char* dest,const char* src,size_t len); /* Change '<' to '<' and '&' to '&'; worst case: len*5 */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_xml(char* dest,const char* src,size_t len); /* Change '\' to "\\", '\n' to "\n", ^A to "\x01" etc; worst case: len*4 */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_cescape(char* dest,const char* src,size_t len); /* Worst case: len*4 */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_cescape2(char* dest,const char* src,size_t len,const char* escapeme); /* Fold whitespace to '_'; this is great for writing fields with * white spaces to a log file and still allow awk to do log analysis */ /* Worst case: same size */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_foldwhitespace(char* dest,const char* src,size_t len); /* Worst case: len*3 */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_ldapescape(char* dest,const char* src,size_t len); -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_ldapescape2(char* dest,const char* src,size_t len,const char* escapeme); /* Encode JSON string from UTF-8; will backslash-escape the bare minimum. * Invalid UTF-8 in input will output as valid UTF-8 for each byte * Worst case: len*6 */ -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_jsonescape(char* dest,const char* src,size_t len); -__writemem__(1) __readmemsz__(2,3) +__strout_ornull(1) __bufin(2,3) size_t fmt_base85(char* dest,const char* src,size_t len); /* These read one line from src, decode it, and write the result to * dest. The number of decoded bytes is written to destlen. dest * should be able to hold strlen(src) bytes as a rule of thumb. */ +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_uuencoded(const char* src,char* dest,size_t* destlen); +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_base64(const char* src,char* dest,size_t* destlen); +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_base64url(const char* src,char* dest,size_t* destlen); +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_quotedprintable(const char* src,char* dest,size_t* destlen); +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_urlencoded(const char* src,char* dest,size_t* destlen); +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_urlencoded2(const char* src,char* dest,size_t* destlen); +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_yenc(const char* src,char* dest,size_t* destlen); +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_hexdump(const char* src,char* dest,size_t* destlen); /* decodes all html5-standardized &foo; escapes, and also * "
" to "\n" and "

" to "\n\n", leaves the rest of the tags alone */ +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_html(const char* src,char* dest,size_t* destlen); /* decodes all html5-standardized &foo; escapes, but leaves all tags * alone */ +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_html_tagarg(const char* src,char* dest,size_t* destlen); /* Decodes escaped C string text, turning e.g. \n into newline */ +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_cescape(const char* src,char* dest,size_t* destlen); /* Decodes escaped LDIF text, turning e.g. \5C into \ */ +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_ldapescape(const char* src,char* dest,size_t* destlen); /* Decodes escaped JSON strings (like \"\r\n\u0013), turns escaped * surrogate pairs into UTF-8. Expects input to be valid UTF-8. Ends at * \0 or unescaped double quote. */ +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_jsonescape(const char* src,char* dest,size_t* destlen); +__strin(1) __strout_ornull(2) __retarg_ornull(3) size_t scan_base85(const char* src,char* dest,size_t* destlen); #ifdef STRALLOC_H diff --git a/textcode/scan_jsonescape.c b/textcode/scan_jsonescape.c index ed62103..e223c49 100644 --- a/textcode/scan_jsonescape.c +++ b/textcode/scan_jsonescape.c @@ -63,11 +63,11 @@ size_t scan_jsonescape(const char *src,char *dest,size_t *destlen) { ++written; } done: - *destlen=written; + if (destlen) *destlen=written; return i; abort: if (prev!=(unsigned int)-1) i-=6; // if we abort and there still was an open surrogate pair, cancel it - *destlen=written; + if (destlen) *destlen=written; return i; } diff --git a/textcode/scan_quotedprintable.c b/textcode/scan_quotedprintable.c index 1fce529..827961f 100644 --- a/textcode/scan_quotedprintable.c +++ b/textcode/scan_quotedprintable.c @@ -8,16 +8,16 @@ size_t scan_quotedprintable(const char *src,char *dest,size_t *destlen) { if (s[i]=='=') { int j=scan_fromhex(s[i+1]); if (j<0) break; - dest[written]=j<<4; + if (dest) dest[written]=j<<4; j=scan_fromhex(s[i+2]); if (j<0) break; - dest[written]|=j; + if (dest) dest[written]|=j; i+=2; } else { - dest[written]=s[i]; + if (dest) dest[written]=s[i]; } ++written; } - *destlen=written; + if (destlen) *destlen=written; return i; } diff --git a/textcode/scan_urlencoded.c b/textcode/scan_urlencoded.c index b0e64f1..b8378fc 100644 --- a/textcode/scan_urlencoded.c +++ b/textcode/scan_urlencoded.c @@ -12,17 +12,17 @@ static size_t inner_scan_urlencoded(const char *src,char *dest,size_t *destlen,i c=j<<4; j=scan_fromhex(s[i+2]); if (j<0) break; - dest[written]=c|j; + if (dest) dest[written]=c|j; i+=2; - } else if (s[i]=='+' && plus) - dest[written]=' '; - else if (s[i]<=' ' || s[i]=='?' || s[i]=='&') + } else if (s[i]=='+' && plus) { + if (dest) dest[written]=' '; + } else if (s[i]<=' ' || s[i]=='?' || s[i]=='&') break; /* invalid input */ else - dest[written]=s[i]; + if (dest) dest[written]=s[i]; ++written; } - *destlen=written; + if (destlen) *destlen=written; return i; } diff --git a/textcode/scan_yenc.c b/textcode/scan_yenc.c index fbaab15..c4a1cf8 100644 --- a/textcode/scan_yenc.c +++ b/textcode/scan_yenc.c @@ -8,13 +8,13 @@ size_t scan_yenc(const char *src,char *dest,size_t *destlen) { if (s[i]=='=') { ++i; if (s[i]=='y') break; - dest[written]=s[i]-64-42; + if (dest) dest[written]=s[i]-64-42; } else if (s[i]=='\n' || s[i]=='\r' || s[i]=='\0') break; else - dest[written]=s[i]-42; + if (dest) dest[written]=s[i]-42; ++written; } - *destlen=written; + if (destlen) *destlen=written; return i; }