RSS

(root)/dmassist/trunk : 20 : csrc/templates/templates.c

« back to all changes in this revision

Viewing changes to csrc/templates/templates.c

ziroby
2009-10-15 20:20:18
Revision ID: ziroby@users.sourceforge.net-20091015202018-1lowim1bxs4gn3np
Removed NPC Gen / JNI stuff.

Show diffs side-by-side

added added

removed removed

1
 
#if defined( linux )
2
 
# define DLOPEN_TYPE
3
 
# include <dlfcn.h>
4
 
#elif defined( _HPUX_SOURCE )
5
 
# include <dl.h>
6
 
#endif
7
 
 
8
 
#include <stdlib.h>
9
 
#include <string.h>
10
 
#include <time.h>
11
 
#include <unistd.h>
12
 
#include <errno.h>
13
 
 
14
 
#include "templates.h"
15
 
 
16
 
/* ------------------------------------------------------------------------- */
17
 
/* macros and constants                                                      */
18
 
/* ------------------------------------------------------------------------- */
19
 
 
20
 
  /* we do this as a define since the replace tag and cyclical replace tag
21
 
   * use the same header... in other words, the replace tag inherits from
22
 
   * the standard tag, and the cyclical replace tag inherits from the replace
23
 
   * tag */
24
 
 
25
 
#define STANDARD_REPLACE_TAG_HDR \
26
 
  STANDARD_TAG_HDR; \
27
 
  char* m_data
28
 
 
29
 
#define DEFAULT_TAG_START "<!--%"
30
 
#define DEFAULT_TAG_END   "%-->"
31
 
#define DEFAULT_DELIMITER "="
32
 
 
33
 
#define NEW( item_name )     (item_name*)malloc( sizeof( item_name ) )
34
 
#define NEWTAG( name, type ) (type*)ae_tag_new( name, sizeof( type ) )
35
 
#define DELETE( x )          free( x )
36
 
 
37
 
#define DECL_CAST( var, parm, type )  type* var = (type*)parm
38
 
#define MGR_CAST( var, parm )         DECL_CAST( var, parm, t_ae_mgr )
39
 
#define GENERIC_TAG( var, parm )      DECL_CAST( var, parm, t_ae_generic_tag )
40
 
 
41
 
#define COMP_TYPE_EQ      ( 0 )
42
 
#define COMP_TYPE_NE      ( 1 )
43
 
#define COMP_TYPE_LT      ( 2 )
44
 
#define COMP_TYPE_LE      ( 3 )
45
 
#define COMP_TYPE_GT      ( 4 )
46
 
#define COMP_TYPE_GE      ( 5 )
47
 
 
48
 
/* ------------------------------------------------------------------------- */
49
 
/* type implementations                                                      */
50
 
/* ------------------------------------------------------------------------- */
51
 
 
52
 
typedef t_ae_tag (*t_standard_tag_def)();
53
 
 
54
 
typedef struct {
55
 
  STANDARD_STREAM_HDR;
56
 
} t_ae_generic_stream;
57
 
 
58
 
typedef struct {
59
 
  STANDARD_STREAM_HDR;
60
 
  FILE* fptr;
61
 
  int   wrapped;
62
 
} t_ae_file_stream;
63
 
 
64
 
typedef struct {
65
 
  STANDARD_STREAM_HDR;
66
 
  char* buffer;
67
 
  int   pos;
68
 
} t_ae_buffer_stream;
69
 
 
70
 
typedef struct {
71
 
  STANDARD_REPLACE_TAG_HDR;
72
 
} t_ae_replace_tag;
73
 
 
74
 
typedef struct {
75
 
  STANDARD_REPLACE_TAG_HDR;
76
 
  char* m_rpt_delim;
77
 
  char* m_next;
78
 
} t_ae_cyclical_replace_tag;
79
 
 
80
 
typedef struct {
81
 
  STANDARD_TAG_HDR;
82
 
  char* m_lib;
83
 
  char* m_func;
84
 
  void* m_cookie;
85
 
} t_ae_shared_fn_tag;
86
 
 
87
 
typedef struct {
88
 
  STANDARD_TAG_HDR;
89
 
  int comp_type;
90
 
} t_ae_comparison_tag;
91
 
 
92
 
typedef struct __ae_tag_list t_ae_tag_list;
93
 
struct __ae_tag_list {
94
 
  t_ae_tag_list*    next;
95
 
  t_ae_tag_list*    prev;
96
 
  t_ae_generic_tag* tag;
97
 
};
98
 
 
99
 
typedef struct {
100
 
  t_ae_tag_list* m_taglist_head;
101
 
  t_ae_tag_list* m_taglist_tail;
102
 
  char* m_tag_start;
103
 
  char* m_tag_end;
104
 
  char* m_tag_delimiter;
105
 
  t_ae_preproc_fn preproc;
106
 
  void* cookie;
107
 
  int recursive_depth;
108
 
} t_ae_mgr;
109
 
 
110
 
typedef struct __ae_cookie t_ae_cookie;
111
 
struct __ae_cookie {
112
 
  t_ae_cookie* next;
113
 
  char* name;
114
 
  char* value;
115
 
  int ttl;
116
 
};
117
 
 
118
 
typedef struct {
119
 
  int headers;
120
 
  int no_cache;
121
 
  t_ae_cookie* cookies;
122
 
  FILE* output;
123
 
} t_ae_html_proc_data;
124
 
 
125
 
/* ------------------------------------------------------------------------- */
126
 
/* static function definitions                                               */
127
 
/* ------------------------------------------------------------------------- */
128
 
 
129
 
static t_ae_file_stream*   static_ae_file_stream_new( void );
130
 
static t_ae_buffer_stream* static_ae_buffer_stream_new( void );
131
 
 
132
 
static int static_ae_file_stream_get_length( t_ae_stream stream );
133
 
static int static_ae_file_stream_read( t_ae_stream stream, char* buffer, int length );
134
 
static int static_ae_file_stream_close( t_ae_stream stream );
135
 
 
136
 
static int static_ae_buffer_stream_get_length( t_ae_stream stream );
137
 
static int static_ae_buffer_stream_read( t_ae_stream stream, char* buffer, int length );
138
 
static int static_ae_buffer_stream_close( t_ae_stream stream );
139
 
 
140
 
static t_ae_tag static_ae_comparison_tag( CONST char* name,
141
 
                                          int comparison );
142
 
 
143
 
static int static_ae_replace_tag_apply( t_ae_tag tag,
144
 
                                        CONST char* text,
145
 
                                        t_ae_template_mgr mgr,
146
 
                                        FILE* output );
147
 
static int static_ae_replace_tag_process( t_ae_tag tag,
148
 
                                          CONST char* text,
149
 
                                          t_ae_template_mgr mgr,
150
 
                                          FILE* output );
151
 
static int static_ae_replace_tag_cleanup( t_ae_tag tag );
152
 
 
153
 
static int static_ae_cyclical_replace_tag_process( t_ae_tag tag,
154
 
                                                   CONST char* text,
155
 
                                                   t_ae_template_mgr mgr,
156
 
                                                   FILE* output );
157
 
static int static_ae_cyclical_replace_tag_cleanup( t_ae_tag tag );
158
 
static int static_ae_shared_fn_tag_cleanup( t_ae_tag tag );
159
 
 
160
 
static int static_ae_typed_tag_apply( t_ae_tag tag,
161
 
                                      CONST char* text,
162
 
                                      t_ae_template_mgr mgr,
163
 
                                      FILE* output );
164
 
 
165
 
static int static_ae_if_tag_process( t_ae_tag tag,
166
 
                                     CONST char* text,
167
 
                                     t_ae_template_mgr mgr,
168
 
                                     FILE* output );
169
 
static int static_ae_if_not_tag_process( t_ae_tag tag,
170
 
                                         CONST char* text,
171
 
                                         t_ae_template_mgr mgr,
172
 
                                         FILE* output );
173
 
static int static_ae_include_tag_process( t_ae_tag tag,
174
 
                                          CONST char* text,
175
 
                                          t_ae_template_mgr mgr,
176
 
                                          FILE* output );
177
 
static int static_ae_repeat_tag_process( t_ae_tag tag,
178
 
                                         CONST char* text,
179
 
                                         t_ae_template_mgr mgr,
180
 
                                         FILE* output );
181
 
static int static_ae_env_tag_process( t_ae_tag tag,
182
 
                                      CONST char* text,
183
 
                                      t_ae_template_mgr mgr,
184
 
                                      FILE* output );
185
 
static int static_ae_exec_tag_process( t_ae_tag tag,
186
 
                                       CONST char* text,
187
 
                                       t_ae_template_mgr mgr,
188
 
                                       FILE* output );
189
 
static int static_ae_comparison_tag_process( t_ae_tag tag,
190
 
                                             CONST char* text,
191
 
                                             t_ae_template_mgr mgr,
192
 
                                             FILE* output );
193
 
static int static_ae_include_tag_named_process( t_ae_tag tag,
194
 
                                                CONST char* text,
195
 
                                                t_ae_template_mgr mgr,
196
 
                                                FILE* output );
197
 
           
198
 
static int static_ae_shared_fn_apply( t_ae_tag tag,
199
 
                                      CONST char* text,
200
 
                                      t_ae_template_mgr mgr,
201
 
                                      FILE* output );
202
 
static int static_ae_shared_fn_process( t_ae_tag tag,
203
 
                                        CONST char* text,
204
 
                                        t_ae_template_mgr mgr,
205
 
                                        FILE* output );
206
 
 
207
 
static int   static_html_preproc_fn( t_ae_template_mgr mgr, FILE* output );
208
 
 
209
 
static char* static_get_non_value( t_ae_tag tag );
210
 
static char* static_get_replace_tag_value( t_ae_tag tag );
211
 
 
212
 
/* ------------------------------------------------------------------------- */
213
 
/* static data                                                               */
214
 
/* ------------------------------------------------------------------------- */
215
 
 
216
 
static t_standard_tag_def static_standard_tags[] = {
217
 
  ae_if_tag,
218
 
  ae_if_not_tag,
219
 
  ae_if_eq_tag,
220
 
  ae_if_not_eq_tag,
221
 
  ae_if_lt_tag,
222
 
  ae_if_le_tag,
223
 
  ae_if_gt_tag,
224
 
  ae_if_ge_tag,
225
 
  ae_include_tag,
226
 
  ae_repeat_tag,
227
 
  ae_env_tag,
228
 
  ae_exec_tag,
229
 
  0
230
 
};
231
 
 
232
 
/* ------------------------------------------------------------------------- */
233
 
/* stream function implementations                                           */
234
 
/* ------------------------------------------------------------------------- */
235
 
 
236
 
t_ae_stream ae_stream_open_file( CONST char* file_name ) {
237
 
  t_ae_file_stream* stream;
238
 
 
239
 
  /* create a new file stream object and open the requested file */
240
 
  stream = static_ae_file_stream_new();
241
 
  stream->fptr = fopen( file_name, "r" );
242
 
  if( stream->fptr == NULL ) {
243
 
    stream->close( stream );
244
 
    return NULL;
245
 
  }
246
 
 
247
 
  return (t_ae_stream)stream;
248
 
}
249
 
 
250
 
t_ae_stream ae_stream_wrap_file( FILE* fptr ) {
251
 
  t_ae_file_stream* stream;
252
 
 
253
 
  /* create a new file stream object and set the file pointer to be the one
254
 
   * indicated */
255
 
 
256
 
  stream = static_ae_file_stream_new();
257
 
  stream->fptr = fptr;
258
 
  stream->wrapped = 1;
259
 
 
260
 
  return (t_ae_stream)stream;
261
 
}
262
 
 
263
 
t_ae_stream ae_stream_open_buffer( CONST char* buffer ) {
264
 
  t_ae_buffer_stream* stream;
265
 
 
266
 
  stream = static_ae_buffer_stream_new();
267
 
  stream->buffer = strdup( buffer );
268
 
  stream->pos = 0;
269
 
 
270
 
  return (t_ae_stream)stream;
271
 
}
272
 
 
273
 
/* the following functions use the function pointers in the stream
274
 
 * structure to implement "virtual" methods of the stream object. */
275
 
 
276
 
int ae_stream_get_length( t_ae_stream stream ) {
277
 
  DECL_CAST( str, stream, t_ae_generic_stream );
278
 
  return str->get_length( stream );
279
 
}
280
 
 
281
 
int ae_stream_read( t_ae_stream stream, char* buffer, int length ) {
282
 
  DECL_CAST( str, stream, t_ae_generic_stream );
283
 
  return str->read( stream, buffer, length );
284
 
}
285
 
 
286
 
int ae_stream_close( t_ae_stream stream ) {
287
 
  DECL_CAST( str, stream, t_ae_generic_stream );
288
 
  str->close( stream );
289
 
  free( str );
290
 
  return 0;
291
 
}
292
 
 
293
 
/* ------------------------------------------------------------------------- */
294
 
/* tag function implementations                                              */
295
 
/* ------------------------------------------------------------------------- */
296
 
 
297
 
t_ae_tag ae_tag_new( CONST char* name, int size ) {
298
 
  t_ae_generic_tag* tag;
299
 
 
300
 
  /* create a new tag by allocating space for it, setting it's name and
301
 
   * delimiter, and setting default values for it's methods. */
302
 
 
303
 
  tag = (t_ae_generic_tag*)malloc( size );
304
 
  tag->m_tag = strdup( name );
305
 
  tag->m_delim = strdup( DEFAULT_DELIMITER );
306
 
  tag->apply = NULL;
307
 
  tag->process = NULL;
308
 
  tag->cleanup = NULL;
309
 
  tag->get_value = static_get_non_value;
310
 
 
311
 
  /* setting the type to TAG_TYPE_NO_VALUE means that the tag is untyped --
312
 
   * if you call it's get-value function, you will always get NULL back. */
313
 
 
314
 
  tag->type = TAG_TYPE_NO_VALUE;
315
 
 
316
 
  return (t_ae_tag)tag;
317
 
}
318
 
 
319
 
void ae_tag_destroy( t_ae_tag tag ) {
320
 
  GENERIC_TAG( tag_data, tag );
321
 
 
322
 
  /* if the tag has a cleanup function defined, call it */
323
 
 
324
 
  if( tag_data->cleanup ) {
325
 
    tag_data->cleanup( tag );
326
 
  }
327
 
 
328
 
  /* free the memory for the tag */
329
 
 
330
 
  free( tag_data->m_tag );
331
 
  free( tag_data->m_delim );
332
 
  free( tag_data );
333
 
}
334
 
 
335
 
char* ae_get_tag_name( t_ae_tag tag ) {
336
 
  GENERIC_TAG( tag_data, tag );
337
 
  return tag_data->m_tag;
338
 
}
339
 
 
340
 
char* ae_get_tag_delim( t_ae_tag tag ) {
341
 
  GENERIC_TAG( tag_data, tag );
342
 
  return tag_data->m_delim;
343
 
}
344
 
 
345
 
char* ae_get_tag_value( t_ae_tag tag ) {
346
 
  GENERIC_TAG( tag_data, tag );
347
 
  return tag_data->get_value( tag );
348
 
}
349
 
 
350
 
 
351
 
t_ae_tag ae_replace_tag( CONST char* name, CONST char* data ) {
352
 
  t_ae_replace_tag* tag;
353
 
 
354
 
  /* a replace tag simply replaces itself with the specified data.
355
 
   * If the data is NULL, the tag is replaced with the empty string. */
356
 
 
357
 
  tag = NEWTAG( name, t_ae_replace_tag );
358
 
  if( data != NULL ) {
359
 
/*    tag->m_data = strdup( data );*/
360
 
    tag->m_data = (char*)malloc( strlen( data ) + 1 );
361
 
    strcpy( tag->m_data, data );
362
 
  } else {
363
 
    tag->m_data = NULL;
364
 
  }
365
 
  tag->apply = static_ae_replace_tag_apply;
366
 
  tag->process = static_ae_replace_tag_process;
367
 
  tag->cleanup = static_ae_replace_tag_cleanup;
368
 
  tag->get_value = static_get_replace_tag_value;
369
 
  tag->type = TAG_TYPE_VALUE;
370
 
 
371
 
  return (t_ae_tag)tag;
372
 
}
373
 
 
374
 
t_ae_tag ae_cyclical_replace_tag( CONST char* name, CONST char* data, CONST char* delim ) {
375
 
  t_ae_cyclical_replace_tag* tag;
376
 
 
377
 
  /* a cyclical replace tag replaces itself with the next value in the associated delimited
378
 
   * list of values.  Each time the cyclical tag's "process" function is called, it's
379
 
   * m_next pointer is incremented so that on each subsequent call, the next value in the
380
 
   * list is obtained. */
381
 
 
382
 
  tag = NEWTAG( name, t_ae_cyclical_replace_tag );
383
 
  tag->m_data = strdup( data );
384
 
  tag->m_rpt_delim = strdup( delim );
385
 
  tag->m_next = tag->m_data;
386
 
  tag->apply = static_ae_replace_tag_apply;
387
 
  tag->process = static_ae_cyclical_replace_tag_process;
388
 
  tag->cleanup = static_ae_cyclical_replace_tag_cleanup;
389
 
  tag->get_value = static_get_replace_tag_value;
390
 
  tag->type = TAG_TYPE_VALUE;
391
 
 
392
 
  return (t_ae_tag)tag;
393
 
}
394
 
 
395
 
t_ae_tag ae_typed_tag( CONST char* type, t_ae_tag_fn process, int size ) {
396
 
  t_ae_generic_tag* tag;
397
 
 
398
 
  tag = (t_ae_generic_tag*)ae_tag_new( type, size );
399
 
  tag->apply = static_ae_typed_tag_apply;
400
 
  tag->process = process;
401
 
 
402
 
  return (t_ae_tag)tag;
403
 
}
404
 
 
405
 
t_ae_tag ae_if_tag( void ) {
406
 
  return ae_typed_tag( "IF", static_ae_if_tag_process, sizeof( t_ae_generic_tag ) );
407
 
}
408
 
 
409
 
t_ae_tag ae_if_not_tag( void ) {
410
 
  return ae_typed_tag( "IF_NOT", static_ae_if_not_tag_process, sizeof( t_ae_generic_tag ) );
411
 
}
412
 
 
413
 
t_ae_tag ae_if_eq_tag( void ) {
414
 
  return static_ae_comparison_tag( "IF_EQ", COMP_TYPE_EQ );
415
 
}
416
 
 
417
 
t_ae_tag ae_if_not_eq_tag( void ) {
418
 
  return static_ae_comparison_tag( "IF_NOT_EQ", COMP_TYPE_NE );
419
 
}
420
 
 
421
 
t_ae_tag ae_if_lt_tag( void ) {
422
 
  return static_ae_comparison_tag( "IF_LT", COMP_TYPE_LT );
423
 
}
424
 
 
425
 
t_ae_tag ae_if_le_tag( void ) {
426
 
  return static_ae_comparison_tag( "IF_LE", COMP_TYPE_LE );
427
 
}
428
 
 
429
 
t_ae_tag ae_if_gt_tag( void ) {
430
 
  return static_ae_comparison_tag( "IF_GT", COMP_TYPE_GT );
431
 
}
432
 
 
433
 
t_ae_tag ae_if_ge_tag( void ) {
434
 
  return static_ae_comparison_tag( "IF_GE", COMP_TYPE_GE );
435
 
}
436
 
 
437
 
t_ae_tag ae_include_tag( void ) {
438
 
  return ae_typed_tag( "INCLUDE", static_ae_include_tag_process, sizeof( t_ae_generic_tag ) );
439
 
}
440
 
 
441
 
t_ae_tag ae_repeat_tag( void ) {
442
 
  return ae_typed_tag( "REPEAT2", static_ae_repeat_tag_process, sizeof( t_ae_generic_tag ) );
443
 
}
444
 
 
445
 
t_ae_tag ae_env_tag( void ) {
446
 
  return ae_typed_tag( "ENV", static_ae_env_tag_process, sizeof( t_ae_generic_tag ) );
447
 
}
448
 
 
449
 
t_ae_tag ae_exec_tag( void ) {
450
 
  return ae_typed_tag( "EXEC", static_ae_exec_tag_process, sizeof( t_ae_generic_tag ) );
451
 
}
452
 
 
453
 
t_ae_tag ae_shared_fn_tag( CONST char* name, CONST char* lib, CONST char* func, void* cookie ) {
454
 
  t_ae_shared_fn_tag* tag;
455
 
 
456
 
  tag = NEWTAG( name, t_ae_shared_fn_tag );
457
 
  tag->apply = static_ae_shared_fn_apply;
458
 
  tag->process = static_ae_shared_fn_process;
459
 
  tag->cleanup = static_ae_shared_fn_tag_cleanup;
460
 
  tag->m_lib = strdup( lib );
461
 
  tag->m_func = strdup( func );
462
 
  tag->m_cookie = cookie;
463
 
 
464
 
  return (t_ae_tag)tag;
465
 
}
466
 
 
467
 
t_ae_tag ae_shared_fn_tag_named( CONST char* name, CONST char* lib,
468
 
                                 CONST char* func, void* cookie )
469
 
{
470
 
  t_ae_shared_fn_tag* tag;
471
 
 
472
 
  tag = (t_ae_shared_fn_tag*)ae_shared_fn_tag( name, lib, func, cookie );
473
 
  tag->apply = static_ae_replace_tag_apply;
474
 
 
475
 
  return (t_ae_tag)tag;
476
 
}
477
 
 
478
 
t_ae_tag ae_include_tag_named( CONST char* name, CONST char* file ) {
479
 
  t_ae_replace_tag* tag;
480
 
 
481
 
  tag = (t_ae_replace_tag*)ae_replace_tag( name, file );
482
 
  tag->process = static_ae_include_tag_named_process;
483
 
 
484
 
  return (t_ae_tag)tag;
485
 
}
486
 
 
487
 
/* ------------------------------------------------------------------------- */
488
 
/* template function implementations                                         */
489
 
/* ------------------------------------------------------------------------- */
490
 
 
491
 
t_ae_template_mgr ae_template_mgr_new( void ) {
492
 
  t_ae_mgr* mgr_data;
493
 
  int i;
494
 
 
495
 
  mgr_data = NEW( t_ae_mgr );
496
 
  mgr_data->m_taglist_head = NULL;
497
 
  mgr_data->m_taglist_tail = NULL;
498
 
  mgr_data->m_tag_start = strdup( DEFAULT_TAG_START );
499
 
  mgr_data->m_tag_end = strdup( DEFAULT_TAG_END );
500
 
  mgr_data->m_tag_delimiter = strdup( DEFAULT_DELIMITER );
501
 
  mgr_data->preproc = NULL;
502
 
  mgr_data->cookie = NULL;
503
 
  mgr_data->recursive_depth = 0;
504
 
 
505
 
  /* add the standard tag types, defined in the static_standard_tags array */
506
 
  for( i = 0; static_standard_tags[i] != NULL; i++ ) {
507
 
    ae_add_tag_ex( (t_ae_template_mgr)mgr_data, static_standard_tags[i]() );
508
 
  }
509
 
 
510
 
  return (t_ae_template_mgr)mgr_data;
511
 
}
512
 
 
513
 
void ae_template_mgr_done( t_ae_template_mgr mgr ) {
514
 
  MGR_CAST( mgr_data, mgr );
515
 
  t_ae_tag_list* curr;
516
 
  t_ae_tag_list* next;
517
 
 
518
 
  free( mgr_data->m_tag_start );
519
 
  free( mgr_data->m_tag_end );
520
 
  free( mgr_data->m_tag_delimiter );
521
 
 
522
 
  /* destroy the tags associated with this manager */
523
 
  curr = mgr_data->m_taglist_head;
524
 
  while( curr != NULL ) {
525
 
    ae_tag_destroy( (t_ae_tag)curr->tag );
526
 
    next = curr->next;
527
 
    free( curr );
528
 
    curr = next;
529
 
  }
530
 
 
531
 
  mgr_data->m_taglist_head = NULL;
532
 
  mgr_data->m_taglist_tail = NULL;
533
 
 
534
 
  free( mgr_data );
535
 
}
536
 
 
537
 
void ae_add_tag( t_ae_template_mgr mgr, CONST char* name, CONST char* value ) {
538
 
  /* add the name/value pair as a replace tag */
539
 
  ae_add_tag_ex( mgr, ae_replace_tag( name, value ) );
540
 
}
541
 
 
542
 
void ae_add_tag_i( t_ae_template_mgr mgr, CONST char* name, int value ) {
543
 
  char buffer[ 12 ];
544
 
 
545
 
  /* add the name/value pair as a replace tag */
546
 
  snprintf( buffer, sizeof( buffer ), "%d", value );
547
 
  ae_add_tag_ex( mgr, ae_replace_tag( name, buffer ) );
548
 
}
549
 
 
550
 
void ae_add_tags( t_ae_template_mgr mgr, char** names, char** values ) {
551
 
  int i;
552
 
  
553
 
  /* for each value in the given names/values arrays, add a tag.  If the
554
 
   * tag starts with a '-', then add the value as if it were a t_ae_tag
555
 
   * pointer, otherwise add it as a generic replace tag */
556
 
 
557
 
  if( names == 0 ) return;
558
 
  for( i = 0; names[i] && *names[i]; i++ ) {
559
 
    if( *names[i] == '-' ) {
560
 
      ae_add_tag_ex( mgr, (t_ae_tag)values[i] );
561
 
    } else {
562
 
      ae_add_tag( mgr, names[ i ], values[ i ] );
563
 
    }
564
 
  }
565
 
}
566
 
 
567
 
void ae_add_tag_ex( t_ae_template_mgr mgr, t_ae_tag tag ) {
568
 
  MGR_CAST( mgr_data, mgr );
569
 
  GENERIC_TAG( tag_data, tag );
570
 
  t_ae_tag_list* item;
571
 
  t_ae_tag_list* c;
572
 
 
573
 
  /* add the given tag to the manager's linked list of tags.  The
574
 
   * most recently added tag is added at the end of the list, and
575
 
   * the m_taglist_head and m_taglist_tail variables keep track of
576
 
   * (respectively) the head and tail of the list */
577
 
 
578
 
  if( tag == NULL ) return;
579
 
  ae_remove_tag( mgr, ae_get_tag_name( tag ) );
580
 
 
581
 
  free( tag_data->m_delim );
582
 
  tag_data->m_delim = strdup( mgr_data->m_tag_delimiter );
583
 
 
584
 
  c = mgr_data->m_taglist_tail;
585
 
  if( c == NULL ) {
586
 
    item = NEW( t_ae_tag_list );
587
 
    item->next = item->prev = NULL;
588
 
    item->tag = tag_data;
589
 
    mgr_data->m_taglist_tail = mgr_data->m_taglist_head = item;
590
 
  } else {
591
 
    while( c != NULL ) {
592
 
      if( strcmp( c->tag->m_tag, tag_data->m_tag ) == 0 ) {
593
 
        ae_tag_destroy( c->tag );
594
 
        c->tag = tag_data;
595
 
        break;
596
 
      }
597
 
      c = c->next;
598
 
    }
599
 
    if( c == NULL ) {
600
 
      item = NEW( t_ae_tag_list );
601
 
      item->next = NULL;
602
 
      item->prev = mgr_data->m_taglist_tail;
603
 
      item->prev->next = item;
604
 
      item->tag = tag_data;
605
 
      mgr_data->m_taglist_tail = item;
606
 
    }
607
 
  }
608
 
}
609
 
 
610
 
void ae_remove_tag( t_ae_template_mgr mgr, CONST char* name ) {
611
 
  MGR_CAST( mgr_data, mgr );
612
 
  t_ae_tag_list* item;
613
 
 
614
 
  /* remove the first tag found with the given name.  The tag
615
 
   * will be destroyed. */
616
 
 
617
 
  item = mgr_data->m_taglist_head;
618
 
  while( item != NULL ) {
619
 
    if( strcmp( item->tag->m_tag, name ) == 0 ) {
620
 
      if( item->prev != NULL ) {
621
 
        item->prev->next = item->next;
622
 
      }
623
 
      if( item->next != NULL ) {
624
 
        item->next->prev = item->prev;
625
 
      }
626
 
      if( item == mgr_data->m_taglist_tail ) {
627
 
        mgr_data->m_taglist_tail = item->prev;
628
 
      }
629
 
      if( item == mgr_data->m_taglist_head ) {
630
 
        mgr_data->m_taglist_head = item->next;
631
 
      }
632
 
      ae_tag_destroy( item->tag );
633
 
      free( item );
634
 
      break;
635
 
    }
636
 
    item = item->next;
637
 
  }
638
 
}
639
 
 
640
 
void ae_remove_tag_ex( t_ae_template_mgr mgr, t_ae_tag tag ) {
641
 
  /* remove the first tag answering to the same name as the given tag */
642
 
  ae_remove_tag( mgr, ((t_ae_generic_tag*)tag)->m_tag );
643
 
}
644
 
 
645
 
int ae_tag_count( t_ae_template_mgr mgr ) {
646
 
  MGR_CAST( mgr_data, mgr );
647
 
  t_ae_tag_list* item;
648
 
  int count = 0;
649
 
 
650
 
  for( item = mgr_data->m_taglist_head; item != NULL; item = item->next ) {
651
 
    count++;
652
 
  }
653
 
 
654
 
  return count;
655
 
}
656
 
 
657
 
void ae_set_start_end_delim( t_ae_template_mgr mgr,
658
 
                             CONST char* start,
659
 
                             CONST char* end )
660
 
{
661
 
  MGR_CAST( mgr_data, mgr );
662
 
 
663
 
  free( mgr_data->m_tag_start );
664
 
  free( mgr_data->m_tag_end );
665
 
 
666
 
  mgr_data->m_tag_start = strdup( start );
667
 
  mgr_data->m_tag_end   = strdup( end );
668
 
}
669
 
 
670
 
t_ae_tag ae_get_tag( t_ae_template_mgr mgr, CONST char* name ) {
671
 
  MGR_CAST( mgr_data, mgr );
672
 
  t_ae_tag_list* item;
673
 
 
674
 
  /* return the first tag answering to the given name */
675
 
  item = mgr_data->m_taglist_head;
676
 
  while( item != NULL ) {
677
 
    if( strcmp( item->tag->m_tag, name ) == 0 ) {
678
 
      return (t_ae_tag)item->tag;
679
 
    }
680
 
    item = item->next;
681
 
  }
682
 
 
683
 
  return NULL;
684
 
}
685
 
 
686
 
char* ae_get_value( t_ae_template_mgr mgr, CONST char* name ) {
687
 
  MGR_CAST( mgr_data, mgr );
688
 
  t_ae_tag_list* item;
689
 
 
690
 
  /* return the value of the first tag answering to the given name */
691
 
  item = mgr_data->m_taglist_head;
692
 
  while( item != NULL ) {
693
 
    if( strcmp( item->tag->m_tag, name ) == 0 ) {
694
 
      if( item->tag->type != TAG_TYPE_VALUE ) return NULL;
695
 
      return item->tag->get_value( (t_ae_tag)item->tag );
696
 
    }
697
 
    item = item->next;
698
 
  }
699
 
 
700
 
  return NULL;
701
 
}
702
 
 
703
 
t_ae_tag ae_get_tag_at( t_ae_template_mgr mgr, int index ) {
704
 
  MGR_CAST( mgr_data, mgr );
705
 
  t_ae_tag_list* item;
706
 
 
707
 
  item = mgr_data->m_taglist_head;
708
 
  while( index > 0 && item != NULL ) {
709
 
    item = item->next;
710
 
    index--;
711
 
  }
712
 
 
713
 
  if( item != NULL ) return item->tag;
714
 
 
715
 
  return item;
716
 
}
717
 
 
718
 
int ae_process_template( t_ae_template_mgr mgr, CONST char* file, FILE* output ) {
719
 
  t_ae_stream stream;
720
 
  int rc;
721
 
 
722
 
  /* open a file stream for the given file-name, and process the stream */
723
 
 
724
 
  stream = ae_stream_open_file( file );
725
 
  if( stream == NULL ) {
726
 
    return -1;
727
 
  }
728
 
  rc = ae_process_stream( mgr, stream, output );
729
 
  ae_stream_close( stream );
730
 
 
731
 
  return rc;
732
 
}
733
 
 
734
 
int ae_process_buffer( t_ae_template_mgr mgr, CONST char* buffer, FILE* output ) {
735
 
  t_ae_stream stream;
736
 
  int rc;
737
 
 
738
 
  /* open a buffer stream for the given buffer, and process the stream */
739
 
 
740
 
  stream = ae_stream_open_buffer( buffer );
741
 
  if( stream == NULL ) {
742
 
    return -1;
743
 
  }
744
 
  rc = ae_process_stream( mgr, stream, output );
745
 
  ae_stream_close( stream );
746
 
 
747
 
  return rc;
748
 
}
749
 
 
750
 
int ae_process_stream( t_ae_template_mgr mgr, t_ae_stream stream, FILE* output ) {
751
 
  MGR_CAST( mgr_data, mgr );
752
 
  t_ae_tag_list* item;
753
 
  char* text;
754
 
  char* data;
755
 
  char* start;
756
 
  char* last_start;
757
 
  char* end;
758
 
  int   size;
759
 
  int   start_delim_len;
760
 
  int   end_delim_len;
761
 
  int   rc = 0;
762
 
  int   original_fd = -1;
763
 
 
764
 
  /* if a preprocessing function has been specified, use it */
765
 
  if( mgr_data->recursive_depth < 1 && mgr_data->preproc != NULL ) {
766
 
    original_fd = ae_redirect_to( output, STDOUT_FILENO );
767
 
    mgr_data->preproc( mgr, output );
768
 
  }
769
 
 
770
 
  /* increment the recursive depth */
771
 
  mgr_data->recursive_depth++;
772
 
 
773
 
  /* precompute the length of the start and end delimiters */
774
 
  start_delim_len = strlen( mgr_data->m_tag_start );
775
 
  end_delim_len = strlen( mgr_data->m_tag_end );
776
 
 
777
 
  /* read the entire stream into a buffer */
778
 
  size = ae_stream_get_length( stream );
779
 
  data = (char*)malloc( size+1 );
780
 
  ae_stream_read( stream, data, size+1 );
781
 
  data[ size ] = 0;
782
 
 
783
 
  /* search through the text of the stream, replacing tags as they are encountered */
784
 
  text = data;
785
 
  start = strstr( text, mgr_data->m_tag_start );
786
 
  while( start != NULL ) {
787
 
    *start = 0;
788
 
    fputs( text, output );
789
 
 
790
 
    /* find the next end-token */
791
 
    end = strstr( start + start_delim_len, mgr_data->m_tag_end );
792
 
    if( end == NULL ) {
793
 
      fputs( "[unclosed tag]", output );
794
 
      rc = -1;
795
 
      break;
796
 
    }
797
 
 
798
 
    /* skip past nested tags, by looking for start-tags that begin after the current
799
 
     * start position, but before the next end-token. That is to say, if the tag delimiters
800
 
     * are <% and %>:
801
 
     *   <%   <%   <%  %>   %>       %>
802
 
     *   ^    ^        ^
803
 
     *   | last_start  |
804
 
     *   start         end
805
 
     * Here, start is the first start-token found, and end is the first end-token found.
806
 
     * Nested tags are detected because last_start exists between start and end. */
807
 
 
808
 
    last_start = strstr( start + start_delim_len, mgr_data->m_tag_start );
809
 
    while( last_start != NULL && last_start < end ) {
810
 
      /* We've found a nested token, so we skip it by looking for the next 'last_start' tag
811
 
       * AND the next 'end' tag, and we continue the loop if the last_start tag is before the
812
 
       * end tag.  In other words:
813
 
       *   End of Iteration #1  <%   <%   <%  %>   %>       %>
814
 
       *                        S         L        E
815
 
       *   End of Iteration #2  <%   <%   <%  %>   %>       %>
816
 
       *                        S                           E   ... L
817
 
       * Thus, by the end of iteration #2, last_start is either NULL or after E, which
818
 
       * means that the stretch of data from S to E completely contains all tags within
819
 
       * it, with no tags overlapping the ends of S-E. */
820
 
 
821
 
      end = strstr( end + end_delim_len, mgr_data->m_tag_end );
822
 
      if( end == NULL ) break;
823
 
      last_start = strstr( last_start + start_delim_len, mgr_data->m_tag_start );
824
 
    }
825
 
 
826
 
    /* if end is NULL, then the tag was not closed */
827
 
    if( end == NULL ) {
828
 
      fputs( "[unclosed tag]", output );
829
 
      rc = -1;
830
 
      break;
831
 
    }
832
 
 
833
 
    /* skip past the starting delimiter */
834
 
    start = start + start_delim_len;
835
 
    *end = 0;
836
 
 
837
 
    /* look for the first tag that can apply the given tag text.  Each tag contains
838
 
     * the logic it needs to recognize itself at the head of a chunk of text ('start'). */
839
 
    for( item = mgr_data->m_taglist_head; item != NULL; item = item->next ) {
840
 
      if( item->tag->apply( item->tag, start, mgr, output ) ) {
841
 
        break;
842
 
      }
843
 
    }
844
 
 
845
 
    /* start the next loop after the end of the ending delimiter */
846
 
    text = end + end_delim_len;
847
 
 
848
 
    /* look for the next starting delimiter */
849
 
    start = strstr( text, mgr_data->m_tag_start );
850
 
  }
851
 
 
852
 
  /* write the remaining data */
853
 
  fputs( text, output );
854
 
  free( data );
855
 
 
856
 
  /* decrement the recursive depth, as we are now leaving this function */
857
 
  mgr_data->recursive_depth--;
858
 
  if( mgr_data->recursive_depth < 1 ) {
859
 
    ae_restore_file( original_fd, stdout );
860
 
  }
861
 
 
862
 
  return rc;
863
 
}
864
 
 
865
 
void ae_set_preprocessor_func( t_ae_template_mgr mgr, t_ae_preproc_fn func ) {
866
 
  MGR_CAST( mgr_data, mgr );
867
 
  mgr_data->preproc = func;
868
 
}
869
 
 
870
 
void ae_set_mgr_cookie( t_ae_template_mgr mgr, void* cookie ) {
871
 
  MGR_CAST( mgr_data, mgr );
872
 
  mgr_data->cookie = cookie;
873
 
}
874
 
 
875
 
void* ae_get_mgr_cookie( t_ae_template_mgr mgr ) {
876
 
  MGR_CAST( mgr_data, mgr );
877
 
  return mgr_data->cookie;
878
 
}
879
 
 
880
 
 
881
 
/* ------------------------------------------------------------------------- */
882
 
/* ToHTML Replacement Functions                                              */
883
 
/* ------------------------------------------------------------------------- */
884
 
 
885
 
int ToHTML2( CONST char* tem_file, char** tokens, char** values, int mode ) {
886
 
  return ae_done_html( ae_init_html( tokens, values, mode ), tem_file );
887
 
}
888
 
 
889
 
 
890
 
t_ae_template_mgr ae_init_html( char** tokens, char** values, int mode ) {
891
 
  t_ae_template_mgr mgr;
892
 
  t_ae_html_proc_data* data;
893
 
 
894
 
  /* set up the HTML proc data structure, with fields' values depending on the value of mode */
895
 
  data = NEW( t_ae_html_proc_data );
896
 
  data->headers = ( mode & HTML_HEADER );
897
 
  data->no_cache = ( mode & HTML_NO_CACHE );
898
 
  data->cookies = NULL;
899
 
 
900
 
  /* default the output to stdout, but see ae_set_html_output */
901
 
  data->output = stdout;
902
 
 
903
 
  /* create the template manager */
904
 
  mgr = ae_template_mgr_new();
905
 
 
906
 
  /* set the HTML proc data structure in the template manager */
907
 
  ae_set_mgr_cookie( mgr, data );
908
 
 
909
 
  /* set the HTML preprocessor function (to handle writing of headers */
910
 
  ae_set_preprocessor_func( mgr, static_html_preproc_fn );
911
 
 
912
 
  /* add the token/value pairs */
913
 
  ae_add_tags( mgr, tokens, values );
914
 
 
915
 
  return mgr;
916
 
}
917
 
 
918
 
 
919
 
int ae_done_html( t_ae_template_mgr mgr, CONST char* tem_file ) {
920
 
  int rc = 0;
921
 
  t_ae_html_proc_data* data;
922
 
  t_ae_cookie* cookie;
923
 
  t_ae_cookie* next;
924
 
 
925
 
  data = (t_ae_html_proc_data*)ae_get_mgr_cookie( mgr );
926
 
 
927
 
  /* if a template file is specified, process it */
928
 
  if( tem_file != NULL ) {
929
 
    rc = ae_process_template( mgr, tem_file, data->output );
930
 
  }
931
 
 
932
 
  /* free the cookie list */
933
 
  cookie = data->cookies;
934
 
  while( cookie != NULL ) {
935
 
    free( cookie->name );
936
 
    free( cookie->value );
937
 
    next = cookie->next;
938
 
    free( cookie );
939
 
    cookie = next;
940
 
  }
941
 
 
942
 
  /* free the data */
943
 
  free( data );
944
 
 
945
 
  /* cleanup the manager */
946
 
  ae_template_mgr_done( mgr );
947
 
 
948
 
  /* convert return code into boolean -- '1' means success, '0' means failure.
949
 
   * This is left over from the original ToHTML implementation. */
950
 
  return ( rc == 0 ? 1 : 0 );
951
 
}
952
 
 
953
 
 
954
 
void ae_set_cookie( t_ae_template_mgr mgr,
955
 
                    CONST char* name,
956
 
                    CONST char* value,
957
 
                    int ttl )
958
 
{
959
 
  t_ae_html_proc_data* data;
960
 
  t_ae_cookie* cookie;
961
 
 
962
 
  data = (t_ae_html_proc_data*)ae_get_mgr_cookie( mgr );
963
 
  cookie = NEW( t_ae_cookie );
964
 
 
965
 
  cookie->name = strdup( name );
966
 
  cookie->value = strdup( value );
967
 
  cookie->ttl = ttl;
968
 
  cookie->next = data->cookies;
969
 
 
970
 
  data->cookies = cookie;
971
 
}
972
 
 
973
 
 
974
 
void ae_set_html_output( t_ae_template_mgr mgr, FILE* output ) {
975
 
  t_ae_html_proc_data* data;
976
 
  data = (t_ae_html_proc_data*)ae_get_mgr_cookie( mgr );
977
 
  data->output = output;
978
 
}
979
 
 
980
 
/* ------------------------------------------------------------------------- */
981
 
/* miscellaneous utility functions                                           */
982
 
/* ------------------------------------------------------------------------- */
983
 
 
984
 
char* ae_get_field( CONST char* text, CONST char* delim, int which ) {
985
 
  DECL_CAST( ptr, text, char );
986
 
 
987
 
  while( which > 0 ) {
988
 
    ptr = strstr( ptr, delim );
989
 
    if( ptr == NULL ) break;
990
 
    ptr += strlen( delim );
991
 
    which--;
992
 
  }
993
 
 
994
 
  return ptr;
995
 
}
996
 
 
997
 
char* ae_get_field_alloc( CONST char* text, CONST char* delim, int which ) {
998
 
  char* ptr;
999
 
  char* new_ptr;
1000
 
  int   len;
1001
 
 
1002
 
  ptr = ae_get_field( text, delim, which );
1003
 
  if( ptr == NULL ) return NULL;
1004
 
  len = ae_field_len( ptr, delim );
1005
 
  new_ptr = (char*)malloc( len+1 );
1006
 
  ae_field_cpy( new_ptr, ptr, delim );
1007
 
 
1008
 
  return new_ptr;
1009
 
}
1010
 
 
1011
 
int ae_field_cmp( CONST char* field, CONST char* text, CONST char* delim ) {
1012
 
  char* end;
1013
 
  char* fptr;
1014
 
  char* tptr;
1015
 
 
1016
 
  end = strstr( field, delim );
1017
 
  if( end == NULL ) end = (char*)field+strlen(field);
1018
 
 
1019
 
  /* look for the end of one of the strings, or the first point where they differ */
1020
 
  for( fptr = (char*)field, tptr = (char*)text; *tptr && *fptr == *tptr && fptr < end; fptr++, tptr++ ) {
1021
 
    /* do nothing */
1022
 
  }
1023
 
 
1024
 
  if( fptr == end && *tptr == 0 ) return 0;
1025
 
  if( *tptr == 0 ) return 1;
1026
 
  return -1;
1027
 
}
1028
 
 
1029
 
int ae_field_len( CONST char* field, CONST char* delim ) {
1030
 
  char* end;
1031
 
 
1032
 
  end = strstr( field, delim );
1033
 
  if( end == NULL ) end = (char*)field+strlen(field);
1034
 
 
1035
 
  return (int)( end - field );
1036
 
}
1037
 
 
1038
 
char* ae_field_cpy( char* dest, CONST char* field, CONST char* delim ) {
1039
 
  char* end;
1040
 
 
1041
 
  end = strstr( field, delim );
1042
 
  if( end == NULL ) end = (char*)field+strlen(field);
1043
 
 
1044
 
  memcpy( dest, (char*)field, (int)(end-field) );
1045
 
  dest[ (int)(end-field) ] = 0;
1046
 
 
1047
 
  return dest;
1048
 
}
1049
 
 
1050
 
void* ae_load_dynamic_function( CONST char* lib, CONST char* func ) {
1051
 
  void* func_ptr = NULL;
1052
 
  int load_flags;
1053
 
 
1054
 
#if defined( DLOPEN_TYPE )
1055
 
  void* lib_handle;
1056
 
 
1057
 
  load_flags = RTLD_NOW;
1058
 
  if( !( lib_handle = dlopen( lib, load_flags ) ) ) {
1059
 
    fprintf( stderr, "[could not load shared library '%s': %s]", lib, dlerror() );
1060
 
    return NULL;
1061
 
  }
1062
 
 
1063
 
  if( !( func_ptr = dlsym( lib_handle, func ) ) ) {
1064
 
    fprintf( stderr, "[could not load entry point '%s:%s', %s]", lib, func, dlerror() );
1065
 
    return NULL;
1066
 
  }
1067
 
#elif defined( _HPUX_SOURCE )
1068
 
  shl_t lib_handle;
1069
 
 
1070
 
  load_flags = BIND_IMMEDIATE | BIND_VERBOSE;
1071
 
  if( !(lib_handle = shl_load( lib, load_flags, 0 ) ) ) {
1072
 
    fprintf( stderr, "[could not load shared library '%s']", lib );
1073
 
    return NULL;
1074
 
  }
1075
 
 
1076
 
  if( shl_findsym( &lib_handle, func, TYPE_PROCEDURE, (void*)&func_ptr ) ) {
1077
 
    fprintf( stderr, "[could not load entry point '%s:%s']", lib, func );
1078
 
    return NULL;
1079
 
  }
1080
 
#endif
1081
 
 
1082
 
  return func_ptr;
1083
 
}
1084
 
 
1085
 
char* ae_build_library_name( char* dest, CONST char* root ) {
1086
 
  char* buffer;
1087
 
  char  cwd[ 256 ];
1088
 
  char* sfx;
1089
 
  char* webroot;
1090
 
 
1091
 
  buffer = dest;
1092
 
  if( buffer == NULL ) {
1093
 
    buffer = (char*)malloc( 256 );
1094
 
  }
1095
 
 
1096
 
#if defined( _HPUX_SOURCE )
1097
 
  /* with AE's framework, all libs are in /opt/<stage>/lib, where <stage> is
1098
 
   * 'dev', 'tst', or 'prod'.  Depending on what the working directory is,
1099
 
   * figure out which <stage> we are in and look for the library in that
1100
 
   * library dir. */
1101
 
  getcwd( cwd, sizeof( cwd ) );
1102
 
  webroot = strstr(cwd, "web");
1103
 
  if(webroot != NULL)
1104
 
  {
1105
 
    *webroot = '\0';
1106
 
    strcpy( buffer, cwd );
1107
 
  }
1108
 
  else
1109
 
  {
1110
 
    strcpy( buffer, "/opt/" );
1111
 
    if( strstr( cwd, "/prod/" ) ) {
1112
 
      strcat( buffer, "prod/" );
1113
 
    } else if( strstr( cwd, "/tst/" ) ) {
1114
 
      strcat( buffer, "tst/" );
1115
 
    } else {
1116
 
      strcat( buffer, "dev/" );
1117
 
    }
1118
 
  }
1119
 
  strcat( buffer, "lib/" );
1120
 
  sfx = ".sl";
1121
 
#else
1122
 
  strcpy( buffer, "" );
1123
 
  sfx = ".so";
1124
 
#endif
1125
 
 
1126
 
  strcat( buffer, "lib" );
1127
 
  strcat( buffer, root );
1128
 
  strcat( buffer, sfx );
1129
 
 
1130
 
  return buffer;
1131
 
}
1132
 
 
1133
 
 
1134
 
int ae_redirect_to( FILE* output, int original_fd ) {
1135
 
  int old_fd = -1;
1136
 
 
1137
 
  /* if 'output' is not already 'original_fd'... */
1138
 
  if( fileno( output ) != original_fd ) {
1139
 
    /* flush any cached data on output */
1140
 
    fflush( output );
1141
 
    /* copy original_fd */
1142
 
    old_fd = dup( original_fd );
1143
 
    /* set original_fd to be the same as 'output' */
1144
 
    dup2( fileno( output ), original_fd );
1145
 
  }
1146
 
  return old_fd;
1147
 
}
1148
 
 
1149
 
 
1150
 
void ae_restore_file( int original_fd, FILE* file ) {
1151
 
  /* if original_fd is valid... */
1152
 
  if( original_fd >= 0 ) {
1153
 
    /* flush any cached data on 'file' */
1154
 
    fflush( file );
1155
 
    /* set file to be a copy of 'original_fd' */
1156
 
    dup2( original_fd, fileno( file ) );
1157
 
    /* close 'original_fd' */
1158
 
    close( original_fd );
1159
 
  }
1160
 
}
1161
 
 
1162
 
/* ------------------------------------------------------------------------- */
1163
 
/* static function implementations                                           */
1164
 
/* ------------------------------------------------------------------------- */
1165
 
 
1166
 
static t_ae_file_stream* static_ae_file_stream_new( void ) {
1167
 
  t_ae_file_stream* ptr;
1168
 
  ptr = (t_ae_file_stream*)malloc( sizeof( t_ae_file_stream ) );
1169
 
  ptr->get_length = static_ae_file_stream_get_length;
1170
 
  ptr->read = static_ae_file_stream_read;
1171
 
  ptr->close = static_ae_file_stream_close;
1172
 
  ptr->wrapped = 0;
1173
 
  ptr->fptr = NULL;
1174
 
  return ptr;
1175
 
}
1176
 
 
1177
 
static t_ae_buffer_stream* static_ae_buffer_stream_new( void ) {
1178
 
  t_ae_buffer_stream* ptr;
1179
 
  ptr = (t_ae_buffer_stream*)malloc( sizeof( t_ae_buffer_stream ) );
1180
 
  ptr->get_length = static_ae_buffer_stream_get_length;
1181
 
  ptr->read = static_ae_buffer_stream_read;
1182
 
  ptr->close = static_ae_buffer_stream_close;
1183
 
  ptr->buffer = NULL;
1184
 
  ptr->pos = 0;
1185
 
  return ptr;
1186
 
}
1187
 
 
1188
 
static int static_ae_file_stream_get_length( t_ae_stream stream ) {
1189
 
  DECL_CAST( ptr, stream, t_ae_file_stream );
1190
 
  int pos;
1191
 
  int len;
1192
 
 
1193
 
  if( ptr->fptr == NULL ) return -1;
1194
 
 
1195
 
  /* compute the file's length by seeking to the end, getting the position,
1196
 
   * and the seeking back to our original position.  The position at the end
1197
 
   * of the file is the length of the file. */
1198
 
 
1199
 
  pos = ftell( ptr->fptr );
1200
 
  fseek( ptr->fptr, 0, SEEK_END );
1201
 
  len = ftell( ptr->fptr );
1202
 
  fseek( ptr->fptr, pos, SEEK_SET );
1203
 
 
1204
 
  return len;
1205
 
}
1206
 
 
1207
 
static int static_ae_file_stream_read( t_ae_stream stream, char* buffer, int length ) {
1208
 
  DECL_CAST( ptr, stream, t_ae_file_stream );
1209
 
  if( ptr->fptr == NULL ) return -1;
1210
 
  return fread( buffer, 1, length, ptr->fptr );
1211
 
}
1212
 
 
1213
 
static int static_ae_file_stream_close( t_ae_stream stream ) {
1214
 
  DECL_CAST( ptr, stream, t_ae_file_stream );
1215
 
  if( ptr->fptr == NULL ) return -1;
1216
 
  if( !ptr->wrapped ) {
1217
 
    fclose( ptr->fptr );
1218
 
  }
1219
 
  ptr->fptr = NULL;
1220
 
  ptr->wrapped = 0;
1221
 
  return 0;
1222
 
}
1223
 
 
1224
 
static int static_ae_buffer_stream_get_length( t_ae_stream stream ) {
1225
 
  DECL_CAST( ptr, stream, t_ae_buffer_stream );
1226
 
  if( ptr->buffer == NULL ) return -1;
1227
 
  return strlen( ptr->buffer );
1228
 
}
1229
 
 
1230
 
static int static_ae_buffer_stream_read( t_ae_stream stream, char* buffer, int length ) {
1231
 
  DECL_CAST( ptr, stream, t_ae_buffer_stream );
1232
 
  int len;
1233
 
 
1234
 
  if( ptr->buffer == NULL ) return -1;
1235
 
  len = strlen( ptr->buffer ) - ptr->pos;
1236
 
  len = ( len > length ? length : len );
1237
 
  memcpy( buffer, ptr->buffer+ptr->pos, len );
1238
 
 
1239
 
  return len;
1240
 
}
1241
 
 
1242
 
static int static_ae_buffer_stream_close( t_ae_stream stream ) {
1243
 
  DECL_CAST( ptr, stream, t_ae_buffer_stream );
1244
 
  if( ptr->buffer == NULL ) return -1;
1245
 
  free( ptr->buffer );
1246
 
  ptr->buffer = NULL;
1247
 
  ptr->pos = 0;
1248
 
  return 0;
1249
 
}
1250
 
 
1251
 
static t_ae_tag static_ae_comparison_tag( CONST char* name,
1252
 
                                          int comparison )
1253
 
{
1254
 
  t_ae_comparison_tag* tag;
1255
 
 
1256
 
  tag = (t_ae_comparison_tag*)ae_typed_tag( name,
1257
 
                                            static_ae_comparison_tag_process,
1258
 
                                            sizeof( t_ae_comparison_tag ) );
1259
 
  tag->comp_type = comparison;
1260
 
 
1261
 
  return (t_ae_tag)tag;
1262
 
}
1263
 
 
1264
 
static int static_ae_replace_tag_apply( t_ae_tag tag,
1265
 
                                        CONST char* text,
1266
 
                                        t_ae_template_mgr mgr,
1267
 
                                        FILE* output )
1268
 
{
1269
 
  DECL_CAST( tag_data, tag, t_ae_replace_tag );
1270
 
  if( strcmp( tag_data->m_tag, text ) != 0 ) return 0;
1271
 
  return tag_data->process( tag, text, mgr, output );
1272
 
}
1273
 
 
1274
 
static int static_ae_replace_tag_process( t_ae_tag tag,
1275
 
                                          CONST char* text,
1276
 
                                          t_ae_template_mgr mgr,
1277
 
                                          FILE* output )
1278
 
{
1279
 
  DECL_CAST( tag_data, tag, t_ae_replace_tag );
1280
 
  if( tag_data->m_data != NULL ) {
1281
 
    fputs( tag_data->m_data, output );
1282
 
  }
1283
 
  return 1;
1284
 
}
1285
 
 
1286
 
static int static_ae_replace_tag_cleanup( t_ae_tag tag ) {
1287
 
  DECL_CAST( tag_data, tag, t_ae_replace_tag );
1288
 
  if( tag_data->m_data != NULL ) {
1289
 
    free( tag_data->m_data );
1290
 
  }
1291
 
  tag_data->m_data = NULL;
1292
 
  return 0;
1293
 
}
1294
 
 
1295
 
static int static_ae_cyclical_replace_tag_process( t_ae_tag tag,
1296
 
                                                   CONST char* text,
1297
 
                                                   t_ae_template_mgr mgr,
1298
 
                                                   FILE* output )
1299
 
{
1300
 
  DECL_CAST( tag_data, tag, t_ae_cyclical_replace_tag );
1301
 
  char* end;
1302
 
 
1303
 
  if( *(tag_data->m_next) == 0 ) {
1304
 
    fputs( "no more data values in cyclical replace tag", output );
1305
 
    tag_data->m_next = 0;
1306
 
    return 1;
1307
 
  }
1308
 
 
1309
 
  /* find the next delimiter, in the data */
1310
 
  end = strstr( tag_data->m_next, tag_data->m_rpt_delim );
1311
 
  if( end == 0 ) {
1312
 
    fputs( "non-terminated data string in cyclical replace tag", output );
1313
 
    tag_data->m_next = 0;
1314
 
    return 1;
1315
 
  }
1316
 
 
1317
 
  /* write out all data up to the 'end' pointer */
1318
 
  while( tag_data->m_next < end ) {
1319
 
    fputc( *(tag_data->m_next), output );
1320
 
    tag_data->m_next++;
1321
 
  }
1322
 
 
1323
 
  /* move the pointer past the delimiter at the end of the record, so it now
1324
 
   * points to the beginning of the next record. */
1325
 
 
1326
 
  tag_data->m_next += strlen( tag_data->m_rpt_delim );
1327
 
  return 1;
1328
 
}
1329
 
 
1330
 
static int static_ae_cyclical_replace_tag_cleanup( t_ae_tag tag ) {
1331
 
  DECL_CAST( tag_data, tag, t_ae_cyclical_replace_tag );
1332
 
  free( tag_data->m_data );
1333
 
  free( tag_data->m_rpt_delim );
1334
 
  tag_data->m_next = NULL;
1335
 
  return 0;
1336
 
}
1337
 
 
1338
 
static int static_ae_typed_tag_apply( t_ae_tag tag,
1339
 
                                      CONST char* text,
1340
 
                                      t_ae_template_mgr mgr,
1341
 
                                      FILE* output )
1342
 
{
1343
 
  GENERIC_TAG( tag_data, tag );
1344
 
  char* type;
1345
 
 
1346
 
  type = ae_get_field( text, tag_data->m_delim, 0 );
1347
 
  if( type == NULL ) return 0;
1348
 
  /* a typed tag matches if the first field of the text chunk matches the m_tag (name)
1349
 
   * field of the tag.  If it does, then we call the process function for this tag. */
1350
 
  if( ae_field_cmp( type, tag_data->m_tag, tag_data->m_delim ) != 0 ) return 0;
1351
 
  return tag_data->process( tag, text, mgr, output );
1352
 
}
1353
 
 
1354
 
static int static_ae_if_tag_process( t_ae_tag tag,
1355
 
                                     CONST char* text,
1356
 
                                     t_ae_template_mgr mgr,
1357
 
                                     FILE* output )
1358
 
{
1359
 
  GENERIC_TAG( tag_data, tag );
1360
 
  char* tok;
1361
 
  char* value;
1362
 
  char  tok_buf[ 64 ];
1363
 
 
1364
 
  tok = ae_get_field( text, tag_data->m_delim, 1 );
1365
 
  ae_field_cpy( tok_buf, tok, tag_data->m_delim );
1366
 
  value = ae_get_value( mgr, tok_buf );
1367
 
  if( !( value && *value ) ) {
1368
 
    return 0;
1369
 
  }
1370
 
 
1371
 
  ae_process_buffer( mgr, ae_get_field( text, tag_data->m_delim, 2 ), output );
1372
 
  return 1;
1373
 
}
1374
 
 
1375
 
static int static_ae_if_not_tag_process( t_ae_tag tag,
1376
 
                                         CONST char* text,
1377
 
                                         t_ae_template_mgr mgr,
1378
 
                                         FILE* output )
1379
 
{
1380
 
  GENERIC_TAG( tag_data, tag );
1381
 
  char* tok;
1382
 
  char* value;
1383
 
  char  tok_buf[ 64 ];
1384
 
 
1385
 
  tok = ae_get_field( text, tag_data->m_delim, 1 );
1386
 
  ae_field_cpy( tok_buf, tok, tag_data->m_delim );
1387
 
  value = ae_get_value( mgr, tok_buf );
1388
 
  if( value && *value ) {
1389
 
    return 0;
1390
 
  }
1391
 
 
1392
 
  ae_process_buffer( mgr, ae_get_field( text, tag_data->m_delim, 2 ), output );
1393
 
  return 1;
1394
 
}
1395
 
 
1396
 
static int static_ae_include_tag_process( t_ae_tag tag,
1397
 
                                          CONST char* text,
1398
 
                                          t_ae_template_mgr mgr,
1399
 
                                          FILE* output )
1400
 
{
1401
 
  GENERIC_TAG( tag_data, tag );
1402
 
  char* tok;
1403
 
 
1404
 
  tok = ae_get_field( text, tag_data->m_delim, 1 );
1405
 
  if( ae_get_tag( mgr, tok ) != NULL ) {
1406
 
    tok = ae_get_value( mgr, tok );
1407
 
  }
1408
 
  ae_process_template( mgr, tok, output );
1409
 
 
1410
 
  return 1;
1411
 
}
1412
 
 
1413
 
#define ROW_NUM_TAG_NAME "ae_row_num"
1414
 
 
1415
 
static int static_ae_repeat_tag_process( t_ae_tag tag,
1416
 
                                         CONST char* text,
1417
 
                                         t_ae_template_mgr mgr,
1418
 
                                         FILE* output )
1419
 
{
1420
 
  GENERIC_TAG( tag_data, tag );
1421
 
  t_ae_cyclical_replace_tag* repl_tag;
1422
 
  t_ae_replace_tag* row_tag;
1423
 
  char* source;
1424
 
  char* token;
1425
 
  char* delim;
1426
 
  char* data;
1427
 
  char  row_num_tag[32];
1428
 
  char  row_num_value[10];
1429
 
  int   i;
1430
 
  
1431
 
  source = ae_get_field_alloc( text, tag_data->m_delim, 1 );
1432
 
  token  = ae_get_field_alloc( text, tag_data->m_delim, 2 );
1433
 
  delim  = ae_get_field_alloc( text, tag_data->m_delim, 3 );
1434
 
  data   = ae_get_field( text, tag_data->m_delim, 4 );
1435
 
 
1436
 
  /* create a new cyclical replace tag from the delimited string associated with this
1437
 
   * repeat tag.  Add it to the manager */
1438
 
 
1439
 
  repl_tag = ae_cyclical_replace_tag( token, ae_get_value( mgr, source ), delim );
1440
 
  ae_add_tag_ex( mgr, repl_tag );
1441
 
 
1442
 
  /* look for the first available row_num tag name.  By default, we use ae_row_num, but
1443
 
   * if it is taken then that means that we are currently embedded inside of a repeat tag.
1444
 
   * So, we add a number to the end of the tag name and try again.  This continues until
1445
 
   * a number is found that is not taken.  This allows repeat tags to be nested to an
1446
 
   * arbitrary depth. */
1447
 
 
1448
 
  i = 1;
1449
 
  strcpy( row_num_tag, ROW_NUM_TAG_NAME );
1450
 
  while( ae_get_tag( mgr, row_num_tag ) != NULL ) {
1451
 
    i++;
1452
 
    sprintf( row_num_tag, ROW_NUM_TAG_NAME "_%d", i );
1453
 
  }
1454
 
  
1455
 
  /* repeatedly process the data for the repeat tag, until the cyclical replace tag
1456
 
   * is out of data.  Each pass through the data, we increment the row num and set
1457
 
   * it in the row_num_tag variable. */
1458
 
 
1459
 
  i = 1;
1460
 
  while( *(repl_tag->m_next) != 0 ) {
1461
 
    sprintf( row_num_value, "%d", i );
1462
 
    ae_add_tag( mgr, row_num_tag, row_num_value );
1463
 
    ae_process_buffer( mgr, data, output );
1464
 
    i++;
1465
 
  }
1466
 
 
1467
 
  /* remove the row_num_tag and the cyclical replace tag from the manager */
1468
 
  ae_remove_tag( mgr, row_num_tag );
1469
 
  ae_remove_tag_ex( mgr, repl_tag );
1470
 
 
1471
 
  /* free our allocated data */
1472
 
  free( source );
1473
 
  free( token );
1474
 
  free( delim );
1475
 
 
1476
 
  return 1;
1477
 
}
1478
 
 
1479
 
static int static_ae_env_tag_process( t_ae_tag tag,
1480
 
                                      CONST char* text,
1481
 
                                      t_ae_template_mgr mgr,
1482
 
                                      FILE* output )
1483
 
{
1484
 
  char *env;
1485
 
  char* val;
1486
 
 
1487
 
  env = ae_get_field( text, ae_get_tag_delim( tag ), 1 );
1488
 
  val = getenv( env );
1489
 
 
1490
 
  if( val ) {
1491
 
    fputs( val, output );
1492
 
  }
1493
 
 
1494
 
  return 1;
1495
 
}
1496
 
 
1497
 
static int static_ae_exec_tag_process( t_ae_tag tag,
1498
 
                                       CONST char* text,
1499
 
                                       t_ae_template_mgr mgr,
1500
 
                                       FILE* output )
1501
 
{
1502
 
  char *tok;
1503
 
  char* val;
1504
 
  FILE* pipe_output;
1505
 
  char  buf[ 128 ];
1506
 
  int   count;
1507
 
 
1508
 
  tok = ae_get_field( text, ae_get_tag_delim( tag ), 1 );
1509
 
  if( ae_get_tag( mgr, tok ) != NULL ) {
1510
 
    tok = ae_get_value( mgr, tok );
1511
 
  }
1512
 
 
1513
 
  pipe_output = popen( tok, "r" );
1514
 
  if( pipe_output == NULL ) {
1515
 
    fprintf( output, "[popen failed: %d (%s)]", errno, strerror( errno ) );
1516
 
  } else {
1517
 
    while( ( count = fread( buf, 1, sizeof( buf )-1, pipe_output ) ) > 0 ) {
1518
 
      buf[ count ] = 0;
1519
 
      fputs( buf, output );
1520
 
    }
1521
 
    pclose( pipe_output );
1522
 
  }
1523
 
 
1524
 
  return 1;
1525
 
}
1526
 
 
1527
 
static int static_ae_comparison_tag_process( t_ae_tag tag,
1528
 
                                             CONST char* text,
1529
 
                                             t_ae_template_mgr mgr,
1530
 
                                             FILE* output )
1531
 
{
1532
 
  DECL_CAST( tag_data, tag, t_ae_comparison_tag );
1533
 
  char* tok_buf;
1534
 
  char* val_buf;
1535
 
  int   comp_result;
1536
 
 
1537
 
  tok_buf = ae_get_field_alloc( text, tag_data->m_delim, 1 );
1538
 
  val_buf = ae_get_field_alloc( text, tag_data->m_delim, 2 );
1539
 
  comp_result = strcmp( ae_get_value( mgr, tok_buf ), val_buf );
1540
 
 
1541
 
  switch( tag_data->comp_type ) {
1542
 
    case COMP_TYPE_EQ: comp_result = ( comp_result == 0 ); break;
1543
 
    case COMP_TYPE_NE: comp_result = ( comp_result != 0 ); break;
1544
 
    case COMP_TYPE_LT: comp_result = ( comp_result < 0 ); break;
1545
 
    case COMP_TYPE_LE: comp_result = ( comp_result <= 0 ); break;
1546
 
    case COMP_TYPE_GT: comp_result = ( comp_result > 0 ); break;
1547
 
    case COMP_TYPE_GE: comp_result = ( comp_result >= 0 ); break;
1548
 
  }
1549
 
 
1550
 
  if( comp_result ) {
1551
 
    ae_process_buffer( mgr, ae_get_field( text, tag_data->m_delim, 3 ), output );
1552
 
  }
1553
 
 
1554
 
  free( val_buf );
1555
 
  free( tok_buf );
1556
 
 
1557
 
  return 1;
1558
 
}
1559
 
 
1560
 
static int static_ae_include_tag_named_process( t_ae_tag tag,
1561
 
                                                CONST char* text,
1562
 
                                                t_ae_template_mgr mgr,
1563
 
                                                FILE* output )
1564
 
{
1565
 
  ae_process_template( mgr, ae_get_tag_value( tag ), output );
1566
 
  return 1;
1567
 
}
1568
 
 
1569
 
static int static_ae_shared_fn_apply( t_ae_tag tag,
1570
 
                                      CONST char* text,
1571
 
                                      t_ae_template_mgr mgr,
1572
 
                                      FILE* output )
1573
 
{
1574
 
  GENERIC_TAG( tag_data, tag );
1575
 
 
1576
 
  if( ae_field_cmp( ae_get_field( text, tag_data->m_delim, 0 ), "EXEC_SHARED", tag_data->m_delim ) != 0 )
1577
 
    return 0;
1578
 
 
1579
 
  if( ae_field_cmp( ae_get_field( text, tag_data->m_delim, 1 ), tag_data->m_tag, tag_data->m_delim ) != 0 )
1580
 
    return 0;
1581
 
 
1582
 
  return tag_data->process( tag, text, mgr, output );
1583
 
}
1584
 
 
1585
 
static int static_ae_shared_fn_process( t_ae_tag tag,
1586
 
                                        CONST char* text,
1587
 
                                        t_ae_template_mgr mgr,
1588
 
                                        FILE* output )
1589
 
{
1590
 
  DECL_CAST( tag_data, tag, t_ae_shared_fn_tag );
1591
 
  int (*func_ptr)( void* );
1592
 
  char libname[ 256 ];
1593
 
 
1594
 
  ae_build_library_name( libname, tag_data->m_lib );
1595
 
  func_ptr = (int(*)(void*))ae_load_dynamic_function( libname, tag_data->m_func );
1596
 
  if( func_ptr == NULL ) return 1;
1597
 
 
1598
 
  /* flush the output, since the function may write to stdout.  Although stdout is
1599
 
   * redirected to output already, if we don't flush the output here (and flush stdout
1600
 
   * at the end of the function) we will get text written in the wrong order, due to
1601
 
   * caching. */
1602
 
 
1603
 
  fflush( output );
1604
 
 
1605
 
  /* call the function */
1606
 
  func_ptr( tag_data->m_cookie );
1607
 
  fflush( stdout );
1608
 
 
1609
 
  return 1;
1610
 
}
1611
 
 
1612
 
static int static_ae_shared_fn_tag_cleanup( t_ae_tag tag ) {
1613
 
  DECL_CAST( tag_data, tag, t_ae_shared_fn_tag );
1614
 
  free( tag_data->m_lib );
1615
 
  free( tag_data->m_func );
1616
 
  return 0;
1617
 
}
1618
 
 
1619
 
static int static_html_preproc_fn( t_ae_template_mgr mgr, FILE* output ) {
1620
 
  t_ae_html_proc_data* data;
1621
 
  t_ae_cookie* cookie;
1622
 
  struct tm *tstr;
1623
 
  time_t curTime;
1624
 
  char ttlBuffer[ 128 ];
1625
 
 
1626
 
  data = (t_ae_html_proc_data*)ae_get_mgr_cookie( mgr );
1627
 
 
1628
 
  if( data->headers ) {
1629
 
    fputs( "Content-type: text/html\n", output );
1630
 
    if( data->no_cache ) {
1631
 
      fputs( "Pragma: no-cache\n", output );
1632
 
      fputs( "Expires: Thu, 1 Jan 1970 00:00:01 GMT\n", output );
1633
 
    }
1634
 
 
1635
 
    /* write the cookie definitions */
1636
 
    cookie = data->cookies;
1637
 
    while( cookie != NULL ) {
1638
 
      fprintf( output, "Set-Cookie: %s=%s; PATH=/", cookie->name, cookie->value );
1639
 
 
1640
 
      if( cookie->ttl >= 0 ) {
1641
 
        /* compute the time-to-live as the number of seconds from the current time.
1642
 
         * Cookie TTL's must be given in GMT. */
1643
 
        curTime = time( NULL ) + cookie->ttl;
1644
 
        tstr = gmtime( &curTime );
1645
 
        strftime( ttlBuffer, sizeof( ttlBuffer ), "%a, %d-%b-%y %H:%M:%S GMT", tstr );
1646
 
        fprintf( output, "; EXPIRES=%s", ttlBuffer );
1647
 
      }
1648
 
 
1649
 
      fprintf( output, "\n" );
1650
 
      cookie = cookie->next;
1651
 
    }
1652
 
 
1653
 
    fputs( "\n", output );
1654
 
  }
1655
 
 
1656
 
  return 0;
1657
 
}
1658
 
 
1659
 
 
1660
 
static char* static_get_non_value( t_ae_tag tag ) {
1661
 
  return NULL;
1662
 
}
1663
 
 
1664
 
static char* static_get_replace_tag_value( t_ae_tag tag ) {
1665
 
  DECL_CAST( tag_data, tag, t_ae_replace_tag );
1666
 
  return tag_data->m_data;
1667
 
}
1668
 
 

Loggerhead 1.17 is a web-based interface for Bazaar branches