def __init__(self, seed: int, log_filename: str): """ Initializes the game :param seed: :param log_filename: """ self.maps = [] self.default_entities = [] self.user_input = "" self.configurations = read_configuration_file() self.language = LanguageManagement(self.configurations.get("language_file")) self.options = OptionsMenu(self) mapname = get_level_file_name(self.language) self.read_units_dat() self.colours = Colours() self.player = self.set_entity("Player", -1, -1) self.maps.append(Map(mapname, self)) self.current_level = self.maps[0] self.rng = Random(seed) self.all_status_effects = status_effects.set_effect_values(status_effects.read_status_effects_dat(self)) self.brezelheim = Brezelheim(self.current_level) self.scr = Screen(self.configurations.get("screen_height"), self.configurations.get("screen_width")) self.msg_box = Messagebox(self.scr.len_x) self.keys = Input() # inits the input keys self.log_filename = log_filename self.log_file = None
def __init__(self, conffile): self.conf = read_yaml(conffile) self.col = Colours() self.req = {} self.req['headers'] = {'user-agent': self.conf['ua']} self.s_in = self.session_login() self.s_out = requests.Session()
def __init__(self, conffile): urllib3.disable_warnings() self.conf = read_toml(conffile) self.col = Colours() self.req = {} self.req['headers'] = {'user-agent': self.conf['ua']} self.s_in = self.session_login() self.s_out = requests.Session()
def __init__(self, setup, rules): self.array = None self.setup = None self.rules = None self.reset(setup=setup, rules=rules) self.team_colours = Colours(setup.teams) self.set_last_evolution_millis()
def __init__(self): super(HighScoreOverlay, self).__init__() self.cyclingColours=Colours.getCyclingColours() self.cyclingRow=None self.rowReferences=[] y=self.getHeadersRow() self.addRowHeaders(y) y=y-2 for i in range(self.getNumberOfRows()): self.rowReferences.append({ 'no': self.addText('norow'+str(i),'',5,y,1.0,1.0,1.0,self.alignRight), 'score': self.addText('scorerow'+str(i),'',12,y,1.0,1.0,1.0,self.alignRight), 'time': self.addText('timerow'+str(i),'',19,y,1.0,1.0,1.0,self.alignRight), 'initials0': self.addText('namerow'+str(i),'',24,y,1.0,1.0,1.0,self.alignRight), 'initials1': self.addText('namerow'+str(i),'',25,y,1.0,1.0,1.0,self.alignRight), 'initials2': self.addText('namerow'+str(i),'',26,y,1.0,1.0,1.0,self.alignRight) }) y=y-2 self.addPeripheralText() self.ticks=0 self.endOfLife=False
def main(): do_tree, do_tess = get_args() c = Colours(background_alpha).complimentary() image = Image.new("RGBA", (imgx, imgy), choice(c)) draw = ImageDraw.Draw(image) if do_tess: f = Fortunes(imgx, imgy) for p in f.get_polygons(): draw.polygon(list(p.exterior.coords), fill=choice(c)) if do_tree: bright = True if brightness(c) > bright_threshold else False rbg_low, rbg_high = (bright_threshold, 255) if bright else (0, bright_threshold) FractalTree(imgx, imgy, draw).draw(imgx / 2, imgy, randint(-tilt_higher, -tilt_lower), branches=10, branch_width=20, colour=randomColour(rbg_low, rbg_high), bright=brightness(c) > bright_threshold) image.save("background.png", "PNG")
def do_cd(self, line): #error handling ensures wrong directory path or permission denial will not crash shell try: if self.home in line: os.chdir('/' + line) else: os.chdir(os.getcwd() + '/' + line) except FileNotFoundError: print(Colours.red("Invalid directory: {}".format(line))) except Exception as e: print(e) #update the prompt to show the new directory cmd.Cmd.prompt = Colours.cyan('(KarlShell:') + Colours.pink( os.getcwd() + ') ')
def editColours(self, color=False): # if they've selected some items I'll create a palette of colours for them palette = [] if self.palette: for item in self.order.selectedItems(): palette.append(item.text()) for item in self.ignore.selectedItems(): palette.append(item.text()) dialr = Colours(section='Plot Colors', ini_file=self.config_file, add_colour=color, palette=palette, underscore=True) dialr.exec_() self.colours = {} config = configparser.RawConfigParser() config.read(self.config_file) try: colours = config.items('Plot Colors') for item, colour in colours: itm = item.replace('_', ' ') self.colours[itm] = colour except: pass for c in range(self.order.count()): col = self.order.item(c).text() try: self.order.item(c).setBackground( QtGui.QColor(self.colours[col.lower()])) except: pass for c in range(self.ignore.count()): col = self.ignore.item(c).text() try: self.ignore.item(c).setBackground( QtGui.QColor(self.colours[col.lower()])) except: pass
def lightHandler(request, response): command = request.query.get("command") if command is not None: print(command) if command == "disco": lc.goDisco() elif command == "random": lc.goRandom() else: rgb = Colours.get(command) if rgb is not None: lc.tranistionTo(rgb, 1000) response.sendOK()
def __init__(self,visualTrackSession,carsPassed): super(PassingBonusDisplay, self).__init__() self.cyclingColours=Colours.getCyclingColours() self.passingBonusCaptionNode=self.addText('passingbonus','PASSING BONUS',16,3,1.0,1.0,1.0,self.alignRight) self.passingBonusValueNode=self.addText('passingbonusvalue','',24,3,1.0,1.0,1.0,self.alignRight) self.endOfLife=False self.ticks=0 self.visualTrackSession=visualTrackSession self.startCountdownNumber=carsPassed
def editColours(self): dialr = Colours(ini_file=self.config_file) dialr.exec_() # refresh some config values config = ConfigParser.RawConfigParser() self.config.read(self.config_file) try: map = self.config.get('Map', 'map_choice') except: map = '' try: colours0 = self.config.items('Colors') except: pass if map != '': try: colours1 = self.config.items('Colors' + map) colours = [] for it, col in colours0: for it1, col1 in colours1: if it1 == it: colours.append((it1, col1)) break else: colours.append((it, col)) except: colours = colours0 else: colours = colours0 for item, colour in colours: if item == 'ruler': continue if colour != self.view.scene().colors[item]: self.changeColours(colour, self.view.scene()._stationCircles[item]) comment = 'Colours edited. Reload may be required.' self.view.emit(QtCore.SIGNAL('statusmsg'), comment)
def invoke(self, line): line = self.get_tokens(line) pid = os.fork() if pid > 0: wait_pid = os.waitpid(pid, 0) else: try: os.execvp(line[0], line) except FileNotFoundError: print( Colours.red( " '{}' not found. Type 'help' for shell documentation." .format(' '.join(line)))) self.do_quit('') except: print("Exception!") self.do_quit('')
def __init__(self): super(QualifyingResultsDisplay, self).__init__() self.cyclingColours=Colours.getCyclingColours() self.positionCaptionNode=self.addText('position','POSITION',10,5,1.0,1.0,1.0,self.alignRight) self.lapTimeCaptionNode=self.addText('laptime','LAP TIME',15,7,1.0,1.0,1.0,self.alignRight) self.bonusCaptionNode=self.addText('bonus','BONUS',15,3,1.0,1.0,1.0,self.alignRight) self.numberedPositionNodes={} for currentPosition in range(1,9): self.numberedPositionNodes[currentPosition]=self.addText('pos'+str(currentPosition),str(currentPosition),10+currentPosition*2,5,1.0,1.0,1.0,self.alignRight) self.lapTimeValueNode=self.addText('lapvalue','',21,7,1.0,1.0,1.0,self.alignRight) self.bonusValueNode=self.addText('bonusvalue','',20,3,1.0,1.0,1.0,self.alignRight) self.position=1 self.endOfLife=False self.ticks=0
print(f"{error_text}\"screen_height\"") exit(-1) elif "screen_width" in line: try: configurations["screen_width"] = int(line.split("=")[1]) except ValueError or IndexError: print(f"{error_text}\"screen_width\"") exit(-1) elif "input_delay" in line: try: configurations["input_delay"] = float(line.split("=")[1]) except ValueError or IndexError: print(f"{error_text}\"input_delay\"") exit(-1) if len(configurations) < 4: print("config.txt is incomplete.") exit(-1) return configurations if __name__ == '__main__': record, replay, replay_filename, seed = interpret_parameters() if not replay: gtg = GateToGods(seed, replay_filename) gtg.play() else: colours = Colours() r = Replay(replay_filename, colours) r.play_replay(Input(), colours)
dest = 'hex_colour', help = "Non-standard foreground colour as hex value" ) parser.add_option( "-s", "--size", action = 'store', dest = 'size', help = "Size of the table cells" ) options, args = parser.parse_args() if not options.size: options.size = 3 if not options.colour: options.colour = "red" colours = Colours() colour = colours.get_hex(options.colour) if options.hex_colour: colour = "#%s" % (options.hex_colour) try: hs = HTMLSpectrum( args[0], colour = colour, size = options.size ) print hs except IndexError: parser.print_usage() import sys sys.exit(1)
def display_equipment_stats(key, display_price=True, display_name=True, item_quantity='', extra_text=None): if key in entities.all_player_weapons or key in entities.all_player_armour or key in all_items or key in new_inventory.items_dict: key_to_display = Colours.tag(key) + ' ' space_to_display = System.indent(key) else: key_to_display = '' space_to_display = '' specific_equipment = key if key in entities.all_player_weapons: specific_equipment = entities.all_player_weapons[key] elif key in entities.all_player_armour: specific_equipment = entities.all_player_armour[key] elif key in all_items: specific_equipment = all_items[key] elif key in new_inventory.items_dict: specific_equipment = new_inventory.items_dict[key][0] item_quantity = new_inventory.items_dict[key][1] if display_price: price_string = f"{space_to_display}{Colours.fg.yellow}Price: {specific_equipment.price}" else: price_string = '' if display_name: name_to_display = specific_equipment.name_string else: name_to_display = '' if type(item_quantity) == int: item_quantity = str(item_quantity) + ' ' if isinstance(specific_equipment, entities.Weapon): print(f"""{key_to_display}{name_to_display} {space_to_display}{Colours.fg.red}Damage: {specific_equipment.str_damage} {space_to_display}{Colours.fg.orange}Crit Chance: {specific_equipment.str_crit_chance} {space_to_display}{Colours.fg.cyan}Accuracy: {specific_equipment.str_accuracy} {price_string}""") elif isinstance(specific_equipment, entities.Armour): print(f"""{key_to_display}{name_to_display} {space_to_display}{Colours.fg.red}Defense: {specific_equipment.str_defense} {space_to_display}{Colours.fg.cyan}Weight: {specific_equipment.weight} {price_string}""") elif isinstance(specific_equipment, Item): if display_name: print( f"{key_to_display}{Colours.fg.red}{item_quantity}{name_to_display}" ) else: space_to_display = System.indent(extra_text) for line in specific_equipment.description: print(space_to_display + line) if price_string != '': print(price_string) print('\n')
class World: """The world upon which the Game of Life occurs""" # instance variables def __init__(self, setup, rules): self.array = None self.setup = None self.rules = None self.reset(setup=setup, rules=rules) self.team_colours = Colours(setup.teams) self.set_last_evolution_millis() def update(self, game_tick_wait): if self.enough_time_since_last_evolution(game_tick_wait): self.evolve() self.set_last_evolution_millis() def time_since_last_evolution(self): return monotonic() * 1000 - self.last_world_update_millis def enough_time_since_last_evolution(self, game_tick_wait): return self.time_since_last_evolution() >= game_tick_wait def set_last_evolution_millis(self): self.last_world_update_millis = monotonic() * 1000 def evolve(self): self.array = self.rules.evolve(self.array) def render(self, screen): # TODO: there will be a more efficient way to do this team_grid = self.team_grid_from_world_array(self.array) for x in range(len(team_grid)): for y in range(len(team_grid[0])): screen.draw_block((x, y), self.get_team_colour(team_grid[x][y])) def reset(self, setup=None, world_size=None, teams=None, rules=None): if setup is not None: self.setup = setup world_x, world_y = setup.world_size # self.array = np.zeros((world_x, world_y, setup.teams)) self.create_empty_world_array(setup.world_size, setup.teams) elif world_size == -1 and teams == -1: self.array.fill(0) else: self.create_empty_world_array(world_size, teams) if rules is not None: self.rules = rules else: # Leave the rules as they are pass def create_empty_world_array(self, world_size, teams): world_x, world_y = world_size self.array = np.zeros((world_x, world_y, teams), dtype=int) def set(self, new_array): self.array = new_array def get_team_colour(self, team): return self.team_colours.get_team_colour(team) def size_segment_grid(self, use_corners=True): # Get relevant info world_x, world_y = self.array.shape teams = self.setup.teams if use_corners: required_segments = teams else: required_segments = teams + 4 # Begin with an approximation, will either be correct or be just above # the largest square number that is too small segment_x_guess = floor(4 * world_x / (required_segments + 4)) segment_y_guess = floor(4 * world_y / (required_segments + 4)) segments_in_x = floor(world_x / segment_x_guess) segments_in_y = floor(world_y / segment_y_guess) # add extra segments (by making segment sizes more square where # possible) until there are enough segments for all the teams while 2 * (segments_in_x + segments_in_y - 2) < required_segments: # not enough segments, so divide the larger edge further if segment_x_guess > segment_y_guess: segments_in_x += 1 else: segments_in_y += 1 # now that number of segments is set well (filling around edge as best # as possible, matching the aspect ratio of the world pretty closely), # return recalculated segment size return floor(world_x / segments_in_x), floor(world_x / segments_in_y),\ teams def is_cell_alive(self, position): x, y = position for team in range(self.setup.teams): if self.array[x, y, team-1] == 1: return True return False @staticmethod def replace_array_subset(array, subset, index): # TODO: raise Exception if array, subset, index have dif num dimensions index_other_end = np.empty(index.shape) # for each dimension of the arrays for ii in range(len(array.shape)): if index[ii] < 0 or index[ii] >= array[ii]: raise IndexError("Index out of bounds") if index[ii] + subset.shape[ii] > array.shape[ii]: raise ValueError("Subset too large for list at this index") index_other_end[ii] = index[ii] + index.shape[ii] # TODO: LEFT UNFINISHED? np.put(array, ) @staticmethod def make_random_grid(size, teams, emptiness=1.0, first_team=1): emptiness_lower_bound = 1 - floor(teams * emptiness) options = np.arange(emptiness_lower_bound, teams + 1) options[options < 0] = 0 options += (first_team - 1) return np.random.choice(options, size=size) @staticmethod def make_empty_grid(size): return np.zeros(size) @staticmethod def change_cell_team(world_array, position, team): x, y = position teams = world_array.shape[2] for t in range(teams): if t == team - 1: world_array[x, y, t] = 1 else: world_array[x, y, t] = 0 return world_array @staticmethod def world_array_from_team_grid(team_grid): # TODO: REFACTOR so take a World object or at least a number of teams teams = np.amax(team_grid) x, y = team_grid.shape world_array = np.zeros((x, y, teams), dtype=int) # fill world_array from team_grid for t in range(teams): world_array[:, :, t] = np.where(team_grid == t + 1, team_grid / (t + 1), 0*team_grid) return world_array @staticmethod def team_grid_from_world_array(world_array): x = len(world_array) y = len(world_array[0]) teams = len(world_array[0][0]) team_grid = np.zeros((x, y), dtype=int) for t in range(teams): team_grid += (world_array[:,:,t] * (t+1)) return team_grid
class ReqCheck(): def __init__(self, conffile): self.conf = read_yaml(conffile) self.col = Colours() self.req = {} self.req['headers'] = {'user-agent': self.conf['ua']} self.s_in = self.session_login() self.s_out = requests.Session() def get(self, url, login=False): rqu = self.conf['urls']['base'] + url if login is False: return self.s_out.get(rqu, headers=self.req['headers']) else: return self.s_in.get(rqu, headers=self.req['headers']) def post(self, url, data=None, login=False): rqu = self.conf['urls']['base'] + url if login is False: return self.s_out.post(rqu, data=data, headers=self.req['headers']) else: return self.s_in.post(rqu, data=data, headers=self.req['headers']) def assert_page(self, url, rx, login=False): try: t = self.get(url, login) except requests.exceptions.ConnectionError: return [self.col.red('[fail]'), login, url, rx] else: b = bool(re.search(rx, t.text)) if b is True: return [self.col.gre('[good]'), login, url, rx] else: return [self.col.red('[fail]'), login, url, rx] def assert_source(self, src, rx): return bool(re.search(rx, src)) def assert_all(self): tab = [] for el in self.conf['request_check']: tab.append(self.assert_page(el['url'], el['exp_out'], login=False)) tab.append(self.assert_page(el['url'], el['exp_in'], login=True)) if el['url'].endswith('/'): rqu = el['url'][:-1] tab.append(self.assert_page(rqu, el['exp_out'], login=False)) tab.append(self.assert_page(rqu, el['exp_in'], login=True)) tab = sorted(tab, key=lambda x: (x[1], x[2])) return tab def session_login(self): sess = requests.Session() src = sess.get(self.conf['urls']['base'] + '/accounts/login/') formtoken = re.search(r'(csrfmiddlewaretoken.*value=")([a-zA-Z0-9]+)', src.text).group(2) csrftoken = sess.cookies['csrftoken'] login_data = { 'login': self.conf['cred']['user'], 'password': self.conf['cred']['pass'], 'csrfmiddlewaretoken': csrftoken, 'csrftoken': formtoken, 'next': '/query/' } src = sess.post(self.conf['urls']['base'] + self.conf['urls']['login'], data=login_data, headers=self.req['headers']) if bool(re.search(r'If you forgot your password', src.text)) is True: print( self.col.red('\nLogin failed. Please check your login data\n')) return sess def logout(self): self.post(self.conf['urls']['logout'])
class GateToGods: def __init__(self, seed: int, log_filename: str): """ Initializes the game :param seed: :param log_filename: """ self.maps = [] self.default_entities = [] self.user_input = "" self.configurations = read_configuration_file() self.language = LanguageManagement(self.configurations.get("language_file")) self.options = OptionsMenu(self) mapname = get_level_file_name(self.language) self.read_units_dat() self.colours = Colours() self.player = self.set_entity("Player", -1, -1) self.maps.append(Map(mapname, self)) self.current_level = self.maps[0] self.rng = Random(seed) self.all_status_effects = status_effects.set_effect_values(status_effects.read_status_effects_dat(self)) self.brezelheim = Brezelheim(self.current_level) self.scr = Screen(self.configurations.get("screen_height"), self.configurations.get("screen_width")) self.msg_box = Messagebox(self.scr.len_x) self.keys = Input() # inits the input keys self.log_filename = log_filename self.log_file = None def read_units_dat(self): """ This function opens and reads the "units.dat" file, which contains all information regarding entities. Exits the game if a definition is wrong or incomplete. :return: Nothing """ try: units_file = open("data/units.dat", "r") valid_units_file = True player_defined = False lines = units_file.readlines() units_file.close() line = 0 while line < len(lines): entity_id = lines[line].split(":")[0] if "Player" in entity_id: player_defined = True name = "" hp = -1 minimum_damage = -1 maximum_damage = -1 range_of_vision = -1 aggression = False effects = {} accuracy = 1.0 line += 1 while line < len(lines) and lines[line][0] == " ": if "healthPoints" in lines[line]: try: hp = int(lines[line].split(":")[1]) except ValueError: print(self.language.texts.get("unitsdat_number_error", self.language.undefined) .replace("(LINE)", str(line)).replace("(NOT_A_NUMBER)", lines[line].split(":")[1])) valid_units_file = False elif "damage" in lines[line]: try: if "/" in lines[line]: minimum_damage = int(lines[line].split("(")[1].split("/")[0]) maximum_damage = int(lines[line].split("/")[1].split(")")[0]) else: minimum_damage = int(lines[line].split("(")[1].split(")")[0]) maximum_damage = minimum_damage except ValueError: print(self.language.texts.get("unitsdat_damage_error", self.language.undefined) .replace("(LINE)", str(line))) valid_units_file = False elif "fieldOfVision" in lines[line]: try: range_of_vision = int(lines[line].split(":")[1]) except ValueError: print(self.language.texts.get("unitsdat_number_error", self.language.undefined) .replace("(LINE)", str(line)).replace("(NOT_A_NUMBER)", lines[line].split(":")[1])) valid_units_file = False elif "hostile" in lines[line]: if "false" in lines[line] or "False" in lines[line]: aggression = False elif "true" in lines[line] or "True" in lines[line]: aggression = True elif "name" in lines[line]: if entity_id in self.language.texts: name = self.language.texts.get(entity_id) else: name = lines[line].split(":")[1].replace("\n", "") while name[0] == " ": name = name[1:] # if a blank is in front of a name, it gets removed elif "effects" in lines[line]: line += 1 while line < len(lines) and "-" in lines[line]: effect = lines[line].split("-")[1].replace("\n", "") while effect[0] == " ": effect = effect[1:] effects[effect] = {"effect_id": effect} line += 1 line -= 1 elif "accuracy" in lines[line]: try: accuracy = float(lines[line].split(":")[1]) except ValueError: print(self.language.texts.get("unitsdat_number_error", self.language.undefined) .replace("(LINE)", str(line)).replace("(NOT_A_NUMBER)", lines[line].split(":")[1])) valid_units_file = False line += 1 if name == "" or hp == -1 or minimum_damage == -1 == maximum_damage or range_of_vision == -1: print(self.language.texts.get("unitsdat_incomplete_definition", self.language.undefined) .replace("(ENTITY_ID)", entity_id)) exit(-1) else: self.default_entities.append(DefaultEntity(entity_id, name, range_of_vision, hp, minimum_damage, maximum_damage, aggression, effects, accuracy)) if line >= len(lines): break if not player_defined: print(self.language.texts.get("unitsdat_player_not_defined", self.language.undefined)) exit(-1) if not valid_units_file: exit(-1) except FileNotFoundError: print(self.language.texts.get("unitsdat_not_found", self.language.undefined)) exit(-1) def set_entity(self, entity_id, pos_y, pos_x): """ Creates an entity based on their ID and a given position. :param entity_id: ID of the entity, defined in "units.dat" :param pos_y: y-coordinate of the entity :param pos_x: x-coordinate of the entity :return: The entity that is created or None if the entity is not defined in "units.dat" """ for entity in self.default_entities: if entity.entity_id == entity_id: return entity.create(pos_y, pos_x) return None def prepare_new_map(self): """ When starting the game, it is required to calculate the colours before the main loop is entered. :return: Nothing """ self.brezelheim.reset_brezelheim(self.current_level) self.current_level.build_map_colour(self) def play(self): """ This method handles the main loop of the game, including procession of player input and everything else. :return: """ playing = True skip_npc_turn = False record = False last_input_time = time.time() if self.log_filename != "": self.log_file = open(self.log_filename, "w") record = True self.prepare_new_map() print(self.colours.clear()) while playing: self.scr.print(record, self) status_effects.remove_status_effects(self) input_delay.apply_delay(self.configurations["input_delay"], last_input_time) last_input_time = time.time() self.user_input = readchar.readkey() # try: # self.user_input = input()[0] # except IndexError: # self.user_input = " " playing, skip_npc_turn = self.player_turn(playing, skip_npc_turn) if playing: if not skip_npc_turn: self.current_level.npc_actions(self) status_effects.apply_status_effects(self) else: skip_npc_turn = False self.current_level.build_map_colour(self) if not self.player.is_alive(): self.scr.print(record, self) playing = False else: pass def player_turn(self, playing: bool, skip_npc_turn: bool): """ Selects an action based on the player's input :param playing: :param skip_npc_turn: :return: """ if self.user_input == self.keys.exit_game: playing = False elif self.user_input == self.keys.open_door or self.user_input == self.keys.close_door: self.current_level.door_actions(self, self.user_input) elif self.player.move(self.user_input, self.keys, self.current_level) == -1: if not self.current_level.auto_toggle(self, self.user_input): self.player.attack(self, self.user_input) elif self.user_input == self.keys.enter_entrance or self.user_input == self.keys.enter_exit: entrance = self.current_level.find_entrance(self) if entrance is not None: entrance.enter(self) skip_npc_turn = True elif self.user_input == self.keys.show_coordinates: if not self.player.show_coordinates: self.player.show_coordinates = True else: self.player.show_coordinates = False elif self.user_input == self.keys.options: self.options.enter_menu(self) skip_npc_turn = True return playing, skip_npc_turn
class MyShell(cmd.Cmd): shell = os.environ['PWD'] cmd.Cmd.intro = "Hello and welcome to KarlShell! (V1.3.1 running from {})".format( shell) cmd.Cmd.prompt = Colours.cyan('(KarlShell:') + Colours.pink(os.getcwd() + ') ') dirs = os.getcwd().split('/') home = dirs[1] #changes the directory #is designed to take either the full path starting from the home directory e.g. /home/user/Documents, or take a single subdirectory of the cwd e.g. /Documents def do_cd(self, line): #error handling ensures wrong directory path or permission denial will not crash shell try: if self.home in line: os.chdir('/' + line) else: os.chdir(os.getcwd() + '/' + line) except FileNotFoundError: print(Colours.red("Invalid directory: {}".format(line))) except Exception as e: print(e) #update the prompt to show the new directory cmd.Cmd.prompt = Colours.cyan('(KarlShell:') + Colours.pink( os.getcwd() + ') ') #displays current working directory def do_pwd(self, line): print(os.getcwd()) #lists and displays all subdirectories and files # if redirect is True, pass output onto output_redirect method def do_dir(self, line): if self.check_redirect(line) == False: print("\n".join(os.listdir())) else: out = ("\n".join(os.listdir())) self.output_redirect(line, out) #lists and displays environmental strings def do_environ(self, line): if self.check_redirect(line) == False: for k, v in os.environ.items(): print(k + ": " + v) else: out = [] for k, v in os.environ.items(): out.append(k + ": " + v) out = "\n".join(out) self.output_redirect(line, out) #outputs the argument supplied by user def do_echo(self, line): tokens = self.get_tokens(line) if self.check_redirect(line) == False: print(line + '\n') else: out = (' '.join(tokens[0:-2])) self.output_redirect(line, out) #opens manual located in readme file and displays to user twenty lines at a time def do_help(self, line): try: if self.check_redirect(line) == False: with open(self.shell + "/readme", "r") as f: i = 2 j = 22 help_lines = f.read().split("\n") next_twenty = '\n'.join(help_lines[i:j]) while j < len(help_lines): next_twenty = '\n'.join(help_lines[i:j]) print(next_twenty) input() i += 20 j += 20 else: with open(self.shell + "/readme", "r") as f: out = f.read() self.output_redirect(line, out) except: (print("There appears to be a problem with the help manual...")) #clears the display by checking terminal size and printing new lines def do_clr(self, line): rows, columns = os.popen('stty size', 'r').read().split() for i in range(0, int(rows)): print("\n") #pauses operation of the shell until enter is pressed def do_pause(self, line): input("Press enter to resume..." + "\n") #an extra internal command I added to help with testing def do_sleep(self, line): try: time.sleep(int(line)) except: print("Exception!") #exits the shell def do_quit(self, line): sys.exit() #default action for when user inputs an empty line def emptyline(self): print("") #default action for commands that are not defined def default(self, line): tokens = self.get_tokens(line) if tokens[-1] == "&": self.background_exec(line) else: self.invoke(line) #if user enters a command that is not among the internal commands, check if the command is invocation of external programs and execute them def invoke(self, line): line = self.get_tokens(line) pid = os.fork() if pid > 0: wait_pid = os.waitpid(pid, 0) else: try: os.execvp(line[0], line) except FileNotFoundError: print( Colours.red( " '{}' not found. Type 'help' for shell documentation." .format(' '.join(line)))) self.do_quit('') except: print("Exception!") self.do_quit('') #execute program defined in line as background process def background_exec(self, line): line = self.get_tokens(line) subprocess.Popen(line) #check if user is attempting to redirect output def check_redirect(self, line): tokens = self.get_tokens(line) if len(tokens) > 0 and (">" in tokens or ">>" in tokens): return True else: return False #determine whether user wants to append or truncate and find position of new file name def output_redirect(self, line, output): tokens = self.get_tokens(line) i = 0 while i < len(tokens) and (tokens[i - 1] != ">" or tokens[i - 1] != ">>"): if tokens[i] == ">": self.truncate(line, output, i) elif tokens[i] == ">>": self.append(line, output, i) i += 1 #get name of new file by using position supplied by output_redirect, and either create new file or truncate existing def truncate(self, line, output, position): i = position tokens = self.get_tokens(line) with open(tokens[i + 1], "w") as f: f.write(output) #same as truncate method, except append to existing file def append(self, line, output, position): i = position tokens = self.get_tokens(line) with open(tokens[i + 1], "a") as f: f.write("\n" + output) #a simple method for splitting a line into tokens def get_tokens(self, line): tokens = line.split() return tokens