1 /* $NetBSD: attr_print_plain.c,v 1.2 2017/02/14 01:16:49 christos Exp $ */ 2 3 /*++ 4 /* NAME 5 /* attr_print_plain 3 6 /* SUMMARY 7 /* send attributes over byte stream 8 /* SYNOPSIS 9 /* #include <attr.h> 10 /* 11 /* int attr_print_plain(fp, flags, type, name, ..., ATTR_TYPE_END) 12 /* VSTREAM fp; 13 /* int flags; 14 /* int type; 15 /* char *name; 16 /* 17 /* int attr_vprint_plain(fp, flags, ap) 18 /* VSTREAM fp; 19 /* int flags; 20 /* va_list ap; 21 /* DESCRIPTION 22 /* attr_print_plain() takes zero or more (name, value) simple attributes 23 /* and converts its input to a byte stream that can be recovered with 24 /* attr_scan_plain(). The stream is not flushed. 25 /* 26 /* attr_vprint_plain() provides an alternate interface that is convenient 27 /* for calling from within variadic functions. 28 /* 29 /* Attributes are sent in the requested order as specified with the 30 /* attr_print_plain() argument list. This routine satisfies the formatting 31 /* rules as outlined in attr_scan_plain(3). 32 /* 33 /* Arguments: 34 /* .IP fp 35 /* Stream to write the result to. 36 /* .IP flags 37 /* The bit-wise OR of zero or more of the following. 38 /* .RS 39 /* .IP ATTR_FLAG_MORE 40 /* After sending the requested attributes, leave the output stream in 41 /* a state that is usable for more attribute sending operations on 42 /* the same output attribute list. 43 /* By default, attr_print_plain() automatically appends an attribute list 44 /* terminator when it has sent the last requested attribute. 45 /* .RE 46 /* .IP List of attributes followed by terminator: 47 /* .RS 48 /* .IP "SEND_ATTR_INT(const char *name, int value)" 49 /* The arguments are an attribute name and an integer. 50 /* .IP "SEND_ATTR_LONG(const char *name, long value)" 51 /* The arguments are an attribute name and a long integer. 52 /* .IP "SEND_ATTR_STR(const char *name, const char *value)" 53 /* The arguments are an attribute name and a null-terminated 54 /* string. 55 /* .IP "SEND_ATTR_DATA(const char *name, ssize_t len, const void *value)" 56 /* The arguments are an attribute name, an attribute value 57 /* length, and an attribute value pointer. 58 /* .IP "SEND_ATTR_FUNC(ATTR_PRINT_SLAVE_FN, const void *value)" 59 /* The arguments are a function pointer and generic data 60 /* pointer. The caller-specified function returns whatever the 61 /* specified attribute printing function returns. 62 /* .IP "SEND_ATTR_HASH(const HTABLE *table)" 63 /* .IP "SEND_ATTR_NAMEVAL(const NVTABLE *table)" 64 /* The content of the table is sent as a sequence of string-valued 65 /* attributes with names equal to the table lookup keys. 66 /* .IP ATTR_TYPE_END 67 /* This terminates the attribute list. 68 /* .RE 69 /* DIAGNOSTICS 70 /* The result value is 0 in case of success, VSTREAM_EOF in case 71 /* of trouble. 72 /* 73 /* Panic: interface violation. All system call errors are fatal. 74 /* SEE ALSO 75 /* attr_scan_plain(3) recover attributes from byte stream 76 /* LICENSE 77 /* .ad 78 /* .fi 79 /* The Secure Mailer license must be distributed with this software. 80 /* AUTHOR(S) 81 /* Wietse Venema 82 /* IBM T.J. Watson Research 83 /* P.O. Box 704 84 /* Yorktown Heights, NY 10598, USA 85 /* 86 /* Wietse Venema 87 /* Google, Inc. 88 /* 111 8th Avenue 89 /* New York, NY 10011, USA 90 /*--*/ 91 92 /* System library. */ 93 94 #include <sys_defs.h> 95 #include <stdarg.h> 96 #include <string.h> 97 98 /* Utility library. */ 99 100 #include <msg.h> 101 #include <mymalloc.h> 102 #include <vstream.h> 103 #include <htable.h> 104 #include <base64_code.h> 105 #include <vstring.h> 106 #include <attr.h> 107 108 #define STR(x) vstring_str(x) 109 #define LEN(x) VSTRING_LEN(x) 110 111 /* attr_vprint_plain - send attribute list to stream */ 112 113 int attr_vprint_plain(VSTREAM *fp, int flags, va_list ap) 114 { 115 const char *myname = "attr_print_plain"; 116 int attr_type; 117 char *attr_name; 118 unsigned int_val; 119 unsigned long long_val; 120 char *str_val; 121 HTABLE_INFO **ht_info_list; 122 HTABLE_INFO **ht; 123 static VSTRING *base64_buf; 124 ssize_t len_val; 125 ATTR_PRINT_SLAVE_FN print_fn; 126 void *print_arg; 127 128 /* 129 * Sanity check. 130 */ 131 if (flags & ~ATTR_FLAG_ALL) 132 msg_panic("%s: bad flags: 0x%x", myname, flags); 133 134 /* 135 * Iterate over all (type, name, value) triples, and produce output on 136 * the fly. 137 */ 138 while ((attr_type = va_arg(ap, int)) != ATTR_TYPE_END) { 139 switch (attr_type) { 140 case ATTR_TYPE_INT: 141 attr_name = va_arg(ap, char *); 142 int_val = va_arg(ap, int); 143 vstream_fprintf(fp, "%s=%u\n", attr_name, (unsigned) int_val); 144 if (msg_verbose) 145 msg_info("send attr %s = %u", attr_name, (unsigned) int_val); 146 break; 147 case ATTR_TYPE_LONG: 148 attr_name = va_arg(ap, char *); 149 long_val = va_arg(ap, long); 150 vstream_fprintf(fp, "%s=%lu\n", attr_name, long_val); 151 if (msg_verbose) 152 msg_info("send attr %s = %lu", attr_name, long_val); 153 break; 154 case ATTR_TYPE_STR: 155 attr_name = va_arg(ap, char *); 156 str_val = va_arg(ap, char *); 157 vstream_fprintf(fp, "%s=%s\n", attr_name, str_val); 158 if (msg_verbose) 159 msg_info("send attr %s = %s", attr_name, str_val); 160 break; 161 case ATTR_TYPE_DATA: 162 attr_name = va_arg(ap, char *); 163 len_val = va_arg(ap, ssize_t); 164 str_val = va_arg(ap, char *); 165 if (base64_buf == 0) 166 base64_buf = vstring_alloc(10); 167 base64_encode(base64_buf, str_val, len_val); 168 vstream_fprintf(fp, "%s=%s\n", attr_name, STR(base64_buf)); 169 if (msg_verbose) 170 msg_info("send attr %s = [data %ld bytes]", 171 attr_name, (long) len_val); 172 break; 173 case ATTR_TYPE_FUNC: 174 print_fn = va_arg(ap, ATTR_PRINT_SLAVE_FN); 175 print_arg = va_arg(ap, void *); 176 print_fn(attr_print_plain, fp, flags | ATTR_FLAG_MORE, print_arg); 177 break; 178 case ATTR_TYPE_HASH: 179 vstream_fwrite(fp, ATTR_NAME_OPEN, sizeof(ATTR_NAME_OPEN)); 180 VSTREAM_PUTC('\n', fp); 181 ht_info_list = htable_list(va_arg(ap, HTABLE *)); 182 for (ht = ht_info_list; *ht; ht++) { 183 vstream_fprintf(fp, "%s=%s\n", ht[0]->key, (char *) ht[0]->value); 184 if (msg_verbose) 185 msg_info("send attr name %s value %s", 186 ht[0]->key, (char *) ht[0]->value); 187 } 188 myfree((void *) ht_info_list); 189 vstream_fwrite(fp, ATTR_NAME_CLOSE, sizeof(ATTR_NAME_CLOSE)); 190 VSTREAM_PUTC('\n', fp); 191 break; 192 default: 193 msg_panic("%s: unknown type code: %d", myname, attr_type); 194 } 195 } 196 if ((flags & ATTR_FLAG_MORE) == 0) 197 VSTREAM_PUTC('\n', fp); 198 return (vstream_ferror(fp)); 199 } 200 201 int attr_print_plain(VSTREAM *fp, int flags,...) 202 { 203 va_list ap; 204 int ret; 205 206 va_start(ap, flags); 207 ret = attr_vprint_plain(fp, flags, ap); 208 va_end(ap); 209 return (ret); 210 } 211 212 #ifdef TEST 213 214 /* 215 * Proof of concept test program. Mirror image of the attr_scan_plain test 216 * program. 217 */ 218 #include <msg_vstream.h> 219 220 int main(int unused_argc, char **argv) 221 { 222 HTABLE *table = htable_create(1); 223 224 msg_vstream_init(argv[0], VSTREAM_ERR); 225 msg_verbose = 1; 226 htable_enter(table, "foo-name", mystrdup("foo-value")); 227 htable_enter(table, "bar-name", mystrdup("bar-value")); 228 attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE, 229 SEND_ATTR_INT(ATTR_NAME_INT, 4711), 230 SEND_ATTR_LONG(ATTR_NAME_LONG, 1234L), 231 SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"), 232 SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"), 233 SEND_ATTR_HASH(table), 234 SEND_ATTR_LONG(ATTR_NAME_LONG, 4321L), 235 ATTR_TYPE_END); 236 attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE, 237 SEND_ATTR_INT(ATTR_NAME_INT, 4711), 238 SEND_ATTR_LONG(ATTR_NAME_LONG, 1234L), 239 SEND_ATTR_STR(ATTR_NAME_STR, "whoopee"), 240 SEND_ATTR_DATA(ATTR_NAME_DATA, strlen("whoopee"), "whoopee"), 241 ATTR_TYPE_END); 242 if (vstream_fflush(VSTREAM_OUT) != 0) 243 msg_fatal("write error: %m"); 244 245 htable_free(table, myfree); 246 return (0); 247 } 248 249 #endif 250