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.

367 lines
7.3KB

  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. printf( "should create new %s here\n", classname );
  136. char **sa = parse_alist( arguments );
  137. _class_map[ string( classname ) ]( sa );
  138. }
  139. else
  140. if ( ! strcmp( command, "set" ) )
  141. {
  142. printf( "got set command.\n" );
  143. char **sa = parse_alist( arguments );
  144. l->log_start();
  145. l->set( sa );
  146. l->log_end();
  147. }
  148. else
  149. if ( ! strcmp( command, "create" ) )
  150. {
  151. int id = l->id();
  152. delete l;
  153. _loggables[ id ] = NULL;
  154. }
  155. // FIXME: bogus... needs to account for multiple events.
  156. _undo_index = ui + 1;
  157. ++_undo_index;
  158. delete buf;
  159. }
  160. void
  161. Loggable::log ( const char *fmt, ... )
  162. {
  163. va_list args;
  164. if ( fmt )
  165. {
  166. va_start( args, fmt );
  167. vfprintf( _fp, fmt, args );
  168. va_end( args );
  169. }
  170. fflush( _fp );
  171. }
  172. void
  173. Loggable::log_print( char **o, char **n )
  174. {
  175. if ( n )
  176. for ( ; *n; n++ )
  177. log( "%s%s", *n, *(n + 1) ? " " : "" );
  178. if ( o && *o )
  179. {
  180. if ( n ) log( " << " );
  181. for ( ; *o; o++ )
  182. log( "%s%s", *o, *(o + 1) ? " " : "" );
  183. }
  184. log( "\n" );
  185. }
  186. /** compare elements of dumps s1 and s2, removing those elements
  187. of dst which are not changed from src */
  188. static
  189. bool
  190. log_diff ( char **sa1, char **sa2 )
  191. {
  192. if ( ! sa1 )
  193. return true;
  194. int w = 0;
  195. for ( int i = 0; sa1[ i ]; ++i )
  196. {
  197. if ( ! strcmp( sa1[ i ], sa2[ i ] ) )
  198. {
  199. free( sa2[ i ] );
  200. free( sa1[ i ] );
  201. }
  202. else
  203. {
  204. sa2[ w ] = sa2[ i ];
  205. sa1[ w ] = sa1[ i ];
  206. w++;
  207. }
  208. }
  209. sa1[ w ] = NULL;
  210. sa2[ w ] = NULL;
  211. return w == 0 ? false : true;
  212. }
  213. void
  214. Loggable::log_start ( void )
  215. {
  216. if ( ! _old_state )
  217. _old_state = log_dump();
  218. ++_nest;
  219. _undo_index = 1;
  220. }
  221. void
  222. Loggable::log_end ( void )
  223. {
  224. if ( --_nest > 0 )
  225. return;
  226. // assert( _old_state );
  227. char **_new_state = log_dump();
  228. // if ( _old_state )
  229. if ( log_diff( _old_state, _new_state ) )
  230. {
  231. indent();
  232. log( "%s 0x%X set ", class_name(), _id );
  233. log_print( _old_state, _new_state );
  234. }
  235. if ( _new_state )
  236. free_sa( _new_state );
  237. if ( _old_state )
  238. free_sa( _old_state );
  239. _old_state = NULL;
  240. /* if ( _old_state ) */
  241. /* { */
  242. /* free_sa( _old_state ); */
  243. /* _old_state = NULL; */
  244. /* } */
  245. // _old_state = NULL;
  246. }
  247. void
  248. Loggable::log_create ( void )
  249. {
  250. indent();
  251. log( "%s 0x%X create ", class_name(), _id );
  252. char **sa = log_dump();
  253. if ( sa )
  254. {
  255. log_print( NULL, sa );
  256. free_sa( sa );
  257. }
  258. else
  259. log( "\n" );
  260. }
  261. void
  262. Loggable::log_destroy ( void )
  263. {
  264. indent();
  265. log( "%s 0x%X destroy (nothing) << ", class_name(), _id );
  266. char **sa = log_dump();
  267. // log_print( sa, NULL );
  268. log_print( NULL, sa );
  269. free_sa( sa );
  270. }