Home modules.gotpike.org
Username: Password: [Create Account]
[Forgot Password?]

Modules

ADT
Database
GTK2
GUI
IP
PiJAX
Public
Sql
Stdio
Subversion
System
Tools
Xosd
lua
v4l2
wx

Recent Changes

Public.Parser.XML2 1.50
Public.ZeroMQ 1.1
Public.Template.Mustache 1.0
Public.Protocols.XMPP 1.4
Sql.Provider.jdbc 1.0

Popular Downloads

Public.Parser.JSON2 1.0
Public.Parser.JSON 0.2
GTK2 2.23
Public.Web.FCGI 1.8
Public.Parser.XML2 1.48


Module Information
Public.Tools.FAM
Viewing contents of Public_Tools_FAM-0.1/FAM.cmod

/* Pike "binding" for FAM (http://http://oss.sgi.com/projects/fam/)
 *
 * - Johan Bjorklund 
 */

/* This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "global.h"
#include "svalue.h"
#include "interpret.h"
#include "program.h"
#include "array.h"
#include "mapping.h"
#include "builtin_functions.h"

#include 

#include "module.h"

#define THISOBJ (Pike_fp->current_object)

struct object *new_object(struct program *prog) {
  struct object *o;
  o = low_clone(prog);
  call_c_initializers(o);
  return o;
}

/*! @module Public
 */

/*! @module Tools
 */

/*! @module FAM
 *!
 *! Example:
 *!
 *! @pre{
 *!   object connection = Public.Tools.FAM.Connection();
 *! 
 *!   object request = connection->monitor_file("/path/to/file");
 *!   object event = connection->next_event();
 *!   
 *!   switch (event->code()) {
 *!     case Public.Tools.FAM.Event.Changed: 
 *!     case Public.Tools.FAM.Event.Deleted:  
 *!     case Public.Tools.FAM.Event.EndExists:
 *!       update_things();
 *!       break;
 *!    }
 *! @}
 *! 
 *! Monitoring ends when there are no references to the request object, so keep the request
 *! object for as long as you want to monitor.
 *!
 */

/*! @module Event
 *!
 *! From the FAM Manual:
 *!
 *!     Changes to files and directories are encoded in the FAMEvent structure.
 *!     The code field of this structure contains one of the following
 *!     enumeration constants:
 *!
 *!     Changed
 *!              Some value which can be obtained with fstat(1) changed for a
 *!              file or directory being monitored.
 *!
 *!     Deleted
 *!              A file or directory being monitored was deleted or its name was
 *!              changed.  This event is also generated when monitoring starts on
 *!              a nonexistent file or directory.
 *!
 *!     StartExecuting
 *!              An executable file or shared library being monitored started
 *!              executing.  If multiple processes execute the same file, this
 *!              event only occurs when the first process starts.
 *!
 *!     StopExecuting
 *!              An executable file being monitored which was running finished.
 *!              If multiple processes from an executable are running, this event
 *!              is only generated when the last one finishes.
 *!
 *!     Created
 *!              A file was created in a directory being monitored.  Note: this
 *!              event is only generated for files created directly in a
 *!              directory being monitored; subdirectories are not automatically
 *!              monitored.
 *!
 *!     Moved FAMMoved events never occur.  The name remains defined so that
 *!              programs that reference it will still compile.
 *!
 *!     Acknowledge
 *!              After a FAMCancelMonitor, fam generates a FAMAcknowledge event.
 *!              Also, if an invalid pathname is specified, fam  generates a
 *!              FAMAcknowledge event.
 *!
 *!     Exists
 *!              When the application requests a file be monitored, fam generates
 *!              a FAMExists event for that file.  When the application requests
 *!              a directory be monitored, fam generates a FAMExists event for
 *!              that directory and every file directly contained in that
 *!              directory.
 *!
 *!     EndExist
 *!              When the application requests a file directory be monitored, a
 *!              series of FAMExists events is generated as described above.
 *!              After the last FAMExists message, fam generates a FAMEndExist
 *!              message.
 *!
 *!     If a FAM event applies to a file or directory being monitored, the
 *!     FAMEvent's filename field contains the full pathname that was passed to
 *!     fam.  If an event applies to an entry in a monitored directory, the
 *!     filename field contains the relative path only.  For example, if the
 *!     directory /usr/tmp/xyzzy were monitored, and the file
 *!     /usr/tmp/xyzzy/plugh  were deleted, a FAMDeleted event would be generated
 *!     containing "plugh" in filename.  If the directory itself were deleted,
 *!     filename would contain "/usr/tmp/xyzzy".
 *!
 */

PIKECLASS Event {
  CVAR FAMEvent *fe;
  CVAR struct object *connection;

  /*! @decl int reqnum()
   *!
   *! @returns
   *!   Returns a number corresponding to the Request object.
   */

  PIKEFUN int reqnum() {
    RETURN (int) THIS->fe->fr.reqnum;
  }

  /*! @decl Connection get_connection()
   *!
   *! @returns
   *!   Returns the corresponding @[Public.Tools.Fam.Connection]
   */

  PIKEFUN object get_connection () {
    if (THIS_EVENT->connection)
      RETURN THIS_EVENT->connection;
    else
      push_int(0);
  }  

  /*! @decl int code()
   */

  PIKEFUN int code() {
    RETURN (int) (THIS_EVENT->fe) ? THIS->fe->code : 0;
  }

  /*! @decl string hostname()
   *
   *! @returns
   *!   Returns the corresponding hostname, or 0 if unavailable
   */

  PIKEFUN string hostname() {
    if (THIS_EVENT->fe && THIS_EVENT->fe->hostname != NULL)
      RETURN make_shared_string(THIS->fe->hostname);
    else
      push_int(0);
  }

  /*! @decl string filename()
   *! @returns
   *!   Returns the corresponding filename, or 0 if unavailable
   */

  PIKEFUN string filename() {
    if (THIS_EVENT->fe && THIS_EVENT->fe->filename != NULL)
      RETURN make_shared_string(THIS->fe->filename);
    else
      push_int(0);
  }

  PIKEFUN string userdata() {
    if (THIS_EVENT->fe && THIS_EVENT->fe->userdata != NULL)
      RETURN make_shared_string(THIS->fe->userdata);
    else
      push_int(0);
  }

  EXTRA {
    add_integer_constant("Changed",        FAMChanged, 0);
    add_integer_constant("Deleted",        FAMDeleted, 0);
    add_integer_constant("StartExecuting", FAMStartExecuting, 0);
    add_integer_constant("StopExecuting",  FAMStopExecuting, 0);
    add_integer_constant("Created",        FAMCreated, 0);
    add_integer_constant("Moved",          FAMMoved, 0);
    add_integer_constant("Acknowledge",    FAMAcknowledge, 0);
    add_integer_constant("Exists",         FAMExists, 0);
    add_integer_constant("EndExist",       FAMEndExist, 0);
  }

  INIT {
    THIS_EVENT->connection = NULL;
    THIS_EVENT->fe = NULL;
  }
  EXIT {
    if (THIS_EVENT->connection != NULL) {
      sub_ref(THIS_EVENT->connection);
      THIS_EVENT->connection = NULL;
    }
    if (THIS_EVENT->fe != NULL) {
      free(THIS_EVENT->fe);
      THIS_EVENT->fe = NULL;
    }
  }
}

/*! @endmodule
 */


/*! @module Request
 */

PIKECLASS Request {
  CVAR FAMConnection *fc;
  CVAR FAMRequest *fr;
  CVAR struct object *connection;

  /*! @decl int reqnum()
   *!
   *! @returns
   *!   Returns a number corresponding to the Request object.
   */

  PIKEFUN int reqnum () {
    RETURN THIS->fr->reqnum;
  }

  /*! @decl Connection get_connection()
   *!
   *! @returns
   *!   Returns the corresponding @[Public.Tools.Fam.Connection]
   */

  PIKEFUN object get_connection () {
    RETURN THIS_REQUEST->connection;
  }

  /*! @decl void suspend()
   *! @decl void resume()
   *!
   *! From the FAM manual:
   *!
   *!   FAMSuspendMonitor temporarily suspends monitoring of files or
   *!   directories.  This is useful when an application is not displaying
   *!   information about files, when it is iconified, for example.
   *!   FAMResumeMonitor signals fam to start monitoring the file or directory
   *!   again.  Changes which occur while monitoring is suspended are enqueued
   *!   and delivered when monitoring is resumed.
   *!
   *!   Because fam runs as an asynchronous process, FAMNextEvent may return a
   *!   few events regarding a given request after that request has been
   *!   suspended.
   */

  PIKEFUN void suspend () {
    if (FAMSuspendMonitor(THIS_REQUEST->fc, THIS_REQUEST->fr) != 0)
      Pike_error("FAMSuspendMonitor returned failure code.\n");
  }

  PIKEFUN void resume () {
    if (FAMResumeMonitor(THIS_REQUEST->fc, THIS_REQUEST->fr) != 0)
      Pike_error("FAMResumeMonitor returned failure code.\n");
  }

  INIT { THIS_REQUEST->connection = NULL; THIS_REQUEST->fc = NULL; THIS_REQUEST->fr = NULL; }
  EXIT {
    if (THIS_REQUEST->fr != NULL) {
      FAMCancelMonitor(THIS_REQUEST->fc, THIS_REQUEST->fr);
      free(THIS_REQUEST->fr);
      THIS_REQUEST->fr = NULL; 
    }
    if (THIS_REQUEST->connection != NULL) {
      sub_ref(THIS_REQUEST->connection);
      THIS_REQUEST->connection = NULL;
    }
  }
}

/*! @endmodule
 */

/*! @module Connection
 */

PIKECLASS Connection {
  CVAR FAMConnection fc;

  PIKEFUN void create () {
    if (FAMOpen(&THIS->fc) != 0)
      Pike_error("Failed to open FAM connection.\n");
  }

  PIKEFUN int get_fd () {
    RETURN THIS_CONNECTION->fc.fd;
  }

  /*! @decl Request monitor_file(string filename)
   *! @decl Request monitor_dir(string filename)
   *!
   *! From the FAM manual:
   *!
   *!   FAMMonitorDirectory and FAMMonitorFile tell FAM to start monitoring a
   *!   directory or file, respectively.  The parameters to this function are a
   *!   FAMConnection (initialized by FAMOpen), a FAMRequest structure, a
   *!   filename and a user data pointer.  The FAMRequest structure is modified
   *!   to subsequently identify this request.  When the file or directory
   *!   changes, a FAM event structure will be generated.  The application can
   *!   retrieve this structure by calling FAMNextEvent (see description under
   *!   FAMNextEvent).
   *!
   *!   FAMMonitorDirectory monitors changes that happens to the contents of the
   *!   directory (as well as the directory file itself); FAMMonitorFile monitors
   *!   only what happens to a particular file.  Both routines return 0 if
   *!   successful and -1 otherwise.
   *!
   *! @param filename
   *!   The filename argument must be a full pathname.
   *!
   *! @returns
   *!   Returns the corresponding @[Public.Tools.Fam.Request]
   *!
   */

  PIKEFUN object(Request) monitor_file (string filename) {
    FAMRequest *fr = malloc(sizeof(FAMRequest));
    struct object *o = NULL;
    if (FAMMonitorFile(&(THIS_CONNECTION->fc), STR0(filename), fr, NULL) == 0) {
      o = new_object(Request_program);
      OBJ2_REQUEST(o)->connection = THISOBJ;
      OBJ2_REQUEST(o)->fc = &THIS_CONNECTION->fc;
      OBJ2_REQUEST(o)->fr = fr;
      add_ref(THISOBJ);
    }
    RETURN o;
  }

  PIKEFUN object(Request) monitor_dir (string filename) {
    FAMRequest *fr = malloc(sizeof(FAMRequest));
    struct object *o = NULL;
    if (FAMMonitorDirectory(&THIS_CONNECTION->fc, STR0(filename), fr, NULL) == 0) {
      o = new_object(Request_program);
      OBJ2_REQUEST(o)->connection = THISOBJ;
      OBJ2_REQUEST(o)->fc = &THIS_CONNECTION->fc;
      OBJ2_REQUEST(o)->fr = fr;
      add_ref(THISOBJ);
    }
    RETURN o;
  }

  /*! @decl int(0..1) pending()
   *!
   *! From the FAM manual:
   *! 
   *!   FAMPending returns 1 if an event is waiting and 0 if no event is waiting.
   *!   It also returns 1 if an error has been encountered.  This routine returns
   *!   immediately to the caller.
   */
  
  PIKEFUN int(0..1) pending () {
    RETURN FAMPending(&THIS->fc);
  }

  /*! @decl Event next_event()
   *!
   *!   FAMNextEvent will get the next FAM event.  If there are no FAM events
   *!   waiting, then the calling application blocks until a FAM event is
   *!   received.  If blocking is not desirable, call FAMPending before
   *!   FAMNextEvent, and only call FAMNextEvent when FAMPending says an event is
   *!   available.
   */

  PIKEFUN object(Event) next_event () {
    FAMEvent *fe = malloc(sizeof(FAMEvent));
    struct object *o = NULL;
    if (FAMNextEvent(&THIS_CONNECTION->fc, fe) == 1) {
      o = new_object(Event_program);
      OBJ2_EVENT(o)->connection = THISOBJ;
      add_ref(THISOBJ);
      OBJ2_EVENT(o)->fe = fe;
      RETURN o;
    } else {
      free(fe);
      push_int(0);
    }
  }

  EXIT {
    FAMClose(&THIS_CONNECTION->fc);
  }
}

/*! @endmodule
 */

/*! @endmodule
 */

/*! @endmodule
 */

/*! @endmodule
 */

EXTRA {
  add_string_constant("__author", "Johan Björklund ", 0);
  add_string_constant("__version", "0.1", 0);
}


gotpike.org | Copyright © 2004 - 2019 | Pike is a trademark of Department of Computer and Information Science, Linköping University