/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/*
Copyright 2013-2021 The Libfossil Authors, see LICENSES/BSD-2-Clause.txt
SPDX-License-Identifier: BSD-2-Clause-FreeBSD
SPDX-FileCopyrightText: 2021 The Libfossil Authors
SPDX-ArtifactOfProjectName: Libfossil
SPDX-FileType: Code
*/
/**
This is a template application for libfossil fcli client apps, with
commentary explaining how to do various common things with the
API. Copy/paste this and modify it to suit.
*/
#include "libfossil.h"
// Only for testing/debugging..
#define MARKER(pfexp) \
do{ printf("MARKER: %s:%d:%s():\t",__FILE__,__LINE__,__func__); \
printf pfexp; \
} while(0)
// Global app state.
struct App_ {
char const * file1;
char const * file2;
char const * builderName;
uint32_t diffFlags;
int contextLines;
bool ansiColor;
} App = {
NULL,//file1
NULL,//file2
"unified",//builderName
0/*diffFlags*/,
-1/*contextLines*/,
false/*ansiColor*/
};
static int fdb__create(fsl_dibu **b){
fsl_dibu_e t = FSL_DIBU_DEBUG;
switch(*App.builderName){
case (int)'d':
break;
case (int)'j': t = FSL_DIBU_JSON1;
break;
case (int)'t': t = FSL_DIBU_TCL;
break;
case (int)'u': t = FSL_DIBU_UNIFIED_TEXT;
break;
case (int)'s': t = FSL_DIBU_SPLIT_TEXT;
break;
default:
return fcli_err_set(FSL_RC_MISUSE,
"Unknown diff builder name: %s",
App.builderName);
break;
}
return fsl_dibu_factory(t, b);
}
static int app_stuff(){
fsl_buffer f1 = fsl_buffer_empty;
fsl_buffer f2 = fsl_buffer_empty;
fsl_buffer hash1 = fsl_buffer_empty;
fsl_buffer hash2 = fsl_buffer_empty;
fsl_dibu * b = 0;
fsl_diff_opt opt = fsl_diff_opt_empty;
int rc = 0;
int * rawDiff = 0;
#define RC if(rc) goto end
if('r'!=App.builderName[0]/*raw diff*/){
rc = fdb__create(&b);
if(rc) goto end;
assert(b);
b->opt = &opt;
}
if(App.ansiColor && fsl_isatty(1)){
fcli_diff_colors(&opt, FCLI_DIFF_COLORS_DEFAULT);
}
opt.diffFlags = App.diffFlags;
opt.contextLines = App.contextLines;
assert(0==rc);
opt.out = fsl_output_f_FILE;
opt.outState = stdout;
RC;
rc = fsl_buffer_fill_from_filename(&f1, App.file1);
RC;
rc = fsl_buffer_fill_from_filename(&f2, App.file2);
RC;
if(1){
fsl_sha3sum_buffer(&f1, &hash1);
fsl_sha3sum_buffer(&f2, &hash2);
opt.hashLHS = fsl_buffer_cstr(&hash1);
opt.hashRHS = fsl_buffer_cstr(&hash2);
opt.nameLHS = App.file1;
opt.nameRHS = App.file2;
}
rc = b
? fsl_diff_v2(&f1, &f2, b)
: fsl_diff_v2_raw(&f1, &f2, &opt, &rawDiff);
RC;
if(rawDiff){
f_out("Raw diff triples:\n");
for(int i = 0; rawDiff[i] || rawDiff[i+1] || rawDiff[i+2]; i+=3){
f_out(" copy %6d delete %6d insert %6d\n",
rawDiff[i], rawDiff[i+1], rawDiff[i+2]);
}
}
end:
fsl_free(rawDiff);
if(b) b->finalize(b);
fsl_buffer_clear(&f1);
fsl_buffer_clear(&f2);
fsl_buffer_clear(&hash1);
fsl_buffer_clear(&hash2);
return rc;
#undef RC
}
static int fcli_flag_callback_f_diffflags(fcli_cliflag const *f){
switch(*f->flagShort){
case (int)'#': App.diffFlags |= FSL_DIFF2_LINE_NUMBERS;
break;
case (int)'v': App.diffFlags |= FSL_DIFF2_INVERT;
break;
default: break;
}
return 0;
}
int main(int argc, const char * const * argv ){
bool bogus;
const fcli_cliflag FCliFlags[] = {
FCLI_FLAG("b","builer","string",&App.builderName,
"Builder name. One of: "
"u (unified), s (split), r (raw), "
"d (debug), j (json), t (tcl)"),
FCLI_FLAG_I32("F","diff-flags", "integer", &App.diffFlags,
"Bitmask of flags for builder's clientFlags."),
FCLI_FLAG_I32("c","context", "integer", &App.contextLines,
"Number of context lines for the diff."),
FCLI_FLAG_BOOL_X("#", "line-numbers", &bogus,
fcli_flag_callback_f_diffflags,
"Enable line numbers for diff formats "
"which optionally support it."),
FCLI_FLAG_BOOL_X("v", "invert", &bogus,
fcli_flag_callback_f_diffflags,
"Invert the diff's LHS and RHS."),
FCLI_FLAG_BOOL("a","ansi", &App.ansiColor,
"Enable ANSI color if possible."),
fcli_cliflag_empty_m
};
const fcli_help_info FCliHelp = {
"Test app for fsl_dibu.",
"file1 file2",
NULL
};
fcli.clientFlags.checkoutDir = NULL; // same effect as global -C flag.
int rc = fcli_setup_v2(argc, argv, FCliFlags, &FCliHelp);
if(rc) goto end;
App.file1 = fcli_next_arg(true);
App.file2 = fcli_next_arg(true);
if(!App.file2){
rc =fcli_err_set(FSL_RC_MISUSE,
"Expecting two filenames.");
goto end;
}
if((rc=fcli_has_unused_args(false))) goto end;
if(0>App.contextLines) App.contextLines = fsl_diff_opt_empty.contextLines;
else if(0==App.contextLines) App.diffFlags |= FSL_DIFF2_CONTEXT_ZERO;
rc = app_stuff();
end:
return fcli_end_of_main(rc);
}