1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 1998
20 * the Initial Developer. All Rights Reserved.
24 * Alternatively, the contents of this file may be used under the terms of
25 * either of the GNU General Public License Version 2 or later (the "GPL"),
26 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
43 #define DEFAULT_MANIFEST_EXT ".mn"
44 #define DEFAULT_MAKEFILE_EXT ".win"
46 typedef struct char_list_struct
{
48 struct char_list_struct
*m_pNext
;
51 typedef struct macro_list_struct
{
54 struct macro_list_struct
*m_pNext
;
58 char *input_filename(const char *);
59 char *output_filename(const char *, const char *);
60 int input_to_output(FILE *, FILE *);
61 int output_rules(FILE *);
62 int output_end(FILE *);
63 int buffer_to_output(char *, FILE *);
64 macro_list
*extract_macros(char *);
65 char *find_macro(char *, char **);
66 void add_macro(char *, macro_list
**);
67 int macro_length(char *);
68 int value_length(char *);
69 void add_values(char *, char_list
**);
70 char *skip_white(char *);
71 int write_macros(macro_list
*, FILE *);
72 int write_values(char_list
*, FILE *, int);
73 void free_macro_list(macro_list
*);
74 void free_char_list(char_list
*);
75 void morph_macro(macro_list
**, char *, char *, char *);
76 void slash_convert(macro_list
*, char *);
77 int explicit_rules(macro_list
*, char *, FILE *);
78 void create_classroot(macro_list
**ppList
);
80 int main(int argc
, char *argv
[])
83 char *pInputFile
= NULL
;
84 char *pOutputFile
= NULL
;
86 /* Figure out arguments.
87 * [REQUIRED] First argument is input file.
88 * [OPTIONAL] Second argument is output file.
91 FILE *pInputStream
= NULL
;
92 FILE *pOutputStream
= NULL
;
94 /* Form respective filenames.
96 pInputFile
= input_filename(argv
[1]);
97 pOutputFile
= output_filename(pInputFile
, argc
> 2 ? argv
[2] : NULL
);
99 if(pInputFile
== NULL
) {
100 fprintf(stderr
, "MANTOMAK: Unable to form input filename\n");
104 pInputStream
= fopen(pInputFile
, "rb");
105 if(pInputStream
== NULL
) {
106 fprintf(stderr
, "MANTOMAK: Unable to open input file %s\n", pInputFile
);
110 if(pOutputFile
== NULL
) {
111 fprintf(stderr
, "MANTOMAK: Unable to form output filename\n");
114 else if(pInputStream
!= NULL
) {
115 pOutputStream
= fopen(pOutputFile
, "wt");
116 if(pOutputStream
== NULL
) {
117 fprintf(stderr
, "MANTOMAK: Unable to open output file %s\n", pOutputFile
);
122 /* Only do the real processing if our error code is not
126 iOS
= input_to_output(pInputStream
, pOutputStream
);
129 if(pInputStream
!= NULL
) {
130 fclose(pInputStream
);
133 if(pOutputStream
!= NULL
) {
134 fclose(pOutputStream
);
135 pOutputStream
= NULL
;
157 fprintf(stderr
, "USAGE:\tmantomak.exe InputFile [OutputFile]\n\n");
158 fprintf(stderr
, "InputFile:\tManifest file. If without extension, \"%s\" assumed.\n", DEFAULT_MANIFEST_EXT
);
159 fprintf(stderr
, "OutputFile:\tNMake file. If not present, \"InputFile%s\" assumed.\n", DEFAULT_MAKEFILE_EXT
);
162 char *input_filename(const char *pInputFile
)
164 char aResult
[_MAX_PATH
];
165 char aDrive
[_MAX_DRIVE
];
167 char aName
[_MAX_FNAME
];
170 if(pInputFile
== NULL
) {
174 _splitpath(pInputFile
, aDrive
, aDir
, aName
, aExt
);
176 if(aExt
[0] == '\0') {
177 /* No extension provided.
180 strcpy(aExt
, DEFAULT_MANIFEST_EXT
);
184 _makepath(aResult
, aDrive
, aDir
, aName
, aExt
);
186 if(aResult
[0] == '\0') {
190 return(strdup(aResult
));
194 char *output_filename(const char *pInputFile
, const char *pOutputFile
)
196 char aResult
[_MAX_PATH
];
197 char aDrive
[_MAX_DRIVE
];
199 char aName
[_MAX_FNAME
];
202 if(pOutputFile
!= NULL
) {
203 return(strdup(pOutputFile
));
206 /* From here on out, we have to create our own filename,
207 * implied from the input file name.
210 if(pInputFile
== NULL
) {
214 _splitpath(pInputFile
, aDrive
, aDir
, aName
, aExt
);
215 strcpy(aExt
, DEFAULT_MAKEFILE_EXT
);
218 _makepath(aResult
, aDrive
, aDir
, aName
, aExt
);
220 if(aResult
[0] == '\0') {
224 return(strdup(aResult
));
228 int input_to_output(FILE *pInput
, FILE *pOutput
)
234 /* Read the entire file into memory.
236 fseek(pInput
, 0, SEEK_END
);
237 lSize
= ftell(pInput
);
238 fseek(pInput
, 0, SEEK_SET
);
240 pHog
= (char *)malloc(lSize
+ 1);
242 *(pHog
+ lSize
) = '\0';
243 fread(pHog
, lSize
, 1, pInput
);
245 iRetval
= buffer_to_output(pHog
, pOutput
);
251 fprintf(stderr
, "MANTOMAK: Out of Memory....\n");
258 int output_rules(FILE *pOutput
)
264 "!if \"$(MANIFEST_LEVEL)\"==\"RULES\""
268 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
274 int output_end(FILE *pOutput
)
284 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
291 int buffer_to_output(char *pBuffer
, FILE *pOutput
)
294 macro_list
*pMacros
= NULL
;
296 /* Tokenize the macros and their corresponding values.
298 pMacros
= extract_macros(pBuffer
);
299 if(pMacros
!= NULL
) {
300 /* Perform forward to backslash conversion on those macros known to be
301 * path information only.
303 slash_convert(pMacros
, "JBOOTDIRS");
304 slash_convert(pMacros
, "JDIRS");
305 slash_convert(pMacros
, "DEPTH");
306 slash_convert(pMacros
, "NS_DEPTH");
307 slash_convert(pMacros
, "PACKAGE");
308 slash_convert(pMacros
, "JMC_GEN_DIR");
309 slash_convert(pMacros
, "DIST_PUBLIC");
311 /* Process some of the macros, and convert them
312 * into different macros with different data.
314 morph_macro(&pMacros
, "JMC_GEN", "JMC_HEADERS", "$(JMC_GEN_DIR)\\%s.h");
315 morph_macro(&pMacros
, "JMC_GEN", "JMC_STUBS", "$(JMC_GEN_DIR)\\%s.c");
316 morph_macro(&pMacros
, "JMC_GEN", "JMC_OBJS", ".\\$(OBJDIR)\\%s.obj");
317 morph_macro(&pMacros
, "CSRCS", "C_OBJS", ".\\$(OBJDIR)\\%s.obj");
318 morph_macro(&pMacros
, "CPPSRCS", "CPP_OBJS", ".\\$(OBJDIR)\\%s.obj");
319 morph_macro(&pMacros
, "REQUIRES", "LINCS", "-I$(XPDIST)\\public\\%s");
321 create_classroot( &pMacros
);
323 /* Output the Macros and the corresponding values.
325 iRetval
= write_macros(pMacros
, pOutput
);
327 /* Output rule file inclusion
330 iRetval
= output_rules(pOutput
);
333 /* Output explicit build rules/dependencies for JMC_GEN.
336 iRetval
= explicit_rules(pMacros
, "JMC_GEN", pOutput
);
340 iRetval
= output_end(pOutput
);
342 /* Free off the macro list.
344 free_macro_list(pMacros
);
351 int explicit_rules(macro_list
*pList
, char *pMacro
, FILE *pOutput
)
354 macro_list
*pEntry
= NULL
;
356 if(pList
== NULL
|| pMacro
== NULL
|| pOutput
== NULL
) {
360 /* Find macro of said name.
365 if(stricmp(pEntry
->m_pMacro
, pMacro
) == 0) {
369 pEntry
= pEntry
->m_pNext
;
373 /* Decide style of rule depending on macro name.
375 if(stricmp(pEntry
->m_pMacro
, "JMC_GEN") == 0) {
376 char_list
*pNames
= NULL
;
377 char *pModuleName
= NULL
;
378 char *pClassName
= NULL
;
380 pNames
= pEntry
->m_pValue
;
382 pModuleName
= pNames
->m_pString
;
383 pClassName
= pModuleName
+ 1;
385 fprintf(pOutput
, "$(JMC_GEN_DIR)\\%s.h", pModuleName
);
386 fprintf(pOutput
, ": ");
387 fprintf(pOutput
, "$(JMCSRCDIR)\\%s.class", pClassName
);
388 fprintf(pOutput
, "\n ");
389 fprintf(pOutput
, "$(JMC) -d $(JMC_GEN_DIR) -interface $(JMC_GEN_FLAGS) $(?F:.class=)");
390 fprintf(pOutput
, "\n");
392 fprintf(pOutput
, "$(JMC_GEN_DIR)\\%s.c", pModuleName
);
393 fprintf(pOutput
, ": ");
394 fprintf(pOutput
, "$(JMCSRCDIR)\\%s.class", pClassName
);
395 fprintf(pOutput
, "\n ");
396 fprintf(pOutput
, "$(JMC) -d $(JMC_GEN_DIR) -module $(JMC_GEN_FLAGS) $(?F:.class=)");
397 fprintf(pOutput
, "\n");
399 pNames
= pNames
->m_pNext
;
403 /* Don't know how to format macro.
412 void slash_convert(macro_list
*pList
, char *pMacro
)
414 macro_list
*pEntry
= NULL
;
416 if(pList
== NULL
|| pMacro
== NULL
) {
420 /* Find macro of said name.
425 if(stricmp(pEntry
->m_pMacro
, pMacro
) == 0) {
429 pEntry
= pEntry
->m_pNext
;
433 char *pConvert
= NULL
;
434 char_list
*pValue
= pEntry
->m_pValue
;
437 pConvert
= pValue
->m_pString
;
438 while(pConvert
&& *pConvert
) {
439 if(*pConvert
== '/') {
444 pValue
= pValue
->m_pNext
;
449 void morph_macro(macro_list
**ppList
, char *pMacro
, char *pMorph
, char *pPrintf
)
451 macro_list
*pEntry
= NULL
;
453 if(ppList
== NULL
|| pMacro
== NULL
|| pMorph
== NULL
|| pPrintf
== NULL
) {
457 /* Find macro of said name.
462 if(stricmp(pEntry
->m_pMacro
, pMacro
) == 0) {
466 pEntry
= pEntry
->m_pNext
;
470 char_list
*pFilename
= NULL
;
471 char aPath
[_MAX_PATH
];
472 char aDrive
[_MAX_DRIVE
];
474 char aFName
[_MAX_FNAME
];
476 char *pBuffer
= NULL
;
478 /* Start with buffer size needed.
479 * We expand this as we go along if needed.
481 pBuffer
= (char *)malloc(strlen(pMorph
) + 2);
482 strcpy(pBuffer
, pMorph
);
483 strcat(pBuffer
, "=");
485 /* Go through each value, converting over to new macro.
487 pFilename
= pEntry
->m_pValue
;
489 _splitpath(pFilename
->m_pString
, aDrive
, aDir
, aFName
, aExt
);
491 /* Expand buffer by required amount.
493 sprintf(aPath
, pPrintf
, aFName
);
495 pBuffer
= (char *)realloc(pBuffer
, _msize(pBuffer
) + strlen(aPath
));
496 strcat(pBuffer
, aPath
);
498 pFilename
= pFilename
->m_pNext
;
503 add_macro(pBuffer
, ppList
);
510 void create_classroot(macro_list
**ppList
)
514 macro_list
*pEntry
= NULL
;
517 /* Find macro of said name.
522 if(stricmp(pEntry
->m_pMacro
, "PACKAGE") == 0) {
526 pEntry
= pEntry
->m_pNext
;
529 if(pEntry
== 0 || pEntry
->m_pValue
== 0 || pEntry
->m_pValue
->m_pString
== 0) {
535 i
= strlen( pEntry
->m_pValue
->m_pString
);
541 pE
= (macro_list
*)calloc(sizeof(macro_list
),1);
542 pE
->m_pMacro
= strdup("CLASSROOT");
543 pE
->m_pValue
= (char_list
*)calloc(sizeof(char_list
),1);
544 pE
->m_pValue
->m_pString
= strdup(cwd
);
547 ppList
= &((*ppList
)->m_pNext
);
553 int write_macros(macro_list
*pList
, FILE *pOutput
)
558 if(pList
== NULL
|| pOutput
== NULL
) {
564 "!if \"$(MANIFEST_LEVEL)\"==\"MACROS\""
568 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
573 int bIgnoreForWin16
= 0;
575 /* The following macros should not be emitted for Win16 */
576 if (0 == strcmp(pList
->m_pMacro
, "LINCS")) {
581 if (bIgnoreForWin16
) {
582 if(0 > fprintf(pOutput
, "!if \"$(MOZ_BITS)\" != \"16\"\n")) {
583 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
589 if(0 > fprintf(pOutput
, "%s=", pList
->m_pMacro
)) {
590 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
594 iLineLength
+= strlen(pList
->m_pMacro
) + 1;
596 iRetval
= write_values(pList
->m_pValue
, pOutput
, iLineLength
);
601 if(EOF
== fputc('\n', pOutput
)) {
602 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
608 pList
= pList
->m_pNext
;
610 if (bIgnoreForWin16
) {
611 if(0 > fprintf(pOutput
, "!endif\n")) {
612 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
626 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
632 int write_values(char_list
*pList
, FILE *pOutput
, int iLineLength
)
636 if(pList
== NULL
|| pOutput
== NULL
) {
641 if(iLineLength
== 0) {
642 if(EOF
== fputs(" ", pOutput
)) {
643 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
649 if(0 > fprintf(pOutput
, "%s ", pList
->m_pString
)) {
650 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
654 iLineLength
+= strlen(pList
->m_pString
) + 1;
656 else if(iLineLength
+ strlen(pList
->m_pString
) > 72) {
657 if(EOF
== fputs("\\\n", pOutput
)) {
658 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
666 if(0 > fprintf(pOutput
, "%s ", pList
->m_pString
)) {
667 fprintf(stderr
, "MANTOMAK: Error writing to file....\n");
671 iLineLength
+= strlen(pList
->m_pString
) + 1;
674 pList
= pList
->m_pNext
;
680 macro_list
*extract_macros(char *pBuffer
)
682 macro_list
*pRetval
= NULL
;
683 char *pTraverse
= NULL
;
689 pTraverse
= find_macro(pTraverse
, &pMacro
);
691 add_macro(pMacro
, &pRetval
);
698 void add_macro(char *pString
, macro_list
**ppList
)
700 macro_list
*pEntry
= NULL
;
703 if(pString
== NULL
|| *pString
== '\0' || ppList
== NULL
) {
707 /* Allocate a new list entry for the macro.
709 pEntry
= (macro_list
*)calloc(1, sizeof(macro_list
));
711 /* Very first part of the string is the macro name.
714 iLength
= macro_length(pString
);
715 pEntry
->m_pMacro
= (char *)calloc(iLength
+ 1, 1);
716 strncpy(pEntry
->m_pMacro
, pString
, iLength
);
718 /* Skip to the values.
719 * These are always on the right side of an '='
721 pString
= strchr(pString
, '=');
725 add_values(pString
, &(pEntry
->m_pValue
));
727 /* Add the macro to the end of the macro list.
730 ppList
= &((*ppList
)->m_pNext
);
735 void add_values(char *pString
, char_list
**ppList
)
737 char_list
**ppTraverse
= NULL
;
738 char_list
*pEntry
= NULL
;
742 if(pString
== NULL
|| *pString
== '\0' || ppList
== NULL
) {
747 /* Find start of value.
751 if(*pString
== '\\') {
754 else if(*pString
== '\n') {
755 if(iBackslash
== 0) {
757 * Setting to NULL gets out of all loops.
764 else if(!isspace(*pString
)) {
765 /* Backslashes part of string.
766 * This screws up if a backslash is in the middle of the string.
768 pString
-= iBackslash
;
774 if(pString
== NULL
|| *pString
== '\0') {
778 /* Do not honor anything beginning with a #
780 if(*pString
== '#') {
783 while(*pString
&& *pString
!= '\n') {
789 /* Very first part of the string is value name.
792 iLength
= value_length(pString
);
794 /* Do not honor $(NULL)
796 if(_strnicmp(pString
, "$(NULL)", 7) == 0) {
801 /* Allocate a new list entry for the next value.
803 pEntry
= (char_list
*)calloc(1, sizeof(char_list
));
805 pEntry
->m_pString
= (char *)calloc(iLength
+ 1, 1);
806 strncpy(pEntry
->m_pString
, pString
, iLength
);
808 /* Add new value entry to the end of the list.
812 ppTraverse
= &((*ppTraverse
)->m_pNext
);
814 *ppTraverse
= pEntry
;
816 /* Go on to next value.
822 char *find_macro(char *pBuffer
, char **ppMacro
)
824 char *pRetval
= NULL
;
827 if(pBuffer
== NULL
|| ppMacro
== NULL
) {
831 /* Skip any whitespace in the buffer.
832 * If comments need to be skipped also, this is the place.
835 while(*pBuffer
&& isspace(*pBuffer
)) {
838 if(*pBuffer
== '#') {
839 /* Go to the end of the line, it's a comment.
841 while(*pBuffer
&& *pBuffer
!= '\n') {
851 /* Should be at the start of a macro.
856 /* Find the end of the macro for the return value.
857 * This is the end of a line which does not contain a backslash at the end.
860 if(*pBuffer
== '\\') {
863 else if(*pBuffer
== '\n') {
864 if(iBackslash
== 0) {
865 pRetval
= pBuffer
+ 1;
870 else if(!isspace(*pBuffer
)) {
880 int macro_length(char *pMacro
)
888 /* Length is no big deal.
889 * Problem is finding the end:
897 else if(isspace(*pMacro
)) {
908 int value_length(char *pValue
)
916 /* Length is no big deal.
917 * Problem is finding the end:
922 if(*pValue
== '\\') {
923 char *pFindNewline
= pValue
+ 1;
924 /* If whitespace to end of line, break here.
926 while(isspace(*pFindNewline
)) {
927 if(*pFindNewline
== '\n') {
932 if(*pFindNewline
== '\n') {
936 else if(isspace(*pValue
)) {
947 char *skip_white(char *pString
)
949 if(pString
== NULL
) {
953 while(*pString
&& isspace(*pString
)) {
960 void free_macro_list(macro_list
*pList
)
962 macro_list
*pFree
= NULL
;
970 pList
= pList
->m_pNext
;
972 pFree
->m_pNext
= NULL
;
974 free_char_list(pFree
->m_pValue
);
975 pFree
->m_pValue
= NULL
;
977 free(pFree
->m_pMacro
);
978 pFree
->m_pMacro
= NULL
;
985 void free_char_list(char_list
*pList
)
987 char_list
*pFree
= NULL
;
995 pList
= pList
->m_pNext
;
997 pFree
->m_pNext
= NULL
;
999 free(pFree
->m_pString
);
1000 pFree
->m_pString
= NULL
;