package nginx import ( "fmt" "io" ) var ( defaultPrefix = "" defaultIndent = "\t" ) // Encoder implements parser.Encoder type Encoder struct { writer io.Writer prefix []byte indent []byte } // SetIndent with the that begins each line (default is emptys string) // and the string repeated for each indentation level (default is tab '\t') func (e *Encoder) SetIndent(prefix, indent string) { e.prefix = make([]byte, 0) e.prefix = append(e.prefix, []byte(prefix)...) e.indent = make([]byte, 0) e.indent = append(e.indent, []byte(indent)...) } // Encode is the main function of the parser.Encoder interface func (e *Encoder) Encode(v interface{}) error { // default indentation if e.prefix == nil || e.indent == nil { e.SetIndent(defaultPrefix, defaultIndent) } // check 'v' vcast, ok := v.(*Line) if !ok { return ErrInvalidReceiver } // empty config if len(vcast.Lines) < 1 { return nil } // actual indentation level indent := 0 // actual lines to write stack := make([]*Line, 0) // push nginx.Lines in reverse order for l := len(vcast.Lines) - 1; l >= 0; l-- { stack = append(stack, vcast.Lines[l]) } for len(stack) > 0 { // pop stack line := stack[len(stack)-1] stack = stack[:len(stack)-1] // line representation repr := make([]byte, 0) if line == nil { // section end indent-- } // 1. add indentation repr = append(repr, []byte(e.prefix)...) for i := 0; i < indent; i++ { repr = append(repr, []byte(e.indent)...) } // 2. section end if line == nil { repr = append(repr, []byte("}\n\n")...) // Note: new line after section for readability // 3. comments } else if line.Type == COMMENT { repr = append(repr, []byte(fmt.Sprintf("#%s\n", line.Components[0]))...) } else if line.Type == COLONCOMMENT { repr = append(repr, []byte(fmt.Sprintf(";%s\n", line.Components[0]))...) // 4.assignments } else if line.Type == ASSIGNMENT { repr = append(repr, []byte(fmt.Sprintf("%s\t\t%s;\n", line.Components[0], line.Components[1]))...) // 5. include } else if line.Type == INCLUDE { repr = append(repr, []byte(fmt.Sprintf("include %s;\n", line.Components[0]))...) // 6. section } else { // push to stack stack = append(stack, nil) // push children lines in reverse order if len(line.Lines) > 0 { for l := len(line.Lines) - 1; l >= 0; l-- { stack = append(stack, line.Lines[l]) } } if len(line.Components) > 1 { repr = append(repr, []byte(fmt.Sprintf("%s %s {\n", line.Components[0], line.Components[1]))...) } else { repr = append(repr, []byte(fmt.Sprintf("%s {\n", line.Components[0]))...) } indent++ } _, err := e.writer.Write(repr) if err != nil { return err } } return nil }