Logo Search packages:      
Sourcecode: adesklets version File versions

command.c

/*--- command.c ----------------------------------------------------------------
Copyright (C) 2004, 2005 Sylvain Fourmanoit <syfou@users.sourceforge.net>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies of the Software and its documentation and acknowledgment shall be
given in the documentation and software packages that this Software was
used.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.   
------------------------------------------------------------------------------*/
/* Management routines for adesklets command interpreter, based
   on GNU readline.
 */

/*----------------------------------------------------------------------------*/
#include "command.h"          /* Adesklets command interpreter header */ 

/*----------------------------------------------------------------------------*/
       char * command_generator(const char *, int);
       char * on_off_generator (const char *, int);
extern char * image_generator  (const char *, int);
extern char * font_generator   (const char *, int);
extern char * font_generator_with_null   (const char *, int);
extern char * base_font_generator (const char *, int);
extern char * base_font_path_generator(const char *, int);
extern char * menu_generator   (const char *, int);
extern char * window_manager_generator (const char *, int);
       char * xwindow_event_generator(const char *, int);
extern char * color_range_generator (const char *, int);
extern char * color_range_generator_with_null (const char *, int);
extern char * color_modifier_generator (const char *, int);
extern char * color_modifier_generator_with_null (const char *, int);
       char * color_modifier_value_generator(const char *, int);
extern char * filter_generator (const char *, int);
extern char * filter_generator_with_null (const char *, int);
       char * direction_generator(const char *, int);
       char * operation_generator(const char *, int);
extern char * polygon_generator(const char *, int);
extern char * variable_generator(const char *,int);

/* WARNING: this array is requested to have all its 'doc' strings beginning
   with a capital letter since this characteristic is used by
   the `command_enum.sh' script as hint to perform filtering.
   For similar reasons, command names are expected to be entirely lower case. 
*/
const COMMAND COMMANDS[] = {
  { "time_gate", NULL, "Set a time gate" },
  { "help", command_generator, "Display short help about a command" },
  { "ping", NULL, "Ping the interpreter" },
  { "pause", NULL, "Freeze the interpreter for debugging" },
  { "version", NULL, "Get interpreter version" },
  { "get_id", NULL, "Get current applet identificator" },
  { "history", rl_filename_completion_function, "List/save commands history" },
  { "set", variable_generator, "Set or unset a textual variable" },
  { "unset_all", NULL, "Unset all defined textual variables" },
  { "echo" , NULL, "Echo a string" },
  { "start_recording", NULL, "Start recording a macro" },
  { "stop_recording", NULL, "Stop recording the macro" },
  { "play_get_abort_on_events", NULL,
      "Get replays interuptable status" },
  { "play_set_abort_on_events", on_off_generator, 
      "Set replays to be interuptable" },
  { "play", NULL, "Play a given macro" },
  { "context_get_dither", NULL, "Get context dither" },
  { "context_get_anti_alias", NULL, "Get context anti alias" },
  { "context_get_blend", NULL, "Get context blending"},
  { "context_get_operation", NULL, "Get context operation"},
  { "context_get_cliprect", NULL, "Get clipping rectange"},
  { "context_get_image", NULL, "Get context image" },
  { "context_get_font", NULL, "Get context font" },
  { "context_get_color_range", NULL, "Get context color range" },
  { "context_get_color_modifier", NULL, "Get context color modifier" },
  { "context_get_filter", NULL, "Get context filter" },
  { "context_get_color", NULL, "Get context color" },
  { "context_get_angle", NULL, "Get context angle" },
  { "context_get_direction", NULL, "Get context direction" },
  { "context_set_dither", on_off_generator, "Set context dither" },
  { "context_set_anti_alias", on_off_generator, "Set context anti-alias" },
  { "context_set_blend", on_off_generator, "Set context blending" },
  { "context_set_operation", operation_generator, "Set context operation" },
  { "context_set_cliprect", NULL, "Set context clipping rectangle" },
  { "context_set_image", image_generator, "Set context image" },
  { "context_set_font", font_generator_with_null, 
       "Set context font" },
  { "context_set_color_range", color_range_generator_with_null, 
       "Set context color range" },
  { "context_set_color_modifier", color_modifier_generator_with_null, 
       "Set context color modifier" },
  { "context_set_filter" , filter_generator_with_null, "Set context filter" },
  { "context_set_color", NULL, "Set context RGBA color" },
  { "context_set_angle", NULL, "Set context angle" },
  { "context_set_direction", direction_generator, "Set context direction" },
  { "add_color_to_color_range", NULL, "Add a color to a color range" },
  { "blend_image_onto_image_at_angle", image_generator, 
    "Blend images together"},
  { "blend_image_onto_image_skewed", image_generator, "Blend images together"},
  { "blend_image_onto_image", image_generator, "Blend images together" },
  { "apply_filter", NULL, "Apply a dynamic filter" },
  { "get_text_size", NULL, "Get size of text" },
  { "get_text_advance", NULL, "Get advance of text"},
  { "text_draw", NULL, "Draw a text string" },
  { "modify_color_modifier_gamma", NULL, "Modify gamma correction" },
  { "modify_color_modifier_brightness", NULL, "Modify brightness" },
  { "modify_color_modifier_contrast", NULL, "Modify contrast" },
  { "get_color_modifier_tables", NULL, "Get tables for a color modifier" },
  { "set_color_modifier_tables", NULL, "Set tables for a color modifier" },
  { "get_color_modifier_value", color_modifier_value_generator, 
       "Get a value for a color modifier" },
  { "set_color_modifier_value", color_modifier_value_generator, 
       "Set a value for a color modifier" },
  { "apply_color_modifier", NULL, "Apply a color modifier" },
  { "apply_color_modifier_to_rectangle", NULL, "Apply a color modifier" },
  { "load_image_without_cache", rl_filename_completion_function,
       "Load an image from disk bypassing the cache" },
  { "load_image", rl_filename_completion_function , "Load an image from disk" },
  { "save_image", rl_filename_completion_function , "Save an image to disk" },
  { "create_image", NULL, "Create an image" },
  { "create_image_using_data", NULL, "Create an image from data" },
  { "clone_image", NULL, "Create a copy of an image" },
  { "free_image", image_generator, "Free an image" },
  { "load_font", base_font_generator, "Load a font" },
  { "free_font", font_generator, "Free a font" },
  { "list_fonts", NULL, "List all fonts"},
  { "list_font_path", NULL, "List all fonts path"},
  { "add_path_to_font_path", rl_filename_completion_function, "Add a font path" },
  { "remove_path_from_font_path", base_font_path_generator, 
       "Remove a font path" }, 
  { "create_color_range", NULL, "Create a color range" },
  { "free_color_range", color_range_generator, "Free a color range" },
  { "create_color_modifier", NULL, "Create a color modifier" },
  { "free_color_modifier", color_modifier_generator, "Free a color modifier" },
  { "create_filter", NULL, "Create a filter"},
  { "free_filter", filter_generator, "Free a filter"},
  { "polygon_new", NULL, "Create a polygon" },
  { "polygon_free", polygon_generator, "Free a polygon"},
  { "polygon_add_point", polygon_generator, "Add point to a polygon" },
  { "images_reset_all", NULL, "Free all images and refresh foreground" },
  { "images_info", NULL, "Get information on all images"},
  { "fonts_reset_all", NULL, "Free all fonts" },
  { "fonts_info", NULL, "Get information on all fonts"},
  { "color_ranges_reset_all", NULL, "Free all color ranges" },
  { "color_ranges_info", NULL, "Get information on all color ranges" },
  { "color_modifiers_reset_all", NULL, "Free all color modifiers" },
  { "color_modifiers_info", NULL, "Get information on all color modifiers"},
  { "filters_reset_all", NULL, "Free all filters" },
  { "filters_info", NULL, "Get information on all filters" },
  { "polygons_reset_all", NULL, "Free all polygons" },
  { "polygons_info", NULL, "Get information on all polygons" },
  { "image_has_alpha", NULL, "Get alpha channel setting of an image" },
  { "image_get_width", NULL, "Get width of an image" },
  { "image_get_height", NULL, "Get height of an image" },
  { "image_get_filename", NULL, "Get filename of an image" },
  { "image_get_data"  , NULL, "Get the data of an image" },
  { "image_query_pixel", NULL, "Query a pixel value" },
  { "image_set_has_alpha", on_off_generator, "Set alpha channel of an image"},
  { "image_set_changes_on_disk", NULL, "Set image load time behavior"},
  { "image_set_format", NULL, "Set image format" },
  { "image_filter_recurse ", NULL, "Apply filter again and again to image" },
  { "image_draw_line", NULL, "Draw a line" },
  { "image_draw_rectangle", NULL, "Draw a rectangle" },
  { "image_fill_rectangle", NULL, "Draw a filled rectangle" },
  { "image_fill_color_range_rectangle", NULL, "Draw a gradian filled rectange" },
  { "image_draw_ellipse", NULL, "Draw an ellipse" },
  { "image_fill_ellipse", NULL, "Fill an ellipse" },
  { "image_copy_alpha_to_image", image_generator, "Transfert alpha channel" },
  { "image_copy_alpha_rectangle_to_image", image_generator, 
      "Transfert alpha channel" },
  { "image_draw_polygon", polygon_generator, "Draw a polygon onto image" },
  { "image_fill_polygon", polygon_generator, "Fill a polygon onto image" },
  { "image_flip_horizontal", NULL, "Flip an image horizontally" },
  { "image_flip_vertical", NULL, "Flip an image vertically" },
  { "image_flip_diagonal", NULL, "Flip an image diagonally" },
  { "image_orientate", NULL, "Orientate an image" },
  { "image_blur", NULL, "Blur an image" },
  { "image_sharpen", NULL, "Sharpen an image" },
  { "filter_set", NULL, "Set filter" },
  { "filter_set_red", NULL, "Set filter red channel" },
  { "filter_set_green", NULL, "Set filter grean channel" },
  { "filter_set_blue", NULL, "Set filter blue channel" },
  { "filter_set_alpha", NULL, "Set filter alpha channel" },
  { "filter_constants", NULL, "Set filter constants" },
  { "filter_divisors", NULL, "Set filter divisors" },
  { "menu_fire", menu_generator, "Fire a given menu"},
  { "menu_reset_all", NULL, "Reset all menus to initial state" },
  { "menu_add_menu", NULL, "Add a new menu"},
  { "menu_add_submenu", NULL, "Add a submenu to current menu" },
  { "menu_add_item", NULL, "Add an item to current menu" },
  { "menu_add_separator", NULL, "Add a separator to current menu" },
  { "menu_end_submenu", NULL, "End a submenu construction" },
  { "event_catch", xwindow_event_generator, "Set an event to catch" },
  { "event_uncatch", xwindow_event_generator, "Unset an event to catch" },
  { "events_reset_all", NULL, "Unset catching of all events" },
  { "events_info", NULL, "Get all caught events" },
  { "events_get_echo", NULL, "Get events echo status" },
  { "events_set_echo", on_off_generator, "Set events echo status" },
  { "events_get_send_sigusr1", NULL,
       "Get sending of SIGUSR1 to parent on event" },
  { "events_set_send_sigusr1", on_off_generator, 
       "Set sending of SIGUSR1 to parent on event" },
  { "events_purge", NULL, "Get all accumulated events" },
  { "window_reset", window_manager_generator, "Reset the window" },
  { "window_show", NULL, "Map the window on the screen" },
  { "window_hide", NULL, "Unmap the window from the screen" },
  { "window_resize", NULL, "Resize the window" },
  { "window_get_transparency", NULL, "Get automatic transparency" },
  { "window_get_background_grab", NULL, "Get automatic grab" },
  { "window_get_background_image", NULL, "Get background image"},
  { "window_get_managed_status", NULL, "Get managed status" },
  { "window_set_transparency", on_off_generator, "Set automatic transparency" },
  { "window_set_background_grab", on_off_generator, "Set automatic grab" },
  { "window_set_background_image", image_generator, "Set background image" },
  { "screen_get_width", NULL, "Get screen width" },
  { "screen_get_height", NULL, "Get screen height" },
  { "screen_get_depth", NULL, "Get screen depth" },
  { "get_charset", NULL, "Get input charset" },
  { "set_charset", NULL, "Set input charset" },
  { "charset_status", NULL, "Get charset capabilities" },
  { "x_status", NULL, "Status of connection to X Window server" },
  { "quit", NULL, "Quit the program" },
  { NULL, NULL, NULL }
};

/* begin enums */
const char * DIRECTIONS[] = {             /* prefix TEXT */
  "text_to_right",            
  "text_to_left", 
  "text_to_down", 
  "text_to_up",
  "text_to_angle",
  NULL 
};

const char * OPERATIONS[] = {       /* prefix OP */
  "op_copy",                  
  "op_add",
  "op_substract",
  "op_reshade",
  NULL
};

const char * RGBA_TABLES[] = {            /* prefix CHANNEL */
  "red",                
  "green",
  "blue",
  "alpha",
  NULL
};

const char * WINDOW_MANAGER[] = {   /* prefix WINDOW */
  "unmanaged",                
  "managed",
  NULL
};                      
/* end enums */

const char * LOAD_ERRORS[] = {
  "none",               
  "file does not exist",
  "file is a directory",
  "permission denied to read",
  "no loader for file format",
  "path too long",
  "path component non existant",
  "path component not directory",
  "path points outside address space",
  "too many symbolic links",
  "out of memory",
  "out of file descriptors",
  "permission denied to write",
  "out of disk space"
};

#ifndef X_DISPLAY_MISSING
const X_WINDOW_EVENT X_WINDOW_EVENTS[] = {
  { "BackgroundGrab", BackgroundGrabMask },
  { "MenuFire",       MenuFireMask       },
  { "ButtonPress",    ButtonPressMask    }, 
  { "ButtonRelease",  ButtonReleaseMask  },
  { "MotionNotify",   PointerMotionMask  },
  { "EnterNotify",    EnterWindowMask    },
  { "LeaveNotify",    LeaveWindowMask    },
  { NULL,             0L                 }
};                      
#endif

/*----------------------------------------------------------------------------*/
t_command command = {         /* Main structure to pass command back
                           to the event loop            */
  0,                          /* int     interactive;         */
  0,                            /* int     recording;             */
  0,                            /* int     replay_pos;        */
  0,                            /* int     replay_stop;       */
  0,                            /* int     replay_abort;      */
  0,                            /* int     replay_abort_on_events;*/
  {0, 0},               /* struct  timeval replay_time;   */
  0,                    /* int     rank;                */
  0,                          /* int     ready;               */
  0,                          /* int     message_out;         */
  NULL,                       /* char *  line;                */
  NULL                        /* char *  message;             */
#ifdef HAVE_ICONV_H
  , NULL,               /* char *  from_page;             */
  NULL                        /* iconv_t cd;                    */
#endif
};

/*----------------------------------------------------------------------------*/
/* History convenience function: it exists in GNU readline >= 5.0,
   but this is a backport for older libraries 

   Please note there is no `char * timestamp' field in `_hist_entry' structures
   for GNU readline prior to 5.0.
*/
#ifdef HAVE_READLINE_HISTORY_H
#ifndef HAVE_FREE_HISTORY_ENTRY
histdata_t 
free_history_entry (HIST_ENTRY* hist)
{
  histdata_t x;
  if (hist == 0)
    return ((histdata_t) 0);
  if (hist->line) free(hist->line);
  x = hist->data;
  free(hist);
  return (x);
}
#endif
#endif

/*----------------------------------------------------------------------------*/
/* NOTE: the four next functions are truly ugly, but that's a necessity.
   Since they are called _really_ often (and are IO related), we need 
   to strip them as much as possible whenever debugging is not involved.

   I know this goes against GNU guidelines (http://www.gnu.org/prep/standards/), 
   but what else could be done?
*/
/*----------------------------------------------------------------------------*/
/* Command output formatting function */
void 
command_ok(char * format, ...) 
{
  va_list ap;
#ifdef DEBUG
  va_list apcopy;
#endif
  const char PREFIX[] = "command %d ok: ";
  if(!command.replay_pos) {
    printf(PREFIX, command.rank);
#ifdef DEBUG
    if (!debug_on_stderr())
      debug (PREFIX, command.rank);
#endif
    if(!command.message_out) {
      va_start(ap,format);
#ifdef DEBUG
      if (!debug_on_stderr()) {
      va_copy(apcopy,ap);
      vdebug(format,apcopy);
      va_end(apcopy);
      }
#endif
      vprintf(format,ap);
      va_end(ap);
    }
#ifdef DEBUG
    else debug("Double message out processing!\n"); 
#endif
  }
  command.message_out=1;
#ifdef DEBUG
  if(command.replay_pos) {
    debug("(replay) ");
    debug(PREFIX,command.rank);
    va_start(ap,format);
    vdebug(format,ap);
    va_end(ap);
  }
#endif
}

/*----------------------------------------------------------------------------*/
/* Command output formating function */
void 
command_error(char * format, ...)
{
  va_list ap;
#ifdef DEBUG
  va_list apcopy;
#endif
  const char PREFIX[] = "command %d error: ";
  if(!command.replay_pos) {
    printf(PREFIX, command.rank);
#ifdef DEBUG
    if (!debug_on_stderr())
      debug(PREFIX, command.rank);
#endif
    if(!command.message_out) {
      va_start(ap,format);
#ifdef DEBUG
      if(!debug_on_stderr()) {
      va_copy(apcopy,ap);
      vdebug(format,apcopy);
      va_end(apcopy);
      }
#endif
      vprintf(format,ap);
      va_end(ap);
    }
#ifdef DEBUG
    else debug("Double message out processing!\n"); 
#endif
  } else {
#ifdef DEBUG
    if (!debug_on_stderr()) {
      debug("(replay) ");
      debug(PREFIX,command.rank);
      va_start(ap,format);
      va_copy(apcopy,ap);
      vdebug(format,apcopy);
      va_end(apcopy);
    }
#endif
    if ((command.message=malloc(sizeof(char)*100))) {
#ifndef DEBUG
      va_start(ap,format);
#endif
      vsnprintf(command.message,99,format,ap);
      va_end(ap);
      command.message[99]=0;
    }
    command.replay_abort=1;
  }
  command.message_out=1;
}

/*----------------------------------------------------------------------------*/
/* stdout printf for command execution: make sure no input is generated 
   while replaying, and always send an output to debug if it is a log file. */
int 
command_printf(const char * format, ...)
{
  int result = 0;
  va_list ap;
#ifdef DEBUG
  va_list apcopy;
#endif
  if (!command.replay_pos
#ifdef DEBUG
      || !debug_on_stderr()
#endif
      ) {
    va_start(ap,format);
#ifdef DEBUG
    va_copy(apcopy,ap);
    vdebug(format,apcopy);
    va_end(apcopy);
#endif
    if (!command.replay_pos)
      result = vprintf(format,ap);
    va_end(ap);
  }
  return result;
}

/*----------------------------------------------------------------------------*/
/* Duplicate a string.
   Return dynamically allocated string copy. 
*/
char *
dupstr(const char *s)
{
  char *r=NULL;
  if (s && 
      (r=malloc(strlen(s)+1)))
    strcpy (r, s);
  return r;
}

/*----------------------------------------------------------------------------*/
/* Duplicate a string.
   Return dynamically allocated string copy. 
*/
char *
dupnstr(const char *s, int n)
{
  char *r=NULL;
  if (s && n>=0 && 
      (r=malloc(sizeof(char)*n+1))) {
    strncpy (r, s, n);
    r[n]=0;
  }
  return r;
}

/*----------------------------------------------------------------------------*/
/* Duplicate a string and convert it from local charset to utf8, but only if
   a correct conversion descriptor has been set using CMD_SET_CHARSET. Always
   return at least a newly allocated copy of initial string. */
char *
dupstr_utf8(const char * s)
{
  int m = 2, result=0;
  char *i_buf = NULL, * o_buf = NULL, *o = NULL;
  size_t i_bytes, o_bytes, o_len;

#ifdef HAVE_ICONV_H
  errno=0;
  if (command.cd) {
    do {
      if (i_buf) free(i_buf);
      if ((i_buf=strdup(s)) &&
        (o=(o_buf=realloc(o_buf,(o_len=o_bytes=sizeof(char)*
                        (i_bytes=strlen(s))*(m++))+1))) && 
        errno!=ENOMEM) {
      result=(iconv(command.cd,
                  &i_buf,&i_bytes,
                  &o_buf,&o_bytes)!=(size_t)(-1));
      o[o_len-o_bytes]=0;
      }
      /* In case of output buffer overflow, we resize things until it works */
    } while (o_buf && errno==E2BIG);
  }
#endif
  if (!result) {
    if (o) free(o);
    o=strdup(s);
#ifdef HAVE_ICONV_H
#ifdef DEBUG
    if (errno)
      debug("string '%s' conversion error: %s\n",
          s, strerror(errno));
#endif
#endif
  }

  /* debug("Conversion %s -> %s\n",s,o); */

  return o;
}

/*----------------------------------------------------------------------------*/
/* Return actual size of history list*/
#ifdef HAVE_READLINE_HISTORY_H
int 
history_size(void)
{
  HISTORY_STATE * state;
  return ((state=history_get_history_state())?state->length:0);
}
#endif

/*----------------------------------------------------------------------------*/
/* Test if a given string is only filled with space characters.
   Returns 1 if there is nothing significant (or if the reference is NULL),
   0 otherwise.
*/
int 
blank_line(const char * s)
{
  int i=0;
  if (s)
    for(i=0;
      s[i] && s[i]==' ';
      ++i);
  return !(s && s[i]);      
}


/*----------------------------------------------------------------------------*/
double
command_gate_chronometer(void)
{
  double result=1E9;
  struct timeval time;
  if (gettimeofday(&time,0)==0)
    result=(time.tv_sec+((double)time.tv_usec)/1E6)-
      (command.replay_time.tv_sec+((double)command.replay_time.tv_usec)/1E6);
  return result;
}

/*----------------------------------------------------------------------------*/
/* Generic generator mecanism: used for different wrappers.*/
char * generic_generator(const char * text, int state, 
                   char ** names, int number)
{
  static int list_index, len;
  char * name;

  if(!state) {
    list_index=0;
    len=strlen(text);
  }
  
  while((number==-1 || list_index<number) &&
      (name=names[list_index])) {
    ++list_index;
    if(strncmp(name,text,len)==0)
      return(dupstr(name));
  }
  
 return NULL;
}

/*----------------------------------------------------------------------------*/
char * 
generic_index_generator(const char * text, int state, int number)
{
  int i;
  static char ** index;
  static uint list_index;
  static int len;

  if(!state) {
    number=(number>=0)?number:0;
    /* Initial construction */
    index=(char**)malloc(sizeof(char*)*(number+1));
    for(i=0;i<number;++i) {
      index[i]=(char*)malloc(sizeof(char)*8);
      snprintf(index[i],8,"%d",i);
    }
    index[i]=NULL;
    len=strlen(text);
    list_index=0;
  }

  while(index[list_index]) {
    ++list_index;
    if(strncmp(index[list_index-1],text,len)==0)
      return index[list_index-1];
  }
  
  free(index);
  return NULL;
}

/*----------------------------------------------------------------------------*/
char * 
generic_index_generator_with_null(const char * text, int state, int number)
{
  int i;
  static char ** index;
  static uint list_index;
  static int len;

  if(!state) {
    number=(number>0)?number:0;
    /* Initial construction */
    index=(char**)malloc(sizeof(char*)*(number+2));
    for(i=0;i<=number;++i) {
      index[i]=(char*)malloc(sizeof(char)*8);
      snprintf(index[i],8,"%d",i-1);
    }
    index[i]=NULL;
    len=strlen(text);
    list_index=0;
  }

  while(index[list_index]) {
    ++list_index;
    if(strncmp(index[list_index-1],text,len)==0)
      return index[list_index-1];
  }
  
  /*debug("Freeing: %8x\n", index);*/
  free(index);
  return NULL;
}

/*----------------------------------------------------------------------------*/
/* Our generator function */
char *
command_generator(const char * text, int state)
{
  static int list_index, len;
  char * name;
  
  if(!state) {
    list_index=0;
    len=strlen(text);
  }

  while((name=COMMANDS[list_index].name)) {
    ++list_index;
    if(strncmp(name,text,len)==0)
      return(dupstr(name));
  }

  return NULL;
}

/*----------------------------------------------------------------------------*/
char *
xwindow_event_generator(const char * text, int state)
{
#ifndef X_DISPLAY_MISSING
  static int list_index, len;
  char * name;
  
  if(!state) {
    list_index=0;
    len=strlen(text);
  }

  while((name=X_WINDOW_EVENTS[list_index].name)) {
    ++list_index;
    if(strncmp(name,text,len)==0)
      return(dupstr(name));
  }

#endif
  return NULL;
}

/*----------------------------------------------------------------------------*/
char *
on_off_generator(const char * text, int state)
{ 
  return generic_index_generator(text, state, 2);
}

/*----------------------------------------------------------------------------*/
char *
operation_generator(const char * text, int state)
{
  return generic_generator(text, state, (char**)OPERATIONS, -1);
}

/*----------------------------------------------------------------------------*/
char * 
direction_generator(const char * text, int state)
{
  return generic_generator(text, state, (char**)DIRECTIONS, -1);
}

/*----------------------------------------------------------------------------*/
char *
color_modifier_value_generator(const char * text, int state)
{
  return generic_generator(text, state, (char**)RGBA_TABLES, -1);
}

/*----------------------------------------------------------------------------*/
char *
window_manager_generator(const char * text, int state)
{
  return generic_generator(text,state,(char**)WINDOW_MANAGER, -1);
}

/*----------------------------------------------------------------------------*/
/* Our completion function */
char **
command_completion(const char * text, int start, int end)
{
  int i;
  char **matches = NULL;
  rl_attempted_completion_over=1;
  if (start==0)
    matches=rl_completion_matches(text,
                          (rl_compentry_func_t*)command_generator);
  else {
    for(i=0;COMMANDS[i].name;++i)
      if (strstr(rl_line_buffer,COMMANDS[i].name)==rl_line_buffer)
      break;
    if (COMMANDS[i].name && 
      start==strlen(COMMANDS[i].name)+1 && 
      COMMANDS[i].generator)
      matches=rl_completion_matches(text,COMMANDS[i].generator); 
  }
  return matches;
}

/*----------------------------------------------------------------------------*/
/* Callback function: called by readline every time a line is finished reading
   Comply to rl_vcpfunc_t* typedef, installed by rc_callback_handler_install:
   see command_interpreter_reset() below.

   In fact, it is a very simple placeholder function that puts its entry
   back into the `command' structure and set the command.ready flag
   for future use; the only processing here is remplacement of tabs with
   spaces.

   If GNU history library support is enabled, it also records all
   non-empty commands below the configured lenght (if applicable).
*/
void 
readline_process_line_callback(char* line)
{
  int i;

  command.line=line;
  command.ready=1;

  if (line) {    
    /* Replace all tabs with spaces */
    for(i=0;line[i];++i)
      if(line[i]=='\t') line[i]=' ';
    /* And trim down comments */
    for(i=0;line[i];++i)
      if(line[i]=='#') {
      line[i]=0;
      break;
      }
  }
  
#ifdef HAVE_READLINE_HISTORY_H
  if(!blank_line(line) &&
     (command.recording ||
      ((command.interactive && 
       (!HISTORY_MAX_COMMAND_LENGHT || 
      strlen(line)<=HISTORY_MAX_COMMAND_LENGHT)))
      )
     )
    add_history(line);
#endif
  if (command.interactive) 
    rl_callback_handler_remove();
}

/*----------------------------------------------------------------------------*/
int
command_interpreter_reset(void) 
{
  int  result=1;
  char prompt[20];

  if(command.interactive &&
     snprintf(prompt,sizeof(prompt),"%d >>> ",command.rank)==-1)
      result=0;
  rl_attempted_completion_function = command_completion;
  rl_callback_handler_install(((command.interactive)?
                         ((result)?prompt:">>> "):NULL),
                        readline_process_line_callback);
  return result;
}

/*----------------------------------------------------------------------------*/
/* This is the indirect mode counterpart to `command_interpreter()'. 
   When called, if the interpreter is indeed in indirect mode 
   (the 'play' command  has been successfully used), it fills
   the command.line with the next command to replay and set to
   true the command.ready flag. If there is no commands left to replay,
   it switches back the interpreter to direct mode.

   It returns 1 if a result is available, 0 otherwise.
*/
int
command_replayer(void)
{
#ifdef HAVE_READLINE_HISTORY_H
  int pos;
  static int replay_start=0;
  HIST_ENTRY * entry;

  if(command.replay_pos) {
    if (!replay_start)
      replay_start=command.replay_pos;
    --command.rank;
 
    if(command.replay_pos-1<=command.replay_stop && 
       !command.replay_abort &&
       !(command.replay_abort_on_events && events && events->pos)) {
      if((entry=history_get(command.replay_pos))) {
      command.line=strdup(entry->line);
      command.ready=1;
      ++command.replay_pos;
      }
    } else {
      pos=command.replay_pos-1;
      //      replay_start=(command.replay_abort)?command.replay_pos-1:replay_start;
      command.replay_pos=command.message_out=0;

      if (!command.replay_abort && 
        !(command.replay_abort_on_events && events && events->pos))
      command_ok("play %d %d\n", replay_start-1,command.replay_stop);
      else {
      if (command.replay_abort) {
        command_error("on command %d - %s", pos-1, 
                  (command.message)?command.message:"too long\n");
        if (command.message) {
          free(command.message); 
          command.message=NULL;
        }
        command.replay_abort=0;
      } else {
        command_ok("play_aborded %d\n", pos);
      }
      }
      ++command.rank;
      replay_start=0;
      if (command.interactive)
      command_interpreter_reset();
      events_delay=0;
      if (events_echo)
      events_purge();
    }
  }
  return command.ready;
#else
  return 0;
#endif
}

/*----------------------------------------------------------------------------*/
int 
command_interpreter(void)
{
  int polling;
  fd_set fds;
  struct timeval timeout;

  /* Character polling */
  FD_ZERO(&fds);
  FD_SET(fileno(stdin), &fds);
  timeout.tv_sec=0;timeout.tv_usec=X_POLLING_PERIOD;
  
  if((polling=select(FD_SETSIZE,&fds,NULL,NULL,&timeout))>=0) {
    if(FD_ISSET(fileno(stdin),&fds)) {
      timeout.tv_usec=0;
      /* There is at least one character: let us poll
       until nothing is left in stdin, or that a line
         is completed. */
      do {
      rl_callback_read_char();
      FD_ZERO(&fds);
      FD_SET(fileno(stdin),&fds);
      }
      while(!command.ready &&
          (polling=select(FD_SETSIZE,&fds,NULL,NULL,&timeout))>0);
    }
  }

  if (polling<0)
    fprintf(stderr,"Command interpreter: error with character polling\n");

  return (polling>=0);
}

/*----------------------------------------------------------------------------*/
char *
command_subsplitter(char * text, int index)
{
  int i,j,pos;

  /* Strip initial whitespace */
  pos=i=j=0;
  while(text[i]) {
    /* Find beginning of the word */
    for(;text[i] && text[i]==' ';++i);
    pos=i;
    /* Find end of the word */
    for(;text[i] && text[i]!=' ';++i);
    if(pos!=i) {
      ++j;
      if (j==index+1) {
      /* Stripping terminal blank */
      for(i=strlen(text)-1;i>=0;--i)
        if(text[i]==' ')text[i]=0;else break;
      /* Returns result */
      return text+pos;
      
      }
    }
  }
  return NULL;
}

/*----------------------------------------------------------------------------*/
vector * 
command_splitter(const char * text, command_enum * command_type) {
  int i,pos;
  vector * vec;

  *command_type=CMD_UNKNOWN;
  if((vec=vector_init())) {   
    /* Strip initial whitespace */
    pos=i=0;
    while(text[i]) {
      /* Find beginning of the word */
      for(;text[i] && text[i]==' ';++i);
      pos=i;
      /* Find end of the word */
      for(;text[i] && text[i]!=' ';++i);
      if(pos!=i) vector_push(vec,dupnstr(text+pos,i-pos));
    }
    if (vec->pos) {
      for(i=0;
        COMMANDS[i].name && strcmp(vec->content[0],COMMANDS[i].name);
        ++i);
      *command_type=(command_enum)i;
    }
  }
  return vec;
}

Generated by  Doxygen 1.6.0   Back to index