summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--calc.go335
-rw-r--r--calc_test.go101
-rw-r--r--cell_test.go11
-rw-r--r--col.go5
-rw-r--r--col_test.go6
-rw-r--r--crypt.go26
-rw-r--r--drawing.go4
-rw-r--r--excelize_test.go6
-rw-r--r--file.go2
-rw-r--r--file_test.go2
-rw-r--r--lib.go2
-rw-r--r--picture.go4
-rw-r--r--pivotTable.go4
-rw-r--r--rows.go4
-rw-r--r--sheet.go4
-rw-r--r--sheet_test.go6
-rw-r--r--stream.go32
-rw-r--r--stream_test.go4
-rw-r--r--styles.go18
-rw-r--r--table.go11
20 files changed, 462 insertions, 125 deletions
diff --git a/calc.go b/calc.go
index b684a77..33c504d 100644
--- a/calc.go
+++ b/calc.go
@@ -100,7 +100,6 @@ const (
// formulaArg is the argument of a formula or function.
type formulaArg struct {
- f *File
SheetName string
Number float64
String string
@@ -164,6 +163,21 @@ func (fa formulaArg) ToBool() formulaArg {
return newBoolFormulaArg(b)
}
+// ToList returns a formula argument with array data type.
+func (fa formulaArg) ToList() []formulaArg {
+ if fa.Type == ArgMatrix {
+ list := []formulaArg{}
+ for _, row := range fa.Matrix {
+ list = append(list, row...)
+ }
+ return list
+ }
+ if fa.Type == ArgList {
+ return fa.List
+ }
+ return nil
+}
+
// formulaFuncs is the type of the formula functions.
type formulaFuncs struct {
f *File
@@ -201,8 +215,11 @@ var tokenPriority = map[string]int{
// ARABIC
// ASIN
// ASINH
+// ATAN
// ATAN2
// ATANH
+// AVERAGE
+// AVERAGEA
// BASE
// CEILING
// CEILING.MATH
@@ -211,11 +228,15 @@ var tokenPriority = map[string]int{
// CLEAN
// COMBIN
// COMBINA
+// CONCAT
+// CONCATENATE
// COS
// COSH
// COT
// COTH
+// COUNT
// COUNTA
+// COUNTBLANK
// CSC
// CSCH
// DATE
@@ -254,6 +275,7 @@ var tokenPriority = map[string]int{
// LOG10
// LOOKUP
// LOWER
+// MAX
// MDETERM
// MEDIAN
// MOD
@@ -322,7 +344,7 @@ func (f *File) CalcCellValue(sheet, cell string) (result string, err error) {
// getPriority calculate arithmetic operator priority.
func getPriority(token efp.Token) (pri int) {
- pri, _ = tokenPriority[token.TValue]
+ pri = tokenPriority[token.TValue]
if token.TValue == "-" && token.TType == efp.TokenTypeOperatorPrefix {
pri = 6
}
@@ -962,7 +984,7 @@ func (f *File) rangeResolver(cellRefs, cellRanges *list.List) (arg formulaArg, e
err = errors.New(formulaErrorVALUE)
}
rng := []int{cr.From.Col, cr.From.Row, cr.To.Col, cr.To.Row}
- sortCoordinates(rng)
+ _ = sortCoordinates(rng)
cr.From.Col, cr.From.Row, cr.To.Col, cr.To.Row = rng[0], rng[1], rng[2], rng[3]
prepareValueRange(cr, valueRange)
if cr.From.Sheet != "" {
@@ -1208,7 +1230,7 @@ func (fn *formulaFuncs) ARABIC(argsList *list.List) formulaArg {
prefix = -1
continue
}
- digit, _ = charMap[char]
+ digit = charMap[char]
val += digit
switch {
case last == digit && (last == 5 || last == 50 || last == 500):
@@ -1950,22 +1972,18 @@ func (fn *formulaFuncs) GCD(argsList *list.List) formulaArg {
var (
val float64
nums = []float64{}
- err error
)
for arg := argsList.Front(); arg != nil; arg = arg.Next() {
token := arg.Value.(formulaArg)
switch token.Type {
case ArgString:
- if token.String == "" {
- continue
- }
- if val, err = strconv.ParseFloat(token.String, 64); err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+ num := token.ToNumber()
+ if num.Type == ArgError {
+ return num
}
- break
+ val = num.Number
case ArgNumber:
val = token.Number
- break
}
nums = append(nums, val)
}
@@ -2083,10 +2101,8 @@ func (fn *formulaFuncs) LCM(argsList *list.List) formulaArg {
if val, err = strconv.ParseFloat(token.String, 64); err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- break
case ArgNumber:
val = token.Number
- break
}
nums = append(nums, val)
}
@@ -2321,10 +2337,8 @@ func (fn *formulaFuncs) MULTINOMIAL(argsList *list.List) formulaArg {
if val, err = strconv.ParseFloat(token.String, 64); err != nil {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
- break
case ArgNumber:
val = token.Number
- break
}
num += val
denom *= fact(val)
@@ -2449,10 +2463,8 @@ func (fn *formulaFuncs) PRODUCT(argsList *list.List) formulaArg {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
product = product * val
- break
case ArgNumber:
product = product * token.Number
- break
case ArgMatrix:
for _, row := range token.Matrix {
for _, value := range row {
@@ -2934,10 +2946,8 @@ func (fn *formulaFuncs) SUMSQ(argsList *list.List) formulaArg {
return newErrorFormulaArg(formulaErrorVALUE, err.Error())
}
sq += val * val
- break
case ArgNumber:
sq += token.Number
- break
case ArgMatrix:
for _, row := range token.Matrix {
for _, value := range row {
@@ -3023,7 +3033,98 @@ func (fn *formulaFuncs) TRUNC(argsList *list.List) formulaArg {
return newNumberFormulaArg(float64(int(number.Number*adjust)) / adjust)
}
-// Statistical functions
+// Statistical Functions
+
+// AVERAGE function returns the arithmetic mean of a list of supplied numbers.
+// The syntax of the function is:
+//
+// AVERAGE(number1,[number2],...)
+//
+func (fn *formulaFuncs) AVERAGE(argsList *list.List) formulaArg {
+ args := []formulaArg{}
+ for arg := argsList.Front(); arg != nil; arg = arg.Next() {
+ args = append(args, arg.Value.(formulaArg))
+ }
+ count, sum := fn.countSum(false, args)
+ if count == 0 {
+ return newErrorFormulaArg(formulaErrorDIV, "AVERAGE divide by zero")
+ }
+ return newNumberFormulaArg(sum / count)
+}
+
+// AVERAGEA function returns the arithmetic mean of a list of supplied numbers
+// with text cell and zero values. The syntax of the function is:
+//
+// AVERAGEA(number1,[number2],...)
+//
+func (fn *formulaFuncs) AVERAGEA(argsList *list.List) formulaArg {
+ args := []formulaArg{}
+ for arg := argsList.Front(); arg != nil; arg = arg.Next() {
+ args = append(args, arg.Value.(formulaArg))
+ }
+ count, sum := fn.countSum(true, args)
+ if count == 0 {
+ return newErrorFormulaArg(formulaErrorDIV, "AVERAGEA divide by zero")
+ }
+ return newNumberFormulaArg(sum / count)
+}
+
+// countSum get count and sum for a formula arguments array.
+func (fn *formulaFuncs) countSum(countText bool, args []formulaArg) (count, sum float64) {
+ for _, arg := range args {
+ switch arg.Type {
+ case ArgNumber:
+ if countText || !arg.Boolean {
+ sum += arg.Number
+ count++
+ }
+ case ArgString:
+ num := arg.ToNumber()
+ if countText && num.Type == ArgError && arg.String != "" {
+ count++
+ }
+ if num.Type == ArgNumber {
+ sum += num.Number
+ count++
+ }
+ case ArgList, ArgMatrix:
+ cnt, summary := fn.countSum(countText, arg.ToList())
+ sum += summary
+ count += cnt
+ }
+ }
+ return
+}
+
+// COUNT function returns the count of numeric values in a supplied set of
+// cells or values. This count includes both numbers and dates. The syntax of
+// the function is:
+//
+// COUNT(value1,[value2],...)
+//
+func (fn *formulaFuncs) COUNT(argsList *list.List) formulaArg {
+ var count int
+ for token := argsList.Front(); token != nil; token = token.Next() {
+ arg := token.Value.(formulaArg)
+ switch arg.Type {
+ case ArgString:
+ if arg.ToNumber().Type != ArgError {
+ count++
+ }
+ case ArgNumber:
+ count++
+ case ArgMatrix:
+ for _, row := range arg.Matrix {
+ for _, value := range row {
+ if value.ToNumber().Type != ArgError {
+ count++
+ }
+ }
+ }
+ }
+ }
+ return newNumberFormulaArg(float64(count))
+}
// COUNTA function returns the number of non-blanks within a supplied set of
// cells or values. The syntax of the function is:
@@ -3039,17 +3140,135 @@ func (fn *formulaFuncs) COUNTA(argsList *list.List) formulaArg {
if arg.String != "" {
count++
}
+ case ArgNumber:
+ count++
case ArgMatrix:
- for _, row := range arg.Matrix {
- for _, value := range row {
- if value.String != "" {
+ for _, row := range arg.ToList() {
+ switch row.Type {
+ case ArgString:
+ if row.String != "" {
count++
}
+ case ArgNumber:
+ count++
+ }
+ }
+ }
+ }
+ return newNumberFormulaArg(float64(count))
+}
+
+// COUNTBLANK function returns the number of blank cells in a supplied range.
+// The syntax of the function is:
+//
+// COUNTBLANK(range)
+//
+func (fn *formulaFuncs) COUNTBLANK(argsList *list.List) formulaArg {
+ if argsList.Len() != 1 {
+ return newErrorFormulaArg(formulaErrorVALUE, "COUNTBLANK requires 1 argument")
+ }
+ var count int
+ token := argsList.Front().Value.(formulaArg)
+ switch token.Type {
+ case ArgString:
+ if token.String == "" {
+ count++
+ }
+ case ArgList, ArgMatrix:
+ for _, row := range token.ToList() {
+ switch row.Type {
+ case ArgString:
+ if row.String == "" {
+ count++
+ }
+ case ArgEmpty:
+ count++
+ }
+ }
+ case ArgEmpty:
+ count++
+ }
+ return newNumberFormulaArg(float64(count))
+}
+
+// MAX function returns the largest value from a supplied set of numeric
+// values. The syntax of the function is:
+//
+// MAX(number1,[number2],...)
+//
+func (fn *formulaFuncs) MAX(argsList *list.List) formulaArg {
+ if argsList.Len() == 0 {
+ return newErrorFormulaArg(formulaErrorVALUE, "MAX requires at least 1 argument")
+ }
+ return fn.max(false, argsList)
+}
+
+// MAXA function returns the largest value from a supplied set of numeric values, while counting text and the logical value FALSE as the value 0 and counting the logical value TRUE as the value 1. The syntax of the function is:
+//
+// MAXA(number1,[number2],...)
+//
+func (fn *formulaFuncs) MAXA(argsList *list.List) formulaArg {
+ if argsList.Len() == 0 {
+ return newErrorFormulaArg(formulaErrorVALUE, "MAXA requires at least 1 argument")
+ }
+ return fn.max(true, argsList)
+}
+
+// max is an implementation of the formula function MAX and MAXA.
+func (fn *formulaFuncs) max(maxa bool, argsList *list.List) formulaArg {
+ max := -math.MaxFloat64
+ for token := argsList.Front(); token != nil; token = token.Next() {
+ arg := token.Value.(formulaArg)
+ switch arg.Type {
+ case ArgString:
+ if !maxa && (arg.Value() == "TRUE" || arg.Value() == "FALSE") {
+ continue
+ } else {
+ num := arg.ToBool()
+ if num.Type == ArgNumber && num.Number > max {
+ max = num.Number
+ continue
+ }
+ }
+ num := arg.ToNumber()
+ if num.Type != ArgError && num.Number > max {
+ max = num.Number
+ }
+ case ArgNumber:
+ if arg.Number > max {
+ max = arg.Number
+ }
+ case ArgList, ArgMatrix:
+ for _, row := range arg.ToList() {
+ switch row.Type {
+ case ArgString:
+ if !maxa && (row.Value() == "TRUE" || row.Value() == "FALSE") {
+ continue
+ } else {
+ num := row.ToBool()
+ if num.Type == ArgNumber && num.Number > max {
+ max = num.Number
+ continue
+ }
+ }
+ num := row.ToNumber()
+ if num.Type != ArgError && num.Number > max {
+ max = num.Number
+ }
+ case ArgNumber:
+ if row.Number > max {
+ max = row.Number
+ }
}
}
+ case ArgError:
+ return arg
}
}
- return newStringFormulaArg(fmt.Sprintf("%d", count))
+ if max == -math.MaxFloat64 {
+ max = 0
+ }
+ return newNumberFormulaArg(max)
}
// MEDIAN function returns the statistical median (the middle value) of a list
@@ -3068,14 +3287,13 @@ func (fn *formulaFuncs) MEDIAN(argsList *list.List) formulaArg {
arg := token.Value.(formulaArg)
switch arg.Type {
case ArgString:
- if digits, err = strconv.ParseFloat(argsList.Back().Value.(formulaArg).String, 64); err != nil {
- return newErrorFormulaArg(formulaErrorVALUE, err.Error())
+ num := arg.ToNumber()
+ if num.Type == ArgError {
+ return newErrorFormulaArg(formulaErrorVALUE, num.Error)
}
- values = append(values, digits)
- break
+ values = append(values, num.Number)
case ArgNumber:
values = append(values, arg.Number)
- break
case ArgMatrix:
for _, row := range arg.Matrix {
for _, value := range row {
@@ -3099,7 +3317,7 @@ func (fn *formulaFuncs) MEDIAN(argsList *list.List) formulaArg {
return newNumberFormulaArg(median)
}
-// Information functions
+// Information Functions
// ISBLANK function tests if a specified cell is blank (empty) and if so,
// returns TRUE; Otherwise the function returns FALSE. The syntax of the
@@ -3137,7 +3355,7 @@ func (fn *formulaFuncs) ISERR(argsList *list.List) formulaArg {
}
token := argsList.Front().Value.(formulaArg)
result := "FALSE"
- if token.Type == ArgString {
+ if token.Type == ArgError {
for _, errType := range []string{formulaErrorDIV, formulaErrorNAME, formulaErrorNUM, formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA} {
if errType == token.String {
result = "TRUE"
@@ -3159,7 +3377,7 @@ func (fn *formulaFuncs) ISERROR(argsList *list.List) formulaArg {
}
token := argsList.Front().Value.(formulaArg)
result := "FALSE"
- if token.Type == ArgString {
+ if token.Type == ArgError {
for _, errType := range []string{formulaErrorDIV, formulaErrorNAME, formulaErrorNA, formulaErrorNUM, formulaErrorVALUE, formulaErrorREF, formulaErrorNULL, formulaErrorSPILL, formulaErrorCALC, formulaErrorGETTINGDATA} {
if errType == token.String {
result = "TRUE"
@@ -3208,7 +3426,7 @@ func (fn *formulaFuncs) ISNA(argsList *list.List) formulaArg {
}
token := argsList.Front().Value.(formulaArg)
result := "FALSE"
- if token.Type == ArgString && token.String == formulaErrorNA {
+ if token.Type == ArgError && token.String == formulaErrorNA {
result = "TRUE"
}
return newStringFormulaArg(result)
@@ -3304,7 +3522,7 @@ func (fn *formulaFuncs) NA(argsList *list.List) formulaArg {
if argsList.Len() != 0 {
return newErrorFormulaArg(formulaErrorVALUE, "NA accepts no arguments")
}
- return newStringFormulaArg(formulaErrorNA)
+ return newErrorFormulaArg(formulaErrorNA, formulaErrorNA)
}
// SHEET function returns the Sheet number for a specified reference. The
@@ -3536,6 +3754,49 @@ func (fn *formulaFuncs) CLEAN(argsList *list.List) formulaArg {
return newStringFormulaArg(b.String())
}
+// CONCAT function joins together a series of supplied text strings into one
+// combined text string.
+//
+// CONCAT(text1,[text2],...)
+//
+func (fn *formulaFuncs) CONCAT(argsList *list.List) formulaArg {
+ return fn.concat("CONCAT", argsList)
+}
+
+// CONCATENATE function joins together a series of supplied text strings into
+// one combined text string.
+//
+// CONCATENATE(text1,[text2],...)
+//
+func (fn *formulaFuncs) CONCATENATE(argsList *list.List) formulaArg {
+ return fn.concat("CONCATENATE", argsList)
+}
+
+// concat is an implementation of the formula function CONCAT and CONCATENATE.
+func (fn *formulaFuncs) concat(name string, argsList *list.List) formulaArg {
+ buf := bytes.Buffer{}
+ for arg := argsList.Front(); arg != nil; arg = arg.Next() {
+ token := arg.Value.(formulaArg)
+ switch token.Type {
+ case ArgString:
+ buf.WriteString(token.String)
+ case ArgNumber:
+ if token.Boolean {
+ if token.Number == 0 {
+ buf.WriteString("FALSE")
+ } else {
+ buf.WriteString("TRUE")
+ }
+ } else {
+ buf.WriteString(token.Value())
+ }
+ default:
+ return newErrorFormulaArg(formulaErrorVALUE, fmt.Sprintf("%s requires arguments to be strings", name))
+ }
+ }
+ return newStringFormulaArg(buf.String())
+}
+
// EXACT function tests if two supplied text strings or values are exactly
// equal and if so, returns TRUE; Otherwise, the function returns FALSE. The
// function is case-sensitive. The syntax of the function is:
@@ -4142,7 +4403,9 @@ func lookupCol(arr formulaArg) []formulaArg {
// Web Functions
-// ENCODEURL function returns a URL-encoded string, replacing certain non-alphanumeric characters with the percentage symbol (%) and a hexadecimal number. The syntax of the function is:
+// ENCODEURL function returns a URL-encoded string, replacing certain
+// non-alphanumeric characters with the percentage symbol (%) and a
+// hexadecimal number. The syntax of the function is:
//
// ENCODEURL(url)
//
diff --git a/calc_test.go b/calc_test.go
index 437a7b5..ef028a9 100644
--- a/calc_test.go
+++ b/calc_test.go
@@ -15,7 +15,7 @@ func prepareCalcData(cellData [][]interface{}) *File {
for r, row := range cellData {
for c, value := range row {
cell, _ := CoordinatesToCellName(c+1, r+1)
- f.SetCellValue("Sheet1", cell, value)
+ _ = f.SetCellValue("Sheet1", cell, value)
}
}
return f
@@ -245,7 +245,6 @@ func TestCalcCellValue(t *testing.T) {
"=_xlfn.FLOOR.PRECISE(_xlfn.FLOOR.PRECISE(26.75),-5)": "25",
// GCD
"=GCD(0)": "0",
- `=GCD("",1)`: "1",
"=GCD(1,0)": "1",
"=GCD(1,5)": "1",
"=GCD(15,10,25)": "5",
@@ -469,10 +468,43 @@ func TestCalcCellValue(t *testing.T) {
"=TRUNC(-99.999,-1)": "-90",
"=TRUNC(TRUNC(1),-1)": "0",
// Statistical Functions
+ // AVERAGE
+ "=AVERAGE(INT(1))": "1",
+ "=AVERAGE(A1)": "1",
+ "=AVERAGE(A1:A2)": "1.5",
+ "=AVERAGE(D2:F9)": "38014.125",
+ // AVERAGEA
+ "=AVERAGEA(INT(1))": "1",
+ "=AVERAGEA(A1)": "1",
+ "=AVERAGEA(A1:A2)": "1.5",
+ "=AVERAGEA(D2:F9)": "12671.375",
+ // COUNT
+ "=COUNT()": "0",
+ "=COUNT(E1:F2,\"text\",1,INT(2))": "3",
// COUNTA
- `=COUNTA()`: "0",
- `=COUNTA(A1:A5,B2:B5,"text",1,2)`: "8",
- `=COUNTA(COUNTA(1))`: "1",
+ "=COUNTA()": "0",
+ "=COUNTA(A1:A5,B2:B5,\"text\",1,INT(2))": "8",
+ "=COUNTA(COUNTA(1),MUNIT(1))": "2",
+ // COUNTBLANK
+ "=COUNTBLANK(MUNIT(1))": "0",
+ "=COUNTBLANK(1)": "0",
+ "=COUNTBLANK(B1:C1)": "1",
+ "=COUNTBLANK(C1)": "1",
+ // MAX
+ "=MAX(1)": "1",
+ "=MAX(TRUE())": "1",
+ "=MAX(0.5,TRUE())": "1",
+ "=MAX(FALSE())": "0",
+ "=MAX(MUNIT(2))": "1",
+ "=MAX(INT(1))": "1",
+ // MAXA
+ "=MAXA(1)": "1",
+ "=MAXA(TRUE())": "1",
+ "=MAXA(0.5,TRUE())": "1",
+ "=MAXA(FALSE())": "0",
+ "=MAXA(MUNIT(2))": "1",
+ "=MAXA(INT(1))": "1",
+ "=MAXA(A1:B4,MUNIT(1),INT(0),1,E1:F2,\"\")": "36693",
// MEDIAN
"=MEDIAN(A1:A5,12)": "2",
"=MEDIAN(A1:A5)": "1.5",
@@ -482,8 +514,9 @@ func TestCalcCellValue(t *testing.T) {
"=ISBLANK(A1)": "FALSE",
"=ISBLANK(A5)": "TRUE",
// ISERR
- "=ISERR(A1)": "FALSE",
- "=ISERR(NA())": "FALSE",
+ "=ISERR(A1)": "FALSE",
+ "=ISERR(NA())": "FALSE",
+ "=ISERR(POWER(0,-1)))": "TRUE",
// ISERROR
"=ISERROR(A1)": "FALSE",
"=ISERROR(NA())": "TRUE",
@@ -497,7 +530,7 @@ func TestCalcCellValue(t *testing.T) {
"=ISNONTEXT(A1)": "FALSE",
"=ISNONTEXT(A5)": "TRUE",
`=ISNONTEXT("Excelize")`: "FALSE",
- "=ISNONTEXT(NA())": "FALSE",
+ "=ISNONTEXT(NA())": "TRUE",
// ISNUMBER
"=ISNUMBER(A1)": "TRUE",
"=ISNUMBER(D1)": "FALSE",
@@ -507,8 +540,6 @@ func TestCalcCellValue(t *testing.T) {
// ISTEXT
"=ISTEXT(D1)": "TRUE",
"=ISTEXT(A1)": "FALSE",
- // NA
- "=NA()": "#N/A",
// SHEET
"SHEET()": "1",
// Logical Functions
@@ -547,6 +578,10 @@ func TestCalcCellValue(t *testing.T) {
// CLEAN
"=CLEAN(\"\u0009clean text\")": "clean text",
"=CLEAN(0)": "0",
+ // CONCAT
+ "=CONCAT(TRUE(),1,FALSE(),\"0\",INT(2))": "TRUE1FALSE02",
+ // CONCATENATE
+ "=CONCATENATE(TRUE(),1,FALSE(),\"0\",INT(2))": "TRUE1FALSE02",
// EXACT
"=EXACT(1,\"1\")": "TRUE",
"=EXACT(1,1)": "TRUE",
@@ -756,6 +791,7 @@ func TestCalcCellValue(t *testing.T) {
`=_xlfn.FLOOR.PRECISE(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// GCD
"=GCD()": "GCD requires at least 1 argument",
+ "=GCD(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
"=GCD(-1)": "GCD only accepts positive arguments",
"=GCD(1,-1)": "GCD only accepts positive arguments",
`=GCD("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
@@ -897,8 +933,22 @@ func TestCalcCellValue(t *testing.T) {
`=TRUNC("X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
`=TRUNC(1,"X")`: "strconv.ParseFloat: parsing \"X\": invalid syntax",
// Statistical Functions
+ // AVERAGE
+ "=AVERAGE(H1)": "AVERAGE divide by zero",
+ // AVERAGE
+ "=AVERAGEA(H1)": "AVERAGEA divide by zero",
+ // COUNTBLANK
+ "=COUNTBLANK()": "COUNTBLANK requires 1 argument",
+ "=COUNTBLANK(1,2)": "COUNTBLANK requires 1 argument",
+ // MAX
+ "=MAX()": "MAX requires at least 1 argument",
+ "=MAX(NA())": "#N/A",
+ // MAXA
+ "=MAXA()": "MAXA requires at least 1 argument",
+ "=MAXA(NA())": "#N/A",
// MEDIAN
"=MEDIAN()": "MEDIAN requires at least 1 argument",
+ "=MEDIAN(\"\")": "strconv.ParseFloat: parsing \"\": invalid syntax",
"=MEDIAN(D1:D2)": "strconv.ParseFloat: parsing \"Month\": invalid syntax",
// Information Functions
// ISBLANK
@@ -922,6 +972,7 @@ func TestCalcCellValue(t *testing.T) {
// ISTEXT
"=ISTEXT()": "ISTEXT requires 1 argument",
// NA
+ "=NA()": "#N/A",
"=NA(1)": "NA accepts no arguments",
// SHEET
"=SHEET(1)": "SHEET accepts no arguments",
@@ -956,6 +1007,10 @@ func TestCalcCellValue(t *testing.T) {
// CLEAN
"=CLEAN()": "CLEAN requires 1 argument",
"=CLEAN(1,2)": "CLEAN requires 1 argument",
+ // CONCAT
+ "=CONCAT(MUNIT(2))": "CONCAT requires arguments to be strings",
+ // CONCATENATE
+ "=CONCATENATE(MUNIT(2))": "CONCATENATE requires arguments to be strings",
// EXACT
"=EXACT()": "EXACT requires 2 arguments",
"=EXACT(1,2,3)": "EXACT requires 2 arguments",
@@ -1197,6 +1252,13 @@ func TestCalcToBool(t *testing.T) {
assert.Equal(t, b.Boolean, true)
assert.Equal(t, b.Number, 1.0)
}
+
+func TestCalcToList(t *testing.T) {
+ assert.Equal(t, []formulaArg(nil), newEmptyFormulaArg().ToList())
+ formulaList := []formulaArg{newEmptyFormulaArg()}
+ assert.Equal(t, formulaList, newListFormulaArg(formulaList).ToList())
+}
+
func TestCalcCompareFormulaArg(t *testing.T) {
assert.Equal(t, compareFormulaArg(newEmptyFormulaArg(), newEmptyFormulaArg(), false, false), criteriaEq)
lhs := newListFormulaArg([]formulaArg{newEmptyFormulaArg()})
@@ -1253,6 +1315,25 @@ func TestCalcVLOOKUP(t *testing.T) {
}
}
+func TestCalcMAX(t *testing.T) {
+ cellData := [][]interface{}{
+ {0.5, "TRUE"},
+ }
+ f := prepareCalcData(cellData)
+ formulaList := map[string]string{
+ "=MAX(0.5,B1)": "0.5",
+ "=MAX(A1:B1)": "0.5",
+ "=MAXA(A1:B1)": "1",
+ "=MAXA(0.5,B1)": "1",
+ }
+ for formula, expected := range formulaList {
+ assert.NoError(t, f.SetCellFormula("Sheet1", "B10", formula))
+ result, err := f.CalcCellValue("Sheet1", "B10")
+ assert.NoError(t, err, formula)
+ assert.Equal(t, expected, result, formula)
+ }
+}
+
func TestCalcHLOOKUP(t *testing.T) {
cellData := [][]interface{}{
{"Example Result Table"},
diff --git a/cell_test.go b/cell_test.go
index 93e9f4c..c3c20f7 100644
--- a/cell_test.go
+++ b/cell_test.go
@@ -16,12 +16,13 @@ func TestConcurrency(t *testing.T) {
wg := new(sync.WaitGroup)
for i := 1; i <= 5; i++ {
wg.Add(1)
- go func(val int) {
- f.SetCellValue("Sheet1", fmt.Sprintf("A%d", val), val)
- f.SetCellValue("Sheet1", fmt.Sprintf("B%d", val), strconv.Itoa(val))
- f.GetCellValue("Sheet1", fmt.Sprintf("A%d", val))
+ go func(val int, t *testing.T) {
+ assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("A%d", val), val))
+ assert.NoError(t, f.SetCellValue("Sheet1", fmt.Sprintf("B%d", val), strconv.Itoa(val)))
+ _, err := f.GetCellValue("Sheet1", fmt.Sprintf("A%d", val))
+ assert.NoError(t, err)
wg.Done()
- }(i)
+ }(i, t)
}
wg.Wait()
val, err := f.GetCellValue("Sheet1", "A1")
diff --git a/col.go b/col.go
index 9d46733..0980596 100644
--- a/col.go
+++ b/col.go
@@ -1,4 +1,4 @@
-// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
@@ -35,7 +35,6 @@ type Cols struct {
err error
curCol, totalCol, stashCol, totalRow int
sheet string
- cols []xlsxCols
f *File
sheetXML []byte
}
@@ -140,7 +139,6 @@ func (cols *Cols) Rows() ([]string, error) {
// columnXMLIterator defined runtime use field for the worksheet column SAX parser.
type columnXMLIterator struct {
err error
- inElement string
cols Cols
cellCol, curRow, row int
}
@@ -175,7 +173,6 @@ func columnXMLHandler(colIterator *columnXMLIterator, xmlElement *xml.StartEleme
colIterator.cols.totalCol = colIterator.cellCol
}
}
- return
}
// Cols returns a columns iterator, used for streaming reading data for a
diff --git a/col_test.go b/col_test.go
index 97c4b7f..706f90a 100644
--- a/col_test.go
+++ b/col_test.go
@@ -138,7 +138,7 @@ func TestColsRows(t *testing.T) {
f := NewFile()
f.NewSheet("Sheet1")
- cols, err := f.Cols("Sheet1")
+ _, err := f.Cols("Sheet1")
assert.NoError(t, err)
assert.NoError(t, f.SetCellValue("Sheet1", "A1", 1))
@@ -150,12 +150,12 @@ func TestColsRows(t *testing.T) {
f = NewFile()
f.XLSX["xl/worksheets/sheet1.xml"] = nil
- cols, err = f.Cols("Sheet1")
+ _, err = f.Cols("Sheet1")
if !assert.NoError(t, err) {
t.FailNow()
}
f = NewFile()
- cols, err = f.Cols("Sheet1")
+ cols, err := f.Cols("Sheet1")
if !assert.NoError(t, err) {
t.FailNow()
}
diff --git a/crypt.go b/crypt.go
index 8ae8332..64eadd6 100644
--- a/crypt.go
+++ b/crypt.go
@@ -1,4 +1,4 @@
-// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
@@ -42,14 +42,7 @@ var (
packageOffset = 8 // First 8 bytes are the size of the stream
packageEncryptionChunkSize = 4096
iterCount = 50000
- cryptoIdentifier = []byte{ // checking protect workbook by [MS-OFFCRYPTO] - v20181211 3.1 FeatureIdentifier
- 0x3c, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x69, 0x00, 0x63, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x73, 0x00,
- 0x6f, 0x00, 0x66, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x43, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x74, 0x00,
- 0x61, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x72, 0x00, 0x2e, 0x00, 0x44, 0x00, 0x61, 0x00,
- 0x74, 0x00, 0x61, 0x00, 0x53, 0x00, 0x70, 0x00, 0x61, 0x00, 0x63, 0x00, 0x65, 0x00, 0x73, 0x00,
- 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
- }
- oleIdentifier = []byte{
+ oleIdentifier = []byte{
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1,
}
)
@@ -153,7 +146,6 @@ func Decrypt(raw []byte, opt *Options) (packageBuf []byte, err error) {
return standardDecrypt(encryptionInfoBuf, encryptedPackageBuf, opt)
default:
err = errors.New("unsupport encryption mechanism")
- break
}
return
}
@@ -209,11 +201,11 @@ func Encrypt(raw []byte, opt *Options) (packageBuf []byte, err error) {
return
}
// Use the package key and the IV to encrypt the HMAC key.
- encryptedHmacKey, err := crypt(true, encryptionInfo.KeyData.CipherAlgorithm, encryptionInfo.KeyData.CipherChaining, packageKey, hmacKeyIV, hmacKey)
+ encryptedHmacKey, _ := crypt(true, encryptionInfo.KeyData.CipherAlgorithm, encryptionInfo.KeyData.CipherChaining, packageKey, hmacKeyIV, hmacKey)
// Create the HMAC.
h := hmac.New(sha512.New, append(hmacKey, encryptedPackage...))
for _, buf := range [][]byte{hmacKey, encryptedPackage} {
- h.Write(buf)
+ _, _ = h.Write(buf)
}
hmacValue := h.Sum(nil)
// Generate an initialization vector for encrypting the resulting HMAC value.
@@ -222,7 +214,7 @@ func Encrypt(raw []byte, opt *Options) (packageBuf []byte, err error) {
return
}
// Encrypt the value.
- encryptedHmacValue, err := crypt(true, encryptionInfo.KeyData.CipherAlgorithm, encryptionInfo.KeyData.CipherChaining, packageKey, hmacValueIV, hmacValue)
+ encryptedHmacValue, _ := crypt(true, encryptionInfo.KeyData.CipherAlgorithm, encryptionInfo.KeyData.CipherChaining, packageKey, hmacValueIV, hmacValue)
// Put the encrypted key and value on the encryption info.
encryptionInfo.DataIntegrity.EncryptedHmacKey = base64.StdEncoding.EncodeToString(encryptedHmacKey)
encryptionInfo.DataIntegrity.EncryptedHmacValue = base64.StdEncoding.EncodeToString(encryptedHmacValue)
@@ -235,7 +227,7 @@ func Encrypt(raw []byte, opt *Options) (packageBuf []byte, err error) {
return
}
// Encrypt the package key with the encryption key.
- encryptedKeyValue, err := crypt(true, encryptionInfo.KeyEncryptors.KeyEncryptor[0].EncryptedKey.CipherAlgorithm, encryptionInfo.KeyEncryptors.KeyEncryptor[0].EncryptedKey.CipherChaining, key, keyEncryptors, packageKey)
+ encryptedKeyValue, _ := crypt(true, encryptionInfo.KeyEncryptors.KeyEncryptor[0].EncryptedKey.CipherAlgorithm, encryptionInfo.KeyEncryptors.KeyEncryptor[0].EncryptedKey.CipherChaining, key, keyEncryptors, packageKey)
encryptionInfo.KeyEncryptors.KeyEncryptor[0].EncryptedKey.EncryptedKeyValue = base64.StdEncoding.EncodeToString(encryptedKeyValue)
// Verifier hash
@@ -412,7 +404,7 @@ func standardConvertPasswdToKey(header StandardEncryptionHeader, verifier Standa
// standardXORBytes perform XOR operations for two bytes slice.
func standardXORBytes(a, b []byte) []byte {
- r := make([][2]byte, len(a), len(a))
+ r := make([][2]byte, len(a))
for i, e := range a {
r[i] = [2]byte{e, b[i]}
}
@@ -447,7 +439,7 @@ func agileDecrypt(encryptionInfoBuf, encryptedPackageBuf []byte, opt *Options) (
if err != nil {
return
}
- packageKey, err := crypt(false, encryptedKey.CipherAlgorithm, encryptedKey.CipherChaining, key, saltValue, encryptedKeyValue)
+ packageKey, _ := crypt(false, encryptedKey.CipherAlgorithm, encryptedKey.CipherChaining, key, saltValue, encryptedKeyValue)
// Use the package key to decrypt the package.
return cryptPackage(false, packageKey, encryptedPackageBuf, encryptionInfo)
}
@@ -503,7 +495,7 @@ func hashing(hashAlgorithm string, buffer ...[]byte) (key []byte) {
return key
}
for _, buf := range buffer {
- handler.Write(buf)
+ _, _ = handler.Write(buf)
}
key = handler.Sum(nil)
return key
diff --git a/drawing.go b/drawing.go
index f0eb7e9..2518651 100644
--- a/drawing.go
+++ b/drawing.go
@@ -1,4 +1,4 @@
-// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
@@ -51,7 +51,6 @@ func (f *File) prepareChartSheetDrawing(cs *xlsxChartsheet, drawingID int, sheet
cs.Drawing = &xlsxDrawing{
RID: "rId" + strconv.Itoa(rID),
}
- return
}
// addChart provides a function to create chart as xl/charts/chart%d.xml by
@@ -1272,7 +1271,6 @@ func (f *File) addSheetDrawingChart(drawingXML string, rID int, formatSet *forma
}
content.AbsoluteAnchor = append(content.AbsoluteAnchor, &absoluteAnchor)
f.Drawings[drawingXML] = content
- return
}
// deleteDrawing provides a function to delete chart graphic frame by given by
diff --git a/excelize_test.go b/excelize_test.go
index 1b48872..8bce6d1 100644
--- a/excelize_test.go
+++ b/excelize_test.go
@@ -542,10 +542,10 @@ func TestWriteArrayFormula(t *testing.T) {
assert.NoError(t, f.SetCellFormula("Sheet1", avgCell, fmt.Sprintf("ROUND(AVERAGEIF(%s,%s,%s),0)", assocRange, nameCell, valRange)))
ref := stdevCell + ":" + stdevCell
- t := STCellFormulaTypeArray
+ arr := STCellFormulaTypeArray
// Use an array formula for standard deviation
- f.SetCellFormula("Sheet1", stdevCell, fmt.Sprintf("ROUND(STDEVP(IF(%s=%s,%s)),0)", assocRange, nameCell, valRange),
- FormulaOpts{}, FormulaOpts{Type: &t}, FormulaOpts{Ref: &ref})
+ assert.NoError(t, f.SetCellFormula("Sheet1", stdevCell, fmt.Sprintf("ROUND(STDEVP(IF(%s=%s,%s)),0)", assocRange, nameCell, valRange),
+ FormulaOpts{}, FormulaOpts{Type: &arr}, FormulaOpts{Ref: &ref}))
}
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestWriteArrayFormula.xlsx")))
diff --git a/file.go b/file.go
index 9adc859..582099e 100644
--- a/file.go
+++ b/file.go
@@ -1,4 +1,4 @@
-// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
diff --git a/file_test.go b/file_test.go
index 0f979b8..656271f 100644
--- a/file_test.go
+++ b/file_test.go
@@ -35,7 +35,7 @@ func BenchmarkWrite(b *testing.B) {
func TestWriteTo(t *testing.T) {
f := File{}
buf := bytes.Buffer{}
- f.XLSX = make(map[string][]byte, 0)
+ f.XLSX = make(map[string][]byte)
f.XLSX["/d/"] = []byte("s")
_, err := f.WriteTo(bufio.NewWriter(&buf))
assert.EqualError(t, err, "zip: write to directory")
diff --git a/lib.go b/lib.go
index 0ebe468..b6ea321 100644
--- a/lib.go
+++ b/lib.go
@@ -421,7 +421,7 @@ func (f *File) setIgnorableNameSpace(path string, index int, ns xml.Attr) {
// addSheetNameSpace add XML attribute for worksheet.
func (f *File) addSheetNameSpace(sheet string, ns xml.Attr) {
- name, _ := f.sheetMap[trimSheetName(sheet)]
+ name := f.sheetMap[trimSheetName(sheet)]
f.addNameSpaces(name, ns)
}
diff --git a/picture.go b/picture.go
index 77898fc..e46d37e 100644
--- a/picture.go
+++ b/picture.go
@@ -1,4 +1,4 @@
-// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
@@ -613,7 +613,7 @@ func (f *File) drawingResize(sheet string, cell string, width, height float64, f
}
if inMergeCell {
rng, _ = areaRangeToCoordinates(mergeCell.GetStartAxis(), mergeCell.GetEndAxis())
- sortCoordinates(rng)
+ _ = sortCoordinates(rng)
}
}
if inMergeCell {
diff --git a/pivotTable.go b/pivotTable.go
index bffda17..ff21ac1 100644
--- a/pivotTable.go
+++ b/pivotTable.go
@@ -1,4 +1,4 @@
-// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
@@ -615,7 +615,7 @@ func (f *File) getPivotTableFieldsSubtotal(fields []PivotTableField) []string {
enums := []string{"average", "count", "countNums", "max", "min", "product", "stdDev", "stdDevp", "sum", "var", "varp"}
inEnums := func(enums []string, val string) string {
for _, enum := range enums {
- if strings.ToLower(enum) == strings.ToLower(val) {
+ if strings.EqualFold(enum, val) {
return enum
}
}
diff --git a/rows.go b/rows.go
index 75bea47..7b4f998 100644
--- a/rows.go
+++ b/rows.go
@@ -1,4 +1,4 @@
-// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
@@ -60,7 +60,6 @@ type Rows struct {
err error
curRow, totalRow, stashRow int
sheet string
- rows []xlsxRow
f *File
decoder *xml.Decoder
}
@@ -165,7 +164,6 @@ func rowXMLHandler(rowIterator *rowXMLIterator, xmlElement *xml.StartElement) {
val, _ := colCell.getValueFrom(rowIterator.rows.f, rowIterator.d)
rowIterator.columns = append(appendSpace(blank, rowIterator.columns), val)
}
- return
}
// Rows returns a rows iterator, used for streaming reading data for a
diff --git a/sheet.go b/sheet.go
index b0e2971..26c0081 100644
--- a/sheet.go
+++ b/sheet.go
@@ -610,8 +610,8 @@ func (f *File) copySheet(from, to int) error {
if ok {
f.XLSX[toRels] = f.XLSX[fromRels]
}
- fromSheetXMLPath, _ := f.sheetMap[trimSheetName(fromSheet)]
- fromSheetAttr, _ := f.xmlAttr[fromSheetXMLPath]
+ fromSheetXMLPath := f.sheetMap[trimSheetName(fromSheet)]
+ fromSheetAttr := f.xmlAttr[fromSheetXMLPath]
f.xmlAttr[path] = fromSheetAttr
return err
}
diff --git a/sheet_test.go b/sheet_test.go
index f218da7..a721472 100644
--- a/sheet_test.go
+++ b/sheet_test.go
@@ -409,7 +409,7 @@ func newSheetWithSet() {
file := NewFile()
file.NewSheet("sheet1")
for i := 0; i < 1000; i++ {
- file.SetCellInt("sheet1", "A"+strconv.Itoa(i+1), i)
+ _ = file.SetCellInt("sheet1", "A"+strconv.Itoa(i+1), i)
}
file = nil
}
@@ -426,7 +426,7 @@ func newSheetWithSave() {
file := NewFile()
file.NewSheet("sheet1")
for i := 0; i < 1000; i++ {
- file.SetCellInt("sheet1", "A"+strconv.Itoa(i+1), i)
+ _ = file.SetCellInt("sheet1", "A"+strconv.Itoa(i+1), i)
}
- file.Save()
+ _ = file.Save()
}
diff --git a/stream.go b/stream.go
index e2f7935..f5fda9d 100644
--- a/stream.go
+++ b/stream.go
@@ -1,4 +1,4 @@
-// Copyright 2016 - 2020 The excelize Authors. All rights reserved. Use of
+// Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
// this source code is governed by a BSD-style license that can be found in
// the LICENSE file.
//
@@ -93,9 +93,9 @@ func (f *File) NewStreamWriter(sheet string) (*StreamWriter, error) {
}
f.streams[sheetXML] = sw
- sw.rawData.WriteString(XMLHeader + `<worksheet` + templateNamespaceIDMap)
+ _, _ = sw.rawData.WriteString(XMLHeader + `<worksheet` + templateNamespaceIDMap)
bulkAppendFields(&sw.rawData, sw.worksheet, 2, 6)
- sw.rawData.WriteString(`<sheetData>`)
+ _, _ = sw.rawData.WriteString(`<sheetData>`)
return sw, err
}
@@ -184,7 +184,7 @@ func (sw *StreamWriter) AddTable(hcell, vcell, format string) error {
tableXML := strings.Replace(sheetRelationshipsTableXML, "..", "xl", -1)
// Add first table for given sheet.
- sheetPath, _ := sw.File.sheetMap[trimSheetName(sw.Sheet)]
+ sheetPath := sw.File.sheetMap[trimSheetName(sw.Sheet)]
sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetPath, "xl/worksheets/") + ".rels"
rID := sw.File.addRels(sheetRels, SourceRelationshipTable, sheetRelationshipsTableXML, "")
@@ -296,12 +296,12 @@ func (sw *StreamWriter) SetRow(axis string, values []interface{}) error {
val = v.Value
}
if err = setCellValFunc(&c, val); err != nil {
- sw.rawData.WriteString(`</row>`)
+ _, _ = sw.rawData.WriteString(`</row>`)
return err
}
writeCell(&sw.rawData, c)
}
- sw.rawData.WriteString(`</row>`)
+ _, _ = sw.rawData.WriteString(`</row>`)
return sw.rawData.Sync()
}
@@ -361,7 +361,7 @@ func setCellIntFunc(c *xlsxC, val interface{}) (err error) {
}
func writeCell(buf *bufferedWriter, c xlsxC) {
- buf.WriteString(`<c`)
+ _, _ = buf.WriteString(`<c`)
if c.XMLSpace.Value != "" {
fmt.Fprintf(buf, ` xml:%s="%s"`, c.XMLSpace.Name.Local, c.XMLSpace.Value)
}
@@ -372,22 +372,22 @@ func writeCell(buf *bufferedWriter, c xlsxC) {
if c.T != "" {
fmt.Fprintf(buf, ` t="%s"`, c.T)
}
- buf.WriteString(`>`)
+ _, _ = buf.WriteString(`>`)
if c.V != "" {
- buf.WriteString(`<v>`)
- xml.EscapeText(buf, []byte(c.V))
- buf.WriteString(`</v>`)
+ _, _ = buf.WriteString(`<v>`)
+ _ = xml.EscapeText(buf, []byte(c.V))
+ _, _ = buf.WriteString(`</v>`)
}
- buf.WriteString(`</c>`)
+ _, _ = buf.WriteString(`</c>`)
}
// Flush ending the streaming writing process.
func (sw *StreamWriter) Flush() error {
- sw.rawData.WriteString(`</sheetData>`)
+ _, _ = sw.rawData.WriteString(`</sheetData>`)
bulkAppendFields(&sw.rawData, sw.worksheet, 8, 38)
- sw.rawData.WriteString(sw.tableParts)
+ _, _ = sw.rawData.WriteString(sw.tableParts)
bulkAppendFields(&sw.rawData, sw.worksheet, 40, 40)
- sw.rawData.WriteString(`</worksheet>`)
+ _, _ = sw.rawData.WriteString(`</worksheet>`)
if err := sw.rawData.Flush(); err != nil {
return err
}
@@ -407,7 +407,7 @@ func bulkAppendFields(w io.Writer, ws *xlsxWorksheet, from, to int) {
enc := xml.NewEncoder(w)
for i := 0; i < s.NumField(); i++ {
if from <= i && i <= to {
- enc.Encode(s.Field(i).Interface())
+ _ = enc.Encode(s.Field(i).Interface())
}
}
}
diff --git a/stream_test.go b/stream_test.go
index ec7bd08..7c6eb9b 100644
--- a/stream_test.go
+++ b/stream_test.go
@@ -26,7 +26,7 @@ func BenchmarkStreamWriter(b *testing.B) {
streamWriter, _ := file.NewStreamWriter("Sheet1")
for rowID := 10; rowID <= 110; rowID++ {
cell, _ := CoordinatesToCellName(1, rowID)
- streamWriter.SetRow(cell, row)
+ _ = streamWriter.SetRow(cell, row)
}
}
@@ -98,7 +98,7 @@ func TestStreamWriter(t *testing.T) {
file = NewFile()
delete(file.Sheet, "xl/worksheets/sheet1.xml")
file.XLSX["xl/worksheets/sheet1.xml"] = MacintoshCyrillicCharset
- streamWriter, err = file.NewStreamWriter("Sheet1")
+ _, err = file.NewStreamWriter("Sheet1")
assert.EqualError(t, err, "xml decode error: XML syntax error on line 1: invalid UTF-8")
}
diff --git a/styles.go b/styles.go
index 851332b..06215f3 100644
--- a/styles.go
+++ b/styles.go
@@ -2043,33 +2043,33 @@ var getXfIDFuncs = map[string]func(int, xlsxXf, *Style) bool{
},
"font": func(fontID int, xf xlsxXf, style *Style) bool {
if style.Font == nil {
- return (xf.FontID == nil || *xf.FontID == 0) && (xf.ApplyFont == nil || *xf.ApplyFont == false)
+ return (xf.FontID == nil || *xf.FontID == 0) && (xf.ApplyFont == nil || !*xf.ApplyFont)
}
- return xf.FontID != nil && *xf.FontID == fontID && xf.ApplyFont != nil && *xf.ApplyFont == true
+ return xf.FontID != nil && *xf.FontID == fontID && xf.ApplyFont != nil && *xf.ApplyFont
},
"fill": func(fillID int, xf xlsxXf, style *Style) bool {
if style.Fill.Type == "" {
- return (xf.FillID == nil || *xf.FillID == 0) && (xf.ApplyFill == nil || *xf.ApplyFill == false)
+ return (xf.FillID == nil || *xf.FillID == 0) && (xf.ApplyFill == nil || !*xf.ApplyFill)
}
- return xf.FillID != nil && *xf.FillID == fillID && xf.ApplyFill != nil && *xf.ApplyFill == true
+ return xf.FillID != nil && *xf.FillID == fillID && xf.ApplyFill != nil && *xf.ApplyFill
},
"border": func(borderID int, xf xlsxXf, style *Style) bool {
if len(style.Border) == 0 {
- return (xf.BorderID == nil || *xf.BorderID == 0) && (xf.ApplyBorder == nil || *xf.ApplyBorder == false)
+ return (xf.BorderID == nil || *xf.BorderID == 0) && (xf.ApplyBorder == nil || !*xf.ApplyBorder)
}
- return xf.BorderID != nil && *xf.BorderID == borderID && xf.ApplyBorder != nil && *xf.ApplyBorder == true
+ return xf.BorderID != nil && *xf.BorderID == borderID && xf.ApplyBorder != nil && *xf.ApplyBorder
},
"alignment": func(ID int, xf xlsxXf, style *Style) bool {
if style.Alignment == nil {
- return xf.ApplyAlignment == nil || *xf.ApplyAlignment == false
+ return xf.ApplyAlignment == nil || !*xf.ApplyAlignment
}
return reflect.DeepEqual(xf.Alignment, newAlignment(style))
},
"protection": func(ID int, xf xlsxXf, style *Style) bool {
if style.Protection == nil {
- return xf.ApplyProtection == nil || *xf.ApplyProtection == false
+ return xf.ApplyProtection == nil || !*xf.ApplyProtection
}
- return reflect.DeepEqual(xf.Protection, newProtection(style)) && xf.ApplyProtection != nil && *xf.ApplyProtection == true
+ return reflect.DeepEqual(xf.Protection, newProtection(style)) && xf.ApplyProtection != nil && *xf.ApplyProtection
},
}
diff --git a/table.go b/table.go
index ba8de25..8862b57 100644
--- a/table.go
+++ b/table.go
@@ -39,7 +39,14 @@ func parseFormatTableSet(formatSet string) (*formatTable, error) {
//
// Create a table of F2:H6 on Sheet2 with format set:
//
-// err := f.AddTable("Sheet2", "F2", "H6", `{"table_name":"table","table_style":"TableStyleMedium2", "show_first_column":true,"show_last_column":true,"show_row_stripes":false,"show_column_stripes":true}`)
+// err := f.AddTable("Sheet2", "F2", "H6", `{
+// "table_name": "table",
+// "table_style": "TableStyleMedium2",
+// "show_first_column": true,
+// "show_last_column": true,
+// "show_row_stripes": false,
+// "show_column_stripes": true
+// }`)
//
// Note that the table must be at least two lines including the header. The
// header cells must contain strings and must be unique, and must set the
@@ -153,7 +160,7 @@ func (f *File) addTable(sheet, tableXML string, x1, y1, x2, y2, i int, formatSet
}
if name == "" {
name = "Column" + strconv.Itoa(idx)
- f.SetCellStr(sheet, cell, name)
+ _ = f.SetCellStr(sheet, cell, name)
}
tableColumn = append(tableColumn, &xlsxTableColumn{
ID: idx,