コード例 #1
0
ファイル: jirafun.go プロジェクト: cmccabe/cmccabe-hbin
func (c *Commit) Match(regex *regexp.Regexp) *string {
	if regex.NumSubexp() == 1 {
		m := regex.FindStringSubmatch(c.text)
		if m == nil {
			return nil
		}
		return &m[1]
	} else {
		if !regex.MatchString(c.text) {
			return nil
		}
		return &c.text
	}
	return nil
}
コード例 #2
0
ファイル: regexp_test.go プロジェクト: RomainVabre/origin
func checkRegexp(t *testing.T, r *regexp.Regexp, m regexpMatch) {
	matches := r.FindStringSubmatch(m.input)
	if m.match && matches != nil {
		if len(matches) != (r.NumSubexp()+1) || matches[0] != m.input {
			t.Fatalf("Bad match result %#v for %q", matches, m.input)
		}
		if len(matches) < (len(m.subs) + 1) {
			t.Errorf("Expected %d sub matches, only have %d for %q", len(m.subs), len(matches)-1, m.input)
		}
		for i := range m.subs {
			if m.subs[i] != matches[i+1] {
				t.Errorf("Unexpected submatch %d: %q, expected %q for %q", i+1, matches[i+1], m.subs[i], m.input)
			}
		}
	} else if m.match {
		t.Errorf("Expected match for %q", m.input)
	} else if matches != nil {
		t.Errorf("Unexpected match for %q", m.input)
	}
}
コード例 #3
0
func New(svcs ...EndPointHandler) (*Service, error) {
	var resp *Service
	var svc EndPointHandler
	var svcElem EndPointHandler
	var svcRecv reflect.Value
	var consumes string
	var svcConsumes string
	var produces string
	var svcProduces string
	var allowGzip string
	var enableCORS string
	var proto []string
	var svcProto []string
	var svcRoot string
	var i, j, k int
	var typ reflect.Type
	var typPtr reflect.Type
	var pt []reflect.Type
	var fld reflect.StructField
	var method reflect.Method
	var parmcount int
	var httpmethod, path string
	var methodName string
	var tk string
	var ok bool
	var re string
	var reAllOps string
	var reComp *regexp.Regexp
	var c rune
	var err error
	var stmp string
	var SwaggerParameter *SwaggerParameterT
	var swaggerParameters []SwaggerParameterT
	var swaggerInfo SwaggerInfoT
	var swaggerLicense SwaggerLicenseT
	var swaggerContact SwaggerContactT
	var globalDataCount int
	var responseOk string
	var responseCreated string
	var responseAccepted string
	var responses map[string]SwaggerResponseT
	var fldType reflect.Type
	var doc string
	var description *string
	var headers []string
	var query []string
	var optIndex map[string]int
	var HdrNew, HdrOld string
	var MatchedOpsIndex int
	var postFields []string
	var postField string
	var postdata string
	//   var accesstype           uint8
	var parmnames []string

	for _, svc = range svcs {
		Goose.New.Logf(6, "Elem: %#v (Kind: %#v)", reflect.ValueOf(svc), reflect.ValueOf(svc).Kind())
		if reflect.ValueOf(svc).Kind() == reflect.Ptr {
			Goose.New.Logf(6, "Elem: %#v", reflect.ValueOf(svc).Elem())
			svcElem = reflect.ValueOf(svc).Elem().Interface().(EndPointHandler)
			Goose.New.Logf(6, "Elem type: %s, ptr type: %s", reflect.TypeOf(svcElem), reflect.TypeOf(svc))
		} else {
			svcElem = svc
			Goose.New.Logf(6, "Elem type: %s", reflect.TypeOf(svcElem))
		}

		// The first endpoint handler MUST have a config defined, otherwise we'll ignore endpoint handlers until we find one which provides a configuration
		if resp == nil {
			resp, err = initSvc(svcElem)
			if err != nil {
				return nil, err
			}
			if resp == nil {
				continue // If we still don't have a config defined and the endpoint handler has no config defined it WILL BE IGNORED!!!
			}
		}

		typ = reflect.ValueOf(svcElem).Type()
		if typ.Kind() == reflect.Ptr {
			typPtr = typ
			typ = typ.Elem()
		} else {
			typPtr = reflect.PtrTo(typ)
		}

		if resp.Swagger == nil {
			for i = 0; (i < typ.NumField()) && (globalDataCount < 4); i++ {
				if svcRoot == "" {
					svcRoot = typ.Field(i).Tag.Get("root")
					if svcRoot != "" {
						svcConsumes = typ.Field(i).Tag.Get("consumes")
						svcProduces = typ.Field(i).Tag.Get("produces")
						allowGzip = typ.Field(i).Tag.Get("allowGzip")
						enableCORS = typ.Field(i).Tag.Get("enableCORS")
						if typ.Field(i).Tag.Get("proto") != "" {
							svcProto = strings.Split(strings.ToLower(strings.Trim(typ.Field(i).Tag.Get("proto"), " ")), ",")
						} else {
							svcProto = []string{"https"}
						}

						Goose.New.Logf(3, "Access tag: %s", typ.Field(i).Tag.Get("access"))

						if typ.Field(i).Tag.Get("access") != "" {
							switch strings.ToLower(strings.Trim(typ.Field(i).Tag.Get("access"), " ")) {
							case "none":
								resp.Access = AccessNone
							case "auth":
								resp.Access = AccessAuth
							case "authinfo":
								resp.Access = AccessAuthInfo
							case "verifyauth":
								resp.Access = AccessVerifyAuth
							case "verifyauthinfo":
								resp.Access = AccessVerifyAuthInfo
							}
							Goose.New.Logf(3, "Custom access type: %d", resp.Access)
						} else {
							resp.Access = AccessAuthInfo
							Goose.New.Logf(3, "Default access type: %d", resp.Access)
						}
						globalDataCount++
					}
				}
				if swaggerInfo.Title == "" {
					stmp = typ.Field(i).Tag.Get("title")
					if stmp != "" {
						swaggerInfo.Title = stmp
						swaggerInfo.Description = typ.Field(i).Tag.Get("description")
						swaggerInfo.TermsOfService = typ.Field(i).Tag.Get("tos")
						swaggerInfo.Version = typ.Field(i).Tag.Get("version")
						globalDataCount++
					}
				}
				if swaggerContact.Name == "" {
					stmp = typ.Field(i).Tag.Get("contact")
					if stmp != "" {
						swaggerContact.Name = stmp
						swaggerContact.Url = typ.Field(i).Tag.Get("url")
						swaggerContact.Email = typ.Field(i).Tag.Get("email")
						globalDataCount++
					}
				}
				if swaggerLicense.Name == "" {
					stmp = typ.Field(i).Tag.Get("license")
					if stmp != "" {
						swaggerLicense.Name = stmp
						swaggerLicense.Url = typ.Field(i).Tag.Get("url")
						globalDataCount++
					}
				}
			}

			swaggerInfo.Contact = swaggerContact
			swaggerInfo.License = swaggerLicense

			svcRoot = strings.Trim(strings.Trim(svcRoot, " "), "/") + "/"
			svcConsumes = strings.Trim(svcConsumes, " ")
			svcProduces = strings.Trim(svcProduces, " ")

			if (svcRoot == "") || (svcConsumes == "") || (svcProduces == "") {
				Goose.New.Logf(1, "Err: %s", ErrorNoRoot)
				return nil, ErrorNoRoot
			}

			hostport := strings.Split(resp.Config.ListenAddress(), ":")
			if hostport[0] == "" {
				hostport[0] = resp.Authorizer.GetDNSNames()[0]
			}

			resp.Swagger = &SwaggerT{
				Version:     "2.0",
				Info:        swaggerInfo,
				Host:        strings.Join(hostport, ":"),
				BasePath:    "/" + svcRoot[:len(svcRoot)-1],
				Schemes:     svcProto,
				Consumes:    []string{svcConsumes},
				Produces:    []string{svcProduces},
				Paths:       map[string]SwaggerPathT{},
				Definitions: map[string]SwaggerSchemaT{},
			}

			resp.Proto = svcProto

			Goose.New.Logf(6, "enableCORS: [%s]", enableCORS)
			if enableCORS != "" {
				resp.EnableCORS, err = strconv.ParseBool(enableCORS)
				Goose.New.Logf(6, "resp.EnableCORS: %#v", resp.EnableCORS)
				if err != nil {
					Goose.New.Logf(1, "Err: %s", ErrorServiceSyntax)
					return nil, ErrorServiceSyntax
				}
			}

			Goose.New.Logf(6, "allowGzip: [%s]", allowGzip)
			if allowGzip != "" {
				resp.AllowGzip, err = strconv.ParseBool(allowGzip)
				Goose.New.Logf(6, "resp.AllowGzip: %#v", resp.AllowGzip)
				if err != nil {
					Goose.New.Logf(1, "Err: %s", ErrorServiceSyntax)
					return nil, ErrorServiceSyntax
				}
			}
		}

		for i = 0; i < typ.NumField(); i++ {
			fld = typ.Field(i)
			httpmethod = fld.Tag.Get("method")
			if httpmethod != "" {
				methodName = strings.ToUpper(fld.Name[:1]) + fld.Name[1:]
				svcRecv = reflect.ValueOf(svcElem)
				if method, ok = typ.MethodByName(methodName); !ok {
					if method, ok = typPtr.MethodByName(methodName); !ok {
						Goose.New.Logf(5, "|methods|=%d", typ.NumMethod())
						Goose.New.Logf(5, "type=%s.%s", typ.PkgPath(), typ.Name())
						for j = 0; j < typ.NumMethod(); j++ {
							mt := typ.Method(j)
							Goose.New.Logf(5, "%d: %s", j, mt.Name)
						}

						Goose.New.Logf(1, "Method not found: %s, Data: %#v", methodName, typ)
						return nil, errors.New(fmt.Sprintf("Method not found: %s", methodName))
					} else {
						Goose.New.Logf(1, "Pointer method found, type of svcElem: %s", reflect.TypeOf(svcElem))
						svcRecv = reflect.ValueOf(svc)
						Goose.New.Logf(5, "Pointer method found: %s", methodName)
					}
				}
				path = fld.Tag.Get("path")

				if _, ok := resp.Swagger.Paths[path]; !ok {
					resp.Swagger.Paths[path] = SwaggerPathT{}
					//         } else if _, ok := resp.Swagger.Paths[path][httpmethod]; !ok {
					//            resp.Swagger.Paths[path][httpmethod] = SwaggerOperationT{}
				}

				swaggerParameters = []SwaggerParameterT{}

				re = "^" + strings.ToUpper(httpmethod) + ":/" + svcRoot

				parmcount = 0
				parmnames = []string{}

				for _, tk = range strings.Split(strings.Trim(path, "/"), "/") {
					if tk != "" {
						if (tk[0] == '{') && (tk[len(tk)-1] == '}') {
							re += "([^/]+)/"
							parmcount++
							SwaggerParameter, err = GetSwaggerType(method.Type.In(parmcount))
							if err != nil {
								return nil, err
							}

							if SwaggerParameter == nil {
								return nil, ErrorInvalidNilParam
							}

							if (SwaggerParameter.Items != nil) || (SwaggerParameter.CollectionFormat != "") || (SwaggerParameter.Schema.Required != nil) {
								Goose.New.Logf(1, "%s: %s", tk[1:len(tk)-1])
								return nil, ErrorInvalidParameterType
							}

							doc = fld.Tag.Get(tk[1 : len(tk)-1])
							if doc != "" {
								description = new(string)
								(*description) = doc
							} else {
								description = SwaggerParameter.Schema.Description
								if description == nil {
									description = new(string)
								}
							}

							xkeytype := ""
							if SwaggerParameter.Schema != nil {
								xkeytype = SwaggerParameter.Schema.XKeyType
							}

							swaggerParameters = append(
								swaggerParameters,
								SwaggerParameterT{
									Name:        tk[1 : len(tk)-1],
									In:          "path",
									Required:    true,
									Type:        SwaggerParameter.Schema.Type,
									XKeyType:    xkeytype,
									Description: *description,
									Format:      SwaggerParameter.Format,
								})
							parmnames = append(parmnames, tk[1:len(tk)-1])
						} else if (tk[0] != '{') && (tk[len(tk)-1] != '}') {
							for _, c = range tk {
								re += fmt.Sprintf("\\x{%x}", c)
							}
							re += "/"
						} else {
							return nil, errors.New("syntax error at " + tk)
						}
					}
				}

				if resp.Svc == nil {
					resp.Svc = []UrlNode{}
				}

				re += "{0,1}$"

				Goose.New.Logf(4, "Service "+strings.ToUpper(httpmethod)+":/"+svcRoot+path+", RE="+re)

				query, parmcount, _, swaggerParameters, err = ParseFieldList("query", parmcount, fld, method, methodName, swaggerParameters)
				if err != nil {
					return nil, err
				}

				headers, parmcount, _, swaggerParameters, err = ParseFieldList("header", parmcount, fld, method, methodName, swaggerParameters)
				if err != nil {
					return nil, err
				}

				parmnames = append(parmnames, query...)
				parmnames = append(parmnames, headers...)

				postdata = fld.Tag.Get("postdata")
				if postdata != "" {
					// Body fields definitions
					postFields = strings.Split(postdata, ",")
					pt = make([]reflect.Type, len(postFields))
					for k, postField = range postFields {
						parmcount++
						pt[k] = method.Type.In(parmcount)
						SwaggerParameter, err = GetSwaggerType(pt[k])
						if err != nil {
							return nil, err
						}

						if SwaggerParameter == nil {
							return nil, ErrorInvalidNilParam
						}

						doc = fld.Tag.Get(postField)
						if doc != "" {
							SwaggerParameter.Schema.Description = new(string)
							(*SwaggerParameter.Schema.Description) = doc
						}

						parmnames = append(parmnames, postField)
						SwaggerParameter.Name = postField
						SwaggerParameter.In = "body"
						SwaggerParameter.Required = true

						swaggerParameters = append(swaggerParameters, *SwaggerParameter)
					}

					/*
					   if resp.Access == AccessAuthInfo || resp.Access == AccessVerifyAuthInfo {
					      parmcount++
					   }

					   if (parmcount+len(postFields)+1) != method.Type.NumIn() {
					      return nil, errors.New("Wrong parameter count (with post) at method " + methodName)
					   }
					*/
				} else {
					pt = nil
				}

				if resp.Access == AccessAuthInfo || resp.Access == AccessVerifyAuthInfo {
					if (parmcount + 1) != method.Type.NumIn() {
						parmcount++
						if (parmcount + 1) != method.Type.NumIn() {
							return nil, errors.New("Wrong parameter (with info) count at method " + methodName)
						}
					}
				} else {
					if (parmcount + 1) != method.Type.NumIn() {
						return nil, errors.New("Wrong parameter count at method " + methodName)
					}
				}

				Goose.New.Logf(5, "Registering: %s", re)
				consumes = fld.Tag.Get("consumes")
				Goose.New.Logf(1, "op:%s consumes: %s tag:%#v", methodName, consumes, fld.Tag)
				if consumes == "" {
					consumes = svcConsumes
				}

				produces = fld.Tag.Get("produces")
				if produces == "" {
					produces = svcProduces
				}

				if fld.Tag.Get("proto") != "" {
					proto = strings.Split(strings.ToLower(strings.Trim(typ.Field(i).Tag.Get("proto"), " ")), ",")
				} else {
					proto = svcProto
				}

				responses = map[string]SwaggerResponseT{}

				responseOk = fld.Tag.Get("ok")
				responseCreated = fld.Tag.Get("created")
				responseAccepted = fld.Tag.Get("accepted")
				if responseOk != "" || responseCreated != "" || responseAccepted != "" {
					if responseOk != "" {
						fldType = fld.Type
						if fldType.Kind() == reflect.Ptr {
							fldType = fldType.Elem()
						}

						SwaggerParameter, err = GetSwaggerType(fldType)
						if err != nil {
							return nil, err
						}

						if SwaggerParameter == nil {
							responses[fmt.Sprintf("%d", http.StatusNoContent)] = SwaggerResponseT{
								Description: responseOk,
							}
						} else {

							doc = fld.Tag.Get(fld.Name)

							if doc != "" {
								SwaggerParameter.Schema.Description = new(string)
								(*SwaggerParameter.Schema.Description) = doc
							}

							if SwaggerParameter.Schema == nil {
								SwaggerParameter.Schema = &SwaggerSchemaT{}
							}

							if (SwaggerParameter.Schema.Type == "") && (SwaggerParameter.Type != "") {
								SwaggerParameter.Schema.Type = SwaggerParameter.Type
							}

							responses[fmt.Sprintf("%d", http.StatusOK)] = SwaggerResponseT{
								Description: responseOk,
								Schema:      SwaggerParameter.Schema,
							}
							//(*responses[fmt.Sprintf("%d",http.StatusOK)].Schema) = *SwaggerParameter.Schema
							//ioutil.WriteFile("debug.txt", []byte(fmt.Sprintf("%#v",responses)), os.FileMode(0770))
							Goose.New.Logf(6, "====== %#v", *(responses[fmt.Sprintf("%d", http.StatusOK)].Schema))
						}
					}
					if responseCreated != "" {
						fldType = fld.Type
						if fldType.Kind() == reflect.Ptr {
							fldType = fldType.Elem()
						}

						SwaggerParameter, err = GetSwaggerType(fldType)
						if err != nil {
							return nil, err
						}

						if SwaggerParameter == nil {
							responses[fmt.Sprintf("%d", http.StatusCreated)] = SwaggerResponseT{
								Description: responseCreated,
							}
						} else {

							doc = fld.Tag.Get(fld.Name)

							if doc != "" {
								SwaggerParameter.Schema.Description = new(string)
								(*SwaggerParameter.Schema.Description) = doc
							}

							if SwaggerParameter.Schema == nil {
								SwaggerParameter.Schema = &SwaggerSchemaT{}
							}

							if (SwaggerParameter.Schema.Type == "") && (SwaggerParameter.Type != "") {
								SwaggerParameter.Schema.Type = SwaggerParameter.Type
							}

							responses[fmt.Sprintf("%d", http.StatusCreated)] = SwaggerResponseT{
								Description: responseCreated,
								Schema:      SwaggerParameter.Schema,
							}
							//(*responses[fmt.Sprintf("%d",http.StatusOK)].Schema) = *SwaggerParameter.Schema
							//ioutil.WriteFile("debug.txt", []byte(fmt.Sprintf("%#v",responses)), os.FileMode(0770))
							Goose.New.Logf(6, "====== %#v", *(responses[fmt.Sprintf("%d", http.StatusCreated)].Schema))
						}
					}
					if responseAccepted != "" {
						fldType = fld.Type
						if fldType.Kind() == reflect.Ptr {
							fldType = fldType.Elem()
						}

						SwaggerParameter, err = GetSwaggerType(fldType)
						if err != nil {
							return nil, err
						}

						if SwaggerParameter == nil {
							responses[fmt.Sprintf("%d", http.StatusAccepted)] = SwaggerResponseT{
								Description: responseAccepted,
							}
						} else {

							doc = fld.Tag.Get(fld.Name)

							if doc != "" {
								SwaggerParameter.Schema.Description = new(string)
								(*SwaggerParameter.Schema.Description) = doc
							}

							if SwaggerParameter.Schema == nil {
								SwaggerParameter.Schema = &SwaggerSchemaT{}
							}

							if (SwaggerParameter.Schema.Type == "") && (SwaggerParameter.Type != "") {
								SwaggerParameter.Schema.Type = SwaggerParameter.Type
							}

							responses[fmt.Sprintf("%d", http.StatusAccepted)] = SwaggerResponseT{
								Description: responseAccepted,
								Schema:      SwaggerParameter.Schema,
							}
							//(*responses[fmt.Sprintf("%d",http.StatusOK)].Schema) = *SwaggerParameter.Schema
							//ioutil.WriteFile("debug.txt", []byte(fmt.Sprintf("%#v",responses)), os.FileMode(0770))
							Goose.New.Logf(6, "====== %#v", *(responses[fmt.Sprintf("%d", http.StatusAccepted)].Schema))
						}
					}
				} else if responseFunc, ok := typ.MethodByName(fld.Name + "Responses"); ok {
					responseList := responseFunc.Func.Call([]reflect.Value{})[0].Interface().(map[string]ResponseT)
					for responseStatus, responseSchema := range responseList {
						SwaggerParameter, err = GetSwaggerType(reflect.TypeOf(responseSchema.TypeReturned))
						if err != nil {
							return nil, err
						}
						if SwaggerParameter == nil {
							responses[responseStatus] = SwaggerResponseT{
								Description: responseSchema.Description,
							}
						} else {
							responses[responseStatus] = SwaggerResponseT{
								Description: responseSchema.Description,
								Schema:      SwaggerParameter.Schema,
							}
						}
					}
				}

				resp.Swagger.Paths[path][strings.ToLower(httpmethod)] = SwaggerOperationT{
					Schemes:     proto,
					OperationId: methodName,
					Parameters:  swaggerParameters,
					Responses:   responses,
					Consumes:    []string{consumes},
					Produces:    []string{produces},
				}

				Goose.New.Logf(5, "Registering marshalers: %s, %s", consumes, produces)

				resp.MatchedOps[MatchedOpsIndex] = len(resp.Svc)
				reComp = regexp.MustCompile(re)
				MatchedOpsIndex += reComp.NumSubexp() + 1

				/*
				   switch strings.ToLower(fld.Tag.Get("access")) {
				      case "none":     accesstype = AccessNone
				      case "auth":     accesstype = AccessAuth
				      case "authinfo": accesstype = AccessAuthInfo
				      default:         accesstype = AccessAuth
				   }
				*/

				resp.Svc = append(resp.Svc, UrlNode{
					Proto:     proto,
					Path:      path,
					consumes:  consumes,
					produces:  produces,
					Headers:   headers,
					Query:     query,
					Body:      postFields,
					ParmNames: parmnames,
					Handle:    buildHandle(svcRecv, method, pt, resp.Access),
					//               Access:    resp.Access,
				})

				reAllOps += "|(" + re + ")"
				Goose.New.Logf(6, "Partial Matcher for %s is %s", path, reAllOps)

				if resp.EnableCORS {
					index := len(resp.Svc)
					if optIndex == nil {
						optIndex = map[string]int{path: index}
					} else if index, ok = optIndex[path]; ok {
						for _, HdrNew = range headers {
							for _, HdrOld = range resp.Svc[index].Headers {
								if HdrOld == HdrNew {
									break
								}
							}
							if HdrOld != HdrNew {
								resp.Svc[index].Headers = append(resp.Svc[index].Headers, HdrNew)
							}
						}
						continue
					} else {
						optIndex[path] = len(resp.Svc)
					}

					re = "^OPTIONS" + re[len(httpmethod)+1:]
					resp.MatchedOps[MatchedOpsIndex] = len(resp.Svc)
					reComp = regexp.MustCompile(re)
					MatchedOpsIndex += reComp.NumSubexp() + 1

					resp.Svc = append(resp.Svc, UrlNode{
						Path:    path,
						Headers: headers,
					})
					reAllOps += "|(" + re + ")"
					Goose.New.Logf(6, "Partial Matcher with options for %s is %s", path, reAllOps)
				}
			}
		}
	}

	Goose.New.Logf(6, "Operations matcher: %s\n", reAllOps[1:])
	Goose.New.Logf(6, "Operations %#v\n", resp.Svc)
	resp.Matcher = regexp.MustCompile(reAllOps[1:]) // Cutting the leading '|'
	return resp, nil
}
コード例 #4
0
ファイル: sed.go プロジェクト: akutz/gnixutils
func main() {
	flag.Parse()

	fargs := flag.Args()
	if len(fargs) == 0 {
		flag.Usage()
		os.Exit(1)
	}

	patt := fargs[0]
	delim := string(patt[1])
	parts := strings.Split(patt, delim)

	sedFrom := parts[1]
	sedTo := parts[2]
	sedFlags := parts[3]

	var pattFlags syntax.Flags

	if ere || erE {
		pattFlags |= syntax.Perl
	}
	if strings.Contains(sedFlags, "i") {
		pattFlags |= syntax.FoldCase
	}

	sedFlagG = strings.Contains(sedFlags, "g")

	rxParsed, err := syntax.Parse(sedFrom, pattFlags)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	}

	rxsz := rxParsed.String()

	var rx *regexp.Regexp
	if pattFlags&syntax.Perl > 0 {
		rx = regexp.MustCompile(rxsz)
	} else {
		rx = regexp.MustCompilePOSIX(rxsz)
	}

	var maxReplIndex int
	if m := replIndicesLenRx.FindAllStringSubmatch(sedTo, -1); len(m) > 0 {
		for _, sm := range m {
			i, err := strconv.Atoi(sm[1])
			if err != nil {
				fmt.Println(err.Error())
				os.Exit(1)
			}
			if i > maxReplIndex {
				maxReplIndex = i
			}
		}
	}

	if maxReplIndex > rx.NumSubexp() {
		fmt.Println("sed: replacement indices exceed capture groups")
		os.Exit(1)
	}

	switch len(fargs) {
	case 1:
		if sed(rx, sedTo, os.Stdin) {
			os.Exit(0)
		}
		os.Exit(1)
	case 2:
		fr, err := os.Open(fargs[1])
		if err != nil {
			fmt.Println(err.Error())
			os.Exit(1)
		}
		defer fr.Close()
		if sed(rx, sedTo, fr) {
			os.Exit(0)
		}
		os.Exit(1)
	}
}