\n");
blob_reset(&orig);
blob_reset(&out);
}
/*
@@ -1122,468 +1018,990 @@
}
}
db_finalize(&stmt);
return zFileUuid;
}
+
+/*
+** Helper for /fileedit_xyz routes. Clears the CGI content buffer,
+** sets an error status code, and queues up a JSON response in the
+** form of an object:
+**
+** {error: formatted message}
+**
+** After calling this, the caller should immediately return.
+ */
+static void fileedit_ajax_error(int httpCode, const char * zFmt, ...){
+ Blob msg = empty_blob;
+ Blob content = empty_blob;
+ va_list vargs;
+ va_start(vargs,zFmt);
+ blob_vappendf(&msg, zFmt, vargs);
+ va_end(vargs);
+ blob_appendf(&content,"{\"error\":\"%j\"}", blob_str(&msg));
+ blob_reset(&msg);
+ cgi_set_content(&content);
+ cgi_set_status(httpCode, "Error");
+ cgi_set_content_type("application/json");
+}
+
+/*
+** Performs bootstrapping common to the /fileedit_xyz AJAX routes.
+** Returns 0 if bootstrapping fails (wrong permissions), in which
+** case it has reported the error and the route should immediately
+** return. Returns true on success.
+*/
+static int fileedit_ajax_boostrap(void){
+ login_check_credentials();
+ if( !g.perm.Write ){
+ fileedit_ajax_error(403,"Write permissions required.");
+ return 0;
+ }
+
+ return 1;
+}
+/*
+** Returns true if the current user is allowed to edit the given
+** filename, as determined by fileedit_is_editable(), else false,
+** in which case it queues up an error response and the caller
+** must return immediately.
+*/
+static int fileedit_ajax_check_filename(const char * zFilename){
+ if(0==fileedit_is_editable(zFilename)){
+ fileedit_ajax_error(403, "File is disallowed by the "
+ "fileedit-glob setting.");
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+** If zFn is not NULL, it is assigned the value of the first one of
+** the "filename" or "fn" CGI parameters which is set.
+**
+** If zCi is not NULL, it is assigned the value of the first one of
+** the "checkin" or "ci" CGI parameters which is set.
+**
+** If a parameter is not NULL, it will be assigned NULL if the
+** corresponding parameter is not set.
+**
+** Returns the number of non-NULL values it assigns to arguments. Thus
+** if passed (&x, NULL), it returns 1 if it assigns non-NULL to *x and
+** 0 if it assigns NULL to *x.
+*/
+static int fileedit_get_fnci_args( const char **zFn, const char **zCi ){
+ int rc = 0;
+ if(zCi!=0){
+ *zCi = PD("checkin",P("ci"));
+ if( *zCi ) ++rc;
+ }
+ if(zFn!=0){
+ *zFn = PD("filename",P("fn"));
+ if (*zFn) ++rc;
+ }
+ return rc;
+}
+
+/*
+** Passed the values of the "checkin" and "filename" request
+** properties, this function verifies that they are valid and
+** populates:
+**
+** - *zRevUuid = the fully-expanded value of zRev (owned by the
+** caller). zRevUuid may be NULL.
+**
+** - *vid = the RID of zRevUuid. May not be NULL.
+**
+** - *frid = the RID of zFilename's blob content. May not be NULL
+** unless zFilename is also NULL. If BOTH of zFilename and frid are
+** NULL then no confirmation is done on the filename argument - only
+** zRev is checked.
+**
+** Returns 0 if the given file is not in the given checkin or if
+** fileedit_ajax_check_filename() fails, else returns true. If it
+** returns false, it queues up an error response and the caller must
+** return immediately.
+*/
+static int fileedit_ajax_setup_filerev(const char * zRev,
+ char ** zRevUuid,
+ int * vid,
+ const char * zFilename,
+ int * frid){
+ char * zFileUuid; /* file UUID */
+ const int checkFile = zFilename!=0 || frid!=0;
+
+ if(checkFile && !fileedit_ajax_check_filename(zFilename)){
+ return 0;
+ }
+ *vid = symbolic_name_to_rid(zRev, "ci");
+ if(0==*vid){
+ fileedit_ajax_error(404,"Cannot resolve name as a checkin: %s",
+ zRev);
+ return 0;
+ }else if(*vid<0){
+ fileedit_ajax_error(400,"Checkin name is ambiguous: %s",
+ zRev);
+ return 0;
+ }
+ if(checkFile){
+ zFileUuid = fileedit_file_uuid(zFilename, *vid, 0);
+ if(zFileUuid==0){
+ fileedit_ajax_error(404,"Checkin does not contain file.");
+ return 0;
+ }
+ }
+ if(zRevUuid!=0){
+ *zRevUuid = rid_to_uuid(*vid);
+ }
+ if(checkFile){
+ assert(zFileUuid!=0);
+ if(frid!=0){
+ *frid = fast_uuid_to_rid(zFileUuid);
+ }
+ fossil_free(zFileUuid);
+ }
+ return 1;
+}
+
+/*
+** AJAX route /fileedit?ajax=content
+**
+** Query parameters:
+**
+** filename=FILENAME
+** checkin=CHECKIN_NAME
+**
+** User must have Write access to use this page.
+**
+** Responds with the raw content of the given page. On error it
+** produces a JSON response as documented for fileedit_ajax_error().
+*/
+static void fileedit_ajax_content(void){
+ const char * zFilename = 0;
+ const char * zRev = 0;
+ int vid, frid;
+ Blob content = empty_blob;
+ const char * zMime;
+
+ fileedit_get_fnci_args( &zFilename, &zRev );
+ if(!fileedit_ajax_boostrap()
+ || !fileedit_ajax_setup_filerev(zRev, 0, &vid,
+ zFilename, &frid)){
+ return;
+ }
+ zMime = mimetype_from_name(zFilename);
+ content_get(frid, &content);
+ if(0==zMime){
+ if(looks_like_binary(&content)){
+ zMime = "application/octet-stream";
+ }else{
+ zMime = "text/plain";
+ }
+ }
+ cgi_set_content_type(zMime);
+ cgi_set_content(&content);
+}
+
+/*
+** AJAX route /fileedit?ajax=preview
+**
+** Required query parameters:
+**
+** filename=FILENAME
+** content=text
+**
+** Optional query parameters:
+**
+** render_mode=integer (FE_RENDER_xxx) (default=FE_RENDER_GUESS)
+**
+** ln=0 or 1 to disable/enable line number mode in
+** FE_RENDER_PLAIN_TEXT mode.
+**
+** iframe_height=integer (default=40) Height, in EMs of HTML preview
+** iframe.
+**
+** User must have Write access to use this page.
+**
+** Responds with the HTML content of the preview. On error it produces
+** a JSON response as documented for fileedit_ajax_error().
+*/
+static void fileedit_ajax_preview(void){
+ const char * zFilename = 0;
+ const char * zContent = P("content");
+ int renderMode = atoi(PD("render_mode","0"));
+ int ln = atoi(PD("ln","0"));
+ int iframeHeight = atoi(PD("iframe_height","40"));
+ Blob content = empty_blob;
+
+ fileedit_get_fnci_args( &zFilename, 0 );
+ if(!fileedit_ajax_boostrap()
+ || !fileedit_ajax_check_filename(zFilename)){
+ return;
+ }
+ cgi_set_content_type("text/html");
+ blob_init(&content, zContent, -1);
+ fileedit_render_preview(&content, zFilename,
+ ln ? FE_PREVIEW_LINE_NUMBERS : 0,
+ renderMode, iframeHeight);
+}
+
+/*
+** AJAX route /fileedit?ajax=diff
+**
+** Required query parameters:
+**
+** filename=FILENAME
+** content=text
+** checkin=checkin version
+**
+** Optional parameters:
+**
+** sbs=integer (1=side-by-side or 0=unified, default=0)
+**
+** User must have Write access to use this page.
+**
+** Responds with the HTML content of the diff. On error it produces a
+** JSON response as documented for fileedit_ajax_error().
+*/
+static void fileedit_ajax_diff(void){
+ /*
+ ** Reminder: we only need the filename to perform valdiation
+ ** against fileedit_is_editable(), else this route could be
+ ** abused to get diffs against content disallowed by the
+ ** whitelist.
+ */
+ const char * zFilename = 0;
+ const char * zRev = 0;
+ const char * zContent = P("content");
+ char * zRevUuid = 0;
+ int isSbs = atoi(PD("sbs","0"));
+ int vid, frid;
+ Blob content = empty_blob;
+
+ fileedit_get_fnci_args( &zFilename, &zRev );
+ if(!fileedit_ajax_boostrap()
+ || !fileedit_ajax_setup_filerev(zRev, &zRevUuid, &vid,
+ zFilename, &frid)){
+ return;
+ }
+ if(!zContent){
+ zContent = "";
+ }
+ cgi_set_content_type("text/html");
+ blob_init(&content, zContent, -1);
+ fileedit_render_diff(&content, frid, zRevUuid, isSbs);
+ fossil_free(zRevUuid);
+ blob_reset(&content);
+}
+
+/*
+** Sets up and validates most, but not all, of p's checkin-related
+** state from the CGI environment. Returns 0 on success or a suggested
+** HTTP result code on error, in which case a message will have been
+** written to pErr.
+**
+** It always fails if it cannot completely resolve the 'file' and 'r'
+** parameters, including verifying that the refer to a real
+** file/version combination and editable by the current user. All
+** others are optional (at this level, anyway, but upstream code might
+** require them).
+**
+** Intended to be used only by /filepage and /filepage_commit.
+*/
+static int fileedit_setup_cimi_from_p(CheckinMiniInfo * p, Blob * pErr){
+ char * zFileUuid = 0; /* UUID of file content */
+ const char * zFlag; /* generic flag */
+ int rc = 0, vid = 0, frid = 0; /* result code, checkin/file rids */
+
+#define fail(EXPR) blob_appendf EXPR; goto end_fail
+ zFlag = PD("filename",P("fn"));
+ if(zFlag==0 || !*zFlag){
+ rc = 400;
+ fail((pErr,"Missing required 'filename' parameter."));
+ }
+ p->zFilename = mprintf("%s",zFlag);
+
+ if(0==fileedit_is_editable(p->zFilename)){
+ rc = 403;
+ fail((pErr,"Filename [%h] is disallowed "
+ "by the [fileedit-glob] repository "
+ "setting.",
+ p->zFilename));
+ }
+
+ zFlag = PD("checkin",P("ci"));
+ if(!zFlag){
+ rc = 400;
+ fail((pErr,"Missing required 'checkin' parameter."));
+ }
+ vid = symbolic_name_to_rid(zFlag, "ci");
+ if(0==vid){
+ rc = 404;
+ fail((pErr,"Could not resolve checkin version."));
+ }else if(vid<0){
+ rc = 400;
+ fail((pErr,"Checkin name is ambiguous."));
+ }
+ p->zParentUuid = rid_to_uuid(vid)/*fully expand it*/;
+
+ zFileUuid = fileedit_file_uuid(p->zFilename, vid, &p->filePerm);
+ if(!zFileUuid){
+ rc = 404;
+ fail((pErr,"Checkin [%S] does not contain file: "
+ "[%h]", p->zParentUuid, p->zFilename));
+ }else if(PERM_LNK==p->filePerm){
+ rc = 400;
+ fail((pErr,"Editing symlinks is not permitted."));
+ }
+
+ /* Find the repo-side file entry or fail... */
+ frid = fast_uuid_to_rid(zFileUuid);
+ assert(frid);
+
+ /* Read file content from submit request or repo... */
+ zFlag = P("content");
+ if(zFlag==0){
+ content_get(frid, &p->fileContent);
+ }else{
+ blob_init(&p->fileContent,zFlag,-1);
+ }
+ if(looks_like_binary(&p->fileContent)){
+ rc = 400;
+ fail((pErr,"File appears to be binary. Cannot edit: "
+ "[%h]",p->zFilename));
+ }
+
+ zFlag = PT("comment");
+ if(zFlag!=0 && *zFlag!=0){
+ blob_append(&p->comment, zFlag, -1);
+ }
+ zFlag = P("comment_mimetype");
+ if(zFlag){
+ p->zCommentMimetype = mprintf("%s",zFlag);
+ zFlag = 0;
+ }
+#define p_int(K) atoi(PD(K,"0"))
+ if(p_int("dry_run")!=0){
+ p->flags |= CIMINI_DRY_RUN;
+ }
+ if(p_int("allow_fork")!=0){
+ p->flags |= CIMINI_ALLOW_FORK;
+ }
+ if(p_int("allow_older")!=0){
+ p->flags |= CIMINI_ALLOW_OLDER;
+ }
+ if(p_int("exec_bit")!=0){
+ p->filePerm = PERM_EXE;
+ }
+ if(p_int("allow_merge_conflict")!=0){
+ p->flags |= CIMINI_ALLOW_MERGE_MARKER;
+ }
+ if(p_int("prefer_delta")!=0){
+ p->flags |= CIMINI_PREFER_DELTA;
+ }
+
+ /* EOL conversion policy... */
+ switch(p_int("eol")){
+ case 1: p->flags |= CIMINI_CONVERT_EOL_UNIX; break;
+ case 2: p->flags |= CIMINI_CONVERT_EOL_WINDOWS; break;
+ default: p->flags |= CIMINI_CONVERT_EOL_INHERIT; break;
+ }
+#undef p_int
+ /*
+ ** TODO?: date-override date selection field. Maybe use
+ ** an input[type=datetime-local].
+ */
+ p->zUser = mprintf("%s",g.zLogin);
+ return 0;
+end_fail:
+#undef fail
+ fossil_free(zFileUuid);
+ return rc ? rc : 500;
+}
+
+/*
+** AJAX route /fileedit?ajax=filelist
+**
+** Fetches a JSON-format list of leaves and/or filenames for use in
+** creating a file selection list in /fileedit. It has different modes
+** of operation depending on its arguments:
+**
+** 'leaves': just fetch a list of open leaf versions, in this
+** format:
+**
+** [
+** {checkin: UUID, branch: branchName, timestamp: string}
+** ]
+**
+** The entries are ordered newest first.
+**
+** 'checkin=CHECKIN_NAME': fetch the current list of is-editable files
+** for the current user and given checkin name:
+**
+** {
+** checkin: UUID,
+** editableFiles: [ filename1, ... filenameN ] // sorted by name
+** }
+**
+** On error it produces a JSON response as documented for
+** fileedit_ajax_error().
+*/
+static void fileedit_ajax_filelist(void){
+ const char * zCi = PD("checkin",P("ci"));
+ Blob sql = empty_blob;
+ Stmt q = empty_Stmt;
+ int i = 0;
+
+ if(!fileedit_ajax_boostrap()){
+ return;
+ }
+ cgi_set_content_type("application/json");
+ if(zCi!=0){
+ char * zCiFull = 0;
+ int vid = 0;
+ if(0==fileedit_ajax_setup_filerev(zCi, &zCiFull, &vid, 0, 0)){
+ /* Error already reported */
+ return;
+ }
+ CX("{\"checkin\":\"%j\","
+ "\"editableFiles\":[", zCiFull);
+ blob_append_sql(&sql, "SELECT filename FROM files_of_checkin(%Q) "
+ "ORDER BY filename %s",
+ zCiFull, filename_collation());
+ db_prepare_blob(&q, &sql);
+ while( SQLITE_ROW==db_step(&q) ){
+ const char * zFilename = db_column_text(&q, 0);
+ if(fileedit_is_editable(zFilename)){
+ if(i++){
+ CX(",");
+ }
+ CX("\"%j\"", zFilename);
+ }
+ }
+ db_finalize(&q);
+ CX("]}");
+ }else if(P("leaves")!=0){
+ blob_append(&sql, timeline_query_for_tty(), -1);
+ blob_append_sql(&sql, " AND blob.rid IN (SElECT rid FROM leaf "
+ "WHERE NOT EXISTS("
+ "SELECT 1 from tagxref WHERE tagid=%d AND "
+ "tagtype>0 AND rid=leaf.rid"
+ ")) "
+ "ORDER BY mtime DESC", TAG_CLOSED);
+ db_prepare_blob(&q, &sql);
+ CX("[");
+ while( SQLITE_ROW==db_step(&q) ){
+ if(i++){
+ CX(",");
+ }
+ CX("{");
+ CX("\"checkin\":\"%j\",", db_column_text(&q, 1));
+ CX("\"timestamp\":\"%j\",", db_column_text(&q, 2));
+ CX("\"branch\":\"%j\"", db_column_text(&q, 7));
+ CX("}");
+ }
+ CX("]");
+ db_finalize(&q);
+ }else{
+ fileedit_ajax_error(500, "Unhandled URL argument.");
+ }
+}
+
+/*
+** AJAX route /fileedit?ajax=commit
+**
+** Required query parameters:
+**
+** filename=FILENAME
+** checkin=Parent checkin UUID
+** content=text
+** comment=text
+**
+** Optional query parameters:
+**
+** comment_mimetype=text
+** dry_run=int (1 or 0)
+**
+**
+** User must have Write access to use this page.
+**
+** Responds with JSON:
+**
+** {
+** uuid: newUUID,
+** manifest: text of manifest,
+** dryRun: bool
+** }
+**
+** On error it produces a JSON response as documented for
+** fileedit_ajax_error().
+*/
+static void fileedit_ajax_commit(void){
+ Blob err = empty_blob; /* Error messages */
+ Blob manifest = empty_blob; /* raw new manifest */
+ CheckinMiniInfo cimi; /* checkin state */
+ int rc; /* generic result code */
+ int newVid = 0; /* new version's RID */
+ char * zNewUuid = 0; /* newVid's UUID */
+
+ if(!fileedit_ajax_boostrap()){
+ return;
+ }
+ db_begin_transaction();
+ CheckinMiniInfo_init(&cimi);
+ rc = fileedit_setup_cimi_from_p(&cimi, &err);
+ if(0!=rc){
+ fileedit_ajax_error(rc,"%b",&err);
+ goto end_cleanup;
+ }
+ if(blob_size(&cimi.comment)==0){
+ fileedit_ajax_error(400,"Empty checkin comment is not permitted.");
+ goto end_cleanup;
+ }
+ cimi.pMfOut = &manifest;
+ checkin_mini(&cimi, &newVid, &err);
+ if(blob_size(&err)){
+ fileedit_ajax_error(500,"%b",&err);
+ goto end_cleanup;
+ }
+ assert(newVid>0);
+ zNewUuid = rid_to_uuid(newVid);
+ cgi_set_content_type("application/json");
+ CX("{");
+ CX("\"uuid\":\"%j\",", zNewUuid);
+ CX("\"dryRun\": %s,",
+ (CIMINI_DRY_RUN & cimi.flags) ? "true" : "false");
+ CX("\"manifest\": \"%j\"", blob_str(&manifest));
+ CX("}");
+ db_end_transaction(0/*noting that dry-run mode will have already
+ ** set this to rollback mode. */);
+end_cleanup:
+ fossil_free(zNewUuid);
+ blob_reset(&err);
+ blob_reset(&manifest);
+ CheckinMiniInfo_cleanup(&cimi);
+}
/*
** WEBPAGE: fileedit
**
** EXPERIMENTAL and subject to change and removal at any time. The goal
** is to allow online edits of files.
**
** Query parameters:
**
-** file=FILENAME Repo-relative path to the file.
-** r=VERSION Checkin version, using any unambiguous
-** supported symbolic version name.
+** filename=FILENAME Repo-relative path to the file.
+** checkin=VERSION Checkin version, using any unambiguous
+** supported symbolic version name.
**
** All other parameters are for internal use only, submitted via the
** form-submission process, and may change with any given revision of
** this code.
*/
-void fileedit_page(){
- enum submit_modes {
- SUBMIT_NONE = 0, SUBMIT_SAVE, SUBMIT_PREVIEW,
- SUBMIT_DIFF_SBS, SUBMIT_DIFF_UNIFIED,
- SUBMIT_end /* sentinel for range validation */
- };
- const char * zFilename = PD("file",P("name"));
- /* filename. We'll accept 'name'
+void fileedit_page(void){
+ const char * zFilename = 0; /* filename. We'll accept 'name'
because that param is handled
specially by the core. */
- const char * zRev = P("r"); /* checkin version */
- const char * zContent = P("content"); /* file content */
- const char * zComment = P("comment"); /* checkin comment */
+ const char * zRev = 0; /* checkin version */
const char * zFileMime = 0; /* File mime type guess */
CheckinMiniInfo cimi; /* Checkin state */
- int submitMode = SUBMIT_NONE; /* See mapping below */
- int vid, newVid = 0; /* checkin rid */
- int frid = 0; /* File content rid */
- int previewLn = P("preview_ln")!=0; /* Line number mode */
int previewHtmlHeight = 0; /* iframe height (EMs) */
int previewRenderMode = FE_RENDER_GUESS; /* preview mode */
- char * zFileUuid = 0; /* File content UUID */
Blob err = empty_blob; /* Error report */
- Blob submitResult = empty_blob; /* Error report */
- const char * zFlagCheck = 0; /* Temp url flag holder */
Blob endScript = empty_blob; /* Script code to run at the
end. This content will be
combined into a single JS
function call, thus each
entry must end with a
semicolon. */
Stmt stmt = empty_Stmt;
- const int loadMode = 0; /* See next comment block */
- /* loadMode: How to populate the TEXTAREA:
- **
- ** 0: HTML encode: despite my personal reservations regarding HTML
- ** escaping, this seems to be the only reliable approach
- ** until/unless we completely AJAXify this page.
- **
- ** 1: JSON mode: JSON-izes the file content and injects it, via JS,
- ** into the editor TEXTAREA. This works wonderfully until the input
- ** file contains an raw
+ @
}
/*
** All extra JS files to load.
*/
@@ -1259,10 +1259,11 @@
@ anonymous-adds = %s(find_anon_capabilities(zCap))
}
@ g.zRepositoryName = %h(g.zRepositoryName)
@ load_average() = %f(load_average())
@ cgi_csrf_safe(0) = %d(cgi_csrf_safe(0))
+ @ fossil_exe_id() = %h(fossil_exe_id())
@
P("HTTP_USER_AGENT");
cgi_print_all(showAll, 0);
if( showAll && blob_size(&g.httpHeader)>0 ){
@
@@ -1297,42 +1298,51 @@
#if INTERFACE
# define webpage_assert(T) if(!(T)){webpage_assert_page(__FILE__,__LINE__,#T);}
#endif
/*
-** Outputs a labeled checkbox element. zFieldName is the form element
-** name. zLabel is the label for the checkbox. zValue is the optional
-** value for the checkbox. zTip is an optional tooltip, which gets set
-** as the "title" attribute of the outermost element. If isChecked is
-** true, the checkbox gets the "checked" attribute set, else it is
-** not.
+** Outputs a labeled checkbox element. zWrapperId is an optional ID
+** value for the containing element (see below). zFieldName is the
+** form element name. zLabel is the label for the checkbox. zValue is
+** the optional value for the checkbox. zTip is an optional tooltip,
+** which gets set as the "title" attribute of the outermost
+** element. If isChecked is true, the checkbox gets the "checked"
+** attribute set, else it is not.
**
** Resulting structure:
**
-**
+**
**
** {{zLabel}}
-**
+**
**
-** zFieldName, zLabel, and zValue are required. zTip is optional.
+** zLabel, and zValue are required. zFieldName, zWrapperId, and zTip
+** are may be NULL or empty.
**
** Be sure that the input-with-label CSS class is defined sensibly, in
** particular, having its display:inline-block is useful for alignment
** purposes.
*/
-void style_labeled_checkbox(const char *zFieldName, const char * zLabel,
- const char * zValue, const char * zTip,
- int isChecked){
- CX("
", zLabel);
+ CX("%h", zLabel);
}
/*
** Outputs a SELECT list from a compile-time list of integers.
** The vargs must be a list of (const char *, int) pairs, terminated
@@ -1347,41 +1357,50 @@
**
** Note that the pairs are not in (int, const char *) order because
** there is no well-known integer value which we can definitively use
** as a list terminator.
**
-** zFieldName is the value of the form element's name attribute.
+** zWrapperId is an optional ID value for the containing element (see
+** below).
+**
+** zFieldName is the value of the form element's name attribute. Note
+** that fossil prefers underscores over '-' for separators in form
+** element names.
**
** zLabel is an optional string to use as a "label" for the element
** (see below).
**
** zTooltip is an optional value for the SELECT's title attribute.
**
** The structure of the emitted HTML is:
**
-**
");
if(zLabel && *zLabel){
CX("%h", zLabel);
}
@@ -1401,33 +1420,249 @@
CX("%d",v);
}
CX("\n");
}
CX("\n");
+ CX("\n");
+ va_end(vargs);
+}
+
+/*
+** The C-string counterpart of style_select_list_int(), this variant
+** differs only in that its variadic arguments are C-strings in pairs
+** of (optionLabel, optionValue). If a given optionLabel is an empty
+** string, the corresponding optionValue is used as its label. If any
+** given value matches zSelectedVal, that option gets preselected. If
+** no options match zSelectedVal then the first entry is selected by
+** default.
+**
+** Any of (zWrapperId, zTooltip, zSelectedVal) may be NULL or empty.
+**
+** Example:
+**
+** style_select_list_str("my-grapes", "my_grapes", "Grapes",
+** "Select the number of grapes",
+** P("my_field"),
+** "1", "One", "2", "Two", "", "3",
+** NULL);
+*/
+void style_select_list_str(const char * zWrapperId,
+ const char *zFieldName, const char * zLabel,
+ const char * zToolTip, char const * zSelectedVal,
+ ... ){
+ va_list vargs;
+
+ va_start(vargs,zSelectedVal);
+ if(!zSelectedVal){
+ zSelectedVal = __FILE__/*some string we'll never match*/;
+ }
+ CX("");
if(zLabel && *zLabel){
- CX("
\n");
+ CX("%h", zLabel);
+ }
+ CX("\n");
+ CX("\n");
va_end(vargs);
}
/*
-** If passed 0, it emits a script opener tag with this session's
-** nonce. If passed non-0 it emits a script closing tag. The very
-** first time it is called, it emits some bootstrapping JS code
-** immediately after the script opener. Specifically, it defines
-** window.fossil if it's not already defined, and may set some
-** properties on it.
+** The first time this is called, it emits code to install and
+** bootstrap the window.fossil object, using the built-in file
+** fossil.bootstrap.js (not to be confused with bootstrap.js).
+**
+** Subsequent calls are no-ops.
+**
+** If passed a true value, it emits the contents directly to the page
+** output, else it emits a script tag with a src=builtin/... to load
+** the script. It always outputs a small pre-bootstrap element in its
+** own script tag to initialize parts which need C-runtime-level
+** information, before loading the main fossil.bootstrap.js either
+** inline or via a
+**
+** zSrc is always assumed to be a repository-relative path without
+** a leading slash, and has %R/ prepended to it.
+**
+** Meaning that no follow-up call to pass a non-0 first argument
+** to close the tag. zSrc is ignored if the first argument is not
+** 0.
+**
+*/
+void style_emit_script_tag(int isCloser, const char * zSrc){
+ if(0==isCloser){
+ if(zSrc!=0 && zSrc[0]!=0){
+ CX("\n", zSrc);
+ }else{
+ CX("\n");
}
}
+
+/*
+** Emits a script tag which uses content from a builtin script file.
+**
+** If asInline is true, it is emitted directly as an opening tag, the
+** content of the zName builtin file, and a closing tag.
+**
+** If it is false, a script tag loading it via
+** src=builtin/{{zName}}?cache=XYZ is emitted, where XYZ is a
+** build-time-dependent cache-buster value.
+*/
+void style_emit_script_builtin(int asInline, char const * zName){
+ if(asInline){
+ style_emit_script_tag(0,0);
+ CX("%s", builtin_text(zName));
+ style_emit_script_tag(1,0);
+ }else{
+ char * zFullName = mprintf("builtin/%s",zName);
+ const char * zHash = fossil_exe_id();
+ CX("\n",
+ zFullName, zHash);
+ fossil_free(zFullName);
+ }
+}
+
+/*
+** The first time this is called it emits the JS code from the
+** built-in file fossil.fossil.js. Subsequent calls are no-ops.
+**
+** If passed a true value, it emits the contents directly
+** to the page output, else it emits a script tag with a
+** src=builtin/... to load the script.
+**
+** Note that this code relies on that loaded via
+** style_emit_script_fossil_bootstrap() but it does not call that
+** routine.
+*/
+void style_emit_script_fetch(int asInline){
+ static int once = 0;
+ if(0==once++){
+ style_emit_script_builtin(asInline, "fossil.fetch.js");
+ }
+}
+
+/*
+** The first time this is called it emits the JS code from the
+** built-in file fossil.dom.js. Subsequent calls are no-ops.
+**
+** If passed a true value, it emits the contents directly
+** to the page output, else it emits a script tag with a
+** src=builtin/... to load the script.
+**
+** Note that this code relies on that loaded via
+** style_emit_script_fossil_bootstrap(), but it does not call that
+** routine.
+*/
+void style_emit_script_dom(int asInline){
+ static int once = 0;
+ if(0==once++){
+ style_emit_script_builtin(asInline, "fossil.dom.js");
+ }
+}
+
+/*
+** The first time this is called, it calls style_emit_script_dom(),
+** passing it the given asInline value, and emits the JS code from the
+** built-in file fossil.tabs.js. Subsequent calls are no-ops.
+**
+** If passed a true value, it emits the contents directly
+** to the page output, else it emits a script tag with a
+** src=builtin/... to load the script.
+*/
+void style_emit_script_tabs(int asInline){
+ static int once = 0;
+ if(0==once++){
+ style_emit_script_dom(asInline);
+ style_emit_script_builtin(asInline, "fossil.tabs.js");
+ }
+}
+
+/*
+** The first time this is called it emits the JS code from the
+** built-in file fossil.confirmer.js. Subsequent calls are no-ops.
+**
+** If passed a true value, it emits the contents directly
+** to the page output, else it emits a script tag with a
+** src=builtin/... to load the script.
+*/
+void style_emit_script_confirmer(int asInline){
+ static int once = 0;
+ if(0==once++){
+ style_emit_script_builtin(asInline, "fossil.confirmer.js");
+ }
+}
ADDED src/terminal.c
Index: src/terminal.c
==================================================================
--- /dev/null
+++ src/terminal.c
@@ -0,0 +1,130 @@
+/*
+** Copyright (c) 2020 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 contains code used to query terminal info
+*/
+
+#include "config.h"
+#include "terminal.h"
+#include
+#ifdef _WIN32
+# include
+#else
+#include
+#include
+#include
+#endif
+
+
+
+#if INTERFACE
+/*
+** Terminal size defined in terms of columns and lines.
+*/
+struct TerminalSize {
+ unsigned int nColumns; /* Number of characters on a single line */
+ unsigned int nLines; /* Number of lines */
+};
+#endif
+
+
+/* Get the current terminal size by calling a system service.
+**
+** Return 1 on success. This sets the size parameters to the values retured by
+** the system call, when such is supported; set the size to zero otherwise.
+** Return 0 on the system service call failure.
+**
+** Under Linux/bash the size info is also available from env $LINES, $COLUMNS.
+** Or it can be queried using tput `echo -e "lines\ncols"|tput -S`.
+** Technically, this info could be cached, but then we'd need to handle
+** SIGWINCH signal to requery the terminal on resize event.
+*/
+int terminal_get_size(TerminalSize *t){
+ memset(t, 0, sizeof(*t));
+
+#if defined(TIOCGSIZE)
+ {
+ struct ttysize ts;
+ if( ioctl(STDIN_FILENO, TIOCGSIZE, &ts)!=-1 ){
+ t->nColumns = ts.ts_cols;
+ t->nLines = ts.ts_lines;
+ return 1;
+ }
+ return 0;
+ }
+#elif defined(TIOCGWINSZ)
+ {
+ struct winsize ws;
+ if( ioctl(STDIN_FILENO, TIOCGWINSZ, &ws)!=-1 ){
+ t->nColumns = ws.ws_col;
+ t->nLines = ws.ws_row;
+ return 1;
+ }
+ return 0;
+ }
+#elif defined(_WIN32)
+ {
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+ if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) ){
+ t->nColumns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
+ t->nLines = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
+ return 1;
+ }
+ return 0;
+ }
+#else
+ return 1;
+#endif
+}
+
+/*
+** Return the terminal's current width in columns when available, otherwise
+** return the specified default value.
+*/
+unsigned int terminal_get_width(unsigned int nDefault){
+ TerminalSize ts;
+ if( terminal_get_size(&ts) ){
+ return ts.nColumns;
+ }
+ return nDefault;
+}
+
+/*
+** Return the terminal's current height in lines when available, otherwise
+** return the specified default value.
+*/
+unsigned int terminal_get_height(unsigned int nDefault){
+ TerminalSize ts;
+ if( terminal_get_size(&ts) ){
+ return ts.nLines;
+ }
+ return nDefault;
+}
+
+/*
+** COMMAND: test-terminal-size
+**
+** Show the size of the terminal window from which the command is launched
+** as two integers, the width in charaters and the height in lines.
+**
+** If the size cannot be determined, two zeros are shown.
+*/
+void test_terminal_size_cmd(void){
+ TerminalSize ts;
+ terminal_get_size(&ts);
+ fossil_print("%d %d\n", ts.nColumns, ts.nLines);
+}
Index: src/timeline.c
==================================================================
--- src/timeline.c
+++ src/timeline.c
@@ -1312,11 +1312,11 @@
){
if( zChng==0 || zChng[0]==0 ) return;
blob_append_sql(pSql," AND event.objid IN ("
"SELECT mlink.mid FROM mlink, filename"
" WHERE mlink.fnid=filename.fnid AND %s)",
- glob_expr("filename.name", zChng));
+ glob_expr("filename.name", mprintf("\"%s\"", zChng)));
}
static void addFileGlobDescription(
const char *zChng, /* The filename GLOB list */
Blob *pDescription /* Result description */
){
@@ -1742,10 +1742,11 @@
|| (bisectLocal && !g.perm.Setup)
){
login_needed(g.anon.Read && g.anon.RdTkt && g.anon.RdWiki);
return;
}
+ etag_check(ETAG_QUERY|ETAG_COOKIE|ETAG_DATA, 0);
cookie_read_parameter("y","y");
zType = P("y");
if( zType==0 ){
zType = g.perm.Read ? "ci" : "all";
cgi_set_parameter("y", zType);
Index: src/unversioned.c
==================================================================
--- src/unversioned.c
+++ src/unversioned.c
@@ -524,10 +524,11 @@
int showDel = 0;
char zSzName[100];
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
+ etag_check(ETAG_DATA,0);
style_header("Unversioned Files");
if( !db_table_exists("repository","unversioned") ){
@ No unversioned files on this server
style_footer();
return;
@@ -636,10 +637,11 @@
Blob json;
login_check_credentials();
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
cgi_set_content_type("text/json");
+ etag_check(ETAG_DATA,0);
if( !db_table_exists("repository","unversioned") ){
blob_init(&json, "[]", -1);
cgi_set_content(&json);
return;
}
Index: src/url.c
==================================================================
--- src/url.c
+++ src/url.c
@@ -377,13 +377,15 @@
*/
void url_proxy_options(void){
zProxyOpt = find_option("proxy", 0, 1);
if( find_option("nosync",0,0) ) g.fNoSync = 1;
if( find_option("ipv4",0,0) ) g.fIPv4 = 1;
+#ifdef FOSSIL_ENABLE_SSL
if( find_option("accept-any-cert",0,0) ){
ssl_disable_cert_verification();
}
+#endif /* FOSSIL_ENABLE_SSL */
}
/*
** If the "proxy" setting is defined, then change the URL settings
** (initialized by a prior call to url_parse()) so that the HTTP
ADDED test/subdir with spaces/filename with spaces.txt
Index: test/subdir with spaces/filename with spaces.txt
==================================================================
--- /dev/null
+++ test/subdir with spaces/filename with spaces.txt
@@ -0,0 +1,2 @@
+This file has a name that contains spaces. It is used to help verify
+that fossil can handle filenames that contain spaces.
ADDED tools/fossil-diff-log
Index: tools/fossil-diff-log
==================================================================
--- /dev/null
+++ tools/fossil-diff-log
@@ -0,0 +1,72 @@
+#!/usr/bin/env perl
+# Fossil emulation of the "git log --patch / -p" feature: emit a stream
+# of diffs from one version to the next for each file named on the
+# command line.
+#
+# LIMITATIONS: It does not assume "all files" if you give no args, and
+# it cannot take a directory to mean "all files under this parent".
+#
+# PREREQUISITES: This script needs several CPAN modules to run properly.
+# There are multiple methods to install them:
+#
+# sudo dnf install perl-File-Which perl-IO-Interactive
+# sudo apt install libfile-which-perl libio-interactive-perl
+# sudo cpanm File::Which IO::Interactive
+# ...etc...
+
+use strict;
+use warnings;
+
+use Carp;
+use File::Which;
+use IO::Interactive qw(is_interactive);
+
+die "usage: $0 \n\n" unless @ARGV;
+
+my $out;
+if (is_interactive()) {
+ my $pager = $ENV{PAGER} || which('less') || which('more');
+ open $out, '|-', $pager or croak "Cannot pipe to $pager: $!";
+}
+else {
+ $out = *STDOUT;
+}
+
+open my $bcmd, '-|', 'fossil branch current'
+ or die "Cannot get branch: $!\n";
+my $cbranch = <$bcmd>;
+chomp $cbranch;
+close $bcmd;
+
+for my $file (@ARGV) {
+ my $lastckid;
+ open my $finfo, '-|', "fossil finfo --brief --limit 0 '$file'"
+ or die "Failed to get file info: $!\n";
+ my @filines = <$finfo>;
+ close $finfo;
+
+ for my $line (@filines) {
+ my ($currckid, $date, $user, $branch, @cwords) = split ' ', $line;
+ next unless $branch eq $cbranch;
+ if (defined $lastckid and defined $branch) {
+ my $comment = join ' ', @cwords;
+ open my $diff, '-|', 'fossil', 'diff', $file,
+ '--from', $currckid,
+ '--to', $lastckid,
+ or die "Failed to diff $currckid -> $lastckid: $!\n";
+ my @dl = <$diff>;
+ close $diff;
+ my $patch = join '', @dl;
+
+ print $out <<"OUT"
+Checkin ID $currckid to $branch by $user on $date
+Comment: $comment
+
+$patch
+
+OUT
+ }
+
+ $lastckid = $currckid;
+ }
+}
Index: win/Makefile.dmc
==================================================================
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -28,13 +28,13 @@
SQLITE_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0
SHELL_OPTIONS = -DNDEBUG=1 -DSQLITE_DQS=0 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1 -DSQLITE_LIKE_DOESNT_MATCH_BLOBS -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_GET_TABLE -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_MAX_EXPR_DEPTH=0 -DSQLITE_USE_ALLOCA -DSQLITE_ENABLE_LOCKING_STYLE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_EXPLAIN_COMMENTS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_DBSTAT_VTAB -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_STMTVTAB -DSQLITE_HAVE_ZLIB -DSQLITE_INTROSPECTION_PRAGMAS -DSQLITE_ENABLE_DBPAGE_VTAB -DSQLITE_TRUSTED_SCHEMA=0 -Dmain=sqlite3_shell -DSQLITE_SHELL_IS_UTF8=1 -DSQLITE_OMIT_LOAD_EXTENSION=1 -DUSE_SYSTEM_SQLITE=$(USE_SYSTEM_SQLITE) -DSQLITE_SHELL_DBNAME_PROC=sqlcmd_get_dbname -DSQLITE_SHELL_INIT_PROC=sqlcmd_init_proc -Daccess=file_access -Dsystem=fossil_system -Dgetenv=fossil_getenv -Dfopen=fossil_fopen
-SRC = add_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
+SRC = add_.c alerts_.c allrepo_.c attach_.c backlink_.c backoffice_.c bag_.c bisect_.c blob_.c branch_.c browse_.c builtin_.c bundle_.c cache_.c capabilities_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c cookies_.c db_.c delta_.c deltacmd_.c deltafunc_.c descendants_.c diff_.c diffcmd_.c dispatch_.c doc_.c encode_.c etag_.c event_.c export_.c extcgi_.c file_.c fileedit_.c finfo_.c foci_.c forum_.c fshell_.c fusefs_.c fuzz_.c glob_.c graph_.c gzip_.c hname_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c json_.c json_artifact_.c json_branch_.c json_config_.c json_diff_.c json_dir_.c json_finfo_.c json_login_.c json_query_.c json_report_.c json_status_.c json_tag_.c json_timeline_.c json_user_.c json_wiki_.c leaf_.c loadctrl_.c login_.c lookslike_.c main_.c manifest_.c markdown_.c markdown_html_.c md5_.c merge_.c merge3_.c moderate_.c name_.c path_.c piechart_.c pivot_.c popen_.c pqueue_.c printf_.c publish_.c purge_.c rebuild_.c regexp_.c repolist_.c report_.c rss_.c schema_.c search_.c security_audit_.c setup_.c setupuser_.c sha1_.c sha1hard_.c sha3_.c shun_.c sitemap_.c skins_.c smtp_.c sqlcmd_.c stash_.c stat_.c statrep_.c style_.c sync_.c tag_.c tar_.c terminal_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c unicode_.c unversioned_.c update_.c url_.c user_.c utf8_.c util_.c verify_.c vfile_.c webmail_.c wiki_.c wikiformat_.c winfile_.c winhttp_.c wysiwyg_.c xfer_.c xfersetup_.c zip_.c
-OBJ = $(OBJDIR)\add$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
+OBJ = $(OBJDIR)\add$O $(OBJDIR)\alerts$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\backlink$O $(OBJDIR)\backoffice$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\builtin$O $(OBJDIR)\bundle$O $(OBJDIR)\cache$O $(OBJDIR)\capabilities$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\cookies$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\deltafunc$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\dispatch$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\etag$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\extcgi$O $(OBJDIR)\file$O $(OBJDIR)\fileedit$O $(OBJDIR)\finfo$O $(OBJDIR)\foci$O $(OBJDIR)\forum$O $(OBJDIR)\fshell$O $(OBJDIR)\fusefs$O $(OBJDIR)\fuzz$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\hname$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\json$O $(OBJDIR)\json_artifact$O $(OBJDIR)\json_branch$O $(OBJDIR)\json_config$O $(OBJDIR)\json_diff$O $(OBJDIR)\json_dir$O $(OBJDIR)\json_finfo$O $(OBJDIR)\json_login$O $(OBJDIR)\json_query$O $(OBJDIR)\json_report$O $(OBJDIR)\json_status$O $(OBJDIR)\json_tag$O $(OBJDIR)\json_timeline$O $(OBJDIR)\json_user$O $(OBJDIR)\json_wiki$O $(OBJDIR)\leaf$O $(OBJDIR)\loadctrl$O $(OBJDIR)\login$O $(OBJDIR)\lookslike$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\markdown$O $(OBJDIR)\markdown_html$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\moderate$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\piechart$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\publish$O $(OBJDIR)\purge$O $(OBJDIR)\rebuild$O $(OBJDIR)\regexp$O $(OBJDIR)\repolist$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\security_audit$O $(OBJDIR)\setup$O $(OBJDIR)\setupuser$O $(OBJDIR)\sha1$O $(OBJDIR)\sha1hard$O $(OBJDIR)\sha3$O $(OBJDIR)\shun$O $(OBJDIR)\sitemap$O $(OBJDIR)\skins$O $(OBJDIR)\smtp$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$O $(OBJDIR)\statrep$O $(OBJDIR)\style$O $(OBJDIR)\sync$O $(OBJDIR)\tag$O $(OBJDIR)\tar$O $(OBJDIR)\terminal$O $(OBJDIR)\th_main$O $(OBJDIR)\timeline$O $(OBJDIR)\tkt$O $(OBJDIR)\tktsetup$O $(OBJDIR)\undo$O $(OBJDIR)\unicode$O $(OBJDIR)\unversioned$O $(OBJDIR)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\utf8$O $(OBJDIR)\util$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\webmail$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winfile$O $(OBJDIR)\winhttp$O $(OBJDIR)\wysiwyg$O $(OBJDIR)\xfer$O $(OBJDIR)\xfersetup$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O
RC=$(DMDIR)\bin\rcc
RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__
@@ -49,11 +49,11 @@
$(OBJDIR)\fossil.res: $B\win\fossil.rc
$(RC) $(RCFLAGS) -o$@ $**
$(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res
- +echo add alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
+ +echo add alerts allrepo attach backlink backoffice bag bisect blob branch browse builtin bundle cache capabilities captcha cgi checkin checkout clearsign clone comformat configure content cookies db delta deltacmd deltafunc descendants diff diffcmd dispatch doc encode etag event export extcgi file fileedit finfo foci forum fshell fusefs fuzz glob graph gzip hname http http_socket http_ssl http_transport import info json json_artifact json_branch json_config json_diff json_dir json_finfo json_login json_query json_report json_status json_tag json_timeline json_user json_wiki leaf loadctrl login lookslike main manifest markdown markdown_html md5 merge merge3 moderate name path piechart pivot popen pqueue printf publish purge rebuild regexp repolist report rss schema search security_audit setup setupuser sha1 sha1hard sha3 shun sitemap skins smtp sqlcmd stash stat statrep style sync tag tar terminal th_main timeline tkt tktsetup undo unicode unversioned update url user utf8 util verify vfile webmail wiki wikiformat winfile winhttp wysiwyg xfer xfersetup zip shell sqlite3 th th_lang > $@
+echo fossil >> $@
+echo fossil >> $@
+echo $(LIBS) >> $@
+echo. >> $@
+echo fossil >> $@
@@ -836,10 +836,16 @@
$(OBJDIR)\tar$O : tar_.c tar.h
$(TCC) -o$@ -c tar_.c
tar_.c : $(SRCDIR)\tar.c
+translate$E $** > $@
+
+$(OBJDIR)\terminal$O : terminal_.c terminal.h
+ $(TCC) -o$@ -c terminal_.c
+
+terminal_.c : $(SRCDIR)\terminal.c
+ +translate$E $** > $@
$(OBJDIR)\th_main$O : th_main_.c th_main.h
$(TCC) -o$@ -c th_main_.c
th_main_.c : $(SRCDIR)\th_main.c
@@ -976,7 +982,7 @@
zip_.c : $(SRCDIR)\zip.c
+translate$E $** > $@
headers: makeheaders$E page_index.h builtin_data.h default_css.h VERSION.h
- +makeheaders$E add_.c:add.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
+ +makeheaders$E add_.c:add.h alerts_.c:alerts.h allrepo_.c:allrepo.h attach_.c:attach.h backlink_.c:backlink.h backoffice_.c:backoffice.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h builtin_.c:builtin.h bundle_.c:bundle.h cache_.c:cache.h capabilities_.c:capabilities.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h cookies_.c:cookies.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h deltafunc_.c:deltafunc.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h dispatch_.c:dispatch.h doc_.c:doc.h encode_.c:encode.h etag_.c:etag.h event_.c:event.h export_.c:export.h extcgi_.c:extcgi.h file_.c:file.h fileedit_.c:fileedit.h finfo_.c:finfo.h foci_.c:foci.h forum_.c:forum.h fshell_.c:fshell.h fusefs_.c:fusefs.h fuzz_.c:fuzz.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h hname_.c:hname.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_config_.c:json_config.h json_diff_.c:json_diff.h json_dir_.c:json_dir.h json_finfo_.c:json_finfo.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_status_.c:json_status.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h loadctrl_.c:loadctrl.h login_.c:login.h lookslike_.c:lookslike.h main_.c:main.h manifest_.c:manifest.h markdown_.c:markdown.h markdown_html_.c:markdown_html.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h moderate_.c:moderate.h name_.c:name.h path_.c:path.h piechart_.c:piechart.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h publish_.c:publish.h purge_.c:purge.h rebuild_.c:rebuild.h regexp_.c:regexp.h repolist_.c:repolist.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h security_audit_.c:security_audit.h setup_.c:setup.h setupuser_.c:setupuser.h sha1_.c:sha1.h sha1hard_.c:sha1hard.h sha3_.c:sha3.h shun_.c:shun.h sitemap_.c:sitemap.h skins_.c:skins.h smtp_.c:smtp.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h statrep_.c:statrep.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h terminal_.c:terminal.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h unicode_.c:unicode.h unversioned_.c:unversioned.h update_.c:update.h url_.c:url.h user_.c:user.h utf8_.c:utf8.h util_.c:util.h verify_.c:verify.h vfile_.c:vfile.h webmail_.c:webmail.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winfile_.c:winfile.h winhttp_.c:winhttp.h wysiwyg_.c:wysiwyg.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
@copy /Y nul: headers
Index: win/Makefile.mingw
==================================================================
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -554,10 +554,11 @@
$(SRCDIR)/statrep.c \
$(SRCDIR)/style.c \
$(SRCDIR)/sync.c \
$(SRCDIR)/tag.c \
$(SRCDIR)/tar.c \
+ $(SRCDIR)/terminal.c \
$(SRCDIR)/th_main.c \
$(SRCDIR)/timeline.c \
$(SRCDIR)/tkt.c \
$(SRCDIR)/tktsetup.c \
$(SRCDIR)/undo.c \
@@ -640,10 +641,16 @@
$(SRCDIR)/accordion.js \
$(SRCDIR)/ci_edit.js \
$(SRCDIR)/copybtn.js \
$(SRCDIR)/diff.tcl \
$(SRCDIR)/forum.js \
+ $(SRCDIR)/fossil.bootstrap.js \
+ $(SRCDIR)/fossil.confirmer.js \
+ $(SRCDIR)/fossil.dom.js \
+ $(SRCDIR)/fossil.fetch.js \
+ $(SRCDIR)/fossil.page.fileedit.js \
+ $(SRCDIR)/fossil.tabs.js \
$(SRCDIR)/graph.js \
$(SRCDIR)/href.js \
$(SRCDIR)/login.js \
$(SRCDIR)/markdown.md \
$(SRCDIR)/menu.js \
@@ -788,10 +795,11 @@
$(OBJDIR)/statrep_.c \
$(OBJDIR)/style_.c \
$(OBJDIR)/sync_.c \
$(OBJDIR)/tag_.c \
$(OBJDIR)/tar_.c \
+ $(OBJDIR)/terminal_.c \
$(OBJDIR)/th_main_.c \
$(OBJDIR)/timeline_.c \
$(OBJDIR)/tkt_.c \
$(OBJDIR)/tktsetup_.c \
$(OBJDIR)/undo_.c \
@@ -931,10 +939,11 @@
$(OBJDIR)/statrep.o \
$(OBJDIR)/style.o \
$(OBJDIR)/sync.o \
$(OBJDIR)/tag.o \
$(OBJDIR)/tar.o \
+ $(OBJDIR)/terminal.o \
$(OBJDIR)/th_main.o \
$(OBJDIR)/timeline.o \
$(OBJDIR)/tkt.o \
$(OBJDIR)/tktsetup.o \
$(OBJDIR)/undo.o \
@@ -1294,10 +1303,11 @@
$(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \
$(OBJDIR)/style_.c:$(OBJDIR)/style.h \
$(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
$(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
$(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
+ $(OBJDIR)/terminal_.c:$(OBJDIR)/terminal.h \
$(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
$(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \
$(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \
$(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \
$(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \
@@ -2269,10 +2279,18 @@
$(OBJDIR)/tar.o: $(OBJDIR)/tar_.c $(OBJDIR)/tar.h $(SRCDIR)/config.h
$(XTCC) -o $(OBJDIR)/tar.o -c $(OBJDIR)/tar_.c
$(OBJDIR)/tar.h: $(OBJDIR)/headers
+
+$(OBJDIR)/terminal_.c: $(SRCDIR)/terminal.c $(TRANSLATE)
+ $(TRANSLATE) $(SRCDIR)/terminal.c >$@
+
+$(OBJDIR)/terminal.o: $(OBJDIR)/terminal_.c $(OBJDIR)/terminal.h $(SRCDIR)/config.h
+ $(XTCC) -o $(OBJDIR)/terminal.o -c $(OBJDIR)/terminal_.c
+
+$(OBJDIR)/terminal.h: $(OBJDIR)/headers
$(OBJDIR)/th_main_.c: $(SRCDIR)/th_main.c $(TRANSLATE)
$(TRANSLATE) $(SRCDIR)/th_main.c >$@
$(OBJDIR)/th_main.o: $(OBJDIR)/th_main_.c $(OBJDIR)/th_main.h $(SRCDIR)/config.h
Index: win/Makefile.mingw.mistachkin
==================================================================
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -553,10 +553,11 @@
$(SRCDIR)/statrep.c \
$(SRCDIR)/style.c \
$(SRCDIR)/sync.c \
$(SRCDIR)/tag.c \
$(SRCDIR)/tar.c \
+ $(SRCDIR)/terminal.c \
$(SRCDIR)/th_main.c \
$(SRCDIR)/timeline.c \
$(SRCDIR)/tkt.c \
$(SRCDIR)/tktsetup.c \
$(SRCDIR)/undo.c \
@@ -786,10 +787,11 @@
$(OBJDIR)/statrep_.c \
$(OBJDIR)/style_.c \
$(OBJDIR)/sync_.c \
$(OBJDIR)/tag_.c \
$(OBJDIR)/tar_.c \
+ $(OBJDIR)/terminal_.c \
$(OBJDIR)/th_main_.c \
$(OBJDIR)/timeline_.c \
$(OBJDIR)/tkt_.c \
$(OBJDIR)/tktsetup_.c \
$(OBJDIR)/undo_.c \
@@ -928,10 +930,11 @@
$(OBJDIR)/statrep.o \
$(OBJDIR)/style.o \
$(OBJDIR)/sync.o \
$(OBJDIR)/tag.o \
$(OBJDIR)/tar.o \
+ $(OBJDIR)/terminal.o \
$(OBJDIR)/th_main.o \
$(OBJDIR)/timeline.o \
$(OBJDIR)/tkt.o \
$(OBJDIR)/tktsetup.o \
$(OBJDIR)/undo.o \
@@ -1290,10 +1293,11 @@
$(OBJDIR)/statrep_.c:$(OBJDIR)/statrep.h \
$(OBJDIR)/style_.c:$(OBJDIR)/style.h \
$(OBJDIR)/sync_.c:$(OBJDIR)/sync.h \
$(OBJDIR)/tag_.c:$(OBJDIR)/tag.h \
$(OBJDIR)/tar_.c:$(OBJDIR)/tar.h \
+ $(OBJDIR)/terminal_.c:$(OBJDIR)/terminal.h \
$(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h \
$(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h \
$(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h \
$(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h \
$(OBJDIR)/undo_.c:$(OBJDIR)/undo.h \
@@ -2257,10 +2261,18 @@
$(OBJDIR)/tar.o: $(OBJDIR)/tar_.c $(OBJDIR)/tar.h $(SRCDIR)/config.h
$(XTCC) -o $(OBJDIR)/tar.o -c $(OBJDIR)/tar_.c
$(OBJDIR)/tar.h: $(OBJDIR)/headers
+
+$(OBJDIR)/terminal_.c: $(SRCDIR)/terminal.c $(TRANSLATE)
+ $(TRANSLATE) $(SRCDIR)/terminal.c >$@
+
+$(OBJDIR)/terminal.o: $(OBJDIR)/terminal_.c $(OBJDIR)/terminal.h $(SRCDIR)/config.h
+ $(XTCC) -o $(OBJDIR)/terminal.o -c $(OBJDIR)/terminal_.c
+
+$(OBJDIR)/terminal.h: $(OBJDIR)/headers
$(OBJDIR)/th_main_.c: $(SRCDIR)/th_main.c $(TRANSLATE)
$(TRANSLATE) $(SRCDIR)/th_main.c >$@
$(OBJDIR)/th_main.o: $(OBJDIR)/th_main_.c $(OBJDIR)/th_main.h $(SRCDIR)/config.h
Index: win/Makefile.msc
==================================================================
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -462,10 +462,11 @@
statrep_.c \
style_.c \
sync_.c \
tag_.c \
tar_.c \
+ terminal_.c \
th_main_.c \
timeline_.c \
tkt_.c \
tktsetup_.c \
undo_.c \
@@ -547,10 +548,16 @@
$(SRCDIR)\accordion.js \
$(SRCDIR)\ci_edit.js \
$(SRCDIR)\copybtn.js \
$(SRCDIR)\diff.tcl \
$(SRCDIR)\forum.js \
+ $(SRCDIR)\fossil.bootstrap.js \
+ $(SRCDIR)\fossil.confirmer.js \
+ $(SRCDIR)\fossil.dom.js \
+ $(SRCDIR)\fossil.fetch.js \
+ $(SRCDIR)\fossil.page.fileedit.js \
+ $(SRCDIR)\fossil.tabs.js \
$(SRCDIR)\graph.js \
$(SRCDIR)\href.js \
$(SRCDIR)\login.js \
$(SRCDIR)\markdown.md \
$(SRCDIR)\menu.js \
@@ -697,10 +704,11 @@
$(OX)\statrep$O \
$(OX)\style$O \
$(OX)\sync$O \
$(OX)\tag$O \
$(OX)\tar$O \
+ $(OX)\terminal$O \
$(OX)\th$O \
$(OX)\th_lang$O \
$(OX)\th_main$O \
$(OX)\th_tcl$O \
$(OX)\timeline$O \
@@ -902,10 +910,11 @@
echo $(OX)\statrep.obj >> $@
echo $(OX)\style.obj >> $@
echo $(OX)\sync.obj >> $@
echo $(OX)\tag.obj >> $@
echo $(OX)\tar.obj >> $@
+ echo $(OX)\terminal.obj >> $@
echo $(OX)\th.obj >> $@
echo $(OX)\th_lang.obj >> $@
echo $(OX)\th_main.obj >> $@
echo $(OX)\th_tcl.obj >> $@
echo $(OX)\timeline.obj >> $@
@@ -1753,10 +1762,16 @@
$(OX)\tar$O : tar_.c tar.h
$(TCC) /Fo$@ -c tar_.c
tar_.c : $(SRCDIR)\tar.c
translate$E $** > $@
+
+$(OX)\terminal$O : terminal_.c terminal.h
+ $(TCC) /Fo$@ -c terminal_.c
+
+terminal_.c : $(SRCDIR)\terminal.c
+ translate$E $** > $@
$(OX)\th_main$O : th_main_.c th_main.h
$(TCC) /Fo$@ -c th_main_.c
th_main_.c : $(SRCDIR)\th_main.c
@@ -2014,10 +2029,11 @@
statrep_.c:statrep.h \
style_.c:style.h \
sync_.c:sync.h \
tag_.c:tag.h \
tar_.c:tar.h \
+ terminal_.c:terminal.h \
th_main_.c:th_main.h \
timeline_.c:timeline.h \
tkt_.c:tkt.h \
tktsetup_.c:tktsetup.h \
undo_.c:undo.h \
Index: www/changes.wiki
==================================================================
--- www/changes.wiki
+++ www/changes.wiki
@@ -55,10 +55,12 @@
* Security: Fossil now puts the Content-Security-Policy in the
HTTP reply header, in addition to also leaving it in the
HTML <head> section, so that it is always available, even
if a custom skin overrides the HTML <head> and omits
the CSP in the process.
+ * Output of the [/help?cmd=diff|fossil diff -y] command automatically
+ adjusts according to the terminal width.
* The Content-Security-Policy is now set using the
[/help?cmd=default-csp|default-csp setting].
* Merge conflicts caused via the [/help?cmd=merge|merge] and
[/help?cmd=update|update] commands no longer leave temporary
files behind unless the new --keep-merge-files flag