"Fossies" - the Fresh Open Source Software Archive

Member "gamgi0.17.5x/src/io/gamgi_io_file.c" (23 Feb 2022, 25986 Bytes) of package /linux/misc/gamgi-all-0.17.5x.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "gamgi_io_file.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.17.4x_vs_0.17.5x.

    1 /******************************************
    2  *
    3  * $GAMGI/src/io/gamgi_io_file.c
    4  *
    5  * Copyright (C) 2004 Carlos Pereira
    6  *
    7  * Distributed under the terms of the GNU
    8  * General Public License: $GAMGI/LICENSE
    9  *
   10  */
   11 
   12 #include "gamgi_engine.h"
   13 #include "gamgi_gtk.h"
   14 #include "gamgi_math.h"
   15 #include "gamgi_expat.h"
   16 #include "gamgi_io.h"
   17 #include "gamgi_global.h"
   18 
   19 #include "gamgi_engine_list.h"
   20 #include "gamgi_engine_count.h"
   21 #include "gamgi_engine_dlist.h"
   22 #include "gamgi_gtk_dialog.h"
   23 #include "gamgi_mesa_area.h"
   24 #include "gamgi_expat_import.h"
   25 #include "gamgi_expat_export.h"
   26 #include "gamgi_io_socket.h"
   27 #include "gamgi_io_token.h"
   28 #include "gamgi_io_error.h"
   29 #include "gamgi_io_xyz.h"
   30 
   31 #include <fcntl.h>
   32 
   33 static gamgi_bool static_tokens (char *string, char *tokens,
   34 int n_tokens, gamgi_bool end)
   35 {
   36 gamgi_bool start;
   37 char *substring;
   38 int i, length = 0;
   39 
   40 for (i = 0; i < n_tokens; i++)
   41   {
   42   if (tokens[0] == '\0') { start = TRUE; tokens++; }
   43   else start = FALSE;
   44 
   45   if ((substring = strstr (string, tokens)) == NULL) return FALSE;
   46   if (start == FALSE && substring != string) return FALSE;
   47 
   48   length = strlen (tokens);
   49   string = substring;
   50   tokens += length;
   51   }
   52 
   53 if (end == FALSE && strstr (string + strlen (string) - length,
   54 tokens - length) == NULL) return FALSE;
   55 
   56 return TRUE;
   57 }
   58 
   59 static gamgi_bool static_pattern (char *string, char *pattern)
   60 {
   61 gamgi_bool start, end;
   62 char *tokens = pattern;
   63 int i, n_tokens;
   64 
   65 /********************************************
   66  * convert the whole pattern sequence to a  *
   67  * list of patterns separated by '\0' chars *
   68  ********************************************/
   69 
   70 n_tokens = 0;
   71 for (i = 0; *pattern != '\0'; pattern++)
   72   {
   73   if (*pattern == '*')
   74     {
   75     if (*(pattern + 1) == '*') continue;
   76     tokens[i++] = '\0';
   77     n_tokens++;
   78     }
   79   else tokens[i++] = *pattern;
   80   }
   81 tokens[i] = '\0';
   82 
   83 if (tokens[0] == '\0') start = TRUE;
   84 else start = FALSE;
   85 
   86 if (tokens[i - 1] == '\0') end = TRUE;
   87 else end = FALSE;
   88 
   89 if (start == TRUE && end == TRUE) n_tokens--;
   90 if (start == FALSE && end == FALSE) n_tokens++;
   91 
   92 return static_tokens (string, tokens, n_tokens, end);
   93 }
   94 
   95 static gamgi_bool static_line (int socket,
   96 char *buffer, char *line, int *available)
   97 {
   98 static char *start;
   99 char *end;
  100 int vacant, copied;
  101 
  102 /*******************
  103  * initialize line *
  104  *******************/
  105 
  106 strcpy (line, "");
  107 vacant = GAMGI_ENGINE_LINE - 1;
  108 
  109 do
  110   {
  111   /********************************
  112    * read from socket into buffer *
  113    ********************************/
  114 
  115   if (*available == 0)
  116     {
  117     *available = read (socket, buffer, GAMGI_IO_BUFFER);
  118     if (*available <= 0) return FALSE;
  119 
  120     start = buffer;
  121     }
  122 
  123   end = strchr (start, '\n');
  124   if (end == NULL) end = start + *available - 1;
  125 
  126   /********************
  127    * \n is not copied *
  128    ********************/
  129 
  130   copied = end - start;
  131   if (copied > vacant) return FALSE;
  132   strncat (line, start, copied);
  133   vacant -= copied;
  134 
  135   /****************
  136    * add 1 for \n *
  137    ****************/
  138 
  139   *available -= copied + 1;
  140   start += copied + 1;
  141   }
  142   while (end == NULL);
  143 
  144 return TRUE;
  145 }
  146 
  147 static char *static_read (int socket, 
  148 int code, char *buffer, char *line)
  149 {
  150 char more[5], end[5];
  151 int available = 0;
  152 
  153 sprintf (more, "%d-", code);
  154 sprintf (end, "%d ", code);
  155 
  156 do
  157   {
  158   if (static_line (socket, buffer, line, &available) == FALSE || 
  159   strlen (line) < 4) return NULL;
  160 
  161   line[4] = '\0';
  162 
  163   if (strcmp (line, end) == 0) return line;
  164 
  165   if (strcmp (line, more) != 0) return NULL;
  166   }
  167   while (1 > 0);
  168 }
  169 
  170 static gamgi_bool static_passive (unsigned char socket, char *line, 
  171 unsigned char *a1, unsigned char *a2, unsigned char *a3, 
  172 unsigned char *a4, unsigned char *p1, unsigned char *p2)
  173 {
  174 int n1, n2, n3, n4;
  175 
  176 /**********************
  177  * retrieve ip number *
  178  **********************/
  179 
  180 line = strpbrk (line+5, "0123456789");
  181 if (sscanf (line, " %d, %d, %d, %d ", &n1, &n2, &n3, &n4) != 4)
  182   return FALSE;
  183 
  184 *a1 = n1; *a2 = n2; *a3 = n3; *a4 = n4; 
  185 
  186 /************************
  187  * retrieve port number *
  188  ************************/
  189 
  190 line = strchr (line+1, ','); line = strchr (line+1, ',');
  191 line = strchr (line+1, ','); line = strchr (line+1, ',');
  192 if (sscanf (line+1, " %d, %d ", &n1, &n2) != 2)
  193   return FALSE;
  194 
  195 *p1 = n1; *p2 = n2;
  196 
  197 return TRUE;
  198 }
  199 
  200 gamgi_bool gamgi_io_file_patterns (char *file, const char *filters)
  201 {
  202 char patterns[GAMGI_GTK_FILE_PATTERNS + 1];
  203 char *pattern;
  204 
  205 /******************************************
  206  * divide sequence in individual patterns *
  207  ******************************************/
  208  
  209 strcpy (patterns, filters);
  210 pattern = strtok (patterns, " ,");
  211 do
  212   {
  213   if (static_pattern (file, pattern) == TRUE) return TRUE;
  214   }
  215   while ((pattern = strtok (NULL, " ,")) != NULL);
  216    
  217 return FALSE;
  218 }
  219 
  220 char *gamgi_io_file_shortname (const char *fullname)
  221 {
  222 char *shortname;
  223 
  224 shortname = strrchr (fullname, '/');
  225 if (shortname != NULL) shortname++;
  226 else shortname = (char *) fullname;
  227 
  228 return shortname;
  229 }
  230 
  231 char *gamgi_io_file_extension (const char *fullname)
  232 {
  233 char *extension;
  234 
  235 /**********************
  236  * get file extension *
  237  **********************/
  238 
  239 extension = strrchr (fullname, '.');
  240 if (extension != NULL)
  241   {
  242   extension++;
  243 
  244   /*******************************
  245    * make sure the dot is in the *
  246    * file and not in a directory *
  247    *******************************/
  248 
  249   if (strchr (extension, '/') != NULL)
  250     extension = NULL;
  251   }
  252 
  253 return extension;
  254 }
  255 
  256 /***************** external function *********************
  257  *                                                       *
  258  *********************************************************/
  259 
  260 void gamgi_io_file_fprintf (FILE *fp, char *string, gamgi_bool *error)
  261 {
  262 /***************************************************************
  263  * We set the error flag as FALSE before the first fprintf     *
  264  * call and check its state only after the last fprintf. If    *
  265  * error is now TRUE, then at least one fprintf call failed,   *
  266  * in which case we show an error message saying that we were  *
  267  * unable to successfully write the file and ask the user if   *
  268  * we should remove it (it is certainly corrupted, but reading *
  269  * it might give the user a clue anyway about what went wrong) *
  270  *                                                             *
  271  * The upside of this procedure is that our code is much       *
  272  * simpler because we are not taking action immediately        *
  273  * if fprintf fails (at this stage the file is already open    *
  274  * in write mode, with sucess, so permission errors are not    *
  275  * likely to occur here, a typical error would occur here      *
  276  * for example if the hard disk filesystem fills up). We       *
  277  * can do this because we are not compromising Gamgi or the    *
  278  * system, just the file, which we remove (or not) in the end. *
  279  *                                                             *
  280  * The downside of this procedure is that our message in       *
  281  * the end cannot tell the user where the failure occurred.    *
  282  * This should not be a problem though, because as soon as     *
  283  * one fprintf fails, all the other should fail as well and    *
  284  * inspecting directly the file should clarify everything.     *
  285  ***************************************************************/
  286 
  287 if (fprintf (fp, "%s", string) < 0) *error = TRUE;
  288 }
  289 
  290 char *gamgi_io_file_name (const char *fullname, 
  291 gamgi_window *window)
  292 {
  293 char *name, *shortname;
  294 
  295 shortname = gamgi_io_file_shortname (fullname);
  296 
  297 /************************************************
  298  * make sure the shortname used for example     *
  299  * in error messages is not too long and always *
  300  * fits inside the message string arrays.       *
  301  ************************************************/
  302 
  303 if (gamgi_io_token_size_check (shortname, GAMGI_IO_SHORTNAME) == FALSE)
  304   {
  305   gamgi_io_error_open (shortname, window);
  306   return NULL;
  307   }
  308 
  309 /***************************************
  310  * make sure fullname is not too long, *
  311  * so filename and hostname always fit *
  312  * inside their string arrays          *
  313  **************************************/
  314 
  315 if (gamgi_io_token_size_check (fullname, GAMGI_IO_FULLNAME) == FALSE)
  316   {
  317   gamgi_io_error_open (shortname, window);
  318   return NULL;
  319   }
  320 
  321 /***************************************
  322  * HTTP label must be in the beginning *
  323  ***************************************/
  324 
  325 name = strstr (fullname, "http://");
  326 if (name != NULL && name != fullname)
  327   {
  328   gamgi_io_error_open (shortname, window);       
  329   return NULL;
  330   }
  331 
  332 /**************************************
  333  * FTP label must be in the beginning *
  334  **************************************/
  335 
  336 name = strstr (fullname, "ftp://");
  337 if (name != NULL && name != fullname)
  338   {
  339   gamgi_io_error_open (shortname, window);       
  340   return NULL;
  341   }
  342 
  343 return shortname;
  344 }
  345 
  346 gamgi_bool gamgi_io_file_http (const char *fullname, char *shortname, 
  347 gamgi_parser parser, gamgi_window *window, void *data)
  348 {
  349 int fd, size, number;
  350 char buffer[GAMGI_IO_BUFFER];
  351 char filename[GAMGI_ENGINE_LINE];
  352 char hostname[GAMGI_ENGINE_LINE];
  353 char *body;
  354 gamgi_bool valid;
  355 
  356 /*****************************
  357  * get hostname and filename *
  358  *****************************/
  359 
  360 fullname += strlen("http://");
  361 
  362 size = strcspn (fullname, "/");
  363 strcpy (filename, fullname + size);
  364 
  365 strncpy (hostname, fullname, size);
  366 hostname[size] = '\0';
  367 
  368 /*******************
  369  * open connection *
  370  *******************/
  371 
  372 fd = gamgi_io_socket_name ("http", hostname);
  373 if (fd < 0) return gamgi_io_error_open (shortname, window);
  374 
  375 /*****************************************
  376  * write instructions to the HTTP server *
  377  *****************************************/
  378 
  379 sprintf (buffer, "GET %s HTTP/1.1\r\n" "Host: %s\r\n"
  380 "Pragma: no-cache\r\n" "Connection: close\r\n\r\n",
  381 filename, hostname);
  382 write (fd, buffer, strlen (buffer));
  383 
  384 /**********************
  385  * handle HTTP header *
  386  **********************/
  387 
  388 /***************************
  389  * check header first line *
  390  ***************************/
  391 
  392 size = read (fd, buffer, GAMGI_IO_BUFFER);
  393 if (size <= 0 || sscanf (buffer, "%*s %d %*s \n", &number) != 1
  394 || number != GAMGI_IO_HTTP_OK)
  395   {
  396   close (fd);
  397   return gamgi_io_error_open (shortname, window);
  398   }
  399 
  400 do
  401   {
  402   /*******************************
  403    * ignore everything and just  *
  404    * search for header last line *
  405    *******************************/
  406 
  407   body = strstr (buffer, "\r\n\r\n");
  408   if (body != NULL) break;
  409 
  410   size = read (fd, buffer, GAMGI_IO_BUFFER);
  411   if (size <= 0) 
  412   {
  413   close (fd);
  414   return gamgi_io_error_open (shortname, window);
  415   }
  416 
  417   } while (1 > 0);
  418 
  419 if (body == NULL)
  420   {
  421   close (fd);
  422   return gamgi_io_error_open (shortname, window);
  423   }
  424 
  425 /********************************************
  426  * move forward the 4 char "\r\n\r\n" and   *
  427  * discount the header characters in buffer *
  428  ********************************************/
  429 
  430 body += 4;
  431 size -= body - buffer;
  432 
  433 /*******************
  434  * parse HTTP file *
  435  *******************/
  436 
  437 valid = (parser) (fd, body, size, data);
  438 
  439 close (fd);
  440 
  441 return valid;
  442 }
  443 
  444 gamgi_bool gamgi_io_file_ftp (const char *fullname, char *shortname, 
  445 gamgi_parser parser, gamgi_window *window, void *data)
  446 {
  447 int fd_main, fd_data, size;
  448 char buffer[GAMGI_IO_BUFFER], line[GAMGI_ENGINE_LINE];
  449 char filename[GAMGI_ENGINE_LINE], hostname[GAMGI_ENGINE_LINE];
  450 char *last;
  451 unsigned char a1, a2, a3, a4, p1, p2;
  452 gamgi_bool valid;
  453 
  454 /*****************************
  455  * get hostname and filename *
  456  *****************************/
  457 
  458 fullname += strlen("ftp://");
  459 
  460 size = strcspn (fullname, "/");
  461 strcpy (filename, fullname + size);
  462 
  463 strncpy (hostname, fullname, size);
  464 hostname[size] = '\0';
  465 
  466 /********************
  467  * open main socket *
  468  ********************/
  469 
  470 if ((fd_main = gamgi_io_socket_name ("ftp", hostname)) < 0)
  471   return gamgi_io_error_open (shortname, window);
  472 
  473 if (static_read (fd_main, GAMGI_IO_FTP_GREETINGS, buffer, line) == NULL)
  474   {
  475   close (fd_main);
  476   return gamgi_io_error_open (shortname, window);
  477   }
  478 
  479 /******************
  480  * enter username *
  481  ******************/
  482 
  483 sprintf (buffer, "USER anonymous\r\n");
  484 if (write (fd_main, (char *) buffer, strlen (buffer)) < 0)
  485   {
  486   close (fd_main);
  487   return gamgi_io_error_open (shortname, window);
  488   }
  489 
  490 if (static_read (fd_main, GAMGI_IO_FTP_USER, buffer, line) == NULL)
  491   {
  492   close (fd_main);
  493   return gamgi_io_error_open (shortname, window);
  494   }
  495 
  496 /******************
  497  * enter password *
  498  ******************/
  499 
  500 sprintf (buffer, "PASS gamgi@www.gamgi.org\r\n");
  501 if (write (fd_main, (char *) buffer, strlen (buffer)) < 0)
  502   {
  503   close (fd_main);
  504   return gamgi_io_error_open (shortname, window);
  505   }
  506 
  507 if (static_read (fd_main, GAMGI_IO_FTP_PASSWORD, buffer, line) == NULL)
  508   {
  509   close (fd_main);
  510   return gamgi_io_error_open (shortname, window);
  511   }
  512 
  513 /**********************************
  514  * set data type (text or binary) *
  515  **********************************/
  516 
  517 sprintf (buffer, "TYPE A\r\n");
  518 if (write (fd_main, (char *) buffer, strlen (buffer)) < 0)
  519   {
  520   close (fd_main);
  521   return gamgi_io_error_open (shortname, window);
  522   }
  523 
  524 if (static_read (fd_main, GAMGI_IO_FTP_TYPE, buffer, line) == NULL)
  525   {
  526   close (fd_main);
  527   return gamgi_io_error_open (shortname, window);
  528   }
  529 
  530 /************************************
  531  * enter passive mode: get IP, Port *
  532  ************************************/
  533 
  534 sprintf (buffer, "PASV\r\n");
  535 if (write (fd_main, (char *) buffer, strlen (buffer)) < 0)
  536   {
  537   close (fd_main);
  538   return gamgi_io_error_open (shortname, window);
  539   }
  540 
  541 if ((last = static_read (fd_main, GAMGI_IO_FTP_PASSIVE, buffer, line)) == NULL)
  542   {
  543   close (fd_main);
  544   return gamgi_io_error_open (shortname, window);
  545   }
  546 
  547 if (static_passive (fd_main, last, &a1, &a2, &a3, &a4, &p1, &p2) == FALSE)
  548   {
  549   close (fd_main);
  550   return gamgi_io_error_open (shortname, window);
  551   }
  552 
  553 /********************
  554  * open data socket *
  555  ********************/
  556 
  557 if ((fd_data = gamgi_io_socket_number ("ftp", a1, a2, a3, a4, p1, p2)) < 0)
  558   {
  559   close (fd_main);
  560   return gamgi_io_error_open (shortname, window);
  561   }
  562 
  563 /****************
  564  * ask for file *
  565  ****************/
  566 
  567 sprintf (buffer, "RETR %s\r\n", filename);
  568 if (write (fd_main, (char *) buffer, strlen (buffer)) < 0)
  569   {
  570   close (fd_main);
  571   close (fd_data);
  572   return gamgi_io_error_open (shortname, window);
  573   }
  574 
  575 if (static_read (fd_main, GAMGI_IO_FTP_FILE, buffer, line) == NULL)
  576   {
  577   close (fd_main);
  578   close (fd_data);
  579   return gamgi_io_error_open (shortname, window);
  580   }
  581 
  582 /************************************
  583  * parse FTP file using data socket *
  584  ************************************/
  585 
  586 valid = (parser) (fd_data, NULL, 0, data);
  587 
  588 close (fd_data);
  589 
  590 if (static_read (fd_main, GAMGI_IO_FTP_READ, buffer, line) == NULL)
  591   {
  592   close (fd_main);
  593   return gamgi_io_error_open (shortname, window);
  594   }
  595 
  596 close (fd_main);
  597 
  598 return valid;
  599 }
  600 
  601 gamgi_bool gamgi_io_file_local (const char *fullname, char *shortname, 
  602 gamgi_parser parser, gamgi_window *window, void *data)
  603 {
  604 int fd;
  605 gamgi_bool valid;
  606 
  607 /*************
  608  * open file *
  609  *************/
  610 
  611 fd = open (fullname, O_RDONLY);
  612 if (fd < 0) return gamgi_io_error_open (shortname, window);
  613 
  614 /**************
  615  * parse file *
  616  **************/
  617 
  618 valid = (parser) (fd, NULL, 0, data);
  619 
  620 /**************
  621  * close file *
  622  **************/
  623 
  624 close (fd);
  625 
  626 return valid;
  627 }
  628 
  629 gamgi_bool gamgi_io_file_protocol (const char *fullname, char *filename, 
  630 gamgi_parser parser, gamgi_window *window, void *data)
  631 {
  632 if (strstr (fullname, "http://") != NULL)
  633   return gamgi_io_file_http (fullname, filename, parser, window, data);
  634 else if (strstr (fullname, "ftp://") != NULL)
  635   return gamgi_io_file_ftp (fullname, filename, parser, window, data);
  636 else
  637   return gamgi_io_file_local (fullname, filename, parser, window, data);
  638 }
  639 
  640 gamgi_bool gamgi_io_file_export_ps (FILE *fp,
  641 int width, int height, gamgi_bool *error)
  642 {
  643 int components, i;
  644 unsigned char *pixels;
  645 char string[GAMGI_ENGINE_LINE];
  646 
  647 /*************
  648  * grab data *
  649  *************/
  650 
  651 components = 3;
  652 pixels = gamgi_mesa_area_read (0, 0, width, height);
  653 
  654 /***********************************************************
  655  * Write header, adapted from: 1) the header produced      *
  656  * by Gimp 2.4.6 when exporting .eps encapsulated          *
  657  * postcript files (without level 2), written by Peter     *
  658  * Kirchgessner; 2) the book Postcript Language, Tutorial  *
  659  * and Cookbook, Adobe Systems Inc., Addison-Wesley, 1986  *
  660  ***********************************************************/
  661 
  662 gamgi_io_file_fprintf (fp, "%!PS-Adobe-3.0 EPSF-3.0\n", error);
  663 sprintf (string, "%%%%Creator: GAMGI %s\n", GAMGI_IO_VERSION);
  664 gamgi_io_file_fprintf (fp, string, error);
  665 gamgi_io_file_fprintf (fp, "%%DocumentData: Clean7Bit\n", error);
  666 gamgi_io_file_fprintf (fp, "%%LanguageLevel: 2\n", error);
  667 gamgi_io_file_fprintf (fp, "%%Pages: 1\n", error);
  668 sprintf (string, "%%%%BoundingBox: 0 0 %d %d\n", width, height);
  669 gamgi_io_file_fprintf (fp, string, error);
  670 gamgi_io_file_fprintf (fp, "%%EndComments\n", error);
  671 sprintf (string, "/scanline %d string def\n", width * components);
  672 gamgi_io_file_fprintf (fp, string, error);
  673 sprintf (string, "%d %d scale\n", width, height);
  674 gamgi_io_file_fprintf (fp, string, error);
  675 sprintf (string, "%d %d %d\n", width, height, 8);
  676 gamgi_io_file_fprintf (fp, string, error);
  677 sprintf (string, "[%d 0 0 %d 0 0]\n", width, height);
  678 gamgi_io_file_fprintf (fp, string, error);
  679 gamgi_io_file_fprintf (fp, "{currentfile scanline readhexstring pop}\n", error);
  680 sprintf (string, "false %d\n", components);
  681 gamgi_io_file_fprintf (fp, string, error);
  682 gamgi_io_file_fprintf (fp, "colorimage\n", error);
  683 
  684 /********************************************
  685  * Write data: adapted from the book OpenGL *
  686  * Programming for the X Window System p98, *
  687  * Mark J. Kilgard, Addison-Wesley, 1996.   *
  688  ********************************************/
  689 
  690 i = 0;
  691 while (i < width * height * components)
  692   {
  693   sprintf (string, "%02x", pixels[i++]);
  694   gamgi_io_file_fprintf (fp, string, error);
  695   if (i % 40 == 0) gamgi_io_file_fprintf (fp, "\n", error);
  696   }
  697 if (i % 40 != 0) gamgi_io_file_fprintf (fp, "\n", error);
  698 
  699 /*******************************************
  700  * show postscript page and free resources *
  701  *******************************************/
  702  
  703 gamgi_io_file_fprintf (fp, "showpage\n", error);
  704 free (pixels);
  705 
  706 return TRUE;
  707 }
  708 
  709 gamgi_bool gamgi_io_file_export_ppm (FILE *fp,
  710 int width, int height, gamgi_bool *error)
  711 {
  712 unsigned char *pixels;
  713 char string[GAMGI_ENGINE_LINE];
  714 int i, components, maximum, offset;
  715 
  716 /***************************************************************
  717  * grab data: assume a maximum depth of 8 bits per rgb channel *
  718  * so each color component can take values between 0 and 255   *
  719  ***************************************************************/
  720 
  721 components = 3;
  722 pixels = gamgi_mesa_area_read (0, 0, width, height);
  723 maximum = GAMGI_IO_PPM_MAX;
  724 
  725 /****************
  726  * write header *
  727  ****************/
  728 
  729 gamgi_io_file_fprintf (fp, "P3\n", error);
  730 
  731 sprintf (string, "#Made with GAMGI %s\n", GAMGI_IO_VERSION);
  732 gamgi_io_file_fprintf (fp, string, error);
  733 
  734 sprintf (string, "%d %d\n%d\n", width, height, maximum);
  735 gamgi_io_file_fprintf (fp, string, error);
  736 
  737 /**********************************************
  738  * write data: from end to start, because ppm *
  739  * formats read data from top to bottom while *
  740  * OpenGL array grabs data from bottom to top *
  741  **********************************************/
  742 
  743 while (height-- > 0)
  744   {
  745   offset = components * width * height;
  746   for (i = 0; i < width; i++)
  747     {
  748     sprintf (string, "%d %d %d ",
  749     pixels[offset + 0], pixels[offset + 1], pixels[offset + 2]);
  750     gamgi_io_file_fprintf (fp, string, error);
  751     offset += components;
  752     }
  753   gamgi_io_file_fprintf (fp, "\n", error);
  754   }
  755 
  756 /******************
  757  * free resources *
  758  ******************/
  759 
  760 free (pixels);
  761 
  762 return TRUE;
  763 }
  764 
  765 gamgi_bool gamgi_io_file_export_png (char *fullname,
  766 FILE *fp, int width, int height, gamgi_bool *error)
  767 {
  768 char auxname[2 * GAMGI_ENGINE_TOKEN];
  769 char command[2 * GAMGI_ENGINE_LINE];
  770 
  771 /**********************************
  772  * 1) create fullname ppm file    *
  773  * 2) convert to auxname png file *
  774  * (with special name, to avoid   *
  775  * destroying a user's file!)     *
  776  * 3) move auxname to fullname    *
  777  **********************************/
  778 
  779 gamgi_io_file_export_ppm (fp, width, height, error);
  780 if (*error != 0) return FALSE;
  781 
  782 sprintf (auxname, "gamgi%d", getpid ());
  783 
  784 sprintf (command, "(%s %s >%s; mv -f %s %s) &",
  785 GAMGI_IO_PNMTOPNG, fullname, auxname, auxname, fullname);
  786 system (command);
  787 
  788 return TRUE;
  789 }
  790 
  791 gamgi_bool gamgi_io_file_export_jpeg (char *fullname,
  792 FILE *fp, int width, int height, gamgi_bool *error)
  793 {
  794 char auxname[2 * GAMGI_ENGINE_TOKEN];
  795 char command[2 * GAMGI_ENGINE_LINE];
  796 
  797 /**********************************
  798  * 1) create fullname ppm file    *
  799  * 2) convert to auxname png file *
  800  * (with special name, to avoid   *
  801  * destroying a user's file!)     *
  802  * 3) move auxname to fullname    *
  803  **********************************/
  804 
  805 gamgi_io_file_export_ppm (fp, width, height, error);
  806 if (*error != 0) return FALSE;
  807 
  808 sprintf (auxname, "gamgi%d", getpid ());
  809 
  810 sprintf (command, "(%s %s >%s; mv -f %s %s) &",
  811 GAMGI_IO_PNMTOJPEG, fullname, auxname, auxname, fullname);
  812 system (command);
  813 
  814 return TRUE;
  815 }
  816 
  817 gamgi_bool gamgi_io_file_export_tiff (char *fullname,
  818 FILE *fp, int width, int height, gamgi_bool *error)
  819 {
  820 char auxname[2 * GAMGI_ENGINE_TOKEN];
  821 char command[2 * GAMGI_ENGINE_LINE];
  822 
  823 /**********************************
  824  * 1) create fullname ppm file    *
  825  * 2) convert to auxname png file *
  826  * (with special name, to avoid   *
  827  * destroying a user's file!)     *
  828  * 3) move auxname to fullname    *
  829  **********************************/
  830 
  831 gamgi_io_file_export_ppm (fp, width, height, error);
  832 if (*error != 0) return FALSE;
  833 
  834 sprintf (auxname, "gamgi%d", getpid ());
  835 
  836 sprintf (command, "(%s -color %s >%s; mv -f %s %s) &",
  837 GAMGI_IO_PNMTOTIFF, fullname, auxname, auxname, fullname);
  838 system (command);
  839 
  840 return TRUE;
  841 }
  842 
  843 gamgi_bool gamgi_io_file_read (char *fullname, gamgi_window *window)
  844 {
  845 char *extension;
  846 
  847 /**********************
  848  * get file extension *
  849  **********************/
  850 
  851 extension = gamgi_io_file_extension (fullname);
  852 
  853 /*******************************
  854  * read according to extension *
  855  *******************************/
  856 
  857 if (extension == NULL)
  858   return gamgi_expat_import_gml (fullname, window);
  859 if (strcmp (extension, "xyz") == 0)
  860   return gamgi_io_xyz_import (fullname, window);
  861 return gamgi_expat_import_gml (fullname, window);
  862 }
  863 
  864 gamgi_bool gamgi_io_file_shell (int argc,
  865 char **argv, gamgi_window *window)
  866 {
  867 int i;
  868 
  869 /***************************
  870  * load command line files *
  871  *                         *
  872  * if an error is found:   *
  873  * 1) ignore wrong file;   *
  874  * 2) show error message;  *
  875  * 3) ignore next files;   *
  876  ***************************/
  877 
  878 for (i = 1; i < argc; i++)
  879   {
  880   if (gamgi_io_file_read (argv[i], window) == FALSE) return FALSE;
  881   }
  882 
  883 return TRUE;
  884 }
  885 
  886 gamgi_bool gamgi_io_file_write (char *fullname, gamgi_window *window)
  887 {
  888 gamgi_bool error = FALSE;
  889 GtkAllocation allocation;
  890 FILE *fp;
  891 char *shortname;
  892 char *extension;
  893 int width, height;
  894 
  895 /************************************************
  896  * discard the pathname, keep only the filename *
  897  ************************************************/
  898 
  899 shortname = gamgi_io_file_shortname (fullname);
  900 
  901 /*******************************
  902  * open file in overwrite mode *
  903  *******************************/
  904 
  905 fp = fopen (fullname, "w");
  906 if (fp == NULL)
  907   {
  908   gamgi_io_error_write (shortname, window);
  909   return FALSE;
  910   }
  911 
  912 /**********************
  913  * get file extension *
  914  **********************/
  915 
  916 extension = gamgi_io_file_extension (fullname);
  917 
  918 /*******************************************************
  919  * write according to extension: when the extension is *
  920  * nonexistent or unrecognized export a GAMGI xml file *
  921  *******************************************************/
  922 
  923 gtk_widget_get_allocation (window->area, &allocation);
  924 width = allocation.width;
  925 height = allocation.height;
  926 
  927 if (extension == NULL)
  928   gamgi_expat_export_gml (fp, window, &error);
  929 else if (strcmp (extension, "jpeg") == 0 || strcmp (extension, "jpg") == 0)
  930   gamgi_io_file_export_jpeg (fullname, fp, width, height, &error);
  931 else if (strcmp (extension, "png") == 0)
  932   gamgi_io_file_export_png (fullname, fp, width, height, &error);
  933 else if (strcmp (extension, "eps") == 0 || strcmp (extension, "ps") == 0)
  934   gamgi_io_file_export_ps (fp, width, height, &error);
  935 else if (strcmp (extension, "ppm") == 0)
  936   gamgi_io_file_export_ppm (fp, width, height, &error);
  937 else if (strcmp (extension, "tiff") == 0 || strcmp (extension, "tif") == 0)
  938   gamgi_io_file_export_tiff (fullname, fp, width, height, &error);
  939 else if (strcmp (extension, "x3d") == 0)
  940   gamgi_expat_export_x3d (fp, window, &error);
  941 else if (strcmp (extension, "xyz") == 0)
  942   gamgi_io_xyz_export (fp, window, &error);
  943 else
  944   gamgi_expat_export_gml (fp, window, &error);
  945 
  946 /**************
  947  * close file *
  948  **************/
  949 
  950 fclose (fp);
  951 
  952 /******************************************
  953  * in the end, check if an error occurred *
  954  * during writing to file (disk full?)    *
  955  ******************************************/
  956 
  957 if (error == TRUE)
  958   {
  959   gamgi_io_error_write (shortname, window);
  960   return FALSE;
  961   }
  962 
  963 return TRUE;
  964 }
  965 
  966 void gamgi_io_file_overwrite (char *filename, 
  967 gamgi_callback2 function, gamgi_window *window)
  968 {
  969 char string[GAMGI_ENGINE_LINE];
  970 char *shortname;
  971 FILE *fp;
  972 
  973 /************************************************
  974  * discard the pathname, keep only the filename *
  975  ************************************************/
  976 
  977 shortname = gamgi_io_file_shortname (filename);
  978 
  979 /*****************************
  980  * open file in append mode, *
  981  * to check file existence   *
  982  *****************************/
  983 
  984 fp = fopen (filename, "a+");
  985 if (fp == NULL)
  986   { gamgi_io_error_write (shortname, window); 
  987     return; }
  988 
  989 /*******************
  990  * overwrite file? *
  991  *******************/
  992 
  993 fseek(fp, 0, SEEK_SET);
  994 fgetc(fp);
  995 if (feof(fp) == 0)
  996   { fclose (fp);
  997     sprintf (string, "Overwrite file \"%s\"?", shortname);
  998     gamgi_gtk_dialog_question_create ("Warning", string, function, window);
  999     return; }
 1000 
 1001 /*****************************
 1002  * close file in append mode *
 1003  *****************************/
 1004 
 1005 fclose (fp);
 1006 (*function) (NULL, window);
 1007 }