1# 2# Copyright (c) 1996, 2020 Oracle and/or its affiliates. All rights reserved. 3# 4# See the file LICENSE for license information. 5# 6# $Id$ 7# 8 9BEGIN { 10 if (source_file == "" || header_file == "") { 11 print "Usage: gen_msg.awk requires these variables to be set:"; 12 print "\theader_file\t-- the message #include file being created"; 13 print "\tsource_file\t-- the message source file being created"; 14 exit; 15 } 16 CFILE=source_file; 17 HFILE=header_file; 18 maxmsg = 0; 19} 20/^[ ]*PREFIX/ { 21 prefix = $2; 22 23 # Start .c files. 24 printf("/* Do not edit: automatically built by gen_msg.awk. */\n\n") \ 25 > CFILE 26 printf("#include \"db_config.h\"\n\n") >> CFILE 27 28 # Start .h file, make the entire file conditional. 29 printf("/* Do not edit: automatically built by gen_msg.awk. */\n\n") \ 30 > HFILE 31 printf("#ifndef\t%s_AUTOMSG_H\n#define\t%s_AUTOMSG_H\n\n", prefix, prefix) \ 32 >> HFILE; 33 printf("/*\n") >> HFILE; 34 printf(" * Message sizes are simply the sum of field sizes (not\n") \ 35 >> HFILE; 36 printf(" * counting variable size parts, when DBTs are present),\n") \ 37 >> HFILE; 38 printf(" * and may be different from struct sizes due to padding.\n") \ 39 >> HFILE; 40 printf(" */\n") >> HFILE; 41} 42/^[ ]*INCLUDE/ { 43 for (i = 2; i < NF; i++) 44 printf("%s ", $i) >> CFILE; 45 printf("%s\n", $i) >> CFILE; 46} 47/^[ ]*BEGIN_MSG/ { 48 if (in_begin) { 49 print "Invalid format: missing END statement"; 50 exit; 51 } 52 in_begin = 1; 53 nvars = 0; 54 thismsg = $2; 55 for (i = 2; i<= NF; i++) { 56 if ($i == "alloc") 57 alloc = 1; 58 else if ($i == "check_length") 59 check_length = 1; 60 } 61 62 base_name = sprintf("%s_%s", prefix, thismsg); 63 typedef_name = sprintf("%s_args", base_name); 64 msg_size_name = toupper(sprintf("%s_SIZE", base_name)); 65 max_name = toupper(sprintf("%s_MAXMSG_SIZE", prefix)); 66} 67/^[ ]*ARG/ { 68 vars[nvars] = $2; 69 types[nvars] = $3; 70 if (types[nvars] == "DBT") 71 has_dbt = 1; 72 nvars++; 73} 74/^[ ]*END/ { 75 if (!in_begin) { 76 print "Invalid format: missing BEGIN statement"; 77 exit; 78 } 79 if (nvars == 0) { 80 printf("%s needs at least one field\n", thismsg); 81 exit; 82 } 83 84 sum = 0; 85 for (i = 0; i < nvars; i++) 86 sum += type_length(types[i]); 87 printf("#define\t%s\t%d\n", msg_size_name, sum) >> HFILE; 88 if (sum > maxmsg) 89 maxmsg = sum; 90 91 printf("typedef struct _%s {\n", typedef_name) >> HFILE; 92 for (i = 0; i < nvars; i++) { 93 if (types[i] == "DB_LSN" || types[i] == "DBT") 94 printf("\t%s\t\t%s;\n", types[i], vars[i]) >> HFILE; 95 else 96 printf("\t%s\t%s;\n", types[i], vars[i]) >> HFILE; 97 } 98 printf("} %s;\n\n", typedef_name) >> HFILE; 99 100 emit_marshal(); 101 emit_unmarshal(); 102 103 # Reinitialize variables for next time. 104 in_begin = 0; 105 alloc = 0; 106 check_length = 0; 107 has_dbt = 0; 108} 109END { 110 # End the conditional for the HFILE 111 printf("#define\t%s\t%d\n", max_name, maxmsg) >> HFILE; 112 printf("#endif\n") >> HFILE; 113} 114 115# Length of fixed part of message. Does not count variable-length data portion 116# of DBT. 117# 118function type_length(type) 119{ 120 if (type == "DB_LSN" || type == "u_int64_t") 121 return (8); 122 if (type == "DBT" || type == "u_int32_t" || type == "db_pgno_t") 123 return (4); 124 if (type == "u_int16_t") 125 return (2); 126 if (type == "u_int8_t") 127 return (1); 128 printf("unknown field type: %s", type); 129 exit(1); 130} 131 132function emit_marshal() 133{ 134 pi = 1; 135 if (check_length) 136 p[pi++] = "int "; 137 else 138 p[pi++] = "void "; 139 function_name = sprintf("%s_marshal", base_name); 140 p[pi++] = function_name; 141 p[pi++] = " __P((ENV *, "; 142 p[pi++] = sprintf("%s *, u_int8_t *", typedef_name); 143 if (check_length) 144 p[pi++] = ", size_t, size_t *"; 145 p[pi++] = "));"; 146 proto_format(p, CFILE); 147 148 if (check_length) 149 printf("int\n") >> CFILE; 150 else 151 printf("void\n") >> CFILE; 152 printf("%s(env", function_name) >> CFILE; 153 printf(", argp, bp") >> CFILE; 154 if (check_length) 155 printf(", max, lenp") >> CFILE; 156 printf(")\n") >> CFILE; 157 158 printf("\tENV *env;\n") >> CFILE; 159 printf("\t%s *argp;\n", typedef_name) >> CFILE; 160 printf("\tu_int8_t *bp;\n") >> CFILE; 161 if (check_length) 162 printf("\tsize_t *lenp, max;\n") >> CFILE; 163 printf("{\n") >> CFILE; 164 165 if (check_length) { 166 printf("\tu_int8_t *start;\n\n") >> CFILE; 167 printf("\tif (max < %s", msg_size_name) >> CFILE; 168 for (i = 0; i < nvars; i++) 169 if (types[i] == "DBT") 170 printf("\n\t + (size_t)argp->%s.size", \ 171 vars[i]) >> CFILE; 172 # add in dbt sizes 173 printf(")\n") >> CFILE; 174 printf("\t\treturn (ENOMEM);\n") >> CFILE; 175 printf("\tstart = bp;\n\n") >> CFILE; 176 } 177 178 for (i = 0; i < nvars; i++) { 179 if (types[i] == "u_int32_t" || types[i] == "db_pgno_t") { 180 printf("\tDB_HTONL_COPYOUT(env, bp, argp->%s);\n", \ 181 vars[i]) >> CFILE; 182 } else if (types[i] == "u_int16_t") { 183 printf("\tDB_HTONS_COPYOUT(env, bp, argp->%s);\n", \ 184 vars[i]) >> CFILE; 185 } else if (types[i] == "u_int8_t") { 186 printf(\ 187 "\t*bp++ = argp->%s;\n", vars[i]) >> CFILE; 188 } else if (types[i] == "DB_LSN") { 189 printf("\tDB_HTONL_COPYOUT(env, bp, argp->%s.file);\n",\ 190 vars[i]) >> CFILE; 191 printf( \ 192 "\tDB_HTONL_COPYOUT(env, bp, argp->%s.offset);\n", \ 193 vars[i]) >> CFILE; 194 } else if (types[i] == "DBT") { 195 printf("\tDB_HTONL_COPYOUT(env, bp, argp->%s.size);\n",\ 196 vars[i]) >> CFILE; 197 printf("\tif (argp->%s.size > 0) {\n", vars[i]) \ 198 >> CFILE; 199 printf( \ 200 "\t\tmemcpy(bp, argp->%s.data, argp->%s.size);\n", \ 201 vars[i], vars[i]) >> CFILE; 202 printf("\t\tbp += argp->%s.size;\n", vars[i]) >> CFILE; 203 printf("\t}\n") >> CFILE; 204 } else if (types[i] == "u_int64_t") { 205 printf("\tDB_HTONLL_COPYOUT(env, bp, argp->%s);\n", \ 206 vars[i]) >> CFILE; 207 } else { 208 printf("unknown field type: %s", types[i]); 209 exit(1); 210 } 211 } 212 213 if (check_length) { 214 printf("\n\t*lenp = (size_t)(bp - start);\n") >> CFILE; 215 printf("\treturn (0);\n") >> CFILE; 216 } 217 printf("}\n\n") >> CFILE; 218} 219 220function emit_unmarshal() 221{ 222 pi = 1; 223 p[pi++] = "int "; 224 function_name = sprintf("%s_unmarshal", base_name); 225 p[pi++] = function_name; 226 p[pi++] = " __P((ENV *, "; 227 if (alloc) 228 p[pi++] = sprintf("%s **, u_int8_t *, ", typedef_name); 229 else 230 p[pi++] = sprintf("%s *, u_int8_t *, ", typedef_name); 231 p[pi++] = sprintf("size_t, u_int8_t **));"); 232 proto_format(p, CFILE); 233 234 printf("int\n") >> CFILE; 235 if (alloc) 236 arg_name = "argpp"; 237 else 238 arg_name = "argp"; 239 printf("%s(env, ", function_name) >> CFILE; 240 printf("%s, bp, ", arg_name) >> CFILE; 241 printf("max, nextp)\n") >> CFILE; 242 printf("\tENV *env;\n") >> CFILE; 243 if (alloc) 244 printf("\t%s **argpp;\n", typedef_name) >> CFILE; 245 else 246 printf("\t%s *argp;\n", typedef_name) >> CFILE; 247 printf("\tu_int8_t *bp;\n") >> CFILE; 248 printf("\tsize_t max;\n") >> CFILE; 249 printf("\tu_int8_t **nextp;\n") >> CFILE; 250 printf("{\n") >> CFILE; 251 has_locals = 0; 252 if (has_dbt) { 253 printf("\tsize_t needed;\n") >> CFILE; 254 has_locals = 1; 255 } 256 if (alloc) { 257 printf("\t%s *argp;\n", typedef_name) >> CFILE; 258 printf("\tint ret;\n") >> CFILE; 259 has_locals = 1; 260 } 261 if (has_locals) 262 printf("\n") >> CFILE; 263 264 # Check that input byte buffer is long enough. 265 # 266 if (has_dbt) { 267 printf("\tneeded = %s;\n", msg_size_name) >> CFILE; 268 printf("\tif (max < needed)\n") >> CFILE; 269 } else 270 printf("\tif (max < %s)\n", msg_size_name) >> CFILE; 271 printf("\t\tgoto too_few;\n") >> CFILE; 272 273 if (alloc) { 274 printf( \ 275 "\tif ((ret = __os_malloc(env, sizeof(*argp), &argp)) != 0)\n") \ 276 >> CFILE; 277 printf("\t\treturn (ret);\n\n") >> CFILE; 278 } 279 280 for (i = 0; i < nvars; i++) { 281 if (types[i] == "u_int32_t" || types[i] == "db_pgno_t") { 282 printf("\tDB_NTOHL_COPYIN(env, argp->%s, bp);\n", \ 283 vars[i]) >> CFILE; 284 } else if (types[i] == "u_int16_t") { 285 printf("\tDB_NTOHS_COPYIN(env, argp->%s, bp);\n", \ 286 vars[i]) >> CFILE; 287 } else if (types[i] == "u_int8_t") { 288 printf(\ 289 "\targp->%s = *bp++;\n", vars[i]) >> CFILE; 290 } else if (types[i] == "DB_LSN") { 291 printf("\tDB_NTOHL_COPYIN(env, argp->%s.file, bp);\n", \ 292 vars[i]) >> CFILE; 293 printf( \ 294 "\tDB_NTOHL_COPYIN(env, argp->%s.offset, bp);\n", \ 295 vars[i]) >> CFILE; 296 } else if (types[i] == "DBT") { 297 printf("\tDB_NTOHL_COPYIN(env, argp->%s.size, bp);\n", \ 298 vars[i]) >> CFILE; 299 printf("\tif (argp->%s.size == 0)\n", vars[i]) >> CFILE; 300 printf("\t\targp->%s.data = NULL;\n", vars[i]) >> CFILE; 301 printf("\telse\n") >> CFILE; 302 printf("\t\targp->%s.data = bp;\n", vars[i]) >> CFILE; 303 printf("\tneeded += (size_t)argp->%s.size;\n", \ 304 vars[i]) >> CFILE; 305 printf("\tif (max < needed)\n") >> CFILE; 306 printf("\t\tgoto too_few;\n") >> CFILE; 307 printf("\tbp += argp->%s.size;\n", vars[i]) >> CFILE; 308 } else if (types[i] == "u_int64_t") { 309 printf("\tDB_NTOHLL_COPYIN(env, argp->%s, bp);\n", \ 310 vars[i]) >> CFILE; 311 } else { 312 printf("unknown field type: %s", types[i]); 313 exit(1); 314 } 315 } 316 317 printf("\n\tif (nextp != NULL)\n") >> CFILE; 318 printf("\t\t*nextp = bp;\n") >> CFILE; 319 if (alloc) { 320 printf("\t*argpp = argp;\n") >> CFILE; 321 } 322 printf("\treturn (0);\n\n") >> CFILE; 323 324 printf("too_few:\n") >> CFILE; 325 printf("\t__db_errx(env, DB_STR_A(\"3675\",\n") >> CFILE; 326 printf( \ 327 "\t \"Not enough input bytes to fill a %%s message\",\n") >> CFILE; 328 printf("\t \"%%s\"), \"%s\");\n", base_name) >> CFILE; 329 printf("\treturn (EINVAL);\n") >> CFILE; 330 printf("}\n\n") >> CFILE; 331} 332 333# proto_format -- 334# Pretty-print a function prototype. 335function proto_format(p, fp) 336{ 337 printf("/*\n") >> fp; 338 339 s = ""; 340 for (i = 1; i in p; ++i) 341 s = s p[i]; 342 343 t = " * PUBLIC: " 344 if (length(s) + length(t) < 80) 345 printf("%s%s", t, s) >> fp; 346 else { 347 split(s, p, "__P"); 348 len = length(t) + length(p[1]); 349 printf("%s%s", t, p[1]) >> fp 350 351 n = split(p[2], comma, ","); 352 comma[1] = "__P" comma[1]; 353 for (i = 1; i <= n; i++) { 354 if (len + length(comma[i]) > 70) { 355 printf("\n * PUBLIC: ") >> fp; 356 len = 0; 357 } 358 printf("%s%s", comma[i], i == n ? "" : ",") >> fp; 359 len += length(comma[i]) + 2; 360 } 361 } 362 printf("\n */\n") >> fp; 363 delete p; 364} 365