Login
Check-in [b5b5a52965]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Added new file for Event APIs. Minor refactoring and code consolidation. Fixed a crosslinking bug which used a wrong (old/changed) format specifier for event-XXX tags.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: b5b5a529656d4287f92f1d9921a453b3257d4da5
User & Date: stephan 2013-08-24 23:21:01.453
Context
2013-08-25
09:12
API renamings (shortenings) and minor API simplifications. Doc updates, some work on making the R-card optional. check-in: c0752c60c2 user: stephan tags: trunk
2013-08-24
23:21
Added new file for Event APIs. Minor refactoring and code consolidation. Fixed a crosslinking bug which used a wrong (old/changed) format specifier for event-XXX tags. check-in: b5b5a52965 user: stephan tags: trunk
15:54
more wiki work check-in: 7df0b1de78 user: stephan tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to Makefile.in.
21
22
23
24
25
26
27

28
29
30
31
32
33
34
	fsl_buffer.c \
	fsl_content.c \
	fsl_config.c \
	fsl_cx.c \
	fsl_db.c \
	fsl_delta.c \
	fsl_encode.c \

	fsl_fs.c \
	fsl_io.c \
	fsl_leaf.c \
	fsl_md5.c \
	fsl_mf.c \
	fsl_pq.c \
	fsl_repo.c \







>







21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
	fsl_buffer.c \
	fsl_content.c \
	fsl_config.c \
	fsl_cx.c \
	fsl_db.c \
	fsl_delta.c \
	fsl_encode.c \
	fsl_event.c \
	fsl_fs.c \
	fsl_io.c \
	fsl_leaf.c \
	fsl_md5.c \
	fsl_mf.c \
	fsl_pq.c \
	fsl_repo.c \
Changes to f-event.c.
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68








69
70


71
72
73
74
75
76
77
  fsl_cx * f = FossilApp.f;
  fsl_db * db = fsl_cx_db_repo(f);
  fsl_deck DECK = fsl_deck_empty;
  fsl_deck * d = &DECK;
  fsl_buffer dout = fsl_buffer_empty;
  fsl_buffer hash = fsl_buffer_empty;
  int rc;
  fsl_double_t now = 0
    ? 2456525.3001276273 /* 2013-08-20T19:12:11.027 */
    : fsl_db_julian_now(db);
  if(!db){
    return fsl_cx_err_set(f, FSL_RC_MISUSE, "This app requires a repo.");
  }
  VERBOSE(("now=%"FSL_JULIAN_T_PFMT"\n", now));
  fsl_deck_init(f, d, FSL_CATYPE_EVENT);
  assert(f==d->f);
  assert(FSL_CATYPE_EVENT==d->type);
  assert(NULL==d->allocStamp);

  rc = fsl_deck_C_set(d, "Test event - automatically generated", -1);
  assert(!rc);

  rc = fsl_deck_D_set( d, now );
  assert(!rc);









  rc = fsl_deck_E_set( d, now,
                       "07384b266d9ddb8f00bf906fd1b6414802761bbf" );


  assert(!rc);

  rc = fsl_deck_T_add( d, FSL_TAGTYPE_ADD, NULL, "automated", NULL);
  assert(!rc);

  
  {







|

















>
>
>
>
>
>
>
>

<
>
>







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
  fsl_cx * f = FossilApp.f;
  fsl_db * db = fsl_cx_db_repo(f);
  fsl_deck DECK = fsl_deck_empty;
  fsl_deck * d = &DECK;
  fsl_buffer dout = fsl_buffer_empty;
  fsl_buffer hash = fsl_buffer_empty;
  int rc;
  fsl_double_t now = 1
    ? 2456525.3001276273 /* 2013-08-20T19:12:11.027 */
    : fsl_db_julian_now(db);
  if(!db){
    return fsl_cx_err_set(f, FSL_RC_MISUSE, "This app requires a repo.");
  }
  VERBOSE(("now=%"FSL_JULIAN_T_PFMT"\n", now));
  fsl_deck_init(f, d, FSL_CATYPE_EVENT);
  assert(f==d->f);
  assert(FSL_CATYPE_EVENT==d->type);
  assert(NULL==d->allocStamp);

  rc = fsl_deck_C_set(d, "Test event - automatically generated", -1);
  assert(!rc);

  rc = fsl_deck_D_set( d, now );
  assert(!rc);

#if 0
  {
    char * eventId = fsl_db_random_hex(db, FSL_UUID_STRLEN);
    assert(fsl_is_uuid(eventId));
    rc = fsl_deck_E_set( d, now, eventId );
    fsl_free(eventId);
  }
#else
  rc = fsl_deck_E_set( d, now,

                       "b82b583b2cf60075c99e2ee5accec41906d3e6a2");
#endif
  assert(!rc);

  rc = fsl_deck_T_add( d, FSL_TAGTYPE_ADD, NULL, "automated", NULL);
  assert(!rc);

  
  {
Changes to include/fossil-scm/fossil.h.
3694
3695
3696
3697
3698
3699
3700













3701
3702
3703
3704
3705
3706
3707
   ** Passes each element in the given list to
   ** childFinalizer(item,finalizerState). If that returns non-0,
   ** processing stops and that value is returned, otherwise
   ** fsl_list_reserve(list,0) is called and 0 is returned.
   **/
  int fsl_list_clear( fsl_list * list, fsl_list_visitor_f childFinalizer,
                      void * finalizerState );













  
  /**
   **
   **
   ** Works similarly to the visit operation without the _p suffix
   ** except that the pointer the visitor function gets is a (**)
   ** pointing back to the entry within this list. That means that







>
>
>
>
>
>
>
>
>
>
>
>
>







3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
   ** Passes each element in the given list to
   ** childFinalizer(item,finalizerState). If that returns non-0,
   ** processing stops and that value is returned, otherwise
   ** fsl_list_reserve(list,0) is called and 0 is returned.
   **/
  int fsl_list_clear( fsl_list * list, fsl_list_visitor_f childFinalizer,
                      void * finalizerState );
  /**
   ** Similar to fsl_list_clear(list, fsl_list_v_fsl_free, NULL), but
   ** only clears the list itself if the second argument is true,
   ** otherwise it sets the list's length to 0 but keeps its memory
   ** intact for later use.
   **
   ** Be sure only to use this on lists of types for which fsl_free()
   ** is legal. i.e. don't use it on a list of fsl_deck objects or
   ** other types which have their own finalizers.
   **
   ** Results are undefined if list is NULL.
   */
  void fsl_list_visit_free( fsl_list * list, char freeListMem );
  
  /**
   **
   **
   ** Works similarly to the visit operation without the _p suffix
   ** except that the pointer the visitor function gets is a (**)
   ** pointing back to the entry within this list. That means that
5159
5160
5161
5162
5163
5164
5165








5166
5167
5168
5169
5170
5171
5172
  int fsl_deck_D_set( fsl_deck * mf, fsl_double_t date);

  /**
   ** Sets the E card in the given deck. date may not be negative - use
   ** fsl_db_julian_now() or similar to get a default time if needed.
   ** Retursn FSL_RC_MISUSE if !mf or !uuid, FSL_RC_RANGE if date is
   ** not positive, FSL_RC_RANGE if uuid is not a valid UUID string.








   */
  int fsl_deck_E_set( fsl_deck * mf, fsl_double_t date, fsl_uuid_cstr uuid);

  /**
   ** Adds a new F card to the given deck. The uuid argument is
   ** required to pass the fsl_is_uuid() test. The name must be a
   ** "simplified path name" (as determined by







>
>
>
>
>
>
>
>







5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
  int fsl_deck_D_set( fsl_deck * mf, fsl_double_t date);

  /**
   ** Sets the E card in the given deck. date may not be negative - use
   ** fsl_db_julian_now() or similar to get a default time if needed.
   ** Retursn FSL_RC_MISUSE if !mf or !uuid, FSL_RC_RANGE if date is
   ** not positive, FSL_RC_RANGE if uuid is not a valid UUID string.
   **
   ** Note that the UUID for an event, unlike most other UUIDs, need
   ** not be calculated - it may be a random hex string, but it must
   ** pass the fsl_is_uuid() test. Use fsl_db_random_hex() to generate
   ** random UUIDs. When editing events, e.g. using the HTML UI, only
   ** the most recent event with the same UUID is shown. So when
   ** updating events, be sure to apply the same UUID to the edited
   ** copies before saving them.
   */
  int fsl_deck_E_set( fsl_deck * mf, fsl_double_t date, fsl_uuid_cstr uuid);

  /**
   ** Adds a new F card to the given deck. The uuid argument is
   ** required to pass the fsl_is_uuid() test. The name must be a
   ** "simplified path name" (as determined by
5476
5477
5478
5479
5480
5481
5482



5483
5484
5485
5486
5487
5488
5489
   ** success because they would otherwise refer to db records which
   ** get destroyed when the transaction rolls back.
   **
   ** After saving, the deck gets crosslinked (fsl_deck_crosslink()).
   **
   ** The save operation happens within a transaction, of course,
   ** and on any sort of error, db-side changes are rolled back.



   **
   ** @see fsl_deck_output()
   ** @see fsl_repo_content_put_ex()
   */
  int fsl_deck_save( fsl_cx * f, fsl_deck * d, char isPrivate );
  
  /**







>
>
>







5497
5498
5499
5500
5501
5502
5503
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
   ** success because they would otherwise refer to db records which
   ** get destroyed when the transaction rolls back.
   **
   ** After saving, the deck gets crosslinked (fsl_deck_crosslink()).
   **
   ** The save operation happens within a transaction, of course,
   ** and on any sort of error, db-side changes are rolled back.
   **
   ** Maintenance reminder: this function also does a small bit of
   ** artifact-type-specific processing.
   **
   ** @see fsl_deck_output()
   ** @see fsl_repo_content_put_ex()
   */
  int fsl_deck_save( fsl_cx * f, fsl_deck * d, char isPrivate );
  
  /**
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
6109
6110
6111
6112
6113
6114
6115
6116
6117
6118
6119
6120
6121
6122
   ** Tries to convert the value of errNo, which is assumed to come
   ** from the global errno, to a fsl_rc_t code. If it can, it returns
   ** something approximating the errno value, else it returns dflt.
   */
  int fsl_errno_to_rc(int errNo, int dflt);

  /**
   ** Experimental generic callback interface for traversing over
   ** decks. The interface does not generically require that d survive
   ** after this call returns.
   */
  typedef int (*fsl_deck_cb_f)( fsl_cx * f, fsl_deck const * d,
                                void * state );

  /**
   ** Experimental approach to iterating over wikis. This calls cb()
   ** one time for each wiki page in the repo, passing it the manifest
   ** of the most recent version of that page. The callback should
   ** return 0 on success, FSL_RC_BREAK to stop looping without an
   ** error, or any other non-0 code (preferably a value from
   ** fsl_rc_t) on error.
   **
   ** The 3rd parameter has no meaning for this function but it is
   ** passed on as-is to the callback.
   **
   ** ACHTUNG: the deck passed to the callback is transient and will
   ** be cleaned up after the callback has returned, so the callback
   ** must not hold a pointer to it or its contents.







|
|
|





<
|
|
|
|
|







6119
6120
6121
6122
6123
6124
6125
6126
6127
6128
6129
6130
6131
6132
6133

6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
   ** Tries to convert the value of errNo, which is assumed to come
   ** from the global errno, to a fsl_rc_t code. If it can, it returns
   ** something approximating the errno value, else it returns dflt.
   */
  int fsl_errno_to_rc(int errNo, int dflt);

  /**
   ** Experimental generic callback interface for visiting decks. The
   ** interface does not generically require that d survive after this
   ** call returns.
   */
  typedef int (*fsl_deck_cb_f)( fsl_cx * f, fsl_deck const * d,
                                void * state );

  /**

   ** For each unique wiki page name in f's repostory, this calls
   ** cb(), passing it the manifest of the most recent version of that
   ** page. The callback should return 0 on success, FSL_RC_BREAK to
   ** stop looping without an error, or any other non-0 code
   ** (preferably a value from fsl_rc_t) on error.
   **
   ** The 3rd parameter has no meaning for this function but it is
   ** passed on as-is to the callback.
   **
   ** ACHTUNG: the deck passed to the callback is transient and will
   ** be cleaned up after the callback has returned, so the callback
   ** must not hold a pointer to it or its contents.
6131
6132
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142
6143
6144
6145
   ** indicating more serious problems. If no such page is found,n
   ** newRid is not modified and this function returns 0 (as opposed
   ** to FSL_RC_NOT_FOUND) because that simplifies usage (so far).
   **
   ** On error *newRid is not modified.
   */
  int fsl_wiki_latest_rid( fsl_cx * f, char const * pageName, fsl_id_t * newRid );

  
  /**
   ** Loads the artifact for the most recent version of the given wiki page,
   ** populating d with its contents.
   **
   ** Returns 0 on success. On error d might be partially populated,
   ** so it needs to be passed to fsl_deck_finalize() regardless of







<







6154
6155
6156
6157
6158
6159
6160

6161
6162
6163
6164
6165
6166
6167
   ** indicating more serious problems. If no such page is found,n
   ** newRid is not modified and this function returns 0 (as opposed
   ** to FSL_RC_NOT_FOUND) because that simplifies usage (so far).
   **
   ** On error *newRid is not modified.
   */
  int fsl_wiki_latest_rid( fsl_cx * f, char const * pageName, fsl_id_t * newRid );

  
  /**
   ** Loads the artifact for the most recent version of the given wiki page,
   ** populating d with its contents.
   **
   ** Returns 0 on success. On error d might be partially populated,
   ** so it needs to be passed to fsl_deck_finalize() regardless of
6174
6175
6176
6177
6178
6179
6180
6181
6182

6183
6184
6185
6186
6187
6188
6189
6190
6191
6192
6193
6194
6195
6196
6197
6198
6199
6200
6201
6202
6203
6204
6205


6206
6207
6208
6209
6210







6211


















































6212
6213
6214
6215
6216
6217
   **
   ** Whether or not this function is allowed to create a new page
   ** or not is determined by isNew. If isNew is true then then this
   ** will fail with FSL_RC_ALREADY_EXISTS if a page with the given
   ** name already exists. If it is false and the page does _not_
   ** exist, FSL_RC_NOT_FOUND is returned.
   **
   ** TODO: find better semantics for isNew, so clients don't have
   ** to check if it exists first.

   **
   ** @see fsl_wiki_page_exists()
   */
  int fsl_wiki_save(fsl_cx * f, char const * pageName,
                    fsl_buffer const * b,
                    char const * userName,
                    char const * mimeType,
                    char isNew );

  /**
   ** Fetches the list of all wiki page names in f's current repo db
   ** and appends them as new (char *) strings to tgt. On error tgt
   ** might be partially populated (but this will only happen on an
   ** OOM).
   **
   ** It is up to the caller free the entries added to the list. The
   ** simplest way is:
   **
   ** @code
   ** fsl_list_visit( list, 0, fsl_list_v_fsl_free, NULL );
   ** fsl_list_reserve(list,0);
   ** // Or simply:
   ** fsl_list_clear(list, fsl_list_v_fsl_free, NULL);


   ** @endcode
   **
   */
  int fsl_wiki_names_get( fsl_cx * f, fsl_list * tgt );
  


























































#if defined(__cplusplus)
} /*extern "C"*/
#endif

#endif
/* NET_FOSSIL_SCM_LIBFOSSIL_H_INCLUDED */







|
|
>















|
|




|

>
>




|
>
>
>
>
>
>
>

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>






6196
6197
6198
6199
6200
6201
6202
6203
6204
6205
6206
6207
6208
6209
6210
6211
6212
6213
6214
6215
6216
6217
6218
6219
6220
6221
6222
6223
6224
6225
6226
6227
6228
6229
6230
6231
6232
6233
6234
6235
6236
6237
6238
6239
6240
6241
6242
6243
6244
6245
6246
6247
6248
6249
6250
6251
6252
6253
6254
6255
6256
6257
6258
6259
6260
6261
6262
6263
6264
6265
6266
6267
6268
6269
6270
6271
6272
6273
6274
6275
6276
6277
6278
6279
6280
6281
6282
6283
6284
6285
6286
6287
6288
6289
6290
6291
6292
6293
6294
6295
6296
6297
6298
6299
   **
   ** Whether or not this function is allowed to create a new page
   ** or not is determined by isNew. If isNew is true then then this
   ** will fail with FSL_RC_ALREADY_EXISTS if a page with the given
   ** name already exists. If it is false and the page does _not_
   ** exist, FSL_RC_NOT_FOUND is returned.
   **
   ** TODO: find better semantics for isNew, so clients don't have to
   ** check if it exists first. e.g. a policy enum which specifies
   ** whether to allow creation of a new page.
   **
   ** @see fsl_wiki_page_exists()
   */
  int fsl_wiki_save(fsl_cx * f, char const * pageName,
                    fsl_buffer const * b,
                    char const * userName,
                    char const * mimeType,
                    char isNew );

  /**
   ** Fetches the list of all wiki page names in f's current repo db
   ** and appends them as new (char *) strings to tgt. On error tgt
   ** might be partially populated (but this will only happen on an
   ** OOM).
   **
   ** It is up to the caller free the entries added to the list. Some
   ** of the many possibilities include:
   **
   ** @code
   ** fsl_list_visit( list, 0, fsl_list_v_fsl_free, NULL );
   ** fsl_list_reserve(list,0);
   ** // Or:
   ** fsl_list_clear(list, fsl_list_v_fsl_free, NULL);
   ** // Or simply:
   ** fsl_list_visit_free( list, 1 );
   ** @endcode
   **
   */
  int fsl_wiki_names_get( fsl_cx * f, fsl_list * tgt );

  /**
   ** Returns n bytes of random lower-case hexidecimal characters
   ** using the given db as its data source. The returned memory must
   ** eventually be freed using fsl_free(). Returns NULL if !db, !n,
   ** or on a db-level error.
   */
  char * fsl_db_random_hex(fsl_db * db, fsl_size_t n);

  /**
   ** Expects fmt to be a SELECT-style query. For each row in the
   ** query, the first column is fetched as a string and appended to
   ** the tgt list.
   **
   ** Returns 0 on success, FSL_RC_MISUSE if !db, !tgt, or !fmt, any
   ** number of potential FSL_RC_OOM or db-related errors.
   **
   ** Results rows with a NULL value (resulting from an SQL NULL) are
   ** added to the list as NULL entries.
   **
   ** Each entry appended to the list is a (char *) which must
   ** be freed using fsl_free(). To easiest way to clean up
   ** the list and its contents is:
   **
   ** @code
   ** fsl_list_visit_free(tgt);
   ** @endcode
   **
   ** On error the list may be partially populated.
   **
   ** Complete example:
   ** @code
   ** fsl_list li = fsl_list_empty;
   ** int rc = fsl_db_select_slist(db, &li,
   **           "SELECT uuid FROM blob WHERE rid<20");
   ** if(!rc){
   **   fsl_size_t i;
   **   for(i = 0;i < li.used; ++i){
   **      char const * uuid = (char const *)li.list[i];
   **      fsl_fprintf(stdout, "UUID: %s\n", uuid);
   **   }
   ** }
   ** fsl_list_visit_free(&li, 1);
   ** @endcode
   **
   ** Of course fsl_list_visit() may be used to traverse the list as
   ** well, as long as the visitor expects (char [const]*) list
   ** elements.
   */
  int fsl_db_select_slist( fsl_db * db, fsl_list * tgt,
                                 char const * fmt, ... );

  /**
   ** The va_list counterpart of fsl_db_select_slist().
   */
  int fsl_db_select_slistv( fsl_db * db, fsl_list * tgt,
                            char const * fmt, va_list args );

  
#if defined(__cplusplus)
} /*extern "C"*/
#endif

#endif
/* NET_FOSSIL_SCM_LIBFOSSIL_H_INCLUDED */
Changes to src/fsl.c.
293
294
295
296
297
298
299






300
301
302
303
304
305
306

int fsl_list_clear( fsl_list * self, fsl_list_visitor_f childFinalizer,
                    void * finalizerState ){
  int rc = fsl_list_visit(self, 0, childFinalizer, finalizerState );
  if(!rc) fsl_list_reserve(self, 0);
  return rc;
}








int fsl_list_visit( fsl_list const * self, char order,
                    fsl_list_visitor_f visitor,
                    void * visitorState ){
  int rc = FSL_RC_OK;
  if( self && self->used && visitor ){







>
>
>
>
>
>







293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312

int fsl_list_clear( fsl_list * self, fsl_list_visitor_f childFinalizer,
                    void * finalizerState ){
  int rc = fsl_list_visit(self, 0, childFinalizer, finalizerState );
  if(!rc) fsl_list_reserve(self, 0);
  return rc;
}

void fsl_list_visit_free( fsl_list * self, char freeListMem ){
  fsl_list_visit(self, 0, fsl_list_v_fsl_free, NULL );
  if(freeListMem) fsl_list_reserve(self, 0);
  else self->used = 0;
}


int fsl_list_visit( fsl_list const * self, char order,
                    fsl_list_visitor_f visitor,
                    void * visitorState ){
  int rc = FSL_RC_OK;
  if( self && self->used && visitor ){
Changes to src/fsl_db.c.
1728
1729
1730
1731
1732
1733
1734











1735








































1736
1737
      break;
    }
  }
  fsl_stmt_finalize(&q);
  return rv;
}






















































#undef MARKER







>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
      break;
    }
  }
  fsl_stmt_finalize(&q);
  return rv;
}

char * fsl_db_random_hex(fsl_db * db, fsl_size_t n){
  if(!db || !n) return NULL;
  else{
    fsl_size_t rvLen = 0;
    char * rv = fsl_db_g_text(db, &rvLen,
                              "SELECT lower(hex("
                              "randomblob(%"FSL_SIZE_T_PFMT")))",
                              n/2+1);
    if(rv){
      assert(rvLen>=n);
      rv[n]=0;
    }
    return rv;
  }
}


int fsl_db_select_slistv( fsl_db * db, fsl_list * tgt,
                          char const * fmt, va_list args ){
  if(!db || !tgt || !fmt) return FSL_RC_MISUSE;
  else if(!*fmt) return FSL_RC_RANGE;
  else{
    int rc;
    fsl_stmt st = fsl_stmt_empty;
    fsl_size_t nlen;
    char const * n;
    char * cp;
    rc = fsl_db_preparev(db, &st, fmt, args);
    while( !rc && (FSL_RC_STEP_ROW==fsl_stmt_step(&st)) ){
      nlen = 0;
      n = fsl_stmt_g_text(&st, 0, &nlen);
      cp = fsl_strndup(n, (fsl_int_t)nlen);
      if(n && !cp) rc = FSL_RC_OOM;
      else{
        rc = fsl_list_append(tgt, cp);
        if(rc) fsl_free(cp);
      }
    }
    fsl_stmt_finalize(&st);
    return rc;
  }
}

int fsl_db_select_slist( fsl_db * db, fsl_list * tgt,
                         char const * fmt, ... ){
  int rc;
  va_list va;
  va_start (va,fmt);
  rc = fsl_db_select_slistv(db, tgt, fmt, va);
  va_end(va);
  return rc;
}

#undef MARKER
Added src/fsl_event.c.




































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 
/* vim: set ts=2 et sw=2 tw=80: */
/*
** Copyright (c) 2013 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
**
** 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.
**
** Author contact information:
**   drh@hwaci.com
**   http://www.hwaci.com/drh/
**
*******************************************************************************
** This file implements event-related parts of the library.
*/
#include "fossil-scm/fossil-internal.h"
#include <assert.h>

/* Only for debugging */
#include <stdio.h>
#define MARKER(pfexp)                                               \
  do{ printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__);   \
    printf pfexp;                                                   \
  } while(0)


int fsl_event_ids_get( fsl_cx * f, fsl_list * tgt ){
  fsl_db * db = fsl_needs_repo(f);
  if(!f || !tgt) return FSL_RC_MISUSE;
  else if(!db) return FSL_RC_NOT_A_REPO;
  else {
    int rc = fsl_db_select_slist( db, tgt,
                                  "SELECT substr(tagname,7) AS n "
                                  "FROM tag "
                                  "WHERE tagname GLOB 'event-*' "
                                  "ORDER BY n");
    if(rc && db->error.code && !f->error.code){
      fsl_cx_uplift_db_error(f, db);
    }
    return rc;
  }
}


#undef MARKER
Changes to src/fsl_mf.c.
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
  SFREE(uuid);
  CBUF(A.name);
  SFREE(A.tgt);
  SFREE(A.src);
  SFREE(B.uuid);
  CBUF(C);
  SFREE(E.uuid);
  fsl_list_visit(&m->F.list, 0, fsl_list_v_fsl_mf_fcard_free, NULL);
  fsl_list_reserve(&m->F.list, 0);
  CBUF(L);
  fsl_list_visit(&m->J, 0, fsl_list_v_fsl_mf_jcard_free, NULL);
  fsl_list_reserve(&m->J, 0);
  SFREE(K);
  fsl_list_visit(&m->M, 0, fsl_list_v_fsl_free, NULL);
  fsl_list_reserve(&m->M, 0);
  CBUF(N);
  fsl_list_visit(&m->P, 0, fsl_list_v_fsl_free, NULL);
  fsl_list_reserve(&m->P, 0);
  fsl_list_visit(&m->Q, 0, fsl_list_v_fsl_mf_qcard_free, NULL);
  fsl_list_reserve(&m->Q, 0);
  SFREE(R);
  fsl_list_visit(&m->T, 0, fsl_list_v_fsl_mf_tcard_free, NULL);
  fsl_list_reserve(&m->T, 0);
  CBUF(U);
  CBUF(W);

  fsl_error_clean(&m->error);
  {
    void const * allocStampKludge = m->allocStamp;
    *m = fsl_deck_empty;







|
<

|
<

|
<

|
<
|
<

|
<







231
232
233
234
235
236
237
238

239
240

241
242

243
244

245

246
247

248
249
250
251
252
253
254
  SFREE(uuid);
  CBUF(A.name);
  SFREE(A.tgt);
  SFREE(A.src);
  SFREE(B.uuid);
  CBUF(C);
  SFREE(E.uuid);
  fsl_list_clear(&m->F.list, fsl_list_v_fsl_mf_fcard_free, NULL);

  CBUF(L);
  fsl_list_clear(&m->J, fsl_list_v_fsl_mf_jcard_free, NULL);

  SFREE(K);
  fsl_list_visit_free(&m->M, 1);

  CBUF(N);
  fsl_list_visit_free(&m->P, 1);

  fsl_list_clear(&m->Q, fsl_list_v_fsl_mf_qcard_free, NULL);

  SFREE(R);
  fsl_list_clear(&m->T, fsl_list_v_fsl_mf_tcard_free, NULL);

  CBUF(U);
  CBUF(W);

  fsl_error_clean(&m->error);
  {
    void const * allocStampKludge = m->allocStamp;
    *m = fsl_deck_empty;
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
                              fsl_buffer_cstr(&d->L));
    }else{
      rc = fsl_buffer_appendf(&buf,
                              "Deleted wiki page [%h]",
                              fsl_buffer_cstr(&d->L));
    }
    if(!rc){
      fsl_db_exec_multi(db,
      "REPLACE INTO event(type,mtime,objid,user,comment,"
      "                  bgcolor,euser,ecomment) "
      "VALUES('w',%"FSL_JULIAN_T_PFMT",%"FSL_ID_T_PFMT",%B,%B,"
      "  (SELECT value FROM tagxref "
           "WHERE tagid=%"FSL_ID_T_PFMT" AND rid=%"FSL_ID_T_PFMT
           " AND tagtype>1),"
      "  (SELECT value FROM tagxref "







|







2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
                              fsl_buffer_cstr(&d->L));
    }else{
      rc = fsl_buffer_appendf(&buf,
                              "Deleted wiki page [%h]",
                              fsl_buffer_cstr(&d->L));
    }
    if(!rc){
      fsl_db_exec(db,
      "REPLACE INTO event(type,mtime,objid,user,comment,"
      "                  bgcolor,euser,ecomment) "
      "VALUES('w',%"FSL_JULIAN_T_PFMT",%"FSL_ID_T_PFMT",%B,%B,"
      "  (SELECT value FROM tagxref "
           "WHERE tagid=%"FSL_ID_T_PFMT" AND rid=%"FSL_ID_T_PFMT
           " AND tagtype>1),"
      "  (SELECT value FROM tagxref "
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
    fsl_buffer buf = fsl_buffer_empty;
    fsl_id_t tagid;
    fsl_id_t prior, subsequent;
    char zLength[40] = {0};
    char const * zWiki;
    char const * zTag;
    fsl_size_t nWiki = 0;
    rc = fsl_buffer_appendf(&buf, "event-%b", &d->E.uuid);
    if(rc) goto wiki_end;
    zTag = fsl_buffer_cstr(&buf);
    tagid = fsl_repo_tag_id( f, zTag, 1 );
    if(tagid<=0){
      rc = f->error.code ? f->error.code :
        fsl_cx_err_set(f, FSL_RC_RANGE,
                       "Got unexpected RID (%"FSL_ID_T_PFMT") "







|







2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
    fsl_buffer buf = fsl_buffer_empty;
    fsl_id_t tagid;
    fsl_id_t prior, subsequent;
    char zLength[40] = {0};
    char const * zWiki;
    char const * zTag;
    fsl_size_t nWiki = 0;
    rc = fsl_buffer_appendf(&buf, "event-%s", d->E.uuid);
    if(rc) goto wiki_end;
    zTag = fsl_buffer_cstr(&buf);
    tagid = fsl_repo_tag_id( f, zTag, 1 );
    if(tagid<=0){
      rc = f->error.code ? f->error.code :
        fsl_cx_err_set(f, FSL_RC_RANGE,
                       "Got unexpected RID (%"FSL_ID_T_PFMT") "
2569
2570
2571
2572
2573
2574
2575
2576

2577
2578
2579
2580
2581
2582
2583
      assert(db->error.code);
      rc = fsl_cx_uplift_db_error(f, db);
      goto event_end;
    }
    subsequent = fsl_db_g_id(db, 0,
                             "SELECT rid FROM tagxref"
                             " WHERE tagid=%"FSL_ID_T_PFMT
                             " AND mtime>=%"FSL_JULIAN_T_PFMT" AND rid!=%"FSL_ID_T_PFMT

                             " ORDER BY mtime",
                             tagid, d->D, rid);
    if(subsequent<0){
      assert(db->error.code);
      rc = fsl_cx_uplift_db_error(f, db);
      goto event_end;
    }







|
>







2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
      assert(db->error.code);
      rc = fsl_cx_uplift_db_error(f, db);
      goto event_end;
    }
    subsequent = fsl_db_g_id(db, 0,
                             "SELECT rid FROM tagxref"
                             " WHERE tagid=%"FSL_ID_T_PFMT
                             " AND mtime>=%"FSL_JULIAN_T_PFMT
                             " AND rid!=%"FSL_ID_T_PFMT
                             " ORDER BY mtime",
                             tagid, d->D, rid);
    if(subsequent<0){
      assert(db->error.code);
      rc = fsl_cx_uplift_db_error(f, db);
      goto event_end;
    }
Changes to src/fsl_wiki.c.
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
  } while(0)


int fsl_wiki_names_get( fsl_cx * f, fsl_list * tgt ){
  fsl_db * db = fsl_needs_repo(f);
  if(!f || !tgt) return FSL_RC_MISUSE;
  else if(!db) return FSL_RC_NOT_A_REPO;
  else{
    int rc;
    fsl_stmt st = fsl_stmt_empty;
    fsl_size_t nlen;
    char const * n;
    char * cp;
    rc = fsl_db_prepare(db, &st,
                        "SELECT substr(tagname,6) AS name "
                        "FROM tag "
                        "WHERE tagname GLOB 'wiki-*' "
                        "ORDER BY lower(name)");
    while( !rc && (FSL_RC_STEP_ROW==fsl_stmt_step(&st)) ){
      nlen = 0;
      n = fsl_stmt_g_text(&st, 0, &nlen);
      cp = fsl_strndup(n, (fsl_int_t)nlen);
      if(!cp) rc = FSL_RC_OOM;
      else{
        rc = fsl_list_append(tgt, cp);
        if(rc) fsl_free(cp);
      }
    }
    fsl_stmt_finalize(&st);
    if(db->error.code && !f->error.code){
      fsl_cx_uplift_db_error(f, db);
    }
    return rc;
  }
}

int fsl_wiki_latest_rid( fsl_cx * f, char const * pageName, fsl_id_t * rid ){







|
|
<
<
<
<
<
|
|
|
|
<
<
<
<
<
<
<
<
<
<
<
|







29
30
31
32
33
34
35
36
37





38
39
40
41











42
43
44
45
46
47
48
49
  } while(0)


int fsl_wiki_names_get( fsl_cx * f, fsl_list * tgt ){
  fsl_db * db = fsl_needs_repo(f);
  if(!f || !tgt) return FSL_RC_MISUSE;
  else if(!db) return FSL_RC_NOT_A_REPO;
  else {
    int rc = fsl_db_select_slist( db, tgt,





                                  "SELECT substr(tagname,6) AS name "
                                  "FROM tag "
                                  "WHERE tagname GLOB 'wiki-*' "
                                  "ORDER BY lower(name)");











    if(rc && db->error.code && !f->error.code){
      fsl_cx_uplift_db_error(f, db);
    }
    return rc;
  }
}

int fsl_wiki_latest_rid( fsl_cx * f, char const * pageName, fsl_id_t * rid ){