github.com/archlabjp/eeslism-go@v0.0.0-20231109122333-4bb7bfcdf292/eeslism/eschdata.go (about) 1 //This file is part of EESLISM. 2 // 3 //Foobar is free software : you can redistribute itand /or modify 4 //it under the terms of the GNU General Public License as published by 5 //the Free Software Foundation, either version 3 of the License, or 6 //(at your option) any later version. 7 // 8 //Foobar is distributed in the hope that it will be useful, 9 //but WITHOUT ANY WARRANTY; without even the implied warranty of 10 //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the 11 //GNU General Public License for more details. 12 // 13 //You should have received a copy of the GNU General Public License 14 //along with Foobar.If not, see < https://www.gnu.org/licenses/>. 15 16 /* schdata.c */ 17 18 package eeslism 19 20 import ( 21 "bufio" 22 "fmt" 23 "regexp" 24 "strconv" 25 "strings" 26 ) 27 28 /* 曜日の設定 */ 29 30 func Dayweek(fi string, week string, daywk []int, key int) { 31 var s string 32 var d, id, M, D int 33 34 var DAYweek = [8]string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun", ""} 35 36 if key == 0 { 37 n, err := fmt.Sscanf(fi, "%d/%d=%s", &M, &D, &s) 38 if n != 3 || err != nil { 39 panic(err) 40 } 41 } else { 42 re := regexp.MustCompile(`(\d+)/(\d+)=(\S+)`) 43 matches := re.FindStringSubmatch(week) 44 45 if matches != nil && len(matches) == 4 { 46 M, _ = strconv.Atoi(matches[1]) 47 D, _ = strconv.Atoi(matches[2]) 48 s = matches[3] 49 } else { 50 panic("WEEKの書式が想定外です") 51 } 52 } 53 54 id = 0 55 for d = 0; d < 8; d++ { 56 if s == DAYweek[d] { 57 id = d 58 } 59 } 60 if id == 8 { 61 Eprint("<Dayweek>", s) 62 } 63 64 // 開始日と終了日 65 ds := FNNday(M, D) 66 de := ds + 365 67 68 // 1日ごとのループ 69 for dd := ds; dd < de; dd++ { 70 d = dd 71 if dd > 365 { 72 d = dd - 365 73 } 74 daywk[d] = id // 曜日の記録 75 id++ 76 77 if id > 6 { 78 id = 0 79 } 80 } 81 82 // `dayweek.efl`から祝日を読み取る 83 tokens := NewEeTokens(fi) 84 85 for { 86 s = tokens.GetToken() 87 if s == "" || s == ";" { 88 break 89 } 90 91 re := regexp.MustCompile(`^(\d+)/(\d+)$`) 92 matches := re.FindStringSubmatch(s) 93 94 if matches != nil && len(matches) == 3 { 95 M, _ = strconv.Atoi(matches[1]) 96 D, _ = strconv.Atoi(matches[2]) 97 d = FNNday(M, D) 98 daywk[d] = 7 99 } 100 } 101 } 102 103 /* ------------------------------------------------------------ */ 104 105 /* スケジュ-ル表の入力 */ 106 107 // SCHTBデータセットの読み取り 108 // SCHTBデータセット=一日の設定値、切換スケジュールおよび季節、曜日の指定 109 // 入力文字列`schtba`を読み取って、 [eeslism.SCHDL]に書き込む 110 // NOTE: SCHTBデータセットと %s の両方を読み取るために無理が出ている 111 func Schtable(schtba string, Schdl *SCHDL) { 112 var code ControlSWType 113 114 tokens := NewEeTokens(schtba) 115 116 for tokens.IsEnd() == false { 117 s := tokens.GetToken() 118 if s == "*" { 119 break 120 } 121 if s == "\n" || s == ";" { 122 continue 123 } 124 125 switch s { 126 case "-ssn", "SSN": 127 // 季節設定 128 129 fields := tokens.GetLogicalLine() 130 n := len(fields) - 1 131 132 Sn := SEASN{ 133 name: fields[0], // 季節名 134 N: n, 135 sday: make([]int, n), 136 eday: make([]int, n), 137 } 138 139 // 開始日・終了日 140 for i := 0; i < n; i++ { 141 var Ms, Ds, Me, De int 142 fmt.Sscanf(fields[i+1], "%d/%d-%d/%d", &Ms, &Ds, &Me, &De) 143 Sn.sday[i] = FNNday(Ms, Ds) 144 Sn.eday[i] = FNNday(Me, De) 145 } 146 147 Schdl.Seasn = append(Schdl.Seasn, Sn) 148 149 break 150 case "-wkd", "WKD": 151 // 曜日設定 152 153 fields := tokens.GetLogicalLine() 154 n := len(fields) - 1 155 156 Wk := WKDY{ 157 name: fields[0], // 曜日名 158 } 159 160 // 対応する曜日のフラグを埋める 161 for i := 0; i < n; i++ { 162 for j := 0; j < 8; j++ { 163 if fields[i+1] == DAYweek[j] { 164 Wk.wday[j] = true 165 break 166 } 167 } 168 } 169 170 Schdl.Wkdy = append(Schdl.Wkdy, Wk) 171 172 break 173 case "-v", "VL": 174 // 設定値スケジュール定義 175 fields := tokens.GetLogicalLine() 176 n := len(fields) - 1 177 178 Dh := DSCH{ 179 name: fields[0], // 設定値名 180 N: n, 181 stime: make([]int, n), 182 etime: make([]int, n), 183 val: make([]float64, n), 184 } 185 186 // 開始時分, 終了時分, 設定値 187 Dh.stime = make([]int, n) 188 Dh.val = make([]float64, n) 189 Dh.etime = make([]int, n) 190 for i := 0; i < n; i++ { 191 fmt.Sscanf(fields[i+1], "%d-(%f)-%d", &Dh.stime[i], &Dh.val[i], &Dh.etime[i]) 192 } 193 194 Schdl.Dsch = append(Schdl.Dsch, Dh) 195 196 break 197 case "-s", "SW": 198 // 切替設定スケジュール定義 199 fields := tokens.GetLogicalLine() 200 n := len(fields) - 1 201 nmod := 0 202 203 Dw := DSCW{ 204 name: fields[0], // 切り替え設定名 205 N: n, 206 Nmod: 0, 207 stime: make([]int, 10), 208 etime: make([]int, 10), 209 mode: make([]ControlSWType, 10), 210 //dcode: make([]rune, swmx), 211 } 212 213 Dw.stime = make([]int, n) 214 Dw.etime = make([]int, n) 215 Dw.mode = make([]ControlSWType, n) 216 for i := 0; i < n; i++ { 217 fmt.Sscanf(fields[i+1], "%d-(%c)-%d", &Dw.stime[i], &code, &Dw.etime[i]) 218 Dw.mode[i] = ControlSWType(code) 219 } 220 221 // モード数を調べる 222 var j int 223 for j = 0; j < nmod; j++ { 224 if Dw.dcode[j] == code { 225 break 226 } 227 } 228 229 if j == nmod { 230 Dw.dcode[nmod] = code 231 nmod++ 232 } 233 234 Dw.Nmod = nmod 235 236 Schdl.Dscw = append(Schdl.Dscw, Dw) 237 238 break 239 } 240 } 241 } 242 243 /* ------------------------------------------------------------ */ 244 245 /* 季節、曜日によるスケジュ-ル表の組み合わせ */ 246 247 // SCHNMデータセットの読み取り 248 // SCHNMデータセット = 季節、曜日によるスケジュ-ル表の組み合わせ 249 // 入力文字列`schenma`を読み取って、[eeslism.SCHDL]に書き込む 250 func Schdata(schnma string, dsn string, daywk []int, Schdl *SCHDL) { 251 fi := strings.NewReader(schnma) 252 253 var err error 254 const dmax = 366 255 256 Seasn := Schdl.Seasn 257 Wkdy := Schdl.Wkdy 258 Dsch := Schdl.Dsch 259 Dscw := Schdl.Dscw 260 261 scanner := bufio.NewScanner(fi) 262 for scanner.Scan() { 263 line := scanner.Text() 264 if line == "*" { 265 break 266 } 267 fields := strings.Fields(line) 268 269 // 定義の種類 270 var dmod rune 271 if fields[0] == "-v" || fields[0] == "VL" { 272 // 設定値名 273 dmod = 'v' 274 } else if fields[0] == "-s" || fields[0] == "SW" { 275 // 切換設定名 276 dmod = 'w' 277 } else { 278 panic(fields[0]) 279 } 280 281 // 年間スケジュールの初期化 282 S := SCH{ 283 name: fields[1], // 設定値名 or 切替設定名 284 } 285 for d := range S.day { 286 S.day[d] = -1 287 } 288 289 // ';' まで繰り返す 290 for _, field := range fields[2:] { 291 292 if field == ";" { 293 break 294 } 295 296 var dname string 297 var sname string 298 var wname string 299 is := -1 300 var wkday *WKDY = nil 301 sc := -1 302 sw := -1 303 304 // 正規表現パターン 305 pattern := `^(\w+)(?::(\w*))?(?:-(\w+))?` 306 re := regexp.MustCompile(pattern) 307 308 // マッチする部分を取り出す 309 match := re.FindStringSubmatch(field) 310 311 // 3つの部分を取り出し 312 if len(match) >= 2 { 313 // ex) `TrsetC` 314 dname = match[1] // 参照する1日の設定名 315 } 316 if len(match) >= 3 { 317 // ex) `TrsetH:Winter` 318 sname = match[2] // 季節設定名 ex)Summer 319 } 320 if len(match) >= 4 { 321 // ex) `ACSWLDwd:Summer-Weekday` 322 // ex) `ACSWLDwd:-Weekday` 323 wname = match[3] // 曜日設定名 ex)Weekday 324 } 325 326 if sname != "" { 327 // 季節設定の検索 328 is, err = idssn(sname, Seasn) 329 if err != nil { 330 panic(err) 331 } 332 } 333 if wname != "" { 334 // 曜日設定の検索 335 iw, err := idwkd(wname, Wkdy) 336 if err != nil { 337 panic(err) 338 } 339 wkday = &Wkdy[iw] 340 } 341 if dname != "" { 342 if dmod == 'v' { 343 // 一日の設定値スケジュ-ルの検索 344 sc, err = iddsc(dname, Dsch) 345 if err != nil { 346 panic(err) 347 } 348 } else if dmod == 'w' { 349 // 一日の切り替えスケジュ-ルの検索 350 sw, err = iddsw(string(dname), Dscw) 351 if err != nil { 352 panic(err) 353 } 354 } else { 355 panic(dmod) 356 } 357 } 358 359 // ループ回数 360 var N int 361 if is >= 0 { 362 // ** 季節設定がある場合 ** 363 N = Seasn[is].N 364 } else { 365 // ** 季節設定がない場合 ** 366 N = 1 367 } 368 369 // 年間スケジュールの作成ループ 370 for k := 0; k < N; k++ { 371 var ds, de int 372 if is >= 0 { 373 // ** 季節設定がある場合 ** 374 // ex) `TrsetC:Winter` 375 // ex) `ACSWLDwd:Winter-Weekday` 376 Sn := Seasn[is] 377 ds = Sn.sday[k] //開始日 378 de = Sn.eday[k] //終了日 379 380 if ds > de { 381 de += 365 // 年末跨ぎ 382 } 383 } else { 384 // ** 季節設定がない場合場合 ** 385 // ex) `TrsetC` 386 // ex) `ACSWLDwd:-Weekday` 387 ds = 1 // 開始日 NOTE: 配列インデックス1-366を想定 (Fortran譲りか) 388 de = dmax // 終了日 389 } 390 391 for day := ds; day <= de; day++ { 392 d := day 393 if day > 365 { 394 d = day - 365 // NOTE: d=1に戻る条件になっている 395 } 396 397 // 曜日指定が無い or 指定曜日であることを確認 398 if wkday == nil || wkday.wday[daywk[d]] { 399 if dmod == 'v' { 400 S.day[d] = sc 401 } else if dmod == 'w' { 402 S.day[d] = sw 403 } else { 404 panic(dmod) 405 } 406 } 407 } 408 } 409 } 410 411 // 年間スケジュールに追加 412 if dmod == 'v' { 413 Schdl.Sch = append(Schdl.Sch, S) 414 } else if dmod == 'w' { 415 Schdl.Scw = append(Schdl.Scw, S) 416 } else { 417 panic(dmod) 418 } 419 } 420 421 // Val, Isw の領域確保 422 Schdl.Val = make([]float64, len(Schdl.Sch)) 423 Schdl.Isw = make([]ControlSWType, len(Schdl.Scw)) 424 } 425 426 /* ------------------------------------------------------------ */ 427 428 /* 季節、曜日によるスケジュ-ル表の組み合わせ名へのスケジュ-ル名の追加 */ 429 430 func Schname(schdl *SCHDL) { 431 // 年間一定のスケジュールを追加 432 for i, sc := range schdl.Dsch { 433 sch := SCH{ 434 name: sc.name, 435 } 436 for d := range sch.day { 437 sch.day[d] = i 438 } 439 440 schdl.Sch = append(schdl.Sch, sch) 441 } 442 443 // 年間一定のスケジュールを追加 444 for j, sw := range schdl.Dscw { 445 scw := SCH{ 446 name: sw.name, 447 } 448 for d := range scw.day { 449 scw.day[d] = j 450 } 451 452 schdl.Scw = append(schdl.Scw, scw) 453 } 454 455 // Val, Isw の領域確保 456 schdl.Val = make([]float64, len(schdl.Sch)) 457 schdl.Isw = make([]ControlSWType, len(schdl.Scw)) 458 }