Added Type 1 and Type 42 font downloading.
[wine] / tools / fnt2bdf.c
1 /************************************************
2  *
3  * Extract fonts from .fnt or Windows DLL files
4  * and convert them to the .bdf format.
5  *
6  * Copyright 1994-1996 Kevin Carothers and Alex Korobka
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #ifdef HAVE_SYS_PARAM_H
26 # include <sys/param.h>
27 #endif
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35
36 #include "fnt2bdf.h"
37 #include "module.h"
38
39 #define FILE_ERROR      0
40 #define FILE_DLL        1
41 #define FILE_FNT        2
42
43 /* global options */
44
45 int dump_bdf( fnt_fontS* cpe_font_struct, unsigned char* file_buffer);
46 int dump_bdf_hdr(FILE* fs, fnt_fontS* cpe_font_struct, unsigned char* file_buffer);
47
48 char*   g_lpstrFileName = NULL;
49 char*   g_lpstrCharSet = NULL;
50 char*   g_lpstrInputFile = NULL;
51 int     g_outputPoints = 0;
52
53 static char*    errorDLLRead = "Unable to read Windows DLL.\n";
54 static char*    errorFNTRead = "Unable to read .FNT file.\n";
55 static char*    errorOpenFile = "Unable to open file.\n";
56 static char*    errorMemory = "Memory allocation error.\n";
57 static char*    errorFile = "Corrupt or invalid file.\n";
58 static char*    errorFontData = "Unable to parse font data: Error ";
59 static char*    errorEmpty = "No fonts found.\n";
60
61 /* info */
62
63 void usage(void)
64 {
65     printf("Usage: fnt2bdf [-t] [-c charset] [-o basename] [input file]\n");
66     printf("  -c charset\tcharset name for OEM_CHARSET fonts\n");
67     printf("  -f basename\tbasic output filename\n");
68     printf("  -t \t\toutput files by point size instead of pixel height\n");
69     printf("  input file\tMSWindows .fon, .fnt, .dll, or .exe file.\n");
70     printf("\nExample:\n  fnt2bdf -c winsys vgasys.fnt\n\n");
71     exit(-1);
72 }
73
74 /* convert little-endian value to the local format */
75
76 int return_data_value(enum data_types dtype, void * pChr)
77 {
78 int   ret_val = 0;
79
80     switch(dtype) {
81         case (dfChar):
82             ret_val = (int) *(unsigned char *)pChr;
83             break;
84
85         case(dfShort):
86             ret_val = *(unsigned char *)pChr;
87             ret_val += (*((unsigned char *)pChr + 1) << 8);
88             break;
89
90         case(dfLong): {
91             int  i;
92
93             for(i=3; i >= 0; i--)  {
94                 ret_val += *((unsigned char *)pChr + i) << (8*i);
95                 }
96             break;
97             }
98                 case(dfString):
99                         break;
100         }
101     return ret_val;
102 }
103
104 int make_bdf_filename(char* name, fnt_fontS* cpe_font_struct, unsigned char* file_buffer)
105 {
106 long    l_nameoffset = return_data_value(dfLong, &cpe_font_struct->hdr.fi.dfFace);
107 char*   lpChar;
108
109   if( !g_lpstrFileName )
110   {
111     if( !l_nameoffset ||
112          l_nameoffset > return_data_value(dfLong, &cpe_font_struct->hdr.dfSize) + 1 )
113          return ERROR_DATA;
114     lpChar =  (char*)(file_buffer + l_nameoffset);
115   }
116     else lpChar = g_lpstrFileName;
117
118   strcpy( name, lpChar );
119
120   while( (lpChar = strchr( name, ' ')) )
121          *lpChar = '-';
122
123   /* construct a filename from the font typeface, slant, weight, and size */
124
125   if( cpe_font_struct->hdr.fi.dfItalic ) strcat(name, "_i" );
126   else strcat(name, "_r" );
127
128   lpChar = name + strlen( name );
129   sprintf(lpChar, "%d-%d.bdf", return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfWeight),
130           (g_outputPoints) ? return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfPoints)
131                            : return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfPixHeight) );
132   return 0;
133 }
134
135 /* parse FONT resource and write .bdf file */
136
137 int parse_fnt_data(unsigned char* file_buffer, int length)
138 {
139   fnt_fontS     cpe_font_struct;
140   int           ic=0, t;
141
142   memcpy((char *) &cpe_font_struct.hdr, file_buffer, sizeof(fnt_hdrS));
143
144   /* check font header */
145
146   t = return_data_value(dfShort, &cpe_font_struct.hdr.dfVersion);
147   if( t != 0x300 && t != 0x200) return ERROR_VERSION;
148
149   t = return_data_value(dfLong, &cpe_font_struct.hdr.dfSize);
150   if( t > length ) return ERROR_SIZE;
151   else
152   {
153     /* set up the charWidth/charOffset  structure pairs (dfCharTable)... */
154
155     int l_fchar = return_data_value(dfChar, &cpe_font_struct.hdr.fi.dfFirstChar),
156         l_lchar = return_data_value(dfChar, &cpe_font_struct.hdr.fi.dfLastChar);
157     int l_len   = l_lchar - l_fchar + 1;
158     int l_ptr = sizeof(fnt_hdrS);
159
160     /* some fields were introduced for Windows 3.x fonts */
161     if( return_data_value(dfShort, &cpe_font_struct.hdr.dfVersion) == 0x200 )
162         l_ptr -= 30;
163
164     /* malloc size = (# chars) * sizeof(WinCharS) */
165
166     if((cpe_font_struct.dfCharTable = (WinCharS *) calloc(sizeof(WinCharS), l_len)) == NULL)
167         return ERROR_MEMORY;
168
169     /* NOW, convert them all to UNIX (lton) notation... */
170
171     for(ic=0; ic < l_len; ic++) {
172         cpe_font_struct.dfCharTable[ic].charWidth = return_data_value(dfShort, &file_buffer[l_ptr]);
173         l_ptr += 2;     /* bump by sizeof(short) */
174
175
176         if( return_data_value(dfShort, &cpe_font_struct.hdr.dfVersion) == 0x200) {
177             cpe_font_struct.dfCharTable[ic].charOffset =
178                         return_data_value(dfShort, &file_buffer[l_ptr]);
179             l_ptr += 2; /* bump by sizeof(long) */
180             }
181         else {  /*  Windows Version 3.0 type font */
182             cpe_font_struct.dfCharTable[ic].charOffset =
183                         return_data_value(dfLong, &file_buffer[l_ptr]);
184             l_ptr += 4; /* bump by sizeof(long) */
185             }
186         }
187     t = dump_bdf(&cpe_font_struct, file_buffer);
188     free( cpe_font_struct.dfCharTable );
189   }
190   return t;
191 }
192
193 int dump_bdf( fnt_fontS* cpe_font_struct, unsigned char* file_buffer)
194 {
195   FILE*   fp;
196   int     ic;
197   int     l_fchar = return_data_value(dfChar, &cpe_font_struct->hdr.fi.dfFirstChar),
198           l_lchar = return_data_value(dfChar, &cpe_font_struct->hdr.fi.dfLastChar);
199
200   int     l_len = l_lchar-l_fchar + 1,
201           l_hgt = return_data_value(dfChar, &cpe_font_struct->hdr.fi.dfPixHeight);
202   int     l_ascent = return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfAscent);
203   char    l_filename[256];
204
205     if( (ic = make_bdf_filename(l_filename, cpe_font_struct, file_buffer)) )
206         return ic;
207
208     if((fp = fopen(l_filename, "w")) == (FILE *) 0)
209     {
210       fprintf(stderr, "Couldn't open \"%s\" for output.\n", l_filename);
211       return ERROR_FILE;
212     }
213
214     ic = dump_bdf_hdr(fp, cpe_font_struct, file_buffer);
215     if (ic) return (ic);
216
217     /* NOW, convert all chars to UNIX (lton) notation... */
218
219     for(ic=0; ic < l_len; ic++) {
220         int rowidx, l_span,             /* how many char-cols wide is char? */
221             l_idx = cpe_font_struct->dfCharTable[ic].charOffset;
222
223         l_span = (int) (cpe_font_struct->dfCharTable[ic].charWidth-1)/8;
224
225         fprintf(fp, "STARTCHAR %d  \n", ic);
226         fprintf(fp, "ENCODING %d\n",   l_fchar);
227         fprintf(fp, "SWIDTH    %d    %d \n",
228                 cpe_font_struct->dfCharTable[ic].charWidth*1000,
229                 0);
230
231         fprintf(fp, "DWIDTH    %d    %d \n",
232                 cpe_font_struct->dfCharTable[ic].charWidth, 0);
233
234         fprintf(fp, "BBX  %d  %d  %d   %d\n",
235                 cpe_font_struct->dfCharTable[ic].charWidth, l_hgt, 0,
236                 l_ascent - l_hgt);
237
238         fprintf(fp, "BITMAP\n");
239         for(rowidx=0; rowidx < l_hgt; rowidx++) {
240             switch(l_span) {
241                 case(0):        /* 1-7 pixels wide font */
242                     {
243                     fprintf(fp, "%02X\n", (int) file_buffer[l_idx+rowidx]);
244                     break;
245                     }
246
247                 case(1):        /* 8-15 pixels wide font */
248                     {
249                     fprintf(fp, "%02X%02X",
250                         (int) file_buffer[l_idx+rowidx], file_buffer[l_idx+l_hgt+rowidx]);
251                     fprintf(fp, "\n");
252                     break;
253                     }
254
255                 case(2):        /* 16-23 pixels wide font */
256                     {
257                     fprintf(fp, "%02X%02X%02X",
258                         file_buffer[l_idx+rowidx],
259                         file_buffer[l_idx+l_hgt+rowidx],
260                         file_buffer[l_idx+(2*l_hgt)+rowidx]);
261                     fprintf(fp, "\n");
262                     break;
263                     }
264
265                 case(3):        /* 24-31 pixels wide font */
266                     {
267                     fprintf(fp, "%02X%02X%02X%02X",
268                         file_buffer[l_idx+rowidx],
269                         file_buffer[l_idx+l_hgt+rowidx],
270                         file_buffer[l_idx+(2*l_hgt)+rowidx],
271                         file_buffer[l_idx+(3*l_hgt)+rowidx]);
272                     fprintf(fp, "\n");
273                     break;
274                     }
275                 case(4):        /* 32-39 */
276                     {
277                     fprintf(fp, "%02X%02X%02X%02X%02X",
278                         file_buffer[l_idx+rowidx],
279                         file_buffer[l_idx+l_hgt+rowidx],
280                         file_buffer[l_idx+(2*l_hgt)+rowidx],
281                         file_buffer[l_idx+(3*l_hgt)+rowidx],
282                         file_buffer[l_idx+(4*l_hgt)+rowidx]);
283                     fprintf(fp, "\n");
284                     break;
285                     }
286                 default:
287                     fclose(fp);
288                     unlink(l_filename);
289                     return ERROR_DATA;
290                 }
291             }
292         fprintf(fp, "ENDCHAR\n");
293
294         l_fchar++;      /* Go to next one */
295         }
296 fprintf(fp, "ENDFONT\n");
297 fclose(fp);
298 return 0;
299 }
300
301
302 int dump_bdf_hdr(FILE* fs, fnt_fontS* cpe_font_struct, unsigned char* file_buffer)
303 {
304 int     l_fchar = return_data_value(dfChar, &cpe_font_struct->hdr.fi.dfFirstChar),
305         l_lchar = return_data_value(dfChar, &cpe_font_struct->hdr.fi.dfLastChar);
306 int     l_len = l_lchar - l_fchar + 1;
307 long    l_nameoffset = return_data_value(dfLong, &cpe_font_struct->hdr.fi.dfFace);
308 int     l_cellheight = return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfPixHeight);
309 int     l_ascent = return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfAscent);
310
311     fprintf(fs, "STARTFONT   2.1\n");
312
313     /* Compose font name */
314
315     if( l_nameoffset &&
316         l_nameoffset < return_data_value(dfLong, &cpe_font_struct->hdr.dfSize) )
317     {
318       int     dpi, point_size;
319       char*   lpFace = (char*)(file_buffer + l_nameoffset), *lpChar;
320       short   tmWeight = return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfWeight);
321
322       while((lpChar = strchr(lpFace, '-')) )
323             *lpChar = ' ';
324
325       fprintf(fs, "FONT -windows-%s-", lpFace );
326
327       if( tmWeight == 0 )                       /* weight */
328           fputs("medium-", fs);
329       else if( tmWeight <= FW_LIGHT )
330           fputs("light-", fs);
331       else if( tmWeight <= FW_MEDIUM )
332           fputs("medium-", fs);
333       else if( tmWeight <= FW_DEMIBOLD )
334           fputs("demibold-", fs);
335       else if( tmWeight <= FW_BOLD )
336           fputs("bold-", fs);
337       else fputs("black-", fs);
338
339       if( cpe_font_struct->hdr.fi.dfItalic )    /* slant */
340           fputs("i-", fs);
341       else fputs("r-", fs);
342
343       /* style */
344
345       if( (cpe_font_struct->hdr.fi.dfPitchAndFamily & 0xF0) == FF_SWISS )
346           fputs("normal-sans-", fs);
347       else fputs("normal--", fs);       /* still can be -sans */
348
349       /* y extents */
350
351       point_size = 10 * return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfPoints );
352       dpi = (l_cellheight * 720) / point_size;
353
354       fprintf(fs, "%d-%d-%d-%d-",l_cellheight, point_size,
355             return_data_value (dfShort, &cpe_font_struct->hdr.fi.dfHorizRes),
356             return_data_value (dfShort, &cpe_font_struct->hdr.fi.dfVertRes));
357
358       /* spacing */
359
360       if( return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfPixWidth) ) fputs("c-", fs);
361       else fputs("p-", fs);
362
363       /* average width */
364
365       fprintf( fs, "%d-", 10 * return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfAvgWidth) );
366
367       /* charset */
368
369      if( g_lpstrCharSet ) fprintf(fs, "%s\n", g_lpstrCharSet);
370      else
371       switch( cpe_font_struct->hdr.fi.dfCharSet )
372       {
373         /* Microsoft just had to invent its own charsets! */
374
375         case ANSI_CHARSET:      fputs("microsoft-cp1252\n", fs); break;
376         case GREEK_CHARSET:     fputs("microsoft-cp1253\n", fs); break;
377         case TURKISH_CHARSET:   fputs("microsoft-cp1254\n", fs); break;
378         case HEBREW_CHARSET:    fputs("microsoft-cp1255\n", fs); break;
379         case ARABIC_CHARSET:    fputs("microsoft-cp1256\n", fs); break;
380         case BALTIC_CHARSET:    fputs("microsoft-cp1257\n", fs); break;
381         case RUSSIAN_CHARSET:   fputs("microsoft-cp1251\n", fs); break;
382         case EE_CHARSET:        fputs("microsoft-cp1250\n", fs); break;
383         case SYMBOL_CHARSET:    fputs("microsoft-symbol\n", fs); break;
384         case SHIFTJIS_CHARSET:  fputs("jisx0208.1983-0\n", fs); break;
385         case DEFAULT_CHARSET:   fputs("iso8859-1\n", fs); break;
386
387         default:
388         case OEM_CHARSET:
389                     fputs("Undefined charset, use -c option.\n", stderr);
390                     return ERROR_DATA;
391       }
392     }
393     else return ERROR_DATA;
394
395     fprintf(fs, "SIZE  %d  %d   %d\n",
396         return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfPoints ),
397         return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfHorizRes),
398         return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfVertRes));   /* dfVertRes[2] */
399
400     fprintf(fs, "FONTBOUNDINGBOX %d  %d  %d  %d\n",
401         return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfMaxWidth),
402         return_data_value(dfChar, &cpe_font_struct->hdr.fi.dfPixHeight),
403         0, l_ascent - l_cellheight );
404
405     fprintf(fs, "STARTPROPERTIES  4\n");
406
407     fprintf(fs, "FONT_ASCENT %d\n", l_ascent );                       /*  dfAscent[2] */
408     fprintf(fs, "FONT_DESCENT %d\n", l_cellheight - l_ascent );
409     fprintf(fs, "CAP_HEIGHT %d\n", l_ascent -
410                                    return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfInternalLeading));
411     fprintf(fs, "DEFAULT_CHAR %d\n", return_data_value(dfShort, &cpe_font_struct->hdr.fi.dfDefaultChar));
412
413     fprintf(fs, "ENDPROPERTIES\n");
414
415     fprintf(fs, "CHARS  %d\n",  l_len);
416     return 0;
417 }
418
419
420
421 void parse_options(int argc, char **argv)
422 {
423   int i;
424
425   switch( argc )
426   {
427     case 2:
428          g_lpstrInputFile = argv[1];
429          break;
430
431     case 3:
432     case 4:
433     case 5:
434     case 6:
435     case 7:
436     case 8:
437          for( i = 1; i < argc - 1; i++ )
438          {
439            if( argv[i][0] != '-' ||
440                strlen(argv[i]) != 2 ) break;
441
442            if( argv[i][1] == 'c' )
443                g_lpstrCharSet = argv[i+1];
444            else
445            if( argv[i][1] == 'f' )
446                g_lpstrFileName = argv[i+1];
447            else
448            if( argv[i][1] == 't' )
449            {
450               g_outputPoints = 1;
451               continue;
452            }
453            else
454            usage();
455
456            i++;
457          }
458          if( i == argc - 1 )
459          {
460            g_lpstrInputFile = argv[i];
461            break;
462          }
463     default: usage();
464   }
465
466 }
467
468 /* read file data and return file type */
469
470 int get_resource_table(int fd, unsigned char** lpdata, int fsize)
471 {
472   IMAGE_DOS_HEADER mz_header;
473   IMAGE_OS2_HEADER ne_header;
474   long s, offset, size;
475   int retval;
476
477   lseek( fd, 0, SEEK_SET );
478
479   if( read(fd, &mz_header, sizeof(mz_header)) != sizeof(mz_header) )
480       return FILE_ERROR;
481
482   s = return_data_value(dfShort, &mz_header.e_magic);
483
484   if( s == IMAGE_DOS_SIGNATURE)         /* looks like .dll file so far... */
485   {
486     s = return_data_value(dfShort, &mz_header.e_lfanew);
487     lseek( fd, s, SEEK_SET );
488
489     if( read(fd, &ne_header, sizeof(ne_header)) != sizeof(ne_header) )
490         return FILE_ERROR;
491
492     s = return_data_value(dfShort, &ne_header.ne_magic);
493
494     if( s == IMAGE_NT_SIGNATURE)
495     {
496        fprintf( stderr, "Do not know how to handle 32-bit Windows DLLs.\n");
497        return FILE_ERROR;
498     }
499     else if ( s != IMAGE_OS2_SIGNATURE) return FILE_ERROR;
500
501     s = return_data_value(dfShort, &ne_header.ne_rsrctab);
502     size = return_data_value(dfShort, &ne_header.ne_restab);
503
504     if( size > fsize ) return FILE_ERROR;
505
506     size -= s;
507     offset = s + return_data_value(dfShort, &mz_header.e_lfanew);
508
509     if( size <= sizeof(NE_TYPEINFO) ) return FILE_ERROR;
510     retval = FILE_DLL;
511   }
512   else if( s == 0x300 || s == 0x200 )           /* maybe .fnt ? */
513   {
514     size = return_data_value(dfLong, &((fnt_hdrS *)&mz_header)->dfSize);
515
516     if( size != fsize ) return FILE_ERROR;
517     offset  = 0;
518     retval = FILE_FNT;
519   }
520   else return FILE_ERROR;
521
522   *lpdata = (unsigned char*)malloc(size);
523
524   if( *lpdata )
525   {
526     lseek( fd, offset, SEEK_SET );
527     if( read(fd, *lpdata, size) != size )
528            { free( *lpdata ); *lpdata = NULL; }
529   }
530   return retval;
531 }
532
533
534 /* entry point */
535
536 int main(int argc, char **argv)
537 {
538   unsigned char* lpdata = NULL;
539   int            fd;
540
541   parse_options( argc, argv);
542
543   if( (fd = open( g_lpstrInputFile, O_RDONLY)) )
544   {
545     int    i;
546     struct stat file_stat;
547
548     fstat( fd, &file_stat);
549     i = get_resource_table( fd, &lpdata, file_stat.st_size );
550
551     switch(i)
552     {
553         case FILE_DLL:
554              if( lpdata )
555              {
556                int          j, count = 0;
557                NE_TYPEINFO* pTInfo = (NE_TYPEINFO*)(lpdata + 2);
558                NE_NAMEINFO* pFontStorage = NULL;
559
560                while( (i = return_data_value(dfShort, &pTInfo->type_id)) )
561                {
562                   j = return_data_value(dfShort, &pTInfo->count);
563                   if( i == NE_RSCTYPE_FONT )
564                   {
565                     count = j;
566                     pFontStorage = (NE_NAMEINFO*)(pTInfo + 1);
567                     break; /* found one */
568                   }
569
570                   pTInfo = (NE_TYPEINFO *)((char*)(pTInfo+1) + j*sizeof(NE_NAMEINFO));
571                }
572                if( pFontStorage && count )
573                {
574                  unsigned short         size_shift = return_data_value(dfShort, lpdata);
575                  unsigned char*         lpfont = NULL;
576                  unsigned               offset;
577                  unsigned               length;
578
579                  for( j = 0; j < count; j++, pFontStorage++ )
580                  {
581                     length = return_data_value(dfShort, &pFontStorage->length) << size_shift;
582                     offset = return_data_value(dfShort, &pFontStorage->offset) << size_shift;
583
584                     if( !(lpfont = (unsigned char*) realloc( lpfont, length )) )
585                     {
586                         fprintf(stderr, errorMemory );
587                         exit(1);
588                     }
589
590                     lseek( fd, offset, SEEK_SET );
591                     if( read(fd, lpfont, length) != length )
592                     {
593                         fprintf(stderr, errorDLLRead );
594                         exit(1);
595                     }
596
597                     if( (i = parse_fnt_data( lpfont, length )) )
598                     {
599                         fprintf(stderr, "%s%d\n", errorFontData, i );
600                         exit(1);
601                     }
602                  }
603                  free(lpfont); free(lpdata);
604                  exit(0);
605                }
606                else
607                {
608                  fprintf(stderr, errorEmpty );
609                  exit(1);
610                }
611                free( lpdata );
612              }
613              else
614              {
615                fprintf(stderr, errorDLLRead);
616                exit(1);
617              }
618              break;
619
620         case FILE_FNT:
621              if( lpdata )
622              {
623                if( (i = parse_fnt_data( lpdata, file_stat.st_size )) )
624                {
625                    fprintf(stderr, "%s%d\n", errorFontData, i );
626                    exit(1);
627                }
628                free( lpdata );
629              }
630              else
631              {
632                fprintf(stderr, errorFNTRead);
633                exit(1);
634              }
635              break;
636
637         case FILE_ERROR:
638              fprintf(stderr, errorFile );
639              exit(1);
640     }
641     close(fd);
642     exit(0);
643   }
644   else
645   {
646     fprintf(stderr, errorOpenFile );
647     exit(1);
648   }
649 }