Fossil

Check-in [6d066783]
Login

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

Overview
Comment:minor cleanups and doc additions to the json/artifact handling.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | json-multitag-test | json
Files: files | file ages | folders
SHA1: 6d0667831a0aa39f1bbf248f1869769b35463eea
User & Date: stephan 2011-10-02 11:43:08.504
Context
2011-10-02
12:31
initial code for reading POST data from a file/stdin in CLI mode. ... (check-in: 8145cdbf user: stephan tags: json-multitag-test, json)
11:43
minor cleanups and doc additions to the json/artifact handling. ... (check-in: 6d066783 user: stephan tags: json-multitag-test, json)
11:16
Reorganized json_page_artifact(), fixed a C99ism, fixed permissions check. ... (check-in: c9261700 user: stephan tags: json-multitag-test, json)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/json.c.
749
750
751
752
753
754
755




756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780

781




782
783
784
785
786
787

788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822







823
824
825
826
827
828
829
  }
}

/*
** Splits zStr (which must not be NULL) into tokens separated by the
** given separator character. If doDeHttp is true then each element
** will be passed through dehttpize(), otherwise they are used




** as-is. Each new element is appended to the given target array
** object, which must not be NULL and ownership of it is not changed
** by this call.
**
** On success, returns the number of items appended to target. On
** error a NEGATIVE number is returned - its absolute value is the
** number of items inserted before the error occurred. There is a
** corner case here if we fail on the 1st element, which will cause 0
** to be returned, which the client cannot immediately distinguish as
** success or error.
**
** Achtung: leading whitespace of elements is NOT elided. We should
** add an option to do that, but don't have one yet.
**
** Achtung: empty elements will be skipped, meaning consecutive
** empty elements are collapsed.
*/
int json_string_split( char const * zStr,
                       char separator,
                       char doDeHttp,
                       cson_array * target ){
  char const * p = zStr /* current byte */;
  char const * head = p  /* current start-of-token */;
  unsigned int len = 0   /* current token's length */;
  int rc = 0   /* return code (number of added elements)*/;

  assert( zStr && target );




  for( ; ; ++p){
    if( !*p || (separator == *p) ){
      if( len ){/* append head..(head+len) as next array
                   element. */
        cson_value * part = NULL;
        char * zPart = NULL;

        assert( head != p );
        zPart = (char*)malloc(len+1);
        assert( (zPart != NULL) && "malloc failure" );
        memcpy(zPart, head, len);
        zPart[len] = 0;
        if(doDeHttp){
          dehttpize(zPart);
        }
        if( *zPart ){ /* should only fail if someone manages to url-encoded a NUL byte */
          part = cson_value_new_string(zPart, strlen(zPart));
          if( 0 == cson_array_append( target, part ) ){
            ++rc;
          }else{
            cson_value_free(part);
            rc = rc ? -rc : 0;
            break;
          }
        }else{
          assert(0 && "i didn't think this was possible!");
          fprintf(stderr,"%s:%d: My God! It's full of stars!\n",
                  __FILE__, __LINE__);
          fossil_exit(1)
            /* Not fossil_panic() b/c this code needs to be able to
              run before some of the fossil/json bits are initialized,
              and fossil_panic() calls into the JSON API.
            */
            ;
        }
        free(zPart);
        len = 0;
      }
      if( !*p ){
        break;
      }
      head = p+1;







      continue;
    }
    ++len;
  }
  return rc;
}








>
>
>
>
|
|
|

|
|
<
<
|
|

|
<

|
|






|


>

>
>
>
>






>










|
<
<

|




















>
>
>
>
>
>
>







749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765


766
767
768
769

770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805


806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  }
}

/*
** Splits zStr (which must not be NULL) into tokens separated by the
** given separator character. If doDeHttp is true then each element
** will be passed through dehttpize(), otherwise they are used
** as-is. Note that tokenization happens before dehttpize(),
** which is significant if the ENcoded tokens might contain the
** separator character.
**
** Each new element is appended to the given target array object,
** which must not be NULL and ownership of it is not changed by this
** call.
**
** On success, returns the number of tokens _encountered_. On error a
** NEGATIVE number is returned - its absolute value is the number of


** tokens encountered (i.e. it reveals which token in zStr was
** problematic).
**
** Achtung: leading and trailing whitespace of elements are elided.

**
** Achtung: empty elements will be skipped, meaning consecutive empty
** elements are collapsed.
*/
int json_string_split( char const * zStr,
                       char separator,
                       char doDeHttp,
                       cson_array * target ){
  char const * p = zStr /* current byte */;
  char const * head  /* current start-of-token */;
  unsigned int len = 0   /* current token's length */;
  int rc = 0   /* return code (number of added elements)*/;
  char skipWs = fossil_isspace(separator) ? 0 : 1;
  assert( zStr && target );
  while( fossil_isspace(*p) ){
    ++p;
  }
  head = p;
  for( ; ; ++p){
    if( !*p || (separator == *p) ){
      if( len ){/* append head..(head+len) as next array
                   element. */
        cson_value * part = NULL;
        char * zPart = NULL;
        ++rc;
        assert( head != p );
        zPart = (char*)malloc(len+1);
        assert( (zPart != NULL) && "malloc failure" );
        memcpy(zPart, head, len);
        zPart[len] = 0;
        if(doDeHttp){
          dehttpize(zPart);
        }
        if( *zPart ){ /* should only fail if someone manages to url-encoded a NUL byte */
          part = cson_value_new_string(zPart, strlen(zPart));
          if( 0 != cson_array_append( target, part ) ){


            cson_value_free(part);
            rc = -rc;
            break;
          }
        }else{
          assert(0 && "i didn't think this was possible!");
          fprintf(stderr,"%s:%d: My God! It's full of stars!\n",
                  __FILE__, __LINE__);
          fossil_exit(1)
            /* Not fossil_panic() b/c this code needs to be able to
              run before some of the fossil/json bits are initialized,
              and fossil_panic() calls into the JSON API.
            */
            ;
        }
        free(zPart);
        len = 0;
      }
      if( !*p ){
        break;
      }
      head = p+1;
      while( *head && fossil_isspace(*head) ){
        ++head;
        ++p;
      }
      if(!*head){
        break;
      }
      continue;
    }
    ++len;
  }
  return rc;
}

1326
1327
1328
1329
1330
1331
1332



1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347

1348
1349

1350
1351
1352
1353
1354
1355
1356
1357
1358
}


/*
** If the given rid has any tags associated with it, this function
** returns a JSON Array containing the tag names, else it returns
** NULL.



*/
cson_value * json_tags_for_rid(int rid){
  cson_value * v = NULL;
  Stmt q;
  assert((rid>0) && "rid is invalid");
  db_prepare(&q,"SELECT group_concat(substr(tagname,5), ',')"
             " FROM tag t, tagxref x "
             " WHERE x.rid=%d "
             " AND tagname GLOB 'sym-*' "
             " AND t.tagid=x.tagid AND x.tagtype>0",
             rid);
  if( (SQLITE_ROW==db_step(&q)) ){
    char const * tags;
    tags = db_column_text(&q,0);
    if(tags && *tags){

      v = json_string_split2(tags,',',0);
    }

  }
  db_finalize(&q);
  return v;  
}


/*
** /json/version implementation.
**







>
>
>

|

<
<
<
<
<
<
<
<
<
|
<
|
>


>

<







1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350









1351

1352
1353
1354
1355
1356
1357

1358
1359
1360
1361
1362
1363
1364
}


/*
** If the given rid has any tags associated with it, this function
** returns a JSON Array containing the tag names, else it returns
** NULL.
**
** See info_tags_of_checkin() for more details (this is simply a JSON
** wrapper for that function).
*/
cson_value * json_tags_for_rid(int rid, char propagatingOnly){
  cson_value * v = NULL;









  char * tags = info_tags_of_checkin(rid, propagatingOnly);

  if(tags){
    if(*tags){
      v = json_string_split2(tags,',',0);
    }
    free(tags);
  }

  return v;  
}


/*
** /json/version implementation.
**
Changes to src/json_artifact.c.
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
51
52
#include "json_detail.h"
#endif

/*
** Internal callback for /json/artifact handlers. rid refers to
** the rid of a given type of artifact, and each callback is
** specialized to return a JSON form of one type of artifact.




*/
typedef cson_value * (*artifact_f)( int rid );




typedef struct ArtifactDispatchEntry {
  /**
     Artifact type name, e.g. "checkin".
   */
  char const * name;

  /**
     JSON construction callback.

   */
  artifact_f func;

  /**
     Must return true if g.perm has the proper permissions to fetch
     this info, else false. If it returns false, func() is skipped
     (producing no extra payload output).

   */
  char (*permCheck)();
} ArtifactDispatchEntry;


/*
** Generates an artifact Object for the given rid/zUuid. rid
** must refer to a Checkin.







>
>
>
>



>
>
>


|


>

|
>
|

>



|
>
|







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
51
52
53
54
55
56
57
58
59
60
61
62
63
#include "json_detail.h"
#endif

/*
** Internal callback for /json/artifact handlers. rid refers to
** the rid of a given type of artifact, and each callback is
** specialized to return a JSON form of one type of artifact.
**
** Implementations may assert() that rid refers to requested artifact
** type, since mismatches in the artifact types come from
** json_page_artifact() as opposed to client data.
*/
typedef cson_value * (*artifact_f)( int rid );

/*
** Internal per-artifact-type dispatching helper.
*/
typedef struct ArtifactDispatchEntry {
  /**
     Artifact type name, e.g. "checkin", "ticket", "wiki".
   */
  char const * name;

  /**
     JSON construction callback. Creates the contents for the
     payload.artifact property of /json/artifact responses.
  */
  artifact_f func;

  /**
     Must return true if g.perm has the proper permissions to fetch
     this info, else false. If it returns false, func() is skipped
     (producing no extra payload output) and an access error is
     generated.
  */
  char (*permCheck)();
} ArtifactDispatchEntry;


/*
** Generates an artifact Object for the given rid/zUuid. rid
** must refer to a Checkin.
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
      SET("originTime",json_new_int(omtime));
    }

    if(zParent){
      SET("parentUuid", json_new_string(zParent));
    }

    tmpV = json_tags_for_rid(rid);
    if(tmpV){
      SET("tags",tmpV);
    }

    if( showFiles ){
      cson_value * fileList = json_get_changed_files(rid);
      if(fileList){







|







140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
      SET("originTime",json_new_int(omtime));
    }

    if(zParent){
      SET("parentUuid", json_new_string(zParent));
    }

    tmpV = json_tags_for_rid(rid,0);
    if(tmpV){
      SET("tags",tmpV);
    }

    if( showFiles ){
      cson_value * fileList = json_get_changed_files(rid);
      if(fileList){
155
156
157
158
159
160
161



162
163
164
165
166
167
168
/*
** Sub-impl of /json/artifact for checkins.
*/
static cson_value * json_artifact_ci( int rid ){
  return json_artifact_for_ci(rid, 1);
}




static char perms_can_read(){
  return g.perm.Read ? 1 : 0;
}

static ArtifactDispatchEntry ArtifactDispatchList[] = {
{"checkin", json_artifact_ci, perms_can_read},
{"tag", NULL, perms_can_read},







>
>
>







166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
** Sub-impl of /json/artifact for checkins.
*/
static cson_value * json_artifact_ci( int rid ){
  return json_artifact_for_ci(rid, 1);
}

/*
** Permissions callback func for ArtifactDispatchEntry.
*/
static char perms_can_read(){
  return g.perm.Read ? 1 : 0;
}

static ArtifactDispatchEntry ArtifactDispatchList[] = {
{"checkin", json_artifact_ci, perms_can_read},
{"tag", NULL, perms_can_read},