Fossil

Check-in [ec56d8ff58]
Login

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

Overview
Comment:Add the ability to parse and use manifests with the B-card. Add documentation for the B-card.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | experimental
Files: files | file ages | folders
SHA1: ec56d8ff58c5cccebf1fb8d2a427d2201a02eedc
User & Date: drh 2010-10-17 17:25:12.000
Context
2010-10-18
22:34
Rework manifest parsing in order to process delta-manifests correctly. check-in: aa61a65c18 user: drh tags: experimental
2010-10-17
17:25
Add the ability to parse and use manifests with the B-card. Add documentation for the B-card. check-in: ec56d8ff58 user: drh tags: experimental
2010-10-16
16:32
Bring over the latest bug fixes from trunk. check-in: b2175857cc user: drh tags: experimental
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/branch.c.
68
69
70
71
72
73
74





75
76
77



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99


100
101
102
103
104
105
106

  user_select();
  db_begin_transaction();
  rootid = name_to_rid(g.argv[4]);
  if( rootid==0 ){
    fossil_fatal("unable to locate check-in off of which to branch");
  }






  /* Create a manifest for the new branch */
  blob_zero(&branch);



  zComment = mprintf("Create new branch named \"%h\"", zBranch);
  blob_appendf(&branch, "C %F\n", zComment);
  zDate = date_in_standard_format(zDateOvrd ? zDateOvrd : "now");
  zDate[10] = 'T';
  blob_appendf(&branch, "D %s\n", zDate);

  /* Copy all of the content from the parent into the branch */
  pParent = manifest_get(rootid, CFTYPE_MANIFEST);
  if( pParent==0 ){
    fossil_fatal("%s is not a valid check-in", g.argv[4]);
  }
  for(i=0; i<pParent->nFile; ++i){
    if( pParent->aFile[i].zPerm[0] ){
      blob_appendf(&branch, "F %F %s %s\n",
                   pParent->aFile[i].zName,
                   pParent->aFile[i].zUuid,
                   pParent->aFile[i].zPerm);
    }else{
      blob_appendf(&branch, "F %F %s\n",
                   pParent->aFile[i].zName,
                   pParent->aFile[i].zUuid);
    }


  }
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rootid);
  blob_appendf(&branch, "P %s\n", zUuid);
  blob_appendf(&branch, "R %s\n", pParent->zRepoCksum);
  manifest_destroy(pParent);

  /* Add the symbolic branch name and the "branch" tag to identify







>
>
>
>
>



>
>
>







<
<
<
<

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







68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92




93

94
95
96
97

98


99
100
101
102
103
104
105
106
107
108

  user_select();
  db_begin_transaction();
  rootid = name_to_rid(g.argv[4]);
  if( rootid==0 ){
    fossil_fatal("unable to locate check-in off of which to branch");
  }

  pParent = manifest_get(rootid, CFTYPE_MANIFEST);
  if( pParent==0 ){
    fossil_fatal("%s is not a valid check-in", g.argv[4]);
  }

  /* Create a manifest for the new branch */
  blob_zero(&branch);
  if( pParent->zBaseline ){
    blob_appendf(&branch, "B %s\n", pParent->zBaseline);
  }
  zComment = mprintf("Create new branch named \"%h\"", zBranch);
  blob_appendf(&branch, "C %F\n", zComment);
  zDate = date_in_standard_format(zDateOvrd ? zDateOvrd : "now");
  zDate[10] = 'T';
  blob_appendf(&branch, "D %s\n", zDate);

  /* Copy all of the content from the parent into the branch */




  for(i=0; i<pParent->nFile; ++i){

    blob_appendf(&branch, "F %F", pParent->aFile[i].zName);
    if( pParent->aFile[i].zUuid[0] ){
      blob_appendf(&branch, " %s", pParent->aFile[i].zUuid);
      if( pParent->aFile[i].zPerm[0] ){

        blob_appendf(&branch, " %s", pParent->aFile[i].zPerm);


      }
    }
    blob_append(&branch, "\n", 1);
  }
  zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rootid);
  blob_appendf(&branch, "P %s\n", zUuid);
  blob_appendf(&branch, "R %s\n", pParent->zRepoCksum);
  manifest_destroy(pParent);

  /* Add the symbolic branch name and the "branch" tag to identify
Changes to src/browse.c.
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135

136
137
138
139
140
141
142
  int nCol, nRow;
  int cnt, i;
  char *zPrefix;
  Stmt q;
  const char *zCI = P("ci");
  int rid = 0;
  char *zUuid = 0;
  Blob content;
  Blob dirname;
  Manifest *pM = 0;
  const char *zSubdirLink;

  login_check_credentials();
  if( !g.okHistory ){ login_needed(); return; }
  style_header("File List");
  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);

  /* If the name= parameter is an empty string, make it a NULL pointer */
  if( zD && strlen(zD)==0 ){ zD = 0; }

  /* If a specific check-in is requested, fetch and parse it.  If the
  ** specific check-in does not exist, clear zCI.  zCI==0 will cause all
  ** files from all check-ins to be displayed.
  */
  if( zCI ){
    if( (rid = name_to_rid(zCI))==0 || content_get(rid, &content)==0 ){
      zCI = 0;  /* No artifact named zCI exists */
    }else if( (pM = manifest_new(&content))!=0 || pM->type!=CFTYPE_MANIFEST ){
      zCI = 0;  /* The artifact exists but is not a manifest */
    }else{

      zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
    }
  }


  /* Compute the title of the page */  
  blob_zero(&dirname);







<


















<
<
|
<
<
>







105
106
107
108
109
110
111

112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129


130


131
132
133
134
135
136
137
138
  int nCol, nRow;
  int cnt, i;
  char *zPrefix;
  Stmt q;
  const char *zCI = P("ci");
  int rid = 0;
  char *zUuid = 0;

  Blob dirname;
  Manifest *pM = 0;
  const char *zSubdirLink;

  login_check_credentials();
  if( !g.okHistory ){ login_needed(); return; }
  style_header("File List");
  sqlite3_create_function(g.db, "pathelement", 2, SQLITE_UTF8, 0,
                          pathelementFunc, 0, 0);

  /* If the name= parameter is an empty string, make it a NULL pointer */
  if( zD && strlen(zD)==0 ){ zD = 0; }

  /* If a specific check-in is requested, fetch and parse it.  If the
  ** specific check-in does not exist, clear zCI.  zCI==0 will cause all
  ** files from all check-ins to be displayed.
  */
  if( zCI ){


    pM = manifest_get_by_name(zCI, &rid);


    if( pM ){
      zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", rid);
    }
  }


  /* Compute the title of the page */  
  blob_zero(&dirname);
Changes to src/diffcmd.c.
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
  int diffFlags
){
  Manifest *pFrom, *pTo;
  ManifestFile *pFromFile, *pToFile;
  int ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0 ? 1 : 0;
  int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0;

  pFrom = manifest_from_name(zFrom);
  manifest_file_rewind(pFrom);
  pFromFile = manifest_file_next(pFrom,0);
  pTo = manifest_from_name(zTo);
  manifest_file_rewind(pTo);
  pToFile = manifest_file_next(pTo,0);

  while( pFromFile || pToFile ){
    int cmp;
    if( pFromFile==0 ){
      cmp = +1;







|


|







358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
  int diffFlags
){
  Manifest *pFrom, *pTo;
  ManifestFile *pFromFile, *pToFile;
  int ignoreEolWs = (diffFlags & DIFF_NOEOLWS)!=0 ? 1 : 0;
  int asNewFlag = (diffFlags & DIFF_NEWFILE)!=0 ? 1 : 0;

  pFrom = manifest_get_by_name(zFrom, 0);
  manifest_file_rewind(pFrom);
  pFromFile = manifest_file_next(pFrom,0);
  pTo = manifest_get_by_name(zTo, 0);
  manifest_file_rewind(pTo);
  pToFile = manifest_file_next(pTo,0);

  while( pFromFile || pToFile ){
    int cmp;
    if( pFromFile==0 ){
      cmp = +1;
Changes to src/manifest.c.
51
52
53
54
55
56
57


58
59
60
61
62
63
64

/*
** A parsed manifest or cluster.
*/
struct Manifest {
  Blob content;         /* The original content blob */
  int type;             /* Type of artifact.  One of CFTYPE_xxxxx */


  char *zComment;       /* Decoded comment.  The C card. */
  double rDate;         /* Date and time from D card.  0.0 if no D card. */
  char *zUser;          /* Name of the user from the U card. */
  char *zRepoCksum;     /* MD5 checksum of the baseline content.  R card. */
  char *zWiki;          /* Text of the wiki page.  W card. */
  char *zWikiTitle;     /* Name of the wiki page. L card. */
  double rEventDate;    /* Date of an event.  E card. */







>
>







51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

/*
** A parsed manifest or cluster.
*/
struct Manifest {
  Blob content;         /* The original content blob */
  int type;             /* Type of artifact.  One of CFTYPE_xxxxx */
  char *zBaseline;      /* Baseline manifest.  The B card. */
  Manifest *pBaseline;  /* The actual baseline manifest */
  char *zComment;       /* Decoded comment.  The C card. */
  double rDate;         /* Date and time from D card.  0.0 if no D card. */
  char *zUser;          /* Name of the user from the U card. */
  char *zRepoCksum;     /* MD5 checksum of the baseline content.  R card. */
  char *zWiki;          /* Text of the wiki page.  W card. */
  char *zWikiTitle;     /* Name of the wiki page. L card. */
  double rEventDate;    /* Date of an event.  E card. */
112
113
114
115
116
117
118

119
120
121
122
123
124
125
static void manifest_clear(Manifest *p){
  blob_reset(&p->content);
  free(p->aFile);
  free(p->azParent);
  free(p->azCChild);
  free(p->aTag);
  free(p->aField);

  memset(p, 0, sizeof(*p));
}

/*
** Add an element to the manifest cache using LRU replacement.
*/
void manifest_cache_insert(int rid, Manifest *p){







>







114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
static void manifest_clear(Manifest *p){
  blob_reset(&p->content);
  free(p->aFile);
  free(p->azParent);
  free(p->azCChild);
  free(p->aTag);
  free(p->aField);
  if( p->pBaseline ) manifest_clear(p->pBaseline);
  memset(p, 0, sizeof(*p));
}

/*
** Add an element to the manifest cache using LRU replacement.
*/
void manifest_cache_insert(int rid, Manifest *p){
283
284
285
286
287
288
289


















290
291
292
293
294
295
296
          goto manifest_syntax_error;
        }
        p->zAttachName = (char*)file_tail(zName);
        p->zAttachSrc = zSrc;
        p->zAttachTarget = zTarget;
        break;
      }



















      /*
      **     C <comment>
      **
      ** Comment text is fossil-encoded.  There may be no more than
      ** one C line.  C lines are required for manifests and are
      ** disallowed on all other control files.







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







286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
          goto manifest_syntax_error;
        }
        p->zAttachName = (char*)file_tail(zName);
        p->zAttachSrc = zSrc;
        p->zAttachTarget = zTarget;
        break;
      }

      /*
      **    B <uuid>
      **
      ** A B-line gives the UUID for the baselinen of a delta-manifest.
      */
      case 'B': {
        char *zBaseline;
        if( p->zBaseline ) goto manifest_syntax_error;
        md5sum_step_text(blob_buffer(&line), blob_size(&line));
        if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
        zBaseline = blob_terminate(&a1);
        if( blob_size(&a1)!=UUID_SIZE ) goto manifest_syntax_error;
        if( !validate16(zBaseline, UUID_SIZE) ) goto manifest_syntax_error;
        p->zBaseline = zBaseline;
        break;
      }


      /*
      **     C <comment>
      **
      ** Comment text is fossil-encoded.  There may be no more than
      ** one C line.  C lines are required for manifests and are
      ** disallowed on all other control files.
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366

367
368



369
370
371
372
373
374
375
        if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error;
        p->zEventId = blob_terminate(&a2);
        if( !validate16(p->zEventId, UUID_SIZE) ) goto manifest_syntax_error;
        break;
      }

      /*
      **     F <filename> <uuid> ?<permissions>? ?<old-name>?
      **
      ** Identifies a file in a manifest.  Multiple F lines are
      ** allowed in a manifest.  F lines are not allowed in any
      ** other control file.  The filename and old-name are fossil-encoded.
      */
      case 'F': {
        char *zName, *zUuid, *zPerm, *zPriorName;
        md5sum_step_text(blob_buffer(&line), blob_size(&line));
        if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;
        if( blob_token(&line, &a2)==0 ) goto manifest_syntax_error;
        zName = blob_terminate(&a1);
        zUuid = blob_terminate(&a2);
        blob_token(&line, &a3);
        zPerm = blob_terminate(&a3);

        if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error;
        if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error;



        defossilize(zName);
        if( !file_is_simple_pathname(zName) ){
          goto manifest_syntax_error;
        }
        blob_token(&line, &a4);
        zPriorName = blob_terminate(&a4);
        if( zPriorName[0] ){







|









<

<
|
|
>
|
|
>
>
>







366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382

383

384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
        if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error;
        p->zEventId = blob_terminate(&a2);
        if( !validate16(p->zEventId, UUID_SIZE) ) goto manifest_syntax_error;
        break;
      }

      /*
      **     F <filename> ?<uuid>? ?<permissions>? ?<old-name>?
      **
      ** Identifies a file in a manifest.  Multiple F lines are
      ** allowed in a manifest.  F lines are not allowed in any
      ** other control file.  The filename and old-name are fossil-encoded.
      */
      case 'F': {
        char *zName, *zUuid, *zPerm, *zPriorName;
        md5sum_step_text(blob_buffer(&line), blob_size(&line));
        if( blob_token(&line, &a1)==0 ) goto manifest_syntax_error;

        zName = blob_terminate(&a1);

        blob_token(&line, &a2);
        zUuid = blob_terminate(&a2);
        if( p->zBaseline==0 || zUuid[0]!=0 ){
          if( blob_size(&a2)!=UUID_SIZE ) goto manifest_syntax_error;
          if( !validate16(zUuid, UUID_SIZE) ) goto manifest_syntax_error;
        }
        blob_token(&line, &a3);
        zPerm = blob_terminate(&a3);
        defossilize(zName);
        if( !file_is_simple_pathname(zName) ){
          goto manifest_syntax_error;
        }
        blob_token(&line, &a4);
        zPriorName = blob_terminate(&a4);
        if( zPriorName[0] ){
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
      default: {
        goto manifest_syntax_error;
      }
    }
  }
  if( !seenHeader ) goto manifest_syntax_error;

  if( p->nFile>0 || p->zRepoCksum!=0 ){
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->rDate<=0.0 ) goto manifest_syntax_error;
    if( p->nField>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zWiki ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( p->zEventId ) goto manifest_syntax_error;







|







698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
      default: {
        goto manifest_syntax_error;
      }
    }
  }
  if( !seenHeader ) goto manifest_syntax_error;

  if( p->nFile>0 || p->zRepoCksum!=0 || p->zBaseline ){
    if( p->nCChild>0 ) goto manifest_syntax_error;
    if( p->rDate<=0.0 ) goto manifest_syntax_error;
    if( p->nField>0 ) goto manifest_syntax_error;
    if( p->zTicketUuid ) goto manifest_syntax_error;
    if( p->zWiki ) goto manifest_syntax_error;
    if( p->zWikiTitle ) goto manifest_syntax_error;
    if( p->zEventId ) goto manifest_syntax_error;
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
** parse of pContent.  Return a pointer ot the new object.
**
** If pContent is not a well-formed control artifact, return 0.
**
** pContent is reset, regardless of whether or not a Manifest object
** is returned.
*/
Manifest *manifest_new(Blob *pContent){
  Manifest *p = fossil_malloc( sizeof(*p) );
  if( manifest_parse(p, pContent)==0 ){
    fossil_free(p);
    p = 0;
  }
  return p;
}







|







801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
** parse of pContent.  Return a pointer ot the new object.
**
** If pContent is not a well-formed control artifact, return 0.
**
** pContent is reset, regardless of whether or not a Manifest object
** is returned.
*/
static Manifest *manifest_new(Blob *pContent){
  Manifest *p = fossil_malloc( sizeof(*p) );
  if( manifest_parse(p, pContent)==0 ){
    fossil_free(p);
    p = 0;
  }
  return p;
}
802
803
804
805
806
807
808



















809
810
811
812
813
814
815
  p = manifest_new(&content);
  if( p && cfType!=CFTYPE_ANY && cfType!=p->type ){
    manifest_destroy(p);
    p = 0;
  }
  return p;
}




















/*
** Destroy a Manifest object previously obtained from manifest_new().
*/
void manifest_destroy(Manifest *p){
  if( p ){
    manifest_clear(p);







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







825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
  p = manifest_new(&content);
  if( p && cfType!=CFTYPE_ANY && cfType!=p->type ){
    manifest_destroy(p);
    p = 0;
  }
  return p;
}

/*
** Given a checkin name, load and parse the manifest for that checkin.
** Throw a fatal error if anything goes wrong.
*/
Manifest *manifest_get_by_name(const char *zName, int *pRid){
  int rid;
  Manifest *p;

  rid = name_to_rid(zName);
  if( !is_a_version(rid) ){
    fossil_fatal("no such checkin: %s", zName);
  }
  p = manifest_get(rid, CFTYPE_MANIFEST);
  if( p==0 ){
    fossil_fatal("cannot parse manifest for checkin: %s", zName);
  }
  return p;
}

/*
** Destroy a Manifest object previously obtained from manifest_new().
*/
void manifest_destroy(Manifest *p){
  if( p ){
    manifest_clear(p);
843
844
845
846
847
848
849
850









851
852
853
854
855
856
857
858
859
860
861
862

863
864

865
866
867
868
869
870
871
872
873
874
875





876















877







878


879



880



881
882
883
884
885
886
887
  }
}

/*
** Rewind a manifest-file iterator back to the beginning of the manifest.
*/
void manifest_file_rewind(Manifest *p){
  p->iFile = -1;









}

/*
** Advance to the next manifest-file.
**
** Return NULL for end-of-records or if there is an error.  If an error
** occurs and pErr!=0 then store 1 in *pErr.
*/
ManifestFile *manifest_file_next(
  Manifest *p,   
  int *pErr
){

  if( pErr ) *pErr = 0;
  if( p->iFile+1<p->nFile ){

    p->iFile++;
    return &p->aFile[p->iFile];
  }else{
    return 0;
  }
}

/*
** Return a pointer to the current file.
*/
ManifestFile *manifest_file_current(Manifest *p){





  if( p->iFile>=0 && p->iFile<p->nFile ){















    return &p->aFile[p->iFile];







  }else{


    return 0;



  }



}

/*
** Translate a filename into a filename-id (fnid).  Create a new fnid
** if no previously exists.
*/
static int filename_to_fnid(const char *zFilename){







|
>
>
>
>
>
>
>
>
>












>

|
>
|
|

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







885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920



921

922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
  }
}

/*
** Rewind a manifest-file iterator back to the beginning of the manifest.
*/
void manifest_file_rewind(Manifest *p){
  p->iFile = 0;
  if( p->zBaseline!=0 && p->pBaseline==0 ){
    p->pBaseline = manifest_get_by_name(p->zBaseline, 0);
    if( p->pBaseline==0 ){
      fossil_fatal("cannot access baseline manifest %S", p->zBaseline);
    }
  }
  if( p->pBaseline ){
    p->pBaseline->iFile = 0;
  }
}

/*
** Advance to the next manifest-file.
**
** Return NULL for end-of-records or if there is an error.  If an error
** occurs and pErr!=0 then store 1 in *pErr.
*/
ManifestFile *manifest_file_next(
  Manifest *p,   
  int *pErr
){
  ManifestFile *pOut = 0;
  if( pErr ) *pErr = 0;
  if( p->pBaseline==0 ){
    /* Manifest p is a baseline-manifest.  Just scan down the list
    ** of files. */
    if( p->iFile<p->nFile ) pOut = &p->aFile[p->iFile++];
  }else{



    /* Manifest p is a delta-manifest.  Scan the baseline but amend the

    ** file list in the baseline with changes described by p.
    */
    Manifest *pB = p->pBaseline;
    int cmp;
    while(1){
      if( pB->iFile>=pB->nFile ){
        /* We have used all entries out of the baseline.  Return the next
        ** entry from the delta. */
        if( p->iFile<p->nFile ) pOut = &p->aFile[p->iFile++];
        break;
      }else if( p->iFile>=p->nFile ){
        /* We have used all entries from the delta.  Return the next
        ** entry from the baseline. */
        if( pB->iFile<pB->nFile ) pOut = &pB->aFile[pB->iFile++];
        break;
      }else if( (cmp = strcmp(pB->aFile[pB->iFile].zName,
                              p->aFile[p->iFile].zName)) < 0 ){
        /* The next baseline entry comes before the next delta entry.
        ** So return the baseline entry. */
        pOut = &pB->aFile[pB->iFile++];
        break;
      }else if( cmp>0 ){
        /* The next delta entry comes before the next baseline
        ** entry so return the delta entry */
        pOut = &p->aFile[p->iFile++];
        break;
      }else if( p->aFile[p->iFile].zUuid[0] ){
        /* The next delta entry is a replacement for the next baseline
        ** entry.  Skip the baseline entry and return the delta entry */
        pB->iFile++;
        pOut = &p->aFile[p->iFile++];
        break;
      }else{
        /* The next delta entry is a delete of the next baseline
        ** entry.  Skip them both.  Repeat the loop to find the next
        ** non-delete entry. */
        pB->iFile++;
        p->iFile++;
        continue;
      }
    }
  }
  return pOut;
}

/*
** Translate a filename into a filename-id (fnid).  Create a new fnid
** if no previously exists.
*/
static int filename_to_fnid(const char *zFilename){
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
  if( m.type==CFTYPE_MANIFEST ){
    manifest_cache_insert(rid, &m);
  }else{
    manifest_clear(&m);
  }
  return 1;
}

/*
** Given a checkin name, load and parse the manifest for that checkin.
** Throw a fatal error if anything goes wrong.
*/
Manifest *manifest_from_name(const char *zName){
  int rid;
  Manifest *p;

  rid = name_to_rid(zName);
  if( !is_a_version(rid) ){
    fossil_fatal("no such checkin: %s", zName);
  }
  p = manifest_get(rid, CFTYPE_MANIFEST);
  if( p==0 ){
    fossil_fatal("cannot parse manifest for checkin: %s", zName);
  }
  return p;
}







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
1534
1535
1536
1537
1538
1539
1540



















  if( m.type==CFTYPE_MANIFEST ){
    manifest_cache_insert(rid, &m);
  }else{
    manifest_clear(&m);
  }
  return 1;
}



















Changes to src/zip.c.
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
** added to as part of the zip file. It may be 0 or an empty string,
** in which case it is ignored. The intention is to create a zip which
** politely expands into a subdir instead of filling your current dir
** with source files. For example, pass a UUID or "ProjectName".
**
*/
void zip_of_baseline(int rid, Blob *pZip, const char *zDir){
  Blob mfile, file, hash;
  Manifest *pManifest;
  ManifestFile *pFile;
  Blob filename;
  int nPrefix;
  
  content_get(rid, &mfile);
  if( blob_size(&mfile)==0 ){
    blob_zero(pZip);
    return;
  }
  blob_zero(&file);
  blob_zero(&hash);
  blob_copy(&file, &mfile);
  blob_zero(&filename);
  zip_open();

  if( zDir && zDir[0] ){
    blob_appendf(&filename, "%s/", zDir);
  }
  nPrefix = blob_size(&filename);

  pManifest = manifest_new(&mfile);
  if( pManifest ){
    char *zName;
    zip_set_timedate(pManifest->rDate);
    blob_append(&filename, "manifest", -1);
    zName = blob_str(&filename);
    zip_add_folders(zName);
    zip_add_file(zName, &file);
    sha1sum_blob(&file, &hash);
    blob_reset(&file);
    blob_append(&hash, "\n", 1);
    blob_resize(&filename, nPrefix);
    blob_append(&filename, "manifest.uuid", -1);
    zName = blob_str(&filename);
    zip_add_file(zName, &hash);
    blob_reset(&hash);
    manifest_file_rewind(pManifest);
    while( (pFile = manifest_file_next(pManifest,0))!=0 ){
      int fid = uuid_to_rid(pFile->zUuid, 0);
      if( fid ){
        content_get(fid, &file);
        blob_resize(&filename, nPrefix);
        blob_append(&filename, pFile->zName, -1);
        zName = blob_str(&filename);
        zip_add_folders(zName);
        zip_add_file(zName, &file);
        blob_reset(&file);
      }
    }
  }else{
    blob_reset(&file);
  }
  manifest_destroy(pManifest);
  blob_reset(&filename);
  zip_close(pZip);
}

/*







|










<

<








|






|
|
|




















|







311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328

329

330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
** added to as part of the zip file. It may be 0 or an empty string,
** in which case it is ignored. The intention is to create a zip which
** politely expands into a subdir instead of filling your current dir
** with source files. For example, pass a UUID or "ProjectName".
**
*/
void zip_of_baseline(int rid, Blob *pZip, const char *zDir){
  Blob mfile, hash, file;
  Manifest *pManifest;
  ManifestFile *pFile;
  Blob filename;
  int nPrefix;
  
  content_get(rid, &mfile);
  if( blob_size(&mfile)==0 ){
    blob_zero(pZip);
    return;
  }

  blob_zero(&hash);

  blob_zero(&filename);
  zip_open();

  if( zDir && zDir[0] ){
    blob_appendf(&filename, "%s/", zDir);
  }
  nPrefix = blob_size(&filename);

  pManifest = manifest_get(rid, CFTYPE_MANIFEST);
  if( pManifest ){
    char *zName;
    zip_set_timedate(pManifest->rDate);
    blob_append(&filename, "manifest", -1);
    zName = blob_str(&filename);
    zip_add_folders(zName);
    zip_add_file(zName, &mfile);
    sha1sum_blob(&mfile, &hash);
    blob_reset(&mfile);
    blob_append(&hash, "\n", 1);
    blob_resize(&filename, nPrefix);
    blob_append(&filename, "manifest.uuid", -1);
    zName = blob_str(&filename);
    zip_add_file(zName, &hash);
    blob_reset(&hash);
    manifest_file_rewind(pManifest);
    while( (pFile = manifest_file_next(pManifest,0))!=0 ){
      int fid = uuid_to_rid(pFile->zUuid, 0);
      if( fid ){
        content_get(fid, &file);
        blob_resize(&filename, nPrefix);
        blob_append(&filename, pFile->zName, -1);
        zName = blob_str(&filename);
        zip_add_folders(zName);
        zip_add_file(zName, &file);
        blob_reset(&file);
      }
    }
  }else{
    blob_reset(&mfile);
  }
  manifest_destroy(pManifest);
  blob_reset(&filename);
  zip_close(pZip);
}

/*
Changes to www/fileformat.wiki.
93
94
95
96
97
98
99

100
101
102
103
104
105
106
107
108








109
110
111
112
113
114
115
No card may be duplicated.
The entire manifest may be PGP clear-signed, but otherwise it
may contain no additional text or data beyond what is described here.

Allowed cards in the manifest are as follows:

<blockquote>

<b>C</b> <i>checkin-comment</i><br>
<b>D</b> <i>time-and-date-stamp</i><br>
<b>F</b> <i>filename</i> <i>SHA1-hash</i> <i>permissions</i> <i>old-name</i><br>
<b>P</b> <i>SHA1-hash</i>+<br>
<b>R</b> <i>repository-checksum</i><br>
<b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name  <b>*</b> ?value?</i><br>
<b>U</b> <i>user-login</i><br>
<b>Z</b> <i>manifest-checksum</i>
</blockquote>









A manifest must have exactly one C-card.  The sole argument to
the C-card is a check-in comment that describes the check-in that
the manifest defines.  The check-in comment is text.  The following
escape sequences are applied to the text:
A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73).  A
newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E).  A backslash 







>









>
>
>
>
>
>
>
>







93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
No card may be duplicated.
The entire manifest may be PGP clear-signed, but otherwise it
may contain no additional text or data beyond what is described here.

Allowed cards in the manifest are as follows:

<blockquote>
<b>B</b> <i>baseline-manifest</i><br>
<b>C</b> <i>checkin-comment</i><br>
<b>D</b> <i>time-and-date-stamp</i><br>
<b>F</b> <i>filename</i> <i>SHA1-hash</i> <i>permissions</i> <i>old-name</i><br>
<b>P</b> <i>SHA1-hash</i>+<br>
<b>R</b> <i>repository-checksum</i><br>
<b>T</b> (<b>+</b>|<b>-</b>|<b>*</b>)<i>tag-name  <b>*</b> ?value?</i><br>
<b>U</b> <i>user-login</i><br>
<b>Z</b> <i>manifest-checksum</i>
</blockquote>

A manifest may optionally have a single B-card.  The B-card specifies
another manifest that serves as the "baseline" for this manifest.  A
manifest that has a B-card is called a delta-manifest and a manifest
that omits the B-card is a baseline-manifest.  The other manifest
identified by the argument of the B-card must be a baseline-manifest.
A baseline-manifest records the complete contents of a checkin.
A delta-manifest records all changes from its baseline.  

A manifest must have exactly one C-card.  The sole argument to
the C-card is a check-in comment that describes the check-in that
the manifest defines.  The check-in comment is text.  The following
escape sequences are applied to the text:
A space (ASCII 0x20) is represented as "\s" (ASCII 0x5C, 0x73).  A
newline (ASCII 0x0a) is "\n" (ASCII 0x6C, x6E).  A backslash 
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140



141
142
143
144
145
146
147
148
date and time should be in coordinated universal time (UTC).
The format is:

<blockquote>
<i>YYYY</i><b>-</b><i>MM</i><b>-</b><i>DD</i><b>T</b><i>HH</i><b>:</b><i>MM</i><b>:</b><i>SS</i>
</blockquote>

A manifest has zero or more F-cards.  Each F-card defines a file
(other than the manifest itself) which is part of the check-in that
the manifest defines.  There are two, three, or four arguments.
The first argument
is the pathname of the file in the check-in relative to the root
of the project file hierarchy.  No ".." or "." directories are allowed
within the filename.  Space characters are escaped as in C-card
comment text.  Backslash characters and newlines are not allowed
within filenames.  The directory separator character is a forward
slash (ASCII 0x2F).  The second argument to the F-card is the
full 40-character lower-case hexadecimal SHA1 hash of the content



artifact.  The optional 3rd argument defines any special access 
permissions associated with the file.  The only special code currently
defined is "x" which means that the file is executable.  All files are
always readable and writable.  This can be expressed by "w" permission
if desired but is optional.
The optional 4th argument is the name of the same file as it existed in
the parent check-in.  If the name of the file is unchanged from its
parent, then the 4th argument is omitted.







|
<
|








>
>
>
|







132
133
134
135
136
137
138
139

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
date and time should be in coordinated universal time (UTC).
The format is:

<blockquote>
<i>YYYY</i><b>-</b><i>MM</i><b>-</b><i>DD</i><b>T</b><i>HH</i><b>:</b><i>MM</i><b>:</b><i>SS</i>
</blockquote>

A manifest has zero or more F-cards.  Each F-card identifies a file

that is part of the check-in.  There are one, two, three, or four arguments.
The first argument
is the pathname of the file in the check-in relative to the root
of the project file hierarchy.  No ".." or "." directories are allowed
within the filename.  Space characters are escaped as in C-card
comment text.  Backslash characters and newlines are not allowed
within filenames.  The directory separator character is a forward
slash (ASCII 0x2F).  The second argument to the F-card is the
full 40-character lower-case hexadecimal SHA1 hash of the content
artifact.  The second argument is required for baselin manifests
but is optional for delta manifests.  When the second argument to the
F-card is omitted, it means that the file has been deleted relative
to the baseline.  The optional 3rd argument defines any special access 
permissions associated with the file.  The only special code currently
defined is "x" which means that the file is executable.  All files are
always readable and writable.  This can be expressed by "w" permission
if desired but is optional.
The optional 4th argument is the name of the same file as it existed in
the parent check-in.  If the name of the file is unchanged from its
parent, then the 4th argument is omitted.