/*
Copyright (c) 2000-2010, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above 
  opyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of the Dirk Krause nor the names of
  contributors may be used to endorse or promote
  products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/


/**	@file	dkwftreg.c	The dkwftreg program.

This program set the PATH environment variable on windows
system and add registry keys for explorer context menus.
*/

#include <stdio.h>
#include <process.h>
#include <io.h>




#line 51 "dkwftreg.ctr"



/** Command: Install bmeps file context menu entries. */
#define CMD_BMEPS_FILE		1

/** Command: Install fig2vect file context menu entries. */
#define CMD_FIG2VECT_FILE	2

/** Command: Install tracecc GUI directory context menu entries. */
#define CMD_TRACECC_DIR		4

/** Command: Install bmeps GUI directory context menu entries. */
#define CMD_BMEPS_DIR		8

/** Command: Install fig2vect directory context menu entries. */
#define CMD_FIG2VECT_DIR	16


#include "dkstr.h"
#include "dksf.h"

#include <windows.h>



/** Size for buffers. */
#define LINESIZE 1024



/** Exit status. */
static int exval = 0;



/** Installation command. */
static int install_cmd = (
  CMD_BMEPS_FILE
  | CMD_BMEPS_DIR
  | CMD_TRACECC_DIR
  | CMD_FIG2VECT_FILE
  | CMD_FIG2VECT_DIR
);



/** Data to register context menu entries. */
typedef struct {
  char  *tt;  /**< Title text. */
  char  *cm;  /**< Command to run. */
  char	*ar;  /**< Command arguments. */
} FileAction;



/** Default installation directory name. */
static char default_base_dir[] = { "C:\\Programme\\Krause" };

/** Buffer 1. */
static char buffer1[1024];

/** Buffer 2. */
static char buffer2[1024];

/** String -jar. */
static char part1[] = { "-jar " };

/** String: bmeps GUI jar file. */
static char part2[] = { "\\bin\\bmepsgui.jar" };

/** String: tracecc GUI jar file. */
static char part3[] = { "\\bin\\tracegui.jar" };

/** String: Argument 1. */
static char fn1[] = { "\"%1\"" };

/** String: Space. */
static char str_sp[] = { " " };

/** String: double quote. */
static char str_dq[] = { "\"" };



/**	File context menu entries for bmeps.
*/
FileAction bmeps_actions[] = {
  {
    "bmeps: Convert to BoundingBox",
    "bmeps.exe",
    "-lbb -a \"%1\""
  },
  {
    "bmeps: Convert to EPS1",
    "bmeps.exe",
    "-leps1 -a \"%1\""
  },
  {
    "bmeps: Convert to EPS2",
    "bmeps.exe",
    "-leps2 -a \"%1\""
  },
  {
    "bmeps: Convert to EPS3",
    "bmeps.exe",
    "-leps3 -a \"%1\""
  },
  {
    "bmeps: Convert to PDF",
    "bmeps.exe",
    "-lpdf -a -A \"%1\""
  },

  { NULL, NULL, NULL }
};




/**	File context menu entries for bmeps (Fax to PDF).
*/
FileAction bmeps_fax_actions[] = {
  {
    "bmeps: Fax to PDF",
    "bmeps.exe",
    "-lfaxpdf -a -A \"%1\""
  },
  { NULL, NULL, NULL }
};



/**	Directory context menu entries for tracecc GUI.
*/
FileAction tracecc_actions[] = {
  {
    "Open in Tracecc GUI",
    "javaw.exe",
    NULL
  },
  { NULL, NULL, NULL }
};



/**	Directory context menu entries for bmeps GUI.
*/
FileAction bmeps_dir_actions[] = {
  {
    "Open in Bmeps GUI",
    "javaw.exe",
    NULL
  },
  { NULL, NULL, NULL }
};



/**	File context menu entries for fig2vect.
*/
FileAction fig2vect_actions[] = {
  {
    "fig2vect: Convert to EPS",
    "fig2vect.exe",
    "-leps -a --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to PDF",
    "fig2vect.exe",
    "-lpdf -a --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to EPS.TEX",
    "fig2vect.exe",
    "-leps.tex -a --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to PDF.TEX",
    "fig2vect.exe",
    "-lpdf.tex -a --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to TEX",
    "fig2vect.exe",
    "-ltex -a --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to TEX FULL",
    "fig2vect.exe",
    "-ltex.full -a --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to BB",
    "fig2vect.exe",
    "-lbb -a --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to SVG",
    "fig2vect.exe",
    "-lsvg -a --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  { NULL, NULL, NULL}
};



/**	Directory contenxt menu entries for fig2vect.
*/
FileAction fig2vect_directory_actions[] = {
  {
    "fig2vect: Convert to EPS",
    "fig2vect.exe",
    "-leps -a -m- --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to PDF",
    "fig2vect.exe",
    "-lpdf -a -m- --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to EPS.TEX",
    "fig2vect.exe",
    "-leps.tex -a -m- --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to PDF.TEX",
    "fig2vect.exe",
    "-lpdf.tex -a -m- --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to TEX",
    "fig2vect.exe",
    "-ltex -a -m- --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to EPS FULL",
    "fig2vect.exe",
    "-ltex.full -a -m- --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to BB",
    "fig2vect.exe",
    "-lbb -a -m- --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to SVG",
    "fig2vect.exe",
    "-lsvg -a -m- --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to EPS (make)",
    "fig2vect.exe",
    "-leps -a -m --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to PDF (make)",
    "fig2vect.exe",
    "-lpdf -a -m --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to EPS.TEX (make)",
    "fig2vect.exe",
    "-leps.tex -a -m --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to PDF.TEX (make)",
    "fig2vect.exe",
    "-lpdf.tex -a -m --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to TEX (make)",
    "fig2vect.exe",
    "-ltex -a -m --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to EPS FULL (make)",
    "fig2vect.exe",
    "-ltex.full -a -m --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to BB (make)",
    "fig2vect.exe",
    "-lbb -a -m --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  {
    "fig2vect: Convert to SVG (make)",
    "fig2vect.exe",
    "-lsvg -a -m --/log/stdout/level=none --/log/stderr/level=progress \"%1\""
  },
  { NULL, NULL, NULL}
};


/** Subdirectory bin. */
static char subdirectory[] = { "\\bin" };

/** Name of environment variable to change. */
static char str_path[] = { "PATH" };

/** String: Registry key name for environment variables. */
static char str_key[] =
{ "System\\CurrentControlSet\\Control\\Session Manager\\Environment" };

/** String: semicolon. */
static char str_semicolon[] = { ";" };



/**	Get environment variable.
	@param	b	Result buffer.
	@param	s	Size of \a b in bytes.
	@param	n	Variable name.
	@return	1 on success, 0 on error.
*/
static
int
get_environment_variable(char *b, size_t s, char *n) {
  int back = 0;
  LONG result;
  HKEY base = HKEY_LOCAL_MACHINE;
  HKEY reskey;
  DWORD dwType, dwSz;
  
  result = RegCreateKeyExA(
    base, str_key, (DWORD)0, NULL, REG_OPTION_NON_VOLATILE,
    KEY_ALL_ACCESS, NULL, &reskey, NULL
  );
  if(result == ERROR_SUCCESS) {	
    dwType = REG_SZ; dwSz = s;
    result = RegQueryValueExA(reskey, n, NULL, &dwType, (BYTE *)b, &dwSz);
    if(result == ERROR_SUCCESS) {	
      if((dwType == REG_SZ) || (REG_EXPAND_SZ)) {		
	if(dwSz > 0) {			
	  b[(dwSz < s) ? dwSz : (s-1)] = '\0';
	  back = 1;
	  
	} else {			
	}
      } else {				
        if(dwType == REG_EXPAND_SZ) {	
	}
      }
    } else {				
    }
    RegCloseKey(reskey);
  } else {	
  }
  
  return back;
}



/**	Set new value for environment variable.
	@param	k	Variable name.
	@param	v	New value.
	@return	1 on success, 0 on error.
*/
static
int
set_environment_variable(char *k, char *v) {
  int back = 0;
  char oldval[4096];
  LONG result;
  HKEY base = HKEY_LOCAL_MACHINE;
  HKEY reskey;
  DWORD newDwType, dwType, dwSz;
  
  result = RegCreateKeyExA(
    base, str_key, (DWORD)0, NULL, REG_OPTION_NON_VOLATILE,
    KEY_ALL_ACCESS, NULL, &reskey, NULL
  );
  if(result == ERROR_SUCCESS) {		
    newDwType = REG_SZ;
    dwType = REG_SZ; dwSz = (DWORD)sizeof(oldval);
    result = RegQueryValueExA(reskey, k, NULL, &dwType, (BYTE *)oldval, &dwSz);
    if(result == ERROR_SUCCESS) {	
      newDwType = dwType;
    }
    if((newDwType == REG_SZ) || (newDwType == REG_EXPAND_SZ)) {
      
      result = RegSetValueExA(
        reskey, k, (DWORD)0, newDwType, (BYTE *)v, (DWORD)(1+strlen(v))
      );
      if(result == ERROR_SUCCESS) { back = 1; }
    }
    RegCloseKey(reskey);
  } else {				
  } 
  return back;
}



/**	Check whether a string contains a directory.
	@param	fullpath	Entire value of PATH
	@param	dir		Directory name to search for.
	@return	1 on success, 0 on error.
*/
static
int
path_contains(char *fullpath, char *dir) {
  int back = 0;
  char *p1, *p2;
  p1 = fullpath;
  while((p1) && (back == 0)) {
    p2 = strchr(p1, ';');
    if(p2) {
      *p2 = '\0';
    }
    if(stricmp(p1, dir) == 0) {
      back = 1;
    }
    if(p2) {
      *p2 = ';'; p2++;
    }
    p1 = p2;
  }
  return back;
}



/**	Register directory in PATH environment variable.
	@param	s	Directory to register.
*/
static
void
register_directory_in_path_if_necessary(char *s) {
  char cpldir[4096];	/**< Complete directory name. */
  char oldval[4096];	/**< Current PATH environment variable. */
  char newval[4096];	/**< New PATH environment variable. */
  
  if((strlen(s) + strlen(subdirectory)) < sizeof(cpldir)) {
    strcpy(cpldir, s);
    strcat(cpldir, subdirectory);
    if(get_environment_variable(oldval, sizeof(oldval), str_path)) {
      
      if(!path_contains(oldval, cpldir)) {
        
        if((strlen(cpldir) + strlen(oldval) + 2) < sizeof(newval)) {
	  strcpy(newval, cpldir);
	  strcat(newval, str_semicolon);
	  strcat(newval, oldval);
	  
	  set_environment_variable(str_path, newval);
	}
      }
    }
  }
  
}



/**	Unregister directory from PATH environment variable.
	@param	s	Directory to remove from PATH.
*/
static
void
unregister_directory_in_path_if_necessary(char *s) {
  char cpldir[4096];	/**< Complete directory name. */
  char oldval[4096];	/**< Current PATH environment variable. */
  char newval[4096];	/**< New PATH environment variable. */
  int  values_found;	/**< Flag: this is not the first directory. */
  char *p1;		/**< Pointer to current directory. */
  char *p2;		/**< Pointer to next directory to process. */
  
  if((strlen(s) + strlen(subdirectory)) < sizeof(cpldir)) {
    strcpy(cpldir, s);
    strcat(cpldir, subdirectory);
    if(get_environment_variable(oldval, sizeof(oldval), str_path)) {
      p1 = oldval; values_found = 0;
      newval[0] = '\0';
      while(p1) {
        p2 = strchr(p1, ';');
	if(p2) { *p2 = '\0'; }
	
	if(stricmp(p1, cpldir)) {
	  if(values_found) {
	    strcat(newval, str_semicolon);
	    strcat(newval, p1);
	  } else {
	    strcpy(newval, p1);
	  }
	  values_found = 1;
	}
	if(p2) { *(p2++) = ';'; }
	p1 = p2;
      } 
      set_environment_variable(str_path, newval);
    }
  }
  
}



/**	Open a registry key.
	@param	base		Base key.
	@param	n		Name of subkey.
	@param	reskey	Pointer to HKEY to store the result.
	@return	1 on success, 0 on error.
*/
static
int
open_registry_key(HKEY base, char *n, HKEY *reskey) {
  int back = 0;
  LONG result;
  
  result = RegCreateKeyExA(
    base, n, (DWORD)0, NULL, REG_OPTION_NON_VOLATILE,
    KEY_ALL_ACCESS, NULL, reskey, NULL
  );
  if(result == ERROR_SUCCESS) {
    back = 1;
  } 
  return back;
}



/**	Set string registry entry.
	@param	hk	Key to create the entry.
	@param	n	The name of the entry.
	@param	v	Entry value.
	@return	1 on success, 0 on error.
*/
static
int
set_string_entry(HKEY hk, char *n, char *v) {
  int back = 0;
  long result;
  
  result = RegSetValueExA(
    hk, n, (DWORD)0, REG_SZ, (BYTE *)v, (DWORD)(1 + strlen(v))
  );
  if(result == ERROR_SUCCESS) { back = 1; } 
  return back;
}



/**	Retrieve string registry entry.
	@param	hk	The key to retrieve the entry from.
	@param	n	Name of the entry.
	@param	b	Buffer to store result.
	@param	sz	Result buffer size.
	@return	1 on success, 0 on error.
*/
static
int
get_string_entry(HKEY hk, char *n, char *b, size_t sz) {
  int back = 0;
  long result;
  DWORD dwSz, dwType;
  dwSz = sz; dwType = REG_SZ;
  
  result = RegQueryValueExA(
    hk, n, NULL, &dwType, (BYTE *)b, &dwSz
  ); 
  if(result == ERROR_SUCCESS) {	
    if(dwType == REG_SZ) {
    if(dwSz > 0) {	
      b[(dwSz < sz) ? dwSz : (sz - 1)] = '\0';
      back = 1;		
    }
    }
  } else {	
  } 
  return back;
}



/**	String backslash. */
static char str_bs[] = { "\\" };



/**	String "shell". */
static char str_shell[] = { "shell" };



/**	Command interpreter. */
static char str_command[] = { "command" };


/**	bin subdirectory of installation directory. */
static char str_bin[] = { "bin" };



/**	Remove a context menu entry.
	@param	act	Array listing all menu entries.
	@param	ft	File type to remove actions from.
	@param	dn	Directory where bmeps and tracecc reside.
*/
static
void
unregister_filetype_action(FileAction *act, char *ft, char *dn) {
  char keyname[LINESIZE];
  size_t sz;
  FileAction *actptr;
  
  actptr = act;

  
  
  
  while((actptr->tt) || (actptr->cm) || (actptr->ar)) {
    if(actptr->tt) {
      
      
      
      sz = strlen(ft);
      sz += 2 * strlen(str_bs);
      sz += strlen(str_shell);
      sz += strlen(actptr->tt);
      if(sz < sizeof(keyname)) {	
        sz += strlen(str_bs); sz += strlen(str_command);
	if(sz < sizeof(keyname)) {	
	  strcpy(keyname, ft);
	  strcat(keyname, str_bs);
	  strcat(keyname, str_shell);
	  strcat(keyname, str_bs);
	  strcat(keyname, actptr->tt);
	  strcat(keyname, str_bs);
	  strcat(keyname, str_command);
	  
	  RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname);
	} else {			
	}
	strcpy(keyname, ft);
	strcat(keyname, str_bs);
	strcat(keyname, str_shell);
	strcat(keyname, str_bs);
	strcat(keyname, actptr->tt);
	
	RegDeleteKeyA(HKEY_CLASSES_ROOT, keyname);
      } else {		
      }
    }
    actptr++;
  }
  
}



/**	Remove context menu entries for file name suffix.
	@param	fns	File name suffix.
	@param	act	List of context menu entries to remove.
	@param	ft	File type default.
	@param	dn	Directory name where bmeps and tracecc reside.
*/
static
void
unregister_action(char *fns, FileAction *act, char *ft, char *dn) { 
  HKEY hk;
  char filetypebuffer[LINESIZE]; int have_filetype = 0;
  
  if(open_registry_key(HKEY_CLASSES_ROOT, fns, &hk)) {
    
    if(get_string_entry(hk, "", filetypebuffer, sizeof(filetypebuffer))) {
      have_filetype = 1;	
    } else {			
      if(strlen(ft) < sizeof(filetypebuffer)) {	
        strcpy(filetypebuffer, ft); have_filetype = 1;
      }
    }	
    RegCloseKey(hk);	
    if(have_filetype) {
      if(open_registry_key(HKEY_CLASSES_ROOT, filetypebuffer, &hk)) {
        RegCloseKey(hk);
	unregister_filetype_action(act, filetypebuffer, dn);
      }
    }
  } else {		
    /* ##### FAILED TO OPEN/CREATE KEY */
  }
  unregister_filetype_action(act, ft, dn);
  
}



/**	Register context menu entries for file type.
	@param	act	List of context menu entries.
	@param	ft	File type.
	@param	dn	Directory where tracecc and bmeps reside.
*/
static
void
register_filetype_action(FileAction *act, char *ft, char *dn) {
  HKEY hk;
  char keyname[LINESIZE];
  char valuebuffer[LINESIZE];
  FileAction *actptr;
  size_t sz;
  sz = strlen(ft);
  sz += strlen(str_bs); sz += strlen(str_shell);
  if(sz < sizeof(keyname)) {
    strcpy(keyname, ft);
    strcat(keyname, str_bs); strcat(keyname, str_shell);
    if(open_registry_key(HKEY_CLASSES_ROOT, keyname, &hk)) {
      RegCloseKey(hk);
      actptr = act;
      while((actptr->tt) || (actptr->cm) || (actptr->ar)) {
        if((actptr->tt) && (actptr->cm) && (actptr->ar)) {
          sz = strlen(ft);
  	  sz += strlen(str_bs); sz += strlen(str_shell);
          sz += strlen(str_bs); sz += strlen(actptr->tt);
  	  if(sz < sizeof(keyname)) {
  	    strcpy(keyname, ft);
  	    strcat(keyname, str_bs); strcat(keyname, str_shell);
  	    strcat(keyname, str_bs); strcat(keyname, actptr->tt);
  	    if(open_registry_key(HKEY_CLASSES_ROOT, keyname, &hk)) {
  	      RegCloseKey(hk);
  	      sz += strlen(str_bs); sz += strlen(str_command);
  	      if(sz < sizeof(keyname)) {
  	        strcat(keyname, str_bs); strcat(keyname, str_command);
  	        if(open_registry_key(HKEY_CLASSES_ROOT, keyname, &hk)) {
  	          sz = strlen(actptr->cm);
  		  sz += 2 * strlen(str_dq);
  		  if(dn) {
  		    sz += strlen(dn); sz += 2 * strlen(str_bs);
  		    sz += strlen(str_bin);
  		  }
  		  sz += strlen(actptr->ar);
  		  sz += 1;
  		  if(sz < sizeof(valuebuffer)) {
  		    strcpy(valuebuffer, str_dq);
  		    if(dn) {
  		      strcat(valuebuffer, dn);
  		      strcat(valuebuffer, str_bs);
  		      strcat(valuebuffer, str_bin);
  		      strcat(valuebuffer, str_bs);
  		    }
  		    strcat(valuebuffer, actptr->cm);
  		    strcat(valuebuffer, str_dq);
  		    strcat(valuebuffer, str_sp);
  		    strcat(valuebuffer, actptr->ar);
  		    set_string_entry(hk, "", valuebuffer);
  		  }
  		  RegCloseKey(hk);
  	        }
  	      }
  	    }
  	  }
        }
        actptr++;
      }
    }
  }
}



/**	Register context menu entries for file name suffix.
	@param	fns	File name suffix.
	@param	act	List of context menu entries.
	@param	ft	Default file type name.
	@param	dn	Directory where bmeps and tracecc reside.
*/
static
void
register_action(char *fns, FileAction *act, char *ft, char *dn) {
  HKEY hk;
  char filetypebuffer[LINESIZE]; int have_filetype = 0;
  
  if(open_registry_key(HKEY_CLASSES_ROOT, fns, &hk)) {
    
    if(get_string_entry(hk, "", filetypebuffer, sizeof(filetypebuffer))) {
      have_filetype = 1;	
    } else {			
      if(strlen(ft) < sizeof(filetypebuffer)) {	
        strcpy(filetypebuffer, ft); have_filetype = 1;
      }
    }	
    RegCloseKey(hk);	
    if(have_filetype) {
      if(open_registry_key(HKEY_CLASSES_ROOT, filetypebuffer, &hk)) {
        RegCloseKey(hk);
	register_filetype_action(act, filetypebuffer, dn);
      }
    }
  } else {		
    /* ##### FAILED TO OPEN/CREATE KEY */
  } 
}



/**	Create context menu entries for bitmap files to invoke bmeps.
	@param	dirname	Installation directory name.
*/
void
BmepsContextMenuEntries(char *dirname) {
  register_action(".png",  bmeps_actions, "pngfile", dirname);
  register_action(".jpg",  bmeps_actions, "jpegfile", dirname);
  register_action(".jpeg", bmeps_actions, "jpegfile", dirname);
  register_action(".pgm",  bmeps_actions, "netpbmfile", dirname);
  register_action(".pbm",  bmeps_actions, "netpbmfile", dirname);
  register_action(".ppm",  bmeps_actions, "netpbmfile", dirname);
  register_action(".pnm",  bmeps_actions, "netpbmfile", dirname);
  register_action(".tif",  bmeps_actions, "tifffile", dirname);
  register_action(".tiff", bmeps_actions, "tifffile", dirname);
  register_action(".tif",  bmeps_fax_actions, "tifffile", dirname);
  register_action(".tiff", bmeps_fax_actions, "tifffile", dirname);
}



/**	Create context menu entries for directories to invoke bmeps.
	@param	dirname	Installation directory name.
*/
void
BmepsDirectoryContextMenuEntries(char *dirname) {
  register_filetype_action(bmeps_dir_actions, "Directory", NULL);
}



/**	Create context menu entries for directories to invoke tracecc.
	@param	dirname	Installation directory name.
*/
void
TraceccDirectoryContextMenuEntries(char *dirname) {
  register_filetype_action(tracecc_actions, "Directory", NULL);
}



/**	Create context menu entries for Fig files.
	@param	dirname	Installation directory name.
*/
void
FigContextMenuEntries(char *dirname) {
  register_action(".fig", fig2vect_actions, "figfile", dirname);
}



/**	Add context menu entries for Fig files.
	@param	dirname	Installation directory name.
*/
void
FigDirectoryContextMenuEntries(char *dirname) {
#if 0
  register_filetype_action(fig2vect_directory_actions, "Directory", dirname);
#endif
}



/**	Create context menu enries.
	@param	dirname	Installation directory name.
*/
static
void
register_actions(char *dirname) {
  
  if(install_cmd & CMD_BMEPS_FILE) {
    BmepsContextMenuEntries(dirname);
  }
  if(install_cmd & CMD_BMEPS_DIR) {
    BmepsDirectoryContextMenuEntries(dirname);
  }
  if(install_cmd & CMD_TRACECC_DIR) {
    TraceccDirectoryContextMenuEntries(dirname);
  }
  if(install_cmd & CMD_FIG2VECT_FILE) {
    FigContextMenuEntries(dirname);
  }
  if(install_cmd & CMD_FIG2VECT_DIR) {
    FigDirectoryContextMenuEntries(dirname);
  }
  
}



/**	Remove all context menu entries.
	@param	dirname	Installation directory name.
*/
void
RemoveContextMenuEntries(char *dirname) {
  
  unregister_action(".png",  bmeps_actions, "pngfile", dirname);
  unregister_action(".jpg",  bmeps_actions, "jpegfile", dirname);
  unregister_action(".jpeg", bmeps_actions, "jpegfile", dirname);
  unregister_action(".pgm",  bmeps_actions, "netpbmfile", dirname);
  unregister_action(".pbm",  bmeps_actions, "netpbmfile", dirname);
  unregister_action(".ppm",  bmeps_actions, "netpbmfile", dirname);
  unregister_action(".pnm",  bmeps_actions, "netpbmfile", dirname);
  unregister_action(".tif",  bmeps_actions, "tifffile", dirname);
  unregister_action(".tiff", bmeps_actions, "tifffile", dirname);
  unregister_action(".tif",  bmeps_fax_actions, "tifffile", dirname);
  unregister_action(".tiff", bmeps_fax_actions, "tifffile", dirname);
  unregister_action(".fig", fig2vect_actions, "figfile", dirname);
  unregister_filetype_action(bmeps_dir_actions, "Directory", NULL);
  unregister_filetype_action(tracecc_actions, "Directory", NULL);
  unregister_filetype_action(fig2vect_directory_actions, "Directory", dirname);
  
}



/**	Question, whether to install or uninstall.
*/
static char *q1[] = {
"Do you wish to install or uninstall context menu entries?",
"1   Install",
"2   Uninstall",
"q   Quit",
NULL
};



/**	Decide for install or uninstall.
	@return	0=install, 1=uninstall, -1=no action.
*/
static
int
install_or_uninstall(void) {
  char  buffer[1024];
  int back = 0, value = 0;  char **ptr;
  ptr = q1; while(*ptr) { printf("%s\n", *(ptr++)); }
  if(fgets(buffer, sizeof(buffer), stdin)) {
    if(sscanf(buffer, "%d", &value) == 1) {
      switch(value) {
        case 1: back = 0; break;
        case 2: back = 1; break;
        default: back = -1; break;
      }
    } else {
      back = -1;
    }
  } else {
    back = -1;
  }
  return back;
}



/**	Questions for install command modification.
*/
static char *q2[] = {
"Add bmeps context menu entries to bitmap files? (Y/n): ",
"Add fig2vect context menu entries to *.fig files? (Y/n): ",
"Add tracecc context menu entries to directories? (Y/n): ",
"Add bmeps context menu entries to directories (Y/N): ",
"Add fig2vect context menu entries to directories? (y/N): ",
NULL
};



/**	Modify the install command.
	@param	i	Index of question text in \a q2.
	@param	v	Value to add or remove.
	@param	d	Default answer.
	@return	Modified installation command.
*/
static
int
mod_install_cmd(int i, int v, int d) {
  char buffer[256], *p1;
  int back = 0;
  int m = d;
  printf("%s", q2[i]);
  if(fgets(buffer, sizeof(buffer), stdin)) {
    p1 = dkstr_start(buffer, NULL);
    if(p1) {
      dkstr_chomp(p1, NULL);
      if(dkstr_is_bool(p1)) {
        back = (dkstr_is_on(p1) ? v : 0);
      }
    }
  }
  if(m) {
    back = v;
  }
  return back;
}



/**	Set up buffers.
	@param	dn	Directory name (installation directory).
*/
static
void
setup_buffers(char *dn) {
  size_t sz;
  if(dn) {
    sz = strlen(part1) + strlen(dn) + strlen(part2) + strlen(fn1) + strlen(str_sp) + 3;
    if(sz < sizeof(buffer1)) {
      strcpy(buffer1, part1);
      strcat(buffer1, str_dq);
      strcat(buffer1, dn);
      strcat(buffer1, part2);
      strcat(buffer1, str_dq);
      strcat(buffer1, str_sp);
      strcat(buffer1, fn1);
      bmeps_dir_actions[0].ar = buffer1;
    }
    sz = strlen(part1) + strlen(dn) + strlen(part3) + strlen(fn1) + strlen(str_sp) + 3;
    if(sz < sizeof(buffer2)) {
      strcpy(buffer2, part1);
      strcat(buffer2, str_dq);
      strcat(buffer2, dn);
      strcat(buffer2, part3);
      strcat(buffer2, str_dq);
      strcat(buffer2, str_sp);
      strcat(buffer2, fn1);
      tracecc_actions[0].ar = buffer2;
    }
  }
}



/**	Modify PATH environmetn variable to remove dktools.
*/
static
void
modify_path_to_remove_dklibs(void) {
  int have_directory	= 0;	/**< Flag: Have directory name to remove. */
  char dirname[4096];		/**< Base directory to remove from PATH. */
  HKEY reskey;			/**< Registry key. */
  LONG result;			/**< Registry operation result. */
  DWORD	dwType;			/**< Registry entry type. */
  DWORD dwSz;			/**< Registry entry value buffer size. */
  result = RegCreateKeyExA(
    HKEY_LOCAL_MACHINE, "Software\\DkApp", (DWORD)0, NULL,
    REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &reskey, NULL
  );
  if(result == ERROR_SUCCESS) {
    dwType = REG_SZ; dwSz = sizeof(dirname);
    result = RegQueryValueExA(
      reskey, "DIRECTORY", NULL, &dwType, (BYTE *)dirname, &dwSz
    );
    if(result == ERROR_SUCCESS) {
      if(dwType == REG_SZ) {
        if(dwSz > 0) {
	  dirname[(dwSz < sizeof(dirname)) ? dwSz : (sizeof(dirname) - 1)]='\0';
	  have_directory = 1;
	  dksf_correct_fnsep(dirname);
	}
      }
    }
    RegCloseKey(reskey);
  }
  if(have_directory) {
    unregister_directory_in_path_if_necessary(dirname);
  }
}



#if !DKWFTREG_DLL


/**	The main() function in the dkwftreg program.
	@param	argc	number of command line arguments.
	@param	argv	Command line arguments array.
	@return	0 on success, 1 on errors.
*/
int main(int argc, char *argv[]) {
  char dirbuffer[1024];
  char	*dynbuffer = NULL;
  int cmd = 0;
  int i;
  char *directoryname = NULL;
  
#line 1131 "dkwftreg.ctr"

  

  if(argc > 1) {
    if(strcmp(argv[1], "-u") == 0) {
      cmd = 1;
    } else {
      {
        size_t sz;
	sz = 0;
        for(i = 1; i < argc; i++) {
	  sz += strlen(argv[i]);
	  sz++;
        }
	dynbuffer = malloc(sz);
	if(dynbuffer) {
	  for(i = 1; i < argc; i++) {
	    if(i == 1) {
	      strcpy(dynbuffer, argv[i]);
	    } else {
	      strcat(dynbuffer, str_sp);
	      strcat(dynbuffer, argv[i]);
	    }
	  }
	  directoryname = dynbuffer;
	} else {
	  directoryname = argv[1];
	  fprintf(stderr, "ERROR: Not enough memory!\n");
	  fflush(stderr);
	}
      }
    }
  } else {
    install_cmd = 0;
    cmd = install_or_uninstall();
    if(cmd == 0) {
      printf("Dirk Krause's Tools base directory [%s]: ", default_base_dir);
      if(fgets(dirbuffer, sizeof(dirbuffer), stdin)) {
        directoryname = dkstr_start(dirbuffer, NULL);
	if(!(directoryname)) {
	  directoryname = default_base_dir;
	} else {
	  dkstr_chomp(directoryname, NULL);
	}
      } else {
        directoryname = default_base_dir;
      }
      install_cmd |= mod_install_cmd(0, CMD_BMEPS_FILE, 1);
      install_cmd |= mod_install_cmd(1, CMD_FIG2VECT_FILE, 1);
      install_cmd |= mod_install_cmd(2, CMD_TRACECC_DIR, 1);
      install_cmd |= mod_install_cmd(3, CMD_BMEPS_DIR, 1);
      install_cmd |= mod_install_cmd(4, CMD_FIG2VECT_DIR, 0);
    }
  } 
  setup_buffers(directoryname);
  switch(cmd) {
    case -1: {} break;
    case 1: {
      RemoveContextMenuEntries(directoryname);
      modify_path_to_remove_dklibs();
    } break;
    default: {
      register_actions(directoryname);
      register_directory_in_path_if_necessary(directoryname);
    } break;
  }
  if(dynbuffer) { free(dynbuffer); }
  
  
#line 1199 "dkwftreg.ctr"

  exit(exval); return exval;
}

#endif


