Skip to content
This repository was archived by the owner on Apr 12, 2019. It is now read-only.

Commit 11d0057

Browse files
0.1.1 release, fixed crash on unhandled input formats
1 parent ba253c8 commit 11d0057

File tree

4 files changed

+65
-10
lines changed

4 files changed

+65
-10
lines changed

CHANGELOG

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,11 @@
88

99
* Added support for switching mixer devices via the "basic" tab by
1010
re-starting the application in-place.
11+
12+
0.1.1
13+
14+
* Revised parsing logic to be regex based, removing the possibility
15+
for a number of possible crashes.
16+
17+
* If the basic tab fails to build, an error dialog is displayed before
18+
crashing.

gmixerctl/constants.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010

1111
mixer_device = "/dev/mixer"
1212

13+
project_homepage = "https://github.com/charlesdaniels/gmixerctl"
14+
1315
# control names to appear in the basic tab
1416
basic_controls = [
1517
"outputs.master",
@@ -21,10 +23,10 @@
2123
"record.slaves"
2224
]
2325

24-
version = "0.1.0"
26+
version = "0.1.1"
2527

2628
license = """
27-
Copyright (c) 2018, Charles Daniels (except where otherwise noted)
29+
Copyright (c) 2018, Charles Daniels (except where otherwise noted)
2830
All rights reserved.
2931
3032
Redistribution and use in source and binary forms, with or without
@@ -53,3 +55,13 @@
5355
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
5456
POSSIBILITY OF SUCH DAMAGE.
5557
"""
58+
59+
basic_error = """
60+
Something is wrong.
61+
62+
If you see this message, one of the assumptions gmixerctl makes about your
63+
audio setup is so fundamentally wrong that it can't generate a "basic"
64+
tab for you. Either this is a bug in gmixerctl, or a problem with your system.
65+
66+
Please report this issue on the gmixerctl homepage: {}
67+
""".format(project_homepage)

gmixerctl/gui.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ def main():
231231

232232
tabs = {}
233233
tkvars = {}
234+
tab_name = "basic"
234235

235236
# custom-build "basic" tab
236237
row_counter = 0
@@ -252,6 +253,9 @@ def main():
252253
render_control(tabs[tab_name], control, tabs, tkvars, row_counter)
253254
row_counter += 1
254255

256+
if "basic" not in tabs:
257+
tkinter.messagebox.showerror("Error", constants.basic_error)
258+
255259
# add mixer device selector to basic tab
256260
dev_selector_label = tkinter.Label(tabs[tab_name],
257261
text = "select mixer device")

gmixerctl/mixerctl.py

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import os
22
import logging
33
import subprocess
4+
import re
45

56
from . import util
67
from . import constants
@@ -13,13 +14,19 @@ def parse_line(line):
1314
:param line:
1415
"""
1516

17+
if len(line.split("=")) != 2:
18+
logging.warning(
19+
"don't know what to do with line '{}', no '='".format(line))
20+
return (line, {})
21+
1622
name = line.split("=")[0]
17-
rest = line.split("=")[1]
23+
rest = line.split("=")[1].strip()
1824

1925
state = {}
2026
state["name"] = name
2127

22-
if "[" in rest:
28+
# enum case, i.e. off [ off on ]
29+
if re.match("^[a-zA-Z0-9:-]+\s+\[[a-zA-Z0-9 :-]+\]$", rest):
2330
state["type"] = "enum"
2431
state["current"] = rest.split("[")[0].strip()
2532

@@ -30,7 +37,8 @@ def parse_line(line):
3037
else:
3138
state["possible"].append(val)
3239

33-
elif "{" in rest:
40+
# set case, i.e. hp { spkr hp }
41+
elif re.match("((^[a-zA-Z0-9,:-]+\s+)|^)\{[a-zA-Z0-9 :-]+\}$", rest):
3442
state["type"] = "set"
3543
rest = rest.replace("}", "")
3644
state["current"] = tuple(rest.split("{")[0].strip().split(","))
@@ -42,13 +50,30 @@ def parse_line(line):
4250
else:
4351
state["possible"].append(val)
4452

45-
else:
53+
# value case, single int value
54+
elif re.match("^[0-9]+$", rest):
55+
state["type"] = "value"
56+
state["current"] = int(rest)
57+
58+
# value case, pair of int values
59+
elif re.match("^[0-9]+[,][0-9]+$", rest):
60+
state["type"] = "value"
61+
state["current"] = tuple((int(x) for x in rest.split(",")))
62+
63+
# value case, single int value, with annotation
64+
elif re.match("^[0-9]+\s+[a-zA-Z]+$", rest):
4665
state["type"] = "value"
47-
if "," in rest:
48-
state["current"] = tuple((int(x) for x in rest.split(",")))
49-
else:
50-
state["current"] = int(rest)
66+
state["current"] = int(rest.split(' ')[0])
5167

68+
# value case, pair of int values, with annotation
69+
elif re.match("^[0-9]+[,][0-9]+\s+[a-zA-Z]+$", rest):
70+
state["type"] = "value"
71+
rest = rest.split(' ')[0]
72+
state["current"] = tuple((int(x) for x in rest.split(",")))
73+
74+
else:
75+
logging.warning("unhanded format for '{}', giving up".format(rest))
76+
return (line, {})
5277

5378
return name, state
5479

@@ -70,6 +95,12 @@ def get_state():
7095
continue
7196

7297
key, val = parse_line(line)
98+
99+
if len(val.keys()) == 0:
100+
logging.warning(
101+
"discarding key '{}' due to empty value".format(key))
102+
continue
103+
73104
control[key] = val
74105

75106
return control

0 commit comments

Comments
 (0)