| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package sysdown |
| |
| import ( |
| "bytes" |
| "fmt" |
| "io" |
| |
| "mynewt.apache.org/newt/newt/newtutil" |
| "mynewt.apache.org/newt/newt/pkg" |
| "mynewt.apache.org/newt/newt/stage" |
| "mynewt.apache.org/newt/newt/syscfg" |
| ) |
| |
| type SysdownCfg struct { |
| // Sorted in call order (stage-num,function-name). |
| StageFuncs []stage.StageFunc |
| |
| // Strings describing errors encountered while parsing the sysdown config. |
| InvalidSettings []string |
| |
| // Contains sets of entries with conflicting function names. |
| // [function-name] => <slice-of-stages-with-function-name> |
| Conflicts map[string][]stage.StageFunc |
| } |
| |
| func (scfg *SysdownCfg) readOnePkg(lpkg *pkg.LocalPackage, cfg *syscfg.Cfg) { |
| settings := cfg.AllSettingsForLpkg(lpkg) |
| initMap := lpkg.DownFuncs(settings) |
| for name, stageStr := range initMap { |
| sf, err := stage.NewStageFunc(name, stageStr, lpkg, cfg) |
| if err != nil { |
| scfg.InvalidSettings = append(scfg.InvalidSettings, err.Error()) |
| } |
| sf.ReturnType = "int" |
| sf.ArgList = "int reason" |
| |
| scfg.StageFuncs = append(scfg.StageFuncs, sf) |
| } |
| } |
| |
| // Searches the sysdown configuration for entries with identical function |
| // names. The sysdown configuration object is populated with the results. |
| func (scfg *SysdownCfg) detectConflicts() { |
| m := map[string][]stage.StageFunc{} |
| |
| for _, sf := range scfg.StageFuncs { |
| m[sf.Name] = append(m[sf.Name], sf) |
| } |
| |
| for name, sfs := range m { |
| if len(sfs) > 1 { |
| scfg.Conflicts[name] = sfs |
| } |
| } |
| } |
| |
| func Read(lpkgs []*pkg.LocalPackage, cfg *syscfg.Cfg) SysdownCfg { |
| scfg := SysdownCfg{} |
| |
| for _, lpkg := range lpkgs { |
| scfg.readOnePkg(lpkg, cfg) |
| } |
| |
| scfg.detectConflicts() |
| stage.SortStageFuncs(scfg.StageFuncs, "sysdown") |
| |
| return scfg |
| } |
| |
| func (scfg *SysdownCfg) filter(lpkgs []*pkg.LocalPackage) []stage.StageFunc { |
| m := make(map[*pkg.LocalPackage]struct{}, len(lpkgs)) |
| |
| for _, lpkg := range lpkgs { |
| m[lpkg] = struct{}{} |
| } |
| |
| filtered := []stage.StageFunc{} |
| for _, sf := range scfg.StageFuncs { |
| if _, ok := m[sf.Pkg]; ok { |
| filtered = append(filtered, sf) |
| } |
| } |
| |
| return filtered |
| } |
| |
| // If any errors were encountered while parsing sysdown definitions, this |
| // function returns a string indicating the errors. If no errors were |
| // encountered, "" is returned. |
| func (scfg *SysdownCfg) ErrorText() string { |
| str := "" |
| |
| if len(scfg.InvalidSettings) > 0 { |
| str += "Invalid sysdown definitions detected:" |
| for _, e := range scfg.InvalidSettings { |
| str += "\n " + e |
| } |
| } |
| |
| if len(scfg.Conflicts) > 0 { |
| str += "Sysdown function name conflicts detected:\n" |
| for name, sfs := range scfg.Conflicts { |
| for _, sf := range sfs { |
| str += fmt.Sprintf(" Function=%s Package=%s\n", |
| name, sf.Pkg.FullName()) |
| } |
| } |
| |
| str += "\nResolve the problem by assigning unique function names " + |
| "to each entry." |
| } |
| |
| return str |
| } |
| |
| func (scfg *SysdownCfg) write(lpkgs []*pkg.LocalPackage, isLoader bool, |
| w io.Writer) error { |
| |
| var sfs []stage.StageFunc |
| if lpkgs == nil { |
| sfs = scfg.StageFuncs |
| } else { |
| sfs = scfg.filter(lpkgs) |
| } |
| |
| fmt.Fprintf(w, newtutil.GeneratedPreamble()) |
| |
| if isLoader { |
| fmt.Fprintf(w, "#if SPLIT_LOADER\n\n") |
| } else { |
| fmt.Fprintf(w, "#if !SPLIT_LOADER\n\n") |
| } |
| |
| stage.WritePrototypes(sfs, w) |
| |
| var arrName string |
| |
| // XXX: Assign a different array name depending on isLoader. |
| arrName = "sysdown_cbs" |
| |
| fmt.Fprintf(w, "\nint (* const %s[])(int reason) = {\n", arrName) |
| stage.WriteArr(sfs, w) |
| fmt.Fprintf(w, "};\n") |
| |
| fmt.Fprintf(w, "#endif\n") |
| |
| return nil |
| } |
| |
| func (scfg *SysdownCfg) EnsureWritten(lpkgs []*pkg.LocalPackage, srcDir string, |
| targetName string, isLoader bool) error { |
| |
| buf := bytes.Buffer{} |
| if err := scfg.write(lpkgs, isLoader, &buf); err != nil { |
| return err |
| } |
| |
| var path string |
| if isLoader { |
| path = fmt.Sprintf("%s/%s-sysdown-loader.c", srcDir, targetName) |
| } else { |
| path = fmt.Sprintf("%s/%s-sysdown-app.c", srcDir, targetName) |
| } |
| |
| return stage.EnsureWritten(path, buf.Bytes()) |
| } |