2 *******************************************************************************
4 * Copyright (C) 1999-2006, 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
22 #include "unicode/utypes.h"
26 # define WIN32_LEAN_AND_MEAN
34 /* _M_IA64 should be defined in windows.h */
36 # define ICU_OBJECT_MACHINE_TYPE IMAGE_FILE_MACHINE_IA64
37 # define ICU_ENTRY_OFFSET 0
38 #elif defined(_M_AMD64)
39 # define ICU_OBJECT_MACHINE_TYPE IMAGE_FILE_MACHINE_AMD64
40 # define ICU_ENTRY_OFFSET 0
42 # define ICU_OBJECT_MACHINE_TYPE IMAGE_FILE_MACHINE_I386
43 # define ICU_ENTRY_OFFSET 1
50 #include "unicode/putil.h"
55 #include "unicode/uclean.h"
58 #define MAX_COLUMN ((uint32_t)(0xFFFFFFFFU))
60 static uint32_t column
=MAX_COLUMN
;
63 #define CAN_GENERATE_OBJECTS
66 /* prototypes --------------------------------------------------------------- */
69 writeCCode(const char *filename
, const char *destdir
);
72 writeAssemblyCode(const char *filename
, const char *destdir
);
74 #ifdef CAN_GENERATE_OBJECTS
76 writeObjectCode(const char *filename
, const char *destdir
);
80 getOutFilename(const char *inFilename
, const char *destdir
, char *outFilename
, char *entryName
, const char *newSuffix
);
83 write8(FileStream
*out
, uint8_t byte
);
86 write32(FileStream
*out
, uint32_t byte
);
90 write8str(FileStream
*out
, uint8_t byte
);
92 /* -------------------------------------------------------------------------- */
100 #ifdef CAN_GENERATE_OBJECTS
108 Creating Template Files for New Platforms
110 Let the cc compiler help you get started.
112 const unsigned int x[5] = {1, 2, 0xdeadbeef, 0xffffffff, 16};
113 with the -S option to produce assembly output.
115 For example, this will generate array.s:
118 This will produce a .s file that may look like this:
134 .ident "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.1 2.96-85)"
136 which gives a starting point that will compile, and can be transformed
137 to become the template, generally with some consulting of as docs and
138 some experimentation.
140 If you want ICU to automatically use this assembly, you should
141 specify "GENCCODE_ASSEMBLY=-a name" in the specific config/mh-* file,
142 where the name is the compiler or platform that you used in this
143 assemblyHeader data structure.
145 static const struct AssemblyType
{
148 const char *beginLine
;
149 } assemblyHeader
[] = {
152 "\t.section .note.GNU-stack,\"\",@progbits\n"
153 "\t.section .rodata\n"
154 "\t.align 8\n" /* Either align 8 bytes or 2^8 (256) bytes. 8 bytes is needed. */
155 "\t.type %s,@object\n"
161 /*"\t.section __TEXT,__text,regular,pure_instructions\n"
162 "\t.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32\n"*/
166 "\t.align 4\n" /* 1<<4 = 16 */
173 "\t.section .rodata\n"
174 "\t.align 8\n" /* Either align 8 bytes or 2^8 (256) bytes. 8 bytes is needed. */
180 "\t.section \".rodata\"\n"
191 "\t.csect %s{RO}, 4\n",
206 static int32_t assemblyHeaderIndex
= -1;
208 static UOption options
[]={
210 UOPTION_HELP_QUESTION_MARK
,
212 UOPTION_DEF("name", 'n', UOPT_REQUIRES_ARG
),
213 UOPTION_DEF("entrypoint", 'e', UOPT_REQUIRES_ARG
),
214 #ifdef CAN_GENERATE_OBJECTS
215 /*5*/UOPTION_DEF("object", 'o', UOPT_NO_ARG
),
217 UOPTION_DEF("filename", 'f', UOPT_REQUIRES_ARG
),
218 UOPTION_DEF("assembly", 'a', UOPT_REQUIRES_ARG
)
222 main(int argc
, char* argv
[]) {
223 UBool verbose
= TRUE
;
226 U_MAIN_INIT_ARGS(argc
, argv
);
228 options
[kOptDestDir
].value
= ".";
230 /* read command line options */
231 argc
=u_parseArgs(argc
, argv
, sizeof(options
)/sizeof(options
[0]), options
);
233 /* error handling, printing usage message */
236 "error in command line argument \"%s\"\n",
239 if(argc
<0 || options
[kOptHelpH
].doesOccur
|| options
[kOptHelpQuestionMark
].doesOccur
) {
241 "usage: %s [-options] filename1 filename2 ...\n"
242 "\tread each binary input file and \n"
243 "\tcreate a .c file with a byte array that contains the input file's data\n"
245 "\t-h or -? or --help this usage text\n"
246 "\t-d or --destdir destination directory, followed by the path\n"
247 "\t-n or --name symbol prefix, followed by the prefix\n"
248 "\t-e or --entrypoint entry point name, followed by the name\n"
249 "\t-r or --revision Specify a version\n"
250 #ifdef CAN_GENERATE_OBJECTS
251 "\t-o or --object write a .obj file instead of .c\n"
253 "\t-f or --filename Specify an alternate base filename. (default: symbolname_typ)\n"
256 "\t-a or --assembly Create assembly file. (possible values are: ");
258 fprintf(stderr
, "%s", assemblyHeader
[0].name
);
259 for (idx
= 1; idx
< (int32_t)(sizeof(assemblyHeader
)/sizeof(assemblyHeader
[0])); idx
++) {
260 fprintf(stderr
, ", %s", assemblyHeader
[idx
].name
);
265 const char *message
, *filename
;
266 void (*writeCode
)(const char *, const char *);
268 if(options
[kOptAssembly
].doesOccur
) {
269 message
="generating assembly code for %s\n";
270 writeCode
=&writeAssemblyCode
;
271 for (idx
= 0; idx
< (int32_t)(sizeof(assemblyHeader
)/sizeof(assemblyHeader
[0])); idx
++) {
272 if (uprv_strcmp(options
[kOptAssembly
].value
, assemblyHeader
[idx
].name
) == 0) {
273 assemblyHeaderIndex
= idx
;
277 if (assemblyHeaderIndex
< 0) {
279 "Assembly type \"%s\" is unknown.\n", options
[kOptAssembly
].value
);
283 #ifdef CAN_GENERATE_OBJECTS
284 else if(options
[kOptObject
].doesOccur
) {
285 message
="generating object code for %s\n";
286 writeCode
=&writeObjectCode
;
291 message
="generating C code for %s\n";
292 writeCode
=&writeCCode
;
295 filename
=getLongPathname(argv
[argc
]);
297 fprintf(stdout
, message
, filename
);
300 writeCode(filename
, options
[kOptDestDir
].value
);
308 writeAssemblyCode(const char *filename
, const char *destdir
) {
310 uint32_t buffer
[1024];
311 char *bufferStr
= (char *)buffer
;
312 FileStream
*in
, *out
;
315 in
=T_FileStream_open(filename
, "rb");
317 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
318 exit(U_FILE_ACCESS_ERROR
);
321 getOutFilename(filename
, destdir
, bufferStr
, entry
, ".s");
322 out
=T_FileStream_open(bufferStr
, "w");
324 fprintf(stderr
, "genccode: unable to open output file %s\n", bufferStr
);
325 exit(U_FILE_ACCESS_ERROR
);
328 if(options
[kOptEntryPoint
].doesOccur
) {
329 uprv_strcpy(entry
, options
[kOptEntryPoint
].value
);
330 uprv_strcat(entry
, "_dat");
333 /* turn dashes or dots in the entry name into underscores */
334 length
=uprv_strlen(entry
);
335 for(i
=0; i
<length
; ++i
) {
336 if(entry
[i
]=='-' || entry
[i
]=='.') {
341 sprintf(bufferStr
, assemblyHeader
[assemblyHeaderIndex
].header
,
342 entry
, entry
, entry
, entry
,
343 entry
, entry
, entry
, entry
);
344 T_FileStream_writeLine(out
, bufferStr
);
345 T_FileStream_writeLine(out
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
348 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
352 if (length
!= sizeof(buffer
)) {
353 /* pad with extra 0's when at the end of the file */
354 for(i
=0; i
< (length
% sizeof(uint32_t)); ++i
) {
355 buffer
[length
+i
] = 0;
358 for(i
=0; i
<(length
/sizeof(buffer
[0])); i
++) {
359 write32(out
, buffer
[i
]);
363 T_FileStream_writeLine(out
, "\n");
365 if(T_FileStream_error(in
)) {
366 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
367 exit(U_FILE_ACCESS_ERROR
);
370 if(T_FileStream_error(out
)) {
371 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
372 exit(U_FILE_ACCESS_ERROR
);
375 T_FileStream_close(out
);
376 T_FileStream_close(in
);
380 writeCCode(const char *filename
, const char *destdir
) {
381 char buffer
[4096], entry
[64];
382 FileStream
*in
, *out
;
385 in
=T_FileStream_open(filename
, "rb");
387 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
388 exit(U_FILE_ACCESS_ERROR
);
391 if(options
[kOptName
].doesOccur
) { /* prepend 'icudt28_' */
392 strcpy(entry
, options
[kOptName
].value
);
398 getOutFilename(filename
, destdir
, buffer
, entry
+uprv_strlen(entry
), ".c");
399 out
=T_FileStream_open(buffer
, "w");
401 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
402 exit(U_FILE_ACCESS_ERROR
);
405 /* turn dashes or dots in the entry name into underscores */
406 length
=uprv_strlen(entry
);
407 for(i
=0; i
<length
; ++i
) {
408 if(entry
[i
]=='-' || entry
[i
]=='.') {
415 TODO: Fix this once the compiler implements this feature. Keep in sync with udatamem.c
417 This is here because this platform can't currently put
418 const data into the read-only pages of an object or
419 shared library (service program). Only strings are allowed in read-only
420 pages, so we use char * strings to store the data.
422 In order to prevent the beginning of the data from ever matching the
423 magic numbers we must still use the initial double.
427 "#define U_DISABLE_RENAMING 1\n"
428 "#include \"unicode/umachine.h\"\n"
432 " const char *bytes; \n"
435 T_FileStream_writeLine(out
, buffer
);
438 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
442 for(i
=0; i
<length
; ++i
) {
443 write8str(out
, (uint8_t)buffer
[i
]);
447 T_FileStream_writeLine(out
, "\"\n};\nU_CDECL_END\n");
449 /* Function renaming shouldn't be done in data */
451 "#define U_DISABLE_RENAMING 1\n"
452 "#include \"unicode/umachine.h\"\n"
456 " uint8_t bytes[%ld]; \n"
458 (long)T_FileStream_size(in
), entry
);
459 T_FileStream_writeLine(out
, buffer
);
462 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
466 for(i
=0; i
<length
; ++i
) {
467 write8(out
, (uint8_t)buffer
[i
]);
471 T_FileStream_writeLine(out
, "\n}\n};\nU_CDECL_END\n");
474 if(T_FileStream_error(in
)) {
475 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
476 exit(U_FILE_ACCESS_ERROR
);
479 if(T_FileStream_error(out
)) {
480 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
481 exit(U_FILE_ACCESS_ERROR
);
484 T_FileStream_close(out
);
485 T_FileStream_close(in
);
488 #ifdef CAN_GENERATE_OBJECTS
490 writeObjectCode(const char *filename
, const char *destdir
) {
492 char buffer
[4096], entry
[40];
494 IMAGE_FILE_HEADER fileHeader
;
495 IMAGE_SECTION_HEADER sections
[2];
496 char linkerOptions
[100];
498 IMAGE_SYMBOL symbols
[1];
500 DWORD sizeofLongNames
;
503 FileStream
*in
, *out
;
504 DWORD i
, entryLength
, length
, size
;
506 in
=T_FileStream_open(filename
, "rb");
508 fprintf(stderr
, "genccode: unable to open input file %s\n", filename
);
509 exit(U_FILE_ACCESS_ERROR
);
512 /* entry have a leading '_' */
514 getOutFilename(filename
, destdir
, buffer
, entry
+ICU_ENTRY_OFFSET
, ".obj");
516 if(options
[kOptEntryPoint
].doesOccur
) {
517 uprv_strcpy(entry
+ICU_ENTRY_OFFSET
, options
[kOptEntryPoint
].value
);
518 uprv_strcat(entry
, "_dat");
520 /* turn dashes in the entry name into underscores */
521 entryLength
=(int32_t)uprv_strlen(entry
);
522 for(i
=0; i
<entryLength
; ++i
) {
528 /* open the output file */
529 out
=T_FileStream_open(buffer
, "wb");
531 fprintf(stderr
, "genccode: unable to open output file %s\n", buffer
);
532 exit(U_FILE_ACCESS_ERROR
);
535 /* populate the .obj headers */
536 uprv_memset(&objHeader
, 0, sizeof(objHeader
));
537 uprv_memset(&symbols
, 0, sizeof(symbols
));
538 uprv_memset(&symbolNames
, 0, sizeof(symbolNames
));
539 size
=T_FileStream_size(in
);
541 /* write the linker export directive */
542 uprv_strcpy(objHeader
.linkerOptions
, "-export:");
544 uprv_strcpy(objHeader
.linkerOptions
+length
, entry
);
546 uprv_strcpy(objHeader
.linkerOptions
+length
, ",data ");
549 /* set the file header */
550 objHeader
.fileHeader
.Machine
=ICU_OBJECT_MACHINE_TYPE
;
551 objHeader
.fileHeader
.NumberOfSections
=2;
552 objHeader
.fileHeader
.TimeDateStamp
=time(NULL
);
553 objHeader
.fileHeader
.PointerToSymbolTable
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
+size
; /* start of symbol table */
554 objHeader
.fileHeader
.NumberOfSymbols
=1;
556 /* set the section for the linker options */
557 uprv_strncpy((char *)objHeader
.sections
[0].Name
, ".drectve", 8);
558 objHeader
.sections
[0].SizeOfRawData
=length
;
559 objHeader
.sections
[0].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
;
560 objHeader
.sections
[0].Characteristics
=IMAGE_SCN_LNK_INFO
|IMAGE_SCN_LNK_REMOVE
|IMAGE_SCN_ALIGN_1BYTES
;
562 /* set the data section */
563 uprv_strncpy((char *)objHeader
.sections
[1].Name
, ".rdata", 6);
564 objHeader
.sections
[1].SizeOfRawData
=size
;
565 objHeader
.sections
[1].PointerToRawData
=IMAGE_SIZEOF_FILE_HEADER
+2*IMAGE_SIZEOF_SECTION_HEADER
+length
;
566 objHeader
.sections
[1].Characteristics
=IMAGE_SCN_CNT_INITIALIZED_DATA
|IMAGE_SCN_ALIGN_16BYTES
|IMAGE_SCN_MEM_READ
;
568 /* set the symbol table */
570 uprv_strncpy((char *)symbols
[0].N
.ShortName
, entry
, entryLength
);
571 symbolNames
.sizeofLongNames
=4;
573 symbols
[0].N
.Name
.Short
=0;
574 symbols
[0].N
.Name
.Long
=4;
575 symbolNames
.sizeofLongNames
=4+entryLength
+1;
576 uprv_strcpy(symbolNames
.longNames
, entry
);
578 symbols
[0].SectionNumber
=2;
579 symbols
[0].StorageClass
=IMAGE_SYM_CLASS_EXTERNAL
;
581 /* write the file header and the linker options section */
582 T_FileStream_write(out
, &objHeader
, objHeader
.sections
[1].PointerToRawData
);
584 /* copy the data file into section 2 */
586 length
=T_FileStream_read(in
, buffer
, sizeof(buffer
));
590 T_FileStream_write(out
, buffer
, (int32_t)length
);
593 /* write the symbol table */
594 T_FileStream_write(out
, symbols
, IMAGE_SIZEOF_SYMBOL
);
595 T_FileStream_write(out
, &symbolNames
, symbolNames
.sizeofLongNames
);
597 if(T_FileStream_error(in
)) {
598 fprintf(stderr
, "genccode: file read error while generating from file %s\n", filename
);
599 exit(U_FILE_ACCESS_ERROR
);
602 if(T_FileStream_error(out
)) {
603 fprintf(stderr
, "genccode: file write error while generating from file %s\n", filename
);
604 exit(U_FILE_ACCESS_ERROR
);
607 T_FileStream_close(out
);
608 T_FileStream_close(in
);
614 getOutFilename(const char *inFilename
, const char *destdir
, char *outFilename
, char *entryName
, const char *newSuffix
) {
615 const char *basename
=findBasename(inFilename
), *suffix
=uprv_strrchr(basename
, '.');
618 if(destdir
!=NULL
&& *destdir
!=0) {
620 *outFilename
++=*destdir
++;
621 } while(*destdir
!=0);
622 if(*(outFilename
-1)!=U_FILE_SEP_CHAR
) {
623 *outFilename
++=U_FILE_SEP_CHAR
;
627 while(inFilename
<basename
) {
628 *outFilename
++=*inFilename
++;
633 /* the filename does not have a suffix */
634 uprv_strcpy(entryName
, inFilename
);
635 if(options
[kOptFilename
].doesOccur
) {
636 uprv_strcpy(outFilename
, options
[kOptFilename
].value
);
638 uprv_strcpy(outFilename
, inFilename
);
640 uprv_strcat(outFilename
, newSuffix
);
642 char *saveOutFilename
= outFilename
;
644 while(inFilename
<suffix
) {
645 if(*inFilename
=='-') {
646 /* iSeries cannot have '-' in the .o objects. */
647 *outFilename
++=*entryName
++='_';
651 *outFilename
++=*entryName
++=*inFilename
++;
655 /* replace '.' by '_' */
656 *outFilename
++=*entryName
++='_';
660 while(*inFilename
!=0) {
661 *outFilename
++=*entryName
++=*inFilename
++;
666 if(options
[kOptFilename
].doesOccur
) {
667 uprv_strcpy(saveOutFilename
, options
[kOptFilename
].value
);
668 uprv_strcat(saveOutFilename
, newSuffix
);
671 uprv_strcpy(outFilename
, newSuffix
);
677 write32(FileStream
*out
, uint32_t bitField
) {
679 char bitFieldStr
[64]; /* This is more bits than needed for a 32-bit number */
680 char *s
= bitFieldStr
;
681 uint8_t *ptrIdx
= (uint8_t *)&bitField
;
682 static const char hexToStr
[16] = {
689 /* write the value, possibly with comma and newline */
690 if(column
==MAX_COLUMN
) {
693 } else if(column
<32) {
698 uprv_strcpy(s
, assemblyHeader
[assemblyHeaderIndex
].beginLine
);
704 /* It's a small number. Don't waste the space for 0x */
705 *(s
++)=hexToStr
[bitField
];
708 int seenNonZero
= 0; /* This is used to remove leading zeros */
713 /* This creates a 32-bit field */
715 for (i
= 0; i
< sizeof(uint32_t); i
++)
717 for (i
= sizeof(uint32_t)-1; i
>= 0 ; i
--)
720 uint8_t value
= ptrIdx
[i
];
721 if (value
|| seenNonZero
) {
722 *(s
++)=hexToStr
[value
>>4];
723 *(s
++)=hexToStr
[value
&0xF];
730 T_FileStream_writeLine(out
, bitFieldStr
);
734 write8(FileStream
*out
, uint8_t byte
) {
738 /* convert the byte value to a string */
740 s
[i
++]=(char)('0'+byte
/100);
743 if(i
>0 || byte
>=10) {
744 s
[i
++]=(char)('0'+byte
/10);
747 s
[i
++]=(char)('0'+byte
);
750 /* write the value, possibly with comma and newline */
751 if(column
==MAX_COLUMN
) {
754 } else if(column
<16) {
755 T_FileStream_writeLine(out
, ",");
758 T_FileStream_writeLine(out
, ",\n");
761 T_FileStream_writeLine(out
, s
);
766 write8str(FileStream
*out
, uint8_t byte
) {
770 sprintf(s
, "\\x%X", byte
);
772 sprintf(s
, "\\%X", byte
);
774 /* write the value, possibly with comma and newline */
775 if(column
==MAX_COLUMN
) {
778 T_FileStream_writeLine(out
, "\"");
779 } else if(column
<24) {
782 T_FileStream_writeLine(out
, "\"\n\"");
785 T_FileStream_writeLine(out
, s
);