mojoshader_preprocessor.c
changeset 944 9f9fa9650772
parent 941 405a57d342a1
child 945 f00ea3986db8
equal deleted inserted replaced
943:775cd2ac324b 944:9f9fa9650772
    78 
    78 
    79 static inline void Free(Context *ctx, void *ptr)
    79 static inline void Free(Context *ctx, void *ptr)
    80 {
    80 {
    81     ctx->free(ptr, ctx->malloc_data);
    81     ctx->free(ptr, ctx->malloc_data);
    82 } // Free
    82 } // Free
       
    83 
       
    84 static void *MallocBridge(int bytes, void *data)
       
    85 {
       
    86     return Malloc((Context *) data, (size_t) bytes);
       
    87 } // MallocBridge
       
    88 
       
    89 static void FreeBridge(void *ptr, void *data)
       
    90 {
       
    91     Free((Context *) data, ptr);
       
    92 } // FreeBridge
    83 
    93 
    84 static inline char *StrDup(Context *ctx, const char *str)
    94 static inline char *StrDup(Context *ctx, const char *str)
    85 {
    95 {
    86     char *retval = (char *) Malloc(ctx, strlen(str) + 1);
    96     char *retval = (char *) Malloc(ctx, strlen(str) + 1);
    87     if (retval != NULL)
    97     if (retval != NULL)
   282     f((void *) data, d);
   292     f((void *) data, d);
   283 } // MOJOSHADER_internal_include_close
   293 } // MOJOSHADER_internal_include_close
   284 #endif  // !MOJOSHADER_FORCE_INCLUDE_CALLBACKS
   294 #endif  // !MOJOSHADER_FORCE_INCLUDE_CALLBACKS
   285 
   295 
   286 
   296 
   287 // !!! FIXME: move this stuff to mojoshader_common.c ...
       
   288 // data buffer stuff...
       
   289 
       
   290 #define BUFFER_LEN (64 * 1024)
       
   291 typedef struct BufferList
       
   292 {
       
   293     char buffer[BUFFER_LEN];
       
   294     size_t bytes;
       
   295     struct BufferList *next;
       
   296 } BufferList;
       
   297 
       
   298 typedef struct Buffer
       
   299 {
       
   300     size_t total_bytes;
       
   301     BufferList head;
       
   302     BufferList *tail;
       
   303 } Buffer;
       
   304 
       
   305 static void init_buffer(Buffer *buffer)
       
   306 {
       
   307     buffer->total_bytes = 0;
       
   308     buffer->head.bytes = 0;
       
   309     buffer->head.next = NULL;
       
   310     buffer->tail = &buffer->head;
       
   311 } // init_buffer
       
   312 
       
   313 
       
   314 static int add_to_buffer(Buffer *buffer, const char *data,
       
   315                          size_t len, MOJOSHADER_malloc m, void *d)
       
   316 {
       
   317     buffer->total_bytes += len;
       
   318     while (len > 0)
       
   319     {
       
   320         const size_t avail = BUFFER_LEN - buffer->tail->bytes;
       
   321         const size_t cpy = (avail > len) ? len : avail;
       
   322         memcpy(buffer->tail->buffer + buffer->tail->bytes, data, cpy);
       
   323         len -= cpy;
       
   324         data += cpy;
       
   325         buffer->tail->bytes += cpy;
       
   326         assert(buffer->tail->bytes <= BUFFER_LEN);
       
   327         if (buffer->tail->bytes == BUFFER_LEN)
       
   328         {
       
   329             BufferList *item = (BufferList *) m(sizeof (BufferList), d);
       
   330             if (item == NULL)
       
   331                 return 0;
       
   332             item->bytes = 0;
       
   333             item->next = NULL;
       
   334             buffer->tail->next = item;
       
   335             buffer->tail = item;
       
   336         } // if
       
   337     } // while
       
   338 
       
   339     return 1;
       
   340 } // add_to_buffer
       
   341 
       
   342 
       
   343 static char *flatten_buffer(Buffer *buffer, MOJOSHADER_malloc m, void *d)
       
   344 {
       
   345     char *retval = (char *) m(buffer->total_bytes + 1, d);
       
   346     if (retval == NULL)
       
   347         return NULL;
       
   348     BufferList *item = &buffer->head;
       
   349     char *ptr = retval;
       
   350     while (item != NULL)
       
   351     {
       
   352         BufferList *next = item->next;
       
   353         memcpy(ptr, item->buffer, item->bytes);
       
   354         ptr += item->bytes;
       
   355         item = next;
       
   356     } // while
       
   357     *ptr = '\0';
       
   358 
       
   359     assert(ptr == (retval + buffer->total_bytes));
       
   360     return retval;
       
   361 } // flatten_buffer
       
   362 
       
   363 
       
   364 static void free_buffer(Buffer *buffer, MOJOSHADER_free f, void *d)
       
   365 {
       
   366     // head is statically allocated, so start with head.next...
       
   367     BufferList *item = buffer->head.next;
       
   368     while (item != NULL)
       
   369     {
       
   370         BufferList *next = item->next;
       
   371         f(item, d);
       
   372         item = next;
       
   373     } // while
       
   374     init_buffer(buffer);
       
   375 } // free_buffer
       
   376 
       
   377 
       
   378 // !!! FIXME: maybe use these pool magic elsewhere?
   297 // !!! FIXME: maybe use these pool magic elsewhere?
   379 // !!! FIXME: maybe just get rid of this? (maybe the fragmentation isn't a big deal?)
   298 // !!! FIXME: maybe just get rid of this? (maybe the fragmentation isn't a big deal?)
   380 
   299 
   381 // Pool stuff...
   300 // Pool stuff...
   382 // ugh, I hate this macro salsa.
   301 // ugh, I hate this macro salsa.
  1058     lexer(state);
   977     lexer(state);
  1059     state->report_whitespace = 0;
   978     state->report_whitespace = 0;
  1060 
   979 
  1061     int params = 0;
   980     int params = 0;
  1062     char **idents = NULL;
   981     char **idents = NULL;
  1063     MOJOSHADER_malloc m = ctx->malloc;
       
  1064     void *d = ctx->malloc_data;
       
  1065     static const char space = ' ';
   982     static const char space = ' ';
  1066 
   983 
  1067     if (state->tokenval == ((Token) ' '))
   984     if (state->tokenval == ((Token) ' '))
  1068         lexer(state);  // skip it.
   985         lexer(state);  // skip it.
  1069     else if (state->tokenval == ((Token) '('))
   986     else if (state->tokenval == ((Token) '('))
  1131         lexer(state);
  1048         lexer(state);
  1132     } // else if
  1049     } // else if
  1133 
  1050 
  1134     pushback(state);
  1051     pushback(state);
  1135 
  1052 
  1136     Buffer buffer;
  1053     Buffer *buffer = buffer_create(128, MallocBridge, FreeBridge, ctx);
  1137     init_buffer(&buffer);
       
  1138 
  1054 
  1139     state->report_whitespace = 1;
  1055     state->report_whitespace = 1;
  1140     while ((!done) && (!ctx->out_of_memory))
  1056     while ((!done) && (!ctx->out_of_memory))
  1141     {
  1057     {
  1142         const Token token = lexer(state);
  1058         const Token token = lexer(state);
  1151             case ((Token) '\n'):
  1067             case ((Token) '\n'):
  1152                 done = 1;
  1068                 done = 1;
  1153                 break;
  1069                 break;
  1154 
  1070 
  1155             case ((Token) ' '):  // may not actually point to ' '.
  1071             case ((Token) ' '):  // may not actually point to ' '.
  1156                 assert(buffer.total_bytes > 0);
  1072                 assert(buffer_size(buffer) > 0);
  1157                 if (!add_to_buffer(&buffer, &space, 1, m, d))
  1073                 buffer_append(buffer, &space, 1);
  1158                     out_of_memory(ctx);
       
  1159                 break;
  1074                 break;
  1160 
  1075 
  1161             default:
  1076             default:
  1162                 if (!add_to_buffer(&buffer,state->token,state->tokenlen,m,d))
  1077                 buffer_append(buffer, state->token, state->tokenlen);
  1163                     out_of_memory(ctx);
       
  1164                 break;
  1078                 break;
  1165         } // switch
  1079         } // switch
  1166     } // while
  1080     } // while
  1167     state->report_whitespace = 0;
  1081     state->report_whitespace = 0;
  1168 
  1082 
       
  1083     size_t buflen = buffer_size(buffer) + 1;
  1169     if (!ctx->out_of_memory)
  1084     if (!ctx->out_of_memory)
  1170     {
  1085         definition = buffer_flatten(buffer);
  1171         definition = flatten_buffer(&buffer, m, d);
  1086 
  1172         if (definition == NULL)
  1087     buffer_destroy(buffer);
  1173             out_of_memory(ctx);
       
  1174     } // if
       
  1175 
       
  1176     size_t buflen = buffer.total_bytes + 1;
       
  1177     free_buffer(&buffer, ctx->free, d);
       
  1178 
  1088 
  1179     if (ctx->out_of_memory)
  1089     if (ctx->out_of_memory)
  1180         goto handle_pp_define_failed;
  1090         goto handle_pp_define_failed;
  1181 
  1091 
  1182     int hashhash_error = 0;
  1092     int hashhash_error = 0;
  1324 
  1234 
  1325 static int replace_and_push_macro(Context *ctx, const Define *def,
  1235 static int replace_and_push_macro(Context *ctx, const Define *def,
  1326                                   const Define *params)
  1236                                   const Define *params)
  1327 {
  1237 {
  1328     char *final = NULL;
  1238     char *final = NULL;
  1329     MOJOSHADER_malloc m = ctx->malloc;
       
  1330     MOJOSHADER_free f = ctx->free;
       
  1331     void *d = ctx->malloc_data;
       
  1332 
  1239 
  1333     // We push the #define and lex it, building a buffer with argument
  1240     // We push the #define and lex it, building a buffer with argument
  1334     //  replacement, stringification, and concatenation.
  1241     //  replacement, stringification, and concatenation.
       
  1242     Buffer *buffer = buffer_create(128, MallocBridge, FreeBridge, ctx);
       
  1243     if (buffer == NULL)
       
  1244         return 0;
       
  1245 
  1335     IncludeState *state = ctx->include_stack;
  1246     IncludeState *state = ctx->include_stack;
  1336     if (!push_source(ctx, state->filename, def->definition,
  1247     if (!push_source(ctx, state->filename, def->definition,
  1337                      strlen(def->definition), state->line, NULL))
  1248                      strlen(def->definition), state->line, NULL))
       
  1249     {
       
  1250         buffer_destroy(buffer);
  1338         return 0;
  1251         return 0;
  1339 
  1252     } // if
  1340     Buffer buffer;
       
  1341     init_buffer(&buffer);
       
  1342 
  1253 
  1343     state = ctx->include_stack;
  1254     state = ctx->include_stack;
  1344     while (lexer(state) != TOKEN_EOI)
  1255     while (lexer(state) != TOKEN_EOI)
  1345     {
  1256     {
  1346         int wantorig = 0;
  1257         int wantorig = 0;
  1353             lexer(state);
  1264             lexer(state);
  1354             assert(state->tokenval != TOKEN_EOI);
  1265             assert(state->tokenval != TOKEN_EOI);
  1355         } // if
  1266         } // if
  1356         else
  1267         else
  1357         {
  1268         {
  1358             if (buffer.total_bytes > 0)
  1269             if (buffer_size(buffer) > 0)
  1359             {
  1270             {
  1360                 if (!add_to_buffer(&buffer, " ", 1, m, d))
  1271                 if (!buffer_append(buffer, " ", 1))
  1361                     goto replace_and_push_macro_failed;
  1272                     goto replace_and_push_macro_failed;
  1362             } // if
  1273             } // if
  1363         } // else
  1274         } // else
  1364 
  1275 
  1365         const char *data = state->token;
  1276         const char *data = state->token;
  1368         if (state->tokenval == TOKEN_HASH)  // stringify?
  1279         if (state->tokenval == TOKEN_HASH)  // stringify?
  1369         {
  1280         {
  1370             lexer(state);
  1281             lexer(state);
  1371             assert(state->tokenval != TOKEN_EOI);  // we checked for this.
  1282             assert(state->tokenval != TOKEN_EOI);  // we checked for this.
  1372 
  1283 
  1373             if (!add_to_buffer(&buffer, "\"", 1, m, d))
  1284             if (!buffer_append(buffer, "\"", 1))
  1374                 goto replace_and_push_macro_failed;
  1285                 goto replace_and_push_macro_failed;
  1375 
  1286 
  1376             if (state->tokenval == TOKEN_IDENTIFIER)
  1287             if (state->tokenval == TOKEN_IDENTIFIER)
  1377             {
  1288             {
  1378                 arg = find_macro_arg(state, params);
  1289                 arg = find_macro_arg(state, params);
  1381                     data = arg->original;
  1292                     data = arg->original;
  1382                     len = strlen(data);
  1293                     len = strlen(data);
  1383                 } // if
  1294                 } // if
  1384             } // if
  1295             } // if
  1385 
  1296 
  1386             if (!add_to_buffer(&buffer, data, len, m, d))
  1297             if (!buffer_append(buffer, data, len))
  1387                 goto replace_and_push_macro_failed;
  1298                 goto replace_and_push_macro_failed;
  1388 
  1299 
  1389             if (!add_to_buffer(&buffer, "\"", 1, m, d))
  1300             if (!buffer_append(buffer, "\"", 1))
  1390                 goto replace_and_push_macro_failed;
  1301                 goto replace_and_push_macro_failed;
  1391 
  1302 
  1392             continue;
  1303             continue;
  1393         } // if
  1304         } // if
  1394 
  1305 
  1405                 data = wantorig ? arg->original : arg->definition;
  1316                 data = wantorig ? arg->original : arg->definition;
  1406                 len = strlen(data);
  1317                 len = strlen(data);
  1407             } // if
  1318             } // if
  1408         } // if
  1319         } // if
  1409 
  1320 
  1410         if (!add_to_buffer(&buffer, data, len, m, d))
  1321         if (!buffer_append(buffer, data, len))
  1411             goto replace_and_push_macro_failed;
  1322             goto replace_and_push_macro_failed;
  1412     } // while
  1323     } // while
  1413 
  1324 
  1414     final = flatten_buffer(&buffer, m, d);
  1325     final = buffer_flatten(buffer);
  1415     if (!final)
  1326     if (!final)
  1416     {
       
  1417         out_of_memory(ctx);
       
  1418         goto replace_and_push_macro_failed;
  1327         goto replace_and_push_macro_failed;
  1419     } // if
  1328 
  1420 
  1329     buffer_destroy(buffer);
  1421     free_buffer(&buffer, f, d);
       
  1422     pop_source(ctx);  // ditch the macro.
  1330     pop_source(ctx);  // ditch the macro.
  1423     state = ctx->include_stack;
  1331     state = ctx->include_stack;
  1424     if (!push_source(ctx, state->filename, final, strlen(final), state->line,
  1332     if (!push_source(ctx, state->filename, final, strlen(final), state->line,
  1425                      close_define_include))
  1333                      close_define_include))
  1426     {
  1334     {
  1430 
  1338 
  1431     return 1;
  1339     return 1;
  1432 
  1340 
  1433 replace_and_push_macro_failed:
  1341 replace_and_push_macro_failed:
  1434     pop_source(ctx);
  1342     pop_source(ctx);
  1435     free_buffer(&buffer, f, d);
  1343     buffer_destroy(buffer);
  1436     return 0;
  1344     return 0;
  1437 } // replace_and_push_macro
  1345 } // replace_and_push_macro
  1438 
  1346 
  1439 
  1347 
  1440 static int handle_macro_args(Context *ctx, const char *sym, const Define *def)
  1348 static int handle_macro_args(Context *ctx, const char *sym, const Define *def)
  1441 {
  1349 {
  1442     int retval = 0;
  1350     int retval = 0;
  1443     MOJOSHADER_malloc m = ctx->malloc;
       
  1444     MOJOSHADER_free f = ctx->free;
       
  1445     void *d = ctx->malloc_data;
       
  1446     IncludeState *state = ctx->include_stack;
  1351     IncludeState *state = ctx->include_stack;
  1447     Define *params = NULL;
  1352     Define *params = NULL;
  1448     const int expected = (def->paramcount < 0) ? 0 : def->paramcount;
  1353     const int expected = (def->paramcount < 0) ? 0 : def->paramcount;
  1449     int saw_params = 0;
  1354     int saw_params = 0;
  1450     IncludeState saved;  // can't pushback, we need the original token.
  1355     IncludeState saved;  // can't pushback, we need the original token.
  1459 
  1364 
  1460     int void_call = 0;
  1365     int void_call = 0;
  1461     int paren = 1;
  1366     int paren = 1;
  1462     while (paren > 0)
  1367     while (paren > 0)
  1463     {
  1368     {
  1464         Buffer buffer;
  1369         Buffer *buffer = buffer_create(128, MallocBridge, FreeBridge, ctx);
  1465         Buffer origbuffer;
  1370         Buffer *origbuffer = buffer_create(128, MallocBridge, FreeBridge, ctx);
  1466         init_buffer(&buffer);
       
  1467         init_buffer(&origbuffer);
       
  1468 
  1371 
  1469         Token t = lexer(state);
  1372         Token t = lexer(state);
  1470 
  1373 
  1471         assert(!void_call);
  1374         assert(!void_call);
  1472 
  1375 
  1496             else if (t == ((Token) ' '))
  1399             else if (t == ((Token) ' '))
  1497             {
  1400             {
  1498                 // don't add whitespace to the start, so we recognize
  1401                 // don't add whitespace to the start, so we recognize
  1499                 //  void calls correctly.
  1402                 //  void calls correctly.
  1500                 origexpr = expr = " ";
  1403                 origexpr = expr = " ";
  1501                 origexprlen = (buffer.total_bytes == 0) ? 0 : 1;
  1404                 origexprlen = (buffer_size(buffer) == 0) ? 0 : 1;
  1502             } // else if
  1405             } // else if
  1503 
  1406 
  1504             else if (t == TOKEN_IDENTIFIER)
  1407             else if (t == TOKEN_IDENTIFIER)
  1505             {
  1408             {
  1506                 const Define *def = find_define_by_token(ctx);
  1409                 const Define *def = find_define_by_token(ctx);
  1519                 goto handle_macro_args_failed;
  1422                 goto handle_macro_args_failed;
  1520             } // else if
  1423             } // else if
  1521 
  1424 
  1522             assert(expr != NULL);
  1425             assert(expr != NULL);
  1523 
  1426 
  1524             if (!add_to_buffer(&buffer, expr, exprlen, m, d))
  1427             if (!buffer_append(buffer, expr, exprlen))
  1525             {
       
  1526                 out_of_memory(ctx);
       
  1527                 goto handle_macro_args_failed;
  1428                 goto handle_macro_args_failed;
  1528             } // if
  1429 
  1529 
  1430             if (!buffer_append(origbuffer, origexpr, origexprlen))
  1530             if (!add_to_buffer(&origbuffer, origexpr, origexprlen, m, d))
       
  1531             {
       
  1532                 out_of_memory(ctx);
       
  1533                 goto handle_macro_args_failed;
  1431                 goto handle_macro_args_failed;
  1534             } // if
       
  1535 
  1432 
  1536             t = lexer(state);
  1433             t = lexer(state);
  1537         } // while
  1434         } // while
  1538 
  1435 
  1539         if (buffer.total_bytes == 0)
  1436         if (buffer_size(buffer) == 0)
  1540             void_call = ((saw_params == 0) && (paren == 0));
  1437             void_call = ((saw_params == 0) && (paren == 0));
  1541 
  1438 
  1542         if (saw_params < expected)
  1439         if (saw_params < expected)
  1543         {
  1440         {
  1544             char *origdefinition = flatten_buffer(&origbuffer, m, d);
  1441             char *origdefinition = buffer_flatten(origbuffer);
  1545             char *definition = flatten_buffer(&buffer, m, d);
  1442             char *definition = buffer_flatten(buffer);
  1546             Define *p = get_define(ctx);
  1443             Define *p = get_define(ctx);
  1547             if ((!origdefinition) || (!definition) || (!p))
  1444             if ((!origdefinition) || (!definition) || (!p))
  1548             {
  1445             {
  1549                 Free(ctx, origdefinition);
  1446                 Free(ctx, origdefinition);
  1550                 Free(ctx, definition);
  1447                 Free(ctx, definition);
  1551                 free_buffer(&origbuffer, f, d);
  1448                 buffer_destroy(origbuffer);
  1552                 free_buffer(&buffer, f, d);
  1449                 buffer_destroy(buffer);
  1553                 free_define(ctx, p);
  1450                 free_define(ctx, p);
  1554                 goto handle_macro_args_failed;
  1451                 goto handle_macro_args_failed;
  1555             } // if
  1452             } // if
  1556 
  1453 
  1557             // trim any whitespace from the end of the string...
  1454             // trim any whitespace from the end of the string...
  1558             int i;
  1455             int i;
  1559             for (i = (int) buffer.total_bytes - 1; i >= 0; i--)
  1456             for (i = (int) buffer_size(buffer) - 1; i >= 0; i--)
  1560             {
  1457             {
  1561                 if (definition[i] == ' ')
  1458                 if (definition[i] == ' ')
  1562                     definition[i] = '\0';
  1459                     definition[i] = '\0';
  1563                 else
  1460                 else
  1564                     break;
  1461                     break;
  1565             } // for
  1462             } // for
  1566 
  1463 
  1567             for (i = (int) origbuffer.total_bytes - 1; i >= 0; i--)
  1464             for (i = (int) buffer_size(origbuffer) - 1; i >= 0; i--)
  1568             {
  1465             {
  1569                 if (origdefinition[i] == ' ')
  1466                 if (origdefinition[i] == ' ')
  1570                     origdefinition[i] = '\0';
  1467                     origdefinition[i] = '\0';
  1571                 else
  1468                 else
  1572                     break;
  1469                     break;
  1577             p->original = origdefinition;
  1474             p->original = origdefinition;
  1578             p->next = params;
  1475             p->next = params;
  1579             params = p;
  1476             params = p;
  1580         } // if
  1477         } // if
  1581 
  1478 
  1582         free_buffer(&buffer, f, d);
  1479         buffer_destroy(buffer);
  1583         free_buffer(&origbuffer, f, d);
  1480         buffer_destroy(origbuffer);
  1584         saw_params++;
  1481         saw_params++;
  1585     } // while
  1482     } // while
  1586 
  1483 
  1587     assert(paren == 0);
  1484     assert(paren == 0);
  1588 
  1485 
  2261     *pos = ctx->include_stack->line;
  2158     *pos = ctx->include_stack->line;
  2262     return ctx->include_stack->filename;
  2159     return ctx->include_stack->filename;
  2263 } // preprocessor_sourcepos
  2160 } // preprocessor_sourcepos
  2264 
  2161 
  2265 
  2162 
  2266 static int indent_buffer(Buffer *buffer, int n, int newline,
  2163 static void indent_buffer(Buffer *buffer, int n, const int newline)
  2267                          MOJOSHADER_malloc m, void *d)
       
  2268 {
  2164 {
  2269     static char spaces[4] = { ' ', ' ', ' ', ' ' };
  2165     static char spaces[4] = { ' ', ' ', ' ', ' ' };
  2270     if (newline)
  2166     if (newline)
  2271     {
  2167     {
  2272         while (n--)
  2168         while (n--)
  2273         {
  2169         {
  2274             if (!add_to_buffer(buffer, spaces, sizeof (spaces), m, d))
  2170             if (!buffer_append(buffer, spaces, sizeof (spaces)))
  2275                 return 0;
  2171                 return;
  2276         } // while
  2172         } // while
  2277     } // if
  2173     } // if
  2278     else
  2174     else
  2279     {
  2175     {
  2280         if (!add_to_buffer(buffer, spaces, 1, m, d))
  2176         if (!buffer_append(buffer, spaces, 1))
  2281             return 0;
  2177             return;
  2282     } // else
  2178     } // else
  2283     return 1;
       
  2284 } // indent_buffer
  2179 } // indent_buffer
  2285 
  2180 
  2286 
  2181 
  2287 static const MOJOSHADER_preprocessData out_of_mem_data_preprocessor = {
  2182 static const MOJOSHADER_preprocessData out_of_mem_data_preprocessor = {
  2288     1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0
  2183     1, &MOJOSHADER_out_of_mem_error, 0, 0, 0, 0, 0
  2297                              unsigned int define_count,
  2192                              unsigned int define_count,
  2298                              MOJOSHADER_includeOpen include_open,
  2193                              MOJOSHADER_includeOpen include_open,
  2299                              MOJOSHADER_includeClose include_close,
  2194                              MOJOSHADER_includeClose include_close,
  2300                              MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
  2195                              MOJOSHADER_malloc m, MOJOSHADER_free f, void *d)
  2301 {
  2196 {
       
  2197     // !!! FIXME: what's wrong with ENDLINE_STR?
  2302     #ifdef _WINDOWS
  2198     #ifdef _WINDOWS
  2303     static const char endline[] = { '\r', '\n' };
  2199     static const char endline[] = { '\r', '\n' };
  2304     #else
  2200     #else
  2305     static const char endline[] = { '\n' };
  2201     static const char endline[] = { '\n' };
  2306     #endif
  2202     #endif
  2308     if (!m) m = MOJOSHADER_internal_malloc;
  2204     if (!m) m = MOJOSHADER_internal_malloc;
  2309     if (!f) f = MOJOSHADER_internal_free;
  2205     if (!f) f = MOJOSHADER_internal_free;
  2310     if (!include_open) include_open = MOJOSHADER_internal_include_open;
  2206     if (!include_open) include_open = MOJOSHADER_internal_include_open;
  2311     if (!include_close) include_close = MOJOSHADER_internal_include_close;
  2207     if (!include_close) include_close = MOJOSHADER_internal_include_close;
  2312 
  2208 
  2313     ErrorList *errors = errorlist_create(m, f, d);
       
  2314     if (errors == NULL)
       
  2315         return &out_of_mem_data_preprocessor;
       
  2316 
       
  2317     Preprocessor *pp = preprocessor_start(filename, source, sourcelen,
  2209     Preprocessor *pp = preprocessor_start(filename, source, sourcelen,
  2318                                           include_open, include_close,
  2210                                           include_open, include_close,
  2319                                           defines, define_count, 0, m, f, d);
  2211                                           defines, define_count, 0, m, f, d);
  2320 
  2212 
  2321     if (pp == NULL)
  2213     if (pp == NULL)
       
  2214         return &out_of_mem_data_preprocessor;
       
  2215 
       
  2216     ErrorList *errors = errorlist_create(MallocBridge, FreeBridge, pp);
       
  2217     if (errors == NULL)
       
  2218     {
       
  2219         preprocessor_end(pp);
       
  2220         return &out_of_mem_data_preprocessor;
       
  2221     } // if
       
  2222 
       
  2223     Buffer *buffer = buffer_create(4096, MallocBridge, FreeBridge, pp);
       
  2224     if (!buffer)
  2322     {
  2225     {
  2323         errorlist_destroy(errors);
  2226         errorlist_destroy(errors);
       
  2227         preprocessor_end(pp);
  2324         return &out_of_mem_data_preprocessor;
  2228         return &out_of_mem_data_preprocessor;
  2325     } // if
  2229     } // if
  2326 
  2230 
  2327     Token token = TOKEN_UNKNOWN;
  2231     Token token = TOKEN_UNKNOWN;
  2328     const char *tokstr = NULL;
  2232     const char *tokstr = NULL;
  2329 
       
  2330     Buffer buffer;
       
  2331     init_buffer(&buffer);
       
  2332 
  2233 
  2333     int nl = 1;
  2234     int nl = 1;
  2334     int indent = 0;
  2235     int indent = 0;
  2335     unsigned int len = 0;
  2236     unsigned int len = 0;
  2336     int out_of_memory = 0;
       
  2337     while ((tokstr = preprocessor_nexttoken(pp, &len, &token)) != NULL)
  2237     while ((tokstr = preprocessor_nexttoken(pp, &len, &token)) != NULL)
  2338     {
  2238     {
  2339         int isnewline = 0;
  2239         int isnewline = 0;
  2340 
  2240 
  2341         assert(token != TOKEN_EOI);
  2241         assert(token != TOKEN_EOI);
  2342 
  2242 
  2343         if (!out_of_memory)
  2243         if (preprocessor_outofmemory(pp))
  2344             out_of_memory = preprocessor_outofmemory(pp);
  2244         {
       
  2245             preprocessor_end(pp);
       
  2246             buffer_destroy(buffer);
       
  2247             errorlist_destroy(errors);
       
  2248             return &out_of_mem_data_preprocessor;
       
  2249         } // if
  2345 
  2250 
  2346         // Microsoft's preprocessor is weird.
  2251         // Microsoft's preprocessor is weird.
  2347         // It ignores newlines, and then inserts its own around certain
  2252         // It ignores newlines, and then inserts its own around certain
  2348         //  tokens. For example, after a semicolon. This allows HLSL code to
  2253         //  tokens. For example, after a semicolon. This allows HLSL code to
  2349         //  be mostly readable, instead of a stream of tokens.
  2254         //  be mostly readable, instead of a stream of tokens.
  2350         if ( (token == ((Token) '}')) || (token == ((Token) ';')) )
  2255         if ( (token == ((Token) '}')) || (token == ((Token) ';')) )
  2351         {
  2256         {
  2352             if (!out_of_memory)
  2257             if ( (token == ((Token) '}')) && (indent > 0) )
  2353             {
  2258                 indent--;
  2354                 if ( (token == ((Token) '}')) && (indent > 0) )
  2259 
  2355                     indent--;
  2260             indent_buffer(buffer, indent, nl);
  2356 
  2261             buffer_append(buffer, tokstr, len);
  2357                 out_of_memory =
  2262             buffer_append(buffer, endline, sizeof (endline));
  2358                     (!indent_buffer(&buffer, indent, nl, m, d)) ||
  2263 
  2359                     (!add_to_buffer(&buffer, tokstr, len, m, d)) ||
  2264             isnewline = 1;
  2360                     (!add_to_buffer(&buffer, endline, sizeof (endline), m, d));
       
  2361 
       
  2362                 isnewline = 1;
       
  2363             } // if
       
  2364         } // if
  2265         } // if
  2365 
  2266 
  2366         else if (token == ((Token) '\n'))
  2267         else if (token == ((Token) '\n'))
  2367         {
  2268         {
  2368             if (!out_of_memory)
  2269             buffer_append(buffer, endline, sizeof (endline));
  2369             {
       
  2370                 out_of_memory =
       
  2371                     (!add_to_buffer(&buffer, endline, sizeof (endline), m, d));
       
  2372             } // if
       
  2373             isnewline = 1;
  2270             isnewline = 1;
  2374         } // else if
  2271         } // else if
  2375 
  2272 
  2376         else if (token == ((Token) '{'))
  2273         else if (token == ((Token) '{'))
  2377         {
  2274         {
  2378             if (!out_of_memory)
  2275             buffer_append(buffer, endline, sizeof (endline));
  2379             {
  2276             indent_buffer(buffer, indent, 1);
  2380                 out_of_memory =
  2277             buffer_append(buffer, "{", 1);
  2381                     (!add_to_buffer(&buffer,endline,sizeof (endline),m,d)) ||
  2278             buffer_append(buffer, endline, sizeof (endline));
  2382                     (!indent_buffer(&buffer, indent, 1, m, d)) ||
  2279             indent++;
  2383                     (!add_to_buffer(&buffer, "{", 1, m, d)) ||
  2280             isnewline = 1;
  2384                     (!add_to_buffer(&buffer,endline,sizeof (endline),m,d));
       
  2385                 indent++;
       
  2386                 isnewline = 1;
       
  2387             } // if
       
  2388         } // else if
  2281         } // else if
  2389 
  2282 
  2390         else if (token == TOKEN_PREPROCESSING_ERROR)
  2283         else if (token == TOKEN_PREPROCESSING_ERROR)
  2391         {
  2284         {
  2392             if (!out_of_memory)
  2285             unsigned int pos = 0;
  2393             {
  2286             const char *fname = preprocessor_sourcepos(pp, &pos);
  2394                 unsigned int pos = 0;
  2287             errorlist_add(errors, fname, (int) pos, tokstr);
  2395                 const char *fname = preprocessor_sourcepos(pp, &pos);
       
  2396                 if (!errorlist_add(errors, fname, (int) pos, tokstr))
       
  2397                     out_of_memory = 1;
       
  2398             } // if
       
  2399         } // else if
  2288         } // else if
  2400 
  2289 
  2401         else
  2290         else
  2402         {
  2291         {
  2403             if (!out_of_memory)
  2292             indent_buffer(buffer, indent, nl);
  2404             {
  2293             buffer_append(buffer, tokstr, len);
  2405                 out_of_memory = (!indent_buffer(&buffer, indent, nl, m, d)) ||
       
  2406                                 (!add_to_buffer(&buffer, tokstr, len, m, d));
       
  2407 
       
  2408             } // if
       
  2409         } // else
  2294         } // else
  2410 
  2295 
  2411         nl = isnewline;
  2296         nl = isnewline;
  2412 
       
  2413         if (out_of_memory)
       
  2414         {
       
  2415             preprocessor_end(pp);
       
  2416             free_buffer(&buffer, f, d);
       
  2417             errorlist_destroy(errors);
       
  2418             return &out_of_mem_data_preprocessor;
       
  2419         } // if
       
  2420     } // while
  2297     } // while
  2421     
  2298     
  2422     assert((token == TOKEN_EOI) || (out_of_memory));
  2299     assert(token == TOKEN_EOI);
  2423 
  2300 
  2424     preprocessor_end(pp);
  2301     preprocessor_end(pp);
  2425 
  2302 
  2426     const size_t total_bytes = buffer.total_bytes;
  2303     const size_t total_bytes = buffer_size(buffer);
  2427     char *output = flatten_buffer(&buffer, m, d);
  2304     char *output = buffer_flatten(buffer);
  2428     free_buffer(&buffer, f, d);
  2305     buffer_destroy(buffer);
  2429     if (output == NULL)
  2306     if (output == NULL)
  2430     {
  2307     {
  2431         errorlist_destroy(errors);
  2308         errorlist_destroy(errors);
  2432         return &out_of_mem_data_preprocessor;
  2309         return &out_of_mem_data_preprocessor;
  2433     } // if
  2310     } // if