Fossil

Artifact [e9fe5da3]
Login

Artifact e9fe5da3fabb21398774c195f20192962b0856fc1f367ccac680b5cfef0f18e7:


     1  /*
     2  ** Copyright (c) 2007 D. Richard Hipp
     3  **
     4  ** This program is free software; you can redistribute it and/or
     5  ** modify it under the terms of the Simplified BSD License (also
     6  ** known as the "2-Clause License" or "FreeBSD License".)
     7  **
     8  ** This program is distributed in the hope that it will be useful,
     9  ** but without any warranty; without even the implied warranty of
    10  ** merchantability or fitness for a particular purpose.
    11  **
    12  ** Author contact information:
    13  **   drh@hwaci.com
    14  **   http://www.hwaci.com/drh/
    15  **
    16  *******************************************************************************
    17  **
    18  ** This file contains code used to format and print comments or other
    19  ** text on a TTY.
    20  */
    21  #include "config.h"
    22  #include "comformat.h"
    23  #include <assert.h>
    24  #ifdef _WIN32
    25  # include <windows.h>
    26  #else
    27  # include <termios.h>
    28  # include <sys/ioctl.h>
    29  #endif
    30  
    31  #if INTERFACE
    32  #define COMMENT_PRINT_NONE       ((u32)0x00000000) /* No flags = non-legacy. */
    33  #define COMMENT_PRINT_LEGACY     ((u32)0x00000001) /* Use legacy algorithm. */
    34  #define COMMENT_PRINT_TRIM_CRLF  ((u32)0x00000002) /* Trim leading CR/LF. */
    35  #define COMMENT_PRINT_TRIM_SPACE ((u32)0x00000004) /* Trim leading/trailing. */
    36  #define COMMENT_PRINT_WORD_BREAK ((u32)0x00000008) /* Break lines on words. */
    37  #define COMMENT_PRINT_ORIG_BREAK ((u32)0x00000010) /* Break before original. */
    38  #define COMMENT_PRINT_DEFAULT    (COMMENT_PRINT_LEGACY) /* Defaults. */
    39  #define COMMENT_PRINT_UNSET      (-1)              /* Not initialized. */
    40  #endif
    41  
    42  /*
    43  ** This is the previous value used by most external callers when they
    44  ** needed to specify a default maximum line length to be used with the
    45  ** comment_print() function.
    46  */
    47  #ifndef COMMENT_LEGACY_LINE_LENGTH
    48  # define COMMENT_LEGACY_LINE_LENGTH    (78)
    49  #endif
    50  
    51  /*
    52  ** This is the number of spaces to print when a tab character is seen.
    53  */
    54  #ifndef COMMENT_TAB_WIDTH
    55  # define COMMENT_TAB_WIDTH             (8)
    56  #endif
    57  
    58  /*
    59  ** This function sets the maximum number of characters to print per line
    60  ** based on the detected terminal line width, if available; otherwise, it
    61  ** uses the legacy default terminal line width minus the amount to indent.
    62  **
    63  ** Zero is returned to indicate any failure.  One is returned to indicate
    64  ** the successful detection of the terminal line width.  Negative one is
    65  ** returned to indicate the terminal line width is using the hard-coded
    66  ** legacy default value.
    67  */
    68  static int comment_set_maxchars(
    69    int indent,
    70    int *pMaxChars
    71  ){
    72  #if defined(_WIN32)
    73    CONSOLE_SCREEN_BUFFER_INFO csbi;
    74    memset(&csbi, 0, sizeof(CONSOLE_SCREEN_BUFFER_INFO));
    75    if( GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi) ){
    76      *pMaxChars = csbi.srWindow.Right - csbi.srWindow.Left - indent;
    77      return 1;
    78    }
    79    return 0;
    80  #elif defined(TIOCGWINSZ)
    81    struct winsize w;
    82    memset(&w, 0, sizeof(struct winsize));
    83    if( ioctl(0, TIOCGWINSZ, &w)!=-1 ){
    84      *pMaxChars = w.ws_col - indent;
    85      return 1;
    86    }
    87    return 0;
    88  #else
    89    /*
    90    ** Fallback to using more-or-less the "legacy semantics" of hard-coding
    91    ** the maximum line length to a value reasonable for the vast majority
    92    ** of supported systems.
    93    */
    94    *pMaxChars = COMMENT_LEGACY_LINE_LENGTH - indent;
    95    return -1;
    96  #endif
    97  }
    98  
    99  /*
   100  ** This function checks the current line being printed against the original
   101  ** comment text.  Upon matching, it updates the provided character and line
   102  ** counts, if applicable.  The caller needs to emit a new line, if desired.
   103  */
   104  static int comment_check_orig(
   105    const char *zOrigText, /* [in] Original comment text ONLY, may be NULL. */
   106    const char *zLine,     /* [in] The comment line to print. */
   107    int *pCharCnt,         /* [in/out] Pointer to the line character count. */
   108    int *pLineCnt          /* [in/out] Pointer to the total line count. */
   109  ){
   110    if( zOrigText && fossil_strcmp(zLine, zOrigText)==0 ){
   111      if( pCharCnt ) *pCharCnt = 0;
   112      if( pLineCnt ) (*pLineCnt)++;
   113      return 1;
   114    }
   115    return 0;
   116  }
   117  
   118  /*
   119  ** This function scans the specified comment line starting just after the
   120  ** initial index and returns the index of the next spacing character -OR-
   121  ** zero if such a character cannot be found.  For the purposes of this
   122  ** algorithm, the NUL character is treated the same as a spacing character.
   123  */
   124  static int comment_next_space(
   125    const char *zLine, /* [in] The comment line being printed. */
   126    int index,         /* [in] The current character index being handled. */
   127    int *distUTF8      /* [out] Distance to next space in UTF-8 sequences. */
   128  ){
   129    int nextIndex = index + 1;
   130    int fNonASCII=0;
   131    for(;;){
   132      char c = zLine[nextIndex];
   133      if( (c&0x80)==0x80 ) fNonASCII=1;
   134      if( c==0 || fossil_isspace(c) ){
   135        if( distUTF8 ){
   136          if( fNonASCII!=0 ){
   137            *distUTF8 = strlen_utf8(&zLine[index], nextIndex-index);
   138          }else{
   139            *distUTF8 = nextIndex-index;
   140          }
   141        }
   142        return nextIndex;
   143      }
   144      nextIndex++;
   145    }
   146    return 0; /* NOT REACHED */
   147  }
   148  
149 /* 150 ** Count the number of UTF-8 sequences in a string. Incomplete, ill-formed and 151 ** overlong sequences are counted as one sequence. The invalid lead bytes 0xC0 152 ** to 0xC1 and 0xF5 to 0xF7 are allowed to initiate (ill-formed) 2- and 4-byte 153 ** sequences, respectively, the other invalid lead bytes 0xF8 to 0xFF are 154 ** treated as invalid 1-byte sequences (as lone trail bytes). 155 ** Combining characters and East Asian Wide and Fullwidth characters are counted 156 ** as one, so this function does not calculate the effective "display width". 157 */ 158 int strlen_utf8(const char *zString, int lengthBytes){ 159 int i; /* Counted bytes. */ 160 int lengthUTF8; /* Counted UTF-8 sequences. */ 161 #if 0 162 assert( lengthBytes>=0 ); 163 #endif 164 for(i=0, lengthUTF8=0; i<lengthBytes; i++, lengthUTF8++){ 165 char c = zString[i]; 166 int cchUTF8=1; /* Code units consumed. */ 167 int maxUTF8=1; /* Expected sequence length. */ 168 if( (c&0xe0)==0xc0 )maxUTF8=2; /* UTF-8 lead byte 110vvvvv */ 169 else if( (c&0xf0)==0xe0 )maxUTF8=3; /* UTF-8 lead byte 1110vvvv */ 170 else if( (c&0xf8)==0xf0 )maxUTF8=4; /* UTF-8 lead byte 11110vvv */ 171 while( cchUTF8<maxUTF8 && 172 i<lengthBytes-1 && 173 (zString[i+1]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */ 174 cchUTF8++; 175 i++; 176 } 177 } 178 return lengthUTF8; 179 }
180 181 /* 182 ** This function is called when printing a logical comment line to calculate 183 ** the necessary indenting. The caller needs to emit the indenting spaces. 184 */ 185 static void comment_calc_indent( 186 const char *zLine, /* [in] The comment line being printed. */ 187 int indent, /* [in] Number of spaces to indent, zero for none. */ 188 int trimCrLf, /* [in] Non-zero to trim leading/trailing CR/LF. */ 189 int trimSpace, /* [in] Non-zero to trim leading/trailing spaces. */ 190 int *piIndex /* [in/out] Pointer to first non-space character. */ 191 ){ 192 if( zLine && piIndex ){ 193 int index = *piIndex; 194 if( trimCrLf ){ 195 while( zLine[index]=='\r' || zLine[index]=='\n' ){ index++; } 196 } 197 if( trimSpace ){ 198 while( fossil_isspace(zLine[index]) ){ index++; } 199 } 200 *piIndex = index; 201 } 202 } 203 204 /* 205 ** This function prints one logical line of a comment, stopping when it hits 206 ** a new line -OR- runs out of space on the logical line. 207 */ 208 static void comment_print_line( 209 const char *zOrigText, /* [in] Original comment text ONLY, may be NULL. */ 210 const char *zLine, /* [in] The comment line to print. */ 211 int origIndent, /* [in] Number of spaces to indent before the original 212 ** comment. */ 213 int indent, /* [in] Number of spaces to indent, before the line 214 ** to print. */ 215 int lineChars, /* [in] Maximum number of characters to print. */ 216 int trimCrLf, /* [in] Non-zero to trim leading/trailing CR/LF. */ 217 int trimSpace, /* [in] Non-zero to trim leading/trailing spaces. */ 218 int wordBreak, /* [in] Non-zero to try breaking on word boundaries. */ 219 int origBreak, /* [in] Non-zero to break before original comment. */ 220 int *pLineCnt, /* [in/out] Pointer to the total line count. */ 221 const char **pzLine /* [out] Pointer to the end of the logical line. */ 222 ){ 223 int index = 0, charCnt = 0, lineCnt = 0, maxChars, i; 224 char zBuf[400]; int iBuf=0; /* Output buffer and counter. */ 225 int cchUTF8, maxUTF8; /* Helper variables to count UTF-8 sequences. */ 226 if( !zLine ) return; 227 if( lineChars<=0 ) return; 228 #if 0 229 assert( indent<sizeof(zBuf)-5 ); /* See following comments to explain */ 230 assert( origIndent<sizeof(zBuf)-5 ); /* these limits. */ 231 #endif 232 if( indent>sizeof(zBuf)-6 ){ 233 /* Limit initial indent to fit output buffer. */ 234 indent = sizeof(zBuf)-6; 235 } 236 comment_calc_indent(zLine, indent, trimCrLf, trimSpace, &index); 237 if( indent>0 ){ 238 for(i=0; i<indent; i++){ 239 zBuf[iBuf++] = ' '; 240 } 241 } 242 if( origIndent>sizeof(zBuf)-6 ){ 243 /* Limit line indent to fit output buffer. */ 244 origIndent = sizeof(zBuf)-6; 245 } 246 maxChars = lineChars; 247 for(;;){ 248 int useChars = 1; 249 char c = zLine[index]; 250 /* Flush the output buffer if there's no space left for at least one more 251 ** (potentially 4-byte) UTF-8 sequence, one level of indentation spaces, 252 ** a new line, and a terminating NULL. */ 253 if( iBuf>sizeof(zBuf)-origIndent-6 ){ 254 zBuf[iBuf]=0; 255 iBuf=0; 256 fossil_print("%s", zBuf); 257 } 258 if( c==0 ){ 259 break; 260 }else{ 261 if( origBreak && index>0 ){ 262 const char *zCurrent = &zLine[index]; 263 if( comment_check_orig(zOrigText, zCurrent, &charCnt, &lineCnt) ){ 264 zBuf[iBuf++] = '\n'; 265 comment_calc_indent(zLine, origIndent, trimCrLf, trimSpace, &index); 266 for( i=0; i<origIndent; i++ ){ 267 zBuf[iBuf++] = ' '; 268 } 269 maxChars = lineChars; 270 } 271 } 272 index++; 273 } 274 if( c=='\n' ){ 275 lineCnt++; 276 charCnt = 0; 277 useChars = 0; 278 }else if( c=='\t' ){ 279 int distUTF8; 280 int nextIndex = comment_next_space(zLine, index, &distUTF8); 281 if( nextIndex<=0 || distUTF8>maxChars ){ 282 break; 283 } 284 charCnt++; 285 useChars = COMMENT_TAB_WIDTH; 286 if( maxChars<useChars ){ 287 zBuf[iBuf++] = ' '; 288 break; 289 } 290 }else if( wordBreak && fossil_isspace(c) ){ 291 int distUTF8; 292 int nextIndex = comment_next_space(zLine, index, &distUTF8); 293 if( nextIndex<=0 || distUTF8>maxChars ){ 294 break; 295 } 296 charCnt++; 297 }else{ 298 charCnt++; 299 } 300 assert( c!='\n' || charCnt==0 ); 301 zBuf[iBuf++] = c; 302 /* Skip over UTF-8 sequences, see comment on strlen_utf8() for details. */ 303 cchUTF8=1; /* Code units consumed. */ 304 maxUTF8=1; /* Expected sequence length. */ 305 if( (c&0xe0)==0xc0 )maxUTF8=2; /* UTF-8 lead byte 110vvvvv */ 306 else if( (c&0xf0)==0xe0 )maxUTF8=3; /* UTF-8 lead byte 1110vvvv */ 307 else if( (c&0xf8)==0xf0 )maxUTF8=4; /* UTF-8 lead byte 11110vvv */ 308 while( cchUTF8<maxUTF8 && 309 (zLine[index]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */ 310 cchUTF8++; 311 zBuf[iBuf++] = zLine[index++]; 312 } 313 maxChars -= useChars; 314 if( maxChars<=0 ) break; 315 if( c=='\n' ) break; 316 } 317 if( charCnt>0 ){ 318 zBuf[iBuf++] = '\n'; 319 lineCnt++; 320 } 321 /* Flush the remaining output buffer. */ 322 if( iBuf>0 ){ 323 zBuf[iBuf]=0; 324 iBuf=0; 325 fossil_print("%s", zBuf); 326 } 327 if( pLineCnt ){ 328 *pLineCnt += lineCnt; 329 } 330 if( pzLine ){ 331 *pzLine = zLine + index; 332 } 333 } 334 335 /* 336 ** This is the legacy comment printing algorithm. It is being retained 337 ** for backward compatibility. 338 ** 339 ** Given a comment string, format that string for printing on a TTY. 340 ** Assume that the output cursors is indent spaces from the left margin 341 ** and that a single line can contain no more than 'width' characters. 342 ** Indent all subsequent lines by 'indent'. 343 ** 344 ** Returns the number of new lines emitted. 345 */ 346 static int comment_print_legacy( 347 const char *zText, /* The comment text to be printed. */ 348 int indent, /* Number of spaces to indent each non-initial line. */ 349 int width /* Maximum number of characters per line. */ 350 ){ 351 int maxChars = width - indent; 352 int si, sk, i, k, kc; 353 int doIndent = 0; 354 char *zBuf; 355 char zBuffer[400]; 356 int lineCnt = 0; 357 int cchUTF8, maxUTF8; /* Helper variables to count UTF-8 sequences. */ 358 359 if( width<0 ){ 360 comment_set_maxchars(indent, &maxChars); 361 } 362 if( zText==0 ) zText = "(NULL)"; 363 if( maxChars<=0 ){ 364 maxChars = strlen(zText); 365 } 366 /* Ensure the buffer can hold the longest-possible UTF-8 sequences. */ 367 if( maxChars >= (sizeof(zBuffer)/4-1) ){ 368 zBuf = fossil_malloc(maxChars*4+1); 369 }else{ 370 zBuf = zBuffer; 371 } 372 for(;;){ 373 while( fossil_isspace(zText[0]) ){ zText++; } 374 if( zText[0]==0 ){ 375 if( doIndent==0 ){ 376 fossil_print("\n"); 377 lineCnt = 1; 378 } 379 if( zBuf!=zBuffer) fossil_free(zBuf); 380 return lineCnt; 381 } 382 for(sk=si=i=k=kc=0; zText[i] && kc<maxChars; i++){ 383 char c = zText[i]; 384 kc++; /* Count complete UTF-8 sequences. */ 385 /* Skip over UTF-8 sequences, see comment on strlen_utf8() for details. */ 386 cchUTF8=1; /* Code units consumed. */ 387 maxUTF8=1; /* Expected sequence length. */ 388 if( (c&0xe0)==0xc0 )maxUTF8=2; /* UTF-8 lead byte 110vvvvv */ 389 else if( (c&0xf0)==0xe0 )maxUTF8=3; /* UTF-8 lead byte 1110vvvv */ 390 else if( (c&0xf8)==0xf0 )maxUTF8=4; /* UTF-8 lead byte 11110vvv */ 391 if( maxUTF8>1 ){ 392 zBuf[k++] = c; 393 while( cchUTF8<maxUTF8 && 394 (zText[i+1]&0xc0)==0x80 ){ /* UTF-8 trail byte 10vvvvvv */ 395 cchUTF8++; 396 zBuf[k++] = zText[++i]; 397 } 398 } 399 else if( fossil_isspace(c) ){ 400 si = i; 401 sk = k; 402 if( k==0 || zBuf[k-1]!=' ' ){ 403 zBuf[k++] = ' '; 404 } 405 }else{ 406 zBuf[k] = c; 407 if( c=='-' && k>0 && fossil_isalpha(zBuf[k-1]) ){ 408 si = i+1; 409 sk = k+1; 410 } 411 k++; 412 } 413 } 414 if( doIndent ){ 415 fossil_print("%*s", indent, ""); 416 } 417 doIndent = 1; 418 if( sk>0 && zText[i] ){ 419 zText += si; 420 zBuf[sk] = 0; 421 }else{ 422 zText += i; 423 zBuf[k] = 0; 424 } 425 fossil_print("%s\n", zBuf); 426 lineCnt++; 427 } 428 } 429 430 /* 431 ** This is the comment printing function. The comment printing algorithm 432 ** contained within it attempts to preserve the formatting present within 433 ** the comment string itself while honoring line width limitations. There 434 ** are several flags that modify the default behavior of this function: 435 ** 436 ** COMMENT_PRINT_LEGACY: Forces use of the legacy comment printing 437 ** algorithm. For backward compatibility, 438 ** this is the default. 439 ** 440 ** COMMENT_PRINT_TRIM_CRLF: Trims leading and trailing carriage-returns 441 ** and line-feeds where they do not materially 442 ** impact pre-existing formatting (i.e. at the 443 ** start of the comment string -AND- right 444 ** before line indentation). This flag does 445 ** not apply to the legacy comment printing 446 ** algorithm. This flag may be combined with 447 ** COMMENT_PRINT_TRIM_SPACE. 448 ** 449 ** COMMENT_PRINT_TRIM_SPACE: Trims leading and trailing spaces where they 450 ** do not materially impact the pre-existing 451 ** formatting (i.e. at the start of the comment 452 ** string -AND- right before line indentation). 453 ** This flag does not apply to the legacy 454 ** comment printing algorithm. This flag may 455 ** be combined with COMMENT_PRINT_TRIM_CRLF. 456 ** 457 ** COMMENT_PRINT_WORD_BREAK: Attempts to break lines on word boundaries 458 ** while honoring the logical line length. 459 ** If this flag is not specified, honoring the 460 ** logical line length may result in breaking 461 ** lines in the middle of words. This flag 462 ** does not apply to the legacy comment 463 ** printing algorithm. 464 ** 465 ** COMMENT_PRINT_ORIG_BREAK: Looks for the original comment text within 466 ** the text being printed. Upon matching, a 467 ** new line will be emitted, thus preserving 468 ** more of the pre-existing formatting. 469 ** 470 ** Given a comment string, format that string for printing on a TTY. 471 ** Assume that the output cursors is indent spaces from the left margin 472 ** and that a single line can contain no more than 'width' characters. 473 ** Indent all subsequent lines by 'indent'. 474 ** 475 ** Returns the number of new lines emitted. 476 */ 477 int comment_print( 478 const char *zText, /* The comment text to be printed. */ 479 const char *zOrigText, /* Original comment text ONLY, may be NULL. */ 480 int indent, /* Spaces to indent each non-initial line. */ 481 int width, /* Maximum number of characters per line. */ 482 int flags /* Zero or more "COMMENT_PRINT_*" flags. */ 483 ){ 484 int maxChars = width - indent; 485 int legacy = flags & COMMENT_PRINT_LEGACY; 486 int trimCrLf = flags & COMMENT_PRINT_TRIM_CRLF; 487 int trimSpace = flags & COMMENT_PRINT_TRIM_SPACE; 488 int wordBreak = flags & COMMENT_PRINT_WORD_BREAK; 489 int origBreak = flags & COMMENT_PRINT_ORIG_BREAK; 490 int lineCnt = 0; 491 const char *zLine; 492 493 if( legacy ){ 494 return comment_print_legacy(zText, indent, width); 495 } 496 if( width<0 ){ 497 comment_set_maxchars(indent, &maxChars); 498 } 499 if( zText==0 ) zText = "(NULL)"; 500 if( maxChars<=0 ){ 501 maxChars = strlen(zText); 502 } 503 if( trimSpace ){ 504 while( fossil_isspace(zText[0]) ){ zText++; } 505 } 506 if( zText[0]==0 ){ 507 fossil_print("\n"); 508 lineCnt++; 509 return lineCnt; 510 } 511 zLine = zText; 512 for(;;){ 513 comment_print_line(zOrigText, zLine, indent, zLine>zText ? indent : 0, 514 maxChars, trimCrLf, trimSpace, wordBreak, origBreak, 515 &lineCnt, &zLine); 516 if( !zLine || !zLine[0] ) break; 517 } 518 return lineCnt; 519 } 520 521 /* 522 ** Return the "COMMENT_PRINT_*" flags specified by the following sources, 523 ** evaluated in the following cascading order: 524 ** 525 ** 1. The global --comfmtflags (alias --comment-format) command-line option. 526 ** 2. The local (per-repository) "comment-format" setting. 527 ** 3. The global (all-repositories) "comment-format" setting. 528 ** 4. The default value COMMENT_PRINT_DEFAULT. 529 */ 530 int get_comment_format(){ 531 int comFmtFlags; 532 /* The global command-line option is present, or the value has been cached. */ 533 if( g.comFmtFlags!=COMMENT_PRINT_UNSET ){ 534 comFmtFlags = g.comFmtFlags; 535 return comFmtFlags; 536 } 537 /* Load the local (per-repository) or global (all-repositories) value, and use 538 ** g.comFmtFlags as a cache. */ 539 comFmtFlags = db_get_int("comment-format", COMMENT_PRINT_UNSET); 540 if( comFmtFlags!=COMMENT_PRINT_UNSET ){ 541 g.comFmtFlags = comFmtFlags; 542 return comFmtFlags; 543 } 544 /* Fallback to the default value. */ 545 comFmtFlags = COMMENT_PRINT_DEFAULT; 546 return comFmtFlags; 547 } 548 549 /* 550 ** 551 ** COMMAND: test-comment-format 552 ** 553 ** Usage: %fossil test-comment-format ?OPTIONS? PREFIX TEXT ?ORIGTEXT? 554 ** 555 ** Test comment formatting and printing. Use for testing only. 556 ** 557 ** Options: 558 ** --file The comment text is really just a file name to 559 ** read it from. 560 ** --decode Decode the text using the same method used when 561 ** handling the value of a C-card from a manifest. 562 ** --legacy Use the legacy comment printing algorithm. 563 ** --trimcrlf Enable trimming of leading/trailing CR/LF. 564 ** --trimspace Enable trimming of leading/trailing spaces. 565 ** --wordbreak Attempt to break lines on word boundaries. 566 ** --origbreak Attempt to break when the original comment text 567 ** is detected. 568 ** --indent Number of spaces to indent (default (-1) is to 569 ** auto-detect). Zero means no indent. 570 ** -W|--width <num> Width of lines (default (-1) is to auto-detect). 571 ** Zero means no limit. 572 */ 573 void test_comment_format(void){ 574 const char *zWidth; 575 const char *zIndent; 576 const char *zPrefix; 577 char *zText; 578 char *zOrigText; 579 int indent, width; 580 int fromFile = find_option("file", 0, 0)!=0; 581 int decode = find_option("decode", 0, 0)!=0; 582 int flags = COMMENT_PRINT_NONE; 583 if( find_option("legacy", 0, 0) ){ 584 flags |= COMMENT_PRINT_LEGACY; 585 } 586 if( find_option("trimcrlf", 0, 0) ){ 587 flags |= COMMENT_PRINT_TRIM_CRLF; 588 } 589 if( find_option("trimspace", 0, 0) ){ 590 flags |= COMMENT_PRINT_TRIM_SPACE; 591 } 592 if( find_option("wordbreak", 0, 0) ){ 593 flags |= COMMENT_PRINT_WORD_BREAK; 594 } 595 if( find_option("origbreak", 0, 0) ){ 596 flags |= COMMENT_PRINT_ORIG_BREAK; 597 } 598 zWidth = find_option("width","W",1); 599 if( zWidth ){ 600 width = atoi(zWidth); 601 }else{ 602 width = -1; /* automatic */ 603 } 604 zIndent = find_option("indent",0,1); 605 if( zIndent ){ 606 indent = atoi(zIndent); 607 }else{ 608 indent = -1; /* automatic */ 609 } 610 if( g.argc!=4 && g.argc!=5 ){ 611 usage("?OPTIONS? PREFIX TEXT ?ORIGTEXT?"); 612 } 613 zPrefix = g.argv[2]; 614 zText = g.argv[3]; 615 if( g.argc==5 ){ 616 zOrigText = g.argv[4]; 617 }else{ 618 zOrigText = 0; 619 } 620 if( fromFile ){ 621 Blob fileData; 622 blob_read_from_file(&fileData, zText, ExtFILE); 623 zText = mprintf("%s", blob_str(&fileData)); 624 blob_reset(&fileData); 625 if( zOrigText ){ 626 blob_read_from_file(&fileData, zOrigText, ExtFILE); 627 zOrigText = mprintf("%s", blob_str(&fileData)); 628 blob_reset(&fileData); 629 } 630 } 631 if( decode ){ 632 zText = mprintf(fromFile?"%z":"%s" /*works-like:"%s"*/, zText); 633 defossilize(zText); 634 if( zOrigText ){ 635 zOrigText = mprintf(fromFile?"%z":"%s" /*works-like:"%s"*/, zOrigText); 636 defossilize(zOrigText); 637 } 638 } 639 if( indent<0 ){ 640 indent = strlen(zPrefix); 641 } 642 if( zPrefix && *zPrefix ){ 643 fossil_print("%s", zPrefix); 644 } 645 fossil_print("(%d lines output)\n", 646 comment_print(zText, zOrigText, indent, width, flags)); 647 if( zOrigText && zOrigText!=g.argv[4] ) fossil_free(zOrigText); 648 if( zText && zText!=g.argv[3] ) fossil_free(zText); 649 }