// This is an open source non-commercial project. Dear PVS-Studio, please check
// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
#include <assert.h>
#include <inttypes.h>
#include <stdbool.h>
#include "nvim/ascii.h"
#include "nvim/assert.h"
#include "nvim/buffer.h"
#include "nvim/change.h"
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
#include "nvim/extmark.h"
#include "nvim/indent.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/plines.h"
#include "nvim/regexp.h"
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/strings.h"
#include "nvim/textformat.h"
#include "nvim/undo.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "indent.c.generated.h"
#endif
/// Set the integer values corresponding to the string setting of 'vartabstop'.
/// "array" will be set, caller must free it if needed.
///
/// @return false for an error.
bool tabstop_set(char *var, long **array)
{
long valcount = 1;
int t;
char *cp;
if (var[0] == NUL || (var[0] == '0' && var[1] == NUL)) {
*array = NULL;
return true;
}
for (cp = var; *cp != NUL; cp++) {
if (cp == var || cp[-1] == ',') {
char *end;
if (strtol(cp, &end, 10) <= 0) {
if (cp != end) {
emsg(_(e_positive));
} else {
semsg(_(e_invarg2), cp);
}
return false;
}
}
if (ascii_isdigit(*cp)) {
continue;
}
if (cp[0] == ',' && cp > var && cp[-1] != ',' && cp[1] != NUL) {
valcount++;
continue;
}
semsg(_(e_invarg2), var);
return false;
}
*array = (long *)xmalloc((unsigned)(valcount + 1) * sizeof(long));
(*array)[0] = valcount;
t = 1;
for (cp = var; *cp != NUL;) {
int n = atoi(cp);
// Catch negative values, overflow and ridiculous big values.
if (n <= 0 || n > TABSTOP_MAX) {
semsg(_(e_invarg2), cp);
XFREE_CLEAR(*array);
return false;
}
(*array)[t++] = n;
while (*cp != NUL && *cp != ',') {
cp++;
}
if (*cp != NUL) {
cp++;
}
}
return true;
}
/// Calculate the number of screen spaces a tab will occupy.
/// If "vts" is set then the tab widths are taken from that array,
/// otherwise the value of ts is used.
int tabstop_padding(colnr_T col, long ts_arg, long *vts)
{
long ts = ts_arg == 0 ? 8 : ts_arg;
colnr_T tabcol = 0;
int t;
long padding = 0;
if (vts == NULL || vts[0] == 0) {
return (int)(ts - (col % ts));
}
const long tabcount = vts[0];
for (t = 1; t <= tabcount; t++) {
tabcol += (colnr_T)vts[t];
if (tabcol > col) {
padding = tabcol - col;
break;
}
}
if (t > tabcount) {
padding = vts[tabcount] - ((col - tabcol) % vts[tabcount]);
}
return (int)padding;
}
/// Find the size of the tab that covers a particular column.
int tabstop_at(colnr_T col, long ts, long *vts)
{
colnr_T tabcol = 0;
int t;
long tab_size = 0;
if (vts == NULL || vts[0] == 0) {
return (int)ts;
}
const long tabcount = vts[0];
for (t = 1; t <= tabcount; t++) {
tabcol += (colnr_T)vts[t];
if (tabcol > col) {
tab_size = vts[t];
break;
}
}
if (t > tabcount) {
tab_size = vts[tabcount];
}
return (int)tab_size;
}
/// Find the column on which a tab starts.
colnr_T tabstop_start(colnr_T col, long ts, long *vts)
{
colnr_T tabcol = 0;
int t;
if (vts == NULL || vts[0] == 0) {
return (int)((col / ts) * ts);
}
const long tabcount = vts[0];
for (t = 1; t <= tabcount; t++) {
tabcol += (colnr_T)vts[t];
if (tabcol > col) {
return (int)(tabcol - vts[t]);
}
}
const int excess = (int)(tabcol % vts[tabcount]);
return (int)(excess + ((col - excess) / vts[tabcount]) * vts[tabcount]);
}
/// Find the number of tabs and spaces necessary to get from one column
/// to another.
void tabstop_fromto(colnr_T start_col, colnr_T end_col, long ts_arg, long *vts, int *ntabs,
int *nspcs)
{
int spaces = end_col - start_col;
colnr_T tabcol = 0;
long padding = 0;
int t;
long ts = ts_arg == 0 ? curbuf->b_p_ts : ts_arg;
if (vts == NULL || vts[0] == 0) {
int tabs = 0;
const int initspc = (int)(ts - (start_col % ts));
if (spaces >= initspc) {
spaces -= initspc;
tabs++;
}
tabs += (int)(spaces / ts);
spaces -= (int)((spaces / ts) * ts);
*ntabs = tabs;
*nspcs = spaces;
return;
}
// Find the padding needed to reach the next tabstop.
const long tabcount = vts<
|