<commit_before>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package draw

import (
	"github.com/richardwilkes/ui/color"
	"github.com/richardwilkes/ui/geom"
	"unsafe"
)

func (gc *graphics) platformSave() {
	// RAW: Implement platformSave for Linux
}

func (gc *graphics) platformRestore() {
	// RAW: Implement platformRestore for Linux
}

func (gc *graphics) platformSetOpacity(opacity float32) {
	// RAW: Implement platformSetOpacity for Linux
}

func (gc *graphics) platformSetFillColor(color color.Color) {
	// RAW: Implement platformSetFillColor for Linux
}

func (gc *graphics) platformSetStrokeColor(color color.Color) {
	// RAW: Implement platformSetStrokeColor for Linux
}

func (gc *graphics) platformSetStrokeWidth(width float32) {
	// RAW: Implement platformSetStrokeWidth for Linux
}

func (gc *graphics) platformFillRect(bounds geom.Rect) {
	// RAW: Implement platformFillRect for Linux
}

func (gc *graphics) platformStrokeRect(bounds geom.Rect) {
	// RAW: Implement platformFillRect for Linux
}

func (gc *graphics) platformFillEllipse(bounds geom.Rect) {
	// RAW: Implement platformFillEllipse for Linux
}

func (gc *graphics) platformStrokeEllipse(bounds geom.Rect) {
	// RAW: Implement platformStrokeEllipse for Linux
}

func (gc *graphics) platformFillPath() {
	// RAW: Implement platformFillPath for Linux
}

func (gc *graphics) platformFillPathEvenOdd() {
	// RAW: Implement platformFillPathEvenOdd for Linux
}

func (gc *graphics) platformStrokePath() {
	// RAW: Implement platformStrokePath for Linux
}

func (gc *graphics) platformFillAndStrokePath() {
	// RAW: Implement platformFillAndStrokePath for Linux
}

func (gc *graphics) platformBeginPath() {
	// RAW: Implement platformBeginPath for Linux
}

func (gc *graphics) platformClosePath() {
	// RAW: Implement platformClosePath for Linux
}

func (gc *graphics) platformMoveTo(x, y float32) {
	// RAW: Implement platformMoveTo for Linux
}

func (gc *graphics) platformLineTo(x, y float32) {
	// RAW: Implement platformLineTo for Linux
}

func (gc *graphics) platformArc(cx, cy, radius, startAngleRadians, endAngleRadians float32, clockwise bool) {
	// RAW: Implement platformArc for Linux
}

func (gc *graphics) platformArcTo(x1, y1, x2, y2, radius float32) {
	// RAW: Implement platformArcTo for Linux
}

func (gc *graphics) platformCurveTo(cp1x, cp1y, cp2x, cp2y, x, y float32) {
	// RAW: Implement platformCurveTo for Linux
}

func (gc *graphics) platformQuadCurveTo(cpx, cpy, x, y float32) {
	// RAW: Implement platformQuadCurveTo for Linux
}

func (gc *graphics) platformAddPath(path *geom.Path) {
	// RAW: Implement platformAddPath for Linux
}

func (gc *graphics) platformClip() {
	// RAW: Implement platformClip for Linux
}

func (gc *graphics) platformClipEvenOd() {
	// RAW: Implement platformClipEvenOd for Linux
}

func (gc *graphics) platformClipRect(bounds geom.Rect) {
	// RAW: Implement platformClipRect for Linux
}

func (gc *graphics) platformDrawLinearGradient(gradient *Gradient, sx, sy, ex, ey float32) {
	// RAW: Implement platformDrawLinearGradient for Linux
}

func (gc *graphics) platformDrawRadialGradient(gradient *Gradient, scx, scy, startRadius, ecx, ecy, endRadius float32) {
	// RAW: Implement platformDrawRadialGradient for Linux
}

func (gc *graphics) platformDrawImageInRect(img *Image, bounds geom.Rect) {
	// RAW: Implement platformDrawImageInRect for Linux
}

func (gc *graphics) platformDrawString(x, y float32, str string) {
	// RAW: Implement platformDrawString for Linux
}

func (gc *graphics) platformTranslate(x, y float32) {
	// RAW: Implement platformTranslate for Linux
}

func (gc *graphics) platformScale(x, y float32) {
	// RAW: Implement platformScale for Linux
}

func (gc *graphics) platformRotate(angleInRadians float32) {
	// RAW: Implement platformRotate for Linux
}
<commit_msg>Remove unused import<commit_after>// Copyright (c) 2016 by Richard A. Wilkes. All rights reserved.
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, version 2.0. If a copy of the MPL was not distributed with
// this file, You can obtain one at http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible With Secondary Licenses", as
// defined by the Mozilla Public License, version 2.0.

package draw

import (
	"github.com/richardwilkes/ui/color"
	"github.com/richardwilkes/ui/geom"
)

func (gc *graphics) platformSave() {
	// RAW: Implement platformSave for Linux
}

func (gc *graphics) platformRestore() {
	// RAW: Implement platformRestore for Linux
}

func (gc *graphics) platformSetOpacity(opacity float32) {
	// RAW: Implement platformSetOpacity for Linux
}

func (gc *graphics) platformSetFillColor(color color.Color) {
	// RAW: Implement platformSetFillColor for Linux
}

func (gc *graphics) platformSetStrokeColor(color color.Color) {
	// RAW: Implement platformSetStrokeColor for Linux
}

func (gc *graphics) platformSetStrokeWidth(width float32) {
	// RAW: Implement platformSetStrokeWidth for Linux
}

func (gc *graphics) platformFillRect(bounds geom.Rect) {
	// RAW: Implement platformFillRect for Linux
}

func (gc *graphics) platformStrokeRect(bounds geom.Rect) {
	// RAW: Implement platformFillRect for Linux
}

func (gc *graphics) platformFillEllipse(bounds geom.Rect) {
	// RAW: Implement platformFillEllipse for Linux
}

func (gc *graphics) platformStrokeEllipse(bounds geom.Rect) {
	// RAW: Implement platformStrokeEllipse for Linux
}

func (gc *graphics) platformFillPath() {
	// RAW: Implement platformFillPath for Linux
}

func (gc *graphics) platformFillPathEvenOdd() {
	// RAW: Implement platformFillPathEvenOdd for Linux
}

func (gc *graphics) platformStrokePath() {
	// RAW: Implement platformStrokePath for Linux
}

func (gc *graphics) platformFillAndStrokePath() {
	// RAW: Implement platformFillAndStrokePath for Linux
}

func (gc *graphics) platformBeginPath() {
	// RAW: Implement platformBeginPath for Linux
}

func (gc *graphics) platformClosePath() {
	// RAW: Implement platformClosePath for Linux
}

func (gc *graphics) platformMoveTo(x, y float32) {
	// RAW: Implement platformMoveTo for Linux
}

func (gc *graphics) platformLineTo(x, y float32) {
	// RAW: Implement platformLineTo for Linux
}

func (gc *graphics) platformArc(cx, cy, radius, startAngleRadians, endAngleRadians float32, clockwise bool) {
	// RAW: Implement platformArc for Linux
}

func (gc *graphics) platformArcTo(x1, y1, x2, y2, radius float32) {
	// RAW: Implement platformArcTo for Linux
}

func (gc *graphics) platformCurveTo(cp1x, cp1y, cp2x, cp2y, x, y float32) {
	// RAW: Implement platformCurveTo for Linux
}

func (gc *graphics) platformQuadCurveTo(cpx, cpy, x, y float32) {
	// RAW: Implement platformQuadCurveTo for Linux
}

func (gc *graphics) platformAddPath(path *geom.Path) {
	// RAW: Implement platformAddPath for Linux
}

func (gc *graphics) platformClip() {
	// RAW: Implement platformClip for Linux
}

func (gc *graphics) platformClipEvenOd() {
	// RAW: Implement platformClipEvenOd for Linux
}

func (gc *graphics) platformClipRect(bounds geom.Rect) {
	// RAW: Implement platformClipRect for Linux
}

func (gc *graphics) platformDrawLinearGradient(gradient *Gradient, sx, sy, ex, ey float32) {
	// RAW: Implement platformDrawLinearGradient for Linux
}

func (gc *graphics) platformDrawRadialGradient(gradient *Gradient, scx, scy, startRadius, ecx, ecy, endRadius float32) {
	// RAW: Implement platformDrawRadialGradient for Linux
}

func (gc *graphics) platformDrawImageInRect(img *Image, bounds geom.Rect) {
	// RAW: Implement platformDrawImageInRect for Linux
}

func (gc *graphics) platformDrawString(x, y float32, str string) {
	// RAW: Implement platformDrawString for Linux
}

func (gc *graphics) platformTranslate(x, y float32) {
	// RAW: Implement platformTranslate for Linux
}

func (gc *graphics) platformScale(x, y float32) {
	// RAW: Implement platformScale for Linux
}

func (gc *graphics) platformRotate(angleInRadians float32) {
	// RAW: Implement platformRotate for Linux
}
<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2016 Ivan Dejanovic

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package codegen

import (
	"errors"
	"fmt"
	"mlpl/types"
)

const (
	pc  int = 7 // pc = program counter
	mp  int = 6 // mp = "memory pointer" point to top of memory (for temp storage)
	gp  int = 5 // gp = "global pointer" points to bottom of memory for (global) variable storage
	ac  int = 0 // accumulator
	ac1 int = 1 // 2nd accumulator
)

type codeBuffer struct {
	code        []string
	tmpOffset   int // tmpOffset is the memory offset for temps. It is decremented each time a temp is stored, and incremeted when loaded again.
	emitLoc     int // TM location number for current instruction emission
	highEmitLoc int // Highest TM location emitted so far. For use in conjunction with emitSkip, emitBackup, and emitRestore
}

/* Procedure emitRO emits a register-only TM instruction
   op = the opcode
   r = target register
   s = 1st source register
   t = 2nd source register
*/
func (codeBuf *codeBuffer) emitRO(op string, r int, s int, t int) {
	code := fmt.Sprintf("%3d: %5s %d, %d, %d", codeBuf.emitLoc, op, r, s, t)
	codeBuf.emitLoc += 1
	if codeBuf.highEmitLoc < codeBuf.emitLoc {
		codeBuf.highEmitLoc = codeBuf.emitLoc
	}
	codeBuf.code = append(codeBuf.code, code)
}

/* Procedure emitRM emits a register-to-memory TM instruction
   op = the opcode
   r = target register
   d = the offset
   s = the base register
*/
func (codeBuf *codeBuffer) emitRM(op string, r int, d int, s int) {
	code := fmt.Sprintf("%3d: %5s %d, %d(%d)", codeBuf.emitLoc, op, r, d, s)
	codeBuf.emitLoc += 1
	if codeBuf.highEmitLoc < codeBuf.emitLoc {
		codeBuf.highEmitLoc = codeBuf.emitLoc
	}
	codeBuf.code = append(codeBuf.code, code)
}

// Function emitSkip skips "howMany" code locations for later backpatch. It also returns the current code position
func (codeBuf *codeBuffer) emitSkip(howMany int) int {
	i := codeBuf.emitLoc
	codeBuf.emitLoc += howMany
	if codeBuf.highEmitLoc < codeBuf.emitLoc {
		codeBuf.highEmitLoc = codeBuf.emitLoc
	}

	return i
}

// Procedure emitRestore restores the current code position to the highest previously unemitted position
func (codeBuf *codeBuffer) emitRestore() {
	codeBuf.emitLoc = codeBuf.highEmitLoc
}

/* Procedure emitRM_Abs converts an absolute reference to a pc-relative reference when emitting a register-to-memory TM instruction
   op = the opcode
   r = target register
   a = the absolute location in memory
*/
func (codeBuf *codeBuffer) emitRM_Abs(op string, r int, a int) {
	abs := a - codeBuf.emitLoc + 1
	code := fmt.Sprintf("%3d: %5s %d, %d(%d)", codeBuf.emitLoc, op, r, abs, pc)
	codeBuf.emitLoc += 1
	if codeBuf.highEmitLoc < codeBuf.emitLoc {
		codeBuf.highEmitLoc = codeBuf.emitLoc
	}
	codeBuf.code = append(codeBuf.code, code)
}

func findLoc(bucketMap map[string]types.Bucket, name string) int {
	bucket, ok := bucketMap[name]

	if ok {
		return bucket.MemLoc
	}

	return -1
}

// Procedure genStmt generates code at a statement node
func genStmt(treeNode *types.TreeNode, bucketMap map[string]types.Bucket, codeBuf *codeBuffer) {
	var p1, p2, p3 *types.TreeNode = nil, nil, nil
	var loc int

	switch treeNode.Stmt {
	case types.IfK:
		p1 = treeNode.Children[0]
		p2 = treeNode.Children[1]
		if len(treeNode.Children) == 3 {
			p3 = treeNode.Children[2]
		}

		// Generate code for test expression
		cGen(p1, bucketMap, codeBuf)
		codeBuf.emitSkip(1)

		// Recurse on then part
		cGen(p2, bucketMap, codeBuf)
		codeBuf.emitSkip(1)
		loc = codeBuf.emitSkip(0)
		codeBuf.emitRM_Abs("JEQ", ac, loc)
		codeBuf.emitRestore()

		// Recurse on else part
		cGen(p3, bucketMap, codeBuf)
		loc = codeBuf.emitSkip(0)
		codeBuf.emitRM_Abs("LDA", pc, loc)
		codeBuf.emitRestore()
	case types.RepeatK:
		p1 = treeNode.Children[0]
		p2 = treeNode.Children[1]
		loc = codeBuf.emitSkip(0)

		// Generate code for body
		cGen(p1, bucketMap, codeBuf)
		// Generate code for test
		cGen(p2, bucketMap, codeBuf)

		codeBuf.emitRM_Abs("JEQ", ac, loc)
	case types.AssignK:
		// Generate code for rhs
		p1 = treeNode.Children[0]
		cGen(p1, bucketMap, codeBuf)
		// Now store value
		loc = findLoc(bucketMap, treeNode.Name)
		codeBuf.emitRM("ST", ac, loc, gp)
	case types.ReadK:
		codeBuf.emitRO("IN", ac, 0, 0)
		loc = findLoc(bucketMap, treeNode.Name)
		codeBuf.emitRM("ST", ac, loc, gp)
	case types.WriteK:
		// Generate code for expression to write
		p1 = treeNode.Children[0]
		cGen(p1, bucketMap, codeBuf)
		// Now output it
		codeBuf.emitRO("OUT", ac, 0, 0)
	}
}

// Procedure genExp generates code at an expression node
func genExp(treeNode *types.TreeNode, bucketMap map[string]types.Bucket, codeBuf *codeBuffer) {
	var p1, p2 *types.TreeNode
	var loc int

	switch treeNode.Exp {
	case types.ConstK:
		// Gen code to load integer constant using LDC
		codeBuf.emitRM("LDC", ac, treeNode.Val, 0)
	case types.IdK:
		loc = findLoc(bucketMap, treeNode.Name)
		codeBuf.emitRM("LD", ac, loc, gp)
	case types.OpK:
		p1 = treeNode.Children[0]
		p2 = treeNode.Children[1]
		// Gen code for ac = left arg
		cGen(p1, bucketMap, codeBuf)
		// Gen code to push left operand
		codeBuf.emitRM("ST", ac, codeBuf.tmpOffset, mp)
		codeBuf.tmpOffset -= 1
		// Gen code for ac = right operand
		cGen(p2, bucketMap, codeBuf)
		// Now load left operand
		codeBuf.tmpOffset += 1
		codeBuf.emitRM("LD", ac1, codeBuf.tmpOffset, mp)
		switch treeNode.Op {
		case types.PLUS:
			codeBuf.emitRO("ADD", ac, ac1, ac)
		case types.MINUS:
			codeBuf.emitRO("SUB", ac, ac1, ac)
		case types.TIMES:
			codeBuf.emitRO("MUL", ac, ac1, ac)
		case types.OVER:
			codeBuf.emitRO("DIV", ac, ac1, ac)
		case types.LT:
			codeBuf.emitRO("SUB", ac, ac1, ac)
			codeBuf.emitRM("JLT", ac, 2, pc)
			codeBuf.emitRM("LDC", ac, 0, ac)
			codeBuf.emitRM("LDA", pc, 1, pc)
			codeBuf.emitRM("LDC", ac, 1, ac)
		case types.EQ:
			codeBuf.emitRO("SUB", ac, ac1, ac)
			codeBuf.emitRM("JEQ", ac, 2, pc)
			codeBuf.emitRM("LDC", ac, 0, ac)
			codeBuf.emitRM("LDA", pc, 1, pc)
			codeBuf.emitRM("LDC", ac, 1, ac)
		default:
			panic(errors.New("Unknown operator"))
		}
	}
}

//Procedure cGen recursively generates code by tree traversal
func cGen(treeNode *types.TreeNode, bucketMap map[string]types.Bucket, codeBuf *codeBuffer) {
	if treeNode != nil {
		switch treeNode.Node {
		case types.StmtK:
			genStmt(treeNode, bucketMap, codeBuf)
		case types.ExpK:
			genExp(treeNode, bucketMap, codeBuf)
		default:
			err := errors.New("Unknow type for code generation")
			panic(err)
		}
		cGen(treeNode.Sibling, bucketMap, codeBuf)
	}
}

func CodeGen(treeNode *types.TreeNode, bucketMap map[string]types.Bucket) []string {
	codeBuf := &codeBuffer{make([]string, 0, 0), 0, 0, 0}

	codeBuf.emitRM("LD", mp, 0, ac)
	codeBuf.emitRM("ST", ac, 0, ac)
	cGen(treeNode, bucketMap, codeBuf)
	codeBuf.emitRO("HALT", 0, 0, 0)

	return codeBuf.code
}
<commit_msg>Fixed bugs in code generation.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2016 Ivan Dejanovic

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

package codegen

import (
	"errors"
	"fmt"
	"mlpl/types"
)

const (
	pc  int = 7 // pc = program counter
	mp  int = 6 // mp = "memory pointer" point to top of memory (for temp storage)
	gp  int = 5 // gp = "global pointer" points to bottom of memory for (global) variable storage
	ac  int = 0 // accumulator
	ac1 int = 1 // 2nd accumulator
)

type codeBuffer struct {
	code        []string
	tmpOffset   int // tmpOffset is the memory offset for temps. It is decremented each time a temp is stored, and incremeted when loaded again.
	emitLoc     int // TM location number for current instruction emission
	highEmitLoc int // Highest TM location emitted so far. For use in conjunction with emitSkip, emitBackup, and emitRestore
}

/* Procedure emitRO emits a register-only TM instruction
   op = the opcode
   r = target register
   s = 1st source register
   t = 2nd source register
*/
func (codeBuf *codeBuffer) emitRO(op string, r int, s int, t int) {
	code := fmt.Sprintf("%3d: %5s %d, %d, %d", codeBuf.emitLoc, op, r, s, t)
	codeBuf.emitLoc += 1
	if codeBuf.highEmitLoc < codeBuf.emitLoc {
		codeBuf.highEmitLoc = codeBuf.emitLoc
	}
	codeBuf.code = append(codeBuf.code, code)
}

/* Procedure emitRM emits a register-to-memory TM instruction
   op = the opcode
   r = target register
   d = the offset
   s = the base register
*/
func (codeBuf *codeBuffer) emitRM(op string, r int, d int, s int) {
	code := fmt.Sprintf("%3d: %5s %d, %d(%d)", codeBuf.emitLoc, op, r, d, s)
	codeBuf.emitLoc += 1
	if codeBuf.highEmitLoc < codeBuf.emitLoc {
		codeBuf.highEmitLoc = codeBuf.emitLoc
	}
	codeBuf.code = append(codeBuf.code, code)
}

// Function emitSkip skips "howMany" code locations for later backpatch. It also returns the current code position
func (codeBuf *codeBuffer) emitSkip(howMany int) int {
	i := codeBuf.emitLoc
	codeBuf.emitLoc += howMany
	if codeBuf.highEmitLoc < codeBuf.emitLoc {
		codeBuf.highEmitLoc = codeBuf.emitLoc
	}

	return i
}

// Procedure emitBackup backs up to loc = a previously skipped location
func (codeBuf *codeBuffer) emitBackup(loc int) {
	codeBuf.emitLoc = loc
}

// Procedure emitRestore restores the current code position to the highest previously unemitted position
func (codeBuf *codeBuffer) emitRestore() {
	codeBuf.emitLoc = codeBuf.highEmitLoc
}

/* Procedure emitRM_Abs converts an absolute reference to a pc-relative reference when emitting a register-to-memory TM instruction
   op = the opcode
   r = target register
   a = the absolute location in memory
*/
func (codeBuf *codeBuffer) emitRM_Abs(op string, r int, a int) {
	abs := a - (codeBuf.emitLoc + 1)
	code := fmt.Sprintf("%3d: %5s %d, %d(%d)", codeBuf.emitLoc, op, r, abs, pc)
	codeBuf.emitLoc += 1
	if codeBuf.highEmitLoc < codeBuf.emitLoc {
		codeBuf.highEmitLoc = codeBuf.emitLoc
	}
	codeBuf.code = append(codeBuf.code, code)
}

func findLoc(bucketMap map[string]types.Bucket, name string) int {
	bucket, ok := bucketMap[name]

	if ok {
		return bucket.MemLoc
	}

	return -1
}

// Procedure genStmt generates code at a statement node
func genStmt(treeNode *types.TreeNode, bucketMap map[string]types.Bucket, codeBuf *codeBuffer) {
	var p1, p2, p3 *types.TreeNode = nil, nil, nil
	var savedLoc1, savedLoc2, loc int

	switch treeNode.Stmt {
	case types.IfK:
		p1 = treeNode.Children[0]
		p2 = treeNode.Children[1]
		if len(treeNode.Children) == 3 {
			p3 = treeNode.Children[2]
		}

		// Generate code for test expression
		cGen(p1, bucketMap, codeBuf)
		savedLoc1 = codeBuf.emitSkip(1)

		// Recurse on then part
		cGen(p2, bucketMap, codeBuf)
		savedLoc2 = codeBuf.emitSkip(1)
		loc = codeBuf.emitSkip(0)
		codeBuf.emitBackup(savedLoc1)
		codeBuf.emitRM_Abs("JEQ", ac, loc)
		codeBuf.emitRestore()

		// Recurse on else part
		cGen(p3, bucketMap, codeBuf)
		loc = codeBuf.emitSkip(0)
		codeBuf.emitBackup(savedLoc2)
		codeBuf.emitRM_Abs("LDA", pc, loc)
		codeBuf.emitRestore()
	case types.RepeatK:
		p1 = treeNode.Children[0]
		p2 = treeNode.Children[1]
		loc = codeBuf.emitSkip(0)

		// Generate code for body
		cGen(p1, bucketMap, codeBuf)
		// Generate code for test
		cGen(p2, bucketMap, codeBuf)

		codeBuf.emitRM_Abs("JEQ", ac, loc)
	case types.AssignK:
		// Generate code for rhs
		p1 = treeNode.Children[0]
		cGen(p1, bucketMap, codeBuf)
		// Now store value
		loc = findLoc(bucketMap, treeNode.Name)
		codeBuf.emitRM("ST", ac, loc, gp)
	case types.ReadK:
		codeBuf.emitRO("IN", ac, 0, 0)
		loc = findLoc(bucketMap, treeNode.Name)
		codeBuf.emitRM("ST", ac, loc, gp)
	case types.WriteK:
		// Generate code for expression to write
		p1 = treeNode.Children[0]
		cGen(p1, bucketMap, codeBuf)
		// Now output it
		codeBuf.emitRO("OUT", ac, 0, 0)
	}
}

// Procedure genExp generates code at an expression node
func genExp(treeNode *types.TreeNode, bucketMap map[string]types.Bucket, codeBuf *codeBuffer) {
	var p1, p2 *types.TreeNode
	var loc int

	switch treeNode.Exp {
	case types.ConstK:
		// Gen code to load integer constant using LDC
		codeBuf.emitRM("LDC", ac, treeNode.Val, 0)
	case types.IdK:
		loc = findLoc(bucketMap, treeNode.Name)
		codeBuf.emitRM("LD", ac, loc, gp)
	case types.OpK:
		p1 = treeNode.Children[0]
		p2 = treeNode.Children[1]
		// Gen code for ac = left arg
		cGen(p1, bucketMap, codeBuf)
		// Gen code to push left operand
		codeBuf.emitRM("ST", ac, codeBuf.tmpOffset, mp)
		codeBuf.tmpOffset -= 1
		// Gen code for ac = right operand
		cGen(p2, bucketMap, codeBuf)
		// Now load left operand
		codeBuf.tmpOffset += 1
		codeBuf.emitRM("LD", ac1, codeBuf.tmpOffset, mp)
		switch treeNode.Op {
		case types.PLUS:
			codeBuf.emitRO("ADD", ac, ac1, ac)
		case types.MINUS:
			codeBuf.emitRO("SUB", ac, ac1, ac)
		case types.TIMES:
			codeBuf.emitRO("MUL", ac, ac1, ac)
		case types.OVER:
			codeBuf.emitRO("DIV", ac, ac1, ac)
		case types.LT:
			codeBuf.emitRO("SUB", ac, ac1, ac)
			codeBuf.emitRM("JLT", ac, 2, pc)
			codeBuf.emitRM("LDC", ac, 0, ac)
			codeBuf.emitRM("LDA", pc, 1, pc)
			codeBuf.emitRM("LDC", ac, 1, ac)
		case types.EQ:
			codeBuf.emitRO("SUB", ac, ac1, ac)
			codeBuf.emitRM("JEQ", ac, 2, pc)
			codeBuf.emitRM("LDC", ac, 0, ac)
			codeBuf.emitRM("LDA", pc, 1, pc)
			codeBuf.emitRM("LDC", ac, 1, ac)
		default:
			panic(errors.New("Unknown operator"))
		}
	}
}

//Procedure cGen recursively generates code by tree traversal
func cGen(treeNode *types.TreeNode, bucketMap map[string]types.Bucket, codeBuf *codeBuffer) {
	if treeNode != nil {
		switch treeNode.Node {
		case types.StmtK:
			genStmt(treeNode, bucketMap, codeBuf)
		case types.ExpK:
			genExp(treeNode, bucketMap, codeBuf)
		default:
			err := errors.New("Unknow type for code generation")
			panic(err)
		}
		cGen(treeNode.Sibling, bucketMap, codeBuf)
	}
}

func CodeGen(treeNode *types.TreeNode, bucketMap map[string]types.Bucket) []string {
	codeBuf := &codeBuffer{make([]string, 0, 0), 0, 0, 0}

	codeBuf.emitRM("LD", mp, 0, ac)
	codeBuf.emitRM("ST", ac, 0, ac)
	cGen(treeNode, bucketMap, codeBuf)
	codeBuf.emitRO("HALT", 0, 0, 0)

	return codeBuf.code
}
<|endoftext|>


<commit_before>// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package fieldalignment defines an Analyzer that detects structs that would use less
// memory if their fields were sorted.
package main

import (
	"fmt"
	"go/ast"
	"go/token"
	"go/types"
	"log"
	"sort"
	"strings"

	"golang.org/x/tools/go/analysis"
	"golang.org/x/tools/go/analysis/passes/inspect"
	"golang.org/x/tools/go/ast/inspector"
)

const Doc = `find structs that would use less memory if their fields were sorted

This analyzer find structs that can be rearranged to use less memory, and provides
a suggested edit with the most compact order.

Note that there are two different diagnostics reported. One checks struct size,
and the other reports "pointer bytes" used. Pointer bytes is how many bytes of the
object that the garbage collector has to potentially scan for pointers, for example:

	struct { uint32; string }

have 16 pointer bytes because the garbage collector has to scan up through the string's
inner pointer.

	struct { string; *uint32 }

has 24 pointer bytes because it has to scan further through the *uint32.

	struct { string; uint32 }

has 8 because it can stop immediately after the string pointer.

Be aware that the most compact order is not always the most efficient.
In rare cases it may cause two variables each updated by its own goroutine
to occupy the same CPU cache line, inducing a form of memory contention
known as "false sharing" that slows down both goroutines.
`

var Analyzer = &analysis.Analyzer{
	Name:     "fieldalignment",
	Doc:      Doc,
	Requires: []*analysis.Analyzer{inspect.Analyzer},
	Run:      run,
}

func run(pass *analysis.Pass) (interface{}, error) {
	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
	nodeFilter := []ast.Node{
		(*ast.File)(nil),
		(*ast.StructType)(nil),
	}
	var ignore bool
	inspect.Preorder(nodeFilter, func(node ast.Node) {
		if ignore {
			return
		}

		if nf, ok := node.(*ast.File); ok {
			f := pass.Fset.File(nf.Pos())
			// protobuf 自动生成的 go 文，其编解码器直接依赖其生成的字段顺序，不能优化
			if strings.HasSuffix(f.Name(), ".pb.go") ||
				strings.HasSuffix(f.Name(), "_test.go") ||
				doNotEdit(nf) {
				ignore = true
				return
			}
		}

		var s *ast.StructType
		var ok bool
		if s, ok = node.(*ast.StructType); !ok {
			return
		}
		if tv, ok := pass.TypesInfo.Types[s]; ok {
			if ss, ok1 := tv.Type.(*types.Struct); ok1 {
				fieldalignment(pass, s, ss)
			}
		}
	})
	return nil, nil
}

func doNotEdit(f *ast.File) bool {
	for _, cg := range f.Comments {
		if strings.Contains(cg.Text(), "DO NOT EDIT") {
			return true
		}
	}
	return false
}

var unsafePointerTyp = types.Unsafe.Scope().Lookup("Pointer").(*types.TypeName).Type()

func fieldalignment(pass *analysis.Pass, node *ast.StructType, typ *types.Struct) {
	wordSize := pass.TypesSizes.Sizeof(unsafePointerTyp)
	maxAlign := pass.TypesSizes.Alignof(unsafePointerTyp)

	s := gcSizes{WordSize: wordSize, MaxAlign: maxAlign}
	optimal, indexes := optimalOrder(typ, &s)
	optsz, optptrs := s.Sizeof(optimal), s.ptrdata(optimal)

	var message string
	if sz := s.Sizeof(typ); sz != optsz {
		message = fmt.Sprintf("struct of size %d could be %d", sz, optsz)
	} else if ptrs := s.ptrdata(typ); ptrs != optptrs {
		message = fmt.Sprintf("struct with %d pointer bytes could be %d", ptrs, optptrs)
	} else {
		// Already optimal order.
		return
	}

	after, err := doFix(pass, node, indexes)
	if err != nil {
		log.Println(message)
		log.Println("doFix has error:", err.Error())
		return
	}

	pass.Report(analysis.Diagnostic{
		Pos:     node.Pos(),
		End:     node.Pos() + token.Pos(len("struct")),
		Message: message,
		SuggestedFixes: []analysis.SuggestedFix{{
			Message: "Rearrange fields",
			TextEdits: []analysis.TextEdit{{
				Pos:     node.Pos(),
				End:     node.End(),
				NewText: after,
			}},
		}},
	})
}

func optimalOrder(str *types.Struct, sizes *gcSizes) (*types.Struct, []int) {
	nf := str.NumFields()

	type elem struct {
		index   int
		alignof int64
		sizeof  int64
		ptrdata int64
	}

	elems := make([]elem, nf)
	for i := 0; i < nf; i++ {
		field := str.Field(i)
		ft := field.Type()
		elems[i] = elem{
			index:   i,
			alignof: sizes.Alignof(ft),
			sizeof:  sizes.Sizeof(ft),
			ptrdata: sizes.ptrdata(ft),
		}
	}

	sort.Slice(elems, func(i, j int) bool {
		ei := &elems[i]
		ej := &elems[j]

		// Place zero sized objects before non-zero sized objects.
		zeroi := ei.sizeof == 0
		zeroj := ej.sizeof == 0
		if zeroi != zeroj {
			return zeroi
		}

		// Next, place more tightly aligned objects before less tightly aligned objects.
		if ei.alignof != ej.alignof {
			return ei.alignof > ej.alignof
		}

		// Place pointerful objects before pointer-free objects.
		noptrsi := ei.ptrdata == 0
		noptrsj := ej.ptrdata == 0
		if noptrsi != noptrsj {
			return noptrsj
		}

		if !noptrsi {
			// If both have pointers...

			// ... then place objects with less trailing
			// non-pointer bytes earlier. That is, place
			// the field with the most trailing
			// non-pointer bytes at the end of the
			// pointerful section.
			traili := ei.sizeof - ei.ptrdata
			trailj := ej.sizeof - ej.ptrdata
			if traili != trailj {
				return traili < trailj
			}
		}

		// Lastly, order by size.
		if ei.sizeof != ej.sizeof {
			return ei.sizeof > ej.sizeof
		}

		return false
	})

	fields := make([]*types.Var, nf)
	indexes := make([]int, nf)
	for i, e := range elems {
		fields[i] = str.Field(e.index)
		indexes[i] = e.index
	}
	return types.NewStruct(fields, nil), indexes
}

// Code below based on go/types.StdSizes.

type gcSizes struct {
	WordSize int64
	MaxAlign int64
}

func (s *gcSizes) Alignof(T types.Type) int64 {
	// For arrays and structs, alignment is defined in terms
	// of alignment of the elements and fields, respectively.
	switch t := T.Underlying().(type) {
	case *types.Array:
		// spec: "For a variable x of array type: unsafe.Alignof(x)
		// is the same as unsafe.Alignof(x[0]), but at least 1."
		return s.Alignof(t.Elem())
	case *types.Struct:
		// spec: "For a variable x of struct type: unsafe.Alignof(x)
		// is the largest of the values unsafe.Alignof(x.f) for each
		// field f of x, but at least 1."
		max := int64(1)
		for i, nf := 0, t.NumFields(); i < nf; i++ {
			if a := s.Alignof(t.Field(i).Type()); a > max {
				max = a
			}
		}
		return max
	}
	a := s.Sizeof(T) // may be 0
	// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
	if a < 1 {
		return 1
	}
	if a > s.MaxAlign {
		return s.MaxAlign
	}
	return a
}

var basicSizes = [...]byte{
	types.Bool:       1,
	types.Int8:       1,
	types.Int16:      2,
	types.Int32:      4,
	types.Int64:      8,
	types.Uint8:      1,
	types.Uint16:     2,
	types.Uint32:     4,
	types.Uint64:     8,
	types.Float32:    4,
	types.Float64:    8,
	types.Complex64:  8,
	types.Complex128: 16,
}

func (s *gcSizes) Sizeof(T types.Type) int64 {
	switch t := T.Underlying().(type) {
	case *types.Basic:
		k := t.Kind()
		if int(k) < len(basicSizes) {
			if s := basicSizes[k]; s > 0 {
				return int64(s)
			}
		}
		if k == types.String {
			return s.WordSize * 2
		}
	case *types.Array:
		return t.Len() * s.Sizeof(t.Elem())
	case *types.Slice:
		return s.WordSize * 3
	case *types.Struct:
		nf := t.NumFields()
		if nf == 0 {
			return 0
		}

		var o int64
		max := int64(1)
		for i := 0; i < nf; i++ {
			ft := t.Field(i).Type()
			a, sz := s.Alignof(ft), s.Sizeof(ft)
			if a > max {
				max = a
			}
			if i == nf-1 && sz == 0 && o != 0 {
				sz = 1
			}
			o = align(o, a) + sz
		}
		return align(o, max)
	case *types.Interface:
		return s.WordSize * 2
	}
	return s.WordSize // catch-all
}

// align returns the smallest y >= x such that y % a == 0.
func align(x, a int64) int64 {
	y := x + a - 1
	return y - y%a
}

func (s *gcSizes) ptrdata(T types.Type) int64 {
	switch t := T.Underlying().(type) {
	case *types.Basic:
		switch t.Kind() {
		case types.String, types.UnsafePointer:
			return s.WordSize
		}
		return 0
	case *types.Chan, *types.Map, *types.Pointer, *types.Signature, *types.Slice:
		return s.WordSize
	case *types.Interface:
		return 2 * s.WordSize
	case *types.Array:
		n := t.Len()
		if n == 0 {
			return 0
		}
		a := s.ptrdata(t.Elem())
		if a == 0 {
			return 0
		}
		z := s.Sizeof(t.Elem())
		return (n-1)*z + a
	case *types.Struct:
		nf := t.NumFields()
		if nf == 0 {
			return 0
		}

		var o, p int64
		for i := 0; i < nf; i++ {
			ft := t.Field(i).Type()
			a, sz := s.Alignof(ft), s.Sizeof(ft)
			fp := s.ptrdata(ft)
			o = align(o, a)
			if fp != 0 {
				p = o + fp
			}
			o += sz
		}
		return p
	}

	panic("impossible")
}
<commit_msg>update<commit_after>// Copyright 2020 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package fieldalignment defines an Analyzer that detects structs that would use less
// memory if their fields were sorted.
package main

import (
	"bytes"
	"flag"
	"fmt"
	"go/ast"
	"go/format"
	"go/token"
	"go/types"
	"log"
	"sort"
	"strconv"
	"strings"

	"golang.org/x/tools/go/analysis"
	"golang.org/x/tools/go/analysis/passes/inspect"
	"golang.org/x/tools/go/ast/inspector"
)

const Doc = `find structs that would use less memory if their fields were sorted

This analyzer find structs that can be rearranged to use less memory, and provides
a suggested edit with the most compact order.

Note that there are two different diagnostics reported. One checks struct size,
and the other reports "pointer bytes" used. Pointer bytes is how many bytes of the
object that the garbage collector has to potentially scan for pointers, for example:

	struct { uint32; string }

have 16 pointer bytes because the garbage collector has to scan up through the string's
inner pointer.

	struct { string; *uint32 }

has 24 pointer bytes because it has to scan further through the *uint32.

	struct { string; uint32 }

has 8 because it can stop immediately after the string pointer.

Be aware that the most compact order is not always the most efficient.
In rare cases it may cause two variables each updated by its own goroutine
to occupy the same CPU cache line, inducing a form of memory contention
known as "false sharing" that slows down both goroutines.
`

var Analyzer = &analysis.Analyzer{
	Name:     "fieldalignment",
	Doc:      Doc,
	Requires: []*analysis.Analyzer{inspect.Analyzer},
	Run:      run,
}

var debug bool

func run(pass *analysis.Pass) (interface{}, error) {
	if ft := flag.Lookup("v"); ft != nil {
		debug, _ = strconv.ParseBool(ft.Value.String())
	}

	inspect := pass.ResultOf[inspect.Analyzer].(*inspector.Inspector)
	nodeFilter := []ast.Node{
		(*ast.File)(nil),
		(*ast.StructType)(nil),
	}

	var ignore bool
	inspect.Preorder(nodeFilter, func(node ast.Node) {
		if ignore {
			return
		}

		if nf, ok := node.(*ast.File); ok {
			f := pass.Fset.File(nf.Pos())
			// protobuf 自动生成的 go 文，其编解码器直接依赖其生成的字段顺序，不能优化
			if strings.HasSuffix(f.Name(), ".pb.go") ||
				strings.HasSuffix(f.Name(), "_test.go") ||
				doNotEdit(nf) {
				ignore = true
				if debug {
					log.Println("ignore:", f.Name())
				}
				return
			}
		}

		var s *ast.StructType
		var ok bool
		if s, ok = node.(*ast.StructType); !ok {
			return
		}
		if tv, ok := pass.TypesInfo.Types[s]; ok {
			if ss, ok1 := tv.Type.(*types.Struct); ok1 {
				fieldalignment(pass, s, ss)
			}
		}
	})
	return nil, nil
}

func doNotEdit(f *ast.File) bool {
	for _, cg := range f.Comments {
		if strings.Contains(cg.Text(), "DO NOT EDIT") {
			return true
		}
	}
	return false
}

var unsafePointerTyp = types.Unsafe.Scope().Lookup("Pointer").(*types.TypeName).Type()

func fieldalignment(pass *analysis.Pass, node *ast.StructType, typ *types.Struct) {
	wordSize := pass.TypesSizes.Sizeof(unsafePointerTyp)
	maxAlign := pass.TypesSizes.Alignof(unsafePointerTyp)

	s := gcSizes{WordSize: wordSize, MaxAlign: maxAlign}
	optimal, indexes := optimalOrder(typ, &s)
	optsz, optptrs := s.Sizeof(optimal), s.ptrdata(optimal)

	buf := &bytes.Buffer{}
	_ = format.Node(buf, pass.Fset, node)

	var message string
	if sz := s.Sizeof(typ); sz != optsz {
		message += fmt.Sprintf("struct of size %d could be %d ", sz, optsz)
	} else if ptrs := s.ptrdata(typ); ptrs != optptrs {
		message += fmt.Sprintf("struct with %d pointer bytes could be %d ", ptrs, optptrs)
	} else {
		// Already optimal order.
		message += fmt.Sprintf("Already optimal order. struct of size %d, pointer bytes %d", sz, ptrs)
		message += "\n" + buf.String()
		if debug {
			pass.Report(analysis.Diagnostic{
				Pos:     node.Pos(),
				End:     node.Pos() + token.Pos(len("struct")),
				Message: message,
			})
		}
		return
	}
	if debug {
		message += "\n" + buf.String()
	}

	after, err := doFix(pass, node, indexes)
	if err != nil {
		log.Println(message)
		log.Println("doFix has error:", err.Error())
		return
	}

	if debug {
		message += "\nCurrent ↑↑↑" + strings.Repeat(">", 100) + "Expect ↓↓↓\n" + string(after)
	}

	pass.Report(analysis.Diagnostic{
		Pos:     node.Pos(),
		End:     node.Pos() + token.Pos(len("struct")),
		Message: message,
		SuggestedFixes: []analysis.SuggestedFix{{
			Message: "Rearrange fields",
			TextEdits: []analysis.TextEdit{{
				Pos:     node.Pos(),
				End:     node.End(),
				NewText: after,
			}},
		}},
	})
}

func optimalOrder(str *types.Struct, sizes *gcSizes) (*types.Struct, []int) {
	nf := str.NumFields()

	type elem struct {
		index   int
		alignof int64
		sizeof  int64
		ptrdata int64
	}

	elems := make([]elem, nf)
	for i := 0; i < nf; i++ {
		field := str.Field(i)
		ft := field.Type()
		elems[i] = elem{
			index:   i,
			alignof: sizes.Alignof(ft),
			sizeof:  sizes.Sizeof(ft),
			ptrdata: sizes.ptrdata(ft),
		}
	}

	sort.Slice(elems, func(i, j int) bool {
		ei := &elems[i]
		ej := &elems[j]

		// Place zero sized objects before non-zero sized objects.
		zeroi := ei.sizeof == 0
		zeroj := ej.sizeof == 0
		if zeroi != zeroj {
			return zeroi
		}

		// Next, place more tightly aligned objects before less tightly aligned objects.
		if ei.alignof != ej.alignof {
			return ei.alignof > ej.alignof
		}

		// Place pointerful objects before pointer-free objects.
		noptrsi := ei.ptrdata == 0
		noptrsj := ej.ptrdata == 0
		if noptrsi != noptrsj {
			return noptrsj
		}

		if !noptrsi {
			// If both have pointers...

			// ... then place objects with less trailing
			// non-pointer bytes earlier. That is, place
			// the field with the most trailing
			// non-pointer bytes at the end of the
			// pointerful section.
			traili := ei.sizeof - ei.ptrdata
			trailj := ej.sizeof - ej.ptrdata
			if traili != trailj {
				return traili < trailj
			}
		}

		// Lastly, order by size.
		if ei.sizeof != ej.sizeof {
			return ei.sizeof > ej.sizeof
		}

		return false
	})

	fields := make([]*types.Var, nf)
	indexes := make([]int, nf)
	for i, e := range elems {
		fields[i] = str.Field(e.index)
		indexes[i] = e.index
	}
	return types.NewStruct(fields, nil), indexes
}

// Code below based on go/types.StdSizes.

type gcSizes struct {
	WordSize int64
	MaxAlign int64
}

func (s *gcSizes) Alignof(T types.Type) int64 {
	// For arrays and structs, alignment is defined in terms
	// of alignment of the elements and fields, respectively.
	switch t := T.Underlying().(type) {
	case *types.Array:
		// spec: "For a variable x of array type: unsafe.Alignof(x)
		// is the same as unsafe.Alignof(x[0]), but at least 1."
		return s.Alignof(t.Elem())
	case *types.Struct:
		// spec: "For a variable x of struct type: unsafe.Alignof(x)
		// is the largest of the values unsafe.Alignof(x.f) for each
		// field f of x, but at least 1."
		max := int64(1)
		for i, nf := 0, t.NumFields(); i < nf; i++ {
			if a := s.Alignof(t.Field(i).Type()); a > max {
				max = a
			}
		}
		return max
	}
	a := s.Sizeof(T) // may be 0
	// spec: "For a variable x of any type: unsafe.Alignof(x) is at least 1."
	if a < 1 {
		return 1
	}
	if a > s.MaxAlign {
		return s.MaxAlign
	}
	return a
}

var basicSizes = [...]byte{
	types.Bool:       1,
	types.Int8:       1,
	types.Int16:      2,
	types.Int32:      4,
	types.Int64:      8,
	types.Uint8:      1,
	types.Uint16:     2,
	types.Uint32:     4,
	types.Uint64:     8,
	types.Float32:    4,
	types.Float64:    8,
	types.Complex64:  8,
	types.Complex128: 16,
}

func (s *gcSizes) Sizeof(T types.Type) int64 {
	switch t := T.Underlying().(type) {
	case *types.Basic:
		k := t.Kind()
		if int(k) < len(basicSizes) {
			if s := basicSizes[k]; s > 0 {
				return int64(s)
			}
		}
		if k == types.String {
			return s.WordSize * 2
		}
	case *types.Array:
		return t.Len() * s.Sizeof(t.Elem())
	case *types.Slice:
		return s.WordSize * 3
	case *types.Struct:
		nf := t.NumFields()
		if nf == 0 {
			return 0
		}

		var o int64
		max := int64(1)
		for i := 0; i < nf; i++ {
			ft := t.Field(i).Type()
			a, sz := s.Alignof(ft), s.Sizeof(ft)
			if a > max {
				max = a
			}
			if i == nf-1 && sz == 0 && o != 0 {
				sz = 1
			}
			o = align(o, a) + sz
		}
		return align(o, max)
	case *types.Interface:
		return s.WordSize * 2
	}
	return s.WordSize // catch-all
}

// align returns the smallest y >= x such that y % a == 0.
func align(x, a int64) int64 {
	y := x + a - 1
	return y - y%a
}

func (s *gcSizes) ptrdata(T types.Type) int64 {
	switch t := T.Underlying().(type) {
	case *types.Basic:
		switch t.Kind() {
		case types.String, types.UnsafePointer:
			return s.WordSize
		}
		return 0
	case *types.Chan, *types.Map, *types.Pointer, *types.Signature, *types.Slice:
		return s.WordSize
	case *types.Interface:
		return 2 * s.WordSize
	case *types.Array:
		n := t.Len()
		if n == 0 {
			return 0
		}
		a := s.ptrdata(t.Elem())
		if a == 0 {
			return 0
		}
		z := s.Sizeof(t.Elem())
		return (n-1)*z + a
	case *types.Struct:
		nf := t.NumFields()
		if nf == 0 {
			return 0
		}

		var o, p int64
		for i := 0; i < nf; i++ {
			ft := t.Field(i).Type()
			a, sz := s.Alignof(ft), s.Sizeof(ft)
			fp := s.ptrdata(ft)
			o = align(o, a)
			if fp != 0 {
				p = o + fp
			}
			o += sz
		}
		return p
	}

	panic("impossible")
}
<|endoftext|>


<commit_before>package client

import (
	"context"
	"fmt"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/keybase1"
)

type CmdChatCreateChannel struct {
	g *libkb.GlobalContext

	resolvingRequest chatConversationResolvingRequest
}

func NewCmdChatCreateChannelRunner(g *libkb.GlobalContext) *CmdChatCreateChannel {
	return &CmdChatCreateChannel{
		g: g,
	}
}

func newCmdChatCreateChannel(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name:         "create-channel",
		Usage:        "Create a conversation channel",
		ArgumentHelp: "<team name> <channel name>",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(NewCmdChatCreateChannelRunner(g), "create-channel", c)
		},
		Flags: mustGetChatFlags("topic-type"),
	}
}

func (c *CmdChatCreateChannel) Run() error {
	c.g.StartStandaloneChat()
	return chatSend(context.TODO(), c.g, ChatSendArg{
		resolvingRequest: c.resolvingRequest,
		nonBlock:         false,
		team:             true,
		message:          fmt.Sprintf("Welcome to #%s!", c.resolvingRequest.TopicName),
		setHeadline:      "",
		clearHeadline:    false,
		hasTTY:           true,
		setTopicName:     "",
		mustNotExist:     true,
	})
}

func (c *CmdChatCreateChannel) ParseArgv(ctx *cli.Context) (err error) {

	var tlfName, topicName string
	var topicType chat1.TopicType

	if len(ctx.Args()) == 2 {
		tlfName = ctx.Args().Get(0)
		topicName = ctx.Args().Get(1)
	} else {
		return fmt.Errorf("create channel takes two arguments.")
	}
	if topicType, err = parseConversationTopicType(ctx); err != nil {
		return err
	}

	c.resolvingRequest.TlfName = tlfName
	c.resolvingRequest.TopicType = topicType
	c.resolvingRequest.TopicName = topicName
	c.resolvingRequest.MembersType = chat1.ConversationMembersType_TEAM
	c.resolvingRequest.Visibility = keybase1.TLFVisibility_PRIVATE

	return nil
}

func (c *CmdChatCreateChannel) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config: true,
		API:    true,
	}
}
<commit_msg>Fix chat create-channel to use NewConversation<commit_after>package client

import (
	"errors"

	"golang.org/x/net/context"

	"github.com/keybase/cli"
	"github.com/keybase/client/go/libcmdline"
	"github.com/keybase/client/go/libkb"
	"github.com/keybase/client/go/protocol/chat1"
	"github.com/keybase/client/go/protocol/keybase1"
)

type CmdChatCreateChannel struct {
	libkb.Contextified
	teamName    string
	channelName string
	topicType   chat1.TopicType
}

func NewCmdChatCreateChannelRunner(g *libkb.GlobalContext) *CmdChatCreateChannel {
	return &CmdChatCreateChannel{Contextified: libkb.NewContextified(g)}
}

func newCmdChatCreateChannel(cl *libcmdline.CommandLine, g *libkb.GlobalContext) cli.Command {
	return cli.Command{
		Name:         "create-channel",
		Usage:        "Create a conversation channel",
		ArgumentHelp: "<team name> <channel name>",
		Action: func(c *cli.Context) {
			cl.ChooseCommand(NewCmdChatCreateChannelRunner(g), "create-channel", c)
		},
		Flags: mustGetChatFlags("topic-type"),
	}
}

func (c *CmdChatCreateChannel) Run() error {
	c.G().StartStandaloneChat()
	chatClient, err := GetChatLocalClient(c.G())
	if err != nil {
		return err
	}
	resolver := &chatConversationResolver{G: c.G(), ChatClient: chatClient}

	req := chatConversationResolvingRequest{
		TlfName:     c.teamName,
		TopicName:   c.channelName,
		TopicType:   c.topicType,
		MembersType: chat1.ConversationMembersType_TEAM,
		Visibility:  keybase1.TLFVisibility_PRIVATE,
		ctx: &chatConversationResolvingRequestContext{
			canonicalizedTlfName: c.teamName,
		},
	}

	_, err = resolver.create(context.Background(), req)
	return err
}

func (c *CmdChatCreateChannel) ParseArgv(ctx *cli.Context) error {
	if len(ctx.Args()) != 2 {
		return errors.New("create channel takes two arguments.")
	}

	c.teamName = ctx.Args().Get(0)
	c.channelName = ctx.Args().Get(1)

	var err error
	c.topicType, err = parseConversationTopicType(ctx)
	if err != nil {
		return err
	}

	return nil
}

func (c *CmdChatCreateChannel) GetUsage() libkb.Usage {
	return libkb.Usage{
		Config:    true,
		API:       true,
		KbKeyring: true,
	}
}
<|endoftext|>


<commit_before>// Code generated by go-bindata.
// sources:
// config.json
// DO NOT EDIT!

package config

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"
)

func bindataRead(data []byte, name string) ([]byte, error) {
	gz, err := gzip.NewReader(bytes.NewBuffer(data))
	if err != nil {
		return nil, fmt.Errorf("Read %q: %v", name, err)
	}

	var buf bytes.Buffer
	_, err = io.Copy(&buf, gz)
	clErr := gz.Close()

	if err != nil {
		return nil, fmt.Errorf("Read %q: %v", name, err)
	}
	if clErr != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

type asset struct {
	bytes []byte
	info  os.FileInfo
}

type bindataFileInfo struct {
	name    string
	size    int64
	mode    os.FileMode
	modTime time.Time
}

func (fi bindataFileInfo) Name() string {
	return fi.name
}
func (fi bindataFileInfo) Size() int64 {
	return fi.size
}
func (fi bindataFileInfo) Mode() os.FileMode {
	return fi.mode
}
func (fi bindataFileInfo) ModTime() time.Time {
	return fi.modTime
}
func (fi bindataFileInfo) IsDir() bool {
	return false
}
func (fi bindataFileInfo) Sys() interface{} {
	return nil
}

var _configJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xd4\x94\xc1\x6a\xc3\x30\x0c\x86\xef\x79\x8a\xa0\x73\x9a\xac\xbb\x0c\xfa\x2a\x63\x87\x2c\x16\xad\x49\x22\x19\x5b\x09\x1d\x23\xef\x3e\xc5\x5e\x37\xb7\x30\xe8\x2e\x23\xa3\x27\xff\xbf\xa4\x7e\x7c\x87\xbc\x17\x65\x09\x9e\x27\xc1\x00\x87\x72\x7d\xe9\xdb\xe0\x5c\xf7\x6c\x2c\x1d\xeb\x8e\x47\xcd\x61\xff\xf8\x54\x3f\xe8\x6f\x0f\x3a\xb1\x54\xeb\x12\x92\x71\x6c\x49\xb2\x3d\x99\x88\x70\x08\xe8\x67\xf4\x9a\x3e\xc7\xb4\xfc\x6c\xe3\x04\xd2\x6c\x3d\xd3\x88\x24\xd9\x40\xac\x9c\x67\x33\x75\x62\x99\xa0\xca\xf3\xb1\xa5\xf6\x88\x06\xbe\xb2\x97\xef\x1a\x26\x3f\xac\x78\x27\x11\x77\x68\x9a\xf4\xff\x7a\xe8\xfc\x96\xf1\x37\xbd\x15\xbc\xac\x2f\xd5\xaf\xa0\xd4\x04\x0e\xec\x62\x55\xdd\x14\x17\xb0\xab\x3c\xb4\x64\x5e\xf9\x7c\x0f\xad\x9e\xb8\x07\xb8\xc8\xae\x80\x75\x7f\xee\x35\x28\xaa\xcb\xe9\x76\x8d\x52\x6c\x4c\x67\x48\x3e\x77\x3f\x83\xde\x68\xec\x4e\xd8\xf5\xdb\x70\x99\x50\xfe\x8b\xd0\x6b\xda\x64\x75\xfd\x26\x14\x4b\xf1\x11\x00\x00\xff\xff\xcb\xeb\x6f\x40\x4c\x04\x00\x00")

func configJsonBytes() ([]byte, error) {
	return bindataRead(
		_configJson,
		"config.json",
	)
}

func configJson() (*asset, error) {
	bytes, err := configJsonBytes()
	if err != nil {
		return nil, err
	}

	info := bindataFileInfo{name: "config.json", size: 1100, mode: os.FileMode(420), modTime: time.Unix(1446555960, 0)}
	a := &asset{bytes: bytes, info: info}
	return a, nil
}

// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
	cannonicalName := strings.Replace(name, "\\", "/", -1)
	if f, ok := _bindata[cannonicalName]; ok {
		a, err := f()
		if err != nil {
			return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
		}
		return a.bytes, nil
	}
	return nil, fmt.Errorf("Asset %s not found", name)
}

// MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables.
func MustAsset(name string) []byte {
	a, err := Asset(name)
	if err != nil {
		panic("asset: Asset(" + name + "): " + err.Error())
	}

	return a
}

// AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) {
	cannonicalName := strings.Replace(name, "\\", "/", -1)
	if f, ok := _bindata[cannonicalName]; ok {
		a, err := f()
		if err != nil {
			return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
		}
		return a.info, nil
	}
	return nil, fmt.Errorf("AssetInfo %s not found", name)
}

// AssetNames returns the names of the assets.
func AssetNames() []string {
	names := make([]string, 0, len(_bindata))
	for name := range _bindata {
		names = append(names, name)
	}
	return names
}

// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
	"config.json": configJson,
}

// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
//     data/
//       foo.txt
//       img/
//         a.png
//         b.png
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
// AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) {
	node := _bintree
	if len(name) != 0 {
		cannonicalName := strings.Replace(name, "\\", "/", -1)
		pathList := strings.Split(cannonicalName, "/")
		for _, p := range pathList {
			node = node.Children[p]
			if node == nil {
				return nil, fmt.Errorf("Asset %s not found", name)
			}
		}
	}
	if node.Func != nil {
		return nil, fmt.Errorf("Asset %s not found", name)
	}
	rv := make([]string, 0, len(node.Children))
	for childName := range node.Children {
		rv = append(rv, childName)
	}
	return rv, nil
}

type bintree struct {
	Func     func() (*asset, error)
	Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
	"config.json": &bintree{configJson, map[string]*bintree{}},
}}

// RestoreAsset restores an asset under the given directory
func RestoreAsset(dir, name string) error {
	data, err := Asset(name)
	if err != nil {
		return err
	}
	info, err := AssetInfo(name)
	if err != nil {
		return err
	}
	err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
	if err != nil {
		return err
	}
	err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
	if err != nil {
		return err
	}
	return nil
}

// RestoreAssets restores an asset under the given directory recursively
func RestoreAssets(dir, name string) error {
	children, err := AssetDir(name)
	// File
	if err != nil {
		return RestoreAsset(dir, name)
	}
	// Dir
	for _, child := range children {
		err = RestoreAssets(dir, filepath.Join(name, child))
		if err != nil {
			return err
		}
	}
	return nil
}

func _filePath(dir, name string) string {
	cannonicalName := strings.Replace(name, "\\", "/", -1)
	return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
}

<commit_msg>go: run go generate<commit_after>// Code generated by go-bindata.
// sources:
// config.json
// DO NOT EDIT!

package config

import (
	"bytes"
	"compress/gzip"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"time"
)

func bindataRead(data []byte, name string) ([]byte, error) {
	gz, err := gzip.NewReader(bytes.NewBuffer(data))
	if err != nil {
		return nil, fmt.Errorf("Read %q: %v", name, err)
	}

	var buf bytes.Buffer
	_, err = io.Copy(&buf, gz)
	clErr := gz.Close()

	if err != nil {
		return nil, fmt.Errorf("Read %q: %v", name, err)
	}
	if clErr != nil {
		return nil, err
	}

	return buf.Bytes(), nil
}

type asset struct {
	bytes []byte
	info  os.FileInfo
}

type bindataFileInfo struct {
	name    string
	size    int64
	mode    os.FileMode
	modTime time.Time
}

func (fi bindataFileInfo) Name() string {
	return fi.name
}
func (fi bindataFileInfo) Size() int64 {
	return fi.size
}
func (fi bindataFileInfo) Mode() os.FileMode {
	return fi.mode
}
func (fi bindataFileInfo) ModTime() time.Time {
	return fi.modTime
}
func (fi bindataFileInfo) IsDir() bool {
	return false
}
func (fi bindataFileInfo) Sys() interface{} {
	return nil
}

var _configJson = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xd4\x94\x41\x6b\xc3\x30\x0c\x85\xef\xf9\x15\x41\xe7\x34\x59\x77\x19\xf4\xaf\x8c\x1d\xb2\x58\xb4\x26\x89\x64\x6c\x39\x0c\x46\xfe\xfb\x64\xb7\xdd\xdc\x42\x61\xbb\x8c\x16\x9f\xf4\x9e\x9e\xf9\xfc\x0e\xfe\xac\xea\x1a\x3c\x47\xc1\x00\xbb\x3a\x4d\x3a\x1b\x5c\xda\x91\x8d\xa5\x7d\x3b\xf0\xac\x3a\x6c\x9f\x5f\xda\x27\x3d\x5b\xd0\x8d\xb5\x49\x21\x24\xe3\xd8\x92\x14\x39\x89\x44\x38\x05\xf4\x0b\x7a\x55\x5f\xb3\x5a\x9f\xdc\xbc\x81\xb4\x58\xcf\x34\x23\x49\xb1\x90\x2d\xe7\xd9\xc4\x41\x2c\x13\x34\xa5\x3e\xf7\xd4\xef\xd1\xc0\xb7\xf6\xf6\x63\x43\xf4\x53\xc2\x3b\x88\xb8\x5d\xd7\x49\x41\xdd\x8d\x56\xf0\x1c\x5a\x9b\x3f\xa1\xe8\xfb\x71\x62\x97\xad\xe6\xca\x38\xe3\x5c\xe8\xa1\x27\xf3\xce\x1f\xbf\x61\xd4\x2b\x36\xb7\x39\xab\x22\x0c\xd6\xfd\x7b\x89\x41\x09\x5d\x49\xb7\xe9\x94\xe2\xce\x5a\x0c\xa7\x1a\x6f\x83\x5e\xd5\x38\x1c\x70\x18\xef\xa3\xcb\x23\xca\xa3\x14\x7a\x49\x7b\x6c\x35\x7d\x00\xd5\x5a\x7d\x05\x00\x00\xff\xff\x8a\xd5\x09\x92\x39\x04\x00\x00")

func configJsonBytes() ([]byte, error) {
	return bindataRead(
		_configJson,
		"config.json",
	)
}

func configJson() (*asset, error) {
	bytes, err := configJsonBytes()
	if err != nil {
		return nil, err
	}

	info := bindataFileInfo{name: "config.json", size: 1081, mode: os.FileMode(420), modTime: time.Unix(1446555960, 0)}
	a := &asset{bytes: bytes, info: info}
	return a, nil
}

// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
	cannonicalName := strings.Replace(name, "\\", "/", -1)
	if f, ok := _bindata[cannonicalName]; ok {
		a, err := f()
		if err != nil {
			return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
		}
		return a.bytes, nil
	}
	return nil, fmt.Errorf("Asset %s not found", name)
}

// MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables.
func MustAsset(name string) []byte {
	a, err := Asset(name)
	if err != nil {
		panic("asset: Asset(" + name + "): " + err.Error())
	}

	return a
}

// AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) {
	cannonicalName := strings.Replace(name, "\\", "/", -1)
	if f, ok := _bindata[cannonicalName]; ok {
		a, err := f()
		if err != nil {
			return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
		}
		return a.info, nil
	}
	return nil, fmt.Errorf("AssetInfo %s not found", name)
}

// AssetNames returns the names of the assets.
func AssetNames() []string {
	names := make([]string, 0, len(_bindata))
	for name := range _bindata {
		names = append(names, name)
	}
	return names
}

// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
	"config.json": configJson,
}

// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
//     data/
//       foo.txt
//       img/
//         a.png
//         b.png
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
// AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) {
	node := _bintree
	if len(name) != 0 {
		cannonicalName := strings.Replace(name, "\\", "/", -1)
		pathList := strings.Split(cannonicalName, "/")
		for _, p := range pathList {
			node = node.Children[p]
			if node == nil {
				return nil, fmt.Errorf("Asset %s not found", name)
			}
		}
	}
	if node.Func != nil {
		return nil, fmt.Errorf("Asset %s not found", name)
	}
	rv := make([]string, 0, len(node.Children))
	for childName := range node.Children {
		rv = append(rv, childName)
	}
	return rv, nil
}

type bintree struct {
	Func     func() (*asset, error)
	Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
	"config.json": &bintree{configJson, map[string]*bintree{}},
}}

// RestoreAsset restores an asset under the given directory
func RestoreAsset(dir, name string) error {
	data, err := Asset(name)
	if err != nil {
		return err
	}
	info, err := AssetInfo(name)
	if err != nil {
		return err
	}
	err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
	if err != nil {
		return err
	}
	err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
	if err != nil {
		return err
	}
	err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
	if err != nil {
		return err
	}
	return nil
}

// RestoreAssets restores an asset under the given directory recursively
func RestoreAssets(dir, name string) error {
	children, err := AssetDir(name)
	// File
	if err != nil {
		return RestoreAsset(dir, name)
	}
	// Dir
	for _, child := range children {
		err = RestoreAssets(dir, filepath.Join(name, child))
		if err != nil {
			return err
		}
	}
	return nil
}

func _filePath(dir, name string) string {
	cannonicalName := strings.Replace(name, "\\", "/", -1)
	return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
}

<|endoftext|>


<commit_before>package models

const (
	Safe  = 0
	Troll = 1 << iota
)

type MetaBits int16

// IsSafe checks for data against if it is showable to the user
func (m MetaBits) IsSafe() bool {
	return (m == 0)
}

func (m *MetaBits) MarkTroll() {
	// set first bit as 1
	*m = *m | Troll
}

func (m MetaBits) IsTroll() bool {
	// get first bit
	return (m & Troll) == Troll
}
<commit_msg>Social: cleanup metabits<commit_after>package models

const (
	Troll MetaBits = 1 << iota
	// all other bits will up be here

	// safe should be the last one assigned as 0
	Safe MetaBits = 0
)

type MetaBits int16

func (m *MetaBits) Mark(data MetaBits) {
	// bitwise OR
	*m = *m | data
}

func (m *MetaBits) UnMark(data MetaBits) {
	// bit clear (AND NOT)
	*m = *m &^ data
}

func (m MetaBits) Is(data MetaBits) bool {
	return (m & data) == data
}
<|endoftext|>


<commit_before>// EVH is designed to be a single-use file transfer system.  Its purpose is to replace
// aging methods of sharing files such as FTP.  With the advent of services like
// DropBox, Box, Google Drive and the like, this type of service is becoming more
// commonplace EVH has some differentiating features that make it an especially
// good tool for corporations and/or home use.
//
// EVH runs in two modes: server and client.  Server hosts a web server interface for
// uploading and downloading files.  The Client is for uploading only and runs
// in a terminal.  This app is designed to run on all platforms that Go supports.
package main

import (
	"flag"
	"html/template"
	"log"
	"net/http"
	"os"
)

// Flags
var ConfigFileFlag string
var DstEmailFlag string
var ExpirationFlag string
var FileDescrFlag string
var FilesFieldFlag string
var ProgressFlag bool
var ServerFlag bool
var SrcEmailFlag string
var UrlFlag string

// Global Variables
var UploadUrlPath = "/upload/"
var DownloadUrlPath = "/download/"
var Files []string
var HttpProto = "http"
var SiteDown bool
var Templates *template.Template

// Constants
const VERSION = "2.0.3"
const TimeLayout = "Jan 2, 2006 at 3:04pm (MST)"

func init() {
	flag.StringVar(&ConfigFileFlag, "c", "", "Location of the Configuration file")
	flag.BoolVar(&ServerFlag, "server", false, "Listen for incoming file uploads")

	// Client flags
	flag.StringVar(&UrlFlag, "url", "", "Remote server URL to send files to (client only)")
	flag.StringVar(&FilesFieldFlag, "field", "", "Field name of the form (client only)")
	flag.StringVar(&SrcEmailFlag, "from", "", "Email address of uploader (client only)")
	flag.StringVar(&DstEmailFlag, "to", "", "Comma separated set of email address(es) of file recipient(s) (client only)")
	flag.StringVar(&FileDescrFlag, "description", "", "File desription (use quotes) (client only)")
	flag.BoolVar(&ProgressFlag, "progress", true, "Show progress bar during upload (client only)")
	flag.StringVar(&ExpirationFlag, "expires", "", "Example 1:d for 1 day (client only)")
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
	// Redirect to SSL if enabled
	if r.TLS == nil && Config.Server.Ssl {
		log.Println(r.RequestURI)
		redirectToSsl(w, r)
		return
	}

	var page = NewPage()
	DisplayPage(w, r, "home", page)
}

func redirectToSsl(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "https://"+Config.Server.Address+":"+Config.Server.SslPort+r.RequestURI, http.StatusTemporaryRedirect)
	return
}

func main() {
	flag.Parse()

	// Load in our Config
	Config = NewConfig(ConfigFileFlag)
	Config.ImportFlags()

	if ServerFlag {
		// Final sanity check
		if Config.Server.Assets == "" {
			log.Fatal("ERROR: Cannot continue without specifying assets path")
		}
		if Config.Server.Templates == "" {
			log.Fatal("ERROR: Cannot continue without specifying templates path")
		}
		if Config.Server.ListenAddr == "" {
			log.Fatal("ERROR: Cannot continue without specifying listenaddr value")
		}
		if Config.Server.Mailserver == "" {
			log.Println("WARNING: cannot send emails, mailserver not set")
		}

		// Set so all generated URLs use https if enabled
		if Config.Server.Ssl {
			HttpProto = "https"
		}

		// Setup our assets dir (if it don't already exist)
		err := os.MkdirAll(Config.Server.Assets, 0700)
		if err != nil {
			log.Fatal("Cannot setup assetdir as needed: " + err.Error())
		}

		// Parse our html templates
		go RefreshTemplates()
		go ScrubDownloads()

		// Register our handler functions
		http.HandleFunc(UploadUrlPath, uploadHandler)
		http.HandleFunc(DownloadUrlPath, assetHandler)
		http.HandleFunc("/", homeHandler)

		// Listen
		log.Println("Listening...")

		// Spawn HTTPS listener in another thread
		go func() {
			if Config.Server.Ssl == false || Config.Server.SslPort == "" {
				return
			}
			var addrSsl = Config.Server.ListenAddr + ":" + Config.Server.SslPort
			listenErrSsl := http.ListenAndServeTLS(addrSsl, Config.Server.CertFile, Config.Server.KeyFile, nil)
			if listenErrSsl != nil {
				log.Fatal(listenErrSsl.Error())
			}
		}()

		// Start non-SSL listener
		var addrNonSsl = Config.Server.ListenAddr + ":" + Config.Server.NonSslPort
		listenErr := http.ListenAndServe(addrNonSsl, nil)
		if listenErr != nil {
			log.Fatal(listenErr.Error())
		}
	} else {
		// Final sanity check
		if Config.Client.DestEmail == "" {
			log.Println("WARNING: no -destemail value set, cannot send reciever an email")
		}
		if Config.Client.Email == "" {
			log.Println("WARNING: no -email value set, cannot send email to uploader")
		}
		if Config.Client.Field == "" {
			log.Println("WARNING: no -field value set, using \"file\" instead")
			Config.Client.Field = "file"
		}
		if Config.Client.Url == "" {
			log.Fatal("ERROR: Cannot continue without specifying -url value")
		}

		// All filenames are unflagged arguments, loop through them and uplod the file(s)
		for _, fname := range flag.Args() {
			fi, err := os.Stat(fname)
			if err != nil {
				log.Println("WARNING: Cannot read file, skipping ", fname, ": ", err.Error())
			} else {
				if fi.Mode().IsRegular() {
					Files = append(Files, fname)
				}
			}
		}

		Upload(Files)
	}
}
<commit_msg>Version bump to 2.0.4<commit_after>// EVH is designed to be a single-use file transfer system.  Its purpose is to replace
// aging methods of sharing files such as FTP.  With the advent of services like
// DropBox, Box, Google Drive and the like, this type of service is becoming more
// commonplace EVH has some differentiating features that make it an especially
// good tool for corporations and/or home use.
//
// EVH runs in two modes: server and client.  Server hosts a web server interface for
// uploading and downloading files.  The Client is for uploading only and runs
// in a terminal.  This app is designed to run on all platforms that Go supports.
package main

import (
	"flag"
	"html/template"
	"log"
	"net/http"
	"os"
)

// Flags
var ConfigFileFlag string
var DstEmailFlag string
var ExpirationFlag string
var FileDescrFlag string
var FilesFieldFlag string
var ProgressFlag bool
var ServerFlag bool
var SrcEmailFlag string
var UrlFlag string

// Global Variables
var UploadUrlPath = "/upload/"
var DownloadUrlPath = "/download/"
var Files []string
var HttpProto = "http"
var SiteDown bool
var Templates *template.Template

// Constants
const VERSION = "2.0.4"
const TimeLayout = "Jan 2, 2006 at 3:04pm (MST)"

func init() {
	flag.StringVar(&ConfigFileFlag, "c", "", "Location of the Configuration file")
	flag.BoolVar(&ServerFlag, "server", false, "Listen for incoming file uploads")

	// Client flags
	flag.StringVar(&UrlFlag, "url", "", "Remote server URL to send files to (client only)")
	flag.StringVar(&FilesFieldFlag, "field", "", "Field name of the form (client only)")
	flag.StringVar(&SrcEmailFlag, "from", "", "Email address of uploader (client only)")
	flag.StringVar(&DstEmailFlag, "to", "", "Comma separated set of email address(es) of file recipient(s) (client only)")
	flag.StringVar(&FileDescrFlag, "description", "", "File desription (use quotes) (client only)")
	flag.BoolVar(&ProgressFlag, "progress", true, "Show progress bar during upload (client only)")
	flag.StringVar(&ExpirationFlag, "expires", "", "Example 1:d for 1 day (client only)")
}

func homeHandler(w http.ResponseWriter, r *http.Request) {
	// Redirect to SSL if enabled
	if r.TLS == nil && Config.Server.Ssl {
		log.Println(r.RequestURI)
		redirectToSsl(w, r)
		return
	}

	var page = NewPage()
	DisplayPage(w, r, "home", page)
}

func redirectToSsl(w http.ResponseWriter, r *http.Request) {
	http.Redirect(w, r, "https://"+Config.Server.Address+":"+Config.Server.SslPort+r.RequestURI, http.StatusTemporaryRedirect)
	return
}

func main() {
	flag.Parse()

	// Load in our Config
	Config = NewConfig(ConfigFileFlag)
	Config.ImportFlags()

	if ServerFlag {
		// Final sanity check
		if Config.Server.Assets == "" {
			log.Fatal("ERROR: Cannot continue without specifying assets path")
		}
		if Config.Server.Templates == "" {
			log.Fatal("ERROR: Cannot continue without specifying templates path")
		}
		if Config.Server.ListenAddr == "" {
			log.Fatal("ERROR: Cannot continue without specifying listenaddr value")
		}
		if Config.Server.Mailserver == "" {
			log.Println("WARNING: cannot send emails, mailserver not set")
		}

		// Set so all generated URLs use https if enabled
		if Config.Server.Ssl {
			HttpProto = "https"
		}

		// Setup our assets dir (if it don't already exist)
		err := os.MkdirAll(Config.Server.Assets, 0700)
		if err != nil {
			log.Fatal("Cannot setup assetdir as needed: " + err.Error())
		}

		// Parse our html templates
		go RefreshTemplates()
		go ScrubDownloads()

		// Register our handler functions
		http.HandleFunc(UploadUrlPath, uploadHandler)
		http.HandleFunc(DownloadUrlPath, assetHandler)
		http.HandleFunc("/", homeHandler)

		// Listen
		log.Println("Listening...")

		// Spawn HTTPS listener in another thread
		go func() {
			if Config.Server.Ssl == false || Config.Server.SslPort == "" {
				return
			}
			var addrSsl = Config.Server.ListenAddr + ":" + Config.Server.SslPort
			listenErrSsl := http.ListenAndServeTLS(addrSsl, Config.Server.CertFile, Config.Server.KeyFile, nil)
			if listenErrSsl != nil {
				log.Fatal(listenErrSsl.Error())
			}
		}()

		// Start non-SSL listener
		var addrNonSsl = Config.Server.ListenAddr + ":" + Config.Server.NonSslPort
		listenErr := http.ListenAndServe(addrNonSsl, nil)
		if listenErr != nil {
			log.Fatal(listenErr.Error())
		}
	} else {
		// Final sanity check
		if Config.Client.DestEmail == "" {
			log.Println("WARNING: no -destemail value set, cannot send reciever an email")
		}
		if Config.Client.Email == "" {
			log.Println("WARNING: no -email value set, cannot send email to uploader")
		}
		if Config.Client.Field == "" {
			log.Println("WARNING: no -field value set, using \"file\" instead")
			Config.Client.Field = "file"
		}
		if Config.Client.Url == "" {
			log.Fatal("ERROR: Cannot continue without specifying -url value")
		}

		// All filenames are unflagged arguments, loop through them and uplod the file(s)
		for _, fname := range flag.Args() {
			fi, err := os.Stat(fname)
			if err != nil {
				log.Println("WARNING: Cannot read file, skipping ", fname, ": ", err.Error())
			} else {
				if fi.Mode().IsRegular() {
					Files = append(Files, fname)
				}
			}
		}

		Upload(Files)
	}
}
<|endoftext|>


<commit_before>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package pprof serves via its HTTP server runtime profiling data
// in the format expected by the pprof visualization tool.
// For more information about pprof, see
// http://code.google.com/p/google-perftools/.
//
// The package is typically only imported for the side effect of
// registering its HTTP handlers.
// The handled paths all begin with /debug/pprof/.
//
// To use pprof, link this package into your program:
//	import _ "net/http/pprof"
//
// If your application is not already running an http server, you
// need to start one.  Add "net/http" and "log" to your imports and
// the following code to your main function:
//
// 	go func() {
// 		log.Println(http.ListenAndServe("localhost:6060", nil))
// 	}()
//
// Then use the pprof tool to look at the heap profile:
//
//	go tool pprof http://localhost:6060/debug/pprof/heap
//
// Or to look at a 30-second CPU profile:
//
//	go tool pprof http://localhost:6060/debug/pprof/profile
//
// Or to look at the goroutine blocking profile:
//
//	go tool pprof http://localhost:6060/debug/pprof/block
//
// To view all available profiles, open http://localhost:6060/debug/pprof/
// in your browser.
//
// For a study of the facility in action, visit
//
//	http://blog.golang.org/2011/06/profiling-go-programs.html
//
package pprof

import (
	"bufio"
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"runtime"
	"runtime/pprof"
	"strconv"
	"strings"
	"time"
)

func init() {
	http.Handle("/debug/pprof/", http.HandlerFunc(Index))
	http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
	http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
	http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
}

// Cmdline responds with the running program's
// command line, with arguments separated by NUL bytes.
// The package initialization registers it as /debug/pprof/cmdline.
func Cmdline(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
}

// Profile responds with the pprof-formatted cpu profile.
// The package initialization registers it as /debug/pprof/profile.
func Profile(w http.ResponseWriter, r *http.Request) {
	sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
	if sec == 0 {
		sec = 30
	}

	// Set Content Type assuming StartCPUProfile will work,
	// because if it does it starts writing.
	w.Header().Set("Content-Type", "application/octet-stream")
	if err := pprof.StartCPUProfile(w); err != nil {
		// StartCPUProfile failed, so no writes yet.
		// Can change header back to text content
		// and send error code.
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
		return
	}
	time.Sleep(time.Duration(sec) * time.Second)
	pprof.StopCPUProfile()
}

// Symbol looks up the program counters listed in the request,
// responding with a table mapping program counters to function names.
// The package initialization registers it as /debug/pprof/symbol.
func Symbol(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")

	// We have to read the whole POST body before
	// writing any output.  Buffer the output here.
	var buf bytes.Buffer

	// We don't know how many symbols we have, but we
	// do have symbol information.  Pprof only cares whether
	// this number is 0 (no symbols available) or > 0.
	fmt.Fprintf(&buf, "num_symbols: 1\n")

	var b *bufio.Reader
	if r.Method == "POST" {
		b = bufio.NewReader(r.Body)
	} else {
		b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
	}

	for {
		word, err := b.ReadSlice('+')
		if err == nil {
			word = word[0 : len(word)-1] // trim +
		}
		pc, _ := strconv.ParseUint(string(word), 0, 64)
		if pc != 0 {
			f := runtime.FuncForPC(uintptr(pc))
			if f != nil {
				fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name())
			}
		}

		// Wait until here to check for err; the last
		// symbol will have an err because it doesn't end in +.
		if err != nil {
			if err != io.EOF {
				fmt.Fprintf(&buf, "reading request: %v\n", err)
			}
			break
		}
	}

	w.Write(buf.Bytes())
}

// Handler returns an HTTP handler that serves the named profile.
func Handler(name string) http.Handler {
	return handler(name)
}

type handler string

func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	debug, _ := strconv.Atoi(r.FormValue("debug"))
	p := pprof.Lookup(string(name))
	if p == nil {
		w.WriteHeader(404)
		fmt.Fprintf(w, "Unknown profile: %s\n", name)
		return
	}
	p.WriteTo(w, debug)
	return
}

// Index responds with the pprof-formatted profile named by the request.
// For example, "/debug/pprof/heap" serves the "heap" profile.
// Index responds to a request for "/debug/pprof/" with an HTML page
// listing the available profiles.
func Index(w http.ResponseWriter, r *http.Request) {
	if strings.HasPrefix(r.URL.Path, "/debug/pprof/") {
		name := strings.TrimPrefix(r.URL.Path, "/debug/pprof/")
		if name != "" {
			handler(name).ServeHTTP(w, r)
			return
		}
	}

	profiles := pprof.Profiles()
	if err := indexTmpl.Execute(w, profiles); err != nil {
		log.Print(err)
	}
}

var indexTmpl = template.Must(template.New("index").Parse(`

<title>/debug/pprof/</title>

/debug/pprof/

profiles:

{{range .}}

{{.Count}}{{.Name}}
{{end}}

full goroutine stack dump

`))
<commit_msg>net/http/pprof: run GC for /debug/pprof/heap?gc=1<commit_after>// Copyright 2010 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package pprof serves via its HTTP server runtime profiling data
// in the format expected by the pprof visualization tool.
// For more information about pprof, see
// http://code.google.com/p/google-perftools/.
//
// The package is typically only imported for the side effect of
// registering its HTTP handlers.
// The handled paths all begin with /debug/pprof/.
//
// To use pprof, link this package into your program:
//	import _ "net/http/pprof"
//
// If your application is not already running an http server, you
// need to start one.  Add "net/http" and "log" to your imports and
// the following code to your main function:
//
// 	go func() {
// 		log.Println(http.ListenAndServe("localhost:6060", nil))
// 	}()
//
// Then use the pprof tool to look at the heap profile:
//
//	go tool pprof http://localhost:6060/debug/pprof/heap
//
// Or to look at a 30-second CPU profile:
//
//	go tool pprof http://localhost:6060/debug/pprof/profile
//
// Or to look at the goroutine blocking profile:
//
//	go tool pprof http://localhost:6060/debug/pprof/block
//
// To view all available profiles, open http://localhost:6060/debug/pprof/
// in your browser.
//
// For a study of the facility in action, visit
//
//	http://blog.golang.org/2011/06/profiling-go-programs.html
//
package pprof

import (
	"bufio"
	"bytes"
	"fmt"
	"html/template"
	"io"
	"log"
	"net/http"
	"os"
	"runtime"
	"runtime/pprof"
	"strconv"
	"strings"
	"time"
)

func init() {
	http.Handle("/debug/pprof/", http.HandlerFunc(Index))
	http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
	http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
	http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
}

// Cmdline responds with the running program's
// command line, with arguments separated by NUL bytes.
// The package initialization registers it as /debug/pprof/cmdline.
func Cmdline(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	fmt.Fprintf(w, strings.Join(os.Args, "\x00"))
}

// Profile responds with the pprof-formatted cpu profile.
// The package initialization registers it as /debug/pprof/profile.
func Profile(w http.ResponseWriter, r *http.Request) {
	sec, _ := strconv.ParseInt(r.FormValue("seconds"), 10, 64)
	if sec == 0 {
		sec = 30
	}

	// Set Content Type assuming StartCPUProfile will work,
	// because if it does it starts writing.
	w.Header().Set("Content-Type", "application/octet-stream")
	if err := pprof.StartCPUProfile(w); err != nil {
		// StartCPUProfile failed, so no writes yet.
		// Can change header back to text content
		// and send error code.
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
		w.WriteHeader(http.StatusInternalServerError)
		fmt.Fprintf(w, "Could not enable CPU profiling: %s\n", err)
		return
	}
	time.Sleep(time.Duration(sec) * time.Second)
	pprof.StopCPUProfile()
}

// Symbol looks up the program counters listed in the request,
// responding with a table mapping program counters to function names.
// The package initialization registers it as /debug/pprof/symbol.
func Symbol(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")

	// We have to read the whole POST body before
	// writing any output.  Buffer the output here.
	var buf bytes.Buffer

	// We don't know how many symbols we have, but we
	// do have symbol information.  Pprof only cares whether
	// this number is 0 (no symbols available) or > 0.
	fmt.Fprintf(&buf, "num_symbols: 1\n")

	var b *bufio.Reader
	if r.Method == "POST" {
		b = bufio.NewReader(r.Body)
	} else {
		b = bufio.NewReader(strings.NewReader(r.URL.RawQuery))
	}

	for {
		word, err := b.ReadSlice('+')
		if err == nil {
			word = word[0 : len(word)-1] // trim +
		}
		pc, _ := strconv.ParseUint(string(word), 0, 64)
		if pc != 0 {
			f := runtime.FuncForPC(uintptr(pc))
			if f != nil {
				fmt.Fprintf(&buf, "%#x %s\n", pc, f.Name())
			}
		}

		// Wait until here to check for err; the last
		// symbol will have an err because it doesn't end in +.
		if err != nil {
			if err != io.EOF {
				fmt.Fprintf(&buf, "reading request: %v\n", err)
			}
			break
		}
	}

	w.Write(buf.Bytes())
}

// Handler returns an HTTP handler that serves the named profile.
func Handler(name string) http.Handler {
	return handler(name)
}

type handler string

func (name handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/plain; charset=utf-8")
	debug, _ := strconv.Atoi(r.FormValue("debug"))
	p := pprof.Lookup(string(name))
	if p == nil {
		w.WriteHeader(404)
		fmt.Fprintf(w, "Unknown profile: %s\n", name)
		return
	}
	gc, _ := strconv.Atoi(r.FormValue("gc"))
	if name == "heap" && gc > 0 {
		runtime.GC()
	}
	p.WriteTo(w, debug)
	return
}

// Index responds with the pprof-formatted profile named by the request.
// For example, "/debug/pprof/heap" serves the "heap" profile.
// Index responds to a request for "/debug/pprof/" with an HTML page
// listing the available profiles.
func Index(w http.ResponseWriter, r *http.Request) {
	if strings.HasPrefix(r.URL.Path, "/debug/pprof/") {
		name := strings.TrimPrefix(r.URL.Path, "/debug/pprof/")
		if name != "" {
			handler(name).ServeHTTP(w, r)
			return
		}
	}

	profiles := pprof.Profiles()
	if err := indexTmpl.Execute(w, profiles); err != nil {
		log.Print(err)
	}
}

var indexTmpl = template.Must(template.New("index").Parse(`

<title>/debug/pprof/</title>

/debug/pprof/

profiles:

{{range .}}

{{.Count}}{{.Name}}
{{end}}

full goroutine stack dump

`))
<|endoftext|>