1ffe3c632Sopenharmony_cipackage main
2ffe3c632Sopenharmony_ci
3ffe3c632Sopenharmony_ciimport (
4ffe3c632Sopenharmony_ci	"bufio"
5ffe3c632Sopenharmony_ci	"fmt"
6ffe3c632Sopenharmony_ci	"io"
7ffe3c632Sopenharmony_ci	"io/ioutil"
8ffe3c632Sopenharmony_ci	"log"
9ffe3c632Sopenharmony_ci	"os"
10ffe3c632Sopenharmony_ci	"strings"
11ffe3c632Sopenharmony_ci
12ffe3c632Sopenharmony_ci	"github.com/golang/protobuf/proto"
13ffe3c632Sopenharmony_ci	pb "github.com/protocolbuffers/protobuf/examples/tutorial"
14ffe3c632Sopenharmony_ci)
15ffe3c632Sopenharmony_ci
16ffe3c632Sopenharmony_cifunc promptForAddress(r io.Reader) (*pb.Person, error) {
17ffe3c632Sopenharmony_ci	// A protocol buffer can be created like any struct.
18ffe3c632Sopenharmony_ci	p := &pb.Person{}
19ffe3c632Sopenharmony_ci
20ffe3c632Sopenharmony_ci	rd := bufio.NewReader(r)
21ffe3c632Sopenharmony_ci	fmt.Print("Enter person ID number: ")
22ffe3c632Sopenharmony_ci	// An int32 field in the .proto file is represented as an int32 field
23ffe3c632Sopenharmony_ci	// in the generated Go struct.
24ffe3c632Sopenharmony_ci	if _, err := fmt.Fscanf(rd, "%d\n", &p.Id); err != nil {
25ffe3c632Sopenharmony_ci		return p, err
26ffe3c632Sopenharmony_ci	}
27ffe3c632Sopenharmony_ci
28ffe3c632Sopenharmony_ci	fmt.Print("Enter name: ")
29ffe3c632Sopenharmony_ci	name, err := rd.ReadString('\n')
30ffe3c632Sopenharmony_ci	if err != nil {
31ffe3c632Sopenharmony_ci		return p, err
32ffe3c632Sopenharmony_ci	}
33ffe3c632Sopenharmony_ci	// A string field in the .proto file results in a string field in Go.
34ffe3c632Sopenharmony_ci	// We trim the whitespace because rd.ReadString includes the trailing
35ffe3c632Sopenharmony_ci	// newline character in its output.
36ffe3c632Sopenharmony_ci	p.Name = strings.TrimSpace(name)
37ffe3c632Sopenharmony_ci
38ffe3c632Sopenharmony_ci	fmt.Print("Enter email address (blank for none): ")
39ffe3c632Sopenharmony_ci	email, err := rd.ReadString('\n')
40ffe3c632Sopenharmony_ci	if err != nil {
41ffe3c632Sopenharmony_ci		return p, err
42ffe3c632Sopenharmony_ci	}
43ffe3c632Sopenharmony_ci	p.Email = strings.TrimSpace(email)
44ffe3c632Sopenharmony_ci
45ffe3c632Sopenharmony_ci	for {
46ffe3c632Sopenharmony_ci		fmt.Print("Enter a phone number (or leave blank to finish): ")
47ffe3c632Sopenharmony_ci		phone, err := rd.ReadString('\n')
48ffe3c632Sopenharmony_ci		if err != nil {
49ffe3c632Sopenharmony_ci			return p, err
50ffe3c632Sopenharmony_ci		}
51ffe3c632Sopenharmony_ci		phone = strings.TrimSpace(phone)
52ffe3c632Sopenharmony_ci		if phone == "" {
53ffe3c632Sopenharmony_ci			break
54ffe3c632Sopenharmony_ci		}
55ffe3c632Sopenharmony_ci		// The PhoneNumber message type is nested within the Person
56ffe3c632Sopenharmony_ci		// message in the .proto file.  This results in a Go struct
57ffe3c632Sopenharmony_ci		// named using the name of the parent prefixed to the name of
58ffe3c632Sopenharmony_ci		// the nested message.  Just as with pb.Person, it can be
59ffe3c632Sopenharmony_ci		// created like any other struct.
60ffe3c632Sopenharmony_ci		pn := &pb.Person_PhoneNumber{
61ffe3c632Sopenharmony_ci			Number: phone,
62ffe3c632Sopenharmony_ci		}
63ffe3c632Sopenharmony_ci
64ffe3c632Sopenharmony_ci		fmt.Print("Is this a mobile, home, or work phone? ")
65ffe3c632Sopenharmony_ci		ptype, err := rd.ReadString('\n')
66ffe3c632Sopenharmony_ci		if err != nil {
67ffe3c632Sopenharmony_ci			return p, err
68ffe3c632Sopenharmony_ci		}
69ffe3c632Sopenharmony_ci		ptype = strings.TrimSpace(ptype)
70ffe3c632Sopenharmony_ci
71ffe3c632Sopenharmony_ci		// A proto enum results in a Go constant for each enum value.
72ffe3c632Sopenharmony_ci		switch ptype {
73ffe3c632Sopenharmony_ci		case "mobile":
74ffe3c632Sopenharmony_ci			pn.Type = pb.Person_MOBILE
75ffe3c632Sopenharmony_ci		case "home":
76ffe3c632Sopenharmony_ci			pn.Type = pb.Person_HOME
77ffe3c632Sopenharmony_ci		case "work":
78ffe3c632Sopenharmony_ci			pn.Type = pb.Person_WORK
79ffe3c632Sopenharmony_ci		default:
80ffe3c632Sopenharmony_ci			fmt.Printf("Unknown phone type %q.  Using default.\n", ptype)
81ffe3c632Sopenharmony_ci		}
82ffe3c632Sopenharmony_ci
83ffe3c632Sopenharmony_ci		// A repeated proto field maps to a slice field in Go.  We can
84ffe3c632Sopenharmony_ci		// append to it like any other slice.
85ffe3c632Sopenharmony_ci		p.Phones = append(p.Phones, pn)
86ffe3c632Sopenharmony_ci	}
87ffe3c632Sopenharmony_ci
88ffe3c632Sopenharmony_ci	return p, nil
89ffe3c632Sopenharmony_ci}
90ffe3c632Sopenharmony_ci
91ffe3c632Sopenharmony_ci// Main reads the entire address book from a file, adds one person based on
92ffe3c632Sopenharmony_ci// user input, then writes it back out to the same file.
93ffe3c632Sopenharmony_cifunc main() {
94ffe3c632Sopenharmony_ci	if len(os.Args) != 2 {
95ffe3c632Sopenharmony_ci		log.Fatalf("Usage:  %s ADDRESS_BOOK_FILE\n", os.Args[0])
96ffe3c632Sopenharmony_ci	}
97ffe3c632Sopenharmony_ci	fname := os.Args[1]
98ffe3c632Sopenharmony_ci
99ffe3c632Sopenharmony_ci	// Read the existing address book.
100ffe3c632Sopenharmony_ci	in, err := ioutil.ReadFile(fname)
101ffe3c632Sopenharmony_ci	if err != nil {
102ffe3c632Sopenharmony_ci		if os.IsNotExist(err) {
103ffe3c632Sopenharmony_ci			fmt.Printf("%s: File not found.  Creating new file.\n", fname)
104ffe3c632Sopenharmony_ci		} else {
105ffe3c632Sopenharmony_ci			log.Fatalln("Error reading file:", err)
106ffe3c632Sopenharmony_ci		}
107ffe3c632Sopenharmony_ci	}
108ffe3c632Sopenharmony_ci
109ffe3c632Sopenharmony_ci	// [START marshal_proto]
110ffe3c632Sopenharmony_ci	book := &pb.AddressBook{}
111ffe3c632Sopenharmony_ci	// [START_EXCLUDE]
112ffe3c632Sopenharmony_ci	if err := proto.Unmarshal(in, book); err != nil {
113ffe3c632Sopenharmony_ci		log.Fatalln("Failed to parse address book:", err)
114ffe3c632Sopenharmony_ci	}
115ffe3c632Sopenharmony_ci
116ffe3c632Sopenharmony_ci	// Add an address.
117ffe3c632Sopenharmony_ci	addr, err := promptForAddress(os.Stdin)
118ffe3c632Sopenharmony_ci	if err != nil {
119ffe3c632Sopenharmony_ci		log.Fatalln("Error with address:", err)
120ffe3c632Sopenharmony_ci	}
121ffe3c632Sopenharmony_ci	book.People = append(book.People, addr)
122ffe3c632Sopenharmony_ci	// [END_EXCLUDE]
123ffe3c632Sopenharmony_ci
124ffe3c632Sopenharmony_ci	// Write the new address book back to disk.
125ffe3c632Sopenharmony_ci	out, err := proto.Marshal(book)
126ffe3c632Sopenharmony_ci	if err != nil {
127ffe3c632Sopenharmony_ci		log.Fatalln("Failed to encode address book:", err)
128ffe3c632Sopenharmony_ci	}
129ffe3c632Sopenharmony_ci	if err := ioutil.WriteFile(fname, out, 0644); err != nil {
130ffe3c632Sopenharmony_ci		log.Fatalln("Failed to write address book:", err)
131ffe3c632Sopenharmony_ci	}
132ffe3c632Sopenharmony_ci	// [END marshal_proto]
133ffe3c632Sopenharmony_ci}
134