Assists music production by grouping standalone programs into sessions. Community version of "Non Session Manager".
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
7.4KB

  1. /*******************************************************************************/
  2. /* Copyright (C) 2008 Jonathan Moore Liles */
  3. /* */
  4. /* This program is free software; you can redistribute it and/or modify it */
  5. /* under the terms of the GNU General Public License as published by the */
  6. /* Free Software Foundation; either version 2 of the License, or (at your */
  7. /* option) any later version. */
  8. /* */
  9. /* This program is distributed in the hope that it will be useful, but WITHOUT */
  10. /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
  11. /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
  12. /* more details. */
  13. /* */
  14. /* You should have received a copy of the GNU General Public License along */
  15. /* with This program; see the file COPYING. If not,write to the Free Software */
  16. /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  17. /*******************************************************************************/
  18. #define _LOGGABLE_C
  19. #include "Loggable.H"
  20. #undef _LOGABLE_C
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <stdarg.h>
  24. FILE *Loggable::_fp;
  25. int Loggable::_log_id = 0;
  26. int Loggable::_level = 0;
  27. int Loggable::_undo_index = 1;
  28. vector <Loggable *> Loggable::_loggables;
  29. map <string, create_func*> Loggable::_class_map;
  30. bool
  31. Loggable::open ( const char *filename )
  32. {
  33. if ( ! ( Loggable::_fp = fopen( filename, "a+" ) ) )
  34. {
  35. printf( "Could not open log file for writing!" );
  36. return false;
  37. }
  38. return true;
  39. }
  40. /** sigh. parse a string of ":name value :name value" pairs into an array of strings, one per pair */
  41. // FIXME: doesn't handle the case of :name ":foo bar". Also, quotes should be removed here, not in client code.
  42. static
  43. char **
  44. parse_alist( const char *s )
  45. {
  46. // FIXME: bogus over allocation...
  47. int tl = strlen( s );
  48. char **r = (char**)malloc( sizeof( char* ) * tl );
  49. const char *e = s + tl;
  50. const char *c = NULL;
  51. int i = 0;
  52. for ( ; ; s++ )
  53. {
  54. /* if ( *s == '\n' ) */
  55. /* break; */
  56. // if ( *s == ':' || s == e )
  57. if ( *s == ':' || *s == '\0' )
  58. {
  59. if ( c )
  60. {
  61. int l = s - c;
  62. char *pair = (char*)malloc( l + 1 );
  63. strncpy( pair, c, l );
  64. pair[ l ] = '\0';
  65. r[ i++ ] = pair;
  66. }
  67. c = s;
  68. if ( *s == '\0' )
  69. break;
  70. }
  71. }
  72. r[ i ] = NULL;
  73. return r;
  74. }
  75. static
  76. void free_sa ( char **sa )
  77. {
  78. char **a = sa;
  79. for ( ; *a; a++ )
  80. free( *a );
  81. free( sa );
  82. }
  83. void
  84. Loggable::undo ( void )
  85. {
  86. char *buf = new char[ BUFSIZ ];
  87. // fflush( _fp );
  88. fseek( _fp, 0, SEEK_END );
  89. size_t len = ftell( _fp );
  90. fseek( _fp, 0 - (BUFSIZ > len ? len : BUFSIZ), SEEK_END );
  91. len = fread( buf, 1, BUFSIZ, _fp );
  92. char *s = buf + len - 1;
  93. // FIXME: handle blocks
  94. int i = 1;
  95. /* move back _undo_index items from the end */
  96. for ( int j = _undo_index; j-- ; )
  97. for ( --s; *s && s >= buf; --s, ++i )
  98. {
  99. if ( *s == '\n' )
  100. {
  101. if ( *(s + 1) == '\t' )
  102. continue;
  103. break;
  104. }
  105. }
  106. s++;
  107. strtok( s, "\n" );
  108. buf[ len ] = NULL;
  109. // fsync( fileno( _fp ) );
  110. /* pop the entry off the end */
  111. /* fseek( _fp, 0 - i, SEEK_END ); */
  112. /* ftruncate( fileno( _fp ), ftell( _fp ) ); */
  113. if ( ! strlen( s ) )
  114. {
  115. printf( "corrupt undo file or no undo entries.\n" );
  116. return;
  117. }
  118. printf( "undoing \"%s\"\n", s );
  119. int id;
  120. sscanf( s, "%*s %X ", &id );
  121. Loggable *l = find( id );
  122. // assert( l );
  123. char classname[40];
  124. char command[40];
  125. char *arguments;
  126. sscanf( s, "%s %*X %s %*[^\n<] << %a[^\n]", classname, command, &arguments );
  127. int ui = _undo_index;
  128. if ( ! l )
  129. {
  130. printf( "corrupt undo?\n" );
  131. abort();
  132. }
  133. if ( ! strcmp( command, "destroy" ) )
  134. {
  135. char **sa = parse_alist( arguments );
  136. if ( ! _class_map[ string( classname ) ] )
  137. printf( "error class %s is unregistered!\n", classname );
  138. else
  139. _class_map[ string( classname ) ]( sa );
  140. }
  141. else
  142. if ( ! strcmp( command, "set" ) )
  143. {
  144. printf( "got set command.\n" );
  145. char **sa = parse_alist( arguments );
  146. l->log_start();
  147. l->set( sa );
  148. l->log_end();
  149. }
  150. else
  151. if ( ! strcmp( command, "create" ) )
  152. {
  153. int id = l->id();
  154. delete l;
  155. _loggables[ id ] = NULL;
  156. }
  157. // FIXME: bogus... needs to account for multiple events.
  158. _undo_index = ui + 1;
  159. ++_undo_index;
  160. delete buf;
  161. }
  162. void
  163. Loggable::log ( const char *fmt, ... )
  164. {
  165. va_list args;
  166. if ( fmt )
  167. {
  168. va_start( args, fmt );
  169. vfprintf( _fp, fmt, args );
  170. va_end( args );
  171. }
  172. fflush( _fp );
  173. }
  174. void
  175. Loggable::log_print( char **o, char **n )
  176. {
  177. if ( n )
  178. for ( ; *n; n++ )
  179. log( "%s%s", *n, *(n + 1) ? " " : "" );
  180. if ( o && *o )
  181. {
  182. if ( n ) log( " << " );
  183. for ( ; *o; o++ )
  184. log( "%s%s", *o, *(o + 1) ? " " : "" );
  185. }
  186. log( "\n" );
  187. }
  188. /** compare elements of dumps s1 and s2, removing those elements
  189. of dst which are not changed from src */
  190. static
  191. bool
  192. log_diff ( char **sa1, char **sa2 )
  193. {
  194. if ( ! sa1 )
  195. return true;
  196. int w = 0;
  197. for ( int i = 0; sa1[ i ]; ++i )
  198. {
  199. if ( ! strcmp( sa1[ i ], sa2[ i ] ) )
  200. {
  201. free( sa2[ i ] );
  202. free( sa1[ i ] );
  203. }
  204. else
  205. {
  206. sa2[ w ] = sa2[ i ];
  207. sa1[ w ] = sa1[ i ];
  208. w++;
  209. }
  210. }
  211. sa1[ w ] = NULL;
  212. sa2[ w ] = NULL;
  213. return w == 0 ? false : true;
  214. }
  215. void
  216. Loggable::log_start ( void )
  217. {
  218. if ( ! _old_state )
  219. _old_state = get();
  220. ++_nest;
  221. _undo_index = 1;
  222. }
  223. void
  224. Loggable::log_end ( void )
  225. {
  226. if ( --_nest > 0 )
  227. return;
  228. // assert( _old_state );
  229. char **_new_state = get();
  230. // if ( _old_state )
  231. if ( log_diff( _old_state, _new_state ) )
  232. {
  233. indent();
  234. log( "%s 0x%X set ", class_name(), _id );
  235. log_print( _old_state, _new_state );
  236. }
  237. if ( _new_state )
  238. free_sa( _new_state );
  239. if ( _old_state )
  240. free_sa( _old_state );
  241. _old_state = NULL;
  242. /* if ( _old_state ) */
  243. /* { */
  244. /* free_sa( _old_state ); */
  245. /* _old_state = NULL; */
  246. /* } */
  247. // _old_state = NULL;
  248. }
  249. void
  250. Loggable::log_create ( void )
  251. {
  252. indent();
  253. log( "%s 0x%X create ", class_name(), _id );
  254. char **sa = get();
  255. if ( sa )
  256. {
  257. log_print( NULL, sa );
  258. free_sa( sa );
  259. }
  260. else
  261. log( "\n" );
  262. }
  263. void
  264. Loggable::log_destroy ( void )
  265. {
  266. indent();
  267. log( "%s 0x%X destroy (nothing) << ", class_name(), _id );
  268. char **sa = get();
  269. // log_print( sa, NULL );
  270. log_print( NULL, sa );
  271. free_sa( sa );
  272. }