home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2002 April / pcpro0402.iso / essentials / graphics / Gimp / gimp-src-20001226.exe / src / gimp / plug-ins / gap / gap_lib.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-12-20  |  84.6 KB  |  2,963 lines

  1. /* gap_lib.c
  2.  * 1997.11.18 hof (Wolfgang Hofer)
  3.  *
  4.  * GAP ... Gimp Animation Plugins
  5.  *
  6.  * basic anim functions:
  7.  *   Delete, Duplicate, Exchange, Shift 
  8.  *   Next, Prev, First, Last, Goto
  9.  * 
  10.  *
  11.  */
  12. /* The GIMP -- an image manipulation program
  13.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  14.  *
  15.  * This program is free software; you can redistribute it and/or modify
  16.  * it under the terms of the GNU General Public License as published by
  17.  * the Free Software Foundation; either version 2 of the License, or
  18.  * (at your option) any later version.
  19.  *
  20.  * This program is distributed in the hope that it will be useful,
  21.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  22.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23.  * GNU General Public License for more details.
  24.  *
  25.  * You should have received a copy of the GNU General Public License
  26.  * along with this program; if not, write to the Free Software
  27.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  28.  */
  29.  
  30. /* revision history:
  31.  * 1.1.29a; 2000/11/23   hof: gap locking (changed to procedures and placed here)
  32.  * 1.1.28a; 2000/11/05   hof: check for GIMP_PDB_SUCCESS (not for FALSE)
  33.  * 1.1.20a; 2000/04/25   hof: new: p_get_video_paste_name p_vid_edit_clear
  34.  * 1.1.17b; 2000/02/27   hof: bug/style fixes
  35.  * 1.1.14a; 1999/12/18   hof: handle .xvpics on fileops (copy, rename and delete)
  36.  *                            new: p_get_frame_nr,
  37.  * 1.1.9a;  1999/09/14   hof: handle frame filenames with framenumbers
  38.  *                            that are not the 4digit style. (like frame1.xcf)
  39.  * 1.1.8a;  1999/08/31   hof: for AnimFrame Filtypes != XCF:
  40.  *                            p_decide_save_as does save INTERACTIVE at 1.st time
  41.  *                            and uses GIMP_RUN_WITH_LAST_VALS for subsequent calls
  42.  *                            (this enables to set Fileformat specific save-Parameters
  43.  *                            at least at the 1.st call, using the save dialog
  44.  *                            of the selected (by gimp_file_save) file_save procedure.
  45.  *                            in NONINTERACTIVE mode we have no access to
  46.  *                            the Fileformat specific save-Parameters
  47.  *          1999/07/22   hof: accept anim framenames without underscore '_'
  48.  *                            (suggested by Samuel Meder)
  49.  * 0.99.00; 1999/03/15   hof: prepared for win/dos filename conventions
  50.  * 0.98.00; 1998/11/30   hof: started Port to GIMP 1.1:
  51.  *                               exchange of Images (by next frame) is now handled in the
  52.  *                               new module: gap_exchange_image.c
  53.  * 0.96.02; 1998/07/30   hof: extended gap_dup (duplicate range instead of singele frame)
  54.  *                            added gap_shift
  55.  * 0.96.00               hof: - now using gap_arr_dialog.h
  56.  * 0.95.00               hof:  increased duplicate frames limit from 50 to 99
  57.  * 0.93.01               hof: fixup bug when frames are not in the current directory
  58.  * 0.90.00;              hof: 1.st (pre) release
  59.  */
  60. #include "config.h"
  61.  
  62. /* SYSTEM (UNIX) includes */ 
  63. #include <stdio.h>
  64. #include <stdlib.h>
  65. #include <time.h>
  66. #include <string.h>
  67. #include <signal.h>           /* for kill */
  68. #ifdef HAVE_SYS_TIMES_H
  69. #include <sys/times.h>
  70. #endif
  71. #include <sys/types.h>
  72. #include <sys/stat.h>
  73. #include <errno.h>
  74. #ifdef HAVE_UNISTD_H
  75. #include <unistd.h>
  76. #endif
  77. #ifdef HAVE_DIRENT_H
  78. #include <dirent.h>
  79. #endif
  80.  
  81. /* GIMP includes */
  82. #include "gtk/gtk.h"
  83. #include "libgimp/stdplugins-intl.h"
  84. #include "libgimp/gimp.h"
  85.  
  86. #ifdef G_OS_WIN32
  87. #include <io.h>
  88. #  ifndef S_ISDIR
  89. #    define S_ISDIR(m) ((m) & _S_IFDIR)
  90. #  endif
  91. #  ifndef S_ISREG
  92. #    define S_ISREG(m) ((m) & _S_IFREG)
  93. #  endif
  94. #endif
  95.  
  96. #ifdef G_OS_WIN32
  97. #include <direct.h>        /* For _mkdir() */
  98. #define mkdir(path,mode) _mkdir(path)
  99. #endif
  100.  
  101. #ifdef G_OS_WIN32
  102. #include <process.h>        /* For _getpid() */
  103. #endif
  104.  
  105. /* GAP includes */
  106. #include "gap_layer_copy.h"
  107. #include "gap_lib.h"
  108. #include "gap_pdb_calls.h"
  109. #include "gap_arr_dialog.h"
  110. #include "gap_exchange_image.h"
  111.  
  112. extern      int gap_debug; /* ==0  ... dont print debug infos */
  113.  
  114. /* ------------------------------------------ */
  115. /* forward  working procedures */
  116. /* ------------------------------------------ */
  117.  
  118. static int          p_save_old_frame(t_anim_info *ainfo_ptr);
  119.  
  120. static int   p_rename_frame(t_anim_info *ainfo_ptr, long from_nr, long to_nr);
  121. static int   p_delete_frame(t_anim_info *ainfo_ptr, long nr);
  122. static int   p_del(t_anim_info *ainfo_ptr, long cnt);
  123. static int   p_decide_save_as(gint32 image_id, char *sav_name);
  124.  
  125. /* ============================================================================
  126.  * p_alloc_fname_thumbnail
  127.  *   return the thumbnail name (in .xvpics subdir)
  128.  *   for the given filename
  129.  * ============================================================================
  130.  */
  131. char *
  132. p_alloc_fname_thumbnail(char *name)
  133. {
  134.   int   l_len;
  135.   int   l_len2;
  136.   int   l_idx;
  137.   char *l_str;
  138.   
  139.   if(name == NULL)
  140.   {
  141.     return(g_strdup("\0"));
  142.   }
  143.  
  144.   l_len = strlen(name);
  145.   l_len2 = l_len + 10;
  146.   l_str = g_malloc(l_len2);
  147.   strcpy(l_str, name);
  148.   if(l_len > 0)
  149.   {
  150.      for(l_idx = l_len -1; l_idx > 0; l_idx--)
  151.      {
  152.         if((name[l_idx] == G_DIR_SEPARATOR) || (name[l_idx] == DIR_ROOT))
  153.     {
  154.        l_idx++;
  155.        break;
  156.     }
  157.      }
  158.      g_snprintf(&l_str[l_idx], l_len2 - l_idx, ".xvpics%s%s", G_DIR_SEPARATOR_S, &name[l_idx]);      
  159.   }
  160.   if(gap_debug) printf("p_alloc_fname_thumbnail: thumbname=%s:\n", l_str );
  161.   return(l_str);
  162. }
  163.  
  164. /* ============================================================================
  165.  * p_strdup_*_underscore
  166.  *   duplicate string and if last char is no underscore add one at end.
  167.  *   duplicate string and delete last char if it is the underscore
  168.  * ============================================================================
  169.  */
  170. char *
  171. p_strdup_add_underscore(char *name)
  172. {
  173.   int   l_len;
  174.   char *l_str;
  175.   if(name == NULL)
  176.   {
  177.     return(g_strdup("\0"));
  178.   }
  179.  
  180.   l_len = strlen(name);
  181.   l_str = g_malloc(l_len+1);
  182.   strcpy(l_str, name);
  183.   if(l_len > 0)
  184.   {
  185.     if (name[l_len-1] != '_')
  186.     {
  187.        l_str[l_len    ] = '_';
  188.        l_str[l_len +1 ] = '\0';
  189.     }
  190.       
  191.   }
  192.   return(l_str);
  193. }
  194.  
  195. char *
  196. p_strdup_del_underscore(char *name)
  197. {
  198.   int   l_len;
  199.   char *l_str;
  200.   if(name == NULL)
  201.   {
  202.     return(g_strdup("\0"));
  203.   }
  204.  
  205.   l_len = strlen(name);
  206.   l_str = g_strdup(name);
  207.   if(l_len > 0)
  208.   {
  209.     if (l_str[l_len-1] == '_')
  210.     {
  211.        l_str[l_len -1 ] = '\0';
  212.     }
  213.       
  214.   }
  215.   return(l_str);
  216. }
  217.  
  218. /* ============================================================================
  219.  * p_msg_win
  220.  *   print a message both to stderr
  221.  *   and to a gimp info window with OK button (only when run INTERACTIVE)
  222.  * ============================================================================
  223.  */
  224.  
  225. void p_msg_win(GimpRunModeType run_mode, char *msg)
  226. {
  227.   static t_but_arg  l_argv[1];
  228.   int               l_argc;  
  229.   
  230.   l_argv[0].but_txt  = _("OK");
  231.   l_argv[0].but_val  = 0;
  232.   l_argc             = 1;
  233.  
  234.   if(msg)
  235.   {
  236.     if(*msg)
  237.     {
  238.        fwrite(msg, 1, strlen(msg), stderr);
  239.        fputc('\n', stderr);
  240.  
  241.        if(run_mode == GIMP_RUN_INTERACTIVE) p_buttons_dialog  (_("GAP Message"), msg, l_argc, l_argv, -1);
  242.     }
  243.   }
  244. }    /* end  p_msg_win */
  245.  
  246. /* ============================================================================
  247.  * p_file_exists
  248.  *
  249.  * return 0  ... file does not exist, or is not accessable by user,
  250.  *               or is empty,
  251.  *               or is not a regular file
  252.  *        1  ... file exists
  253.  * ============================================================================
  254.  */
  255. int p_file_exists(char *fname)
  256. {
  257.   struct stat  l_stat_buf;
  258.   long         l_len;
  259.  
  260.   /* File Laenge ermitteln */
  261.   if (0 != stat(fname, &l_stat_buf))
  262.   {
  263.     /* stat error (file does not exist) */
  264.     return(0);
  265.   }
  266.   
  267.   if(!S_ISREG(l_stat_buf.st_mode))
  268.   {
  269.     return(0);
  270.   }
  271.   
  272.   l_len = (long)l_stat_buf.st_size;
  273.   if(l_len < 1)
  274.   {
  275.     /* File is empty*/
  276.     return(0);
  277.   }
  278.   
  279.   return(1);
  280. }    /* end p_file_exists */
  281.  
  282. /* ============================================================================
  283.  * p_image_file_copy
  284.  *    (copy the imagefile and its thumbnail)
  285.  * ============================================================================
  286.  */
  287. int p_image_file_copy(char *fname, char *fname_copy)
  288. {
  289.    char          *l_from_fname_thumbnail;
  290.    char          *l_to_fname_thumbnail;
  291.    int            l_rc;
  292.  
  293.    l_from_fname_thumbnail = p_alloc_fname_thumbnail(fname);
  294.    l_to_fname_thumbnail = p_alloc_fname_thumbnail(fname_copy);
  295.    
  296.    l_rc = p_file_copy(fname, fname_copy);
  297.    if((l_from_fname_thumbnail) 
  298.    && (l_to_fname_thumbnail))
  299.    {
  300.      p_file_copy(l_from_fname_thumbnail, l_to_fname_thumbnail);
  301.    }
  302.    
  303.    if(l_from_fname_thumbnail) g_free(l_from_fname_thumbnail);
  304.    if(l_to_fname_thumbnail) g_free(l_to_fname_thumbnail);
  305.    return(l_rc);
  306. }
  307.  
  308. /* ============================================================================
  309.  * p_file_copy
  310.  * ============================================================================
  311.  */
  312. int p_file_copy(char *fname, char *fname_copy)
  313. {
  314.   FILE          *l_fp;
  315.   char                     *l_buffer;
  316.   struct stat               l_stat_buf;
  317.   long           l_len;
  318.  
  319.  
  320.   if(gap_debug) printf("p_file_copy src:%s dst:%s\n", fname, fname_copy);
  321.  
  322.   /* File Laenge ermitteln */
  323.   if (0 != stat(fname, &l_stat_buf))
  324.   {
  325.     fprintf (stderr, "stat error on '%s'\n", fname);
  326.     return -1;
  327.   }
  328.   l_len = (long)l_stat_buf.st_size;
  329.  
  330.   /* Buffer allocate */
  331.   l_buffer=(char *)g_malloc0((size_t)l_len+1);
  332.   if(l_buffer == NULL)
  333.   {
  334.     fprintf(stderr, "file_copy: calloc error (%ld Bytes not available)\n", l_len);
  335.     return -1;
  336.   }
  337.  
  338.   /* load File into Buffer */
  339.   l_fp = fopen(fname, "r");            /* open read */
  340.   if(l_fp == NULL)
  341.   {
  342.     fprintf (stderr, "open(read) error on '%s'\n", fname);
  343.     g_free(l_buffer);
  344.     return -1;
  345.   }
  346.   fread(l_buffer, 1, (size_t)l_len, l_fp);
  347.   fclose(l_fp);
  348.   
  349.   l_fp = fopen(fname_copy, "w");            /* open write */
  350.   if(l_fp == NULL)
  351.   {
  352.     fprintf (stderr, "file_copy: open(write) error on '%s' \n", fname_copy);
  353.     g_free(l_buffer);
  354.     return -1;
  355.   }
  356.  
  357.   if(l_len > 0)
  358.   {
  359.      fwrite(l_buffer,  l_len, 1, l_fp);
  360.   }
  361.  
  362.   fclose(l_fp);
  363.   g_free(l_buffer);
  364.   return 0;           /* all done OK */
  365. }    /* end p_file_copy */
  366.  
  367.  
  368. /* ============================================================================
  369.  * p_delete_frame
  370.  * ============================================================================
  371.  */
  372. int p_delete_frame(t_anim_info *ainfo_ptr, long nr)
  373. {
  374.    char          *l_fname;
  375.    char          *l_fname_thumbnail;
  376.    int            l_rc;
  377.    
  378.    l_fname = p_alloc_fname(ainfo_ptr->basename, nr, ainfo_ptr->extension);
  379.    if(l_fname == NULL) { return(1); }
  380.  
  381.    l_fname_thumbnail = p_alloc_fname_thumbnail(l_fname);
  382.    if(l_fname_thumbnail == NULL) { return(1); }
  383.      
  384.    if(gap_debug) fprintf(stderr, "\nDEBUG p_delete_frame: %s\n", l_fname);
  385.    l_rc = remove(l_fname);
  386.      
  387.    if(gap_debug) fprintf(stderr, "\nDEBUG p_delete_frame: %s\n", l_fname_thumbnail);
  388.    remove(l_fname_thumbnail);
  389.    
  390.    g_free(l_fname);
  391.    g_free(l_fname_thumbnail);
  392.    
  393.    return(l_rc);
  394.    
  395. }    /* end p_delete_frame */
  396.  
  397. /* ============================================================================
  398.  * p_rename_frame
  399.  * ============================================================================
  400.  */
  401. int p_rename_frame(t_anim_info *ainfo_ptr, long from_nr, long to_nr)
  402. {
  403.    char          *l_from_fname;
  404.    char          *l_to_fname;
  405.    char          *l_from_fname_thumbnail;
  406.    char          *l_to_fname_thumbnail;
  407.    int            l_rc;
  408.    
  409.    l_from_fname = p_alloc_fname(ainfo_ptr->basename, from_nr, ainfo_ptr->extension);
  410.    if(l_from_fname == NULL) { return(1); }
  411.    
  412.    l_to_fname = p_alloc_fname(ainfo_ptr->basename, to_nr, ainfo_ptr->extension);
  413.    if(l_to_fname == NULL) { g_free(l_from_fname); return(1); }
  414.    
  415.    l_from_fname_thumbnail = p_alloc_fname_thumbnail(l_from_fname);
  416.    if(l_from_fname_thumbnail == NULL) { return(1); }
  417.    
  418.    l_to_fname_thumbnail = p_alloc_fname_thumbnail(l_to_fname);
  419.    if(l_to_fname_thumbnail == NULL) { g_free(l_from_fname_thumbnail); return(1); }
  420.    
  421.      
  422.    if(gap_debug) fprintf(stderr, "\nDEBUG p_rename_frame: %s ..to.. %s\n", l_from_fname, l_to_fname);
  423.    l_rc = rename(l_from_fname, l_to_fname);
  424.    if(gap_debug) fprintf(stderr, "\nDEBUG p_rename_frame: %s ..to.. %s\n", l_from_fname_thumbnail, l_to_fname_thumbnail);
  425.    rename(l_from_fname_thumbnail, l_to_fname_thumbnail);
  426.    
  427.    g_free(l_from_fname);
  428.    g_free(l_to_fname);
  429.    g_free(l_from_fname_thumbnail);
  430.    g_free(l_to_fname_thumbnail);
  431.    
  432.    return(l_rc);
  433.    
  434. }    /* end p_rename_frame */
  435.  
  436.  
  437. /* ============================================================================
  438.  * p_alloc_basename
  439.  *
  440.  * build the basename from an images name
  441.  * Extension and trailing digits ("0000.xcf") are cut off.
  442.  * return name or NULL (if malloc fails)
  443.  * Output: number contains the integer representation of the stripped off
  444.  *         number String. (or 0 if there was none)
  445.  * ============================================================================
  446.  */
  447. char*  p_alloc_basename(char *imagename, long *number)
  448. {
  449.   char *l_fname;
  450.   char *l_ptr;
  451.   long  l_idx;
  452.  
  453.   *number = 0;
  454.   if(imagename == NULL) return (NULL);
  455.   l_fname = (char *)g_malloc(strlen(imagename) + 1);
  456.   if(l_fname == NULL)   return (NULL);
  457.  
  458.   /* copy from imagename */
  459.   strcpy(l_fname, imagename);
  460.  
  461.   if(gap_debug) fprintf(stderr, "DEBUG p_alloc_basename  source: '%s'\n", l_fname);
  462.   /* cut off extension */
  463.   l_ptr = &l_fname[strlen(l_fname)];
  464.   while(l_ptr != l_fname)
  465.   {
  466.     if((*l_ptr == G_DIR_SEPARATOR) || (*l_ptr == DIR_ROOT))  { break; }  /* dont run into dir part */
  467.     if(*l_ptr == '.')                                        { *l_ptr = '\0'; break; }
  468.     l_ptr--;
  469.   }
  470.   if(gap_debug) fprintf(stderr, "DEBUG p_alloc_basename (ext_off): '%s'\n", l_fname);
  471.  
  472.   /* cut off trailing digits (0000) */
  473.   l_ptr = &l_fname[strlen(l_fname)];
  474.   if(l_ptr != l_fname) l_ptr--;
  475.   l_idx = 1;
  476.   while(l_ptr != l_fname)
  477.   {
  478.     if((*l_ptr >= '0') && (*l_ptr <= '9'))
  479.     { 
  480.       *number += ((*l_ptr - '0') * l_idx);
  481.        l_idx = l_idx * 10;
  482.       *l_ptr = '\0'; 
  483.        l_ptr--; 
  484.     }
  485.     else
  486.     {
  487.       /* do not cut off underscore any longer */
  488.       /*
  489.        * if(*l_ptr == '_')
  490.        * { 
  491.        *    *l_ptr = '\0';
  492.        * }
  493.        */
  494.        break;
  495.     }
  496.   }
  497.   
  498.   if(gap_debug) fprintf(stderr, "DEBUG p_alloc_basename  result:'%s'\n", l_fname);
  499.  
  500.   return(l_fname);
  501.    
  502. }    /* end p_alloc_basename */
  503.  
  504.  
  505.  
  506. /* ============================================================================
  507.  * p_alloc_extension
  508.  *
  509.  * input: a filename
  510.  * returns: a copy of the filename extension (incl "." )
  511.  *          if the filename has no extension, a pointer to
  512.  *          an empty string is returned ("\0")
  513.  *          NULL if allocate mem for extension failed.
  514.  * ============================================================================
  515.  */
  516. char*  p_alloc_extension(char *imagename)
  517. {
  518.   int   l_exlen;
  519.   char *l_ext;
  520.   char *l_ptr;
  521.   
  522.   l_exlen = 0;
  523.   l_ptr = &imagename[strlen(imagename)];
  524.   while(l_ptr != imagename)
  525.   {
  526.     if((*l_ptr == G_DIR_SEPARATOR) || (*l_ptr == DIR_ROOT))  { break; }     /* dont run into dir part */
  527.     if(*l_ptr == '.')                                        { l_exlen = strlen(l_ptr); break; }
  528.     l_ptr--;
  529.   }
  530.   
  531.   l_ext = g_malloc0((size_t)(l_exlen + 1));
  532.   if(l_ext == NULL)
  533.       return (NULL);
  534.   
  535.   
  536.   if(l_exlen > 0)
  537.      strcpy(l_ext, l_ptr);
  538.      
  539.   return(l_ext);
  540. }
  541.  
  542.  
  543. /* ============================================================================
  544.  * p_alloc_fname
  545.  *
  546.  * build the name of a frame using "basename_0000.ext"
  547.  * 
  548.  * return name or NULL (if malloc fails)
  549.  * ============================================================================
  550.  */
  551. char*  p_alloc_fname(char *basename, long nr, char *extension)
  552. {
  553.   gchar *l_fname;
  554.   gint   l_leading_zeroes;
  555.   gint   l_len;
  556.   long   l_nr_chk;
  557.   
  558.   if(basename == NULL) return (NULL);
  559.   l_len = (strlen(basename)  + strlen(extension) + 10);
  560.   l_fname = (char *)g_malloc(l_len);
  561.  
  562.     l_leading_zeroes = TRUE;
  563.     if(nr < 1000)
  564.     {
  565.        /* try to figure out if the frame numbers are in
  566.         * 4-digit style, with leading zeroes  "frame_0001.xcf"
  567.         * or not                              "frame_1.xcf"
  568.         */
  569.        l_nr_chk = nr;
  570.  
  571.        while(l_nr_chk >= 0)
  572.        {
  573.          /* check if frame is on disk with 4-digit style framenumber */
  574.          g_snprintf(l_fname, l_len, "%s%04ld%s", basename, l_nr_chk, extension);
  575.          if (p_file_exists(l_fname))
  576.          {
  577.             break;
  578.          }
  579.  
  580.          /* now check for filename without leading zeroes in the framenumber */
  581.          g_snprintf(l_fname, l_len, "%s%ld%s", basename, l_nr_chk, extension);
  582.          if (p_file_exists(l_fname))
  583.          {
  584.             l_leading_zeroes = FALSE;
  585.             break;
  586.          }
  587.          l_nr_chk--;
  588.          
  589.          /* if the frames nr and nr-1  were not found
  590.           * try to check frames 1 and 0
  591.           * to limit down the loop to max 4 cycles
  592.           */
  593.          if((l_nr_chk == nr -2) && (l_nr_chk > 1))
  594.          {
  595.            l_nr_chk = 1;
  596.          }
  597.       }
  598.     }
  599.     else
  600.     {
  601.       l_leading_zeroes = FALSE;
  602.     }
  603.  
  604.   g_free(l_fname);
  605.  
  606.   if(l_leading_zeroes) l_fname = g_strdup_printf("%s%04ld%s", basename, nr, extension);
  607.   else                 l_fname = g_strdup_printf("%s%ld%s", basename, nr, extension);
  608.  
  609.   return(l_fname);
  610. }    /* end p_alloc_fname */
  611.  
  612.  
  613.  
  614.  
  615. /* ============================================================================
  616.  * p_alloc_ainfo
  617.  *
  618.  * allocate and init an ainfo structure from the given image.
  619.  * ============================================================================
  620.  */
  621. t_anim_info *p_alloc_ainfo(gint32 image_id, GimpRunModeType run_mode)
  622. {
  623.    t_anim_info   *l_ainfo_ptr;
  624.  
  625.    l_ainfo_ptr = (t_anim_info*)g_malloc(sizeof(t_anim_info));
  626.    if(l_ainfo_ptr == NULL) return(NULL);
  627.    
  628.    l_ainfo_ptr->basename = NULL;
  629.    l_ainfo_ptr->new_filename = NULL;
  630.    l_ainfo_ptr->extension = NULL;
  631.    l_ainfo_ptr->image_id = image_id;
  632.  
  633.    /* get current gimp images name  */   
  634.    l_ainfo_ptr->old_filename = gimp_image_get_filename(image_id);
  635.    if(l_ainfo_ptr->old_filename == NULL)
  636.    {
  637.      l_ainfo_ptr->old_filename = g_strdup("frame_0001.xcf");    /* assign a defaultname */
  638.      gimp_image_set_filename (image_id, l_ainfo_ptr->old_filename);
  639.    }
  640.  
  641.    l_ainfo_ptr->basename = p_alloc_basename(l_ainfo_ptr->old_filename, &l_ainfo_ptr->frame_nr);
  642.    if(NULL == l_ainfo_ptr->basename)
  643.    {
  644.        p_free_ainfo(&l_ainfo_ptr);
  645.        return(NULL);
  646.    }
  647.  
  648.    l_ainfo_ptr->extension = p_alloc_extension(l_ainfo_ptr->old_filename);
  649.  
  650.    l_ainfo_ptr->curr_frame_nr = l_ainfo_ptr->frame_nr;
  651.    l_ainfo_ptr->first_frame_nr = -1;
  652.    l_ainfo_ptr->last_frame_nr = -1;
  653.    l_ainfo_ptr->frame_cnt = 0;
  654.    l_ainfo_ptr->run_mode = run_mode;
  655.  
  656.  
  657.    return(l_ainfo_ptr);
  658.  
  659.  
  660. }    /* end p_init_ainfo */
  661.  
  662. /* ============================================================================
  663.  * p_dir_ainfo
  664.  *
  665.  * fill in more items into the given ainfo structure.
  666.  * - first_frame_nr
  667.  * - last_frame_nr
  668.  * - frame_cnt
  669.  *
  670.  * to get this information, the directory entries have to be checked
  671.  * ============================================================================
  672.  */
  673. int p_dir_ainfo(t_anim_info *ainfo_ptr)
  674. {
  675.    char          *l_dirname;
  676.    char          *l_dirname_ptr;
  677.    char          *l_ptr;
  678.    char          *l_exptr;
  679.    char          *l_dummy;
  680.    /* int            l_cmp_len;   */
  681.    DIR           *l_dirp;
  682.    struct dirent *l_dp;
  683.    long           l_nr;
  684.    long           l_maxnr;
  685.    long           l_minnr;
  686.    short          l_dirflag;
  687.    char           dirname_buff[1024];
  688.  
  689.    l_dirname = g_malloc(strlen(ainfo_ptr->basename) +1);
  690.    if(l_dirname == NULL)
  691.      return -1;
  692.  
  693.    ainfo_ptr->frame_cnt = 0;
  694.    l_dirp = NULL;
  695.    l_minnr = 99999999;
  696.    l_maxnr = 0;
  697.    strcpy(l_dirname, ainfo_ptr->basename);
  698.  
  699.    l_ptr = &l_dirname[strlen(l_dirname)];
  700.    while(l_ptr != l_dirname)
  701.    {
  702.       if ((*l_ptr == G_DIR_SEPARATOR) || (*l_ptr == DIR_ROOT))
  703.       { 
  704.         *l_ptr = '\0';   /* split the string into dirpath 0 basename */
  705.         l_ptr++;
  706.         break;           /* stop at char behind the slash */
  707.       }
  708.       l_ptr--;
  709.    }
  710.    /* l_cmp_len = strlen(l_ptr); */
  711.  
  712.    if(gap_debug) fprintf(stderr, "DEBUG p_dir_ainfo: BASENAME:%s\n", l_ptr);
  713.    
  714.    if      (l_ptr == l_dirname)   { l_dirname_ptr = ".";  l_dirflag = 0; }
  715.    else if (*l_dirname == '\0')   { l_dirname_ptr = G_DIR_SEPARATOR_S ; l_dirflag = 1; }
  716.    else                           { l_dirname_ptr = l_dirname; l_dirflag = 2; }
  717.  
  718.    if(gap_debug) fprintf(stderr, "DEBUG p_dir_ainfo: DIRNAME:%s\n", l_dirname_ptr);
  719.    l_dirp = opendir( l_dirname_ptr );  
  720.    
  721.    if(!l_dirp) fprintf(stderr, "ERROR p_dir_ainfo: can't read directory %s\n", l_dirname_ptr);
  722.    else
  723.    {
  724.      while ( (l_dp = readdir( l_dirp )) != NULL )
  725.      {
  726.  
  727.        /* if(gap_debug) fprintf(stderr, "DEBUG p_dir_ainfo: l_dp->d_name:%s\n", l_dp->d_name); */
  728.        
  729.        
  730.        /* findout extension of the directory entry name */
  731.        l_exptr = &l_dp->d_name[strlen(l_dp->d_name)];
  732.        while(l_exptr != l_dp->d_name)
  733.        {
  734.          if(*l_exptr == G_DIR_SEPARATOR) { break; }                 /* dont run into dir part */
  735.          if(*l_exptr == '.')       { break; }
  736.          l_exptr--;
  737.        }
  738.        /* l_exptr now points to the "." of the direntry (or to its begin if has no ext) */
  739.        /* now check for equal extension */
  740.        if((*l_exptr == '.') && (0 == strcmp(l_exptr, ainfo_ptr->extension)))
  741.        {
  742.          /* build full pathname (to check if file exists) */
  743.          switch(l_dirflag)
  744.          {
  745.            case 0:
  746.             g_snprintf(dirname_buff, sizeof(dirname_buff), "%s", l_dp->d_name);
  747.             break;
  748.            case 1:
  749.             g_snprintf(dirname_buff, sizeof(dirname_buff), "%c%s",  G_DIR_SEPARATOR, l_dp->d_name);
  750.             break;
  751.            default:
  752.             /* UNIX:  "/dir/file"
  753.              * DOS:   "drv:\dir\file"
  754.              */
  755.             g_snprintf(dirname_buff, sizeof(dirname_buff), "%s%c%s", l_dirname_ptr,  G_DIR_SEPARATOR,  l_dp->d_name);
  756.             break;
  757.          }
  758.          
  759.          if(1 == p_file_exists(dirname_buff)) /* check for regular file */
  760.          {
  761.            /* get basename and frame number of the directory entry */
  762.            l_dummy = p_alloc_basename(l_dp->d_name, &l_nr);
  763.            if(l_dummy != NULL)
  764.            { 
  765.                /* check for files, with equal basename (frames)
  766.                 * (length must be greater than basepart+extension
  767.                 * because of the frame_nr part "0000")
  768.                 */
  769.                if((0 == strcmp(l_ptr, l_dummy))
  770.                && ( strlen(l_dp->d_name) > strlen(l_dummy) + strlen(l_exptr)  ))
  771.                {
  772.                  ainfo_ptr->frame_cnt++;
  773.  
  774.  
  775.                  if(gap_debug) fprintf(stderr, "DEBUG p_dir_ainfo:  %s NR=%ld\n", l_dp->d_name, l_nr);
  776.  
  777.                  if (l_nr > l_maxnr)
  778.                     l_maxnr = l_nr;
  779.                  if (l_nr < l_minnr)
  780.                     l_minnr = l_nr;
  781.                }
  782.  
  783.                g_free(l_dummy);
  784.            }
  785.          }
  786.        }
  787.      }
  788.      closedir( l_dirp );
  789.    }
  790.  
  791.   g_free(l_dirname);
  792.  
  793.   /* set first_frame_nr and last_frame_nr (found as "_0099" in diskfile namepart) */
  794.   ainfo_ptr->last_frame_nr = l_maxnr;
  795.   ainfo_ptr->first_frame_nr = l_minnr;
  796.  
  797.   return 0;           /* OK */
  798. }    /* end p_dir_ainfo */
  799.  
  800.  
  801. /* ============================================================================
  802.  * p_free_ainfo
  803.  *
  804.  * free ainfo and its allocated stuff
  805.  * ============================================================================
  806.  */
  807.  
  808. void p_free_ainfo(t_anim_info **ainfo)
  809. {
  810.   t_anim_info *aptr;
  811.   
  812.   if((aptr = *ainfo) == NULL)
  813.      return;
  814.   
  815.   if(aptr->basename)
  816.      g_free(aptr->basename);
  817.   
  818.   if(aptr->extension)
  819.      g_free(aptr->extension);
  820.    
  821.   if(aptr->new_filename)
  822.      g_free(aptr->new_filename);
  823.  
  824.   if(aptr->old_filename)
  825.      g_free(aptr->old_filename);
  826.      
  827.   g_free(aptr);
  828. }
  829.  
  830.  
  831. /* ============================================================================
  832.  * p_get_frame_nr
  833.  * ============================================================================
  834.  */
  835. long
  836. p_get_frame_nr_from_name(char *fname)
  837. {
  838.   long number;
  839.   int  len;
  840.   char *basename;
  841.   if(fname == NULL) return(-1);
  842.   
  843.   basename = p_alloc_basename(fname, &number);
  844.   if(basename == NULL) return(-1);
  845.   
  846.   len = strlen(basename);
  847.   g_free(basename);
  848.   
  849.   if(number > 0)  return(number);
  850.  
  851.   if(fname[len]  == '0') return(number);
  852. /*
  853.  *   if(fname[len]  == '_')
  854.  *   {
  855.  *     if(fname[len+1]  == '0') return(TRUE);
  856.  *   }
  857.  */
  858.   return(-1);
  859. }
  860.  
  861. long
  862. p_get_frame_nr(gint32 image_id)
  863. {
  864.   char *fname;
  865.   long  number;
  866.   
  867.   number = -1;
  868.   fname = gimp_image_get_filename(image_id);
  869.   if(fname)
  870.   {
  871.      number = p_get_frame_nr_from_name(fname);
  872.      g_free(fname);
  873.   }
  874.   return (number);
  875. }
  876.  
  877. /* ============================================================================
  878.  * p_chk_framechange
  879.  *
  880.  * check if the current frame nr has changed. 
  881.  * useful after dialogs, because the user may have renamed the current image
  882.  * (using save as)
  883.  * while the gap-plugin's dialog was open.
  884.  * return: 0 .. OK
  885.  *        -1 .. Changed (or error occured)
  886.  * ============================================================================
  887.  */
  888. int p_chk_framechange(t_anim_info *ainfo_ptr)
  889. {
  890.   int l_rc;
  891.   t_anim_info *l_ainfo_ptr;
  892.  
  893.   l_rc = -1;
  894.   l_ainfo_ptr = p_alloc_ainfo(ainfo_ptr->image_id, ainfo_ptr->run_mode);
  895.   if(l_ainfo_ptr != NULL)
  896.   {
  897.     if(ainfo_ptr->curr_frame_nr == l_ainfo_ptr->curr_frame_nr )
  898.     { 
  899.        l_rc = 0;
  900.     }
  901.     else
  902.     {
  903.        p_msg_win(ainfo_ptr->run_mode,
  904.          _("OPERATION CANCELLED.\n"
  905.        "Current frame changed while dialog was open."));
  906.     }
  907.     p_free_ainfo(&l_ainfo_ptr);
  908.   }
  909.  
  910.   return l_rc;   
  911. }    /* end p_chk_framechange */
  912.  
  913. /* ============================================================================
  914.  * p_chk_framerange
  915.  *
  916.  * check ainfo struct if there is a framerange (of at least one frame)
  917.  * return: 0 .. OK
  918.  *        -1 .. No frames there (print error)
  919.  * ============================================================================
  920.  */
  921. int p_chk_framerange(t_anim_info *ainfo_ptr)
  922. {
  923.   if(ainfo_ptr->frame_cnt == 0)
  924.   {
  925.      p_msg_win(ainfo_ptr->run_mode,
  926.            _("OPERATION CANCELLED.\n"
  927.          "GAP-plugins works only with filenames\n"
  928.          "that end with _0001.xcf.\n"
  929.          "==> Rename your image, then try again."));
  930.      return -1;
  931.   }
  932.   return 0;
  933. }    /* end p_chk_framerange */
  934.  
  935. /* ============================================================================
  936.  * p_gzip
  937.  *   gzip or gunzip the file to a temporary file.
  938.  *   zip == "zip"    compress
  939.  *   zip == "unzip"  decompress
  940.  *   return a pointer to the temporary created (by gzip) file.
  941.  *          NULL  in case of errors
  942.  * ============================================================================
  943.  */
  944. char * p_gzip (char *orig_name, char *new_name, char *zip)
  945. {
  946.   gchar*   l_cmd;
  947.   gchar*   l_tmpname;
  948.   gint     l_rc, l_rc2;
  949.  
  950.   if(zip == NULL) return NULL;
  951.   
  952.   l_cmd = NULL;
  953.   l_tmpname = new_name;
  954.   
  955.   /* used gzip options:
  956.    *     -c --stdout --to-stdout
  957.    *          Write  output  on  standard  output
  958.    *     -d --decompress --uncompress
  959.    *          Decompress.
  960.    *     -f --force
  961.    *           Force compression or decompression even if the file
  962.    */
  963.  
  964.   if(*zip == 'u')
  965.   {
  966.     l_cmd = g_strdup_printf("gzip -cfd <\"%s\"  >\"%s\"", orig_name, l_tmpname);
  967.   }
  968.   else
  969.   {
  970.     l_cmd = g_strdup_printf("gzip -cf  <\"%s\"  >\"%s\"", orig_name, l_tmpname);
  971.   }
  972.  
  973.   if(gap_debug) fprintf(stderr, "system: %s\n", l_cmd);
  974.   
  975.   l_rc = system(l_cmd);
  976.   if(l_rc != 0)
  977.   {
  978.      /* Shift 8 Bits gets Retcode of the executed Program */
  979.      l_rc2 = l_rc >> 8;
  980.      fprintf(stderr, "ERROR system: %s\nreturncodes %d %d", l_cmd, l_rc, l_rc2);
  981.      l_tmpname = NULL;
  982.   }
  983.   g_free(l_cmd);
  984.   return l_tmpname;
  985.   
  986. }    /* end p_gzip */
  987.  
  988. /* ============================================================================
  989.  * p_decide_save_as
  990.  *   decide what to to, when attempt to save a frame in any image format 
  991.  *  (other than xcf)
  992.  *   Let the user decide if the frame is to save "as it is" or "flattened"
  993.  *   ("as it is" will save only the backround layer in most fileformat types)
  994.  *   The SAVE_AS_MODE is stored , and reused
  995.  *   (without displaying the dialog) on subsequent calls.
  996.  *
  997.  *   return -1  ... CANCEL (do not save)
  998.  *           0  ... save the image (may be flattened)
  999.  * ============================================================================
  1000.  */
  1001. int p_decide_save_as(gint32 image_id, char *sav_name)
  1002. {
  1003.   static char *l_msg;
  1004.  
  1005.  
  1006.   static char l_save_as_name[80];
  1007.   
  1008.   static t_but_arg  l_argv[3];
  1009.   int               l_argc;  
  1010.   int               l_save_as_mode;
  1011.   GimpRunModeType      l_run_mode;  
  1012.  
  1013.   l_msg = _("You are using a file format != xcf\n"
  1014.         "Save Operations may result\n"
  1015.         "in loss of layer information.");
  1016.   /* check if there are SAVE_AS_MODE settings (from privious calls within one gimp session) */
  1017.   l_save_as_mode = -1;
  1018.   /* g_snprintf(l_save_as_name, sizeof(l_save_as_name), "plug_in_gap_plugins_SAVE_AS_MODE_%d", (int)image_id);*/
  1019.   g_snprintf(l_save_as_name, sizeof(l_save_as_name), "plug_in_gap_plugins_SAVE_AS_MODE");
  1020.   gimp_get_data (l_save_as_name, &l_save_as_mode);
  1021.  
  1022.   if(l_save_as_mode == -1)
  1023.   {
  1024.     /* no defined value found (this is the 1.st call for this image_id)
  1025.      * ask what to do with a 3 Button dialog
  1026.      */
  1027.     l_argv[0].but_txt  = _("Cancel");
  1028.     l_argv[0].but_val  = -1;
  1029.     l_argv[1].but_txt  = _("Save Flattened");
  1030.     l_argv[1].but_val  = 1;
  1031.     l_argv[2].but_txt  = _("Save As Is");
  1032.     l_argv[2].but_val  = 0;
  1033.     l_argc             = 3;
  1034.  
  1035.     l_save_as_mode =  p_buttons_dialog  (_("GAP Question"), l_msg, l_argc, l_argv, -1);
  1036.     
  1037.     if(gap_debug) fprintf(stderr, "DEBUG: decide SAVE_AS_MODE %d\n", (int)l_save_as_mode);
  1038.     
  1039.     if(l_save_as_mode < 0) return -1;
  1040.     l_run_mode = GIMP_RUN_INTERACTIVE;
  1041.   }
  1042.   else
  1043.   {
  1044.     l_run_mode = GIMP_RUN_WITH_LAST_VALS;
  1045.   }
  1046.  
  1047.   gimp_set_data (l_save_as_name, &l_save_as_mode, sizeof(l_save_as_mode));
  1048.    
  1049.   
  1050.   if(l_save_as_mode == 1)
  1051.   {
  1052.       gimp_image_flatten (image_id);
  1053.   }
  1054.  
  1055.   return(p_save_named_image(image_id, sav_name, l_run_mode));
  1056. }    /* end p_decide_save_as */
  1057.  
  1058.  
  1059.  
  1060. /* ============================================================================
  1061.  * p_save_named_image
  1062.  * ============================================================================
  1063.  */
  1064. gint32 p_save_named_image(gint32 image_id, char *sav_name, GimpRunModeType run_mode)
  1065. {
  1066.   GimpDrawable  *l_drawable;
  1067.   gint        l_nlayers;
  1068.   gint32     *l_layers_list;
  1069.   GimpParam     *l_params;
  1070.   gint        l_retvals;
  1071.  
  1072.   if(gap_debug) fprintf(stderr, "DEBUG: before   p_save_named_image: '%s'\n", sav_name);
  1073.  
  1074.   l_layers_list = gimp_image_get_layers(image_id, &l_nlayers);
  1075.   if(l_layers_list == NULL)
  1076.      return -1;
  1077.  
  1078.   l_drawable =  gimp_drawable_get(l_layers_list[l_nlayers -1]);  /* use the background layer */
  1079.   if(l_drawable == NULL)
  1080.   {
  1081.      fprintf(stderr, "ERROR: p_save_named_image gimp_drawable_get failed '%s' nlayers=%d\n",
  1082.                      sav_name, (int)l_nlayers);
  1083.      g_free (l_layers_list);
  1084.      return -1;
  1085.   }
  1086.   
  1087.   l_params = gimp_run_procedure ("gimp_file_save",
  1088.                    &l_retvals,
  1089.                    GIMP_PDB_INT32,    run_mode,
  1090.                    GIMP_PDB_IMAGE,    image_id,
  1091.                    GIMP_PDB_DRAWABLE, l_drawable->id,
  1092.                    GIMP_PDB_STRING, sav_name,
  1093.                    GIMP_PDB_STRING, sav_name, /* raw name ? */
  1094.                    GIMP_PDB_END);
  1095.  
  1096.   if(gap_debug) fprintf(stderr, "DEBUG: after    p_save_named_image: '%s' nlayers=%d image=%d drw=%d run_mode=%d\n", sav_name, (int)l_nlayers, (int)image_id, (int)l_drawable->id, (int)run_mode);
  1097.  
  1098.   p_gimp_file_save_thumbnail(image_id, sav_name);
  1099.  
  1100.   g_free (l_layers_list);
  1101.   g_free (l_drawable);
  1102.  
  1103.  
  1104.   if (l_params[0].data.d_status != GIMP_PDB_SUCCESS)
  1105.   {
  1106.     fprintf(stderr, "ERROR: p_save_named_image  gimp_file_save failed '%s'\n", sav_name);
  1107.     g_free(l_params);
  1108.     return -1;
  1109.   }
  1110.   else
  1111.   {
  1112.     g_free(l_params);
  1113.     return image_id;
  1114.   }
  1115.    
  1116. }    /* end p_save_named_image */
  1117.  
  1118.  
  1119.  
  1120. /* ============================================================================
  1121.  * p_save_named_frame
  1122.  *  save frame into temporary image,
  1123.  *  on success rename it to desired framename.
  1124.  *  (this is done, to avoid corrupted frames on disk in case of
  1125.  *   crash in one of the save procedures)
  1126.  * ============================================================================
  1127.  */
  1128. int p_save_named_frame(gint32 image_id, char *sav_name)
  1129. {
  1130.   GimpParam* l_params;
  1131.   char  *l_ext;
  1132.   char  *l_tmpname;
  1133.   gint   l_retvals;
  1134.   int    l_gzip;
  1135.   int    l_xcf;
  1136.   int    l_rc;
  1137.  
  1138.   l_tmpname = NULL;
  1139.   l_rc   = -1;
  1140.   l_gzip = 0;          /* dont zip */
  1141.   l_xcf  = 0;          /* assume no xcf format */
  1142.   
  1143.   /* check extension to decide if savd file will be zipped */      
  1144.   l_ext = p_alloc_extension(sav_name);
  1145.   if(l_ext == NULL)  return -1;
  1146.   
  1147.   if(0 == strcmp(l_ext, ".xcf"))
  1148.   { 
  1149.     l_xcf  = 1;
  1150.   }
  1151.   else if(0 == strcmp(l_ext, ".xcfgz"))
  1152.   { 
  1153.     l_gzip = 1;          /* zip it */
  1154.     l_xcf  = 1;
  1155.   }
  1156.   else if(0 == strcmp(l_ext, ".gz"))
  1157.   { 
  1158.     l_gzip = 1;          /* zip it */
  1159.   }
  1160.  
  1161.   /* find a temp name 
  1162.    * that resides on the same filesystem as sav_name
  1163.    * and has the same extension as the original sav_name 
  1164.    */
  1165.   l_tmpname = g_strdup_printf("%s.gtmp%s", sav_name, l_ext);
  1166.   if(1 == p_file_exists(l_tmpname))
  1167.   {
  1168.       /* FILE exists: let gimp find another temp name */
  1169.       l_params = gimp_run_procedure ("gimp_temp_name",
  1170.                                 &l_retvals,
  1171.                                 GIMP_PDB_STRING, 
  1172.                                 &l_ext[1],
  1173.                                 GIMP_PDB_END);
  1174.  
  1175.       if(l_params[1].data.d_string != NULL)
  1176.       {
  1177.          l_tmpname = l_params[1].data.d_string;
  1178.       }
  1179.       g_free(l_params);
  1180.   }
  1181.  
  1182.   g_free(l_ext);
  1183.  
  1184.  
  1185.    if(gap_debug)
  1186.    {
  1187.      l_ext = g_getenv("GAP_NO_SAVE");
  1188.      if(l_ext != NULL)
  1189.      {
  1190.        fprintf(stderr, "DEBUG: GAP_NO_SAVE is set: save is skipped: '%s'\n", l_tmpname);
  1191.        g_free(l_tmpname);  /* free if it was a temporary name */
  1192.        return 0;
  1193.      }
  1194.    }
  1195.  
  1196.   if(gap_debug) fprintf(stderr, "DEBUG: before   p_save_named_frame: '%s'\n", l_tmpname);
  1197.  
  1198.   if(l_xcf != 0)
  1199.   {
  1200.     /* save current frame as xcf image
  1201.      * xcf_save does operate on the complete image,
  1202.      * the drawable is ignored. (we can supply a dummy value)
  1203.      */
  1204.     l_params = gimp_run_procedure ("gimp_xcf_save",
  1205.                      &l_retvals,
  1206.                      GIMP_PDB_INT32,    GIMP_RUN_NONINTERACTIVE,
  1207.                      GIMP_PDB_IMAGE,    image_id,
  1208.                      GIMP_PDB_DRAWABLE, 0,
  1209.                      GIMP_PDB_STRING, l_tmpname,
  1210.                      GIMP_PDB_STRING, l_tmpname, /* raw name ? */
  1211.                      GIMP_PDB_END);
  1212.     if(gap_debug) fprintf(stderr, "DEBUG: after   xcf  p_save_named_frame: '%s'\n", l_tmpname);
  1213.  
  1214.     if (l_params[0].data.d_status == GIMP_PDB_SUCCESS)
  1215.     {
  1216.        l_rc = image_id;
  1217.     }
  1218.     g_free(l_params);
  1219.   }
  1220.   else
  1221.   {
  1222.      /* let gimp try to save (and detect filetype by extension)
  1223.       * Note: the most imagefileformats do not support multilayer
  1224.       *       images, and extra channels
  1225.       *       the result may not contain the whole imagedata
  1226.       *
  1227.       * To Do: Should warn the user at 1.st attempt to do this.
  1228.       */
  1229.       
  1230.      l_rc = p_decide_save_as(image_id, l_tmpname);
  1231.   } 
  1232.  
  1233.   if(l_rc < 0)
  1234.   {
  1235.      remove(l_tmpname);
  1236.      g_free(l_tmpname);  /* free temporary name */
  1237.      return l_rc;
  1238.   }
  1239.  
  1240.   if(l_gzip == 0)
  1241.   {
  1242.      /* remove sav_name, then rename tmpname ==> sav_name */
  1243.      remove(sav_name);
  1244.      if (0 != rename(l_tmpname, sav_name))
  1245.      {
  1246.         /* if tempname is located on another filesystem (errno == EXDEV)
  1247.          * rename will not work.
  1248.          * so lets try a  copy ; remove sequence
  1249.          */
  1250.          if(gap_debug) fprintf(stderr, "DEBUG: p_save_named_frame: RENAME 2nd try\n");
  1251.          if(0 == p_file_copy(l_tmpname, sav_name))
  1252.      {
  1253.         remove(l_tmpname);
  1254.      }
  1255.          else
  1256.          {
  1257.             fprintf(stderr, "ERROR in p_save_named_frame: can't rename %s to %s\n",
  1258.                             l_tmpname, sav_name);
  1259.             return -1;
  1260.          }
  1261.      }
  1262.   }
  1263.   else
  1264.   {
  1265.     /* ZIP tmpname ==> sav_name */
  1266.     if(NULL != p_gzip(l_tmpname, sav_name, "zip"))
  1267.     {
  1268.        /* OK zip created compressed file named sav_name
  1269.         * now delete the uncompressed l_tempname
  1270.         */
  1271.        remove(l_tmpname);
  1272.     }
  1273.   }
  1274.  
  1275.   p_gimp_file_save_thumbnail(image_id, sav_name);
  1276.  
  1277.   g_free(l_tmpname);  /* free temporary name */
  1278.  
  1279.   return l_rc;
  1280.    
  1281. }    /* end p_save_named_frame */
  1282.  
  1283.  
  1284. /* ============================================================================
  1285.  * p_save_old_frame
  1286.  * ============================================================================
  1287.  */
  1288. int p_save_old_frame(t_anim_info *ainfo_ptr)
  1289. {
  1290.   /* (here we should check if image has unsaved changes
  1291.    * before save)
  1292.    */ 
  1293.   if(1)
  1294.   {
  1295.     return (p_save_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename));
  1296.   }
  1297.   else
  1298.   {
  1299.     return -1;
  1300.   }
  1301. }    /* end p_save_old_frame */
  1302.  
  1303.  
  1304.  
  1305. /* ============================================================================
  1306.  * p_load_image
  1307.  * load image of any type by filename, and return its image id
  1308.  * (or -1 in case of errors)
  1309.  * ============================================================================
  1310.  */
  1311. gint32 p_load_image (char *lod_name)
  1312. {
  1313.   GimpParam* l_params;
  1314.   char  *l_ext;
  1315.   char  *l_tmpname;
  1316.   gint   l_retvals;
  1317.   gint32 l_tmp_image_id;
  1318.   int    l_rc;
  1319.   
  1320.   l_rc = 0;
  1321.   l_tmpname = NULL;
  1322.   l_ext = p_alloc_extension(lod_name);
  1323.   if(l_ext != NULL)
  1324.   {
  1325.     if((0 == strcmp(l_ext, ".xcfgz"))
  1326.     || (0 == strcmp(l_ext, ".gz")))
  1327.     { 
  1328.  
  1329.       /* find a temp name */
  1330.       l_params = gimp_run_procedure ("gimp_temp_name",
  1331.                        &l_retvals,
  1332.                        GIMP_PDB_STRING, 
  1333.                        &l_ext[1],           /* extension */
  1334.                        GIMP_PDB_END);
  1335.  
  1336.       if(l_params[1].data.d_string != NULL)
  1337.       {
  1338.          /* try to unzip file, before loading it */
  1339.          l_tmpname = p_gzip(lod_name, l_params[1].data.d_string, "unzip");
  1340.       }
  1341.  
  1342.       g_free(l_params);
  1343.     }
  1344.     else l_tmpname = lod_name;
  1345.     g_free(l_ext);
  1346.   }
  1347.  
  1348.   if(l_tmpname == NULL)
  1349.   {
  1350.     return -1;
  1351.   }
  1352.  
  1353.  
  1354.   if(gap_debug) fprintf(stderr, "DEBUG: before   p_load_image: '%s'\n", l_tmpname);
  1355.  
  1356.   l_params = gimp_run_procedure ("gimp_file_load",  /* "gimp_xcf_load" */
  1357.                    &l_retvals,
  1358.                    GIMP_PDB_INT32,  GIMP_RUN_NONINTERACTIVE,
  1359.                    GIMP_PDB_STRING, l_tmpname,
  1360.                    GIMP_PDB_STRING, l_tmpname, /* raw name ? */
  1361.                    GIMP_PDB_END);
  1362.  
  1363.   l_tmp_image_id = l_params[1].data.d_int32;
  1364.   
  1365.   if(gap_debug) fprintf(stderr, "DEBUG: after    p_load_image: '%s' id=%d\n\n",
  1366.                                l_tmpname, (int)l_tmp_image_id);
  1367.  
  1368.   if(l_tmpname != lod_name)
  1369.   {
  1370.     remove(l_tmpname);
  1371.     g_free(l_tmpname);  /* free if it was a temporary name */
  1372.   }
  1373.   
  1374.  
  1375.   g_free(l_params);
  1376.   return l_tmp_image_id;
  1377.  
  1378. }    /* end p_load_image */
  1379.  
  1380.  
  1381.  
  1382. /* ============================================================================
  1383.  * p_load_named_frame
  1384.  * load new frame, replacing the existing image
  1385.  * file must be of same type and size
  1386.  * ============================================================================
  1387.  */
  1388. int p_load_named_frame (gint32 image_id, char *lod_name)
  1389. {
  1390.   gint32 l_tmp_image_id;
  1391.   int    l_rc;
  1392.   
  1393.   l_rc = 0;
  1394.  
  1395.   l_tmp_image_id = p_load_image(lod_name);
  1396.   
  1397.   if(gap_debug) fprintf(stderr, "DEBUG: after    p_load_named_frame: '%s' id=%d  new_id=%d\n\n",
  1398.                                lod_name, (int)image_id, (int)l_tmp_image_id);
  1399.  
  1400.   if(l_tmp_image_id < 0)
  1401.       return -1;
  1402.  
  1403.  
  1404.    /* replace image_id with the content of l_tmp_image_id */
  1405.    if(p_exchange_image (image_id, l_tmp_image_id) < 0)
  1406.    {
  1407.       /* in case of errors the image will be trashed */
  1408.       image_id = -1;
  1409.    }
  1410.  
  1411.    /* delete the temporary image (old content of the original image) */
  1412.    if(gap_debug)  printf("p_load_named_frame: BEFORE gimp_image_delete %d\n", (int)l_tmp_image_id);
  1413.    gimp_image_delete(l_tmp_image_id);
  1414.    if(gap_debug)  printf("p_load_named_frame: AFTER gimp_image_delete %d\n", (int)l_tmp_image_id);
  1415.  
  1416.    /* use the original lod_name */
  1417.    gimp_image_set_filename (image_id, lod_name);
  1418.    
  1419.    /* dont consider image dirty after load */
  1420.    gimp_image_clean_all(image_id);
  1421.    return image_id;
  1422.  
  1423. }    /* end p_load_named_frame */
  1424.  
  1425.  
  1426.  
  1427. /* ============================================================================
  1428.  * p_replace_image
  1429.  *
  1430.  * make new_filename of next file to load, check if that file does exist on disk
  1431.  * then save current image and replace it, by loading the new_filename
  1432.  * ============================================================================
  1433.  */
  1434. int p_replace_image(t_anim_info *ainfo_ptr)
  1435. {
  1436.   if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename);
  1437.   ainfo_ptr->new_filename = p_alloc_fname(ainfo_ptr->basename,
  1438.                                       ainfo_ptr->frame_nr,
  1439.                                       ainfo_ptr->extension);
  1440.   if(ainfo_ptr->new_filename == NULL)
  1441.      return -1;
  1442.  
  1443.   if(0 == p_file_exists(ainfo_ptr->new_filename ))
  1444.      return -1;
  1445.  
  1446.   if(p_save_old_frame(ainfo_ptr) <0)
  1447.   {
  1448.     return -1;
  1449.   }
  1450.   else
  1451.   {
  1452.     return (p_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->new_filename));
  1453.   }
  1454. }    /* end p_replace_image */
  1455.  
  1456.  
  1457.  
  1458. /* ============================================================================
  1459.  * p_del
  1460.  *
  1461.  * delete cnt frames starting at current
  1462.  * all following frames are renamed (renumbered down by cnt) 
  1463.  * ============================================================================
  1464.  */
  1465. int p_del(t_anim_info *ainfo_ptr, long cnt)
  1466. {
  1467.    long  l_lo, l_hi, l_curr, l_idx;
  1468.  
  1469.    if(gap_debug) fprintf(stderr, "DEBUG  p_del\n");
  1470.  
  1471.    if(cnt < 1) return -1;
  1472.  
  1473.    l_curr =  ainfo_ptr->curr_frame_nr;
  1474.    if((1 + ainfo_ptr->last_frame_nr - l_curr) < cnt)
  1475.    {
  1476.       /* limt cnt to last existing frame */
  1477.       cnt = 1 + ainfo_ptr->frame_cnt - l_curr;
  1478.    }
  1479.  
  1480.    if(cnt >= ainfo_ptr->frame_cnt)
  1481.    {
  1482.       /* dont want to delete all frames
  1483.        * so we have to leave a rest of one frame
  1484.        */
  1485.       cnt--;
  1486.    }
  1487.  
  1488.    
  1489.    l_idx   = l_curr;
  1490.    while(l_idx < (l_curr + cnt))
  1491.    {
  1492.       p_delete_frame(ainfo_ptr, l_idx);
  1493.       l_idx++;
  1494.    }
  1495.    
  1496.    /* rename (renumber) all frames with number greater than current
  1497.     */
  1498.    l_lo   = l_curr;
  1499.    l_hi   = l_curr + cnt;
  1500.    while(l_hi <= ainfo_ptr->last_frame_nr)
  1501.    {
  1502.      if(0 != p_rename_frame(ainfo_ptr, l_hi, l_lo))
  1503.      {
  1504.         gchar *tmp_errtxt;
  1505.     
  1506.         tmp_errtxt = g_strdup_printf(_("Error: could not rename frame %ld to %ld") ,l_hi, l_lo);
  1507.         p_msg_win(ainfo_ptr->run_mode, tmp_errtxt);
  1508.     g_free(tmp_errtxt);
  1509.         return -1;
  1510.      }
  1511.      l_lo++;
  1512.      l_hi++;
  1513.    }
  1514.  
  1515.    /* calculate how much frames are left */
  1516.    ainfo_ptr->frame_cnt -= cnt;
  1517.    ainfo_ptr->last_frame_nr = ainfo_ptr->first_frame_nr + ainfo_ptr->frame_cnt -1;
  1518.    
  1519.    /* set current position to previous frame (if there is one) */
  1520.    if(l_curr > ainfo_ptr->first_frame_nr) 
  1521.    { 
  1522.      ainfo_ptr->frame_nr = l_curr -1;
  1523.    }
  1524.    else
  1525.    { 
  1526.       ainfo_ptr->frame_nr = ainfo_ptr->first_frame_nr;
  1527.    }
  1528.  
  1529.    /* make filename, then load the new current frame */
  1530.    if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename);
  1531.    ainfo_ptr->new_filename = p_alloc_fname(ainfo_ptr->basename,
  1532.                                       ainfo_ptr->frame_nr,
  1533.                                       ainfo_ptr->extension);
  1534.  
  1535.    if(ainfo_ptr->new_filename != NULL)
  1536.       return (p_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->new_filename));
  1537.    else
  1538.       return -1;
  1539.       
  1540. }        /* end p_del */
  1541.  
  1542. /* ============================================================================
  1543.  * p_dup
  1544.  *
  1545.  * all following frames are renamed (renumbered up by cnt) 
  1546.  * current frame is duplicated (cnt) times
  1547.  * ============================================================================
  1548.  */
  1549. int p_dup(t_anim_info *ainfo_ptr, long cnt, long range_from, long range_to)
  1550. {
  1551.    long  l_lo, l_hi;
  1552.    long  l_cnt2;
  1553.    long  l_step;
  1554.    long  l_src_nr, l_src_nr_min, l_src_nr_max;
  1555.    char  *l_dup_name;
  1556.    char  *l_curr_name;
  1557.    gdouble    l_percentage, l_percentage_step;  
  1558.  
  1559.    if(gap_debug) fprintf(stderr, "DEBUG  p_dup fr:%d to:%d cnt:%d\n",
  1560.                          (int)range_from, (int)range_to, (int)cnt);
  1561.  
  1562.    if(cnt < 1) return -1;
  1563.  
  1564.    l_curr_name = p_alloc_fname(ainfo_ptr->basename, ainfo_ptr->curr_frame_nr, ainfo_ptr->extension);
  1565.    /* save current frame  */   
  1566.    p_save_named_frame(ainfo_ptr->image_id, l_curr_name);
  1567.  
  1568.    /* use a new name (0001.xcf Konvention) */ 
  1569.    gimp_image_set_filename (ainfo_ptr->image_id, l_curr_name);
  1570.    g_free(l_curr_name);
  1571.  
  1572.  
  1573.    if((range_from <0 ) && (range_to < 0 ))
  1574.    {
  1575.       /* set range to one single current frame
  1576.        * (used for the old non_interactive PDB-interface without range params)
  1577.        */
  1578.       range_from = ainfo_ptr->curr_frame_nr;
  1579.       range_to   = ainfo_ptr->curr_frame_nr;
  1580.    }
  1581.  
  1582.    /* clip range */
  1583.    if(range_from > ainfo_ptr->last_frame_nr)  range_from = ainfo_ptr->last_frame_nr;
  1584.    if(range_to   > ainfo_ptr->last_frame_nr)  range_to   = ainfo_ptr->last_frame_nr;
  1585.    if(range_from < ainfo_ptr->first_frame_nr) range_from = ainfo_ptr->first_frame_nr;
  1586.    if(range_to   < ainfo_ptr->first_frame_nr) range_to   = ainfo_ptr->first_frame_nr;
  1587.  
  1588.    if(range_to < range_from)
  1589.    {
  1590.        /* invers range */
  1591.       l_cnt2 = ((range_from - range_to ) + 1) * cnt;
  1592.       l_step = -1;
  1593.       l_src_nr_max = range_from;
  1594.       l_src_nr_min = range_to;
  1595.    }
  1596.    else
  1597.    {
  1598.       l_cnt2 = ((range_to - range_from ) + 1) * cnt;  
  1599.       l_step = 1;
  1600.       l_src_nr_max = range_to;
  1601.       l_src_nr_min = range_from;
  1602.    }    
  1603.  
  1604.    if(gap_debug) fprintf(stderr, "DEBUG  p_dup fr:%d to:%d cnt2:%d l_src_nr_max:%d\n",
  1605.                          (int)range_from, (int)range_to, (int)l_cnt2, (int)l_src_nr_max);
  1606.    
  1607.  
  1608.    l_percentage = 0.0;  
  1609.    if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
  1610.    { 
  1611.      gimp_progress_init( _("Duplicating frames..."));
  1612.    }
  1613.  
  1614.    /* rename (renumber) all frames with number greater than current
  1615.     */
  1616.    l_lo   = ainfo_ptr->last_frame_nr;
  1617.    l_hi   = l_lo + l_cnt2;
  1618.    while(l_lo > l_src_nr_max)
  1619.    {     
  1620.      if(0 != p_rename_frame(ainfo_ptr, l_lo, l_hi))
  1621.      {
  1622.         gchar *tmp_errtxt;
  1623.         tmp_errtxt = g_strdup_printf(_("Error: could not rename frame %ld to %ld"), l_lo, l_hi);
  1624.         p_msg_win(ainfo_ptr->run_mode, tmp_errtxt);
  1625.     g_free(tmp_errtxt);
  1626.         return -1;
  1627.      }
  1628.      l_lo--;
  1629.      l_hi--;
  1630.    }
  1631.  
  1632.  
  1633.    l_percentage_step = 1.0 / ((1.0 + l_hi) - l_src_nr_max);
  1634.    if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
  1635.    { 
  1636.       l_percentage += l_percentage_step;
  1637.       gimp_progress_update (l_percentage);
  1638.    }
  1639.  
  1640.    /* copy cnt duplicates */   
  1641.    l_src_nr = range_to;
  1642.    while(l_hi > l_src_nr_max)
  1643.    {
  1644.       l_curr_name = p_alloc_fname(ainfo_ptr->basename, l_src_nr, ainfo_ptr->extension);  
  1645.       l_dup_name = p_alloc_fname(ainfo_ptr->basename, l_hi, ainfo_ptr->extension);
  1646.       if((l_dup_name != NULL) && (l_curr_name != NULL))
  1647.       {
  1648.          p_image_file_copy(l_curr_name, l_dup_name);
  1649.          g_free(l_dup_name);
  1650.          g_free(l_curr_name);
  1651.       }
  1652.       if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
  1653.       { 
  1654.          l_percentage += l_percentage_step;
  1655.          gimp_progress_update (l_percentage);
  1656.       }
  1657.       
  1658.       
  1659.       l_src_nr -= l_step;
  1660.       if(l_src_nr < l_src_nr_min) l_src_nr = l_src_nr_max;
  1661.       if(l_src_nr > l_src_nr_max) l_src_nr = l_src_nr_min;
  1662.       
  1663.       l_hi--;
  1664.    }
  1665.  
  1666.    /* restore current position */
  1667.    ainfo_ptr->frame_cnt += l_cnt2;
  1668.    ainfo_ptr->last_frame_nr = ainfo_ptr->first_frame_nr + ainfo_ptr->frame_cnt -1;
  1669.  
  1670.    /* load from the "new" current frame */   
  1671.    if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename);
  1672.    ainfo_ptr->new_filename = p_alloc_fname(ainfo_ptr->basename,
  1673.                                       ainfo_ptr->curr_frame_nr,
  1674.                                       ainfo_ptr->extension);
  1675.    return (p_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->new_filename));
  1676. }        /* end p_dup */
  1677.  
  1678. /* ============================================================================
  1679.  * p_exchg
  1680.  *
  1681.  * save current frame, exchange its name with destination frame on disk 
  1682.  * and reload current frame (now has contents of dest. and vice versa)
  1683.  * ============================================================================
  1684.  */
  1685. int p_exchg(t_anim_info *ainfo_ptr, long dest)
  1686. {
  1687.    long  l_tmp_nr;
  1688.    gchar *tmp_errtxt;
  1689.  
  1690.    l_tmp_nr = ainfo_ptr->last_frame_nr + 4;  /* use a free frame_nr for temp name */
  1691.  
  1692.    if((dest < 1) || (dest == ainfo_ptr->curr_frame_nr)) 
  1693.       return -1;
  1694.  
  1695.    if(p_save_named_frame(ainfo_ptr->image_id, ainfo_ptr->old_filename) < 0)
  1696.       return -1;
  1697.    
  1698.  
  1699.    /* rename (renumber) frames */
  1700.    if(0 != p_rename_frame(ainfo_ptr, dest, l_tmp_nr))
  1701.    {
  1702.         tmp_errtxt = g_strdup_printf(_("Error: could not rename frame %ld to %ld"), dest, l_tmp_nr);
  1703.         p_msg_win(ainfo_ptr->run_mode, tmp_errtxt);
  1704.     g_free(tmp_errtxt);
  1705.         return -1;
  1706.    }
  1707.    if(0 != p_rename_frame(ainfo_ptr, ainfo_ptr->curr_frame_nr, dest))
  1708.    {
  1709.         tmp_errtxt = g_strdup_printf(_("Error: could not rename frame %ld to %ld"), ainfo_ptr->curr_frame_nr, dest);
  1710.         p_msg_win(ainfo_ptr->run_mode, tmp_errtxt);
  1711.     g_free(tmp_errtxt);
  1712.         return -1;
  1713.    }
  1714.    if(0 != p_rename_frame(ainfo_ptr, l_tmp_nr, ainfo_ptr->curr_frame_nr))
  1715.    {
  1716.         tmp_errtxt = g_strdup_printf(_("Error: could not rename frame %ld to %ld"), l_tmp_nr, ainfo_ptr->curr_frame_nr);
  1717.         p_msg_win(ainfo_ptr->run_mode, tmp_errtxt);
  1718.     g_free(tmp_errtxt);
  1719.         return -1;
  1720.    }
  1721.  
  1722.    /* load from the "new" current frame */   
  1723.    if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename);
  1724.    ainfo_ptr->new_filename = p_alloc_fname(ainfo_ptr->basename,
  1725.                                       ainfo_ptr->curr_frame_nr,
  1726.                                       ainfo_ptr->extension);
  1727.    return (p_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->new_filename));
  1728.  
  1729. }        /* end p_exchg */
  1730.  
  1731. /* ============================================================================
  1732.  * p_shift
  1733.  *
  1734.  * all frmaes in the given range are renumbered (shifted)
  1735.  * according to cnt:
  1736.  *  example:  cnt == 1 :  range before 3, 4, 5, 6, 7
  1737.  *                        range after  4, 5, 6, 7, 3
  1738.  * ============================================================================
  1739.  */
  1740. static int
  1741. p_shift(t_anim_info *ainfo_ptr, long cnt, long range_from, long range_to)
  1742. {
  1743.    long  l_lo, l_hi, l_curr, l_dst;
  1744.    long  l_upper;
  1745.    long  l_shift;
  1746.    gchar *l_curr_name;
  1747.    gchar *tmp_errtxt;
  1748.     
  1749.    gdouble    l_percentage, l_percentage_step;  
  1750.  
  1751.    if(gap_debug) fprintf(stderr, "DEBUG  p_shift fr:%d to:%d cnt:%d\n",
  1752.                          (int)range_from, (int)range_to, (int)cnt);
  1753.  
  1754.    if(range_from == range_to) return -1;
  1755.  
  1756.    /* clip range */
  1757.    if(range_from > ainfo_ptr->last_frame_nr)  range_from = ainfo_ptr->last_frame_nr;
  1758.    if(range_to   > ainfo_ptr->last_frame_nr)  range_to   = ainfo_ptr->last_frame_nr;
  1759.    if(range_from < ainfo_ptr->first_frame_nr) range_from = ainfo_ptr->first_frame_nr;
  1760.    if(range_to   < ainfo_ptr->first_frame_nr) range_to   = ainfo_ptr->first_frame_nr;
  1761.  
  1762.    if(range_to < range_from)
  1763.    {
  1764.       l_lo = range_to;
  1765.       l_hi = range_from;
  1766.    }
  1767.    else
  1768.    {
  1769.       l_lo = range_from;
  1770.       l_hi = range_to;
  1771.    }
  1772.    
  1773.    /* limit shift  amount to number of frames in range */
  1774.    l_shift = cnt % (l_hi - l_lo);
  1775.    if(gap_debug) fprintf(stderr, "DEBUG  p_shift shift:%d\n",
  1776.                          (int)l_shift);
  1777.    if(l_shift == 0) return -1;
  1778.  
  1779.    l_curr_name = p_alloc_fname(ainfo_ptr->basename, ainfo_ptr->curr_frame_nr, ainfo_ptr->extension);
  1780.    /* save current frame  */   
  1781.    p_save_named_frame(ainfo_ptr->image_id, l_curr_name);
  1782.    g_free(l_curr_name);
  1783.  
  1784.    l_percentage = 0.0;  
  1785.    if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
  1786.    { 
  1787.      gimp_progress_init( _("Renumber Framesequence..."));
  1788.    }
  1789.  
  1790.    /* rename (renumber) all frames (using high numbers)
  1791.     */
  1792.  
  1793.    l_upper = ainfo_ptr->last_frame_nr +100;
  1794.    l_percentage_step = 0.5 / ((1.0 + l_lo) - l_hi);
  1795.    for(l_curr = l_lo; l_curr <= l_hi; l_curr++)
  1796.    {
  1797.      if(0 != p_rename_frame(ainfo_ptr, l_curr, l_curr + l_upper))
  1798.      {
  1799.         tmp_errtxt = g_strdup_printf(_("Error: could not rename frame %ld to %ld"), l_lo, l_hi);
  1800.         p_msg_win(ainfo_ptr->run_mode, tmp_errtxt);
  1801.     g_free(tmp_errtxt);
  1802.         return -1;
  1803.      }
  1804.      if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
  1805.      { 
  1806.        l_percentage += l_percentage_step;
  1807.        gimp_progress_update (l_percentage);
  1808.      }
  1809.    }
  1810.  
  1811.    /* rename (renumber) all frames (using desied destination numbers)
  1812.     */
  1813.    l_dst = l_lo + l_shift;
  1814.    if (l_dst > l_hi) { l_dst -= (l_lo -1); }
  1815.    if (l_dst < l_lo) { l_dst += ((l_hi - l_lo) +1); }
  1816.    for(l_curr = l_upper + l_lo; l_curr <= l_upper + l_hi; l_curr++)
  1817.    {
  1818.      if (l_dst > l_hi) { l_dst = l_lo; }
  1819.      if(0 != p_rename_frame(ainfo_ptr, l_curr, l_dst))
  1820.      {
  1821.         tmp_errtxt = g_strdup_printf(_("Error: could not rename frame %ld to %ld"), l_lo, l_hi);
  1822.         p_msg_win(ainfo_ptr->run_mode, tmp_errtxt);
  1823.     g_free(tmp_errtxt);
  1824.         return -1;
  1825.      }
  1826.      if(ainfo_ptr->run_mode == GIMP_RUN_INTERACTIVE)
  1827.      { 
  1828.        l_percentage += l_percentage_step;
  1829.        gimp_progress_update (l_percentage);
  1830.      }
  1831.  
  1832.      l_dst ++;     
  1833.    }
  1834.  
  1835.  
  1836.    /* load from the "new" current frame */   
  1837.    if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename);
  1838.    ainfo_ptr->new_filename = p_alloc_fname(ainfo_ptr->basename,
  1839.                                       ainfo_ptr->curr_frame_nr,
  1840.                                       ainfo_ptr->extension);
  1841.    return (p_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->new_filename));
  1842. }  /* end p_shift */
  1843.  
  1844.  
  1845.  
  1846.  
  1847.  
  1848. /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ 
  1849. /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ 
  1850. /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ 
  1851.  
  1852.  
  1853. /* ============================================================================
  1854.  * gap_next gap_prev
  1855.  *
  1856.  * store the current Gimp Image to the current anim Frame
  1857.  * and load it from the next/prev anim Frame on disk.
  1858.  * ============================================================================
  1859.  */
  1860. int gap_next(GimpRunModeType run_mode, gint32 image_id)
  1861. {
  1862.   int rc;
  1863.   t_anim_info *ainfo_ptr;
  1864.  
  1865.   rc = -1;
  1866.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  1867.   if(ainfo_ptr != NULL)
  1868.   {
  1869.     ainfo_ptr->frame_nr = ainfo_ptr->curr_frame_nr + 1;
  1870.     rc = p_replace_image(ainfo_ptr);
  1871.   
  1872.     p_free_ainfo(&ainfo_ptr);
  1873.   }
  1874.   
  1875.   return(rc);    
  1876. }    /* end gap_next */
  1877.  
  1878. int gap_prev(GimpRunModeType run_mode, gint32 image_id)
  1879. {
  1880.   int rc;
  1881.   t_anim_info *ainfo_ptr;
  1882.  
  1883.   rc = -1;
  1884.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  1885.   if(ainfo_ptr != NULL)
  1886.   {
  1887.     ainfo_ptr->frame_nr = ainfo_ptr->curr_frame_nr - 1;
  1888.     rc = p_replace_image(ainfo_ptr);
  1889.   
  1890.     p_free_ainfo(&ainfo_ptr);
  1891.   }
  1892.   
  1893.   return(rc);    
  1894. }    /* end gap_prev */
  1895.  
  1896. /* ============================================================================
  1897.  * gap_first  gap_last
  1898.  *
  1899.  * store the current Gimp Image to the current anim Frame
  1900.  * and load it from the first/last anim Frame on disk.
  1901.  * ============================================================================
  1902.  */
  1903.  
  1904. int gap_first(GimpRunModeType run_mode, gint32 image_id)
  1905. {
  1906.   int rc;
  1907.   t_anim_info *ainfo_ptr;
  1908.  
  1909.   rc = -1;
  1910.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  1911.   if(ainfo_ptr != NULL)
  1912.   {
  1913.     if (0 == p_dir_ainfo(ainfo_ptr))
  1914.     {
  1915.       ainfo_ptr->frame_nr = ainfo_ptr->first_frame_nr;
  1916.       rc = p_replace_image(ainfo_ptr);
  1917.     }
  1918.     p_free_ainfo(&ainfo_ptr);
  1919.   }
  1920.   
  1921.   return(rc);    
  1922. }    /* end gap_first */
  1923.  
  1924. int gap_last(GimpRunModeType run_mode, gint32 image_id)
  1925. {
  1926.   int rc;
  1927.   t_anim_info *ainfo_ptr;
  1928.  
  1929.   rc = -1;
  1930.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  1931.   if(ainfo_ptr != NULL)
  1932.   {
  1933.     if (0 == p_dir_ainfo(ainfo_ptr))
  1934.     {
  1935.       ainfo_ptr->frame_nr = ainfo_ptr->last_frame_nr;
  1936.       rc = p_replace_image(ainfo_ptr);
  1937.     }
  1938.     p_free_ainfo(&ainfo_ptr);
  1939.   }
  1940.   
  1941.   return(rc);    
  1942. }    /* end gap_last */
  1943.  
  1944. /* ============================================================================
  1945.  * gap_goto
  1946.  * 
  1947.  * store the current Gimp Image to disk
  1948.  * and load it from the anim Frame on disk that has the specified frame Nr.
  1949.  * GIMP_RUN_INTERACTIVE:
  1950.  *    show dialogwindow where user can enter the destination frame Nr.
  1951.  * ============================================================================
  1952.  */
  1953.  
  1954. int gap_goto(GimpRunModeType run_mode, gint32 image_id, int nr)
  1955. {
  1956.   int rc;
  1957.   t_anim_info *ainfo_ptr;
  1958.  
  1959.   long            l_dest;
  1960.   gchar          *l_hline;
  1961.   gchar          *l_title;
  1962.  
  1963.   rc = -1;
  1964.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  1965.   if(ainfo_ptr != NULL)
  1966.   {
  1967.     if (0 == p_dir_ainfo(ainfo_ptr))
  1968.     {
  1969.       if(0 != p_chk_framerange(ainfo_ptr))   return -1;
  1970.  
  1971.       if(run_mode == GIMP_RUN_INTERACTIVE)
  1972.       {
  1973.         l_title = g_strdup_printf (_("Goto Frame (%ld/%ld)")
  1974.                    , ainfo_ptr->curr_frame_nr
  1975.                    , ainfo_ptr->frame_cnt);
  1976.         l_hline =  g_strdup_printf (_("Destination Frame Number (%ld  - %ld)")
  1977.                     , ainfo_ptr->first_frame_nr
  1978.                     , ainfo_ptr->last_frame_nr);
  1979.  
  1980.         l_dest = p_slider_dialog(l_title, l_hline, _("Number:"), NULL
  1981.                 , ainfo_ptr->first_frame_nr
  1982.                 , ainfo_ptr->last_frame_nr
  1983.                 , ainfo_ptr->curr_frame_nr
  1984.                 , TRUE);
  1985.  
  1986.     g_free (l_title);
  1987.     g_free (l_hline);
  1988.                 
  1989.         if(l_dest < 0)
  1990.         {
  1991.            /* Cancel button: go back to current frame */
  1992.            l_dest = ainfo_ptr->curr_frame_nr;
  1993.         }  
  1994.         if(0 != p_chk_framechange(ainfo_ptr))
  1995.         {
  1996.            l_dest = -1;
  1997.         }
  1998.       }
  1999.       else
  2000.       {
  2001.         l_dest = nr;
  2002.       }
  2003.  
  2004.       if(l_dest >= 0)
  2005.       {
  2006.         ainfo_ptr->frame_nr = l_dest;
  2007.         rc = p_replace_image(ainfo_ptr);
  2008.       }
  2009.  
  2010.     }
  2011.     p_free_ainfo(&ainfo_ptr);
  2012.   }
  2013.   
  2014.   return(rc);    
  2015. }    /* end gap_goto */
  2016.  
  2017. /* ============================================================================
  2018.  * gap_del
  2019.  * ============================================================================
  2020.  */
  2021. int gap_del(GimpRunModeType run_mode, gint32 image_id, int nr)
  2022. {
  2023.   int rc;
  2024.   t_anim_info *ainfo_ptr;
  2025.  
  2026.   long           l_cnt;
  2027.   long           l_max;
  2028.   gchar         *l_hline;
  2029.   gchar         *l_title;
  2030.  
  2031.   rc = -1;
  2032.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  2033.   if(ainfo_ptr != NULL)
  2034.   {
  2035.     if (0 == p_dir_ainfo(ainfo_ptr))
  2036.     {
  2037.       if(0 != p_chk_framerange(ainfo_ptr))   return -1;
  2038.       
  2039.       if(run_mode == GIMP_RUN_INTERACTIVE)
  2040.       {
  2041.         l_title = g_strdup_printf (_("Delete Frames (%ld/%ld)")
  2042.                    , ainfo_ptr->curr_frame_nr
  2043.                    , ainfo_ptr->frame_cnt);
  2044.         l_hline = g_strdup_printf (_("Delete Frames from %ld to (number)")
  2045.                    , ainfo_ptr->curr_frame_nr);
  2046.  
  2047.         l_max = ainfo_ptr->last_frame_nr;
  2048.         if(l_max == ainfo_ptr->curr_frame_nr)
  2049.         { 
  2050.           /* bugfix: the slider needs a maximum > minimum
  2051.            *         (if not an error is printed, and
  2052.            *          a default range 0 to 100 is displayed)
  2053.            */
  2054.           l_max++;
  2055.         }
  2056.         
  2057.         l_cnt = p_slider_dialog(l_title, l_hline, _("Number:"), NULL
  2058.               , ainfo_ptr->curr_frame_nr
  2059.               , l_max
  2060.               , ainfo_ptr->curr_frame_nr
  2061.               , TRUE);
  2062.                 
  2063.     g_free (l_title);
  2064.     g_free (l_hline);
  2065.     
  2066.         if(l_cnt >= 0)
  2067.         {
  2068.            l_cnt = 1 + l_cnt - ainfo_ptr->curr_frame_nr;
  2069.         } 
  2070.         if(0 != p_chk_framechange(ainfo_ptr))
  2071.         {
  2072.            l_cnt = -1;
  2073.         }
  2074.       }
  2075.       else
  2076.       {
  2077.         l_cnt = nr;
  2078.       }
  2079.  
  2080.       if(l_cnt >= 0)
  2081.       {
  2082.          /* delete l_cnt number of frames (-1 CANCEL button) */
  2083.  
  2084.          rc = p_del(ainfo_ptr, l_cnt);
  2085.       }
  2086.  
  2087.  
  2088.     }
  2089.     p_free_ainfo(&ainfo_ptr);
  2090.   }
  2091.   
  2092.   return(rc);    
  2093.  
  2094. }    /* end gap_del */
  2095.  
  2096.  
  2097. /* ============================================================================
  2098.  * p_dup_dialog
  2099.  *
  2100.  * ============================================================================
  2101.  */
  2102. int p_dup_dialog(t_anim_info *ainfo_ptr, long *range_from, long *range_to)
  2103. {
  2104.   static t_arr_arg  argv[3];
  2105.   gchar            *l_title;
  2106.  
  2107.   l_title = g_strdup_printf (_("Duplicate Frames (%ld/%ld)")
  2108.                  , ainfo_ptr->curr_frame_nr
  2109.                  , ainfo_ptr->frame_cnt);
  2110.  
  2111.   p_init_arr_arg(&argv[0], WGT_INT_PAIR);
  2112.   argv[0].label_txt = _("From:");
  2113.   argv[0].constraint = TRUE;
  2114.   argv[0].int_min   = (gint)ainfo_ptr->first_frame_nr;
  2115.   argv[0].int_max   = (gint)ainfo_ptr->last_frame_nr;
  2116.   argv[0].int_ret   = (gint)ainfo_ptr->curr_frame_nr;
  2117.   argv[0].help_txt  = _("Source Range starts at this framenumber");
  2118.  
  2119.   p_init_arr_arg(&argv[1], WGT_INT_PAIR);
  2120.   argv[1].label_txt = _("To:");
  2121.   argv[1].constraint = TRUE;
  2122.   argv[1].int_min   = (gint)ainfo_ptr->first_frame_nr;
  2123.   argv[1].int_max   = (gint)ainfo_ptr->last_frame_nr;
  2124.   argv[1].int_ret   = (gint)ainfo_ptr->curr_frame_nr;
  2125.   argv[1].help_txt  = _("Source Range ends at this framenumber");
  2126.     
  2127.   p_init_arr_arg(&argv[2], WGT_INT_PAIR);
  2128.   argv[2].label_txt = _("N times:");
  2129.   argv[2].constraint = FALSE;
  2130.   argv[2].int_min   = 0;
  2131.   argv[2].int_max   = 99;
  2132.   argv[2].int_ret   = 1;
  2133.   argv[2].umin      = 0;
  2134.   argv[2].umax      = 9999;
  2135.   argv[2].help_txt  = _("Copy selected Range n-times  \n(you may type in Values > 99)");
  2136.   
  2137.   if(TRUE == p_array_dialog(l_title, _("Duplicate Frame Range"),  3, argv))
  2138.   { 
  2139.     g_free (l_title);
  2140.     *range_from = (long)(argv[0].int_ret);
  2141.     *range_to   = (long)(argv[1].int_ret);
  2142.        return (int)(argv[2].int_ret);
  2143.   }
  2144.   else
  2145.   {
  2146.     g_free (l_title);
  2147.     return -1;
  2148.   }
  2149.    
  2150.  
  2151. }    /* end p_dup_dialog */
  2152.  
  2153.  
  2154. /* ============================================================================
  2155.  * gap_dup
  2156.  * ============================================================================
  2157.  */
  2158. int gap_dup(GimpRunModeType run_mode, gint32 image_id, int nr,
  2159.             long range_from, long range_to)
  2160. {
  2161.   int rc;
  2162.   t_anim_info *ainfo_ptr;
  2163.  
  2164.   long           l_cnt, l_from, l_to;
  2165.  
  2166.   rc = -1;
  2167.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  2168.   if(ainfo_ptr != NULL)
  2169.   {
  2170.     if (0 == p_dir_ainfo(ainfo_ptr))
  2171.     {
  2172.       if(run_mode == GIMP_RUN_INTERACTIVE)
  2173.       {
  2174.          if(0 != p_chk_framechange(ainfo_ptr)) { l_cnt = -1; }
  2175.          else { l_cnt = p_dup_dialog(ainfo_ptr, &l_from, &l_to); }
  2176.  
  2177.          if((0 != p_chk_framechange(ainfo_ptr)) || (l_cnt < 1))
  2178.          {
  2179.             l_cnt = -1;
  2180.          }
  2181.                 
  2182.       }
  2183.       else
  2184.       {
  2185.         l_cnt  = nr;
  2186.         l_from = range_from;
  2187.         l_to   = range_to;
  2188.       }
  2189.  
  2190.       if(l_cnt > 0)
  2191.       {
  2192.          /* make l_cnt duplicate frames (on disk) */
  2193.          rc = p_dup(ainfo_ptr, l_cnt, l_from, l_to);
  2194.       }
  2195.  
  2196.  
  2197.     }
  2198.     p_free_ainfo(&ainfo_ptr);
  2199.   }
  2200.   
  2201.   return(rc);    
  2202.  
  2203.  
  2204. }    /* end gap_dup */
  2205.  
  2206.  
  2207. /* ============================================================================
  2208.  * gap_exchg
  2209.  * ============================================================================
  2210.  */
  2211.  
  2212. int gap_exchg(GimpRunModeType run_mode, gint32 image_id, int nr)
  2213. {
  2214.   int rc;
  2215.   t_anim_info *ainfo_ptr;
  2216.  
  2217.   long           l_dest;
  2218.   long           l_initial;
  2219.   gchar         *l_title;
  2220.  
  2221.   rc = -1;
  2222.   l_initial = 1;
  2223.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  2224.   if(ainfo_ptr != NULL)
  2225.   {
  2226.     if (0 == p_dir_ainfo(ainfo_ptr))
  2227.     {
  2228.       if(0 != p_chk_framerange(ainfo_ptr))   return -1;
  2229.       
  2230.       if(run_mode == GIMP_RUN_INTERACTIVE)
  2231.       {
  2232.          if(ainfo_ptr->curr_frame_nr < ainfo_ptr->last_frame_nr)
  2233.          {
  2234.            l_initial = ainfo_ptr->curr_frame_nr + 1;
  2235.          }
  2236.          else
  2237.          {
  2238.            l_initial = ainfo_ptr->last_frame_nr; 
  2239.          }
  2240.          l_title = g_strdup_printf (_("Exchange current Frame (%ld)")
  2241.                     , ainfo_ptr->curr_frame_nr);
  2242.  
  2243.          l_dest = p_slider_dialog(l_title, 
  2244.                   _("With Frame (number)"), 
  2245.                   _("Number:"), NULL
  2246.                   , ainfo_ptr->first_frame_nr 
  2247.                   , ainfo_ptr->last_frame_nr
  2248.                   , l_initial
  2249.                   , TRUE);
  2250.      g_free (l_title);
  2251.                   
  2252.          if(0 != p_chk_framechange(ainfo_ptr))
  2253.          {
  2254.             l_dest = -1;
  2255.          }
  2256.       }
  2257.       else
  2258.       {
  2259.         l_dest = nr;
  2260.       }
  2261.  
  2262.       if((l_dest >= ainfo_ptr->first_frame_nr ) && (l_dest <= ainfo_ptr->last_frame_nr ))
  2263.       {
  2264.          /* excange current frames with destination frame (on disk) */
  2265.          rc = p_exchg(ainfo_ptr, l_dest);
  2266.       }
  2267.  
  2268.  
  2269.     }
  2270.     p_free_ainfo(&ainfo_ptr);
  2271.   }
  2272.   
  2273.   return(rc);    
  2274. }    /* end gap_exchg */
  2275.  
  2276. /* ============================================================================
  2277.  * p_shift_dialog
  2278.  *
  2279.  * ============================================================================
  2280.  */
  2281. int p_shift_dialog(t_anim_info *ainfo_ptr, long *range_from, long *range_to)
  2282. {
  2283.   static t_arr_arg  argv[3];
  2284.   gchar            *l_title;
  2285.  
  2286.   l_title = g_strdup_printf (_("Framesequence Shift (%ld/%ld)")
  2287.                  , ainfo_ptr->curr_frame_nr
  2288.                  , ainfo_ptr->frame_cnt);
  2289.  
  2290.   p_init_arr_arg(&argv[0], WGT_INT_PAIR);
  2291.   argv[0].label_txt = _("From:");
  2292.   argv[0].constraint = TRUE;
  2293.   argv[0].int_min   = (gint)ainfo_ptr->first_frame_nr;
  2294.   argv[0].int_max   = (gint)ainfo_ptr->last_frame_nr;
  2295.   argv[0].int_ret   = (gint)ainfo_ptr->curr_frame_nr;
  2296.   argv[0].help_txt  = _("Affected Range starts at this framenumber");
  2297.  
  2298.   p_init_arr_arg(&argv[1], WGT_INT_PAIR);
  2299.   argv[1].label_txt = _("To:");
  2300.   argv[1].constraint = TRUE;
  2301.   argv[1].int_min   = (gint)ainfo_ptr->first_frame_nr;
  2302.   argv[1].int_max   = (gint)ainfo_ptr->last_frame_nr;
  2303.   argv[1].int_ret   = (gint)ainfo_ptr->last_frame_nr;
  2304.   argv[1].help_txt  = _("Affected Range ends at this framenumber");
  2305.     
  2306.   p_init_arr_arg(&argv[2], WGT_INT_PAIR);
  2307.   argv[2].label_txt = _("N-Shift:");
  2308.   argv[2].constraint = TRUE;
  2309.   argv[2].int_min   = -1 * (gint)ainfo_ptr->last_frame_nr;
  2310.   argv[2].int_max   = (gint)ainfo_ptr->last_frame_nr;
  2311.   argv[2].int_ret   = 1;
  2312.   argv[2].help_txt  = _("Renumber the affected framesequence     \n(numbers are shifted in circle by N)");
  2313.   
  2314.   if(TRUE == p_array_dialog(l_title, _("Framesequence shift"),  3, argv))
  2315.   { 
  2316.     g_free (l_title);
  2317.     *range_from = (long)(argv[0].int_ret);
  2318.     *range_to   = (long)(argv[1].int_ret);
  2319.     return (int)(argv[2].int_ret);
  2320.   }
  2321.   else
  2322.   {
  2323.     g_free (l_title);
  2324.     return 0;
  2325.   }
  2326.    
  2327.  
  2328. }    /* end p_shift_dialog */
  2329.  
  2330.  
  2331. /* ============================================================================
  2332.  * gap_shift
  2333.  * ============================================================================
  2334.  */
  2335. int gap_shift(GimpRunModeType run_mode, gint32 image_id, int nr,
  2336.             long range_from, long range_to)
  2337. {
  2338.   int rc;
  2339.   t_anim_info *ainfo_ptr;
  2340.  
  2341.   long           l_cnt, l_from, l_to;
  2342.  
  2343.   rc = -1;
  2344.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  2345.   if(ainfo_ptr != NULL)
  2346.   {
  2347.     if (0 == p_dir_ainfo(ainfo_ptr))
  2348.     {
  2349.       if(run_mode == GIMP_RUN_INTERACTIVE)
  2350.       {
  2351.          l_cnt = 1;
  2352.          if(0 != p_chk_framechange(ainfo_ptr)) { l_cnt = 0; }
  2353.          else { l_cnt = p_shift_dialog(ainfo_ptr, &l_from, &l_to); }
  2354.  
  2355.          if((0 != p_chk_framechange(ainfo_ptr)) || (l_cnt == 0))
  2356.          {
  2357.             l_cnt = 0;
  2358.          }
  2359.                 
  2360.       }
  2361.       else
  2362.       {
  2363.         l_cnt  = nr;
  2364.         l_from = range_from;
  2365.         l_to   = range_to;
  2366.       }
  2367.  
  2368.       if(l_cnt != 0)
  2369.       {
  2370.          /* shift framesquence by l_cnt frames 
  2371.           * (rename all frames in the given range on disk)
  2372.           */
  2373.          rc = p_shift(ainfo_ptr, l_cnt, l_from, l_to);
  2374.       }
  2375.  
  2376.  
  2377.     }
  2378.     p_free_ainfo(&ainfo_ptr);
  2379.   }
  2380.   
  2381.   return(rc);    
  2382.  
  2383.  
  2384. }    /* end gap_shift */
  2385.  
  2386.  
  2387. /* ============================================================================
  2388.  * gap_video_paste Buffer procedures
  2389.  * ============================================================================
  2390.  */
  2391.  
  2392. gchar *
  2393. p_get_video_paste_basename(void)
  2394. {
  2395.   gchar *l_basename;
  2396.   
  2397.   l_basename = p_gimp_gimprc_query("video-paste-basename");
  2398.   if(l_basename == NULL)
  2399.   {
  2400.      l_basename = g_strdup("gap_video_pastebuffer_");
  2401.   }
  2402.   return(l_basename);
  2403. }
  2404.  
  2405. gchar *
  2406. p_get_video_paste_dir(void)
  2407. {
  2408.   gchar *l_dir;
  2409.   gint   l_len;
  2410.   
  2411.   l_dir = p_gimp_gimprc_query("video-paste-dir");
  2412.   if(l_dir == NULL)
  2413.   {
  2414.      l_dir = g_strdup("/tmp");
  2415.   }
  2416.   
  2417.   /* if dir is configured with trailing dir seprator slash
  2418.    * then cut it off
  2419.    */
  2420.   l_len = strlen(l_dir);
  2421.   if((l_dir[l_len -1] == G_DIR_SEPARATOR) && (l_len > 1))
  2422.   {
  2423.      l_dir[l_len -1] = '\0';
  2424.   }
  2425.   return(l_dir);
  2426. }
  2427.  
  2428. gchar *
  2429. p_get_video_paste_name(void)
  2430. {
  2431.   gchar *l_dir;
  2432.   gchar *l_basename;
  2433.   gchar *l_video_name;
  2434.   gchar *l_dir_thumb;
  2435.      
  2436.   l_dir = p_get_video_paste_dir();
  2437.   l_basename = p_get_video_paste_basename();
  2438.   l_video_name = g_strdup_printf("%s%s%s", l_dir, G_DIR_SEPARATOR_S, l_basename);
  2439.   l_dir_thumb = g_strdup_printf("%s%s%s", l_dir, G_DIR_SEPARATOR_S, ".xvpics");
  2440.  
  2441.   mkdir (l_dir_thumb, 0755);
  2442.  
  2443.   g_free(l_dir);
  2444.   g_free(l_basename);
  2445.   g_free(l_dir_thumb);
  2446.  
  2447.   if(gap_debug) printf("p_get_video_paste_name: %s\n", l_video_name);
  2448.   return(l_video_name); 
  2449. }
  2450.  
  2451. static gint32
  2452. p_clear_or_count_video_paste(gint delete_flag)
  2453. {
  2454.   gchar *l_dir;
  2455.   gchar *l_basename;
  2456.   gchar *l_filename;
  2457.   gchar *l_fname_thumbnail;
  2458.   gint   l_len;
  2459.   gint32 l_framecount;
  2460.   DIR           *l_dirp;
  2461.   struct dirent *l_dp;
  2462.  
  2463.   l_dir = p_get_video_paste_dir();
  2464.   l_dirp = opendir(l_dir);  
  2465.   l_framecount = 0;
  2466.   
  2467.   if(!l_dirp)
  2468.   {
  2469.     printf("ERROR p_vid_edit_clear: can't read directory %s\n", l_dir);
  2470.     l_framecount = -1;
  2471.   }
  2472.   else
  2473.   {
  2474.      l_basename = p_get_video_paste_basename();
  2475.      
  2476.      l_len = strlen(l_basename);
  2477.      while ( (l_dp = readdir( l_dirp )) != NULL )
  2478.      {
  2479.        if(strncmp(l_basename, l_dp->d_name, l_len) == 0)
  2480.        {
  2481.           l_filename = g_strdup_printf("%s%s%s", l_dir, G_DIR_SEPARATOR_S, l_dp->d_name);
  2482.           if(1 == p_file_exists(l_filename)) /* check for regular file */
  2483.       {
  2484.              /* delete all files in the video paste directory
  2485.           * with names matching the basename part
  2486.           */
  2487.          l_framecount++;
  2488.          if(delete_flag)
  2489.          {
  2490.             if(gap_debug) printf("p_vid_edit_clear: remove file %s\n", l_filename);
  2491.         remove(l_filename);
  2492.  
  2493.         /* also delete thumbnail */
  2494.             l_fname_thumbnail = p_alloc_fname_thumbnail(l_filename);
  2495.             remove(l_fname_thumbnail);
  2496.                 g_free(l_fname_thumbnail);
  2497.          }
  2498.       }
  2499.           g_free(l_filename);
  2500.        }
  2501.      }
  2502.      closedir( l_dirp );
  2503.      g_free(l_basename);
  2504.    }
  2505.    g_free(l_dir);
  2506.    return(l_framecount);
  2507. }
  2508.  
  2509. gint32
  2510. p_vid_edit_clear(void)
  2511. {
  2512.   return(p_clear_or_count_video_paste(TRUE)); /* delete frames */
  2513. }
  2514.  
  2515. gint32
  2516. p_vid_edit_framecount()
  2517. {
  2518.   return (p_clear_or_count_video_paste(FALSE)); /* delete_flag is off, just count frames */
  2519. }
  2520.  
  2521.  
  2522. /* ============================================================================
  2523.  * gap_vid_edit_copy
  2524.  * ============================================================================
  2525.  */
  2526. gint
  2527. gap_vid_edit_copy(GimpRunModeType run_mode, gint32 image_id, long range_from, long range_to)
  2528. {
  2529.   int rc;
  2530.   t_anim_info *ainfo_ptr;
  2531.   
  2532.   gchar *l_curr_name;
  2533.   gchar *l_fname ;
  2534.   gchar *l_fname_copy;
  2535.   gchar *l_basename;
  2536.   gint32 l_frame_nr;
  2537.   gint32 l_cnt_range;
  2538.   gint32 l_cnt2;
  2539.   gint32 l_idx;
  2540.   gint32 l_tmp_image_id;
  2541.  
  2542.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  2543.   if(ainfo_ptr == NULL)
  2544.   {
  2545.      return (-1);
  2546.   }
  2547.   rc = 0;
  2548.  
  2549.   if((ainfo_ptr->curr_frame_nr >= MIN(range_to, range_from))
  2550.   && (ainfo_ptr->curr_frame_nr <= MAX(range_to, range_from)))
  2551.   {
  2552.     /* current frame is in the affected range
  2553.      * so we have to save current frame to file
  2554.      */   
  2555.     l_curr_name = p_alloc_fname(ainfo_ptr->basename, ainfo_ptr->curr_frame_nr, ainfo_ptr->extension);
  2556.     p_save_named_frame(ainfo_ptr->image_id, l_curr_name);
  2557.     g_free(l_curr_name);
  2558.   }
  2559.   
  2560.   l_basename = p_get_video_paste_name();
  2561.   l_cnt2 = p_vid_edit_framecount();  /* count frames in the video paste buffer */
  2562.   l_frame_nr = 1 + l_cnt2;           /* start at one, or continue (append) at end +1 */
  2563.   
  2564.   l_cnt_range = 1 + MAX(range_to, range_from) - MIN(range_to, range_from);
  2565.   for(l_idx = 0; l_idx < l_cnt_range;  l_idx++)
  2566.   {
  2567.      if(rc < 0)
  2568.      {
  2569.        break;
  2570.      }
  2571.      l_fname = p_alloc_fname(ainfo_ptr->basename,
  2572.                              MIN(range_to, range_from) + l_idx,
  2573.                              ainfo_ptr->extension);
  2574.      l_fname_copy = g_strdup_printf("%s%04ld.xcf", l_basename, (long)l_frame_nr);
  2575.      
  2576.      if(strcmp(ainfo_ptr->extension, ".xcf") == 0)
  2577.      {
  2578.         rc = p_image_file_copy(l_fname, l_fname_copy);
  2579.      }
  2580.      else
  2581.      {
  2582.         /* convert other fileformats to xcf before saving to video paste buffer */
  2583.     l_tmp_image_id = p_load_image(l_fname);
  2584.     rc = p_save_named_frame(l_tmp_image_id, l_fname_copy);
  2585.     gimp_image_delete(l_tmp_image_id);
  2586.      }
  2587.      g_free(l_fname);
  2588.      g_free(l_fname_copy);
  2589.      l_frame_nr++;
  2590.   }
  2591.   p_free_ainfo(&ainfo_ptr);
  2592.   return(rc);
  2593. }    /* end gap_vid_edit_copy */
  2594.  
  2595. /* ============================================================================
  2596.  * p_custom_palette_file
  2597.  *   write a gimp palette file
  2598.  * ============================================================================
  2599.  */
  2600.  
  2601. static gint p_custom_palette_file(char *filename, guchar *rgb, gint count)
  2602. {
  2603.   FILE *l_fp;
  2604.  
  2605.   l_fp= fopen(filename, "w");
  2606.   if (l_fp == NULL)
  2607.   {
  2608.     return -1;
  2609.   }
  2610.   
  2611.   fprintf(l_fp, "GIMP Palette\n");
  2612.   fprintf(l_fp, "# this file will be overwritten each time when video frames are converted to INDEXED\n");
  2613.  
  2614.   while (count > 0)
  2615.   {
  2616.     fprintf(l_fp, "%d %d %d\tUnknown\n", rgb[0], rgb[1], rgb[2]);
  2617.     rgb+= 3;
  2618.     --count;
  2619.   }
  2620.  
  2621.  
  2622.   fclose (l_fp);
  2623.   return 0;
  2624. }    /* end p_custom_palette_file */
  2625.  
  2626.  
  2627. /* ============================================================================
  2628.  * gap_vid_edit_paste
  2629.  * ============================================================================
  2630.  */
  2631. gint
  2632. gap_vid_edit_paste(GimpRunModeType run_mode, gint32 image_id, long paste_mode)
  2633. {
  2634. #define CUSTOM_PALETTE_NAME "gap_cmap"
  2635.   int rc;
  2636.   t_anim_info *ainfo_ptr;
  2637.   
  2638.   gchar *l_curr_name;
  2639.   gchar *l_fname ;
  2640.   gchar *l_fname_copy;
  2641.   gchar *l_basename;
  2642.   gint32 l_frame_nr;
  2643.   gint32 l_dst_frame_nr;
  2644.   gint32 l_cnt2;
  2645.   gint32 l_lo, l_hi;
  2646.   gint32 l_insert_frame_nr;
  2647.   gint32 l_tmp_image_id;
  2648.   gint       l_rc;
  2649.   GimpParam     *l_params;
  2650.   gint        l_retvals;
  2651.   GimpImageBaseType  l_orig_basetype;
  2652.  
  2653.   l_cnt2 = p_vid_edit_framecount();
  2654.   if(gap_debug)
  2655.   {
  2656.     printf("gap_vid_edit_paste: paste_mode %d found %d frames to paste\n"
  2657.            , (int)paste_mode, (int)l_cnt2);
  2658.   }
  2659.   if (l_cnt2 < 1)
  2660.   {
  2661.     return(0);  /* video paste buffer is empty */
  2662.   }
  2663.  
  2664.  
  2665.   ainfo_ptr = p_alloc_ainfo(image_id, run_mode);
  2666.   if(ainfo_ptr == NULL)
  2667.   {
  2668.      return (-1);
  2669.   }
  2670.   if (0 != p_dir_ainfo(ainfo_ptr))
  2671.   {
  2672.      return (-1);
  2673.   }
  2674.  
  2675.   rc = 0;
  2676.  
  2677.   l_insert_frame_nr = ainfo_ptr->curr_frame_nr;
  2678.  
  2679.   if(paste_mode != VID_PASTE_INSERT_AFTER)
  2680.   {
  2681.     /* we have to save current frame to file */   
  2682.     l_curr_name = p_alloc_fname(ainfo_ptr->basename, ainfo_ptr->curr_frame_nr, ainfo_ptr->extension);
  2683.     p_save_named_frame(ainfo_ptr->image_id, l_curr_name);
  2684.     g_free(l_curr_name);
  2685.   }
  2686.   
  2687.   if(paste_mode != VID_PASTE_REPLACE)
  2688.   {
  2689.      if(paste_mode == VID_PASTE_INSERT_AFTER)
  2690.      {
  2691.        l_insert_frame_nr = ainfo_ptr->curr_frame_nr +1;
  2692.      }
  2693.     
  2694.      /* rename (renumber) all frames with number greater (or greater equal)  than current
  2695.       */
  2696.      l_lo   = ainfo_ptr->last_frame_nr;
  2697.      l_hi   = l_lo + l_cnt2;
  2698.  
  2699.      if(gap_debug)
  2700.      {
  2701.        printf("gap_vid_edit_paste: l_insert_frame_nr %d l_lo:%d l_hi:%d\n"
  2702.            , (int)l_insert_frame_nr, (int)l_lo, (int)l_hi);
  2703.      }
  2704.      
  2705.      while(l_lo >= l_insert_frame_nr)
  2706.      {     
  2707.        if(0 != p_rename_frame(ainfo_ptr, l_lo, l_hi))
  2708.        {
  2709.           gchar *tmp_errtxt;
  2710.           tmp_errtxt = g_strdup_printf(_("Error: could not rename frame %ld to %ld"), l_lo, l_hi);
  2711.           p_msg_win(ainfo_ptr->run_mode, tmp_errtxt);
  2712.       g_free(tmp_errtxt);
  2713.           return -1;
  2714.        }
  2715.        l_lo--;
  2716.        l_hi--;
  2717.      }
  2718.   }
  2719.  
  2720.   l_basename = p_get_video_paste_name();
  2721.   l_dst_frame_nr = l_insert_frame_nr;
  2722.   for(l_frame_nr = 1; l_frame_nr <= l_cnt2; l_frame_nr++)
  2723.   {
  2724.      l_fname = p_alloc_fname(ainfo_ptr->basename,
  2725.                              l_dst_frame_nr,
  2726.                              ainfo_ptr->extension);
  2727.      l_fname_copy = g_strdup_printf("%s%04ld.xcf", l_basename, (long)l_frame_nr);
  2728.  
  2729.      l_tmp_image_id = p_load_image(l_fname_copy);
  2730.      
  2731.      /* check size and resize if needed */
  2732.      if((gimp_image_width(l_tmp_image_id) != gimp_image_width(image_id))
  2733.      || (gimp_image_height(l_tmp_image_id) != gimp_image_height(image_id)))
  2734.      {
  2735.          GimpParam     *l_params;
  2736.          gint        l_retvals;
  2737.      gint32      l_size_x, l_size_y;
  2738.  
  2739.          l_size_x = gimp_image_width(image_id);
  2740.          l_size_y = gimp_image_height(image_id);
  2741.      if(gap_debug) printf("DEBUG: scale to size %d %d\n", (int)l_size_x, (int)l_size_y);
  2742.  
  2743.          l_params = gimp_run_procedure ("gimp_image_scale",
  2744.                      &l_retvals,
  2745.                      GIMP_PDB_IMAGE,    l_tmp_image_id,
  2746.                      GIMP_PDB_INT32,    l_size_x,
  2747.                      GIMP_PDB_INT32,    l_size_y,
  2748.                      GIMP_PDB_END);
  2749.  
  2750.  
  2751.      }
  2752.      
  2753.      /* check basetype and convert if needed */
  2754.      l_orig_basetype = gimp_image_base_type(image_id);
  2755.      if(gimp_image_base_type(l_tmp_image_id) != l_orig_basetype)
  2756.      {
  2757.        switch(l_orig_basetype)
  2758.        {
  2759.            gchar      *l_palette_filename;
  2760.            gchar      *l_gimp_dir;
  2761.            guchar     *l_cmap;
  2762.            gint        l_ncolors;
  2763.  
  2764.            /* convert tmp image to dest type */
  2765.            case GIMP_INDEXED:
  2766.              l_cmap = gimp_image_get_cmap(image_id, &l_ncolors);
  2767.              if(gap_debug) printf("DEBUG: convert to INDEXED %d colors\n", (int)l_ncolors);
  2768.  
  2769.              l_params = gimp_run_procedure ("gimp_gimprc_query",
  2770.                                 &l_retvals,
  2771.                                 GIMP_PDB_STRING, "gimp_dir",
  2772.                                 GIMP_PDB_END);
  2773.  
  2774.              l_gimp_dir = g_strdup(l_params[1].data.d_string);
  2775.              gimp_destroy_params(l_params, l_retvals);
  2776.  
  2777.              l_palette_filename = g_strdup_printf("%s%spalettes%s%s"
  2778.                                                  , l_gimp_dir
  2779.                                                  , G_DIR_SEPARATOR_S
  2780.                                                  , G_DIR_SEPARATOR_S
  2781.                                                  , CUSTOM_PALETTE_NAME);
  2782.  
  2783.              l_rc = p_custom_palette_file(l_palette_filename, l_cmap, l_ncolors);
  2784.              if(l_rc == 0)
  2785.              {
  2786.                l_params = gimp_run_procedure ("gimp_palette_refresh",
  2787.                                 &l_retvals,
  2788.                                 GIMP_PDB_END);
  2789.                gimp_destroy_params(l_params, l_retvals);
  2790.                
  2791.                l_params = gimp_run_procedure ("gimp_convert_indexed",
  2792.                                 &l_retvals,
  2793.                                 GIMP_PDB_IMAGE,    l_tmp_image_id,
  2794.                                 GIMP_PDB_INT32,    1,               /* dither  value 1== floyd-steinberg */
  2795.                                 GIMP_PDB_INT32,    4,               /* palette_type 4 == CUSTOM_PALETTE */
  2796.                                 GIMP_PDB_INT32,    l_ncolors,       /* number of colors */
  2797.                                 GIMP_PDB_INT32,    0,               /* alpha_dither */
  2798.                                 GIMP_PDB_INT32,    0,               /* remove_unused */
  2799.                                 GIMP_PDB_STRING,   CUSTOM_PALETTE_NAME, /* name of the custom palette */
  2800.                                 GIMP_PDB_END);
  2801.                gimp_destroy_params(l_params, l_retvals);
  2802.              }
  2803.              else
  2804.              {
  2805.                printf("ERROR: gap_vid_edit_paste: could not save custom palette %s\n", l_palette_filename);
  2806.              }
  2807.              g_free(l_cmap);
  2808.              g_free(l_palette_filename);
  2809.              g_free(l_gimp_dir);          
  2810.              break;
  2811.  
  2812.            case GIMP_GRAY:
  2813.              if(gap_debug) printf("DEBUG: convert to GRAY'\n");
  2814.              l_params = gimp_run_procedure ("gimp_convert_grayscale",
  2815.                               &l_retvals,
  2816.                               GIMP_PDB_IMAGE,    l_tmp_image_id,
  2817.                               GIMP_PDB_END);
  2818.              gimp_destroy_params(l_params, l_retvals);
  2819.              break;
  2820.  
  2821.            case GIMP_RGB:
  2822.              if(gap_debug) printf("DEBUG: convert to RGB'\n");
  2823.              l_params = gimp_run_procedure ("gimp_convert_rgb",
  2824.                               &l_retvals,
  2825.                               GIMP_PDB_IMAGE,    l_tmp_image_id,
  2826.                               GIMP_PDB_END);
  2827.              gimp_destroy_params(l_params, l_retvals);
  2828.              break;
  2829.  
  2830.            default:
  2831.              printf( "DEBUG: unknown image type\n");
  2832.              return -1;
  2833.              break;
  2834.         }
  2835.      }
  2836.      rc = p_save_named_frame(l_tmp_image_id, l_fname);
  2837.      gimp_image_delete(l_tmp_image_id);
  2838.      g_free(l_fname);
  2839.      g_free(l_fname_copy);
  2840.  
  2841.      l_dst_frame_nr++;
  2842.   }
  2843.   
  2844.   if((rc >= 0)  && (paste_mode != VID_PASTE_INSERT_AFTER))
  2845.   {
  2846.     /* load from the "new" current frame */   
  2847.     if(ainfo_ptr->new_filename != NULL) g_free(ainfo_ptr->new_filename);
  2848.     ainfo_ptr->new_filename = p_alloc_fname(ainfo_ptr->basename,
  2849.                                       ainfo_ptr->curr_frame_nr,
  2850.                                       ainfo_ptr->extension);
  2851.     rc = p_load_named_frame(ainfo_ptr->image_id, ainfo_ptr->new_filename);
  2852.   }
  2853.   
  2854.   p_free_ainfo(&ainfo_ptr);
  2855.   
  2856.   return(rc);
  2857. }    /* end gap_vid_edit_paste */
  2858.  
  2859.  
  2860. gint32
  2861. p_getpid(void)
  2862. {
  2863. #ifndef G_OS_WIN32
  2864.   /* for UNIX */
  2865.   return ((gint32)getpid());
  2866. #else
  2867.   /* hof: dont know how to getpid on windows */
  2868.   return 0;
  2869. #endif
  2870. }
  2871.  
  2872. gint 
  2873. p_pid_is_alive(gint32 pid)
  2874. {
  2875. #ifndef G_OS_WIN32
  2876.   /* for UNIX */
  2877.  
  2878.   /* kill  with signal 0 checks only if the process is alive (no signal is sent)
  2879.    *       returns 0 if alive, 1 if no process with given pid found.
  2880.    */
  2881.   if (0 == kill(pid, 0))
  2882.   {
  2883.     return(TRUE);
  2884.   }
  2885.   return (FALSE);
  2886. #else
  2887.   /* hof: dont know how to check on Windows
  2888.    *      assume that process is always alive
  2889.    *      (therefore on Windows locks will not be cleared 
  2890.    *       automatically after crashes of the locking process)
  2891.    */
  2892.   return(TRUE);
  2893. #endif
  2894. }
  2895.  
  2896. static void
  2897. p_gap_lock_build_lockkey(t_gap_lockdata *lock,  gint32 image_id)
  2898. {
  2899.   g_snprintf(lock->key, sizeof(lock->key), "plug_in_gap_plugins_LOCK_%d", (int)image_id);
  2900. }
  2901.  
  2902. gint
  2903. p_gap_lock_is_locked(gint32 image_id, GimpRunModeType run_mode)
  2904. {
  2905.   gint32          l_pid;
  2906.   t_gap_lockdata  l_lock;
  2907.   
  2908.   /* check for locks */
  2909.   l_pid = p_getpid();
  2910.   l_lock.lock = 0;
  2911.   p_gap_lock_build_lockkey(&l_lock, image_id);  
  2912.   gimp_get_data (l_lock.key, &l_lock);
  2913.  
  2914.   if((l_lock.lock != 0) && (l_lock.image_id == image_id))
  2915.   {
  2916.      if(p_pid_is_alive(l_lock.pid))
  2917.      {
  2918.        if(run_mode == GIMP_RUN_INTERACTIVE)
  2919.        {
  2920.           gchar *l_lockmsg;
  2921.        
  2922.           l_lockmsg = g_strdup_printf(_("Can't execute more than 1 Video Function\n"
  2923.                                         "on the same AnimFrame Image at the same time\n"
  2924.                                         "LOCK ID:%s\n")
  2925.                                    , l_lock.key);
  2926.           gimp_message(l_lockmsg);
  2927.           g_free(l_lockmsg);
  2928.        }
  2929.        printf("GAP plugin is LOCKED  ID:%s PID:%d\n", l_lock.key, (int)l_lock.pid);
  2930.        
  2931.        return(TRUE);
  2932.      }
  2933.   }
  2934.   return(FALSE);
  2935. }
  2936.  
  2937. void
  2938. p_gap_lock_set(gint32 image_id)
  2939. {
  2940.   t_gap_lockdata  l_lock;
  2941.   
  2942.   p_gap_lock_build_lockkey(&l_lock, image_id);  
  2943.  
  2944.   /* set LOCK on image (for all gap_plugins) */
  2945.   l_lock.lock = 1;
  2946.   l_lock.image_id = image_id;
  2947.   l_lock.pid = p_getpid();
  2948.   gimp_set_data (l_lock.key, &l_lock, sizeof(l_lock));
  2949. }
  2950.  
  2951. void
  2952. p_gap_lock_remove(gint32 image_id)
  2953. {
  2954.   t_gap_lockdata  l_lock;
  2955.   
  2956.   p_gap_lock_build_lockkey(&l_lock, image_id);  
  2957.  
  2958.   /* remove LOCK on this image for all gap_plugins */
  2959.   l_lock.lock = 0;
  2960.   l_lock.image_id = -1;
  2961.   gimp_set_data (l_lock.key, &l_lock, sizeof(l_lock));
  2962. }
  2963.