libbif.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. /*
  2. * Here is a very simple set of routines to write an Excel worksheet
  3. * Microsoft BIFF format. The Excel version is set to 2.0 so that it
  4. * will work with all versions of Excel.
  5. *
  6. * Author: Don Capps
  7. */
  8. /*
  9. * Note: rows and colums should not exceed 255 or this code will
  10. * act poorly
  11. */
  12. #ifdef Windows
  13. #include <Windows.h>
  14. #endif
  15. #include <sys/types.h>
  16. #include <stdio.h>
  17. #include <sys/file.h>
  18. #if defined(__AIX__) || defined(__FreeBSD__) || defined(__DragonFly__)
  19. #include <fcntl.h>
  20. #else
  21. #include <sys/fcntl.h>
  22. #endif
  23. #if defined(OSV5) || defined(linux) || defined (__FreeBSD__) || defined(__OpenBSD__) || defined(__bsdi__) || defined(__APPLE__) || defined(__DragonFly__)
  24. #include <string.h>
  25. #endif
  26. #if defined(linux) || defined(__DragonFly__) || defined(IOZ_macosx)
  27. #include <unistd.h>
  28. #include <stdlib.h>
  29. #endif
  30. #if (defined(solaris) && defined( __LP64__ )) || defined(__s390x__) || defined(FreeBSD)
  31. /* If we are building for 64-bit Solaris, all functions that return pointers
  32. * must be declared before they are used; otherwise the compiler will assume
  33. * that they return ints and the top 32 bits of the pointer will be lost,
  34. * causing segmentation faults. The following includes take care of this.
  35. * It should be safe to add these for all other OSs too, but we're only
  36. * doing it for Solaris now in case another OS turns out to be a special case.
  37. */
  38. #include <sys/stat.h>
  39. #include <fcntl.h>
  40. #include <unistd.h>
  41. #include <stdlib.h>
  42. #include <string.h>
  43. #endif
  44. /* Little Endian */
  45. #define ENDIAN_1 1
  46. /* Big Endian */
  47. #define ENDIAN_2 2
  48. /* Middle Endian */
  49. #define ENDIAN_3 3
  50. /* Middle Endian */
  51. #define ENDIAN_4 4
  52. int junk, *junkp;
  53. #ifdef HAVE_ANSIC_C
  54. /************************************************************************/
  55. /* Here is the API... Enjoy */
  56. /************************************************************************/
  57. /* Create worksheet */
  58. int create_xls(char *);
  59. /* Args: Filename */
  60. /* */
  61. /* Close worksheet */
  62. void close_xls(int);
  63. /* Args: file descriptor */
  64. /* */
  65. /* Put a 16 bit integer in worksheet */
  66. void do_int(int,int,int,int);
  67. /* Args: file descriptor, */
  68. /* value, */
  69. /* row, */
  70. /* column */
  71. /* Put a double in 8 byte float */
  72. void do_float(int,double,int,int);
  73. /* Args: file descriptor, */
  74. /* value, */
  75. /* row, */
  76. /* column */
  77. /* Put a string in worksheet */
  78. void do_label(int,char *,int,int);
  79. /* Args: file descriptor, */
  80. /* string, */
  81. /* row, */
  82. /* column */
  83. /************************************************************************/
  84. char libbif_version[] = "Libbif Version $Revision: 3.26 $";
  85. void do_eof(int ); /* Used internally */
  86. void do_header(int ); /* Used internally */
  87. int endian(void);
  88. #endif
  89. #define BOF 0x9
  90. #define INTEGER 0x2
  91. #define FLOAT 0x3
  92. #define LABEL 0x4
  93. #define EXCEL_VERS 0x2
  94. #define WORKSHEET 0x10
  95. struct bof_record{ /* Beginning of file */
  96. char hi_opcode;
  97. char lo_opcode;
  98. char hi_length;
  99. char lo_length;
  100. char hi_version; /* Excel version */
  101. char lo_version;
  102. char hi_filetype;
  103. char lo_filetype;
  104. };
  105. struct int_record {
  106. char hi_opcode; /* Type 2 of record */
  107. char lo_opcode;
  108. char hi_length;
  109. char lo_length;
  110. char hi_row;
  111. char lo_row;
  112. char hi_column;
  113. char lo_column;
  114. char rgbhi;
  115. char rgbmed;
  116. char rgblo;
  117. char hi_data;
  118. char lo_data;
  119. };
  120. struct label_record {
  121. char hi_opcode; /* Type 4 of record */
  122. char lo_opcode;
  123. char hi_length;
  124. char lo_length;
  125. char hi_row;
  126. char lo_row;
  127. char hi_column;
  128. char lo_column;
  129. char rgbhi;
  130. char rgbmed;
  131. char rgblo;
  132. char string_length;
  133. char str_array[256];
  134. };
  135. struct float_record { /* Type 3 record */
  136. char hi_opcode;
  137. char lo_opcode;
  138. char hi_length;
  139. char lo_length;
  140. char hi_row;
  141. char lo_row;
  142. char hi_column;
  143. char lo_column;
  144. char rgbhi;
  145. char rgbmed;
  146. char rgblo;
  147. double data;
  148. };
  149. /*
  150. * Write the EOF and close the file
  151. */
  152. #ifdef HAVE_ANSIC_C
  153. void
  154. close_xls(int fd)
  155. {
  156. #else
  157. close_xls(fd)
  158. int fd;
  159. {
  160. #endif
  161. do_eof(fd);
  162. close(fd);
  163. }
  164. /*
  165. * Create xls worksheet. Create file and put the BOF record in it.
  166. */
  167. #ifdef HAVE_ANSIC_C
  168. int
  169. create_xls(char *name)
  170. {
  171. #else
  172. create_xls(name)
  173. char *name;
  174. {
  175. #endif
  176. int fd;
  177. unlink(name);
  178. #ifdef Windows
  179. fd=open(name,O_BINARY|O_CREAT|O_RDWR,0666);
  180. #else
  181. fd=open(name,O_CREAT|O_RDWR,0666);
  182. #endif
  183. if(fd<0)
  184. {
  185. printf("Error opening file %s\n",name);
  186. exit(-1);
  187. }
  188. do_header(fd);
  189. return(fd);
  190. }
  191. #ifdef HAVE_ANSIC_C
  192. void
  193. do_header(int fd) /* Stick the BOF at the beginning of the file */
  194. {
  195. #else
  196. do_header(fd)
  197. int fd;
  198. {
  199. #endif
  200. struct bof_record bof;
  201. bof.hi_opcode=BOF;
  202. bof.lo_opcode = 0x0;
  203. bof.hi_length=0x4;
  204. bof.lo_length=0x0;
  205. bof.hi_version=EXCEL_VERS;
  206. bof.lo_version=0x0;
  207. bof.hi_filetype=WORKSHEET;
  208. bof.lo_filetype=0x0;
  209. junk=write(fd,&bof,sizeof(struct bof_record));
  210. }
  211. /*
  212. * Put an integer (16 bit) in the worksheet
  213. */
  214. #ifdef HAVE_ANSIC_C
  215. void
  216. do_int(int fd,int val, int row, int column)
  217. {
  218. #else
  219. do_int(fd,val,row,column)
  220. int fd,val,row,column;
  221. {
  222. #endif
  223. struct int_record intrec;
  224. short s_row,s_column;
  225. s_row=(short)row;
  226. s_column=(short)column;
  227. intrec.hi_opcode=INTEGER;
  228. intrec.lo_opcode=0x00;
  229. intrec.hi_length=0x09;
  230. intrec.lo_length=0x00;
  231. intrec.rgbhi=0x0;
  232. intrec.rgbmed=0x0;
  233. intrec.rgblo=0x0;
  234. intrec.hi_row=(char)s_row&0xff;
  235. intrec.lo_row=(char)(s_row>>8)&0xff;
  236. intrec.hi_column=(char)(s_column&0xff);
  237. intrec.lo_column=(char)(s_column>>8)&0xff;
  238. intrec.hi_data=(val & 0xff);
  239. intrec.lo_data=(val & 0xff00)>>8;
  240. junk=write(fd,&intrec,13);
  241. }
  242. /* Note: This routine converts Big Endian to Little Endian
  243. * and writes the record out.
  244. */
  245. /*
  246. * Put a double in the worksheet as 8 byte float in IEEE format.
  247. */
  248. #ifdef HAVE_ANSIC_C
  249. void
  250. do_float(int fd, double value, int row, int column)
  251. {
  252. #else
  253. do_float(fd, value, row, column)
  254. int fd;
  255. double value;
  256. int row,column;
  257. {
  258. #endif
  259. struct float_record floatrec;
  260. short s_row,s_column;
  261. unsigned char *sptr,*dptr;
  262. s_row=(short)row;
  263. s_column=(short)column;
  264. floatrec.hi_opcode=FLOAT;
  265. floatrec.lo_opcode=0x00;
  266. floatrec.hi_length=0xf;
  267. floatrec.lo_length=0x00;
  268. floatrec.rgbhi=0x0;
  269. floatrec.rgbmed=0x0;
  270. floatrec.rgblo=0x0;
  271. floatrec.hi_row=(char)(s_row&0xff);
  272. floatrec.lo_row=(char)((s_row>>8)&0xff);
  273. floatrec.hi_column=(char)(s_column&0xff);
  274. floatrec.lo_column=(char)((s_column>>8)&0xff);
  275. sptr =(unsigned char *) &value;
  276. dptr =(unsigned char *) &floatrec.data;
  277. if(endian()==ENDIAN_2) /* Big Endian */
  278. {
  279. dptr[0]=sptr[7]; /* Convert to Little Endian */
  280. dptr[1]=sptr[6];
  281. dptr[2]=sptr[5];
  282. dptr[3]=sptr[4];
  283. dptr[4]=sptr[3];
  284. dptr[5]=sptr[2];
  285. dptr[6]=sptr[1];
  286. dptr[7]=sptr[0];
  287. }
  288. if(endian()==ENDIAN_3) /* Middle Endian */
  289. {
  290. dptr[0]=sptr[4]; /* 16 bit swapped ARM */
  291. dptr[1]=sptr[5];
  292. dptr[2]=sptr[6];
  293. dptr[3]=sptr[7];
  294. dptr[4]=sptr[0];
  295. dptr[5]=sptr[1];
  296. dptr[6]=sptr[2];
  297. dptr[7]=sptr[3];
  298. }
  299. if(endian()==ENDIAN_1) /* Little Endian */
  300. {
  301. dptr[0]=sptr[0]; /* Do not convert to Little Endian */
  302. dptr[1]=sptr[1];
  303. dptr[2]=sptr[2];
  304. dptr[3]=sptr[3];
  305. dptr[4]=sptr[4];
  306. dptr[5]=sptr[5];
  307. dptr[6]=sptr[6];
  308. dptr[7]=sptr[7];
  309. }
  310. if(endian()==-1) /* Unsupported architecture */
  311. {
  312. dptr[0]=0;
  313. dptr[1]=0;
  314. dptr[2]=0;
  315. dptr[3]=0;
  316. dptr[4]=0;
  317. dptr[5]=0;
  318. dptr[6]=0;
  319. dptr[7]=0;
  320. printf("Excel output not supported on this architecture.\n");
  321. }
  322. junk=write(fd,&floatrec,11); /* Don't write floatrec. Padding problems */
  323. junk=write(fd,&floatrec.data,8); /* Write value seperately */
  324. }
  325. /*
  326. * Put a string as a label in the worksheet.
  327. */
  328. #ifdef HAVE_ANSIC_C
  329. void
  330. do_label(int fd, char *string, int row, int column)
  331. {
  332. #else
  333. do_label(fd, string, row, column)
  334. int fd;
  335. char *string;
  336. int row,column;
  337. {
  338. #endif
  339. struct label_record labelrec;
  340. short s_row,s_column;
  341. int i;
  342. for(i=0;i<255;i++)
  343. labelrec.str_array[i]=0;
  344. s_row=(short)row;
  345. s_column=(short)column;
  346. i=strlen(string);
  347. labelrec.hi_opcode=LABEL;
  348. labelrec.lo_opcode=0x00;
  349. labelrec.hi_length=0x08; /* 264 total bytes */
  350. labelrec.lo_length=0x01;
  351. labelrec.rgblo=0x0;
  352. labelrec.rgbmed=0x0;
  353. labelrec.rgbhi=0x0;
  354. labelrec.hi_row=(char)(s_row&0xff);
  355. labelrec.lo_row=(char)((s_row>>8)&0xff);
  356. labelrec.hi_column=(char)(s_column&0xff);
  357. labelrec.lo_column=(char)((s_column>>8)&0xff);
  358. labelrec.string_length=i;
  359. if(i > 255) /* If too long then terminate it early */
  360. string[254]=0;
  361. i=strlen(string);
  362. strcpy(labelrec.str_array,string);
  363. junk=write(fd,&labelrec,sizeof(struct label_record));
  364. }
  365. /*
  366. * Write the EOF in the file
  367. */
  368. #ifdef HAVE_ANSIC_C
  369. void
  370. do_eof(int fd)
  371. {
  372. #else
  373. do_eof(fd)
  374. int fd;
  375. {
  376. #endif
  377. char buf[]={0x0a,0x00,0x00,0x00};
  378. junk=write(fd,buf,4);
  379. }
  380. /*
  381. * Routine to determine the Endian-ness of the system. This
  382. * is needed for Iozone to convert doubles (floats) into
  383. * Little-endian format. This is needed for Excel to be
  384. * able to interpret the file
  385. */
  386. int
  387. endian(void)
  388. {
  389. long long foo = 0x0102030405060708LL;
  390. long foo1 = 0x012345678;
  391. unsigned char *c,c1,c2,c3,c4,c5,c6,c7,c8;
  392. c=(unsigned char *)&foo;
  393. c1=*c++;
  394. c2=*c++;
  395. c3=*c++;
  396. c4=*c++;
  397. c5=*c++;
  398. c6=*c++;
  399. c7=*c++;
  400. c8=*c;
  401. /*--------------------------------------------------------------*/
  402. /* printf("%x %x %x %x %x %x %x %x\n",c1,c2,c3,c4,c5,c6,c7,c8); */
  403. /*--------------------------------------------------------------*/
  404. /* Little Endian format ? ( Intel ) */
  405. if( (c1==0x08) && (c2==0x07) && (c3==0x06) && (c4==0x05) &&
  406. (c5==0x04) && (c6==0x03) && (c7==0x02) && (c8==0x01) )
  407. return(ENDIAN_1);
  408. /* Big Endian format ? ( Sparc, Risc... */
  409. if( (c1==0x01) && (c2==0x02) && (c3==0x03) && (c4==0x04) &&
  410. (c5==0x05) && (c6==0x06) && (c7==0x07) && (c8==0x08) )
  411. return(ENDIAN_2);
  412. /* Middle Endian format ? ( ARM ... ) */
  413. if( (c1==0x04) && (c2==0x03) && (c3==0x02) && (c4==0x01) &&
  414. (c5==0x08) && (c6==0x07) && (c7==0x06) && (c8==0x05) )
  415. return(ENDIAN_3);
  416. c=(unsigned char *)&foo1;
  417. c1=*c++;
  418. c2=*c++;
  419. c3=*c++;
  420. c4=*c++;
  421. /* Another middle endian format ? ( PDP-11 ... ) */
  422. if( (c1==0x34) && (c2==0x12) && (c3==0x78) && (c4==0x56))
  423. return(ENDIAN_4);
  424. return(-1);
  425. }