move imap_vprintf() to util.c and rename it to xvasprintf()
it's currently used only by IMAP, but it's logically low-level.
This commit is contained in:
		
							parent
							
								
									859b7dd7f2
								
							
						
					
					
						commit
						1a89f8a178
					
				
					 3 changed files with 109 additions and 103 deletions
				
			
		|  | @ -165,6 +165,8 @@ void ATTR_PRINTFLIKE(1, 0) vsys_error( const char *, va_list va ); | ||||||
| void ATTR_PRINTFLIKE(1, 2) sys_error( const char *, ... ); | void ATTR_PRINTFLIKE(1, 2) sys_error( const char *, ... ); | ||||||
| void flushn( void ); | void flushn( void ); | ||||||
| 
 | 
 | ||||||
|  | char *xvasprintf( const char *fmt, va_list ap ); | ||||||
|  | 
 | ||||||
| #if !defined(_POSIX_SYNCHRONIZED_IO) || _POSIX_SYNCHRONIZED_IO <= 0 | #if !defined(_POSIX_SYNCHRONIZED_IO) || _POSIX_SYNCHRONIZED_IO <= 0 | ||||||
| # define fdatasync fsync | # define fdatasync fsync | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
							
								
								
									
										104
									
								
								src/drv_imap.c
									
										
									
									
									
								
							
							
						
						
									
										104
									
								
								src/drv_imap.c
									
										
									
									
									
								
							|  | @ -487,108 +487,6 @@ submit_imap_cmd( imap_store_t *ctx, imap_cmd_t *cmd ) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* Minimal printf() replacement that supports an %\s format sequence to print backslash-escaped
 |  | ||||||
|  * string literals. Note that this does not automatically add quotes around the printed string, |  | ||||||
|  * so it is possible to concatenate multiple segments. */ |  | ||||||
| static char * |  | ||||||
| imap_vprintf( const char *fmt, va_list ap ) |  | ||||||
| { |  | ||||||
| 	const char *s; |  | ||||||
| 	char *d, *ed; |  | ||||||
| 	char c; |  | ||||||
| #define MAX_SEGS 16 |  | ||||||
| #define add_seg(s, l) \ |  | ||||||
| 		do { \ |  | ||||||
| 			if (nsegs == MAX_SEGS) \ |  | ||||||
| 				oob(); \ |  | ||||||
| 			segs[nsegs] = s; \ |  | ||||||
| 			segls[nsegs++] = l; \ |  | ||||||
| 			totlen += l; \ |  | ||||||
| 		} while (0) |  | ||||||
| 	int nsegs = 0; |  | ||||||
| 	uint totlen = 0; |  | ||||||
| 	const char *segs[MAX_SEGS]; |  | ||||||
| 	uint segls[MAX_SEGS]; |  | ||||||
| 	char buf[1000]; |  | ||||||
| 
 |  | ||||||
| 	d = buf; |  | ||||||
| 	ed = d + sizeof(buf); |  | ||||||
| 	s = fmt; |  | ||||||
| 	for (;;) { |  | ||||||
| 		c = *fmt; |  | ||||||
| 		if (!c || c == '%') { |  | ||||||
| 			uint l = fmt - s; |  | ||||||
| 			if (l) |  | ||||||
| 				add_seg( s, l ); |  | ||||||
| 			if (!c) |  | ||||||
| 				break; |  | ||||||
| 			uint maxlen = UINT_MAX; |  | ||||||
| 			c = *++fmt; |  | ||||||
| 			if (c == '\\') { |  | ||||||
| 				c = *++fmt; |  | ||||||
| 				if (c != 's') { |  | ||||||
| 					fputs( "Fatal: unsupported escaped format specifier. Please report a bug.\n", stderr ); |  | ||||||
| 					abort(); |  | ||||||
| 				} |  | ||||||
| 				char *bd = d; |  | ||||||
| 				s = va_arg( ap, const char * ); |  | ||||||
| 				while ((c = *s++)) { |  | ||||||
| 					if (d + 2 > ed) |  | ||||||
| 						oob(); |  | ||||||
| 					if (c == '\\' || c == '"') |  | ||||||
| 						*d++ = '\\'; |  | ||||||
| 					*d++ = c; |  | ||||||
| 				} |  | ||||||
| 				l = d - bd; |  | ||||||
| 				if (l) |  | ||||||
| 					add_seg( bd, l ); |  | ||||||
| 			} else { /* \\ cannot be combined with anything else. */ |  | ||||||
| 				if (c == '.') { |  | ||||||
| 					c = *++fmt; |  | ||||||
| 					if (c != '*') { |  | ||||||
| 						fputs( "Fatal: unsupported string length specification. Please report a bug.\n", stderr ); |  | ||||||
| 						abort(); |  | ||||||
| 					} |  | ||||||
| 					maxlen = va_arg( ap, uint ); |  | ||||||
| 					c = *++fmt; |  | ||||||
| 				} |  | ||||||
| 				if (c == 'c') { |  | ||||||
| 					if (d + 1 > ed) |  | ||||||
| 						oob(); |  | ||||||
| 					add_seg( d, 1 ); |  | ||||||
| 					*d++ = (char)va_arg( ap , int ); |  | ||||||
| 				} else if (c == 's') { |  | ||||||
| 					s = va_arg( ap, const char * ); |  | ||||||
| 					l = strnlen( s, maxlen ); |  | ||||||
| 					if (l) |  | ||||||
| 						add_seg( s, l ); |  | ||||||
| 				} else if (c == 'd') { |  | ||||||
| 					l = nfsnprintf( d, ed - d, "%d", va_arg( ap, int ) ); |  | ||||||
| 					add_seg( d, l ); |  | ||||||
| 					d += l; |  | ||||||
| 				} else if (c == 'u') { |  | ||||||
| 					l = nfsnprintf( d, ed - d, "%u", va_arg( ap, uint ) ); |  | ||||||
| 					add_seg( d, l ); |  | ||||||
| 					d += l; |  | ||||||
| 				} else { |  | ||||||
| 					fputs( "Fatal: unsupported format specifier. Please report a bug.\n", stderr ); |  | ||||||
| 					abort(); |  | ||||||
| 				} |  | ||||||
| 			} |  | ||||||
| 			s = ++fmt; |  | ||||||
| 		} else { |  | ||||||
| 			fmt++; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	char *out = d = nfmalloc( totlen + 1 ); |  | ||||||
| 	for (int i = 0; i < nsegs; i++) { |  | ||||||
| 		memcpy( d, segs[i], segls[i] ); |  | ||||||
| 		d += segls[i]; |  | ||||||
| 	} |  | ||||||
| 	*d = 0; |  | ||||||
| 	return out; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void | static void | ||||||
| imap_exec( imap_store_t *ctx, imap_cmd_t *cmdp, | imap_exec( imap_store_t *ctx, imap_cmd_t *cmdp, | ||||||
|            void (*done)( imap_store_t *ctx, imap_cmd_t *cmd, int response ), |            void (*done)( imap_store_t *ctx, imap_cmd_t *cmd, int response ), | ||||||
|  | @ -600,7 +498,7 @@ imap_exec( imap_store_t *ctx, imap_cmd_t *cmdp, | ||||||
| 		cmdp = new_imap_cmd( sizeof(*cmdp) ); | 		cmdp = new_imap_cmd( sizeof(*cmdp) ); | ||||||
| 	cmdp->param.done = done; | 	cmdp->param.done = done; | ||||||
| 	va_start( ap, fmt ); | 	va_start( ap, fmt ); | ||||||
| 	cmdp->cmd = imap_vprintf( fmt, ap ); | 	cmdp->cmd = xvasprintf( fmt, ap ); | ||||||
| 	va_end( ap ); | 	va_end( ap ); | ||||||
| 	submit_imap_cmd( ctx, cmdp ); | 	submit_imap_cmd( ctx, cmdp ); | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										106
									
								
								src/util.c
									
										
									
									
									
								
							
							
						
						
									
										106
									
								
								src/util.c
									
										
									
									
									
								
							|  | @ -184,6 +184,112 @@ sys_error( const char *msg, ... ) | ||||||
| 	va_end( va ); | 	va_end( va ); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Minimal printf() replacement with custom format sequence(s):
 | ||||||
|  | // - %\\s
 | ||||||
|  | //   Print backslash-escaped string literals. Note that this does not
 | ||||||
|  | //   automatically add quotes around the printed string, so it is
 | ||||||
|  | //   possible to concatenate multiple segments.
 | ||||||
|  | 
 | ||||||
|  | // TODO: Trade off segments vs. buffer capacity dynamically.
 | ||||||
|  | #define QPRINTF_SEGS 16 | ||||||
|  | #define QPRINTF_BUFF 1000 | ||||||
|  | 
 | ||||||
|  | char * | ||||||
|  | xvasprintf( const char *fmt, va_list ap ) | ||||||
|  | { | ||||||
|  | 	int nsegs = 0; | ||||||
|  | 	uint totlen = 0; | ||||||
|  | 	const char *segs[QPRINTF_SEGS]; | ||||||
|  | 	uint segls[QPRINTF_SEGS]; | ||||||
|  | 	char buf[QPRINTF_BUFF]; | ||||||
|  | 
 | ||||||
|  | #define ADD_SEG(p, l) \ | ||||||
|  | 		do { \ | ||||||
|  | 			if (nsegs == QPRINTF_SEGS) \ | ||||||
|  | 				oob(); \ | ||||||
|  | 			segs[nsegs] = p; \ | ||||||
|  | 			segls[nsegs++] = l; \ | ||||||
|  | 			totlen += l; \ | ||||||
|  | 		} while (0) | ||||||
|  | 
 | ||||||
|  | 	char *d = buf; | ||||||
|  | 	char *ed = d + sizeof(buf); | ||||||
|  | 	const char *s = fmt; | ||||||
|  | 	for (;;) { | ||||||
|  | 		char c = *fmt; | ||||||
|  | 		if (!c || c == '%') { | ||||||
|  | 			uint l = fmt - s; | ||||||
|  | 			if (l) | ||||||
|  | 				ADD_SEG( s, l ); | ||||||
|  | 			if (!c) | ||||||
|  | 				break; | ||||||
|  | 			uint maxlen = UINT_MAX; | ||||||
|  | 			c = *++fmt; | ||||||
|  | 			if (c == '\\') { | ||||||
|  | 				c = *++fmt; | ||||||
|  | 				if (c != 's') { | ||||||
|  | 					fputs( "Fatal: unsupported escaped format specifier. Please report a bug.\n", stderr ); | ||||||
|  | 					abort(); | ||||||
|  | 				} | ||||||
|  | 				char *bd = d; | ||||||
|  | 				s = va_arg( ap, const char * ); | ||||||
|  | 				while ((c = *s++)) { | ||||||
|  | 					if (d + 2 > ed) | ||||||
|  | 						oob(); | ||||||
|  | 					if (c == '\\' || c == '"') | ||||||
|  | 						*d++ = '\\'; | ||||||
|  | 					*d++ = c; | ||||||
|  | 				} | ||||||
|  | 				l = d - bd; | ||||||
|  | 				if (l) | ||||||
|  | 					ADD_SEG( bd, l ); | ||||||
|  | 			} else {  // \\ cannot be combined with anything else.
 | ||||||
|  | 				if (c == '.') { | ||||||
|  | 					c = *++fmt; | ||||||
|  | 					if (c != '*') { | ||||||
|  | 						fputs( "Fatal: unsupported string length specification. Please report a bug.\n", stderr ); | ||||||
|  | 						abort(); | ||||||
|  | 					} | ||||||
|  | 					maxlen = va_arg( ap, uint ); | ||||||
|  | 					c = *++fmt; | ||||||
|  | 				} | ||||||
|  | 				if (c == 'c') { | ||||||
|  | 					if (d + 1 > ed) | ||||||
|  | 						oob(); | ||||||
|  | 					ADD_SEG( d, 1 ); | ||||||
|  | 					*d++ = (char)va_arg( ap, int ); | ||||||
|  | 				} else if (c == 's') { | ||||||
|  | 					s = va_arg( ap, const char * ); | ||||||
|  | 					l = strnlen( s, maxlen ); | ||||||
|  | 					if (l) | ||||||
|  | 						ADD_SEG( s, l ); | ||||||
|  | 				} else if (c == 'd') { | ||||||
|  | 					l = nfsnprintf( d, ed - d, "%d", va_arg( ap, int ) ); | ||||||
|  | 					ADD_SEG( d, l ); | ||||||
|  | 					d += l; | ||||||
|  | 				} else if (c == 'u') { | ||||||
|  | 					l = nfsnprintf( d, ed - d, "%u", va_arg( ap, uint ) ); | ||||||
|  | 					ADD_SEG( d, l ); | ||||||
|  | 					d += l; | ||||||
|  | 				} else { | ||||||
|  | 					fputs( "Fatal: unsupported format specifier. Please report a bug.\n", stderr ); | ||||||
|  | 					abort(); | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 			s = ++fmt; | ||||||
|  | 		} else { | ||||||
|  | 			fmt++; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	char *out = d = nfmalloc( totlen + 1 ); | ||||||
|  | 	for (int i = 0; i < nsegs; i++) { | ||||||
|  | 		memcpy( d, segs[i], segls[i] ); | ||||||
|  | 		d += segls[i]; | ||||||
|  | 	} | ||||||
|  | 	*d = 0; | ||||||
|  | 	return out; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| void | void | ||||||
| vFprintf( FILE *f, const char *msg, va_list va ) | vFprintf( FILE *f, const char *msg, va_list va ) | ||||||
| { | { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue