github.com/lhzd863/cherry@v0.0.0-20200403104631-8e2d1d8f2d8a/src/pkg/config/parser/parser.go (about)

     1  /*
     2  Package parser parse and loads a cherry file to the memory.
     3  --
     4   *                               Copyright (C) 2015 by Rafael Santiago
     5   *
     6   * This is a free software. You can redistribute it and/or modify under
     7   * the terms of the GNU General Public License version 2.
     8   *
     9  */
    10  package parser
    11  
    12  import (
    13  	"fmt"
    14  	"io/ioutil"
    15  	"os"
    16  	"github.com/lhzd863/cherry/src/pkg/config"
    17  	"strconv"
    18  	"strings"
    19  )
    20  
    21  // CherryFileError is returned by any parse function implemented in "parser.go".
    22  type CherryFileError struct {
    23  	src  string
    24  	line int
    25  	msg  string
    26  }
    27  
    28  // Error spits the error string.
    29  func (c *CherryFileError) Error() string {
    30  	if c.line > -1 {
    31  		return fmt.Sprintf("ERROR: %s: at line %d: %s\n", c.src, c.line, c.msg)
    32  	}
    33  	return fmt.Sprintf("ERROR: %s: %s\n", c.src, c.msg)
    34  }
    35  
    36  // NewCherryFileError creates a *CherryFileError.
    37  func NewCherryFileError(src string, line int, msg string) *CherryFileError {
    38  	return &CherryFileError{src, line, msg}
    39  }
    40  
    41  // GetDataFromSection returns the raw section data from a cherry file section data.
    42  func GetDataFromSection(section, configData string, currLine int, currFile string) (string, int, int, *CherryFileError) {
    43  	var s int
    44  	var temp string
    45  	for s = 0; s < len(configData); s++ {
    46  		switch configData[s] {
    47  		case '#':
    48  			for configData[s] != '\n' && configData[s] != '\r' && s < len(configData) {
    49  				s++
    50  			}
    51  			if s < len(configData) {
    52  				currLine++
    53  			}
    54  			continue
    55  		case '(', '\n', ' ', '\t', '\r':
    56  			if configData[s] == '\n' {
    57  				currLine++
    58  			}
    59  			if temp == section {
    60  				if configData[s] == '\n' || configData[s] == '\r' || configData[s] == ' ' || configData[s] == '\t' {
    61  					for s < len(configData) && configData[s] != '(' {
    62  						s++
    63  						if s < len(configData) && configData[s] == '\n' {
    64  							currLine++
    65  						}
    66  					}
    67  				}
    68  				if s < len(configData) && configData[s] == '(' {
    69  					s++
    70  				}
    71  				var data string
    72  				for s < len(configData) {
    73  					if configData[s] == '"' {
    74  						data += string(configData[s])
    75  						s++
    76  						for s < len(configData) && configData[s] != '"' {
    77  							if configData[s] != '\\' {
    78  								data += string(configData[s])
    79  							} else {
    80  								data += string(configData[s+1])
    81  								s++
    82  							}
    83  							s++
    84  						}
    85  						if s < len(configData) {
    86  							data += string(configData[s])
    87  						}
    88  					} else if configData[s] != ')' {
    89  						data += string(configData[s])
    90  					} else {
    91  						break
    92  					}
    93  					s++
    94  				}
    95  				return data, s, currLine, nil
    96  			} else if temp == "cherry.branch" {
    97  				for s < len(configData) && (configData[s] == ' ' || configData[s] == '\t') {
    98  					s++
    99  				}
   100  				if s < len(configData) {
   101  					var branchFilepath string
   102  					for s < len(configData) && configData[s] != '\n' && configData[s] != '\r' {
   103  						branchFilepath += string(configData[s])
   104  						s++
   105  					}
   106  					if s < len(configData) {
   107  						currLine++
   108  					}
   109  					branchBuffer, err := ioutil.ReadFile(branchFilepath)
   110  					if err != nil {
   111  						fmt.Println(fmt.Sprintf("WARNING: %s: at line %d: %s. Be tidy... removing or commenting this dry branch from your cherry.", currFile, currLine-1, err.Error()))
   112  						//return "", s, currLine, NewCherryFileError(currFile,
   113  						//                                            currLine - 1,
   114  						//                                            "unable to read cherry.branch from \"" + branchFilepath + "\" [ details: " + err.Error() + " ]")
   115  					} else {
   116  						branchData, branchOffset, branchLine, _ := GetDataFromSection(section, string(branchBuffer), 1, branchFilepath)
   117  						if len(branchData) > 0 {
   118  							return branchData, branchOffset, branchLine, nil
   119  						}
   120  					}
   121  				}
   122  			}
   123  			temp = ""
   124  			break
   125  		default:
   126  			temp += string(configData[s])
   127  			break
   128  		}
   129  	}
   130  	return "", s, currLine, NewCherryFileError(currFile, -1, "section \""+section+"\" not found.")
   131  }
   132  
   133  // GetNextSetFromData returns the next "field = value".
   134  func GetNextSetFromData(data string, currLine int, tok string) ([]string, int, string) {
   135  	if len(data) == 0 {
   136  		return make([]string, 0), currLine, ""
   137  	}
   138  	var s int
   139  	for s = 0; s < len(data) && (data[s] == ' ' || data[s] == '\t' || data[s] == '\n' || data[s] == '\r'); s++ {
   140  		if data[s] == '\n' {
   141  			currLine++
   142  		}
   143  	}
   144  	var line string
   145  	for s < len(data) && data[s] != '\n' && data[s] != '\r' {
   146  		if data[s] == '"' {
   147  			line += string(data[s])
   148  			s++
   149  			for s < len(data) && data[s] != '"' {
   150  				if data[s] == '\\' {
   151  					s++
   152  				}
   153  				line += string(data[s])
   154  				if data[s] == '\n' {
   155  					currLine++
   156  				}
   157  				s++
   158  			}
   159  			if s < len(data) {
   160  				line += string(data[s])
   161  			}
   162  		} else if data[s] == '#' {
   163  			for s < len(data) && data[s] != '\n' {
   164  				s++
   165  			}
   166  			if s < len(data) {
   167  				currLine++
   168  			}
   169  		} else {
   170  			line += string(data[s])
   171  		}
   172  		s++
   173  	}
   174  	if len(line) == 0 {
   175  		if len(data) == 0 {
   176  			return make([]string, 0), currLine, ""
   177  		}
   178  	}
   179  	set := strings.Split(line, tok)
   180  	if len(set) == 2 {
   181  		set[0] = StripBlanks(set[0])
   182  		set[1] = StripBlanks(set[1])
   183  	}
   184  	var nextData string
   185  	if s < len(data) {
   186  		nextData = data[s:]
   187  	}
   188  	return set, currLine, nextData
   189  }
   190  
   191  // StripBlanks strips all blanks.
   192  func StripBlanks(data string) string {
   193  	var retval string
   194  	var dStart int
   195  	for dStart < len(data) && (data[dStart] == ' ' || data[dStart] == '\t') {
   196  		dStart++
   197  	}
   198  	var dEnd = len(data) - 1
   199  	for dEnd > 0 && (data[dEnd] == ' ' || data[dEnd] == '\t') {
   200  		dEnd--
   201  	}
   202  	retval = data[dStart : dEnd+1]
   203  	return retval
   204  }
   205  
   206  // ParseCherryFile parses a file at @filepath and returns a *config.CherryRooms or a *CherryFileError.
   207  func ParseCherryFile(filepath string) (*config.CherryRooms, *CherryFileError) {
   208  	var cherryRooms *config.CherryRooms
   209  	var cherryFileData []byte
   210  	var data string
   211  	var err *CherryFileError
   212  	var line int
   213  	cherryFileData, ioErr := ioutil.ReadFile(filepath)
   214  	if ioErr != nil {
   215  		return nil, NewCherryFileError("(no file)", -1, fmt.Sprintf("unable to read from \"%s\" [more details: %s].", filepath, ioErr.Error()))
   216  	}
   217  	data, _, line, err = GetDataFromSection("cherry.root", string(cherryFileData), 1, filepath)
   218  	if err != nil {
   219  		return nil, err
   220  	}
   221  	var set []string
   222  	cherryRooms = config.NewCherryRooms()
   223  	set, line, data = GetNextSetFromData(data, line, "=")
   224  	for len(set) == 2 {
   225  		switch set[0] {
   226  		case "servername", "certificate", "private-key":
   227  			if set[1][0] != '"' || set[1][len(set[1])-1] != '"' {
   228  				return nil, NewCherryFileError(filepath, line, fmt.Sprintf("invalid string."))
   229  			}
   230  			data := set[1][1 : len(set[1])-1]
   231  
   232  			if set[0] == "certificate" || set[0] == "private-key" {
   233  				if _, err := os.Stat(data); os.IsNotExist(err) {
   234  					return nil, NewCherryFileError(filepath, line, fmt.Sprintf("\"%s\" must receive an accessible file path.", set[0]))
   235  				}
   236  			}
   237  
   238  			if set[0] == "servername" {
   239  				cherryRooms.SetServername(data)
   240  			} else if set[0] == "certificate" {
   241  				cherryRooms.SetCertificatePath(data)
   242  			} else if set[0] == "private-key" {
   243  				cherryRooms.SetPrivateKeyPath(data)
   244  			}
   245  			break
   246  
   247  		default:
   248  			return nil, NewCherryFileError(filepath, line, fmt.Sprintf("unknown config set \"%s\".", set[0]))
   249  		}
   250  		set, line, data = GetNextSetFromData(data, line, "=")
   251  	}
   252  	if cherryRooms.GetServername() == "localhost" {
   253  		fmt.Println("WARN: cherry.root.servername is equals to \"localhost\". Things will not work outside this node.")
   254  	}
   255  	data, _, line, err = GetDataFromSection("cherry.rooms", string(cherryFileData), 1, filepath)
   256  	if err != nil {
   257  		return nil, err
   258  	}
   259  	//  INFO(Santiago): Adding all scanned rooms from the first cherry.rooms section found
   260  	//                  [cherry branches were scanned too at this point].
   261  	set, line, data = GetNextSetFromData(data, line, ":")
   262  	for len(set) == 2 {
   263  		if cherryRooms.HasRoom(set[0]) {
   264  			return nil, NewCherryFileError(filepath, line, fmt.Sprintf("room \"%s\" redeclared.", set[0]))
   265  		}
   266  		var value int64
   267  		var convErr error
   268  		value, convErr = strconv.ParseInt(set[1], 10, 16)
   269  		if convErr != nil {
   270  			return nil, NewCherryFileError(filepath, line, fmt.Sprintf("invalid port value \"%s\" [more details: %s].", set[1], convErr))
   271  		}
   272  		var port int16
   273  		port = int16(value)
   274  		if cherryRooms.PortBusyByAnotherRoom(port) {
   275  			return nil, NewCherryFileError(filepath, line, fmt.Sprintf("the port \"%s\" is already busy by another room.", set[1]))
   276  		}
   277  
   278  		cherryRooms.AddRoom(set[0], port)
   279  
   280  		errRoomConfig := GetRoomTemplates(set[0], cherryRooms, string(cherryFileData), filepath)
   281  		if errRoomConfig != nil {
   282  			return nil, errRoomConfig
   283  		}
   284  
   285  		errRoomConfig = GetRoomActions(set[0], cherryRooms, string(cherryFileData), filepath)
   286  		if errRoomConfig != nil {
   287  			return nil, errRoomConfig
   288  		}
   289  
   290  		//  INFO(Santiago): until now these two following sections are non-mandatory.
   291  
   292  		_ = GetRoomImages(set[0], cherryRooms, string(cherryFileData), filepath)
   293  
   294  		//_ = GetRoomSounds(set[0], cherryRooms, string(cherryFileData), filepath)
   295  
   296  		errRoomConfig = GetRoomMisc(set[0], cherryRooms, string(cherryFileData), filepath)
   297  		if errRoomConfig != nil {
   298  			return nil, errRoomConfig
   299  		}
   300  
   301  		//  INFO(Santiago): Let's transfer the next room from file to the memory.
   302  		set, line, data = GetNextSetFromData(data, line, ":")
   303  	}
   304  	return cherryRooms, nil
   305  }
   306  
   307  // GetRoomTemplates parses "cherry.[roomName].templates" section.
   308  func GetRoomTemplates(roomName string, cherryRooms *config.CherryRooms, configData, filepath string) *CherryFileError {
   309  	var data string
   310  	var line int
   311  	var err *CherryFileError
   312  	data, _, line, err = GetDataFromSection("cherry."+roomName+".templates",
   313  		configData, 1, filepath)
   314  	if err != nil {
   315  		return err
   316  	}
   317  	var set []string
   318  	set, line, data = GetNextSetFromData(data, line, "=")
   319  	for len(set) == 2 {
   320  		if cherryRooms.HasTemplate(roomName, set[0]) {
   321  			return NewCherryFileError(filepath, line, "room template \""+set[0]+"\" redeclared.")
   322  		}
   323  		if len(set[1]) == 0 {
   324  			return NewCherryFileError(filepath, line, "room template with no value.")
   325  		}
   326  		if set[1][0] != '"' || set[1][len(set[1])-1] != '"' {
   327  			return NewCherryFileError(filepath, line, "room template must be set with a valid string.")
   328  		}
   329  		var templateData []byte
   330  		var templateDataErr error
   331  		templateData, templateDataErr = ioutil.ReadFile(set[1][1 : len(set[1])-1])
   332  		if templateDataErr != nil {
   333  			return NewCherryFileError(filepath, line, "unable to access room template file [more details: "+templateDataErr.Error()+"].")
   334  		}
   335  		cherryRooms.AddTemplate(roomName, set[0], string(templateData))
   336  		set, line, data = GetNextSetFromData(data, line, "=")
   337  	}
   338  	return nil
   339  }
   340  
   341  // GetRoomActions parses "cherry.[roomName].actions" section.
   342  func GetRoomActions(roomName string, cherryRooms *config.CherryRooms, configData, filepath string) *CherryFileError {
   343  	return getIndirectConfig("cherry."+roomName+".actions",
   344  		"cherry."+roomName+".actions.templates",
   345  		roomActionMainVerifier, roomActionSubVerifier, roomActionSetter,
   346  		roomName, cherryRooms, configData, filepath)
   347  }
   348  
   349  // GetRoomImages parses "cherry.[roomName].images" and "cherry.[roomName].images.url".
   350  func GetRoomImages(roomName string, cherryRooms *config.CherryRooms, configData, filepath string) *CherryFileError {
   351  	return getIndirectConfig("cherry."+roomName+".images",
   352  		"cherry."+roomName+".images.url",
   353  		roomImageMainVerifier, roomImageSubVerifier, roomImageSetter,
   354  		roomName, cherryRooms, configData, filepath)
   355  }
   356  
   357  //func GetRoomSounds(roomName string, cherryRooms *config.CherryRooms, configData, filepath string) *CherryFileError {
   358  //    return getIndirectConfig("cherry." + roomName + ".sounds",
   359  //                               "cherry." + roomName + ".sounds.url",
   360  //                               room_sound_main_verifier, room_sound_sub_verifier, room_sound_setter,
   361  //                               roomName, cherryRooms, configData, filepath)
   362  //}
   363  
   364  // GetRoomMisc parses "cherry.[roomName].misc" section.
   365  func GetRoomMisc(roomName string, cherryRooms *config.CherryRooms, configData, filepath string) *CherryFileError {
   366  	var mData string
   367  	var mLine int
   368  	var mErr *CherryFileError
   369  	mData, _, mLine, mErr = GetDataFromSection("cherry."+roomName+".misc", configData, 1, filepath)
   370  	if mErr != nil {
   371  		return mErr
   372  	}
   373  
   374  	var verifier map[string]func(string) bool
   375  	verifier = make(map[string]func(string) bool)
   376  	verifier["join-message"] = verifyString
   377  	verifier["exit-message"] = verifyString
   378  	verifier["on-ignore-message"] = verifyString
   379  	verifier["on-deignore-message"] = verifyString
   380  	verifier["greeting-message"] = verifyString
   381  	verifier["private-message-marker"] = verifyString
   382  	verifier["max-users"] = verifyNumber
   383  	verifier["allow-brief"] = verifyBool
   384  	//verifier["flooding-police"]               = verifyBool
   385  	//verifier["max-flood-allowed-before-kick"] = verifyNumber
   386  	verifier["all-users-alias"] = verifyString
   387  	verifier["ignore-action"] = verifyString
   388  	verifier["deignore-action"] = verifyString
   389  	verifier["public-directory"] = verifyString
   390  
   391  	var setter map[string]func(*config.CherryRooms, string, string)
   392  	setter = make(map[string]func(*config.CherryRooms, string, string))
   393  	setter["join-message"] = setJoinMessage
   394  	setter["exit-message"] = setExitMessage
   395  	setter["on-ignore-message"] = setOnIgnoreMessage
   396  	setter["on-deignore-message"] = setOnDeIgnoreMessage
   397  	setter["greeting-message"] = setGreetingMessage
   398  	setter["private-message-marker"] = setPrivateMessageMarker
   399  	setter["max-users"] = setMaxUsers
   400  	setter["allow-brief"] = setAllowBrief
   401  	//setter["flooding-police"]               = set_flooding_police
   402  	//setter["max-flood-allowed-before-kick"] = set_max_flood_allowed_before_kick
   403  	setter["all-users-alias"] = setAllUsersAlias
   404  	setter["ignore-action"] = setIgnoreAction
   405  	setter["deignore-action"] = setDeIgnoreAction
   406  	setter["public-directory"] = setPublicDirectory
   407  
   408  	var alreadySet map[string]bool
   409  	alreadySet = make(map[string]bool)
   410  	alreadySet["join-message"] = false
   411  	alreadySet["exit-message"] = false
   412  	alreadySet["on-ignore-message"] = false
   413  	alreadySet["on-deignore-message"] = false
   414  	alreadySet["greeting-message"] = false
   415  	alreadySet["private-message-marker"] = false
   416  	alreadySet["max-users"] = false
   417  	//alreadySet["flooding-police"]               = false
   418  	//alreadySet["max-flood-allowed-before-kick"] = false
   419  	alreadySet["all-users-alias"] = false
   420  	alreadySet["ignore-action"] = false
   421  	alreadySet["deignore-action"] = false
   422  	alreadySet["public-directory"] = false
   423  
   424  	var mSet []string
   425  	mSet, mLine, mData = GetNextSetFromData(mData, mLine, "=")
   426  	for len(mSet) == 2 {
   427  		_, exists := verifier[mSet[0]]
   428  		if !exists {
   429  			return NewCherryFileError(filepath, mLine, "misc configuration named as \""+mSet[0]+"\" is unrecognized.")
   430  		}
   431  		if alreadySet[mSet[0]] {
   432  			return NewCherryFileError(filepath, mLine, "misc configuration \""+mSet[0]+"\" re-configured.")
   433  		}
   434  		if !verifier[mSet[0]](mSet[1]) {
   435  			return NewCherryFileError(filepath, mLine, "misc configuration \""+mSet[0]+"\" has invalid value : "+mSet[1])
   436  		}
   437  		setter[mSet[0]](cherryRooms, roomName, mSet[1])
   438  		alreadySet[mSet[0]] = true
   439  		mSet, mLine, mData = GetNextSetFromData(mData, mLine, "=")
   440  	}
   441  
   442  	return nil
   443  }
   444  
   445  func setIgnoreAction(cherryRooms *config.CherryRooms, roomName, action string) {
   446  	cherryRooms.SetIgnoreAction(roomName, action[1:len(action)-1])
   447  }
   448  
   449  func setDeIgnoreAction(cherryRooms *config.CherryRooms, roomName, action string) {
   450  	cherryRooms.SetDeIgnoreAction(roomName, action[1:len(action)-1])
   451  }
   452  
   453  func setJoinMessage(cherryRooms *config.CherryRooms, roomName, message string) {
   454  	cherryRooms.SetJoinMessage(roomName, message[1:len(message)-1])
   455  }
   456  
   457  func setExitMessage(cherryRooms *config.CherryRooms, roomName, message string) {
   458  	cherryRooms.SetExitMessage(roomName, message[1:len(message)-1])
   459  }
   460  
   461  func setOnIgnoreMessage(cherryRooms *config.CherryRooms, roomName, message string) {
   462  	cherryRooms.SetOnIgnoreMessage(roomName, message[1:len(message)-1])
   463  }
   464  
   465  func setOnDeIgnoreMessage(cherryRooms *config.CherryRooms, roomName, message string) {
   466  	cherryRooms.SetOnDeIgnoreMessage(roomName, message[1:len(message)-1])
   467  }
   468  
   469  func setGreetingMessage(cherryRooms *config.CherryRooms, roomName, message string) {
   470  	cherryRooms.SetGreetingMessage(roomName, message[1:len(message)-1])
   471  }
   472  
   473  func setPrivateMessageMarker(cherryRooms *config.CherryRooms, roomName, marker string) {
   474  	cherryRooms.SetPrivateMessageMarker(roomName, marker[1:len(marker)-1])
   475  }
   476  
   477  func setMaxUsers(cherryRooms *config.CherryRooms, roomName, value string) {
   478  	var intValue int64
   479  	intValue, _ = strconv.ParseInt(value, 10, 64)
   480  	cherryRooms.SetMaxUsers(roomName, int(intValue))
   481  }
   482  
   483  func setAllowBrief(cherryRooms *config.CherryRooms, roomName, value string) {
   484  	var allow bool
   485  	allow = (value == "yes" || value == "true")
   486  	cherryRooms.SetAllowBrief(roomName, allow)
   487  }
   488  
   489  func setPublicDirectory(cherryRooms *config.CherryRooms, roomName, value string) {
   490  	cherryRooms.SetPublicDirectory(roomName, value[1:len(value)-1])
   491  }
   492  
   493  //func set_flooding_police(cherryRooms *config.CherryRooms, roomName, value string) {
   494  //    var impose bool
   495  //    impose = (value == "yes")
   496  //    cherryRooms.SetFloodingPolice(roomName, impose)
   497  //}
   498  
   499  func setAllUsersAlias(cherryRooms *config.CherryRooms, roomName, value string) {
   500  	cherryRooms.SetAllUsersAlias(roomName, value[1:len(value)-1])
   501  }
   502  
   503  //func set_max_flood_allowed_before_kick(cherryRooms *config.CherryRooms, roomName, value string) {
   504  //    var intValue int64
   505  //    intValue, _ = strconv.ParseInt(value, 10, 64)
   506  //    cherryRooms.SetMaxFloodAllowedBeforeKick(roomName, int(intValue))
   507  //}
   508  
   509  func verifyNumber(buffer string) bool {
   510  	if len(buffer) == 0 {
   511  		return false
   512  	}
   513  	for _, b := range buffer {
   514  		if b != '0' &&
   515  			b != '1' &&
   516  			b != '2' &&
   517  			b != '3' &&
   518  			b != '4' &&
   519  			b != '5' &&
   520  			b != '6' &&
   521  			b != '7' &&
   522  			b != '8' &&
   523  			b != '9' {
   524  			return false
   525  		}
   526  	}
   527  	return true
   528  }
   529  
   530  func verifyString(buffer string) bool {
   531  	if len(buffer) <= 1 {
   532  		return false
   533  	}
   534  	return (buffer[0] == '"' && buffer[len(buffer)-1] == '"')
   535  }
   536  
   537  func verifyBool(buffer string) bool {
   538  	if len(buffer) == 0 {
   539  		return false
   540  	}
   541  	return (buffer == "yes" || buffer == "no" || buffer == "true" || buffer == "false")
   542  }
   543  
   544  //  WARN(Santiago): The following codes are a brain damage. I am sorry.
   545  
   546  func getIndirectConfig(mainSection,
   547  	subSection string,
   548  	mainVerifier,
   549  	subVerifier func([]string, []string, int, int, string, string, *config.CherryRooms) *CherryFileError,
   550  	setter func(*config.CherryRooms, string, []string, []string),
   551  	roomName string,
   552  	cherryRooms *config.CherryRooms,
   553  	configData,
   554  	filepath string) *CherryFileError {
   555  	var mData string
   556  	var mLine int
   557  	var mErr *CherryFileError
   558  	mData, _, mLine, mErr = GetDataFromSection(mainSection, configData, 1, filepath)
   559  	if mErr != nil {
   560  		return mErr
   561  	}
   562  
   563  	var sData string
   564  	var sLine int
   565  	var sErr *CherryFileError
   566  	sData, _, sLine, sErr = GetDataFromSection(subSection, configData, 1, filepath)
   567  
   568  	if sErr != nil {
   569  		return sErr
   570  	}
   571  
   572  	var mSet []string
   573  	mSet, mLine, mData = GetNextSetFromData(mData, mLine, "=")
   574  	for len(mSet) == 2 {
   575  		var sSet []string
   576  		mErr = mainVerifier(mSet, sSet, mLine, sLine, roomName, filepath, cherryRooms)
   577  		if mErr != nil {
   578  			return mErr
   579  		}
   580  
   581  		//  INFO(Santiago): Getting the template for the current action label from a section to another.
   582  		var temp = sData
   583  
   584  		var tempLine = sLine
   585  		sSet, tempLine, temp = GetNextSetFromData(temp, tempLine, "=")
   586  		for len(sSet) == 2 && sSet[0] != mSet[0] {
   587  			sSet, tempLine, temp = GetNextSetFromData(temp, tempLine, "=")
   588  		}
   589  
   590  		sErr = subVerifier(mSet, sSet, mLine, sLine, roomName, filepath, cherryRooms)
   591  
   592  		if sErr != nil {
   593  			return sErr
   594  		}
   595  
   596  		setter(cherryRooms, roomName, mSet, sSet)
   597  
   598  		mSet, mLine, mData = GetNextSetFromData(mData, mLine, "=")
   599  	}
   600  	return nil
   601  }
   602  
   603  func roomActionMainVerifier(mSet, sSet []string, mLine, sLine int, roomName, filepath string, cherryRooms *config.CherryRooms) *CherryFileError {
   604  	if cherryRooms.HasAction(roomName, mSet[0]) {
   605  		return NewCherryFileError(filepath, mLine, "room action \""+mSet[0]+"\" redeclared.")
   606  	}
   607  	if len(mSet[1]) == 0 {
   608  		return NewCherryFileError(filepath, mLine, "unlabeled room action.")
   609  	}
   610  	if mSet[1][0] != '"' || mSet[1][len(mSet[1])-1] != '"' {
   611  		return NewCherryFileError(filepath, mLine, "room action must be set with a valid string.")
   612  	}
   613  	return nil
   614  }
   615  
   616  func roomActionSubVerifier(mSet, sSet []string, mLine, sLine int, roomName, filepath string, cherryRooms *config.CherryRooms) *CherryFileError {
   617  	if sSet[0] != mSet[0] {
   618  		return NewCherryFileError(filepath, sLine, "there is no template for action \""+mSet[0]+"\".")
   619  	}
   620  	if len(sSet[1]) == 0 {
   621  		return NewCherryFileError(filepath, sLine, "empty room action template.")
   622  	}
   623  	if sSet[1][0] != '"' || sSet[1][len(sSet[1])-1] != '"' {
   624  		return NewCherryFileError(filepath, sLine, "room action template must be set with a valid string.")
   625  	}
   626  	var templatePath = sSet[1][1 : len(sSet[1])-1]
   627  	_, err := ioutil.ReadFile(templatePath)
   628  	if err != nil {
   629  		return NewCherryFileError(filepath, sLine, fmt.Sprintf("unable to access file, details: [ %s ]", err.Error()))
   630  	}
   631  	return nil
   632  }
   633  
   634  func roomActionSetter(cherryRooms *config.CherryRooms, roomName string, mSet, sSet []string) {
   635  	data, _ := ioutil.ReadFile(sSet[1][1 : len(sSet[1])-1])
   636  	cherryRooms.AddAction(roomName, mSet[0], mSet[1][1:len(mSet[1])-1], string(data))
   637  }
   638  
   639  func roomImageMainVerifier(mSet, sSet []string, mLine, sLine int, roomName, filepath string, cherryRooms *config.CherryRooms) *CherryFileError {
   640  	if cherryRooms.HasImage(roomName, mSet[0]) {
   641  		return NewCherryFileError(filepath, mLine, "room image \""+mSet[0]+"\" redeclared.")
   642  	}
   643  	if len(mSet[1]) == 0 {
   644  		return NewCherryFileError(filepath, mLine, "unlabeled room image.")
   645  	}
   646  	if mSet[1][0] != '"' || mSet[1][len(mSet[1])-1] != '"' {
   647  		return NewCherryFileError(filepath, mLine, "room image must be set with a valid string.")
   648  	}
   649  	return nil
   650  }
   651  
   652  func roomImageSubVerifier(mSet, sSet []string, mLine, sLine int, roomName, filepath string, cherryRooms *config.CherryRooms) *CherryFileError {
   653  	if sSet[0] != mSet[0] {
   654  		return NewCherryFileError(filepath, sLine, "there is no url for image \""+mSet[0]+"\".")
   655  	}
   656  	if len(sSet[1]) == 0 {
   657  		return NewCherryFileError(filepath, sLine, "empty room image url.")
   658  	}
   659  	if sSet[1][0] != '"' || sSet[1][len(sSet[1])-1] != '"' {
   660  		return NewCherryFileError(filepath, sLine, "room image url must be set with a valid string.")
   661  	}
   662  	return nil
   663  }
   664  
   665  func roomImageSetter(cherryRooms *config.CherryRooms, roomName string, mSet, sSet []string) {
   666  	//  WARN(Santiago): by now we will pass the image template as empty.
   667  	cherryRooms.AddImage(roomName, mSet[0], mSet[1][1:len(mSet[1])-1], "", sSet[1][1:len(sSet[1])-1])
   668  }
   669  
   670  //func room_sound_main_verifier(mSet, sSet []string, mLine, sLine int, roomName, filepath string, cherryRooms *config.CherryRooms) *CherryFileError {
   671  //    if cherryRooms.HasImage(roomName, mSet[0]) {
   672  //        return NewCherryFileError(filepath, mLine, "room sound \"" + mSet[0] + "\" redeclared.")
   673  //    }
   674  //    if len(mSet[1]) == 0 {
   675  //        return NewCherryFileError(filepath, mLine, "unlabeled room sound.")
   676  //    }
   677  //    if mSet[1][0] != '"' || mSet[1][len(mSet[1])-1] != '"' {
   678  //        return NewCherryFileError(filepath, mLine, "room sound must be set with a valid string.")
   679  //    }
   680  //    return nil
   681  //}
   682  
   683  //func room_sound_sub_verifier(mSet, sSet []string, mLine, sLine int, roomName, filepath string, cherryRooms *config.CherryRooms) *CherryFileError {
   684  //    if sSet[0] != mSet[0] {
   685  //        return NewCherryFileError(filepath, sLine, "there is no url for sound \"" + mSet[0] + "\".")
   686  //    }
   687  //    if len(sSet[1]) == 0 {
   688  //        return NewCherryFileError(filepath, sLine, "empty room sound url.")
   689  //    }
   690  //    if sSet[1][0] != '"' || sSet[1][len(sSet[1])-1] != '"' {
   691  //        return NewCherryFileError(filepath, sLine, "room sound url must be set with a valid string.")
   692  //    }
   693  //    return nil
   694  //}
   695  
   696  //func room_sound_setter(cherryRooms *config.CherryRooms, roomName string, mSet, sSet []string) {
   697  //    //  WARN(Santiago): by now we will pass the sound template as empty.
   698  //    cherryRooms.AddSound(roomName, mSet[0], mSet[1][1:len(mSet[1])-1], "", sSet[1][1:len(sSet[1])-1])
   699  //}