2 *******************************************************************************
4 * Copyright (C) 1999-2004, International Business Machines
5 * Corporation and others. All Rights Reserved.
7 *******************************************************************************
8 * file name: gennames.c
10 * tab size: 8 (not used)
13 * created on: 1999nov01
14 * created by: Markus W. Scherer
16 * This program reads a binary file and creates a C source code file
17 * with a byte array that contains the data of the binary file.
19 * 12/09/1999 weiv Added multiple file handling
24 # define WIN32_LEAN_AND_MEAN
32 /* _M_IA64 should be defined in windows.h */
34 # define ICU_OBJECT_MACHINE_TYPE IMAGE_FILE_MACHINE_IA64
35 # define ICU_ENTRY_OFFSET 0
36 #elif defined(_M_AMD64)
37 # define ICU_OBJECT_MACHINE_TYPE IMAGE_FILE_MACHINE_AMD64
38 # define ICU_ENTRY_OFFSET 0
40 # define ICU_OBJECT_MACHINE_TYPE IMAGE_FILE_MACHINE_I386
41 # define ICU_ENTRY_OFFSET 1
48 #include "unicode/utypes.h"
49 #include "unicode/putil.h"
54 #include "unicode/uclean.h"
57 #define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU))
59 static uint32_t column
=MAX_COLUMN
;
62 #define CAN_GENERATE_OBJECTS
65 /* prototypes --------------------------------------------------------------- */
68 writeCCode(const char *filename
, const char *destdir
);
71 writeAssemblyCode(const char *filename
, const char *destdir
);
73 #ifdef CAN_GENERATE_OBJECTS
75 writeObjectCode(const char *filename
, const char *destdir
);
79 getOutFilename(const char *inFilename
, const char *destdir
, char *outFilename
, char *entryName
, const char *newSuffix
);
82 write8(FileStream
*out
, uint8_t byte
);
85 write32(FileStream
*out
, uint32_t byte
);
89 write8str(FileStream
*out
, uint8_t byte
);
91 /* -------------------------------------------------------------------------- */
99 #ifdef CAN_GENERATE_OBJECTS
107 Creating Template Files for New Platforms
109 Let the cc compiler help you get started.
111 const unsigned int x[5] = {1, 2, 0xdeadbeef, 0xffffffff, 16};
112 with the -S option to produce assembly output.
114 For example, this will generate array.s:
117 This will produce a .s file that may look like this:
133 .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)"
135 which gives a starting point that will compile, and can be transformed
136 to become the template, generally with some consulting of as docs and
137 some experimentation.
139 If you want ICU to automatically use this assembly, you should
140 specify "GENCCODE_ASSEMBLY=-a name" in the specific config/mh-* file,
141 where the name is the compiler or platform that you used in this
142 assemblyHeader data structure.
144 static const struct AssemblyType
{
147 const char *beginLine
;
148 } assemblyHeader
[] = {
151 "\t.section .rodata\n"
152 "\t.align 8\n" /* Either align 8 bytes or 2^8 (256) bytes. 8 bytes is needed. */
158 /*"\t.section __TEXT,__text,regular,pure_instructions\n"
159 "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/
163 "\t.align 4\n" /* 1<<4 = 16 */
170 "\t.section .rodata\n"
171 "\t.align 8\n" /* Either align 8 bytes or 2^8 (256) bytes. 8 bytes is needed. */
177 "\t.section \".rodata\"\n"
188 "\t.csect %s{RO}, 4\n",
203 static int32_t assemblyHeaderIndex
= -1;
205 static UOption options
[]={
207 UOPTION_HELP_QUESTION_MARK
,
209 UOPTION_DEF("name", 'n', UOPT_REQUIRES_ARG
),
210 UOPTION_DEF("entrypoint", 'e', UOPT_REQUIRES_ARG
),
211 #ifdef CAN_GENERATE_OBJECTS
212 /*5*/UOPTION_DEF("object", 'o', UOPT_NO_ARG
),
214 UOPTION_DEF("filename", 'f', UOPT_REQUIRES_ARG
),
215 UOPTION_DEF("assembly", 'a', UOPT_REQUIRES_ARG
)
219 main(int argc
, char* argv
[]) {
220 UBool verbose
= TRUE
;
223 U_MAIN_INIT_ARGS(argc
, argv
);
225 options
[kOptDestDir
].value
= ".";
227 /* read command line options */
228 argc
=u_parseArgs(argc
, argv
, sizeof(options
)/sizeof(options
[0]), options
);
230 /* error handling, printing usage message */
233 "error in command line argument \"%s\"\n",
236 if(argc
<0 || options
[kOptHelpH
].doesOccur
|| options
[kOptHelpQuestionMark
].doesOccur
) {
238 "usage: %s [-options] filename1 filename2 ...\n"
239 "\tread each binary input file and \n"
240 "\tcreate a .c file with a byte array that contains the input file's data\n"
242 "\t-h or -? or --help this usage text\n"
243 "\t-d or --destdir destination directory, followed by the path\n"
244 "\t-n or --name symbol prefix, followed by the prefix\n"
245 "\t-e or --entrypoint entry point name, followed by the name\n"
246 "\t-r or --revision Specify a version\n"
247 #ifdef CAN_GENERATE_OBJECTS
248 "\t-o or --object write a .obj file instead of .c\n"
250 "\t-f or --filename Specify an alternate base filename. (default: symbolname_typ)\n"
253 "\t-a or --assembly Create assembly file. (possible values are: ");
255 fprintf(stderr
, "%s", assemblyHeader
[0].name
);
256 for (idx
= 1; idx
< (int32_t)(sizeof(assemblyHeader
)/sizeof(assemblyHeader
[0])); idx
++) {
257 fprintf(stderr
, ", %s", assemblyHeader
[idx
].name
);
262 const char *message
, *filename
;
263 void (*writeCode
)(const char *, const char *);
265 if(options
[kOptAssembly
].doesOccur
) {
266 message
="generating assembly code for %s\n";
267 writeCode
=&writeAssemblyCode
;
268 for (idx
= 0; idx
< (int32_t)(sizeof(assemblyHeader
)/sizeof(assemblyHeader
[0])); idx
++) {
269 if (uprv_strcmp(options
[kOptAssembly
].value
, assemblyHeader
[idx
].name
) == 0) {
270 assemblyHeaderIndex
= idx
;
274 if (assemblyHeaderIndex
< 0) {
276 "Assembly type \"%s\" is unknown.\n", options
[kOptAssembly
].value
);
280 #ifdef CAN_GENERATE_OBJECTS
281 else if(options
[kOptObject
].doesOccur
) {
282 message
="generating object code for %s\n";
283 writeCode
=&writeObjectCode
;
288 message
="generating C code for %s\n";
289 writeCode
=&writeCCode
;
292 filename
=getLongPathname(argv
[argc
]);
294 fprintf(stdout
, message
, filename
);
297 writeCode(filename
, options
[kOptDestDir
].value
);
305 writeAssemblyCode(const char *filename
, const char *destdir
) {
307 uint32_t buffer
[1024];
308 char *bufferStr
= (char *)buffer
;
309 FileStream
*in
, *out
;
312 in
=T_FileStream_open(filename
, "rb");
314 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
315 exit(U_FILE_ACCESS_ERROR
);
318 getOutFilename(filename
, destdir
, bufferStr
, entry
, ".s");
319 out
=T_FileStream_open(bufferStr
, "w");
321 fprintf(stderr
, "genccode: unable to open output file %s\n", bufferStr
);
322 exit(U_FILE_ACCESS_ERROR
);
325 if(options
[kOptEntryPoint
].doesOccur
) {
326 uprv_strcpy(entry
, options
[kOptEntryPoint
].value
);
327 uprv_strcat(entry
, "_dat");
330 /* turn dashes or dots in the entry name into underscores */
331 length
=uprv_strlen(entry
);
332 for(i
=0; i
<length
; ++i
) {
333 if(entry
[i
]=='-' || entry
[i
]=='.') {
338 sprintf(bufferStr
, assemblyHeader
[assemblyHeaderIndex
].header
,
339 entry
, entry
, entry
, entry
,
340 entry
, entry
, entry
, entry
);
341 T_FileStream_writeLine(out
, bufferStr
);
342 T_FileStream_writeLine(out
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
345 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
349 if (length
!= sizeof(buffer
)) {
350 /* pad with extra 0's when at the end of the file */
351 for(i
=0; i
< (length
% sizeof(uint32_t)); ++i
) {
352 buffer
[length
+i
] = 0;
355 for(i
=0; i
<(length
/sizeof(buffer
[0])); i
++) {
356 write32(out
, buffer
[i
]);
360 T_FileStream_writeLine(out
, "\n");
362 if(T_FileStream_error(in
)) {
363 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
364 exit(U_FILE_ACCESS_ERROR
);
367 if(T_FileStream_error(out
)) {
368 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
369 exit(U_FILE_ACCESS_ERROR
);
372 T_FileStream_close(out
);
373 T_FileStream_close(in
);
377 writeCCode(const char *filename
, const char *destdir
) {
378 char buffer
[4096], entry
[64];
379 FileStream
*in
, *out
;
382 in
=T_FileStream_open(filename
, "rb");
384 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
385 exit(U_FILE_ACCESS_ERROR
);
388 if(options
[kOptName
].doesOccur
) { /* prepend 'icudt28_' */
389 strcpy(entry
, options
[kOptName
].value
);
395 getOutFilename(filename
, destdir
, buffer
, entry
+uprv_strlen(entry
), ".c");
396 out
=T_FileStream_open(buffer
, "w");
398 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
399 exit(U_FILE_ACCESS_ERROR
);
402 /* turn dashes or dots in the entry name into underscores */
403 length
=uprv_strlen(entry
);
404 for(i
=0; i
<length
; ++i
) {
405 if(entry
[i
]=='-' || entry
[i
]=='.') {
412 TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
414 This is here because this platform can't currently put
415 const data into the read-only pages of an object or
416 shared library (service program). Only strings are allowed in read-only
417 pages, so we use char * strings to store the data.
419 In order to prevent the beginning of the data from ever matching the
420 magic numbers we must still use the initial double.
424 "#define U_DISABLE_RENAMING 1\n"
425 "#include \"unicode/umachine.h\"\n"
429 " const char *bytes; \n"
432 T_FileStream_writeLine(out
, buffer
);
435 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
439 for(i
=0; i
<length
; ++i
) {
440 write8str(out
, (uint8_t)buffer
[i
]);
444 T_FileStream_writeLine(out
, "\"\n};\nU_CDECL_END\n");
446 /* Function renaming shouldn't be done in data */
448 "#define U_DISABLE_RENAMING 1\n"
449 "#include \"unicode/umachine.h\"\n"
453 " uint8_t bytes[%ld]; \n"
455 (long)T_FileStream_size(in
), entry
);
456 T_FileStream_writeLine(out
, buffer
);
459 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
463 for(i
=0; i
<length
; ++i
) {
464 write8(out
, (uint8_t)buffer
[i
]);
468 T_FileStream_writeLine(out
, "\n}\n};\nU_CDECL_END\n");
471 if(T_FileStream_error(in
)) {
472 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
473 exit(U_FILE_ACCESS_ERROR
);
476 if(T_FileStream_error(out
)) {
477 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
478 exit(U_FILE_ACCESS_ERROR
);
481 T_FileStream_close(out
);
482 T_FileStream_close(in
);
485 #ifdef CAN_GENERATE_OBJECTS
487 writeObjectCode(const char *filename
, const char *destdir
) {
489 char buffer
[4096], entry
[40];
491 IMAGE_FILE_HEADER fileHeader
;
492 IMAGE_SECTION_HEADER sections
[2];
493 char linkerOptions
[100];
495 IMAGE_SYMBOL symbols
[1];
497 DWORD sizeofLongNames
;
500 FileStream
*in
, *out
;
501 DWORD i
, entryLength
, length
, size
;
503 in
=T_FileStream_open(filename
, "rb");
505 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
506 exit(U_FILE_ACCESS_ERROR
);
509 /* entry have a leading '_' */
511 getOutFilename(filename
, destdir
, buffer
, entry
+ICU_ENTRY_OFFSET
, ".obj");
513 if(options
[kOptEntryPoint
].doesOccur
) {
514 uprv_strcpy(entry
+ICU_ENTRY_OFFSET
, options
[kOptEntryPoint
].value
);
515 uprv_strcat(entry
, "_dat");
517 /* turn dashes in the entry name into underscores */
518 entryLength
=(int32_t)uprv_strlen(entry
);
519 for(i
=0; i
<entryLength
; ++i
) {
525 /* open the output file */
526 out
=T_FileStream_open(buffer
, "wb");
528 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
529 exit(U_FILE_ACCESS_ERROR
);
532 /* populate the .obj headers */
533 uprv_memset(&objHeader
, 0, sizeof(objHeader
));
534 uprv_memset(&symbols
, 0, sizeof(symbols
));
535 uprv_memset(&symbolNames
, 0, sizeof(symbolNames
));
536 size
=T_FileStream_size(in
);
538 /* write the linker export directive */
539 uprv_strcpy(objHeader
.linkerOptions
, "-export:");
541 uprv_strcpy(objHeader
.linkerOptions
+length
, entry
);
543 uprv_strcpy(objHeader
.linkerOptions
+length
, ",data ");
546 /* set the file header */
547 objHeader
.fileHeader
.Machine
=ICU_OBJECT_MACHINE_TYPE
;
548 objHeader
.fileHeader
.NumberOfSections
=2;
549 objHeader
.fileHeader
.TimeDateStamp
=time(NULL
);
550 objHeader
.fileHeader
.PointerToSymbolTable
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
+size
; /* start of symbol table */
551 objHeader
.fileHeader
.NumberOfSymbols
=1;
553 /* set the section for the linker options */
554 uprv_strncpy((char *)objHeader
.sections
[0].Name
, ".drectve", 8);
555 objHeader
.sections
[0].SizeOfRawData
=length
;
556 objHeader
.sections
[0].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
;
557 objHeader
.sections
[0].Characteristics
=IMAGE_SCN_LNK_INFO
|IMAGE_SCN_LNK_REMOVE
|IMAGE_SCN_ALIGN_1BYTES
;
559 /* set the data section */
560 uprv_strncpy((char *)objHeader
.sections
[1].Name
, ".rdata", 6);
561 objHeader
.sections
[1].SizeOfRawData
=size
;
562 objHeader
.sections
[1].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
;
563 objHeader
.sections
[1].Characteristics
=IMAGE_SCN_CNT_INITIALIZED_DATA
|IMAGE_SCN_ALIGN_16BYTES
|IMAGE_SCN_MEM_READ
;
565 /* set the symbol table */
567 uprv_strncpy((char *)symbols
[0].N
.ShortName
, entry
, entryLength
);
568 symbolNames
.sizeofLongNames
=4;
570 symbols
[0].N
.Name
.Short
=0;
571 symbols
[0].N
.Name
.Long
=4;
572 symbolNames
.sizeofLongNames
=4+entryLength
+1;
573 uprv_strcpy(symbolNames
.longNames
, entry
);
575 symbols
[0].SectionNumber
=2;
576 symbols
[0].StorageClass
=IMAGE_SYM_CLASS_EXTERNAL
;
578 /* write the file header and the linker options section */
579 T_FileStream_write(out
, &objHeader
, objHeader
.sections
[1].PointerToRawData
);
581 /* copy the data file into section 2 */
583 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
587 T_FileStream_write(out
, buffer
, (int32_t)length
);
590 /* write the symbol table */
591 T_FileStream_write(out
, symbols
, IMAGE_SIZEOF_SYMBOL
);
592 T_FileStream_write(out
, &symbolNames
, symbolNames
.sizeofLongNames
);
594 if(T_FileStream_error(in
)) {
595 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
596 exit(U_FILE_ACCESS_ERROR
);
599 if(T_FileStream_error(out
)) {
600 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
601 exit(U_FILE_ACCESS_ERROR
);
604 T_FileStream_close(out
);
605 T_FileStream_close(in
);
611 getOutFilename(const char *inFilename
, const char *destdir
, char *outFilename
, char *entryName
, const char *newSuffix
) {
612 const char *basename
=findBasename(inFilename
), *suffix
=uprv_strrchr(basename
, '.');
615 if(destdir
!=NULL
&& *destdir
!=0) {
617 *outFilename
++=*destdir
++;
618 } while(*destdir
!=0);
619 if(*(outFilename
-1)!=U_FILE_SEP_CHAR
) {
620 *outFilename
++=U_FILE_SEP_CHAR
;
624 while(inFilename
<basename
) {
625 *outFilename
++=*inFilename
++;
630 /* the filename does not have a suffix */
631 uprv_strcpy(entryName
, inFilename
);
632 if(options
[kOptFilename
].doesOccur
) {
633 uprv_strcpy(outFilename
, options
[kOptFilename
].value
);
635 uprv_strcpy(outFilename
, inFilename
);
637 uprv_strcat(outFilename
, newSuffix
);
639 char *saveOutFilename
= outFilename
;
641 while(inFilename
<suffix
) {
642 if(*inFilename
=='-') {
643 /* iSeries cannot have '-' in the .o objects. */
644 *outFilename
++=*entryName
++='_';
648 *outFilename
++=*entryName
++=*inFilename
++;
652 /* replace '.' by '_' */
653 *outFilename
++=*entryName
++='_';
657 while(*inFilename
!=0) {
658 *outFilename
++=*entryName
++=*inFilename
++;
663 if(options
[kOptFilename
].doesOccur
) {
664 uprv_strcpy(saveOutFilename
, options
[kOptFilename
].value
);
665 uprv_strcat(saveOutFilename
, newSuffix
);
668 uprv_strcpy(outFilename
, newSuffix
);
674 write32(FileStream
*out
, uint32_t bitField
) {
676 char bitFieldStr
[64]; /* This is more bits than needed for a 32-bit number */
677 char *s
= bitFieldStr
;
678 uint8_t *ptrIdx
= (uint8_t *)&bitField
;
679 static const char hexToStr
[16] = {
686 /* write the value, possibly with comma and newline */
687 if(column
==MAX_COLUMN
) {
690 } else if(column
<32) {
695 uprv_strcpy(s
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
701 /* It's a small number. Don't waste the space for 0x */
702 *(s
++)=hexToStr
[bitField
];
705 int seenNonZero
= 0; /* This is used to remove leading zeros */
710 /* This creates a 32-bit field */
712 for (i
= 0; i
< sizeof(uint32_t); i
++)
714 for (i
= sizeof(uint32_t)-1; i
>= 0 ; i
--)
717 uint8_t value
= ptrIdx
[i
];
718 if (value
|| seenNonZero
) {
719 *(s
++)=hexToStr
[value
>>4];
720 *(s
++)=hexToStr
[value
&0xF];
727 T_FileStream_writeLine(out
, bitFieldStr
);
731 write8(FileStream
*out
, uint8_t byte
) {
735 /* convert the byte value to a string */
737 s
[i
++]=(char)('0'+byte
/100);
740 if(i
>0 || byte
>=10) {
741 s
[i
++]=(char)('0'+byte
/10);
744 s
[i
++]=(char)('0'+byte
);
747 /* write the value, possibly with comma and newline */
748 if(column
==MAX_COLUMN
) {
751 } else if(column
<16) {
752 T_FileStream_writeLine(out
, ",");
755 T_FileStream_writeLine(out
, ",\n");
758 T_FileStream_writeLine(out
, s
);
763 write8str(FileStream
*out
, uint8_t byte
) {
767 sprintf(s
, "\\x%X", byte
);
769 sprintf(s
, "\\%X", byte
);
771 /* write the value, possibly with comma and newline */
772 if(column
==MAX_COLUMN
) {
775 T_FileStream_writeLine(out
, "\"");
776 } else if(column
<24) {
779 T_FileStream_writeLine(out
, "\"\n\"");
782 T_FileStream_writeLine(out
, s
);